This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,731 @@
using DTS.Common.Enums;
using DTS.Common.Enums.Sensors;
using DTS.Common.Interface.Sensors;
using DTS.Common.Interface.Sensors.SoftwareFilters;
using DTS.Common.Interface.Tags;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data;
using System.Data.SqlTypes;
namespace DTS.Common.Classes.Sensors
{
/// <summary>
/// represents a record of an analog sensor in the db
/// <inheritdoc cref="IAnalogDbRecord"/>
/// </summary>
public class AnalogDbRecord : TagAwareBase, IAnalogDbRecord
{
public override TagTypes TagType => TagTypes.SensorModels;
protected int _id = -1;
/// <summary>
/// the database id of the sensor
/// </summary>
[Key]
public int Id
{
get => _id;
set => SetProperty(ref _id, value, "Id");
}
protected string _serialNumber = "";
/// <summary>
/// Serial number of sensor
/// [required to be unique]
/// </summary>
[Required]
[StringLength(50)]
public string SerialNumber
{
get => _serialNumber;
set => SetProperty(ref _serialNumber, value, "SerialNumber");
}
protected short _axisNumber = 0;
/// <summary>
/// deprecated
/// which axis the record is for when the sensor is multi-axis
/// </summary>
public short AxisNumber
{
get => _axisNumber;
set => SetProperty(ref _axisNumber, value, "AxisNumber");
}
protected short _bridgeLegMode;
/// <summary>
/// deprecated
/// </summary>
public short BridgeLegMode
{
get => _bridgeLegMode;
set => SetProperty(ref _bridgeLegMode, value, "BridgeLegMode");
}
protected double _bridgeResistance = 350D;
/// <summary>
/// the expected resistance in Ohms if applicable for the sensor
/// </summary>
public double BridgeResistance
{
get => _bridgeResistance;
set => SetProperty(ref _bridgeResistance, value, "BridgeResistance");
}
protected SensorConstants.BridgeType _bridge = SensorConstants.BridgeType.FullBridge;
/// <summary>
/// the type of bridge or sensor
/// [DO NOT USE BITMASKED VALUE WHEN READING/WRITING TO DB]
/// </summary>
public SensorConstants.BridgeType Bridge
{
get => _bridge;
set => SetProperty(ref _bridge, value, "Bridge");
}
protected void SetBridge(SensorConstants.BridgeType bridge)
{
_bridge = bridge;
}
protected bool _broken = false;
/// <summary>
/// Whether the sensor has been marked as broken by a user
/// </summary>
public bool Broken
{
get => _broken;
set => SetProperty(ref _broken, value, "Broken");
}
protected bool _bypassFilter = false;
/// <summary>
/// whether the sensor has it's own filtering or should otherwise bypass
/// hardware filters when collecting data
/// (not supported on all hardware)
/// </summary>
public bool BypassFilter
{
get => _bypassFilter;
set => SetProperty(ref _bypassFilter, value, "BypassFilter");
}
protected bool _calibrationSignal;
/// <summary>
/// deprecated?
/// </summary>
public bool CalibrationSignal
{
get => _calibrationSignal;
set => SetProperty(ref _calibrationSignal, value, "CalibrationSignal");
}
protected int _calInterval = 365;
/// <summary>
/// calibration interval in days, used in determining when sensor is out of cal
/// </summary>
public int CalInterval
{
get => _calInterval;
set => SetProperty(ref _calInterval, value, "CalInterval");
}
protected double _capacity = 2400D;
/// <summary>
/// capacity of the sensor in EU
/// </summary>
public double Capacity
{
get => _capacity;
set => SetProperty(ref _capacity, value, "Capacity");
}
protected bool _checkOffset = true;
/// <summary>
/// Whether to check the sensor output in mV against thresholds in diagnostics
/// </summary>
public bool CheckOffset
{
get => _checkOffset;
set => SetProperty(ref _checkOffset, value, "CheckOffset");
}
protected string _comment = "";
/// <summary>
/// user supplied descriptive comment on sensor
/// </summary>
[Required]
[StringLength(50)]
public string Comment
{
get => _comment;
set => SetProperty(ref _comment, value, "Comment");
}
protected SensorConstants.CouplingModes _couplingMode = SensorConstants.CouplingModes.AC;
/// <summary>
/// IEPE coupling mode to use for data collection if applicable
/// </summary>
public SensorConstants.CouplingModes CouplingMode
{
get => _couplingMode;
set => SetProperty(ref _couplingMode, value, "CouplingMode");
}
protected DateTime _created;
/// <summary>
/// date sensor record was created (if available)
/// </summary>
[Column(TypeName = "datetime")]
public DateTime Created
{
get => _created;
set => SetProperty(ref _created, value, "Created");
}
protected bool _diagnosticsMode = false;
/// <summary>
/// Whether this sensor should only record internal resistance and record no external signal
/// [generally only useful for testing purposes]
/// </summary>
public bool DiagnosticsMode
{
get => _diagnosticsMode;
set => SetProperty(ref _diagnosticsMode, value, "DiagnosticsMode");
}
protected string _displayUnit = "";
/// <summary>
/// engineering units collected data should be displayed in
/// note that calibration records are also tied against a specific engineering unit that should be used
/// the sensor db value is not used
/// </summary>
public string DisplayUnit
{
get => _displayUnit;
set => SetProperty(ref _displayUnit, value, "DisplayUnit");
}
protected bool _doNotUse = false;
/// <summary>
/// whether this sensor has been marked not to be used by user
/// </summary>
public bool DoNotUse
{
get => _doNotUse;
set => SetProperty(ref _doNotUse, value, "DoNotUse");
}
protected string _eId = "";
/// <summary>
/// Electronic Identification tag
/// [DALLAS or TEDS ID TAG]
/// if present required to be unique
/// </summary>
[Required]
[Column("eId")]
[StringLength(50)]
public string EId
{
get => _eId;
set => SetProperty(ref _eId, value, "EId");
}
protected double _externalShuntResistance;
/// <summary>
/// TDAS supports external resistance when measuring shunt resistance
/// this is the value of external resistance applied
/// </summary>
public double ExternalShuntResistance
{
get => _externalShuntResistance;
set => SetProperty(ref _externalShuntResistance, value, "ExternalShuntResistance");
}
private IFilterClass _filter= new FilterClass(FilterClassType.CFC1000);
/// <summary>
/// The default software filter class to apply to data channel when viewing
/// filtered EU data
/// </summary>
public IFilterClass Filter
{
get => _filter;
set => SetProperty(ref _filter, value, "Filter");
}
private double? _initialEU;
/// <summary>
/// Amount of EU to add in when EU is calculated
/// Used to offset EU readings by a specific amount
/// Note that analog sensor calibration records
/// can contain a more sophisticated EU offset
/// </summary>
[Column("InitialEU")]
[Required]
[StringLength(50)]
public double? InitialEu
{
get => _initialEU;
set => SetProperty(ref _initialEU, value, "InitialEu");
}
protected double _internalShuntResistance;
/// <summary>
/// TDAS supports performing external and internal resistance when measuring shunt resistance
/// This is the value to use when internal shunt resistance is used
/// </summary>
public double InternalShuntResistance
{
get => _internalShuntResistance;
set => SetProperty(ref _internalShuntResistance, value, "InternalShuntResistance");
}
protected bool _invert = false;
/// <summary>
/// whether output of the sensor in EU should be inverted or not
/// </summary>
public bool Invert
{
get => _invert;
set => SetProperty(ref _invert, value, "Invert");
}
private string _isoChannelName = string.Empty;
/// <summary>
/// ISO 13499 channel name to apply to a data channel when a data channel is
/// created using the sensor
/// </summary>
[Required]
[StringLength(255)]
public string ISOChannelName
{
get => _isoChannelName;
set => SetProperty(ref _isoChannelName, value, "ISOChannelName");
}
private string _isoCode = string.Empty;
/// <summary>
/// ISO 13499 code to apply to a data channel when a data channel is created
/// using the sensor
/// </summary>
[Required]
[StringLength(50)]
public string ISOCode
{
get => _isoCode;
set => SetProperty(ref _isoCode, value, "ISOCode");
}
private DateTime _lastModified = (DateTime)SqlDateTime.MinValue;
/// <summary>
/// when the sensor was last modified
/// </summary>
[Column(TypeName = "datetime")]
public DateTime LastModified
{
get => _lastModified;
set => SetProperty(ref _lastModified, value, "LastModified");
}
protected bool _localOnly = false;
/// <summary>
/// deprecated, used to determine which sensors should not propagate up to central database
/// </summary>
public bool LocalOnly
{
get => _localOnly;
set => SetProperty(ref _localOnly, value, "LocalOnly");
}
protected string _manufacturer = "";
/// <summary>
/// Maker of sensor
/// </summary>
[StringLength(50)]
public string Manufacturer
{
get => _manufacturer;
set => SetProperty(ref _manufacturer, value, "Manufacturer");
}
protected string _model = "";
/// <summary>
/// model of sensor
/// </summary>
[StringLength(50)]
public string Model
{
get => _model;
set => SetProperty(ref _model, value, "Model");
}
private string _modifiedBy = "";
/// <summary>
/// who last modified the sensor record
/// </summary>
[Required]
[StringLength(50)]
public string ModifiedBy
{
get => _modifiedBy;
set => SetProperty(ref _modifiedBy, value, "ModifiedBy");
}
private short _numberOfAxes = 1;
/// <summary>
/// deprecated/reserved
/// number of axes associated with this serial number
/// </summary>
public short NumberOfAxes
{
get => _numberOfAxes;
set => SetProperty(ref _numberOfAxes, value, "NumberOfAxes");
}
protected double _offsetToleranceHigh = SensorConstants.DefaultBridgeOffsetMVTolHigh;
/// <summary>
/// allowable tolerance in mV on the high side for an idle reading of sensor
/// used to determine if the sensor output is too high in diagnostics
/// </summary>
public double OffsetToleranceHigh
{
get => _offsetToleranceHigh;
set => SetProperty(ref _offsetToleranceHigh, value, "OffsetToleranceHigh");
}
protected double _offsetToleranceLow = SensorConstants.DefaultBridgeOffsetMVTolLow;
/// <summary>
/// allowable tolerance in mV on the low side for an idle reading of sensor
/// used to determine if the sensor output is too low in diagnostics
/// </summary>
public double OffsetToleranceLow
{
get => _offsetToleranceLow;
set => SetProperty(ref _offsetToleranceLow, value, "OffsetToleranceLow");
}
private double _rangeMedium;
/// <summary>
/// typical medium range for sensor in applications
/// </summary>
public double RangeMedium
{
get => 0 == _rangeMedium ? Capacity : _rangeMedium;
set => SetProperty(ref _rangeMedium, value, "RangeMedium");
}
private double _rangeHigh;
/// <summary>
/// typical high range for sensor in applications
/// </summary>
public double RangeHigh
{
get => 0 == _rangeHigh ? Capacity : _rangeHigh;
set => SetProperty(ref _rangeHigh, value, "RangeHigh");
}
private double _rangeLow;
/// <summary>
/// typical low range for sensor in applications
/// </summary>
public double RangeLow
{
get => 0 == _rangeLow ? Capacity : _rangeLow;
set => SetProperty(ref _rangeLow, value, "RangeLow");
}
protected int _sensorCategory;
/// <summary>
/// The type of sensor
/// Deprecated, remains for TDC purposes
/// Normal = 0,
/// POT = 1,
/// IRTracc = 2,
/// Polynomial = 3
/// </summary>
public int SensorCategory
{
get => _sensorCategory;
set => SetProperty(ref _sensorCategory, value, "SensorCategory");
}
private int _sensorModelId;
/// <summary>
/// the database id of the sensor model, if applicable
/// </summary>
public int SensorModelId
{
get => _sensorModelId;
set => SetProperty(ref _sensorModelId, value, "SensorModelId");
}
private const short SHUNT_MODE_EMULATION = 1;
protected short _shunt = SHUNT_MODE_EMULATION;
/// <summary>
/// The type of shunt used for measuring shunt results
/// note all SLICE hardware only supports emulation (or none)
/// None = 0,
/// Emulation = 1,
/// Internal = 2,
/// External = 3
/// </summary>
public short Shunt
{
get => _shunt;
set => SetProperty(ref _shunt, value, "Shunt");
}
protected SensorStatus _status = SensorStatus.Available;
[Required]
[StringLength(50)]
/// <summary>
/// reserved/not in use
/// </summary>
public SensorStatus Status
{
get => _status;
set => SetProperty(ref _status, value, "Status");
}
protected ExcitationVoltageOptions.ExcitationVoltageOption[] _supportedExcitation = new[] { ExcitationVoltageOptions.ExcitationVoltageOption.Volt5 };
/// <summary>
/// Excitation voltages supported by the sensor
/// used to prevent the sensor from being used in a situation that might damaged it
/// (say a 2V sensor being fed 10V excitation)
/// </summary>
[Required]
[StringLength(50)]
public ExcitationVoltageOptions.ExcitationVoltageOption[] SupportedExcitation
{
get => _supportedExcitation;
set => SetProperty(ref _supportedExcitation, value, "SupportedExcitation");
}
protected long _timesUsed;
/// <summary>
/// Reserved/Not used
/// </summary>
public long TimesUsed
{
get => _timesUsed;
set => SetProperty(ref _timesUsed, value, "TimesUsed");
}
protected bool _uniPolar = false;
/// <summary>
/// flag indicating that the sensor should be interpreted as 0-n rather than -x<0<x
/// </summary>
public bool UniPolar
{
get => _uniPolar;
set => SetProperty(ref _uniPolar, value, "UniPolar");
}
private string _userChannelName = string.Empty;
/// <summary>
/// User channel name to apply when sensor is applied to a blank channel
/// </summary>
[Required]
[StringLength(255)]
public string UserChannelName
{
get => _userChannelName;
set => SetProperty(ref _userChannelName, value, "UserChannelName");
}
private string _userCode = string.Empty;
/// <summary>
/// User channel code to apply when sensor is applied to a blank channel
/// </summary>
[Required]
[StringLength(50)]
public string UserCode
{
get => _userCode;
set => SetProperty(ref _userCode, value, "UserCode");
}
protected string _userSerialNumber = string.Empty;
[Required]
[StringLength(50)]
public string UserSerialNumber
{
get => _userSerialNumber;
set => SetProperty(ref _userSerialNumber, value, "UserSerialNumber");
}
protected string _userValue1 = string.Empty;
/// <summary>
/// user supplied string
/// travels with the sensor to data channels when
/// data is recorded with the sensor
/// </summary>
[StringLength(50)]
public string UserValue1
{
get => _userValue1;
set => SetProperty(ref _userValue1, value, "UserValue1");
}
protected string _userValue2 = string.Empty;
/// <summary>
/// user supplied string
/// travels with the sensor to data channels when
/// data is recorded with the sensor
/// </summary>
[StringLength(50)]
public string UserValue2
{
get => _userValue2;
set => SetProperty(ref _userValue2, value, "UserValue2");
}
protected string _userValue3 = string.Empty;
/// <summary>
/// user supplied string
/// travels with the sensor to data channels when
/// data is recorded with the sensor
/// </summary>
[StringLength(50)]
public string UserValue3
{
get => _userValue3;
set => SetProperty(ref _userValue3, value, "UserValue3");
}
private int _version = 1;
/// <summary>
/// deprecated
/// </summary>
public int Version
{
get => _version;
set => SetProperty(ref _version, value, "Version");
}
private DateTime? _firstUseDate;
[Column(TypeName = "datetime")]
/// <summary>
/// Date of first destructive use since sensor was calibrated,
/// only valid when using latest calibration
/// null indicates not set
/// </summary>
public DateTime? FirstUseDate
{
get => _firstUseDate;
set => SetProperty(ref _firstUseDate, value, "FirstUseDate");
}
private int? _latestCalibrationId;
/// <summary>
/// deprecated
/// Originally held the id of the latest calibration record
/// for sensor
/// </summary>
public int? LatestCalibrationId
{
get => _latestCalibrationId;
set => SetProperty(ref _latestCalibrationId, value, "LatestCalibrationId");
}
public AnalogDbRecord() { }
public AnalogDbRecord(IAnalogDbRecord copy)
{
AxisNumber = copy.AxisNumber;
Bridge = copy.Bridge;
BridgeLegMode = copy.BridgeLegMode;
BridgeResistance = copy.BridgeResistance;
BypassFilter = copy.BypassFilter;
CalibrationSignal = copy.CalibrationSignal;
CalInterval = copy.CalInterval;
Capacity = copy.Capacity;
CheckOffset = copy.CheckOffset;
Comment = copy.Comment;
CouplingMode = copy.CouplingMode;
Created = copy.Created;
ExternalShuntResistance = copy.ExternalShuntResistance;
Filter = new FilterClass(copy.Filter.FClass, copy.Filter.Frequency);
EId = copy.EId;
InternalShuntResistance = copy.InternalShuntResistance;
Invert = copy.Invert;
ISOCode = copy.ISOCode;
ISOChannelName = copy.ISOChannelName;
UserCode = copy.UserCode;
UserChannelName = copy.UserChannelName;
LastModified = copy.LastModified;
LocalOnly = copy.LocalOnly;
Manufacturer = copy.Manufacturer;
DisplayUnit = copy.DisplayUnit;
Model = copy.Model;
ModifiedBy = copy.ModifiedBy;
NumberOfAxes = copy.NumberOfAxes;
OffsetToleranceHigh = copy.OffsetToleranceHigh;
OffsetToleranceLow = copy.OffsetToleranceLow;
RangeMedium = copy.RangeMedium;
RangeHigh = copy.RangeHigh;
RangeLow = copy.RangeLow;
SensorCategory = copy.SensorCategory;
SerialNumber = copy.SerialNumber;
Shunt = copy.Shunt;
Status = copy.Status;
TimesUsed = copy.TimesUsed;
UniPolar = copy.UniPolar;
UserSerialNumber = copy.UserSerialNumber;
DiagnosticsMode = copy.DiagnosticsMode;
UserValue1 = copy.UserValue1;
UserValue2 = copy.UserValue2;
UserValue3 = copy.UserValue3;
Version = copy.Version;
SupportedExcitation = copy.SupportedExcitation;
TagsBlobBytes = copy.TagsBlobBytes;
DoNotUse = copy.DoNotUse;
Broken = copy.Broken;
Id = copy.Id;
FirstUseDate = copy.FirstUseDate;
LatestCalibrationId = copy.LatestCalibrationId;
ACCouplingModeEnabled = copy.ACCouplingModeEnabled;
}
public AnalogDbRecord(IDataReader reader)
{
AxisNumber = Utility.GetShort(reader, "AxisNumber", 0);
SetBridge(SensorConstants.ConvertIntToBridgeType(Utility.GetInt(reader, "BridgeType")));
BridgeLegMode = Utility.GetShort(reader, "BridgeLegMode", 0);
BridgeResistance = Utility.GetDouble(reader, "BridgeResistance");
BypassFilter = Utility.GetBool(reader, "BypassFilter");
CalibrationSignal = Utility.GetBool(reader, "CalibrationSignal");
CalInterval = Utility.GetInt(reader, "CalInterval");
Capacity = Utility.GetDouble(reader, "Capacity");
CheckOffset = Utility.GetBool(reader, "CheckOffset");
Comment = Utility.GetString(reader, "Comment");
CouplingMode = (SensorConstants.CouplingModes)Utility.GetInt(reader, "CouplingMode");
Created = Utility.GetDateTime(reader, "Created", DateTime.MinValue);
ExternalShuntResistance = Utility.GetDouble(reader, "ExternalShuntResistance");
Filter = new FilterClass(Utility.GetString(reader, "FilterClass"));
EId = Utility.GetString(reader, "eId");
InternalShuntResistance = Utility.GetDouble(reader, "InternalShuntResistance");
Invert = Utility.GetBool(reader, "Invert");
ISOCode = Utility.GetString(reader, "IsoCode");
ISOChannelName = Utility.GetString(reader, "IsoChannelName");
UserCode = Utility.GetString(reader, "UserCode");
UserChannelName = Utility.GetString(reader, "UserChannelName");
LastModified = Utility.GetDateTime(reader, "LastModified", DateTime.MinValue);
LocalOnly = Utility.GetBool(reader, "LocalOnly", false);
Manufacturer = Utility.GetString(reader, "Manufacturer");
DisplayUnit = Utility.GetString(reader, "MeasurementUnit");
Model = Utility.GetString(reader, "Model");
ModifiedBy = Utility.GetString(reader, "ModifiedBy");
NumberOfAxes = Utility.GetShort(reader, "NumberOfAxes");
OffsetToleranceHigh = Utility.GetDouble(reader, "OffsetToleranceHigh");
OffsetToleranceLow = Utility.GetDouble(reader, "OffsetToleranceLow");
RangeMedium = Utility.GetDouble(reader, "RangeAve");
RangeHigh = Utility.GetDouble(reader, "RangeHigh");
RangeLow = Utility.GetDouble(reader, "RangeLow");
SensorCategory = Utility.GetInt(reader, "SensorCategory");
SerialNumber = Utility.GetString(reader, "SerialNumber");
Shunt = Utility.GetShort(reader, "Shunt");
var oStatus = reader["Status"];
if (oStatus is string s)
{
if (Enum.TryParse(s, out SensorStatus newStatus))
{
Status = newStatus;
}
}
else
{
Status = (SensorStatus)Convert.ToInt32(oStatus);
}
TimesUsed = Utility.GetInt(reader, "TimesUsed");
UniPolar = Utility.GetBool(reader, "UniPolar");
UserSerialNumber = Utility.GetString(reader, "UserSerialNumber");
DiagnosticsMode = Utility.GetBool(reader, "DiagnosticsMode");
UserValue1 = Utility.GetString(reader, "UserValue1");
UserValue2 = Utility.GetString(reader, "UserValue2");
UserValue3 = Utility.GetString(reader, "UserValue3");
Version = Utility.GetInt(reader, "Version");
SetSupportedExcitationFromString(Utility.GetString(reader, "SupportedExcitation"));
TagsBlobBytes = (byte[])reader["UserTags"];
DoNotUse = Utility.GetBool(reader, "DoNotUse");
Broken = Utility.GetBool(reader, "Broken");
Id = Utility.GetInt(reader, "Id", -1);
FirstUseDate = Utility.GetNullableDateTime(reader, "FirstUseDate");
LatestCalibrationId = Utility.GetNullableInt(reader, "LatestCalibrationId");
ACCouplingModeEnabled = Utility.GetBool(reader, "ACCouplingModeEnabled", false);
}
public void SetSupportedExcitationFromString(string s)
{
var excitations = new List<ExcitationVoltageOptions.ExcitationVoltageOption>();
var tokens = s.Split(new[] { System.Globalization.CultureInfo.InvariantCulture.TextInfo.ListSeparator }, StringSplitOptions.None);
foreach (var token in tokens)
{
if (Enum.TryParse(token, out ExcitationVoltageOptions.ExcitationVoltageOption option)) { excitations.Add(option); }
}
SupportedExcitation = excitations.ToArray();
}
private bool _bACCouplingModeEnabled = false;
/// <summary>
/// whether to use AC Coupling when using a bridge mode (full/half/quarter/half+sig)
/// 18294 Implement Bridge AC/DC coupling(fw update dependent)
/// </summary>
public bool ACCouplingModeEnabled
{
get => _bACCouplingModeEnabled;
set => SetProperty(ref _bACCouplingModeEnabled, value, "ACCouplingModeEnabled");
}
}
}

