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