using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Inputpre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.BL;
using Tango.BL.Entities;
using Tango.Core;
using Tango.Integration.Operation;
using Tango.Integration.ExternalBridge;
using Tango.PMR.Connection;
using Tango.Transport.Adapters;
using Tango.Settings;
using Tango.Logging;
using Tango.BL.Builders;
using Tango.Core.DI;
using Tango.PPC.Common.Messages;
using Tango.Emulations.Emulators;
using Tango.Transport.Transporters;
using Tango.Integration;
using Tango.Transport;
using System.Threading;
using Tango.Core.ExtensionMethods;
using System.IO.Ports;
namespace Tango.PPC.Common.Connection
{
/// <summary>
/// Represents the default <see cref="IMachineProvider"/>.
/// </summary>
/// <seealso cref="Tango.Core.ExtendedObject" />
/// <seealso cref="Tango.PPC.Common.Connection.IMachineProvider" />
public class DefaultMachineProvider : ExtendedObject, IMachineProvider
{
private bool _isInitialized;
private Thread _connection_thread;
private ObservablesContext _context;
/// <summary>
/// Occurs when the machine has connected.
/// </summary>
public event EventHandler MachineConnected;
/// <summary>
/// Occurs when the machine has disconnected.
/// </summary>
public event EventHandler MachineDisconnected;
private bool _isConnected;
/// <summary>
/// Gets a value indicating whether the machine is currently connected.
/// </summary>
public bool IsConnected
{
get { return _isConnected; }
private set { _isConnected = value; RaisePropertyChangedAuto(); }
}
private Machine _machine;
/// <summary>
/// Gets the database machine entity associated with the current machine.
/// </summary>
public Machine Machine
{
get
{
return _machine;
}
private set
{
_machine = value;
RaisePropertyChangedAuto();
}
}
private IMachineOperator _machineOperator;
/// <summary>
/// Gets the machine operator.
/// </summary>
public IMachineOperator MachineOperator
{
get
{
return _machineOperator;
}
private set
{
_machineOperator = value;
RaisePropertyChangedAuto();
}
}
/// <summary>
/// Initializes a new instance of the <see cref="DefaultMachineProvider"/> class.
/// </summary>
public DefaultMachineProvider()
{
var settings = SettingsManager.Default.GetOrCreate<PPCSettings>();
MachineOperator = new MachineOperator();
MachineOperator.StatusChanged += MachineOperator_StatusChanged;
MachineOperator.EnableEventsNotification = true;
MachineOperator.EnableJobResume = true;
MachineOperator.UseKeepAlive = true;
MachineOperator.EnableMachineStatusUpdates = true;
MachineOperator.EnableDiagnostics = true;
MachineOperator.EnablePowerUpSequence = true;
MachineOperator.EnableEmbeddedDebugging = settings.EnableEmbeddedDebugLogs;
MachineOperator.EnableAutomaticThreadLoading = settings.EnableAutomaticThreadLoading;
MachineOperator.JobRunsLogger.JobSource = BL.Enumerations.JobSource.Local;
MachineOperator.FirmwareUpgradeMode = Integration.Upgrade.FirmwareUpgradeModes.DFU | Integration.Upgrade.FirmwareUpgradeModes.TFP_PACKAGE;
MachineOperator.JobUploadStrategy = settings.JobUploadStrategy;
MachineOperator.JobUnitsMethod = settings.JobUnitsMethod;
MachineOperator.GradientGenerationConfiguration.IsEnabled = settings.EnableGradientGeneration;
MachineOperator.GradientGenerationConfiguration.ResolutionCM = settings.GradientGenerationResolution;
MachineOperator.EmergencyNotificationProvider.Address = settings.EmergencyComPort;
MachineOperator.EmergencyNotificationProvider.IsEnabled = settings.EnableEmergencyNotifications;
MachineOperator.EnableJobLiquidQuantityValidation = settings.EnableJobLiquidQuantityValidation;
}
private void MachineOperator_StatusChanged(object sender, MachineStatuses status)
{
if (status != MachineStatuses.Disconnected)
{
if (!IsConnected)
{
OnMachineConnected();
}
}
else
{
if (IsConnected)
{
OnMachineDisconnected();
}
}
}
private async void ConnectionThreadMethod()
{
bool fileLoggingDisabled = false;
while (true)
{
if (MachineOperator.State != TransportComponentState.Connected)
{
try
{
Thread.Sleep(2000);
if (!fileLoggingDisabled)
{
LogManager.Log("Starting machine connection procedure...", LogCategory.Info);
}
var settings = SettingsManager.Default.GetOrCreate<PPCSettings>();
if (!Machine.IsDemo)
{
if (String.IsNullOrWhiteSpace(settings.EmbeddedComPort))
{
TimeSpan timeout = TimeSpan.FromSeconds(SettingsManager.Default.GetOrCreate<PPCSettings>().MachineScanningTimeoutSeconds);
LogManager.Log("Scanning for machine on available serial ports...", LogCategory.Info);
Transport.Discovery.UsbCommunicationScanner<ConnectRequest, ConnectResponse> scanner = new Transport.Discovery.UsbCommunicationScanner<ConnectRequest, ConnectResponse>(UsbSerialBaudRates.BR_115200);
var response = await scanner.Scan(new ConnectRequest() { Password = "1234" }, settings.EmbeddedDeviceHint, timeout);
LogManager.Log("Machine discovered on port: " + response.Adapter.Address, LogCategory.Info);
LogManager.Log("Device Information:", LogCategory.Debug);
LogManager.Log(response.Response.DeviceInformation.ToJsonString(), LogCategory.Info);
LogManager.Log("Disconnecting machine operator...", LogCategory.Info);
await MachineOperator.Disconnect();
MachineOperator.Adapter = response.Adapter;
MachineOperator.JobHandlingMode = JobHandlerModes.SettingUp;
LogManager.Log("Connecting machine operator...", LogCategory.Info);
try
{
await MachineOperator.Connect();
if (MachineOperator.DeviceInformation != null)
{
settings.FirmwareVersion = MachineOperator.DeviceInformation.Version;
settings.Save();
}
}
catch (Exception)
{
await response.Adapter.Disconnect();
throw;
}
await Task.Delay(1000);
await MachineOperator.UploadHardwareConfiguration(Machine.Configuration.HardwareVersion, Machine.Configuration);
MachineOperator.UseKeepAlive = true;
}
else
{
//Perform a pre-test to not overload the log file when machine is off for a long time.
using (SerialPort preCheckSerialPort = new SerialPort(settings.EmbeddedComPort))
{
preCheckSerialPort.BaudRate = UsbSerialBaudRates.BR_115200.ToInt32();
preCheckSerialPort.Open();
preCheckSerialPort.Close();
fileLoggingDisabled = false;
Thread.Sleep(500); //Wait a little while to not scare the other side?..
}
LogManager.Log($"Connecting to machine on {settings.EmbeddedComPort}...", LogCategory.Info);
UsbTransportAdapter adapter = new UsbTransportAdapter(settings.EmbeddedComPort, UsbSerialBaudRates.BR_115200);
MachineOperator.Adapter = adapter;
MachineOperator.JobHandlingMode = JobHandlerModes.SettingUp;
try
{
await MachineOperator.Connect();
if (MachineOperator.DeviceInformation != null)
{
settings.FirmwareVersion = MachineOperator.DeviceInformation.Version;
settings.Save();
}
}
catch (Exception)
{
await adapter.Disconnect();
throw;
}
await Task.Delay(1000);
await MachineOperator.UploadHardwareConfiguration(Machine.Configuration.HardwareVersion, Machine.Configuration);
MachineOperator.UseKeepAlive = true;
}
}
else
{
LogManager.Log("Application in demo mode!");
var emulator_channel_name = "emulator-" + Guid.NewGuid().ToString();
LogManager.Log("Starting embedded emulator...");
MachineEmulator emulator = new MachineEmulator(new BasicTransporter(new MemoryTransportAdapter(emulator_channel_name)));
await emulator.Start();
LogManager.Log("Emulator started. Connecting to emulator...");
MemoryTransportAdapter adapter = new MemoryTransportAdapter(emulator_channel_name);
MachineOperator.Adapter = adapter;
MachineOperator.JobHandlingMode = JobHandlerModes.SettingUp;
LogManager.Log("Connecting machine operator...");
await MachineOperator.Connect();
if (MachineOperator.DeviceInformation != null)
{
settings.FirmwareVersion = MachineOperator.DeviceInformation.Version;
settings.Save();
}
await Task.Delay(1000);
await MachineOperator.UploadHardwareConfiguration(Machine.Configuration.HardwareVersion, Machine.Configuration);
}
}
catch (Exception ex)
{
if (!fileLoggingDisabled || LogManager.Categories.Contains(LogCategory.Debug))
{
LogManager.Log(ex, "Error while trying to scan and connect to the machine.");
LogManager.Log("Application logging of further connection attempts is now disabled and will resume when connection is successful.");
fileLoggingDisabled = true;
}
}
}
Thread.Sleep(5000);
}
}
/// <summary>
/// Initializes this machine provider start machine port scanning and connection.
/// </summary>
public void Init(Machine machine, ObservablesContext context)
{
if (!_isInitialized)
{
LogManager.Log("Initializing machine operator...");
_isInitialized = true;
LogManager.Log("Retrieving first machine database entry...");
_context = context;
Machine = machine;
if (Machine != null)
{
LogManager.Log("First machine entry found. Machine serial number is: " + Machine.SerialNumber + ".");
if (Machine.IsDemo)
{
LogManager.Log("Machine is in demo mode. Changing firmware upgrade mode to TFP package only.");
MachineOperator.FirmwareUpgradeMode = Integration.Upgrade.FirmwareUpgradeModes.TFP_PACKAGE;
}
MachineOperator.JobRunsLogger.SetDefaultMachine(Machine);
ConnectToMachine();
}
else
{
LogManager.Log("No machine entry found on database. Could not connect to the embedded device!", LogCategory.Error);
}
}
}
/// <summary>
/// Tries to connect to the machine by scanning all available serial ports.
/// The timeout for a scan cycle is specified on <see cref="PPCSettings.MachineScanningTimeoutSeconds"/>.
/// </summary>
private void ConnectToMachine()
{
if (_connection_thread == null)
{
_connection_thread = new Thread(ConnectionThreadMethod);
_connection_thread.IsBackground = true;
_connection_thread.Start();
}
}
/// <summary>
/// Saves the machine settings.
/// </summary>
/// <returns></returns>
public async Task SaveMachine()
{
await _context.SaveChangesAsync();
Machine = await new MachineBuilder(_context).SetFirst().BuildAsync();
TangoMessenger.Default.Send(new MachineSettingsSavedMessage() { Machine = Machine });
}
/// <summary>
/// Creates and connects a machine operator with no continuous requests at all.
/// </summary>
/// <returns></returns>
public static async Task<IMachineOperator> CreateMinimalMachineOperator(Action<String> onProgress = null)
{
LogManager.Default.Log("Creating minimal machine operator...");
var machineOperator = new MachineOperator();
machineOperator.EnableDiagnostics = false;
machineOperator.EnableEmbeddedDebugging = false;
machineOperator.EnableEventsNotification = false;
machineOperator.EnableMachineStatusUpdates = false;
machineOperator.EnableJobResume = false;
LogManager.Default.Log("Starting machine connection procedure...");
var settings = SettingsManager.Default.GetOrCreate<PPCSettings>();
if (String.IsNullOrWhiteSpace(settings.EmbeddedComPort))
{
TimeSpan timeout = TimeSpan.FromSeconds(SettingsManager.Default.GetOrCreate<PPCSettings>().MachineScanningTimeoutSeconds);
onProgress?.Invoke("Scanning for the machine...");
LogManager.Default.Log("Scanning for machine on available serial ports...");
Transport.Discovery.UsbCommunicationScanner<ConnectRequest, ConnectResponse> scanner = new Transport.Discovery.UsbCommunicationScanner<ConnectRequest, ConnectResponse>(UsbSerialBaudRates.BR_115200);
var response = await scanner.Scan(new ConnectRequest() { Password = "1234" }, timeout);
onProgress?.Invoke("Machine discovered on port: " + response.Adapter.Address);
LogManager.Default.Log("Machine discovered on port: " + response.Adapter.Address);
LogManager.Default.Log("Device Information:");
LogManager.Default.Log(response.Response.DeviceInformation.ToJsonString());
machineOperator.Adapter = response.Adapter;
machineOperator.JobHandlingMode = JobHandlerModes.SettingUp;
LogManager.Default.Log("Connecting machine operator...");
onProgress?.Invoke("Connecting machine operator...");
await machineOperator.Connect();
}
else
{
LogManager.Default.Log($"Connecting to machine on {settings.EmbeddedComPort}...");
onProgress?.Invoke($"Connecting to machine on {settings.EmbeddedComPort}...");
UsbTransportAdapter adapter = new UsbTransportAdapter(settings.EmbeddedComPort, UsbSerialBaudRates.BR_115200);
machineOperator.Adapter = adapter;
machineOperator.JobHandlingMode = JobHandlerModes.SettingUp;
await machineOperator.Connect();
}
return machineOperator;
}
/// <summary>
/// Called when the machine has connected.
/// </summary>
protected virtual void OnMachineConnected()
{
IsConnected = true;
MachineConnected?.Invoke(this, new EventArgs());
}
/// <summary>
/// Called when the machine has disconnected.
/// </summary>
protected virtual void OnMachineDisconnected()
{
IsConnected = false;
MachineDisconnected?.Invoke(this, new EventArgs());
}
}
}