Files
DP44/DataPRO/IService/Classes/SLICEService/SLICE Service.Configuration.cs
2026-04-17 14:55:32 -04:00

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
}
}