using System; using System.Collections.Generic; using System.IO; using System.IO.Ports; using System.Linq; using System.Threading; using DTS.Common.Enums.DASFactory; using DTS.Common.Enums.Sensors; using DTS.Common.Interface.DASFactory; using DTS.Common.Interface.Connection; using DTS.Common.Interface.TestSetups; using DTS.Common.Utilities; using DTS.Common.Utilities.Logging; using DTS.Common.Utils; using DTS.DASLib.Command; using DTS.DASLib.Command.SLICE; using DTS.DASLib.Service.Interfaces; using DTS.Common.ICommunication; using DTS.Common.Interface.DASFactory.Download; using DTS.DASLib.Command.SLICE.DownloadCommands; using DTS.Common.Interface.StatusAndProgressBar; using DTS.Common.Constant.DASSpecific; using DTS.Common.Enums; using DTS.Common; using DTS.Common.Interface.DASFactory.Config; namespace DTS.DASLib.Service { public class SLICE6AIR : SLICE6_Base, ITestDASOrder, IUARTDownload, IUARTDownloadActions, IAlignUDPToPPSAware where T : IConnection, new() { public bool AlignUDPToPPS { get; set; } public override bool SupportsADCSamplesPerPacket => true; public override bool SupportsRemoveLeapSeconds => true; protected override bool AdjustInputRange(AnalogInputDASChannel analog) { return analog.IEPEChannel; } protected override bool SupportsDiagnosticsMode => true; public override void SetIsStreamingSupported(bool supported) { IsStreamingSupported = true; } protected override void FirmwareVersionUpdated() { base.FirmwareVersionUpdated(); if (DFConstantsAndEnums.IsSLICE6ERFirmware(FirmwareVersion)) { IsEthernetRecorder = true; } } private bool _IsEthernetRecorder = false; public bool IsEthernetRecorder { get => _IsEthernetRecorder; set { _IsEthernetRecorder = value; if (value) { SetEthernetRecorderProtocolMins(); } } } private void SetEthernetRecorderProtocolMins() { SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryTiltSensorData] = byte.MaxValue; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.InSliceTiltSensorADCPre] = byte.MaxValue; } protected override DASModule MakeConfigModuleFromInfoModule(InfoResult.Module infoModule) { //per LP we can make this simpler, S6A always supports 1/2,Full,IEPE var configModule = new DASModule(infoModule.ModuleArrayIndex, this); configModule.Channels = new DASChannel[infoModule.NumberOfChannels]; for (var i = 0; i < infoModule.NumberOfChannels; i++) { if (DFConstantsAndEnums.ModuleType.UART == configModule.ModuleType()) { var uartChannel = new UARTInputDASChannel(configModule, i); configModule.Channels[i] = uartChannel; } else if (DFConstantsAndEnums.ModuleType.StreamOut == configModule.ModuleType()) { var streamOutChannel = new StreamOutputDASChannel(configModule, i); configModule.Channels[i] = streamOutChannel; } else if (DFConstantsAndEnums.ModuleType.StreamIn == configModule.ModuleType()) { var streamInChannel = new StreamInputDASChannel(configModule, i); configModule.Channels[i] = streamInChannel; } else { var channel = new AnalogInputDASChannel(configModule, i); channel.SupportedBridges = new SensorConstants.BridgeType[] { SensorConstants.BridgeType.FullBridge, SensorConstants.BridgeType.HalfBridge, SensorConstants.BridgeType.IEPE }; configModule.Channels[i] = channel; } } return configModule; } private const byte DEVICE_STREAMING_ONLY = 1; protected override void AsyncAutoDetect(object o) { if (!(o is AutoDetectServiceAsyncInfo info)) { return; } if (GetIsStreaming()) { //if we are streaming avoid getting this information info.Success(); return; } if (null == DASInfo || null == DASInfo.Modules || 0 == DASInfo.Modules.Length || null == ConfigData || 0 == ConfigData.Modules.Length) { info.Error($"no configuration on unit {SerialNumber}"); return; } if (DASInfo.Modules[0].IsProgrammable) { var channels = new List(); foreach (var module in ConfigData.Modules) { foreach (var channel in module.Channels) { channels.Add(SetStackChannelTypeConfiguration.ChannelTypes.AUTO_DETECT); } } var cmd = new SetStackChannelTypeConfiguration(this); cmd.SetValue(channels.ToArray()); if (info.QueryConfiguration) { var query = new QueryStackSensorIDs(this); query.Exec(); var idx = 0; foreach (var m in ConfigData.Modules) { foreach (var c in m.Channels) { if (c is AnalogInputDASChannel) { switch (Convert.ToInt32(query.Types[idx])) { case (int)SetStackChannelTypeConfiguration.ChannelTypes.FORCE_IEPE: (c as AnalogInputDASChannel).IEPEChannel = true; break; case (int)SetStackChannelTypeConfiguration.ChannelTypes.FORCE_IEPE_LOW: (c as AnalogInputDASChannel).IEPEChannel = true; break; default: (c as AnalogInputDASChannel).IEPEChannel = false; break; } var id = new EID(HexEncoding.ToString(query.IDs[idx])); if (id.IsValid() && !RunTestVariables.BypassEIDRead) { c.IDs = new EID[] { id }; } } idx++; } } } } try { // FB15353 Is this device hardware configured for streaming only? var qsaDeviceStreamingOnly = new QuerySystemAttributeSLICE6AIR(this, QuerySystemAttribute.Default_IO_Timeout); qsaDeviceStreamingOnly.Key = AttributeTypes.SystemAttributesSLICE6AIR.S6A_DeviceStreamingOnly; qsaDeviceStreamingOnly.SyncExecute(); //we made it, set results DASInfo.DeviceStreamingOnly = (DEVICE_STREAMING_ONLY == (byte)qsaDeviceStreamingOnly.Value); } catch (Exception ex) { APILogger.Log("Problem getting Device Streaming only system attribute", ex); } info.Success(); } public override double[] GetNominalRanges(SensorConstants.BridgeType bridgeType) { //FB15462 separate S6 gain limits from S6A switch (bridgeType) { case SensorConstants.BridgeType.IEPE: return WinUSBSlice.StaticDASS6AEIEPEInfo.NominalRanges; default: return WinUSBSlice.StaticDASBridgeInfo.NominalRanges; } } #region protocol settings/overrides private readonly Dictionary SLICE6AIR_MinimumProtocols = new Dictionary(); protected override bool SupportsIEPECalSignal => IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.IEPE); private const int MIN_HW_REVISION_ETHERNET_RECORDER = 10; protected override void QueryHardwareRevisionPost() { if (_hardwareRevision >= MIN_HW_REVISION_ETHERNET_RECORDER) { IsEthernetRecorder = true; } } protected override void VerifyConfig(bool DoStrictCheck, ErrorCallback failedChallengeFunc) { if (IsEthernetRecorder) { //no verify needed } else { base.VerifyConfig(DoStrictCheck, failedChallengeFunc); } } public override void InitMinProto() { // SLICE 6 AIR Protocol Limitations SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MultipleAndHybridEvents] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MultipleEvents] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AutoArm] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmRepeatEnable] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SetDefaultMIF] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.FileData] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackSensors] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.BaseSystemTime] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.TestCommunication] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackLowPowerMode] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SetRealtimeSampleRate] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SLICE2_OneWireID] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.HardwareRevision] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.HardwareConfiguration] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.EventFaultFlags] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.EventArmAttempts] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryActualSampleRateImmediate] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.InitHardwareInputLines] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.VoltageSysAttributes] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.DiagnosticsMode] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.LevelTrigger] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AttributeStoreBlocks] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryArmAndTriggerStatus_VoltageReadings] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MaxEvents] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmDiagnosticDelay] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackChannelAutoArmDiagLevel] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.FlashClear] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.MultipleSamplesRealtime] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.BaseCalibrationDate] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.IgnoreShortedStartEvent] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.ResetAttributeStore] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.DiangosShuntDAC] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.VoltageInsertion] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.PTPTimestamp] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StartRecDelayInSecond] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryTiltSensorData] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.InSliceTiltSensorADCPre] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StartRealtimeStream] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.UDPRealtimeStream] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.ProgramStackChannels] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.IEPE] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackChannelTypeConfiguration] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackSensors] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryClockSyncStatus] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SetClockSyncConfig] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryUARTDownload] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.GetUARTSettings] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SetUARTSettings] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.SetDSPFilterSettings] = SLICE6AIR.SET_DSP_FILTER_SETTINGS; //18090 Implement chapter 10 streaming while recording(in DTS format) SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.RecordAndStreamSubSample] = SLICE6AIR.RECORD_AND_STREAM_SUBSAMPLE; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.StackChannelBridgeACCouplerEnable] = SLICE6AIR.AC_COUPLER_ENABLE; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.QueryMSP430Firmware] = SLICE6AIR.MIN_PROTOCOL_VER; //31747 Add-support-for-GPS-Time-leap-seconds SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.RemoveLeapSeconds] = SLICE6AIR.REMOVE_LEAP_SECONDS_VER; //31754 expose-number-of-ADC-samples-in-UDP-packet SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.ADCSamplesPerPacket] = SLICE6AIR.ADC_SAMPLES_PER_PACKET_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.PTPDomainID] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.ActiveRAM] = SLICE6AIR.MIN_PROTOCOL_VER; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.RecordOnBoot] = SLICE6AIR.RECORD_ON_BOOT_PROTOCOL; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmRecordDelay] = SLICE6AIR.AUTOARM_RECORD_DELAY_PROTOCOL; SLICE6AIR_MinimumProtocols[DFConstantsAndEnums.ProtocolLimitedCommands.UDPAlignOnPPS] = SLICE6AIR.UDPALIGNONPPS_PROTOCOL; MinimumProtocols = SLICE6AIR_MinimumProtocols; } #endregion private void AsyncPrepareForArmNowOBRDDR(ArmPacket info) { try { var recordingMode = GetOBRDDREquivalentMode(ConfigData.Modules[0].RecordingMode, info.MaxNumberEvents); var saa = new SetArmAttribute(this); saa.SetValue(AttributeTypes.ArmAndEventAttributes.SampleRate, ConfigData.Modules[0].SampleRateHz, true); saa.SyncExecute(); SetArmMode(recordingMode); saa = new SetArmAttribute(this); var postTriggerSamples = Convert.ToUInt64(ConfigData.Modules[0].PostTriggerSeconds * ConfigData.Modules[0].SampleRateHz); saa.SetValue(AttributeTypes.ArmAndEventAttributes.PostTriggerSamplesRequested, postTriggerSamples, true); saa.SyncExecute(); saa = new SetArmAttribute(this); var preTriggerSamples = 0UL; if (ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBuffer || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBufferPlusUART || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.RAMActive || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.MultipleEventRAMActive) { preTriggerSamples = Convert.ToUInt64(Math.Abs(ConfigData.Modules[0].PreTriggerSeconds * ConfigData.Modules[0].SampleRateHz)); } saa.SetValue(AttributeTypes.ArmAndEventAttributes.PreTriggerSamplesRequested, preTriggerSamples, true); saa.SyncExecute(); SetMaxEvents(info.MaxNumberEvents); var ssa = new SetSystemAttributeSLICE6AIR(this); ssa.SetValue(AttributeTypes.SystemAttributesSLICE6AIR.EthRecordingAddr, ConfigData.UDPReceiveAddress, true); ssa.SyncExecute(); //var ssaV = new SetSystemAttributeSLICE6DB(this); ////input min, input max, battery min, battery max //var requirements = new[] { InputLowVoltage, InputHighVoltage, BatteryLowVoltage, BatteryHighVoltage }; //ssaV.SetValue(AttributeTypes.SystemAttributesSLICE6DB.VoltageRequirements, requirements, true); //ssaV.SyncExecute(); info.Success(); } catch (Exception ex) { APILogger.Log(ex); info.Error(ex.Message); } } public override void Download(ServiceCallback callback, object userData) { if (IsEthernetRecorder) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice6A.DownloadOBRDDR", AsyncDownloadOBRDDDR, info); } else { base.Download(callback, userData); } } /// /// returns true if the DAS supports DiagnosticsFactoryExcitation attribute, /// false otherwise /// /// protected override bool SupportsDiagnosticsFactoryExcitation { get { if (IsTSRAIR()) { return false; } return base.SupportsDiagnosticsFactoryExcitation; } } public override bool IsSlice6Air() { return true; } public override bool IsScheduleEventCountSupported() { return false; } private void AsyncDownloadOBRDDDR(object o) { var info = (SliceServiceAsyncInfo)o; try { var queryEthernetEventInfo = new QueryEthernetEventInfo(this); queryEthernetEventInfo.EventID = WhatToDownload.EventNumber; queryEthernetEventInfo.SyncExecute(); if (0 == queryEthernetEventInfo.TotalByteCount) { var msg = $"No Ethernet Recorder data to download: {SerialNumber}"; APILogger.Log(msg); info.Success(); return; } var bytesToRead = queryEthernetEventInfo.TotalByteCount;//34844UL var curBytesRead = 0UL; while (curBytesRead < bytesToRead) { var queryEthernetEventData = new QueryEthernetEventData(this); queryEthernetEventData.EventID = queryEthernetEventInfo.EventID; var requestSize = (bytesToRead - curBytesRead) < int.MaxValue ? (int)(bytesToRead - curBytesRead) : int.MaxValue; queryEthernetEventData.RequestByteCount = (uint)requestSize; queryEthernetEventData.StartDataOffsetBytes = curBytesRead; queryEthernetEventData.SyncExecute(); var data = new byte[queryEthernetEventData.Data.Length]; Array.Copy(queryEthernetEventData.Data, 0, data, 0, queryEthernetEventData.Data.Length); curBytesRead += (ulong)queryEthernetEventData.Data.Length; info.NewData(data); info.Progress(Convert.ToInt32(100D * curBytesRead / bytesToRead)); } } catch (Exception ex) { APILogger.Log(ex); info.Error(ex.Message); return; } APILogger.Log($"Data successfully downloaded from {SerialNumber}"); info.Progress(100); var config = GetConfigAttributes(this); config.SetEventDownloaded(WhatToDownload.EventNumber, 1); info.Success(); } protected override void AsyncPrepareForArmNow(object asyncInfo) { if (!IsEthernetRecorder) { base.AsyncPrepareForArmNow(asyncInfo); } else { if (!(asyncInfo is ArmPacket info)) { return; } AsyncPrepareForArmNowOBRDDR(info); } } /// /// returns whether the unit supports 2V or not /// /// protected override bool GetSupports2Volt() { return false; } /// /// 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; } protected override void PerformBridgeResistanceMeasurement(Common.Interface.DASFactory.Diagnostics.IDiagnosticActions[] ChannelActions, SliceServiceAsyncInfo info, ref Common.Interface.DASFactory.Diagnostics.IDiagnosticResult[] results) { //18927 Bridge resistance inaccurate due to channel config setting prior to measurement try { if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.ProgramStackChannels)) { ReconfigureAccordingToConfig(); } } catch (Exception ex) { APILogger.Log("Failed to force stack channel types", ex); } base.PerformBridgeResistanceMeasurement(ChannelActions, info, ref results); } #region configure overrides /// /// adjusts the requested input range to avoid certain gains if needed /// we are doing this for /// 15462 Limit SLICE 6 AIR gains as they are not functional with IEPE accel /// we manipulate the input range requested so we fall /// within acceptable gains /// /// /// protected override double AdjustInputRangeIfNeeded(double originalRange, bool bModified) { var gains = Enum.GetValues(typeof(GainCodesSLICE6IEPE)).Cast().ToList(); gains.Sort(new GainSorterSLICE6IEPE()); gains.Reverse(); var lastAcceptableValue = double.NaN; //assume gains are in order from 1 to 1600, so find the first gain which is too restrictive and bounce back from that //so for instance, if someone selected a range of 700mV, we would start with G1, pass, go to G2, pass, go to G4, fail, so we would use //G2. Also note, while we know the min/max theoretical value foreach gain, when we request a range from the firmware we don't use that value //we use somewhere inbetween (the FirmwareInputRangemV) to increase the chances we get the gain we want... //note there are gains greater than 1600, but they are currently explicitly disabled by issue 10080 foreach (var gain in gains) { if (GainDisabledAttribute.IsGainDisabled(gain)) { continue; } var maxValue = MaxInputRangeAttribute.GetMaxInputRangemV(gain); if (originalRange < maxValue) { lastAcceptableValue = FirmwareInputRangeAttribute.GetFirmwareInputRangemV(gain); } else { break; } } return !double.IsNaN(lastAcceptableValue) ? lastAcceptableValue : originalRange; } /// /// queries download information /// protected override void AsyncQueryDownload(object asyncInfo) { if (IsEthernetRecorder) { AsyncQueryDownloadDDR(asyncInfo); } else { base.AsyncQueryDownload(asyncInfo); } } /// /// handles quering download information but specifically for OBR-DDR /// most of it is copied from the base, but the DDR doesn't have the same /// amount of information available, and has some alternate info available /// private void AsyncQueryDownloadDDR(object asyncInfo) { var info = asyncInfo as QueryDownloadAsyncInfo; // since we don't know exact how many XML attributes, modules or channels that's in the // configuration, we guess on the high end. // (44 per stored config + 4 + 3 per module + 3 per channel) * number of events // equals 44 + 4 + 30 + 90 = 168 per event const int StepsPerEvent = 168; try { if (info.EventIndex < 0) { RetrieveDASBootCount(); } var EventCount = new QueryTotalEventCount(this); EventCount.SyncExecute(); var config = GetConfigAttributes(this); var progress = new QueryDownloadProgress(info, StepsPerEvent * EventCount.Count, 1); // we'll also freshen up the cached event GUIDs // NOT IF WE ARE QUERYING A SPECIFIC GUID var eventGuids = new Guid[EventCount.Count]; var faultFlags = new ushort[EventCount.Count]; var faultFlagsEx = new ushort[EventCount.Count]; var armAttempts = new byte[EventCount.Count]; //each index in outer array belongs to event index, there are 4 extended fault ids for each event var extendedFaultIds = new List(); var dlReport = new DownloadReport(); if (0 > info.EventIndex) { dlReport.Events = new DownloadReport.EventInfo[EventCount.Count]; var queryAutoArmError = new QuerySystemAttribute(this) { Key = AttributeTypes.SystemAttributes.AutoArmError }; try { queryAutoArmError.SyncExecute(); AutoArmStatus = (DFConstantsAndEnums.CommandStatus)(Convert.ToInt32(queryAutoArmError.Value)); } catch (Exception ex) { APILogger.Log(ex); } } for (var eventIdx = 0; eventIdx < EventCount.Count; eventIdx++) { if (info.EventIndex >= 0 && eventIdx != info.EventIndex) { continue; } extendedFaultIds.Add(GetExtendedFaultFlags(eventIdx)); // Retrieved the stored configuration var storedConfigStr = config.RetrieveEventXMLConfig(eventIdx, progress, this); // I/O * n var triggerSampleNumber = 0UL; try { triggerSampleNumber = config.GetEventTriggerSampleNumber(eventIdx); // I/O } catch (Exception ex) { APILogger.Log(ex); } // convert it from XML to object var storedConfig = ConfigurationData.DeserializeFromString(storedConfigStr); // the object to store it all in var eventInfo = new DownloadReport.EventInfo(); // get the event level values try { eventInfo.Description = config.GetEventDescription(eventIdx); // I/O if (null != ConfigData) { eventInfo.Description = ConfigData.Description; } } catch (Exception) { } progress.Step(); try { eventInfo.TestID = config.GetEventID(eventIdx, this).TrimEnd(new char[] { '\0' }); ; // I/O } catch (Exception ex) { eventInfo.TestID = string.Empty; APILogger.Log(ex); } progress.Step(); eventInfo.EventNumber = eventIdx; progress.Step(); try { eventInfo.TestGUID = GetEventGuid(eventIdx); } catch (Exception) { eventInfo.TestGUID = Guid.NewGuid(); } try { eventInfo.FaultFlags = config.GetEventFaultFlags(eventIdx); eventInfo.FaultFlagsEx = config.GetEventFaultFlagsEx(eventIdx); } catch (Exception ex) { APILogger.Log("could not get fault flags", ex); } try { eventInfo.ArmAttempts = config.GetEventArmAttempts(eventIdx); } catch (Exception ex) { APILogger.Log("could not get arm attempts", ex); } eventGuids[eventIdx] = eventInfo.TestGUID; faultFlags[eventIdx] = eventInfo.FaultFlags; faultFlagsEx[eventIdx] = eventInfo.FaultFlagsEx; armAttempts[eventIdx] = eventInfo.ArmAttempts; try { var q = new QueryEthernetEventInfo(this); q.EventID = Convert.ToUInt16(eventIdx); q.SyncExecute(); if (0 == q.TotalByteCount) { faultFlags[eventIdx] |= (ushort)DFConstantsAndEnums.FaultFlags.NO_DATA; eventInfo.FaultFlags |= (ushort)DFConstantsAndEnums.FaultFlags.NO_DATA; } } catch (Exception ex) { APILogger.Log("could not get EventTotalByteCount", ex); } eventInfo.HasBeenDownloaded = config.EventHasBeenDownloaded(eventIdx, out uint flag); // I/O progress.Step(); // take the module from the stored config var module = (DASModule)storedConfig.Modules[0]; //module.SampleRateHz = Convert.ToUInt32(actualSampleRate); //module.EmbeddedSampleRateHz = stackActualSampleRate; /// /// Amongst other things, the level trigger offset correction, if it exists, is getting applied /// to the module trigger sample numbers below. There shouldn't be any danger of this value being /// erroneously applied to outside "tweaking" since the only outside tweak should only ever happen /// if there was no trigger. Still I'm a little concerned that this value will still be invisibly /// applied to user-overridden trigger sample numbers. We could conceivably guard against this /// situation with an "original trigger sample number" concept, which we could then check against /// and not re-apply things like level trigger offset correction if the current value doesn't /// match it, implying it has been manually overridden. /// // now update the module with dynamic data module.OwningDAS = this; //module.NumberOfSamples = numberOfSamples; progress.Step(); module.TriggerSampleNumbers = new ulong[1]; // only one so far //var phaseShift = GetPhaseShiftSamples(Convert.ToUInt32(1 + module.ModuleArrayIndex), Convert.ToDouble(actualSampleRate), Convert.ToUInt32(aafilter), triggerSampleNumber); module.TriggerSampleNumbers[0] = triggerSampleNumber; eventInfo.WasTriggered = module.TriggerSampleNumbers[0] > 0; progress.Step(); eventInfo.Modules = new DASModule[1]; eventInfo.Modules[0] = module; if (0 > info.EventIndex) { // store it in the object dlReport.Events[eventIdx] = eventInfo; } else { EventInfo.Events[eventIdx] = eventInfo; } } // now assigned the data to the public property if (0 > info.EventIndex) { SetEventInfo(dlReport); } SetEventFaultFlags(faultFlags); ((IDownload)this)?.SetExtendedFaultFlags(extendedFaultIds.ToArray()); SetEventGuids(eventGuids); SetEventArmAttemps(armAttempts); info.Success(); } catch (CanceledException) { info.Cancel(); } catch (Exception ex) { info.Error(ex.Message, ex); } } /// /// the minimum version that supports TMATS interval attribute is 33 per LP /// http://manuscript.dts.local/f/cases/30460/S6-Air-attribute-145-interval-is-not-being-set-by-Datapro-because-of-protocol-version-41-ON-G0N5-FW /// protected override int MIN_PROTOCOL_TMATS_INTERVAL => 33; /// /// 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(); IncrementNumberOfTimesWritten(); if (IsEthernetRecorder) { var ssa = new SetSystemAttributeSLICE6AIR(this); ssa.SetValue(AttributeTypes.SystemAttributesSLICE6AIR.EthRecordingAddr, ConfigData.UDPReceiveAddress, true); ssa.SyncExecute(); } else { SetRemoveSeconds(); if ((info.StreamADCPerPacket != null) && info.StreamADCPerPacket.ContainsKey(this)) { 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 numUartChannels = DASInfo.Modules.Sum(mod => DFConstantsAndEnums.ModuleType.UART == mod.TypeOfModule ? mod.NumberOfChannels : 0); 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, numUartChannels, 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(); } protected override ConfigAttributes GetConfigAttributes(ICommunication com) { return new SLICE6AIRConfigAttributes(com); } /// /// SLICE6 config attributes, mostly inherits from SLICE.ConfigAttributes with some functionality removed /// protected class SLICE6AIRConfigAttributes : ConfigAttributes { /// /// I'm not aware of a purgeStaleData function in SLICE6/6AIR yet /// this may be unnecessary if the firmware is intelligent enough, and maybe this is legacy /// /// public override void PurgeStaleData(IDASCommunication das) { } public SLICE6AIRConfigAttributes(ICommunication _com) : base(_com) { } #region CONFIG_XML private readonly object _storeXMLConfigLock = new object(); /// /// SLICE6 stores the xml in flash using SetFileData. We compress the XML string, write the header, /// then write data 400 bytes at a time. For the header, we first write XML_STORE_MAGIC_BYTES followed /// by the length of the compressed XML in bytes. /// /// /// /// public override void StoreXMLConfig(string data, FileStore fileStore) { lock (_storeXMLConfigLock) { if (string.IsNullOrEmpty(data)) { return; } // since this might contain multi byte characters, we need to convert it to a byte array first var ByteArrayData = GetCompressedBytes(GetBytes(fileStore, data)); var fileid = (ushort)fileStore; //EventConfig ? Convert.ToUInt16(1) : Convert.ToUInt16(0); //Store Header - magic bytes and data length //Store Magic bytes var sfd = new SetFileData(com, 600000); sfd.StartByteCount = 0; sfd.FileID = fileid; sfd.Data = Constants.XML_STORE_MAGIC_BYTES; sfd.SyncExecute(); //Store Header - data length sfd.StartByteCount = (Constants.XML_HEADER_LENGTH / 2); sfd.FileID = fileid; sfd.Data = BitConverter.GetBytes((uint)ByteArrayData.Length); sfd.SyncExecute(); //purposely corrupt for testing purposes //if (EventConfig) //{ // System.Random r = new Random(DateTime.Now.Second); // for (int i = 0; i < 100; i++) // { // int position = r.Next(0, ByteArrayData.Length - 1); // ByteArrayData[position] = Convert.ToByte(r.Next(0, 255)); // } //} //Store Data for (uint i = 0; i < ByteArrayData.Length; i += (uint)sfd.MaximumFileStreamBytes) { long array_size = sfd.MaximumFileStreamBytes; if ((i + sfd.MaximumFileStreamBytes) > ByteArrayData.Length) { array_size = ByteArrayData.Length - i; } var dataToSend = new byte[array_size]; Array.Copy(ByteArrayData, i, dataToSend, 0, array_size); sfd.Data = dataToSend; sfd.FileID = fileid; sfd.StartByteCount = i + Constants.XML_HEADER_LENGTH; sfd.SyncExecute(); } if ((FileStore.Diagnostic == fileStore) || (FileStore.Event == fileStore)) { StoreXmlConfigPC(data); } } } /// /// We retrieve the xml from SLICE 2 flash using QueryFileData. We read the header, then read data 400 /// bytes at a time. For the header, we first read XML_STORE_MAGIC_BYTES followed by the length of the /// compressed XML in bytes. We then unzip the data and return the XML string. /// /// public override string RetrieveXMLConfig(FileStore fileStore, IDASCommunication das) { lock (_storeXMLConfigLock) { var WholeStr = ""; try { var allBytes = new List(); allBytes.Clear(); //Get Header - magic bytes and data length //Get Magic bytes var qfd = new QueryFileData(com, 600000); var fileid = (ushort)fileStore; qfd.FileID = fileid; qfd.StartByteCount = 0; qfd.EndByteCount = (Constants.XML_HEADER_LENGTH / 2) - 1; if (das.GetIsStreaming()) { //this is a big assumption here, when das is streaming we can't query it from the unit //but we might be able to from the pc ... //15949 S6A when streaming does a whole bunch of unnecessary queries if (FileStore.UserAttributes != fileStore) { //event config falls back to regular config, regular config falls back to pc file WholeStr = RetrieveXmlConfigPC(); } } else { qfd.SyncExecute(); if (qfd.Data.Length < 4) { return ""; } if (qfd.Data[0] == 0xFF && qfd.Data[1] == 0xFF && qfd.Data[2] == 0xFF && qfd.Data[3] == 0xFF) { return ""; } if (BitConverter.ToUInt32(qfd.Data, 0) != BitConverter.ToUInt32(Constants.XML_STORE_MAGIC_BYTES, 0)) { throw new InvalidDataException("Magic bytes not found"); } //Get data length qfd.FileID = fileid; qfd.StartByteCount = (Constants.XML_HEADER_LENGTH / 2); //account for magic bytes qfd.EndByteCount = Constants.XML_HEADER_LENGTH - 1; qfd.SyncExecute(); var ByteArrayDataLength = BitConverter.ToUInt32(qfd.Data, 0); if (Math.Pow(2, 21) < ByteArrayDataLength) { throw new InvalidDataException("data length is greater than store size"); } //Get Data for (uint i = 0; i < ByteArrayDataLength; i += (uint)qfd.MaximumFileStreamBytes) { var array_size = (uint)qfd.MaximumFileStreamBytes; if ((i + qfd.MaximumFileStreamBytes) > ByteArrayDataLength) { array_size = ByteArrayDataLength - i; } qfd.StartByteCount = Constants.XML_HEADER_LENGTH + i; qfd.EndByteCount = Constants.XML_HEADER_LENGTH - 1 + (i + array_size); qfd.FileID = fileid; qfd.SyncExecute(); allBytes.InsertRange((int)i, qfd.Data); } if (allBytes.Count < 1) { // "Slice.RetrieveAttributes: Attributes are empty" throw new Exception("Attributes are empty"); } // Decopress data WholeStr = GetDecompressedString(allBytes.ToArray(), fileStore); } } catch (Exception ex) { APILogger.Log("failed to retrieve xml config - EventConfig: ", fileStore.ToString(), " error: ", ex); //if (!EventConfig) if (FileStore.UserAttributes != fileStore) { //event config falls back to regular config, regular config falls back to pc file WholeStr = RetrieveXmlConfigPC(); } } try { APILogger.ConfLog(com.SerialNumber, "XML Config\n", Utils.PrettyPrint(WholeStr)); } catch (Exception) { } return WholeStr; } } private void StoreXmlConfigPC(string data) { try { const string dasConfigs = "DASConfigs"; var fileName = Path.Combine( Path.Combine( Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), dasConfigs), string.Format("{0}.xml", com.SerialNumber)); if (File.Exists(fileName)) { File.Delete(fileName); } using (var file = File.CreateText(fileName)) { file.Write(data); } } catch (Exception ex) { APILogger.Log(ex); } } #endregion /// /// Retrieve the XML string that was split and stored in the Arm attributes /// note that SLICE2 is apparently not going to store separate event configs, /// so we just grab the same one off the pc again /// [this is a bad idea as the event could be from earlier and the system config could have been /// changed after the use ran the test, and then reconfigured but wants to download the old test] /// /// The event number to get it from /// /// The combined XML string public override string RetrieveEventXMLConfig(int eventNum, QueryDownloadProgress progress, IDASCommunication das) { lock (_storeXMLConfigLock) { var s = string.Empty; try { s = RetrieveXMLConfig(FileStore.Event, das); } catch (Exception ex) { APILogger.Log("failed to retrieve event xml config for event ", eventNum, ex); } //fall back to whatever is on the live config if (string.IsNullOrEmpty(s)) { APILogger.Log("failed to retrieve event xml config (it was empty) for event ", eventNum); s = RetrieveXMLConfig(FileStore.Diagnostic, das); } return s; } } } #endregion protected override void SetArmAttribute(AttributeTypes.ArmAndEventAttributes key, DFConstantsAndEnums.RecordingMode value) { var mode = value; if (IsEthernetRecorder) { mode = GetOBRDDREquivalentMode(value, 1); } base.SetArmAttribute(key, mode); } #region IClockSyncActions protected override void AsyncGetClockSyncStatus(object asyncInfo) { //S6A has a command for both profile and status fetch if (!(asyncInfo is GetClockSyncStatusPacket packet)) { return; } if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryClockSyncStatus)) { packet.Info.Error("Get clock sync status not supported"); return; } var info = packet.Info; var bLocked = false; try { Lock(); bLocked = true; var status = new QueryClockSyncStatus(this); status.SyncExecute(); DASClockSyncProfile = status.ClockSyncProfile; DASClockSyncStatus = status.InputSyncStatus; DoRTCInUTCCheck(); 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("GetClockSyncStatus error - has failed ", straightFailures, " times, giving up", ce); info.Error(ce.Message, ce); } else { if (info.userData is ServiceBase.CallbackData cbData) { cbData.Target.DASClockSyncStatus = null; } info.Success(); APILogger.Log("GetClockSyncStatus error", ce); } } catch (Exception ex) { if (bLocked) { bLocked = false; Release(); } info.Error(ex.Message, ex); } finally { if (bLocked) { Release(); } } } #endregion public bool DownloadEthernetData { get; set; } = false; #region IUARTDownload 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 IUARTDownloadRequest WhatUARTToDownload { get; set; } public void SetWhatUARTToDownload(IUARTDownloadRequest request, bool bSetInDb = true) { UARTDownloadRequest.SetWhatToDownload(this, request, bSetInDb); } #endregion #region IUARTDownloadActions public void UARTDownload(ServiceCallback callback, object userData) { var state = new SliceUARTDownloadState(callback, userData, WhatUARTToDownload); if (null == WhatUARTToDownload) { APILogger.Log("UART download - what to download is null"); state.Success(); return; } APILogger.Log("Starting UART Download ", WhatUARTToDownload.StartTimestamp, WhatUARTToDownload.EndTimestamp); ulong totalDownloaded = 0, needed = WhatUARTToDownload.TotalByteCount; try { while (totalDownloaded < needed) { var getData = new QueryUARTEventData(this) { EventNumber = WhatUARTToDownload.EventNumber, LogCommands = false, RequestOffsetByteCount = totalDownloaded, RequestByteCount = needed - totalDownloaded < uint.MaxValue ? (uint)(needed - totalDownloaded) : uint.MaxValue }; getData.SyncExecute(); if (null == getData.PayloadData) { Thread.Sleep(10); continue; } state.NewData(new ServiceCallbackData.UARTNewData { DataOffset = getData.RequestOffsetByteCount, UARTData = getData.PayloadData }); var ratio = 100D * totalDownloaded / needed; if (ratio < 0) { ratio = 0; } else if (ratio > 100) { ratio = 100D; } state.Progress(Convert.ToInt32(ratio)); totalDownloaded += getData.PayloadByteCount; } state.Success(); } catch (CanceledException) { state.Cancel(); } catch (Exception e) { APILogger.LogException(e); state.Error(e.Message, e); } } /// /// 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(DFConstantsAndEnums.ProtocolLimitedCommands.QueryUARTDownload)) { info.Error("Query UART download is not supported"); return; } var bLocked = false; try { Lock(); bLocked = true; var status = new QueryUARTEventInfo(this) { EventNumber = (ushort)info.EventIndex }; status.SyncExecute(); 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("QueryUARTDownload error - has failed ", straightFailures, " times, giving up", ce); info.Error(ce.Message, ce); } else { if (info.userData is ServiceBase.CallbackData cbData) { //cbData.Target.DASClockSyncStatus = null; } info.Success(); APILogger.Log("QueryUARTDownload error", ce); } } catch (Exception ex) { if (bLocked) { bLocked = false; Release(); } info.Error(ex.Message, ex); } finally { if (bLocked) { Release(); } } } internal class SetUARTSettingsAsyncInfo : SliceServiceAsyncInfo { public uint BaudRate { get; set; } public uint DataBits { get; set; } public uint StopBits { get; set; } public uint Parity { get; set; } public uint FlowControl { get; set; } public SetUARTSettingsAsyncInfo(ServiceCallback callback, object userData, uint baudRate, uint dataBits, uint stopBits, uint parity, uint flowControl) : base(callback, userData) { BaudRate = baudRate; DataBits = dataBits; StopBits = stopBits; Parity = parity; FlowControl = flowControl; } } 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(DFConstantsAndEnums.ProtocolLimitedCommands.GetUARTSettings)) { info.Error("Get UART settings is not supported"); return; } var bLocked = false; try { Lock(); bLocked = true; try { var qsaUARTSettings = new QuerySystemAttributeSLICE6AIR(this, QuerySystemAttribute.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(DFConstantsAndEnums.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, SetSystemAttribute.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(); } } } #endregion private DFConstantsAndEnums.RecordingMode GetOBRDDREquivalentMode(DFConstantsAndEnums.RecordingMode input, int numEvents) { switch (input) { case DFConstantsAndEnums.RecordingMode.InvalidArmMode: case DFConstantsAndEnums.RecordingMode.ImmediateMode: case DFConstantsAndEnums.RecordingMode.HighPowerRecorderMode: case DFConstantsAndEnums.RecordingMode.LowPowerRecorderMode: case DFConstantsAndEnums.RecordingMode.ContinuousRecorderMode: case DFConstantsAndEnums.RecordingMode.AutoActiveMode: case DFConstantsAndEnums.RecordingMode.AerospaceWithMotion: case DFConstantsAndEnums.RecordingMode.S6A_DeviceStreamingOnly: APILogger.Log($"Invalid recording mode for OBR-DDR {input}"); return input; case DFConstantsAndEnums.RecordingMode.AutoCircularBufferMode: return DFConstantsAndEnums.RecordingMode.MultiEthernetUDPRecordingCircularMode; case DFConstantsAndEnums.RecordingMode.AutoRecorderMode: return DFConstantsAndEnums.RecordingMode.MultiEthernetUDPRecordingRecorderMode; case DFConstantsAndEnums.RecordingMode.CircularBuffer: case DFConstantsAndEnums.RecordingMode.a16_CircularBufferAndStreamSubSampleMode: case DFConstantsAndEnums.RecordingMode.CircularBufferPlusUART: case DFConstantsAndEnums.RecordingMode.MultipleEventRAMActive: case DFConstantsAndEnums.RecordingMode.RAMActive: return numEvents > 1 ? DFConstantsAndEnums.RecordingMode.MultiEthernetUDPRecordingCircularMode : DFConstantsAndEnums.RecordingMode.EthernetUDPRecordingCircularMode; case DFConstantsAndEnums.RecordingMode.RecorderMode: case DFConstantsAndEnums.RecordingMode.a14_NormalRecorderAndStreamSubSampleMode: case DFConstantsAndEnums.RecordingMode.RecorderModePlusUART: return numEvents > 1 ? DFConstantsAndEnums.RecordingMode.MultiEthernetUDPRecordingRecorderMode : DFConstantsAndEnums.RecordingMode.EthernetUDPRecordingRecorderMode; case DFConstantsAndEnums.RecordingMode.HybridRecorderMode: return numEvents > 1 ? DFConstantsAndEnums.RecordingMode.MultiEthernetHybridRecorderMode : DFConstantsAndEnums.RecordingMode.EthernetHybridRecorderMode; case DFConstantsAndEnums.RecordingMode.MultiHybridRecorderMode: return DFConstantsAndEnums.RecordingMode.MultiEthernetHybridRecorderMode; default: APILogger.Log($"possible invalid recording mode for OBR-DDR {input}"); return input; } } // http://manuscript.dts.local/f/cases/16493/How-to-bypass-adjustable-HW-filter-for-Data-Collection-on-S6A // Loc, 11:44 AM S6A should have limit to 50K only.Anything< 50K will be with SCF. 50K and higher will be in by-pass mode. private uint _maxAAFilterRateHz = 0U; protected override uint MaxAAFilterRateHz { get { if (_maxAAFilterRateHz == 0) { // FW added bandwidth to the MIF for S6A, lets use that. var qsa = new QuerySystemAttribute_BridgeSlice6(this) { Key = AttributeTypes.SystemAttributes_BridgeSlice6.Hardware_Analog_Bandwidth, DeviceID = 0x01 //per Loc we can always use 1 with slice6 }; try { qsa.SyncExecute(); _maxAAFilterRateHz = (uint)((float)qsa.Value * 1000F); } catch { // Something went wrong. Set to default // This is the max SCF for the current S6A device family as of 9/28/2020 _maxAAFilterRateHz = SLICE6AIR.MaxAAFilterRateHz; } } return _maxAAFilterRateHz; } } protected override uint MaxSampleRateHz => IsEthernetRecorder ? SLICE6AIR.MaxSampleRateHz_OBRDDR : SLICE6AIR.MaxSampleRateHz; } }