Files
DP44/DataPRO/IService/.svn/pristine/1c/1cf11166d89728bb32ac0e007d84bc78254ee21f.svn-base

2493 lines
116 KiB
Plaintext
Raw Normal View History

2026-04-17 14:55:32 -04:00
using System;
using DTS.Common.Enums.Sensors;
using DTS.Common.Interface.Connection;
using DTS.Common.Enums.DASFactory;
using DTS.Common.Interface.DASFactory;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DTS.Common;
using DTS.Common.Enums;
using DTS.Common.Utilities.Logging;
using DTS.DASLib.Command.SLICE;
using DTS.DASLib.Command.SLICE.DownloadCommands;
using DTS.Common.Enums.Hardware;
using DTS.Common.ICommunication;
using DTS.Common.WINUSBConnection;
using DTS.DASLib.Command;
using DTS.DASLib.Command.SLICE.RealtimeCommands;
using DTS.Common.Interface.DASFactory.Download;
using DTS.Common.DASResource;
using DTS.Common.DAS.Concepts;
using DTS.Common.Constant.DASSpecific;
using DTS.Common.Interface.DASFactory.Config;
using DTS.Common.Classes.Connection;
using DTS.Common.Interface.DASFactory.Diagnostics;
using Prism.Ioc;
using DTS.Common.Events;
using DTS.Common.Classes.TMAT;
using DTS.DASLib.Service.Classes;
using DTS.Common.Interface.TestSetups;
using DTS.DASLib.Service.Interfaces;
using System.IO.Ports;
using System.Threading;
using Prism.Events;
namespace DTS.DASLib.Service
{
public class TSRAIR<T> : TSRAIR_Base<T>, IDASReconfigure where T : IConnection, new()
{
public TSRAIR()
{
MinimumValidBatteryVoltage = 2.5D;
}
/// <summary>
/// sets the maximum module count for unit
/// this is not done through a service, so there's no protection from other commands
/// executing at the same time
/// </summary>
void IDASReconfigure.SetMaxModuleCount(int count)
{
SetMaxModuleCount(count, false);
_maxModuleCount = count;
}
private int _maxModuleCount = -1;
/// <summary>
/// gets the physical max number of modules.
/// this value is cached
/// </summary>
/// <returns></returns>
int IDASReconfigure.GetMaxModuleCount()
{
_maxModuleCount = GetMaxModuleCount(_maxModuleCount);
return _maxModuleCount;
}
}
public class TSRAIR_Base<T> : SLICE6_Base<T>, ITestDASOrder, IArmActions, IUARTDownload, IUARTDownloadActions where T : IConnection, new()
{
private double _BMI_EU_LIMIT = -1;
/// <summary>
/// don't check level triggers between the levels provided by BMI sensors for TSR AIR.
/// 36807 Already level triggered error preventing arm with system of TSR AIR DAS
/// </summary>
/// <param name="limitEU"></param>
/// <returns></returns>
protected override bool ShouldCheckLevelTrigger(double limitEU)
{
if (_BMI_EU_LIMIT < 0)
{
try
{
var query = new QueryArmAttribute(this) { Key = AttributeTypes.ArmAndEventAttributes.LevelTriggerLessThanLimit };
query.SyncExecute();
_BMI_EU_LIMIT = ((float[])query.Value)[3];
if (_BMI_EU_LIMIT <= 0) { _BMI_EU_LIMIT = 5; }
}
catch (Exception ex)
{
_BMI_EU_LIMIT = 5;
APILogger.Log(ex);
}
}
if (_BMI_EU_LIMIT > 0)
{
if (limitEU >= (-1 * _BMI_EU_LIMIT) && limitEU <= _BMI_EU_LIMIT)
{
return false;
}
}
return base.ShouldCheckLevelTrigger(limitEU);
}
public override int NumberOfChannels()
{
if (null == ConfigData) { return 0; }
if (null == ConfigData.Modules || 0 == ConfigData.Modules.Length) { return 0; }
var count = 0;
var streamingModuleFound = false;
foreach (var module in ConfigData.Modules)
{
if (module.IsStreamOut())
{
streamingModuleFound = true;
//when someone configured this unit streaming was supported, it's now not
//don't count the module
if (!IsStreamingSupported) { continue; }
}
count += module.NumberOfChannels();
}
//check if someone configured this unit when streaming was NOT supported and now it is
if (IsStreamingSupported && !streamingModuleFound) { count++; }
return count;
}
public override void SetIsStreamingSupported(bool supported = false)
{
if (supported)
{
//If called with True, the TSR AIR has firmware that is too old to disable streaming
IsStreamingSupported = true;
return;
}
var AttrQueryTSRAir = new QuerySystemAttribute_BridgeTSRAir(this);
AttrQueryTSRAir.DeviceID = 1; // 1-7 will work
AttrQueryTSRAir.Key = AttributeTypes.SystemAttributes_BridgeTSRAir.DISABLE_STREAMING_FEATURE;
AttrQueryTSRAir.SyncExecute();
if (string.IsNullOrWhiteSpace(AttrQueryTSRAir.Value.ToString()))
{
IsStreamingSupported = false;
return;
}
IsStreamingSupported = AttrQueryTSRAir.Value.ToString() == "0";
}
/// <summary>
/// per EF, don't measure the final offset and calculate AutoZeroDeviation on TSRAir yet
/// </summary>
/// <param name="ChannelActions"></param>
/// <param name="info"></param>
/// <param name="results"></param>
protected override void MeasureFinalOffset(IDiagnosticActions[] ChannelActions, SliceServiceAsyncInfo info, ref IDiagnosticResult[] results)
{
// verify the sample rate
var srQuery = new QueryArmAttribute(this);
srQuery.Key = AttributeTypes.ArmAndEventAttributes.DiagnosticsSampleRateHz;
srQuery.SyncExecute();
var samplerate = (double)(uint)srQuery.Value;
if (samplerate == 0)
{
throw new Exception("MeasureFinalOffset: Samplerate is 0");
}
// get the average offset
var measureOffset = new RetrieveSampleAverage(this);
measureOffset.DeviceID = 0; // send to base
var avgTimeSeconds = 1.0 / 60.0 * 2.0; // 2 * 60Hz cycles
measureOffset.Samples = (ushort)(samplerate * avgTimeSeconds);
if (measureOffset.Samples < 1) { measureOffset.Samples = 1; }
measureOffset.SyncExecute();
// store the values in arm attributes
var setSR = new SetArmAttribute(this);
setSR.SetValue(AttributeTypes.ArmAndEventAttributes.StackChannelMeasuredOffsetADC, measureOffset._data, true);
setSR.SyncExecute();
// set the calibration result
for (var idx = 0; idx < results.Length; idx++)
{
results[idx].FinalOffsetADC = measureOffset.GetChannelData(results[idx].DASChannelNumber);
if (ChannelActions[idx].RemoveOffset)
{
results[idx].AutoZeroPercentDeviation = 0;
}
else { results[idx].AutoZeroPercentDeviation = null; }
info.NewData(new ServiceCallbackData.DiagnosticNewData()
{
Result = results[idx].FinalOffsetADC,
DasChannelNumber = results[idx].DASChannelNumber,
Action = ServiceCallbackData.DiagnosticNewData.Actions.FinalOffset
});
//attempt to resolve the removed adc by using the before and after info
try
{
results[idx].RemovedOffsetADC = 0;
}
catch (Exception)
{
}
}
}
protected override bool SupportsDiagnosticsFactoryExcitation => false;
#region api protocol support
protected readonly Dictionary<DFConstantsAndEnums.ProtocolLimitedCommands, byte> TSRAIR_MinimumProtocols = new Dictionary<DFConstantsAndEnums.ProtocolLimitedCommands, byte>();
protected override bool SupportsIEPECalSignal => IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.IEPE);
private const int UDP_REALTIME_STREAM = 19;
public override void InitMinProto()
{
TSRAIR_MinimumProtocols.Clear();
// TSRAIR Protocol Limitations
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MultipleAndHybridEvents] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MultipleEvents] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AutoArm] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmRepeatEnable] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SetDefaultMIF] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.FileData] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackSensors] = TSRAIR.STACK_SENSORS;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.BaseSystemTime] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.TestCommunication] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackLowPowerMode] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SetRealtimeSampleRate] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.HardwareRevision] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.HardwareConfiguration] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.EventFaultFlags] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.EventArmAttempts] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryActualSampleRateImmediate] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.VoltageSysAttributes] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.LevelTrigger] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AttributeStoreBlocks] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryArmAndTriggerStatus_VoltageReadings] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MaxEvents] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmDiagnosticDelay] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackChannelAutoArmDiagLevel] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.FlashClear] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MultipleSamplesRealtime] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.BaseCalibrationDate] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.IgnoreShortedStartEvent] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.ResetAttributeStore] = TSRAIR.MIN_PROTOCOL_VER;
//TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.DiangosShuntDAC] = TSRAIR.VOLTAGE_INSERTION; //TODO: REMOVE THIS HACK when implemented or declared won't be
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.VoltageInsertion] = TSRAIR.VOLTAGE_INSERTION;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.PTPTimestamp] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.PTPSyncStatus] = TSRAIR.MIN_PROTOCOL_VER;
//TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StartRecDelayInSecond] = TSRAIR.START_REC_DELAY_IN_SECONDS; //TODO: REMOVE THIS HACK when implemented or declared won't be
//TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StartRealtimeStream] = TSRAIR.START_REALTIME_STREAM;//TODO: REMOVE THIS HACK when streaming is implemented
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryStackActualSampleRateImmediate] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SetClockSyncConfig] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryClockSyncStatus] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MaxEventsPossible] = 18;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AdcClockSource] = 18;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SliceBusEnabled] = 18;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.UDPRealtimeStream] = UDP_REALTIME_STREAM;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.InitHardwareInputLines] = TSRAIR.MIN_PROTOCOL_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryBatterySOC] = TSRAIR.MIN_PROTOCOL_VER;
//http://manuscript.dts.local/f/cases/29760/Implement-ACCoupleEnable-for-TSR-AIR
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackChannelBridgeACCouplerEnable] = 22;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.DisableStreamingFeature] = TSRAIR.DISABLE_STREAMING_FEATURE;
// 30430 Add Support for IRIGB, 1PPS, IRIGB + 1PPS Time Sync features for TSR AIR
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.GetUARTSettings] = TSRAIR.IRIG_GPS_PPSIN_SYNC;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SetUARTSettings] = TSRAIR.IRIG_GPS_PPSIN_SYNC;
// 30513 PTP Domain ID
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.PTPDomainID] = TSRAIR.MIN_PROTOCOL_VER;
//not currently supported
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryUARTDownload] = TSRAIR.PROTOCOL_VERSION_CIRCULAR_UART;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.ExtendedFaultIds] = TSRAIR.EXTENDED_FAULTS_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.ADCSamplesPerPacket] = TSRAIR.ADC_SAMPLES_PER_PACKET_VER;
TSRAIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.ScheduledEventCount] = TSRAIR.PROTOCOL_VERSION_SCHEDULED_EVENTCOUNT;
MinimumProtocols = TSRAIR_MinimumProtocols;
}
protected enum TSR_AIR_HW_REVISION : int
{
REV_A = 0, //Eth - COTS
REV_B = 1, //Eth - "Kitchen Sink" COTS
DIR = 2, //USB - USAF SBIR
DKR = 3, //USB - NASA SBIR
}
public override HardwareTypes GetHardwareType()
{
//we shouldn't get here. this is overridden in both USB and Ethernet for <T>
return HardwareTypes.UNDEFINED;
}
public override int[] GetStackChannelConfigTypes() => new int[] { 0 };
#endregion
#region config attributes
protected override ConfigAttributes GetConfigAttributes(DTS.Common.Interface.DASFactory.ICommunication com)
{
return new TSRAIRConfigAttributes(com);
}
/// <summary>
/// SLICE6 config attributes, mostly inherits from SLICE.ConfigAttributes with some functionality removed
/// </summary>
protected class TSRAIRConfigAttributes : SLICE6ConfigAttributes
{
public override void ConfigureCoupling(bool[] IsACCoupledArray)
{
var set = new SetArmAttribute(com, QueryArmAttribute.Default_IO_Timeout);
set.SetValue(AttributeTypes.ArmAndEventAttributes.StackChannelACCouplerEnable, IsACCoupledArray, true);
set.SyncExecute();
} //not supported in TSRAIR
public override void ConfigureBridge(byte[] bridgeModeArray) { } //not supported in TSRAIR
public override void ConfigureBridgeResistance(ushort[] BridgeResistanceArray) { } //not supported in TSRAIR
public TSRAIRConfigAttributes(ICommunication _com) : base(_com) { }
}
#endregion
#region display order
public override int GetDASDisplayOrder()
{
return -1;
}
public override void SetDASDisplayOrder(int order)
{
}
public override int[] GetChannelDisplayOrder()
{
return new[] { -1 };
}
public override void SetChannelDisplayOrder(int[] order)
{
}
#endregion
#region event info, data
/// <summary>
/// QueryEventData is customized for TSRAIR, it needs to perform TSRAIR specific data marshalling
/// </summary>
/// <returns></returns>
protected override QueryEventDataBase GetQueryEventData()
{
return new QueryEventData_TSRAIR(this, QueryEventData_TSRAIR.Default_IO_Timeout);
}
#endregion
#region get overrides
//use SLICE2 implementation for minimum SR. That's the minimum super-sampling rate
private uint _minSampleRate = uint.MinValue;
public override uint MinSampleRate()
{
//15949 S6A when streaming does a whole bunch of unnecessary queries
//avoid getting the min sample rate while streaming, it will fail
if (GetIsStreaming() || GetIsInArm())
{
_minSampleRate = 10000;
return _minSampleRate;
}
if (uint.MinValue == _minSampleRate)
{
try
{
var qsa = new QuerySystemAttributeSLICE2(this);
qsa.Key = AttributeTypes.SystemAttributesSLICE2.MinimumSampleRate;
qsa.SyncExecute();
_minSampleRate = Convert.ToUInt16(qsa.Value);
}
catch (Exception)
{
return 10000;
}
}
return _minSampleRate;
}
//use SLICE2 pattern for min for maximum SR . That's the maximum super-sampling rate
private uint _maxSampleRate = uint.MaxValue;
public override uint MaxSampleRate(int numberOfConfiguredChannels)
{
//15949 S6A when streaming does a whole bunch of unnecessary queries
//avoid getting the min sample rate while streaming, it will fail
if (GetIsStreaming() || GetIsInArm())
{
_maxSampleRate = 10000;
return _maxSampleRate;
}
if (uint.MaxValue == _maxSampleRate)
{
try
{
var qsa = new QuerySystemAttributeSLICE2(this);
qsa.Key = AttributeTypes.SystemAttributesSLICE2.MaximumSampleRate;
qsa.SyncExecute();
_maxSampleRate = Convert.ToUInt16(qsa.Value);
}
catch (Exception)
{
_maxSampleRate = 20000;
}
}
return _maxSampleRate;
}
public override uint MaxAAFilterRate()
{
return MaxAAFilterRateHz;
}
protected override uint GetEventTotalChannels(int eventNum)
{
try
{
var eventTC = new QueryEventAttribute(this);
eventTC.EventNumber = (ushort)eventNum;
eventTC.Key = AttributeTypes.ArmAndEventAttributes.TotalChannels;
eventTC.SyncExecute();
var value = Convert.ToUInt32(eventTC.Value);
return value;
}
catch (Exception ex)
{
APILogger.Log("failed to get event total channels: ", ex);
}
return (uint)MaxModules * 3;
}
#endregion
#region other overrides
//FB 25526
/// <summary>
/// the order of this DAS among multiple das
/// </summary>
public int DASIndex { get; set; } = -1;
public override bool IsTSRAIR()
{
return true;
}
public override bool IsSlice6Air()
{
return false;
}
public override bool IsScheduleEventCountSupported()
{
return ProtocolVersion >= TSRAIR.PROTOCOL_VERSION_SCHEDULED_EVENTCOUNT;
}
protected override DASModule MakeConfigModuleFromInfoModule(InfoResult.Module infoModule)
{
//per LP we can make this simpler, S6A always supports 1/2,Full,IEPE
var configModule = new DASModule(infoModule.ModuleArrayIndex, this);
configModule.Channels = new DASChannel[infoModule.NumberOfChannels];
for (var i = 0; i < infoModule.NumberOfChannels; i++)
{
if (infoModule.TypeOfModule == DFConstantsAndEnums.ModuleType.EmbeddedClockSecondsAndMarker ||
infoModule.TypeOfModule == DFConstantsAndEnums.ModuleType.EmbeddedClockNanosAndPad)
{
var channel = new TimestampDASChannel(configModule, i);
configModule.Channels[i] = channel;
}
else if (DFConstantsAndEnums.ModuleType.UART == configModule.ModuleType())
{
var uartChannel = new UARTInputDASChannel(configModule, i);
configModule.Channels[i] = uartChannel;
}
else if (DFConstantsAndEnums.ModuleType.StreamOut == configModule.ModuleType())
{
var streamOutChannel = new StreamOutputDASChannel(configModule, i);
configModule.Channels[i] = streamOutChannel;
}
else
{
var channel = new AnalogInputDASChannel(configModule, i)
{
SupportedBridges = new SensorConstants.BridgeType[]
{
SensorConstants.BridgeType.FullBridge,
SensorConstants.BridgeType.HalfBridge
}
};
configModule.Channels[i] = channel;
}
}
return configModule;
}
/// <summary>
/// returns a GetRealtimeSamples class object appropriate for the DAS
/// tsr-air has different adc math so here we are
/// </summary>
/// <param name="iCommunication"></param>
/// <param name="bPolling">whether realtime is polling for samples or not</param>
/// <returns></returns>
protected override IGetRealtimeSamples GetRealtimeSamplesClass(DTS.Common.Interface.DASFactory.ICommunication iCommunication, bool bPolling = false)
{
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.StartRealtimeStream) && !bPolling)
{
return new RealtimeStreamingNextSamples(iCommunication);
}
return new GetRealtimeSamplesTSRAIR(iCommunication);
}
protected override float GetLevelTriggerThreshold(AnalogInputDASChannel analog, IDiagnosticResult diagnostics, double thresholdeu, double MvPerEu)
{
//I have modified this to be modeled after DataScaler and how it gets EU, it's a bit different than before ...
var dataZeroLevelADC = diagnostics.GetExpectedDataZeroLevelADC(analog.ZeroMethod);
var initialOffsetmVInADC = 0D;
//var io = new InitialOffset();
//io.FromDbSerializeString(analog.InitialOffset);
//if (io.Form == InitialOffsetTypes.EUAtMV)
//{
// initialOffsetmVInADC = io.MV / diagnostics.ScalefactorMilliVoltsPerADC;
//}
MvPerEu = analog.SensitivityMilliVoltsPerEU;
var adcToEUScalingFactor = (diagnostics.ScalefactorMilliVoltsPerADC / (analog.IsProportionalToExcitation
? analog.SensitivityMilliVoltsPerEU * analog.FactoryExcitationVolts : MvPerEu))
* (analog.AtCapacity ? analog.CapacityOutputIsBasedOn : 1.0)
* (analog.IsInverted ? -1.0 : 1.0);
var negativeSensitivity = analog.SensitivityMilliVoltsPerEU < 0;
var negativePolarity = analog.IsInverted;
var eu = 0D;
var adc = 0D;
var mV = 0D;
//16272 3.1 LevelTrigger issues
//there must be some double negative occurring in this case that doesn't occur in others?
if (negativeSensitivity && !negativePolarity)
{
eu = -1D * thresholdeu - analog.InitialEU - dataZeroLevelADC * (double)adcToEUScalingFactor +
initialOffsetmVInADC * (double)adcToEUScalingFactor;
adc = eu / (double)adcToEUScalingFactor;
mV = adc * diagnostics.ScalefactorMilliVoltsPerADC;
}
else
{
eu = thresholdeu - analog.InitialEU + dataZeroLevelADC * (double)adcToEUScalingFactor +
initialOffsetmVInADC * (double)adcToEUScalingFactor;
adc = eu / (double)adcToEUScalingFactor;
mV = adc * diagnostics.ScalefactorMilliVoltsPerADC;
}
var sb = new StringBuilder();
sb.AppendFormat("{0} {1} {2}:{3}\r\n", DateTime.Now.ToShortDateString(), DateTime.Now.ToShortTimeString(), SerialNumber, analog.Number);
sb.AppendFormat("DataZeroLevelADC={0}", dataZeroLevelADC);
sb.AppendFormat("ScaleFactormVPerADC={0}\r\n", diagnostics.ScalefactorMilliVoltsPerADC);
sb.AppendFormat("MvPerEU={0}\r\n", MvPerEu);
sb.AppendFormat("adcToEUScalingFactor = {0}\r\n", adcToEUScalingFactor);
sb.AppendFormat("eu={0}\r\n", eu);
sb.AppendFormat("ZeroMVINADC={0}", diagnostics.ZeroMVInADC);
sb.AppendFormat("adc={0}\r\n", adc);
sb.AppendFormat("mv={0}\r\n", mV);
//////////LevelTriggerLogging.LevelTriggerLog(sb.ToString());
//return Convert.ToSingle(mV);
return Convert.ToSingle(eu);
}
protected override ushort? GetMaxEvents()
{
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.MaxEventsPossible))
{
try
{
QuerySystemAttribute qsa = new QuerySystemAttribute(this, 1000);
qsa.DeviceID = 0;
qsa.Key = AttributeTypes.SystemAttributes.MaxEventsPossible;
qsa.SyncExecute();
return ((ushort[])qsa.Value)[1];
}
catch (Exception ex)
{
APILogger.Log("Exception getting max number of events", ex);
}
}
return null;
}
/// <summary>
/// sets the max number of events to record
/// see http://dtsinfo/dtswiki/index.php/TSR_AIR_Production_Attribute_Settings
/// and http://manuscript.dts.local/f/cases/30431/Check-trigger-runs-more-times-than-necessary
/// </summary>
/// <param name="numEvents"></param>
protected override void SetMaxEvents(int numEvents)
{
try
{
var ssa3 = new SetSystemAttribute(this);
ssa3.DeviceID = 0;
ssa3.SetValue(AttributeTypes.SystemAttributes.MaxEventsPossible, new[] { (ushort)0, (ushort)numEvents }, true);
ssa3.SyncExecute();
}
catch (Exception ex)
{
APILogger.Log("Exception setting max number of events", ex);
}
}
protected override void CommonRangeWork(AnalogInputDASChannel analog,
bool bModified, float[] rangeArray, byte dasChannelNumber, double MvPerEU,
IDASModule module)
{
//29759 Allow Adjustable Channel Ranges in Parameters for TSR AIR
if (SensorConstants.IsTSRAirLowGChannel(module.SerialNumber()))
{
rangeArray[dasChannelNumber] = SensorConstants.LowG64;
}
else if (SensorConstants.IsTSRAirHighGChannel(module.SerialNumber()))
{
rangeArray[dasChannelNumber] = (float)SensorConstants.DefaultRangeHiG;
}
else if (SensorConstants.IsTSRAirARSChannel(module.SerialNumber()))
{
rangeArray[dasChannelNumber] = SensorConstants.ARS2000;
}
else
{
rangeArray[dasChannelNumber] = 0;
}
}
/// <summary>
/// writes a TMATs file to pc and TSR AIR
/// </summary>
private void WriteTmtFile(string serialNumber, IInfoResult dasInfo, IConfigurationData configData, IDiagnosticResult[] channelDiagnostics,
ushort? dataChannelId, ushort? timeChannelId, int dasIndex, float[] scaleFactors,
float[] ranges, float[] measuredOffsets)
{
var lines = new List<string>();
var outMod = Array.Find(ConfigData.Modules, m => m.ModuleType() == DFConstantsAndEnums.ModuleType.StreamOut);
GetTMATTemplates(outMod, out var dasTemplate, out var chTemplate);
lines.AddRange(WriteDASPortion(dasTemplate, configData, serialNumber, dataChannelId, timeChannelId, null, dasIndex));
//now for modules we need to subtract any UART or stream modules, which are each 1 channel modules
var modules = ConfigData.Modules.Where(x => x.NumberOfChannels() > 1);
var channelIndex = 0;
foreach (var module in modules)
{
foreach (var ch in module.Channels)
{
var chPortion = WriteChannelPortion(chTemplate, channelIndex, ranges, scaleFactors, measuredOffsets);
if (null != chPortion)
{
lines.AddRange(chPortion);
}
channelIndex++;
}
}
TmtFile.WriteTMTFile(this, lines.ToArray(), ((IConfiguration)this).TestDirectory);
}
/// <summary>
/// returns all the strings for TMATS file for a given channel
/// </summary>
private string [] WriteChannelPortion(string chTemplatePath, int channelIndex,
float [] ranges, float [] scaleFactors, float [] measuredOffset)
{
var tmtFile = new TmtSingleFile(chTemplatePath);
var keys = Enum.GetValues(typeof(TMTChannelKeysEx)).Cast<TMTChannelKeysEx>().ToArray();
var moduleArrayIndex = DASInfo.MapDASChannelNumber2ModuleArrayIndex(channelIndex);
var moduleChannelIndex = DASInfo.MapDASChannelNumber2ModuleChannelNumber(channelIndex);
var aidc = ConfigData.Modules[moduleArrayIndex].Channels[moduleChannelIndex] as AnalogInputDASChannel;
var diagnosticResult =
(from dr in ChannelDiagnosticsResults where dr.DASChannelNumber == channelIndex select dr)
.FirstOrDefault();
DataScaler scaler = aidc?.GetDataScaler()??null;
if (null == scaler)
{
scaler = new DataScaler();
scaler.SetScaleFactorMv(.1D);
scaler.ProportionalToExcitation = false;
if (channelIndex < scaleFactors.Length)
{
scaleFactors[channelIndex] = .1F;
}
}
var tempEU = scaler.GetEU(short.MinValue);
var tempEU2 = scaler.GetEU(short.MaxValue);
var minEU = Math.Min(tempEU, tempEU2);
var maxEU = Math.Max(tempEU, tempEU2);
var offsetEU = null == aidc?"0":TmtFile.GetOffsetEUString(aidc, scaler, measuredOffset, channelIndex, diagnosticResult);
foreach (var key in keys)
{
TmtSingleFile.UpdateChannelField(key, tmtFile, channelIndex, ranges, minEU, maxEU, aidc?.EngineeringUnits ?? GetEngineeringUnits(channelIndex), scaleFactors,
scaler.GetAdcToEuScalingFactor(), aidc?.ChannelName2 ?? GetChannelName(channelIndex), offsetEU, true);
}
return tmtFile.GetAllLines();
}
private static string GetEngineeringUnits(int chIdx)
{
switch (chIdx)
{
case 12: return "s";
case 13: return "s";
case 14: return "marker";
case 15: return "s";
case 16: return "ns";
case 17: return "trigger";
default: return "---";
}
}
private static string GetChannelName(int chIdx)
{
switch(chIdx)
{
case 12: return "SEC_L";
case 13: return "SEC_H";
case 14: return "MARKER";
case 15: return "NSEC_L";
case 16: return "NSEC_H";
case 17: return "TRIGGER";
default: return "---";
}
}
/// <summary>
/// returns all lines for the DAS portion of the TMATS file
/// </summary>
private string [] WriteDASPortion(string dasTemplatePath, IConfigurationData configData,
string serialNumber, ushort? dataChannelId, ushort? timeChannelId, ushort? uartChannelId, int dasIndex)
{
var tmtFile = new TmtSingleFile(dasTemplatePath);
var globalKeys = Enum.GetValues(typeof(TMTGlobalKeys)).Cast<TMTGlobalKeys>().ToArray();
var modules = configData.Modules.Where(x => x.NumberOfChannels() > 1);
var channelCount = modules.Sum(x => x.NumberOfChannels());
var bitsPerFrame = 32 + 16 * channelCount;
foreach( var key in globalKeys)
{
TmtSingleFile.UpdateGlobalField(this, key, tmtFile, configData,
serialNumber, timeChannelId, dataChannelId, uartChannelId, dasIndex, bitsPerFrame);
}
return tmtFile.GetAllLines();
}
/// <summary>
/// retrieves path to DAS template file, and channel template file
/// </summary>
private void GetTMATTemplates(IDASModule module, out string dasTemplate, out string chTemplate)
{
switch(module.StreamProfile)
{
case UDPStreamProfile.CH10_ANALOG:
case UDPStreamProfile.CH10_ANALOG_2HDR:
{
dasTemplate = "TMTTemplates/TSRAIRTMTTemplate_ANALOG_DAS.TMT";
chTemplate = "TMTTemplates/TSRAIRTMTTemplate_ANALOG_CHANNEL.TMT";
}
break;
default:
{
dasTemplate = "TMTTemplates/TSRAIRTMTTemplate_PCM_DAS.tmt";
chTemplate = "TMTTemplates/TSRAIRTMTTemplate_PCM_CHANNEL.tmt";
}
break;
}
}
/// <summary>
/// 19: Support UDPRealtimeStream Protocols
/// </summary>
protected override int MIN_PROTOCOL_TMATS_INTERVAL => 19;
protected override void ConfigureTMATS(SliceConfigServiceAsyncInfo info,
float[] scaleFactors, float[] ranges, float[] measuredOffset)
{
//FB 25526 Implement TMATS support for TSR AIR stream on boot
if (ShouldWriteStreamInfo() && null != ChannelDiagnosticsResults && ChannelDiagnosticsResults.Any())
{
try
{
ushort? dataChannelId = null;
ushort? timeChannelId = null;
ushort? uartChannelId = null;
if (info.DataChannelIds.ContainsKey(this)) { dataChannelId = info.DataChannelIds[this]; }
if (info.TimeChannelIds.ContainsKey(this)) { timeChannelId = info.TimeChannelIds[this]; }
//FB 43761
//FB 30035 Decide the context based on profile type
WriteTmtFile(SerialNumber, DASInfo, ConfigData, ChannelDiagnosticsResults, dataChannelId, timeChannelId, DASIndex, scaleFactors, ranges, measuredOffset);
}
catch (Exception ex)
{
var eventAggregator = ContainerLocator.Container.Resolve<IEventAggregator>();
var msg = $"Failed to write TMATs file for: {SerialNumber}\r\n{ex.Message}";
eventAggregator.GetEvent<PageErrorEvent>().Publish(new PageErrorArg(new[]{msg}, null));
throw new Exception(ex.Message, ex);
}
SetTMATSInterval(info.TMATSIntervalMs);
}
}
/// <summary>
/// tsr air only uses ch 3-5 for level trigger, so remap anything on 0-2 to 3-5 if set
/// </summary>
/// <param name="index1"></param>
/// <param name="index2"></param>
/// <param name="enable"></param>
/// <param name="dValue"></param>
private void CheckLevelTrigger(int index1, int index2, bool [] enable, float [] dValue)
{
if (enable[index1])
{
enable[index1] = false;
enable[index2] = true;
dValue[index2] = dValue[index1];
dValue[index1] = 0;
}
}
private void RemapLevelTriggers(bool []enableUpperLevelTriggerThreshold, float [] upperLevelTriggerThreshold)
{
CheckLevelTrigger(0, 3, enableUpperLevelTriggerThreshold, upperLevelTriggerThreshold);
CheckLevelTrigger(1, 4, enableUpperLevelTriggerThreshold, upperLevelTriggerThreshold);
CheckLevelTrigger(2, 5, enableUpperLevelTriggerThreshold, upperLevelTriggerThreshold);
}
private void AdjustMultipleEventRecordingModeIfNeeded()
{
if (null == ConfigData) { return; }
foreach (var mod in ConfigData.Modules)
{
if (mod.RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBufferPlusUART) { mod.RecordingMode = DFConstantsAndEnums.RecordingMode.AutoCircularBufferPlusUART; }
if (mod.RecordingMode == DFConstantsAndEnums.RecordingMode.RecorderModePlusUART) { mod.RecordingMode = DFConstantsAndEnums.RecordingMode.AutoRecorderModePlusUART; }
}
}
/// <summary>
/// tsr-air won't have as many things to sort out
/// it's mostly a shortening of SLICE1.AsyncConfigure
/// </summary>
/// <param name="configAsyncInfo"></param>
protected override void AsyncConfigure(object configAsyncInfo)
{
var info = configAsyncInfo as SliceConfigServiceAsyncInfo;
SetUDPAlignOnPPS();
if ((info.StreamADCPerPacket != null) && info.StreamADCPerPacket.ContainsKey(this))
{
SetADCSamplesPerPacket(info.StreamADCPerPacket[this]);
}
AdjustMultipleEventRecordingModeIfNeeded();
IncrementNumberOfTimesWritten();
//12638 DAS does not record data in recorder mode during calibration ~ 40% of time.
//for SLICE6 we call reseteventlist here, prior to configuring and NOT before arming
ResetEventListPriorToConfigure();
int progressValue = 0;
bool bReleased = true;
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.ProgramStackChannels)) { ReconfigureAccordingToConfig(); }
PresetSampleRate();
// these should be the voltage requirements for TSRAIR
InputLowVoltage = 4f;
InputHighVoltage = 35f;
BatteryLowVoltage = 2f;
BatteryHighVoltage = 4.5f;
SetVoltageRequirements();
SetPolarity();
SetArmDisableShortCheck();
try
{
Lock();
bReleased = false;
// loop thru the modules (slices) and configure the channels
var numChannels = DASInfo.Modules.Sum(mod => mod.NumberOfChannels);
var numUartChannels = DASInfo.Modules.Sum(mod => DFConstantsAndEnums.ModuleType.UART == mod.TypeOfModule ? mod.NumberOfChannels : 0);
var numStreamingChannels = DASInfo.Modules.Sum(mod => DFConstantsAndEnums.ModuleType.StreamOut == mod.TypeOfModule ? mod.NumberOfChannels : 0);
var rangeArray = new float[numChannels];
var maxEventsPossible = new UInt16[2];
var activityThresholdInmGInactivityTimeoutInSec = new UInt16[2];
var bridgeModeArray = new byte[numChannels];
var BridgeResistanceArray = new ushort[numChannels];
var IsACCoupledArray = new bool[numChannels];
// level trigger values
var enableLowerLevelTriggerThreshold = new bool[numChannels];
var enableUpperLevelTriggerThreshold = new bool[numChannels];
var lowerLevelTriggerThreshold = new float[numChannels];
var upperLevelTriggerThreshold = new float[numChannels];
var qualificationSamples = new int[numChannels];
var diagnosticChannels = new List<byte>();
var bModified = false;
var bridgeACCouplingArray = new bool[numChannels];
CommonConfigureWork(diagnosticChannels, qualificationSamples, ref bReleased,
info, bridgeModeArray, IsACCoupledArray, BridgeResistanceArray,
ref bModified, rangeArray, enableUpperLevelTriggerThreshold, upperLevelTriggerThreshold,
enableLowerLevelTriggerThreshold, lowerLevelTriggerThreshold, bridgeACCouplingArray);
//http://manuscript.dts.local/f/cases/30428/Implement-Low-G-Triggering-for-TSR-AIR
//level triggers are always 3-5 for TSR AIR, so remap if needed
RemapLevelTriggers(enableUpperLevelTriggerThreshold, upperLevelTriggerThreshold);
if (bReleased) { return; }
// report progress
progressValue = 5;
info.Progress(progressValue);
var config = GetConfigAttributes(this);
// only set attributes to default if we haven't run diagnostics yet
if (!DiagnosticsHasBeenRun)
{
config.PurgeStaleData(this);
}
//FB 25526 make these arrays so we can populate them later
float[] scaleFactors = null;
float[] ranges = null;
float[] measuredOffset = null;
// store some attributes
if (ConfigData.Modules.Length > 0)
{
config.SampleRate = ConfigData.Modules[0].SampleRateHz;
var actualSampleRate = (float)ConfigData.Modules[0].SampleRateHz;
config.AAFilter = ConfigData.Modules[0].AAFilterRateHz;
config.TestID = ConfigData.TestID.TrimEnd('\0');
config.TestSetupUniqueId = ConfigData.TestSetupUniqueId?.TrimEnd('\0');
config.InstanceID = ConfigData.InstanceID?.TrimEnd('\0');
config.TestDescription = ConfigData.Description;
config.PreTriggerSamples = (ulong)(ConfigData.Modules[0].PreTriggerSeconds * actualSampleRate);
config.PostTriggerSamples = (ulong)(ConfigData.Modules[0].PostTriggerSeconds * actualSampleRate);
//Set MaxEventsPossible
try
{
var setMaxEventsPossible = new SetSystemAttribute(this);
setMaxEventsPossible.DeviceID = 0;
var numberOfEvents = Convert.ToUInt16(ConfigData.Modules[0].NumberOfEvents);
maxEventsPossible[0] = 0;
maxEventsPossible[1] = numberOfEvents;
setMaxEventsPossible.SetValue(AttributeTypes.SystemAttributes.MaxEventsPossible, maxEventsPossible, true);
setMaxEventsPossible.SyncExecute();
}
catch (Exception ex)
{
APILogger.Log(ex.Message);
var errorString = "Error attempting to set MaxEventsPossible to ";
foreach (var element in maxEventsPossible)
{
errorString += element;
errorString += ", ";
}
errorString = errorString.Remove(errorString.Length - 2, 2);
APILogger.Log(errorString);
if (!bReleased) { bReleased = true; Release(); }
info.Error(string.Format(errorString));
return;
}
//Set WakeUpMotionTimeout (Motion detect inactivity (sec)/ActivityThresholdInmGInactivityTimeoutInSec)
try
{
var setWakeUpMotionTimeout = new SetArmAttribute(this);
var inactivityTimeoutInSec = Convert.ToUInt16(ConfigData.Modules[0].WakeUpMotionTimeout);
activityThresholdInmGInactivityTimeoutInSec[0] = 350;
activityThresholdInmGInactivityTimeoutInSec[1] = inactivityTimeoutInSec;
setWakeUpMotionTimeout.SetValue(AttributeTypes.ArmAndEventAttributes.ActivityThresholdInmGInactivityTimeoutInSec, activityThresholdInmGInactivityTimeoutInSec, true);
setWakeUpMotionTimeout.SyncExecute();
}
catch (Exception ex)
{
APILogger.Log(ex.Message);
var errorString = "Error attempting to set ActivityThresholdInmGInactivityTimeoutInSec to ";
foreach (var element in activityThresholdInmGInactivityTimeoutInSec)
{
errorString += element;
errorString += ", ";
}
errorString = errorString.Remove(errorString.Length - 2, 2);
APILogger.Log(errorString);
if (!bReleased) { bReleased = true; Release(); }
info.Error(string.Format(errorString));
return;
}
if (ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.Scheduled ||
ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.Interval)
{
config.ScheduledStartTime = ConfigData.Modules[0].ScheduledStartTime;
config.RecordingInterval = ConfigData.Modules[0].RecordingInterval;
}
SetArmMode(ConfigData.Modules[0].RecordingMode);
try
{
//29759 Allow Adjustable Channel Ranges in Parameters for TSR AIR
config.ConfigureRange(rangeArray);
progressValue = 10;
info.Progress(progressValue);
}
catch (Exception ex)
{
var errorString = "Error attempting to set range to ";
foreach (var range in rangeArray)
{
errorString += range;
errorString += ", ";
}
errorString = errorString.Remove(errorString.Length - 2, 2);
if (ex.Message.Contains("StatusSetupRequestedSensorRangeTooSmall"))
{
APILogger.Log("Ignoring: " + errorString, ex);
}
else
{
APILogger.Log("Aborting: errorString", ex);
if (!bReleased) { bReleased = true; Release(); }
info.Error(string.Format(errorString));
return;
}
}
config.ConfigureBridge(bridgeModeArray);
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.StackChannelBridgeACCouplerEnable))
{
config.ConfigureCoupling(IsACCoupledArray);
}
config.ConfigureBridgeResistance(BridgeResistanceArray);
// configure level trigger enable/threshold values
try
{
ConfigureLevelTriggers(enableLowerLevelTriggerThreshold,
enableUpperLevelTriggerThreshold,
lowerLevelTriggerThreshold,
upperLevelTriggerThreshold,
qualificationSamples);
}
catch (Exception ex) { APILogger.Log("Problem setting level triggers", ex); }
//FB 25526 query and populate these threee arrays for TSR AIR to be used in TMT template for TSR AIR
// query scale factors
scaleFactors = config.GetScaleFactors();
// query ranges
ranges = config.GetRanges();
//query offsets
measuredOffset = config.GetMeasuredOffset();
if (numChannels > scaleFactors.Length + numUartChannels + numStreamingChannels)
{
if (!bReleased) { bReleased = true; Release(); }
// "ConfigurationService.Configure: Firmware returned {0} channels but stack contains {1}"
info.Error(string.Format("Firmware returned {0} channels but stack contains {1}", scaleFactors.Length, numChannels - numUartChannels - numStreamingChannels));
return;
}
for (var moduleIdx = 0; moduleIdx < ConfigData.Modules.Length; moduleIdx++)
{
if (DFConstantsAndEnums.ModuleType.UART == ConfigData.Modules[moduleIdx].ModuleType()) continue; //only configuring the analogs
if (DFConstantsAndEnums.ModuleType.StreamOut == ConfigData.Modules[moduleIdx].ModuleType()) { continue; }
for (var channelIdx = 0;
channelIdx < ConfigData.Modules[moduleIdx].Channels.Length;
channelIdx++)
{
var dasChannelNumber = DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(moduleIdx, channelIdx);
if (ConfigData.Modules[moduleIdx].Channels[channelIdx] is AnalogInputDASChannel analog)
{
analog.ScalefactorMilliVoltsPerADC = -1;
analog.ScalefactorEngineeringUnitsPerADC = scaleFactors[dasChannelNumber];
}
}
progressValue++;
info.Progress(Math.Min(19, progressValue));
}
}
progressValue = 20;
info.Progress(progressValue);
SetStreamingRealtimeSampleRate(info);
RemainingConfigWork(ref progressValue, info, diagnosticChannels, config, ref bReleased,
scaleFactors, ranges, measuredOffset);
}
catch (CanceledException)
{
if (!bReleased) { bReleased = true; Release(); }
info.Cancel();
}
catch (Exception ex)
{
if (!bReleased) { bReleased = true; Release(); }
info.Error(ex.Message, ex);
}
finally { if (!bReleased) { bReleased = true; Release(); } }
info.Progress(100);
info.Success();
}
private const double CHARGING_VOLTAGE = 8D;
public override string ConvertInputVoltage2BatteryCharging(double inputVoltage)
{
//per CPB in 31780 TSR-Air-Charging-Status-incorrect-in-DataPro-when-using-the-5V-to-9V-charger
//anything over 8V is charging ...
return inputVoltage >= CHARGING_VOLTAGE ? Resources.Charging : Resources.NotCharging;
}
protected override void ConfigureLevelTriggers(bool[] enableLowerTrigger,
bool[] enableUpperTrigger,
float[] lowerTriggerThreshold,
float[] upperTriggerThreshold,
int[] qualificationSamples)
{
try
{
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.LevelTrigger))
{
//TSR AIRs only need the following two attributes to be set
var set = new SetArmAttribute(this);
set.SetValue(AttributeTypes.ArmAndEventAttributes.LevelTriggerChannelGreaterThanEnabled, enableUpperTrigger, true);
set.SyncExecute();
set = new SetArmAttribute(this);
set.SetValue(AttributeTypes.ArmAndEventAttributes.LevelTriggerGreaterThanLimit, upperTriggerThreshold, true);
set.SyncExecute();
SetLevelTriggerQualificationSamples(qualificationSamples);
}
}
catch (Exception ex)
{
throw new ApplicationException("encountered problem configuring level triggers", ex);
}
}
protected virtual void AsyncQueryConfiguration(object configAsyncInfo)
{
var info = configAsyncInfo as SliceServiceAsyncInfo;
var displayOrder = new int[] { -1 };
var dasDisplayOrder = -1;
try { dasDisplayOrder = GetDASDisplayOrder(); }
catch (Exception ex) { APILogger.Log("Failed to query user attributes", ex); }
info.Progress(10);
try { displayOrder = GetChannelDisplayOrder(); }
catch (Exception ex) { APILogger.Log("Failed to query user attributes", ex); }
info.Progress(20);
try
{
// pickup the channel data
var config = GetConfigAttributes(this);//new ConfigAttributes(this);
try
{
var StoredInfoString = config.RetrieveXMLConfig(ConfigAttributes.FileStore.Diagnostic, this);
ConfigData = ConfigurationData.DeserializeFromString(StoredInfoString);
info.Progress(50);
if (!VerifyConfig()) { ConfigData = null; }
if (ConfigData == null || ConfigData.Modules == null || ConfigData.Modules.Length == 0)
{
APILogger.LogString("QueryConfiguration: ConfigData or Modules empty, using default config");
ConfigData = MakeDefaultConfigFromInfo();
}
else if (DASInfo == null || DASInfo.Modules == null || DASInfo.Modules.Length != ConfigData.Modules.Length)
{
APILogger.LogString("QueryConfiguration: DASInfo or Modules empty, using default config");
ConfigData = MakeDefaultConfigFromInfo();
}
else
{
for (var i = 0; i < ConfigData.Modules.Length && i < DASInfo.Modules.Length; i++)
{
var bIEPE = false;
switch (DASInfo.Modules[i].TypeOfModule)
{
case DFConstantsAndEnums.ModuleType.SLICEIEPE:
bIEPE = true;
break;
}
foreach (var channel in ConfigData.Modules[i].Channels)
{
if (bIEPE)
{
((AnalogInputDASChannel)channel).SupportedBridges = new[] { SensorConstants.BridgeType.IEPE };
}
else
{
((AnalogInputDASChannel)channel).SupportedBridges = new[]{
SensorConstants.BridgeType.FullBridge, SensorConstants.BridgeType.HalfBridge};
}
}
}
}
info.Progress(60);
}
catch (CanceledException)
{
// cancel must be propagated
throw;
}
catch (NotConnectedException)
{
info.Error(string.Format("Connection with {0} failed", SerialNumber));
return;
}
catch (System.Net.Sockets.SocketException socketException)
{
APILogger.LogString("QueryConfiguration: RetrieveXMLConfig threw exception");
APILogger.LogException(socketException);
info.Error($"Connection with {SerialNumber} failed");
return;
}
catch (Exception ex)
{
APILogger.LogString("QueryConfiguration: RetrieveXMLConfig threw exception");
APILogger.LogException(ex);
if (ex.Message.Contains("ReceiveFailed"))
{
info.Error($"Connection with {SerialNumber} failed");
return;
}
// something happend that prevents us from getting the stored config, make a default
ConfigData = MakeDefaultConfigFromInfo();
}
if (null != ConfigData) { ConfigData.DisplayOrder = displayOrder; ConfigData.DasDisplayOrder = dasDisplayOrder; }
// get scale factors
try
{
var scaleFactors = GetScaleFactors();
#if LEVEL_TRIGGER_DEFINED
// These are currently unutilized since we have no application for the offset-adjusted
// level trigger values outside of the Slice firmware.
//
// var levelTriggers = GetLevelTriggers( );
#endif
info.Progress(70);
// set the OwningDAS and OwningModule since it was skipped during serialization
foreach (var iDASModule in ConfigData.Modules)
{
var module = (DASModule)iDASModule;
module.SampleRateHz = Convert.ToUInt32(config.ActualSampleRate);
module.OwningDAS = this;
foreach (var iDASChannel in module.Channels)
{
var channel = (DASChannel)iDASChannel;
channel.OwningModule = module;
// pick up the scalefactor for this channel
if (channel is AnalogInputDASChannel analog)
{
var dasChannelNumber = analog.Number;
if (dasChannelNumber < scaleFactors.Length)
{
analog.ScalefactorEngineeringUnitsPerADC = scaleFactors[dasChannelNumber];
analog.ScalefactorMilliVoltsPerADC = -1;
}
}
}
}
info.Progress(80);
}
catch (System.Net.Sockets.SocketException socketException)
{
APILogger.LogString("QueryConfiguration: RetrieveXMLConfig threw exception");
APILogger.LogException(socketException);
info.Error(string.Format("Connection with {0} failed", SerialNumber));
return;
}
catch (NotConnectedException) { info.Error($"Connection with {SerialNumber} failed"); return; }
catch (CanceledException)
{
// cancel must be propagated
throw;
}
catch (Exception ex)
{
APILogger.LogString("QueryConfiguration: GetScaleFactors threw exception");
APILogger.LogException(ex);
// we don't need no stinking scale factors
}
// get sensor ID's
if (ConfigData.Modules != null)
{
foreach (var iDASModule in ConfigData.Modules)
{
var module = (DASModule)iDASModule;
module.OwningDAS = this; // in case we bailed out above
foreach (var iDASchannel in module.Channels)
{
var channel = (DASChannel)iDASchannel;
channel.OwningModule = module; // in case bailed out above
var dasChannelNumber = DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(module.ModuleArrayIndex, channel.ModuleChannelNumber);
channel.IDs = EIDReader.RetriveEIDs(this, dasChannelNumber, 0);
}
IEID[] ids = null;
//performance improvement, skip getting battery ids if you don't need too
if (ShouldCheckForBatteryIds())
{
ids = EIDReader.RetriveEIDs(this, 255, 0);
}
else
{
ids = null;
}
if (null != ids && 0 != ids.Length)
{
module.OwningDAS.DASInfo.BatteryID = ids[0];
module.OwningDAS.SetDASInfo();
}
}
}
info.Progress(90);
RetrieveEventGuids();
DASInfo.MaxEventStorageSpaceInBytes = ReadSampleStorageSizeInBytes();
info.Progress(95);
GetAutoArmStatus();
info.Success();
}
catch (System.Net.Sockets.SocketException socketException)
{
APILogger.LogString("QueryConfiguration: RetrieveXMLConfig threw exception");
APILogger.LogException(socketException);
info.Error(string.Format("Connection with {0} failed", SerialNumber));
return;
}
catch (NotConnectedException) { info.Error($"Connection with {SerialNumber} failed"); return; }
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
protected override void AsyncPrepareForArmNow(object asyncInfo)
{
base.AsyncPrepareForArmNow(asyncInfo);
if (!(asyncInfo is ArmPacket info)) { return; }
}
/// <summary>
/// returns true if the device is known to be streaming
/// does not query device, just returns a flag if it has been set
/// </summary>
public override bool GetIsStreaming()
{
if (null == DASArmStatus) { return false; }
//18852 Cannot use Stop streaming / (Dis)Auto Arm button if one or more DAS is idle
//can't rely on just having received invalid mode, QATS will still have a status of realtime
//when streaming, so we'll use either for now.
return DASArmStatus.ReceivedInvalidModeDuringSetup || DASArmStatus.IsInRealtime;
}
private DownloadReport.UARTEventInfo GetUARTEventInfo(ushort eventNumber,
bool dataPresent = false, bool dataDownloaded = false, ulong totalByteCount = 0, ulong triggerByteCount = 0,
ulong startTimeStamp = 0, ulong endTimestamp = 0, uint buadRate = 0)
{
var uartEventInfo = new DownloadReport.UARTEventInfo()
{
EventNumber = eventNumber,
DataPresent = dataPresent,
DataDownloaded = dataDownloaded,
TotalByteCount = totalByteCount,
TriggerByteCount = triggerByteCount,
StartTimestamp = startTimeStamp,
EndTimestamp = endTimestamp,
BaudRate = buadRate
};
return uartEventInfo;
}
protected override uint[] GetExtendedFaultFlags(int eventIndex)
{
if ( !IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.ExtendedFaultIds))
{
return new uint[] { 0, 0, 0, 0 };
}
return base.GetExtendedFaultFlags(eventIndex);
}
protected override void AsyncQueryDownload(object asyncInfo)
{
var info = asyncInfo as QueryDownloadAsyncInfo;
// since we don't know exact how many XML attributes, modules or channels that's in the
// configuration, we guess on the high end.
// (44 per stored config + 4 + 3 per module + 3 per channel) * number of events
// equals 44 + 4 + 30 + 90 = 168 per event
const int StepsPerEvent = 168;
try
{
if (info.EventIndex < 0) { RetrieveDASBootCount(); }
else { TurnOffDiagnosticsMode(); }
var qsa = new QuerySystemAttribute(this);
qsa.Key = AttributeTypes.SystemAttributes.TotalEventsStored;
qsa.SyncExecute();
ushort eventCount = (ushort)qsa.Value;
var config = GetConfigAttributes(this);//new ConfigAttributes(this);
// 6 * modules + 44
var progress = new QueryDownloadProgress(info, StepsPerEvent * eventCount, 1);
// we'll also freshen up the cached event GUIDs
// NOT IF WE ARE QUERYING A SPECIFIC GUID
var eventGuids = new Guid[eventCount];
var faultFlags = new ushort[eventCount];
var faultFlagsEx = new ushort[eventCount];
var armAttempts = new byte[eventCount];
var extendedFaultIds = new List<uint[]>();
var dlReport = new DownloadReport();
if (this is IUARTDownload && 0 > info.EventIndex)
{
dlReport.UARTEvents = new DownloadReport.UARTEventInfo[eventCount];
for (var eventIdx = 0; eventIdx < eventCount; eventIdx++)
{
if (info.EventIndex >= 0 && eventIdx != info.EventIndex) { continue; }
extendedFaultIds.Add(GetExtendedFaultFlags(eventIdx));
if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryUARTDownload))
{
var uartInfo = GetUARTEventInfo((ushort)eventIdx);
if (0 > info.EventIndex)
{
dlReport.UARTEvents[eventIdx] = uartInfo;
}
else
{
EventInfo.UARTEvents[eventIdx] = uartInfo;
}
continue;
}
else
{
QueryUartEventInfo(eventIdx, info, dlReport);
}
}
}
if (0 > info.EventIndex)
{
dlReport.Events = new DownloadReport.EventInfo[eventCount];
}
// Retrieved the stored configuration
//this is not a new xml for each event, lets just get it once!
var storedConfigStr = config.RetrieveEventXMLConfig(0, progress, this); // I/O * n
// convert it from XML to object
var eventInfo = new DownloadReport.EventInfo();
var eventDesc = eventInfo.Description = config.GetEventDescription(0); // I/O
var testId = config.GetEventID(0, this).TrimEnd(new char[] { '\0' }); ; // I/O
var eventGuid = GetEventGuid(0);
//scale factors for TSR AIR shouldn't change between events ...
var factors = config.GetEventScaleFactors(0);
var actualSampleRate = config.GetEventSamplerate(0);
var stackActualSampleRate = config.GetEventStackSamplerate(0);
var aafilter = config.GetEventAAFilter(0);
var numberOfChannels = GetEventTotalChannels(0); // I/O
for (var eventIdx = 0; eventIdx < eventCount; eventIdx++)
{
var storedConfig = ConfigurationData.DeserializeFromString(storedConfigStr);
if (info.EventIndex >= 0 && eventIdx != info.EventIndex) { continue; }
GetEventTimeStampInfo(eventIdx, out var startRecordTimestampSec, out var triggerTimestampSec, out var startRecordTimestampNanoSec,
out var triggerTimestampNanoSec, out var pTPMasterSync);
// the object to store it all in
eventInfo = new DownloadReport.EventInfo();
eventInfo.Description = eventDesc;
// get the event level values
try
{
if (null != ConfigData) { eventInfo.Description = ConfigData.Description; }
}
catch (Exception) { }
eventInfo.TestID = testId;
eventInfo.EventNumber = eventIdx;
eventInfo.TestGUID = eventGuid;
try
{
eventInfo.FaultFlags = config.GetEventFaultFlags(eventIdx);
eventInfo.FaultFlagsEx = config.GetEventFaultFlagsEx(eventIdx);
}
catch (Exception ex)
{
APILogger.Log("could not get fault flags", ex);
}
try
{
eventInfo.ArmAttempts = config.GetEventArmAttempts(eventIdx);
}
catch (Exception ex)
{
APILogger.Log("could not get arm attempts", ex);
}
eventGuids[eventIdx] = eventInfo.TestGUID;
faultFlags[eventIdx] = eventInfo.FaultFlags;
faultFlagsEx[eventIdx] = eventInfo.FaultFlagsEx;
armAttempts[eventIdx] = eventInfo.ArmAttempts;
eventInfo.HasBeenDownloaded = config.EventHasBeenDownloaded(eventIdx, out uint flag); // I/O
// figure out how many modules we have
var numberOfModules = config.CalculateNumberOfModules(storedConfig, numberOfChannels, IsTOM());
var numberOfStreamOuts = config.CalculateNumberOfStreamOuts(storedConfig);
var numberOfUARTs = config.CalculateNumberOfUARTs(storedConfig);
// make sure we have the right number of modules
if (numberOfModules + numberOfStreamOuts + numberOfUARTs != storedConfig.Modules.Length)
{
// "Slice.QueryDownload: The information in the recorder is corrupt"
info.Error(Strings.Slice_QueryDownload_Err1);
//SS: need to add code here to try to extract enough info
return;
}
eventInfo.Modules = new DASModule[numberOfModules];
var numberOfSamples = config.GetEventTotalSamples(eventIdx); // I/O
var triggerSampleNumber = config.GetEventTriggerSampleNumber(eventIdx); // I/O
var eventStartRecordSampleNumber = config.GetEventStartRecordSampleNumber(eventIdx); // I/O
var eventStartTime = config.GetEventStartTime(eventIdx); // I/O
var levelTriggerOffsetCorrection = config.GetEventLevelTriggerT0AdjustmentSamples(eventIdx);
var levelTriggerSeen = config.GetEventLevelTriggerSeen(eventIdx);
// 17873 download should only use event attributes rather than arm attributes
var currentChannel = 0;
//toyota boshoku -flat data issue zendesk 5702?
//basically make sure we are using the event attribute ScaleFactorMvADC and not what is in the
//xml
for (var moduleIdx = 0; moduleIdx < numberOfModules; moduleIdx++)
{
// take the module from the stored config
var module = (DASModule)storedConfig.Modules[moduleIdx];
module.SampleRateHz = Convert.ToUInt32(actualSampleRate);
module.ActualSampleRateHz = Convert.ToUInt32(actualSampleRate);
module.EmbeddedSampleRateHz = stackActualSampleRate;
/// <DesignNote topic="Level Trigger Configuration" author="PKXH">
/// Amongst other things, the level trigger offset correction, if it exists, is getting applied
/// to the module trigger sample numbers below. There shouldn't be any danger of this value being
/// erroneously applied to outside "tweaking" since the only outside tweak should only ever happen
/// if there was no trigger. Still I'm a little concerned that this value will still be invisibly
/// applied to user-overridden trigger sample numbers. We could conceivably guard against this
/// situation with an "original trigger sample number" concept, which we could then check against
/// and not re-apply things like level trigger offset correction if the current value doesn't
/// match it, implying it has been manually overridden.
/// </DesignNote>
// now update the module with dynamic data
module.OwningDAS = this;
module.NumberOfSamples = numberOfSamples;
module.TriggerSampleNumbers = new ulong[1]; // only one so far
var phaseShift = GetPhaseShiftSamples(Convert.ToUInt32(1 + module.ModuleArrayIndex), Convert.ToDouble(actualSampleRate), Convert.ToUInt32(aafilter), triggerSampleNumber);
module.TriggerSampleNumbers[0] = triggerSampleNumber + phaseShift;
eventInfo.WasTriggered = module.TriggerSampleNumbers[0] > 0;
module.StartRecordSampleNumber = 0;
if (module.RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBuffer
|| module.RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBufferPlusUART
|| module.RecordingMode == DFConstantsAndEnums.RecordingMode.AutoCircularBufferMode
|| module.RecordingMode == DFConstantsAndEnums.RecordingMode.a16_CircularBufferAndStreamSubSampleMode
|| module.RecordingMode == DFConstantsAndEnums.RecordingMode.RAMActive
|| module.RecordingMode == DFConstantsAndEnums.RecordingMode.MultipleEventRAMActive)
{
ulong preTriggerSamples = Convert.ToUInt64(System.Math.Abs(module.PreTriggerSeconds * module.SampleRateHz + 1D));
if (preTriggerSamples < module.TriggerSampleNumbers[0])
{
module.StartRecordSampleNumber = module.TriggerSampleNumbers[0] - preTriggerSamples;
}
}
else if (module.RecordingMode == DFConstantsAndEnums.RecordingMode.AutoActiveMode ||
module.RecordingMode == DFConstantsAndEnums.RecordingMode.AerospaceWithMotion)
{
ulong preTriggerSamples = Convert.ToUInt64(System.Math.Abs(module.PreTriggerSeconds * module.SampleRateHz + 1D));
if (preTriggerSamples < module.TriggerSampleNumbers[0])
{
module.StartRecordSampleNumber = eventStartRecordSampleNumber;
}
}
#region Get_PTP_Event_Timestamp
module.StartRecordTimestampSec = startRecordTimestampSec;
module.TriggerTimestampSec = triggerTimestampSec;
module.StartRecordTimestampNanoSec = startRecordTimestampNanoSec;
module.TriggerTimestampNanoSec = triggerTimestampNanoSec;
module.PTPMasterSync = pTPMasterSync;
#endregion
#region Slice6TiltSensor
module.TiltSensorAxisXDegreesPre = double.NaN;
module.TiltSensorAxisYDegreesPre = double.NaN;
module.TiltSensorAxisZDegreesPre = double.NaN;
module.TiltSensorAxisXDegreesPost = double.NaN;
module.TiltSensorAxisYDegreesPost = double.NaN;
module.TiltSensorAxisZDegreesPost = double.NaN;
#endregion
// update the channel info
for (var channelIdx = 0; channelIdx < module.Channels.Length; channelIdx++)
{
var channel = (DASChannel)module.Channels[channelIdx];
channel.OwningModule = module;
channel.EventStartTime = eventStartTime;
if (channel is AnalogInputDASChannel analog)
{
analog.ScalefactorEngineeringUnitsPerADC = factors[currentChannel];
}
// CGO
// This is a hacked change for now to support 00G8 and prior firmware
// in the 1.04 release of SLICEWare. This and the other CGO commented
// block of code need more general cleanup before 1.05.
if (null == levelTriggerOffsetCorrection)
{
channel.LevelTriggerT0AdjustmentSamples = 0;
}
else if (currentChannel < levelTriggerOffsetCorrection.Length)
{
channel.LevelTriggerT0AdjustmentSamples = levelTriggerOffsetCorrection[currentChannel];
}
else
{
channel.LevelTriggerT0AdjustmentSamples = 0;
}
if (null == levelTriggerSeen)
{
channel.LevelTriggerSeen = false;
}
else if (currentChannel < levelTriggerSeen.Length)
{
channel.LevelTriggerSeen = levelTriggerSeen[currentChannel];
}
else
{
channel.LevelTriggerSeen = false;
}
currentChannel++;
}
// store it in the object
eventInfo.Modules[moduleIdx] = module;
}
if (0 > info.EventIndex)
{
// store it in the object
dlReport.Events[eventIdx] = eventInfo;
}
else { EventInfo.Events[eventIdx] = eventInfo; }
info.Progress(100 * eventIdx / eventCount);
}
// now assigned the data to the public property
if (0 > info.EventIndex)
{
SetEventInfo(dlReport);
}
SetEventFaultFlags(faultFlags);
((IDownload)this)?.SetExtendedFaultFlags(extendedFaultIds.ToArray());
SetEventGuids(eventGuids);
SetEventArmAttemps(armAttempts);
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
private void QueryUartEventInfo(int eventIdx, QueryDownloadAsyncInfo info, DownloadReport dlReport)
{
var uartInfo = new QueryUARTEventInfo(this) { EventNumber = (ushort)eventIdx };
try
{
uartInfo.SyncExecute();
}
catch (Exception ex)
{
//http://manuscript.dts.local/f/cases/43316/Software-Should-Show-Clear-Error-Instead-of-Misleading-Message-When-Firmware-Bug-Blocks-Data-Download
APILogger.Log(ex);
}
// the object to store it all in
var uartEventInfo = GetUARTEventInfo(uartInfo.EventNumber, uartInfo.DataPresent, uartInfo.DataDownloaded,
uartInfo.TotalByteCount, uartInfo.TriggerByteCount, uartInfo.StartTimestamp, uartInfo.EndTimestamp, uartInfo.BaudRate);
if (0 > info.EventIndex)
{
// store it in the object
dlReport.UARTEvents[eventIdx] = uartEventInfo;
}
else { EventInfo.UARTEvents[eventIdx] = uartEventInfo; }
}
protected override void DownloadEventStartCmd(SliceDownloadState state)
{
//TODO: REMOVE THIS HACK or keep it depending on how FW finishes implementing
try
{
if (state.SamplesDownloaded >= state.Request.EndSample - state.Request.StartSample + 1) return;
state.DownloadCommand = GetQueryEventData();
state.DownloadCommand.LogCommands = false;
state.DownloadCommand.EventNumber = state.Request.EventNumber;
state.DownloadCommand.Channel = state.Request.DASChannelNumber;
if (state.Request.DASChannelNumber == DownloadRequest.ALL_CHANNELS)
{
state.DownloadCommand.ChannelsDownloaded = IsTOM() ?
9 : EventInfo.Events[state.Request.EventNumber].Modules.Sum(module => module.NumberOfChannels());
}
state.DownloadCommand.LastSample = state.Request.EndSample;
// Ask for the next batch of samples
state.DownloadCommand.FirstSample = state.Request.StartSample + state.SamplesDownloaded;
state.DownloadCommand.Execute(DownloadEventCallback, state);
}
catch (CanceledException)
{
state.Cancel();
}
catch (Exception ex)
{
state.Error(ex.Message, ex);
}
}
/// <summary>
/// TSR AIR doesn't AutoArm
/// </summary>
/// <param name="callback"></param>
/// <param name="userData"></param>
/// <param name="eventGuid"></param>
/// <param name="armNowTimeout"></param>
/// <param name="testingMode"></param>
/// <param name="diagnosticsDelayMs"></param>
/// <param name="maxNumberEvents"></param>
/// <param name="repeatEnable"></param>
/// <param name="preserveDiagnostics"></param>
void DTS.DASLib.Service.IArmActions.AutoArmNow(ServiceCallback callback, object userData, Guid eventGuid, int
armNowTimeout, bool testingMode, uint diagnosticsDelayMs, int maxNumberEvents, bool repeatEnable, bool preserveDiagnostics)
{
var info = new AutoArmPacket(callback, userData, eventGuid, armNowTimeout, testingMode, diagnosticsDelayMs, maxNumberEvents, repeatEnable, preserveDiagnostics);
info.Success();
}
/// <summary>
/// for TSR AIR we override WhatToDownload and transparently handle things our own way from the outside
/// </summary>
private WhatToDownloadTSRAIR _whatToDownload;
public override IDownloadRequest WhatToDownload
{
get => _whatToDownload;
set
{
_leftOverData = new ushort[0];
var numChannels = NumberOfDownloadChannels();
if (IsTOM())
{
//number of channels is a lie! don't trust it!
numChannels = 9;
}
_whatToDownload = new WhatToDownloadTSRAIR(value, numChannels, PageSize);
}
}
protected override void AsyncTrigger(object asyncInfo)
{
var info = asyncInfo as SliceServiceAsyncInfo;
try
{
var setSwitch = new SetSwitchImmediate(this);
setSwitch.Switch = (byte)Switches.BaseSwitches.TSRAIR_TriggerOut;
setSwitch.Setting = 1;
setSwitch.DeviceID = 0;
setSwitch.Port = (byte)Switches.SystemSwitches_425B.GPIO__MCU_EVENT;
setSwitch.SyncExecute();
info?.Success();
}
catch (CanceledException)
{
info?.Cancel();
}
catch (Exception ex)
{
info?.Error(ex.Message, ex);
}
}
protected override void AsyncClearTriggerOut(object o)
{
if (!(o is SliceServiceAsyncInfo info)) { return; }
var ssi = new SetSwitchImmediate(this)
{
DeviceID = 0x00,
Switch = (byte)Switches.BaseSwitches.TSRAIR_TriggerOut,
Port = (byte)Switches.SystemSwitches_425B.GPIO__MCU_EVENT,
Setting = InvertTrigger ? Convert.ToByte(1) : Convert.ToByte(0)
};
ssi.SyncExecute();
info.Success();
}
#endregion
#region IClockSyncActions
protected override void AsyncGetClockSyncStatus(object asyncInfo)
{
//TSRAIR has a command for both profile and status fetch
if (!(asyncInfo is GetClockSyncStatusPacket packet)) { return; }
if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryClockSyncStatus))
{
packet.Info.Error("Get clock sync status not supported");
return;
}
var info = packet.Info;
var bLocked = false;
try
{
Lock();
bLocked = true;
var status = new QueryClockSyncStatus(this);
status.SyncExecute();
DASClockSyncProfile = status.ClockSyncProfile;
DASClockSyncStatus = status.InputSyncStatus;
DoRTCInUTCCheck();
bLocked = false;
Release();
info.Success();
}
catch (CanceledException)
{
if (bLocked) { bLocked = false; Release(); }
info.Cancel();
}
catch (CommandException ce)
{
if (bLocked) { Release(); bLocked = false; }
straightFailures++;
if (straightFailures > PERMITTED_FAILURES)
{
APILogger.Log("GetClockSyncStatus error - has failed ", straightFailures, " times, giving up", ce);
info.Error(ce.Message, ce);
}
else
{
if (info.userData is DTS.DASLib.Service.ServiceBase.CallbackData cbData)
{
cbData.Target.DASClockSyncStatus = null;
}
info.Success();
APILogger.Log("GetClockSyncStatus error", ce);
}
}
catch (Exception ex)
{
if (bLocked) { bLocked = false; Release(); }
info.Error(ex.Message, ex);
}
finally { if (bLocked) { Release(); } }
}
#endregion
#region IUARTDownload
public uint BaudRate { get; private set; }
public uint DataBits { get; private set; }
public StopBits StopBits { get; private set; }
public Parity Parity { get; private set; }
public Handshake FlowControl { get; private set; }
public UartDataFormat DataFormat { get; private set; }
public IUARTDownloadRequest WhatUARTToDownload { get; set; }
public void SetWhatUARTToDownload(IUARTDownloadRequest request, bool bSetInDb = true)
{
UARTDownloadRequest.SetWhatToDownload(this, request, bSetInDb);
}
#endregion
#region IUARTDownloadActions
public void UARTDownload(ServiceCallback callback, object userData)
{
var state = new SliceUARTDownloadState(callback, userData, WhatUARTToDownload);
if (null == WhatUARTToDownload)
{
APILogger.Log("UART download - what to download is null");
state.Success();
return;
}
APILogger.Log("Starting UART Download ", WhatUARTToDownload.StartTimestamp,
WhatUARTToDownload.EndTimestamp);
ulong totalDownloaded = 0, needed = WhatUARTToDownload.TotalByteCount;
try
{
while (totalDownloaded < needed)
{
var getData = new QueryUARTEventData(this)
{
EventNumber = WhatUARTToDownload.EventNumber,
LogCommands = false,
RequestOffsetByteCount = totalDownloaded,
RequestByteCount = needed - totalDownloaded < uint.MaxValue
? (uint)(needed - totalDownloaded)
: uint.MaxValue
};
getData.SyncExecute();
if (null == getData.PayloadData)
{
Thread.Sleep(10);
continue;
}
state.NewData(new ServiceCallbackData.UARTNewData { DataOffset = getData.RequestOffsetByteCount, UARTData = getData.PayloadData });
var ratio = 100D * totalDownloaded / needed;
if (ratio < 0)
{
ratio = 0;
}
else if (ratio > 100)
{
ratio = 100D;
}
state.Progress(Convert.ToInt32(ratio));
totalDownloaded += getData.PayloadByteCount;
}
state.Success();
}
catch (CanceledException)
{
state.Cancel();
}
catch (Exception e)
{
APILogger.LogException(e);
state.Error(e.Message, e);
}
}
/// <summary>
/// Retrieve UART info about available events to download
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IUARTDownloadActions.QueryUARTDownload(ServiceCallback callback, object userData, int eventIndex, TDASServiceSetupInfo setupInfo)
{
var info = new QueryDownloadAsyncInfo(callback, userData, eventIndex);
LaunchAsyncWorker("Slice.QueryUARTDownload", AsyncQueryUARTDownload, info);
}
protected virtual void AsyncQueryUARTDownload(object asyncInfo)
{
if (!(asyncInfo is QueryDownloadAsyncInfo info)) { return; }
if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryUARTDownload))
{
info.Error("Query UART download is not supported");
return;
}
var bLocked = false;
try
{
Lock();
bLocked = true;
var status = new QueryUARTEventInfo(this) { EventNumber = (ushort)info.EventIndex };
status.SyncExecute();
bLocked = false;
Release();
info.Success();
}
catch (CanceledException)
{
if (bLocked) { bLocked = false; Release(); }
info.Cancel();
}
catch (CommandException ce)
{
if (bLocked) { Release(); bLocked = false; }
straightFailures++;
if (straightFailures > PERMITTED_FAILURES)
{
APILogger.Log("QueryUARTDownload error - has failed ", straightFailures, " times, giving up", ce);
info.Error(ce.Message, ce);
}
else
{
if (info.userData is DTS.DASLib.Service.ServiceBase.CallbackData cbData)
{
//cbData.Target.DASClockSyncStatus = null;
}
info.Success();
APILogger.Log("QueryUARTDownload error", ce);
}
}
catch (Exception ex)
{
if (bLocked) { bLocked = false; Release(); }
info.Error(ex.Message, ex);
}
finally { if (bLocked) { Release(); } }
}
internal class SetUARTSettingsAsyncInfo : SliceServiceAsyncInfo
{
public uint BaudRate { get; set; }
public uint DataBits { get; set; }
public uint StopBits { get; set; }
public uint Parity { get; set; }
public uint FlowControl { get; set; }
public SetUARTSettingsAsyncInfo(ServiceCallback callback, object userData, uint baudRate, uint dataBits,
uint stopBits, uint parity, uint flowControl)
: base(callback, userData)
{
BaudRate = baudRate;
DataBits = dataBits;
StopBits = stopBits;
Parity = parity;
FlowControl = flowControl;
}
}
void IUARTDownloadActions.GetUARTSettings(ServiceCallback callback, object userData)
{
var info = new SliceServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Slice.GetUARTSettings", AsyncGetUARTSettings, info);
}
protected virtual void AsyncGetUARTSettings(object asyncInfo)
{
if (!(asyncInfo is SliceServiceAsyncInfo info)) { return; }
if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.GetUARTSettings))
{
info.Error("Get UART settings is not supported");
return;
}
var bLocked = false;
try
{
Lock();
bLocked = true;
try
{
var qsaUARTSettings = new QuerySystemAttributeSLICE2(this, QuerySystemAttribute.Default_IO_Timeout);
qsaUARTSettings.Key = AttributeTypes.SystemAttributesSLICE2.S6A_GpsCanUARTSettings;
qsaUARTSettings.SyncExecute();
//we made it, set results
var uartSettings = (uint[])qsaUARTSettings.Value;
BaudRate = uartSettings[0];
DataBits = uartSettings[1];
StopBits = (StopBits)uartSettings[2];
Parity = (Parity)uartSettings[3];
FlowControl = (Handshake)uartSettings[4];
}
catch (Exception ex)
{
APILogger.Log("Problem getting UART settings", ex);
}
bLocked = false;
Release();
info.Success();
}
catch (CanceledException)
{
if (bLocked)
{
bLocked = false;
Release();
}
info.Cancel();
}
catch (CommandException ce)
{
if (bLocked)
{
Release();
bLocked = false;
}
straightFailures++;
if (straightFailures > PERMITTED_FAILURES)
{
APILogger.Log("GetUARTSettings error - has failed ", straightFailures, " times, giving up", ce);
info.Error(ce.Message, ce);
}
else
{
info.Success();
APILogger.Log("GetUARTSettings error", ce);
}
}
catch (Exception ex)
{
if (bLocked)
{
bLocked = false;
Release();
}
info.Error(ex.Message, ex);
}
finally
{
if (bLocked)
{
Release();
}
}
}
void IUARTDownloadActions.SetUARTSettings(ServiceCallback callback, object userData, uint baudRate, uint dataBits, uint stopBits, uint parity, uint flowControl)
{
var info = new SetUARTSettingsAsyncInfo(callback, userData, baudRate, dataBits, stopBits, parity, flowControl);
LaunchAsyncWorker("Slice.SetUARTSettings", AsyncSetUARTSettings, info);
}
protected virtual void AsyncSetUARTSettings(object asyncInfo)
{
if (!(asyncInfo is SetUARTSettingsAsyncInfo info)) { return; }
if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.SetUARTSettings))
{
info.Error("Set UART settings is not supported");
return;
}
var bLocked = false;
try
{
Lock();
bLocked = true;
var value = new uint[] { info.BaudRate, info.DataBits, info.StopBits, info.Parity, info.FlowControl };
try
{
var ssaUARTSettings =
new SetSystemAttributeSLICE2(this, SetSystemAttribute.Default_IO_Timeout);
ssaUARTSettings.SetValue(AttributeTypes.SystemAttributesSLICE2.S6A_GpsCanUARTSettings,
value, true);
ssaUARTSettings.SyncExecute();
}
catch (Exception ex)
{
APILogger.Log("Problem setting UART settings", ex);
}
bLocked = false;
Release();
info.Success();
}
catch (CanceledException)
{
if (bLocked)
{
bLocked = false;
Release();
}
info.Cancel();
}
catch (CommandException ce)
{
if (bLocked)
{
Release();
bLocked = false;
}
straightFailures++;
if (straightFailures > PERMITTED_FAILURES)
{
APILogger.Log("SetUARTSettings error - has failed ", straightFailures, " times, giving up", ce);
info.Error(ce.Message, ce);
}
else
{
info.Success();
APILogger.Log("SetUARTSettings error", ce);
}
}
catch (Exception ex)
{
if (bLocked)
{
bLocked = false;
Release();
}
info.Error(ex.Message, ex);
}
finally
{
if (bLocked)
{
Release();
}
}
}
#endregion
}
#region QueryEventData_TSRAIR
/// <summary>
/// this meaty class handles skipping parts of the download not needed (start of page to desired start sample)
/// [also note we'll need to do the same thing with the end sample too if we want to use the ECC properly,
/// but ECC isn't even implemented yet ...]
/// </summary>
public class QueryEventData_TSRAIR : QueryEventDataBase
{
public override UInt64 FirstSample
{
get => base.FirstSample;
set => base.FirstSample = value;
}
public override UInt64 LastSample
{
get => base.LastSample;
set => base.LastSample = value;
}
public QueryEventData_TSRAIR(DTS.Common.Interface.DASFactory.ICommunication sock)
: base(sock) { LogCommands = false; }
public QueryEventData_TSRAIR(DTS.Common.Interface.DASFactory.ICommunication sock, int TimeoutMillisec)
: base(sock, TimeoutMillisec) { LogCommands = false; }
private ulong GetRequestedStartSpot()
{
if (recorder is TSRAIR<WINUSBConnection> tsr_air_usb)
{
return ((WhatToDownloadTSRAIR)tsr_air_usb.WhatToDownload).RequestedStartSport;
}
else if (recorder is TSRAIR<EthernetConnection> tsr_air_ethernet)
{
return ((WhatToDownloadTSRAIR)tsr_air_ethernet.WhatToDownload).RequestedStartSport;
}
else { throw new NotSupportedException("GetRequestedStartSport not supported for " + recorder.ConnectString); }
}
private void PushLeftOverData(ushort[] daters)
{
if (recorder is TSRAIR<WINUSBConnection> tsr_air_usb)
{
tsr_air_usb.PushLeftOverData(daters);
}
else if (recorder is TSRAIR<EthernetConnection> tsr_air_ethernet)
{
tsr_air_ethernet.PushLeftOverData(daters);
}
}
protected override CommandReceiveAction WholePackagePost()
{
// now send the data to the user
var stat = CommandStatus.Success;
if (response.Status != DFConstantsAndEnums.CommandStatus.StatusNoError)
{
var s = (int)response.Status;
APILogger.LogString("QueryEventData.WholePackagePost: reporting failure, status==" + CommandPacket.StatusLabels[s] + " (0x" + s.ToString("X") + ")");
stat = CommandStatus.Failure;
}
var cbReport = new QueryEventDataReport(stat, UserCallbackData);
cbReport.Data = new short[_channelsDownloaded][];
for (var i = 0; i < _channelsDownloaded; i++)
GetChannelData(i, out cbReport.Data[i]);
//we have processed some data, but there may be some left over (since data isn't channel sample aligned ...)
//figure out what we used and what's left over
//now we have two situations, one, we have already skimmed beyond all the data we need
//or two, we are somewhere in between, we need to skip a few samples
var requestedStartSpot = GetRequestedStartSpot();
if ((FirstSample + (ulong)_data.Length) < requestedStartSpot)
{
//push no data, we don't want it!
}
else if (FirstSample > requestedStartSpot)
{//we want everything in here ...
var samplesProcessed = Convert.ToInt32(Math.Truncate((double)_data.Length / ChannelsDownloaded));
var offset = samplesProcessed * ChannelsDownloaded;
var leftover = new ushort[_data.Length - offset];
for (var i = 0; i < leftover.Length; i++)
{
leftover[i] = _data[i + offset];
}
PushLeftOverData(leftover);
}
else
{
//we need to calculate samples only from the start of the data we are interested in
var offset = Convert.ToInt32(requestedStartSpot - FirstSample);
int samplesProcessed = Convert.ToInt32(Math.Truncate(((double)_data.Length - offset) / ChannelsDownloaded));
var product = samplesProcessed * ChannelsDownloaded;
var leftover = new ushort[_data.Length - offset - product];
offset += product;
for (var i = 0; i < leftover.Length; i++)
{
leftover[i] = _data[i + offset];
}
PushLeftOverData(leftover);
}
return UserCallback(cbReport);
}
private ushort[] PopLeftOverData()
{
if (recorder is TSRAIR<WINUSBConnection> tsr_air_usb)
{
return tsr_air_usb.PopLeftOverData();
}
else if (recorder is TSRAIR<EthernetConnection> tsr_air_ethernet)
{
return tsr_air_ethernet.PopLeftOverData();
}
else { throw new NotImplementedException(); }
}
protected override CommandReceiveAction WholePackage()
{
if (response.Status != DFConstantsAndEnums.CommandStatus.StatusNoError)
{
return CommandReceiveAction.StopReceiving;
}
//we are going to process the data shortly, but before we do we'll need to
//pre-pend any left over data we have to the new incoming data
//since we already count the samples downloaded for samples in the left over stuff
//we don't need to recount it, just the new incoming samples
_samplesDownloaded = (ulong)(response.Parameter.Length) / 2;
var leftover = PopLeftOverData();
_data = new ushort[_samplesDownloaded + (ulong)leftover.Length];
leftover.CopyTo(_data, 0);
for (var i = 0; (ulong)i < _samplesDownloaded; i++)
{
response.GetParameter(2 * i, out _data[i + leftover.Length]);
}
return CommandReceiveAction.StopReceiving;
}
public override void GetChannelData(int channel, out short[] signedADC)
{
if (channel < 0 || channel > _channelsDownloaded)
{
throw new ApplicationException("QueryEventData.GetChannelData: Data requested on a channel that wasn't downloaded.");
}
//first short circuit if we know we are still completely skipping data
if (((ulong)_data.Length + FirstSample) < GetRequestedStartSpot())//(slice2.WhatToDownload as WhatToDownloadSlice2).RequestedStartSport)
{
signedADC = new short[0];//nothing to see here (we are completely before the start of our requested data)
return;
}
//now we have two situations, one, we have already skimmed beyond all the data we need
//or two, we are somewhere in between, we need to skip a few samples
var offset = 0;
if (GetRequestedStartSpot() > FirstSample)
{
offset = Convert.ToInt32(GetRequestedStartSpot() - FirstSample);
}
// Data order for a 9 channel stack
// 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 etc.
ushort val;
var completeSamples = Convert.ToInt32(Math.Truncate((double)(_data.Length - offset) / ChannelsDownloaded));
//performance improvements, use simpler structures and do less calculations over the iterations
var rv = new short[completeSamples];
offset += channel;
for (var i = 0; i < completeSamples; i++)
{
val = _data[i * ChannelsDownloaded + offset];
rv[i] = (short)(((val & 0x00FF) << 8) | ((val >> 8) & 0x00FF)); //+ 0x8000); no offset add for tsr air
}
signedADC = rv.ToArray();
}
// this function isn't used by SLICEWare, but it is used by the FirmwareTestUtility
// SW uses the GetChannelData above
public override void GetRawIndexedData(int index, out ushort[] data)
{
data = new ushort[_samplesDownloaded];
for (var i = 0; i < data.Length; i++)
{
data[i] = _data[i + index];
}
}
}
#endregion
public class WhatToDownloadTSRAIR : DownloadRequest
{
/// <summary>
/// this will hold the number of channels in the download, this is needed
/// to calculate the sample alignment and request/response sample numbers.
/// the SLICE2 firmware uses samples counts irrespective of channels, so they must be realigned post
/// download
/// </summary>
private readonly ulong _numberOfChannels = 0;
public ulong RequestedStartSport { get; }
public WhatToDownloadTSRAIR(IDownloadRequest dr, int numberOfChannels, int pageSize)
{
if (dr is WhatToDownloadTSRAIR dr2)
{
_numberOfChannels = (ulong)numberOfChannels;
DASChannelNumber = dr.DASChannelNumber;
base.EndSample = dr.EndSample;
EventNumber = dr.EventNumber;
SamplesToSkip = dr.SamplesToSkip;
base.StartSample = dr.StartSample;
RequestedStartSport = dr2.RequestedStartSport;
StartRecordTimestampSec = dr.StartRecordTimestampSec;
TriggerTimestampSec = dr.TriggerTimestampSec;
}
else
{
_numberOfChannels = (ulong)numberOfChannels;
if (null == dr)
{
return;
}
DASChannelNumber = dr.DASChannelNumber;
base.EndSample = 0 == dr.EndSample ? 0 : (dr.EndSample + 1) * _numberOfChannels - 1;
EventNumber = dr.EventNumber;
SamplesToSkip = dr.SamplesToSkip;
//find the start of the page the start sample is on
var nearestdiv = Math.Truncate(dr.StartSample * (double)numberOfChannels / pageSize);
base.StartSample = Convert.ToUInt64(nearestdiv * pageSize);
RequestedStartSport = dr.StartSample * (ulong)numberOfChannels;
StartRecordTimestampSec = dr.StartRecordTimestampSec;
TriggerTimestampSec = dr.TriggerTimestampSec;
}
}
/// <inheritdoc />
/// <summary>
/// if EndSample gets set by a generic service, it is not expecting sample counts to be irrespective of channels
/// so we convert it to be irrespective here
/// however, we want to return what we consider the endsample so looping code doesn't give up until we really are done
/// with all the samples we want
/// </summary>
public override ulong EndSample
{
get => base.EndSample;
set => base.EndSample = (value + 1) * _numberOfChannels;
}
/// <inheritdoc />
/// <summary>
/// adjusting the start sample is a little more complicated than adjusting the endsample, we need to start
/// downloading from the start of the page that the start sample we want is on
/// </summary>
public override ulong StartSample
{
get => base.StartSample;
set => base.StartSample = value;
}
}
}