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()); } } }