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;
using Tango.Integration.JobRuns;
namespace Tango.PPC.Common.Connection
{
///
/// Represents the default .
///
///
///
public class DefaultMachineProvider : ExtendedObject, IMachineProvider
{
private bool _isInitialized;
private Thread _connection_thread;
private ObservablesContext _context;
///
/// Occurs when the machine has connected.
///
public event EventHandler MachineConnected;
///
/// Occurs when the machine has disconnected.
///
public event EventHandler MachineDisconnected;
public event EventHandler Initialized;
private bool _isConnected;
///
/// Gets a value indicating whether the machine is currently connected.
///
public bool IsConnected
{
get { return _isConnected; }
private set { _isConnected = value; RaisePropertyChangedAuto(); }
}
private Machine _machine;
///
/// Gets the database machine entity associated with the current machine.
///
public Machine Machine
{
get
{
return _machine;
}
private set
{
_machine = value;
RaisePropertyChangedAuto();
}
}
private IMachineOperator _machineOperator;
///
/// Gets the machine operator.
///
public IMachineOperator MachineOperator
{
get
{
return _machineOperator;
}
private set
{
_machineOperator = value;
RaisePropertyChangedAuto();
}
}
///
/// Initializes a new instance of the class.
///
public DefaultMachineProvider()
{
var settings = SettingsManager.Default.GetOrCreate();
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.EnableNotifications = true;
MachineOperator.EnableTelemetryWire = 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;
(MachineOperator.JobRunsLogger as BasicJobRunsLogger).CreateJobRunsFiles = true;
#if Eureka
ProcessParametersTable.DryerBufferMode = BL.Enumerations.MachineTypes.Eureka;
#endif
}
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();
if (Machine != null)
{
try
{
using (var db = ObservablesContext.CreateDefault())
{
var spoolType = db.SpoolTypes.FirstOrDefault(x => x.Guid == settings.SpoolTypeGuid);
await MachineOperator.SetSpoolType((PMR.Printing.JobSpoolType)spoolType.Code);
}
}
catch (Exception ex)
{
LogManager.Log(ex, "Error setting machine spool type before connection.");
}
}
if (!Machine.IsDemo)
{
if (String.IsNullOrWhiteSpace(settings.EmbeddedComPort))
{
TimeSpan timeout = TimeSpan.FromSeconds(SettingsManager.Default.GetOrCreate().MachineScanningTimeoutSeconds);
LogManager.Log("Scanning for machine on available serial ports...", LogCategory.Info);
Transport.Discovery.UsbCommunicationScanner scanner = new Transport.Discovery.UsbCommunicationScanner(settings.EmbeddedBaudRate);
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 = settings.EmbeddedBaudRate.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, settings.EmbeddedBaudRate);
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!");
if (settings.EmulatorMode == EmulatorMode.InMemory)
{
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;
}
else
{
LogManager.Log("Connecting to external emulator over TCP...");
TcpTransportAdapter adapter = new TcpTransportAdapter("127.0.0.1", 30000);
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, LogCategory.Debug, "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);
}
}
///
/// Initializes this machine provider start machine port scanning and connection.
///
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 + ".");
MachineOperator.MachineType = Machine.Type;
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);
Initialized?.Invoke(this, Machine);
ConnectToMachine();
}
else
{
LogManager.Log("No machine entry found on database. Could not connect to the embedded device!", LogCategory.Error);
}
}
}
///
/// Tries to connect to the machine by scanning all available serial ports.
/// The timeout for a scan cycle is specified on .
///
private void ConnectToMachine()
{
if (_connection_thread == null)
{
_connection_thread = new Thread(ConnectionThreadMethod);
_connection_thread.IsBackground = true;
_connection_thread.Start();
}
}
///
/// Saves the machine settings.
///
///
public async Task SaveMachine()
{
await _context.SaveChangesAsync();
Machine = await new MachineBuilder(_context).SetFirst().BuildAsync();
TangoMessenger.Default.Send(new MachineSettingsSavedMessage() { Machine = Machine });
}
///
/// Creates and connects a machine operator with no continuous requests at all.
///
///
public static async Task CreateMinimalMachineOperator(Action 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;
machineOperator.EnableAutomaticThreadLoading = false;
machineOperator.EnableInkFillingStatus = false;
machineOperator.EnableJobLiquidQuantityValidation = false;
machineOperator.EnablePowerUpSequence = false;
#if Eureka
machineOperator.MachineType = BL.Enumerations.MachineTypes.Eureka;
#endif
#if X1
machineOperator.MachineType = BL.Enumerations.MachineTypes.X1;
#endif
LogManager.Default.Log("Starting machine connection procedure...");
var settings = SettingsManager.Default.GetOrCreate();
if (String.IsNullOrWhiteSpace(settings.EmbeddedComPort))
{
TimeSpan timeout = TimeSpan.FromSeconds(SettingsManager.Default.GetOrCreate().MachineScanningTimeoutSeconds);
onProgress?.Invoke("Scanning for the machine...");
LogManager.Default.Log("Scanning for machine on available serial ports...");
Transport.Discovery.UsbCommunicationScanner scanner = new Transport.Discovery.UsbCommunicationScanner(settings.EmbeddedBaudRate);
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, settings.EmbeddedBaudRate);
machineOperator.Adapter = adapter;
machineOperator.JobHandlingMode = JobHandlerModes.SettingUp;
await machineOperator.Connect();
}
return machineOperator;
}
///
/// Called when the machine has connected.
///
protected async virtual void OnMachineConnected()
{
IsConnected = true;
MachineConnected?.Invoke(this, new EventArgs());
var settings = SettingsManager.Default.GetOrCreate();
if (Machine.Type.IsXMachine())
{
try
{
await MachineOperator.SetPowerSavingMode((int)settings.PowerSavingModeIdle, (int)settings.PowerSavingModePowerOff);
}
catch { }
}
await MachineOperator.SetBuzzerSettings(settings.EnableBuzzer, settings.BuzzerDuration);
await MachineOperator.SetWhiteThreadSkip(settings.EnableWhiteThreadSkip);
}
///
/// Called when the machine has disconnected.
///
protected virtual void OnMachineDisconnected()
{
IsConnected = false;
MachineDisconnected?.Invoke(this, new EventArgs());
}
}
}