View File

@@ -0,0 +1,65 @@
using System;
using System.Text;
namespace DTS.Common.Classes.Sensors
{
/// <summary>
/// helper class for the calmode in SIFs which is actually a 3 character sequence for shunt/bridge/filter
/// </summary>
public class CalMode
{
public bool ShuntCheck { get; set; }
public bool FullBridge { get; set; }
public bool Filter { get; set; }
public CalMode(string value)
{
switch (value[0])
{
case 'S':
ShuntCheck = true;
break;
case 'I':
ShuntCheck = false;
break;
default:
throw new NotSupportedException("TDAS::CalMode Invalid calmode position 0: " + value);
}
switch (value[1])
{
case 'D':
FullBridge = true;
break;
case 'S':
FullBridge = false;
break;
default:
throw new NotSupportedException("TDAS::CalMode Invalid calmode position 1: " + value);
}
switch (value[2])
{
case 'F':
Filter = true;
break;
case 'B':
Filter = false;
break;
default:
throw new NotSupportedException("TDAS::CalMode Invalid calmode position 2: " + value);
}
}
public CalMode() { }
public override string ToString()
{
var sb = new StringBuilder();
sb.Append(ShuntCheck ? 'S' : 'I');
sb.Append(FullBridge ? 'D' : 'S');
sb.Append(Filter ? 'F' : 'B');
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,518 @@
using DTS.Common.Interface.Sensors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DTS.Common.Enums;
using DTS.Common.Enums.Sensors;
using DTS.Common.Utilities.Logging;
using System.Globalization;
namespace DTS.Common.Classes.Sensors
{
public class CalibrationRecords : ICalibrationRecords
{
public ICalibrationRecord[] Records { get; set; } = new CalibrationRecord[] { new CalibrationRecord() };
public CalibrationRecords(ICalibrationRecords copy)
{
var records = new CalibrationRecord[copy.Records.Length];
for (var i = 0; i < copy.Records.Length; i++)
{
records[i] = new CalibrationRecord(copy.Records[i]);
}
Records = records;
}
public CalibrationRecords()
{
Records = new CalibrationRecord[] { new CalibrationRecord() };
}
public CalibrationRecords(string records)
{
FromSerializedString(records);
}
public bool IsEqual(object obj, ISensorCalibration sc)
{
if (obj is CalibrationRecords r)
{
if (r.Records.Length != Records.Length)
{
return false;
}
for (var i = 0; i < r.Records.Length; i++)
{
if (!r.Records[i].IsEqual(Records[i], sc))
{
return false;
}
}
return true;
}
return base.Equals(obj);
}
public void FromSerializedString(string s)
{
var tokens = s.Split(new string[] { MySeparator }, StringSplitOptions.None);
for (var i = 0; i < tokens.Length; i++)
{
tokens[i] = tokens[i].Replace(MySeparatorBackup, MySeparator);
}
var records = new List<CalibrationRecord>();
foreach (string token in tokens)
{
records.Add(new CalibrationRecord(token));
}
Records = records.ToArray();
}
private const string MySeparator = "__x__";
private const string MySeparatorBackup = "___xx___";
public string ToSerializedString(ISensorCalDbRecord sc)
{
var records = new List<string>();
foreach (var r in Records)
{
records.Add(r.ToSerializedString(sc));
}
for (var i = 0; i < records.Count; i++)
{
System.Diagnostics.Trace.Assert(!records[i].Contains(MySeparatorBackup));
records[i] = records[i].Replace(MySeparator, MySeparatorBackup);
}
return string.Join(MySeparator, records.ToArray());
}
public string ToDisplayString(ISensorCalibration sc, ISensorCalibration previous, string linearFormat, string nonlinearFormat)
{
var sb = new StringBuilder();
for (var i = 0; i < Records.Length; i++)
{
if (i > 0)
{
sb.AppendLine();
}
var r = Records[i];
ICalibrationRecord r2 = null;
if (null != previous)
{
if (i < previous.Records.Records.Length)
{
r2 = previous.Records.Records[i];
}
}
var s = r.ToDisplayString(sc, r2, previous, linearFormat, nonlinearFormat);
if (!string.IsNullOrEmpty(s))
{
sb.Append(s);
}
}
return sb.ToString();
}
}
public class CalibrationRecord : ICalibrationRecord
{
public double Sensitivity { get; set; }
/// <summary>
/// ZeroPoint is used to hold the calibration certificate field for 2D/3D IR-TRACC cal certs
/// it is used to zero the IR-TRACC and POT data prior to being fed into the 3D equations
/// </summary>
private double _zeroPoint = 0D;
public double ZeroPoint
{
get
{
if (false == Equals(Poly.CalibrationFactor, 0.0))
{
// This field is always calculated. Do not return stored value unless we are unable to calculate
return Poly.ZeroPositionIntercept / Poly.CalibrationFactor;
}
return _zeroPoint;
}
set => _zeroPoint = value;
}
public LinearizationFormula Poly { get; set; }
public bool AtCapacity { get; set; } = false;
public string EngineeringUnits { get; set; } = "g";
public SensorConstants.SensUnits SensitivityUnits { get; set; } = SensorConstants.SensUnits.NONE;
public ExcitationVoltageOptions.ExcitationVoltageOption Excitation { get; set; } = ExcitationVoltageOptions.ExcitationVoltageOption.Volt5;
public double CapacityOutputIsBasedOn { get; set; } = 1.000;
public InitialOffsetTypes InitialOffsetMethod { get; set; } = InitialOffsetTypes.EU;
public string ISOCode { get; set; } = String.Empty;
private enum Fields
{
Sensitivity,
Poly,
AtCapacity,
EngineeringUnits,
Excitation,
CapacityOutputIsBasedOn,
SensitivityUnits,
ZeroPoint,
ISOCode
};
public string ToSerializedString(ISensorCalDbRecord parentCal)
{
var tokens = new List<string>();
var fields = Enum.GetValues(typeof(Fields)).Cast<Fields>().ToArray();
foreach (var field in fields)
{
switch (field)
{
case Fields.AtCapacity:
tokens.Add(AtCapacity.ToString());
break;
case Fields.EngineeringUnits:
tokens.Add(EngineeringUnits);
break;
case Fields.Excitation:
tokens.Add(Excitation.ToString());
break;
case Fields.Poly:
Poly.MarkValid(parentCal.NonLinear);
if (parentCal.LinearAdded)
{
//We have a mixed-sensitivity sensor. Mark the first CR valid, kill the rest
for (var i = 0; i < parentCal.Records.Records.Length; i++)
{
parentCal.Records.Records[i].Poly.MarkValid(i == 0);
}
}
tokens.Add(Poly.ToSerializeString());
break;
case Fields.Sensitivity:
tokens.Add(Sensitivity.ToString(System.Globalization.CultureInfo.InvariantCulture));
break;
case Fields.CapacityOutputIsBasedOn:
tokens.Add(CapacityOutputIsBasedOn.ToString());
break;
case Fields.SensitivityUnits:
tokens.Add(SensitivityUnits.ToString());
break;
case Fields.ZeroPoint:
tokens.Add(ZeroPoint.ToString(System.Globalization.CultureInfo.InvariantCulture));
break;
case Fields.ISOCode:
if (!string.IsNullOrWhiteSpace(ISOCode)) tokens.Add(ISOCode);
break;
default: throw new NotSupportedException("unknown CalibrationRecord field: " + field.ToString());
}
}
for (var i = 0; i < tokens.Count; i++)
{
if (null == tokens[i])
{
tokens[i] = "";
}
tokens[i] = tokens[i].Replace(System.Globalization.CultureInfo.InvariantCulture.TextInfo.ListSeparator,
"x_Separator_x");
}
return string.Join(System.Globalization.CultureInfo.InvariantCulture.TextInfo.ListSeparator,
tokens.ToArray());
}
public string ToDisplayString(ISensorCalibration sc, ICalibrationRecord previous, ISensorCalibration sc2, string linearFormat, string nonlinearFormat)
{
var sb = new StringBuilder();
var fields = Enum.GetValues(typeof(Fields)).Cast<Fields>().ToArray();
foreach (var field in fields)
{
switch (field)
{
case Fields.AtCapacity:
if (null == previous || AtCapacity != previous.AtCapacity)
{
if (sb.Length > 1)
{
sb.AppendLine();
}
sb.AppendFormat("{0}: {1}", Strings.Strings.SensorFields_AtCapacity, AtCapacity);
}
break;
case Fields.EngineeringUnits:
if (null == previous || false == EngineeringUnits.Equals(previous.EngineeringUnits))
{
if (sb.Length > 1)
{
sb.AppendLine();
}
sb.AppendFormat("{0}: {1}", Strings.Strings.SensorFields_EngineeringUnits, EngineeringUnits);
}
break;
case Fields.Excitation:
if (null == previous || sc.IsProportional != sc2.IsProportional || Excitation != previous.Excitation)
{
if (sc.IsProportional)
{
if (sb.Length > 1)
{
sb.AppendLine();
}
sb.AppendFormat("{0}: {1:0.0}", Strings.Strings.SensorFields_Excitation,
GetExcitationVoltageMagnitudeFromEnum(Excitation));
}
}
break;
case Fields.Poly:
if (null == previous || sc.NonLinear || sc.NonLinear != sc2.NonLinear)
{
if (sc.NonLinear)
{
if (sb.Length > 1)
{
sb.AppendLine();
}
sb.AppendFormat("{0}: {1}", Strings.Strings.SensorFields_NonLinearFormat,
Poly.ToDisplayString(nonlinearFormat));
}
}
break;
case Fields.Sensitivity:
if (null == previous || Sensitivity != previous.Sensitivity)
{
if (sb.Length > 1)
{
sb.AppendLine();
}
sb.AppendFormat("{0}: {1}", Strings.Strings.SensorFields_Sensitivity,
Sensitivity.ToString(linearFormat));
}
break;
case Fields.CapacityOutputIsBasedOn:
if (false == AtCapacity)
{
if (null == previous || CapacityOutputIsBasedOn != previous.CapacityOutputIsBasedOn)
{
if (sb.Length > 1)
{
sb.AppendLine();
}
sb.AppendFormat("{0}: {1}", Strings.Strings.SensorFields_CapacityOutputIsBasedOn,
CapacityOutputIsBasedOn);
}
}
break;
case Fields.SensitivityUnits:
if (null == previous || false == SensitivityUnits.Equals(previous.SensitivityUnits))
{
if (sb.Length > 1)
{
sb.AppendLine();
}
sb.AppendFormat("{0}: {1}", Strings.Strings.SensorFields_SensitivityUnits, SensitivityUnits);
}
break;
case Fields.ZeroPoint:
if (null == previous || ZeroPoint != previous.ZeroPoint)
{
if (sb.Length > 1)
{
sb.AppendLine();
}
sb.AppendFormat("{0}: {1}", Strings.Strings.SensorFields_ZeroPoint, ZeroPoint);
}
break;
default:
break;
}
}
return sb.ToString();
}
public bool IsEqual(object obj, ISensorCalibration sc)
{
if (obj is CalibrationRecord r)
{
return r.ToSerializedString(sc) == ToSerializedString(sc);
}
return base.Equals(obj);
}
public void FromString(string s)
{
var tokens = s.Split(new string[] { CultureInfo.InvariantCulture.TextInfo.ListSeparator },
StringSplitOptions.None);
var fields = Enum.GetValues(typeof(Fields)).Cast<Fields>().ToArray();
for (var i = 0; i < tokens.Length && i < fields.Length; i++)
{
var token = tokens[i].Replace("x_Separator_x",
CultureInfo.InvariantCulture.TextInfo.ListSeparator);
switch (fields[i])
{
case Fields.AtCapacity:
AtCapacity = Convert.ToBoolean(token);
break;
case Fields.EngineeringUnits:
EngineeringUnits = token;
break;
case Fields.Excitation:
Excitation =
(ExcitationVoltageOptions.ExcitationVoltageOption)Enum.Parse(
typeof(ExcitationVoltageOptions.ExcitationVoltageOption), token);
break;
case Fields.Poly:
Poly = new LinearizationFormula();
Poly.FromSerializeString(token);
break;
case Fields.Sensitivity:
Sensitivity = Convert.ToDouble(token, System.Globalization.CultureInfo.InvariantCulture);
break;
case Fields.CapacityOutputIsBasedOn:
CapacityOutputIsBasedOn = Convert.ToDouble(token);
break;
case Fields.SensitivityUnits:
if (Enum.TryParse(token, out SensorConstants.SensUnits unit))
{
SensitivityUnits = unit;
}
else { APILogger.Log($"failed to parse sensitivity units: {token} from {s}"); }
break;
case Fields.ZeroPoint:
ZeroPoint = Convert.ToDouble(token, System.Globalization.CultureInfo.InvariantCulture);
break;
case Fields.ISOCode:
ISOCode = token;
break;
default: throw new NotSupportedException("unknown CalibrationRecord field: " + fields.ToArray());
}
}
}
public CalibrationRecord(string s)
{
FromString(s);
}
public CalibrationRecord(ICalibrationRecord copy)
{
var fields = Enum.GetValues(typeof(Fields)).Cast<Fields>().ToArray();
foreach (var field in fields)
{
switch (field)
{
case Fields.AtCapacity:
AtCapacity = copy.AtCapacity;
break;
case Fields.EngineeringUnits:
EngineeringUnits = copy.EngineeringUnits;
break;
case Fields.Excitation:
Excitation = copy.Excitation;
break;
case Fields.Poly:
Poly = new LinearizationFormula(copy.Poly);
break;
case Fields.Sensitivity:
Sensitivity = copy.Sensitivity;
break;
case Fields.CapacityOutputIsBasedOn:
CapacityOutputIsBasedOn = copy.CapacityOutputIsBasedOn;
break;
case Fields.SensitivityUnits:
SensitivityUnits = copy.SensitivityUnits;
break;
case Fields.ZeroPoint:
ZeroPoint = copy.ZeroPoint;
break;
case Fields.ISOCode:
ISOCode = copy.ISOCode;
break;
default:
throw new NotSupportedException("unknown calibrationrecord field: " + field.ToString());
}
}
}
public CalibrationRecord()
{
Poly = new LinearizationFormula();
}
//helpers moved from DAS.Concepts
public static double GetExcitationVoltageMagnitudeFromEnum(ExcitationVoltageOptions.ExcitationVoltageOption target)
{
try
{
return new ExcitationVoltageOptions.VoltageMagnitudeAttributeCoder().DecodeAttributeValue(target);
}
catch (Exception ex)
{
throw new Exception("encountered problem attempting to get excitation voltage magnitude from enum", ex);
}
}
public static ExcitationVoltageOptions.ExcitationVoltageOption GetExcitationVoltageEnumFromMagnitude(double magnitude)
{
try
{
return new ExcitationVoltageOptions.VoltageMagnitudeAttributeCoder().EncodeAttributeValue(magnitude);
}
catch (Exception ex)
{
APILogger.Log("encountered problem attempting to get excitation voltage enum from magnitude", ex);
return ExcitationVoltageOptions.ExcitationVoltageOption.Undefined;
}
}
}
}

View File

@@ -0,0 +1,320 @@
using DTS.Common.Base;
using DTS.Common.Enums;
using DTS.Common.Interface.Sensors;
using DTS.Common.Interface.Sensors.SoftwareFilters;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data;
using System.Linq;
namespace DTS.Common.Classes.Sensors
{
/// <summary>
/// Implementation of IDigitalInDbRecord
/// represents a record of a digital input setting in the database
/// <inheritdoc cref="IDigitalInDbRecord"/>
/// </summary>
public class DigitalInDbRecord : BasePropertyChanged, IDigitalInDbRecord
{
private int _id = -1;
/// <summary>
/// Database id of record
/// </summary>
[Key]
public int Id
{
get => _id;
set => SetProperty(ref _id, value, "Id");
}
private string _serialNumber = "";
/// <summary>
/// serial number or name of setting
/// </summary>
public string SerialNumber
{
get => _serialNumber;
set => SetProperty(ref _serialNumber, value, "SerialNumber");
}
private DigitalInputModes _settingMode = DigitalInputModes.TLH;
/// <summary>
/// Input mode for setting
/// </summary>
public DigitalInputModes Mode
{
get => _settingMode;
set => SetProperty(ref _settingMode, value, "Mode");
}
private IDigitalInputScaleMultiplier _scaleMultiplier = new DigitalInputScaleMultiplier();
/// <summary>
/// ScaleMultiplier, defines how to interpret output in terms of
/// units or active/default value of input state
/// </summary>
[Required]
[StringLength(50)]
public IDigitalInputScaleMultiplier ScaleMultiplier
{
get => _scaleMultiplier;
set => SetProperty(ref _scaleMultiplier, value, "ScaleMultiplier");
}
private DateTime _lastModified = DateTime.MinValue;
[Column(TypeName = "datetime")]
/// <summary>
/// when setting was last modified
/// </summary>
public DateTime LastModified
{
get => _lastModified;
set => SetProperty(ref _lastModified, value, "LastModified");
}
private string _lastModifiedBy = "";
/// <summary>
/// user that last modified setting in db
/// </summary>
[Required]
[StringLength(50)]
public string LastModifiedBy
{
get => _lastModifiedBy;
set => SetProperty(ref _lastModifiedBy, value, "LastModifiedBy");
}
private string _eId = "";
/// <summary>
/// Electronic ID for digital input setting
/// (dallas or TeDS ID value)
/// </summary>
[Required]
[Column("eId")]
[StringLength(50)]
public string EID
{
get => _eId;
set => SetProperty(ref _eId, value, "EID");
}
private string _isoCode = "";
/// <summary>
/// ISO 13499 code for digital input data collected using this setting
/// this is the default code when the setting is applied to an input channel
/// but can be changed in group or test settings
/// </summary>
[Required]
[StringLength(50)]
public string ISOCode
{
get => _isoCode;
set => SetProperty(ref _isoCode, value, "ISOCode");
}
private string _isoChannelName = "";
/// <summary>
/// the associated ISO 13499 channel name to apply to a channel when applying
/// setting to an input channel
/// but can be changed in group or test settings
/// </summary>
[Required]
[StringLength(255)]
public string ISOChannelName
{
get => _isoChannelName;
set => SetProperty(ref _isoChannelName, value, "ISOChannelName");
}
private string _userCode = "";
/// <summary>
/// the user code to apply to a channel when applying setting to a channel
/// can be changed in group or test settings
/// </summary>
[Required]
[StringLength(50)]
public string UserCode
{
get => _userCode;
set => SetProperty(ref _userCode, value, "UserCode");
}
private string _userChannelName = "";
/// <summary>
/// user channel name to apply to a channel when applying setting to a channel
/// can be changed in group or test settings
/// </summary>
[Required]
[StringLength(255)]
public string UserChannelName
{
get => _userChannelName;
set => SetProperty(ref _userChannelName, value, "UserChannelName");
}
private string _userValue1 = "";
/// <summary>
/// user value to carry through to collected data channel when collecting data with this setting
/// </summary>
[StringLength(255)]
public string UserValue1
{
get => _userValue1;
set => SetProperty(ref _userValue1, value, "UserValue1");
}
private string _userValue2 = "";
/// <summary>
/// user value to carry through to collected data channel when collecting data with this setting
/// </summary>
[StringLength(255)]
public string UserValue2
{
get => _userValue2;
set => SetProperty(ref _userValue2, value, "UserValue2");
}
private string _userValue3 = "";
/// <summary>
/// user value to carry through to collected data channel when collecting data with this setting
/// </summary>
[StringLength(255)]
public string UserValue3
{
get => _userValue3;
set => SetProperty(ref _userValue3, value, "UserValue3");
}
private byte[] _userTags;
/// <summary>
/// bytes describing tag ids for tags associated with setting
/// see ITagAware for more information
/// </summary>
public byte[] UserTags
{
get => _userTags;
set => SetProperty(ref _userTags, value, "UserTags");
}
private string _measurementUnit = "V";
/// <summary>
/// measurement unit for collected data, for example
/// 'V' or Volts
/// </summary>
[Required]
[StringLength(50)]
public string MeasurementUnit
{
get => _measurementUnit;
set => SetProperty(ref _measurementUnit, value, "MeasurementUnit");
}
private IFilterClass _filterClass;
/// <summary>
/// software filter class (applied when viewing data) to apply to collected data by default
/// can be changed when viewing or exporting, this is just a default filter
/// </summary>
[Required]
[StringLength(50)]
public IFilterClass FilterClass
{
get => _filterClass;
set => SetProperty(ref _filterClass, value, "FilterClass");
}
private bool _doNotUse = false;
/// <summary>
/// a flag indicating setting should not be used for arbitrary user specified reason
/// </summary>
public bool DoNotUse
{
get => _doNotUse;
set => SetProperty(ref _doNotUse, value, "DoNotUse");
}
private bool _broken = false;
/// <summary>
/// a flag indicating setting should not be used because it is currently broken
/// </summary>
public bool Broken
{
get => _broken;
set => SetProperty(ref _broken, value, "Broken");
}
public DigitalInDbRecord() { }
public DigitalInDbRecord(ISensorData copy, byte [] tagBlockBytes, IDigitalInputScaleMultiplier digitalScaleMultiplier)
{
Id = copy.DatabaseId;
SerialNumber = copy.SerialNumber;
ISOCode = copy.ISOCode;
ISOChannelName = copy.ISOChannelName;
UserCode = copy.UserCode;
UserChannelName = copy.UserChannelName;
Broken = copy.Broken;
DoNotUse = copy.DoNotUse;
LastModified = copy.LastModified;
LastModifiedBy = copy.LastUpdatedBy;
Mode = copy.InputMode;
MeasurementUnit = copy.DIUnits;
FilterClass = new FilterClass(copy.FilterClass.FClass, copy.FilterClass.Frequency);
ISOCode = copy.ISOCode;
EID = copy.EID;
UserValue1 = copy.UserValue1;
UserValue2 = copy.UserValue2;
UserValue3 = copy.UserValue3;
if (null == tagBlockBytes) { UserTags = null; }
else
{
if (tagBlockBytes.Any())
{
UserTags = new byte[tagBlockBytes.Length];
Array.Copy(tagBlockBytes, UserTags, tagBlockBytes.Length);
}
else { UserTags = new byte[0]; }
}
ScaleMultiplier.FromDbSerializeString(digitalScaleMultiplier.ToSerializeDbString());
}
public DigitalInDbRecord(IDataReader reader)
{
Id = Utility.GetInt(reader, "Id", -1);
SerialNumber = Utility.GetString(reader, "SerialNumber", string.Empty);
ISOCode = Utility.GetString(reader, "ISOCode", string.Empty);
ISOChannelName = Utility.GetString(reader, "ISOChannelName", string.Empty);
UserCode = Utility.GetString(reader, "UserCode", string.Empty);
UserChannelName = Utility.GetString(reader, "UserChannelName", string.Empty);
Broken = Utility.GetBool(reader, "Broken", false);
DoNotUse = Utility.GetBool(reader, "DoNotUse", false);
LastModified = Utility.GetDateTime(reader, "LastModified", DateTime.MinValue);
LastModifiedBy = Utility.GetString(reader, "LastModifiedBy", string.Empty);
Mode = (DigitalInputModes)Utility.GetInt(reader,"SettingMode");
MeasurementUnit = Utility.GetString(reader, "MeasurementUnit");
FilterClass = new FilterClass(Utility.GetString(reader, "FilterClass"));
if( ISOCode.Length< 16) { ISOCode = ISOCode.PadRight(16, '?'); }
var s = ISOCode.ToCharArray();
s[15] = '0';
ISOCode = new string(s);
EID = Utility.GetString(reader, "eId", string.Empty);
UserValue1 = Utility.GetString(reader, "UserValue1", string.Empty);
UserValue2 = Utility.GetString(reader, "UserValue2", string.Empty);
UserValue3 = Utility.GetString(reader, "UserValue3", string.Empty);
UserTags = (byte[])reader["UserTags"];
ScaleMultiplier.FromDbSerializeString(Utility.GetString(reader, "ScaleMultiplier"));
}
public DigitalInDbRecord(IDigitalInDbRecord copy)
{
Id = copy.Id;
SerialNumber = copy.SerialNumber;
ISOCode = copy.ISOCode;
ISOChannelName = copy.ISOChannelName;
UserCode = copy.UserCode;
UserChannelName = copy.UserChannelName;
Broken = copy.Broken;
DoNotUse = copy.DoNotUse;
LastModified = copy.LastModified;
LastModifiedBy = copy.LastModifiedBy;
Mode = copy.Mode;
MeasurementUnit = copy.MeasurementUnit;
FilterClass = new FilterClass(copy.FilterClass.FClass, copy.FilterClass.Frequency);
ISOCode = copy.ISOCode;
EID = copy.EID;
UserValue1 = copy.UserValue1;
UserValue2 = copy.UserValue2;
UserValue3 = copy.UserValue3;
if( null == copy.UserTags) { UserTags = null; }
else
{
if(copy.UserTags.Any())
{
var userTags = new byte[copy.UserTags.Length];
Array.Copy(copy.UserTags, userTags, copy.UserTags.Length);
UserTags = userTags;
}
else { UserTags = new byte[0]; }
}
ScaleMultiplier.FromDbSerializeString(copy.ScaleMultiplier.ToSerializeDbString());
}
}
}

View File

@@ -0,0 +1,131 @@
using DTS.Common.Interface.Sensors;
using System;
namespace DTS.Common.Classes.Sensors
{
/// <summary>
/// the scaler is a bit different than an ordinary scaler, so the name here is inaccurate, however the idea is
/// that we allow the user to transform collected data, primarly by allowing them to define the 0,1 value of the digital output
/// </summary>
public class DigitalInputScaleMultiplier : IDigitalInputScaleMultiplier
{
public Forms Form { get; set; } = Forms.ArbitraryLowAndHigh;
/// <summary>
/// for arbirary low/high, this is the low value, the value 0 should be displayed as (OFF)
/// </summary>
public double DefaultValue { get; set; }
/// <summary>
/// for arbitrary low/high, this is the high value, the value 1 should be displayed as (ON)
/// </summary>
public double ActiveValue { get; set; } = 1D;
public bool SimpleEquals(IDigitalInputScaleMultiplier rhs)
{
return Form == rhs.Form && DefaultValue == rhs.DefaultValue && ActiveValue == rhs.ActiveValue;
}
public override bool Equals(object obj)
{
if (obj is DigitalInputScaleMultiplier)
{
var b = obj as DigitalInputScaleMultiplier;
return b.Form == Form
&& b.ActiveValue == ActiveValue
&& b.DefaultValue == DefaultValue;
}
else { return false; }
}
public override int GetHashCode()
{
//the idea here is to use two primes to avoid collisions, it's not perfect but should work in general and we can predict when it won't
if (ActiveValue == 31 || DefaultValue == 31 || DefaultValue == 79 || ActiveValue == 79)
{
return (int)Form + Convert.ToInt32(ActiveValue * 127) + Convert.ToInt32(DefaultValue * 23);
}
else
{
return (int)Form + Convert.ToInt32(ActiveValue * 31) + Convert.ToInt32(DefaultValue * 79);
}
}
/// <summary>
/// constructor and copy constructor
/// </summary>
public DigitalInputScaleMultiplier()
{
DefaultValue = 0D;
}
public DigitalInputScaleMultiplier(DigitalInputScaleMultiplier copy)
{
Form = copy.Form;
DefaultValue = copy.DefaultValue;
ActiveValue = copy.ActiveValue;
}
/// <summary>
/// serializes scaler to a string
/// </summary>
/// <returns></returns>
public string ToSerializeDbString()
{
switch (Form)
{
case Forms.ArbitraryLowAndHigh: return ToSerializeDbStringLowAndHigh();
default: throw new NotSupportedException("DigitalScaleMultiplier::ToSerializeDbString unsupported form: " + Form);
}
}
/// <summary>
/// serializes an ArbitraryLowHigh to a string
/// </summary>
/// <returns></returns>
private string ToSerializeDbStringLowAndHigh() { return string.Format("{1}{0}{2}{0}{3}", System.Globalization.CultureInfo.InvariantCulture.TextInfo.ListSeparator, Form, DefaultValue.ToString(System.Globalization.CultureInfo.InvariantCulture), ActiveValue.ToString(System.Globalization.CultureInfo.InvariantCulture)); }
/// <summary>
/// deserializes an arbitrary low/high from a string
/// </summary>
/// <param name="tokens"></param>
private void FromDbSerializeStringLowAndHigh(string[] tokens)
{
if (tokens.Length < 3) { throw new NotSupportedException("DigitalInputScaleMultiplier::FromDbSerializeStringLowAndHigh invalid format for scale multiplier"); }
if (double.TryParse(tokens[1], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out double d))
{
DefaultValue = d;
}
else { throw new NotSupportedException("DigitalInputScaleMultiplier::FromDbSerializeStringLowAndHigh invalid format for low value: " + tokens[1]); }
if (double.TryParse(tokens[2], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out d))
{
ActiveValue = d;
}
else { throw new NotSupportedException("DigitalInputScaleMultiplier::FromDbSerializeStringLowAndHigh invalid format for high value: " + tokens[2]); }
}
/// <summary>
/// deserializes a scaler from a string, regardless of format
/// </summary>
/// <param name="s"></param>
public void FromDbSerializeString(string s)
{
if (null == s)
{
Utilities.Logging.APILogger.Log("Unable to serialize Db. String is null.");
//FIXME is this the right thing to do?
return;
//throw new NotSupportedException("DigitalINputScaleMultiplier::FromDbSerializeString nothing to parse");
}
var tokens = s.Split(new[] { System.Globalization.CultureInfo.InvariantCulture.TextInfo.ListSeparator }, StringSplitOptions.None);
if (Enum.TryParse(tokens[0], out Forms form))
{
Form = form;
switch (form)
{
case Forms.ArbitraryLowAndHigh: FromDbSerializeStringLowAndHigh(tokens); break;
default: throw new NotSupportedException("DigitalInputScaleMultiplier::FromDbSerializeString unsupported form " + form);
}
}
else { throw new NotSupportedException("DigitalINputScaleMultiplier::FromDbSerializeString unsupported format: " + s); }
}
}
}

View File

@@ -0,0 +1,180 @@
using DTS.Common.Base;
using DTS.Common.Enums;
using DTS.Common.Interface.Sensors;
using System;
using System.Data;
using System.Linq;
namespace DTS.Common.Classes.Sensors
{
public class DigitalOutDbRecord : BasePropertyChanged, IDigitalOutDbRecord
{
private string _serialNumber = "";
public string SerialNumber
{
get => _serialNumber;
set => SetProperty(ref _serialNumber, value, "SerialNumber");
}
private double _doDelay = 0D;
public double DODelay
{
get => _doDelay;
set => SetProperty(ref _doDelay, value, "DODelay");
}
private double _doDuration = 0D;
public double DODuration
{
get => _doDuration;
set => SetProperty(ref _doDuration, value, "DODuration");
}
private string _modifiedBy = "";
public string ModifiedBy
{
get => _modifiedBy;
set => SetProperty(ref _modifiedBy, value, "ModifiedBy");
}
private DateTime _lastModified = DateTime.MinValue;
public DateTime LastModified
{
get => _lastModified;
set => SetProperty(ref _lastModified, value, "LastModified");
}
private int _databaseId = -1;
public int DatabaseId
{
get => _databaseId;
set => SetProperty(ref _databaseId, value, "DatabaseId");
}
private string _isoCode = "";
public string ISOCode
{
get => _isoCode;
set => SetProperty(ref _isoCode, value, "ISOCode");
}
private string _isoChannelName = "";
public string ISOChannelName
{
get => _isoChannelName;
set => SetProperty(ref _isoChannelName, value, "ISOChannelName");
}
private string _userCode = "";
public string UserCode
{
get => _userCode;
set => SetProperty(ref _userCode, value, "UserCode");
}
private string _userChannelName = "";
public string UserChannelName
{
get => _userChannelName;
set => SetProperty(ref _userChannelName, value, "UserChannelName");
}
private bool _broken = false;
public bool Broken
{
get => _broken;
set => SetProperty(ref _broken, value, "Broken");
}
private bool _doNotUse = false;
public bool DoNotUse
{
get => _doNotUse;
set => SetProperty(ref _doNotUse, value, "DoNotUse");
}
private DigitalOutputModes _doMode = DigitalOutputModes.CCNC;
public DigitalOutputModes DOMode
{
get => _doMode;
set => SetProperty(ref _doMode, value, "DOMode");
}
private bool _limitDuration = true;
public bool LimitDuration
{
get => _limitDuration;
set => SetProperty(ref _limitDuration, value, "LimitDuration");
}
private int _version = 0;
public int Version
{
get => _version;
set => SetProperty(ref _version, value, "Version");
}
private byte[] _tagsBlobBytes = null;
public byte [] TagsBlobBytes
{
get => _tagsBlobBytes;
set => SetProperty(ref _tagsBlobBytes, value, "TagsBlobBytes");
}
public DigitalOutDbRecord()
{
}
public DigitalOutDbRecord(ISensorData copy, byte [] tagsBlobBytes)
{
SerialNumber = copy.SerialNumber;
DatabaseId = copy.DatabaseId;
Broken = copy.Broken;
DoNotUse = copy.DoNotUse;
Version = copy.Version;
DOMode = copy.DigitalOutputMode;
LimitDuration = copy.DigitalOutputLimitDuration;
ModifiedBy = copy.LastUpdatedBy;
LastModified = copy.LastModified;
DODuration = copy.DigitalOutputDurationMS;
DODelay = copy.DigitalOutputDelayMS;
if (null == tagsBlobBytes)
{
TagsBlobBytes = null;
}
else if (tagsBlobBytes.Any())
{
var bytes = new byte[tagsBlobBytes.Length];
Array.Copy(tagsBlobBytes, bytes, tagsBlobBytes.Length);
TagsBlobBytes = bytes;
}
else { TagsBlobBytes = new byte[0]; }
}
public DigitalOutDbRecord(IDigitalOutDbRecord copy)
{
SerialNumber = copy.SerialNumber;
DatabaseId = copy.DatabaseId;
Broken = copy.Broken;
DoNotUse = copy.DoNotUse;
Version = copy.Version;
DOMode = copy.DOMode;
LimitDuration = copy.LimitDuration;
ModifiedBy = copy.ModifiedBy;
LastModified = copy.LastModified;
DODuration = copy.DODuration;
DODelay = copy.DODelay;
if( null == copy.TagsBlobBytes)
{
TagsBlobBytes = null;
}
else if(copy.TagsBlobBytes.Any())
{
var tagsBlobBytes = new byte[copy.TagsBlobBytes.Length];
Array.Copy(copy.TagsBlobBytes, tagsBlobBytes, copy.TagsBlobBytes.Length);
TagsBlobBytes = tagsBlobBytes;
}
else { TagsBlobBytes = new byte[0]; }
}
public DigitalOutDbRecord(IDataReader reader)
{
DatabaseId = Utility.GetInt(reader, "Id", -1);
Broken = Utility.GetBool(reader, "Broken", false);
DoNotUse = Utility.GetBool(reader, "DoNotUse");
SerialNumber = Utility.GetString(reader, "SerialNumber");
Version = Utility.GetInt(reader, "Version");
DOMode = (DigitalOutputModes)Utility.GetInt(reader, "OutputMode");
LimitDuration = Utility.GetBool(reader, "LimitDuration", true);
ModifiedBy = Utility.GetString(reader, "LastModifiedBy", string.Empty);
LastModified = Utility.GetDateTime(reader, "LastModified", DateTime.MinValue);
DODuration = Utility.GetDouble(reader, "DurationMSFloat");
DODelay = Utility.GetDouble(reader, "DelayMS");
TagsBlobBytes = (byte[])reader["UserTags"];
}
}
}

View File

@@ -0,0 +1,13 @@
namespace DTS.Common.Classes.Sensors
{
public class DisplayedCalibrationBehavior
{
public DTS.Common.Enums.Sensors.CalibrationBehaviors CalibrationBehavior;
public string DisplayString;
public override string ToString()
{
return DisplayString;
}
}
}

View File

@@ -0,0 +1,632 @@
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using System.ComponentModel;
using System.Globalization;
using DTS.Common.Enums.Sensors;
using DTS.Common.Interface.Sensors.SoftwareFilters;
using DTS.Common.Interface.Sensors;
using System.Linq;
namespace DTS.Common.Classes.Sensors
{
public class FilterClass : INotifyPropertyChanged, IFilterClass
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, String propertyName = null)
{
if (Equals(storage, value)) return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged(string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public FilterClassType FClass { get; set; }
//FB 13120 used for filter options drop down localization
public string FilterName
{
get
{
string name = "";
if (FClass == FilterClassType.None)
{
name = Strings.Strings.FilterClassType_None;
}
else if (FClass == FilterClassType.Unfiltered)
{
name = Strings.Strings.FilterClassType_Unfiltered;
}
else if (FClass == FilterClassType.AdHoc)
{
name = Frequency.ToString();
}
else
{
name = Frequency + " (" + FClass.ToString() + ")";
}
return name;
}
}
/// <summary>
/// Gets the numeric filter class value for the filter class; EX CFC60 returns 60, CFC1000 returns 1000
/// </summary>
/// <returns>integer for filter class name</returns>
public int GetFilterClassNumericValue()
{
switch (FClass)
{
case FilterClassType.CFC10:
return 10;
case FilterClassType.CFC60:
return 60;
case FilterClassType.CFC180:
return 180;
case FilterClassType.CFC600:
return 600;
case FilterClassType.None:
return 0;
case FilterClassType.Unfiltered:
return -2;
default: // adhoc and cfc1000 enter here
return 1000;
}
}
private double _Frequency;
public double Frequency
{
get { return _Frequency; }
set { _Frequency = value; }
}
#region Tags
internal const string FilterClassTag = "FilterClass";
internal const string ClassTag = "Class";
internal const string FrequencyTag = "Frequency";
#endregion
private string TableName;
public FilterClass(XElement elem, string prefix, string tblName, string id)
{
TableName = tblName;
XElement inner = null;
try
{
inner = elem.Element(mkTag(prefix));
}
catch (ArgumentNullException)
{
if (!string.IsNullOrEmpty(id))
{
throw new System.Exception(string.Format("{0}: Can't find tag {1} for entry {2}", TableName, prefix + "-" + FilterClassTag, id));
}
throw new System.Exception(string.Format("{0}: Can't find tag {1} in file", TableName, prefix + "-" + FilterClassTag));
}
FClass = (FilterClassType)Enum.Parse(typeof(FilterClassType), inner.Attribute(ClassTag).Value);
switch (FClass)
{
case FilterClassType.None:
_Frequency = (double)FilterClassType.None;
break;
case FilterClassType.Unfiltered:
_Frequency = (double)FilterClassType.Unfiltered;
break;
case FilterClassType.CFC10:
_Frequency = (double)FilterClassType.CFC10;
break;
case FilterClassType.CFC60:
_Frequency = (double)FilterClassType.CFC60;
break;
case FilterClassType.CFC180:
_Frequency = (double)FilterClassType.CFC180;
break;
case FilterClassType.CFC600:
_Frequency = (double)FilterClassType.CFC600;
break;
case FilterClassType.CFC1000:
_Frequency = (double)FilterClassType.CFC1000;
break;
case FilterClassType.AdHoc:
if (!double.TryParse(inner.Value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out _Frequency))
{
throw new System.Exception(string.Format("{0}: Invalid filter frequency {1}", TableName, inner.Value));
}
break;
}
}
public FilterClass(FilterClassType fc, double freq)
{
FClass = fc;
Frequency = freq;
}
public static FilterClassType GetFilterClassTypeFromNumericFC(int fc)
{
switch (fc)
{
case 1000:
case -1:
return FilterClassType.CFC1000;
case 600:
return FilterClassType.CFC600;
case 180:
return FilterClassType.CFC180;
case 60:
return FilterClassType.CFC60;
case 10:
return FilterClassType.CFC10;
case 0:
return FilterClassType.None;
case -2:
return FilterClassType.Unfiltered;
default:
return FilterClassType.None;
}
}
public FilterClass(double freq)
{
Frequency = freq;
if (freq == (double)FilterClassType.CFC10)
{
FClass = FilterClassType.CFC10;
}
else if (freq == (double)FilterClassType.CFC60)
{
FClass = FilterClassType.CFC60;
}
else if (freq == (double)FilterClassType.CFC180)
{
FClass = FilterClassType.CFC180;
}
else if (freq == (double)FilterClassType.CFC600)
{
FClass = FilterClassType.CFC600;
}
else if (freq == (double)FilterClassType.CFC1000)
{
FClass = FilterClassType.CFC1000;
}
else if (freq == 0)
{
FClass = FilterClassType.None;
}
else if (freq == (double)FilterClassType.Unfiltered)
{
FClass = FilterClassType.Unfiltered;
}
else
{
FClass = FilterClassType.AdHoc;
//FB 13120 set the frequency for ad hoc filters
Frequency = freq;
}
}
/// <summary>
///FB 13120 Specify and return the default filter class
/// </summary>
/// <returns></returns>
public static FilterClass GetDefaultFilterClass(List<ISoftwareFilter> softwareFilters)
{
if (softwareFilters == null)
{
return new FilterClass(FilterClassType.CFC1000);
}
var softwareFilter = softwareFilters.FirstOrDefault(p => p.IsDefault);
FilterClass fc = null;
switch (softwareFilter?.ISOCode)
{
case '0':
fc = new FilterClass(FilterClassType.Unfiltered);
break;
case 'P':
fc = new FilterClass(FilterClassType.None);
break;
case 'S':
fc = new FilterClass(FilterClassType.AdHoc, softwareFilter.Frequency);
break;
case 'A':
fc = new FilterClass(FilterClassType.CFC1000);
break;
case 'B':
fc = new FilterClass(FilterClassType.CFC600);
break;
case 'C':
fc = new FilterClass(FilterClassType.CFC180);
break;
case 'D':
fc = new FilterClass(FilterClassType.CFC60);
break;
default:
fc = new FilterClass(FilterClassType.CFC1000);
break;
}
return fc;
}
/// <summary>
/// FB 13120 Get the filter class based on the isoCode provided
/// </summary>
/// <param name="isoCode"></param>
/// <param name="frequency">this frequency will be used for AdHoc filter</param>
/// <returns></returns>
public static FilterClass GetFilterClassFromIsoCode(string isoCode, double frequency = 0)
{
if (string.IsNullOrEmpty(isoCode))
{
return new FilterClass(FilterClassType.CFC1000);
}
FilterClass fc = null;
switch (isoCode.ToUpper())
{
case "0":
fc = new FilterClass(FilterClassType.Unfiltered);
break;
case "P":
fc = new FilterClass(FilterClassType.None);
break;
case "S":
fc = new FilterClass(FilterClassType.AdHoc, frequency);
break;
case "A":
fc = new FilterClass(FilterClassType.CFC1000);
break;
case "B":
fc = new FilterClass(FilterClassType.CFC600);
break;
case "C":
fc = new FilterClass(FilterClassType.CFC180);
break;
case "D":
fc = new FilterClass(FilterClassType.CFC60);
break;
default:
fc = new FilterClass(FilterClassType.CFC1000);
break;
}
return fc;
}
/// <summary>
/// FB 15574 Get the FilterClass setting from cfc iso code
/// </summary>
/// <param name="cfcIsoCode">cfc iso code ex: A</param>
/// <returns>filter class setting on format of FilterType,Frequency ex: None,0 </returns>
public static string GetFilterClassSettingFromCFC(string cfcIsoCode)
{
var filterClass = GetFilterClassFromIsoCode(cfcIsoCode);
return $"{filterClass.FClass.ToString()},{filterClass.Frequency}";
}
/// <summary>
///FB 15574 Get the FilterClass setting from FilterClass
/// </summary>
/// <param name="filterClass"></param>
/// <returns>filter class setting on format of FilterType,Frequency ex: None,0 </returns>
public static string GetFilterClassSettingFromFilterClass(IFilterClass filterClass)
{
return $"{filterClass.FClass.ToString()},{filterClass.Frequency}";
}
public static double GetFrequencyFromFilterClassType(FilterClassType filterClassType)
{
if (filterClassType == FilterClassType.AdHoc)
{
throw new Exception("GetFrequencyFromFilterClassType: AdHoc FilterClassType does not have frequency associated");
}
return (double)filterClassType;
}
public static FilterClass GetFilterClassFromFilterClassType(FilterClassType filterClassType, double adHocFrequency = 0)
{
if (filterClassType == FilterClassType.AdHoc)
{
return new FilterClass(filterClassType, adHocFrequency);
}
return new FilterClass(filterClassType);
}
public static FilterClass GetFilterClassFromFilterClassSetting(string filterClassSetting)
{
if (string.IsNullOrEmpty(filterClassSetting))
{
return GetFilterClassFromFilterClassType(FilterClassType.Unfiltered);
}
var setting = filterClassSetting.Split(',');
if (Enum.TryParse(setting[0], out FilterClassType fct))
{
return GetFilterClassFromFilterClassType(fct, Convert.ToDouble(setting[1]));
}
return GetFilterClassFromFilterClassType(FilterClassType.Unfiltered);
}
public FilterClass(FilterClassType fc)
{
FClass = fc;
switch (fc)
{
case FilterClassType.None:
Frequency = 0;
break;
case FilterClassType.AdHoc:
Frequency = (double) FilterClassType.AdHoc;
break;
case FilterClassType.Unfiltered:
Frequency = (double)FilterClassType.Unfiltered;
break;
case FilterClassType.CFC10:
Frequency = (double)FilterClassType.CFC10;
break;
case FilterClassType.CFC60:
Frequency = (double)FilterClassType.CFC60;
break;
case FilterClassType.CFC180:
Frequency = (double)FilterClassType.CFC180;
break;
case FilterClassType.CFC600:
Frequency = (double)FilterClassType.CFC600;
break;
case FilterClassType.CFC1000:
Frequency = (double)FilterClassType.CFC1000;
break;
default:
throw new System.Exception("FilterClass: unknown class");
}
}
public XElement ToXElement(string prefix)
{
var element = new XElement(mkTag(prefix), Frequency);
element.SetAttributeValue(ClassTag, FClass.ToString());
return element;
}
public void Update(XElement elem, string prefix)
{
elem.SetElementValue(mkTag(prefix), Frequency);
var element = elem.Element(mkTag(prefix));
element.SetAttributeValue(ClassTag, FClass.ToString());
}
public static string mkTag(string prefix)
{
return prefix + "-" + FilterClassTag;
}
public override string ToString()
{
switch (FClass)
{
case FilterClassType.None:
return "None";
case FilterClassType.Unfiltered:
return "Unfiltered";
case FilterClassType.CFC10:
return string.Format("{0} (CFC10)", (int)FilterClassType.CFC10);
case FilterClassType.CFC60:
return string.Format("{0} (CFC60)", (int)FilterClassType.CFC60);
case FilterClassType.CFC180:
return string.Format("{0} (CFC180)", (int)FilterClassType.CFC180);
case FilterClassType.CFC600:
return string.Format("{0} (CFC600)", (int)FilterClassType.CFC600);
case FilterClassType.CFC1000:
return string.Format("{0} (CFC1000)", (int)FilterClassType.CFC1000);
case FilterClassType.AdHoc:
return ((int)Frequency).ToString();
}
throw new System.Exception("FilterClass.ToString: Invalid class=" + FClass.ToString());
}
public FilterClass(string fclass)
{
int fc;
if (int.TryParse(fclass, NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out fc))
{
switch (fc)
{
case 17:
FClass = FilterClassType.CFC10;
_Frequency = (double) FClass;
return;
case 100:
FClass = FilterClassType.CFC60;
_Frequency = (double) FClass;
return;
case 300:
FClass = FilterClassType.CFC180;
_Frequency = (double) FClass;
return;
case 1000:
FClass = FilterClassType.CFC600;
_Frequency = (double) FClass;
return;
case 1650:
FClass = FilterClassType.CFC1000;
_Frequency = (double) FClass;
return;
}
}
if (string.IsNullOrEmpty(fclass) || fclass == "None")
{
FClass = FilterClassType.None;
}
else if (fclass.Contains("Unfiltered"))
{
FClass = FilterClassType.Unfiltered;
_Frequency = (double)FilterClassType.Unfiltered;
}
else if (fclass.Contains("CFC1000"))
{
FClass = FilterClassType.CFC1000;
_Frequency = (double)FilterClassType.CFC1000;
}
else if (fclass.Contains("CFC600"))
{
FClass = FilterClassType.CFC600;
_Frequency = (double)FilterClassType.CFC600;
}
else if (fclass.Contains("CFC60"))
{
FClass = FilterClassType.CFC60;
_Frequency = (double)FilterClassType.CFC60;
}
else if (fclass.Contains("CFC180"))
{
FClass = FilterClassType.CFC180;
_Frequency = (double)FilterClassType.CFC180;
}
else
{
//FB 13120 parse and set frequncy
double freq = 0;
if (double.TryParse(fclass, out freq))
{
FClass = FilterClassType.AdHoc;
_Frequency = freq;
}
else
{
FClass = FilterClassType.CFC1000;
_Frequency = (double)FilterClassType.CFC1000;
}
}
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (!(obj is FilterClass))
{
return false;
}
var filterObj = obj as FilterClass;
//FB 13120 needs this since the frequency would be different (-2 & 0) for unfiltered case
if (FClass == filterObj.FClass && FClass == FilterClassType.Unfiltered)
{
return true;
}
return FClass == filterObj.FClass && Frequency == filterObj.Frequency;
}
public int CompareTo(object filterClass)
{
IFilterClass fc = filterClass as FilterClass;
if (this == null)
{
if (fc == null)
{
// both null, equal
return 0;
}
// left null but not right
return -1;
}
if (fc == null)
{
// left not null, right null
return 1;
}
if (this.FClass != FilterClassType.None)
return fc.FClass == FilterClassType.None ? 1 : this.Frequency.CompareTo(fc.Frequency);
if (fc.FClass == FilterClassType.None)
{
return 0;
}
return -1;
}
/// <summary>
/// returns an identical hash index for any two "equal" filterclass objects
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
//.equals compares frequency and class, but we just need to guarantee that
//equal objects hash to the same index
return Convert.ToInt32(Frequency);
}
/// <summary>
/// FB 13120 Factory method to create a filter class
/// </summary>
/// <param name="fc"></param>
/// <param name="frequency"></param>
/// <returns></returns>
public static IFilterClass CreateFilterClass(FilterClassType fc, double frequency = 0)
{
if (fc == FilterClassType.AdHoc)
{
return new FilterClass(frequency);
}
else
{
return new FilterClass(fc);
}
}
/// <summary>
/// Get the filter class based on the string cfc
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static IFilterClass GetFilterClassFromString(string s)
{
if (string.IsNullOrEmpty(s)) return new FilterClass(FilterClassType.Unfiltered);
s = s.ToLower().Replace("cfc", "").Replace("hz", "").Trim();
double freq = 0;
if (double.TryParse(s, out freq))
{
switch (freq)
{
case 10:
return new FilterClass(FilterClassType.CFC10);
case 60:
return new FilterClass(FilterClassType.CFC60);
case 180:
return new FilterClass(FilterClassType.CFC180);
case 600:
return new FilterClass(FilterClassType.CFC600);
case 1000:
return new FilterClass(FilterClassType.CFC1000);
default:
return new FilterClass(FilterClassType.AdHoc, freq);
}
}
else
{
switch (s.ToLower())
{
case "unfiltered":
return new FilterClass(FilterClassType.Unfiltered);
case "none":
return new FilterClass(FilterClassType.None);
default:
return new FilterClass(FilterClassType.Unfiltered);
}
}
}
}
}

View File

@@ -0,0 +1,392 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using DTS.Common.Converters;
using DTS.Common.Enums.Sensors;
using DTS.Common.Interface.Sensors;
namespace DTS.Common.Classes.Sensors
{
/// <summary>
/// InitialOffset is the replacement for InitialEU
/// it encompasses the old InitialOffset specified in EU with a offset of specifying it in mV @EU
/// Initial EU is a post data collection adjustment to engineering units recorded
/// </summary>
public class InitialOffset : Base.BasePropertyChanged
{
/// <summary>
/// copy constructor
/// </summary>
/// <param name="copy"></param>
public InitialOffset(InitialOffset copy)
{
if (null == copy) { return; }
EU = copy.EU;
MV = copy.MV;
Form = copy.Form;
}
/// <summary>
/// default constructor
/// </summary>
public InitialOffset()
{
Form = InitialOffsetTypes.None;
EU = 0D;
MV = 0D;
}
/// <summary>
/// constructor for the old format Initial EU (a single double representing offset in EU)
/// </summary>
/// <param name="d"></param>
public InitialOffset(double d)
{
Form = InitialOffsetTypes.EU;
EU = d;
MV = 0D;
}
/// <summary>
/// constructor for string from db
/// </summary>
/// <param name="s"></param>
public InitialOffset(string s)
{
FromDbSerializeString(s);
}
public override string ToString()
{
var converter = new EnumDescriptionTypeConverter(typeof(InitialOffsetTypes));
return converter.ConvertToString(Form);
}
/// <summary>
/// serializes to a db safe string
/// </summary>
/// <returns></returns>
public string ToDbSerializeString()
{
var s = new List<string>
{
Form.ToString(),
EU.ToString(System.Globalization.CultureInfo.InvariantCulture),
MV.ToString(System.Globalization.CultureInfo.InvariantCulture)
};
return string.Join(System.Globalization.CultureInfo.InvariantCulture.TextInfo.ListSeparator, s.ToArray());
}
/// <summary>
/// deserializes from a string suitable for db storage
/// </summary>
/// <param name="input"></param>
public void FromDbSerializeString(string input)
{
if (string.IsNullOrWhiteSpace(input))
{
Form = InitialOffsetTypes.None;
EU = 0;
MV = 0;
return;
}
if (input == "EU")
{
Form = InitialOffsetTypes.EU;
EU = 0;
return;
}
if (input.Contains(InitialOffsets.MySeparator))
{
//we got an InputOffsets input. just take the first one
input = input.Split(new [] {InitialOffsets.MySeparator}, StringSplitOptions.RemoveEmptyEntries)[0];
}
var tokens = input.Split(new string[] { System.Globalization.CultureInfo.InvariantCulture.TextInfo.ListSeparator }, StringSplitOptions.None);
if (Enum.TryParse(tokens[0], out InitialOffsetTypes form))
{
Form = form;
if (tokens.Length < 3)
{
throw new System.IO.InvalidDataException($"Invalid InitialOffset number of parameters: {input}");
}
else
{
if (double.TryParse(tokens[1], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out var d))
{
EU = d;
}
else { throw new FormatException($"Invalid InitialOffset EU format: {tokens[1]}"); }
if (double.TryParse(tokens[2], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out d))
{
MV = d;
}
else { throw new FormatException($"Invalid InitialOffset MV format: {tokens[2]}"); }
}
}
else { throw new System.IO.InvalidDataException("Invalid InitialOffset form: " + tokens[0]); }
}
private InitialOffsetTypes _form;
/// <summary>
/// the format this intial offset instance is in
/// </summary>
public InitialOffsetTypes Form
{
get => _form;
set => SetProperty(ref _form, value, Fields.Form.ToString());
}
//FB18158 Don't allow removal of None option
public System.Windows.Visibility InitialOffsetVisibility
{
get => Form != InitialOffsetTypes.None ? System.Windows.Visibility.Visible: System.Windows.Visibility.Hidden;
}
private double _eu = 0D;
/// <summary>
/// EU value. In the case of Form == EU, this is the offset in EU
/// In. the form of EU@mV, this is the EU@mV value, and offset in EU still needs to be calculated
/// GetInitialEUValue calculates the offset in eu
/// this value is not used for InitialOffset format None
/// </summary>
public double EU
{
get => _eu;
set => SetProperty(ref _eu, value, Fields.EU.ToString());
}
private double _mv = 0D;
/// <summary>
/// mV value, only applies for the format EU@mV
/// this is the value in mV that The value in EU is observed at by a calibrated instrument
/// </summary>
public double MV
{
get => _mv;
set => SetProperty(ref _mv, value, Fields.MV.ToString());
}
private enum Fields
{
Form,
EU,
MV
}
/// <summary>
/// Displays initial offset structure to string
/// created for FB5429
/// </summary>
/// <param name="NONEFormatString">string resource similar to "None"</param>
/// <param name="EUFormatString">string resource similar to "EU"</param>
/// <param name="mVFormatString">string resource similar to "mV"</param>
/// <returns></returns>
public string ToDisplayString(string NONEFormatString, string EUFormatString, string mVFormatString)
{
var sb = new StringBuilder();
switch (Form)
{
case InitialOffsetTypes.EU:
case InitialOffsetTypes.LHS:
case InitialOffsetTypes.RHS:
case InitialOffsetTypes.FRONTAL:
sb.AppendFormat("{0} {1}", EU, EUFormatString);
break;
case InitialOffsetTypes.EUAtMV:
sb.AppendFormat("{0} {1} @ {2} {3}", EU, EUFormatString, MV, mVFormatString);
break;
case InitialOffsetTypes.None:
sb.AppendFormat("{0}", NONEFormatString);
break;
default:
break;
}
return sb.ToString();
}
/// <summary>
/// Compares attributes to another InitialOffset object
/// created for FB5429
/// </summary>
/// <param name="obj">an InitialOffset object</param>
/// <returns>if contents are equal</returns>
public override bool Equals(object obj)
{
if (obj is InitialOffset io)
{
var fields = Enum.GetValues(typeof(Fields)).Cast<Fields>().ToArray();
foreach (var field in fields)
{
switch (field)
{
case Fields.Form: if (io.Form != Form) { return false; } break;
case Fields.EU: if (io.EU != EU) { return false; } break;
case Fields.MV: if (io.MV != MV) { return false; } break;
default:
throw new NotSupportedException("InitialOffset::Equals Unknown field " + field);
}
}
return true;
}
return base.Equals(obj);
}
}
public class InitialOffsets : IInitialOffsets
{
public InitialOffset[] Offsets { get; set; } = new InitialOffset[] { };
//FB18158 Always add None option to InitialOffsets
private void SeedNoneInInitialOffsets()
{
if (Offsets.Any(p => p.Form == InitialOffsetTypes.None))
{
return;
}
List<InitialOffset> initialOffsets = new List<InitialOffset>();
initialOffsets.Add(new InitialOffset());
foreach (var io in Offsets)
{
initialOffsets.Add(io);
}
Offsets = initialOffsets.ToArray();
}
public InitialOffset DefaultOffset
{
get
{
//30442 Don't default InitialOffset to None if other options exist
if (null != Offsets && Offsets.Any())
{
if ((Offsets.Count() > 1) && (Offsets[0].Form == InitialOffsetTypes.None))
{
return Offsets[1];
}
else
{
return Offsets.First();
}
}
else
{
return new InitialOffset();
}
}
}
public InitialOffsets(InitialOffsets copy)
{
InitialOffset[] offsets = new InitialOffset[copy.Offsets.Length];
for (int i = 0; i < copy.Offsets.Length; i++)
{
offsets[i] = new InitialOffset(copy.Offsets[i]);
}
Offsets = offsets;
SeedNoneInInitialOffsets();
}
/// <summary>
/// This produces an instance of the class based on an existing instance,
/// but without the first Initial Offset, only additional Initial Offsets
/// </summary>
/// <param name="copy"></param>
/// <param name="numAdditionalInitialOffsets"></param>
public InitialOffsets(InitialOffsets copy, int numAdditionalInitialOffsets)
{
InitialOffset[] offsets = new InitialOffset[numAdditionalInitialOffsets];
for (int i = 0; i < numAdditionalInitialOffsets; i++)
{
offsets[i] = new InitialOffset(copy.Offsets[i + 1]);
}
Offsets = offsets;
SeedNoneInInitialOffsets();
}
public InitialOffsets()
{
Offsets = new InitialOffset[] { new InitialOffset() };
SeedNoneInInitialOffsets();
}
public InitialOffsets(string offsets)
{
FromSerializedString(offsets);
SeedNoneInInitialOffsets();
}
public InitialOffsets(InitialOffset startingOffset)
{
Offsets = new InitialOffset[] { startingOffset };
SeedNoneInInitialOffsets();
}
public override bool Equals(object obj)
{
if (obj is InitialOffsets r)
{
if (r.Offsets.Length != Offsets.Length) { return false; }
for (var i = 0; i < r.Offsets.Length; i++)
{
if (!r.Offsets[i].Equals(Offsets[i])) { return false; }
}
return true;
}
return base.Equals(obj);
}
public void FromSerializedString(string s)
{
var tokens = s.Split(new string[] { MySeparator }, StringSplitOptions.None);
for (var i = 0; i < tokens.Length; i++) { tokens[i] = tokens[i].Replace(MySeparatorBackup, MySeparator); }
var offsets = new List<InitialOffset>();
foreach (string token in tokens)
{
offsets.Add(new InitialOffset(token));
}
Offsets = offsets.ToArray();
SeedNoneInInitialOffsets();
}
internal const string MySeparator = "__x__";
internal const string MySeparatorBackup = "___xx___";
public string ToSerializedString()
{
var offsets = new List<string>();
foreach (var r in Offsets) { offsets.Add(r.ToDbSerializeString()); }
for (int i = 0; i < offsets.Count; i++)
{
Trace.Assert(!offsets[i].Contains(MySeparatorBackup));
offsets[i] = offsets[i].Replace(MySeparator, MySeparatorBackup);
}
return string.Join(MySeparator, offsets.ToArray());
}
public string ToDisplayString(string averageOverTimeFormatString, string diagnosticLevelFormatString, string absoluteZeroFormatString)
{
var sb = new StringBuilder();
for (var i = 0; i < Offsets.Length; i++)
{
if (i > 0) { sb.AppendLine(); }
var s = Offsets[i].ToDisplayString(averageOverTimeFormatString, diagnosticLevelFormatString, absoluteZeroFormatString);
if (!string.IsNullOrEmpty(s))
{
sb.Append(s);
}
}
return sb.ToString();
}
public override string ToString()
{
return ToDisplayString(Strings.Strings.SensorFields_InitialOffset_AverageOverTimeFormat, Strings.Strings.SensorFields_InitialOffset_DiagnosticLevelFormat,
Strings.Strings.SensorFields_InitialOffset_AbsoluteZeroFormat);
}
}
}

View File

@@ -0,0 +1,699 @@
using System;
using System.Collections.Generic;
using System.Text;
using DTS.Common.Enums.Sensors;
namespace DTS.Common.Classes.Sensors
{
public class LinearizationFormula
{
private bool _bIsValid;
public bool IsValid() { return _bIsValid; }
public void MarkValid(bool bValid)
{
_bIsValid = bValid;
}
// Translation
public NonLinearSLICEWareStyles NonLinearSliceWareStyle
{
get => (NonLinearSLICEWareStyles)NonLinearStyle;
set => NonLinearStyle = (NonLinearStyles)value;
}
public NonLinearStyles NonLinearStyle { get; set; } = NonLinearStyles.Polynomial; // Dont make the default style one that locks a specific zero-method FB 10323
public double PolynomialSensitivity { get; set; } = 1D;
public double LinearizationExponent { get; set; } = 1D;
/// <summary>
/// THIS IS MM/V, (UI has already been updated, we need to update the variable name)
/// </summary>
private double _mmPerMV;
public double MMPerV
{
get => _mmPerMV;
set => _mmPerMV = value;
}
public double MVAt0MM { get; set; }
public double Slope { get; set; }
public double Intercept { get; set; }
public double CalibrationFactor { get; set; }
public double ZeroPositionIntercept { get; set; }
public LinearizationFormula()
{
ZeroPositionIntercept = 0D;
CalibrationFactor = 0D;
Intercept = 0D;
_coefficients = new List<double>(new double[] { 0, 0, 0, 0 });
_exponents = new List<double>(new double[] { 0, 1, 2, 3 });
}
public LinearizationFormula(LinearizationFormula copy)
{
UsemVOverVForPolys = copy.UsemVOverVForPolys;
_bIsValid = copy._bIsValid;
_coefficients = new List<double>(copy._coefficients.ToArray());
_exponents = new List<double>(copy._exponents.ToArray());
Intercept = copy.Intercept;
LinearizationExponent = copy.LinearizationExponent;
_mmPerMV = copy._mmPerMV;
MVAt0MM = copy.MVAt0MM;
Slope = copy.Slope;
NonLinearStyle = copy.NonLinearStyle;
_coefficients = new List<double>(copy._coefficients);
_exponents = new List<double>(copy._exponents);
PolynomialSensitivity = copy.PolynomialSensitivity;
ZeroPositionIntercept = copy.ZeroPositionIntercept;
CalibrationFactor = copy.CalibrationFactor;
}
public double GetCoefficient(double exponent)
{
for (var i = 0; i < _exponents.Count && i < _coefficients.Count; i++)
{
if (_exponents[i] == exponent) { return _coefficients[i]; }
}
return 0;
}
public void SetCoefficient(double exponent, double coefficient)
{
for (var i = 0; i < _exponents.Count && i < _coefficients.Count; i++)
{
if (_exponents[i] == exponent) { _coefficients[i] = coefficient; return; }
}
}
public double GetLinearizedValue(double input, double excitation, bool? isProportional = null)
{
if (NonLinearStyle != NonLinearStyles.Polynomial && input <= 0)
{
//ir-tracc should never be < 0, however we may get readings less than zero due to
//noise and other factors, treat these as positive near to zero
input = .001;
}
//first linearize
input /= 1000D;//assume input is in mV and we want it in Volts
input = Math.Pow(input, LinearizationExponent);
switch (NonLinearStyle)
{
case NonLinearStyles.IRTraccDiagnosticsZero:
return GetEUDiagnosticsZero(input);
case NonLinearStyles.IRTraccManual:
return GetEUIRTraccManual(input);
case NonLinearStyles.IRTraccZeroMMmV:
return GetEUZeroMMmV(input);
case NonLinearStyles.IRTraccAverageOverTime:
return GetEUAverageOverTime(input);
case NonLinearStyles.Polynomial:
//FB 29728 pass parameter isProportional, consider null as true to use the existing formula to divide by excitation
return GetEUPolynomial(input, excitation, isProportional ?? true);
case NonLinearStyles.IRTraccCalFactor:
return GetEUIRTraccCalFactor(input);
default:
throw new NotSupportedException("unknown format: " + NonLinearStyle);
}
}
private double GetEUIRTraccCalFactor(double volts)
{
return volts * CalibrationFactor + ZeroPositionIntercept;
}
private double GetEUIRTraccManual(double volts)
{
return (volts - Intercept) / Slope;
}
public bool UsemVOverVForPolys { get; set; } = true;
private double GetEUZeroMMmV(double volts)
{
var input = MVAt0MM / 1000D;
input = Math.Pow(input, LinearizationExponent);
if (double.IsNaN(input) || double.IsNegativeInfinity(input) || double.IsPositiveInfinity(input))
{
return volts * MMPerV;
}
return (volts * MMPerV - MMPerV * input);
}
private List<double> _coefficients = new List<double>();
private List<double> _exponents = new List<double>();
private double GetEUPolynomial(double volts, double excitation, bool isProportional)
{
//per J2517
//3.4 Use of the Calibration Coefficients
//The potentiometer assembly should be re-installed in the dummy without any mechanical adjustment of the
//potentiometer. Prior to a crash test, the original zero offset level must be preserved by either not zeroing the
//potentiometer (by signal conditioning or post-processing) or the amount that was zeroed must be added during postprocessing.
//During the test the absolute voltage output time history should be recorded. This voltage signal is then
//converted to engineering units by:
//1. Convert voltage signal to mV/V at the sensor. This is the sensor reading S.
//2. Convert the sensor reading S to displacement D by using the equation:
//D = A*S^3 + B*S^2 + C*S + M (Eq. 2)
//where:
//D is the displacement relative to the thorax design position in mm
//S is the sensor output reading in mV/V
//A, B, C, and M are the calibration coefficients
//NOTE: Make sure to use sufficient significant digits on all coefficients to assure accuracy of the conversion to
//engineering units. It is recommended to use 5 significant digits (example 0.000012345).
//double mV = volts * 1000D;
//double gain = 1D;
//mV = mV / (gain * excitation);
//if (0 != PolynomialSensitivity && 1!= PolynomialSensitivity) { mV /= PolynomialSensitivity; }
//double eu = 0D;
//for (int i = 0; i < _coefficients.Count && i < _exponents.Count; i++)
//{
// eu += _coefficients[i] * Math.Pow(mV, _exponents[i]);
//}
//return eu;
//CHANGED FOR GM TESTING
if (0 != PolynomialSensitivity && 1 != PolynomialSensitivity)
{
volts /= PolynomialSensitivity;
}
var voltsOverV = 0D;
//FB 29728 if is not proportinal then excitation voltage should be 1
if (!isProportional)
{
excitation = 1D;
}
if (UsemVOverVForPolys)
{
//convert to mV first
voltsOverV = volts * 1000D / excitation;
}
else
{
//used by GM
voltsOverV = volts / excitation;
}
double eu = 0;
for (var i = 0; i < _coefficients.Count && i < _exponents.Count; i++)
{
if (_exponents[i] != 0)
{
eu += _coefficients[i] * Math.Pow(voltsOverV, _exponents[i]);
}
else
{
eu += _coefficients[i];
}
}
return eu;
}
/// <summary>
/// MvAt0MM set at diagnostics
/// </summary>
/// <param name="volts"></param>
/// <returns></returns>
private double GetEUDiagnosticsZero(double volts)
{
//double input = MVAt0MM/1000D;
//input = System.Math.Pow(input,LinearizationExponent);
var input = double.NaN;
if (double.IsNaN(input) || double.IsPositiveInfinity(input) || double.IsNegativeInfinity(input))
{
return volts * MMPerV;
}
return volts * MMPerV - MMPerV * input;
}
/// <summary>
/// MVAt0MM set by diagnostics and then later on at
/// Average Over Time
/// </summary>
/// <param name="volts"></param>
/// <returns></returns>
private double GetEUAverageOverTime(double volts)
{
//double input = MVAt0MM / 1000D;
//input = System.Math.Pow(input, LinearizationExponent);
var input = double.NaN;
if (double.IsNaN(input) || double.IsNegativeInfinity(input) || double.IsPositiveInfinity(input))
{
return volts * MMPerV;
}
return volts * MMPerV - MMPerV * input;
}
public string ToSLICEWareSerializeString()
{
if (!_bIsValid) { return ""; }
var sb = new StringBuilder();
sb.AppendFormat("{0}_", NonLinearStyle);
switch (NonLinearStyle)
{
case NonLinearStyles.IRTraccDiagnosticsZero:
sb.Append(ToIRTraccDiagnosticZeroString());
break;
case NonLinearStyles.IRTraccManual:
sb.Append(ToIRTraccManualString());
break;
case NonLinearStyles.IRTraccZeroMMmV:
sb.Append(ToIRTraccZeroMMmVString());
break;
case NonLinearStyles.IRTraccAverageOverTime:
sb.Append(ToIRTraccAverageOverTimeString());
break;
case NonLinearStyles.Polynomial:
sb.Append(ToSLICEWarePolynomialString());
break;
case NonLinearStyles.IRTraccCalFactor:
throw new NotSupportedException("CalFactor not supported in SLICEWare");
default:
throw new NotSupportedException("unknown type: " + NonLinearStyle);
}
return sb.ToString();
}
/// <summary>
/// serializes to a string of the format "c0xe0 c1xe1...cnxen"
/// this will allow us arbitrary length polynomials and fractional exponents.
/// </summary>
/// <returns></returns>
public string ToSerializeString()
{
if (!_bIsValid) { return ""; }
var sb = new StringBuilder();
sb.AppendFormat("{0}_", NonLinearStyle);
switch (NonLinearStyle)
{
case NonLinearStyles.IRTraccDiagnosticsZero:
sb.Append(ToIRTraccDiagnosticZeroString());
break;
case NonLinearStyles.IRTraccManual:
sb.Append(ToIRTraccManualString());
break;
case NonLinearStyles.IRTraccZeroMMmV:
sb.Append(ToIRTraccZeroMMmVString());
break;
case NonLinearStyles.IRTraccAverageOverTime:
sb.Append(ToIRTraccAverageOverTimeString());
break;
case NonLinearStyles.Polynomial:
sb.Append(ToPolynomialString());
break;
case NonLinearStyles.IRTraccCalFactor:
sb.Append(ToIRTraccCalFactorString());
break;
default:
throw new NotSupportedException("unknown type: " + NonLinearStyle);
}
return sb.ToString();
}
public string ToIRTraccDiagnosticZeroString()
{
return $"{MMPerV.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{LinearizationExponent.ToString(System.Globalization.CultureInfo.InvariantCulture)}";
}
public string ToIRTraccCalFactorString()
{
return $"{CalibrationFactor.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{LinearizationExponent.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{ZeroPositionIntercept.ToString(System.Globalization.CultureInfo.InvariantCulture)}";
}
public void FromIRTraccCalFactorString(string s, System.Globalization.CultureInfo culture)
{
var tokens = s.Split('x');
if (tokens.Length < 3) { throw new NotSupportedException("Invalid CalFactor format: " + s); }
CalibrationFactor = double.Parse(tokens[0], culture);
LinearizationExponent = double.Parse(tokens[1], culture);
ZeroPositionIntercept = double.Parse(tokens[2], culture);
}
public void FromIRTraccDiagnosticZeroString(string s, System.Globalization.CultureInfo culture)
{
var tokens = s.Split('x');
if (tokens.Length < 2) { throw new NotSupportedException("Invalid DiagnosticsZero format: " + s); }
MMPerV = double.Parse(tokens[0], culture);
LinearizationExponent = double.Parse(tokens[1], culture);
}
public string ToIRTraccManualString()
{
return $"{Slope.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{Intercept.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{LinearizationExponent.ToString(System.Globalization.CultureInfo.InvariantCulture)}";
}
public void FromIRTraccManualString(string s, System.Globalization.CultureInfo culture)
{
var tokens = s.Split('x');
if (tokens.Length < 3) { throw new NotSupportedException("Invalid IRTraccManual format: " + s); }
Slope = double.Parse(tokens[0], culture);
Intercept = double.Parse(tokens[1], culture);
LinearizationExponent = double.Parse(tokens[2], culture);
}
public string ToIRTraccZeroMMmVString()
{
return $"{MMPerV.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{MVAt0MM.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{LinearizationExponent.ToString(System.Globalization.CultureInfo.InvariantCulture)}";
}
public string ToSLICEWarePolynomialString()
{
//SLICEWare is the reverse order of our DataPRO Database
var sb = new StringBuilder();
for (var i = _exponents.Count - 1; i >= 0; i--)
{
if (i != _exponents.Count - 1) { sb.Append(","); }
sb.AppendFormat("{0}x{1}", _coefficients[i].ToString(System.Globalization.CultureInfo.InvariantCulture),
_exponents[i].ToString(System.Globalization.CultureInfo.InvariantCulture));
}
sb.AppendFormat(",S={0}", PolynomialSensitivity.ToString(System.Globalization.CultureInfo.InvariantCulture));
return sb.ToString();
}
public string ToPolynomialString()
{
var sb = new StringBuilder();
for (var i = 0; i < _coefficients.Count && i < _exponents.Count; i++)
{
if (i > 0) { sb.Append(","); }
sb.AppendFormat("{0}x{1}", _coefficients[i].ToString(System.Globalization.CultureInfo.InvariantCulture),
_exponents[i].ToString(System.Globalization.CultureInfo.InvariantCulture));
}
sb.AppendFormat(",S={0},mV={1}",
PolynomialSensitivity.ToString(System.Globalization.CultureInfo.InvariantCulture),
UsemVOverVForPolys.ToString(System.Globalization.CultureInfo.InvariantCulture));
return sb.ToString();
}
public double[] PolynomialCoefficients
{
get => _coefficients.ToArray();
set => _coefficients = new List<double>(value);
}
public double[] PolynomialExponents
{
get => _exponents.ToArray();
set => _exponents = new List<double>(value);
}
public string ToIRTraccAverageOverTimeString()
{
return $"{MMPerV.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{LinearizationExponent.ToString(System.Globalization.CultureInfo.InvariantCulture)}";
}
public void FromIRTraccAverageOverTimeString(string s, System.Globalization.CultureInfo culture)
{
var tokens = s.Split('x');
if (tokens.Length < 2) { throw new NotSupportedException("Invalid IRTRaccAverageOverTime format: " + s); }
MMPerV = double.Parse(tokens[0], culture);
LinearizationExponent = double.Parse(tokens[1], culture);
}
public void FromIRTraccZeroMMmVString(string s, System.Globalization.CultureInfo culture)
{
var tokens = s.Split('x');
if (tokens.Length < 3) { throw new NotSupportedException("Invalid IRTraccZeroMMmV format: " + s); }
MMPerV = double.Parse(tokens[0], culture);
MVAt0MM = double.Parse(tokens[1], culture);
LinearizationExponent = double.Parse(tokens[2], culture);
}
public void FromPolynomialString(string s, System.Globalization.CultureInfo culture)
{
_coefficients.Clear();
_exponents.Clear();
var tokens = s.Split(',');
foreach (var t in tokens)
{
var subtokens = t.Split(new[] { 'x' }, StringSplitOptions.RemoveEmptyEntries);
if (2 == subtokens.Length)
{
if (double.TryParse(subtokens[0], System.Globalization.NumberStyles.Float, culture, out var d))
{
_coefficients.Add(d);
_exponents.Add(double.Parse(subtokens[1], culture));
}
else
{
PolynomialSensitivity = double.Parse(subtokens[1], culture);
}
}
else
{
subtokens = subtokens[0].Split('=');
if (subtokens.Length == 2)
{
switch (subtokens[0])
{
case "S":
PolynomialSensitivity = double.Parse(subtokens[1], culture);
break;
case "mV":
UsemVOverVForPolys = Convert.ToBoolean(subtokens[1], culture);
break;
}
}
}
}
}
public void FromSerializeString(string s, System.Globalization.CultureInfo culture)
{
if (string.IsNullOrEmpty(s)) { _bIsValid = false; return; }
if (s.Equals("1") || s.Equals("0") || s.Equals("1 ")) { _bIsValid = false; return; }
var tokens = s.Split('_');
if (tokens.Length < 2) { throw new NotSupportedException("unsupported Linearization Formula Format"); }
var style = (NonLinearStyles)Enum.Parse(typeof(NonLinearStyles), tokens[0], true);
NonLinearStyle = style;
switch (NonLinearStyle)
{
case NonLinearStyles.IRTraccDiagnosticsZero:
FromIRTraccDiagnosticZeroString(tokens[1], culture);
_bIsValid = true;
break;
case NonLinearStyles.IRTraccManual:
FromIRTraccManualString(tokens[1], culture);
_bIsValid = true;
break;
case NonLinearStyles.IRTraccZeroMMmV:
FromIRTraccZeroMMmVString(tokens[1], culture);
_bIsValid = true;
break;
case NonLinearStyles.Polynomial:
FromPolynomialString(tokens[1], culture);
_bIsValid = true;
break;
case NonLinearStyles.IRTraccAverageOverTime:
FromIRTraccAverageOverTimeString(tokens[1], culture);
_bIsValid = true;
break;
case NonLinearStyles.IRTraccCalFactor:
FromIRTraccCalFactorString(tokens[1], culture);
_bIsValid = true;
break;
default:
throw new NotSupportedException("Unknown format: " + NonLinearStyle);
}
}
public void FromSerializeString(string s)
{
FromSerializeString(s, System.Globalization.CultureInfo.InvariantCulture);
}
public void FromTDCSerializeString()
{
_bIsValid = true;
}
/// <summary>
/// Will return a display string for a nonlinear calibration based on N4 formating
/// </summary>
public string ToDisplayString()
{
return ToDisplayString("N4");
}
/// <summary>
/// Will return a display string for a nonlinear calibration based on 1st paramater formating string
/// </summary>
/// <param name="nonlinearFormat"></param>
/// <returns></returns>
public string ToDisplayString(string nonlinearFormat)
{
if (string.IsNullOrEmpty(nonlinearFormat)) { nonlinearFormat = "N4"; }
switch (NonLinearStyle)
{
case NonLinearStyles.Polynomial:
{
return ToPolynomial(nonlinearFormat);
}
case NonLinearStyles.IRTraccZeroMMmV:
{
return $"mV = {MVAt0MM:n4}, {MMPerV:n4}*(V^{ToSuperScript(LinearizationExponent.ToString(nonlinearFormat))})";
}
case NonLinearStyles.IRTraccManual:
{
return $"((V^{ToSuperScript(LinearizationExponent.ToString(nonlinearFormat))})-{Intercept:n4})/{Slope:n4}";
}
case NonLinearStyles.IRTraccDiagnosticsZero:
{
return $"{MMPerV:n4}*(V^{ToSuperScript(LinearizationExponent.ToString(nonlinearFormat))})";
}
case NonLinearStyles.IRTraccAverageOverTime:
{
return $"{MMPerV:n4}*(V^{ToSuperScript(LinearizationExponent.ToString(nonlinearFormat))})";
}
case NonLinearStyles.IRTraccCalFactor:
{
return $"{ZeroPositionIntercept:n4}+{CalibrationFactor:n4}*(V^{ToSuperScript(LinearizationExponent.ToString(nonlinearFormat))})";
}
default:
return string.Empty;
}
}
private string ToPolynomial(string nonlinearFormat)
{
if (string.IsNullOrEmpty(nonlinearFormat)) { nonlinearFormat = "N4"; }
var sb = new StringBuilder();
var termNumber = PolynomialCoefficients.Length - 1;
foreach (var x in PolynomialCoefficients)
{
if (PolynomialCoefficients[termNumber] == 0)
{
termNumber--;
continue;
}
double coeff = HandleSign(termNumber);
sb.Append(coeff.ToString(nonlinearFormat));
if (PolynomialExponents[termNumber] != 0)
{
sb.Append("x");
if (PolynomialExponents[termNumber] != 1)
{
sb.Append(ToSuperScript(PolynomialExponents[termNumber].ToString("N0")));
}
}
if (termNumber > 0)
{
// Coerricients are Displayed in absolute value. We need to combine the sign with the addition symbol
sb.Append(PolynomialCoefficients[termNumber - 1] > 0 ? " + " : " - ");
}
termNumber--;
}
return sb.ToString();
}
private double HandleSign(int termNumber)
{
double coeff = PolynomialCoefficients[termNumber];
// Let the appended math symbol handle sign unless we're the first term.
if (termNumber != PolynomialCoefficients.Length - 1)
{
coeff = Math.Abs(coeff);
}
return coeff;
}
private string ToSuperScript(string source)
{
var superScript = new StringBuilder();
foreach (var c in source)
{
switch (c)
{
case '-':
superScript.Append('\u207B');
break;
case '.':
superScript.Append('\u00B7');
break;
case '1':
superScript.Append('\u00B9');
break;
case '2':
superScript.Append('\u00B2');
break;
case '3':
superScript.Append('\u00B3');
break;
case '4':
superScript.Append('\u2074');
break;
case '5':
superScript.Append('\u2075');
break;
case '6':
superScript.Append('\u2076');
break;
case '7':
superScript.Append('\u2077');
break;
case '8':
superScript.Append('\u2078');
break;
case '9':
superScript.Append('\u2079');
break;
case '0':
superScript.Append('\u2070');
break;
case '\'':
superScript.Append('\u02C8');
break;
case ',':
superScript.Append('\u22C5'); // there is no unicode superscript comma. this comes close
break;
case '\u00A0':
superScript.Append('\u2009'); // unicode 'thin' space
break;
default:
superScript.Append('\u207F');
break;
}
}
return superScript.ToString();
}
/*
* we are given an equation in the form of y = ax^1 + b, except x and y are backwards for us (y=V where we'd prefer X was voltage, so we switch it)
* y/a - b/a = x, and then switch y and x, (1/a)x^1 -(b/a)x^0 = y
* now we want to get the coefficient of the first equation, which is "a", we get this by taking the inverse
* we get b on the other hand by taking -1 * (b/a)*a. if we have the "coefficient", we have a
*/
/*
public double GetIRTraccCoefficient()
{
foreach (Factor f in Factors)
{
if (f.Exponent == 1D) { return System.Math.Pow(f.Coefficient, -1); }
}
return 1D; //0 doesn't make sense for ir
}
public double GetIRTraccConstant()
{
foreach (Factor f in Factors)
{
if (f.Exponent == 0D) { return -1D * GetIRTraccCoefficient() * f.Coefficient; }
}
return 0D;
}
public void SetIRTraccFactor(double coefficient, double constant)
{
if (0 == coefficient)
{
//well this doesn't make any sense ...
coefficient = 1;
}
Factors = new Factor[]
{
new Factor(1/coefficient,1),
new Factor(-constant/coefficient,0),
};
}*/
}
}

View File

@@ -0,0 +1,112 @@
using DTS.Common.Enums.Sensors;
using DTS.Common.Interface.Sensors;
using System;
using System.Collections.Generic;
namespace DTS.Common.Classes.Sensors
{
/// <summary>
/// internal helper class to avoid passing a huge number of parameters between methods
/// right now it's needed both in the Wizard CSV import code and in DataPRO CSV import code
/// but it can probably be moved to only be in Wizard CSV import code when DataPRO CSV import code is removed
/// for now it lives here.
/// </summary>
public class ParseParameters
{
private ISensorData _sd;
public ISensorData SensorData { get => _sd; set => _sd = value; }
private IFormatProvider _importCulture;
public IFormatProvider ImportCulture { get => _importCulture; set => _importCulture = value; }
private List<string> _errors;
public List<string> Errors { get => _errors; set => _errors = value; }
private double _dIrTraccExponent;
public double IrtraccExponent { get => _dIrTraccExponent; set => _dIrTraccExponent = value; }
private ISensorCalibration _sc;
public ISensorCalibration SensorCal { get => _sc; set => _sc = value; }
private double _dSensitivity;
public double Sensitivity { get => _dSensitivity; set => _dSensitivity = value; }
private bool _bSavedIsProportional;
public bool SavedIsProportional { get => _bSavedIsProportional; set => _bSavedIsProportional = value; }
private bool _savedRemoveOffset;
public bool SavedRemoveOffset { get => _savedRemoveOffset; set => _savedRemoveOffset = value; }
private bool _stripBackslash;
public bool StripBackslash { get => _stripBackslash; set => _stripBackslash = value; }
private double _dOriginalOffset;
public double OriginalOffset { get => _dOriginalOffset; set => _dOriginalOffset = value; }
private ZeroMethodType _zmt;
public ZeroMethodType ZeroType { get => _zmt; set => _zmt = value; }
private double _zeroMethodEnd;
public double ZeroEnd
{
get => _zeroMethodEnd; set => _zeroMethodEnd = value;
}
private double _zeroMethodStart;
public double ZeroStart { get => _zeroMethodStart; set => _zeroMethodStart = value; }
private ISquibSettingDefaults _squibDefaults;
public ISquibSettingDefaults SquibDefaults
{
get => _squibDefaults; set => _squibDefaults = value;
}
private IDigitalOutDefaults _digitalOutDefaults;
public IDigitalOutDefaults DigitalOutDefaults
{
get => _digitalOutDefaults; set => _digitalOutDefaults = value;
}
private Dictionary<string, string> _sensorGroupNameLookup;
public Dictionary<string, string> SensorGroupNameLookup
{
get => _sensorGroupNameLookup; set => _sensorGroupNameLookup = value;
}
private Dictionary<string, string> _sensorGroupTypeLookup;
public Dictionary<string, string> SensorGroupTypeLookup
{
get => _sensorGroupTypeLookup; set => _sensorGroupTypeLookup = value;
}
private Dictionary<string, string> _groupNameToTestObjectLookup;
public Dictionary<string, string> GroupNameToTestObjectLookup { get => _groupNameToTestObjectLookup; set => _groupNameToTestObjectLookup = value; }
private string _sensorTestObject;
public string SensorTestObject { get => _sensorTestObject; set => _sensorTestObject = value; }
private bool _bUseISOCodeFilterMapping;
public bool UseISOCodeFilterMapping { get => _bUseISOCodeFilterMapping; set => _bUseISOCodeFilterMapping = value; }
private bool _bUseZeroForUnfiltered;
public bool UseZeroForUnfiltered { get => _bUseZeroForUnfiltered; set => _bUseZeroForUnfiltered = value; }
private Dictionary<string, string> _SensorISOCode;
public Dictionary<string, string> SensorISOCode { get=> _SensorISOCode; set=> _SensorISOCode = value; }
private Dictionary<string, string> _SensorISOChannelName;
public Dictionary<string, string> SensorISOChannelName { get=> _SensorISOChannelName; set=> _SensorISOChannelName = value; }
private Dictionary<string, string> _SensorUserCode;
public Dictionary<string, string> SensorUserCode { get=> _SensorUserCode; set=> _SensorUserCode = value; }
private Dictionary<string, string> _SensorUserChannelName;
public Dictionary<string, string> SensorUserChannelName { get=> _SensorUserChannelName; set=> _SensorUserChannelName = value; }
private Dictionary<string, string> _SensorDASSerialNumber;
public Dictionary<string, string> SensorDASSerialNumber { get => _SensorDASSerialNumber; set => _SensorDASSerialNumber = value; }
private Dictionary<string, int> _SensorDASChannelIndex;
public Dictionary<string, int> SensorDASChannelIndex { get=> _SensorDASChannelIndex; set=> _SensorDASChannelIndex = value; }
}
}

View File

@@ -0,0 +1,177 @@
using DTS.Common.Base;
using DTS.Common.Enums.Sensors;
using DTS.Common.Interface.Sensors;
using DTS.Common.Utilities.Logging;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data;
using System.Globalization;
using System.Linq;
namespace DTS.Common.Classes.Sensors
{
public class SensorCalDbRecord : BasePropertyChanged, ISensorCalDbRecord
{
public bool LinearAdded
{
get => NonLinear && Records.Records[0].Poly.NonLinearStyle == NonLinearStyles.Polynomial &&
Records.Records.Length > 1 && ZeroMethods.Methods.Length > 1;
}
private int? _calibrationId = null;
/// <summary>
/// database id, if known, for calibration, null indicates not known
/// 13065 Sensor "First Use" Date
/// </summary>
[Key]
public int? CalibrationId
{
get => _calibrationId;
set => SetProperty(ref _calibrationId, value, "CalibrationId");
}
protected string _serialNumber;
public string SerialNumber
{
get => _serialNumber;
set => SetProperty(ref _serialNumber, value, "SerialNumber");
}
protected DateTime _calibrationDate;
[Column(TypeName = "datetime")]
public DateTime CalibrationDate
{
get => _calibrationDate;
set => SetProperty(ref _calibrationDate, value, "CalibrationDate");
}
protected string _userName = "";
[Required]
[StringLength(50)]
public string Username
{
get => _userName;
set => SetProperty(ref _userName, value, "Username");
}
private bool _localOnly;
public bool LocalOnly
{
get => _localOnly;
set => SetProperty(ref _localOnly, value, "LocalOnly");
}
private bool _nonLinear;
public bool NonLinear
{
get => _nonLinear;
set
{
SetProperty(ref _nonLinear, value, "NonLinear");
if (!value) return;
Records.Records.First().Sensitivity = 1D;
//FB 29728 don't make IsProportinal false
//IsProportional = false;
RemoveOffset = false;
}
}
private ICalibrationRecords _records = new CalibrationRecords();
[Required]
[StringLength(255)]
public ICalibrationRecords Records
{
get => _records;
set => SetProperty(ref _records, value, "Records");
}
private DateTime _modifyDate;
[Column(TypeName = "datetime")]
public DateTime ModifyDate
{
get => _modifyDate;
set => SetProperty(ref _modifyDate, value, "ModifyDate");
}
private bool _isProportional;
public bool IsProportional
{
get => _isProportional;
set => SetProperty(ref _isProportional, value, "IsProportional");
}
private bool _removeOffset;
public bool RemoveOffset
{
get => _removeOffset;
set => SetProperty(ref _removeOffset, value, "RemoveOffset");
}
private ZeroMethods _zeroMethods = new ZeroMethods();
[Required]
[StringLength(255)]
public ZeroMethods ZeroMethods
{
get => _zeroMethods;
set => SetProperty(ref _zeroMethods, value, "ZeroMethods");
}
private string[] _certificationDocuments = new string[0];
[Required]
[StringLength(2048)]
public string[] CertificationDocuments
{
get => _certificationDocuments;
set => SetProperty(ref _certificationDocuments, value, "CertificationDocuments");
}
//FB18158 It's None the default now not EU
private InitialOffsets _initialOffsets = new InitialOffsets(new InitialOffset());
public InitialOffsets InitialOffsets
{
get => _initialOffsets;
set => SetProperty(ref _initialOffsets, value, "InitialOffsets");
}
public SensorCalDbRecord() { }
public SensorCalDbRecord(ISensorCalDbRecord copy)
{
CalibrationDate = copy.CalibrationDate;
LocalOnly = copy.LocalOnly;
SerialNumber = copy.SerialNumber;
Username = copy.Username;
Records = new CalibrationRecords(copy.Records);
NonLinear = copy.NonLinear;
IsProportional = copy.IsProportional;
ModifyDate = copy.ModifyDate;
var list = new List<string>(copy.CertificationDocuments);
CertificationDocuments = list.ToArray();
RemoveOffset = copy.RemoveOffset;
ZeroMethods = new ZeroMethods(copy.ZeroMethods);
InitialOffsets = new InitialOffsets(copy.InitialOffsets);
CalibrationId = copy.CalibrationId;
//this is downright silly, but because the linearization formula marks itself valid when it deserializes with data in it, we go and correct it here.
Records.Records[0].Poly.MarkValid(NonLinear);
}
public SensorCalDbRecord(IDataReader reader)
{
try
{
CalibrationDate = Utility.GetDateTime(reader, "CalibrationDate", DateTime.MinValue);
LocalOnly = Utility.GetBool(reader, "LocalOnly", false);
SerialNumber = Utility.GetString(reader, "SerialNumber");
Username = Utility.GetString(reader, "Username");
Records = new CalibrationRecords(Utility.GetString(reader, "CalibrationRecords"));
NonLinear = Utility.GetBool(reader, "NonLinear");
IsProportional = Utility.GetBool(reader, "IsProportional");
ModifyDate = Utility.GetDateTime(reader, "ModifyDate", DateTime.MinValue);
CertificationDocuments = Utility.GetString(reader, "CertificationDocuments").Split(new[] { CultureInfo.InvariantCulture.TextInfo.ListSeparator }, StringSplitOptions.None).ToArray();
RemoveOffset = Utility.GetBool(reader, "RemoveOffset");
ZeroMethods = new ZeroMethods(Utility.GetString(reader, "ZeroMethod"));
InitialOffsets = new InitialOffsets(Utility.GetString(reader, "InitialOffset"));
CalibrationId = Utility.GetNullableInt(reader, "SensorCalibrationId");
//this is downright silly, but because the linearization formula marks itself valid when it deserializes with data in it, we go and correct it here.
Records.Records[0].Poly.MarkValid(NonLinear);
}
catch (Exception ex)
{
APILogger.Log("Failed to process Sensor Calibration record", ex);
}
}
}
}

View File

@@ -0,0 +1,38 @@
using System.Data;
using DTS.Common.Interface.Tags;
using DTS.Common.Interface.Sensors;
namespace DTS.Common.Classes.Sensors
{
public class SensorDbRecord : TagAwareBase, ISensorDbRecord
{
public override TagTypes TagType => TagTypes.SensorModels;
protected int _id = 0;
public int id
{
get => _id;
set => SetProperty(ref _id, value, "id");
}
protected short _sensorType = 0;
public short SensorType
{
get => _sensorType;
set => SetProperty(ref _sensorType, value, "SensorType");
}
protected string _serialNumber = string.Empty;
public string SerialNumber
{
get => _serialNumber;
set => SetProperty(ref _serialNumber, value, "SerialNumber");
}
public SensorDbRecord(IDataReader reader)
{
id = Utility.GetInt(reader, "id", 0);
SensorType = Utility.GetShort(reader, "SensorType", 0);
SerialNumber = Utility.GetString(reader, "SerialNumber");
}
}
}

View File

@@ -0,0 +1,18 @@
using DTS.Common.Interface.Sensors.SensorsList;
namespace DTS.Common.Classes.Sensors.SensorsList
{
public class DragAndDropPayload
{
public IDragAndDropItem [] Items { get; }
public DragAndDropPayload(IDragAndDropItem[] items)
{
Items = items;
}
public const string FORMAT = "DTS.Common.Classes.Sensors.SensorsList.DragAndDropPayload";
public const string ALT_FORMAT = "ALT_DTS.Common.Classes.Sensors.SensorsList.DragAndDropPayload";
public const string CTRL_FORMAT = "CTRL_DTS.Common.Classes.Sensors.SensorsList.DragAndDropPayload";
}
}

View File

@@ -0,0 +1,316 @@
using DTS.Common.Base;
using DTS.Common.Enums;
using DTS.Common.Interface.Sensors;
using DTS.Common.Utilities.Logging;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data;
using System.Linq;
namespace DTS.Common.Classes.Sensors
{
public class SquibDbRecord : BasePropertyChanged, ISquibDbRecord
{
private string _serialNumber = "";
public string SerialNumber
{
get => _serialNumber;
set => SetProperty(ref _serialNumber, value, "SerialNumber");
}
private int _id = -1;
[Key]
public int Id
{
get => _id;
set => SetProperty(ref _id, value, "Id");
}
private bool _bypassCurrentFilter = false;
public bool BypassCurrentFilter
{
get => _bypassCurrentFilter;
set => SetProperty(ref _bypassCurrentFilter, value, "BypassCurrentFilter");
}
private bool _bypassVoltageFilter = false;
public bool BypassVoltageFilter
{
get => _bypassVoltageFilter;
set => SetProperty(ref _bypassVoltageFilter, value, "BypassVoltageFilter");
}
private double _delayMS = 0D;
[Column("DelayMS")]
public double DelayMs
{
get => _delayMS;
set => SetProperty(ref _delayMS, value, "DelayMs");
}
private double _durationMS = 10D;
[Column("DurationMS")]
public double DurationMs
{
get => _durationMS;
set => SetProperty(ref _durationMS, value, "DurationMs");
}
private SquibFireMode _fireMode = SquibFireMode.NONE;
public SquibFireMode FireMode
{
get => _fireMode;
set => SetProperty(ref _fireMode, value, "FireMode");
}
private string _isoCode = "";
[Required]
[StringLength(50)]
public string IsoCode
{
get => _isoCode;
set => SetProperty(ref _isoCode, value, "IsoCode");
}
private string _isoChannelName = "";
[Required]
[StringLength(255)]
public string IsoChannelName
{
get => _isoChannelName;
set => SetProperty(ref _isoChannelName, value, "IsoChannelName");
}
private string _userCode = "";
[Required]
[StringLength(50)]
public string UserCode
{
get => _userCode;
set => SetProperty(ref _userCode, value, "UserCode");
}
private string _userChannelName = "";
[Required]
[StringLength(255)]
public string UserChannelName
{
get => _userChannelName;
set => SetProperty(ref _userChannelName, value, "UserChannelName");
}
private SquibMeasurementType _squibMeasurementType = SquibMeasurementType.VOLTAGE;
public SquibMeasurementType MeasurementType
{
get => _squibMeasurementType;
set => SetProperty(ref _squibMeasurementType, value, "MeasurementType");
}
private double _squibOutputCurrent = 1.5D;
public double SquibOutputCurrent
{
get => _squibOutputCurrent;
set => SetProperty(ref _squibOutputCurrent, value, "SquibOutputCurrent");
}
private double _squibToleranceLow = 1D;
public double SquibToleranceLow
{
get => _squibToleranceLow;
set => SetProperty(ref _squibToleranceLow, value, "SquibToleranceLow");
}
private double _squibToleranceHigh = 8D;
public double SquibToleranceHigh
{
get => _squibToleranceHigh;
set => SetProperty(ref _squibToleranceHigh, value, "SquibToleranceHigh");
}
private bool _limitDuration = true;
public bool LimitDuration
{
get => _limitDuration;
set => SetProperty(ref _limitDuration, value, "LimitDuration");
}
private string _articleId = "";
[Required]
[StringLength(50)]
public string ArticleId
{
get => _articleId;
set => SetProperty(ref _articleId, value, "ArticleId");
}
private int _version = 1;
public int Version
{
get => _version;
set => SetProperty(ref _version, value, "Version");
}
private DateTime _lastModified = DateTime.MinValue;
[Column(TypeName = "datetime")]
public DateTime LastModified
{
get => _lastModified;
set => SetProperty(ref _lastModified, value, "LastModified");
}
private string _lastModifiedBy = "";
[Required]
[StringLength(50)]
public string LastModifiedBy
{
get => _lastModifiedBy;
set => SetProperty(ref _lastModifiedBy, value, "LastModifiedBy");
}
private string _userValue1 = "";
[StringLength(255)]
public string UserValue1
{
get => _userValue1;
set => SetProperty(ref _userValue1, value, "UserValue1");
}
private string _userValue2 = "";
[StringLength(255)]
public string UserValue2
{
get => _userValue2;
set => SetProperty(ref _userValue2, value, "UserValue2");
}
private string _userValue3 = "";
[StringLength(255)]
public string UserValue3
{
get => _userValue3;
set => SetProperty(ref _userValue3, value, "UserValue3");
}
private byte[] _userTags = new byte[0];
public byte[] UserTags
{
get => _userTags;
set => SetProperty(ref _userTags, value, "UserTags");
}
private bool _doNotUse = false;
public bool DoNotUse
{
get => _doNotUse;
set => SetProperty(ref _doNotUse, value, "DoNotUse");
}
private bool _broken = false;
public bool Broken
{
get => _broken;
set => SetProperty(ref _broken, value, "Broken");
}
private bool _defineDelayInTest = false;
public bool DefineDelayInTest
{
get => _defineDelayInTest;
set => SetProperty(ref _defineDelayInTest, value, "DefineDelayInTest");
}
public SquibDbRecord(ISensorData copy, bool defineDelayInTest, byte [] tags)
{
Id = copy.DatabaseId;
IsoChannelName = copy.ISOChannelName;
UserCode = copy.UserCode;
UserChannelName = copy.UserChannelName;
Broken = copy.Broken;
DoNotUse = copy.DoNotUse;
Version = copy.Version;
SquibToleranceLow = copy.SquibToleranceLow;
SquibToleranceHigh = copy.SquibToleranceHigh;
SquibOutputCurrent = copy.SquibOutputCurrent;
SerialNumber = copy.SerialNumber;
MeasurementType = copy.SquibMeasurementType;
LimitDuration = copy.LimitDuration;
DefineDelayInTest = defineDelayInTest;
LastModifiedBy = copy.LastUpdatedBy;
LastModified = copy.LastModified;
IsoCode = copy.ISOCode;
FireMode = copy.SquibFireMode;
DurationMs = copy.SquibFireDurationMS;
DelayMs = copy.SquibFireDelayMS;
BypassVoltageFilter = copy.BypassVoltageFilter;
BypassCurrentFilter = copy.BypassCurrentFilter;
ArticleId = copy.EID;
UserValue1 = copy.UserValue1;
UserValue2 = copy.UserValue2;
UserValue3 = copy.UserValue3;
if (null == tags) { UserTags = null; }
else if (tags.Any())
{
var userTags = new byte[tags.Length];
Array.Copy(tags, userTags, tags.Length);
UserTags = userTags;
}
else { UserTags = new byte[0]; }
}
public SquibDbRecord() { }
public SquibDbRecord(ISquibDbRecord copy)
{
Id = copy.Id;
IsoChannelName = copy.IsoChannelName;
UserCode = copy.UserCode;
UserChannelName = copy.UserChannelName;
Broken = copy.Broken;
DoNotUse = copy.DoNotUse;
Version = copy.Version;
SquibToleranceLow = copy.SquibToleranceLow;
SquibToleranceHigh = copy.SquibToleranceHigh;
SquibOutputCurrent = copy.SquibOutputCurrent;
SerialNumber = copy.SerialNumber;
MeasurementType = copy.MeasurementType;
LimitDuration = copy.LimitDuration;
DefineDelayInTest = copy.DefineDelayInTest;
LastModifiedBy = copy.LastModifiedBy;
LastModified = copy.LastModified;
IsoCode = copy.IsoCode;
FireMode = copy.FireMode;
DurationMs = copy.DurationMs;
DelayMs = copy.DelayMs;
BypassVoltageFilter = copy.BypassVoltageFilter;
BypassCurrentFilter = copy.BypassCurrentFilter;
ArticleId = copy.ArticleId;
UserValue1 = copy.UserValue1;
//Comment = UserValue1;
UserValue2 = copy.UserValue2;
UserValue3 = copy.UserValue3;
if( null == copy.UserTags) { UserTags = null; }
else if(copy.UserTags.Any())
{
var userTags = new byte[copy.UserTags.Length];
Array.Copy(copy.UserTags, userTags, copy.UserTags.Length);
UserTags = userTags;
}
else { UserTags = new byte[0]; }
}
public SquibDbRecord(IDataReader reader)
{
try
{
Id = Utility.GetInt(reader, "Id", -1);
IsoChannelName = Utility.GetString(reader, "ISOChannelName", string.Empty);
UserCode = Utility.GetString(reader, "UserCode", string.Empty);
UserChannelName = Utility.GetString(reader, "UserChannelName", string.Empty);
Broken = Utility.GetBool(reader, "Broken", false);
DoNotUse = Utility.GetBool(reader, "DoNotUse", false);
Version = Utility.GetInt(reader, "Version", -1);
SquibToleranceLow = Utility.GetDouble(reader, "SquibToleranceLow", 0D);
SquibToleranceHigh = Utility.GetDouble(reader, "SquibToleranceHigh", 8D);
SquibOutputCurrent = Utility.GetDouble(reader, "SquibOutputCurrent", 1.5D);
SerialNumber = Utility.GetString(reader, "SerialNumber", string.Empty);
MeasurementType = (SquibMeasurementType)Utility.GetShort(reader, "MeasurementType");
LimitDuration = Utility.GetBool(reader, "LimitDuration");
DefineDelayInTest = Utility.GetBool(reader, "DefineDelayInTest");
LastModifiedBy = Utility.GetString(reader, "LastModifiedBy", string.Empty);
LastModified = Utility.GetDateTime(reader, "LastModified", DateTime.MinValue);
IsoCode = Utility.GetString(reader, "ISOCode", string.Empty);
FireMode = (SquibFireMode)Utility.GetShort(reader, "FireMode");
DurationMs = Utility.GetDouble(reader, "DurationMS", 0D);
DelayMs = Utility.GetDouble(reader, "DelayMS", 0D);
BypassVoltageFilter = Utility.GetBool(reader, "BypassVoltageFilter", false);
BypassCurrentFilter = Utility.GetBool(reader, "BypassCurrentFilter", false);
ArticleId = Utility.GetString(reader, "ArticleId", string.Empty);
UserValue1 = Utility.GetString(reader, "UserValue1");
//Comment = UserValue1;
UserValue2 = Utility.GetString(reader, "UserValue2", string.Empty);
UserValue3 = Utility.GetString(reader, "UserValue3", string.Empty);
var o = reader["UserTags"];
UserTags = DBNull.Value.Equals(o)
? new byte[0]
: (byte[])o;
}
catch (Exception ex)
{
APILogger.Log("Failed to process: ", ex);
}
}
}
}

View File

@@ -0,0 +1,98 @@
using DTS.Common.Enums;
using DTS.Common.Interface.Sensors;
using DTS.Common.Interface.Tags;
using DTS.Common.Utilities.Logging;
using System;
using System.Data;
namespace DTS.Common.Classes.Sensors
{
public class StreamInputRecord : TagAwareBase, IStreamInputRecord
{
public override TagTypes TagType => TagTypes.Sensors;
private int _id;
public int Id
{
get => _id;
set => SetProperty(ref _id, value, "Id");
}
private string _serialNumber;
public string SerialNumber
{
get => _serialNumber;
set => SetProperty(ref _serialNumber, value, "SerialNumber");
}
private DateTime _lastModified;
public DateTime LastModified
{
get => _lastModified;
set => SetProperty(ref _lastModified, value, "LastModified");
}
private string _lastUpdatedBy;
public string LastUpdatedBy
{
get => _lastUpdatedBy;
set => SetProperty(ref _lastUpdatedBy, value, "LastUpdatedBy");
}
private bool _doNotUse;
public bool DoNotUse
{
get => _doNotUse;
set => SetProperty(ref _doNotUse, value, "DoNotUse");
}
private bool _broken;
public bool Broken
{
get => _broken;
set => SetProperty(ref _broken, value, "Broken");
}
public const string DEFAULT_UDP_ADDRESS = "UDP://239.1.2.10:8400";
protected string _udpAddress = DEFAULT_UDP_ADDRESS;
public string StreamInUDPAddress
{
get => _udpAddress;
set => SetProperty(ref _udpAddress, value, "StreamInUDPAddress");
}
public StreamInputRecord(ISensorData sd)
{
try
{
Id = sd.DatabaseId;
SerialNumber = sd.SerialNumber;
StreamInUDPAddress = sd.StreamInUDPAddress;
Broken = sd.Broken;
DoNotUse = sd.DoNotUse;
LastModified = sd.LastModified;
LastUpdatedBy = sd.LastUpdatedBy;
}
catch (Exception ex)
{
APILogger.Log("Failed to process: ", ex);
}
}
public StreamInputRecord(IDataReader reader)
{
try
{
Id = Utility.GetInt(reader, "Id");
SerialNumber = Utility.GetString(reader, "SerialNumber");
StreamInUDPAddress = Utility.GetString(reader, "UDPAddress");
Broken = Utility.GetBool(reader, "Broken");
DoNotUse = Utility.GetBool(reader, "DoNotUse");
LastModified = Utility.GetDateTime(reader, "LastModified", DateTime.MinValue);
LastUpdatedBy = Utility.GetString(reader, "LastModifiedBy");
}
catch (Exception ex)
{
APILogger.Log("Failed to process: ", ex);
}
}
}
}

View File

@@ -0,0 +1,212 @@
using DTS.Common.Enums;
using DTS.Common.Interface.Sensors;
using DTS.Common.Interface.Tags;
using DTS.Common.Utilities.Logging;
using System;
using System.Collections.Generic;
using System.Data;
namespace DTS.Common.Classes.Sensors
{
public class StreamOutputRecord : TagAwareBase, IStreamOutputRecord
{
public override TagTypes TagType => TagTypes.Sensors;
private int _id;
public int Id
{
get => _id;
set => SetProperty(ref _id, value, "Id");
}
private string _serialNumber;
public string SerialNumber
{
get => _serialNumber;
set => SetProperty(ref _serialNumber, value, "SerialNumber");
}
private DateTime _lastModified;
public DateTime LastModified
{
get => _lastModified;
set => SetProperty(ref _lastModified, value, "LastModified");
}
private string _lastUpdatedBy;
public string LastUpdatedBy
{
get => _lastUpdatedBy;
set => SetProperty(ref _lastUpdatedBy, value, "LastUpdatedBy");
}
private bool _doNotUse;
public bool DoNotUse
{
get => _doNotUse;
set => SetProperty(ref _doNotUse, value, "DoNotUse");
}
private bool _broken;
public bool Broken
{
get => _broken;
set => SetProperty(ref _broken, value, "Broken");
}
protected UDPStreamProfile _udpProfile = DEFAULT_UDP_PROFILE;
public const UDPStreamProfile DEFAULT_UDP_PROFILE = UDPStreamProfile.CH10_ANALOG_2HDR; //supported on both S6A & TSRAIR
public UDPStreamProfile StreamOutUDPProfile
{
get => _udpProfile;
set => SetProperty(ref _udpProfile, value, "StreamOutUDPProfile");
}
public const string DEFAULT_UDP_ADDRESS = "UDP://239.1.2.10:8400";
protected string _udpAddress = DEFAULT_UDP_ADDRESS;
public string StreamOutUDPAddress
{
get => _udpAddress;
set => SetProperty(ref _udpAddress, value, "StreamOutUDPAddress");
}
public const ushort MINIMUM_STREAMOUT_TIMECHANNELID = 10;
public const ushort MAXIMUM_STREAMOUT_TIMECHANNELID = 100;
public const ushort DEFAULT_UDP_TIME_CHANNEL_ID = 1;
protected ushort _udpTimeChannelId = DEFAULT_UDP_TIME_CHANNEL_ID;
public ushort StreamOutUDPTimeChannelId
{
get => _udpTimeChannelId;
set => SetProperty(ref _udpTimeChannelId, value, "StreamOutUDPTimeChannelId");
}
public const ushort MINIMUM_STREAMOUT_DATACHANNELID = 10;
public const ushort MAXIMUM_STREAMOUT_DATACHANNELID = 100;
public const ushort DEFAULT_UDP_DATA_CHANNEL_ID = 3;
protected ushort _udpDataChannelId = DEFAULT_UDP_DATA_CHANNEL_ID;
public ushort StreamOutUDPDataChannelId
{
get => _udpDataChannelId;
set => SetProperty(ref _udpDataChannelId, value, "StreamOutUDPDataChannelId");
}
public const string DEFAULT_UDPTMNS_CONFIG = "(1,6,60,0,0,0,0,0)";
protected string _udpTmNSConfig = DEFAULT_UDPTMNS_CONFIG;
public string StreamOutUDPTmNSConfig
{
get => _udpTmNSConfig;
set => SetProperty(ref _udpTmNSConfig, value, "StreamOutUDPTmNSConfig");
}
public const ushort MINIMUM_STREAMOUT_TDP_INTERVAL_MS = 10;
public const ushort MAXIMUM_STREAMOUT_TDP_INTERVAL_MS = 1000;
public const ushort DEFAULT_IRIG_TIME_DATA_PACKET_INTERVAL_MS = 500;
protected ushort _irigTimeDataPacketIntervalMs = DEFAULT_IRIG_TIME_DATA_PACKET_INTERVAL_MS;
public const ushort MINIMUM_STREAMOUT_TMATS_INTERVAL_MS = ushort.MinValue;
public const ushort MAXIMUM_STREAMOUT_TMATS_INTERVAL_MS = ushort.MaxValue;
private ushort _streamOutTMATSIntervalMs = DEFAULT_TMATS_INTERVAL_MS;
/// <summary>
/// time in MS between sending tmats information while streaming
/// http://manuscript.dts.local/f/cases/29987/Add-CG-DP-TMATS-interval-UI-support
/// </summary>
public ushort StreamOutTMATSIntervalMs
{
get => _streamOutTMATSIntervalMs;
set => SetProperty(ref _streamOutTMATSIntervalMs, value, "StreamOutTMATSIntervalMs");
}
public ushort StreamOutIRIGTimeDataPacketIntervalMs
{
get => _irigTimeDataPacketIntervalMs;
set => SetProperty(ref _irigTimeDataPacketIntervalMs, value, "StreamOutIRIGTimeDataPacketIntervalMs");
}
public StreamOutputRecord(ISensorData sd)
{
try
{
Id = sd.DatabaseId;
SerialNumber = sd.SerialNumber;
StreamOutUDPProfile = sd.StreamOutUDPProfile;
StreamOutUDPAddress = sd.StreamOutUDPAddress;
StreamOutUDPTimeChannelId = sd.StreamOutUDPTimeChannelId;
StreamOutUDPDataChannelId = sd.StreamOutUDPDataChannelId;
StreamOutUDPTmNSConfig = sd.StreamOutUDPTmNSConfig;
StreamOutIRIGTimeDataPacketIntervalMs = sd.StreamOutIRIGTimeDataPacketIntervalMs;
StreamOutTMATSIntervalMs = sd.StreamOutTMATSIntervalMs;
Broken = sd.Broken;
DoNotUse = sd.DoNotUse;
LastModified = sd.LastModified;
LastUpdatedBy = sd.LastUpdatedBy;
}
catch (Exception ex)
{
APILogger.Log("Failed to process: ", ex);
}
}
public StreamOutputRecord(IDataReader reader, int ClientDbVersion, int ConnectionDbVersion)
{
try
{
Id = Utility.GetInt(reader, "Id");
SerialNumber = Utility.GetString(reader, "SerialNumber");
StreamOutUDPProfile = (UDPStreamProfile)Enum.Parse(typeof(UDPStreamProfile),
Utility.GetString(reader, "StreamProfile"));
StreamOutUDPAddress = Utility.GetString(reader, "UDPAddress");
StreamOutUDPTimeChannelId = Utility.GetUShort(reader, "TimeChannelId");
StreamOutUDPDataChannelId = Utility.GetUShort(reader, "DataChannelId");
StreamOutUDPTmNSConfig = Utility.GetString(reader, "TmNSConfig");
StreamOutIRIGTimeDataPacketIntervalMs = Utility.GetUShort(reader, "IRIGTimeDataPacketIntervalMs");
Broken = Utility.GetBool(reader, "Broken");
DoNotUse = Utility.GetBool(reader, "DoNotUse");
LastModified = Utility.GetDateTime(reader, "LastModified", DateTime.MinValue);
LastUpdatedBy = Utility.GetString(reader, "LastModifiedBy");
//only try to retrieve this field if both client and db are high enough level
if (ClientDbVersion >= Constants.TMATS_INTERVAL_VERSION && ConnectionDbVersion >= Constants.TMATS_INTERVAL_VERSION)
{
StreamOutTMATSIntervalMs = Utility.GetUShort(reader, "TMATS_IntervalMS", StreamOutputRecord.DEFAULT_TMATS_INTERVAL_MS);
}
}
catch (Exception ex)
{
APILogger.Log("Failed to process: ", ex);
}
}
//28291 Reduce list of Stream profiles to choose from.
//Define this here so that it only needs to be changed in one place, if a change needs to be made in the future.
//30249 Add LTS behavior for case 30075 (ADC UART stream)
public static UDPStreamProfile[] AvailableUDPStreamProfiles(int ConnectionDbVersion, bool UseAdvancedStreamingProfiles)
{
var profiles = new List<UDPStreamProfile>();
if (UseAdvancedStreamingProfiles)
{
profiles.AddRange(
new UDPStreamProfile[]
{
UDPStreamProfile.CH10_ANALOG,
UDPStreamProfile.CH10_ANALOG_2HDR,
UDPStreamProfile.CH10_PCM128_MM,
UDPStreamProfile.CH10_PCM_128BIT_2HDR,
UDPStreamProfile.TMNS_PCM_STANDARD,
UDPStreamProfile.TMNS_PCM_SUPERCOM,
UDPStreamProfile.IENA_PTYPE_STREAM,
UDPStreamProfile.CH10_MANUAL_CONFIG
});
if (ConnectionDbVersion >= Constants.ADC_TO_UART_DB_VERSION)
{
profiles.Add(UDPStreamProfile.UART_STREAM);
}
}
else
{
// 31840 Basic / Advanced Streaming profiles
profiles.AddRange(
new UDPStreamProfile[]
{
UDPStreamProfile.CH10_ANALOG_2HDR,
UDPStreamProfile.CH10_PCM_128BIT_2HDR
});
}
return profiles.ToArray();
}
/// <summary>
/// the default interval between sending out tmats information while streaming
/// this is used if the value is not set or is null
/// http://manuscript.dts.local/f/cases/29987/Add-CG-DP-TMATS-interval-UI-support
/// </summary>
public const ushort DEFAULT_TMATS_INTERVAL_MS = 1000;
}
}

View File

@@ -0,0 +1,138 @@
using DTS.Common.Base;
using DTS.Common.Enums;
using DTS.Common.Interface.Sensors;
using DTS.Common.Interface.Tags;
using DTS.Common.Utilities.Logging;
using System;
using System.Data;
using System.IO.Ports;
namespace DTS.Common.Classes.Sensors
{
public class UARTRecord : TagAwareBase, IUARTRecord
{
public override TagTypes TagType { get => TagTypes.Sensors; }
private int _id;
public int Id
{
get => _id;
set => SetProperty(ref _id, value, "Id");
}
private string _serialNumber;
public string SerialNumber
{
get => _serialNumber;
set => SetProperty(ref _serialNumber, value, "SerialNumber");
}
public const uint UART_BAUDRATE_DEFAULT = 57600;
private uint _uartBaudRate = UART_BAUDRATE_DEFAULT;
public uint UartBaudRate
{
get => _uartBaudRate;
set => _uartBaudRate = value;
}
public const uint UART_DATABITS_DEFAULT = 8;
private uint _uartDataBits = UART_DATABITS_DEFAULT;
public uint UartDataBits
{
get => _uartDataBits;
set => SetProperty(ref _uartDataBits, value, "UartDataBits");
}
private StopBits _uartStopBits = StopBits.None;
public const StopBits UART_STOPBITS_DEFAULT = StopBits.None;
public StopBits UartStopBits
{
get => _uartStopBits;
set => _uartStopBits = value;
}
public const UartDataFormat UART_DATAFORMAT_DEFAULT = UartDataFormat.Binary;
public const Handshake UART_FLOWCONTROL_DEFAULT = Handshake.None;
protected Handshake _flowControl = Handshake.None;
public Handshake UartFlowControl
{
get => _flowControl;
set => SetProperty(ref _flowControl, value, "UartFlowControl");
}
private UartDataFormat _uartDataFormat = UART_DATAFORMAT_DEFAULT;
public UartDataFormat UartDataFormat
{
get => _uartDataFormat;
set => SetProperty(ref _uartDataFormat, value, "UartDataFormat");
}
private DateTime _lastModified;
public DateTime LastModified
{
get => _lastModified;
set => SetProperty(ref _lastModified, value, "LastModified");
}
private string _lastUpdatedBy;
public string LastUpdatedBy
{
get => _lastUpdatedBy;
set => SetProperty(ref _lastUpdatedBy, value, "LastUpdatedBy");
}
private bool _doNotUse;
public bool DoNotUse
{
get => _doNotUse;
set => SetProperty(ref _doNotUse, value, "DoNotUse");
}
private bool _broken;
public bool Broken
{
get => _broken;
set => SetProperty(ref _broken, value, "Broken");
}
public const Parity UART_PARITY_DEFAULT = Parity.None;
protected Parity _parity = Parity.None;
public Parity UartParity
{
get => _parity;
set => SetProperty(ref _parity, value, "UartParity");
}
public UARTRecord(ISensorData sensor)
{
Id = sensor.DatabaseId;
SerialNumber = sensor.SerialNumber;
UartBaudRate = sensor.UartBaudRate;
UartDataBits = sensor.UartDataBits;
UartStopBits = sensor.UartStopBits;
UartParity = sensor.UartParity;
UartFlowControl = sensor.UartFlowControl;
UartDataFormat = sensor.UartDataFormat;
Broken = sensor.Broken;
DoNotUse = sensor.DoNotUse;
LastModified = sensor.LastModified;
LastUpdatedBy = sensor.LastUpdatedBy;
}
public UARTRecord(IDataReader reader)
{
try
{
Id = Utility.GetInt(reader,"Id");
SerialNumber = Utility.GetString(reader, "SerialNumber");
UartBaudRate = Utility.GetUInt(reader, "BaudRate");
UartDataBits = Utility.GetUInt(reader, "DataBits");
UartStopBits = (StopBits)Enum.Parse(typeof(StopBits), Utility.GetString(reader, "StopBits"));
UartParity = (Parity)Enum.Parse(typeof(Parity), Utility.GetString(reader, "Parity"));
UartFlowControl = (Handshake)Enum.Parse(typeof(Handshake), Utility.GetString(reader, "FlowControl"));
UartDataFormat = (UartDataFormat)Enum.Parse(typeof(UartDataFormat), Utility.GetString(reader, "DataFormat"));
Broken = Utility.GetBool(reader, "Broken");
DoNotUse = Utility.GetBool(reader, "DoNotUse");
LastModified = Utility.GetDateTime(reader, "LastModified", DateTime.MinValue);
LastUpdatedBy = Utility.GetString(reader, "LastModifiedBy");
}
catch (Exception ex)
{
APILogger.Log("Failed to process: ", ex);
}
}
}
}

View File

@@ -0,0 +1,304 @@
using System;
using System.Text;
using System.Xml.Linq;
using System.ComponentModel;
using DTS.Common.Utilities.Logging;
using DTS.Common.Enums.Sensors;
using DTS.Common.Interface.Sensors;
using System.Collections.Generic;
namespace DTS.Common.Classes.Sensors
{
public class ZeroMethod : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, String propertyName = null)
{
if (Equals(storage, value)) return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public override int GetHashCode()
{
return Method.GetHashCode() + Start.GetHashCode() + End.GetHashCode();
}
public ZeroMethodType Method { get; set; } = SensorConstants.DefaultZeroMethodType; // FB12764: Belt-and-suspenders, fetch default from SensorConstants
public double Start { get; set; } = SensorConstants.DefaultZeroMethodStart; // FB12764: Belt-and-suspenders, fetch default from SensorConstants
public double End { get; set; } = SensorConstants.DefaultZeroMethodEnd; // FB12764: Belt-and-suspenders, fetch default from SensorConstants
#region Tags
internal const string ZERO_METHOD_TAG = "ZeroMethod";
internal const string METHOD_TAG = "Method";
internal const string START_TAG = "Start";
internal const string END_TAG = "End";
#endregion
public ZeroMethod(ZeroMethodType zm, double start, double end)
{
Method = zm;
Start = start;
End = end;
}
public ZeroMethod(string zm, System.Globalization.CultureInfo culture)
{
Initialize(zm, culture);
}
public ZeroMethod(string zm)
{
Initialize(zm, System.Globalization.CultureInfo.InvariantCulture);
}
/// <summary>
/// do a deep copy
/// </summary>
/// <param name="copy"></param>
public ZeroMethod(ZeroMethod copy)
{
Method = copy.Method;
Start = copy.Start;
End = copy.End;
}
private void Initialize(string zm, System.Globalization.CultureInfo culture)
{
var tokens = zm.Split(',');
if (tokens.Length < 3) { return; }
Start = Convert.ToDouble(tokens[1], culture);
End = Convert.ToDouble(tokens[2], culture);
if( tokens[0].Contains("PreCalZero") )
{
Method = ZeroMethodType.UsePreEventDiagnosticsZero;
}
else
{
Method = (ZeroMethodType)
Enum.Parse(typeof(ZeroMethodType), tokens[0]);
}
}
public string ToDbString()
{
return $"{Method.ToString()},{Start},{End}";
}
private readonly string _tableName;
public ZeroMethod(XElement elem, string prefix, string tblName, string id)
{
_tableName = tblName;
XElement inner;
try
{
inner = elem.Element(mkTag(prefix));
}
catch (ArgumentNullException)
{
if (!string.IsNullOrEmpty(id))
{
throw new Exception($"{_tableName}: Can't find tag {prefix + "-" + ZERO_METHOD_TAG} for entry {id}");
}
throw new Exception($"{_tableName}: Can't find tag {prefix + "-" + ZERO_METHOD_TAG} in file");
}
try
{
// this is a special case to remain compatible with older TDM
// I moved this to avoid the exception
// 6/8/2010 - dtm
if (inner.Value == "UsePreCalZero")
{
Method = ZeroMethodType.UsePreEventDiagnosticsZero;
}
else if (inner.Value == ZeroMethodType.UsePreEventDiagnosticsZero.ToString())
{
inner.Value = "UsePreCalZero";
Method = ZeroMethodType.UsePreEventDiagnosticsZero;
}
else
{
Method = (ZeroMethodType) Enum.Parse(typeof(ZeroMethodType), inner.Value);
}
}
catch (ArgumentException ex)
{
APILogger.Log(ex);
throw;
}
Start = double.Parse(inner.Attribute(START_TAG).Value, System.Globalization.CultureInfo.InvariantCulture);
End = double.Parse(inner.Attribute(END_TAG).Value, System.Globalization.CultureInfo.InvariantCulture);
}
internal XElement ToXElement(string prefix)
{
string value;
switch (Method)
{
case ZeroMethodType.UsePreEventDiagnosticsZero:
value = "UsePreCalZero";
break;
default:
value = Method.ToString();
break;
}
var element = new XElement(mkTag(prefix), value);
element.SetAttributeValue(START_TAG, Start);
element.SetAttributeValue(END_TAG, End);
return element;
}
internal void Update(XElement elem, string prefix)
{
elem.SetElementValue(mkTag(prefix), Method.ToString());
var element = elem.Element(mkTag(prefix));
element.SetAttributeValue(START_TAG, Start);
element.SetAttributeValue(END_TAG, End);
}
internal static string mkTag(string prefix)
{
return prefix + "-" + ZERO_METHOD_TAG;
}
public string ToSerializeString()
{
return $"{Method.ToString()},{Start.ToString(System.Globalization.CultureInfo.InvariantCulture)},{End.ToString(System.Globalization.CultureInfo.InvariantCulture)}";
}
public string ToDisplayString(string averageOverTimeFormatString, string diagnosticLevelFormatString, string absoluteZeroFormatString)
{
var sb = new StringBuilder();
switch (Method)
{
case ZeroMethodType.AverageOverTime:
sb.AppendFormat("{0} from {1} to {2}", averageOverTimeFormatString, Start, End);
break;
case ZeroMethodType.UsePreEventDiagnosticsZero:
sb.AppendFormat("{0}", diagnosticLevelFormatString);
break;
case ZeroMethodType.None:
sb.AppendFormat("{0}", absoluteZeroFormatString);
break;
}
return sb.ToString();
}
public override bool Equals(object obj)
{
if (obj is ZeroMethod zm)
{
return zm.Method == Method && zm.Start == Start && zm.End == End;
}
return base.Equals(obj);
}
}
public class ZeroMethods : IZeroMethods
{
public ZeroMethod[] Methods { get; set; } = new ZeroMethod[] { };
public ZeroMethods(ZeroMethods copy) : this(copy.Methods)
{
}
public ZeroMethods(ZeroMethod[] copyMethods)
{
ZeroMethod[] methods = new ZeroMethod[copyMethods.Length];
for (int i = 0; i < copyMethods.Length; i++)
{
methods[i] = new ZeroMethod(copyMethods[i]);
}
Methods = methods;
}
public ZeroMethods()
{
Methods = new ZeroMethod[] { };
}
public ZeroMethods(string methods)
{
FromSerializedString(methods);
}
public ZeroMethods(ZeroMethod startingMethod)
{
Methods = new ZeroMethod[] { startingMethod };
}
public override bool Equals(object obj)
{
if (obj is ZeroMethods r)
{
if (r.Methods.Length != Methods.Length) { return false; }
for (int i = 0; i < r.Methods.Length; i++)
{
if (!r.Methods[i].Equals(Methods[i])) { return false; }
}
return true;
}
return base.Equals(obj);
}
public void FromSerializedString(string s)
{
string[] tokens = s.Split(new string[] { MySeparator }, StringSplitOptions.None);
for (int i = 0; i < tokens.Length; i++) { tokens[i] = tokens[i].Replace(MySeparatorBackup, MySeparator); }
List<ZeroMethod> methods = new List<ZeroMethod>();
foreach (string token in tokens)
{
methods.Add(new ZeroMethod(token));
}
Methods = methods.ToArray();
}
private const string MySeparator = "__x__";
private const string MySeparatorBackup = "___xx___";
public string ToSerializedString()
{
List<string> methods = new List<string>();
foreach (var r in Methods) { methods.Add(r.ToSerializeString()); }
for (int i = 0; i < methods.Count; i++)
{
System.Diagnostics.Trace.Assert(!methods[i].Contains(MySeparatorBackup));
methods[i] = methods[i].Replace(MySeparator, MySeparatorBackup);
}
return string.Join(MySeparator, methods.ToArray());
}
public string ToDisplayString(string averageOverTimeFormatString, string diagnosticLevelFormatString, string absoluteZeroFormatString)
{
StringBuilder sb = new StringBuilder();
/*foreach (var r in Methods)
{
if (currentMethod > 1) { sb.AppendLine(); }
sb.AppendFormat("{0}: {1}", currentMethod++, r.ToDisplayString(sc));
}*/
for (int i = 0; i < Methods.Length; i++)
{
if (i > 0) { sb.AppendLine(); }
string s = Methods[i].ToDisplayString(averageOverTimeFormatString, diagnosticLevelFormatString, absoluteZeroFormatString);
if (!string.IsNullOrEmpty(s))
{
sb.Append(s);
}
}
return sb.ToString();
}
public override string ToString()
{
return ToDisplayString(Strings.Strings.SensorFields_InitialOffset_AverageOverTimeFormat, Strings.Strings.SensorFields_InitialOffset_DiagnosticLevelFormat,
Strings.Strings.SensorFields_InitialOffset_AbsoluteZeroFormat);
}
}
}

View File

@@ -0,0 +1,52 @@
using System;
namespace DTS.Common.Classes.Sensors
{
/// <summary>
/// public helper class for ZeroRefence in SIFs, which is serialized to an int
/// </summary>
public class ZeroRef
{
public enum ZeroType
{
AverageOverTime,
UsePreEventDiagnostics,
UseZeroMv
}
public ZeroType ZeroMethod { get; }
public ZeroRef(string zeroref)
{
switch (zeroref)
{
case "0":
ZeroMethod = ZeroType.AverageOverTime;
break;
case "1":
ZeroMethod = ZeroType.UsePreEventDiagnostics;
break;
case "2":
ZeroMethod = ZeroType.UseZeroMv;
break;
default:
throw new NotSupportedException("TDAS::ZeroRef Invalid ZeroRef " + zeroref);
}
}
public ZeroRef(ZeroType type) { ZeroMethod = type; }
public override string ToString()
{
switch (ZeroMethod)
{
case ZeroType.AverageOverTime:
return "0";
case ZeroType.UsePreEventDiagnostics:
return "1";
case ZeroType.UseZeroMv:
return "2";
default:
throw new NotSupportedException("TDAS::ZeroRef Invalid ZeroRef " + ZeroMethod);
}
}
}
}