using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
using DTS.Common.DASResource;
using DTS.Common.Interface.DASFactory;
using DTS.DASLib.Service;
using DTS.Common.Utilities.Logging;
using DTS.Common.Enums.DASFactory;
using DTS.Common.Enums.Communication;
using DTS.Common.Interface.Communication;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using DTS.DASLib.Service.Classes.CAN;
// ReSharper disable once CheckNamespace
namespace DTS.DASLib.DASFactory
{
#region Connected devices list
public interface IConnectedDevice : IDisposable
{
string ConnectString { get; }
ICommunication Comm { get; }
}
public interface IConnectedDAS : IConnectedDevice
{
IDASCommunication DASComm { get; }
}
///
/// This is the base class for all connected DAS's
///
public class ConnectedBaseDevice : IConnectedDAS
{
protected IDASCommunication Device { get; set; }
///
/// Constructor
///
/// The device we're handling
public ConnectedBaseDevice(IDASCommunication device)
{
Debug.Assert(device is ICommunication);
Device = device;
}
///
/// Implementation of the interface.
///
public virtual string ConnectString => Comm.ConnectString;
///
/// Implementation of the interface.
///
public virtual ICommunication Comm => Device as ICommunication;
///
/// Implementation of the interface.
///
public virtual IDASCommunication DASComm => Device;
///
/// A text representation
///
/// The device serial number
public override string ToString()
{
return Device.SerialNumber;
}
///
/// Dispose of the device
///
public virtual void Dispose()
{
try
{
if (Device == null) return;
Device.Dispose();
Device = null;
}
catch (Exception ex)
{
APILogger.Log(ex);
}
}
}
///
/// This represent one SLICE connected thru WinUSB
///
public class ConnectedWinUSBSlice : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedWinUSBSlice(WinUSBSlice device) : base(device)
{
}
}
///
/// This represent one SLICE connected thru WinUSB
///
public class ConnectedCDCUSBSlice : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedCDCUSBSlice(CDCUSBSlice device)
: base(device)
{
}
}
///
/// This represent one SLICE connected thru WinUSB
///
// ReSharper disable once InconsistentNaming
public class ConnectedWinUSBSlice1_5 : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedWinUSBSlice1_5(WinUSBSlice1_5 device)
: base(device)
{
}
}
///
/// This represent one SLICE 6 connected thru WinUSB
///
public class ConnectedWinUSBSlice6 : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedWinUSBSlice6(WinUSBSlice6 device)
: base(device)
{
}
}
///
/// This represent one SLICE 6 AIR connected thru WinUSB
///
public class ConnectedWinUSBSlice6Air : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedWinUSBSlice6Air(WinUSBSlice6Air device)
: base(device)
{
}
}
///
/// This represent one SLICE 6 AIR BR connected thru WinUSB
///
public class ConnectedWinUSBSlice6AirBridge : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedWinUSBSlice6AirBridge(WinUSBSlice6AirBridge device)
: base(device)
{
}
}
///
/// This represent one TSRAIR connected thru WinUSB
///
public class ConnectedWinUSBTsrAir : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedWinUSBTsrAir(WinUSBTsrAir device)
: base(device)
{
}
}
///
/// This represent one SLICE 6 AIR TC connected thru WinUSB
///
public class ConnectedWinUSBSlice6AirThermocoupler : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedWinUSBSlice6AirThermocoupler(WinUSBSlice6AirThermocoupler device)
: base(device)
{
}
}
///
/// This represent one SLICE connected thru a Slice Distributor
///
public class ConnectedEthernetSlice : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedEthernetSlice(EthernetSlice device) : base(device)
{
}
}
///
/// This represents one SLICE 2 connected thru a Slice Distributor
///
public class ConnectedEthernetSlice2 : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedEthernetSlice2(EthernetSlice2 device)
: base(device)
{
}
}
///
/// This represents one SLICE 1.5 connected thru a Slice Distributor
///
// ReSharper disable once InconsistentNaming
public class ConnectedEthernetSlice1_5 : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedEthernetSlice1_5(EthernetSlice1_5 device)
: base(device)
{
}
}
///
/// This represents one SLICE 6 connected thru a Slice Distributor
///
public class ConnectedEthernetSlice6 : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedEthernetSlice6(EthernetSlice6 device)
: base(device)
{
}
}
///
/// This represents one SLICE 6 AIR connected thru a Slice Distributor
///
public class ConnectedEthernetSlice6Air : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedEthernetSlice6Air(EthernetSlice6Air device)
: base(device)
{
}
}
///
/// This represents one SLICE 6 AIR Bridge connected thru a Slice Distributor
///
public class ConnectedEthernetSlice6AirBridge : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedEthernetSlice6AirBridge(EthernetSlice6AirBridge device)
: base(device)
{
}
}
///
/// This represents one SLICE 6 connected thru a Slice Distributor
///
public class ConnectedEthernetSlice6DB : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedEthernetSlice6DB(EthernetSlice6DB _device)
: base(_device)
{
}
}
///
/// This represents one PowerPro
///
public class ConnectedEthernetPowerPro : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedEthernetPowerPro(EthernetPowerPro _device)
: base(_device)
{
}
}
///
/// This represents one SLICE PRO DB
///
public class ConnectedEthernetSliceProDB : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedEthernetSliceProDB(EthernetSlicePRODB _device)
: base(_device)
{
}
}
/// This represents one SDB
///
public class ConnectedEthernetSDB : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedEthernetSDB(EthernetSliceDB device)
: base(device)
{
}
}
///
/// This represents one TSRAIR connected thru a Slice Distributor
///
public class ConnectedEthernetTsrAir : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedEthernetTsrAir(EthernetTsrAir device)
: base(device)
{
}
}
///
/// This represents one S6DB3 connected thru a Slice Distributor
///
public class ConnectedEthernetSlice6DB3 : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedEthernetSlice6DB3(EthernetSlice6DB3 device)
: base(device)
{
}
}
///
/// This represent one SLICE connected thru a Slice Distributor
///
public class ConnectedEthernetTDAS : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedEthernetTDAS(EthernetTDAS device)
: base(device)
{
}
}
///
/// This represent one TDAS connected thru a TDAS RS-232 Port
///
public class ConnectedSerialTDAS : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedSerialTDAS(SerialTDAS device)
: base(device)
{
}
}
///
/// This represent one Ribeye connected thru a Slice Distributor
///
public class ConnectedEthernetRibeye : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedEthernetRibeye(EthernetRibeye device) : base(device)
{
}
}
public class ConnectedRESTSPFD : ConnectedBaseDevice
{
public ConnectedRESTSPFD(RESTSliceProFD device) : base(device) { }
}
///
/// This represents one SLICE 6 AIR TC connected thru a Slice Distributor
///
public class ConnectedEthernetSlice6AirThermocoupler : ConnectedBaseDevice
{
///
/// Constructor
///
/// The device we're handling
public ConnectedEthernetSlice6AirThermocoupler(EthernetSlice6AirThermocoupler device)
: base(device)
{
}
}
///
/// This represents one TSR2 connected thru WinUSB
///
public class ConnectedWinUSBTSR2 : IConnectedDevice
{
private WinUSBSlice Device { get; set; }
///
/// Constructor
///
/// The device we're handling
public ConnectedWinUSBTSR2(WinUSBSlice device)
{
Device = device;
}
///
/// Implementation of the interface.
///
public string ConnectString => Device.ConnectString;
///
/// Implementation of the interface.
///
public ICommunication Comm => Device;
public override string ToString()
{
return Device.SerialNumber;
}
public void Dispose()
{
try
{
if (Device == null) return;
Device.Dispose();
Device = null;
}
catch (Exception ex)
{
APILogger.Log(ex);
}
}
}
public class ConnectedDevice : IDisposable, IComparable
{
public DFConstantsAndEnums.DASType DasType;
public IConnectedDevice Dev;
///
/// is this device in update mode?
///
public bool InUpdateMode { get; set; }
public ConnectedDevice()
{
Dev = null;
DasType = DFConstantsAndEnums.DASType.NONE;
InUpdateMode = false;
}
public ConnectedDevice(IConnectedDevice icd, DFConstantsAndEnums.DASType dt)
{
Dev = icd;
DasType = dt;
InUpdateMode = false;
}
public int CompareTo(ConnectedDevice other)
{
//Use ICommunication.CompareTo()
return Dev.Comm.CompareTo(other.Dev.Comm);
}
public override string ToString()
{
return InUpdateMode ? Dev.ConnectString : Dev.ToString();
}
public void Dispose()
{
try
{
if (Dev == null) return;
Dev.Dispose();
Dev = null;
}
catch (Exception ex)
{
APILogger.Log(ex);
}
}
}
#endregion
public interface IDeviceSetup
{
bool QueryInformation(ConnectedDevice dev);
ICommunication GetICommunication();
ICommunication GetICommunication(ConnectedDevice dev);
IConnectedDevice GetIConnectedDevice(DTS.Common.Interface.DASFactory.ICommunication comm);
bool IsCorrectType(ConnectedDevice dev);
DFConstantsAndEnums.DASType GetDASType();
Guid GetGuid();
int GetProductId();
string GetProductIdString();
void SetHandler(DeviceHandling handler);
}
public abstract class DeviceHandling
{
protected DASFactory Factory { get; set; }
private readonly BlockingCollection> _queueActionPerDevice;
protected DeviceHandling(DASFactory factory, UpdateFinishedEventHandler serialUpdateFinished, BlockingCollection> queueActionPerDevice = null)
{
Factory = factory;
SerialUpdateFinished += serialUpdateFinished;
_queueActionPerDevice = queueActionPerDevice;
}
///
/// called after construction of a devicehandler, this method is used
/// to update the device setups and notify them of their handlers, this way
/// the setup classes can notify the handlers and vice versa.
///
public abstract void UpdateDeviceSetups();
public virtual void Dispose()
{
var tuple = new Tuple(QueueActions.Exit, this);
_queueActionPerDevice.Add(tuple);
DetachAllDevices();
}
protected List ConnectedDevices = new List();
protected readonly object ConnectedDevicesLock = new object();
#region Connect and disconnect handling
///
/// This class is used to transfer device and WaitHandle to callback functions.
///
internal class DeviceAndWaitTuple
{
public object Device { get; set; }
public ManualResetEvent CompletedEvent { get; set; }
public DeviceAndWaitTuple(object dev, ManualResetEvent completed)
{
Device = dev;
CompletedEvent = completed;
}
}
internal class DeviceAndWaitExTuple : DeviceAndWaitTuple
{
public DFConstantsAndEnums.DASType DASType { get; set; }
public IDeviceSetup DevSetup { get; set; }
public DeviceAndWaitExTuple(object dev,
ManualResetEvent completed,
DFConstantsAndEnums.DASType dasType,
IDeviceSetup devSetup)
: base(dev, completed)
{
DASType = dasType;
DevSetup = devSetup;
}
}
#region Connect
protected delegate List GetDeviceStrings();
protected delegate ICommunication GetICommunication();
protected delegate IConnectedDevice GetIConnectedDevice(DTS.Common.Interface.DASFactory.ICommunication comm);
private static readonly object CONNECTING_DEVICES_LOCK = new object();
private readonly List _connectingDevices = new List();
///
///
///
///
///
///
///
///
///
///
protected virtual void ConnectNewDevices(GetDeviceStrings getAllConnected,
GetDeviceStrings getAllActive,
GetICommunication getICommunication,
GetIConnectedDevice getIConnectedDevice,
DFConstantsAndEnums.DASType dasType,
IDeviceSetup devSetup,
int callbackTimeout)
{
var bFailed = false;
try
{
// say hello
var connectedDevices = getAllConnected();
// subtract the ones we already know about
var newDevices = connectedDevices.Except(getAllActive()).ToArray();
if (!newDevices.Any()) { return; } //nothing to connect
// add the new ones
foreach (var devPath in newDevices.AsParallel())
{
try
{
lock (CONNECTING_DEVICES_LOCK)
{
if (_connectingDevices.Contains(devPath))
{
continue; //already connecting
}
//the device may have been added to active devices since we last checked, recheck before connecting
//15584 devices attempt connect while already connected
if (getAllActive().Contains(devPath))
{
continue;
}
APILogger.Log("Connecting, ", devPath);
_connectingDevices.Add(devPath);
}
try
{
var newDevice = getICommunication();
var newConnectedDevice = getIConnectedDevice(newDevice);
var connectedEvent = new ManualResetEvent(false);
//FB 25642 & 18152 Get the das ip from connection string and use it to retreive the host ip
string deviceIp;
string hostIpAddress = "";
//FB 25658 for USB there is no hostIP
if (Common.Utils.NetworkUtils.TryParseConnectionString(devPath, out deviceIp))
{
if (!Factory.DasToHost.ContainsKey(deviceIp))
{
APILogger.Log($"no known host for {deviceIp} we'll try pinging for it");
DASFactory.TryPing(deviceIp);
}
else
{
APILogger.Log($"we have a known host for {deviceIp} and it's {Factory.DasToHost[deviceIp].HostIpAddress}");
}
hostIpAddress = Factory.DasToHost[deviceIp].HostIpAddress;
}
// try to connect it
newDevice.Connect(devPath,
NewDeviceConnectCallback,
new DeviceAndWaitExTuple(newConnectedDevice, connectedEvent, dasType, devSetup),
callbackTimeout, hostIpAddress);
if (!connectedEvent.WaitOne(callbackTimeout, false))
{
bFailed = true;
throw new TimeoutException("Failed to connect new device " + devPath);
}
if (this is EthernetHandling handling)
{
handling.CommandPortConnected = true;
}
}
finally
{
lock (CONNECTING_DEVICES_LOCK)
{
if (_connectingDevices.Contains(devPath))
{
_connectingDevices.Remove(devPath);
}
}
}
}
catch (Exception ex)
{
APILogger.Log("Exception connecting device", ex);
}
}
}
catch (Exception ex)
{
APILogger.Log("ConnectNewDevices: Exception", ex);
}
finally
{
if (bFailed)
{
Thread.Sleep(100);
}
}
}
//lock for concurrency handling on lookup
private static readonly object COM_LOCK = new object();
//lookup of dictionary (network path minus port) to socket
private static Dictionary _CommandPortSockets = new Dictionary();
///
/// adds a new socket into the lookup of ip to socket
///
private static void AddCommandPortSocket(string key, Socket s)
{
lock (COM_LOCK)
{
_CommandPortSockets[key] = s;
}
}
///
/// returns the socket to the command port to an ip (or null if we don't have one)
///
public static Socket GetCommandPortSocket(string key)
{
lock (COM_LOCK)
{
if (_CommandPortSockets.ContainsKey(key))
{
return _CommandPortSockets[key];
}
}
return null;
}
///
/// removes a command port from the lookup
///
public static void RemoveCommandPortSocket(string s)
{
lock (COM_LOCK)
{
_CommandPortSockets.Remove(s);
}
}
///
/// the port (plus : for slice command port (as opposed to heartbeat port)
///
public const string SLICE_COMMAND_PORT = ":8201";
public const string SLICE6_COMMAND_PORT = ":8301";
///
/// Callback for new device connect
///
/// state passed in from connect function
protected virtual bool NewDeviceConnectCallback(ICommunicationReport report)
{
Debug.Assert(report.UserState is DeviceAndWaitExTuple);
var deviceInfo = (DeviceAndWaitExTuple)report.UserState;
var idStr = "";
try
{
var newDev = ExtractConnectedDevice(report, deviceInfo.DASType);
idStr = ConnectedDeviceId(newDev);
// was the connect successful?
if (report.Result == CommunicationConstantsAndEnums.CommunicationResult.ConnectOK)
{
try
{
//if new device is a command port, keep track of it
//so that we don't try to connect to a HB port while
//command port is still active
if (newDev.Dev.ConnectString.EndsWith(SLICE_COMMAND_PORT))
{
if (newDev.Dev.Comm.Transport is DTS.Common.EthernetConnection connection)
{
var key = newDev.Dev.ConnectString.Replace(SLICE_COMMAND_PORT, "");
AddCommandPortSocket(key, connection.Sock);
}
}
else if (newDev.Dev.ConnectString.EndsWith(SLICE6_COMMAND_PORT))
{
if (newDev.Dev.Comm.Transport is DTS.Common.EthernetConnection connection)
{
var key = newDev.Dev.ConnectString.Replace(SLICE6_COMMAND_PORT, "");
AddCommandPortSocket(key, connection.Sock);
}
}
}
catch (Exception ex)
{
APILogger.Log(ex);
}
// fill the DASInfo, this function does NOT throw exceptions
var queryInfoOk = deviceInfo.DevSetup.QueryInformation(newDev);
// update the ID string
idStr = ConnectedDeviceId(newDev);
if (queryInfoOk)
{
// add it to our list
lock (ConnectedDevicesLock)
{
APILogger.LogString($"{APILogger.GetCurrentMethod()}: id:{idStr}");
// add it
ConnectedDevices.Add(newDev);
// sort the list
ConnectedDevices.Sort();
}
// notify our subscribers
Factory.ReportArrived(newDev);
}
else
{
// first dispose of it
newDev.Dispose();
// notify our subscribers
Factory.ReportFailed();
}
}
else
{
// no, connect failed
// first dispose of it
newDev.Dispose();
// notify our users of the failure
Factory.ReportFailed();
}
}
catch (Exception ex)
{
APILogger.LogString(string.Format("{0}: exception: {1} id:{2}", APILogger.GetCurrentMethod(), report.Result, idStr));
APILogger.LogException(ex);
}
finally
{
deviceInfo.CompletedEvent.Set();
}
return false;
}
#endregion
#region Disconnect
protected delegate bool DASTypeFilter(ConnectedDevice dev);
protected delegate ICommunication ConnectedDevice2Communication(ConnectedDevice dev);
///
/// Remove the WinUSB devices that aren't connected
///
/// true if all OK, false if error
protected virtual void DisconnectRemovedDevices(GetDeviceStrings getAllConnected,
DASTypeFilter isCorrectType,
ConnectedDevice2Communication getCommunication,
DFConstantsAndEnums.DASType dasType,
int callbackTimeout)
{
try
{
// get a list of units currently connected
var connectedDeviceStrings = getAllConnected();
// remove the ones that aren't there anymore
// make a local copy of the connected devices list
ConnectedDevice[] connectedDevicesClone;
lock (ConnectedDevicesLock)
{
connectedDevicesClone = ConnectedDevices.ToArray();
}
var removedDeviceSerials = new List();
var devicesWhereRemoved = false;
foreach (var dev in connectedDevicesClone)
{
try
{
//if we are removing a command port, we don't have to worry about
//connecting to the HB port while the command port is active, as
//we should be disconnecting the command port ...
if (dev.Dev.Comm.Transport is DTS.Common.EthernetConnection connection)
{
if (dev.Dev.ConnectString.EndsWith(SLICE_COMMAND_PORT))
{
RemoveCommandPortSocket(dev.Dev.ConnectString.Replace(SLICE_COMMAND_PORT, ""));
}
else if (dev.Dev.ConnectString.EndsWith(SLICE6_COMMAND_PORT))
{
RemoveCommandPortSocket(dev.Dev.ConnectString.Replace(SLICE6_COMMAND_PORT, ""));
}
}
}
catch (Exception ex)
{
APILogger.Log(ex);
}
// if it's not of us we don't deal with it
if (!isCorrectType(dev))
{
continue;
}
// if it's still connected that's good
if (connectedDeviceStrings.Contains(dev.Dev.ConnectString))
{
continue;
}
// say hello
APILogger.LogString(string.Format("{0}:{1}", APILogger.GetCurrentMethod(), dev.Dev.ConnectString));
devicesWhereRemoved = true;
removedDeviceSerials.Add(dev.Dev.Comm.SerialNumber);
try
{
var disconnectedEvent = new ManualResetEvent(false);
// this is one of those places where we need to get to the ICommunication part
try
{
getCommunication(dev).Disconnect(false,
DisconnectDeviceCallback,
new DeviceAndWaitExTuple(dev, disconnectedEvent, dasType, null),
callbackTimeout);
}
catch (SocketException)
{
//15575 No notification if unplug comm cable during downloading on G5
//previously Disconnect would fail in some circumstances - namely if the unit is already disconnected
//this would cause an enormous and unnecessary delay in the waitone below
//to correct this, on socketexception we are done disconnecting, set the event and continue on
disconnectedEvent.Set();
}
disconnectedEvent.WaitOne();
}
catch (Exception ex)
{
APILogger.LogString("DisconnectRemovedDevices: Exception");
APILogger.LogException(ex);
}
finally
{
lock (ConnectedDevicesLock)
{
if (ConnectedDevices.Contains(dev))
{
ConnectedDevices.Remove(dev);
}
}
}
}
// notify our subscribers if we removed something
if (devicesWhereRemoved)
{
Factory.ReportRemoved(removedDeviceSerials.ToArray());
}
}
catch (Exception ex)
{
APILogger.LogString("DisconnectRemovedDevices: Exception");
APILogger.LogException(ex);
}
finally
{
//APILogger.LogString("DisconnectRemovedDevices: Exit");
}
}
///
/// Callback for WinUSB disconnect
///
///
/// always false
private bool DisconnectDeviceCallback(ICommunicationReport report)
{
Debug.Assert(report.UserState is DeviceAndWaitExTuple);
var deviceInfo = (DeviceAndWaitExTuple)report.UserState;
var idStr = "";
try
{
var newDev = ExtractConnectedDevice(report, deviceInfo.DASType);
idStr = ConnectedDeviceId(newDev);
APILogger.LogString("DisconnectDeviceCallback: Enter " + idStr);
// first dispose of it
newDev.Dispose();
// remove it from our list
lock (ConnectedDevicesLock)
{
ConnectedDevices.Remove(newDev);
}
APILogger.LogString("DisconnectDeviceCallback: " + report.Result + " " + idStr);
}
catch (Exception ex)
{
APILogger.LogString("DisconnectDeviceCallback: exception " + report.Result + " " + idStr);
APILogger.LogException(ex);
}
finally
{
APILogger.LogString("DisconnectDeviceCallback: Exit " + idStr);
deviceInfo.CompletedEvent.Set();
}
return false;
}
#endregion
#endregion
#region Get DAS/DEV List
public List GetDASList()
{
lock (ConnectedDevicesLock)
{
var dasList = new List();
try
{
if (ConnectedDevices != null)
{
if (ConnectedDevices.Count == 0)
{
//UpdateConnectedDevices();
}
foreach (var connectedDevice in ConnectedDevices)
{
// if it's not a DAS we're not interested
if (!(connectedDevice.Dev is IConnectedDAS))
{
continue;
}
// make it so
var connectedDAS = (IConnectedDAS)connectedDevice.Dev;
// it must also be an ICommunication
if (!(connectedDAS.DASComm is ICommunication))
{
continue;
}
var devCom = (ICommunication)connectedDAS.DASComm;
if (devCom.Connected)
{
dasList.Add(connectedDAS.DASComm);
}
else if (devCom.Transport.IsSoftDisconnected)
{
//the unit is not actively connected, but is still considered
//one of the das we could connect to ...
dasList.Add(connectedDAS.DASComm);
}
}
}
}
catch
{
// we don't know the state of the devices
dasList.Clear();
}
return dasList;
}
}
public List GetDevList()
{
lock (ConnectedDevicesLock)
{
var devList = new List();
try
{
if (ConnectedDevices != null)
{
foreach (var connectedDevice in ConnectedDevices)
{
// and so it shall be
if (connectedDevice?.Dev.Comm == null)
{
continue;
}
var devCom = connectedDevice.Dev.Comm;
if (devCom.Connected)
{
devList.Add(connectedDevice.Dev.Comm);
}
}
}
}
catch
{
// we don't know the state of the devices
devList.Clear();
}
return devList;
}
}
#endregion
protected List GetConnectedStrings()
{
for (var loop = 0; loop < 10; loop++)
{
lock (ConnectedDevicesLock)
{
try
{
var strings = new List();
foreach (var dev in ConnectedDevices)
{
strings.Add(dev.Dev.ConnectString);
}
return strings;
}
catch (NullReferenceException)
{
}
catch (InvalidOperationException)
{
}
}
}
throw new Exception("DASFactory.GetConnectedStrings: tried 10 times to get strings!!!");
}
///
/// Make DASFactory forget about all devices.
///
internal virtual bool DetachAllDevices()
{
var devicesWhereRemoved = false;
lock (ConnectedDevicesLock)
{
foreach (var dev in ConnectedDevices)
{
dev.Dispose();
devicesWhereRemoved = true;
}
ConnectedDevices.Clear();
}
// let our caller know if something was removed
return devicesWhereRemoved;
}
#region Serialization of connect and disconnect
public enum QueueActions
{
None, // we never enqueue this one
Connect,
Disconnect,
Idle,
Exit,
//FB 17556 Added action to disconnect when we exit
DisconnectAndExit
}
public delegate void UpdateFinishedEventHandler(DeviceHandling dev);
protected event UpdateFinishedEventHandler SerialUpdateFinished;
public abstract void UpdateDisconnectedDevices();
public abstract void UpdateConnectedDevices();
public void EnqueueConnect()
{
var tuple = new Tuple(QueueActions.Connect, this);
_queueActionPerDevice.Add(tuple);
}
public void EnqueueDisconnect()
{
var tuple = new Tuple(QueueActions.Disconnect, this);
_queueActionPerDevice.Add(tuple);
}
public void EnqueueDisconnectAndExit()
{
var tuple = new Tuple(QueueActions.DisconnectAndExit, this);
_queueActionPerDevice.Add(tuple);
}
#endregion
///
/// Convert an ICommunicationReport to a ConnectedDevice
///
/// the report to get the device from
/// The type of DAS we're looking for
/// The new ConnectedDevice
protected ConnectedDevice ExtractConnectedDevice(ICommunicationReport report, DFConstantsAndEnums.DASType dastype)
{
Debug.Assert(report.UserState is DeviceAndWaitTuple);
var deviceParameter = ((DeviceAndWaitTuple)report.UserState).Device;
ConnectedDevice newDev;
if (deviceParameter is ConnectedDevice)
{
newDev = deviceParameter as ConnectedDevice;
}
else
{
newDev = new ConnectedDevice
{
Dev = deviceParameter as IConnectedDevice,
DasType = dastype,
InUpdateMode = false
};
// assume not in update mode
}
return newDev;
}
///
/// Produce a string to identify a device with
///
/// The device
/// Always returns a string
internal string ConnectedDeviceId(ConnectedDevice dev)
{
if (dev == null)
{
return "device==null";
}
if (dev.Dev == null)
{
return "device.dev==null";
}
if (!(dev.Dev is IConnectedDAS))
{
return "device.dev not IConnectedDAS";
}
if (((IConnectedDAS)dev.Dev).DASComm == null)
{
if (string.IsNullOrEmpty(dev.Dev.ConnectString))
{
return "device.dev.ConnectString==null";
}
return dev.Dev.ConnectString;
}
if (!string.IsNullOrEmpty(((IConnectedDAS)dev.Dev).DASComm.SerialNumber))
return ((IConnectedDAS)dev.Dev).DASComm.SerialNumber;
return string.IsNullOrEmpty(dev.Dev.ConnectString) ? "device.dev.ConnectString==null" : dev.Dev.ConnectString;
}
///
/// handlers current monitor connections for disconnects
/// but a das factory handler may actually need to hand off an object
/// and not be able to check it for connectivity actively and may need to
/// rely on being notified that the object is disconnected or available again
///
///
public virtual void ReportDisconnect(object obj)
{
//by default do nothing, only the TDAS connector uses it currently
}
}
}