592 lines
20 KiB
Plaintext
592 lines
20 KiB
Plaintext
using CANFDApiProxy;
|
|
using CANFDApiProxy.Messages;
|
|
using DTS.Common;
|
|
using DTS.Common.Enums.DASFactory;
|
|
using DTS.Common.Events;
|
|
using DTS.Common.ICommunication;
|
|
using DTS.Common.Interface.DASFactory;
|
|
using DTS.Common.Interface.DASFactory.Config;
|
|
using DTS.Common.SharedResource.Strings;
|
|
using DTS.Common.Strings;
|
|
using DTS.Common.Utilities.Logging;
|
|
using DTS.DASLib.Command;
|
|
using DTS.DASLib.Command.TDAS;
|
|
using DTS.DASLib.Service;
|
|
using DTS.DASLib.Service.Classes.CAN;
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Drawing.Text;
|
|
using System.Linq;
|
|
using System.Net.Sockets;
|
|
using System.Threading;
|
|
using static DTS.DASLib.DASFactory.EthernetTDASHandling;
|
|
|
|
namespace DTS.DASLib.DASFactory
|
|
{
|
|
internal abstract class SPFDSetup : IDeviceSetup
|
|
{
|
|
protected SPFDSetup()
|
|
{
|
|
}
|
|
private static string GetSerialNumber(ConnectedDevice das)
|
|
{
|
|
using (var source = new CancellationTokenSource())
|
|
{
|
|
source.CancelAfter(100);
|
|
var t = CANFD.API.GetSerial(das.Dev.ConnectString, source.Token);
|
|
t.Wait();
|
|
if (t.IsCompleted) { return t.Result.Serial; }
|
|
return null;
|
|
}
|
|
}
|
|
private static decimal? GetBattery(string ip)
|
|
{
|
|
try
|
|
{
|
|
using (var source = new CancellationTokenSource())
|
|
{
|
|
var task = CANFD.API.GetBattery(ip, source.Token);
|
|
task.Wait();
|
|
if (task.IsCompleted)
|
|
{
|
|
return task.Result.LoadV;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
//right now we expect exceptions here by nature of sending a connect to ip addresses
|
|
//just discard them for now
|
|
}
|
|
return null;
|
|
}
|
|
private static string GetFirmwareVersion(ConnectedDevice dev)
|
|
{
|
|
try
|
|
{
|
|
using (var cancelSource = new CancellationTokenSource())
|
|
{
|
|
var t = CANFD.API.GetDeviceInfo(dev.Dev.ConnectString, cancelSource.Token);
|
|
t.Wait();
|
|
if (t.IsCompleted)
|
|
{
|
|
var res = t.Result;
|
|
return res.Version_number;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log(ex);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static int GetNumberOfChannels(ConnectedDevice dev)
|
|
{
|
|
try
|
|
{
|
|
using (var cancelSource = new CancellationTokenSource())
|
|
{
|
|
var t = CANFD.API.GetCANInfo(dev.Dev.ConnectString, cancelSource.Token);
|
|
t.Wait();
|
|
if (t.IsCompleted)
|
|
{
|
|
var res = t.Result;
|
|
return res.CANInfoList.Count;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log(ex);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public bool QueryInformation(ConnectedDevice dev)
|
|
{
|
|
try
|
|
{
|
|
APILogger.Log("DasFactory.SPFD::SetupDASInfo enter");
|
|
// shortcut
|
|
dev.Dev.Comm.SerialNumber = GetSerialNumber(dev);
|
|
dev.Dev.Comm.FirmwareVersion = GetFirmwareVersion(dev) ?? string.Empty;
|
|
var numChannels = (uint)GetNumberOfChannels(dev);
|
|
// get the stack contents
|
|
var idas = (IDASCommunication)dev.Dev.Comm;
|
|
|
|
//taking values roughly from here
|
|
//http://build:8080/svn/ProductDevelopment/SLICE%20PRO/Controller%20Area%20Network%20(CAN)%20Recorder/SPDBR/Documents/Reviews/PDR/
|
|
//LED POWER BLUE means chargin 50-90%, GREEn is >90% PURPLE is 20% <50%, <20% is fault or red
|
|
idas.MaximumValidBatteryVoltage = 10;
|
|
idas.MinimumValidBatteryVoltage = 1;
|
|
idas.BatteryHighVoltage = 5;
|
|
idas.BatteryLowVoltage = 3.6F;
|
|
idas.BatteryMediumVoltage = 4F;
|
|
|
|
var serialNumber = new string[1] { dev.Dev.Comm.SerialNumber };
|
|
var firmwareVersion = new string[1] { dev.Dev.Comm.FirmwareVersion };
|
|
dev.Dev.Comm.DASInfo = new Communication_DASInfo(serialNumber, firmwareVersion);
|
|
|
|
var ir = new InfoResult
|
|
{
|
|
NumberOfBridgeChannels = 0,
|
|
MaxNumberOfModules = 1,
|
|
OwningDAS = idas,
|
|
NumberOfBytesPerSampleClock = 1,
|
|
MaxEventStorageSpaceInBytes = 16 * 1024 * 1024
|
|
};
|
|
|
|
ir.Modules = new IInfoResultModule[1];
|
|
ir.Modules[0] = new InfoResult.Module() { ModuleArrayIndex = 0, SerialNumber = serialNumber[0], NumberOfChannels = numChannels };
|
|
|
|
idas.SetDASInfo(ir);
|
|
idas.ConfigData = new ConfigurationData() { Modules = new DASModule[1] };
|
|
idas.ConfigData.Modules[0] = new DASModule() { OwningDAS = idas };
|
|
|
|
var canInfo = GetChannels(dev);
|
|
var channels = new List<DASChannel>();
|
|
var channelNum = 0;
|
|
foreach (var channel in canInfo)
|
|
{
|
|
channels.Add(new CANInputDASChannel()
|
|
{
|
|
UserChannelName = channel.Name,
|
|
ModuleChannelNumber = channelNum,
|
|
HardwareChannelName = channel.Name,
|
|
OwningModule = (DASModule)idas.ConfigData.Modules[0]
|
|
});
|
|
channelNum++;
|
|
}
|
|
idas.ConfigData.Modules[0].Channels = channels.ToArray();
|
|
|
|
GetVoltageInfo(dev);
|
|
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log(ex.ToString());
|
|
return false;
|
|
}
|
|
}
|
|
private static List<CANInfo> GetChannels(ConnectedDevice dev)
|
|
{
|
|
if ((dev == null) || (dev.Dev == null) || (dev.Dev.Comm == null)) { return new List<CANInfo>(); }
|
|
|
|
try
|
|
{
|
|
var t = CANFD.API.GetCANInfo(dev.Dev.ConnectString, CancellationToken.None);
|
|
t.Wait();
|
|
if (t.IsCompleted) { return t.Result.CANInfoList; }
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var msg = string.Format(StringResources.Warning_FailedToRetrieveCanChannels, dev.Dev.ConnectString, dev.Dev.Comm.SerialNumber);
|
|
SurfaceApplicationError(msg);
|
|
APILogger.Log(msg, ex);
|
|
}
|
|
return new List<CANInfo>();
|
|
}
|
|
private static void SurfaceApplicationError(string msg)
|
|
{
|
|
try
|
|
{
|
|
PageErrorEvent.SurfaceApplicationError(msg);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log(ex);
|
|
}
|
|
}
|
|
private static void GetVoltageInfo(ConnectedDevice dev)
|
|
{
|
|
var batteryVoltage = GetBattery(dev.Dev.ConnectString);
|
|
var inputValues = new BaseInputValues();
|
|
var idas = (IDASCommunication)dev.Dev.Comm;
|
|
idas.BaseInput = inputValues;
|
|
if (null == batteryVoltage)
|
|
{
|
|
return;
|
|
}
|
|
var voltage = Convert.ToDouble(batteryVoltage.Value);
|
|
if (voltage < idas.MinimumValidBatteryVoltage) { voltage = 0D; }
|
|
if (voltage > idas.MaximumValidBatteryVoltage) { voltage = 0D; }
|
|
|
|
inputValues.BatteryVoltage = voltage;
|
|
inputValues.BatteryMilliVolts = 1000D * voltage;
|
|
|
|
inputValues.BatteryVoltageStatusColor = RESTSliceProFD.ConvertBatteryVoltage2Color(voltage, idas);
|
|
|
|
//StatusDisplayBattery
|
|
inputValues.StatusDisplayBattery = ((voltage < idas.MinimumValidBatteryVoltage) || (voltage > idas.MaximumValidBatteryVoltage)) ?
|
|
"---" :
|
|
$"{voltage:0.00} V";
|
|
inputValues.BatteryVoltageStatus = inputValues.StatusDisplayBattery;
|
|
}
|
|
|
|
public abstract ICommunication GetICommunication();
|
|
|
|
public abstract ICommunication GetICommunication(ConnectedDevice dev);
|
|
|
|
public abstract IConnectedDevice GetIConnectedDevice(ICommunication comm);
|
|
|
|
public abstract bool IsCorrectType(ConnectedDevice dev);
|
|
|
|
public abstract DFConstantsAndEnums.DASType GetDASType();
|
|
|
|
public abstract Guid GetGuid();
|
|
|
|
public virtual int GetProductId()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
public virtual string GetProductIdString()
|
|
{
|
|
return string.Empty;
|
|
}
|
|
protected DeviceHandling _handler;
|
|
public virtual void SetHandler(DeviceHandling handler)
|
|
{
|
|
_handler = handler;
|
|
}
|
|
}
|
|
internal class SPFDRESTSetup : SPFDSetup
|
|
{
|
|
public override ICommunication GetICommunication()
|
|
{
|
|
var et = new RESTSliceProFD();
|
|
et.OnDisconnected += et_OnDisconnected;
|
|
return et;
|
|
}
|
|
|
|
void et_OnDisconnected(object sender, EventArgs e)
|
|
{
|
|
_handler.ReportDisconnect(sender);
|
|
}
|
|
|
|
public override ICommunication GetICommunication(ConnectedDevice dev)
|
|
{
|
|
return (dev.Dev as ConnectedRESTSPFD).Comm;
|
|
}
|
|
|
|
public override IConnectedDevice GetIConnectedDevice(ICommunication comm)
|
|
{
|
|
return new ConnectedRESTSPFD(comm as RESTSliceProFD);
|
|
}
|
|
|
|
public override bool IsCorrectType(ConnectedDevice dev)
|
|
{
|
|
return dev.Dev is ConnectedRESTSPFD;
|
|
}
|
|
|
|
public override DFConstantsAndEnums.DASType GetDASType()
|
|
{
|
|
return DFConstantsAndEnums.DASType.REST_SPFD;
|
|
}
|
|
|
|
public override Guid GetGuid()
|
|
{
|
|
return Guid.Empty;
|
|
}
|
|
|
|
public SPFDRESTSetup()
|
|
: base()
|
|
{
|
|
}
|
|
}
|
|
internal class RESTSPFDHandling : DeviceHandling
|
|
{
|
|
private static readonly object SPFDHOSTSLOCK = new object();
|
|
private readonly ManualResetEvent SPFDSignalEvent = new ManualResetEvent(false);
|
|
private string[] _SPFDHostNames;
|
|
public string[] SPFDHostNames
|
|
{
|
|
get { lock (SPFDHOSTSLOCK) { return _SPFDHostNames; } }
|
|
set
|
|
{
|
|
if (SPFDListenerThread == null)
|
|
{
|
|
// SLICEDBListenerThread is not running
|
|
if (null == value || value.Length < 1 || string.Empty == value[0])
|
|
{
|
|
// no-op
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// it's already running, we need to stop it
|
|
SPFDSignalEvent.Reset();
|
|
_bKeepGoing = false;
|
|
//setting interrupt here signals anny connection attempts to stop
|
|
Interrupt();
|
|
|
|
// this will signal when the listen thread is done executing
|
|
SPFDSignalEvent.WaitOne(3000, false);
|
|
}
|
|
|
|
lock (SPFDHOSTSLOCK) { _SPFDHostNames = value; }
|
|
// start it up
|
|
SPFDSignalEvent.Reset();
|
|
_interrupt.Reset();
|
|
SPFDListenerThread = new Thread(SPFDEventListenerTask) { IsBackground = true };
|
|
SPFDListenerThread.Start();
|
|
// wait for it to start
|
|
SPFDSignalEvent.WaitOne();
|
|
}
|
|
}
|
|
private void OnSPFDConnected(string s)
|
|
{
|
|
lock (_ConnectedDASLock)
|
|
{
|
|
if (!_connectedSPFD.Contains(s))
|
|
{
|
|
APILogger.Log($"Added to connected devices {s} [SPFD]");
|
|
_connectedSPFD.Add(s);
|
|
}
|
|
}
|
|
UpdateConnectedDevices();
|
|
}
|
|
private void SPFDEventListenerTask()
|
|
{
|
|
lock (_ConnectedDASLock)
|
|
{
|
|
_connectedSPFD.Clear();
|
|
}
|
|
|
|
// signal that we're alive
|
|
_bKeepGoing = true;
|
|
SPFDSignalEvent.Set();
|
|
try
|
|
{
|
|
if (null == _SPFDHostNames || _SPFDHostNames.Length < 1) { return; }
|
|
|
|
|
|
while (_bKeepGoing)
|
|
{
|
|
var hosts = (string [])SPFDHostNames.Clone();
|
|
foreach (var host in hosts)
|
|
{
|
|
if (_connectedSPFD.Contains(host)) { continue; }
|
|
using (var source = new CancellationTokenSource())
|
|
{
|
|
try
|
|
{
|
|
source.CancelAfter(100);
|
|
var task = CANFD.API.GetSerial(host, source.Token);
|
|
task.Wait();
|
|
if ( task.IsCompleted)
|
|
{
|
|
OnSPFDConnected(host);
|
|
}
|
|
}
|
|
catch( Exception ex)
|
|
{
|
|
APILogger.Log($"Failed to connect to {host}", ex);
|
|
}
|
|
}
|
|
}
|
|
Thread.Sleep(RECONNECT_SPIN_MS);
|
|
}
|
|
}
|
|
catch (ThreadInterruptedException)
|
|
{
|
|
//don't log
|
|
}
|
|
|
|
catch (ThreadAbortException)
|
|
{
|
|
// we must exit
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// don't care
|
|
}
|
|
finally
|
|
{
|
|
_bKeepGoing = false;
|
|
//signal that the thread is done and any connection attempts should stop
|
|
_interrupt.Set();
|
|
RemoveAll();
|
|
SPFDListenerThread = null;
|
|
_SPFDHostNames = null;
|
|
// signal that thread is done executing
|
|
SPFDSignalEvent.Set();
|
|
}
|
|
}
|
|
private const int RECONNECT_SPIN_MS = 200;
|
|
private volatile bool _bKeepGoing;
|
|
private readonly ManualResetEvent _interrupt = new ManualResetEvent(false);
|
|
public void Interrupt() { _interrupt.Set(); }
|
|
private void RemoveAll()
|
|
{
|
|
EnqueueDisconnect();
|
|
lock (_ConnectedDASLock)
|
|
{
|
|
_connectedSPFD.Clear();
|
|
}
|
|
}
|
|
public RESTSPFDHandling(DASFactory _factory,
|
|
UpdateFinishedEventHandler _SerialUpdateFinished,
|
|
IDeviceSetup deviceSetup,
|
|
BlockingCollection<Tuple<QueueActions, DeviceHandling>> queueActionPerDevice
|
|
)
|
|
: base(_factory, _SerialUpdateFinished, queueActionPerDevice)
|
|
{
|
|
factory = _factory;
|
|
_spfdSetup = deviceSetup;
|
|
}
|
|
|
|
private static DASFactory factory { get; set; }
|
|
|
|
internal override bool DetachAllDevices()
|
|
{
|
|
var bDevicesRemoved = false;
|
|
SPFDHostNames = new string[0];
|
|
lock (ConnectedDevicesLock)
|
|
{
|
|
foreach (var dev in ConnectedDevices)
|
|
{
|
|
dev.Dispose();
|
|
bDevicesRemoved = true;
|
|
}
|
|
ConnectedDevices.Clear();
|
|
_connectedSPFD.Clear();
|
|
}
|
|
return bDevicesRemoved;
|
|
}
|
|
private Thread SPFDListenerThread;
|
|
public override void Dispose()
|
|
{
|
|
try { if (null != SPFDListenerThread) { SPFDListenerThread.Abort(); } }
|
|
catch (Exception) { }
|
|
base.Dispose();
|
|
}
|
|
internal void OnSPFDConnect(string s)
|
|
{
|
|
lock (_ConnectedDASLock)
|
|
{
|
|
if (!_connectedSPFD.Contains(s))
|
|
{
|
|
APILogger.Log($"Added to connected devices {s} [SPFD]");
|
|
_connectedSPFD.Add(s);
|
|
}
|
|
}
|
|
UpdateConnectedDevices();
|
|
}
|
|
internal void OnSPFDDisconnect(string s)
|
|
{
|
|
var updated = false;
|
|
lock (_ConnectedDASLock)
|
|
{
|
|
if (_connectedSPFD.Contains(s))
|
|
{
|
|
updated = true;
|
|
_connectedSPFD.Remove(s);
|
|
APILogger.Log($"Removed from connected devices {s} [SPFD]");
|
|
}
|
|
}
|
|
if (updated) { UpdateDisconnectedDevices(); }
|
|
}
|
|
|
|
private readonly List<string> _connectedSPFD = new List<string>();
|
|
private readonly object _ConnectedDASLock = new object();
|
|
|
|
private List<string> GetConnectedEthernetDeviceString()
|
|
{
|
|
var list = new List<string>();
|
|
|
|
lock (_ConnectedDASLock)
|
|
{
|
|
if (null == _connectedSPFD || _connectedSPFD.Count < 1) { return list; }
|
|
list.AddRange(_connectedSPFD);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
private List<string> GetActiveConnectedEthernetDeviceStrings()
|
|
{
|
|
var list = new List<string>();
|
|
lock (_ConnectedDASLock)
|
|
{
|
|
if (null == _connectedSPFD || _connectedSPFD.Count < 1) { return list; }
|
|
}
|
|
var devs = ConnectedDevices.ToArray();
|
|
foreach (var dev in devs)
|
|
{
|
|
list.Add(dev.Dev.ConnectString);
|
|
}
|
|
return list;
|
|
}
|
|
private IDeviceSetup _spfdSetup { get; set; }
|
|
|
|
private List<string> GetConnectedDeviceStrings()
|
|
{
|
|
return GetConnectedEthernetDeviceString();
|
|
}
|
|
private List<string> GetAllActiveDeviceStrings()
|
|
{
|
|
return GetActiveConnectedEthernetDeviceStrings();
|
|
}
|
|
private new ICommunication GetICommunication()
|
|
{
|
|
return _spfdSetup.GetICommunication();
|
|
}
|
|
private new IConnectedDevice GetIConnectedDevice(ICommunication com)
|
|
{
|
|
return _spfdSetup.GetIConnectedDevice(com);
|
|
}
|
|
private const int CONNECT_TIMEOUT_MS = 3000;
|
|
private void UpdateConnectedSPFD()
|
|
{
|
|
ConnectNewDevices(GetConnectedDeviceStrings,
|
|
GetAllActiveDeviceStrings,
|
|
GetICommunication,
|
|
GetIConnectedDevice,
|
|
_spfdSetup.GetDASType(),
|
|
_spfdSetup,
|
|
CONNECT_TIMEOUT_MS
|
|
);
|
|
}
|
|
|
|
public override void UpdateConnectedDevices()
|
|
{
|
|
UpdateConnectedSPFD();
|
|
}
|
|
|
|
private bool IsCorrectType(ConnectedDevice dev)
|
|
{
|
|
return _spfdSetup.IsCorrectType(dev);
|
|
}
|
|
private new ICommunication ConnectedDevice2Communication(ConnectedDevice dev)
|
|
{
|
|
return _spfdSetup.GetICommunication(dev);
|
|
}
|
|
|
|
|
|
private void UpdateDisconnectedSPFD()
|
|
{
|
|
DisconnectRemovedDevices(GetConnectedDeviceStrings,
|
|
IsCorrectType,
|
|
ConnectedDevice2Communication,
|
|
_spfdSetup.GetDASType(),
|
|
CONNECT_TIMEOUT_MS);
|
|
}
|
|
|
|
public override void UpdateDisconnectedDevices()
|
|
{
|
|
UpdateDisconnectedSPFD();
|
|
}
|
|
|
|
public override void UpdateDeviceSetups()
|
|
{
|
|
_spfdSetup.SetHandler(this);
|
|
}
|
|
}
|
|
}
|
|
|