using System; using System.Collections.Generic; using System.Globalization; using System.Text; using System.Threading; using DTS.Common.Utilities.Logging; using DTS.DASLib.Command.SLICE; using DTS.DASLib.Command; using DTS.Common.Interface.DASFactory; using DTS.DASLib.Command.SLICE.DownloadCommands; using DTS.DASLib.Command.SLICE.RealtimeCommands; using DTS.Common.DAS.Concepts.DAS.Channel; using DTS.Common.Interface.Connection; using DTS.Common.Enums.DASFactory; using DTS.Common.ICommunication; using DTS.Common.Interface.DASFactory.Diagnostics; using DTS.Common.Enums; using System.IO; using DTS.Common.DASResource; using DTS.Common.Utilities.LTLogging; using DTS.Common.Enums.Hardware; using System.Linq; namespace DTS.DASLib.Service { public partial class Slice : Communication, IDASCommunication, IConfigurationActions, IDiagnosticsActions, ITriggerCheckActions, IRealTimeActions, IArmActions, IDownloadActions where T : IConnection, new() { /// /// sets the arm mode for das /// in the case of CIRCULARBUFFER+UART, etc will set to CIRCULAR BUFFER if the DAS does not /// support UART /// protected void SetArmMode(DFConstantsAndEnums.RecordingMode mode) { var modeToSet = mode; var enum2Mode = RecordingModeExtensions.ToRecordingModes(mode); switch (mode) { case DFConstantsAndEnums.RecordingMode.CircularBufferPlusUART: if (!HardwareConstants.IsRecordingModeSupported(enum2Mode, GetHardwareType(), ProtocolVersion, true)) { modeToSet = DFConstantsAndEnums.RecordingMode.CircularBuffer; } break; case DFConstantsAndEnums.RecordingMode.RecorderModePlusUART: if (!HardwareConstants.IsRecordingModeSupported(enum2Mode, GetHardwareType(), ProtocolVersion, true)) { modeToSet = DFConstantsAndEnums.RecordingMode.RecorderMode; } break; } SetArmAttribute(AttributeTypes.ArmAndEventAttributes.ArmMode, modeToSet); } /// /// /// public string TestDirectory { get; set; } /// /// returns true if the unit is capable of reading arm status /// 17800 Trigger status is "waiting" but PPRO has indeed triggered /// /// bool IDASCommunication.GetCanCheckArmStatus() { return true; } void IConfigurationActions.SetFirstUseDate(DateTime firstUseDate, ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); FirstUseDate = firstUseDate; LaunchAsyncWorker("IConfigurationActions.SetFirstUseDate", SetFirstUseDateAsync, info); } protected virtual void SetFirstUseDateAsync(object o) { if (!(o is SliceServiceAsyncInfo info)) { return; } info.Error("Not supported"); } public bool ConnectionCheck() { try { QuerySerialNumber querySerial = new QuerySerialNumber(this); querySerial.SyncExecute(); return true; } catch (Exception ex) { APILogger.Log(ex); } return false; } void IConfigurationActions.StoreTestSetupXML(ServiceCallback callback, object userData, string testSetupXML) { var info = new SliceServiceSetTestSetupAsyncInfo(callback, userData, testSetupXML); LaunchAsyncWorker("Slice.StoreTestSetupXML", AsyncStoreTestSetupXML, info); } private void AsyncStoreTestSetupXML(object asyncInfo) { if (!(asyncInfo is SliceServiceSetTestSetupAsyncInfo info)) { return; } try { var config = GetConfigAttributes(this); config.StoreXMLConfig(info.TestSetupXML, ConfigAttributes.FileStore.TestSetup); } catch (Exception ex) { APILogger.Log(ex); info.Error(ex.Message, ex); } info.Success(); } void IConfigurationActions.CheckAAFilterRate(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); // look thru all the config data and make sure it's fit to be used // our caller have already checked for null, but... if (ConfigData == null) { // "Slice.VerifyConfig: ConfigData is null" throw new ArgumentException(Strings.Slice_VerifyConfig_Err1); } if (ConfigData.Modules == null || ConfigData.Modules.Length == 0 || ConfigData.Modules.Length > DASInfo.Modules.Length) { // "Slice.VerifyConfig: ConfigData.Modules is null, empty or too long" throw new ArgumentException(Strings.Slice_VerifyConfig_Err4); } var AAFilterRateReducedToMax = false; for (var moduleIdx = 0; moduleIdx < ConfigData.Modules.Length; moduleIdx++) { var module = ConfigData.Modules[moduleIdx]; if (module.IsClock()) continue; if (module.ModuleArrayIndex != moduleIdx) { // "Slice.VerifyConfig: ConfigData.Module[{0}].ModuleNumber doesn't mach index" throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err5, moduleIdx)); } if (module.AAFilterRateHz > MaxAAFilterRateHz) { module.AAFilterRateHz = MaxAAFilterRateHz; AAFilterRateReducedToMax = true; } } if (AAFilterRateReducedToMax) { info.Error(SerialNumber); } else { info.Success(); } } void IConfigurationActions.ResetHardwareLines(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice.ResetHardwareLines", AsyncResetHardwareLines, info); } private void AsyncResetHardwareLines(object asyncInfo) { if (!(asyncInfo is SliceServiceAsyncInfo info)) { return; } if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.InitHardwareInputLines)) { info.Success(); return; } var ssaStart = new SetSystemAttribute(this); var ssaTrigger = new SetSystemAttribute(this); try { ssaStart.SetValue(AttributeTypes.SystemAttributes.StartRecordPolarity, (byte)(InvertStart ? 1 : 0), true); ssaTrigger.SetValue(AttributeTypes.SystemAttributes.TriggerPolarity, (byte)(InvertTrigger ? 1 : 0), true); ssaStart.SyncExecute(); ssaTrigger.SyncExecute(); var ssi = new SetSwitchImmediate(this) { DeviceID = 0x00, Switch = (byte)Switches.BaseSwitches.TriggerOut, SwitchText = Switches.BaseSwitches.TriggerOut.ToString(), Setting = InvertTrigger ? Convert.ToByte(1) : Convert.ToByte(0) }; ssi.SyncExecute(); } catch (Exception ex) { APILogger.Log(ex); } info.Success(); } void IArmActions.CheckAlreadyLevelTriggered(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice.CheckAlreadyLevelTriggered", AsyncCheckAlreadyLevelTriggered, info); } protected virtual bool ShouldCheckLevelTrigger(double eu) { return true; } private void AsyncCheckAlreadyLevelTriggered(object asyncInfo) { var info = asyncInfo as SliceServiceAsyncInfo; try { var measureOffset = new RetrieveSampleAverage(this); measureOffset.DeviceID = 0; // send to base var avgTimeSeconds = 1.0 / 60.0 * 2.0; // 2 * 60Hz cycles measureOffset.Samples = (ushort)(10000 * avgTimeSeconds);//should use sample rate here? if (measureOffset.Samples < 1) { measureOffset.Samples = 1; } measureOffset.SyncExecute(); foreach (var m in ConfigData.Modules) { foreach (var ch in m.Channels.Where(x => x is AnalogInputDASChannel && !(x is ILevelTriggerable))) { var aCh = (AnalogInputDASChannel)ch; var triggerable = (ILevelTriggerable)ch; aCh.AlreadyLevelTriggered = false; aCh.MeasuredEULevelTriggerCheck = double.NaN; if (aCh.LevelTriggerType == LevelTriggerTypes.NONE || aCh.ConfigurationMode != DFConstantsAndEnums.ConfigMode.Normal) continue; try { var ADC = measureOffset.GetChannelData(aCh.Number); if (null != triggerable.SampleAverageADC && !double.IsNaN((double)triggerable.SampleAverageADC)) { ADC = (short)triggerable.SampleAverageADC; } LevelTriggerLogging.LevelTriggerLog($"AsyncCheckAlreadyLevelTriggered {SerialNumber}:{ch.Number} ADC:{ADC}\r\n"); _ = aCh.ScalefactorMilliVoltsPerADC; try { var diagnostics = aCh.Diagnostics; _ = diagnostics.ScalefactorMilliVoltsPerADC; diagnostics.GetExpectedDataZeroLevelADC(aCh.ZeroMethod); } catch (Exception ex) { APILogger.Log(ex); } if (null != aCh.DiagnosticInformation) { _ = aCh.DiagnosticInformation.GetExpectedDataZeroLevelADC(aCh.ZeroMethod); } var ds = aCh.GetDataScaler(); var eu = ds.GetEU(ADC); aCh.MeasuredEULevelTriggerCheck = eu; if (null != aCh.TriggerAboveThresholdEu) { var limit = (double)aCh.TriggerAboveThresholdEu; if (eu > limit && ShouldCheckLevelTrigger(limit)) { aCh.AlreadyLevelTriggered = true; LevelTriggerLogging.LevelTriggerLog( $"AlreadyLevelTriggeredCheck {SerialNumber}:{aCh.Number} is already LevelTriggered ({eu}>{limit})\r\n"); } } if (null != aCh.TriggerBelowThresholdEu) { var limit = (double)aCh.TriggerBelowThresholdEu; if (eu < limit && ShouldCheckLevelTrigger(limit)) { aCh.AlreadyLevelTriggered = true; LevelTriggerLogging.LevelTriggerLog( $"AlreadyLevelTriggeredCheck {SerialNumber}:{aCh.Number} is already LevelTriggered ({eu}<{limit})\r\n"); } } } catch (Exception ex) { APILogger.Log(ex); } } } info?.Success(); } catch (Exception ex) { info.Error(ex.Message, ex); } } public virtual int MaxModules { get => 8; set {; } } /// /// returns the number of samples taken up by the time specified in microseconds /// /// delay in microseconds /// sample rate of collected data /// /// /// samples the collected data got shifted (rounded up) protected ulong GetPhaseShiftSamples(double delayInMicroSeconds, double actualSampleRate, ulong originalT0, string rule) { //we have SamplesPerSecond, so convert to common unit var delayInSeconds = delayInMicroSeconds / 1000000D; if (delayInSeconds < 0) { delayInSeconds = 0; }//we only consider the filter shifting things further in time for now //now round up the number of samples and return as a discrete number var d = Math.Round(delayInSeconds * actualSampleRate); APILogger.Log("PhaseShift: " + d.ToString(CultureInfo.InvariantCulture), SerialNumber); var shift = Convert.ToUInt64(d); APILogger.LogPhaseShift(SerialNumber, delayInMicroSeconds, originalT0, originalT0 + shift, shift, rule); return shift; } /// /// /// returns the number of phase shift samples the hardware filter causes (rounded up) /// /// /// /// /// /// public virtual ulong GetPhaseShiftSamples(uint ModuleIndex, double ActualSampleRate, uint HardwareAAF, ulong originalT0) { //note http://foghat/dtswiki/index.php/SLICE_PRO_Hardware_Overview#SLICE_PRO_Hardware_Input_Signal_Delay_vs_Filter_Rate return 0; } /// /// initiates background flash erase for units that support it /// will return immediately after flash erase begins /// /// /// void IArmActions.BeginBackgroundFlashErase(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); info.Success(); } /// /// returns whether unit is capable of flash erase /// bool IArmActions.SupportsBackgroundFlashErase => false; /// /// returns whether unit has started background flash erase /// bool IArmActions.BackgroundFlashEraseStarted => false; DateTime? IArmActions.BackgroundFlashEraseStartTime => null; /// /// /// slice 1.0 can simply use user attributes to store the display order /// /// public virtual void SetDASDisplayOrder(int order) { try { var sua = new SetUserAttribute(this); sua.SetValue(AttributeTypes.SliceUserAttributes.DasDisplayOrder, Convert.ToByte(order), true); sua.SyncExecute(); } catch (Exception ex) { APILogger.Log("failed to set das display order,", ex); } } public virtual void SetChannelDisplayOrder(int[] order) { try { var sua = new SetUserAttribute(this); sua.SetValue(AttributeTypes.SliceUserAttributes.DisplayOrder, order, true); sua.SyncExecute(); } catch (Exception ex) { APILogger.Log("failed to set channel display order,", ex); } } public virtual int GetDASDisplayOrder() { try { var qa = new QueryUserAttribute(this); qa.Key = AttributeTypes.SliceUserAttributes.DasDisplayOrder; qa.SyncExecute(); return Convert.ToInt32(qa.Value); } catch (Exception) { // ignored - if there's no das display order it's okay } return -1; } public virtual int[] GetChannelDisplayOrder() { int[] ret = { -1 }; try { var qa = new QueryUserAttribute(this); qa.Key = AttributeTypes.SliceUserAttributes.DisplayOrder; qa.SyncExecute(); return (int[])qa.Value; } catch (Exception) { // ignored - if there's no channel display order it's okay } return ret; } void IArmActions.ReadyForArming(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool testingMode, int maxNumberEvents, bool DummyArm, bool SysMode) { var info = new ArmPacket(callback, userData, eventGuid, armNowTimeout, testingMode, maxNumberEvents); LaunchAsyncWorker("Slice.ReadyForArming", AsyncReadyForArming, info); } public bool AutoArmed { get; set; } = false; protected class ArmPacket : SliceServiceAsyncInfo { public Guid EventGuid { get; } public int ArmNowTimeout { get; } public bool TestingMode { get; } public int MaxNumberEvents { get; set; } public ArmPacket(ServiceCallback cb, object ud, Guid eg, int armNowTimeout, bool testingMode, int maxNumberEvents) : base(cb, ud) { EventGuid = eg; ArmNowTimeout = armNowTimeout; TestingMode = testingMode; MaxNumberEvents = maxNumberEvents; } } protected class AutoArmPacket : ArmPacket { public uint DiagnosticsDelayMs { get; } public bool RepeatEnable { get; } public bool PreserveDiagnostics { get; } public AutoArmPacket(ServiceCallback cb, object ud, Guid eg, int armNowTimeout, bool testingMode, uint diagnosticsDelayMs, int maxEventCount, bool repeatEnable, bool preserveDiagnostics) : base(cb, ud, eg, armNowTimeout, testingMode, maxEventCount) { DiagnosticsDelayMs = diagnosticsDelayMs; RepeatEnable = repeatEnable; PreserveDiagnostics = preserveDiagnostics; } } #region FlashErase void IArmActions.BeginFlashErase(ServiceCallback callback, object userData, bool DummyArm) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice.BeginFlashErase", AsyncBeginFlashErase, info); } protected virtual void AsyncBeginFlashErase(object asyncInfo) { var info = asyncInfo as SliceServiceAsyncInfo; if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.FlashClear)) { info?.Success(); return; } var bReleased = true; try { Lock(); bReleased = false; var startErase = new BeginFlashErase(this); startErase.SyncExecute(); bReleased = true; Release(); info?.Success(); } 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) { Release(); } } } void IArmActions.QueryFlashEraseStatus(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice.QueryFlashEraseStatus", AsyncQueryFlashEraseStatus, info); } private void AsyncQueryFlashEraseStatus(object asyncInfo) { var info = asyncInfo as SliceServiceAsyncInfo; if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.FlashClear)) { info?.Progress(100); info?.Success(); return; } try { var done = false; while (!done) { var bReleased = true; try { Lock(); bReleased = false; var queryStatus = new QueryFlashEraseStatus(this, 1 * 30 * 1000); queryStatus.SyncExecute(); var eraseStatus = new FlashEraseStatus(); eraseStatus.PercentComplete = queryStatus.PercentComplete; eraseStatus.LastError = queryStatus.LastError; DASFlashEraseStatus = eraseStatus; if (eraseStatus.LastError != DFConstantsAndEnums.CommandStatus.StatusNoError) { info?.Progress(0); bReleased = true; Release(); info?.Error("Error while clearing flash: " + eraseStatus.LastError.ToString()); done = true; } else if (eraseStatus.PercentComplete < 100.0f) { info?.Progress((int)eraseStatus.PercentComplete); bReleased = true; Release(); Thread.Sleep(500); } else { info?.Progress(100); bReleased = true; Release(); info?.Success(); done = true; } } catch (Exception ex) { APILogger.Log(ex); if (!bReleased) { bReleased = true; Release(); } throw; } finally { if (!bReleased) { Release(); } } } } catch (CanceledException) { info?.Cancel(); } catch (Exception ex) { info?.Error(ex.Message, ex); } } #endregion #region ArmNow void IArmActions.PrepareForArmNow(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool testingMode, int maxNumberEvents, bool SysMode) { var info = new ArmPacket(callback, userData, eventGuid, armNowTimeout, testingMode, maxNumberEvents); LaunchAsyncWorker("Slice.PrepareForArmNow", AsyncPrepareForArmNow, info); } internal class RearmAsyncInfo : SliceServiceAsyncInfo { public bool AutoArm { get; set; } = false; public bool Arm { get; set; } = false; public bool RepeatEnable { get; set; } = false; public RearmAsyncInfo(ServiceCallback _callback, object _userData, bool autoArm, bool arm, bool repeatEnable) : base(_callback, _userData) { AutoArm = autoArm; Arm = arm; RepeatEnable = repeatEnable; } } void IArmActions.ReArm(ServiceCallback callback, object userData, bool autoArm, bool arm, bool repeatEnable) { var info = new RearmAsyncInfo(callback, userData, autoArm, arm, repeatEnable); LaunchAsyncWorker("Slice.ReArm", AsyncRearm, info); } private void AsyncRearm(object data) { var info = (RearmAsyncInfo)data; try { if (info.AutoArm) { SetAutoArm(); } if (info.RepeatEnable) { SetRepeatEnable(); } if (info.Arm) { var arm = new Arm(this); arm.SyncExecute(); } } catch(Exception ex) { APILogger.Log(ex); info.Error(ex.Message); return; } info.Success(); } void IArmActions.PreparedArmNow(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool checkoutMode, int maxNumberEvents, bool SysMode) { var info = new ArmPacket(callback, userData, eventGuid, armNowTimeout, checkoutMode, maxNumberEvents); LaunchAsyncWorker("Slice.PreparedArm", AsyncPreparedArm, info); } void IArmActions.ArmNow(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool testingMode, int maxNumberEvents, bool SysMode) { var info = new ArmPacket(callback, userData, eventGuid, armNowTimeout, testingMode, maxNumberEvents); LaunchAsyncWorker("Slice.ArmNow", AsyncArmNow, info); } protected virtual void AsyncArmNow(object asyncInfo) { if (!(asyncInfo is ArmPacket info)) { return; } var bReleased = true; var armNow = new Arm(this, info.ArmNowTimeout); // 5 minute timeout try { Lock(); bReleased = false; // we must have at least 7V to arm var inputs = new SLICEBaseInputReader(this); if (inputs.InputMilliVolts < 7000.0 && !info.TestingMode) { bReleased = true; Release(); info.Error($"{SerialNumber}: Input is less than 7 volts"); return; } SetMaxEvents(info.MaxNumberEvents); //performance improvement from WIAMan per CPB/LP //this command is unnecessary since firmware will do the same work during the arm if (RunTestVariables.EliminatePrepareForDataCollection) { //skip } else { try { var prepare = new PrepareForDataCollection(this); prepare.SyncExecute(); } catch (Exception ex) { APILogger.Log(ex); try { //this was a way of adding more information in the case //of a failed prepare for data collection, this is just //a quick running command that was added to see if it //executes? var qsa2 = new QuerySystemAttribute(this); qsa2.Key = AttributeTypes.SystemAttributes.AutoArmed; qsa2.DeviceID = 0; qsa2.SyncExecute(); } catch (Exception ex2) { APILogger.Log(ex2); } } } ResetEventListPriorToArm(); // After we've reset the event list, our (the DAS) EventInfo property is now invalid SetEventInfo(null); // store a unique GUID for this event SetEventGuid(info.EventGuid); if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.AutoArm)) { try { var ssa = new SetSystemAttribute(this); ssa.SetValue(AttributeTypes.SystemAttributes.AutoDiagnosticLevel, AUTO_ARM_PERFORM_ALL_DIAG, true); ssa.SyncExecute(); } catch (Exception ex) { APILogger.Log(ex); } } armNow.SyncExecute(); bReleased = true; Release(); info.Success(); } catch (CanceledException) { if (!bReleased) { bReleased = true; Release(); } info.Cancel(); } catch (CommandException ex) { if (!bReleased) { bReleased = true; Release(); } if (ex.Error == CommandErrorReason.ReceiveFailed || ex.Error == CommandErrorReason.SendFailed) { info.Error(string.Format(Resources.ArmFailtureDisconnect, SerialNumber)); } else { info.Error(string.Format(Resources.ArmFailureCommandException, SerialNumber)); } } catch (Exception ex) { APILogger.Log(ex); if (!bReleased) { bReleased = true; Release(); } info.Error(armNow.ArmStatus.ToString()); } finally { if (!bReleased) { Release(); } } } /// /// 12638 DAS does not record data in recorder mode during calibration ~ 40% of time. /// for non SLICE6 we reset the event list prior to arming /// SLICE6 will only call reset event list prior to configuring /// we are doing this to minimize the changes and impact of the fix for 12638 /// protected virtual void ResetEventListPriorToArm() { var resetEvents = new ResetEventList(this); resetEvents.SyncExecute(); } protected virtual void AsyncReadyForArming(object asyncInfo) { var info = asyncInfo as ArmPacket; info?.Success(); } protected virtual void AsyncPrepareForArmNow(object asyncInfo) { if (!(asyncInfo is ArmPacket info)) { return; } var bReleased = true; try { Lock(); bReleased = false; // We must have a valid voltage, and at least InputLowVoltage for this DAS type to arm. // Previously, this check was hardcoded to > 7V, so that users would not experience a // brown out during a test. However, with the introduction of PowerPRO, this would fail // if it did not have external power (a valid configuration). // FB 17687 var inputs = new SLICEBaseInputReader(this); if (inputs.InputMilliVolts > MinimumValidInputVoltage && inputs.InputMilliVolts < MaximumValidInputVoltage && (inputs.InputMilliVolts < InputLowVoltage) && !info.TestingMode) { bReleased = true; Release(); info.Error($"{SerialNumber}: Input is valid and less than {InputLowVoltage} volts"); return; } //31885 Implement RecordOnBootMode //We must set AutoArmed to 1, and AutoArmRepeatEnable to 1 if (((ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.a26_MultiRecordOnBootDataMode) || (ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.a28_MultiRecordOnBootAndUartDataMode)) && IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmRepeatEnable)) { try { SetAutoArm(); SetRepeatEnable(); } catch (Exception ex) { APILogger.Log("Failed to set AutoArm repeat enable/disable", ex); } } SetMaxEvents(info.MaxNumberEvents); //we always have to set post trigger var setPostTrigger = new SetArmAttribute(this); ulong samples = Convert.ToUInt64(Math.Abs(ConfigData.Modules[0].PostTriggerSeconds) * ConfigData.Modules[0].SampleRateHz); setPostTrigger.SetValue(AttributeTypes.ArmAndEventAttributes.PostTriggerSamplesRequested, samples, true); setPostTrigger.SyncExecute(); samples = Convert.ToUInt64(Math.Abs(ConfigData.Modules[0].PreTriggerSeconds) * ConfigData.Modules[0].SampleRateHz); if (ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBuffer) { GetArmAttribute(AttributeTypes.ArmAndEventAttributes.ArmMode, out byte value); var Value = (DFConstantsAndEnums.RecordingMode)value; if (Value != DFConstantsAndEnums.RecordingMode.CircularBuffer) { SetArmMode(DFConstantsAndEnums.RecordingMode.CircularBuffer); } } if (ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.AutoCircularBufferMode) { GetArmAttribute(AttributeTypes.ArmAndEventAttributes.ArmMode, out byte value); var Value = (DFConstantsAndEnums.RecordingMode)value; if (Value != DFConstantsAndEnums.RecordingMode.AutoCircularBufferMode) { SetArmMode(DFConstantsAndEnums.RecordingMode.AutoCircularBufferMode); } } //we should also set pre trigger for circular buffer if (ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBuffer || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBufferPlusUART || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.AutoCircularBufferMode || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.a14_NormalRecorderAndStreamSubSampleMode || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.RAMActive || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.MultipleEventRAMActive ) { setPostTrigger = new SetArmAttribute(this); setPostTrigger.SetValue(AttributeTypes.ArmAndEventAttributes.PreTriggerSamplesRequested, samples, true); setPostTrigger.SyncExecute(); } if (ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.Scheduled || ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.Interval) { //Make sure there's at least 2 minutes before the scheduled start if (ConfigData.Modules[0].ScheduledStartTime < DateTime.UtcNow.AddMinutes(DFConstantsAndEnums.SCHEDULE_AHEAD_IN_MINUTES)) { if (!bReleased) { bReleased = true; Release(); } var error = $"Scheduled start time must be at least 2 minutes in the future"; APILogger.Log(error); info.Error(error); return; } var intervalInSeconds = Convert.ToUInt32(0); if (ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.Interval) { //Convert to seconds from minutes intervalInSeconds = Convert.ToUInt32(ConfigData.Modules[0].RecordingInterval * 60); } var setScheduleStart = new SetArmAttribute(this); var startTimeInSeconds = DTS.Common.Utilities.Time.DateTimeToUnixTimestamp(ConfigData.Modules[0].ScheduledStartTime); var scheduleUnixTimeIntervalInSec = new UInt32[2] { startTimeInSeconds, intervalInSeconds }; setScheduleStart.SetValue(AttributeTypes.ArmAndEventAttributes.ScheduleUnixTimeIntervalInSec, scheduleUnixTimeIntervalInSec, true); setScheduleStart.SyncExecute(); } //performance improvement per LP/CPB //eliminate PrepareForDataCollection since same work is done by arm if (RunTestVariables.EliminatePrepareForDataCollection) { //skip } else { try { var prepare = new PrepareForDataCollection(this); prepare.SyncExecute(); } catch (Exception ex) { APILogger.Log(ex); try { //this was added to just add more debug information in the case //of a failed preparefordatacollection call //I believe the reason was primarily because it should be fast executing var qsa2 = new QuerySystemAttribute(this); qsa2.Key = AttributeTypes.SystemAttributes.AutoArmed; qsa2.DeviceID = 0; qsa2.SyncExecute(); } catch (Exception ex2) { APILogger.Log(ex2); } } } bReleased = true; Release(); info.Success(); } catch (CanceledException) { if (!bReleased) { bReleased = true; Release(); } info.Cancel(); } catch (CommandException ex) { if (!bReleased) { bReleased = true; Release(); } if (ex.Error == CommandErrorReason.ReceiveFailed || ex.Error == CommandErrorReason.SendFailed) { info.Error(string.Format(Resources.ArmFailtureDisconnect, SerialNumber)); } else { info.Error(string.Format(Resources.ArmFailureCommandException, SerialNumber)); } } catch (Exception ex) { APILogger.Log(ex); if (!bReleased) { bReleased = true; Release(); } info.Error(string.Format(Resources.ArmFailureGeneralException, SerialNumber)); } finally { if (!bReleased) { Release(); } } } protected void SetRTCBaseTime() { //14269 Implement SLICE PRO and Base+ RTC //set the RTC, this will cause the EventStartTime event attribute to have //meaningful values try { if (SupportsTimeSynchronization) { SetBaseSystemTime sbst = new SetBaseSystemTime(this); var dt = DateTime.Now; Thread.Sleep(1000 - dt.Millisecond - 1); sbst.SystemTime = DateTime.UtcNow; //18361 using UTC time over local time in case of later data processing sbst.SyncExecute(); } } catch (Exception ex) { APILogger.Log("Failed to set system time: ", ex); } } protected void RetrieveDASBootCount() { try { var query = new QuerySystemAttribute(this) { Key = AttributeTypes.SystemAttributes.DASBootCount }; query.SyncExecute(); } catch (Exception ex) { APILogger.Log(ex); } } protected void AsyncPreparedArm(object asyncInfo) { if (!(asyncInfo is ArmPacket info)) { return; } var bReleased = true; var armNow = new Arm(this, info.ArmNowTimeout); // 5 minute timeout RetrieveDASBootCount(); try { Lock(); bReleased = false; // we must have at least 7V to arm var inputs = new SLICEBaseInputReader(this); if (inputs.InputMilliVolts < 7000.0 && !info.TestingMode) { bReleased = true; Release(); info.Error($"{SerialNumber}: Input is less than 7 volts"); return; } SetMaxEvents(info.MaxNumberEvents); ResetEventListPriorToArm(); // After we've reset the event list, our (the DAS) EventInfo property is now invalid SetEventInfo(null); // store a unique GUID for this event SetEventGuid(info.EventGuid); if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.AutoArm)) { try { var ssa = new SetSystemAttribute(this); ssa.SetValue(AttributeTypes.SystemAttributes.AutoDiagnosticLevel, AUTO_ARM_PERFORM_ALL_DIAG, true); ssa.SyncExecute(); } catch (Exception ex) { APILogger.Log(ex); } } SetRTCBaseTime(); armNow.SyncExecute(); bReleased = true; Release(); info.Success(); } catch (CanceledException) { if (!bReleased) { bReleased = true; Release(); } info.Cancel(); } catch (CommandException ex) { if (!bReleased) { bReleased = true; Release(); } if (ex.Error == CommandErrorReason.ReceiveFailed || ex.Error == CommandErrorReason.SendFailed) { info.Error(string.Format(Resources.ArmFailtureDisconnect, SerialNumber)); } else { info.Error(string.Format(Resources.ArmFailureCommandException, SerialNumber)); } } catch (Exception ex) { if (IsSquibFault(ex)) { NotifySquibFault(); } APILogger.Log(ex); if (!bReleased) { bReleased = true; Release(); } info.Error(armNow.ArmStatus.ToString()); } finally { if (!bReleased) { Release(); } } } /// /// returns true if the error contains a squib resistance fault /// /// /// private bool IsSquibFault(Exception ex) { if (null == ex) { return false; } if (!string.IsNullOrEmpty(ex.Message)) { return ex.Message.Contains(DFConstantsAndEnums.CommandStatus.StatusArmSquibResistanceFault.ToString()); } return false; } /// /// notifies consumer of any squib faults during arming process /// private void NotifySquibFault() { try { var cmd = new MeasureSquibChannelResistances(this); cmd.SyncExecute(); var failingSquibs = new List(); for (int i = 0; i < 4 && i < cmd.MeasuredResistanceOhms.Length; i++) { var dResistance = cmd.MeasuredResistanceOhms[i]; var squib = GetSquibChannel(i); if (null == squib) { continue; } if (squib.ConfigurationMode != DFConstantsAndEnums.ConfigMode.Normal) { continue; } var dRoundUp = Math.Ceiling(dResistance * 10D) / 10D; var dRoundDown = Math.Floor(dResistance * 10D) / 10D; if (dRoundUp > squib.SquibToleranceHigh) { failingSquibs.Add(string.Format(Strings.SquibFailedToleranceHigh, i + 1, dRoundUp, squib.SquibToleranceHigh)); } else if (dRoundDown < squib.SquibToleranceLow) { failingSquibs.Add(string.Format(Strings.SquibFailedToleranceLow, i + 1, dRoundDown, squib.SquibToleranceLow)); } } var sb = new StringBuilder(); sb.AppendLine(string.Format(Strings.SquibToleranceFailure, SerialNumber)); foreach (var line in failingSquibs) { sb.AppendLine(line); } APILogger.RaiseError(sb.ToString()); } catch (Exception ex) { APILogger.Log("Failed to notify of squib fault", ex); } } /// /// gets the squib record by index of that squib among the four squibs /// /// /// private OutputSquibChannel GetSquibChannel(int index) { if (null == ConfigData || null == ConfigData.Modules) { return null; } if (!ConfigData.Modules.Any()) { return null; } //each squib has two records, a current channel and a voltage/init channel //just return the first of the two channels for the squib in question var channel = ConfigData.Modules[0].Channels[index * 2]; return channel as OutputSquibChannel; } /// /// the UDP settings to broadcast auto arm status to on auto arm boot /// 17583 Monitor Test UI /// public string AutoArmUDPSetting { get; set; } = "239.1.2.3:8504"; void IArmActions.AutoArmNow(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool testingMode, uint diagnosticsDelayMs, int MaxEventCount, bool repeatEnable, bool preserveDiagnostics) { var info = new AutoArmPacket(callback, userData, eventGuid, armNowTimeout, testingMode, diagnosticsDelayMs, MaxEventCount, repeatEnable, preserveDiagnostics); LaunchAsyncWorker("Slice.AutoArmNow", AsyncAutoArmNow, info); } protected enum diaglevels { AUTODIAG_REMOVE_OFFSET, AUTODIAG_VOLTAGE_INSERTION, AUTODIAG_SHUNT_TEST, AUTODIAG_EXCITATION_CHECK, AUTODIAG_NOISE_MEASUREMENT, AUTODIAG_INPUTV_BACKUPV, AUTODIAG_LT_CHECK, AUTODIAG_SATURATION, AUTODIAG_CALSIG_CHECK } //Always do all diagnostic options in older 00M3 based firmware protected const UInt16 AUTO_ARM_PERFORM_ALL_DIAG = 1; protected virtual void SetAutoArmUDPSettings() { } protected virtual void SetAutoArmRecordDelay() { try { var ssa = new SetSystemAttributeSLICE2(this); ssa.SetValue(AttributeTypes.SystemAttributesSLICE2.StartRecDelayInSecond, Convert.ToUInt16(RunTestVariables.AutoArmRecordDelaySeconds), true); ssa.SyncExecute(); } catch (Exception ex) { APILogger.Log(ex); } } private void SetRepeatEnable() { if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmRepeatEnable)) { var ssa = new SetSystemAttributeSLICE2(this); ssa.DeviceID = 0; ssa.SetValue(AttributeTypes.SystemAttributesSLICE2.AutoArmRepeatEnable, (byte)0x01, true); ssa.SyncExecute(); } } private void SetAutoArm() { if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.AutoArm)) { var ssa = new SetSystemAttribute(this); ssa.DeviceID = 0; ssa.SetValue(AttributeTypes.SystemAttributes.AutoArmed, (byte)0x01, true); ssa.SyncExecute(); } } private void AsyncAutoArmNow(object asyncInfo) { if (!(asyncInfo is AutoArmPacket info)) { return; } SetRTCBaseTime(); try { if (DFConstantsAndEnums.UseUDPForAutoArmATDMonitor) { var infoFile = new Common.Classes.Hardware.DASMonitorInfo(this, IsoViewModeStatic.ViewMode); infoFile.WriteToFile(Path.Combine(DTS.Common.Constants.DAS_CONFIGS, $"{SerialNumber}_MonitorInfo.txt")); } if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmUDPSetting)) { try { SetAutoArmUDPSettings(); } catch (Exception ex) { APILogger.Log(ex); } } if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmRecordDelay)) { SetAutoArmRecordDelay(); } // we must have at least 7V to arm var inputs = new SLICEBaseInputReader(this); if (inputs.InputMilliVolts < 7000.0 && !info.TestingMode) { info.Error($"{SerialNumber}: Input is less than 7 volts"); return; } ResetEventListPriorToArm(); // After we've reset the event list, our (the DAS) EventInfo property is now invalid SetEventInfo(null); // store a unique GUID for this event SetEventGuid(info.EventGuid); //this is protocol 10 SetAutoArm(); try { var ssa = new SetSystemAttribute(this); ssa.DeviceID = 0; ssa.SetValue(AttributeTypes.SystemAttributes.AutoDiagnosticLevel, AUTO_ARM_PERFORM_ALL_DIAG, true); ssa.SyncExecute(); } catch (Exception ex) { APILogger.Log("Failed to set AutoArm failure checking", ex); } try { if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmRepeatEnable)) { // FB15507: Allow user to elect to repeat auto-arm/streaming after power cycle(s) var ssa = new SetSystemAttributeSLICE2(this); ssa.DeviceID = 0; ssa.SetValue(AttributeTypes.SystemAttributesSLICE2.AutoArmRepeatEnable, info.RepeatEnable ? (byte)0x01 : (byte)0x00, true); ssa.SyncExecute(); } } catch (Exception ex) { APILogger.Log("Failed to set AutoArm repeat enable/disable", ex); } try { if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmDiagnosticDelay)) { var saa = new SetArmAttribute(this); saa.LogCommands = true; saa.SetValue(AttributeTypes.ArmAndEventAttributes.AutoDiagnosticStabilizationTimeoutMs, info.DiagnosticsDelayMs, true); saa.SyncExecute(); } } catch (Exception) { APILogger.Log("Failed to set diagnostics delay time"); } try { if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.StackChannelAutoArmDiagLevel)) { var scadl = new List(); foreach (var da in ChannelDiagnostics) { // FB15507: Allow user to elect to preserve Run Test diagnostics through auto-arm/streaming scadl.Add( (ushort) ( (Convert.ToUInt16(!info.PreserveDiagnostics && da.RemoveOffset) << (ushort)diaglevels.AUTODIAG_REMOVE_OFFSET) + (Convert.ToUInt16(!info.PreserveDiagnostics && da.PerformShuntCheck) << (ushort)diaglevels.AUTODIAG_SHUNT_TEST) + (Convert.ToUInt16(!info.PreserveDiagnostics && da.MeasureExcitation) << (ushort)diaglevels.AUTODIAG_EXCITATION_CHECK) + (Convert.ToUInt16(!info.PreserveDiagnostics && da.MeasureNoise) << (ushort)diaglevels.AUTODIAG_NOISE_MEASUREMENT) + (Convert.ToUInt16(false) << (ushort)diaglevels.AUTODIAG_VOLTAGE_INSERTION) + (Convert.ToUInt16(!info.PreserveDiagnostics && da.PerformCalSignalCheck) << (ushort)diaglevels.AUTODIAG_CALSIG_CHECK) ) ); } var saa = new SetArmAttribute(this); saa.LogCommands = true; saa.SetValue(AttributeTypes.ArmAndEventAttributes.StackChannelAutoArmDiagnosticLevel, scadl.ToArray(), true); saa.SyncExecute(); } } catch (Exception) { APILogger.Log("Failed to set diagnostics delay time"); } SetMaxEvents(info.MaxNumberEvents); AutoArmed = true; info.Success(); } catch (CanceledException) { info.Cancel(); } catch (CommandException ex) { if (ex.Error == CommandErrorReason.ReceiveFailed || ex.Error == CommandErrorReason.SendFailed) { info.Error(string.Format(Resources.ArmFailtureDisconnect, SerialNumber)); } else { info.Error(string.Format(Resources.ArmFailureCommandException, SerialNumber)); } } catch (Exception) { info.Error(string.Format(Resources.ArmFailureGeneralException, SerialNumber)); } } protected virtual void SetEventGuid(Guid guid) { var set = new SetArmAttribute(this); set.SetValue(AttributeTypes.ArmAndEventAttributes.EventGuid, guid.ToString(), true); set.SyncExecute(); } protected virtual Guid GetEventGuid(int eventNum) { var eventGuid = new QueryEventAttribute(this); eventGuid.EventNumber = (ushort)eventNum; eventGuid.Key = AttributeTypes.ArmAndEventAttributes.EventGuid; eventGuid.SyncExecute(); return new Guid(eventGuid.Value as string); } #endregion #region EnableFaultChecking void IArmActions.EnableFaultChecking(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice.EnableFaultChecking", AsyncEnableFaultChecking, info); } private void AsyncEnableFaultChecking(object asyncInfo) { var info = asyncInfo as SliceServiceAsyncInfo; try { var enableFaultChecking = new EnableFaultChecking(this); enableFaultChecking.SyncExecute(); info?.Success(); } catch (CanceledException) { info?.Cancel(); } catch (Exception ex) { info?.Error(ex.Message, ex); } } #endregion #region Disarm void IArmActions.DisAutoArm(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice.DisAutoArm", AsyncDisAutoArm, info); } /// /// abstracted this functionality to it's own method - unsets the auto arm flag /// protected void DisAutoArm() { var ssa = new SetSystemAttribute(this); ssa.DeviceID = 0; ssa.SetValue(AttributeTypes.SystemAttributes.AutoArmed, (byte)0x00, true); ssa.SyncExecute(); AutoArmed = false; } private void AsyncDisAutoArm(object asyncInfo) { var info = asyncInfo as SliceServiceAsyncInfo; try { DisAutoArm(); info?.Success(); } catch (CanceledException) { info?.Cancel(); } catch (Exception ex) { info?.Error(ex.Message, ex); } } void IArmActions.Disarm(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice.Disarm", AsyncDisarm, info); } private void AsyncDisarm(object asyncInfo) { var info = asyncInfo as SliceServiceAsyncInfo; try { var disarmRequest = new Disarm(this, 30000); disarmRequest.SyncExecute(); info?.Success(); } catch (CanceledException) { info?.Cancel(); } catch (Exception ex) { info?.Error(ex.Message, ex); } } #endregion #region GetArmStatus protected class GetArmStatusPacket { public SliceServiceAsyncInfo Info { get; set; } public uint InputVoltageCutoff { get; set; } public GetArmStatusPacket(SliceServiceAsyncInfo info, uint inputVoltageCutoff) { Info = info; InputVoltageCutoff = inputVoltageCutoff; } } void IArmActions.GetArmStatus(ServiceCallback callback, object userData, uint inputVoltageCutoff, int maxTimeout) { var info = new SliceServiceAsyncInfo(callback, userData) { MaxTimeout = maxTimeout }; var packet = new GetArmStatusPacket(info, inputVoltageCutoff); LaunchAsyncWorker("Slice.GetArmStatus", AsyncGetArmStatus, packet); } void IArmActions.GetAutoArmStatus(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice.GetAutoArmStatus", AsyncGetAutoArmStatus, info); } void IArmActions.GetExtendedFaultIds(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice.GetExtendedFaultIds", new WaitCallback(SLICEAsyncGetExtendedFaultIds), info); } private void SLICEAsyncGetExtendedFaultIds(object asyncInfo) { var info = (SliceServiceAsyncInfo)asyncInfo; try { var faults = GetExtendedFaultFlags(); var bytes = new List(); foreach (var fault in faults) { bytes.AddRange(BitConverter.GetBytes((int)fault)); } info.NewData(bytes.ToArray()); } catch (Exception ex) { APILogger.Log(ex); } info.Success(); } protected ushort GetEventCount() { try { var eventCountQuery = new QuerySystemAttribute(this); eventCountQuery.Key = AttributeTypes.SystemAttributes.TotalEventsStored; eventCountQuery.SyncExecute(); return (ushort)eventCountQuery.Value; } catch (Exception ex) { APILogger.Log(ex); } return 0; } protected volatile int straightFailures = 0; protected const int PERMITTED_FAILURES = 30; protected virtual void AsyncGetArmStatus(object asyncInfo) { if (!(asyncInfo is GetArmStatusPacket packet)) { return; } var info = packet.Info; var bLocked = false; try { Lock(); bLocked = true; var status = new QueryArmAndTriggerStatus(this); if (null != info.MaxTimeout) { status.IO_Timeout = (int)info.MaxTimeout; } status.SyncExecute(); var armStatus = new ArmStatus(); armStatus.IsRearming = false; armStatus.IsArmed = status.IsArmed; armStatus.IsInRealtime = status.IsInRealtime; // this one is accurate // if we're not armed, the other values are useless if (status.IsArmed) { armStatus.IsFaulted = status.IsFaulted; armStatus.IsRecording = status.IsRecording; armStatus.IsTriggered = status.IsTriggered; armStatus.TotalSamples = status.TotalSamples; armStatus.CurrentSample = status.CurrentSample; armStatus.SampleRate = status.EventSampleRate; armStatus.TimeRemainingSeconds = (status.TotalSamples - Math.Min(status.TotalSamples, status.CurrentSample)) / (double)status.EventSampleRate; armStatus.EventNumber = status.EventNumber; if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryArmAndTriggerStatus_TimeLeftInArm)) { try { //Remaining samples divided by sample rate armStatus.TimeLeftInArm = (status.MaxSampleAvailable - status.ActualCurrentSample) / status.EventSampleRate; } catch (Exception ex) { APILogger.Log(ex); } } } else { //when QuerySwitchImmediate works if (this is WinUSBTsrAir || this is EthernetTsrAir) { armStatus.IsRecording = status.IsRecording; armStatus.IsTriggered = status.IsTriggered; if (null != DASArmStatus && !DASArmStatus.IsArmed && !status.IsArmed) { armStatus.MaxEventsPossible = DASArmStatus.MaxEventsPossible; } else { armStatus.MaxEventsPossible = GetMaxEvents(); } } else { armStatus.IsRecording = GetRecordingFlag(); armStatus.IsTriggered = GetTriggeredFlag(); } armStatus.TotalSamples = 0; armStatus.CurrentSample = 0; armStatus.SampleRate = 0; armStatus.TimeRemainingSeconds = 0; armStatus.RecordingMode = 0; armStatus.EventNumber = null; } if (status.IsArmed || status.IsInRealtime) { armStatus.RecordingMode = Convert.ToInt32(status.ArmMode); } if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryArmAndTriggerStatus_VoltageReadings)) { armStatus.InputMilliVolts = status.InputVoltage * 1000; if (status.BackupVoltage >= 4) { armStatus.BatteryMilliVolts = status.BackupVoltage * 1000; } } if (status.IsDiagnostics || status.IsFlashClear || status.IsArming) { armStatus.IsArmed = true; armStatus.IsRearming = true; } // update input voltage readings (for optional display) // based on test with 100kHz+ recording, it's not safe to get input voltage check during because we could accidently // stomp on the recording portion. if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryArmAndTriggerStatus_VoltageReadings) && !armStatus.IsRecording && armStatus.SampleRate < packet.InputVoltageCutoff) { var inputs = new SLICEBaseInputReader(this); armStatus.InputMilliVolts = inputs.InputMilliVolts; if (DASInfo != null && DASInfo.HasBattery) { armStatus.BatteryMilliVolts = inputs.DirectBackupMilliVolts; } else { armStatus.BatteryMilliVolts = null; } } if (armStatus.IsArmed && null != armStatus.BatteryMilliVolts && armStatus.BatteryMilliVolts < 200) { status = new QueryArmAndTriggerStatus(this, 8000); status.SyncExecute(); armStatus.IsArmed = status.IsArmed; } SetBaseInputs(status); try { if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.MeasurePowerProAllDiagnosticChannel)) { var mppadc = new MeasurePowerProAllDiagnosticChannel(this); mppadc.SyncExecute(); // Just Log it for now } } catch (Exception ex) { APILogger.Log("Failed to Measure All Diagnostic Channel", ex); } var faults = new List(); foreach (var flag in status.CurrentFaultFlags) { faults.Add(flag.ToString()); } foreach (var flag in status.ExtendedFaultFlags) { faults.Add(flag.ToString()); } if (armStatus.IsArmed) { ExcitationStatus = DFConstantsAndEnums.ExcitationStatus.On; } else { if (null != DASArmStatus && DASArmStatus.EventNumber > 0 && !armStatus.IsArmed && !DASArmStatus.IsArmed) { //we make an assumption here that if we aren't and weren't armed, then it didn't change armStatus.EventNumber = DASArmStatus.EventNumber; } else { armStatus.EventNumber = GetEventCount(); } } armStatus.FaultMessage = string.Join(", ", faults); SetDASArmStatus(armStatus, true); 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("GetArmStatus error - has failed ", straightFailures, " times, giving up", ce); info.Error(ce.Message, ce); } else { var status = new ArmStatus(); status.IsRecording = false; status.IsArmed = true; status.IsRearming = true; status.RecordingMode = 0; status.InputMilliVolts = null; status.EventNumber = null; status.CurrentSample = 0; SetDASArmStatus(status, true); if (ce.Error == CommandErrorReason.ReceiveFailed && null != info.MaxTimeout) { info.Error(ce.Error.ToString()); } else { info.Success(); } APILogger.Log("GetArmStatus error", ce); } } catch (Exception ex) { if (bLocked) { bLocked = false; Release(); } info.Error(ex.Message, ex); } finally { if (bLocked) { Release(); } } } protected void GetAutoArmStatus() { //performance improvement, eliminate unnecessary commands when possible if (RunTestVariables.InRunTest && !RunTestVariables.CheckForAutoArmedInRunTest) { AutoArmed = false; return; } //15949 S6A when streaming does a whole bunch of unnecessary queries //avoid getting autoam status if streaming, it will fail if (GetIsStreaming()) { AutoArmed = false; AutoArmStatus = DFConstantsAndEnums.CommandStatus.StatusNoError; return; } if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.AutoArm)) { var qsa2 = new QuerySystemAttribute(this); qsa2.Key = AttributeTypes.SystemAttributes.AutoArmed; qsa2.DeviceID = 0; qsa2.SyncExecute(); if ((byte)qsa2.Value == 0x02) { var qsa = new QuerySystemAttribute(this); qsa.DeviceID = 0; qsa.Key = AttributeTypes.SystemAttributes.AutoArmError; qsa.SyncExecute(); var iValue = (ushort)qsa.Value; AutoArmStatus = (DFConstantsAndEnums.CommandStatus)iValue; SetAutoArm(); AutoArmed = false; } else if ((byte)qsa2.Value == 0x01) { AutoArmed = true; AutoArmStatus = DFConstantsAndEnums.CommandStatus.StatusNoError; } else { AutoArmed = false; AutoArmStatus = DFConstantsAndEnums.CommandStatus.StatusNoError; } } else { AutoArmStatus = DFConstantsAndEnums.CommandStatus.StatusUnimplemented; } } private void AsyncGetAutoArmStatus(object asyncInfo) { var info = asyncInfo as SliceServiceAsyncInfo; try { GetAutoArmStatus(); info?.Success(); } catch (Exception ex) { info?.Error("Problem querying auto arm status", ex); } } protected bool GetFaultedFlag() { var qs = new QuerySwitchImmediate(this); qs.Switch = (byte)Switches.BaseSwitches.StatusMonitor; qs.SwitchText = Switches.BaseSwitches.StatusMonitor.ToString(); qs.SyncExecute(); return qs.Setting == 1; } protected bool GetRecordingFlag() { var qs = new QuerySwitchImmediate(this); qs.Switch = (byte)Switches.BaseSwitches.StartRecordOut; qs.SwitchText = Switches.BaseSwitches.StartRecordOut.ToString(); qs.SyncExecute(); return qs.Setting == 1; } protected bool GetTriggeredFlag() { var qs = new QuerySwitchImmediate(this); qs.Switch = (byte)Switches.BaseSwitches.TriggerOut; qs.SwitchText = Switches.BaseSwitches.TriggerOut.ToString(); qs.SyncExecute(); return qs.Setting == 1; } #endregion #region EnterLowPowerMode void IArmActions.EnterLowPowerMode(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice.EnterLowPowerMode", AsyncEnterLowPowerMode, info); } protected virtual void AsyncEnterLowPowerMode(object asyncInfo) { var info = asyncInfo as SliceServiceAsyncInfo; DiagnosticsHasBeenRun = false; try { //clear any diagnostic results we have, they will be invalid after going to low power //16164 User can proceed past diag. without running on all channels ClearChannelDiagnosticsResults(); if (DASInfo != null && DASInfo.Modules != null) { // DeviceID is the module index + 1 for (int i = 0; i < DASInfo.Modules.Length; i++) { try { DisablePowerSupply(DASInfo.Modules[i].TypeOfModule, (byte)(i + 1)); } catch (Exception ex) { APILogger.Log("problem disabling power supply", ex); } } } ExcitationStatus = DFConstantsAndEnums.ExcitationStatus.Off; info?.Success(); } catch (CanceledException) { info?.Cancel(); } catch (Exception ex) { info?.Error(ex.Message, ex); } } /// /// sets the SLICEMaxEnable attribute for the das in question /// does not use services, so does not protect from other commands being run at same time /// protected void SetMaxModuleCount(int count, bool disablePowerSupply) { try { //turn off power supplies first if (DASInfo != null && DASInfo.Modules != null && DASInfo.Modules.Length > 0 && disablePowerSupply) { DisablePowerSupply(DASInfo.Modules[0].TypeOfModule, 1); } var ssa = new SetSystemAttributeSLICE2(this); ssa.SetValue(AttributeTypes.SystemAttributesSLICE2.MaxSLICEEnable, (byte)count, true); ssa.SyncExecute(); } catch (Exception ex) { APILogger.Log("Failed to set max module count", SerialNumber, ex); } } /// /// gets the physical max number of modules. /// only retrieves from DAS if passed in value is invalid, otherwise returns the value passed in /// does not use services, so does not protect from other commands being run at same time /// /// protected int GetMaxModuleCount(int maxModuleCount) { if (-1 == maxModuleCount) { try { var q = new QuerySystemAttributeSLICE2(this); q.Key = AttributeTypes.SystemAttributesSLICE2.SLICECountOnStack; q.SyncExecute(); return Convert.ToInt32(q.Value); } catch (Exception ex) { APILogger.Log("Failed to get max module count", SerialNumber, ex); } return DASInfo.Modules.Length; } else { return maxModuleCount; } } protected void DisablePowerSupply(DFConstantsAndEnums.ModuleType moduleType, byte DeviceID) { var setSwitch = new SetSwitchImmediate(this, 10000); switch (moduleType) { case DFConstantsAndEnums.ModuleType.SLICEIEPE: setSwitch.Switch = (byte)Switches.EIPESwitches.IS_EnableAnalogPowerSupply; setSwitch.SwitchText = Switches.EIPESwitches.IS_EnableAnalogPowerSupply.ToString(); break; default: setSwitch.Switch = (byte)Switches.BridgeSwitches.EnableAnalogPowerSupply; setSwitch.SwitchText = Switches.BridgeSwitches.EnableAnalogPowerSupply.ToString(); break; } setSwitch.Setting = 0; setSwitch.DeviceGroup = 0; setSwitch.DeviceID = DeviceID; setSwitch.SyncExecute(); } #endregion #region Start & Trigger void IArmActions.StartRecord(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice.StartRecord", AsyncStartRecord, info); } private void AsyncStartRecord(object asyncInfo) { var info = asyncInfo as SliceServiceAsyncInfo; try { var setSwitch = new SetSwitchImmediate(this); setSwitch.Switch = (byte)Switches.BaseSwitches.StartRecordOut; setSwitch.SwitchText = Switches.BaseSwitches.StartRecordOut.ToString(); setSwitch.Setting = 1; setSwitch.DeviceGroup = 0; setSwitch.DeviceID = 0; setSwitch.SyncExecute(); info?.Success(); } catch (CanceledException) { info?.Cancel(); } catch (Exception ex) { info?.Error(ex.Message, ex); } } void IArmActions.Trigger(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice.Trigger", AsyncTrigger, info); } protected virtual void AsyncTrigger(object asyncInfo) { var info = asyncInfo as SliceServiceAsyncInfo; try { var setSwitch = new SetSwitchImmediate(this); setSwitch.Switch = (byte)Switches.BaseSwitches.TriggerOut; setSwitch.SwitchText = Switches.BaseSwitches.TriggerOut.ToString(); setSwitch.Setting = 1; setSwitch.DeviceGroup = 0; setSwitch.DeviceID = 0; setSwitch.SyncExecute(); info?.Success(); } catch (CanceledException) { info?.Cancel(); } catch (Exception ex) { info?.Error(ex.Message, ex); } } #endregion #region Voltage Check public void PerformVoltageCheck(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice.PerformVoltageCheck", AsyncPerformVoltageCheck, info); } private void AsyncPerformVoltageCheck(object o) { var info = o as SliceServiceAsyncInfo; try { if (GetIsStreaming()) { //15949 S6A when streaming does a whole bunch of unnecessary queries //avoid getting inputs, it will fail } else { GetBaseInputs(); } info?.Success(); } catch (Exception ex) { APILogger.Log(ex); info?.Error(ex.Message); } } public void PerformVoltageCheckTAOnly(ServiceCallback callback, object userData) { var info = new SliceServiceAsyncInfo(callback, userData); LaunchAsyncWorker("Slice.PerformVoltageCheckTAOnly", AsyncPerformVoltageCheckTAOnly, info); } private void AsyncPerformVoltageCheckTAOnly(object o) { var info = o as SliceServiceAsyncInfo; var status = new QueryArmAndTriggerStatus(this); status.SyncExecute(); SetBaseInputs(status); info?.Success(); } #endregion Voltage Check } }