Files
DP44/Common/DTS.Common.DataModel/.svn/pristine/a4/a494e7672ef001eeddf0b32fc8b9b988276e9d3f.svn-base
2026-04-17 14:55:32 -04:00

1502 lines
66 KiB
Plaintext

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using DataPROWin7.Common;
using DataPROWin7.DataModel.Classes.Hardware;
using DTS.Common.SharedResource.Strings;
using DTS.Common.Base;
using DTS.Common.DAS.Concepts;
using DTS.Common.Enums;
using DTS.Common.Enums.Hardware;
using DTS.Common.Enums.Sensors;
using DTS.Common.Interface.DASFactory;
using DTS.Common.Interface.Channels;
using DTS.Common.Interface.DataRecorders;
using DTS.Common.Interface.DASFactory.Diagnostics;
using DTS.Common.Interface.Sensors;
using DTS.Common.Utilities.Logging;
using DTS.DASLib.Service;
using DTS.SensorDB;
using DTS.Common.DataModel;
using DTS.Common.Interface.Sensors.AnalogDiagnostics;
// ReSharper disable ParameterTypeCanBeEnumerable.Local
// ReSharper disable UnusedVariable
// ReSharper disable RedundantDefaultMemberInitializer
// ReSharper disable InconsistentNaming
// ReSharper disable CheckNamespace
namespace DataPROWin7.DataModel
{
public class HardwareChannel : BasePropertyChanged, IComparable<HardwareChannel>, IHardwareChannel
{
private readonly DTS.Common.ISO.HardwareChannel _isoChannel;
public DTS.Common.ISO.HardwareChannel GetISOChannel() { return _isoChannel; }
/// <inheritdoc />
/// <summary>
/// gets the DAS this channel belongs to
/// </summary>
/// <returns></returns>
public IDASHardware GetParentDAS()
{
return Hardware;
}
public bool IsG5()
{
return ModuleSerialNumber.StartsWith("5M");
}
public string ModuleSerialNumber
{
get => null != _isoChannel ? _isoChannel.ModuleSerialNumber : "";
set
{
if (null == _isoChannel) { return; }
_isoChannel.ModuleSerialNumber = value; OnPropertyChanged("ModuleSerialNumber");
}
}
public bool DisplayModuleSerialNumber => Hardware.CareAboutModules;
private DiagnosticStatus _diagnosticStatus = DiagnosticStatus.Untested;
public DiagnosticStatus DiagnosticStatus
{
get => _diagnosticStatus;
set
{
if (DiagnosticStatus.Untested == value)
{
_diagnostics = null;
AutoZeroPercentDeviationStatus = DiagnosticStatus.Untested;
ActualRangeStatus = DiagnosticStatus.Untested;
OffsetStatus = DiagnosticStatus.Untested;
OffsetEUStatus = DiagnosticStatus.Untested;
ShuntStatus = DiagnosticStatus.Untested;
NoiseStatus = DiagnosticStatus.Untested;
ExcitationStatus = DiagnosticStatus.Untested;
_24VPowerStatus = DiagnosticStatus.Untested;
CalSignalStatus = DiagnosticStatus.Untested;
GainStatus = DiagnosticStatus.Untested;
}
SetProperty(ref _diagnosticStatus, value, "DiagnosticStatus");
}
}
public int CompareTo(HardwareChannel right)
{
if (this == right) { return 0; }
if (null == right) { return 0; }
var order = GetISOChannel().DASDisplayOrder.CompareTo(right.GetISOChannel().DASDisplayOrder);
return 0 != order ? order : GetISOChannel().ChannelIdx.CompareTo(right.GetISOChannel().ChannelIdx);
}
#region Properties
/// <inheritdoc />
/// <summary>
/// returns true if the channel supports analog sensors
/// </summary>
public bool IsAnalog => IsSupportedBridgeType(SensorConstants.BridgeType.FullBridge);
/// <inheritdoc />
/// <summary>
/// returns true if the channel supports squibs
/// </summary>
public bool IsSquib => IsSupportedBridgeType(SensorConstants.BridgeType.SQUIB);
/// <inheritdoc />
/// <summary>
/// returns true if the channel supports digital outputs
/// </summary>
public bool IsDigitalOut => IsSupportedBridgeType(SensorConstants.BridgeType.TOMDigital);
/// <inheritdoc />
/// <summary>
/// returns true if the channel supports digital inputs
/// </summary>
public bool IsDigitalIn => IsSupportedBridgeType(SensorConstants.BridgeType.DigitalInput);
/// <inheritdoc />
/// <summary>
/// returns true if the channel supports clocks
/// </summary>
public bool IsClock => IsSupportedBridgeType(SensorConstants.BridgeType.RTC);
/// <inheritdoc />
/// <summary>
/// returns true if the channel supports uart i/o
/// </summary>
public bool IsUart => IsSupportedBridgeType(SensorConstants.BridgeType.UART);
/// <inheritdoc />
/// <summary>
/// returns true if the channel supports stream output
/// </summary>
public bool IsStreamOut => IsSupportedBridgeType(SensorConstants.BridgeType.StreamOut);
/// <inheritdoc />
/// <summary>
/// returns true if the channel supports stream input
/// </summary>
public bool IsStreamIn => IsSupportedBridgeType(SensorConstants.BridgeType.StreamIn);
/// <summary>
/// Returns true if the channel supports a thermocoupler
/// </summary>
public bool IsThermocoupler => IsSupportedBridgeType(SensorConstants.BridgeType.Thermocoupler);
public bool IsTSRAIR
{
get
{
return Hardware.DASTypeEnum == HardwareTypes.DKR ||
Hardware.DASTypeEnum == HardwareTypes.DIR ||
Hardware.DASTypeEnum == HardwareTypes.TSR_AIR ||
Hardware.DASTypeEnum == HardwareTypes.TSR_AIR_RevB;
}
}
public bool IsTSRAIRModule
{
get
{
return Hardware.DASTypeEnum == HardwareTypes.EMB_ANG_ACC ||
Hardware.DASTypeEnum == HardwareTypes.EMB_ANG_ARS ||
Hardware.DASTypeEnum == HardwareTypes.EMB_ATM ||
Hardware.DASTypeEnum == HardwareTypes.EMB_LIN_ACC_HI ||
Hardware.DASTypeEnum == HardwareTypes.EMB_LIN_ACC_LO ||
Hardware.DASTypeEnum == HardwareTypes.EMB_MAG ||
Hardware.DASTypeEnum == HardwareTypes.EMB_MAG_SWITCH ||
Hardware.DASTypeEnum == HardwareTypes.EMB_MIC ||
Hardware.DASTypeEnum == HardwareTypes.EMB_OPT ||
Hardware.DASTypeEnum == HardwareTypes.EMB_RTC_S_MARK ||
Hardware.DASTypeEnum == HardwareTypes.EMB_RTC_NS_PAD;
;
}
}
private bool _excludedFromTSRAIR = false;
public bool IsExcludedFromTSRAIR
{
get => _excludedFromTSRAIR;
set => SetProperty(ref _excludedFromTSRAIR, value, "IsExcludedFromTSRAIR");
}
/// <summary>
/// Returns true if the DAS is a SLICE6 AIR-TC
/// </summary>
public bool IsSLICETC
{
get
{
return Hardware.DASTypeEnum == HardwareTypes.SLICE6_AIR_TC;
}
}
private DiagnosticStatus _offsetStatus = DiagnosticStatus.Untested;
public DiagnosticStatus OffsetStatus
{
get => _offsetStatus;
set => SetProperty(ref _offsetStatus, value, "OffsetStatus");
}
private DiagnosticStatus _offsetEUStatus = DiagnosticStatus.Untested;
/// <summary>
/// the current status of the Initial Offset in EU
/// </summary>
public DiagnosticStatus OffsetEUStatus
{
get => _offsetEUStatus;
set => SetProperty(ref _offsetEUStatus, value, "OffsetEUStatus");
}
private DiagnosticStatus _autoZeroPercentDeviationStatus = DiagnosticStatus.Untested;
public DiagnosticStatus AutoZeroPercentDeviationStatus
{
get => _autoZeroPercentDeviationStatus;
set => SetProperty(ref _autoZeroPercentDeviationStatus, value, "AutoZeroPercentDeviationStatus");
}
private DiagnosticStatus __24VPowerStatus = DiagnosticStatus.Untested;
public DiagnosticStatus _24VPowerStatus
{
get => __24VPowerStatus;
set => SetProperty(ref __24VPowerStatus, value, "_24VPowerStatus");
}
private DiagnosticStatus _excitationStatus = DiagnosticStatus.Untested;
public DiagnosticStatus ExcitationStatus
{
get => _excitationStatus;
set => SetProperty(ref _excitationStatus, value, "ExcitationStatus");
}
private DiagnosticStatus _calSignalStatus = DiagnosticStatus.Untested;
public DiagnosticStatus CalSignalStatus
{
get => _calSignalStatus;
set => SetProperty(ref _calSignalStatus, value, "CalSignalStatus");
}
private DiagnosticStatus _shuntStatus = DiagnosticStatus.Untested;
public DiagnosticStatus ShuntStatus
{
get => _shuntStatus;
set => SetProperty(ref _shuntStatus, value, "ShuntStatus");
}
private DiagnosticStatus _delayStatus = DiagnosticStatus.Untested;
public DiagnosticStatus DelayStatus
{
get => _delayStatus;
set => SetProperty(ref _delayStatus, value, "DelayStatus");
}
private DiagnosticStatus _durationStatus = DiagnosticStatus.Untested;
public DiagnosticStatus DurationStatus
{
get => _durationStatus;
set => SetProperty(ref _durationStatus, value, "DurationStatus");
}
private DiagnosticStatus _actualRangeStatus = DiagnosticStatus.Untested;
public DiagnosticStatus ActualRangeStatus
{
get => _actualRangeStatus;
set => SetProperty(ref _actualRangeStatus, value, "ActualRangeStatus");
}
private DiagnosticStatus _gainStatus = DiagnosticStatus.Untested;
public DiagnosticStatus GainStatus
{
get => _gainStatus;
set => SetProperty(ref _gainStatus, value, "GainStatus");
}
private DiagnosticStatus _noiseStatus = DiagnosticStatus.Untested;
public DiagnosticStatus NoiseStatus
{
get => _noiseStatus;
set => SetProperty(ref _noiseStatus, value, "NoiseStatus");
}
#endregion Properties
/// <summary>
/// returns the high/low acceptable values for 24V
/// </summary>
/// <param name="bHigh"></param>
/// <returns></returns>
public double Get24VPowerValue(bool bHigh)
{
return bHigh ? SerializedSettings._24VPowerHigh : SerializedSettings._24VPowerLow;
}
/// <summary>
/// 14233 Negative Excitation Reported by TDAS hardware not showing in Diagnostics
/// returns the threshold according to allowed excitation error percent
/// </summary>
/// <param name="bHigh">whether to return low or high threshold</param>
/// <returns></returns>
public double GetExcitationPercent(bool bHigh)
{
return DataModelSettings.AllowedExcitationErrorPercent * (bHigh ? 1D : -1D);
}
/// <summary>
/// returns excitation in mV
/// </summary>
/// <returns></returns>
public double GetMeasuredExcitationMV()
{
if (null == _diagnostics) { return double.NaN; }
if (null == _diagnostics.MeasuredExcitationMilliVolts) { return double.NaN; }
return (double)_diagnostics.MeasuredExcitationMilliVolts;
}
/// <summary>
/// 14233 Negative Excitation Reported by TDAS hardware not showing in Diagnostics
/// returns the measured excitation as calculated by MeasX -ExpX/ ExpX
/// </summary>
/// <returns></returns>
public double GetExcitationPercentValue()
{
if (null == _diagnostics) { return double.NaN; }
if (null == _diagnostics.MeasuredExcitationMilliVolts) { return double.NaN; }
var exc = (double)_diagnostics.MeasuredExcitationMilliVolts;
//since measured is absolute, we check if we read a negative when it was read
//and reapply it here
//14233 Negative Excitation Reported by TDAS hardware not showing in Diagnostics
if (_diagnostics.NegativeExcitation)
{
exc *= -1D;
}
return 100D * (exc - _diagnostics.ExpectedExcitationMilliVolts) /
_diagnostics.ExpectedExcitationMilliVolts;
}
public double GetAllowedExcitationValue(bool bHigh)
{
if (null == _diagnostics) { return double.NaN; }
return bHigh
? (1.0D + DataModelSettings.AllowedExcitationErrorPercent / 100.0D) *
_diagnostics.ExpectedExcitationMilliVolts
: (1.0D - DataModelSettings.AllowedExcitationErrorPercent / 100.0D) *
_diagnostics.ExpectedExcitationMilliVolts;
}
/// <summary>
/// indicates eu is inverted, this is needed to calculate from mv to eu or vice versa
/// </summary>
private bool InvertEU
{
get => DataModel.HardwareChannel.IsInvertedEU(Sensor, Sensor.Calibration);
}
/// <summary>
/// retrieves the tolerance value (high/low, mv/EU)
/// </summary>
public double GetOffsetToleranceValue(bool bHigh, bool bEU)
{
if (bEU)
{
if (InvertEU)
{
bHigh = !bHigh;
}
if (null == Sensor.Calibration)
{
return 0D;
}
if (!Sensor.Calibration.NonLinear || Sensor.Calibration.LinearAdded)
{
var mV = bHigh ? Sensor.OffsetToleranceHigh : Sensor.OffsetToleranceLow;
var scaler = GetDataScaler(Sensor, Sensor.Calibration, true, true, this, GroupChannel);
return scaler.GetEUFromMv(mV);
}
else
{
//for now non linear is just expressed as eu
return bHigh ? Sensor.OffsetToleranceHigh : Sensor.OffsetToleranceLow;
}
}
else { return bHigh ? Sensor.OffsetToleranceHigh : Sensor.OffsetToleranceLow; }
}
public double GetAutoZeroPercentDeviationValue()
{
if (_diagnostics?.AutoZeroPercentDeviation == null) { return double.NaN; }
return (double)_diagnostics.AutoZeroPercentDeviation;
}
public double GetAllowedVoltageInsertionError(bool bHigh)
{
return bHigh
? DataModelSettings.AllowedVoltageInsertionErrorPercent
: -1D * DataModelSettings.AllowedVoltageInsertionErrorPercent;
}
public double GetDelayMS()
{
if (_diagnostics?.MeasuredDelayMS == null) { return double.NaN; }
return (double)_diagnostics.MeasuredDelayMS;
}
public double GetDurationMS()
{
if (_diagnostics?.MeasuredDurationMS == null) { return double.NaN; }
return (double)_diagnostics.MeasuredDurationMS;
}
public double GetBridgeResistance()
{
if (_diagnostics?.BridgeResistance == null) { return double.NaN; }
return (double)_diagnostics.BridgeResistance;
}
public double[] GetCurrentData()
{
return null == _diagnostics ? new double[0] : _diagnostics.SquibFireCurrentData;
}
public double[] GetVoltageData()
{
return null == _diagnostics ? new double[0] : _diagnostics.SquibFireVoltageData;
}
public double GetMeasuredExcitation()
{
if (_diagnostics?.MeasuredExcitationMilliVolts == null) { return double.NaN; }
return (double)_diagnostics.MeasuredExcitationMilliVolts;
}
/// <summary>
/// 14233 Negative Excitation Reported by TDAS hardware not showing in Diagnostics
/// this returns true if measured excitation was negative when it was read
/// it seems only TDAS code is currently absoluting excitation though
/// </summary>
/// <returns></returns>
public bool HasNegativeExcitationReading()
{
return _diagnostics?.NegativeExcitation ?? false;
}
public double GetInitialOffset(bool bEU)
{
if (null == _diagnostics) { return double.NaN; }
if (_diagnostics.MeasuredOffsetMilliVolts == null && _diagnostics.MeasuredOffsetEngineeringUnits == null) { return double.NaN; }
if (null == _diagnostics.MeasuredInternalOffsetMilliVolts || double.IsNaN((double)_diagnostics.MeasuredInternalOffsetMilliVolts))
{
return bEU ? GetEU((double)_diagnostics.MeasuredOffsetMilliVolts) : (double)_diagnostics.MeasuredOffsetMilliVolts;
}
if (null != _diagnostics.MeasuredOffsetEngineeringUnits) { return (double)_diagnostics.MeasuredOffsetEngineeringUnits; }
var mv = (double)_diagnostics.MeasuredOffsetMilliVolts - (double)_diagnostics.MeasuredInternalOffsetMilliVolts;
return bEU ? GetEU(mv) : mv;
}
/// <summary>
/// retrieves EU for a given mV
/// </summary>
private double GetEU(double mV)
{
if (null == Sensor.Calibration)
{
return 0D;
}
var scaler = GetDataScaler(Sensor, Sensor.Calibration, true, true, this, GroupChannel);
return scaler.GetEUFromMv(mV);
}
public double GetFinalOffset()
{
if (_diagnostics?.FinalOffsetADC == null) { return double.NaN; }
return (double)(_diagnostics.FinalOffsetADC - _diagnostics.ZeroMVInADC) * _diagnostics.ScalefactorMilliVoltsPerADC;
}
#region Static things to abstract out to common area?
/// <summary>
/// returns the first valid sensitivity according to proportionality and supported excitations
/// returns 1 if no valid excitations are found and sensor is proportional...
/// </summary>
/// <param name="sc"></param>
/// <param name="useAddedLinear"></param>
/// <returns></returns>
public static double GetSensitivity(ISensorBase sensorBase, ISensorCalibration sc, bool useAddedLinear = false, IHardwareChannel hardwareChannel = null)
{
var records = DataModel.HardwareChannel.GetCalibrationRecords(sc, useAddedLinear);
if (!sc.IsProportional) { return records[0].Sensitivity; }
foreach (var se in sensorBase.SupportedExcitation)
{
if (null != hardwareChannel)
{
if (!hardwareChannel.IsSupportedExcitation(se)) { continue; }
}
foreach (var record in records)
{
if (record.Excitation == se)
{
return record.Sensitivity;
}
}
}
//no valid excitation found, we could throw an exception, lets just return 1 for now
return 1;
}
/// <summary>
/// returns the calibration records given a sensor calibration
/// optionally strips off the non linear cal if requested for dual linear/non linear sensors
/// </summary>
/// <param name="sc"></param>
/// <param name="useAddedLinear"></param>
/// <returns></returns>
public static ICalibrationRecord[] GetCalibrationRecords(ISensorCalibration sc, bool useAddedLinear)
{
return sc.LinearAdded && useAddedLinear
? sc.Records.Records.Skip(1).ToArray()
: sc.Records.Records;
}
/// <summary>
/// returns whether eu is inverted given a sensor and a calibration
/// [temporary place for this]
/// @TODO abstract out
/// </summary>
/// <param name="sensorBase"></param>
/// <param name="sc"></param>
/// <returns></returns>
public static bool IsInvertedEU(ISensorBase sensorBase, ISensorCalibration sc)
{
if (null == sensorBase)
{
return false;
}
var invert = sensorBase.Invert;
var sens = GetSensitivity(sensorBase, sc, true);
if (sens < 0)
{
invert = !invert;
}
return invert;
}
/// <summary>
/// returns a data scaler for the current hardware channel
/// </summary>
/// <param name="useAddedLinear"></param>
/// <param name="clearEUAdjustmentParams">whether to clear user and diagnostic set parameters like
/// FinalOffsetADC, UserOffset, user set InitialOffset, etc, parameters which affect EU
/// values. This allows a consumer to get an EU value without consideration of adjustments
/// this is used to get an offset in EU without being padded
/// </param>
/// <returns></returns>
public static DataScaler GetDataScaler(ISensorBase sensor,
ISensorCalibration sc,
bool useAddedLinear = false,
bool clearEUAdjustmentParams = false,
IHardwareChannel hardwareChannel = null,
IGroupChannel groupChannel = null)
{
var ds = new DataScaler();
var records = GetCalibrationRecords(sc, useAddedLinear);
if (sc.NonLinear && !(sc.LinearAdded && useAddedLinear)) //18276 don't set a linearization formula if the cal we want to use is the linear of a dual-cal
{
ds.SetLinearizationFormula(records[0].Poly);
}
if (null != hardwareChannel && null != hardwareChannel.Diagnostics)
{
//hardware with diagnostics stuff
if (sc != null && (sc.LinearAdded && useAddedLinear ? sc.ZeroMethods.Methods[sc.ZeroMethods.Methods.Length - 1] : sc.ZeroMethods.Methods[0]).Method == ZeroMethodType.None)
{
//if ZeroMethod is "None" don't apply ANY zeroing
ds.SetDataZeroLevelADC(0);
}
else
{
if (null == hardwareChannel.Diagnostics.FinalOffsetADC)
{
ds.SetDataZeroLevelADC(hardwareChannel.Diagnostics.ZeroMVInADC);
}
else
{
ds.SetDataZeroLevelADC((short)hardwareChannel.Diagnostics.FinalOffsetADC);
}
}
if (null != hardwareChannel.Diagnostics.RemovedOffsetADC)
{
ds.SetRemovedADC((int)hardwareChannel.Diagnostics.RemovedOffsetADC);
}
if (null != hardwareChannel.Diagnostics.RemovedInternalOffsetADC)
{
ds.SetRemovedInternalADC((int)hardwareChannel.Diagnostics.RemovedInternalOffsetADC);
}
if (hardwareChannel.IsTSRAIR)
{
// EU only
ds.SetScaleFactorEU(hardwareChannel.Diagnostics.ScalefactorEngineeringUnitsPerADC);
ds.SetUseEUScaleFactors(true); // i.e. use EU rather than Mv
}
else
{
ds.SetScaleFactorMv(hardwareChannel.Diagnostics.ScalefactorMilliVoltsPerADC);
ds.SetZeroMvInADC(hardwareChannel.Diagnostics.ZeroMVInADC);
}
ds.MeasuredExcitationVoltage = null == hardwareChannel.Diagnostics.MeasuredExcitationMilliVolts ? 0D : (double)hardwareChannel.Diagnostics.MeasuredExcitationMilliVolts / 1000D;
ds.FactoryExcitationVoltage = hardwareChannel.Diagnostics.ExpectedExcitationMilliVolts / 1000D;
}
else
{
//no hardware channel specific stuff
if (sc.IsProportional)
{
bool bFound = false;
foreach (var se in sensor.SupportedExcitation)
{
if (bFound) { break; }
if (null != hardwareChannel && !hardwareChannel.IsSupportedExcitation(se)) { continue; }
foreach (var record in records)
{
if (record.Excitation == se)
{
ds.FactoryExcitationVoltage = Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(se);
ds.MeasuredExcitationVoltage = ds.FactoryExcitationVoltage;
bFound = true;
break;
}
}
}
if (!bFound)
{
ds.FactoryExcitationVoltage = 5D; //couldn't find a valid excitation, throw exception?
ds.MeasuredExcitationVoltage = 5D;
}
}
}
//common initialization stuff
var zeromethod = sc.LinearAdded && useAddedLinear
? sc.ZeroMethods.Methods[sc.ZeroMethods.Methods.Length - 1]
: sc.ZeroMethods.Methods[0];
var initialoffset = sc.InitialOffsets.DefaultOffset;
if (null != groupChannel)
{
initialoffset = groupChannel.InitialOffset;
}
ds.ZeroMethodType = zeromethod.Method;
ds.UnitConversion = MeasurementUnitList.GetMeasurementUnit(records[0].EngineeringUnits).GetScalerConversion(sensor.DisplayUnit);
ds.SensitivityUnits = records[0].SensitivityUnits;
ds.SetInitialOffset(initialoffset);
ds.SetMvPerEu(GetSensitivity(sensor, sc, useAddedLinear));
//data scaler needs to get inverted or not only from polarity as negative sensitivity
//shows up through scale factor
ds.IsInverted = sensor.Invert;
ds.ProportionalToExcitation = sc.IsProportional;
ds.BasedOnOutputAtCapacity = records[0].AtCapacity;
ds.CapacityOutputIsBasedOn = records[0].CapacityOutputIsBasedOn;
ds.SensitivityUnits = records[0].SensitivityUnits;
ds.IEPE = sensor.Bridge == SensorConstants.BridgeType.IEPE;
ds.Digital = sensor.IsDigitalInput();
ds.DigitalOutput = sensor.IsDigitalOutput();
if (sensor is SensorData sd)
{
ds.DigitalMode = sd.InputMode;
ds.SetDigitalMultiplier(sd.ScaleMultiplier);
}
if (clearEUAdjustmentParams)
{
ds.SetInitialOffset(new DTS.Common.Classes.Sensors.InitialOffset(0));
ds.UserOffsetEU = 0D;
ds.SetDataZeroLevelADC(0);
}
return ds;
}
#endregion
public double GetCapacityOutputIsBasedOn(ISensorCalibration sc)
{
return sc.Records.Records[0].AtCapacity ? sc.Records.Records[0].CapacityOutputIsBasedOn : 1.0;
}
/// <summary>
/// returns preferred excitation given hardware channel and sensor
/// </summary>
/// <param name="sc"></param>
/// <returns></returns>
public double GetExcitation(ISensorCalibration sc)
{
var preferredExcitation = ExcitationVoltageOptions.ExcitationVoltageOption.Undefined;
foreach (var se in Sensor.SupportedExcitation)
{
if (!IsSupportedExcitation(se)) continue;
preferredExcitation = se;
break;
}
if (preferredExcitation == ExcitationVoltageOptions.ExcitationVoltageOption.Undefined)
{
throw new NotSupportedException(string.Format(StringResources.HardwareChannel_SensorVoltageNotSupported, GetId(), ChannelName, Sensor.SerialNumber));
}
return Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(preferredExcitation);
}
public double GetNoisePercentage()
{
if (_diagnostics?.NoisePercentFullScale == null) { return double.NaN; }
return (double)_diagnostics.NoisePercentFullScale;
}
public double GetDesiredRange()
{
return Sensor?.Capacity ?? 0;
}
public double GetActualRangeEu(bool useLinearAdded = false)
{
if (null == Sensor) return 0;
if (_diagnostics?.ScalefactorMilliVoltsPerADC == null && _diagnostics?.ScalefactorEngineeringUnitsPerADC == null) { return double.NaN; }
SensorCalibration sc = null;
foreach (var se in Sensor.SupportedExcitation)
{
if (!IsSupportedExcitation(se)) continue;
sc = SensorCalibration.GetLatestCalibrationBySerialNumberAndExcitation(Sensor, se);
if (null != sc) { break; }
}
if (null == sc) { throw new NotSupportedException(string.Format(StringResources.HardwareChannel_CalibrationNotFound, GetId(), Sensor.SerialNumber, ChannelName)); }
var uniPolarMultiplier = Sensor.UniPolar ? 2D : 1D;
//14055 Range failure in diagnostics when using a dual-sensitivity sensor
// non linear sensors just return capacity
if (sc.LinearAdded)
{
if (useLinearAdded)
{
if (sc.IsProportional && sc.Records.Records.Last().SensitivityUnits != SensorConstants.SensUnits.mVperEU)
{
var dSens = GetSensitivity(Sensor, sc, useLinearAdded, this);
var dExc = GetExcitation(sc);
var dEU = GetCapacityOutputIsBasedOn(sc);
return Math.Abs(ActualRangeMv / (dSens * dExc / dEU)) * uniPolarMultiplier;
}
else
{
return (ActualRangeMv / Math.Abs(GetSensitivity(Sensor, sc, useLinearAdded, this) / GetCapacityOutputIsBasedOn(sc))) *
uniPolarMultiplier;
}
}
else { return Sensor.Capacity; }
}
if (sc.IsProportional && sc.Records.Records[0].SensitivityUnits != SensorConstants.SensUnits.mVperEU)
{
var dSens = GetSensitivity(Sensor, sc, useLinearAdded, this);
var dExc = GetExcitation(sc);
var dEU = GetCapacityOutputIsBasedOn(sc);
return Math.Abs(ActualRangeMv / (dSens * dExc / dEU)) * uniPolarMultiplier;
}
if (sc.NonLinear)
{
return Sensor.Capacity;
}
if (IsTSRAIR && null != _diagnostics?.ScalefactorEngineeringUnitsPerADC)
{
//we're an embedded analog sensor: just multiply scale * maxvalue similar to Mv
var scalefactor = _diagnostics.ScalefactorEngineeringUnitsPerADC;
return Math.Abs(scalefactor * short.MaxValue);
}
return (ActualRangeMv / Math.Abs(GetSensitivity(Sensor, sc, useLinearAdded, this) / GetCapacityOutputIsBasedOn(sc))) * uniPolarMultiplier;
}
public double ActualRangeMv
{
get
{
try
{
if (null != _diagnostics)
{
var scalefactor = _diagnostics.ScalefactorMilliVoltsPerADC;
return Math.Abs(scalefactor * short.MaxValue);
}
}
catch (Exception ex) { APILogger.Log(ex); }
return 2400D;
}
}
/// <summary>
/// returns the High/Low thresholds for gain based on measured gain
/// and allowed gain percent error
/// </summary>
public double GetGainThreshold(bool low)
{
if (_diagnostics?.TargetGain == null)
{
return double.NaN;
}
return (double)_diagnostics?.TargetGain * (100D + GetAllowedGainPercentError(low)) / 100D;
}
/// <summary>
/// returns the actual measured gain
/// <summary>
public double GetGainValue()
{
if (_diagnostics?.MeasuredGain == null)
{
return double.NaN;
}
return (double)_diagnostics.MeasuredGain;
}
public double GetGainPercentError()
{
if (_diagnostics?.MeasuredGain == null || null == _diagnostics.TargetGain) { return double.NaN; }
return (double)(100D * (_diagnostics.MeasuredGain - _diagnostics.TargetGain) / _diagnostics.TargetGain);
}
public double GetAllowedGainPercentError(bool bHigh)
{
var gainThreshold = DataModelSettings.AllowedGainErrorPercent;
// https://dtsweb.zendesk.com/agent/tickets/7982
// http://manuscript.dts.local/f/cases/16473
// Add additional AllowedGainErrorPercent for SLICE6 SLICE6A to system settings at 5%
if (Hardware.IsSLICE6OrSLICE6A)
{
gainThreshold = DataModelSettings.AllowedGainErrorPercent_SLICE6andSLICE6A;
}
return bHigh ? gainThreshold : -1D * gainThreshold;
}
public double GetAllowedNoisePercentError(bool bHigh)
{
var percent = SerializedSettings.AllowedNoisePercentage;
return bHigh ? percent : -1D * percent;
}
public double GetAllowedShuntPercentError(bool bHigh)
{
if (null == _diagnostics) { return double.NaN; }
return bHigh ? DataModelSettings.AllowedShuntErrorPercent : -1 * DataModelSettings.AllowedShuntErrorPercent;
}
public double GetAllowedShuntHighOhmPercentError(bool bHigh)
{
//FB 28086 Read high ohm allowed shunt percent error
if (null == _diagnostics) { return double.NaN; }
return bHigh ? DataModelSettings.ShuntToleranceHighOhmPercent : -1 * DataModelSettings.ShuntToleranceHighOhmPercent;
}
public double GetShuntPercentError()
{
if (_diagnostics?.TargetShuntDeflectionMv == null || null == _diagnostics.MeasuredShuntDeflectionMv) { return double.NaN; }
return (double)(100D * (_diagnostics.MeasuredShuntDeflectionMv - _diagnostics.TargetShuntDeflectionMv) / _diagnostics.TargetShuntDeflectionMv);
}
public string GetOverallStatus()
{
switch (DiagnosticStatus)
{
case DiagnosticStatus.Failed: return "Fail";
case DiagnosticStatus.Passed: return "Pass";
default: return "---";
}
}
public IDiagnosticResult _diagnostics = null;
public IDiagnosticResult Diagnostics { get => _diagnostics; }
public void UpdateDiagnostics(IDiagnosticResult squibChannelDiagnostics, bool bPostTest)
{
if (bPostTest) { DiagnosticStatus = DiagnosticStatus.Untested; return; }
_diagnostics = squibChannelDiagnostics;
if (null == _diagnostics) { DiagnosticStatus = DiagnosticStatus.Untested; }
else if (null != _diagnostics.SquibFirePassed)
{
if (null != _diagnostics.SquibDelayPassed)
{
DelayStatus = (bool)_diagnostics.SquibDelayPassed ? DiagnosticStatus.Passed : DiagnosticStatus.Failed;
}
else
{
DelayStatus = DiagnosticStatus.Untested;
}
if (null != _diagnostics.SquibDurationPassed)
{
DurationStatus = ((bool)_diagnostics.SquibDurationPassed) ? DiagnosticStatus.Passed : DiagnosticStatus.Failed;
}
else { DurationStatus = DiagnosticStatus.Untested; }
DiagnosticStatus = ((bool)_diagnostics.SquibFirePassed) ? DiagnosticStatus.Passed : DiagnosticStatus.Failed;
}
else
{
DelayStatus = DiagnosticStatus.Failed;
DurationStatus = DiagnosticStatus.Failed;
DiagnosticStatus = DiagnosticStatus.Failed;
}
}
public void UpdateDiagnostics(OutputTOMDigitalChannel channel)
{
DiagnosticStatus = DiagnosticStatus.Passed;
}
public void UpdateDiagnostics(IDiagnosticResult result)
{
try
{
_diagnostics = result;
if (null == result && null != Sensor)
{
OffsetStatus = DiagnosticStatus.Untested;
OffsetEUStatus = DiagnosticStatus.Untested;
ExcitationStatus = DiagnosticStatus.Untested;
__24VPowerStatus = DiagnosticStatus.Untested;
}
else if (null != Sensor)
{
var bPassed = true;
if (result?.MeasuredOffsetMilliVolts != null && Sensor.CheckOffset)
{
var mV = GetInitialOffset(false);
//we only want to set EU status if display offset eu is true (and it has a linear cal, etc)
//otherwise show and calculate mV
var setEUStatus = SerializedSettings.DisplayEUOffset && null != Sensor.Calibration && (!Sensor.Calibration.NonLinear || Sensor.Calibration.LinearAdded);
if (!setEUStatus)
{
if (mV > Sensor.OffsetToleranceHigh)
{
bPassed = false;
OffsetStatus = DiagnosticStatus.Failed;
}
else if (mV < Sensor.OffsetToleranceLow)
{
bPassed = false;
OffsetStatus = DiagnosticStatus.Failed;
}
else
{
OffsetStatus = DiagnosticStatus.Passed;
}
}
else
{
OffsetStatus = DiagnosticStatus.Untested;
}
if (setEUStatus)
{
var eu = GetEU(mV);
var euLow = GetOffsetToleranceValue(false, true);
var euHigh = GetOffsetToleranceValue(true, true);
if (eu < euLow || eu > euHigh)
{
bPassed = false;
OffsetEUStatus = DiagnosticStatus.Failed;
}
else
{
OffsetEUStatus = DiagnosticStatus.Passed;
}
}
else
{
OffsetEUStatus = DiagnosticStatus.Untested;
}
}
else if (result?.MeasuredOffsetEngineeringUnits != null && Sensor.CheckOffset)
{
// TODO: REMOVE THIS HACK when offset tolerance of embedded sensors figured out
var eu = GetInitialOffset(true);
var euLow = short.MinValue;
var euHigh = short.MaxValue;
if (eu < euLow || eu > euHigh)
{
bPassed = false;
OffsetEUStatus = DiagnosticStatus.Failed;
}
else
{
OffsetEUStatus = DiagnosticStatus.Passed;
}
}
else
{
OffsetStatus = DiagnosticStatus.Untested;
}
if (result?.MeasuredExcitationMilliVolts != null)
{
if (Sensor.IsDigitalInput())
{
//12476 SLICE PRO DIM failed diagnostics in Run Test tile
//Excitation is not valid on SLICE PRO DIM (I'm guessing also TDAS?)
ExcitationStatus = DiagnosticStatus.Untested;
_24VPowerStatus = DiagnosticStatus.Untested;
}
else
{
if (Sensor.Bridge == SensorConstants.BridgeType.IEPE)
{
var eV = (double)result.MeasuredExcitationMilliVolts / 1000D;
if (eV < Get24VPowerValue(false) || eV > Get24VPowerValue(true))
{
bPassed = false;
_24VPowerStatus = DiagnosticStatus.Failed;
}
else
{
_24VPowerStatus = DiagnosticStatus.Passed;
}
}
else
{
var eV = (double)result.MeasuredExcitationMilliVolts;
if (eV < GetAllowedExcitationValue(false) || eV > GetAllowedExcitationValue(true))
{
bPassed = false;
ExcitationStatus = DiagnosticStatus.Failed;
}
else
{
if (result.NegativeExcitation)
{
ExcitationStatus = DiagnosticStatus.Failed;
bPassed = false;
}
else
{
ExcitationStatus = DiagnosticStatus.Passed;
}
}
}
}
}
if (result?.FinalOffsetADC != null)
{
SensorCalibration sc2 = null;
foreach (var se in Sensor.SupportedExcitation)
{
if (!IsSupportedExcitation(se)) continue;
sc2 = SensorCalibration.GetLatestCalibrationBySerialNumberAndExcitation(Sensor, se);
if (null != sc2) { break; }
}
if (null != sc2 && sc2.RemoveOffset)
{
var finalOffsetADC = (short)result.FinalOffsetADC;
var percent = Math.Abs(100D * finalOffsetADC * result.ScalefactorMilliVoltsPerADC / ActualRangeMv);
if (DataModelSettings.AutoZeroPercentDeviationAllowed <= GetAutoZeroPercentDeviationValue())
{
AutoZeroPercentDeviationStatus = DiagnosticStatus.Failed;
bPassed = false;
}
else { AutoZeroPercentDeviationStatus = DiagnosticStatus.Passed; }
}
else { AutoZeroPercentDeviationStatus = DiagnosticStatus.Untested; }
}
else { AutoZeroPercentDeviationStatus = DiagnosticStatus.Untested; }
if (result?.MeasuredCalSignalMv != null && null != result.TargetCalSignalMv)
{
var mVActual = (double)result.MeasuredCalSignalMv;
var mVExpected = (double)result.TargetCalSignalMv;
var percent = Math.Abs((mVActual - mVExpected) / mVExpected * 100.0D);
if (percent > GetAllowedVoltageInsertionError(true))
{
CalSignalStatus = DiagnosticStatus.Failed;
bPassed = false;
}
else
{
CalSignalStatus = DiagnosticStatus.Passed;
}
}
else { CalSignalStatus = DiagnosticStatus.Untested; }
if (result?.MeasuredShuntDeflectionMv != null && null != result.TargetShuntDeflectionMv)
{
//FB 28086 Adjust shunt tolerance for high ohm sensors
var sensorResistance = Sensor.BridgeResistance;
var allowedShuntPercentError = sensorResistance > DataModelSettings.ShuntToleranceHighOhmResistance ? GetAllowedShuntHighOhmPercentError(true) : GetAllowedShuntPercentError(true);
var actualShuntPercentError = Math.Abs(GetShuntPercentError());
if (actualShuntPercentError > allowedShuntPercentError)
{
bPassed = false;
ShuntStatus = DiagnosticStatus.Failed;
}
else
{
ShuntStatus = DiagnosticStatus.Passed;
}
}
else { ShuntStatus = DiagnosticStatus.Untested; }
if (result?.SquibDurationPassed != null)
{
DurationStatus = ((bool)result.SquibDurationPassed) ? DiagnosticStatus.Passed : DiagnosticStatus.Failed;
}
if (result?.SquibDelayPassed != null)
{
DelayStatus = ((bool)result.SquibDelayPassed) ? DiagnosticStatus.Passed : DiagnosticStatus.Failed;
}
if (result?.MeasuredGain != null && null != result.TargetGain)
{
if (Math.Abs(GetGainPercentError()) > GetAllowedGainPercentError(true))
{
bPassed = false;
GainStatus = DiagnosticStatus.Failed;
}
else { GainStatus = DiagnosticStatus.Passed; }
}
else
{
GainStatus = DiagnosticStatus.Untested;
}
if (result != null)
{
var actualRangemV = result.ScalefactorMilliVoltsPerADC * short.MaxValue;
}
foreach (var se in Sensor.SupportedExcitation)
{
if (!IsSupportedExcitation(se)) continue;
var sc = SensorCalibration.GetLatestCalibrationBySerialNumberAndExcitation(Sensor, se);
if (null != sc) { break; }
}
//14055 Range failure in diagnostics when using a dual-sensitivity sensor
// actual range can be complicated as there could be both a non linear and a linear actual range for the channel
var actualRangeEu = GetActualRangeEu();
if (false == Sensor.IsDigitalInput()) // 7113 - Diagnostics failed on Slice PRO DIM
{
if (Sensor.Bridge == SensorConstants.BridgeType.IEPE)
{
var low = SerializedSettings.IEPERangeLowLimitScalar * Sensor.Capacity;
var high = SerializedSettings.IEPERangeHighLimitScalar * Sensor.Capacity;
if (actualRangeEu < low || actualRangeEu > high)
{
ActualRangeStatus = DiagnosticStatus.Failed;
bPassed = false;
}
else
{
ActualRangeStatus = DiagnosticStatus.Passed;
}
}
else if (false == Sensor.IsTestSpecificEmbedded)
{
if (actualRangeEu < (Sensor.Capacity * SerializedSettings.ActualRangeLowerLimit) ||
actualRangeEu > (Sensor.Capacity * SerializedSettings.ActualRangeUpperLimit * SerializedSettings.DesiredRangeOverheadPercent))
{
ActualRangeStatus = DiagnosticStatus.Failed;
bPassed = false;
}
else
{
ActualRangeStatus = DiagnosticStatus.Passed;
}
}
}
else
{
//10342 Diagnostic results not consistent with TDC for TDAS DIM channels.
//9912 Fix for diagnostics using digital inputs on a TDAS G5.
switch (Hardware.GetHardwareTypeEnum())
{
case HardwareTypes.TDAS_Pro_Rack:
case HardwareTypes.G5VDS:
case HardwareTypes.TDAS_LabRack:
bPassed = true;
break;
default:
if (result != null && result.DigitalInputActiveState)
{
bPassed = false;
}
break;
}
}
if (null != result.NoisePercentFullScale)
{
if (Math.Abs((double)result.NoisePercentFullScale) > GetAllowedNoisePercentError(true))
{
bPassed = false;
NoiseStatus = DiagnosticStatus.Failed;
}
else { NoiseStatus = DiagnosticStatus.Passed; }
}
DiagnosticStatus = bPassed ? DiagnosticStatus.Passed : DiagnosticStatus.Failed;
}
else { DiagnosticStatus = DiagnosticStatus.Passed; }
}
catch (Exception ex)
{
APILogger.Log("failed to updatediagnostics ", ex);
DiagnosticStatus = DiagnosticStatus.Failed;
}
}
public override string ToString()
{
var parent = GetParentDAS();
if (null != parent)
{
return ToString(new[] { parent });
}
return ToString(null);
}
public string ToString(IDASHardware[] hardwares)
{
if (null == GetISOChannel())
{
return string.Empty; // should never get here
}
var index = GetISOChannel().DASDisplayOrder;
if (index < 0)
{
index = ChannelNumber;
}
if (null != Hardware && Hardware.IsModule() && Hardware.IsPseudoRackModule())
{
var channelRepresentation = new ChannelRepresentation(this, 1 + index, hardwares);
if (!DataModelSettings.ShowCompactHardware)
{
return Hardware.IsTSRAIR() ?
$"{channelRepresentation.SerialNumber} {channelRepresentation.ChannelNumberString}" :
$"[{Hardware.SerialNumber}] {channelRepresentation.ChannelNumberString}";
}
return $"[{Hardware}] {channelRepresentation.ChannelNumberString}";
}
else
{
var channelRepresentation = new ChannelRepresentation(this, 1 + index, hardwares);
if (null == Hardware)
return $"[{channelRepresentation.SerialNumber}] {channelRepresentation.ChannelNumberString}";
if (Hardware.CareAboutModules)
{
if (Hardware.IsTSRAIR())
{
return $"{channelRepresentation.SerialNumber} {channelRepresentation.ChannelNumberString}";
}
else
{
return $"[{channelRepresentation.DASSerialNumber}:{channelRepresentation.SerialNumber}] {channelRepresentation.ChannelNumberString}";
}
}
//16083 DAS channel # not incremented correctly for generic DAS
//return a special formatted string if standin
if (Hardware.GetHardware().StandIn)
{
return GetStandInToString(channelRepresentation);
}
return $"[{channelRepresentation.SerialNumber}] {channelRepresentation.ChannelNumberString}";
}
}
/// <summary>
/// gets a formatted string for the channel for stand in hardware
/// this is specific to stacks and labeling them channels 1-n ... for now
/// 16083 DAS channel # not incremented correctly for generic DAS
/// </summary>
/// <param name="ch"></param>
/// <returns></returns>
private string GetStandInToString(ChannelRepresentation ch)
{
switch (Hardware.GetHardwareTypeEnum())
{
case HardwareTypes.SLICE1_5_Micro_Base:
case HardwareTypes.SLICE1_5_Nano_Base:
case HardwareTypes.SLICE_Base:
case HardwareTypes.SLICE_NANO_Base:
case HardwareTypes.SLICE_Micro_Base:
return $"[{ch.SerialNumber}] {1 + ChannelNumber}";
case HardwareTypes.TDAS_Pro_Rack:
case HardwareTypes.TDAS_LabRack:
return $"[{ch.DASSerialNumber}:{ch.SerialNumber}] {ch.ChannelNumberString}";
}
return $"[{ch.SerialNumber}] {ch.ChannelNumberString}";
}
public string GetId()
{
return $"{Hardware.GetHardware().GetId()}x{1 + ChannelNumber}";
}
public string GetIdSimple(DASHardware[] hardwares = null)
{
var index = GetISOChannel().DASDisplayOrder;
if (index < 0) { index = ChannelNumber; }
var channelRepresentation = new ChannelRepresentation(this, 1 + index, hardwares);
if (null != Hardware && Hardware.IsModule() && Hardware.IsPseudoRackModule())
{
return $"[{Hardware}] {channelRepresentation.ChannelNumberString}";
}
return $"[{channelRepresentation.SerialNumber}] {channelRepresentation.ChannelNumberString}";
}
public static string GetId(IDASCommunication das, DASChannel channel)
{
var h = DASHardwareList.GetList().GetHardware(das.SerialNumber, ((ICommunication)das).ConnectString) ?? new DASHardware(das);
return $"{h.GetHardware().GetId()}x{1 + channel.Number}";
}
public static string GetId(DASHardware hardware, DASChannel channel)
{
return $"{hardware.GetHardware().GetId()}x{1 + channel.Number}";
}
public static ChannelRepresentation GetIdSimple(IDASCommunication das, DASChannel channel)
{
var h = DASHardwareList.GetList().GetHardware(das.SerialNumber, ((ICommunication)das).ConnectString) ?? new DASHardware(das);
var channelRepresentation = new ChannelRepresentation(h, channel, 1 + channel.Number);
return channelRepresentation;
}
public static ChannelRepresentation GetIdSimple(IDASCommunication das, DASChannel channel, int channelNumber)
{
var h = DASHardwareList.GetList().GetHardware(das.SerialNumber, ((ICommunication)das).ConnectString) ?? new DASHardware(das);
ChannelRepresentation channelRepresentation;
if (h.DASTypeEnum == HardwareTypes.SLICE1_G5Stack)
{
channelNumber = channel.AbsoluteDisplayOrder;
if (channel is AnalogInputDASChannel)
{
var channelOrder = das.GetChannelDisplayOrder();
channelNumber = channelOrder[channel.Number];
}
channelRepresentation = new ChannelRepresentation(h, channel, 1 + channelNumber);
}
else
{
channelRepresentation = new ChannelRepresentation(h, channel, channelNumber);
}
return channelRepresentation;
}
//private TestObjectChannel _testObjectChannel;
//public TestObjectChannel TestObjectChannel
//{
// get => _testObjectChannel;
// set { SetProperty(ref _testObjectChannel, value, "TestObjectChannel"); OnPropertyChanged("ChannelName"); }
//}
private IGroupChannel _channel;
public IGroupChannel GroupChannel
{
get => _channel;
set
{
SetProperty(ref _channel, value, "GroupChannel");
OnPropertyChanged("ChannelName");
}
}
public string IsoChannelName => null == GroupChannel ? "N/A" : GroupChannel.IsoChannelName;
public string UserCode => null == GroupChannel ? "N/A" : GroupChannel.UserCode;
public string UserChannelName => null == GroupChannel ? "N/A" : GroupChannel.UserChannelName;
public string ChannelName => null == GroupChannel ? "N/A" : GroupChannel.GetChannelName(SerializedSettings.ISOViewMode);
public string DisplayName => null == GroupChannel ? "N/A" : GroupChannel.GetChannelName(SerializedSettings.ISOViewMode);
public Visibility UnassignVisibility => null == _sensor ? Visibility.Collapsed : Visibility.Visible;
public HardwareChannel(HardwareChannel copy)
{
ChannelNumber = copy.ChannelNumber;
if (null != copy.Sensor) { _sensor = new SensorData(copy._sensor); }
_channel = copy._channel;
Hardware = copy.Hardware;
_isoChannel = copy._isoChannel;
}
public HardwareChannel(DTS.Common.ISO.HardwareChannel channel, DASHardware hardware)
{
ChannelNumber = channel.ChannelIdx;
Hardware = hardware;
_isoChannel = channel;
}
public int ModuleArrayIndex
{
get => _isoChannel.ModuleArrayIndex;
set => _isoChannel.ModuleArrayIndex = value;
}
public DASHardware Hardware { get; }
public HardwareChannel(int channelNumber, DASHardware hardware, List<SensorConstants.BridgeType> supportedBridges,
List<ExcitationVoltageOptions.ExcitationVoltageOption> supportedExcitation, int displayOrder,
List<DigitalInputModes> digitalInputModes,
List<SquibFireMode> squibFireModes,
List<DigitalOutputModes> digitalOutputModes,
string moduleSerialNumber,
int moduleArrayIndex)
{
ChannelNumber = channelNumber;
Hardware = hardware;
var bridge = supportedBridges.Sum(b => (int)b);
var excitation = supportedExcitation.Sum(e => (int)e);
var diModes = digitalInputModes.Sum(di => (int)di);
var squibs = squibFireModes.Sum(m => (int)m);
var doModes = digitalOutputModes.Sum(dout => (int)dout);
var isoHardware = hardware.GetHardware();
_isoChannel = new DTS.Common.ISO.HardwareChannel
{
ChannelIdx = channelNumber,
DASDisplayOrder = displayOrder,
SupportedExcitations = excitation,
SupportedBridges = bridge,
LocalOnly = false,
ParentDAS = isoHardware,
SupportedDigitalInputModes = diModes,
SupportedSquibFireModes = squibs,
SupportedDigitalOutputModes = doModes,
ModuleSerialNumber = moduleSerialNumber,
ModuleArrayIndex = moduleArrayIndex
};
isoHardware.SetChannel(_isoChannel);
}
private bool _bSelected = false;
public bool Selected
{
get => _bSelected;
set
{
SetProperty(ref _bSelected, value, "Selected");
OnPropertyChanged("BackgroundColor");
}
}
public int ChannelNumber { get; } = 0;
public string ChannelNumberText
{
get
{
var channelRepresentation = new ChannelRepresentation(this, ChannelNumber + 1);
return $"Ch. {channelRepresentation.ChannelNumberString}";
}
}
public Color BackgroundColor
{
get
{
if (Selected) { return Colors.Yellow; }
return null == _sensor ? Colors.LightPink : Colors.LightGreen;
}
}
public double ScaleFactorMv => _diagnostics?.ScalefactorMilliVoltsPerADC ?? .2D;
private SensorData _sensor = null;
public SensorData Sensor
{
get => _sensor;
set
{
SetProperty(ref _sensor, value, "Sensor");
OnPropertyChanged("BackgroundColor");
OnPropertyChanged("SensorName");
OnPropertyChanged("UnassignVisibility");
}
}
/// <summary>
/// essentially the same as SensorName, except some places use SensorName as serialnumber, and this won't be the case with axis
/// with multi axis sensors we just show the original sensor serial and Axis x where x is the axis number
/// </summary>
public string SensorNameWithAxis => null == _sensor ? "Empty" : _sensor.GetSerialNumberWithAxis(StringResources.SensorDatabase_SerialNumberWithAxis);
public string SensorName => null == _sensor ? "Empty" : _sensor.SerialNumber;
public bool IsSupportedBridgeType(SensorConstants.BridgeType bridgeType)
{
return (GetISOChannel().SupportedBridges & (int)bridgeType) == (int)bridgeType;
}
private static List<SquibFireMode> _configSquibFireModes = null;
public bool IsSupportedSquibFireMode(SquibFireMode mode)
{
var isHardwareSupported = (GetISOChannel().SupportedSquibFireModes & (int)mode) == (int)mode;
if (!isHardwareSupported) return false;
if (mode == SquibFireMode.NONE) { return true; }
if (null == _configSquibFireModes)
{
PopulateConfigSquibFireModes();
}
return _configSquibFireModes != null && _configSquibFireModes.Contains(mode);
}
private void PopulateConfigSquibFireModes()
{
var modes = new List<SquibFireMode>();
var sModes = DataModelSettings.SupportedSquibFireModes.Split(',');
foreach (var s in sModes)
{
if (Enum.TryParse(s, out SquibFireMode mode))
{
modes.Add(mode);
}
}
_configSquibFireModes = modes;
}
public bool IsSupportedExcitation(ExcitationVoltageOptions.ExcitationVoltageOption excitation)
{
return (GetISOChannel().SupportedExcitations & (int)excitation) == (int)excitation;
}
public bool IsSupportedDigitalInputMode(DigitalInputModes mode)
{
return (GetISOChannel().SupportedDigitalInputModes & (int)mode) == (int)mode;
}
public bool IsSupportedDigitalOutputMode(DigitalOutputModes mode)
{
return (GetISOChannel().SupportedDigitalOutputModes & (int)mode) == (int)mode;
}
public bool IsSupportedExcitation(ExcitationVoltageOptions.ExcitationVoltageOption[] excitations)
{
return Array.Exists(excitations, e => (GetISOChannel().SupportedExcitations & (int)e) == (int)e);
}
}
}