1502 lines
66 KiB
Plaintext
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);
|
|
}
|
|
}
|
|
}
|