2476 lines
115 KiB
Plaintext
2476 lines
115 KiB
Plaintext
|
|
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(); } }
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|