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; using System.Reflection; namespace DTS.Common.Classes.Sensors { /// /// represents a record of an analog sensor in the db /// /// public class AnalogDbRecord : TagAwareBase, IAnalogDbRecord { public override TagTypes TagType => TagTypes.SensorModels; protected int _id = -1; /// /// the database id of the sensor /// [Key] public int Id { get => _id; set => SetProperty(ref _id, value, "Id"); } protected string _serialNumber = ""; /// /// Serial number of sensor /// [required to be unique] /// [Required] [StringLength(50)] public string SerialNumber { get => _serialNumber; set => SetProperty(ref _serialNumber, value, "SerialNumber"); } protected short _axisNumber = 0; /// /// deprecated /// which axis the record is for when the sensor is multi-axis /// public short AxisNumber { get => _axisNumber; set => SetProperty(ref _axisNumber, value, "AxisNumber"); } protected short _bridgeLegMode; /// /// deprecated /// public short BridgeLegMode { get => _bridgeLegMode; set => SetProperty(ref _bridgeLegMode, value, "BridgeLegMode"); } protected double _bridgeResistance = 350D; /// /// the expected resistance in Ohms if applicable for the sensor /// public double BridgeResistance { get => _bridgeResistance; set => SetProperty(ref _bridgeResistance, value, "BridgeResistance"); } protected SensorConstants.BridgeType _bridge = SensorConstants.BridgeType.FullBridge; /// /// the type of bridge or sensor /// [DO NOT USE BITMASKED VALUE WHEN READING/WRITING TO DB] /// public SensorConstants.BridgeType Bridge { get => _bridge; set => SetProperty(ref _bridge, value, "Bridge"); } protected void SetBridge(SensorConstants.BridgeType bridge) { _bridge = bridge; } protected bool _broken = false; /// /// Whether the sensor has been marked as broken by a user /// public bool Broken { get => _broken; set => SetProperty(ref _broken, value, "Broken"); } protected bool _bypassFilter = false; /// /// whether the sensor has it's own filtering or should otherwise bypass /// hardware filters when collecting data /// (not supported on all hardware) /// public bool BypassFilter { get => _bypassFilter; set => SetProperty(ref _bypassFilter, value, "BypassFilter"); } protected bool _calibrationSignal; /// /// deprecated? /// public bool CalibrationSignal { get => _calibrationSignal; set => SetProperty(ref _calibrationSignal, value, "CalibrationSignal"); } protected int _calInterval = 365; /// /// calibration interval in days, used in determining when sensor is out of cal /// public int CalInterval { get => _calInterval; set => SetProperty(ref _calInterval, value, "CalInterval"); } protected double _capacity = 2400D; /// /// capacity of the sensor in EU /// public double Capacity { get => _capacity; set => SetProperty(ref _capacity, value, "Capacity"); } protected bool _checkOffset = true; /// /// Whether to check the sensor output in mV against thresholds in diagnostics /// public bool CheckOffset { get => _checkOffset; set => SetProperty(ref _checkOffset, value, "CheckOffset"); } protected string _comment = ""; /// /// user supplied descriptive comment on sensor /// [Required] [StringLength(50)] public string Comment { get => _comment; set => SetProperty(ref _comment, value, "Comment"); } protected SensorConstants.CouplingModes _couplingMode = SensorConstants.CouplingModes.AC; /// /// IEPE coupling mode to use for data collection if applicable /// public SensorConstants.CouplingModes CouplingMode { get => _couplingMode; set => SetProperty(ref _couplingMode, value, "CouplingMode"); } protected DateTime _created; /// /// date sensor record was created (if available) /// [Column(TypeName = "datetime")] public DateTime Created { get => _created; set => SetProperty(ref _created, value, "Created"); } protected bool _diagnosticsMode = false; /// /// Whether this sensor should only record internal resistance and record no external signal /// [generally only useful for testing purposes] /// public bool DiagnosticsMode { get => _diagnosticsMode; set => SetProperty(ref _diagnosticsMode, value, "DiagnosticsMode"); } protected string _displayUnit = ""; /// /// 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 /// public string DisplayUnit { get => _displayUnit; set => SetProperty(ref _displayUnit, value, "DisplayUnit"); } protected bool _doNotUse = false; /// /// whether this sensor has been marked not to be used by user /// public bool DoNotUse { get => _doNotUse; set => SetProperty(ref _doNotUse, value, "DoNotUse"); } public bool InspectBeforeUseCleared { get; set; } protected double _sensitivityTolerancePercent = Constants.SENSITIVITY_CHANGE_TOLERANCE_PERCENT_DEFAULT; /// ///default SensitivityTolerancePercent /// public double SensitivityTolerancePercent { get => _sensitivityTolerancePercent; set => SetProperty(ref _sensitivityTolerancePercent, value, "SensitivityTolerancePercent"); } protected string _eId = ""; /// /// Electronic Identification tag /// [DALLAS or TEDS ID TAG] /// if present required to be unique /// [Required] [Column("eId")] [StringLength(50)] public string EId { get => _eId; set => SetProperty(ref _eId, value, "EId"); } protected double _externalShuntResistance; /// /// TDAS supports external resistance when measuring shunt resistance /// this is the value of external resistance applied /// public double ExternalShuntResistance { get => _externalShuntResistance; set => SetProperty(ref _externalShuntResistance, value, "ExternalShuntResistance"); } private IFilterClass _filter = new FilterClass(FilterClassType.CFC1000); /// /// The default software filter class to apply to data channel when viewing /// filtered EU data /// public IFilterClass Filter { get => _filter; set => SetProperty(ref _filter, value, "Filter"); } private double? _initialEU; /// /// 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 /// [Column("InitialEU")] [Required] [StringLength(50)] public double? InitialEu { get => _initialEU; set => SetProperty(ref _initialEU, value, "InitialEu"); } protected double _internalShuntResistance; /// /// TDAS supports performing external and internal resistance when measuring shunt resistance /// This is the value to use when internal shunt resistance is used /// public double InternalShuntResistance { get => _internalShuntResistance; set => SetProperty(ref _internalShuntResistance, value, "InternalShuntResistance"); } protected bool _invert = false; /// /// whether output of the sensor in EU should be inverted or not /// public bool Invert { get => _invert; set => SetProperty(ref _invert, value, "Invert"); } private string _isoChannelName = string.Empty; /// /// ISO 13499 channel name to apply to a data channel when a data channel is /// created using the sensor /// [Required] [StringLength(255)] public string ISOChannelName { get => _isoChannelName; set => SetProperty(ref _isoChannelName, value, "ISOChannelName"); } private string _isoCode = string.Empty; /// /// ISO 13499 code to apply to a data channel when a data channel is created /// using the sensor /// [Required] [StringLength(50)] public string ISOCode { get => _isoCode; set => SetProperty(ref _isoCode, value, "ISOCode"); } private DateTime _lastModified = (DateTime)SqlDateTime.MinValue; /// /// when the sensor was last modified /// [Column(TypeName = "datetime")] public DateTime LastModified { get => _lastModified; set => SetProperty(ref _lastModified, value, "LastModified"); } protected bool _localOnly = false; /// /// deprecated, used to determine which sensors should not propagate up to central database /// public bool LocalOnly { get => _localOnly; set => SetProperty(ref _localOnly, value, "LocalOnly"); } protected string _manufacturer = ""; /// /// Maker of sensor /// [StringLength(50)] public string Manufacturer { get => _manufacturer; set => SetProperty(ref _manufacturer, value, "Manufacturer"); } protected string _model = ""; /// /// model of sensor /// [StringLength(50)] public string Model { get => _model; set => SetProperty(ref _model, value, "Model"); } private string _modifiedBy = ""; /// /// who last modified the sensor record /// [Required] [StringLength(50)] public string ModifiedBy { get => _modifiedBy; set => SetProperty(ref _modifiedBy, value, "ModifiedBy"); } private short _numberOfAxes = 1; /// /// deprecated/reserved /// number of axes associated with this serial number /// public short NumberOfAxes { get => _numberOfAxes; set => SetProperty(ref _numberOfAxes, value, "NumberOfAxes"); } protected double _offsetToleranceHigh = SensorConstants.DefaultBridgeOffsetMVTolHigh; /// /// 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 /// public double OffsetToleranceHigh { get => _offsetToleranceHigh; set => SetProperty(ref _offsetToleranceHigh, value, "OffsetToleranceHigh"); } protected double _offsetToleranceLow = SensorConstants.DefaultBridgeOffsetMVTolLow; /// /// 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 /// public double OffsetToleranceLow { get => _offsetToleranceLow; set => SetProperty(ref _offsetToleranceLow, value, "OffsetToleranceLow"); } private double _rangeMedium; /// /// typical medium range for sensor in applications /// public double RangeMedium { get => 0 == _rangeMedium ? Capacity : _rangeMedium; set => SetProperty(ref _rangeMedium, value, "RangeMedium"); } private double _rangeHigh; /// /// typical high range for sensor in applications /// public double RangeHigh { get => 0 == _rangeHigh ? Capacity : _rangeHigh; set => SetProperty(ref _rangeHigh, value, "RangeHigh"); } private double _rangeLow; /// /// typical low range for sensor in applications /// public double RangeLow { get => 0 == _rangeLow ? Capacity : _rangeLow; set => SetProperty(ref _rangeLow, value, "RangeLow"); } protected int _sensorCategory; /// /// The type of sensor /// Deprecated, remains for TDC purposes /// Normal = 0, /// POT = 1, /// IRTracc = 2, /// Polynomial = 3 /// public int SensorCategory { get => _sensorCategory; set => SetProperty(ref _sensorCategory, value, "SensorCategory"); } private int _sensorModelId; /// /// the database id of the sensor model, if applicable /// public int SensorModelId { get => _sensorModelId; set => SetProperty(ref _sensorModelId, value, "SensorModelId"); } private const short SHUNT_MODE_EMULATION = 1; protected short _shunt = SHUNT_MODE_EMULATION; /// /// 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 /// public short Shunt { get => _shunt; set => SetProperty(ref _shunt, value, "Shunt"); } protected SensorStatus _status = SensorStatus.Available; [Required] [StringLength(50)] /// /// reserved/not in use /// public SensorStatus Status { get => _status; set => SetProperty(ref _status, value, "Status"); } protected ExcitationVoltageOptions.ExcitationVoltageOption[] _supportedExcitation = new[] { ExcitationVoltageOptions.ExcitationVoltageOption.Volt5 }; /// /// 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) /// [Required] [StringLength(50)] public ExcitationVoltageOptions.ExcitationVoltageOption[] SupportedExcitation { get => _supportedExcitation; set => SetProperty(ref _supportedExcitation, value, "SupportedExcitation"); } protected long _timesUsed; /// /// Reserved/Not used /// public long TimesUsed { get => _timesUsed; set => SetProperty(ref _timesUsed, value, "TimesUsed"); } protected bool _uniPolar = false; /// /// flag indicating that the sensor should be interpreted as 0-n rather than -x<0 public bool UniPolar { get => _uniPolar; set => SetProperty(ref _uniPolar, value, "UniPolar"); } private string _userChannelName = string.Empty; /// /// User channel name to apply when sensor is applied to a blank channel /// [Required] [StringLength(255)] public string UserChannelName { get => _userChannelName; set => SetProperty(ref _userChannelName, value, "UserChannelName"); } private string _userCode = string.Empty; /// /// User channel code to apply when sensor is applied to a blank channel /// [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; /// /// user supplied string /// travels with the sensor to data channels when /// data is recorded with the sensor /// [StringLength(50)] public string UserValue1 { get => _userValue1; set => SetProperty(ref _userValue1, value, "UserValue1"); } protected string _userValue2 = string.Empty; /// /// user supplied string /// travels with the sensor to data channels when /// data is recorded with the sensor /// [StringLength(50)] public string UserValue2 { get => _userValue2; set => SetProperty(ref _userValue2, value, "UserValue2"); } protected string _userValue3 = string.Empty; /// /// user supplied string /// travels with the sensor to data channels when /// data is recorded with the sensor /// [StringLength(50)] public string UserValue3 { get => _userValue3; set => SetProperty(ref _userValue3, value, "UserValue3"); } private int _version = 1; /// /// deprecated /// public int Version { get => _version; set => SetProperty(ref _version, value, "Version"); } private DateTime? _firstUseDate; [Column(TypeName = "datetime")] /// /// Date of first destructive use since sensor was calibrated, /// only valid when using latest calibration /// null indicates not set /// public DateTime? FirstUseDate { get => _firstUseDate; set => SetProperty(ref _firstUseDate, value, "FirstUseDate"); } private int? _latestCalibrationId; /// /// deprecated /// Originally held the id of the latest calibration record /// for sensor /// public int? LatestCalibrationId { get => _latestCalibrationId; set => SetProperty(ref _latestCalibrationId, value, "LatestCalibrationId"); } private string _assemblyName = string.Empty; public string AssemblyName { get => _assemblyName; set => SetProperty(ref _assemblyName, value, "AssemblyName"); } private int _usageCount = 0; public int UsageCount { get => _usageCount; set => SetProperty(ref _usageCount, value, "UsageCount"); } private int _maximumUsage = 2500; public int MaximumUsage { get => _maximumUsage; set => SetProperty(ref _maximumUsage, value, "MaximumUsage"); } private bool _dontAllowDataCollectionIfOverused = false; public bool DontAllowDataCollectionIfOverused { get => _dontAllowDataCollectionIfOverused; set => SetProperty(ref _dontAllowDataCollectionIfOverused, value, "DontAllowDataCollectionIfOverused"); } private int _sensorUsageWarningCount = 5; public int SensorUsageWarningCount { get => _sensorUsageWarningCount; set => SetProperty(ref _sensorUsageWarningCount, value, "SensorUsageWarningCount"); } 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; //43046 SensitivityTolerancePercent = copy.SensitivityTolerancePercent; Id = copy.Id; FirstUseDate = copy.FirstUseDate; LatestCalibrationId = copy.LatestCalibrationId; ACCouplingModeEnabled = copy.ACCouplingModeEnabled; AssemblyName = copy.AssemblyName; UsageCount = copy.UsageCount; MaximumUsage = copy.MaximumUsage; } public AnalogDbRecord(IDataReader reader, int actualDbVersion) { 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); if (actualDbVersion >= Constants.SENSOR_ASSEMBLY_DB_VERSION) { //43046 SensitivityTolerancePercent = Utility.GetDouble(reader, "SensitivityTolerancePercent", Constants.SENSITIVITY_CHANGE_TOLERANCE_PERCENT_DEFAULT); AssemblyName = Utility.GetString(reader, "AssemblyName").Trim(); UsageCount = Utility.GetInt(reader, "UsageCount", 0); MaximumUsage = Utility.GetInt(reader, "MaximumUsage", 2500); } } public void SetSupportedExcitationFromString(string s) { var excitations = new List(); 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; /// /// whether to use AC Coupling when using a bridge mode (full/half/quarter/half+sig) /// 18294 Implement Bridge AC/DC coupling(fw update dependent) /// public bool ACCouplingModeEnabled { get => _bACCouplingModeEnabled; set => SetProperty(ref _bACCouplingModeEnabled, value, "ACCouplingModeEnabled"); } } }