Files
DP44/DataPRO/IService/.svn/pristine/98/9814d8bd241524e56696ea22227ea57a8c7a88c7.svn-base

640 lines
32 KiB
Plaintext
Raw Normal View History

2026-04-17 14:55:32 -04:00
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];
}
}
}
}