640 lines
32 KiB
Plaintext
640 lines
32 KiB
Plaintext
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Linq;
|
||
|
|
using DTS.Common;
|
||
|
|
using DTS.Common.DAS.Concepts;
|
||
|
|
using DTS.DASLib.Command.SLICE;
|
||
|
|
using DTS.DASLib.Command;
|
||
|
|
using DTS.Common.ICommunication;
|
||
|
|
using DTS.Common.Utilities.Logging;
|
||
|
|
using DTS.Common.WINUSBConnection;
|
||
|
|
using DTS.DASLib.Command.SLICE.DownloadCommands;
|
||
|
|
using DTS.Common.Enums.Sensors;
|
||
|
|
using DTS.Common.Interface.Connection;
|
||
|
|
using DTS.Common.Interface.DASFactory.Diagnostics;
|
||
|
|
using DTS.Common.Enums.DASFactory;
|
||
|
|
using DTS.Common.Enums.Hardware;
|
||
|
|
using DTS.Common.Constant.DASSpecific;
|
||
|
|
using DTS.Common.Utilities.LTLogging;
|
||
|
|
|
||
|
|
namespace DTS.DASLib.Service
|
||
|
|
{
|
||
|
|
public class SLICE1_5<T> : SLICE2_Base<T>, IConfigurationActions where T : IConnection, new()
|
||
|
|
{
|
||
|
|
public override HardwareTypes GetHardwareType()
|
||
|
|
{
|
||
|
|
if (SerialNumber.StartsWith("SG5"))
|
||
|
|
{
|
||
|
|
return HardwareTypes.SLICE1_G5Stack;
|
||
|
|
}
|
||
|
|
if (SerialNumber.Contains("BA0"))
|
||
|
|
{
|
||
|
|
return HardwareTypes.SLICE1_5_Micro_Base;
|
||
|
|
}
|
||
|
|
return HardwareTypes.SLICE1_5_Nano_Base;
|
||
|
|
}
|
||
|
|
/// <summary>
|
||
|
|
/// 14269 Implement SLICE PRO and Base+ RTC
|
||
|
|
/// my records indicate SLICE1.5 has always supported this feature ...
|
||
|
|
/// </summary>
|
||
|
|
public override bool SupportsTimeSynchronization => true;
|
||
|
|
/// <inheritdoc />
|
||
|
|
/// <summary>
|
||
|
|
/// gets the expected excitation in mV for a given channel
|
||
|
|
/// returns 0 if excitation could not be retrieved, otherwise excitation in mV
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="moduleIndex"></param>
|
||
|
|
/// <param name="channelOnModule"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
protected override double GetExpectedExcitationMV(int moduleIndex, int channelOnModule)
|
||
|
|
{
|
||
|
|
if (ConfigData?.Modules == null || ConfigData.Modules.Length <= moduleIndex)
|
||
|
|
{
|
||
|
|
APILogger.Log("unable to get excitation, no ConfigData to base excitation on");
|
||
|
|
return 0D;
|
||
|
|
}
|
||
|
|
if (!(ConfigData.Modules[moduleIndex].Channels[channelOnModule] is AnalogInputDASChannel aic))
|
||
|
|
{
|
||
|
|
//only have excitation to consider on analog channels
|
||
|
|
APILogger.Log("unable to get excitation, channel has no excitation (is not analog)");
|
||
|
|
return 0D;
|
||
|
|
}
|
||
|
|
var excitation = Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(aic.Excitation) * 1000D;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var qsa = new QuerySystemAttribute_Bridge(this);
|
||
|
|
|
||
|
|
switch (channelOnModule)
|
||
|
|
{
|
||
|
|
case 0:
|
||
|
|
qsa.Key = AttributeTypes.SystemAttributes_Bridge.FactoryCalibratedExcitationAVolts;
|
||
|
|
break;
|
||
|
|
case 1:
|
||
|
|
qsa.Key = AttributeTypes.SystemAttributes_Bridge.FactoryCalibratedExcitationBVolts;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
qsa.Key = AttributeTypes.SystemAttributes_Bridge.FactoryCalibratedExcitationCVolts;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
//note device 0 is the base, the first module starts at 1, so we have to start at an offset of 1
|
||
|
|
qsa.DeviceID = Convert.ToByte(1 + moduleIndex);
|
||
|
|
qsa.SyncExecute();
|
||
|
|
var bridgeExcitation = Convert.ToDouble(qsa.Value) * 1000D;//convert from V to mV
|
||
|
|
var delta = Math.Abs(excitation - bridgeExcitation);
|
||
|
|
if (delta < 500)
|
||
|
|
{
|
||
|
|
excitation = bridgeExcitation;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
APILogger.Log(ex);
|
||
|
|
}
|
||
|
|
return excitation;
|
||
|
|
}
|
||
|
|
public static StaticInformation StaticDASBridge1_5Info = new StaticInformation(new[]
|
||
|
|
{//1,2,4,8,10,16,20,32,40,64,80,128,160,320,640,1280
|
||
|
|
2400D/1.0,
|
||
|
|
2400D/2.0,
|
||
|
|
2400D/4.0,
|
||
|
|
2400D/8.0,
|
||
|
|
2400D/10.0,
|
||
|
|
2400D/16.0,
|
||
|
|
2400D/20.0,
|
||
|
|
2400D/32.0,
|
||
|
|
2400D/40.0,
|
||
|
|
2400D/64.0,
|
||
|
|
2400D/80.0,
|
||
|
|
2400D/128.0,
|
||
|
|
2400D/160.0,
|
||
|
|
2400D/320.0,
|
||
|
|
2400D/640.0,
|
||
|
|
2400D/1280.0
|
||
|
|
});
|
||
|
|
|
||
|
|
protected override float GetLevelTriggerThreshold(AnalogInputDASChannel analog, IDiagnosticResult diagnostics,
|
||
|
|
double thresholdeu, double mvPerEu)
|
||
|
|
{
|
||
|
|
var now = DateTime.Now;
|
||
|
|
if (analog.SensitivityMilliVoltsPerEU < 0 && !analog.RemoveOffset)
|
||
|
|
{
|
||
|
|
var threshold = Convert.ToSingle(thresholdeu * mvPerEu
|
||
|
|
-
|
||
|
|
diagnostics.GetExpectedDataZeroLevelADC(analog.ZeroMethod) *
|
||
|
|
diagnostics.ScalefactorMilliVoltsPerADC);
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var s =
|
||
|
|
$"{now.ToShortDateString()} {now.ToShortTimeString()}\r\n{SerialNumber}:{analog.Number}:{analog.SerialNumber} : thresholdEU ({thresholdeu}) * MvPerEU ({mvPerEu}) - DataZeroLevelADC ({diagnostics.GetExpectedDataZeroLevelADC(analog.ZeroMethod)}) * ScaleFactorMvPerADC ({diagnostics.ScalefactorMilliVoltsPerADC})={threshold}; SensitivityMv={analog.SensitivityMilliVoltsPerEU}\r\n";
|
||
|
|
LevelTriggerLogging.LevelTriggerLog(s);
|
||
|
|
}
|
||
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
||
|
|
return threshold;
|
||
|
|
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
var threshold = Convert.ToSingle(thresholdeu * mvPerEu
|
||
|
|
+
|
||
|
|
diagnostics.GetExpectedDataZeroLevelADC(analog.ZeroMethod) *
|
||
|
|
diagnostics.ScalefactorMilliVoltsPerADC);
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var s =
|
||
|
|
$"{now.ToShortDateString()} {now.ToShortTimeString()}\r\n{SerialNumber}:{analog.Number}:{analog.SerialNumber} : thresholdEU ({thresholdeu}) * MvPerEU ({mvPerEu}) + DataZeroLevelADC ({diagnostics.GetExpectedDataZeroLevelADC(analog.ZeroMethod)}) * ScaleFactorMvPerADC ({diagnostics.ScalefactorMilliVoltsPerADC})={threshold}; SensitivityMv={analog.SensitivityMilliVoltsPerEU}\r\n";
|
||
|
|
LevelTriggerLogging.LevelTriggerLog(s);
|
||
|
|
}
|
||
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
||
|
|
return threshold;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private const double IEPE_GAIN_DIVIDER = 4.9D;
|
||
|
|
|
||
|
|
//0.2040816327F, 2.0408163265F
|
||
|
|
public static StaticInformation StaticDASIEPE1_5Info = new StaticInformation(new[]
|
||
|
|
{
|
||
|
|
2400D / (1.0D / IEPE_GAIN_DIVIDER),
|
||
|
|
2400D / (10.0D / IEPE_GAIN_DIVIDER),
|
||
|
|
});
|
||
|
|
|
||
|
|
private readonly Dictionary<DFConstantsAndEnums.ProtocolLimitedCommands, byte> _slice15MinimumProtocols = new Dictionary<DFConstantsAndEnums.ProtocolLimitedCommands, byte>();
|
||
|
|
|
||
|
|
public override bool RequireDiagnosticRateMatchSampleRate() { return false; }
|
||
|
|
|
||
|
|
public override void InitMinProto()
|
||
|
|
{
|
||
|
|
// SLICE 1.5 Protocol Limitations
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.DiangosShuntDAC] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryMSP430Firmware] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MultipleAndHybridEvents] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MultipleEvents] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AutoArm] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.FlashCardInfo] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
//SLICE2_MinimumProtocols.Add(ReqProtoVer.Commands.VoltageInsertion, 133);
|
||
|
|
//SLICE2_MinimumProtocols.Add(ReqProtoVer.Commands.SetDefaultMIF, 140);
|
||
|
|
//SLICE2_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.StackFirmwareUpdate, 137);
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.FileData] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackSensors] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.BaseSystemTime] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.PhysicalStartAddress] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.TestCommunication] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackLowPowerMode] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
//SLICE2_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.StackChannelTypeConfiguration, 134);
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SetRealtimeSampleRate] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SLICE2_OneWireID] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.HardwareRevision] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
//SLICE2_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.HardwareConfiguration, 134);
|
||
|
|
//SLICE2_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.ProgramStackChannels, 136);
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.EventFaultFlags] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.EventArmAttempts] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryActualSampleRateImmediate] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.InitHardwareInputLines] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.VoltageSysAttributes] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
//SLICE2_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.DiagnosticTwoVoltExcitation, 138);
|
||
|
|
//SLICE2_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.ExcitationLevel, 133);
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.LevelTrigger] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AttributeStoreBlocks] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryArmAndTriggerStatus_VoltageReadings] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MaxEvents] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmDiagnosticDelay] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackChannelAutoArmDiagLevel] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.FlashClear] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
//SLICE2_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.DiagnosticsMode, 133);
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MultipleSamplesRealtime] = SLICE1_5.MIN_PROTOCOL_VER;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryArmAndTriggerStatus_TimeLeftInArm] = SLICE1_5.QUERY_ARM_AND_TRIGGER_STATUS_TIME_LEFT_IN_ARM;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StartRecDelayInSecond] = SLICE1_5.START_REC_DELAY_IN_SECOND;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MeasureInternalOffset] = SLICE1_5.MEASURE_INTERNAL_OFFSET;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.IgnoreShortedStartEvent] = SLICE1_5.IGNORE_SHORTED_START_EVENT;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StartRealtimeStream] = SLICE1_5.START_REALTIME_STREAM;
|
||
|
|
_slice15MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.GenerateEvent] = 9;
|
||
|
|
MinimumProtocols = _slice15MinimumProtocols;
|
||
|
|
|
||
|
|
}
|
||
|
|
protected override DASModule MakeConfigModuleFromInfoModule(InfoResult.Module infoModule)
|
||
|
|
{
|
||
|
|
var configModule = new DASModule(infoModule.ModuleArrayIndex, this);
|
||
|
|
configModule.Channels = new AnalogInputDASChannel[infoModule.NumberOfChannels];
|
||
|
|
|
||
|
|
for (var i = 0; i < infoModule.NumberOfChannels; i++)
|
||
|
|
{
|
||
|
|
var channel = new AnalogInputDASChannel(configModule, i);
|
||
|
|
if (infoModule.TypeOfModule == DFConstantsAndEnums.ModuleType.SLICEIEPE)
|
||
|
|
{
|
||
|
|
channel.IEPEChannel = true;
|
||
|
|
channel.SupportedBridges = new[] { SensorConstants.BridgeType.IEPE };
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
channel.IEPEChannel = false;
|
||
|
|
channel.SupportedBridges = new[] {SensorConstants.BridgeType.FullBridge,
|
||
|
|
SensorConstants.BridgeType.HalfBridge};
|
||
|
|
}
|
||
|
|
configModule.Channels[i] = channel;
|
||
|
|
}
|
||
|
|
return configModule;
|
||
|
|
}
|
||
|
|
|
||
|
|
protected override void PerformVoltageInsertionCheck(IDiagnosticActions[] channelActions, SliceServiceAsyncInfo info, ref IDiagnosticResult[] results)
|
||
|
|
{
|
||
|
|
// first count how many we need to do it on
|
||
|
|
var numToMeasure = channelActions.Count(a => a.PerformVoltageInsertCheck);
|
||
|
|
if (numToMeasure == 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
//slice 1 bridges can not handle voltage insertion ...
|
||
|
|
|
||
|
|
for (var idx = 0; idx < channelActions.Length; idx++)
|
||
|
|
{
|
||
|
|
if (channelActions[idx].PerformVoltageInsertCheck)
|
||
|
|
{
|
||
|
|
results[idx].MeasuredGain = null;
|
||
|
|
results[idx].TargetGain = null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Measure the internal offset on the channels that have it flagged
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="channelActions">An array of actions. One entry per channel</param>
|
||
|
|
/// <param name="info">Our async data</param>
|
||
|
|
/// <param name="results">An array of results. One entry per channel</param>
|
||
|
|
/// <param name="bFinalOffset"></param>
|
||
|
|
protected override void MeasureInternalOffset(IDiagnosticActions[] channelActions, SliceServiceAsyncInfo info, ref IDiagnosticResult[] results, bool bFinalOffset)
|
||
|
|
{
|
||
|
|
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.MeasureInternalOffset))
|
||
|
|
{
|
||
|
|
#region New internal offset measure
|
||
|
|
// first count how many we need to do it on
|
||
|
|
var numToMeasure = channelActions.Count(a => a.MeasureInternalOffset);
|
||
|
|
if (numToMeasure == 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var measuredChannelBiasADC = new short[ChannelDiagnostics.Length];
|
||
|
|
for (var idx = 0; idx < channelActions.Length; idx++)
|
||
|
|
{
|
||
|
|
if (!ChannelDiagnostics[idx].MeasureInternalOffset) continue;
|
||
|
|
var qsab = new QuerySystemAttribute_Bridge(this)
|
||
|
|
{
|
||
|
|
// Get Module number from DAS Channel Number
|
||
|
|
DeviceID = Convert.ToByte(1 + ChannelDiagnostics[idx].DASChannelNumber / 3),
|
||
|
|
// Get Key offset from DAS Channel Number
|
||
|
|
Key = AttributeTypes.SystemAttributes_Bridge.BIAS_ADC_A + (byte)(ChannelDiagnostics[idx].DASChannelNumber % 3)
|
||
|
|
};
|
||
|
|
qsab.SyncExecute();
|
||
|
|
|
||
|
|
if ((ushort)qsab.Value == 0)
|
||
|
|
{
|
||
|
|
// If value comes back as zero our base supports the bridge
|
||
|
|
// attribute but the bridge does not, or has not been calibrated
|
||
|
|
measuredChannelBiasADC[idx] = 0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// convert from ushort to short
|
||
|
|
measuredChannelBiasADC[idx] = Convert.ToInt16((ushort)qsab.Value - Math.Pow(2, 15));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for (var idx = 0; idx < results.Length; idx++)
|
||
|
|
{
|
||
|
|
info.NewData(new ServiceCallbackData.DiagnosticNewData()
|
||
|
|
{
|
||
|
|
Result = measuredChannelBiasADC[idx],
|
||
|
|
DasChannelNumber = results[idx].DASChannelNumber,
|
||
|
|
Action = ServiceCallbackData.DiagnosticNewData.Actions.MeasureInternalOffset
|
||
|
|
});
|
||
|
|
|
||
|
|
//attempt to resolve the removed adc by using the before and after info
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (bFinalOffset)
|
||
|
|
{
|
||
|
|
if (null != results[idx] && channelActions[idx].RemoveOffset)
|
||
|
|
{
|
||
|
|
results[idx].RemovedInternalOffsetADC =
|
||
|
|
Convert.ToInt32((double)results[idx].MeasuredInternalOffsetMilliVolts / results[idx].ScalefactorMilliVoltsPerADC -
|
||
|
|
measuredChannelBiasADC[idx]);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
results[idx].RemovedInternalOffsetADC = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
results[idx].MeasuredInternalOffsetMilliVolts = measuredChannelBiasADC[idx] * results[idx].ScalefactorMilliVoltsPerADC;
|
||
|
|
results[idx].ZeroMVInADC = Convert.ToInt16(measuredChannelBiasADC[idx]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
APILogger.Log(
|
||
|
|
$"Error Retrieving Internal Offset on {SerialNumber} channel {results[idx].DASChannelNumber}", ex);
|
||
|
|
results[idx].RemovedInternalOffsetADC = 0;
|
||
|
|
results[idx].MeasuredInternalOffsetMilliVolts = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
APILogger.Log("Error Retrieving Internal Offset", ex);
|
||
|
|
foreach (var dr in results)
|
||
|
|
{
|
||
|
|
dr.RemovedInternalOffsetADC = 0;
|
||
|
|
dr.MeasuredInternalOffsetMilliVolts = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
//Command not supported
|
||
|
|
foreach (var dr in results)
|
||
|
|
{
|
||
|
|
dr.RemovedInternalOffsetADC = 0;
|
||
|
|
dr.MeasuredInternalOffsetMilliVolts = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Convert gain code to value based on Slice 1 conversion table
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="gainCode"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
protected override double GainCodeToGainValue(ushort gainCode)
|
||
|
|
{
|
||
|
|
//Run the same code as Slice 1.0, not base:GainCodeToGainValue which is SLICE 2
|
||
|
|
|
||
|
|
var gainValueString = ((GainCodes)gainCode).ToString();
|
||
|
|
if (!double.TryParse(gainValueString.TrimStart('G'), out var gainValue))
|
||
|
|
{
|
||
|
|
gainValue = 1.0D;
|
||
|
|
}
|
||
|
|
|
||
|
|
return gainValue;
|
||
|
|
}
|
||
|
|
|
||
|
|
public override double[] GetNominalRanges(SensorConstants.BridgeType bridgeType)
|
||
|
|
{
|
||
|
|
switch (bridgeType)
|
||
|
|
{
|
||
|
|
case SensorConstants.BridgeType.IEPE:
|
||
|
|
return WinUSBSlice.StaticDASIEPEInfo.NominalRanges;
|
||
|
|
default:
|
||
|
|
return WinUSBSlice.StaticDASBridgeInfo.NominalRanges;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public override bool CheckAAF(float rate) { return true; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// hardcoded constants right now ... maybe these belong in attributes in the firmware!
|
||
|
|
/// </summary>
|
||
|
|
protected override uint MaxAAFilterRateHz => SLICE1_5.MaxAAFilterRateHz;
|
||
|
|
|
||
|
|
protected override uint MaxSampleRateHz => 500000;
|
||
|
|
|
||
|
|
public override long MaxMemory()
|
||
|
|
{
|
||
|
|
if (null == DASInfo || 0 == DASInfo.NumberOfBytesPerSampleClock) { return 0; }
|
||
|
|
|
||
|
|
if (null == DASInfo.MaxEventStorageSpaceInBytes)
|
||
|
|
{
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return (long)(DASInfo.MaxEventStorageSpaceInBytes / DASInfo.NumberOfBytesPerSampleClock);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc />
|
||
|
|
/// <summary>
|
||
|
|
/// calculates the max sample rate
|
||
|
|
/// these are not exact max sample rates, but convenient close enough limits
|
||
|
|
/// drop 100k every module after 3 (starting at 500k)
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public override uint MaxSampleRate(int numberOfConfiguredChannels)
|
||
|
|
{
|
||
|
|
switch (DASInfo.Modules.Length)
|
||
|
|
{
|
||
|
|
case 1:
|
||
|
|
return MaxSampleRateHz;
|
||
|
|
case 2:
|
||
|
|
return 400000;
|
||
|
|
case 3:
|
||
|
|
return 300000;
|
||
|
|
case 4:
|
||
|
|
default:
|
||
|
|
return 200000;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public override uint MaxAAFilterRate()
|
||
|
|
{
|
||
|
|
return MaxAAFilterRateHz;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc />
|
||
|
|
/// <summary>
|
||
|
|
/// QueryEventData also is customized for SLICE 1.5, it needs to perform SLICE 1.5 specific data marshalling
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
protected override QueryEventDataBase GetQueryEventData()
|
||
|
|
{
|
||
|
|
return new QueryEventData_SLICE1_5(this, AbstractCommandBase.Default_IO_Timeout);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <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_SLICE1_5 : 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_SLICE1_5(DTS.Common.Interface.DASFactory.ICommunication sock)
|
||
|
|
: base(sock) { LogCommands = false; }
|
||
|
|
|
||
|
|
public QueryEventData_SLICE1_5(DTS.Common.Interface.DASFactory.ICommunication sock, int timeoutMillisec)
|
||
|
|
: base(sock, timeoutMillisec) { LogCommands = false; }
|
||
|
|
|
||
|
|
private ulong GetRequestedStartSport()
|
||
|
|
{
|
||
|
|
var slice15Usb = recorder as SLICE1_5<WINUSBConnection>;
|
||
|
|
if (recorder is SLICE1_5<EthernetConnection> slice15Ethernet)
|
||
|
|
{
|
||
|
|
return ((WhatToDownloadSlice2)slice15Ethernet.WhatToDownload).RequestedStartSport;
|
||
|
|
}
|
||
|
|
if (null != slice15Usb)
|
||
|
|
{
|
||
|
|
return ((WhatToDownloadSlice2)slice15Usb.WhatToDownload).RequestedStartSport;
|
||
|
|
}
|
||
|
|
throw new NotSupportedException("SLICE1_5::GetRequestedStartSport not supported for " + recorder.ConnectString);
|
||
|
|
}
|
||
|
|
private void PushLeftOverData(ushort[] daters)
|
||
|
|
{
|
||
|
|
var slice15Usb = recorder as SLICE1_5<WINUSBConnection>;
|
||
|
|
var slice15Ethernet = recorder as SLICE1_5<EthernetConnection>;
|
||
|
|
if (null != slice15Usb) { slice15Usb.PushLeftOverData(daters); }
|
||
|
|
else
|
||
|
|
{
|
||
|
|
slice15Ethernet?.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==" + CommandPacketBase.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 = GetRequestedStartSport();
|
||
|
|
|
||
|
|
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(_data.Length / (double)ChannelsDownloaded));
|
||
|
|
var leftover = new ushort[_data.Length - (samplesProcessed * ChannelsDownloaded)];
|
||
|
|
for (var i = 0; i < leftover.Length; i++)
|
||
|
|
{
|
||
|
|
leftover[i] = _data[i + samplesProcessed * ChannelsDownloaded];
|
||
|
|
}
|
||
|
|
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);
|
||
|
|
var samplesProcessed = Convert.ToInt32(Math.Truncate((_data.Length - (double)offset) / ChannelsDownloaded));
|
||
|
|
var leftover = new ushort[(_data.Length - offset) - (samplesProcessed * ChannelsDownloaded)];
|
||
|
|
for (var i = 0; i < leftover.Length; i++)
|
||
|
|
{
|
||
|
|
leftover[i] = _data[i + offset + samplesProcessed * ChannelsDownloaded];
|
||
|
|
}
|
||
|
|
PushLeftOverData(leftover);
|
||
|
|
}
|
||
|
|
|
||
|
|
return UserCallback(cbReport);
|
||
|
|
}
|
||
|
|
|
||
|
|
protected virtual ushort[] PopLeftOverData()
|
||
|
|
{
|
||
|
|
var slice15Usb = recorder as SLICE1_5<WINUSBConnection>;
|
||
|
|
var slice15Ethernet = recorder as SLICE1_5<EthernetConnection>;
|
||
|
|
if (null != slice15Usb)
|
||
|
|
{
|
||
|
|
return slice15Usb.PopLeftOverData();
|
||
|
|
}
|
||
|
|
if (null != slice15Ethernet)
|
||
|
|
{
|
||
|
|
return slice15Ethernet.PopLeftOverData();
|
||
|
|
}
|
||
|
|
throw new NotSupportedException("SLICE1_5::PopLeftOverData not supported for " + recorder.ConnectString);
|
||
|
|
}
|
||
|
|
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) < GetRequestedStartSport())//(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 (GetRequestedStartSport() > FirstSample)
|
||
|
|
{
|
||
|
|
offset = Convert.ToInt32(GetRequestedStartSport() - 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 rv = new List<short>(1024);
|
||
|
|
|
||
|
|
System.Diagnostics.Trace.Assert(_data.Length > offset, @"data length is less than offset");
|
||
|
|
|
||
|
|
var completeSamples = Convert.ToInt32(Math.Truncate((_data.Length - offset) / (double)ChannelsDownloaded));
|
||
|
|
|
||
|
|
for (var i = 0; i < completeSamples; i++)
|
||
|
|
{
|
||
|
|
val = _data[i * ChannelsDownloaded + channel + offset];
|
||
|
|
rv.Add((short)((((val & 0x00FF) << 8) | ((val >> 8) & 0x00FF)) + 0x8000));
|
||
|
|
}
|
||
|
|
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];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|