using DTS.Common.Constant.DASSpecific; 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.Utilities.Logging; using DTS.DASLib.Command.SLICE; using DTS.DASLib.Command.SLICE.RealtimeCommands; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Remoting.Messaging; 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 where T : IConnection, new() #pragma warning restore S101 // Types should be named in PascalCase { 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[DFConstantsAndEnums.ProtocolLimitedCommands.AutoArm] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmRepeatEnable] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SetDefaultMIF] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.FileData] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackSensors] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.BaseSystemTime] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.TestCommunication] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackLowPowerMode] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SetRealtimeSampleRate] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SLICE2_OneWireID] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.HardwareRevision] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.HardwareConfiguration] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.EventFaultFlags] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.EventArmAttempts] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryActualSampleRateImmediate] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.InitHardwareInputLines] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.VoltageSysAttributes] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AttributeStoreBlocks] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryArmAndTriggerStatus_VoltageReadings] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MaxEvents] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmDiagnosticDelay] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackChannelAutoArmDiagLevel] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.FlashClear] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MultipleSamplesRealtime] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.BaseCalibrationDate] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.IgnoreShortedStartEvent] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.ResetAttributeStore] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.PTPTimestamp] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StartRecDelayInSecond] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StartRealtimeStream] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.UDPRealtimeStream] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.GenerateEvent] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.PTPSyncStatus] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SetClockSyncConfig] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SetDSPFilterSettings] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.PTPDomainID] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.RemoveLeapSeconds] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.UDPAlignOnPPS] = SLICE6AIRTC.MIN_PROTOCOL_VER; SLICE6AIR_TC_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.ADCSamplesPerPacket] = SLICE6AIRTC.ADC_SAMPLES_PER_PACKET_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 (DFConstantsAndEnums.ModuleType.StreamOut == configModule.ModuleType()) { var streamOutChannel = new StreamOutputDASChannel(configModule, i); configModule.Channels[i] = streamOutChannel; } 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(DFConstantsAndEnums.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 => DFConstantsAndEnums.ModuleType.StreamOut == mod.TypeOfModule ? mod.NumberOfChannels : 0); var rangeArray = new float[numChannels]; //var IsHalfBridgeArray = new bool[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, 0, 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 }; } } } }