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 : SLICE2_Base, 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; } public override int[] GetStackChannelConfigTypes() => new int[] { 0 }; /// /// 14269 Implement SLICE PRO and Base+ RTC /// my records indicate SLICE1.5 has always supported this feature ... /// public override bool SupportsTimeSynchronization => true; /// /// /// gets the expected excitation in mV for a given channel /// returns 0 if excitation could not be retrieved, otherwise excitation in mV /// /// /// /// 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 _slice15MinimumProtocols = new Dictionary(); 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; } } } /// /// Measure the internal offset on the channels that have it flagged /// /// An array of actions. One entry per channel /// Our async data /// An array of results. One entry per channel /// 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; } } } /// /// Convert gain code to value based on Slice 1 conversion table /// /// /// 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; } /// /// hardcoded constants right now ... maybe these belong in attributes in the firmware! /// 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); } /// /// /// 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) /// /// 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; } /// /// /// QueryEventData also is customized for SLICE 1.5, it needs to perform SLICE 1.5 specific data marshalling /// /// protected override QueryEventDataBase GetQueryEventData() { return new QueryEventData_SLICE1_5(this, AbstractCommandBase.Default_IO_Timeout); } } /// /// 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 ...] /// 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; if (recorder is SLICE1_5 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; var slice15Ethernet = recorder as SLICE1_5; 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; var slice15Ethernet = recorder as SLICE1_5; 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(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]; } } } }