2580 lines
130 KiB
C#
2580 lines
130 KiB
C#
#define LEVEL_TRIGGER_DEFINED
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using System.Threading;
|
|
using System.IO;
|
|
using DTS.DASLib.Command.SLICE;
|
|
using DTS.DASLib.Command;
|
|
using DTS.Common.DAS.Concepts;
|
|
using DTS.Common.DASResource;
|
|
using DTS.Common.ICommunication;
|
|
using DTS.Common.Interface.DASFactory;
|
|
using DTS.Common.Utilities;
|
|
using DTS.Common.Utilities.Logging;
|
|
using DTS.DASLib.Command.SLICE.DownloadCommands;
|
|
using DTS.Common.Enums.Sensors;
|
|
using DTS.Common.Interface.Connection;
|
|
using DTS.Common.Classes.Connection;
|
|
using DTS.Common.Interface.DASFactory.Diagnostics;
|
|
using DTS.Common.Enums.DASFactory;
|
|
using DTS.Common.Interface.Communication;
|
|
using DTS.Common.Interface.DASFactory.Config;
|
|
using DTS.Common.Interface.StatusAndProgressBar;
|
|
using DTS.Common.Enums;
|
|
using DTS.Common.Utilities.LTLogging;
|
|
using System.IO.Ports;
|
|
using DTS.Common.Interface.DASFactory.Download;
|
|
using DTS.Common.Classes.DSP;
|
|
|
|
namespace DTS.DASLib.Service
|
|
{
|
|
public partial class Slice<T> : Communication<T>,
|
|
IDASCommunication,
|
|
IConfigurationActions,
|
|
IDiagnosticsActions,
|
|
ITriggerCheckActions,
|
|
IRealTimeActions,
|
|
IArmActions,
|
|
IDownloadActions where T : IConnection, new()
|
|
{
|
|
protected virtual void SetUDPAlignOnPPS()
|
|
{
|
|
try
|
|
{
|
|
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.UDPAlignOnPPS) && (this is IAlignUDPToPPSAware alignAware))
|
|
{
|
|
SetSystemAttributeSLICE6AIR set = new SetSystemAttributeSLICE6AIR(this);
|
|
set.SetValue(AttributeTypes.SystemAttributesSLICE6AIR.UDPAlignOnPpsEnable, alignAware.AlignUDPToPPS ? (ushort)1 : (ushort)0, true);
|
|
set.SyncExecute();
|
|
}
|
|
}
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
|
}
|
|
/// <summary>
|
|
/// run a command to discover any connected devices to the DAS
|
|
/// currently only S6DB supports directly querying for connected devices
|
|
/// </summary>
|
|
public virtual void QueryConnectedDevices()
|
|
{
|
|
}
|
|
|
|
void IConfigurationActions.VerifyConfig(bool DoStrictCheck)
|
|
{
|
|
VerifyConfig(DoStrictCheck, null);
|
|
}
|
|
void IConfigurationActions.VerifyConfig(bool DoStrictCheck, ErrorCallback failedChallengeFunc)
|
|
{
|
|
VerifyConfig(DoStrictCheck, failedChallengeFunc);
|
|
}
|
|
/// <summary>
|
|
/// returns true if this is a Digital Input Module, false otherwise
|
|
/// </summary>
|
|
private bool IsDIM()
|
|
{
|
|
try
|
|
{
|
|
if (null == SerialNumber) { return false; }
|
|
var serial = SerialNumber.ToUpper();
|
|
return serial.StartsWith("SPD") || serial.StartsWith("SLD");
|
|
}
|
|
catch( Exception ex )
|
|
{
|
|
APILogger.Log(ex);
|
|
}
|
|
return false;
|
|
}
|
|
protected virtual void VerifyConfig(bool DoStrictCheck, ErrorCallback failedChallengeFunc)
|
|
{
|
|
// 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 (string.IsNullOrEmpty(ConfigData.Description))
|
|
{
|
|
// "Slice.VerifyConfig: ConfigData.Description is null"
|
|
//throw new ArgumentException(Strings.Slice_VerifyConfig_Err2);
|
|
ConfigData.Description = "";
|
|
}
|
|
|
|
if (DoStrictCheck && string.IsNullOrEmpty(ConfigData.TestID))
|
|
{
|
|
// "Slice.VerifyConfig: ConfigData.TestID is null"
|
|
//throw new ArgumentException(Strings.Slice_VerifyConfig_Err3);
|
|
APILogger.Log("ConfigData.TestID is null");
|
|
ConfigData.TestID = string.Empty;
|
|
//ConfigData.TestID = "Default Test ID";
|
|
}
|
|
|
|
// we don't care about EID's here
|
|
|
|
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);
|
|
}
|
|
|
|
// SLICE have only DAS storage
|
|
if (DASInfo.MaxEventStorageSpaceInBytes == null) { DASInfo.MaxEventStorageSpaceInBytes = 1024 * 10; }
|
|
if (DASInfo.MaxEventStorageSpaceInBytes != null)
|
|
{
|
|
if (DASInfo.NumberOfBytesPerSampleClock == null)
|
|
{
|
|
throw new ArgumentException("Slice.VerifyConfig: DAS is missing NumberOfBytesPerSampleClock");
|
|
}
|
|
// if data is stored on DAS all modules (skipping the clock modules) must have same samplerate and pre/post
|
|
if (ConfigData.Modules.Where(mod => !mod.IsClock()).Select(module => module.SampleRateHz).Distinct().Count() != 1)
|
|
{
|
|
if (DoStrictCheck) { throw new ArgumentException("Slice.VerifyConfig: DAS modules have more than one unique samplerate"); }
|
|
else
|
|
{
|
|
APILogger.Log("more than one sample rate, normalizing to the first one", ConfigData.Modules[0].SampleRateHz);
|
|
foreach (var module in ConfigData.Modules)
|
|
{
|
|
module.SampleRateHz = ConfigData.Modules[0].SampleRateHz;
|
|
}
|
|
}
|
|
|
|
}
|
|
if (ConfigData.Modules.Where(mod => !mod.IsClock()).Select(module => module.PreTriggerSeconds).Distinct().Count() != 1)
|
|
{
|
|
if (DoStrictCheck) { throw new ArgumentException("Slice.VerifyConfig: DAS modules have more than one unique PreTriggerSeconds"); }
|
|
else
|
|
{
|
|
APILogger.Log("more than one pretriggersecond, normalizing to first one.", ConfigData.Modules[0].PreTriggerSeconds);
|
|
foreach (var module in ConfigData.Modules)
|
|
{
|
|
module.PreTriggerSeconds = ConfigData.Modules[0].PreTriggerSeconds;
|
|
}
|
|
}
|
|
}
|
|
if (ConfigData.Modules.Where(mod => !mod.IsClock()).Select(module => module.PostTriggerSeconds).Distinct().Count() != 1)
|
|
{
|
|
if (DoStrictCheck) { APILogger.Log("more than one posttriggersecond, normalizing to first one.", ConfigData.Modules[0].PostTriggerSeconds); }
|
|
else
|
|
{
|
|
foreach (var module in ConfigData.Modules)
|
|
{
|
|
module.PostTriggerSeconds = ConfigData.Modules[0].PostTriggerSeconds;
|
|
}
|
|
}
|
|
}
|
|
|
|
var secondsToRecord = ConfigData.Modules[0].PreTriggerSeconds + ConfigData.Modules[0].PostTriggerSeconds;
|
|
var sampleClocksToRecord = (ulong)(secondsToRecord * ConfigData.Modules[0].SampleRateHz + 1);
|
|
var bytesToRecord = sampleClocksToRecord * (ulong)DASInfo.NumberOfBytesPerSampleClock;
|
|
// FB15353: Bypass NAND logic for a for a streaming-only device in a streaming-only test
|
|
if (bytesToRecord > (ulong)DASInfo.MaxEventStorageSpaceInBytes &&
|
|
((null != DASInfo.DeviceStreamingOnly && !(bool)DASInfo.DeviceStreamingOnly) || null == DASInfo.DeviceStreamingOnly) &&
|
|
DFConstantsAndEnums.RecordingMode.S6A_DeviceStreamingOnly != ConfigData.Modules[0].RecordingMode)
|
|
{
|
|
var message = string.Format("Bytes to record exceeds maximum possible, {0}secs*{1}sps={2}>{3}",
|
|
secondsToRecord + 1, ConfigData.Modules[0].SampleRateHz, bytesToRecord, DASInfo.MaxEventStorageSpaceInBytes);
|
|
APILogger.Log(message);
|
|
if (DoStrictCheck) { throw new ArgumentException(message); }
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new ArgumentException("DAS is missing MaxEventStorageSpaceInBytes");
|
|
}
|
|
var bModuleAAFilterRateChallenge = false;
|
|
for (var moduleIdx = 0; moduleIdx < ConfigData.Modules.Length; moduleIdx++)
|
|
{
|
|
var module = ConfigData.Modules[moduleIdx];
|
|
if (module.IsClock() || module.IsUart() || module.IsStreamIn() || module.IsStreamOut() || module.IsThermocoupler()) continue;
|
|
if (module.ModuleArrayIndex != moduleIdx)
|
|
{
|
|
// "Slice.VerifyConfig: ConfigData.Module[{0}].ModuleNumber doesn't match index"
|
|
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err5, moduleIdx));
|
|
}
|
|
|
|
// we don't care about EID's here
|
|
|
|
if (module.AAFilterRateHz > MaxAAFilterRateHz)
|
|
{
|
|
module.AAFilterRateHz = MaxAAFilterRateHz;
|
|
bModuleAAFilterRateChallenge = true;
|
|
// "Slice.VerifyConfig: ConfigData.Module[{0}].AAFilterRateHz must be below {1}"
|
|
//throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err6, moduleIdx, MaxAAFilterRateHz));
|
|
}
|
|
|
|
switch (module.RecordingMode)
|
|
{
|
|
case DFConstantsAndEnums.RecordingMode.RecorderMode:
|
|
case DFConstantsAndEnums.RecordingMode.CircularBuffer:
|
|
case DFConstantsAndEnums.RecordingMode.RecorderModePlusUART:
|
|
case DFConstantsAndEnums.RecordingMode.CircularBufferPlusUART:
|
|
case DFConstantsAndEnums.RecordingMode.Streaming:
|
|
case DFConstantsAndEnums.RecordingMode.AerospaceWithMotion:
|
|
case DFConstantsAndEnums.RecordingMode.Scheduled:
|
|
case DFConstantsAndEnums.RecordingMode.Interval:
|
|
case DFConstantsAndEnums.RecordingMode.MultipleEventRecorderTriggerStart:
|
|
break;
|
|
case DFConstantsAndEnums.RecordingMode.AutoActiveMode:
|
|
case DFConstantsAndEnums.RecordingMode.AutoRecorderMode:
|
|
case DFConstantsAndEnums.RecordingMode.AutoCircularBufferMode:
|
|
case DFConstantsAndEnums.RecordingMode.AutoRecorderModePlusUART:
|
|
case DFConstantsAndEnums.RecordingMode.AutoCircularBufferPlusUART:
|
|
case DFConstantsAndEnums.RecordingMode.S6A_DeviceStreamingOnly:
|
|
if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.AutoArm))
|
|
{
|
|
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err7, moduleIdx));
|
|
}
|
|
break;
|
|
case DFConstantsAndEnums.RecordingMode.ContinuousRecorderMode:
|
|
case DFConstantsAndEnums.RecordingMode.HybridRecorderMode:
|
|
case DFConstantsAndEnums.RecordingMode.MultiHybridRecorderMode:
|
|
case DFConstantsAndEnums.RecordingMode.ContinuousRecorderModePlusUART:
|
|
if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.MultipleAndHybridEvents))
|
|
{
|
|
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err7, moduleIdx));
|
|
}
|
|
break;
|
|
case DFConstantsAndEnums.RecordingMode.a14_NormalRecorderAndStreamSubSampleMode:
|
|
case DFConstantsAndEnums.RecordingMode.a16_CircularBufferAndStreamSubSampleMode:
|
|
case DFConstantsAndEnums.RecordingMode.a17_MultiCircularBufferAndStreamSubSampleMode:
|
|
case DFConstantsAndEnums.RecordingMode.a15_MultiRecorderAndStreamSubSampleMode:
|
|
case DFConstantsAndEnums.RecordingMode.a18_HybridRecorderAndStreamSubSampleMode:
|
|
case DFConstantsAndEnums.RecordingMode.a19_MultiHybridRecorderAndStreamSubSampleMode:
|
|
if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.RecordAndStreamSubSample))
|
|
{
|
|
throw new ArgumentException($"{Strings.Slice_VerifyConfigSettings} module index: {moduleIdx}, mode: {module.RecordingMode}");
|
|
}
|
|
break;
|
|
case DFConstantsAndEnums.RecordingMode.MultipleEventRAMActive:
|
|
case DFConstantsAndEnums.RecordingMode.RAMActive:
|
|
if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.ActiveRAM))
|
|
{
|
|
throw new ArgumentException($"{Strings.Slice_VerifyConfigSettings} module index: {moduleIdx}, mode: {module.RecordingMode} not supported");
|
|
}
|
|
break;
|
|
case DFConstantsAndEnums.RecordingMode.a26_MultiRecordOnBootDataMode:
|
|
case DFConstantsAndEnums.RecordingMode.a28_MultiRecordOnBootAndUartDataMode:
|
|
if (!IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.RecordOnBoot))
|
|
{
|
|
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err7, moduleIdx));
|
|
}
|
|
break;
|
|
default:
|
|
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err7, moduleIdx));
|
|
}
|
|
|
|
// if we have a dim, don't use the max sample rate as is
|
|
// instead get the rate given the current configuration
|
|
// I only did this for DIM to avoid side effects
|
|
// http://manuscript.dts.local/f/cases/43548/Add-support-for-1-5MB-SPS-on-SPD
|
|
var maxRate = MaxSampleRateHz;
|
|
try
|
|
{
|
|
if (IsDIM() && MaxSampleRate(18) > maxRate) { maxRate = MaxSampleRate(18); }
|
|
}
|
|
catch( Exception ex)
|
|
{
|
|
APILogger.Log(ex);
|
|
}
|
|
|
|
if(module.SampleRateHz > maxRate)
|
|
{
|
|
// "Slice.VerifyConfig: ConfigData.Module[{0}].SampleRateHz must be below {1}"
|
|
if (DoStrictCheck) { throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err8, moduleIdx, maxRate)); }
|
|
else { module.SampleRateHz = maxRate; }
|
|
}
|
|
|
|
// module.MaxRecordingSamples is null for SLICE
|
|
|
|
if (module.Channels == null || module.Channels.Length == 0 || module.Channels.Length > DASInfo.Modules[moduleIdx].NumberOfChannels)
|
|
{
|
|
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels is null, empty or too long"
|
|
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err10, moduleIdx));
|
|
}
|
|
|
|
for (var channelIdx = 0; channelIdx < module.Channels.Length; channelIdx++)
|
|
{
|
|
var channel = (DASChannel)module.Channels[channelIdx];
|
|
|
|
if (channel.ConfigurationMode == DFConstantsAndEnums.ConfigMode.Disabled)
|
|
continue;
|
|
|
|
if (channel.OwningModule != module)
|
|
{
|
|
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}].OwningModule doesn't mach owner"
|
|
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err11, moduleIdx, channelIdx));
|
|
}
|
|
|
|
if (channel.ModuleChannelNumber != channelIdx)
|
|
{
|
|
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}].ChannelNumber doesn't mach index"
|
|
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err12, moduleIdx, channelIdx));
|
|
}
|
|
|
|
if (channel.ConfigurationMode != DFConstantsAndEnums.ConfigMode.Normal &&
|
|
channel.ConfigurationMode != DFConstantsAndEnums.ConfigMode.DummyArm &&
|
|
channel.ConfigurationMode != DFConstantsAndEnums.ConfigMode.Disabled)
|
|
{
|
|
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}].mode has incorrect value"
|
|
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err13, moduleIdx, channelIdx));
|
|
}
|
|
var infoModule = DASInfo.Modules[module.ModuleArrayIndex];
|
|
if (!(channel is AnalogInputDASChannel) && infoModule.TypeOfModule != DFConstantsAndEnums.ModuleType.SLICEPro_TOM)
|
|
{
|
|
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}] is not an analog input channel"
|
|
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err14, moduleIdx, channelIdx));
|
|
}
|
|
|
|
if (channel is AnalogInputDASChannel analog)
|
|
{
|
|
if (!analog.SupportedBridges.Contains(analog.TypeOfBridge))
|
|
{
|
|
throw new ArgumentException("Unsupported bridge mode: " + analog.TypeOfBridge.ToString());
|
|
}
|
|
|
|
if (analog.ShuntIsEnabled)
|
|
{
|
|
if (analog.BridgeResistanceOhms < SensorConstants.MIN_BRIDGE_RESISTANCE_OHMS) { analog.BridgeResistanceOhms = SensorConstants.MIN_BRIDGE_RESISTANCE_OHMS; }
|
|
if (analog.BridgeResistanceOhms > SensorConstants.MAX_BRIDGE_RESISTANCE_OHMS) { analog.BridgeResistanceOhms = SensorConstants.MAX_BRIDGE_RESISTANCE_OHMS; }
|
|
}
|
|
|
|
if (analog.BypassAAFilter)
|
|
{
|
|
module.AAFilterRateHz = MaxAAFilterRateHz;
|
|
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}], bypassing AA filter is not supported"
|
|
//throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err17, moduleIdx, channelIdx));
|
|
}
|
|
|
|
if (analog.DesiredRangeWithHeadroomEU < 0)
|
|
{
|
|
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}].DesiredRange must be positive"
|
|
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err18, moduleIdx, channelIdx));
|
|
}
|
|
|
|
if (DoStrictCheck && string.IsNullOrEmpty(analog.EngineeringUnits) && channel.ConfigurationMode != DFConstantsAndEnums.ConfigMode.DummyArm)
|
|
{
|
|
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}].EngineeringUnits can't be null or empty"
|
|
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err19, moduleIdx, channelIdx));
|
|
}
|
|
|
|
if (analog.ZeroMethod != ZeroMethodType.AverageOverTime &&
|
|
analog.ZeroMethod != ZeroMethodType.UsePreEventDiagnosticsZero &&
|
|
analog.ZeroMethod != ZeroMethodType.None)
|
|
{
|
|
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}].ZeroMethod has invalid value"
|
|
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err22, moduleIdx, channelIdx));
|
|
}
|
|
|
|
if (DoStrictCheck && analog.ZeroMethod == ZeroMethodType.AverageOverTime)
|
|
{
|
|
if (analog.ZeroAverageStartSeconds >= analog.ZeroAverageStopSeconds)
|
|
{
|
|
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}] zero average start must be less than zero average stop"
|
|
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err23, moduleIdx, channelIdx));
|
|
}
|
|
|
|
if (analog.ZeroAverageStopSeconds > module.PostTriggerSeconds)
|
|
{
|
|
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}] zero average stop must be less than post-trigger"
|
|
if (DoStrictCheck) { throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err25, moduleIdx, channelIdx)); }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (bModuleAAFilterRateChallenge)
|
|
{
|
|
var err = string.Format("Default hardware filter frequency for {0} is out of range. Press OK to continue and use the max hardware rate or cancel to cancel.", SerialNumber);
|
|
var dr = DialogResult.Cancel;
|
|
APILogger.Log("MessageBox", err, dr);
|
|
if (dr == DialogResult.Cancel) { throw new ArgumentOutOfRangeException(DASModule.AAFilterRateHzTag); }
|
|
}
|
|
|
|
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.InitHardwareInputLines) && DoStrictCheck)
|
|
{
|
|
var ihl = new InitializeHardwareLines(this, 6000);
|
|
try
|
|
{
|
|
//performance improvement, reduce unnecessary commands
|
|
//in systems where polarity doesn't need to get set, just eliminate the calls
|
|
if (RunTestVariables.InRunTest && RunTestVariables.DontSetPolarityInRunTest)
|
|
{
|
|
//don't set
|
|
}
|
|
else
|
|
{
|
|
var ssaStart = new SetSystemAttribute(this, SetSystemAttribute.Default_IO_Timeout);
|
|
var ssaTrigger = new SetSystemAttribute(this, SetSystemAttribute.Default_IO_Timeout);
|
|
ssaStart.SetValue(AttributeTypes.SystemAttributes.StartRecordPolarity,
|
|
(byte)(InvertStart ? 1 : 0), true);
|
|
ssaTrigger.SetValue(AttributeTypes.SystemAttributes.TriggerPolarity,
|
|
(byte)(InvertTrigger ? 1 : 0), true);
|
|
ssaStart.SyncExecute();
|
|
ssaTrigger.SyncExecute();
|
|
}
|
|
|
|
ihl.SyncExecute();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (ihl.StartRecordShorted)
|
|
{
|
|
if (!IgnoreShortedStart)
|
|
{
|
|
throw new StartShortedException(string.Format(Strings.StartRecordShorted, SerialNumber));
|
|
}
|
|
}
|
|
if (ihl.TriggerInputShorted)
|
|
{
|
|
if (!IgnoreShortedTrigger)
|
|
{
|
|
throw new TriggerShortedException(string.Format(Strings.TriggerShorted, SerialNumber));
|
|
}
|
|
}
|
|
else if (!ihl.StartRecordShorted && !ihl.TriggerInputShorted)
|
|
{
|
|
//rely on the handlers above for shorted start or trigger, only pass back any _other_ errors
|
|
throw ex;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
protected const ushort SLICE_HALFBRIDGE_RESISTANCE = 3000;
|
|
protected virtual uint MaxAAFilterRateHz => DTS.Common.Constant.DASSpecific.SLICE.MaxAAFilterRateHz;
|
|
protected virtual uint MaxSampleRateHz => 200000;
|
|
|
|
private const double InputRangeMV = 2500;
|
|
private const double HeadRoomPercent = 0.0;
|
|
|
|
#region Query configuration
|
|
|
|
void IConfigurationActions.QueryTestSetup(ServiceCallback callback, object userData)
|
|
{
|
|
var info = new SliceServiceQueryTestSetupAsyncInfo(callback, userData, ConfigData.TestSetupUniqueId.ToString());
|
|
|
|
LaunchAsyncWorker("Slice.QueryTestSetup", new WaitCallback(AsyncQueryTestSetup), info);
|
|
}
|
|
/// <summary>
|
|
/// Retrieve the info to fill in the ConfigData property
|
|
/// </summary>
|
|
/// <param name="callback">The delegate to report to</param>
|
|
/// <param name="userData">User supplied data that we pass along</param>
|
|
void IConfigurationActions.QueryConfiguration(ServiceCallback callback, object userData, uint crc, string strConfig, bool bReadIds, bool bDeviceScaleFactors,
|
|
bool differentModuleCountsAreOK)
|
|
{
|
|
var info = new SliceServiceAsyncInfo(callback, userData);
|
|
|
|
LaunchAsyncWorker("Slice.QueryConfiguration", new WaitCallback(AsyncQueryConfiguration), info);
|
|
}
|
|
|
|
void IConfigurationActions.UpdateConfigurationFromFile(ServiceCallback callback, object userData,
|
|
string filePath)
|
|
{
|
|
var info = new SliceServiceAsyncInfo(callback, userData) { functionData = filePath };
|
|
LaunchAsyncWorker("Slice.UpdateConfigurationFromFile", new WaitCallback(AsyncUpdateConfigurationFromFile),
|
|
info);
|
|
}
|
|
|
|
protected virtual void AsyncUpdateConfigurationFromFile(object asyncInfo)
|
|
{
|
|
var info = asyncInfo as SliceServiceAsyncInfo;
|
|
info.Error("Not supported yet");
|
|
return;
|
|
}
|
|
/// <summary>
|
|
/// The DAS may store configuration information, but the information could be invalid.
|
|
/// in particular we need to throw it out if the old module is IEPE and we aren't in IEPE or vice versa
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
protected bool VerifyConfig()
|
|
{
|
|
try
|
|
{
|
|
if (null == ConfigData) { return false; }
|
|
|
|
for (var i = 0; i < ConfigData.Modules.Length && i < DASInfo.Modules.Length; i++)
|
|
{
|
|
//30429 Invalidate/fail sooner than Arm step if DAS doesn't have streaming capability/channel (TSR AIR may or may not)
|
|
if (DASInfo.Modules[i] == null) { continue; }
|
|
foreach (var channel in ConfigData.Modules[i].Channels)
|
|
{
|
|
//If a Slice DIM (internal) module was not configured correctly (SupportedBridges is not DigitalInput only),
|
|
//return false so that if the module has been corrected after the bad config had been written to the DAS when
|
|
//a previous test ran without the incorrect channels, a default config will be generated based on the corrections.
|
|
if ((DASInfo.Modules[i].TypeOfModule == DFConstantsAndEnums.ModuleType.ProDIM) &&
|
|
(((channel as AnalogInputDASChannel).SupportedBridges.Length != 1) ||
|
|
((channel as AnalogInputDASChannel).SupportedBridges[0] != SensorConstants.BridgeType.DigitalInput) ||
|
|
((channel as AnalogInputDASChannel).TypeOfBridge != SensorConstants.BridgeType.DigitalInput))) { return false; }
|
|
|
|
if (channel.ConfigurationMode == DFConstantsAndEnums.ConfigMode.Normal)
|
|
{
|
|
var IEPE = false;
|
|
if (channel is AnalogInputDASChannel analog) { IEPE = analog.IEPEChannel; }
|
|
|
|
if (IEPE)
|
|
{
|
|
if (DASInfo.Modules[i].IsProgrammable ||
|
|
//if we received an invalid mode during setup, then we don't know if it is programmable
|
|
//so assume we are, otherwise the configuration will be thrown out as invalid
|
|
//15932 Error when performing test when S6A is streaming
|
|
(null != DASArmStatus && DASArmStatus.ReceivedInvalidModeDuringSetup)) {; }
|
|
else if (DASInfo.Modules[i].TypeOfModule != DFConstantsAndEnums.ModuleType.SLICEIEPE
|
|
&& DASInfo.Modules[i].TypeOfModule != DFConstantsAndEnums.ModuleType.SliceIEPE2High)
|
|
{ return false; }
|
|
}
|
|
else
|
|
{
|
|
if (DASInfo.Modules[i].IsProgrammable) {; }
|
|
else if (DASInfo.Modules[i].TypeOfModule == DFConstantsAndEnums.ModuleType.SLICEIEPE
|
|
|| DASInfo.Modules[i].TypeOfModule == DFConstantsAndEnums.ModuleType.SliceIEPE2High)
|
|
{ return false; }
|
|
}
|
|
}
|
|
else if (channel.ConfigurationMode == DFConstantsAndEnums.ConfigMode.Clock)
|
|
{
|
|
// 17776 Clock modules get their own type
|
|
if (channel is TimestampDASChannel stamp) {; }
|
|
else
|
|
{ return false; }
|
|
}
|
|
else if (channel.ConfigurationMode == DFConstantsAndEnums.ConfigMode.StreamIn)
|
|
{
|
|
// 26826 Stream modules get their own type
|
|
if (channel is StreamInputDASChannel streamin) {; }
|
|
else
|
|
{ return false; }
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log("Problem verifying config - ", ex);
|
|
}
|
|
return false;
|
|
}
|
|
/// <summary>
|
|
/// returns true if should check for ids for batteries,
|
|
/// false otherwise
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
protected bool ShouldCheckForBatteryIds()
|
|
{
|
|
if (this is EthernetSlice6 || this is EthernetSlice6Air || this is EthernetSlice6AirBridge || this is EthernetTsrAir) { return false; } //doesn't have battery ids
|
|
return true;
|
|
}
|
|
protected virtual void AsyncQueryTestSetup(object configAsyncInfo)
|
|
{
|
|
var info = configAsyncInfo as SliceServiceAsyncInfo;
|
|
info.Success();
|
|
}
|
|
protected virtual void AsyncQueryConfiguration(object configAsyncInfo)
|
|
{
|
|
var info = configAsyncInfo as SliceServiceAsyncInfo;
|
|
|
|
var displayOrder = new int[] { -1 };
|
|
var dasDisplayOrder = -1;
|
|
|
|
try { dasDisplayOrder = GetDASDisplayOrder(); }
|
|
catch (Exception ex) { APILogger.Log("Failed to query user attributes", ex); }
|
|
|
|
info.Progress(10);
|
|
try { displayOrder = GetChannelDisplayOrder(); }
|
|
catch (Exception ex) { APILogger.Log("Failed to query user attributes", ex); }
|
|
|
|
info.Progress(20);
|
|
try
|
|
{
|
|
// pickup the channel data
|
|
var config = GetConfigAttributes(this);//new ConfigAttributes(this);
|
|
try
|
|
{
|
|
var StoredInfoString = config.RetrieveXMLConfig(ConfigAttributes.FileStore.Diagnostic, this);
|
|
ConfigData = ConfigurationData.DeserializeFromString(StoredInfoString);
|
|
info.Progress(50);
|
|
if (!VerifyConfig()) { ConfigData = null; }
|
|
if (ConfigData == null || ConfigData.Modules == null || ConfigData.Modules.Length == 0)
|
|
{
|
|
APILogger.LogString("QueryConfiguration: ConfigData or Modules empty, using default config");
|
|
ConfigData = MakeDefaultConfigFromInfo();
|
|
}
|
|
else if (DASInfo == null || DASInfo.Modules == null || DASInfo.Modules.Length != ConfigData.Modules.Length)
|
|
{
|
|
APILogger.LogString("QueryConfiguration: DASInfo or Modules empty, using default config");
|
|
ConfigData = MakeDefaultConfigFromInfo();
|
|
}
|
|
else
|
|
{
|
|
for (var i = 0; i < ConfigData.Modules.Length && i < DASInfo.Modules.Length; i++)
|
|
{
|
|
var bIEPE = false;
|
|
switch (DASInfo.Modules[i].TypeOfModule)
|
|
{
|
|
case DFConstantsAndEnums.ModuleType.SLICEIEPE:
|
|
bIEPE = true;
|
|
break;
|
|
}
|
|
foreach (var channel in ConfigData.Modules[i].Channels)
|
|
{
|
|
if (bIEPE)
|
|
{
|
|
((AnalogInputDASChannel)channel).SupportedBridges = new[] { SensorConstants.BridgeType.IEPE };
|
|
}
|
|
else
|
|
{
|
|
((AnalogInputDASChannel)channel).SupportedBridges = new[]{
|
|
SensorConstants.BridgeType.FullBridge, SensorConstants.BridgeType.HalfBridge};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
info.Progress(60);
|
|
}
|
|
catch (CanceledException)
|
|
{
|
|
// cancel must be propagated
|
|
throw;
|
|
}
|
|
catch (NotConnectedException)
|
|
{
|
|
info.Error(string.Format("Connection with {0} failed", SerialNumber));
|
|
return;
|
|
}
|
|
catch (System.Net.Sockets.SocketException socketException)
|
|
{
|
|
APILogger.LogString("QueryConfiguration: RetrieveXMLConfig threw exception");
|
|
APILogger.LogException(socketException);
|
|
info.Error($"Connection with {SerialNumber} failed");
|
|
return;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.LogString("QueryConfiguration: RetrieveXMLConfig threw exception");
|
|
APILogger.LogException(ex);
|
|
if (ex.Message.Contains("ReceiveFailed"))
|
|
{
|
|
info.Error($"Connection with {SerialNumber} failed");
|
|
return;
|
|
}
|
|
|
|
// something happend that prevents us from getting the stored config, make a default
|
|
ConfigData = MakeDefaultConfigFromInfo();
|
|
}
|
|
if (null != ConfigData) { ConfigData.DisplayOrder = displayOrder; ConfigData.DasDisplayOrder = dasDisplayOrder; }
|
|
// get scale factors
|
|
try
|
|
{
|
|
var scaleFactors = GetScaleFactors();
|
|
#if LEVEL_TRIGGER_DEFINED
|
|
// These are currently unutilized since we have no application for the offset-adjusted
|
|
// level trigger values outside of the Slice firmware.
|
|
//
|
|
// var levelTriggers = GetLevelTriggers( );
|
|
#endif
|
|
|
|
info.Progress(70);
|
|
// set the OwningDAS and OwningModule since it was skipped during serialization
|
|
foreach (var iDASModule in ConfigData.Modules)
|
|
{
|
|
var module = (DASModule)iDASModule;
|
|
module.SampleRateHz = Convert.ToUInt32(config.ActualSampleRate);
|
|
module.OwningDAS = this;
|
|
foreach (var iDASChannel in module.Channels)
|
|
{
|
|
var channel = (DASChannel)iDASChannel;
|
|
channel.OwningModule = module;
|
|
|
|
// pick up the scalefactor for this channel
|
|
if (channel is AnalogInputDASChannel analog)
|
|
{
|
|
var dasChannelNumber = analog.Number;
|
|
if (dasChannelNumber < scaleFactors.Length)
|
|
{
|
|
analog.ScalefactorMilliVoltsPerADC = scaleFactors[dasChannelNumber];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
info.Progress(80);
|
|
}
|
|
catch (System.Net.Sockets.SocketException socketException)
|
|
{
|
|
APILogger.LogString("QueryConfiguration: RetrieveXMLConfig threw exception");
|
|
APILogger.LogException(socketException);
|
|
info.Error(string.Format("Connection with {0} failed", SerialNumber));
|
|
return;
|
|
}
|
|
catch (NotConnectedException) { info.Error($"Connection with {SerialNumber} failed"); return; }
|
|
catch (CanceledException)
|
|
{
|
|
// cancel must be propagated
|
|
throw;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.LogString("QueryConfiguration: GetScaleFactors threw exception");
|
|
APILogger.LogException(ex);
|
|
// we don't need no stinking scale factors
|
|
}
|
|
|
|
// get sensor ID's
|
|
if (ConfigData.Modules != null)
|
|
{
|
|
foreach (var iDASModule in ConfigData.Modules)
|
|
{
|
|
var module = (DASModule)iDASModule;
|
|
module.OwningDAS = this; // in case we bailed out above
|
|
foreach (var iDASchannel in module.Channels)
|
|
{
|
|
var channel = (DASChannel)iDASchannel;
|
|
channel.OwningModule = module; // in case bailed out above
|
|
var dasChannelNumber = DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(module.ModuleArrayIndex, channel.ModuleChannelNumber);
|
|
channel.IDs = EIDReader.RetriveEIDs(this, dasChannelNumber, 0);
|
|
}
|
|
IEID[] ids = null;
|
|
//performance improvement, skip getting battery ids if you don't need too
|
|
if (ShouldCheckForBatteryIds())
|
|
{
|
|
ids = EIDReader.RetriveEIDs(this, 255, 0);
|
|
}
|
|
else
|
|
{
|
|
ids = null;
|
|
}
|
|
|
|
if (null != ids && 0 != ids.Length)
|
|
{
|
|
module.OwningDAS.DASInfo.BatteryID = ids[0];
|
|
module.OwningDAS.SetDASInfo();
|
|
}
|
|
}
|
|
}
|
|
info.Progress(90);
|
|
RetrieveEventGuids();
|
|
DASInfo.MaxEventStorageSpaceInBytes = ReadSampleStorageSizeInBytes();
|
|
info.Progress(95);
|
|
GetAutoArmStatus();
|
|
info.Success();
|
|
}
|
|
catch (System.Net.Sockets.SocketException socketException)
|
|
{
|
|
APILogger.LogString("QueryConfiguration: RetrieveXMLConfig threw exception");
|
|
APILogger.LogException(socketException);
|
|
info.Error(string.Format("Connection with {0} failed", SerialNumber));
|
|
return;
|
|
}
|
|
catch (NotConnectedException) { info.Error($"Connection with {SerialNumber} failed"); return; }
|
|
catch (CanceledException)
|
|
{
|
|
info.Cancel();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
info.Error(ex.Message, ex);
|
|
}
|
|
}
|
|
|
|
const UInt64 ReservedFlashSpace = 659 * 2 * 1024 * 1024;
|
|
protected UInt64 ReadSampleStorageSizeInBytes()
|
|
{
|
|
//15949 S6A when streaming does a whole bunch of unnecessary queries
|
|
//avoid getting these attributes while streaming, they will fail...
|
|
if (GetIsStreaming()) { return 1024 * 1024 * 1024; }// 1GB
|
|
try
|
|
{
|
|
var reservedFlashSpace = ReservedFlashSpace;
|
|
try
|
|
{
|
|
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.AttributeStoreBlocks))
|
|
{
|
|
var qsa = new QuerySystemAttribute(this, QuerySystemAttribute.Default_IO_Timeout);
|
|
qsa.DeviceID = 0;
|
|
qsa.Key = AttributeTypes.SystemAttributes.AttributeStoreBlocks;
|
|
qsa.SyncExecute();
|
|
var uValue = (ulong)qsa.Value;
|
|
if (uValue > 0) { reservedFlashSpace = uValue; }
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log("Exception getting attribute store blocks", SerialNumber, ex);
|
|
}
|
|
var query = new QuerySystemAttribute(this, QuerySystemAttribute.Default_IO_Timeout);
|
|
query.Key = AttributeTypes.SystemAttributes.FlashSizeBytes;
|
|
query.SyncExecute();
|
|
var flashSize = (ulong)query.Value;
|
|
if (flashSize >= reservedFlashSpace)
|
|
{
|
|
flashSize -= reservedFlashSpace;
|
|
}
|
|
return flashSize;
|
|
}
|
|
catch (CommandException ce)
|
|
{
|
|
if (ce.Error != CommandErrorReason.InvalidMode)
|
|
{
|
|
APILogger.LogString("DASFactory.ReadSampleStorageSizeInBytes: Exception " + ce.Message + " returning 1GB");
|
|
}
|
|
return 1024 * 1024 * 1024; // 1GB
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// we have to return something
|
|
APILogger.LogString("DASFactory.ReadSampleStorageSizeInBytes: Exception " + ex.Message + " returning 1GB");
|
|
return 1024 * 1024 * 1024; // 1GB
|
|
}
|
|
}
|
|
|
|
protected virtual void RetrieveEventGuids()
|
|
{
|
|
try
|
|
{
|
|
var EventCount = new QueryTotalEventCount(this, QueryTotalEventCount.Default_IO_Timeout);
|
|
EventCount.SyncExecute();
|
|
if (EventCount.Count < 1)
|
|
{
|
|
// no events
|
|
SetEventGuids(null);
|
|
SetEventFaultFlags(null);
|
|
SetEventArmAttemps(null);
|
|
return;
|
|
}
|
|
|
|
var guids = new Guid[EventCount.Count];
|
|
var downloadedStatus = new bool[EventCount.Count];
|
|
var faultFlags = new ushort[EventCount.Count];
|
|
var armAttempts = new byte[EventCount.Count];
|
|
var extendedFaultFlags = new List<uint[]>();
|
|
|
|
var queryEventGuid = new QueryEventAttribute(this, QueryEventAttribute.Default_IO_Timeout);
|
|
var queryFaultFlags = new QueryEventAttribute(this, QueryEventAttribute.Default_IO_Timeout);
|
|
var queryEventArmAttempts = new QueryEventAttribute(this, QueryEventAttribute.Default_IO_Timeout);
|
|
|
|
queryEventGuid.Key = AttributeTypes.ArmAndEventAttributes.EventGuid;
|
|
queryFaultFlags.Key = AttributeTypes.ArmAndEventAttributes.FaultFlags;
|
|
queryEventArmAttempts.Key = AttributeTypes.ArmAndEventAttributes.EventArmAttempts;
|
|
|
|
for (ushort eventIdx = 0; eventIdx < EventCount.Count; eventIdx++)
|
|
{
|
|
queryEventGuid.EventNumber = eventIdx;
|
|
queryFaultFlags.EventNumber = eventIdx;
|
|
|
|
queryEventGuid.SyncExecute();
|
|
|
|
guids[eventIdx] = new Guid(queryEventGuid.Value as string);
|
|
extendedFaultFlags.Add(GetExtendedFaultFlags(eventIdx));
|
|
faultFlags[eventIdx] = 0;
|
|
armAttempts[eventIdx] = 0;
|
|
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.EventFaultFlags))
|
|
{
|
|
try
|
|
{
|
|
queryFaultFlags.SyncExecute();
|
|
faultFlags[eventIdx] = (ushort)queryFaultFlags.Value;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log("could not get fault flags", ex);
|
|
}
|
|
try
|
|
{
|
|
var ca = GetConfigAttributes(this);//new Slice<T>.ConfigAttributes(this);
|
|
downloadedStatus[eventIdx] = ca.EventHasBeenDownloaded(eventIdx, out uint iflag);
|
|
}
|
|
catch (Exception) { }
|
|
|
|
// Get Arm Attempts for this event
|
|
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.EventArmAttempts))
|
|
{
|
|
try
|
|
{
|
|
queryEventArmAttempts.EventNumber = eventIdx;
|
|
queryEventArmAttempts.SyncExecute();
|
|
armAttempts[eventIdx] = (byte)queryEventArmAttempts.Value;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log("could not get arm attempts", ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
SetEventGuids(guids);
|
|
SetEventFaultFlags(faultFlags);
|
|
((IDownload)this)?.SetExtendedFaultFlags(extendedFaultFlags.ToArray());
|
|
SetEventArmAttemps(armAttempts);
|
|
SetEventDownloadStatus(downloadedStatus);
|
|
}
|
|
catch (CommandException ce)
|
|
{
|
|
if (ce.Error != CommandErrorReason.InvalidMode)
|
|
{
|
|
APILogger.LogString("DASFactory.RetriveEventGuids: ");
|
|
APILogger.LogException(ce);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.LogString("DASFactory.RetriveEventGuids: ");
|
|
APILogger.LogException(ex);
|
|
}
|
|
}
|
|
protected virtual DASModule MakeConfigModuleFromInfoModule(InfoResult.Module infoModule)
|
|
{
|
|
var configModule = new DASModule(infoModule.ModuleArrayIndex, this);
|
|
configModule.Channels = new AnalogInputDASChannel[infoModule.NumberOfChannels];
|
|
|
|
for (var i = 0; i < infoModule.NumberOfChannels; i++)
|
|
{
|
|
var channel = new AnalogInputDASChannel(configModule, i);
|
|
if (infoModule.TypeOfModule == DFConstantsAndEnums.ModuleType.SLICEIEPE)
|
|
{
|
|
channel.IEPEChannel = true;
|
|
channel.SupportedBridges = new SensorConstants.BridgeType[] { SensorConstants.BridgeType.IEPE };
|
|
}
|
|
else
|
|
{
|
|
channel.IEPEChannel = false;
|
|
channel.SupportedBridges = new SensorConstants.BridgeType[] {SensorConstants.BridgeType.FullBridge,
|
|
SensorConstants.BridgeType.HalfBridge};
|
|
}
|
|
configModule.Channels[i] = channel;
|
|
}
|
|
return configModule;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculate the EU to mV conversion factor for the specified channel.
|
|
/// </summary>
|
|
///
|
|
/// <param name="analog">
|
|
/// The <see cref="DTS.DASLib.Service.AnalogInputDASChannel"/> whose property is being converted from
|
|
/// EU to mV.
|
|
/// </param>
|
|
///
|
|
/// <returns>
|
|
/// The mV equivalent of 1 EU on the specified channel.
|
|
/// </returns>
|
|
///
|
|
protected double GetMvPerEu(AnalogInputDASChannel analog)
|
|
{
|
|
try
|
|
{
|
|
return Math.Abs(analog.SensitivityMilliVoltsPerEU);
|
|
}
|
|
|
|
catch (Exception ex)
|
|
{
|
|
throw new ApplicationException("encountered problem getting EU to MV conversion factor for channel " + (null != analog && null != analog.SerialNumber ? analog.SerialNumber : "<NULL>"), ex);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// returns true if channel has linear added calibrations
|
|
/// </summary>
|
|
/// <param name="analog"></param>
|
|
/// <returns></returns>
|
|
private bool HasLinearAdded(AnalogInputDASChannel analog)
|
|
{
|
|
//seems like the simplest way of checking currently
|
|
return !string.IsNullOrEmpty(analog.LinearSensorCalibration);
|
|
}
|
|
protected double GetMvPerEUNormalized(AnalogInputDASChannel analog)
|
|
{
|
|
try
|
|
{
|
|
//14079 Gain selection inconsistent between non-linear poly with linear CAL and traditional non-linear poly sensor
|
|
//if we have linear added we may be marked as proportional, but we want the non linear, non proportional mVPerEU
|
|
bool isProportional = HasLinearAdded(analog) ? false : analog.IsProportionalToExcitation;
|
|
|
|
return Math.Abs(analog.SensitivityMilliVoltsPerEU)
|
|
* (isProportional && analog.SensitivityUnits != SensorConstants.SensUnits.mVperEU
|
|
? Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(analog.Excitation)
|
|
: 1.0)
|
|
/ (analog.AtCapacity ? analog.CapacityOutputIsBasedOn : 1.0);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new ApplicationException("encountered problem getting EU to MV conversion factor for channel " + (null != analog && null != analog.SerialNumber ? analog.SerialNumber : "<NULL>"), ex);
|
|
}
|
|
}
|
|
|
|
protected virtual ConfigurationData MakeDefaultConfigFromInfo()
|
|
{
|
|
var conf = new ConfigurationData();
|
|
if (DASInfo != null && DASInfo.Modules != null && DASInfo.Modules.Length > 0)
|
|
{
|
|
conf.Modules = new DASModule[DASInfo.Modules.Length];
|
|
for (int moduleIdx = 0; moduleIdx < DASInfo.Modules.Length; moduleIdx++)
|
|
{
|
|
conf.Modules[moduleIdx] = MakeConfigModuleFromInfoModule((InfoResult.Module)DASInfo.Modules[moduleIdx]);
|
|
}
|
|
}
|
|
return conf;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Set configuration
|
|
public virtual double[] GetNominalRanges(SensorConstants.BridgeType bridgeType)
|
|
{
|
|
switch (bridgeType)
|
|
{
|
|
case SensorConstants.BridgeType.IEPE:
|
|
return WinUSBSlice.StaticDASIEPEInfo.NominalRanges;
|
|
default:
|
|
return WinUSBSlice.StaticDASBridgeInfo.NominalRanges;
|
|
}
|
|
}
|
|
public class CheckSafetyStateAsyncInfo : SliceServiceAsyncInfo
|
|
{
|
|
public bool Armed { get; set; }
|
|
public CheckSafetyStateAsyncInfo(ServiceCallback callback, object userData)
|
|
: base(callback, userData) { }
|
|
}
|
|
void IConfigurationActions.CheckSafetyState(bool bArmed, ServiceCallback callback, object userData)
|
|
{
|
|
var info = new CheckSafetyStateAsyncInfo(callback, userData);
|
|
info.Armed = bArmed;
|
|
|
|
LaunchAsyncWorker("Slice.CheckSafetyState", new WaitCallback(AsyncCheckSafetyState), info);
|
|
}
|
|
|
|
protected virtual bool CheckAutoDetectSupport() { return false; }
|
|
bool IConfiguration.SupportsAutoDetect => CheckAutoDetectSupport();
|
|
void IConfigurationActions.AutoDetect(bool QueryConfiguration, ServiceCallback callback, object userData)
|
|
{
|
|
var info = new AutoDetectServiceAsyncInfo(QueryConfiguration, callback, userData);
|
|
LaunchAsyncWorker("Slice.AutoDetect", new WaitCallback(AsyncAutoDetect), info);
|
|
}
|
|
|
|
protected virtual void AsyncAutoDetect(object o)
|
|
{
|
|
if (!(o is SliceServiceAsyncInfo info)) { return; }
|
|
info.Success();
|
|
}
|
|
public class SliceConfigServiceAsyncInfo : SliceServiceAsyncInfo
|
|
{
|
|
public bool EventConfig { get; set; } = false;
|
|
public bool DummyConfig { get; set; } = false;
|
|
//FB 26736 time & data channel Id
|
|
public Dictionary<IDASCommunication, ushort> TimeChannelIds { get; set; }
|
|
public Dictionary<IDASCommunication, ushort> DataChannelIds { get; set; }
|
|
public Dictionary<IDASCommunication, UDPStreamProfile> StreamProfiles { get; set; }
|
|
public Dictionary<IDASCommunication, int> StreamADCPerPacket { get; set; }
|
|
public Dictionary<IDASCommunication, ushort> IrigTDPIntervals { get; set; }
|
|
public Dictionary<IDASCommunication, string> Addresses { get; set; }
|
|
public Dictionary<IDASCommunication, uint[]> TmNSConfigs { get; set; }
|
|
public Dictionary<IDASCommunication, uint> BaudRates { get; set; }
|
|
public Dictionary<IDASCommunication, uint> DataBits { get; set; }
|
|
public Dictionary<IDASCommunication, StopBits> StopBits { get; set; }
|
|
public Dictionary<IDASCommunication, Parity> Parities { get; set; }
|
|
public Dictionary<IDASCommunication, Handshake> FlowControls { get; set; }
|
|
public Dictionary<IDASCommunication, UartDataFormat> DataFormats { get; set; }
|
|
public Dictionary<IDASCommunication, ushort> TMATSIntervalMs { get; set; }
|
|
public uint CRC { get; set; } = 0;
|
|
public bool TurnOffAAFRealtime { get; set; } = true;
|
|
/// <summary>
|
|
/// determines whether digital outputs are configured
|
|
/// only observed when DummyConfig is true
|
|
/// </summary>
|
|
public bool ConfigureDigitalOutput { get; set; } = false;
|
|
public IStreamingFilterProfile DSPFilterType { get; set; }
|
|
public bool DiscardDiagnostics { get; set; } = true;
|
|
public SliceConfigServiceAsyncInfo(ServiceCallback callback, object userData, bool eventConfig, uint crc, bool turnOffAAFRealtime)
|
|
: base(callback, userData)
|
|
{
|
|
EventConfig = eventConfig;
|
|
CRC = crc;
|
|
TurnOffAAFRealtime = turnOffAAFRealtime;
|
|
}
|
|
}
|
|
void IConfigurationActions.Configure(ServiceCallback callback, object userData, bool EventConfig, bool DummyConfig, double [] maxAAF, bool configureDigitalOutputs, uint crc, bool turnOffAAFRealtime,
|
|
IStreamingFilterProfile dspFilterType, bool discardDiagnostics, Dictionary<IDASCommunication, ushort> timeChannelIds, Dictionary<IDASCommunication, ushort> dataChannelIds,
|
|
Dictionary<IDASCommunication, UDPStreamProfile> streamProfiles, Dictionary<IDASCommunication, int> streamADCPerPacket, Dictionary<IDASCommunication, ushort> irigTDPIntervals,
|
|
Dictionary<IDASCommunication, string> addresses, Dictionary<IDASCommunication, uint[]> tmnsConfigs,
|
|
Dictionary<IDASCommunication, uint> baudRates, Dictionary<IDASCommunication, uint> dataBits, Dictionary<IDASCommunication, StopBits> stopBits,
|
|
Dictionary<IDASCommunication, Parity> parities, Dictionary<IDASCommunication, Handshake> flowControls, Dictionary<IDASCommunication, UartDataFormat> dataFormats,
|
|
Dictionary<IDASCommunication, ushort> tmatsIntervalMs
|
|
)
|
|
{
|
|
var info = new SliceConfigServiceAsyncInfo(callback, userData, EventConfig, crc, turnOffAAFRealtime && DFConstantsAndEnums.SupportsTurnOffAAFRealtime(this));
|
|
info.DummyConfig = DummyConfig;
|
|
//FB 26736 set time & data channel Id
|
|
info.DataChannelIds = dataChannelIds;
|
|
info.TimeChannelIds = timeChannelIds;
|
|
//FB 29434 Quick Build doesn't recognize non-default values of Stream Output settings
|
|
info.StreamProfiles = streamProfiles;
|
|
info.StreamADCPerPacket = streamADCPerPacket;
|
|
info.IrigTDPIntervals = irigTDPIntervals;
|
|
info.TMATSIntervalMs = tmatsIntervalMs;
|
|
info.Addresses = addresses;
|
|
info.TmNSConfigs = tmnsConfigs;
|
|
info.ConfigureDigitalOutput = configureDigitalOutputs;
|
|
info.DSPFilterType = dspFilterType;
|
|
info.DiscardDiagnostics = discardDiagnostics;
|
|
info.BaudRates = baudRates;
|
|
info.DataBits = dataBits;
|
|
info.StopBits = stopBits;
|
|
info.Parities = parities;
|
|
info.FlowControls = flowControls;
|
|
info.DataFormats = dataFormats;
|
|
LaunchAsyncWorker("Slice.Configure", new WaitCallback(AsyncConfigure), info);
|
|
}
|
|
|
|
void IConfigurationActions.ApplyLevelTriggers(ServiceCallback callback, object userData)
|
|
{
|
|
var info = new SliceServiceAsyncInfo(callback, userData);
|
|
LaunchAsyncWorker("SLICE.ApplyLevelTriggers", AsyncApplyLevelTriggers, info);
|
|
}
|
|
private void AsyncCheckSafetyState(object configAsyncInfo)
|
|
{
|
|
var info = configAsyncInfo as CheckSafetyStateAsyncInfo;
|
|
if (IsTOM())
|
|
{
|
|
try
|
|
{
|
|
var qsi = new QuerySwitchImmediate(this);
|
|
qsi.Switch = Convert.ToByte(Switches.BaseSwitches.SquibSafeArmSwitch);
|
|
qsi.SwitchText = Switches.BaseSwitches.SquibSafeArmSwitch.ToString();
|
|
qsi.SyncExecute();
|
|
APILogger.Log("Checking SafetySwitch");
|
|
if (qsi.Setting == 0)
|
|
{
|
|
APILogger.Log("Safetyswitch is in safe");
|
|
if (info.Armed) { info.Error("SAFETYSWITCH_STATE"); }
|
|
}
|
|
else
|
|
{
|
|
APILogger.Log("Safetyswitch is in ARM");
|
|
if (!info.Armed)
|
|
{
|
|
//check squib resistance
|
|
var resistances = new MeasureSquibChannelResistances(this);
|
|
resistances.SyncExecute();
|
|
|
|
var bHaveResistance = false;
|
|
foreach (var f in resistances.MeasuredResistanceOhms)
|
|
{
|
|
if (f > 1F && f <= 8F) { bHaveResistance = true; break; }
|
|
}
|
|
if (bHaveResistance) { info.Error("SQUIB_RESISTANCE"); }
|
|
else { info.Error("SAFETYSWITCH_STATE"); }
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log("failed to get checksafetystate, ", ex);
|
|
info.Success();
|
|
}
|
|
}
|
|
info.Success();
|
|
}
|
|
|
|
protected virtual float GetLevelTriggerThreshold(AnalogInputDASChannel analog, IDiagnosticResult diagnostics, double thresholdeu, double MvPerEu)
|
|
{
|
|
var threshold = Convert.ToSingle((thresholdeu * MvPerEu
|
|
+ diagnostics.GetExpectedDataZeroLevelADC(analog.ZeroMethod) * diagnostics.ScalefactorMilliVoltsPerADC));
|
|
|
|
try
|
|
{
|
|
var now = DateTime.Now;
|
|
var s =
|
|
string.Format(
|
|
"{7} {8} - {6} : thresholdEU ({0}) * MvPerEU ({1}) + DataZeroLevelADC ({2}) * ScaleFactorMvPerADC ({3})={4}; SensitivityMv={5}\r\n",
|
|
thresholdeu,
|
|
MvPerEu,
|
|
diagnostics.GetExpectedDataZeroLevelADC(analog.ZeroMethod),
|
|
diagnostics.ScalefactorMilliVoltsPerADC,
|
|
threshold,
|
|
analog.SensitivityMilliVoltsPerEU,
|
|
analog.SerialNumber,
|
|
now.ToShortDateString(),
|
|
now.ToShortTimeString());
|
|
LevelTriggerLogging.LevelTriggerLog(s);
|
|
}
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
|
return threshold;
|
|
}
|
|
|
|
private Dictionary<DFConstantsAndEnums.ProtocolLimitedCommands, byte> SLICE1_MinimumProtocols = new Dictionary<DFConstantsAndEnums.ProtocolLimitedCommands, byte>();
|
|
|
|
public override void InitMinProto()
|
|
{
|
|
// SLICE 1.0 Protocol Limitations
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.DiangosShuntDAC, 3);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.QueryMSP430Firmware, 9);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.MultipleAndHybridEvents, 10);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.MultipleEvents, 10);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.AutoArm, 7);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.FlashCardInfo, 9);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.PhysicalStartAddress, 2);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.TestCommunication, 2);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.StackLowPowerMode, 2);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.SetRealtimeSampleRate, 4);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.EventFaultFlags, 7);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.EventArmAttempts, 12);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.QueryActualSampleRateImmediate, 6);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.InitHardwareInputLines, 8);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.VoltageSysAttributes, 9);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.LevelTrigger, 4);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.AttributeStoreBlocks, 7);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.QueryArmAndTriggerStatus_VoltageReadings, 7);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.MaxEvents, 7);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.AutoArmDiagnosticDelay, 9);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.StackChannelAutoArmDiagLevel, 11);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.FlashClear, 5);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.MultipleSamplesRealtime, 4);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.ResetAttributeStore, 9);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.IgnoreShortedStartEvent, 13);
|
|
SLICE1_MinimumProtocols.Add(DFConstantsAndEnums.ProtocolLimitedCommands.BaseCalibrationDate, 14);
|
|
MinimumProtocols = SLICE1_MinimumProtocols;
|
|
}
|
|
protected void SetPolarity()
|
|
{
|
|
//performance improvement, don't set polarity in systems that don't need to
|
|
//[reduce # of commands]
|
|
if (RunTestVariables.InRunTest && RunTestVariables.DontSetPolarityInRunTest)
|
|
{
|
|
//dont' set
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
var ssaPolarity = new SetSystemAttribute(this, AbstractCommandBase.Default_IO_Timeout);
|
|
ssaPolarity.SetValue(AttributeTypes.SystemAttributes.StartRecordPolarity,
|
|
(byte)(InvertStart ? 1 : 0), true);
|
|
ssaPolarity.SyncExecute();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log("Problem setting Start Record Polarity", ex);
|
|
}
|
|
|
|
try
|
|
{
|
|
var ssaPolarity = new SetSystemAttribute(this, AbstractCommandBase.Default_IO_Timeout);
|
|
ssaPolarity.SetValue(AttributeTypes.SystemAttributes.TriggerPolarity,
|
|
(byte)(InvertTrigger ? 1 : 0), true);
|
|
ssaPolarity.SyncExecute();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log("Problem setting trigger polarity", ex);
|
|
}
|
|
}
|
|
}
|
|
protected void SetVoltageRequirements()
|
|
{
|
|
try
|
|
{
|
|
var ssaV = new SetSystemAttribute(this, AbstractCommandBase.Default_IO_Timeout);
|
|
//input min, input max, battery min, battery max
|
|
var requirements = new float[] { InputLowVoltage, InputHighVoltage, BatteryLowVoltage, BatteryHighVoltage };
|
|
ssaV.SetValue(AttributeTypes.SystemAttributes.VoltageRequirements, requirements, true);
|
|
ssaV.SyncExecute();
|
|
}
|
|
catch (Exception ex) { APILogger.Log("Problem setting Voltage Requirements", ex); }
|
|
}
|
|
protected virtual void AsyncConfigure(object configAsyncInfo)
|
|
{
|
|
var info = configAsyncInfo as SliceConfigServiceAsyncInfo;
|
|
var progressValue = 0;
|
|
var bReleased = true;
|
|
SetVoltageRequirements();
|
|
try
|
|
{
|
|
SetPolarity();
|
|
|
|
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.IgnoreShortedStartEvent))
|
|
{
|
|
|
|
var shortedStartTrigger = new List<byte>();
|
|
shortedStartTrigger.Add(Convert.ToByte(IgnoreShortedStart)); // Start is First
|
|
shortedStartTrigger.Add(Convert.ToByte(IgnoreShortedTrigger)); // Trigger is Second
|
|
|
|
var ssaIgnoreShortedStartTrigger = new SetSystemAttribute(this, SetSystemAttribute.Default_IO_Timeout);
|
|
ssaIgnoreShortedStartTrigger.SetValue(AttributeTypes.SystemAttributes.SA_IgnoreShortedStartTrigger, shortedStartTrigger.ToArray(), true);
|
|
ssaIgnoreShortedStartTrigger.SyncExecute();
|
|
}
|
|
|
|
Lock();
|
|
bReleased = false;
|
|
// loop thru the modules (slices) and configure the channels
|
|
var numChannels = DASInfo.Modules.Sum(mod => mod.NumberOfChannels);
|
|
var rangeArray = new float[numChannels];
|
|
var bridgeModeArray = new byte[numChannels];
|
|
var BridgeResistanceArray = new ushort[numChannels];
|
|
var IsACCoupledArray = new bool[numChannels];
|
|
|
|
// level trigger values
|
|
var enableLowerLevelTriggerThreshold = new bool[numChannels];
|
|
var enableUpperLevelTriggerThreshold = new bool[numChannels];
|
|
var lowerLevelTriggerThreshold = new float[numChannels];
|
|
var upperLevelTriggerThreshold = new float[numChannels];
|
|
var qualificationSamples = new int[numChannels];
|
|
|
|
for (var moduleIdx = 0; moduleIdx < ConfigData.Modules.Length; moduleIdx++)
|
|
{
|
|
var module = ConfigData.Modules[moduleIdx];
|
|
|
|
// configure the range for this bridge
|
|
for (var channelIdx = 0; channelIdx < module.Channels.Length; channelIdx++)
|
|
{
|
|
var channel = module.Channels[channelIdx];
|
|
var dasChannelNumber = DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(moduleIdx, channelIdx);
|
|
|
|
qualificationSamples[dasChannelNumber] = channel.QualificationSamples;
|
|
|
|
if (channel.ConfigurationMode != DFConstantsAndEnums.ConfigMode.Disabled &&
|
|
(channel.ConfigurationMode == DFConstantsAndEnums.ConfigMode.Normal
|
|
|| channel.ConfigurationMode == DFConstantsAndEnums.ConfigMode.DummyArm))
|
|
{
|
|
if (!(channel is AnalogInputDASChannel analog))
|
|
{
|
|
if (!bReleased) { bReleased = true; Release(); }
|
|
|
|
// "Configure: Slice bridge modules must only contain analog input channels"
|
|
info.Error(Strings.Slice_Configure_Err1);
|
|
return;
|
|
}
|
|
switch (analog.TypeOfBridge)
|
|
{
|
|
case SensorConstants.BridgeType.FullBridge:
|
|
bridgeModeArray[dasChannelNumber] = 0;
|
|
break;
|
|
case SensorConstants.BridgeType.HalfBridge:
|
|
bridgeModeArray[dasChannelNumber] = 1;
|
|
break;
|
|
case SensorConstants.BridgeType.IEPE:
|
|
bridgeModeArray[dasChannelNumber] = 0;
|
|
break;
|
|
case SensorConstants.BridgeType.QuarterBridge:
|
|
bridgeModeArray[dasChannelNumber] = 2;
|
|
break;
|
|
case SensorConstants.BridgeType.HalfBridge_SigPlus:
|
|
bridgeModeArray[dasChannelNumber] = 3;
|
|
break;
|
|
default:
|
|
bridgeModeArray[dasChannelNumber] = 0;
|
|
break;
|
|
}
|
|
|
|
if (analog.IEPEChannel)
|
|
{
|
|
IsACCoupledArray[dasChannelNumber] = analog.CouplingMode == SensorConstants.CouplingModes.AC;
|
|
}
|
|
else { IsACCoupledArray[dasChannelNumber] = false; }
|
|
|
|
|
|
switch (analog.TypeOfBridge)
|
|
{
|
|
case SensorConstants.BridgeType.HalfBridge:
|
|
BridgeResistanceArray[dasChannelNumber] = SLICE_HALFBRIDGE_RESISTANCE;
|
|
break;
|
|
default:
|
|
BridgeResistanceArray[dasChannelNumber] = (ushort)analog.BridgeResistanceOhms;
|
|
break;
|
|
}
|
|
|
|
if (analog.SensitivityMilliVoltsPerEU != 0)
|
|
{
|
|
var MvPerEu = GetMvPerEUNormalized(analog);
|
|
|
|
var requestedRange = analog.DesiredRangeWithHeadroomEU * MvPerEu;
|
|
var nominalRanges = GetNominalRanges(analog.TypeOfBridge);
|
|
|
|
if (requestedRange > nominalRanges[0])
|
|
{
|
|
requestedRange = nominalRanges[0];
|
|
}
|
|
else if (requestedRange < nominalRanges[nominalRanges.Length - 1])
|
|
{
|
|
requestedRange = nominalRanges[nominalRanges.Length - 1];
|
|
}
|
|
rangeArray[dasChannelNumber] = (float)requestedRange;
|
|
|
|
//
|
|
// push level trigger settings out to hardware
|
|
//
|
|
if (null != analog.TriggerBelowThresholdEu)
|
|
{
|
|
//
|
|
// 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 (analog.IsInverted || analog.SensitivityMilliVoltsPerEU < 0)
|
|
{
|
|
enableUpperLevelTriggerThreshold[dasChannelNumber] = true;
|
|
try
|
|
{
|
|
var diagnostics = analog.Diagnostics;
|
|
upperLevelTriggerThreshold[dasChannelNumber] = GetLevelTriggerThreshold(analog, diagnostics, (double)analog.TriggerBelowThresholdEu, MvPerEu);
|
|
if (analog.SensitivityMilliVoltsPerEU < 0)
|
|
{
|
|
upperLevelTriggerThreshold[dasChannelNumber] = -upperLevelTriggerThreshold[dasChannelNumber];
|
|
}
|
|
}
|
|
catch (ApplicationException ex)
|
|
{
|
|
if (null != Exceptional.ExtractFirstExceptionOfTypeFromExceptionTree<NoDiagnosticsAvailable>(ex))
|
|
upperLevelTriggerThreshold[dasChannelNumber] = (float)analog.TriggerBelowThresholdEu;
|
|
else throw ex;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
enableLowerLevelTriggerThreshold[dasChannelNumber] = true;
|
|
try
|
|
{
|
|
var diagnostics = analog.Diagnostics;
|
|
lowerLevelTriggerThreshold[dasChannelNumber] = GetLevelTriggerThreshold(analog, diagnostics, (double)analog.TriggerBelowThresholdEu, MvPerEu);
|
|
}
|
|
catch (ApplicationException ex)
|
|
{
|
|
if (null != Exceptional.ExtractFirstExceptionOfTypeFromExceptionTree<NoDiagnosticsAvailable>(ex))
|
|
lowerLevelTriggerThreshold[dasChannelNumber] = (float)analog.TriggerBelowThresholdEu;
|
|
else throw ex;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (analog.IsInverted || analog.SensitivityMilliVoltsPerEU < 0)
|
|
{
|
|
upperLevelTriggerThreshold[dasChannelNumber] = 0;
|
|
enableUpperLevelTriggerThreshold[dasChannelNumber] = false;
|
|
}
|
|
else
|
|
{
|
|
lowerLevelTriggerThreshold[dasChannelNumber] = 0;
|
|
enableLowerLevelTriggerThreshold[dasChannelNumber] = false;
|
|
}
|
|
}
|
|
|
|
if (null != analog.TriggerAboveThresholdEu)
|
|
{
|
|
//
|
|
// 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 (analog.IsInverted || analog.SensitivityMilliVoltsPerEU < 0)
|
|
{
|
|
enableLowerLevelTriggerThreshold[dasChannelNumber] = true;
|
|
try
|
|
{
|
|
var diagnostics = analog.Diagnostics;
|
|
lowerLevelTriggerThreshold[dasChannelNumber] = GetLevelTriggerThreshold(analog, diagnostics, (double)analog.TriggerAboveThresholdEu, MvPerEu);
|
|
if (analog.SensitivityMilliVoltsPerEU < 0)
|
|
{
|
|
lowerLevelTriggerThreshold[dasChannelNumber] = -lowerLevelTriggerThreshold[dasChannelNumber];
|
|
}
|
|
}
|
|
catch (ApplicationException ex)
|
|
{
|
|
if (null != Exceptional.ExtractFirstExceptionOfTypeFromExceptionTree<NoDiagnosticsAvailable>(ex))
|
|
lowerLevelTriggerThreshold[dasChannelNumber] = (float)analog.TriggerAboveThresholdEu;
|
|
else throw ex;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
enableUpperLevelTriggerThreshold[dasChannelNumber] = true;
|
|
try
|
|
{
|
|
var diagnostics = analog.Diagnostics;
|
|
upperLevelTriggerThreshold[dasChannelNumber] = GetLevelTriggerThreshold(analog, diagnostics, (double)analog.TriggerAboveThresholdEu, MvPerEu);
|
|
}
|
|
catch (ApplicationException ex)
|
|
{
|
|
if (null != Exceptional.ExtractFirstExceptionOfTypeFromExceptionTree<NoDiagnosticsAvailable>(ex))
|
|
upperLevelTriggerThreshold[dasChannelNumber] = (float)analog.TriggerAboveThresholdEu;
|
|
else throw ex;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (analog.IsInverted || analog.SensitivityMilliVoltsPerEU < 0)
|
|
{
|
|
lowerLevelTriggerThreshold[dasChannelNumber] = 0;
|
|
enableLowerLevelTriggerThreshold[dasChannelNumber] = false;
|
|
}
|
|
else
|
|
{
|
|
upperLevelTriggerThreshold[dasChannelNumber] = 0;
|
|
enableUpperLevelTriggerThreshold[dasChannelNumber] = false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rangeArray[dasChannelNumber] = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rangeArray[dasChannelNumber] = 0;
|
|
bridgeModeArray[dasChannelNumber] = 0;
|
|
BridgeResistanceArray[dasChannelNumber] = 0;
|
|
|
|
enableLowerLevelTriggerThreshold[dasChannelNumber] = false;
|
|
enableUpperLevelTriggerThreshold[dasChannelNumber] = false;
|
|
lowerLevelTriggerThreshold[dasChannelNumber] = 0;
|
|
upperLevelTriggerThreshold[dasChannelNumber] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
var config = GetConfigAttributes(this);// new ConfigAttributes(this);
|
|
|
|
// only set attributes to default if we haven't run diagnostics yet
|
|
if (!DiagnosticsHasBeenRun)
|
|
{
|
|
config.PurgeStaleData(this);
|
|
}
|
|
|
|
// report progress
|
|
progressValue = 25;
|
|
info.Progress(progressValue);
|
|
|
|
// store some attributes
|
|
if (ConfigData.Modules.Length > 0)
|
|
{
|
|
config.SampleRate = ConfigData.Modules[0].SampleRateHz;
|
|
var actualSampleRate = (float)ConfigData.Modules[0].SampleRateHz;
|
|
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.QueryActualSampleRateImmediate))
|
|
{
|
|
actualSampleRate = config.ActualSampleRate;
|
|
}
|
|
|
|
config.AAFilter = ConfigData.Modules[0].AAFilterRateHz;
|
|
|
|
config.TestID = ConfigData.TestID.TrimEnd(new char[] { '\0' });
|
|
config.TestSetupUniqueId = ConfigData.TestSetupUniqueId?.TrimEnd('\0');
|
|
|
|
config.TestDescription = ConfigData.Description;
|
|
|
|
config.PreTriggerSamples = (ulong)(ConfigData.Modules[0].PreTriggerSeconds * actualSampleRate);
|
|
|
|
config.PostTriggerSamples = (ulong)(ConfigData.Modules[0].PostTriggerSeconds * actualSampleRate);
|
|
|
|
SetArmMode(ConfigData.Modules[0].RecordingMode);
|
|
|
|
config.ConfigureRange(rangeArray);
|
|
config.ConfigureBridge(bridgeModeArray);
|
|
config.ConfigureCoupling(IsACCoupledArray);
|
|
config.ConfigureBridgeResistance(BridgeResistanceArray);
|
|
progressValue = 50;
|
|
info.Progress(progressValue);
|
|
|
|
// configure level trigger enable/threshold values
|
|
ConfigureLevelTriggers(enableLowerLevelTriggerThreshold,
|
|
enableUpperLevelTriggerThreshold,
|
|
lowerLevelTriggerThreshold,
|
|
upperLevelTriggerThreshold,
|
|
qualificationSamples);
|
|
|
|
// get scale factors
|
|
var scaleFactors = config.GetScaleFactors();
|
|
|
|
if (numChannels > scaleFactors.Length)
|
|
{
|
|
if (!bReleased) { bReleased = true; Release(); }
|
|
// "ConfigurationService.Configure: Firmware returned {0} channels but stack contains {1}"
|
|
info.Error(string.Format(Strings.ConfigurationService_Configure_err1, scaleFactors.Length, numChannels));
|
|
return;
|
|
}
|
|
|
|
for (var moduleIdx = 0; moduleIdx < ConfigData.Modules.Length; moduleIdx++)
|
|
{
|
|
for (var channelIdx = 0; channelIdx < ConfigData.Modules[moduleIdx].Channels.Length; channelIdx++)
|
|
{
|
|
var analog = (AnalogInputDASChannel)ConfigData.Modules[moduleIdx].Channels[channelIdx];
|
|
var dasChannelNumber = DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(moduleIdx, channelIdx);
|
|
analog.ScalefactorMilliVoltsPerADC = scaleFactors[dasChannelNumber];
|
|
}
|
|
progressValue++;
|
|
info.Progress(Math.Min(74, progressValue));
|
|
}
|
|
}
|
|
|
|
// now store the data
|
|
var configStr = ConfigurationData.Serialize((ConfigurationData)ConfigData);
|
|
progressValue = 75;
|
|
info.Progress(progressValue);
|
|
config.StoreXMLConfig(configStr, info.EventConfig ? ConfigAttributes.FileStore.Event : ConfigAttributes.FileStore.Diagnostic);
|
|
ConfigureHasBeenRun = true;
|
|
if (info.DiscardDiagnostics) { DiagnosticsHasBeenRun = false; }
|
|
// report success'
|
|
ConfigurationData.SetConfiguration(this, configStr,
|
|
info.EventConfig
|
|
? (int)ConfigAttributes.FileStore.Event
|
|
: (int)ConfigAttributes.FileStore.Diagnostic);
|
|
if (!bReleased) { 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) { bReleased = true; Release(); } }
|
|
info.Progress(100);
|
|
}
|
|
|
|
#endregion
|
|
|
|
// FB15335: Move UART and ClockProfile sets to RunTest -> Hardware NavStep, add Reboot
|
|
void IConfigurationActions.Reboot(ServiceCallback callback, object userData)
|
|
{
|
|
var info = new SliceServiceAsyncInfo(callback, userData);
|
|
|
|
LaunchAsyncWorker("Slice.Reboot", new WaitCallback(AsyncReboot), info);
|
|
}
|
|
protected virtual void AsyncReboot(object o)
|
|
{
|
|
if (!(o is SliceServiceAsyncInfo info)) { return; }
|
|
|
|
try
|
|
{
|
|
var reboot = new Reboot(this, SetSystemAttribute.Default_IO_Timeout);
|
|
reboot.SyncExecute();
|
|
info.Success();
|
|
if (!ConnectString.ToLower().Contains("usb"))
|
|
{
|
|
//disconnect, but reuse the socket since we're expecting it back
|
|
var disconnectedEvent = new ManualResetEvent(false);
|
|
Disconnect(false, DisconnectCallback, disconnectedEvent, 60000);
|
|
disconnectedEvent.WaitOne();
|
|
}
|
|
}
|
|
catch (CanceledException ex)
|
|
{
|
|
APILogger.Log(ex);
|
|
info.Cancel();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log(ex);
|
|
info.Error(ex.Message, ex);
|
|
}
|
|
}
|
|
|
|
private bool DisconnectCallback(ICommunicationReport report)
|
|
{
|
|
(report.UserState as ManualResetEvent)?.Set();
|
|
return true;
|
|
}
|
|
|
|
protected virtual void AsyncApplyLevelTriggers(object asyncInfo)
|
|
{
|
|
if (!(asyncInfo is SliceServiceAsyncInfo info))
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
// loop thru the modules (slices) and configure the channels
|
|
var numChannels = DASInfo.Modules.Sum(mod => mod.NumberOfChannels);
|
|
// level trigger values
|
|
var enableLowerLevelTriggerThreshold = new bool[numChannels];
|
|
var enableUpperLevelTriggerThreshold = new bool[numChannels];
|
|
var lowerLevelTriggerThreshold = new float[numChannels];
|
|
var upperLevelTriggerThreshold = new float[numChannels];
|
|
var qualificationSamples = new int[numChannels];
|
|
|
|
for (var moduleIdx = 0; moduleIdx < ConfigData.Modules.Length; moduleIdx++)
|
|
{
|
|
var module = ConfigData.Modules[moduleIdx];
|
|
|
|
// configure the range for this bridge
|
|
for (var channelIdx = 0; channelIdx < module.Channels.Length; channelIdx++)
|
|
{
|
|
var channel = module.Channels[channelIdx];
|
|
var dasChannelNumber =
|
|
DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(moduleIdx, channelIdx);
|
|
|
|
qualificationSamples[dasChannelNumber] = channel.QualificationSamples;
|
|
|
|
if (channel.ConfigurationMode != DFConstantsAndEnums.ConfigMode.Disabled &&
|
|
(channel.ConfigurationMode == DFConstantsAndEnums.ConfigMode.Normal
|
|
|| channel.ConfigurationMode == DFConstantsAndEnums.ConfigMode.DummyArm))
|
|
{
|
|
if (!(channel is AnalogInputDASChannel analog)) { continue; }
|
|
if (analog.SensitivityMilliVoltsPerEU == 0) continue;
|
|
var mvPerEu = GetMvPerEUNormalized(analog);
|
|
|
|
//
|
|
// push level trigger settings out to hardware
|
|
//
|
|
if (null != analog.TriggerBelowThresholdEu)
|
|
{
|
|
//
|
|
// 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 (analog.IsInverted || analog.SensitivityMilliVoltsPerEU < 0)
|
|
{
|
|
enableUpperLevelTriggerThreshold[dasChannelNumber] = true;
|
|
try
|
|
{
|
|
var diagnostics = analog.Diagnostics;
|
|
upperLevelTriggerThreshold[dasChannelNumber] =
|
|
GetLevelTriggerThreshold(analog, diagnostics,
|
|
(double)analog.TriggerBelowThresholdEu, mvPerEu);
|
|
if (analog.SensitivityMilliVoltsPerEU < 0)
|
|
{
|
|
upperLevelTriggerThreshold[dasChannelNumber] =
|
|
-upperLevelTriggerThreshold[dasChannelNumber];
|
|
}
|
|
}
|
|
catch (ApplicationException ex)
|
|
{
|
|
if (null != Exceptional.ExtractFirstExceptionOfTypeFromExceptionTree<NoDiagnosticsAvailable>(ex))
|
|
upperLevelTriggerThreshold[dasChannelNumber] = (float)analog.TriggerBelowThresholdEu;
|
|
else throw;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
enableLowerLevelTriggerThreshold[dasChannelNumber] = true;
|
|
try
|
|
{
|
|
var diagnostics = analog.Diagnostics;
|
|
lowerLevelTriggerThreshold[dasChannelNumber] =
|
|
GetLevelTriggerThreshold(analog, diagnostics,
|
|
(double)analog.TriggerBelowThresholdEu, mvPerEu);
|
|
}
|
|
catch (ApplicationException ex)
|
|
{
|
|
if (null != Exceptional.ExtractFirstExceptionOfTypeFromExceptionTree<NoDiagnosticsAvailable>(ex))
|
|
lowerLevelTriggerThreshold[dasChannelNumber] = (float)analog.TriggerBelowThresholdEu;
|
|
else throw;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (analog.IsInverted || analog.SensitivityMilliVoltsPerEU < 0)
|
|
{
|
|
upperLevelTriggerThreshold[dasChannelNumber] = 0;
|
|
enableUpperLevelTriggerThreshold[dasChannelNumber] = false;
|
|
}
|
|
else
|
|
{
|
|
lowerLevelTriggerThreshold[dasChannelNumber] = 0;
|
|
enableLowerLevelTriggerThreshold[dasChannelNumber] = false;
|
|
}
|
|
}
|
|
if (null != analog.TriggerAboveThresholdEu)
|
|
{
|
|
//
|
|
// 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 (analog.IsInverted || analog.SensitivityMilliVoltsPerEU < 0)
|
|
{
|
|
enableLowerLevelTriggerThreshold[dasChannelNumber] = true;
|
|
try
|
|
{
|
|
var diagnostics = analog.Diagnostics;
|
|
lowerLevelTriggerThreshold[dasChannelNumber] =
|
|
GetLevelTriggerThreshold(analog, diagnostics,
|
|
(double)analog.TriggerAboveThresholdEu, mvPerEu);
|
|
if (analog.SensitivityMilliVoltsPerEU < 0)
|
|
{
|
|
lowerLevelTriggerThreshold[dasChannelNumber] =
|
|
-lowerLevelTriggerThreshold[dasChannelNumber];
|
|
}
|
|
}
|
|
catch (ApplicationException ex)
|
|
{
|
|
if (null != Exceptional.ExtractFirstExceptionOfTypeFromExceptionTree<NoDiagnosticsAvailable>(ex))
|
|
lowerLevelTriggerThreshold[dasChannelNumber] = (float)analog.TriggerAboveThresholdEu;
|
|
else throw;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
enableUpperLevelTriggerThreshold[dasChannelNumber] = true;
|
|
try
|
|
{
|
|
var diagnostics = analog.Diagnostics;
|
|
upperLevelTriggerThreshold[dasChannelNumber] =
|
|
GetLevelTriggerThreshold(analog, diagnostics,
|
|
(double)analog.TriggerAboveThresholdEu, mvPerEu);
|
|
}
|
|
catch (ApplicationException ex)
|
|
{
|
|
if (null != Exceptional.ExtractFirstExceptionOfTypeFromExceptionTree<NoDiagnosticsAvailable>(ex))
|
|
upperLevelTriggerThreshold[dasChannelNumber] = (float)analog.TriggerAboveThresholdEu;
|
|
else throw;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (analog.IsInverted || analog.SensitivityMilliVoltsPerEU < 0)
|
|
{
|
|
lowerLevelTriggerThreshold[dasChannelNumber] = 0;
|
|
enableLowerLevelTriggerThreshold[dasChannelNumber] = false;
|
|
}
|
|
else
|
|
{
|
|
upperLevelTriggerThreshold[dasChannelNumber] = 0;
|
|
enableUpperLevelTriggerThreshold[dasChannelNumber] = false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
enableLowerLevelTriggerThreshold[dasChannelNumber] = false;
|
|
enableUpperLevelTriggerThreshold[dasChannelNumber] = false;
|
|
lowerLevelTriggerThreshold[dasChannelNumber] = 0;
|
|
upperLevelTriggerThreshold[dasChannelNumber] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ConfigData.Modules.Length > 0)
|
|
{
|
|
// configure level trigger enable/threshold values
|
|
ConfigureLevelTriggers(enableLowerLevelTriggerThreshold,
|
|
enableUpperLevelTriggerThreshold,
|
|
lowerLevelTriggerThreshold,
|
|
upperLevelTriggerThreshold,
|
|
qualificationSamples);
|
|
}
|
|
info.Success();
|
|
}
|
|
catch (CanceledException ex)
|
|
{
|
|
APILogger.Log(ex);
|
|
info.Cancel();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log(ex);
|
|
info.Error(ex.Message, ex);
|
|
}
|
|
}
|
|
|
|
#region Update sensor IDs
|
|
|
|
internal class UpdateIdAsyncInfo : SliceServiceAsyncInfo
|
|
{
|
|
public DASModule Module { get; set; }
|
|
public DASChannel Channel { get; set; }
|
|
public UpdateIdAsyncInfo(ServiceCallback callback, object userData, DASModule module, DASChannel channel)
|
|
: base(callback, userData) { Module = module; Channel = channel; }
|
|
}
|
|
void IConfigurationActions.UpdateId(ServiceCallback callback, object userData, DASModule module, DASChannel channel)
|
|
{
|
|
var info = new UpdateIdAsyncInfo(callback, userData, module, channel);
|
|
LaunchAsyncWorker("Slice.UpdateId", new WaitCallback(AsyncUpdateId), info);
|
|
}
|
|
protected virtual void AsyncUpdateId(object asyncInfo)
|
|
{
|
|
UpdateIdAsyncInfo info = asyncInfo as UpdateIdAsyncInfo;
|
|
try
|
|
{
|
|
var dasChannelNumber = DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(info.Module.ModuleArrayIndex, info.Channel.ModuleChannelNumber);
|
|
info.Channel.IDs = EIDReader.RetriveEIDs(this, dasChannelNumber, info.Channel.IdType);
|
|
info.Success();
|
|
}
|
|
catch (CanceledException)
|
|
{
|
|
info.Cancel();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
info.Error(ex.Message, ex);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Retrieve the info to fill in the ConfigData property
|
|
/// </summary>
|
|
/// <param name="callback">The delegate to report to</param>
|
|
/// <param name="userData">User supplied data that we pass along</param>
|
|
void IConfigurationActions.UpdateIDs(ServiceCallback callback, object userData)
|
|
{
|
|
var info = new SliceServiceAsyncInfo(callback, userData);
|
|
|
|
LaunchAsyncWorker("Slice.UpdateIDs", new WaitCallback(AsyncUpdateIDs), info);
|
|
}
|
|
|
|
protected virtual void AsyncUpdateIDs(object configAsyncInfo)
|
|
{
|
|
var info = configAsyncInfo as SliceServiceAsyncInfo;
|
|
|
|
if (ConfigData == null)
|
|
{
|
|
info.Error("DAS doesn't have any ConfigData");
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
// get sensor ID's
|
|
if (ConfigData.Modules != null)
|
|
{
|
|
foreach (var module in ConfigData.Modules)
|
|
{
|
|
foreach (var channel in module.Channels)
|
|
{
|
|
var dasChannelNumber = DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(module.ModuleArrayIndex, channel.ModuleChannelNumber);
|
|
channel.IDs = EIDReader.RetriveEIDs(this, dasChannelNumber, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
info.Success();
|
|
}
|
|
catch (CanceledException)
|
|
{
|
|
info.Cancel();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
info.Error(ex.Message, ex);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
private void PurgeStaleData()
|
|
{
|
|
var cmd = new SetArmAttributesToDefaults(this);
|
|
cmd.SyncExecute();
|
|
}
|
|
|
|
#region Arm attribute helpers
|
|
|
|
protected void SetArmAttribute(AttributeTypes.ArmAndEventAttributes key, object value, bool ShouldOverwrite)
|
|
{
|
|
var set = new SetArmAttribute(this);
|
|
set.SetValue(key, value, ShouldOverwrite);
|
|
set.SyncExecute();
|
|
}
|
|
|
|
protected virtual void SetArmAttribute(AttributeTypes.ArmAndEventAttributes key,
|
|
DFConstantsAndEnums.RecordingMode value)
|
|
{
|
|
SetArmAttribute(key, (byte)value, true);
|
|
}
|
|
|
|
protected void SetArmAttribute(AttributeTypes.ArmAndEventAttributes key, UInt32 value)
|
|
{
|
|
SetArmAttribute(key, value, true);
|
|
}
|
|
|
|
protected void SetArmAttribute(AttributeTypes.ArmAndEventAttributes key, float value)
|
|
{
|
|
SetArmAttribute(key, value, true);
|
|
}
|
|
|
|
protected void SetArmAttribute(AttributeTypes.ArmAndEventAttributes key, string value)
|
|
{
|
|
SetArmAttribute(key, value, true);
|
|
}
|
|
|
|
protected void SetArmAttribute(AttributeTypes.ArmAndEventAttributes key, UInt64 value)
|
|
{
|
|
SetArmAttribute(key, value, true);
|
|
}
|
|
|
|
protected void GetArmAttribute(AttributeTypes.ArmAndEventAttributes key, out byte value)
|
|
{
|
|
var query = new QueryArmAttribute(this);
|
|
query.Key = key;
|
|
query.SyncExecute();
|
|
value = (byte)query.Value;
|
|
}
|
|
protected void GetArmAttribute(AttributeTypes.ArmAndEventAttributes key, out DFConstantsAndEnums.RecordingMode value)
|
|
{
|
|
var query = new QueryArmAttribute(this);
|
|
query.Key = key;
|
|
query.SyncExecute();
|
|
if (query.DataType != AttributeTypes.AttributeDataTypes.UInt8)
|
|
throw new Exception("ConfigurationService.GetArmAttribute.RecordingMode: Found type " + query.DataType);
|
|
value = (DFConstantsAndEnums.RecordingMode)query.Value;
|
|
}
|
|
|
|
protected void GetArmAttribute(AttributeTypes.ArmAndEventAttributes key, out UInt32 value)
|
|
{
|
|
var query = new QueryArmAttribute(this);
|
|
query.Key = key;
|
|
query.SyncExecute();
|
|
if (query.DataType != AttributeTypes.AttributeDataTypes.UInt32)
|
|
throw new Exception("ConfigurationService.GetArmAttribute.UInt32: Found type " + query.DataType);
|
|
value = (uint)query.Value;
|
|
}
|
|
|
|
protected void GetArmAttribute(AttributeTypes.ArmAndEventAttributes key, out float value)
|
|
{
|
|
var query = new QueryArmAttribute(this);
|
|
query.Key = key;
|
|
query.SyncExecute();
|
|
if (query.DataType != AttributeTypes.AttributeDataTypes.Float32)
|
|
throw new Exception("ConfigurationService.GetArmAttribute.float: Found type " + query.DataType);
|
|
value = (float)query.Value;
|
|
}
|
|
|
|
protected void GetArmAttribute(AttributeTypes.ArmAndEventAttributes key, out string value)
|
|
{
|
|
var query = new QueryArmAttribute(this);
|
|
query.Key = key;
|
|
query.SyncExecute();
|
|
if (query.DataType != AttributeTypes.AttributeDataTypes.Ascii)
|
|
throw new Exception("ConfigurationService.GetArmAttribute.string: Found type " + query.DataType);
|
|
value = (string)query.Value;
|
|
}
|
|
|
|
protected void GetArmAttribute(AttributeTypes.ArmAndEventAttributes key, out ulong value)
|
|
{
|
|
var query = new QueryArmAttribute(this);
|
|
query.Key = key;
|
|
query.SyncExecute();
|
|
if (query.DataType != AttributeTypes.AttributeDataTypes.UInt64)
|
|
throw new Exception("ConfigurationService.GetArmAttribute.UInt64: Found type " + query.DataType);
|
|
value = (ulong)query.Value;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region XML attributes
|
|
|
|
private void StoreAttributes(string data, SliceServiceAsyncInfo info, double ProgressSteps)
|
|
{
|
|
// first calc how many we need
|
|
var NumBlocks = data.Length / Slice.Service.Attribute.MaxSingleAttributeSize;
|
|
if ((data.Length % Slice.Service.Attribute.MaxSingleAttributeSize) != 0)
|
|
NumBlocks++;
|
|
|
|
// write the blocks
|
|
// for progress, assume that we'll have about 40 blocks to write
|
|
var blockWeight = 40.0 / NumBlocks;
|
|
for (var BlockIdx = 0; BlockIdx < NumBlocks; BlockIdx++)
|
|
{
|
|
var blockLength = data.Length - (BlockIdx * Slice.Service.Attribute.MaxSingleAttributeSize);
|
|
if (blockLength > Slice.Service.Attribute.MaxSingleAttributeSize)
|
|
blockLength = Slice.Service.Attribute.MaxSingleAttributeSize;
|
|
var block = data.Substring(BlockIdx * Slice.Service.Attribute.MaxSingleAttributeSize, blockLength);
|
|
var AttrSet = new SetArmAttribute(this);
|
|
AttrSet.SetValue((AttributeTypes.ArmAndEventAttributes)(Slice.Service.Attribute.BulkAttributeStartNumber + BlockIdx),
|
|
block, AttributeTypes.AttributeDataTypes.Ascii, true);
|
|
AttrSet.SyncExecute();
|
|
info.Progress((int)((12.0 + blockWeight * BlockIdx) / ProgressSteps * 100.0));
|
|
}
|
|
|
|
// write our speacial header attribute
|
|
var BlockList = new StringBuilder(Slice.Service.Attribute.BulkAttributeStartNumber.ToString(),
|
|
DTS.Slice.Service.Attribute.MaxSingleAttributeSize);
|
|
for (var BlockIdx = 1; BlockIdx < NumBlocks; BlockIdx++)
|
|
BlockList.Append("," + (Slice.Service.Attribute.BulkAttributeStartNumber + BlockIdx).ToString());
|
|
var HeaderAttrSet = new SetArmAttribute(this);
|
|
HeaderAttrSet.SetValue(AttributeTypes.ArmAndEventAttributes.StoredConfigIndex,
|
|
BlockList.ToString(), AttributeTypes.AttributeDataTypes.Ascii, true);
|
|
HeaderAttrSet.SyncExecute();
|
|
}
|
|
|
|
private string RetrieveAttributes()
|
|
{
|
|
// first get our special header attribute
|
|
var AttrGet = new QueryArmAttribute(this);
|
|
AttrGet.Key = AttributeTypes.ArmAndEventAttributes.StoredConfigIndex;
|
|
AttrGet.SyncExecute();
|
|
|
|
// make sure we have something
|
|
|
|
|
|
// parse the result
|
|
var BlockListStr = AttrGet.Value as string;
|
|
|
|
// still there?
|
|
if (string.IsNullOrEmpty(BlockListStr))
|
|
{
|
|
// "Slice.RetrieveAttributes: Header attribute as string is empty"
|
|
throw new Exception(Strings.Slice_RetrieveAttributes_Err2);
|
|
}
|
|
|
|
var BlockListStrArr = BlockListStr.Split(',');
|
|
var BlockList = new List<int>();
|
|
foreach (var NumStr in BlockListStrArr)
|
|
{
|
|
if (!int.TryParse(NumStr, out int Number))
|
|
{
|
|
// "Slice.RetrieveAttributes: Header attribute is invalid"
|
|
throw new Exception(Strings.Slice_RetrieveAttributes_Err3);
|
|
}
|
|
BlockList.Add(Number);
|
|
}
|
|
var AllStrings = new StringBuilder(BlockList.Count * Slice.Service.Attribute.MaxSingleAttributeSize);
|
|
foreach (int AttrNumber in BlockList)
|
|
{
|
|
AttrGet.Key = (AttributeTypes.ArmAndEventAttributes)AttrNumber;
|
|
AttrGet.SyncExecute();
|
|
var str = AttrGet.Value as string;
|
|
AllStrings.Append(str);
|
|
}
|
|
var WholeStr = AllStrings.ToString();
|
|
if (string.IsNullOrEmpty(WholeStr))
|
|
{
|
|
// "Slice.RetrieveAttributes: Attributes are empty"
|
|
throw new Exception(Strings.Slice_RetrieveAttributes_Err4);
|
|
}
|
|
return WholeStr;
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Send all level trigger related setup information to the hardware associated with this
|
|
/// service invocation.
|
|
/// </summary>
|
|
///
|
|
/// <param name="enableLowerTrigger">
|
|
/// An array of <see cref="bool"/>s indicating whether or not the index-associated channel
|
|
/// has "level trigger below..." functionality enabled.
|
|
/// </param>
|
|
///
|
|
/// <param name="enableUpperTrigger">
|
|
/// An array of <see cref="bool"/>s indicating whether or not the index-associated channel
|
|
/// has "level trigger above..." functionality enabled.
|
|
/// </param>
|
|
///
|
|
/// <param name="lowerTriggerThreshold">
|
|
/// An array of <see cref="UInt16"/>s indicating the lower level trigger threshold for the
|
|
/// index-associated channel.
|
|
/// </param>
|
|
///
|
|
/// <param name="upperTriggerThreshold">
|
|
/// An array of <see cref="UInt16"/>s indicating the upper level trigger threshold for the
|
|
/// index-associated channel.
|
|
/// </param>
|
|
///
|
|
protected virtual void ConfigureLevelTriggers(bool[] enableLowerTrigger,
|
|
bool[] enableUpperTrigger,
|
|
float[] lowerTriggerThreshold,
|
|
float[] upperTriggerThreshold,
|
|
int[] qualificationSamples)
|
|
{
|
|
try
|
|
{
|
|
#if LEVEL_TRIGGER_DEFINED
|
|
// CGO
|
|
// This is a hacked change for now to support 00G8 and prior firmware
|
|
// in the 1.04 release of SLICEWare. This and the other CGO commented
|
|
// block of code need more general cleanup before 1.05.
|
|
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.LevelTrigger))
|
|
{
|
|
var set = new SetArmAttribute(this);
|
|
set.SetValue(AttributeTypes.ArmAndEventAttributes.LevelTriggerChannelLessThanEnabled, enableLowerTrigger, true);
|
|
set.SyncExecute();
|
|
|
|
set = new SetArmAttribute(this);
|
|
set.SetValue(AttributeTypes.ArmAndEventAttributes.LevelTriggerChannelGreaterThanEnabled, enableUpperTrigger, true);
|
|
set.SyncExecute();
|
|
|
|
set = new SetArmAttribute(this);
|
|
set.SetValue(AttributeTypes.ArmAndEventAttributes.LevelTriggerLessThanLimit, lowerTriggerThreshold, true);
|
|
set.SyncExecute();
|
|
|
|
set = new SetArmAttribute(this);
|
|
set.SetValue(AttributeTypes.ArmAndEventAttributes.LevelTriggerGreaterThanLimit, upperTriggerThreshold, true);
|
|
set.SyncExecute();
|
|
|
|
SetLevelTriggerQualificationSamples(qualificationSamples);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
catch (Exception ex)
|
|
{
|
|
throw new ApplicationException("encountered problem configuring level triggers", ex);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the number of "level triggered" samples required for a level trigger to be declared by the DAS.
|
|
/// </summary>
|
|
///
|
|
/// <param name="numberOfSamples">
|
|
/// The <see cref="int"/> number of contiguous "level triggered" samples required for a level trigger event.
|
|
/// </param>
|
|
///
|
|
protected void SetLevelTriggerQualificationSamples(int[] numberOfSamples)
|
|
{
|
|
try
|
|
{
|
|
var set = new SetArmAttribute(this);
|
|
set.SetValue(AttributeTypes.ArmAndEventAttributes.LevelTriggerQualificationSamples, numberOfSamples, true);
|
|
set.SyncExecute();
|
|
}
|
|
|
|
catch (Exception ex)
|
|
{
|
|
throw new ApplicationException("encountered problem setting number of level trigger qualification samples in hardware", ex);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the number of "level triggered" samples required for a level trigger to be declared by the DAS.
|
|
/// </summary>
|
|
///
|
|
/// <returns>
|
|
/// The <see cref="int"/> number of contiguous "level triggered" samples required for a level trigger event.
|
|
/// </returns>
|
|
///
|
|
private int[] GetLevelTriggerQualificationSamples()
|
|
{
|
|
try
|
|
{
|
|
var query = new QueryArmAttribute(this);
|
|
query.Key = AttributeTypes.ArmAndEventAttributes.LevelTriggerQualificationSamples;
|
|
query.SyncExecute();
|
|
return (int[])query.Value;
|
|
}
|
|
|
|
catch (Exception ex)
|
|
{
|
|
throw new ApplicationException("encountered problem getting number of level trigger qualification samples from hardware", ex);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get determination from hardware whether or not the associated DAS has directly experienced a level trigger event.
|
|
/// </summary>
|
|
///
|
|
/// <returns>
|
|
/// <see cref="bool"/> True if the associated DAS has experienced a level trigger event; False otherwise.
|
|
/// </returns>
|
|
///
|
|
private bool[] GetLevelTriggerSeen()
|
|
{
|
|
try
|
|
{
|
|
var query = new QueryArmAttribute(this);
|
|
query.Key = AttributeTypes.ArmAndEventAttributes.LevelTriggerSeen;
|
|
query.SyncExecute();
|
|
return (bool[])query.Value;
|
|
}
|
|
|
|
catch (Exception ex)
|
|
{
|
|
throw new ApplicationException("encountered problem getting \"level trigger seen\" condition from hardware", ex);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get number of samples that the associated hardware adjusted its level trigger time value from the time it
|
|
/// actually issued a trigger fault. This adjustment is necessary because several contiguous level-triggered
|
|
/// samples are necessary before some flavors of DAS will declare an actual level trigger. Once the hardware has
|
|
/// determined that a trigger has occured, it must "backdate" the T0 to match the time of the first
|
|
/// level-triggered sample. This number only exists for hardware that has directly experienced a level trigger
|
|
/// condition.
|
|
/// </summary>
|
|
///
|
|
/// <returns>
|
|
/// The number of samples that this DAS' trigger time value has been adjusted to compensate for time required
|
|
/// by the hardware for level trigger evaluation. If the associated hardware did not directly experience the
|
|
/// level trigger, this value will be null.
|
|
/// </returns>
|
|
///
|
|
private int?[] GetLevelTriggerT0AdjustmentSamples()
|
|
{
|
|
try
|
|
{
|
|
var armLevTrigT0AdjSamp = new QueryArmAttribute(this);
|
|
armLevTrigT0AdjSamp.Key = AttributeTypes.ArmAndEventAttributes.LevelTriggerT0AdjustmentSamples;
|
|
armLevTrigT0AdjSamp.SyncExecute();
|
|
var levelTriggerAdjSamples = (int?[])(armLevTrigT0AdjSamp.Value);
|
|
|
|
var levelTriggerSeen = GetLevelTriggerSeen();
|
|
|
|
var finalAdjustment = new int?[levelTriggerAdjSamples.Length];
|
|
|
|
for (var channel = 0; channel < finalAdjustment.Length; channel++)
|
|
{
|
|
finalAdjustment[channel] = levelTriggerSeen[channel] ? levelTriggerAdjSamples[channel] : null;
|
|
}
|
|
|
|
return finalAdjustment;
|
|
}
|
|
|
|
catch (Exception ex)
|
|
{
|
|
throw new ApplicationException("encountered problem getting number of level trigger T0 adjustment samples from hardware", ex);
|
|
}
|
|
}
|
|
|
|
///<DesignNote topic="Level Trigger Configuration" author="PKXH">
|
|
/// I'm not sure what the design philosophy is behind this object, and whether or not everything should
|
|
/// happen through method invocation and not property access. I was thinking about main the "level trigger
|
|
/// t0 adustment samples" concept something that was a property at the highest level, and then adding some
|
|
/// automatic "get level trigger seen" guarding inside of that, but now I notice that this object seemed to
|
|
/// have been designed with no properties... only pairs of what amount to "set" and "get" methods. I'm not
|
|
/// sure whether or not that was a conscious decision, but I'm reluctant to do something different.
|
|
///
|
|
/// Also, I'm wondering if such low-level checking using "GetLevelTriggerSeen" is such a good idea since
|
|
/// depending on what happens at a higher level, that transaction may be issued multiple times, since it's not
|
|
/// unreasonable for a user of this service to want to explicitly check whether or not get level trigger was
|
|
/// seen by a module before querying it for it's level trigger t0 adjustment samples. In that case, the
|
|
/// transaction will happen twice every time. On the other hand, if we don't explicitly check, the "get
|
|
/// level trigger t0 adjustment samples" method will regularly throw an exception in response and I'm not sure
|
|
/// that's a good design decision either. Of course that access method could be designed to return a nullable
|
|
/// int... maybe that's the way to go.
|
|
///
|
|
/// I would like to keep the application of the zero-shift within this object, if possible. I need to check,
|
|
/// but if the DAS zeroes are read out also through this object, then it should be possible to apply the
|
|
/// correction internally to each DAS zero, so it can be read by the download code as-is.
|
|
///
|
|
/// Looks like it's the DAS module object that serves up the trigger sample number array that should probably
|
|
/// be changed to internally apply the change... however that could be a problem because I think at some point
|
|
/// the application wants to grab that value and change it, and if the module object doesn't realize that the
|
|
/// modified number incorporates the off-DAS level trigger correction, it could end up re-applying it.
|
|
///
|
|
/// After talking to Chuck, he has reminded me that the trigger sample number isn't rewritten unless there is
|
|
/// no trigger, so this conflict should be entirely avoidable. So maybe we can handle it all inside the module
|
|
/// representation after all. In this case, I think the class we need to target is DTS.DASLib.Service.DASModule.
|
|
/// </DesignNote>
|
|
|
|
private void ConfigureRange(float[] ranges)
|
|
{
|
|
// this function shall just set the range attribute for channel
|
|
var set = new SetArmAttribute(this);
|
|
set.SetValue(AttributeTypes.ArmAndEventAttributes.StackChannelRangesMillivolts, ranges, true);
|
|
set.SyncExecute();
|
|
}
|
|
|
|
//private void ConfigureBridge(bool[] IsHalfBridgeArray)
|
|
private void ConfigureBridge(byte[] bridgeModeArray)
|
|
{
|
|
// we need to construct a byte array, true==1, false==0
|
|
var set = new SetArmAttribute(this);
|
|
set.SetValue(AttributeTypes.ArmAndEventAttributes.StackChannelBridgeCompletionEnable, bridgeModeArray, true);
|
|
set.SyncExecute();
|
|
}
|
|
|
|
private void ConfigureBridgeResistance(UInt16[] BridgeResistanceArray)
|
|
{
|
|
// this function shall just set the bridge resistance for the channels
|
|
var set = new SetArmAttribute(this);
|
|
set.SetValue(AttributeTypes.ArmAndEventAttributes.StackChannelBridgeResistanceOhms, BridgeResistanceArray, true);
|
|
set.SyncExecute();
|
|
}
|
|
|
|
/// <summary>
|
|
/// A representation of all the level trigger information on a module.
|
|
/// </summary>
|
|
private class LevelTriggers
|
|
{
|
|
/// <summary>
|
|
/// An array of <see cref="bool"/>s indicating whether or not the index-associated
|
|
/// channel has "trigger below" functionality enabled.
|
|
/// </summary>
|
|
public bool[] EnableLowerTriggerThreshold { get; set; }
|
|
|
|
/// <summary>
|
|
/// An array of <see cref="bool"/>s indicating whether or not the index-associated
|
|
/// channel has "trigger above" functionality enabled.
|
|
/// </summary>
|
|
public bool[] EnableUpperTriggerThreshold { get; set; }
|
|
|
|
/// <summary>
|
|
/// An array of <see cref="float"/>s representing the "trigger below" threshold
|
|
/// for the index-associated channel.
|
|
/// </summary>
|
|
public float[] LowerTriggerThreshold { get; set; }
|
|
|
|
/// <summary>
|
|
/// An array of <see cref="float"/>s representing the "trigger above" threshold
|
|
/// for the index-associated channel.
|
|
/// </summary>
|
|
public float[] UpperTriggerThreshold { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the level trigger settings from the hardware associated with this object.
|
|
/// </summary>
|
|
///
|
|
/// <returns>
|
|
/// A LevelTriggers object containing the level trigger settings for this object.
|
|
/// </returns>
|
|
///
|
|
private LevelTriggers GetLevelTriggers()
|
|
{
|
|
try
|
|
{
|
|
var levelTriggers = new LevelTriggers();
|
|
|
|
QueryArmAttribute query;
|
|
|
|
// CGO
|
|
// This is a hacked change for now to support 00G8 and prior firmware
|
|
// in the 1.04 release of SLICEWare. This and the other CGO commented
|
|
// block of code need more general cleanup before 1.05.
|
|
// CPB
|
|
// We're on 1.8 now... so... glad this is still hacked?
|
|
if (IsCommandSupported(DFConstantsAndEnums.ProtocolLimitedCommands.LevelTrigger))
|
|
{
|
|
query = new QueryArmAttribute(this);
|
|
query.Key = AttributeTypes.ArmAndEventAttributes.LevelTriggerChannelLessThanEnabled;
|
|
query.SyncExecute();
|
|
levelTriggers.EnableLowerTriggerThreshold = query.Value as bool[];
|
|
|
|
query = new QueryArmAttribute(this);
|
|
query.Key = AttributeTypes.ArmAndEventAttributes.LevelTriggerChannelGreaterThanEnabled;
|
|
query.SyncExecute();
|
|
levelTriggers.EnableUpperTriggerThreshold = query.Value as bool[];
|
|
|
|
query = new QueryArmAttribute(this);
|
|
query.Key = AttributeTypes.ArmAndEventAttributes.LevelTriggerLessThanLimit;
|
|
query.SyncExecute();
|
|
levelTriggers.LowerTriggerThreshold = query.Value as float[];
|
|
|
|
query = new QueryArmAttribute(this);
|
|
query.Key = AttributeTypes.ArmAndEventAttributes.LevelTriggerGreaterThanLimit;
|
|
query.SyncExecute();
|
|
levelTriggers.UpperTriggerThreshold = query.Value as float[];
|
|
}
|
|
else
|
|
{
|
|
levelTriggers.EnableLowerTriggerThreshold = null;
|
|
levelTriggers.EnableUpperTriggerThreshold = null;
|
|
levelTriggers.LowerTriggerThreshold = null;
|
|
levelTriggers.UpperTriggerThreshold = null;
|
|
}
|
|
|
|
return levelTriggers;
|
|
}
|
|
|
|
catch (Exception ex)
|
|
{
|
|
throw new ApplicationException("encountered problem getting level triggers", ex);
|
|
}
|
|
}
|
|
|
|
protected float[] GetScaleFactors()
|
|
{
|
|
// this function shall just set the range attribute for channel
|
|
var query = new QueryArmAttribute(this);
|
|
query.Key = AttributeTypes.ArmAndEventAttributes.StackChannelScaleFactorsMillivoltsPerADC;
|
|
query.SyncExecute();
|
|
return query.Value as float[];
|
|
}
|
|
|
|
#region Attributes
|
|
|
|
private UInt32 SampleRate
|
|
{
|
|
get
|
|
{
|
|
GetArmAttribute(AttributeTypes.ArmAndEventAttributes.SampleRate, out uint Value);
|
|
return Value;
|
|
}
|
|
set => SetArmAttribute(AttributeTypes.ArmAndEventAttributes.SampleRate, value);
|
|
}
|
|
|
|
private float AAFilter
|
|
{
|
|
get
|
|
{
|
|
GetArmAttribute(AttributeTypes.ArmAndEventAttributes.AAFilterFrequency, out float Value);
|
|
return Value;
|
|
}
|
|
set => SetArmAttribute(AttributeTypes.ArmAndEventAttributes.AAFilterFrequency, value);
|
|
}
|
|
|
|
protected string TestID
|
|
{
|
|
get
|
|
{
|
|
GetArmAttribute(AttributeTypes.ArmAndEventAttributes.Name, out string Value);
|
|
try
|
|
{
|
|
Value = ConfigData.TestID;
|
|
}
|
|
catch (Exception) { }
|
|
return Value;
|
|
}
|
|
set
|
|
{
|
|
SetArmAttribute(AttributeTypes.ArmAndEventAttributes.Name, value);
|
|
try
|
|
{
|
|
ConfigData.TestID = value;
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
}
|
|
|
|
protected string TestDescription
|
|
{
|
|
get
|
|
{
|
|
GetArmAttribute(AttributeTypes.ArmAndEventAttributes.Description, out string Value);
|
|
try
|
|
{
|
|
Value = ConfigData.Description;
|
|
}
|
|
catch (Exception) { }
|
|
return Value;
|
|
}
|
|
set
|
|
{
|
|
if (string.IsNullOrEmpty(value)) { value = " "; }
|
|
SetArmAttribute(AttributeTypes.ArmAndEventAttributes.Description, value);
|
|
try
|
|
{
|
|
ConfigData.Description = value;
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
}
|
|
|
|
private UInt64 PreTriggerSamples
|
|
{
|
|
get
|
|
{
|
|
GetArmAttribute(AttributeTypes.ArmAndEventAttributes.PreTriggerSamplesRequested, out ulong Value);
|
|
return Value;
|
|
}
|
|
set => SetArmAttribute(AttributeTypes.ArmAndEventAttributes.PreTriggerSamplesRequested, value);
|
|
}
|
|
|
|
private ulong PostTriggerSamples
|
|
{
|
|
get
|
|
{
|
|
GetArmAttribute(AttributeTypes.ArmAndEventAttributes.PostTriggerSamplesRequested, out ulong Value);
|
|
return Value;
|
|
}
|
|
set => SetArmAttribute(AttributeTypes.ArmAndEventAttributes.PostTriggerSamplesRequested, value);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|