using DTS.Common.Classes.DASFactory; using DTS.Common.Constant.DASSpecific; using DTS.Common.Enums; using DTS.Common.Enums.DASFactory; using DTS.Common.Enums.Sensors; using DTS.Common.ICommunication; using DTS.Common.Interface.Connection; using DTS.Common.Interface.DASFactory; using DTS.Common.Interface.DASFactory.Config; using DTS.Common.Interface.DASFactory.Diagnostics; using DTS.Common.Interface.DASFactory.Download; using DTS.Common.Utilities.Logging; using DTS.Common.Utils; using DTS.DASLib.Command; using DTS.DASLib.Command.SLICE; using DTS.DASLib.Command.SLICE.RealtimeCommands; using DTS.DASLib.Service.Interfaces; using System; using System.Collections.Generic; using System.IO.Ports; using System.Linq; using static DTS.Common.Enums.DASFactory.DFConstantsAndEnums; namespace DTS.DASLib.Service { #pragma warning disable S101 // Types should be named in PascalCase public class SLICE6AIRTC : SLICE6_Base, IAlignUDPToPPSAware, IDASReconfigure, ITCDiagnosticResults, IUARTDownloadActions, IUARTDownload where T : IConnection, new() #pragma warning restore S101 // Types should be named in PascalCase { public IUARTDownloadRequest WhatUARTToDownload { get; set; } public void SetWhatUARTToDownload(IUARTDownloadRequest request, bool bSetInDb = true) { UARTDownloadRequest.SetWhatToDownload(this, request, bSetInDb); } 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 void UARTDownload(ServiceCallback callback, object userData) { var state = new SliceUARTDownloadState(callback, userData, null); state.Error("Not supported"); } /// /// Retrieve UART info about available events to download /// /// The function to call with information /// Whatever you want to pass along 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(ProtocolLimitedCommands.QueryUARTDownload)) { info.Error("Query UART download is not supported"); } } 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(ProtocolLimitedCommands.GetUARTSettings)) { info.Error("Get UART settings is not supported"); return; } var bLocked = false; try { Lock(); bLocked = true; try { var qsaUARTSettings = new QuerySystemAttributeSLICE6AIR(this, AbstractCommandBase.Default_IO_Timeout); qsaUARTSettings.Key = AttributeTypes.SystemAttributesSLICE6AIR.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(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 SetSystemAttributeSLICE6AIR(this, AbstractCommandBase.Default_IO_Timeout); ssaUARTSettings.SetValue(AttributeTypes.SystemAttributesSLICE6AIR.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(); } } } public ITCDiagnosticResult[] TCDiagnosticResults { get; private set; } = new ITCDiagnosticResult[0]; public void ClearTCDiagnosticResults() { TCDiagnosticResults = new ITCDiagnosticResult[0]; } public void SetTCDiagnosticResults(ITCDiagnosticResult[] results) { TCDiagnosticResults = results; } private void InitializeTCDiagnostics() { TCDiagnosticResults = new TCDiagnosticResult[24]; for (var i = 0; i < TCDiagnosticResults.Length; i++) { TCDiagnosticResults[i] = new TCDiagnosticResult() { ChannelIndex = i, ChannelName = GetChannelName(i), Status = Common.Interface.Sensors.AnalogDiagnostics.DiagnosticStatus.Untested, CurrentReading = null }; } } protected override void AsyncDiagnosAndGetResults(object asyncInfo) { if (!(asyncInfo is SliceServiceAsyncInfo info)) { return; } InitializeTCDiagnostics(); _ = MeasureOffsets(info); _ = MeasureShunts(info); base.AsyncDiagnosAndGetResults(asyncInfo); } private bool MeasureShunts(SliceServiceAsyncInfo info) { try { var queryChannelShuntResults = new QueryChannelShuntResults(this); queryChannelShuntResults.DeviceID = 0; // send to base byte[] shuntChannelList = new byte[TCDiagnosticResults.Length]; int channelCounter = 0; for (int idx = 0; idx < TCDiagnosticResults.Length; idx++) { shuntChannelList[channelCounter] = (byte)TCDiagnosticResults[idx].ChannelIndex; channelCounter++; } queryChannelShuntResults.StackChannelList = shuntChannelList; queryChannelShuntResults.SyncExecute(); for( var idx = 0; idx < TCDiagnosticResults.Length; idx++) { var actual = queryChannelShuntResults.ActualDeflectionMV[idx]; if (Utils.IsZero(actual)) { TCDiagnosticResults[idx].ConnectionStatus = ConnectionStatuses.ModuleNotConnected; } else if (Utils.AlmostEqual(actual, 100)) { TCDiagnosticResults[idx].ConnectionStatus = ConnectionStatuses.Connected; } else { TCDiagnosticResults[idx].ConnectionStatus = ConnectionStatuses.NotConnected; } } return true; } catch( Exception ex) { APILogger.Log(ex); info.Error($"Failed to check connections [{SerialNumber}] - {ex.Message}"); return false; } } private bool MeasureOffsets(SliceServiceAsyncInfo info) { try { var measureOffset = new RetrieveSampleAverage(this); measureOffset.DeviceID = 0; // send to base measureOffset.Samples = 4000; if (measureOffset.Samples < 1) { measureOffset.Samples = 1; } measureOffset.SyncExecute(); for( var i = 0; i < TCDiagnosticResults.Length; i++) { var result = TCDiagnosticResults[i]; result.CurrentReading = measureOffset.GetChannelData(result.ChannelIndex) * .1D; } return true; } catch (Exception ex) { APILogger.Log(ex); info.Error($"Failed to retrieve average temperatures [{SerialNumber}] - {ex.Message}"); return false; } } private string GetChannelName(int index) { if (null == ((IDASCommunication)this).ConfigData) { return string.Empty; } var config = ((IDASCommunication)this).ConfigData; if (config.Modules == null || 0 == config.Modules.Length) { return string.Empty; } var match = Array.Find(config.Modules[0].Channels, x => x.Number == index); if (null == match) { return string.Empty; } return string.IsNullOrWhiteSpace(match.UserChannelName) ? match.IsoChannelName : match.UserChannelName; } private const int MAX_TMATS_FILE_LENGTH = 32000; public override bool IsSlice6AirTc() { return true; } public override int GetMaxFileLengthTMATS() { return MAX_TMATS_FILE_LENGTH; } public bool AlignUDPToPPS { get; set; } public override bool SupportsRemoveLeapSeconds => true; public override bool SupportsADCSamplesPerPacket => true; protected override bool RequiresNon0QualificationSamples => true; protected override byte[] GetRTChannelIndices(RealTimeAsyncPacket packet) { switch(_maxModuleCount) { case 0: return new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; case 1: return new byte[] { 0, 1, 2, 3, 4, 5 ,6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; case 2: default: return new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; } } protected override IGetRealtimeSamples GetRealtimeSamplesClass(DTS.Common.Interface.DASFactory.ICommunication iCommunication, bool bPolling = false) { if (IsCommandSupported(ProtocolLimitedCommands.StartRealtimeStream) && !bPolling) { return new RealtimeStreamingNextSamples(iCommunication) { SignedData = true }; } return base.GetRealtimeSamplesClass(this, bPolling); } public override void SetIsStreamingSupported(bool supported = false) { IsStreamingSupported = true; } ///// ///// the order of this DAS among multiple das ///// //public int DASIndex { get; set; } = -1; public override void InitMinProto() { // SLICE 6.0 Protocol Limitations SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.AutoArm] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.AutoArmRepeatEnable] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.SetDefaultMIF] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.FileData] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.StackSensors] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.BaseSystemTime] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.TestCommunication] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.StackLowPowerMode] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.SetRealtimeSampleRate] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.SLICE2_OneWireID] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.HardwareRevision] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.HardwareConfiguration] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.EventFaultFlags] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.EventArmAttempts] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.QueryActualSampleRateImmediate] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.InitHardwareInputLines] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.VoltageSysAttributes] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.AttributeStoreBlocks] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.QueryArmAndTriggerStatus_VoltageReadings] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.MaxEvents] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.AutoArmDiagnosticDelay] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.StackChannelAutoArmDiagLevel] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.FlashClear] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.MultipleSamplesRealtime] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.BaseCalibrationDate] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.IgnoreShortedStartEvent] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.ResetAttributeStore] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.PTPTimestamp] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.StartRealtimeStream] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.UDPRealtimeStream] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.GenerateEvent] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.PTPSyncStatus] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.SetClockSyncConfig] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.SetDSPFilterSettings] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.PTPDomainID] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.RemoveLeapSeconds] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.UDPAlignOnPPS] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.ADCSamplesPerPacket] = SLICE6AIRTC.ADC_SAMPLES_PER_PACKET_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.GetUARTSettings] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.SetUARTSettings] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.AutoArmUDPSetting] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[ProtocolLimitedCommands.AutoArmRecordDelay] = SLICE6AIRTC.MIN_PROTOCOL_VER; MinimumProtocols = SLICE6AIR_TC_MinimumProtocols; } protected class S6ATCConfigAttributes : SLICE6ConfigAttributes { public override void ConfigureCoupling(bool[] IsACCoupledArray) { //not supported in S6ATC - so NOOP } public override void ConfigureBridge(byte[] bridgeModeArray) { //not supported in S6A-TC - so NOOP } public override void ConfigureBridgeResistance(ushort[] BridgeResistanceArray) { //not supported in S6A-TC - so NOOP } public S6ATCConfigAttributes(ICommunication _com) : base(_com) { } } protected override ConfigAttributes GetConfigAttributes(ICommunication com) { return new S6ATCConfigAttributes(this); } #region protocol settings/overrides private readonly Dictionary SLICE6AIR_TC_MinimumProtocols = new Dictionary(); protected override int MIN_PROTOCOL_TMATS_INTERVAL => SLICE6AIRBR.MIN_PROTOCOL_VER; private uint maxSampleRateHz = 0; protected override uint MaxSampleRateHz { get { if (0 == maxSampleRateHz) { try { var qsa = new QuerySystemAttributeSLICE6(this) { Key = AttributeTypes.SystemAttributesSLICE6.MaximumSampleRate }; qsa.SyncExecute(); maxSampleRateHz = (uint)qsa.Value; } catch (Exception ex) { APILogger.Log("Error getting S6A-BR max sample rate, returning 50K"); APILogger.LogException(ex); return 50000; } } return maxSampleRateHz; } } void IDASReconfigure.SetMaxModuleCount(int count) { SetMaxModuleCount(count, false); _maxModuleCount = count; } private int _maxModuleCount = -1; /// /// gets the physical max number of modules. /// this value is cached /// /// int IDASReconfigure.GetMaxModuleCount() { _maxModuleCount = GetMaxModuleCount(_maxModuleCount); return _maxModuleCount; } #endregion protected override DASModule MakeConfigModuleFromInfoModule(InfoResult.Module infoModule) { var configModule = new DASModule(infoModule.ModuleArrayIndex, this); configModule.Channels = new DASChannel[infoModule.NumberOfChannels]; for (var i = 0; i < infoModule.NumberOfChannels; i++) { if (ModuleType.StreamOut == configModule.ModuleType()) { var streamOutChannel = new StreamOutputDASChannel(configModule, i); configModule.Channels[i] = streamOutChannel; } else if ( ModuleType.UART == configModule.ModuleType()) { configModule.Channels[i] = new UARTInputDASChannel(configModule, i); } else { var channel = new AnalogInputDASChannel(configModule, i); channel.SupportedBridges = new SensorConstants.BridgeType[] { SensorConstants.BridgeType.FullBridge, SensorConstants.BridgeType.HalfBridge, }; configModule.Channels[i] = channel; } } return configModule; } /// /// we can probably simplify and take common items (slice6+slice1) out of this function, but for now /// it's mostly a copy of SLICE1.AsyncConfigure /// /// protected override void AsyncConfigure(object configAsyncInfo) { var info = configAsyncInfo as SliceConfigServiceAsyncInfo; SetUDPAlignOnPPS(); SetRemoveSeconds(); SetADCSamplesPerPacket(info.StreamADCPerPacket[this]); //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(ProtocolLimitedCommands.ProgramStackChannels)) { ReconfigureAccordingToConfig(); } PresetSampleRate(); SetVoltageRequirements(); SetPolarity(); SetArmDisableShortCheck(); try { Lock(); bReleased = false; // loop thru the modules (slices) and configure the non-UART channels var numChannels = DASInfo.Modules.Sum(mod => mod.NumberOfChannels); var numStreamingChannels = DASInfo.Modules.Sum(mod => ModuleType.StreamOut == mod.TypeOfModule ? mod.NumberOfChannels : 0); var numUart = DASInfo.Modules.Sum(mod => ModuleType.UART == mod.TypeOfModule ? mod.NumberOfChannels : 0); var rangeArray = new float[numChannels]; var bridgeModeArray = new byte[numChannels]; var BridgeResistanceArray = new ushort[numChannels]; var IsACCoupledArray = new bool[numChannels]; //18294 Implement Bridge AC / DC coupling(fw update dependent) var bridgeACCouplingArray = 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(); var bModified = false; CommonConfigureWork(diagnosticChannels, qualificationSamples, ref bReleased, info, bridgeModeArray, IsACCoupledArray, BridgeResistanceArray, ref bModified, rangeArray, enableUpperLevelTriggerThreshold, upperLevelTriggerThreshold, enableLowerLevelTriggerThreshold, lowerLevelTriggerThreshold, bridgeACCouplingArray); if (bReleased) { return; } // report progress progressValue = 5; info.Progress(progressValue); StoreConfigAttributes(info, rangeArray, ref bReleased, ref progressValue, bridgeModeArray, IsACCoupledArray, BridgeResistanceArray, enableLowerLevelTriggerThreshold, lowerLevelTriggerThreshold, enableUpperLevelTriggerThreshold, upperLevelTriggerThreshold, qualificationSamples, numChannels, out var config, bridgeACCouplingArray, numUart, numStreamingChannels); progressValue = 20; info.Progress(progressValue); RemainingConfigWork(ref progressValue, info, diagnosticChannels, config, ref bReleased, null, null, null); } 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(); } /// /// returns true if the device is known to be streaming /// does not query device, just returns a flag if it has been set /// 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; } public override int[] GetStackChannelConfigTypes() { try { var queryChannelTypes = new QueryArmAttribute(this) { Key = AttributeTypes.ArmAndEventAttributes.StackChannelConfigType }; queryChannelTypes.SyncExecute(); var list = new List(); if (queryChannelTypes.Value is byte[] bytes) { foreach (var channelType in bytes) { list.Add(channelType); } } return list.ToArray(); } catch (Exception ex) { APILogger.Log(ex); return new int[] { 0 }; } } } }