Files
DP44/DataPRO/IService/Classes/TDAS Service/Arming.cs
2026-04-17 14:55:32 -04:00

2209 lines
103 KiB
C#

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<T> : Communication<T>,
IDASCommunication,
IConfigurationActions,
IDiagnosticsActions,
ITriggerCheckActions,
IRealTimeActions,
IArmActions,
IDownloadActions where T : IConnection, new()
{
public int[] GetStackChannelConfigTypes() => new int[] { 0 };
/// <summary>
/// <inheritdoc cref="IConfiguration"/>
/// </summary>
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();
}
/// <summary>
/// returns true if the unit is capable of reading arm status
/// 17800 Trigger status is "waiting" but PPRO has indeed triggered
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// discovers any connected devices
/// TDAS does support this currently
/// </summary>
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<short>();
var levelTriggerLowerThresholds = new List<short>();
var g5LTTypes = new List<SetupG5LevelTrigger.LevelTriggerTypes>();
var levelTriggerChannels = new List<int>();
// 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<NoDiagnosticsAvailable>(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<NoDiagnosticsAvailable>(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;
}
}
/// <summary>
/// the UDP settings to broadcast auto arm status to on auto arm boot
/// 17583 Monitor Test UI
/// </summary>
public string AutoArmUDPSetting { get; set; } = "239.1.2.3:8504";
/// <summary>
/// Auto Arm a single DAS now (not supported for TDAS)
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
/// <param name="eventGuid">A unique GUID that this event will be tagged
/// with</param>
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);
}
/// <summary>
/// returns whether this das is a G5
/// </summary>
/// <returns></returns>
private bool IsG5()
{
return SerialNumber.StartsWith("5M") || SerialNumber.StartsWith("PI");
}
public enum G5Modes
{
VDS,
//IPORT,
INDUMMY
}
public G5Modes G5Mode { get; set; } = G5Modes.VDS;
/// <summary>
/// returns whether a given module in a rack is a Time Output Module (TOM)
/// </summary>
/// <param name="module"></param>
/// <returns></returns>
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;
}
/// <summary>
/// returns true if the module is a digital input module
/// </summary>
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;
}
/// <summary>
/// returns whether a given module type is a Timed Output Module (TOM)
/// </summary>
/// <param name="m"></param>
/// <returns></returns>
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;
/// <summary>
/// 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).
/// </summary>
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<TdasExcitationState> GetModulesExcitationState()
{
var excitationState = new List<TdasExcitationState>();
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);
}
}
/// <summary>
/// calls TA Prev/TA Curr to keep a record of rack state in logs
/// </summary>
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<int>();
var excitation = new List<int>();
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();
}
}
}