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, 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().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().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); } /// /// inserts a sensor calibration into the db /// /// /// /// whether to set the given sensor's latest calibration /// id to the calibration when committing 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); } } /// /// 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 /// /// public string ToSerializedString() { var fields = Enum.GetValues(typeof(DbOperations.SensorDB.SensorCalibrationFields)).Cast().ToArray(); if (CalibrationDate.Year < 1960) { CalibrationDate = DateTime.Now.Date; } var substrings = new List(); 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 docs = new List(); 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().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().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; } } }