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