Files
DP44/DataPRO/IService/Classes/CAN/SLICEProFD.cs

2630 lines
104 KiB
C#
Raw Normal View History

2026-04-17 14:55:32 -04:00
using CANFDApiProxy;
using CANFDApiProxy.Messages;
using CANFDApiProxy.Requests;
using DTS.Common;
using DTS.Common.Classes.DASFactory;
using DTS.Common.Classes.DSP;
using DTS.Common.Enums;
using DTS.Common.Enums.DASFactory;
using DTS.Common.Enums.Hardware;
using DTS.Common.Enums.Sensors;
using DTS.Common.ICommunication;
using DTS.Common.Interface.Connection;
using DTS.Common.Interface.DASFactory;
using DTS.Common.Interface.DASFactory.ARM;
using DTS.Common.Interface.DASFactory.Config;
using DTS.Common.Interface.DASFactory.Diagnostics;
using DTS.Common.Interface.DASFactory.Download;
using DTS.Common.Interface.StatusAndProgressBar;
using DTS.Common.Utilities.Logging;
using DTS.Common.Utils;
using DTS.DASLib.Command.Classes;
using DTS.DASLib.Connection;
using DTS.DASLib.Service.Classes.Diagnostics;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static DTS.Common.Enums.DASFactory.DFConstantsAndEnums;
namespace DTS.DASLib.Service.Classes.CAN
{
/// <summary>
/// this class is backend code for SPFD
/// http://manuscript.dts.local/f/cases/44874/SPFD-SW-5-of-17-IDASCommunication-DASFactory-backend
/// </summary>
/// <typeparam name="T"></typeparam>
public class SliceProFd<T> : Communication<T>,
IDASCommunication,
IConfigurationActions,
IDiagnosticsActions,
IRealTimeActions,
IArmActions,
IDownloadActions,
IDownloadPathAware,
ICanDiagnosticResults,
ITriggerCheckActions,
IDiagnosticMessagesDevice
where T : IConnection, new()
{
private const string SENDING = "->";
private const string RECEIVING = "<-";
private void LogCommand(string command, bool sending, TimeSpan elapsed, params object[] args)
{
var sb = new StringBuilder();
if (sending) { sb.Append($"{SENDING} "); }
else { sb.Append($"{RECEIVING} "); }
sb.Append($"{command}, {SerialNumber} ({ConnectString})");
if (!sending)
{
sb.Append($"({elapsed.TotalMilliseconds}ms) ");
}
APILogger.Log(sb.ToString(), args);
}
/// <summary>
/// initialize minimum protocols, by default if it's not in this list protocol version is MAX
/// </summary>
public override void InitMinProto()
{
var minimumProtocols = new Dictionary<ProtocolLimitedCommands, byte>();
minimumProtocols[ProtocolLimitedCommands.Arm] = 1;
minimumProtocols[ProtocolLimitedCommands.TestCommunication] = 1;
minimumProtocols[ProtocolLimitedCommands.BaseSystemTime] = 1;
minimumProtocols[ProtocolLimitedCommands.Diagnostics] = 1;
minimumProtocols[ProtocolLimitedCommands.EventFaultFlags] = 1;
minimumProtocols[ProtocolLimitedCommands.FileData] = 1;
MinimumProtocols = minimumProtocols;
}
ExcitationStatus IDASCommunication.ExcitationStatus { get; set; } = ExcitationStatus.Unknown;
DateTime? IDASCommunication.FirstUseDate { get; set; } = null;
bool IDASCommunication.IsFirstUseDateSupported
{
get => false;
set
{
if (!value)
{
throw new SpfdNotImplementedException("IsFirstUseDateSupported", false, value, SerialNumber);
}
}
}
bool IDASCommunication.IsStreamingSupported
{
get => false;
set
{
if (!value)
{
throw new SpfdNotImplementedException("IsStreamingSupported", false, value, SerialNumber);
}
}
}
int IDASCommunication.RecordId { get; set; } = HardwareConstants.INVALID_IDASCOMMUNICATION_RECORD_ID;
float IDASCommunication.InputLowVoltage { get; set; }
float IDASCommunication.InputMediumVoltage { get; set; }
float IDASCommunication.InputHighVoltage { get; set; }
float IDASCommunication.BatteryLowVoltage { get; set; }
float IDASCommunication.BatteryMediumVoltage { get; set; }
float IDASCommunication.BatteryHighVoltage { get; set; }
double IDASCommunication.MinimumValidInputVoltage { get; set; }
double IDASCommunication.MaximumValidInputVoltage { get; set; }
double IDASCommunication.MinimumValidBatteryVoltage { get; set; }
double IDASCommunication.MaximumValidBatteryVoltage { get; set; }
bool IDASCommunication.DiagnosticsHasBeenRun { get; set; } = false;
bool IDASCommunication.ConfigureHasBeenRun { get; set; } = false;
int IDASCommunication.MaxModules
{
get => 1;
set => throw new SpfdNotImplementedException("MaxModules", false, value, SerialNumber);
}
bool IDASCommunication.InvertTrigger
{
set { if (value) { throw new SpfdNotImplementedException("InvertTrigger", false, value, SerialNumber); } }
}
private sealed class SpfdNotImplementedException : NotImplementedException
{
private const string GET = "GET";
private const string SET = "SET";
public SpfdNotImplementedException(string property, bool get, object value, string serialnumber)
: base($"{property} not implemented on SPFD ({serialnumber} - {(get ? GET : SET)} {value ?? string.Empty}")
{
APILogger.Log(Message);
}
}
bool IDASCommunication.InvertStart
{
get => false;
set { if (value) { throw new SpfdNotImplementedException("InvertStart", false, value, SerialNumber); } }
}
bool IDASCommunication.IgnoreShortedStart
{
get => false;
set { if (value) { throw new SpfdNotImplementedException("IgnoreShortedStart", false, value, SerialNumber); } }
}
bool IDASCommunication.IgnoreShortedTrigger
{
get => false;
set { if (value) { throw new SpfdNotImplementedException("IgnoreShortedTrigger", false, value, SerialNumber); } }
}
string IDASCommunication.MACAddress { get; set; } = string.Empty;
string[] IDASCommunication.DownstreamMACAddresses
{
get => new string[0];
set => throw new SpfdNotImplementedException("DownstreamMACAccresses", false, value, SerialNumber);
}
bool IDASCommunication.SupportsIndividualChannelRealtimeStreaming => false;
string IConfiguration.TestDirectory { get; set; } = string.Empty;
bool IConfiguration.SupportsAutoDetect => true;
IConfigurationData IConfiguration.ConfigData { get; set; } = null;
ClockSyncProfile IConfiguration.DASClockSyncProfile
{
get => throw new SpfdNotImplementedException("DASClockSyncProfile", true, null, SerialNumber);
set => throw new SpfdNotImplementedException("DASClockSyncProfile", false, null, SerialNumber);
}
IDiagnosticActions[] IDiagnos.ChannelDiagnostics { get; set; } = new IDiagnosticActions[0];
IDiagnosticResult[] IDiagnos.ChannelDiagnosticsResults { get; set; } = new IDiagnosticResult[0];
IModuleDiagnosticsResult[] IDiagnos.ModuleDiagnosticsResults { get; set; } = new IModuleDiagnosticsResult[0];
IBaseInputValues IDiagnos.BaseInput { get; set; } = null;
IDictionary<InputClockSource, bool> IDiagnos.DASClockSyncStatus { get; set; } = null;
bool IDiagnos.ClockSyncInUTC { get; set; } = true;
byte IDiagnos.PTPDomainID
{
get => throw new SpfdNotImplementedException("PTPDomainID", true, null, SerialNumber);
set => throw new SpfdNotImplementedException("PTPDomainID", false, value, SerialNumber);
}
IArmCheckActions IDiagnos.ArmCheckActions { get; set; } = null;
IArmCheckResults IDiagnos.ArmCheckResults { get; set; } = null;
IOptimizationValues IDiagnos.OptimizationValues { get; set; } = null;
ITriggerCheckResult ITriggerCheck.TriggerResult
{
get => throw new SpfdNotImplementedException("TriggerResult", true, null, SerialNumber);
set => throw new SpfdNotImplementedException("TriggerResult", false, value, SerialNumber);
}
List<int> IRealTime.RealtimeDASChannels
{
get => throw new SpfdNotImplementedException("RealtimeDASChannels", true, null, SerialNumber);
set => throw new SpfdNotImplementedException("RealtimeDASChannels", false, value, SerialNumber);
}
List<double> IRealTime.TiltAxisData
{
get => throw new SpfdNotImplementedException("TiltAxisData", true, null, SerialNumber);
set => throw new SpfdNotImplementedException("TiltAxisData", false, value, SerialNumber);
}
string IRealTime.UDPStreamAddress => string.Empty;
IArmStatusData IArmStatus.DASArmStatus { get; set; } = null;
IDownloadRequest IDownload.WhatToDownload { get; set; } = null;
IDownloadReport IDownload.EventInfo { get; set; } = null;
bool[] IDownload.EventDownloadedStatus { get; set; } = null;
Guid[] IDownload.EventGuids { get; set; } = null;
ushort[] IDownload.FaultFlags { get; set; } = null;
uint[] IDownload.ExtendedFaultFlags1 { get; set; } = null;
uint[] IDownload.ExtendedFaultFlags2 { get; set; } = null;
uint[] IDownload.ExtendedFaultFlags3 { get; set; } = null;
uint[] IDownload.ExtendedFaultFlags4 { get; set; } = null;
byte[] IDownload.ArmAttempts
{
get => throw new SpfdNotImplementedException("ArmAttempts", true, null, SerialNumber);
set => throw new SpfdNotImplementedException("ArmAttempts", false, value, SerialNumber);
}
IInfoResult IInformation.DASInfo { get; set; } = null;
CommandStatus IAutoArmStatus.AutoArmStatus
{
get; set;
} = CommandStatus.StatusNoError;
bool IAutoArmed.AutoArmed
{
get; set;
} = false;
bool IRangeBandwidthLimited.RangeBandwidthLimited
{
get => false;
}
bool ITimeSynchronization.SupportsTimeSynchronization => true;
private DateTime _systemBaseTime;
DateTime ITimeSynchronization.SystemBaseTime => _systemBaseTime;
bool IArmActions.SupportsBackgroundFlashErase => false;
bool IArmActions.BackgroundFlashEraseStarted => false;
DateTime? IArmActions.BackgroundFlashEraseStartTime => null;
string IArmActions.AutoArmUDPSetting
{
get => throw new SpfdNotImplementedException("AutoArmUDPSetting", true, null, SerialNumber);
set => throw new SpfdNotImplementedException("AutoArmUDPSetting", false, value, SerialNumber);
}
private class ServiceAsyncInfo
{
public ServiceCallback Callback { get; set; }
public object UserData { get; set; }
public object FunctionData { get; set; }
public ServiceAsyncInfo(ServiceCallback _callback, object _userData)
{
Callback = _callback;
UserData = _userData;
}
public void Error(string msg, Exception ex)
{
try
{
var cbData = new ServiceCallbackData();
cbData.Status = ServiceCallbackData.CallbackStatus.Failure;
cbData.ErrorMessage = msg;
cbData.ErrorException = ex;
cbData.UserData = UserData;
Callback(cbData);
}
catch (Exception eex)
{
APILogger.Log("SliceProFd.Error", eex);
}
}
public void Error(string msg)
{
Error(msg, null);
}
public void Progress(int value)
{
try
{
var progressData = new ServiceCallbackData();
progressData.Status = ServiceCallbackData.CallbackStatus.ProgressReport;
progressData.ProgressValue = value;
progressData.UserData = UserData;
Callback(progressData);
}
catch (Exception ex)
{
APILogger.Log("SliceProFd.Progress", ex);
}
}
public void Success()
{
try
{
var success = new ServiceCallbackData();
success.Status = ServiceCallbackData.CallbackStatus.Success;
success.UserData = UserData;
Callback(success);
}
catch (Exception ex)
{
APILogger.Log("SliceProFd.Success", ex);
}
}
public void Cancel()
{
try
{
var cancelReport = new ServiceCallbackData();
cancelReport.Status = ServiceCallbackData.CallbackStatus.Canceled;
cancelReport.ProgressValue = 0;
cancelReport.UserData = UserData;
Callback(cancelReport);
}
catch (Exception ex)
{
APILogger.Log("SliceProFd.Cancel", ex);
}
}
}
private void LaunchAsyncWorker(string Invoker, WaitCallback cb, object asyncInfo)
{
if (!ThreadPool.QueueUserWorkItem(cb, asyncInfo))
{
// "{0}: Unable to enqueue function"
throw new Exception("Spfd.LaunchAsync failed to queue work");
}
}
void IConfigurationActions.ApplyLevelTriggers(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.ApplyLevelTriggers", new WaitCallback(AsyncApplyLevelTriggers), info);
}
private void AsyncApplyLevelTriggers(object o)
{
GenericSuccess(o);
}
void IArmActions.ArmNow(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool testingMode, int maxNumberEvents, bool SysMode)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.ArmNow", new WaitCallback(AsyncArmNow), info);
}
private void AsyncArmNow(object o)
{
if ( !(o is ServiceAsyncInfo info)) { return; }
var msg = $"Failed to arm [{SerialNumber}] ({ConnectString})";
try
{
LogCommand("AsyncArmNow-SetRecordingStop", true, TimeSpan.MinValue, null);
var stopwatch = ValueStopwatch.StartNew();
var t = CANFD.API.SetRecordingStop(ConnectString, CancellationToken.None);
t.Wait();
var elapsed = stopwatch.GetElapsedTime();
if (t.IsCompleted)
{
LogCommand("AsyncArmNow-SetRecordingStop", false, elapsed, t.Result);
info.Success();
}
else if ( null != t.Exception) { throw t.Exception; }
else { info.Error(msg); }
}
catch(Exception ex)
{
APILogger.Log(msg, ex);
info.Error(msg);
}
}
void IArmActions.AutoArmNow(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool testingMode, uint diagnosticsDelayMs, int MaxEventCount, bool repeatEnable, bool preserveDiagnostics)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.AutoArmNow", new WaitCallback(AsyncAutoArmNow), info);
}
private void AsyncAutoArmNow(object o)
{
//FB 44877
SetRTCBaseTime();
NotSupportedError(o, "SliceProFd.AutoArmNow");
}
void IConfigurationActions.AutoDetect(bool bQueryConfiguration, ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.AutoDetect", new WaitCallback(AsyncAutoDetect), info);
}
private void AsyncAutoDetect(object o)
{
GenericSuccess(o);
}
private const int CHECK_CONNECT_TIMEOUT_MS = 50;
private DiagnosticMessageRow[] _currentDiagnosticMessages = new DiagnosticMessageRow[0];
private DiagnosticMessageRow[] GetDiagnosticMessages()
{
try
{
var stopwatch = ValueStopwatch.StartNew();
LogCommand("GetDiagnosticMessages", true, TimeSpan.MinValue, string.Empty);
using (var source = new CancellationTokenSource())
{
source.CancelAfter(30000);
var task = CANFD.API.GetBIST(ConnectString, source.Token);
task.Wait();
if (task.IsCompleted)
{
var elapsed = stopwatch.GetElapsedTime();
LogCommand("GetDiagnosticMessages", false, elapsed, task.Result);
return task.Result;
}
}
}
catch (Exception ex)
{
APILogger.Log($"Failed to get diagnostic messages [{SerialNumber}]({ConnectString})", ex);
}
return new DiagnosticMessageRow[0];
}
private DateTime? GetCalDate()
{
try
{
var stopwatch = ValueStopwatch.StartNew();
LogCommand("GetCalDate", true, TimeSpan.MinValue, string.Empty);
using (var source = new CancellationTokenSource())
{
source.CancelAfter(1000);
var task = CANFD.API.GetCalibrationDate(ConnectString, source.Token);
task.Wait();
if (task.IsCompleted)
{
var elapsed = stopwatch.GetElapsedTime();
LogCommand("GetCalDate", false, elapsed, task.Result);
var calDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddDays(task.Result.Calibration_date);
if (calDate.Year < 2025) { return null; }
return calDate;
}
}
}
catch( Exception ex)
{
APILogger.Log($"Failed to get calibration date [{SerialNumber}]", ex);
}
return null;
}
private static string GetSerial(string ip)
{
try
{
using (var source = new CancellationTokenSource())
{
source.CancelAfter(CHECK_CONNECT_TIMEOUT_MS);
var task = CANFD.API.GetSerial(ip, source.Token);
task.Wait();
if (task.IsCompleted)
{
return task.Result.Serial;
}
}
}
catch (Exception)
{
//right now we expect exceptions here by nature of sending a connect to ip addresses
//just discard them for now
}
return null;
}
void IArmActions.BeginBackgroundFlashErase(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.BeginBackgroundFlashErase", new WaitCallback(AsyncBeginBackgroundFlashErase), info);
}
private void AsyncBeginBackgroundFlashErase(object o)
{
FlashClearProgress = 0;
Task.Run(() => ClearFlash());
GenericSuccess(o);
}
private volatile int FlashClearProgress = 0;
private Child FindChild(UsbTreeMessage root, string folderName)
{
foreach( var child in root.children)
{
var match = FindChild(child, folderName);
if (match != null) { return match; }
}
return null;
}
private Child FindChild(Child root, string folderName)
{
var path = root.path.Split('/');
if (path[path.Length - 1].ToLower().Equals(folderName.ToLower()))
{
return root;
}
foreach( var child in root.children)
{
var match = FindChild(child, folderName);
if ( match != null) { return match; }
}
return null;
}
private void ClearFlash()
{
var stopwatch = ValueStopwatch.StartNew();
try
{
LogCommand("ClearFlash", true, TimeSpan.MinValue, string.Empty);
FlashClearProgress = 0;
var t = CANFD.API.GetUsbTree(ConnectString, CancellationToken.None);
t.Wait();
if (t.IsCompleted)
{
//first find the "Recordings" parent, we want to delete all the children of that one
var root = FindChild(t.Result, "Recordings");
if (null == root) { FlashClearProgress = 100; return; }
var list = new List<string>();
foreach( var child in root.children)
{
list.Add(child.path);
}
var done = 0;
foreach( var path in list)
{
var tDelete = CANFD.API.Delete(ConnectString, path, CancellationToken.None);
tDelete.Wait();
FlashClearProgress = Convert.ToInt32(100 * Convert.ToDouble(++done / list.Count));
}
FlashClearProgress = 100;
LogCommand("ClearFlash", false, stopwatch.GetElapsedTime(), string.Empty);
}
}
catch( Exception ex)
{
var msg = $"Failed to get USB tree [{SerialNumber}] ({ConnectString})";
APILogger.Log(msg, ex);
FlashClearProgress = 100;
}
}
void IArmActions.BeginFlashErase(ServiceCallback callback, object userData, bool DummyArm)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.BeginFlashErase", new WaitCallback(AsyncBeginFlashErase), info);
}
private void AsyncBeginFlashErase(object o)
{
Task.Run(() => ClearFlash());
GenericSuccess(o);
}
private static void NotSupportedError(object o, string title)
{
if ( !(o is ServiceAsyncInfo info)) { return; }
info.Error($"{title} not supported");
}
bool IDASCommunication.CheckAAF(float rate)
{
return true;
}
void IConfigurationActions.CheckAAFilterRate(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.CheckAAFilterRate", new WaitCallback(AsyncCheckFilterRate), info);
}
private void AsyncCheckFilterRate(object o)
{
GenericSuccess(o);
}
void IArmActions.CheckAlreadyLevelTriggered(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.CheckAlreadyLevelTriggered", new WaitCallback(AsyncCheckAlreadyLevelTriggered), info);
}
private void AsyncCheckAlreadyLevelTriggered(object o)
{
GenericSuccess(o);
}
void IConfigurationActions.CheckSafetyState(bool bArmed, ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.CheckSafetyState", new WaitCallback(AsyncCheckSafetyState), info);
}
private void AsyncCheckSafetyState(object o)
{
GenericSuccess(o);
}
void IDiagnos.ClearChannelDiagnosticsResults(bool bClearDb)
{
DiagnosticsResultActions.ClearChannelDiagnosticsResults(this, bClearDb);
}
void IDiagnosticsActions.ClearDASTriggerLine(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.ClearDASTriggerLine", new WaitCallback(AsyncClearDASTriggerLine), info);
}
private void AsyncClearDASTriggerLine(object o)
{
GenericSuccess(o);
}
void IDiagnosticsActions.ClearLatches(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.ClearLatches", new WaitCallback(AsyncClearLatches), info);
}
private void AsyncClearLatches(object o)
{
GenericSuccess(o);
}
void IDiagnosticsActions.ClearTriggerOut(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.ClearTriggerOut", new WaitCallback(AsyncClearTriggerOut), info);
}
private void AsyncClearTriggerOut(object o)
{
GenericSuccess(o);
}
private static void GenericSuccess(object o)
{
if (!(o is ServiceAsyncInfo info)) { return; }
info.Success();
}
int IComparable<IDASCommunication>.CompareTo(IDASCommunication other)
{
if (other is null) { return 1; }
if (null == other.SerialNumber && null == SerialNumber) { return 0; }
if (null == SerialNumber) { return -1; }
if (null == other.SerialNumber) { return 1; }
return SerialNumber.CompareTo(other.SerialNumber);
}
void IConfigurationActions.Configure(ServiceCallback callback, object userData, bool bEventConfig, bool DummyConfig, double[] MaxAAF, bool configureDigitalOutputs, uint crc, bool turnOffAAFRealtime, IStreamingFilterProfile dspFilterType, bool discardDiagnostics, Dictionary<IDASCommunication, ushort> timeChannelIds, Dictionary<IDASCommunication, ushort> dataChannelIds, Dictionary<IDASCommunication, UDPStreamProfile> streamProfiles, Dictionary<IDASCommunication, int> streamADCPerPacket, Dictionary<IDASCommunication, ushort> irigTDPIntervals, Dictionary<IDASCommunication, string> addresses, Dictionary<IDASCommunication, uint[]> tmnsConfigs, Dictionary<IDASCommunication, uint> baudRates, Dictionary<IDASCommunication, uint> dataBits, Dictionary<IDASCommunication, StopBits> stopBits, Dictionary<IDASCommunication, Parity> parities, Dictionary<IDASCommunication, Handshake> flowControls, Dictionary<IDASCommunication, UartDataFormat> dataFormats, Dictionary<IDASCommunication, ushort> tmatsIntervals)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.Configure", new WaitCallback(AsyncConfigure), info);
}
private void DisarmIfNeeded()
{
var status = new ArmStatus(((IArmStatus)this).DASArmStatus);
if (null == status) { return; }
try
{
Disarm();
}
catch( Exception ex)
{
APILogger.Log(ex);
}
}
private void AsyncConfigure(object o)
{
if (!(o is ServiceAsyncInfo info)) { return; }
var stopwatch = ValueStopwatch.StartNew();
DisarmIfNeeded();
if ( null == ((IDASCommunication)this).ConfigData)
{
info.Error($"No configuration for unit [{SerialNumber}] ({ConnectString})");
return;
}
var configData = ((IDASCommunication)this).ConfigData;
var tEntireConfig = new CANConfig(configData.Modules[0].SerialNumber() + ".xml", true);
var canConfigRequest = new CANConfigRequest();
canConfigRequest.config = new config();
for (int i = 0; i < configData.Modules.Length; i++)
{
var tConfig = new CANModuleConfig(configData.Modules[i].SerialNumber() + ".xml");
DASModule module = (DASModule)configData.Modules[i];
tConfig.RecordingMode = module.RecordingMode;
tConfig.AAFilterRateHz = module.AAFilterRateHz;
tConfig.PreTriggerSeconds = module.PreTriggerSeconds;
tConfig.PostTriggerSeconds = module.PostTriggerSeconds;
tConfig.SerialNumber = module.SerialNumber();
tConfig.FirmwareVersion = module.FirmwareVersion;
tConfig.MaxEventStorageSpaceInBytes = module.MaxEventStorageSpaceInBytes;
tConfig.ModuleArrayIndex = module.ModuleArrayIndex;
for (int z = 0; z < configData.Modules[i].Channels.Length; z++)
{
CANInputDASChannel channel = configData.Modules[i].Channels[z] as CANInputDASChannel;
if (null != channel)
{
tConfig.SetChannel(channel);
BuildCanConfigRequest(canConfigRequest, channel, z);
}
}
tEntireConfig.SetModule(tConfig);
}
using (StreamWriter sw = new StreamWriter(tEntireConfig.FileName))
{
tEntireConfig.WriteXml(System.Xml.XmlWriter.Create(sw));
sw.Flush();
sw.Close();
}
try
{
LogCommand("SetCanConfig", true, TimeSpan.MinValue, canConfigRequest);
var t = CANFD.API.SetCANConfig(ConnectString, canConfigRequest, CancellationToken.None);
t.Wait();
if (t.IsCompleted)
{
LogCommand("SetCanConfig", false, stopwatch.GetElapsedTime(), t.Result);
}
}
catch (Exception ex)
{
APILogger.Log(ex);
}
//ConfigureHasBeenRun = true;
info.Success();
}
/// <summary>
/// If a CAN channel is unused, set it to the default values so errors don't occur.
/// Then, assign channel-specific values to the config.
/// </summary>
/// <param name="canConfigRequest"></param>
/// <param name="channel"></param>
/// <param name="i"></param>
private static void BuildCanConfigRequest(CANConfigRequest canConfigRequest, CANInputDASChannel channel, int i)
{
if (channel.ConfigurationMode != ConfigMode.Normal)
{
channel.ArbBaseBitrate = 500000;
channel.ArbBaseSJW = 1;
channel.DataBitrate = 500000;
channel.DataSJW = 1;
channel.FileType = "asc";
}
switch (i)
{
case 0:
canConfigRequest.config.can1 =
new CanConfigItem(channel.ArbBaseBitrate, channel.ArbBaseSJW, channel.DataBitrate, channel.DataSJW, channel.FileType, channel.ConfigurationMode == ConfigMode.Normal, channel.IsFD);
break;
case 1:
canConfigRequest.config.can2 =
new CanConfigItem(channel.ArbBaseBitrate, channel.ArbBaseSJW, channel.DataBitrate, channel.DataSJW, channel.FileType, channel.ConfigurationMode == ConfigMode.Normal, channel.IsFD);
break;
case 2:
canConfigRequest.config.can3 =
new CanConfigItem(channel.ArbBaseBitrate, channel.ArbBaseSJW, channel.DataBitrate, channel.DataSJW, channel.FileType, channel.ConfigurationMode == ConfigMode.Normal, channel.IsFD);
break;
case 3:
canConfigRequest.config.can4 =
new CanConfigItem(channel.ArbBaseBitrate, channel.ArbBaseSJW, channel.DataBitrate, channel.DataSJW, channel.FileType, channel.ConfigurationMode == ConfigMode.Normal, channel.IsFD);
break;
}
}
bool IDASCommunication.ConnectionCheck()
{
try
{
return !string.IsNullOrWhiteSpace(GetSerial(ConnectString));
}
catch( Exception ex)
{
APILogger.Log($"ConnectionCheck failed [{SerialNumber}] ({ConnectString})", ex);
return false;
}
}
bool IDASCommunication.ControlsDAQ()
{
return true;
}
void IDownloadActions.CorrectT0s(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.CorrectT0s", new WaitCallback(AsyncCorrectT0s), info);
}
private void AsyncCorrectT0s(object o)
{
GenericSuccess(o);
}
void IDiagnosticsActions.DiagnosAndGetResults(int EventNumber, PrePostResults WhichResult, ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.DiagnosAndGetResults", new WaitCallback(AsyncDiagnosAndGetResults), info);
}
private void ProcessCanStates(CANState[] states)
{
foreach( var state in states)
{
ProcessCanState(state);
}
}
private void ProcessCanState(CANState state)
{
var index = GetCanNameToIndex(state.Name);
if ( index >=0 && index < CanDiagnosticResults.Length)
{
CanDiagnosticResults[index].Active = state.State.Equals("ACTIVE");
}
}
private static int GetCanNameToIndex(string name)
{
if (string.IsNullOrEmpty(name)) { return 0; }
switch(name)
{
case "can1":return 0;
case "can2":return 1;
case "can3":return 2;
case "can4":return 3;
default: throw new InvalidCastException($"Invalid can name: {name}");
}
}
private void ProcessCanStats(CANStats[] stats)
{
foreach( var stat in stats)
{
ProcessCanStat(stat);
}
}
private void ProcessCanStat(CANStats stat)
{
var index = GetCanNameToIndex(stat.Name);
if (index >=0 && index < CanDiagnosticResults.Length)
{
CanDiagnosticResults[index].Load = stat.Bus_load;
CanDiagnosticResults[index].Data = stat.Std_data;
CanDiagnosticResults[index].ErrorFrame = stat.Err_frame;
CanDiagnosticResults[index].Overruns = stat.Overruns;
CanDiagnosticResults[index].LastUpdate = DateTimeOffset.FromUnixTimeSeconds((long)stat.Last_updated).LocalDateTime;
}
}
private void InitializeCanDiagnostics()
{
CanDiagnosticResults = new CanDiagnostics[4];
for (var i = 0; i < CanDiagnosticResults.Length; i++)
{
CanDiagnosticResults[i] = new CanDiagnostics()
{
Active = false,
ChannelIndex = i,
ChannelName = GetChannelName(i)
};
}
}
private string GetChannelName(int index)
{
if( null == ((IDASCommunication)this).ConfigData) { return string.Empty; }
var config = ((IDASCommunication)this).ConfigData;
if ( config.Modules == null || 0 == config.Modules.Length) { return string.Empty; }
var match = Array.Find(config.Modules[0].Channels, x => x.Number == index);
if (null == match) { return string.Empty; }
return string.IsNullOrWhiteSpace(match.UserChannelName) ? match.IsoChannelName : match.UserChannelName;
}
private void AsyncDiagnosAndGetResults(object o)
{
if (!(o is ServiceAsyncInfo info)) { return; }
((IDiagnos)this).ChannelDiagnosticsResults = new IDiagnosticResult[0];
((IDiagnos)this).ModuleDiagnosticsResults = new IModuleDiagnosticsResult[0];
try
{
var t = CANFD.API.GetCANState(ConnectString, CancellationToken.None);
t.Wait();
if (t.IsCompleted)
{
InitializeCanDiagnostics();
ProcessCanStates(t.Result.CANStateList.ToArray());
}
else
{
info.Error($"Failed to complete diagnostics [{SerialNumber}] ({ConnectString})");
return;
}
var t2 = CANFD.API.GetCANStats(ConnectString, CancellationToken.None);
t2.Wait();
if (t2.IsCompleted)
{
ProcessCanStats(t2.Result.CANStatsList.ToArray());
}
else
{
info.Error($"Failed to complete diagnostics [{SerialNumber}] ({ConnectString})");
return;
}
}
catch(Exception ex)
{
info.Error($"failed to complete diagnostics [{SerialNumber}] ({ConnectString})", ex);
}
info.Success();
}
void IArmActions.Disarm(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.Disarm", new WaitCallback(AsyncDisarm), info);
}
private void Disarm()
{
var stopWatch = ValueStopwatch.StartNew();
var msg = $"Failed to disarm [{SerialNumber}] ({ConnectString})";
LogCommand("SetRecordingStop", true, TimeSpan.MinValue, string.Empty);
var t = CANFD.API.SetRecordingStop(ConnectString, CancellationToken.None);
t.Wait();
if (t.IsCompleted)
{
LogCommand("SetRecordingStop", false, stopWatch.GetElapsedTime(), t.Result);
}
else if (null != t.Exception) { throw t.Exception; }
else { throw new InvalidOperationException(msg); }
}
private void AsyncDisarm(object o)
{
if ( !(o is ServiceAsyncInfo info)){ return; }
var msg = $"Failed to disarm [{SerialNumber}] ({ConnectString})";
try
{
Disarm();
info.Success();
}
catch( Exception ex)
{
APILogger.Log(msg, ex);
info.Error(msg);
}
}
void IArmActions.DisAutoArm(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.DisAutoArm", new WaitCallback(AsyncDisAutoArm), info);
}
private void AsyncDisAutoArm(object o)
{
NotSupportedError(o, "NotSupportedAutoArm");
}
void IDownloadActions.Download(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.Download", new WaitCallback(AsyncDownload), info);
}
string IDownloadPathAware.EventPath { get; set; } = string.Empty;
public ICanDiagnosticResult[] CanDiagnosticResults { get; private set; } = new ICanDiagnosticResult[0];
public void ClearCanDiagnosticResults()
{
CanDiagnosticResults = new ICanDiagnosticResult[0];
}
public void SetDiagnosticResults(ICanDiagnosticResult[] results)
{
CanDiagnosticResults = results;
}
private void AsyncDownload(object o)
{
if ( !(o is ServiceAsyncInfo info)) { return; }
var msg = $"Failed to download [{SerialNumber}] ({ConnectString})";
try
{
var t = CANFD.API.GetUsbTree(ConnectString, CancellationToken.None);
t.Wait();
if (!t.IsCompleted)
{
if (null != t.Exception) { throw t.Exception; }
else { info.Error(msg); return; }
}
var root = FindChild(t.Result, "Recordings");
if (null == root) { info.Error($"[{SerialNumber}] ({ConnectString}) NO DATA"); return; }
var list = new List<Tuple<string, string>>();
foreach (var eventId in root.children)
{
foreach (var child in eventId.children)
{
list.Add(new Tuple<string, string>(eventId.name, child.path));
}
}
DownloadEvents(info, list);
info.Success();
}
catch (Exception ex)
{
info.Error(msg);
APILogger.Log(msg, ex);
}
}
//FB 45086 sonarqube - reduce cyclomatic complexity
private void DownloadEvents(ServiceAsyncInfo info, List<Tuple<string, string>> list)
{
var timeout = TimeSpan.FromMinutes(5);
var countSoFar = 0;
foreach (var tuple in list)
{
countSoFar++;
//strip out any preceding /
var path1 = tuple.Item1.TrimStart(new char[] { '/' });
var path2 = tuple.Item2.TrimStart(new char[] { '/' });
var outputPath = Path.Combine(((IDownloadPathAware)this).EventPath, "CAN", path1, path2);
try
{
Directory.CreateDirectory(outputPath);
}
catch (Exception ex) { APILogger.Log(ex); }
var tDownload = CANFD.API.Download(ConnectString, tuple.Item2, outputPath, timeout, CancellationToken.None);
tDownload.Wait();
if (!tDownload.IsCompleted)
{
info.Error($"[{SerialNumber}] ({ConnectString}) failed to download {tuple.Item1} to {outputPath}");
}
else { info.Progress(Convert.ToInt32(100D * countSoFar / list.Count)); }
}
}
void IArmActions.EnableFaultChecking(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.EnableFaultChecking", new WaitCallback(AsyncEnableFaultChecking), info);
}
private void AsyncEnableFaultChecking(object o)
{
APILogger.Log($"EnableFaultChecking is not supported on SPFD - {SerialNumber} ({ConnectString})");
GenericSuccess(o);
}
void IArmActions.EnterLowPowerMode(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.EnterLowPowerMode", new WaitCallback(AsyncEnterLowPowerMode), info);
}
private void AsyncEnterLowPowerMode(object o)
{
NotSupportedError(o, "SliceProFd.EnterLowPowerMode");
}
void IRealTimeActions.ExitRealTimeMode(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.ExitRealTimeMode", new WaitCallback(AsyncExitRealtimeMode), info);
}
private void AsyncExitRealtimeMode(object o)
{
NotSupportedError(o, "SliceProFd.ExitRealtimeMode");
}
void IArmActions.GetArmStatus(ServiceCallback callback, object userData, uint inputVoltageCutoff, int maxTimeout)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.GetArmStatus", new WaitCallback(AsyncGetArmStatus), info);
}
private bool GetIsArmed(ServiceAsyncInfo info)
{
try
{
var stopwatch = ValueStopwatch.StartNew();
LogCommand("GetEventPin", true, TimeSpan.MinValue, string.Empty);
using (var cancelSource = new CancellationTokenSource())
{
cancelSource.CancelAfter(500);
var t = CANFD.API.GetEventPin(ConnectString, cancelSource.Token);
t.Wait();
if (t.IsCompleted)
{
LogCommand("GetEventPin", false, stopwatch.GetElapsedTime(), t.Result);
var armed = t.Result.Armed.HasValue && t.Result.Armed.Value;
return armed;
}
else { info.Error($"Failed to get arm status [{SerialNumber}] ({ConnectString})"); }
}
}
catch( Exception ex)
{
APILogger.Log(ex);
}
return false;
}
private const int MAX_TIME_USBSTATS = 1000;
private double GetTimeRemaining()
{
try
{
var stopWatch = ValueStopwatch.StartNew();
LogCommand("GetUsbStats", true, TimeSpan.MinValue, string.Empty);
using (var cancelSource = new CancellationTokenSource())
{
cancelSource.CancelAfter(MAX_TIME_USBSTATS);
var t = CANFD.API.GetUsbStats(ConnectString, cancelSource.Token);
t.Wait();
if (t.IsCompleted)
{
LogCommand("GetUsbStats", false, stopWatch.GetElapsedTime(), t.Result);
return t.Result.Traffic.mins_remaining * 60D;
}
}
}
catch( Exception ex)
{
APILogger.Log(ex);
}
return 0;
}
private void AsyncGetArmStatus(object o)
{
if ( !(o is ServiceAsyncInfo info)) { return; }
try
{
var status = new ArmStatus(((IArmStatus)this).DASArmStatus);
var isArmed = GetIsArmed(info);
if (isArmed)
{
var remaining = GetTimeRemaining();
status.IsArmed = true;
status.TimeLeftInArm = remaining;
status.TimeRemainingSeconds = remaining;
status.IsRecording = true;
}
else { status.IsArmed = false; }
ArmStatus.SetArmStatus(this, status, false);
info.Success();
}
catch( Exception ex)
{
var msg = $"Failed to get arm status [{SerialNumber}] ({ConnectString})";
APILogger.Log(msg, ex);
info.Error(msg, ex);
}
}
void IArmActions.GetAutoArmStatus(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.GetAutoArmStatus", new WaitCallback(AsyncGetAutoArmStatus), info);
}
private void AsyncGetAutoArmStatus(object o)
{
if (!(o is ServiceAsyncInfo info)) { return; }
try
{
using (var cancelSource = new CancellationTokenSource())
{
cancelSource.CancelAfter(500);
var t = CANFD.API.GetRecording(ConnectString, cancelSource.Token);
t.Wait();
if (t.IsCompleted)
{
((IAutoArmed)this).AutoArmed = t.Result.Autoarm;
((IAutoArmStatus)this).AutoArmStatus = CommandStatus.StatusNoError;
info.Success();
}
else { info.Error($"Failed to get arm status [{SerialNumber}] ({ConnectString})"); }
}
}
catch (Exception ex)
{
var msg = $"Failed to get auto arm status [{SerialNumber}] ({ConnectString})";
APILogger.Log(msg, ex);
info.Error(msg, ex);
}
}
void IDiagnosticsActions.GetBridgeMeasurement(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.GetBridgeMeasurement", new WaitCallback(AsyncGetBridgeMeasurement), info);
}
private void AsyncGetBridgeMeasurement(object o)
{
NotSupportedError(o, "SliceProFd.GetBridgeMeasurement");
}
bool IDASCommunication.GetCanCheckArmStatus()
{
return true;
}
private static readonly int[] _channelDisplayOrder = new int[] { -1 };
int[] IConfiguration.GetChannelDisplayOrder()
{
return _channelDisplayOrder;
}
private const int DAS_DISPLAY_ORDER = -1;
int IConfiguration.GetDASDisplayOrder()
{
return DAS_DISPLAY_ORDER;
}
void IDiagnosticsActions.GetEventDiagnosticsResults(int EventNumber, PrePostResults WhichResult, ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
//FB 45086 removed duplicate method
LaunchAsyncWorker("SliceProFd.GetEventDiagnosticsResults", new WaitCallback(AsyncDiagnosAndGetResults), info);
}
void IArmActions.GetExtendedFaultIds(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.GetExtendedFaultIds", new WaitCallback(AsyncGetExtendedFaultIds), info);
}
private void AsyncGetExtendedFaultIds(object o)
{
GenericSuccess(o);
}
HardwareTypes IDASCommunication.GetHardwareType()
{
return HardwareTypes.SLICE_PRO_CAN_FD;
}
bool IArmStatus.GetIsInArm()
{
if (null == ((IArmStatus)this).DASArmStatus) { return false; }
return ((IArmStatus)this).DASArmStatus.IsArmed;
}
bool IArmStatus.GetIsInRealtime()
{
return false;
}
bool IArmStatus.GetIsStreaming()
{
return false;
}
private static readonly double[] _Ranges = new double[] { 1D };
double[] IDASCommunication.GetNominalRanges(SensorConstants.BridgeType bridge)
{
return _Ranges;
}
ulong IDASCommunication.GetPhaseShiftSamples(uint ModuleIndex, double ActualSampleRate, uint HardwareAAF, ulong originalT0)
{
return 0;
}
int[] IDASCommunication.GetStackChannelConfigTypes() => new int[] { 0 };
void IRealTimeActions.GetUDPStreamProfile(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.GetUDPStreamProfile", new WaitCallback(AsyncGetUDPStreamProfile), info);
}
private void AsyncGetUDPStreamProfile(object o)
{
GenericSuccess(o);
}
bool IDASCommunication.IsBattery()
{
return false;
}
bool IDASCommunication.IsEthernetDistributor()
{
return false;
}
bool IDASCommunication.IsScheduleEventCountSupported()
{
return false;
}
bool IDASCommunication.IsSlice6Air()
{
return false;
}
bool IDASCommunication.IsSlice6AirTc()
{
return false;
}
bool IDASCommunication.IsSlice6Distributor()
{
return false;
}
bool IDASCommunication.IsTSRAIR()
{
return false;
}
uint IDASCommunication.MaxAAFilterRate()
{
return 1;
}
long IDASCommunication.MaxMemory()
{
return 16 * 1024 * 1024;
}
uint IDASCommunication.MaxSampleRate(int numberOfConfiguredChannels)
{
return int.MaxValue;
}
void IDiagnosticsActions.MeasureTransferSpeed(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.MeasureTransferSpeed", new WaitCallback(AsyncMeasureTransferSpeed), info);
}
private void AsyncMeasureTransferSpeed(object o)
{
GenericSuccess(o);
}
uint IDASCommunication.MinSampleRate()
{
return 1;
}
int IDASCommunication.NumberOfChannels()
{
return 4;
}
int IDASCommunication.NumberOfConfiguredChannels()
{
return 0;
}
void IDiagnosticsActions.PerformArmChecks(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.PerformArmChecks", new WaitCallback(AsyncPerformArmChecks), info);
}
private void AsyncPerformArmChecks(object o)
{
NotSupportedError(o, "SliceProFd.PerformArmChecks");
}
void IDiagnosticsActions.PerformVoltageCheck(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.PerformVoltageCheck", new WaitCallback(AsyncPerformVoltageCheck), info);
}
public static VoltageStatusColor ConvertBatteryVoltage2Color(double batteryVoltage, IDASCommunication das)
{
if (batteryVoltage > das.MaximumValidBatteryVoltage) { return VoltageStatusColor.Off; }
if (batteryVoltage > das.BatteryHighVoltage) { return VoltageStatusColor.Red; }
if (batteryVoltage > das.BatteryMediumVoltage) { return VoltageStatusColor.Green; }
if (batteryVoltage >= das.BatteryLowVoltage) { return VoltageStatusColor.Yellow; }
if (batteryVoltage >= das.MinimumValidBatteryVoltage) { return VoltageStatusColor.Red; }
return VoltageStatusColor.Off;
}
private void AsyncPerformVoltageCheck(object o)
{
if ( !(o is ServiceAsyncInfo info)) { return; }
if ( !(this is IDASCommunication idas)) { return; }
try
{
using (var tokenSource = new CancellationTokenSource())
{
var t = CANFD.API.GetBattery(ConnectString, tokenSource.Token);
t.Wait();
if (t.IsCompleted)
{
BaseInputValues inputValues = new BaseInputValues(((IDASCommunication)this).BaseInput);
var voltage = Convert.ToDouble(t.Result.LoadV);
if (voltage < idas.MinimumValidBatteryVoltage) { voltage = 0D; }
if (voltage > idas.MaximumValidBatteryVoltage) { voltage = 0D; }
inputValues.BatteryVoltage = voltage;
inputValues.BatteryMilliVolts = 1000D * voltage;
inputValues.BatteryVoltageStatusColor = ConvertBatteryVoltage2Color(voltage, idas);
//StatusDisplayBattery
inputValues.StatusDisplayBattery = ((voltage < idas.MinimumValidBatteryVoltage) || (voltage > idas.MaximumValidBatteryVoltage)) ?
"---" :
$"{voltage:0.00} V";
inputValues.BatteryVoltageStatus = inputValues.StatusDisplayBattery;
((IDASCommunication)this).BaseInput = inputValues;
}
else
{
info.Error($"Failed to perform voltage check [{SerialNumber}] ({ConnectString})");
return;
}
}
}
catch (Exception ex)
{
var msg = $"Failed to perform voltage check [{SerialNumber}] ({ConnectString})";
APILogger.Log(msg, ex);
info.Error(msg);
return;
}
info.Success();
}
void IDiagnosticsActions.PerformVoltageCheckTAOnly(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.PerformVoltageCheckTAOnly", new WaitCallback(AsyncPerformVoltageCheckTAOnly), info);
}
private void AsyncPerformVoltageCheckTAOnly(object o)
{
GenericSuccess(o);
}
void IArmActions.PreparedArmNow(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool checkoutMode, int maxNumberEvents, bool SysMode)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.PreparedArmNow", new WaitCallback(AsyncPreparedArmNow), info);
}
private void AsyncPreparedArmNow(object o)
{
if (!(o is ServiceAsyncInfo info)){ return; }
//FB 44877
SetRTCBaseTime();
try
{
var t = CANFD.API.SetRecordingStart(ConnectString, CancellationToken.None);
t.Wait();
info.Success();
}
catch( Exception ex)
{
var msg = $"Failed PreparedArmNow [{SerialNumber}] ({ConnectString})";
APILogger.Log(msg, ex);
info.Error(msg);
}
}
void IArmActions.PrepareForArmNow(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool testingMode, int maxNumberEvents, bool SysMode)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.PreparForArmNow", new WaitCallback(AsyncPrepareForArmNow), info);
}
private void AsyncPrepareForArmNow(object o)
{
GenericSuccess(o);
}
void IDiagnosticsActions.PrepareForBridgeResistanceMeasurement(uint DiagnosticsSampleRateHz, float DiagnosticsAAFilterFrequencyHz, ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.PrepareForBridgeResistanceMeasurement", new WaitCallback(AsyncPrepareForBridgeResistanceMeasurement), info);
}
private void AsyncPrepareForBridgeResistanceMeasurement(object o)
{
GenericSuccess(o);
}
void IDiagnosticsActions.PrepareForDiagnostics(uint DiagnosticsSampleRateHz, float DiagnosticsAAFilterFrequencyHz, PrePostResults WhichResult, ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.PrepareForDiagnostics", new WaitCallback(AsyncPrepareForDiagnostics), info);
}
private void AsyncPrepareForDiagnostics(object o)
{
GenericSuccess(o);
}
void IConfigurationActions.QueryConfiguration(ServiceCallback callback, object userData, uint crc, string strConfig, bool bReadIds, bool bDeviceScaleFactors, bool sourceDASStorageList)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.QueryConfiguration", new WaitCallback(AsyncQueryConfiguration), info);
}
private void AsyncQueryConfiguration(object o)
{
((IConfiguration)this).ConfigData = MakeDefaultConfigFromInfo();
//FB 44877
QueryAndAssignBaseSystemTime();
var calDate = GetCalDate();
SetCalDateInMemory(calDate, this);
_currentDiagnosticMessages = GetDiagnosticMessages();
GenericSuccess(o);
}
private static void SetCalDateInMemory(DateTime? calDate, SliceProFd<T> device)
{
var idas = (IDASCommunication)device;
if (null == idas.DASInfo) { return; }
idas.DASInfo.CalibrationDate = calDate;
if (null == idas.DASInfo.Modules || 0 == idas.DASInfo.Modules.Length) { return; }
foreach( var module in idas.DASInfo.Modules) { module.CalibrationDate = calDate; }
}
//FB 44877
private void QueryAndAssignBaseSystemTime()
{
try
{
var message = GetClock();
if (message == null)
{
return;
}
//CAN FD returns time as UTC, we don't know the system base is in UTC or local for now set it as we received it from REST API which is in UTC
_systemBaseTime = DateTime.ParseExact(message.System, "yyyy-MM-dd HH:mm:ss.fff", CultureInfo.CurrentCulture);
}
catch (Exception ex)
{
APILogger.Log(ex);
}
}
//FB 44877
private ClocksMessage GetClock()
{
try
{
var t = CANFD.API.GetClocks(ConnectString, CancellationToken.None);
t.Wait();
if (t.IsCompleted)
{
return t.Result;
}
}
catch (Exception ex)
{
APILogger.Log(ex);
}
return null;
}
//FB 44877
private void SetClock(DateTime dateTime)
{
try
{
var t = CANFD.API.SetClocks(ConnectString, dateTime, CancellationToken.None);
t.Wait();
}
catch (Exception ex)
{
APILogger.Log(ex);
}
}
//FB 44877
private void SetRTCBaseTime()
{
try
{
var dt = DateTime.Now;
Thread.Sleep(1000 - dt.Millisecond - 1);
SetClock(DateTime.Now);
}
catch (Exception ex)
{
APILogger.Log("Failed to set system time: ", ex);
}
}
private ConfigurationData MakeDefaultConfigFromInfo()
{
var config = new ConfigurationData();
var numChannels = ((IInformation)this).DASInfo.Modules[0].NumberOfChannels;
config.Modules = new DASModule[1];
config.Modules[0] = MakeConfigModule(numChannels);
return config;
}
private DASModule MakeConfigModule(uint numChannels)
{
var configModule = new DASModule(0, this);
configModule.Channels = new DASChannel[numChannels];
for (var i = 0; i < numChannels; i++)
{
var channel = new CANInputDASChannel(configModule, i) { UserChannelName = $"CAN Channel {i + 1}" };
configModule.Channels[i] = channel;
}
return configModule;
}
void IConfiguration.QueryConnectedDevices()
{
//does not do anything WRT connected devices - so we all done?
}
void IDownloadActions.QueryDownload(ServiceCallback callback, object userData, int eventIndex, TDASServiceSetupInfo setupInfo)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.QueryDownload", new WaitCallback(AsyncQueryDownload), info);
}
private void AsyncQueryDownload(object o)
{
if (!(o is ServiceAsyncInfo info)) { return; }
try
{
var eventDownloadStatus = new List<bool>();
var eventIDs = new List<string>();
var eventDescriptions = new List<string>();
var eventGUIDs = new List<Guid>();
var faultFlags = new List<ushort>();
var dasModulesPerEvent = new List<List<DASModule>>();
DateTime eventStartTime = DateTime.Now;
try
{
var t = CANFD.API.GetUsbTree(ConnectString, CancellationToken.None);
t.Wait();
if (t.IsCompleted && t.Result.children.Any())
{
var child = FindChild(t.Result, "Recordings");
if (null != child && child.children.Any())
{
eventGUIDs.Add(new Guid(GENERIC_SPFD_GUID));
}
}
}
catch( Exception ex)
{
var msg = $"Failed to retrieve USB tree [{SerialNumber}] ({ConnectString})";
APILogger.Log(msg, ex);
info.Error(msg);
return;
}
var modules = ((IDASCommunication)this).DASInfo.Modules;
for (int i = 0; i < modules.Length; i++)
{
float hardwareFilterRate = 1F;
eventIDs.Add(GENERIC_SPFD_GUID);
eventDescriptions.Add(GENERIC_SPFD_GUID);
eventDownloadStatus.Add(true);
dasModulesPerEvent.Add(new List<DASModule>());
var module = new DASModule(modules[i].ModuleArrayIndex, this);
module.RecordingMode = RecordingMode.CircularBuffer;
module.StartRecordSampleNumber = 0;
module.PreTriggerSeconds = 1;
module.PostTriggerSeconds = 1;
module.NumberOfSamples = 3;
module.TriggerSampleNumbers = new UInt64[1];
module.TriggerSampleNumbers[0] = Convert.ToUInt64(1);
module.Channels = new DASChannel[modules[i].NumberOfChannels];
module.AAFilterRateHz = hardwareFilterRate;
module.SampleRateHz = 1;
var configData = ((IDASCommunication)this).ConfigData;
if (null != configData)
{
module.Channels = (DASChannel[])configData.Modules[i].Channels.Clone();
// update the channel info
for (uint channelIdx = 0; channelIdx < module.Channels.Length; channelIdx++)
{
module.Channels[channelIdx].EventStartTime = eventStartTime;
}
dasModulesPerEvent[0].Add(module);
}
}
if (0 < dasModulesPerEvent.Count && 0 < dasModulesPerEvent[0].Count)
{
foreach (DASModule tempModule in dasModulesPerEvent[0])
{
foreach (var channel in tempModule.Channels)
{
channel.LevelTriggerT0AdjustmentSamples = 0;
}
}
}
((IDASCommunication)this).SetEventGuids(eventGUIDs.ToArray());
((IDASCommunication)this).SetEventFaultFlags(faultFlags.ToArray());
DownloadReport dlReport = new DownloadReport();
dlReport.Events = new DownloadReport.EventInfo[eventGUIDs.Count];
for (int eventIndex = 0; eventIndex < eventGUIDs.Count; eventIndex++)
{
dlReport.Events[eventIndex] = new DownloadReport.EventInfo();
dlReport.Events[eventIndex].Description = eventDescriptions[eventIndex];
dlReport.Events[eventIndex].EventNumber = eventIndex;
dlReport.Events[eventIndex].TestID = eventIDs[eventIndex];
dlReport.Events[eventIndex].HasBeenDownloaded = false;
dlReport.Events[eventIndex].WasTriggered = false;
dlReport.Events[eventIndex].TestGUID = eventGUIDs[eventIndex];
dlReport.Events[eventIndex].ClearFaults();
dlReport.Events[eventIndex].Modules = dasModulesPerEvent[eventIndex].ToArray();
}
for (int eventIndex = 0; eventIndex < eventGUIDs.Count; eventIndex++)
{
double minPre = 1;
double minPost = 1;
if (0 != dlReport.Events[eventIndex].Modules.Length)
{
ulong numberOfSamples = 3;
for (int i = 0; i < dlReport.Events[eventIndex].Modules.Length; i++)
{
DASModule module = (DASModule)dlReport.Events[eventIndex].Modules[i];
module.PreTriggerSeconds = minPre;
module.PostTriggerSeconds = minPost;
module.TriggerSampleNumbers = new ulong[]
{
1UL
};
// If not triggered, racks return 0 and G5s return number of samples
if ((module.TriggerSampleNumbers[0] > 0) && (module.TriggerSampleNumbers[0] < numberOfSamples))
{
dlReport.Events[eventIndex].WasTriggered = true;
}
//the above statement the pretrigger seconds appears to be off by one sample, so I adjust it here as
//there might already be a lot of different side effects to changing the pre trigger time.
if (module.TriggerSampleNumbers[0] > 0) { module.TriggerSampleNumbers[0] = module.TriggerSampleNumbers[0] - 1; }
module.NumberOfSamples = numberOfSamples;
}
}
}
((IDASCommunication)this).SetEventInfo(dlReport);
((IDASCommunication)this).SetEventDownloadStatus(eventDownloadStatus.ToArray());
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
var msg = $"Failed QueryDownload [{SerialNumber}] ({ConnectString})";
APILogger.Log(msg, ex);
info.Error(msg);
}
}
void IDownloadActions.QueryDownloadedStatus(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.QueryDownloadStatus", new WaitCallback(AsyncQueryDownloadStatus), info);
}
private void AsyncQueryDownloadStatus(object asyncInfo)
{
var info = asyncInfo as ServiceAsyncInfo;
var statusList = new List<bool>();
var guids = new List<Guid>();
try
{
var t = CANFD.API.GetUsbTree(ConnectString, CancellationToken.None);
t.Wait();
if (t.IsCompleted && t.Result.children.Any())
{
var child = FindChild(t.Result, "Recordings");
if ( null != child && child.children.Any())
{
guids.Add(new Guid(GENERIC_SPFD_GUID));
statusList.Add(true);
}
}
DownloadReport.SetEventDownloadStatus(this, statusList.ToArray(), false);
DownloadReport.SetEventGuids(this, guids.ToArray(), false);
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
APILogger.Log($"Failed to query download status [{SerialNumber}] ({ConnectString})", ex);
info.Error(ex.Message, ex);
}
}
void IArmActions.QueryFlashEraseStatus(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.QueryFlashEraseStatus", new WaitCallback(AsyncQueryFlashEraseStatus), info);
}
private void AsyncQueryFlashEraseStatus(object o)
{
if ( !(o is ServiceAsyncInfo info)){ return; }
while( FlashClearProgress < 100)
{
info.Progress(FlashClearProgress);
Thread.Sleep(100);
}
info.Success();
}
void IConfigurationActions.QueryTestSetup(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.QueryTestStatus", new WaitCallback(AsyncQueryTestSetup), info);
}
private void AsyncQueryTestSetup(object o)
{
NotSupportedError(o, "SliceProFd.QueryTestStatus");
}
void IDASCommunication.ReadFirstUseDate()
{
//not supported, so nothing to do
}
void IArmActions.ReadyForArming(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool testingMode, int maxNumberEvents, bool DummyArm, bool SysMode)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.ReadyForArming", new WaitCallback(AsyncReadyForArming), info);
}
private void AsyncReadyForArming(object o)
{
GenericSuccess(o);
}
void IRealTimeActions.RealTime(int samplesPerSec, int msBetweenSamples, ServiceCallback callback, object userData, bool allowMultipleSampleRealtime, int moduleIndex, ManualResetEvent stopEvent, byte[] channels, double aaf, int minCallbackUpdateTimeMs, bool UseUDPStreaming, string HostIPAddress)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.RealTime", new WaitCallback(AsyncRealTime), info);
}
private void AsyncRealTime(object o)
{
NotSupportedError(o, "SliceProFd.RealTime");
}
void IRealTimeActions.RealTimePolling(ServiceCallback callback, object userData, ManualResetEvent stopEvent, byte[] channels)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.RealtimePolling", new WaitCallback(AsyncRealTimePolling), info);
}
private void AsyncRealTimePolling(object o)
{
NotSupportedError(o, "SliceProFd.RealTimePolling");
}
void IRealTimeActions.RealTimeTiltPolling(ServiceCallback callback, object userData, ManualResetEvent stopEvent)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.RealTimeTiltPolling", new WaitCallback(AsyncRealTimeTiltPolling), info);
}
private void AsyncRealTimeTiltPolling(object o)
{
NotSupportedError(o, "SliceProFd.RealtimeTiltPolling");
}
void IArmActions.ReArm(ServiceCallback callback, object userData, bool autoArm, bool arm, bool repeatEnable)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.ReArm", new WaitCallback(AsyncReArm), info);
}
private void AsyncReArm(object o)
{
NotSupportedError(o, "SliceProFd.ReArm");
}
void IConfigurationActions.Reboot(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.Reboot", new WaitCallback(AsyncReboot), info);
}
private void AsyncReboot(object o)
{
NotSupportedError(o, "SliceProFd.Reboot");
}
bool IDASCommunication.RequireDiagnosticRateMatchSampleRate()
{
return false;
}
void IConfigurationActions.ResetHardwareLines(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.ResetHardwareLines", new WaitCallback(AsyncResetHardwareLines), info);
}
private void AsyncResetHardwareLines(object o)
{
GenericSuccess(o);
}
void IDiagnosticsActions.SaveTemperaturesPre(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.SaveTemperaturesPre", new WaitCallback(AsyncSaveTemperaturesPre), info);
}
private void AsyncSaveTemperaturesPre(object o)
{
GenericSuccess(o);
}
void IDiagnosticsActions.SaveTiltSensorDataPre(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.SaveTiltSensorsDataPre", new WaitCallback(AsyncSaveTiltSensorsDataPre), info);
}
private void AsyncSaveTiltSensorsDataPre(object o)
{
GenericSuccess(o);
}
void IDiagnos.SetChannelDiagnosticActions(IDiagnosticActions[] actions, bool setInDb)
{
((IDiagnos)this).ChannelDiagnostics = actions;
}
void IDiagnos.SetChannelDiagnosticsResults(IDiagnosticResult[] results, bool setInDb)
{
((IDiagnos)this).ChannelDiagnosticsResults = results;
}
void IConfiguration.SetChannelDisplayOrder(int[] order)
{
throw new NotImplementedException("SliceProFd.SetChannelDisplayOrder");
}
void IArmStatus.SetDASArmStatus(IArmStatusData status, bool bSetInDb)
{
((IArmStatus)this).DASArmStatus = status;
}
void IArmStatus.SetDASArmStatus()
{
ArmStatus.SetArmStatus(this, ((IArmStatus)this).DASArmStatus, true);
}
void IConfiguration.SetDASDisplayOrder(int order)
{
throw new NotImplementedException("SliceProFd.SetDASDisplayOrder");
}
void IInformation.SetDASInfo(IInfoResult dasInfo, bool bSetInDb)
{
((IInformation)this).DASInfo = dasInfo;
}
void IInformation.SetDASInfo()
{
InfoResult.SetDASInfo(this);
}
void IDownloadActions.SetDownloaded(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.SetDownloaded", new WaitCallback(AsyncSetDownloaded), info);
}
private void AsyncSetDownloaded(object o)
{
GenericSuccess(o);
}
void IDownload.SetEventArmAttemps(byte[] armAttempts, bool storeInDb)
{
DownloadReport.SetEventArmAttempts(this, armAttempts, storeInDb);
}
void IDownload.SetEventDownloadStatus(bool[] status, bool storeInDb)
{
DownloadReport.SetEventDownloadStatus(this, status, storeInDb);
}
void IDownload.SetEventFaultFlags(ushort[] flags, bool storeInDb)
{
DownloadReport.SetEventFaultFlags(this, flags, storeInDb);
}
void IDownload.SetEventGuids(Guid[] guids, bool storeInDb)
{
DownloadReport.SetEventGuids(this, guids, storeInDb);
}
void IDownload.SetEventInfo(IDownloadReport eventInfo, bool bSetInDb)
{
DownloadReport.SetEventInfo(this, eventInfo, bSetInDb);
}
void IDownloadActions.SetEventInfo(int eventIndex, string id, Guid guid, ulong totalSamples, ulong[] triggerSamples, ulong startRecordSample, uint eventHasDownloaded, ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.SetEventInfo", new WaitCallback(AsyncSetEventInfo), info);
}
private void AsyncSetEventInfo(object o)
{
NotSupportedError(o, "SetEventInfo");
}
void IDownload.SetExtendedFaultFlags(uint[][] flags)
{
DownloadExtendedFaultFunctions.SetExtendedFaultFlags(flags, this);
}
void IConfigurationActions.SetFirstUseDate(DateTime firstUseDate, ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.SetFirstUseDate", new WaitCallback(AsyncSetFirstUseDate), info);
}
private void AsyncSetFirstUseDate(object o)
{
NotSupportedError(o, "SliceProFd.SetFirstUseDate");
}
void IArmStatus.SetInArm(bool WriteToDb)
{
if (null == ((IArmStatus)this).DASArmStatus)
{
((IArmStatus)this).DASArmStatus = new ArmStatus();
}
((IArmStatus)this).DASArmStatus.IsArmed = true;
ArmStatus.SetArmStatus(this, ((IArmStatus)this).DASArmStatus, WriteToDb);
}
void IArmStatus.SetInRealtime(bool WriteToDb, bool ExitRealtimeIfPossible)
{
if (null == ((IArmStatus)this).DASArmStatus)
{
((IArmStatus)this).DASArmStatus = new ArmStatus();
}
((IArmStatus)this).DASArmStatus.IsInRealtime = true;
ArmStatus.SetArmStatus(this, ((IArmStatus)this).DASArmStatus, WriteToDb);
}
void IDASCommunication.SetIsStreamingSupported(bool supported)
{
if (supported)
{
throw new NotSupportedException("SliceProFd.IsStreamingSupported is not supported");
}
((IDASCommunication)this).IsStreamingSupported = false;
}
void IDiagnosticsActions.SetStatusIndicator(DiagnosticsStatusIndicatorState state, ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.SetStatusIndicator", new WaitCallback(AsyncSetStatusIndicator), info);
}
private void AsyncSetStatusIndicator(object o)
{
GenericSuccess(o);
}
void IDownloadActions.SetTriggerSampleNumbers(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.SetTriggerSampleNumbers", new WaitCallback(AsyncSetTriggerSampleNumbers), info);
}
private void AsyncSetTriggerSampleNumbers(object o)
{
NotSupportedError(o, "SliceProFd.SetTriggerSampleNumbers");
}
void IRealTimeActions.SetUDPStreamProfile(ServiceCallback callback, object userData, UDPStreamProfile streamProfile, string udpAddress, ushort timeChannelId, ushort dataChannelId, uint[] tmnsConfig, ushort irigTimeDataPacketIntervalMs)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.SetUDPStreamProfile", new WaitCallback(AsyncSetUDPStreamProfile), info);
}
private void AsyncSetUDPStreamProfile(object o)
{
NotSupportedError(o, "SliceProFd.SetUDPStreamProfile");
}
void IDownload.SetWhatToDownload(IDownloadRequest request, bool bSetInDb)
{
DownloadRequest.SetWhatToDownload(this, request, bSetInDb);
}
void IDiagnosticsActions.SquibFireCheckArm(double delay, double duration, ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.SquibFireCheckArm", new WaitCallback(AsyncSquibFireCheckArm), info);
}
private void AsyncSquibFireCheckArm(object o)
{
if ( !(o is ServiceAsyncInfo info)) { return; }
var msg = $"Failed to SquibFireCheckArm [{SerialNumber}] ({ConnectString})";
try
{
var t = CANFD.API.SetRecordingStart(ConnectString, CancellationToken.None);
t.Wait();
if (t.IsCompleted) { info.Success(); }
else if (null != t.Exception) { throw t.Exception; }
else { info.Error(msg); }
}
catch( Exception ex)
{
APILogger.Log(msg, ex);
info.Error(msg);
}
}
void IArmActions.StartRecord(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.StartRecord", new WaitCallback(AsyncStartRecord), info);
}
private void AsyncStartRecord(object o)
{
NotSupportedError(o, "SliceProFd.StartRecord");
}
void IConfigurationActions.StoreTestSetupXML(ServiceCallback callback, object userData, string testSetupXML)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.StoreTestSetupXML", new WaitCallback(AsyncStoreTestSetupXML), info);
}
private void AsyncStoreTestSetupXML(object o)
{
GenericSuccess(o);
}
bool IDASCommunication.SupportsAutoArm()
{
return false;
}
bool IDASCommunication.SupportsHardwareInputCheck()
{
return false;
}
bool IDASCommunication.SupportsLevelTrigger()
{
return false;
}
bool IDASCommunication.SupportsMultipleConfigurations()
{
return false;
}
bool IDASCommunication.SupportsMultipleEvents()
{
return false;
}
bool IDASCommunication.SupportsMultipleSampleRealtime()
{
return false;
}
bool IDASCommunication.SupportsRealtime()
{
return false;
}
bool IDASCommunication.SupportsStartInversion()
{
return false;
}
bool IDASCommunication.SupportsTriggerInversion()
{
return false;
}
void IArmActions.Trigger(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.Trigger", new WaitCallback(AsyncTrigger), info);
}
private void AsyncTrigger(object o)
{
if (!(o is ServiceAsyncInfo info)) { return; }
var msg = $"Failed to trigger [{SerialNumber}] ({ConnectString})";
try
{
var t = CANFD.API.SetEventPinArm(ConnectString, CancellationToken.None);
t.Wait();
if (t.IsCompleted) { info.Success(); }
else if (null != t.Exception) { throw t.Exception; }
else { info.Error(msg); }
}
catch( Exception ex)
{
APILogger.Log(msg, ex);
info.Error(msg);
}
}
void IDiagnosticsActions.TriggerCheckDownload(double delay, double duration, float diagnosticsAAFilterFrequencyHz, uint diagnosticsSampleRateHz, ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.TriggerCheckDownload", new WaitCallback(AsyncTriggerCheckDownload), info);
}
private void AsyncTriggerCheckDownload(object o)
{
//it doesn't need to do anything in trigger check download, so just return success
GenericSuccess(o);
}
void IDiagnosticsActions.TriggerCheckTrigger(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.TriggerCheckTrigger", new WaitCallback(AsyncTriggerCheckTrigger), info);
}
private void AsyncTriggerCheckTrigger(object o)
{
NotSupportedError(o, "SliceProFd.TriggerCheckTrigger");
}
void IArmActions.TurnOffT0Lights(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.TurnOffT0Lights", new WaitCallback(AsyncTurnOffT0Lights), info);
}
private void AsyncTurnOffT0Lights(object o)
{
GenericSuccess(o);
}
void IConfigurationActions.UpdateConfigurationFromFile(ServiceCallback callback, object userData, string filePath)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.UpdateConfigurationFromFile", new WaitCallback(AsyncUpdateConfigurationFromFile), info);
}
private void AsyncUpdateConfigurationFromFile(object o)
{
NotSupportedError(o, "SliceProFd.UpdateConfigurationFromFile");
}
void IConfigurationActions.UpdateId(ServiceCallback callback, object userData, DASModule module, DASChannel channel)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.UpdateId", new WaitCallback(AsyncUpdateId), info);
}
private void AsyncUpdateId(object o)
{
//there are no ids, so just pass success
GenericSuccess(o);
}
void IConfigurationActions.UpdateIDs(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.UpdateIDs", new WaitCallback(AsyncUpdateIDs), info);
}
private void AsyncUpdateIDs(object o)
{
//nothing to do, so just pass success
GenericSuccess(o);
}
void IConfigurationActions.VerifyConfig(bool DoStrictCheck)
{
((IConfigurationActions)this).VerifyConfig(DoStrictCheck, null);
}
void IConfigurationActions.VerifyConfig(bool DoStrictCheck, ErrorCallback FailedChallengeFunc)
{
var config = ((IConfiguration)this).ConfigData;
// look thru all the config data and make sure it's fit to be used
// our caller have already checked for null, but...
if (config == null)
{
throw new InvalidDataException("ConfigData is null");
}
if (string.IsNullOrEmpty(config.Description))
{
config.Description = "";
}
if (DoStrictCheck && string.IsNullOrEmpty(config.TestID))
{
// "Slice.VerifyConfig: ConfigData.TestID is null"
throw new InvalidDataException("ConfigData.TestID is null");
}
}
void ITriggerCheckActions.PreStartTriggerCheck(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFd.PreStartTriggerCheck", new WaitCallback(AsyncPreStartTriggerCheck), info);
}
/// <summary>
/// complete any prep work before starting trigger check that needs to be done
/// </summary>
protected void AsyncPreStartTriggerCheck(object asyncInfo)
{
GenericSuccess(asyncInfo);
}
void ITriggerCheckActions.PostStartTriggerCheck(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFD.PostStartTriggerCheck", new WaitCallback(AsyncPostStartTriggerCheck), info);
}
private void StopRecording()
{
LogCommand("SetRecordingStop", true, TimeSpan.MinValue);
var elapsed = ValueStopwatch.StartNew();
var t = CANFD.API.SetRecordingStop(ConnectString, CancellationToken.None);
t.Wait();
if (t.IsCompleted)
{
LogCommand("SetRecordingStop", false, elapsed.GetElapsedTime(), $"Replay: {t.Result.Reply}, Recording: {t.Result.Recording}, OK: {t.Result.Ok}");
}
}
protected void AsyncPostStartTriggerCheck(object asyncInfo)
{
GenericSuccess(asyncInfo);
}
void ITriggerCheckActions.StartTriggerCheck(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFD.StartTriggerCheck", new WaitCallback(AsyncStartTriggerCheck), info);
}
private void ArmTriggerCheck()
{
LogCommand("SetRecordingTriggerCheck_Quick", true, TimeSpan.MinValue);
var elapsed = ValueStopwatch.StartNew();
var t = CANFD.API.SetRecordingTriggerCheck_Quick(ConnectString, CancellationToken.None);
t.Wait();
if (t.IsCompleted)
{
LogCommand("SetRecordingTriggerCheck_Quick", false, elapsed.GetElapsedTime(), $"Replay: {t.Result.Reply}, Recording: {t.Result.Recording}, OK: {t.Result.Ok}");
}
}
protected void AsyncStartTriggerCheck(object asyncInfo)
{
if (!(asyncInfo is ServiceAsyncInfo info)) { return; }
try
{
StopRecording();
ArmTriggerCheck();
info.Success();
}
catch( Exception ex)
{
info.Error($"Failed to start trigger check[{SerialNumber}] ({ConnectString})");
APILogger.Log($"Failed to start trigger check[{SerialNumber}] ({ConnectString})", ex);
}
}
void ITriggerCheckActions.DoTriggerCheck(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFD.DoTriggerCheck", new WaitCallback(AsyncDoTriggerCheck), info);
}
void ITriggerCheckActions.DoTriggerCheckSync()
{
var status = new ArmStatus(((IArmStatus)this).DASArmStatus);
using (var cancelSource = new CancellationTokenSource())
{
cancelSource.CancelAfter(10000);
var t = CANFD.API.GetEventPin(ConnectString, cancelSource.Token);
t.Wait();
if (t.IsCompleted)
{
var armed = t.Result.Armed.HasValue && t.Result.Armed.Value;
status.IsArmed = armed;
status.IsRecording = armed;
status.IsTriggered = t.Result.Event.HasValue && t.Result.Event.Value;
}
}
//we don't have a good way of getting triggered currently ...
ArmStatus.SetArmStatus(this, status, false);
}
private void AsyncDoTriggerCheck(object asyncInfo)
{
if ( ! (asyncInfo is ServiceAsyncInfo info)) { return; }
try
{
((ITriggerCheckActions)this).DoTriggerCheckSync();
info?.Success();
}
catch (CanceledException)
{
info?.Cancel();
}
catch (Exception ex)
{
info?.Error(ex.Message, ex);
}
}
void ITriggerCheckActions.DoStartCheck(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFD.DoStartCheck", new WaitCallback(AsyncDoStartCheck), info);
}
protected void AsyncDoStartCheck(object asyncInfo)
{
//SPFD doesn't have a "start record" - if it's armed it's recording ...
if (!(asyncInfo is ServiceAsyncInfo info)) { return; }
try
{
using (var cancelSource = new CancellationTokenSource())
{
cancelSource.CancelAfter(500);
var t = CANFD.API.GetEventPin(ConnectString, cancelSource.Token);
t.Wait();
if (t.IsCompleted)
{
var status = new ArmStatus(((IArmStatus)this).DASArmStatus);
var armed = t.Result.Armed.HasValue && t.Result.Armed.Value;
status.IsArmed = armed;
status.IsRecording = armed;
status.IsTriggered = t.Result.Event.HasValue && t.Result.Event.Value;
ArmStatus.SetArmStatus(this, status, false);
info.Success();
}
else { info.Error($"Failed to get arm status [{SerialNumber}] ({ConnectString})"); }
}
}
catch (Exception ex)
{
var msg = $"Failed to get arm status [{SerialNumber}] ({ConnectString})";
APILogger.Log(msg, ex);
info.Error(msg, ex);
}
}
void ITriggerCheckActions.CancelTriggerCheck(ServiceCallback callback, object userData)
{
var info = new ServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("SliceProFD.CancelTriggerCheck", new WaitCallback(AsyncCancelTriggerCheck), info);
}
protected void AsyncCancelTriggerCheck(object asyncInfo)
{
if (!(asyncInfo is ServiceAsyncInfo info)) { return; }
try
{
StopRecording();
}
catch (Exception ex)
{
APILogger.Log($"Failed to disarm trigger check [{SerialNumber}] ({ConnectString})", ex);
}
info.Success();
}
string[] IDiagnosticMessagesDevice.GetFatalErrorFields()
{
return new[]
{
"service_batterybackupenable.service",
"service_batterystatusbroadcast.service",
"service_candatarecorder.service",
"service_chargerfetinit.service",
"service_chargerstatusbroadcast.service",
"service_eventpinmonitor.service",
"service_flaskapibackend.service",
"service_mainboardledcontrol.service",
"service_prodfrontend.service",
"service_spcfdrecorder.service",
"service_servicelogger.service",
"service_shutdownpinmonitor.service",
"service_slicediscovery.service",
"service_statuslinecontroller.service",
"service_swissbitcontroller.service",
"service_temperaturemonitor.service",
"service_usbsession.service",
"service_usbtrafficmonitor.service",
"service_userfrontend.service",
"system_time",
"ntp_config_read",
"power_good",
"nvin",
"auto - arm",
"recording_arm_command",
"recording_armed_state",
"recording_disarm_command",
"recording_disarmed_state",
"battery_present",
"battery_voltage",
"battery_fault",
"charger_fault",
"boost_fault",
"usb_present",
"swissbit_readable",
"rtc_readable",
"can_reachable",
"4_channel_can"
};
}
DiagnosticMessageRow[] IDiagnosticMessagesDevice.GetCurrentDiagnosticMessages(string[] fields, bool failingOnly)
{
// This assumes you have a source of data, like a private list or array
// Let's assume 'allMessages' is your master collection
IEnumerable<DiagnosticMessageRow> query = _currentDiagnosticMessages;
// 1. Filter by Fields (if the array is provided and not empty)
if (fields != null && fields.Length > 0)
{
// Use HashSet for O(1) lookup if 'fields' is a large array
var fieldSet = new HashSet<string>(fields, StringComparer.OrdinalIgnoreCase);
query = query.Where(m => fieldSet.Contains(m.Field));
}
// 2. Filter by Verdict
if (failingOnly)
{
query = query.Where(m => string.Equals(m.Verdict, "Fail", StringComparison.OrdinalIgnoreCase));
}
return query.ToArray();
}
}
/// <summary>
/// Empty wrapper for a SLICEPROFd over REST
/// </summary>
public class RESTSliceProFD : SliceProFd<RESTConnection>
{
public override string ToString()
{
try
{
return $"{SerialNumber} ({ConnectString}";
}
//FB 45086 removed unused ex
catch
{
return base.ToString();
}
}
}
}