Files
DP44/DataPRO/SensorDB/SensorCalibration.cs
2026-04-17 14:55:32 -04:00

814 lines
42 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Data;
using System.ComponentModel;
using System.Data.SqlClient;
using System.Globalization;
using DTS.Common.Enums;
using DTS.Common.Storage;
using DTS.Common.Utilities.Logging;
using DTS.Common.Enums.Sensors;
using DTS.Common.Classes.Sensors;
using DTS.Common.Interface.Sensors;
using LinearizationFormula = DTS.Common.Classes.Sensors.LinearizationFormula;
namespace DTS.SensorDB
{
public class SensorCalibration : SensorCalDbRecord, IComparable<SensorCalibration>, ISensorCalibration
{
public long CalVersion { get; set; } = long.MinValue;
public string EngineeringUnits
{
get => Records.Records[0].EngineeringUnits;
}
internal const string TOP_LEVEL_TAG = "Calibrations";
internal const string CALIBRATION_TAG = "Calibration";
public enum XMLFields
{
Version,
SerialNumber,
Date,
Sensitivity,
Username,
DocumentID,
MeasurementUnit,
Excitation,
Zmo,
Poly
}
public bool SimpleEquals(SensorCalibration sc)
{
if (null == sc) { return false; }
var fields = Enum.GetValues(typeof(Fields)).Cast<Fields>().ToArray();
foreach (var field in fields)
{
switch (field)
{
case Fields.CalibrationDate: if (sc.CalibrationDate.Date != CalibrationDate.Date) { return false; } break;
case Fields.CalibrationRecords: if (!sc.Records.Records[0].IsEqual(Records.Records[0], this)) { return false; } break;
case Fields.IRTraccCalculationType: if (sc.IRTraccCalculationType != IRTraccCalculationType) { return false; } break;
case Fields.IsProportional: if (sc.IsProportional != IsProportional) { return false; } break;
case Fields.InitialOffsets: if (!sc.InitialOffsets.Equals(InitialOffsets)) { return false; } break; // FB5429
case Fields.LocalOnly: if (sc.LocalOnly != LocalOnly) { return false; } break;
case Fields.NonLinear: if (sc.NonLinear != NonLinear) { return false; } break;
case Fields.RemoveOffset: if (sc.RemoveOffset != RemoveOffset) { return false; } break;
case Fields.SerialNumber: if (sc.SerialNumber != SerialNumber) { return false; } break;
case Fields.ModifyDate: break;
case Fields.Username: break;
case Fields.SensitivityInspection: break;
case Fields.ZeroMethods: if (!sc.ZeroMethods.Equals(ZeroMethods)) { return false; } break;
case Fields.CertificationDocuments: /*if (!sc.CertificationDocuments.SequenceEqual(CertificationDocuments)) { return false; }*/
break;
default:
throw new NotSupportedException("SensorCalibration::Equals Unknown field " + field.ToString());
}
}
return true;
}
public override bool Equals(object obj)
{
if (obj is SensorCalibration sc)
{
var fields = Enum.GetValues(typeof(Fields)).Cast<Fields>().ToArray();
foreach (var field in fields)
{
switch (field)
{
case Fields.CalibrationDate: if (sc.CalibrationDate.Date != CalibrationDate.Date) { return false; } break;
case Fields.CalibrationRecords: if (!sc.Records.IsEqual(Records, this)) { return false; } break;
case Fields.IRTraccCalculationType: if (sc.IRTraccCalculationType != IRTraccCalculationType) { return false; } break;
case Fields.IsProportional: if (sc.IsProportional != IsProportional) { return false; } break;
case Fields.InitialOffsets: if (!sc.InitialOffsets.Equals(InitialOffsets)) { return false; } break; // FB5429
case Fields.LocalOnly: if (sc.LocalOnly != LocalOnly) { return false; } break;
case Fields.ModifyDate: if (sc.ModifyDate != ModifyDate) { return false; } break;
case Fields.NonLinear: if (sc.NonLinear != NonLinear) { return false; } break;
case Fields.RemoveOffset: if (sc.RemoveOffset != RemoveOffset) { return false; } break;
case Fields.SerialNumber: if (sc.SerialNumber != SerialNumber) { return false; } break;
case Fields.Username: break;
case Fields.SensitivityInspection: break;
case Fields.ZeroMethods: if (!sc.ZeroMethods.Equals(ZeroMethods)) { return false; } break;
case Fields.CertificationDocuments:
if (!sc.CertificationDocuments.SequenceEqual(CertificationDocuments)) { return false; }
break;
case Fields.UsageCount: break; //Don't consider Usage Count when comparing, so it gets set to 0
default:
throw new NotSupportedException("SensorCalibration::Equals Unknown field " + field);
}
}
return true;
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public string UUID { get; set; } = "";
public string LinearAddedValues
{
get
{
if (LinearAdded)
{
var records = new CalibrationRecords(Records);
var methods = new ZeroMethods(ZeroMethods);
var offsets = new InitialOffsets(InitialOffsets);
records.Records = records.Records.Where(record => record != records.Records[0]).ToArray();
methods.Methods = new ZeroMethod[] { methods.Methods[1] };
return records.ToSerializedString(this) + SensorConstants.LinearValuesSeparator + methods.ToSerializedString() + SensorConstants.LinearValuesSeparator + offsets.ToSerializedString();
}
return string.Empty;
}
}
public double LinearAddedSensitivity
{
get
{
if (LinearAdded)
{
var records = new CalibrationRecords(Records);
records.Records = records.Records.Where(record => record != records.Records[0]).ToArray();
return records.Records[0].Sensitivity;
}
return 0D;
}
}
public ICalibrationRecord[] LinearAddedRecords
{
get
{
var records = new CalibrationRecords(Records);
if (LinearAdded)
{
records.Records = records.Records.Where(record => record != records.Records[0]).ToArray();
return records.Records;
}
return records.Records;
}
}
public ZeroMethodType LinearAddedZeroMethodType
{
get
{
var methods = new ZeroMethods(ZeroMethods);
var zeroMethods = new ZeroMethod[] { methods.Methods[1] };
return zeroMethods[0].Method;
}
}
public double LinearAddedZeroMethodEnd
{
get
{
var methods = new ZeroMethods(ZeroMethods);
var zeroMethods = new ZeroMethod[] { methods.Methods[1] };
return zeroMethods[0].End;
}
}
public double LinearAddedZeroMethodStart
{
get
{
var methods = new ZeroMethods(ZeroMethods);
var zeroMethods = new ZeroMethod[] { methods.Methods[1] };
return zeroMethods[0].Start;
}
}
public double GetPolynomialEU(double inputmV, double excitation)
{
return Records.Records[0].Poly.GetLinearizedValue(inputmV, excitation);
}
/// <summary>
/// inserts a sensor calibration into the db
/// </summary>
/// <param name="bChangeModifyDate"></param>
/// <param name="sensor"></param>
/// <param name="bSetLatestCalibrationId">whether to set the given sensor's latest calibration
/// id to the calibration when committing</param>
internal void Insert(bool bChangeModifyDate, SensorData sensor, bool bSetLatestCalibrationId = false)
{
if (bChangeModifyDate)
{
ModifyDate = DateTime.Now;
}
_ = DbOperations.SensorCalibrationsInsert(this, sensor.GetSensorType(), bSetLatestCalibrationId);
}
public void CopyValues(ISensorCalibration icopy)
{
var copy = (SensorCalibration)icopy;
CalibrationDate = copy.CalibrationDate;
Records = new CalibrationRecords(copy.Records);
IsProportional = copy.IsProportional;
LocalOnly = copy.LocalOnly;
ModifyDate = copy.ModifyDate;
NonLinear = copy.NonLinear;
RemoveOffset = copy.RemoveOffset;
SerialNumber = copy.SerialNumber;
Username = copy.Username;
ZeroMethods = new ZeroMethods(copy.ZeroMethods);
InitialOffsets = new InitialOffsets(copy.InitialOffsets);
CertificationDocuments = new string[copy.CertificationDocuments.Length];
CalibrationNote = copy.CalibrationNote;
UsageCount = copy.UsageCount;
copy.CertificationDocuments.CopyTo(CertificationDocuments, 0);
OnPropertyChanged(ALL_FIELDS);
}
public const string ALL_FIELDS = "AllFields";
public static SensorCalibration GetLatestCalibrationBySerialNumber(SensorData sd)
{
return SensorCalibrationList.GetLatestCalibrationBySerialNumber(sd);
}
public static SensorCalibration NewDigitalSC(string units)
{
var sc = new SensorCalibration
{
RemoveOffset = false,
CalibrationDate = DateTime.Now.Date,
IsProportional = false,
LocalOnly = false,
NonLinear = false
};
sc.Records.Records[0].Sensitivity = 1;
sc.Records.Records[0].EngineeringUnits = units;
sc.Records.Records[0].Excitation = ExcitationVoltageOptions.ExcitationVoltageOption.Volt5;
sc.ZeroMethods = new ZeroMethods(new[] { new ZeroMethod(ZeroMethodType.None, 0, 0) });
return sc;
}
public static SensorCalibration NewEmbeddedSC(string units)
{
//TODO: REMOVE THIS HACK
//and put in proper variables / gets from device
var sc = new SensorCalibration
{
RemoveOffset = true,
CalibrationDate = DateTime.Now.Date,
IsProportional = false,
LocalOnly = false,
NonLinear = false
};
sc.Records.Records[0].Sensitivity = 1;
sc.Records.Records[0].EngineeringUnits = units;
sc.Records.Records[0].Excitation = ExcitationVoltageOptions.ExcitationVoltageOption.Volt5;
sc.ZeroMethods = new ZeroMethods(new[] { new ZeroMethod(ZeroMethodType.None, 0, 0) });
return sc;
}
public static SensorCalibration GetLatestCalibrationBySerialNumberAndExcitation(SensorData sd, ExcitationVoltageOptions.ExcitationVoltageOption exc)
{
return SensorCalibrationList.GetLatestCalibrationBySerialNumberAndExcitation(sd, exc);
}
public static SensorCalibration GetLatestCalibrationsBySerialNumberAndCalDate(string ser, DateTime calDate)
{
return SensorCalibrationList.GetLatestCalibrationsBySerialNumberAndCalDate(ser, calDate);
}
public static SensorCalibration GetLatestCalibrationsBySerialNumberCalDateAndModifyDate(string ser, DateTime calDate, DateTime modifyDate)
{
return SensorCalibrationList.GetLatestCalibrationsBySerialNumberCalDateAndModifyDate(ser, calDate, modifyDate);
}
public static SensorCalibration[] GetCalibrationsBySerialNumber(SensorData sd)
{
return SensorCalibrationList.GetCalibrationsBySerialNumber(sd);
}
#region Data Fields
private string _documentId = "";
public string DocumentID
{
get => _documentId;
set => SetProperty(ref _documentId, value, "DocumentID");
}
public NonLinearStyles IRTraccCalculationType
{
get => Records.Records[0].Poly.NonLinearStyle;
set => Records.Records[0].Poly.NonLinearStyle = value;
}
//private ZeroMethods _zeroMethods;
public new ZeroMethods ZeroMethods
{
get
{
if (null == base.ZeroMethods || !base.ZeroMethods.Methods.Any())
{
// FB12764: Defaults in SensorConstants
base.ZeroMethods = new ZeroMethods() { Methods = new ZeroMethod[] { new ZeroMethod(SensorConstants.DefaultZeroMethodType, SensorConstants.DefaultZeroMethodStart, SensorConstants.DefaultZeroMethodEnd) } };
}
try
{
if (NonLinear)
{
switch (Records.Records[0].Poly.NonLinearStyle)
{
case NonLinearStyles.IRTraccAverageOverTime: base.ZeroMethods.Methods[0].Method = ZeroMethodType.AverageOverTime; break;
case NonLinearStyles.IRTraccDiagnosticsZero: base.ZeroMethods.Methods[0].Method = ZeroMethodType.UsePreEventDiagnosticsZero; break;
case NonLinearStyles.IRTraccZeroMMmV: base.ZeroMethods.Methods[0].Method = ZeroMethodType.None; break;
case NonLinearStyles.IRTraccCalFactor: base.ZeroMethods.Methods[0].Method = ZeroMethodType.None; break;
}
}
}
catch (Exception ex) { APILogger.Log(ex); }
return base.ZeroMethods;
}
set => base.ZeroMethods = value;
}
#endregion
protected const int CURRENT_VERSION = 1;
public SensorCalibration()
{
if (!NonLinear || LinearAdded) return;
Records.Records[0].Sensitivity = 1D;
//FB 29728 Don't set it to false, user can make the selection
// IsProportional = false;
RemoveOffset = false;
}
public enum Fields
{
CalibrationDate,
CalibrationRecords,
IsProportional,
LocalOnly,
ModifyDate,
NonLinear,
RemoveOffset,
SerialNumber,
Username,
ZeroMethods,
InitialOffsets,
CertificationDocuments,
IRTraccCalculationType,
SensitivityInspection,
UsageCount
}
private void CommonInit()
{
if (!NonLinear || LinearAdded) return;
Records.Records[0].Sensitivity = 1D;
//FB 29728 Don't set it to false, user can make the selection
// IsProportional = false;
RemoveOffset = false;
}
public SensorCalibration(string s)
{
FromSerializedString(s);
CommonInit();
}
public SensorCalibration(ISensorCalDbRecord record) : base(record)
{
CommonInit();
}
public SensorCalibration(IDataReader dr, int actualDbVersion) : base(dr, actualDbVersion)
{
CommonInit();
}
public SensorCalibration(DataRow dr)
{
try
{
CalibrationDate = Convert.ToDateTime(dr[DbOperations.SensorDB.SensorCalibrationFields.CalibrationDate.ToString()]);
CalibrationId = Convert.ToInt32(dr[DbOperations.SensorDB.SensorCalibrationFields.SensorCalibrationId.ToString()]);
LocalOnly = Convert.ToBoolean(dr[DbOperations.SensorDB.SensorCalibrationFields.LocalOnly.ToString()]);
SerialNumber = (string)dr[DbOperations.SensorDB.SensorCalibrationFields.SerialNumber.ToString()];
Username = (string)dr[DbOperations.SensorDB.SensorCalibrationFields.Username.ToString()];
Records = new CalibrationRecords((string)dr[DbOperations.SensorDB.SensorCalibrationFields.CalibrationRecords.ToString()]);
NonLinear = Convert.ToBoolean(dr[DbOperations.SensorDB.SensorCalibrationFields.NonLinear.ToString()]);
IsProportional = Convert.ToBoolean(dr[DbOperations.SensorDB.SensorCalibrationFields.IsProportional.ToString()]);
ModifyDate = Convert.ToDateTime(dr[DbOperations.SensorDB.SensorCalibrationFields.ModifyDate.ToString()]);
CertificationDocuments = ((string)dr[DbOperations.SensorDB.SensorCalibrationFields.CertificationDocuments.ToString()]).Split(new[] { CultureInfo.InvariantCulture.TextInfo.ListSeparator }, StringSplitOptions.None).ToArray();
RemoveOffset = Convert.ToBoolean(dr[DbOperations.SensorDB.SensorCalibrationFields.RemoveOffset.ToString()]);
ZeroMethods = new ZeroMethods((string)dr[DbOperations.SensorDB.SensorCalibrationFields.ZeroMethod.ToString()]);
InitialOffsets = new InitialOffsets((string)dr[DbOperations.SensorDB.SensorCalibrationFields.InitialOffset.ToString()]);
//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);
if (!NonLinear || LinearAdded) return;
Records.Records[0].Sensitivity = 1D;
IsProportional = false;
RemoveOffset = false;
}
catch (Exception ex)
{
APILogger.Log("Failed to process Sensor Calibration record", ex);
}
}
/// <summary>
/// serializes to a string
/// primarily used by sensor models, which only have one calibration entry
/// sensors on the other hand have many and serialize to rows in a db table
/// </summary>
/// <returns></returns>
public string ToSerializedString()
{
var fields = Enum.GetValues(typeof(DbOperations.SensorDB.SensorCalibrationFields)).Cast<DbOperations.SensorDB.SensorCalibrationFields>().ToArray();
if (CalibrationDate.Year < 1960) { CalibrationDate = DateTime.Now.Date; }
var substrings = new List<string>();
foreach (var field in fields)
{
switch (field)
{
case DbOperations.SensorDB.SensorCalibrationFields.CalibrationDate: substrings.Add(CalibrationDate.Date.ToFileTimeUtc().ToString(System.Globalization.CultureInfo.InvariantCulture)); break;
case DbOperations.SensorDB.SensorCalibrationFields.CalibrationRecords: substrings.Add(Records.ToSerializedString(this)); break;
//case DbOperations.SensorDB.SensorCalibrationFields.IRTraccCalculationType: substrings.Add(IRTraccCalculationType.ToString()); break;
case DbOperations.SensorDB.SensorCalibrationFields.IsProportional: substrings.Add(IsProportional.ToString()); break;
case DbOperations.SensorDB.SensorCalibrationFields.LocalOnly: substrings.Add(LocalOnly.ToString()); break;
case DbOperations.SensorDB.SensorCalibrationFields.ModifyDate: substrings.Add(DateTime.Now.ToFileTimeUtc().ToString(System.Globalization.CultureInfo.InvariantCulture)); break;
case DbOperations.SensorDB.SensorCalibrationFields.NonLinear: substrings.Add(NonLinear.ToString()); break;
case DbOperations.SensorDB.SensorCalibrationFields.RemoveOffset: substrings.Add(RemoveOffset.ToString()); break;
case DbOperations.SensorDB.SensorCalibrationFields.SerialNumber: substrings.Add(SerialNumber); break;
case DbOperations.SensorDB.SensorCalibrationFields.Username: substrings.Add(Username); break;
case DbOperations.SensorDB.SensorCalibrationFields.ZeroMethod: substrings.Add(ZeroMethods.ToSerializedString()); break;
case DbOperations.SensorDB.SensorCalibrationFields.InitialOffset: substrings.Add(InitialOffsets.ToSerializedString()); break;
case DbOperations.SensorDB.SensorCalibrationFields.CertificationDocuments:
{
List<string> docs = new List<string>();
foreach (var d in CertificationDocuments) { docs.Add(d); }
substrings.Add(string.Join(System.Globalization.CultureInfo.InvariantCulture.TextInfo.ListSeparator, docs.ToArray()));
}
break;
case DbOperations.SensorDB.SensorCalibrationFields.SensorCalibrationId: substrings.Add(CalibrationId?.ToString() ?? INVALID_CALIBRATION_ID.ToString()); break; //FB16002: follow the import/export pattern for strings as in XML
case DbOperations.SensorDB.SensorCalibrationFields.UsageCount: substrings.Add(UsageCount.ToString()); break;
case DbOperations.SensorDB.SensorCalibrationFields.SensitivityInspection:
try
{
substrings.Add(((int)SensitivityInspection).ToString());
}
catch (Exception ex)
{
APILogger.LogException(ex);
}
break;
case DbOperations.SensorDB.SensorCalibrationFields.CalibrationNote: substrings.Add(CalibrationNote); break;
default: throw new NotSupportedException("SensorCalibration::ToSerializedString unknown field: " + field.ToString());
}
}
for (var i = 0; i < substrings.Count; i++)
{
substrings[i] = substrings[i]?.Replace(CultureInfo.InvariantCulture.TextInfo.ListSeparator, SEPARATOR_REPLACEMENT);
}
return string.Join(CultureInfo.InvariantCulture.TextInfo.ListSeparator, substrings.ToArray());
}
public void FromSerializedString(string s)
{
var fields = Enum.GetValues(typeof(DbOperations.SensorDB.SensorCalibrationFields)).Cast<DbOperations.SensorDB.SensorCalibrationFields>().ToArray();
var tokens = s.Split(new[] { CultureInfo.InvariantCulture.TextInfo.ListSeparator }, StringSplitOptions.None);
for (var i = 0; i < tokens.Length && i < fields.Length; i++)
{
var field = fields[i];
var token = tokens[i].Replace(SEPARATOR_REPLACEMENT, CultureInfo.InvariantCulture.TextInfo.ListSeparator);
switch (field)
{
case DbOperations.SensorDB.SensorCalibrationFields.CalibrationDate: CalibrationDate = DateTime.FromFileTimeUtc(Convert.ToInt64(token)); break;
case DbOperations.SensorDB.SensorCalibrationFields.SensorCalibrationId:
//FB16002: follow the import/export pattern for strings as in XML
if (int.TryParse(token, NumberStyles.Any, CultureInfo.InvariantCulture, out int iTemp))
{
if (iTemp == INVALID_CALIBRATION_ID) { CalibrationId = null; }
else
{
CalibrationId = iTemp;
}
}
else
{
CalibrationId = null;
}
break;
case DbOperations.SensorDB.SensorCalibrationFields.CalibrationRecords: Records = new CalibrationRecords(token); break;
//case DbOperations.SensorDB.SensorCalibrationFields.IRTraccCalculationType: IRTraccCalculationType = (SensorModel.IRTraccFormats)Enum.Parse(typeof(SensorModel.IRTraccFormats), token);break;
case DbOperations.SensorDB.SensorCalibrationFields.IsProportional: IsProportional = Convert.ToBoolean(token); break;
case DbOperations.SensorDB.SensorCalibrationFields.LocalOnly: LocalOnly = Convert.ToBoolean(token); break;
case DbOperations.SensorDB.SensorCalibrationFields.ModifyDate: ModifyDate = DateTime.FromFileTimeUtc(Convert.ToInt64(token)); break;
case DbOperations.SensorDB.SensorCalibrationFields.NonLinear: NonLinear = Convert.ToBoolean(token); break;
case DbOperations.SensorDB.SensorCalibrationFields.RemoveOffset: RemoveOffset = Convert.ToBoolean(token); break;
case DbOperations.SensorDB.SensorCalibrationFields.SerialNumber: SerialNumber = token; break;
case DbOperations.SensorDB.SensorCalibrationFields.Username: Username = token; break;
case DbOperations.SensorDB.SensorCalibrationFields.ZeroMethod: ZeroMethods = new ZeroMethods(token); break;
case DbOperations.SensorDB.SensorCalibrationFields.InitialOffset: InitialOffsets = new InitialOffsets(token); break;
case DbOperations.SensorDB.SensorCalibrationFields.CertificationDocuments: CertificationDocuments = token.Split(new[] { CultureInfo.InvariantCulture.TextInfo.ListSeparator }, StringSplitOptions.None); break;
case DbOperations.SensorDB.SensorCalibrationFields.UsageCount: UsageCount = Convert.ToInt32(token); break;
case DbOperations.SensorDB.SensorCalibrationFields.SensitivityInspection:
try
{
SensitivityInspection = (SensitivityInspectionType)Convert.ToInt32(token);
}
catch (Exception ex)
{
APILogger.LogException(ex);
}
break;
case DbOperations.SensorDB.SensorCalibrationFields.CalibrationNote: CalibrationNote = token; break;
}
}
}
public const string SEPARATOR_REPLACEMENT = "__SC__";
public SensorCalibration(ISensorCalibration iSensorCalibration)
{
var sc = (SensorCalibration)iSensorCalibration;
_serialNumber = sc.SerialNumber;
_userName = sc.Username;
_calibrationDate = sc.CalibrationDate;
ModifyDate = sc.ModifyDate;
NonLinear = sc.NonLinear;
IsProportional = sc.IsProportional;
Records = new CalibrationRecords(sc.Records);
RemoveOffset = sc.RemoveOffset;
ZeroMethods = new ZeroMethods(sc.ZeroMethods);
InitialOffsets = new InitialOffsets(sc.InitialOffsets);
CertificationDocuments = sc.CertificationDocuments;
CalibrationId = sc.CalibrationId;
//43152
SensitivityInspection = sc.SensitivityInspection;
//43141 added note property
CalibrationNote = sc.CalibrationNote;
UsageCount = sc.UsageCount;
}
internal SensorCalibration(XElement elem)
{
var tableName = SensorDBTables.CalibrationTableFilename;
int ver;
try
{
ver = (int)elem.Element(XMLFields.Version.ToString());
}
catch (ArgumentNullException)
{
throw new Exception("SensorData: Can't find version tag in DB file");
}
if (ver != CURRENT_VERSION)
{
throw new Exception(string.Format(Strings.SensorData_Ctor_Err1, CURRENT_VERSION, ver));
}
SensorDBBase.GetValue(elem, XMLFields.SerialNumber.ToString(), out _serialNumber, null, tableName);
SensorDBBase.GetValue(elem, XMLFields.Date.ToString(), out _calibrationDate, SerialNumber, tableName);
SensorDBBase.GetValue(elem, XMLFields.Sensitivity.ToString(), out double sensitivity, SerialNumber, tableName);
Records.Records[0].Sensitivity = sensitivity;
var poly = "";
try { SensorDBBase.GetValueSafe(elem, XMLFields.Poly.ToString(), out poly, SerialNumber, tableName); }
catch (Exception ex) { APILogger.Log(ex); }
Records.Records[0].Poly = new LinearizationFormula();
if (!string.IsNullOrWhiteSpace(poly))
{
Records.Records[0].Poly.FromSerializeString(poly);
NonLinear = true;
}
SensorDBBase.GetValue(elem, XMLFields.MeasurementUnit.ToString(), out string mu, SerialNumber, tableName);
Array.ForEach(Records.Records, record => record.EngineeringUnits = mu); //FB16398: set units on all records, not just first
SensorDBBase.GetValue(elem, XMLFields.Username.ToString(), out _userName, SerialNumber, tableName);
SensorDBBase.GetValueSafe(elem, XMLFields.DocumentID.ToString(), out _documentId, SerialNumber, tableName);
if (null == _documentId) { _documentId = string.Empty; }
if (!NonLinear) return;
Records.Records[0].Sensitivity = 1D;
IsProportional = false;
}
public int CompareTo(SensorCalibration other)
{
if (null == other) { return 1; }
if (Equals(this, other)) { return 0; }
if (CalibrationDate.Date != other.CalibrationDate.Date)
return other.CalibrationDate.CompareTo(CalibrationDate);
var modifyCompare = other.ModifyDate.CompareTo(ModifyDate);
return 0 == modifyCompare ? other.CalVersion.CompareTo(CalVersion) : modifyCompare;
}
private string BuildLinearDisplayString(ICalibrationRecord[] records, ExcitationVoltageOptions.ExcitationVoltageOption excitation, string linearFormat, bool iepe = false)
{
var sb = new StringBuilder();
var dSensitivity = 0D;
if (ExcitationVoltageOptions.ExcitationVoltageOption.Undefined == excitation
|| !IsProportional)
{
dSensitivity = records[0].Sensitivity;
}
else
{
foreach (var r in records)
{
if (r.Excitation != excitation) continue;
dSensitivity = r.Sensitivity;
break;
}
}
var sensUnits = string.Empty;
switch (records[0].SensitivityUnits)
{
case SensorConstants.SensUnits.mV: sensUnits = " mV"; break;
case SensorConstants.SensUnits.mVperEU: sensUnits = " mV/EU"; break;
case SensorConstants.SensUnits.mVperV: sensUnits = " mV/V"; break;
case SensorConstants.SensUnits.mVperVperEU: sensUnits = " mV/V/EU"; break;
}
if (iepe)
{
sensUnits = " mV/EU";
}
sb.Append(string.Concat(dSensitivity.ToString(linearFormat), sensUnits));
if (IsProportional)
{
if (ExcitationVoltageOptions.ExcitationVoltageOption.Undefined != excitation)
{
var excitationString = string.Empty;
switch (excitation)
{
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt1: excitationString = "1V"; break;
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt10: excitationString = "10V"; break;
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt2: excitationString = "2V"; break;
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt2_5: excitationString = "2.5V"; break;
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt3: excitationString = "3V"; break;
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt5: excitationString = "5V"; break;
}
sb.Append($" ({excitationString})");
}
}
if (records[0].AtCapacity)
{
sb.Append($" @({records[0].CapacityOutputIsBasedOn}EU)");
}
return sb.ToString();
}
public string ToDisplayString(ExcitationVoltageOptions.ExcitationVoltageOption excitation,
string linearFormat,
string nonlinearFormat,
bool iepe)
{
if (NonLinear && !iepe)
{
return Records.Records[0].Poly.ToDisplayString(nonlinearFormat);
}
return BuildLinearDisplayString(Records.Records, excitation, linearFormat, iepe);
}
public string ToLinearDisplayString(ExcitationVoltageOptions.ExcitationVoltageOption excitation, string linearFormat, bool iepe)
{
if (NonLinear && !iepe)
{
if (LinearAdded)
{
//build linear string from remaining records after the poly record.
return BuildLinearDisplayString(Records.Records.Where(record => record != Records.Records[0]).ToArray(), excitation, linearFormat);
}
return string.Empty;
}
return ToDisplayString(excitation, linearFormat, null, iepe);
}
public string ToNonLinearDisplayString(string nonlinearFormat, bool iepe)
{
if (!NonLinear) return string.Empty;
return ToDisplayString(ExcitationVoltageOptions.ExcitationVoltageOption.Undefined, null, nonlinearFormat, iepe);
}
public void ReadXML(System.Xml.XmlElement root)
{
foreach (var node in root.ChildNodes)
{
if (node is System.Xml.XmlElement) { ProcessXmlElement(node as System.Xml.XmlElement); }
}
}
private void ProcessXmlElement(System.Xml.XmlElement node)
{
if (!Enum.TryParse(node.Name, out DbOperations.SensorDB.SensorCalibrationFields field)) return;
switch (field)
{
case DbOperations.SensorDB.SensorCalibrationFields.CalibrationDate: CalibrationDate = DateTime.Parse(node.InnerText, CultureInfo.InvariantCulture); break;
case DbOperations.SensorDB.SensorCalibrationFields.CalibrationRecords: Records = new CalibrationRecords(node.InnerText); break;
case DbOperations.SensorDB.SensorCalibrationFields.CertificationDocuments: CertificationDocuments = new string[0]; break;
case DbOperations.SensorDB.SensorCalibrationFields.IsProportional: IsProportional = Convert.ToBoolean(node.InnerText); break;
case DbOperations.SensorDB.SensorCalibrationFields.LocalOnly: LocalOnly = Convert.ToBoolean(node.InnerText); break;
case DbOperations.SensorDB.SensorCalibrationFields.ModifyDate: ModifyDate = DateTime.Parse(node.InnerText, CultureInfo.InvariantCulture); break;
case DbOperations.SensorDB.SensorCalibrationFields.NonLinear: NonLinear = Convert.ToBoolean(node.InnerText); break;
case DbOperations.SensorDB.SensorCalibrationFields.RemoveOffset: RemoveOffset = Convert.ToBoolean(node.InnerText); break;
case DbOperations.SensorDB.SensorCalibrationFields.SerialNumber: SerialNumber = node.InnerText; break;
case DbOperations.SensorDB.SensorCalibrationFields.Username: Username = node.InnerText; break;
case DbOperations.SensorDB.SensorCalibrationFields.ZeroMethod: ZeroMethods = new ZeroMethods(node.InnerText); break;
case DbOperations.SensorDB.SensorCalibrationFields.InitialOffset: InitialOffsets = new InitialOffsets(node.InnerText); break;
case DbOperations.SensorDB.SensorCalibrationFields.SensorCalibrationId:
if (int.TryParse(node.InnerText, NumberStyles.Any, CultureInfo.InvariantCulture, out int iTemp))
{
if (iTemp == INVALID_CALIBRATION_ID) { CalibrationId = null; }
else
{
CalibrationId = iTemp;
}
}
else
{
APILogger.Log($"possible error in sensor calibration id: {node.InnerText}");
CalibrationId = null;
}
break;
case DbOperations.SensorDB.SensorCalibrationFields.UsageCount: UsageCount = Convert.ToInt32(node.InnerText, CultureInfo.InvariantCulture); break;
case DbOperations.SensorDB.SensorCalibrationFields.CalibrationNote: CalibrationNote = node.InnerText; break;
//FB 43267
case DbOperations.SensorDB.SensorCalibrationFields.SensitivityInspection:
try
{
SensitivityInspection = (SensitivityInspectionType)Convert.ToInt32(node.InnerText, CultureInfo.InvariantCulture);
}
catch (Exception ex)
{
APILogger.LogException(ex);
}
break;
default: throw new NotSupportedException("SensorCalibration::ProcessXMLElement unsupported tag: " + field);
}
}
private const int INVALID_CALIBRATION_ID = -1;
public void WriteXML(ref System.Xml.XmlWriter writer)
{
writer.WriteStartElement("SensorCalibration");
var fields = Enum.GetValues(typeof(DbOperations.SensorDB.SensorCalibrationFields)).Cast<DbOperations.SensorDB.SensorCalibrationFields>().ToArray();
foreach (var f in fields)
{
writer.WriteStartElement(f.ToString());
switch (f)
{
case DbOperations.SensorDB.SensorCalibrationFields.CalibrationDate: writer.WriteString(CalibrationDate.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.SensorDB.SensorCalibrationFields.CalibrationRecords: writer.WriteString(Records.ToSerializedString(this)); break;
case DbOperations.SensorDB.SensorCalibrationFields.CertificationDocuments: writer.WriteString(""); break;
case DbOperations.SensorDB.SensorCalibrationFields.IsProportional: writer.WriteString(IsProportional.ToString()); break;
case DbOperations.SensorDB.SensorCalibrationFields.LocalOnly: writer.WriteString(LocalOnly.ToString()); break;
case DbOperations.SensorDB.SensorCalibrationFields.ModifyDate: writer.WriteString(ModifyDate.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.SensorDB.SensorCalibrationFields.NonLinear: writer.WriteString(NonLinear.ToString()); break;
case DbOperations.SensorDB.SensorCalibrationFields.RemoveOffset: writer.WriteString(RemoveOffset.ToString()); break;
case DbOperations.SensorDB.SensorCalibrationFields.SerialNumber: writer.WriteString(SerialNumber); break;
case DbOperations.SensorDB.SensorCalibrationFields.Username: writer.WriteString(Username); break;
case DbOperations.SensorDB.SensorCalibrationFields.ZeroMethod: writer.WriteString(ZeroMethods.ToSerializedString()); break;
case DbOperations.SensorDB.SensorCalibrationFields.InitialOffset: writer.WriteString(InitialOffsets.ToSerializedString()); break;
case DbOperations.SensorDB.SensorCalibrationFields.SensorCalibrationId:
if (null != CalibrationId)
{
writer.WriteString(((int)CalibrationId).ToString(CultureInfo.InvariantCulture));
}
else
{
writer.WriteString(INVALID_CALIBRATION_ID.ToString(CultureInfo.InvariantCulture));
}
break;
case DbOperations.SensorDB.SensorCalibrationFields.UsageCount: writer.WriteString(UsageCount.ToString()); break;
case DbOperations.SensorDB.SensorCalibrationFields.SensitivityInspection:
try
{
writer.WriteString(((int)SensitivityInspection).ToString());
}
catch(Exception ex)
{
APILogger.LogException(ex);
}
break;
case DbOperations.SensorDB.SensorCalibrationFields.CalibrationNote: writer.WriteString(CalibrationNote.ToString()); break;
default: throw new NotSupportedException("SensorCalibration::WriteXML unsupported field: " + f);
}
writer.WriteEndElement();
}
writer.WriteEndElement();
}
public bool IsCompatibleWithIEPE()
{
if (IsProportional) { return false; }
return !NonLinear;
}
}
}