using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using DTS.Common.Utilities; using DTS.Common.Utilities.Logging; using DTS.DASLib.Command; using DTS.Common.DAS.Concepts; using DTS.Common.ICommunication; using DTS.DASLib.Command.TDAS; using DTS.Common.Interface.Connection; using DTS.Common.Enums.DASFactory; using DTS.Common.Interface.DASFactory.Config; using DTS.Common.Interface.DASFactory; namespace DTS.DASLib.Service { public partial class TDAS : Communication, IDASCommunication, IConfigurationActions, IDiagnosticsActions, ITriggerCheckActions, IRealTimeActions, IArmActions, IDownloadActions where T : IConnection, new() { public int[] GetStackChannelConfigTypes() => new int[] { 0 }; /// /// /// public string TestDirectory { get; set; } void IConfigurationActions.QueryTestSetup(ServiceCallback callback, object userData) { var info = new TDASServiceAsyncInfo(callback, userData); info.Success(); } void IConfigurationActions.StoreTestSetupXML(ServiceCallback callback, object userData, string testSetupXML) { var info = new TDASServiceAsyncInfo(callback, userData); info.Success(); } /// /// 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; } public bool SupportsMultipleConfigurations() { return false; } void IDASCommunication.SetIsStreamingSupported(bool supported) { IsStreamingSupported = false; } void IDASCommunication.ReadFirstUseDate() { IsFirstUseDateSupported = false; FirstUseDate = null; } public bool ConnectionCheck() { try { var querySerialNumber = new QuerySerialNumber(this); querySerialNumber.SyncExecute(); return true; } catch (Exception ex) { APILogger.Log(ex); } return false; } /// /// discovers any connected devices /// TDAS does support this currently /// public void QueryConnectedDevices() { } public int MaxModules { get; set; } = 4; bool IArmActions.SupportsBackgroundFlashErase => IsG5(); private DateTime _backgroundFlashClearStart = DateTime.MinValue; DateTime? IArmActions.BackgroundFlashEraseStartTime { get { if (DateTime.MinValue == _backgroundFlashClearStart) { return null; } return _backgroundFlashClearStart; } } bool IArmActions.BackgroundFlashEraseStarted => null != (this as IArmActions).BackgroundFlashEraseStartTime; void IArmActions.BeginBackgroundFlashErase(ServiceCallback callback, object userData) { var info = new TDASServiceAsyncInfo(callback, userData); if (!(this as IArmActions).SupportsBackgroundFlashErase) { info.Success(); return; } if (_backgroundFlashClearStart != DateTime.MinValue) { info.Success(); return; }//it's already been called ... LaunchAsyncWorker("TDAS.BeginBackgroundFlashErase", AsyncBeginBackgroundFlashErase, info); } private void AsyncBeginBackgroundFlashErase(object o) { var info = o as TDASServiceAsyncInfo; DoFlashErase(false); _backgroundFlashClearStart = DateTime.Now; info?.Success(); } private void DoFlashErase(bool dummyArm) { if (!IsG5()) return; if ((this as IArmActions).BackgroundFlashEraseStarted) return; var rfc = new RackFlashClear(this); rfc.SampleRate = Convert.ToDouble(ConfigData.Modules[0].SampleRateHz); //didn't help at all :/ if (dummyArm) { rfc.RecordingTime = .1; } else { rfc.RecordingTime = ConfigData.Modules[0].PreTriggerSeconds + ConfigData.Modules[0].PostTriggerSeconds; } rfc.SyncExecute(); } void IArmActions.TurnOffT0Lights(ServiceCallback callback, object userData) { var info = new TDASServiceAsyncInfo(callback, userData); LaunchAsyncWorker("TDAS.TurnOffT0Lights", AsyncTurnOffT0Lights, info); } private void AsyncTurnOffT0Lights(object o) { var info = o as TDASServiceAsyncInfo; if (!IsG5()) { try { //turn off lights foreach (var mod in ConfigData.Modules) { if (mod.SerialNumber() == "EMPTY") continue; var qsnb = new QuerySerialNumberBroadcast(this, mod.ModuleArrayIndex); qsnb.SyncExecute(); break; } } catch (Exception ex) { info?.Error(ex.Message); } } info?.Success(); } public void SetDASDisplayOrder(int order) { throw new NotSupportedException("Not supported for TDAS"); } public void SetChannelDisplayOrder(int[] order) { throw new NotSupportedException("Not supported for TDAS"); } public int GetDASDisplayOrder() { return -1; } public int[] GetChannelDisplayOrder() { return new[] { -1 }; } public bool RequireDiagnosticRateMatchSampleRate() { return false; } public DateTime SystemBaseTime => DateTime.MinValue; public bool RangeBandwidthLimited => false; public bool SupportsTimeSynchronization => false; 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); info.DummyArm = dummyArm; info.SysMode = sysMode; LaunchAsyncWorker("TDAS.ReadyArming", AsyncReadyArming, info); } private void AsyncReadyArming(object asyncInfo) { var info = asyncInfo as ArmPacket; try { // not needed, we will query it again when turning it on. var bHasDigitalChannels = false; SetupG5LevelTrigger setupLT = null; //if a g5 has _only_ digital channels, we don't want to dummy arm it as the digital channels won't work properly //this little bit detects if there are digital channels in play on this g5 if (IsG5()) { foreach (var m in ConfigData.Modules) { foreach (var c in m.Channels) { if (!(c is AnalogInputDASChannel)) continue; if (!(c as AnalogInputDASChannel).DigitalInputChannel || c.ConfigurationMode != DFConstantsAndEnums.ConfigMode.Normal) continue; bHasDigitalChannels = true; break; } if (bHasDigitalChannels) { break; } } } var bAllModulesDummyArmed = true; for (var moduleIdx = 0; moduleIdx < DASInfo.Modules.Length; moduleIdx++) { if (DASInfo.Modules[moduleIdx].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK) { continue; } var dummyChannels = from c in ConfigData.Modules[moduleIdx].Channels where c.ConfigurationMode == DFConstantsAndEnums.ConfigMode.DummyArm select c; if (DASInfo.Modules[moduleIdx].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK) { continue; } #region IsTom if (IsTom((DASModule)ConfigData.Modules[moduleIdx])) { var bHasDoutsOnly = true; foreach (var ch in ConfigData.Modules[moduleIdx].Channels) { if (ch is OutputTOMDigitalChannel) { //if we've gotten here then are sure there's no normal configured channels, //so we just need to check that there's a digital channel bHasDoutsOnly = false; if (ch.ConfigurationMode != DFConstantsAndEnums.ConfigMode.Normal) continue; bHasDoutsOnly = true; break; } if (ch.ConfigurationMode != DFConstantsAndEnums.ConfigMode.Normal) continue; bHasDoutsOnly = false; break; } var sdl = new SetupTOMDASLoad(this); if (null != dummyChannels && dummyChannels.Any() || info.DummyArm || bHasDoutsOnly) { sdl.IsDummyArm = true; sdl.CollectData = null == dummyChannels || !dummyChannels.Any(); } else { bAllModulesDummyArmed = false; } sdl.TestConfig = $"{info.EventGuid.ToString()}{SETUPDASREAD_SENTINEL}{ConfigData.Description}{SETUPDASREAD_SENTINEL}{ConfigData.Modules[moduleIdx].GetCRC32()}"; switch (ConfigData.Modules[moduleIdx].RecordingMode) { case DFConstantsAndEnums.RecordingMode.AutoCircularBufferMode: case DFConstantsAndEnums.RecordingMode.AutoRecorderMode: throw new NotSupportedException("TOM does not support Auto Mode"); case DFConstantsAndEnums.RecordingMode.CircularBuffer: case DFConstantsAndEnums.RecordingMode.CircularBufferPlusUART: case DFConstantsAndEnums.RecordingMode.a16_CircularBufferAndStreamSubSampleMode: sdl.ArmMode = SetupTOMDASLoad.ARMMode.WAIT; break; case DFConstantsAndEnums.RecordingMode.RecorderMode: case DFConstantsAndEnums.RecordingMode.RecorderModePlusUART: case DFConstantsAndEnums.RecordingMode.a14_NormalRecorderAndStreamSubSampleMode: sdl.ArmMode = SetupTOMDASLoad.ARMMode.TAPE; break; default: throw new NotSupportedException( "Mode not supported for TOM: " + ConfigData.Modules[moduleIdx].RecordingMode.ToString()); } double aaFilter = ConfigData.Modules[moduleIdx].AAFilterRateHz; if (aaFilter > MaxAAFilterRateHz) { aaFilter = MaxAAFilterRateHz; } if (0 == aaFilter && IsG5()) { aaFilter = MaxAAFilterRateHz; } sdl.SetHardwareAAFilter(Convert.ToInt32(aaFilter), MaxAAFilterRateHz); sdl.ModuleIndex = ConfigData.Modules[moduleIdx].ModuleArrayIndex; sdl.PostTriggerSeconds = ConfigData.Modules[moduleIdx].PostTriggerSeconds; sdl.PreTriggerSeconds = ConfigData.Modules[moduleIdx].PreTriggerSeconds; sdl.SampleRate = ConfigData.Modules[moduleIdx].SampleRateHz; sdl.TestId = ConfigData.TestID; sdl.TriggerType = SetupTOMDASLoad.TriggerTypes.BUS; if (info.DummyArm) { sdl.IsDummyArm = true; sdl.CollectData = null == dummyChannels || !dummyChannels.Any(); } sdl.SyncExecute(); } #endregion IsTom else { var module = ConfigData.Modules[moduleIdx]; var levelTriggerMode = SetupDASLoad.TriggerModes.GT; var levelTriggerEnabled = false; //g5 var levelTriggerUpperThresholds = new List(); var levelTriggerLowerThresholds = new List(); var g5LTTypes = new List(); var levelTriggerChannels = new List(); // For SIM var levelTriggerChannel = 0; short levelTriggerUpperThreshold = 0; short levelTriggerLowerThreshold = 0; // configure the range for this bridge for (var channelIdx = 0; channelIdx < module.Channels.Length; channelIdx++) { var g5LTType = SetupG5LevelTrigger.LevelTriggerTypes.OW; var channel = module.Channels[channelIdx]; var dasChannelNumber = DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(moduleIdx, channelIdx); if (channel.ConfigurationMode != DFConstantsAndEnums.ConfigMode.Normal) continue; bAllModulesDummyArmed = false; var analog = channel as AnalogInputDASChannel; if (analog.SensitivityMilliVoltsPerEU == 0) continue; var levelTriggerOnThisChannel = false; var unused = GetMvPerEu(analog); // // push level trigger settings out to hardware // // If this is level trigger, diagnostic results may be null. Need to cope. var scalefactorMilliVoltsPerADC = analog.ScalefactorMilliVoltsPerADC; var offsetRemovalADC = 0; try { var diagnostics = analog.Diagnostics; scalefactorMilliVoltsPerADC = diagnostics.ScalefactorMilliVoltsPerADC; offsetRemovalADC = diagnostics.GetExpectedDataZeroLevelADC(analog.ZeroMethod); } catch (Exception) { } if (null != analog.TriggerBelowThresholdEu) { var invertScaleFactor = 1D; if (analog.IsInverted) { invertScaleFactor = -1D; } levelTriggerOnThisChannel = true; var bInvert = analog.IsInverted; if (analog.ScalefactorMilliVoltsPerADC < 0) { bInvert = !bInvert; } if (analog.SensitivityMilliVoltsPerEU < 0) { bInvert = !bInvert; } if (bInvert) { } try { // Careful here... if remove offset is NOT active, and zero method is "none", // then just send the level trigger as specified down to the hardware. Othewise, // we'll need to apply the appropriate offset to it so it triggers as expected. // if (bInvert) { levelTriggerUpperThreshold = (short)(invertScaleFactor * analog.TriggerBelowThresholdEu * analog.SensitivityMilliVoltsPerEUNormalized / scalefactorMilliVoltsPerADC + offsetRemovalADC); } else { levelTriggerLowerThreshold = (short)(invertScaleFactor * analog.TriggerBelowThresholdEu * analog.SensitivityMilliVoltsPerEUNormalized / scalefactorMilliVoltsPerADC + offsetRemovalADC); } } catch (ApplicationException ex) { if (null != Exceptional .ExtractFirstExceptionOfTypeFromExceptionTree(ex)) levelTriggerLowerThreshold = (short)(analog.TriggerBelowThresholdEu * analog.SensitivityMilliVoltsPerEUNormalized / scalefactorMilliVoltsPerADC); else throw; } levelTriggerMode = SetupDASLoad.TriggerModes.LT; g5LTType = SetupG5LevelTrigger.LevelTriggerTypes.LT; if (bInvert) { //FLIP IT! levelTriggerMode = SetupDASLoad.TriggerModes.GT; g5LTType = SetupG5LevelTrigger.LevelTriggerTypes.GT; } } if (null != analog.TriggerAboveThresholdEu) { levelTriggerOnThisChannel = true; var invertScaleFactor = 1D; if (analog.IsInverted) { invertScaleFactor = -1D; } var bInvert = analog.IsInverted; if (analog.ScalefactorMilliVoltsPerADC < 0) { bInvert = !bInvert; } if (analog.SensitivityMilliVoltsPerEU < 0) { bInvert = !bInvert; } try { // // Careful here... if remove offset is NOT active, and zero method is "none", // then just send the level trigger as specified down to the hardware. Othewise, // we'll need to apply the appropriate offset to it so it triggers as expected. // if (bInvert) { levelTriggerLowerThreshold = (short)(invertScaleFactor * analog.TriggerAboveThresholdEu * analog.SensitivityMilliVoltsPerEUNormalized / scalefactorMilliVoltsPerADC + offsetRemovalADC); } else { levelTriggerUpperThreshold = (short)(analog.TriggerAboveThresholdEu * analog.SensitivityMilliVoltsPerEUNormalized / scalefactorMilliVoltsPerADC + offsetRemovalADC); } } catch (ApplicationException ex) { if (null != Exceptional .ExtractFirstExceptionOfTypeFromExceptionTree(ex)) levelTriggerUpperThreshold = (short)(analog.TriggerAboveThresholdEu * analog.SensitivityMilliVoltsPerEUNormalized / scalefactorMilliVoltsPerADC); else throw; } levelTriggerMode = SetupDASLoad.TriggerModes.GT; g5LTType = SetupG5LevelTrigger.LevelTriggerTypes.GT; if (bInvert) { //FLIP IT! levelTriggerMode = SetupDASLoad.TriggerModes.LT; g5LTType = SetupG5LevelTrigger.LevelTriggerTypes.LT; } } if (null != analog.TriggerAboveThresholdEu && null != analog.TriggerBelowThresholdEu) { switch (analog.LevelTriggerType) { case Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.GreaterThan: break; case Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.InsideWindow: g5LTType = SetupG5LevelTrigger.LevelTriggerTypes.IW; break; case Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.LessThan: break; case Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.OutsideWindow: g5LTType = SetupG5LevelTrigger.LevelTriggerTypes.OW; break; } } if (!levelTriggerOnThisChannel) continue; levelTriggerEnabled = true; if (g5LTType == SetupG5LevelTrigger.LevelTriggerTypes.GT || g5LTType == SetupG5LevelTrigger.LevelTriggerTypes.LT) { levelTriggerChannel = channelIdx + 1; } else { // One based trigger channel levelTriggerChannel = dasChannelNumber + 1; } if (!IsG5() || !levelTriggerEnabled) continue; levelTriggerChannels.Add(levelTriggerChannel); g5LTTypes.Add(g5LTType); levelTriggerUpperThresholds.Add(levelTriggerUpperThreshold); levelTriggerLowerThresholds.Add(levelTriggerLowerThreshold); } //ideally we would have a common base class between these and just one object here, but there's some work to do //basically there's some 3 separate parameters or so separating the two. var sdl = new SetupDASLoad(this); var sdlDIM = new SetupDASLoadDIM(this); if (null == dummyChannels || !dummyChannels.Any()) { bAllModulesDummyArmed = false; } sdl.TestConfig = $"{info.EventGuid.ToString()}{SETUPDASREAD_SENTINEL}{ConfigData.Description}{SETUPDASREAD_SENTINEL}{ConfigData.Modules[moduleIdx].GetCRC32()}"; sdlDIM.TestConfig = sdl.TestConfig; sdl.ModuleIndex = DASInfo.Modules[moduleIdx].ModuleArrayIndex; sdlDIM.ModuleIndex = sdl.ModuleIndex; switch (ConfigData.Modules[moduleIdx].RecordingMode) { case DFConstantsAndEnums.RecordingMode.CircularBuffer: case DFConstantsAndEnums.RecordingMode.CircularBufferPlusUART: case DFConstantsAndEnums.RecordingMode.AutoCircularBufferMode: case DFConstantsAndEnums.RecordingMode.a16_CircularBufferAndStreamSubSampleMode: sdl.ArmMode = SetupDASLoad.ARMMode.WAIT; sdlDIM.ArmMode = SetupDASLoadDIM.ArmModes.WAIT; break; case DFConstantsAndEnums.RecordingMode.RecorderMode: case DFConstantsAndEnums.RecordingMode.a14_NormalRecorderAndStreamSubSampleMode: case DFConstantsAndEnums.RecordingMode.RecorderModePlusUART: case DFConstantsAndEnums.RecordingMode.AutoRecorderMode: sdl.ArmMode = SetupDASLoad.ARMMode.TAPE; sdlDIM.ArmMode = SetupDASLoadDIM.ArmModes.TAPE; break; default: throw new NotSupportedException( "mode not supported for TDAS: " + ConfigData.Modules[moduleIdx].RecordingMode.ToString()); } var aaf = Convert.ToInt32(ConfigData.Modules[moduleIdx].AAFilterRateHz); if (0 == aaf && IsG5()) { aaf = Convert.ToInt32(MaxAAFilterRateHz); } sdl.SetHardwareAAFilter(aaf, MaxAAFilterRateHz); sdl.PreTriggerSeconds = ConfigData.Modules[moduleIdx].PreTriggerSeconds; sdlDIM.PreTriggerSeconds = sdl.PreTriggerSeconds; sdl.PostTriggerSeconds = ConfigData.Modules[moduleIdx].PostTriggerSeconds; sdlDIM.PostTriggerSeconds = ConfigData.Modules[moduleIdx].PostTriggerSeconds; sdl.SampleRate = ConfigData.Modules[moduleIdx].SampleRateHz; sdlDIM.SampleRate = sdl.SampleRate; if (info.DummyArm || (null != dummyChannels && dummyChannels.Any())) { sdl.IsDummyArm = true; sdlDIM.IsDummyArm = true; sdl.CollectData = null == dummyChannels || !dummyChannels.Any(); sdlDIM.CollectData = sdl.CollectData; } sdl.TestId = ConfigData.TestID; sdlDIM.TestId = ConfigData.TestID; if (levelTriggerEnabled && !IsG5()) //G5 always uses HW for SetupDasLoad (use setup trig for lvl trigger) { sdl.TriggerType = SetupDASLoad.TriggerTypes.LV; sdlDIM.TriggerType = SetupDASLoadDIM.TriggerTypes.LT; } else { sdl.TriggerType = SetupDASLoad.TriggerTypes.HW; sdlDIM.TriggerType = SetupDASLoadDIM.TriggerTypes.HW; } switch (levelTriggerMode) { case SetupDASLoad.TriggerModes.GT: sdl.TriggerLevelADC = levelTriggerUpperThreshold; sdl.TriggerChannel = levelTriggerChannel; sdlDIM.TriggerChannel = levelTriggerChannel; sdl.TriggerMode = levelTriggerMode; break; case SetupDASLoad.TriggerModes.LT: sdl.TriggerLevelADC = levelTriggerLowerThreshold; sdl.TriggerChannel = levelTriggerChannel; sdlDIM.TriggerChannel = levelTriggerChannel; sdl.TriggerMode = levelTriggerMode; break; } sdl.NumberOfTriggerSamples = 5; sdlDIM.NumberOfTriggerSamples = 5; if (DASInfo.Modules[moduleIdx].TypeOfModule == DFConstantsAndEnums.ModuleType.ProDIM && !IsG5()) { sdlDIM.SyncExecute(); if (sdlDIM.IsErrored()) { info.Error(sdlDIM.GetErrorString(), new Exception(sdlDIM.GetErrorString())); return; } } else { if (module.ModuleArrayIndex > 0 && IsG5()) { //we only need to do the first module in a g5 } else { sdl.SyncExecute(); if (sdl.IsErrored()) { info.Error(sdl.GetErrorString(), new Exception(sdl.GetErrorString())); return; } } } if (DASInfo.Modules[moduleIdx].TypeOfModule != DFConstantsAndEnums.ModuleType.G5Analog || !levelTriggerEnabled) continue; for (var i = 0; i < g5LTTypes.Count; i++) { var g5LTType = g5LTTypes[i]; levelTriggerUpperThreshold = levelTriggerUpperThresholds[i]; levelTriggerLowerThreshold = levelTriggerLowerThresholds[i]; levelTriggerChannel = levelTriggerChannels[i]; setupLT = new SetupG5LevelTrigger(this); setupLT.LevelTriggerType = g5LTType; if (0 != levelTriggerLowerThreshold) { setupLT.TriggerLevelLowADC = levelTriggerLowerThreshold; } if (0 != levelTriggerUpperThreshold) { setupLT.TriggerLevelHighADC = levelTriggerUpperThreshold; } setupLT.TriggerChannel = levelTriggerChannel; setupLT.NumberOfTriggerSamples = 5; setupLT.SyncExecute(); if (setupLT.IsErrored()) { info.Error(setupLT.GetErrorString(), new Exception(setupLT.GetErrorString())); return; } setupLT = null; } } } setupLT?.SyncExecute(); TurnOnExcitation(); var asl = new ArmSetupLoad(this); if (bAllModulesDummyArmed) { asl.PostADWait = -1; } else { asl.PostADWait = 5; } switch (ConfigData.Modules[0].RecordingMode) { case DFConstantsAndEnums.RecordingMode.CircularBuffer: case DFConstantsAndEnums.RecordingMode.CircularBufferPlusUART: case DFConstantsAndEnums.RecordingMode.AutoCircularBufferMode: case DFConstantsAndEnums.RecordingMode.a16_CircularBufferAndStreamSubSampleMode: asl.ArmMode = ArmSetupLoad.ArmModes.WAIT; break; case DFConstantsAndEnums.RecordingMode.RecorderMode: case DFConstantsAndEnums.RecordingMode.a14_NormalRecorderAndStreamSubSampleMode: case DFConstantsAndEnums.RecordingMode.RecorderModePlusUART: case DFConstantsAndEnums.RecordingMode.AutoRecorderMode: asl.ArmMode = ArmSetupLoad.ArmModes.TAPE; break; default: throw new NotSupportedException("unsupported recording mode " + ConfigData.Modules[0].RecordingMode.ToString()); } asl.RackArmMode = info.SysMode ? ArmSetupLoad.RackArmModes.SYS : ArmSetupLoad.RackArmModes.SOLO; asl.PostTriggerSeconds = ConfigData.Modules[0].PostTriggerSeconds + ConfigData.Modules[0].PreTriggerSeconds; asl.SampleRate = ConfigData.Modules[0].SampleRateHz; asl.SyncExecute(); info.Success(); } catch (CanceledException) { info.Cancel(); } catch (Exception ex) { info.Error(ex.Message.Contains("invalid sample rate") ? DFConstantsAndEnums.CommandStatus.StatusArmInvalidSampleRate.ToString() : ex.Message, ex); } } public bool AutoArmed { get => false; set { } } private class ArmPacket : TDASServiceAsyncInfo { public bool DummyArm { get; set; } public Guid EventGuid { get; set; } public int ArmNowTimeout { get; set; } public bool SysMode { get; set; } public ArmPacket(ServiceCallback cb, object ud, Guid eg, int armNowTimeout) : base(cb, ud) { EventGuid = eg; ArmNowTimeout = armNowTimeout; } } /// /// 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"; /// /// Auto Arm a single DAS now (not supported for TDAS) /// /// The function to call with information /// Whatever you want to pass along /// A unique GUID that this event will be tagged /// with void IArmActions.AutoArmNow(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool testingMode, UInt32 diagnosticsDelayMs, int maxNumberEvents, bool repeatEnable, bool preserveDiagnostics) { throw new NotSupportedException("AutoArmNow not supported for TDAS"); } #region FlashErase private class FlashEraseInfo : TDASServiceAsyncInfo { public bool DummyArm { get; set; } public FlashEraseInfo(ServiceCallback _callback, object _userData) : base(_callback, _userData) { } } void IArmActions.BeginFlashErase(ServiceCallback callback, object userData, bool DummyArm) { var info = new FlashEraseInfo(callback, userData); info.DummyArm = DummyArm; LaunchAsyncWorker("TDAS.BeginFlashErase", AsyncBeginFlashErase, info); } /// /// returns whether this das is a G5 /// /// private bool IsG5() { return SerialNumber.StartsWith("5M") || SerialNumber.StartsWith("PI"); } public enum G5Modes { VDS, //IPORT, INDUMMY } public G5Modes G5Mode { get; set; } = G5Modes.VDS; /// /// returns whether a given module in a rack is a Time Output Module (TOM) /// /// /// private static bool IsTom(IDASModule module) { try { if (module.SerialNumber().ToLower().Contains("tom")) { return true; } } catch (Exception ex) { APILogger.Log("problem getting serial number", ex); } return false; } /// /// returns true if the module is a digital input module /// private static bool IsDIM(IDASModule module) { try { if (module.SerialNumber().ToLower().Contains("dim")) { return true; } } catch (Exception ex) { APILogger.Log("problem getting serial number", ex); } return false; } /// /// returns whether a given module type is a Timed Output Module (TOM) /// /// /// private static bool IsTom(DFConstantsAndEnums.ModuleType m) { switch (m) { case DFConstantsAndEnums.ModuleType.ProTOM: return true; default: return false; } } private void AsyncBeginFlashErase(object asyncInfo) { if (!(asyncInfo is FlashEraseInfo info)) { return; } try { DoFlashErase(info.DummyArm); info.Success(); } catch (CanceledException) { info.Cancel(); } catch (Exception ex) { info.Error(ex.Message, ex); } } void IArmActions.QueryFlashEraseStatus(ServiceCallback callback, object userData) { var info = new TDASServiceAsyncInfo(callback, userData); LaunchAsyncWorker("TDAS.QueryFlashEraseStatus", AsyncQueryFlashEraseStatus, info); } private const double EXPECTED_FLASHCLEAR_TIME = 3 * 60 * 1000; private void AsyncQueryFlashEraseStatus(object asyncInfo) { var info = asyncInfo as TDASServiceAsyncInfo; if (IsG5()) { try { bool done = false; DateTime start = DateTime.Now; if ((this as IArmActions).BackgroundFlashEraseStarted) { start = (DateTime)(this as IArmActions).BackgroundFlashEraseStartTime; } while (false == done) { QueryFlashClear queryStatus = new QueryFlashClear(this); queryStatus.SyncExecute(); var eraseStatus = new FlashEraseStatus(); eraseStatus.LastError = DFConstantsAndEnums.CommandStatus.StatusNoError; if (queryStatus.Done) { _backgroundFlashClearStart = DateTime.MinValue; eraseStatus.PercentComplete = 100F; done = true; } else { done = false; var percentDoneExpected = 100D * DateTime.Now.Subtract(start).TotalMilliseconds / EXPECTED_FLASHCLEAR_TIME; if (percentDoneExpected < 1) { percentDoneExpected = 1; } else if (percentDoneExpected > 100) { percentDoneExpected = 100; } eraseStatus.PercentComplete = Convert.ToSingle(percentDoneExpected); } DASFlashEraseStatus = eraseStatus; if (eraseStatus.LastError != DFConstantsAndEnums.CommandStatus.StatusNoError) { info?.Progress(0); info?.Error("Error while clearing flash: " + eraseStatus.LastError.ToString()); done = true; } else if (eraseStatus.PercentComplete < 100.0f) { info?.Progress((int)eraseStatus.PercentComplete); Thread.Sleep(500); } else { _backgroundFlashClearStart = DateTime.MinValue; info?.Progress(100); info?.Success(); done = true; } } } catch (CanceledException) { info?.Cancel(); } catch (Exception ex) { info?.Error(ex.Message, ex); } } else { info?.Progress(100); info?.Success(); } } #endregion #region ArmNow internal bool _bExcitationOn = false; /// /// TDAS Excitation states On, Off, or Empty Slot. /// If SIM Excitation is ON, it should not be turned ON again, /// because FW does other tasks as well (offset removal). /// internal enum TdasExcitationState { On = 0, Off, EmptySlot }; public bool[] QueryTestPrepareStatus() { var ret = new bool[DASInfo.Modules.Length]; for (var i = 0; i < DASInfo.Modules.Length; i++) { if (DASInfo.Modules[i].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK) { ret[i] = true; continue; } var qtp = new QueryTestPrepare(this); qtp.ModuleIndex = DASInfo.Modules[i].ModuleArrayIndex; qtp.SyncExecute(); ret[i] = qtp.On; } return ret; } private List GetModulesExcitationState() { var excitationState = new List(); for (int i = 0; i < DASInfo.Modules.Length; i++) { if (DASInfo.Modules[i].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK) { excitationState.Add(TdasExcitationState.EmptySlot); continue; } QueryTestPrepare qtp = new QueryTestPrepare(this); qtp.ModuleIndex = DASInfo.Modules[i].ModuleArrayIndex; qtp.SyncExecute(); excitationState.Add(qtp.On ? TdasExcitationState.On : TdasExcitationState.Off); } return excitationState; } public void TurnOnExcitation() { //FB 16115 Undo part of the changes for FB 15873 causing the TestPrepare call in arm step //Refactor the logic to get the excitation sate for modules in GetModulesExcitationSate method var excitationStateForModules = GetModulesExcitationState(); //if there's any modules that are on then we don't need to turn on power if (!excitationStateForModules.Exists(status => status == TdasExcitationState.On)) { if (IsG5()) { var tp = new TestPrepare(this); tp.ModuleIndex = 0; tp.On = true; tp.SyncExecute(); } for (var i = 0; i < DASInfo.Modules.Length; i++) { if (DASInfo.Modules[i].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK) { continue; } var qsn = new QuerySerialNumberBroadcast(this, DASInfo.Modules[i].ModuleArrayIndex); qsn.SyncExecute(); var tpb = new TestPrepareBroadcast(this, DASInfo.Modules[i].ModuleArrayIndex); tpb.On = true; tpb.SyncExecute(); Thread.Sleep(1000); break; } } } public void TurnOffExcitation() { for (int i = 0; i < DASInfo.Modules.Length; i++) { if (DASInfo.Modules[i].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK) { continue; } if (IsG5()) { TestPrepare tp = new TestPrepare(this); tp.ModuleIndex = 0; tp.On = false; tp.SyncExecute(); break; } var qsn = new QuerySerialNumberBroadcast(this, DASInfo.Modules[i].ModuleArrayIndex); qsn.SyncExecute(); var tpb = new TestPrepareBroadcast(this, DASInfo.Modules[i].ModuleArrayIndex); tpb.On = false; ExcitationStatus = DFConstantsAndEnums.ExcitationStatus.Off; tpb.SyncExecute(); Thread.Sleep(1000); break; } } public void TurnOffExcitation(int moduleIdx) { if (DASInfo.Modules[moduleIdx].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK) { return; } var tp = new TestPrepare(this); tp.On = false; tp.ModuleIndex = DASInfo.Modules[moduleIdx].ModuleArrayIndex; tp.SyncExecute(); } 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); info.SysMode = SysMode; LaunchAsyncWorker("TDAS.ArmNow", new WaitCallback(AsyncArmNow), info); } 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); info.SysMode = SysMode; LaunchAsyncWorker("TDAS.PrepareForArmNow", new WaitCallback(AsyncPrepareForArmNow), info); } void IArmActions.ReArm(ServiceCallback callback, object userData, bool autoArm, bool arm, bool repeatEnable) { var info = new TDASServiceAsyncInfo(callback, userData); info.Error("NotSupported"); } 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); info.DummyArm = checkoutMode; info.SysMode = SysMode; LaunchAsyncWorker("TDAS.PreparedArmNow", new WaitCallback(AsyncPreparedArmNow), info); } private const char SETUPDASREAD_SENTINEL = (char)127; private void AsyncArmNow(object asyncInfo) { var info = asyncInfo as ArmPacket; try { StartRecord = false; if (IsG5() && (G5Mode == G5Modes.VDS)) { try { var dockstat = new G5DockStat(this, true); dockstat.SyncExecute(); if (dockstat.BatteryChargeLevel == G5DockStat.BatteryChargeStates.red /*|| dockstat.BatteryChargeLevel == Command.TDAS.G5DockStat.BatteryChargeStates.yellow*/) { info?.Error("BatteryLowVoltage"); return; } } catch (Exception) { } } var ra = new RackArm(this); ra.ArmState = RackArm.ArmStates.NOW; ra.SyncExecute(); if (ra.IsErrored) { throw new Exception(string.Format("{0}:{1}", SerialNumber, ra.ResponseData)); } info?.Success(); } catch (Exception ex) { QueryModules qm = new QueryModules(this); qm.SyncExecute(); info.Error(ex.Message); return; } } private void AsyncPrepareForArmNow(object asyncInfo) { var info = asyncInfo as ArmPacket; info?.Success(); } private void AsyncPreparedArmNow(object asyncInfo) { var info = asyncInfo as ArmPacket; try { var moduleIndexToArm = -1; for (var i = 0; i < ConfigData.Modules.Length; i++) { if (DASInfo.Modules[i].TypeOfModule == DFConstantsAndEnums.ModuleType.EMPTYBANK) { continue; } try { if (moduleIndexToArm == -1) { moduleIndexToArm = DASInfo.Modules[i].ModuleArrayIndex; } //per rollin, this can add debug information if we call it before module arm if (IsTom(DASInfo.Modules[i].TypeOfModule)) { var gts = new GetTOMSwitch(this); gts.ModuleIndex = DASInfo.Modules[i].ModuleArrayIndex; gts.SyncExecute(); var dasModule = DASInfo.Modules[i]; var configModule = ConfigData.Modules[dasModule.ModuleArrayIndex]; if (!info.DummyArm) { var tsa = new TestSquibArray(this); tsa.ModuleIndex = dasModule.ModuleArrayIndex; tsa.SyncExecute(); for (var iCh = 0; iCh < 8; iCh += 2) { if (!(configModule.Channels[iCh] is OutputSquibChannel squib) || ConfigData.TestID == "TESTTRIG") { continue; } // do not check the reistance being in range for the long Test Trigger check. if (squib.ConfigurationMode == DFConstantsAndEnums.ConfigMode.Normal) { var resistance = tsa.ResistanceOhms[Convert.ToInt32(Math.Floor(iCh / 2D))]; if (resistance > squib.SquibToleranceHigh) { info.Error ( string.Format("{0} High", DFConstantsAndEnums.CommandStatus.StatusArmSquibResistanceFault .ToString()) ); return; } if (resistance < squib.SquibToleranceLow) { info.Error ( $"{DFConstantsAndEnums.CommandStatus.StatusArmSquibResistanceFault.ToString()} Low" ); return; } } } } } } catch (Exception) { } } var qsn = new QuerySerialNumberBroadcast(this, moduleIndexToArm); qsn.SyncExecute(); var mArm = new ModuleArmBroadcast(this, moduleIndexToArm, IsG5()); mArm.SyncExecute(); if (!IsG5()) { //17717 ModuleArmBroadcast must wait on G5 //the G5 is waiting on syncexecute above, racks are not //to make sure the rack doesn't try to execute another command too quickly //I introduced a delay here based on EFizer seeing a 1.5s delay happening //the delay should be as long as the slowest fully configured module.. //2.5 to me seems a generous amount of time to allow Thread.Sleep(2500); } } catch (CanceledException) { info.Cancel(); } catch (Exception ex) { //17717 ModuleArmBroadcast must wait on G5 //the modulearmbroadcast for a g5 now processes the response //and in turn can throw an exception, so I handle the new exception here and //send an error back to the service info.Error(ex.Message, ex); return; } try { if (IsG5() && (G5Mode == G5Modes.VDS)) { try { var dockstat = new G5DockStat(this, true); dockstat.SyncExecute(); if (dockstat.BatteryChargeLevel == G5DockStat.BatteryChargeStates.red /*|| dockstat.BatteryChargeLevel == Command.TDAS.G5DockStat.BatteryChargeStates.yellow*/) { info.Error("BatteryLowVoltage"); return; } } catch (Exception) { } } var ra = new RackArm(this); ra.ArmState = ConfigData.TestID == "TESTTRIG" ? RackArm.ArmStates.NOW_TEST : RackArm.ArmStates.NOW; ra.SyncExecute(); if (ra.IsErrored) { throw new Exception(string.Format("{0}:{1}", SerialNumber, ra.ResponseData)); } info.Success(); } catch (Exception ex) { var qm = new QueryModules(this); qm.SyncExecute(); info.Error(ex.Message); } } public const string SQUIB_RESISTANCE_TOOHIGH = "SQUIB resistance too high"; public const string SQUIB_RESISTANCE_TOOLOW = "SQUIB resistance too low"; #endregion #region EnableFaultChecking void IArmActions.EnableFaultChecking(ServiceCallback callback, object userData) { var info = new TDASServiceAsyncInfo(callback, userData); LaunchAsyncWorker("TDAS.EnableFaultChecking", new WaitCallback(AsyncEnableFaultChecking), info); } void IArmActions.CheckAlreadyLevelTriggered(ServiceCallback callback, object userData) { var info = new TDASServiceAsyncInfo(callback, userData); LaunchAsyncWorker("TDAS.CheckAlreadyLevelTriggered", new WaitCallback(AsyncCheckAlreadyLevelTriggered), info); } private void AsyncCheckAlreadyLevelTriggered(object asyncInfo) { var info = asyncInfo as TDASServiceAsyncInfo; try { foreach (var m in ConfigData.Modules) { foreach (var ch in m.Channels) { if (ch is AnalogInputDASChannel) { try { var aCh = ch as AnalogInputDASChannel; if (aCh.LevelTriggerType == Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.NONE || aCh.ConfigurationMode != DFConstantsAndEnums.ConfigMode.Normal) { aCh.AlreadyLevelTriggered = false; aCh.MeasuredEULevelTriggerCheck = double.NaN; } else { aCh.AlreadyLevelTriggered = false; aCh.MeasuredEULevelTriggerCheck = double.NaN; //SA var sa = new SampleAverageWithFallback(this, m.ModuleArrayIndex); sa.SyncExecute(); var adc = sa.ChannelValues[aCh.ModuleChannelNumber]; double scalefactorMilliVoltsPerADC = aCh.ScalefactorMilliVoltsPerADC; int offsetRemovalADC = 0; try { var diagnostics = aCh.Diagnostics; scalefactorMilliVoltsPerADC = diagnostics.ScalefactorMilliVoltsPerADC; offsetRemovalADC = diagnostics.GetExpectedDataZeroLevelADC(aCh.ZeroMethod); } catch (Exception) { } //short dataZeroLevelADC = 0; //if (null != aCh.DiagnosticInformation) { dataZeroLevelADC = aCh.DiagnosticInformation.GetExpectedDataZeroLevelADC(aCh.ZeroMethod); } //var eu = (adc - dataZeroLevelADC) * scalefactorMilliVoltsPerADC / aCh.SensitivityMilliVoltsPerEUNormalized; //if (aCh.IsInverted) { eu *= -1D; } //aCh.MeasuredEULevelTriggerCheck = eu; var ds = aCh.GetDataScaler(); var eu = ds.GetEU(adc); aCh.MeasuredEULevelTriggerCheck = eu; switch (aCh.LevelTriggerType) { case Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.GreaterThan: { double euThreshold = (double)aCh.TriggerAboveThresholdEu; if (euThreshold < eu) { aCh.AlreadyLevelTriggered = true; } } break; case Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.InsideWindow: { double euThresholdLower = (double)aCh.TriggerBelowThresholdEu; double euThresholdHigher = (double)aCh.TriggerAboveThresholdEu; if (euThresholdLower <= eu && eu <= euThresholdHigher) { aCh.AlreadyLevelTriggered = true; } } break; case Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.LessThan: { double euThreshold = (double)aCh.TriggerBelowThresholdEu; if (euThreshold > eu) { aCh.AlreadyLevelTriggered = true; } } break; case Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.OutsideWindow: { double euThresholdLower = (double)aCh.TriggerBelowThresholdEu; double euThresholdHigher = (double)aCh.TriggerAboveThresholdEu; if (euThresholdLower > eu || eu > euThresholdHigher) { aCh.AlreadyLevelTriggered = true; } } break; } } } catch (Exception ex2) { APILogger.Log(ex2); } } } } info.Success(); } catch (Exception ex) { info.Error(ex.Message, ex); } } /// /// calls TA Prev/TA Curr to keep a record of rack state in logs /// private void DoTAPrevCurRFCheck(bool loopOnFaulted) { var ta = new TestAll(this); ta.Mode = TestAllCommandString.Modes.PREV; ta.SyncExecute(); ta = new TestAll(this); ta.Mode = TestAllCommandString.Modes.CURR; ta.SyncExecute(); int maxIterations = 10; int i = 1; while (loopOnFaulted && ta.RackFault == DFConstantsAndEnums.VoltageStatusColor.Red && i <= maxIterations) { APILogger.Log($"### TACURRLOOP {SerialNumber} Iteration {i} RF={ta.RackFault.ToString()}"); // Pause for 100ms Thread.Sleep(100); //Lets Check again ta = new TestAll(this); ta.Mode = TestAllCommandString.Modes.CURR; ta.SyncExecute(); i++; } } private void AsyncEnableFaultChecking(object asyncInfo) { var info = asyncInfo as TDASServiceAsyncInfo; try { if (RecordingModeExtensions.IsARecorderMode(ConfigData.Modules[0].RecordingMode)) { } else { //15616Add additional debug information into TDAS arm sequence DoTAPrevCurRFCheck(true); var queryArmStat = new QueryArmStatus(this); queryArmStat.SyncExecute(); var ra = new RackArm(this); ra.ArmState = RackArm.ArmStates.RF; ra.SyncExecute(); if (ra.IsErrored) { //execute TA PREV to get the state of latched switches, //ARM RF Error will sometimes lead to disarming, so get it now before returning //this is in reference to discoveries in TDC in ZenDesk id7153 //support.dtsweb.com/hc/requests/7153 //code in TDC was RJW 2004, presumably added for more debugging information. DoTAPrevCurRFCheck(false); throw new Exception(string.Format("{0}:{1}", SerialNumber, ra.ResponseData)); } else { //15616 Add additional debug information into TDAS arm sequence queryArmStat = new QueryArmStatus(this); queryArmStat.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) { throw new NotSupportedException("DisAutoArm not supported for TDAS"); } void IArmActions.Disarm(ServiceCallback callback, object userData) { var info = new TDASServiceAsyncInfo(callback, userData); LaunchAsyncWorker("TDAS.Disarm", new WaitCallback(AsyncDisarm), info); } private void AsyncDisarm(object asyncInfo) { var info = asyncInfo as TDASServiceAsyncInfo; if (null != DASArmStatus && DASArmStatus.IsTriggered && DASArmStatus.IsRecording) { try { var stopNow = new ARMSTOP(this); stopNow.SyncExecute(); info.Success(); } catch (CanceledException) { info.Cancel(); } catch (Exception ex) { info.Error(ex.Message); } } else { if (!IsG5()) { //try to disarm any modules ... //this doesn't work, it just hangs things. /*foreach (var m in DASInfo.Modules) { if (m.TypeOfModule == InfoResult.Module.ModuleType.EMPTYBANK) { continue; } try { var armoff = new DTS.DASLib.Command.TDAS.ARMOFF(this); armoff.ModuleIndex = m.ModuleArrayIndex; armoff.SyncExecute(); } catch (System.Exception ex) { APILogger.Log(ex); } }*/ } try { try { var armOff = new ARMOFF(this); armOff.SyncExecute(); } catch (Exception ex) { APILogger.Log(ex); } //11326 Failed to arm in check trigger navi step //see above issue for more details //IMMEDIATELY turn back on all excitation foreach (var module in ConfigData.Modules) { bool bAnalog = true; if (IsG5() && module.ModuleArrayIndex > 3) { continue; }//skip digital banks switch (DASInfo.Modules[module.ModuleArrayIndex].TypeOfModule) { case DFConstantsAndEnums.ModuleType.EMPTYBANK: continue; case DFConstantsAndEnums.ModuleType.ProDIM: continue; case DFConstantsAndEnums.ModuleType.G5Digital: continue; } var setExcitation = new SetExcitation(this); setExcitation.ModuleIndex = module.ModuleArrayIndex; var channels = new List(); var excitation = new List(); foreach (var channel in module.Channels) { if (!channel.IsConfigured() || !bAnalog) { continue; } if (!(channel is AnalogInputDASChannel aic)) { bAnalog = false; continue; } switch (aic.Excitation) { case Common.Enums.ExcitationVoltageOptions.ExcitationVoltageOption.Volt10: channels.Add(aic.ModuleChannelNumber); excitation.Add(SetExcitation.SIM_TEN_VOLT); break; case Common.Enums.ExcitationVoltageOptions.ExcitationVoltageOption.Volt2: channels.Add(aic.ModuleChannelNumber); excitation.Add(IsG5() ? SetExcitation.G5_TWO_VOLT : SetExcitation.SIM_TWO_VOLT); break; case Common.Enums.ExcitationVoltageOptions.ExcitationVoltageOption.Volt5: channels.Add(aic.ModuleChannelNumber); if (IsG5()) { excitation.Add(SetExcitation.G5_FIVE_VOLT); } else { excitation.Add(SetExcitation.FIVE_VOLT); } break; } } try { if (bAnalog && channels.Any()) { setExcitation.Channels = channels.ToArray(); setExcitation.ExcitationModes = excitation.ToArray(); //setExcitation.SyncExecute(); } } catch (Exception ex) { APILogger.Log(ex); } } info?.Success(); } catch (CanceledException) { info?.Cancel(); } catch (Exception ex) { info?.Error(ex.Message, ex); } } } #endregion #region GetArmStatus void IArmActions.GetAutoArmStatus(ServiceCallback callback, object userData) { var info = new TDASServiceAsyncInfo(callback, userData); LaunchAsyncWorker("TDAS.GetAutoArmStatus", new WaitCallback(AsyncGetAutoArmStatus), info); } void IArmActions.GetArmStatus(ServiceCallback callback, object userData, uint inputVoltageCutoff, int maxTimeout) { var info = new TDASServiceAsyncInfo(callback, userData); LaunchAsyncWorker("TDAS.GetArmStatus", new WaitCallback(AsyncGetArmStatus), info); } void IArmActions.GetExtendedFaultIds(ServiceCallback callback, object userData) { var info = new TDASServiceAsyncInfo(callback, userData); LaunchAsyncWorker("TDAS.GetExtendedFaultIds", new WaitCallback(TDASAsyncGetExtendedFaultIds), info); } private void TDASAsyncGetExtendedFaultIds(object asyncInfo) { var info = (TDASServiceAsyncInfo)asyncInfo; info.Success(); } private DateTime recordTime = DateTime.MinValue; private DateTime triggerTime = DateTime.MinValue; private DateTime armedTime = DateTime.MinValue; private volatile bool _bInFlashWrite = false; private DateTime _timeOfFirstFlashWrite = DateTime.MinValue; private static object FlashWriteTimeLock = new object(); private volatile bool _previousRackFault = false; private volatile bool _previousModuleFault = false; private void AsyncGetArmStatus(object asyncInfo) { TDASServiceAsyncInfo info = asyncInfo as TDASServiceAsyncInfo; try { if (null == BaseInput) { //var ta = new Command.TDAS.TestAll(this); //ta.SyncExecute(); BaseInput = new BaseInputValues { InputVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Off, InputVoltageStatus = DFConstantsAndEnums.VoltageStatusColor.Off.ToString(), StatusDisplayInput = String.Empty, BatteryVoltageStatus = DFConstantsAndEnums.VoltageStatusColor.Off.ToString(), BatteryVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Off, StatusDisplayBattery = String.Empty }; } } catch (Exception ex) { APILogger.Log(ex); } try { QueryArmStatus arm = new QueryArmStatus(this); arm.SyncExecute(); LEDS leds = null; if (!IsG5() && arm.Status == QueryArmStatus.ARMStatus.DONE) { Thread.Sleep(1000); // let's hangout for a bit. This is moving too quickly after status done from armstatus is seen leds = new LEDS(this); leds.SyncExecute(); if (leds.CalFault == LEDS.FlagStatus.YellowOrYes) { arm.SetStatus(QueryArmStatus.ARMStatus.CAL); } } if (BaseInput != null) { bool bLowPower = arm.LowPower; if (IsG5()) { if (BaseInput.StatusDisplayBattery == TestAll.VoltageStatus.None.ToString()) { if (BaseInput.StatusDisplayBattery == TestAll.VoltageStatus.None.ToString())/* no battery - display input */ { BaseInput.InputVoltageStatus = bLowPower ? DFConstantsAndEnums.VoltageStatusColor.Red.ToString() : DFConstantsAndEnums.VoltageStatusColor.Green.ToString(); BaseInput.InputVoltageStatusColor = bLowPower ? DFConstantsAndEnums.VoltageStatusColor.Red : DFConstantsAndEnums.VoltageStatusColor.Green; BaseInput.StatusDisplayInput = bLowPower ? TestAll.VoltageStatus.Low.ToString() : TestAll.VoltageStatus.Good.ToString(); BaseInput.BatteryVoltageStatus = String.Empty; BaseInput.BatteryVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Off; BaseInput.StatusDisplayBattery = TestAll.VoltageStatus.None.ToString(); } else { BaseInput.InputVoltageStatus = String.Empty; BaseInput.InputVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Off; BaseInput.StatusDisplayInput = TestAll.VoltageStatus.None.ToString(); BaseInput.BatteryVoltageStatus = bLowPower ? DFConstantsAndEnums.VoltageStatusColor.Red.ToString() : DFConstantsAndEnums.VoltageStatusColor.Green.ToString(); BaseInput.BatteryVoltageStatusColor = bLowPower ? DFConstantsAndEnums.VoltageStatusColor.Red : DFConstantsAndEnums.VoltageStatusColor.Green; BaseInput.StatusDisplayBattery = bLowPower ? TestAll.VoltageStatus.Low.ToString() : TestAll.VoltageStatus.Good.ToString(); } } else { BaseInput.InputVoltageStatus = String.Empty; BaseInput.InputVoltageStatusColor = DFConstantsAndEnums.VoltageStatusColor.Off; BaseInput.StatusDisplayInput = "---"; BaseInput.StatusDisplayBattery = bLowPower ? DFConstantsAndEnums.VoltageStatusColor.Red.ToString() : DFConstantsAndEnums.VoltageStatusColor.Green.ToString(); BaseInput.BatteryVoltageStatusColor = bLowPower ? DFConstantsAndEnums.VoltageStatusColor.Red : DFConstantsAndEnums.VoltageStatusColor.Green; BaseInput.BatteryVoltageStatus = bLowPower ? TestAll.VoltageStatus.Low.ToString() : TestAll.VoltageStatus.Good.ToString(); } } } ArmStatus status = new ArmStatus(); status.IsRearming = false; //there's a bit of a problem here, the das could be faulted, but if it's triggered we don't know, we need if (arm.HardwareTrigger || arm.LevelTrigger) { if (null != DASArmStatus) { status.IsFaulted = DASArmStatus.IsFaulted; } } else { bool taQueried = false; if (arm.ModuleFault) { if (_previousModuleFault) { TestAll ta = new TestAll(this); ta.Mode = TestAllCommandString.Modes.PREV; ta.SyncExecute(); ta = new TestAll(this); ta.Mode = TestAllCommandString.Modes.CURR; ta.SyncExecute(); taQueried = true; status.IsFaulted = true; } _previousModuleFault = true; } else { _previousModuleFault = false; } if (arm.RackFault) { if (!taQueried) { TestAll ta = new TestAll(this); ta.Mode = TestAllCommandString.Modes.PREV; ta.SyncExecute(); ta = new TestAll(this); ta.Mode = TestAllCommandString.Modes.CURR; ta.SyncExecute(); } if (_previousRackFault) { status.IsFaulted = true; } _previousRackFault = true; } else { _previousRackFault = false; } //status.IsFaulted = arm.ModuleFault || arm.RackFault; } status.IsInFlashWrite = false; status.IsInPostTestDiagnostics = false; switch (arm.Status) { case QueryArmStatus.ARMStatus.ARMED: _bInFlashWrite = false; if (null != ConfigData && null != ConfigData.Modules && ConfigData.Modules.Length > 0) { 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.a16_CircularBufferAndStreamSubSampleMode) { if (recordTime == DateTime.MinValue) { recordTime = DateTime.Now; } } else { recordTime = DateTime.MinValue; } } else { recordTime = DateTime.MinValue; } triggerTime = DateTime.MinValue; if (DateTime.MinValue == armedTime) { armedTime = DateTime.Now; } status.IsArmed = true; break; case QueryArmStatus.ARMStatus.ARMING: _bInFlashWrite = false; recordTime = DateTime.MinValue; triggerTime = DateTime.MinValue; status.IsArmed = true; // status.IsRearming = true; status.HasBeenRecording = false; break; case QueryArmStatus.ARMStatus.DONE: _bInFlashWrite = false; status.IsArmed = false; break; case QueryArmStatus.ARMStatus.FLASH: status.IsArmed = false; break; case QueryArmStatus.ARMStatus.FLASHWRITE: status.IsArmed = false; status.IsRecording = false; status.IsInFlashWrite = true; if (!_bInFlashWrite) { _bInFlashWrite = true; lock (FlashWriteTimeLock) { _timeOfFirstFlashWrite = DateTime.Now; } } break; case QueryArmStatus.ARMStatus.REC: if (DateTime.MinValue == recordTime) { recordTime = DateTime.Now; } status.IsArmed = true; status.IsRecording = true; status.HasBeenRecording = true; break; case QueryArmStatus.ARMStatus.TRIG: armedTime = DateTime.MinValue; if (DateTime.MinValue == triggerTime) { triggerTime = DateTime.Now; } status.IsArmed = true; status.IsTriggered = true; status.IsRecording = true; status.HasBeenRecording = true; break; case QueryArmStatus.ARMStatus.UNDEFINED: status.IsArmed = false; break; case QueryArmStatus.ARMStatus.CAL: status.IsArmed = true; status.IsInPostTestDiagnostics = true; break; } if (arm.StartRecord) { StartRecord = true; } else { StartRecord = false; } if (arm.HardwareTrigger) { status.IsTriggered = true; } else if (arm.LevelTrigger) { status.IsTriggered = true; } if (arm.StartRecord && arm.Status != QueryArmStatus.ARMStatus.FLASHWRITE) { status.IsRecording = true; } var faultMessage = new StringBuilder(); //took out TA below as TA should only be called after a fault if (arm.ModuleFault && !arm.HardwareTrigger) { if (_previousModuleFault) { status.IsFaulted = true; if (faultMessage.Length > 0) { faultMessage.Append(", "); } faultMessage.Append("module fault"); } _previousModuleFault = true; } else { _previousModuleFault = false; } //took out TA below as TA should only be called after a fault if (arm.RackFault && !(/*ta.TriggerFlag == Command.TDAS.TestAll.VoltageStatusColor.Red ||*/ arm.HardwareTrigger)) { if (_previousRackFault) { status.IsFaulted = true; if (faultMessage.Length > 0) { faultMessage.Append(", "); } faultMessage.Append("rack fault"); } _previousRackFault = true; } else { _previousRackFault = false; } //took out TA below as TA should only be called after a fault if (arm.LowPower /*|| ta.PrimaryPower == Command.TDAS.TestAll.VoltageStatusColor.Red*/) { status.IsFaulted = true; if (faultMessage.Length > 0) { faultMessage.Append(", "); } faultMessage.Append("low power"); } if (status.IsFaulted) { status.FaultMessage = faultMessage.ToString(); } if (arm.Status == QueryArmStatus.ARMStatus.DONE) { status.IsRecording = false; status.IsTriggered = false; status.IsArmed = false; } if (status.IsArmed) { ExcitationStatus = DFConstantsAndEnums.ExcitationStatus.On; if (null == ConfigData) { ManualResetEvent finished = new ManualResetEvent(false); (this as IConfigurationActions).QueryConfiguration( delegate (ServiceCallbackData data) { switch (data.Status) { case ServiceCallbackData.CallbackStatus.Success: case ServiceCallbackData.CallbackStatus.Failure: case ServiceCallbackData.CallbackStatus.Canceled: finished.Set(); break; default: break; } }, null, 0, string.Empty, false); while (false == finished.WaitOne(50)) { Thread.Sleep(10); } } if (null != ConfigData) { double timeRemaining = ConfigData.Modules[0].PreTriggerSeconds + ConfigData.Modules[0].PostTriggerSeconds; status.CurrentSample = 0; switch (ConfigData.Modules[0].RecordingMode) { case DFConstantsAndEnums.RecordingMode.CircularBuffer: case DFConstantsAndEnums.RecordingMode.CircularBufferPlusUART: case DFConstantsAndEnums.RecordingMode.AutoCircularBufferMode: case DFConstantsAndEnums.RecordingMode.a16_CircularBufferAndStreamSubSampleMode: status.IsRecording = true; status.HasBeenRecording = true; //for circular buffer we only need to calculate if we've seen trigger status.RecordingMode = Convert.ToInt32(ConfigData.Modules[0].RecordingMode); if (DateTime.MinValue != triggerTime) { double secondsSpent = DateTime.Now.Subtract(triggerTime).TotalSeconds; timeRemaining = Math.Max(0, ConfigData.Modules[0].PostTriggerSeconds - (DateTime.Now.Subtract(triggerTime)).TotalSeconds); //timeRemaining = Math.Max(0, ConfigData.Modules[0].PostTriggerSeconds - secondsSpent); status.CurrentSample = Convert.ToUInt64(ConfigData.Modules[0].SampleRateHz * ConfigData.Modules[0].PreTriggerSeconds + ConfigData.Modules[0].SampleRateHz * secondsSpent); } else { if (DateTime.MinValue == recordTime) { if (status.IsRecording) { recordTime = DateTime.Now; } } double secondsSpent = DateTime.Now.Subtract(recordTime).TotalSeconds; //timeRemaining = Math.Max(0, ConfigData.Modules[0].PreTriggerSeconds - secondsSpent); if (secondsSpent > ConfigData.Modules[0].PreTriggerSeconds) { timeRemaining = ConfigData.Modules[0].PostTriggerSeconds; } else { //timeRemaining = ConfigData.Modules[0].PostTriggerSeconds - secondsSpent; timeRemaining = ConfigData.Modules[0].PreTriggerSeconds - secondsSpent; } status.CurrentSample = Convert.ToUInt64(ConfigData.Modules[0].SampleRateHz * secondsSpent); } break; case DFConstantsAndEnums.RecordingMode.RecorderMode: case DFConstantsAndEnums.RecordingMode.a14_NormalRecorderAndStreamSubSampleMode: case DFConstantsAndEnums.RecordingMode.RecorderModePlusUART: case DFConstantsAndEnums.RecordingMode.AutoRecorderMode: //for recorder mode we really only care about the total time spent status.RecordingMode = Convert.ToInt32(ConfigData.Modules[0].RecordingMode); if (DateTime.MinValue != recordTime) { double secondsSpent = DateTime.Now.Subtract(recordTime).TotalSeconds; timeRemaining -= Math.Min(timeRemaining, secondsSpent); status.CurrentSample = Convert.ToUInt64(secondsSpent * ConfigData.Modules[0].SampleRateHz); } break; default: throw new NotSupportedException("unknown recording mode for tdas"); } status.TotalSamples = Convert.ToUInt64((ConfigData.Modules[0].SampleRateHz * (ConfigData.Modules[0].PreTriggerSeconds + ConfigData.Modules[0].PostTriggerSeconds))); status.SampleRate = ConfigData.Modules[0].SampleRateHz; status.TimeRemainingSeconds = timeRemaining; } else { // In theory we should never get to this case. // We need to reconstruct needed info without ConfigData //also note, you're probably going to need a module index, which the code below isn't using? I'm going to leave the code in for now SetupDASRead SDR = new SetupDASRead(this); SDR.SyncExecute(); status.SampleRate = (uint)SDR.ActualSampleRate; status.TotalSamples = Convert.ToUInt64((status.SampleRate * (SDR.PreTriggerTimeInSeconds + SDR.PostTriggerTimeInSeconds))); if (SDR.ArmMode == SetupDASLoad.ARMMode.TAPE) { status.RecordingMode = Convert.ToInt32(DFConstantsAndEnums.RecordingMode.RecorderMode); } else if (SDR.ArmMode == SetupDASLoad.ARMMode.WAIT) { status.RecordingMode = Convert.ToInt32(DFConstantsAndEnums.RecordingMode.CircularBuffer); } else { status.RecordingMode = Convert.ToInt32(DFConstantsAndEnums.RecordingMode.InvalidArmMode); } // Don't have a way to know record time or trigger time, so need to assume the test hasn't started. status.TimeRemainingSeconds = status.SampleRate * status.TotalSamples; status.CurrentSample = 0; } } else { status.SampleRate = 0; status.TimeRemainingSeconds = 0; status.TotalSamples = 0; status.CurrentSample = 0; status.RecordingMode = 0; } if (arm.Status == QueryArmStatus.ARMStatus.FLASHWRITE) { double timeRemaining = 0D; lock (FlashWriteTimeLock) { timeRemaining = EXPECTED_FLASHWRITE_TIME - DateTime.Now.Subtract(_timeOfFirstFlashWrite).TotalSeconds; if (timeRemaining > EXPECTED_FLASHWRITE_TIME) { timeRemaining = EXPECTED_FLASHWRITE_TIME; } if (timeRemaining < 0) { timeRemaining = 0; } } status.TimeRemainingSeconds = timeRemaining; double d = 100D * (EXPECTED_FLASHWRITE_TIME - timeRemaining) / EXPECTED_FLASHWRITE_TIME; if (d < 0) { d = 1; } if (d > 100) { d = 100; } status.PercentComplete = d; //System.Diagnostics.Trace.WriteLine("Time remaining: " + status.TimeRemainingSeconds.ToString() + " percentcomplete: " + status.PercentComplete.ToString()); } if (arm.Status == QueryArmStatus.ARMStatus.UNDEFINED) { status.IsUndefined = true; } status.EventNumber = 0; // Now check power if (IsG5() && G5Mode == G5Modes.VDS && false == status.IsRecording && false == status.IsInFlashWrite && false == status.IsUndefined) { try { G5DockStat ds = new G5DockStat(this, true); ds.SyncExecute(); status.BatteryMilliVolts = ds.BatteryMilliVolts; } catch (Exception) { /* tolerate failure in the case where it's not in a VDS */ } //Command.TDAS.TestBattery tb = new Command.TDAS.TestBattery(this); //tb.SyncExecute(); status.BatteryMilliVolts = null; } SetDASArmStatus(status, true); info.Success(); } catch (CanceledException) { info.Cancel(); } catch (Exception ex) { info.Error(ex.Message, ex); } } private const double EXPECTED_FLASHWRITE_TIME = 120; private void AsyncGetAutoArmStatus(object asyncInfo) { TDASServiceAsyncInfo info = asyncInfo as TDASServiceAsyncInfo; AutoArmStatus = DFConstantsAndEnums.CommandStatus.StatusUnimplemented; info.Success(); } #endregion #region EnterLowPowerMode void IArmActions.EnterLowPowerMode(ServiceCallback callback, object userData) { var info = new TDASServiceAsyncInfo(callback, userData); LaunchAsyncWorker("TDAS.EnterLowPowerMode", new WaitCallback(AsyncEnterLowPowerMode), info); } private void AsyncEnterLowPowerMode(object asyncInfo) { var info = asyncInfo as TDASServiceAsyncInfo; DiagnosticsHasBeenRun = false; try { //clear any diagnostic results we have, they will be invalid after we go to low power //16164 User can proceed past diag. without running on all channels ClearChannelDiagnosticsResults(); TurnOffExcitation(); info.Success(); } catch (CanceledException) { info.Cancel(); } catch (Exception ex) { info.Error(ex.Message, ex); } } #endregion #region Start & Trigger void IArmActions.StartRecord(ServiceCallback callback, object userData) { var info = new TDASServiceAsyncInfo(callback, userData); LaunchAsyncWorker("TDAS.StartRecord", new WaitCallback(AsyncStartRecord), info); } private void AsyncStartRecord(object asyncInfo) { TDASServiceAsyncInfo info = asyncInfo as TDASServiceAsyncInfo; try { RackStartCommand rs = new RackStartCommand(this); rs.SyncExecute(); info.Success(); } catch (Exception ex) { info.Error(ex.Message, ex); } } void IArmActions.Trigger(ServiceCallback callback, object userData) { var info = new TDASServiceAsyncInfo(callback, userData); LaunchAsyncWorker("TDAS.Trigger", new WaitCallback(AsyncTrigger), info); } private void AsyncTrigger(object asyncInfo) { var info = asyncInfo as TDASServiceAsyncInfo; try { RackTriggerCommand rtc = new RackTriggerCommand( this); rtc.SyncExecute(); info.Success(); } catch (Exception ex) { info.Error(ex.Message, ex); } } #endregion public void PerformVoltageCheckTAOnly(ServiceCallback callback, object userData) { var info = new TDASServiceAsyncInfo(callback, userData); LaunchAsyncWorker("TDAS.PerformVoltageCheckTAOnly", new WaitCallback(AsyncPerformVoltageCheckTAOnly), info); } private void AsyncPerformVoltageCheckTAOnly(object o) { TDASServiceAsyncInfo info = o as TDASServiceAsyncInfo; info.Success(); } } }