using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO.Ports; using System.Linq; using System.Management; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using Tango.Core; using Tango.Core.Helpers; using Tango.Logging; using Tango.PMR; using Tango.PMR.Common; using Tango.PMR.Integration; using Tango.Settings; using Tango.Transport.Adapters; namespace Tango.Integration.ExternalBridge { /// /// Scans for available machines on the local area network and physically connected via USB. /// /// public class ExternalBridgeScanner : ExtendedObject { private Thread _tcpDiscoveryThread; private Thread _usbDiscoveryThread; private UdpClient _server; private IntegrationSettings _settings; private SynchronizedObservableCollection _availableMachines; /// /// Gets the available machines. /// public SynchronizedObservableCollection AvailableMachines { get { return _availableMachines; } private set { _availableMachines = value; RaisePropertyChangedAuto(); } } private bool _isStarted; /// /// Gets or sets a value indicating whether this instance is started. /// public bool IsStarted { get { return _isStarted; } private set { _isStarted = value; RaisePropertyChangedAuto(); } } /// /// Initializes a new instance of the class. /// public ExternalBridgeScanner() { _settings = SettingsManager.Default.GetOrCreate(); _server = new UdpClient(_settings.ExternalBridgeServiceDiscoveryPort); AvailableMachines = new SynchronizedObservableCollection(); } /// /// Start scanning. (Results will be available through ). /// public void Start() { if (!IsStarted) { LogManager.Log("External bridge scanner started..."); IsStarted = true; foreach (var machine in AvailableMachines.OfType().ToList()) { AvailableMachines.Remove(machine); } _tcpDiscoveryThread = new Thread(TcpDiscoveryThreadMethod); _tcpDiscoveryThread.IsBackground = true; _tcpDiscoveryThread.Start(); _usbDiscoveryThread = new Thread(UsbDiscoveryThreadMethod); _usbDiscoveryThread.IsBackground = true; _usbDiscoveryThread.Start(); } } /// /// Stops this instance. /// public void Stop() { if (IsStarted) { IsStarted = false; LogManager.Log("External bridge scanner stopped."); } } /// /// USB discovery thread method. /// private void UsbDiscoveryThreadMethod() { while (IsStarted) { foreach (var device in Transport.Components.ComPortEnumerator.EnumerateComPorts()) { if (device.Description.Contains(_settings.EmbeddedDeviceName) || !_settings.FilterExternalBridgeUsbMachines) { if (!AvailableMachines.OfType().ToList().Exists(x => x.ComPort == device.Port)) { LogManager.Log("Found a new machine via USB " + device.Description); ThreadsHelper.InvokeUINow(() => { AvailableMachines.Add(new ExternalBridgeUsbClient(device.Port, device.Description, _settings.EmbeddedSerialBaudRate)); }); } } } Thread.Sleep(2000); } } /// /// TCP discovery thread method. /// [DebuggerStepThrough] private void TcpDiscoveryThreadMethod() { while (IsStarted) { try { var ClientEp = new IPEndPoint(IPAddress.Any, _settings.ExternalBridgeServiceDiscoveryPort); _server.EnableBroadcast = true; var ClientRequestData = _server.Receive(ref ClientEp); ExternalBridgeUdpDiscoveryPacket packet = ExternalBridgeUdpDiscoveryPacket.Parser.ParseFrom(ClientRequestData); String address = ClientEp.Address.ToString(); //validate service existence using TCP connection. try { TcpClient client = new TcpClient(); client.Connect(address, _settings.ExternalBridgeServiceDiscoveryPort); client.Dispose(); } catch { var disconnected_machine = AvailableMachines.OfType().ToList().FirstOrDefault(x => x.SerialNumber == packet.SerialNumber && x.IPAddress == address); if (disconnected_machine != null) { LogManager.Log("Disconnected machine detected via TCP: " + disconnected_machine.SerialNumber); AvailableMachines.Remove(disconnected_machine); } continue; } if (!AvailableMachines.OfType().ToList().Exists(x => x.SerialNumber == packet.SerialNumber && x.IPAddress == address)) { ExternalBridgeTcpClient newMachine = new ExternalBridgeTcpClient(packet.SerialNumber, address); LogManager.Log("Found a new machine via TCP " + newMachine.SerialNumber); ThreadsHelper.InvokeUINow(() => { AvailableMachines.Insert(1, newMachine); }); } } catch (Exception ex) { LogManager.Log(ex); } } } private DateTime ParseDateTime(String dateTime) { try { return DateTime.ParseExact(dateTime, "dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture); } catch (Exception) { return DateTime.Parse(dateTime); } } /// /// Handles the available machines component state changed event. /// /// The sender. /// The e. private void Client_StateChanged(object sender, Transport.TransportComponentState e) { if (e == Transport.TransportComponentState.Failed || e == Transport.TransportComponentState.Disposed) { LogManager.Log("External bridge client failed or disposed. Removing from available machines..."); AvailableMachines.Remove(sender as IExternalBridgeClient); } } } }