1755 lines
86 KiB
C#
1755 lines
86 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using DTS.Common.Base;
|
|
using DTS.Common.Enums.DBExport;
|
|
using DTS.Common.Utilities.Logging;
|
|
using DTS.Common.Enums;
|
|
using DTS.Common.Enums.Sensors;
|
|
using DTS.Common.Classes.Sensors;
|
|
using DTS.Common.Utils;
|
|
using System.Xml;
|
|
using DTS.Common.Interface.Sensors;
|
|
using DTS.SensorDB;
|
|
using System.Xml.Serialization;
|
|
using System.IO;
|
|
using EQX;
|
|
using DTS.Common.DAS.Concepts;
|
|
|
|
namespace DTS.Common.DataModel
|
|
{
|
|
/// <summary>
|
|
/// handles exporting (to TDCSensorDatabase CSV format)
|
|
/// couple of important notes.
|
|
/// 1) uses current culture list separator (not necessarily a comma)
|
|
/// 2) uses local culture decimal/number formats
|
|
/// 3) doesn't specify an encoding for export file
|
|
/// </summary>
|
|
public class SensorDatabaseExport : BasePropertyChanged
|
|
{
|
|
// ReSharper disable once InconsistentNaming
|
|
private bool _TDCOnly = false;
|
|
public bool TDCOnly
|
|
{
|
|
get => _TDCOnly;
|
|
set => SetProperty(ref _TDCOnly, value, "TDCOnly");
|
|
}
|
|
|
|
private string _defaultFolder = DataModelSettings.DefaultTDCSensorDatabaseFolder;
|
|
/// <summary>
|
|
/// the default folder for the export, is initialed using default value in config file
|
|
/// </summary>
|
|
public string DefaultFolder
|
|
{
|
|
get => _defaultFolder;
|
|
set => SetProperty(ref _defaultFolder, value, "DefaultFolder");
|
|
}
|
|
|
|
private string _defaultFile = DataModelSettings.DefaultTDCSensorDatabaseFile;
|
|
/// <summary>
|
|
/// the filename to export to, by default is controlled by config file
|
|
/// </summary>
|
|
public string DefaultFile
|
|
{
|
|
get => _defaultFile;
|
|
set => SetProperty(ref _defaultFile, value, "DefaultFile");
|
|
}
|
|
|
|
/// <summary>
|
|
/// sets the default file and folder for export
|
|
/// </summary>
|
|
/// <param name="fullPathToFile">full path to destination file. Can be a relative path, it will be resolved to absolute path.</param>
|
|
public void SetFilename(string fullPathToFile)
|
|
{
|
|
var fi = new FileInfo(fullPathToFile);
|
|
DefaultFolder = Path.GetFullPath(fi.DirectoryName);
|
|
DefaultFile = fi.Name;
|
|
}
|
|
|
|
/// <summary>
|
|
/// controls what to do if there is an error during export
|
|
/// an errored export will not finish and returns immediately
|
|
/// </summary>
|
|
/// <param name="message"></param>
|
|
public delegate void ErrorDelegate(string message);
|
|
public event ErrorDelegate OnError;
|
|
|
|
/// <summary>
|
|
/// controls what to do when export finishes
|
|
/// </summary>
|
|
public delegate void DoneDelegate();
|
|
public event DoneDelegate OnDone;
|
|
|
|
private SensorData[] _sensors = null;
|
|
/// <summary>
|
|
/// sensors to export, if null all sensors are exported
|
|
/// </summary>
|
|
public SensorData[] Sensors
|
|
{
|
|
get => _sensors;
|
|
set => SetProperty(ref _sensors, value, "Sensors");
|
|
}
|
|
/// <summary>
|
|
/// whether the user wants to export first use dates or not
|
|
/// 13065 Sensor "First Use" Date
|
|
/// </summary>
|
|
public bool ExportFirstUseDate { get; set; } = true;
|
|
private List<string> _modelStrings;
|
|
public void ExportSLICEWare()
|
|
{
|
|
try
|
|
{
|
|
if (!Directory.Exists(DefaultFolder))
|
|
{
|
|
Directory.CreateDirectory(DefaultFolder);
|
|
}
|
|
var di = new DirectoryInfo(DefaultFolder);
|
|
|
|
var calFilename = Path.Combine(DefaultFolder, "Calibration.SensorDB.xml");
|
|
var dataFilename = Path.Combine(DefaultFolder, "Data.SensorDB.xml");
|
|
var modelFilename = Path.Combine(DefaultFolder, "Model.SensorDB.xml");
|
|
|
|
if (File.Exists(calFilename)) { BackupAndDelete(calFilename); }
|
|
if (File.Exists(dataFilename)) { BackupAndDelete(dataFilename); }
|
|
if (File.Exists(modelFilename)) { BackupAndDelete(modelFilename); }
|
|
|
|
var sb = new StringBuilder(5000000);
|
|
var sb2 = new StringBuilder(5000000);
|
|
var sb3 = new StringBuilder(5000000);
|
|
|
|
//stringbuilder always uses UTF-16, so we don't _really_ get a choice here.
|
|
var xSet = new XmlWriterSettings() { Indent = true, CheckCharacters = true, Encoding = Encoding.Unicode };
|
|
var writerSensors = XmlWriter.Create(sb, xSet);
|
|
var writerCals = XmlWriter.Create(sb2, xSet);
|
|
var writerModels = XmlWriter.Create(sb3, xSet);
|
|
|
|
writerSensors.WriteStartDocument();
|
|
writerCals.WriteStartDocument();
|
|
writerModels.WriteStartDocument();
|
|
|
|
|
|
writerCals.WriteStartElement("Calibrations");
|
|
writerSensors.WriteStartElement("SensorData");
|
|
|
|
writerSensors.WriteAttributeString("Software", System.Reflection.Assembly.GetEntryAssembly().GetName().Name);
|
|
writerSensors.WriteAttributeString("SoftwareVersion", System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString(4));
|
|
|
|
writerModels.WriteStartElement("SensorModels");
|
|
_modelStrings = new List<string>();
|
|
foreach (var s in Sensors)
|
|
{
|
|
// First Axis
|
|
var thisSensor = new SensorData(s);
|
|
WriteSLICEWareXML(thisSensor, ref writerSensors, ref writerCals, ref writerModels);
|
|
}
|
|
writerSensors.WriteEndElement();//SensorData
|
|
writerSensors.WriteEndDocument();
|
|
|
|
writerCals.WriteEndElement();//calibrations
|
|
writerCals.WriteEndDocument();
|
|
|
|
writerModels.WriteEndElement();//SensorModels
|
|
writerModels.WriteEndDocument();
|
|
|
|
writerSensors.Close();
|
|
writerCals.Close();
|
|
writerModels.Close();
|
|
|
|
File.WriteAllText(dataFilename, sb.ToString(), xSet.Encoding);
|
|
File.WriteAllText(calFilename, sb2.ToString(), xSet.Encoding);
|
|
File.WriteAllText(modelFilename, sb3.ToString(), xSet.Encoding);
|
|
|
|
OnDone?.Invoke();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
OnError?.Invoke(ex.Message); APILogger.Log(ex);
|
|
}
|
|
finally
|
|
{
|
|
_modelStrings = null;
|
|
}
|
|
}
|
|
|
|
private void WriteElement(ref XmlWriter sensorWriter, string tag, string val)
|
|
{
|
|
sensorWriter.WriteStartElement(tag);
|
|
sensorWriter.WriteString(val);
|
|
sensorWriter.WriteEndElement();
|
|
}
|
|
private SensorCalibration GetPreferredSensorCalibration(SensorData s)
|
|
{
|
|
return s.SupportedExcitation.Select(e => SensorCalibration.GetLatestCalibrationBySerialNumberAndExcitation(s, e)).FirstOrDefault(sc => null != sc);
|
|
}
|
|
private SensorCalibration GetFirstSensorCalibration(SensorData sd)
|
|
{
|
|
var scPreferred = new SensorCalibration();
|
|
Array.ForEach(scPreferred.Records.Records, record => record.EngineeringUnits = sd.DisplayUnit); //FB16398: set units on all records, not just first
|
|
try
|
|
{
|
|
scPreferred.Records.Records[0].Excitation = sd.SupportedExcitation[0];
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log(ex);
|
|
} // If no SupportedExcitation, don't crash. Then, the sensor will not be exported below.
|
|
return scPreferred;
|
|
}
|
|
private bool ShouldExport(SensorData sd, SensorCalibration scPreferred)
|
|
{
|
|
if (sd.IsSquib() || sd.IsDigitalInput() || sd.IsDigitalOutput()
|
|
|| scPreferred.NonLinear && scPreferred.IRTraccCalculationType == NonLinearStyles.IRTraccCalFactor)
|
|
{ return false; }//skip for now
|
|
return true;
|
|
}
|
|
private string GetSanitizedSN(SensorData sd)
|
|
{
|
|
var serialNumber = sd.SerialNumber;
|
|
if (1 < sd.NumberOfAxes || 0 < sd.AxisNumber)
|
|
{
|
|
// sanitize serialnumber string
|
|
if (0 < sd.AxisNumber) { serialNumber = serialNumber.Remove(serialNumber.IndexOf("_axis_", StringComparison.Ordinal)); }
|
|
|
|
// put back the axis designation
|
|
serialNumber = string.Concat(serialNumber, "_axis_", sd.AxisNumber + 1);
|
|
}
|
|
return serialNumber;
|
|
}
|
|
private string GetSanitizedModel(SensorData sd)
|
|
{
|
|
var model = sd.Model;
|
|
if (1 < sd.NumberOfAxes || 0 < sd.AxisNumber)
|
|
{
|
|
// sanitize model string
|
|
if (0 < sd.AxisNumber) { model = model.Remove(model.IndexOf("_axis_", StringComparison.Ordinal)); }
|
|
model = string.IsNullOrEmpty(model) ? string.Empty : string.Concat(model, "_axis_", sd.AxisNumber + 1);
|
|
}
|
|
return model;
|
|
}
|
|
private void WriteSLICEWareXML(SensorData sd, ref XmlWriter sensorWriter, ref XmlWriter calWriter, ref XmlWriter modelWriter)
|
|
{
|
|
var scPreferred = GetPreferredSensorCalibration(sd);
|
|
//Handle the off chance that we have no valid calibration for this sensor at this excitation.
|
|
if (null == scPreferred)
|
|
{
|
|
scPreferred = GetFirstSensorCalibration(sd);
|
|
}
|
|
|
|
if (!ShouldExport(sd, scPreferred)) { return; }
|
|
foreach (var se in sd.SupportedExcitation)
|
|
{
|
|
var sc = SensorCalibration.GetLatestCalibrationBySerialNumberAndExcitation(sd, se);
|
|
if (null == sc) continue;
|
|
|
|
WriteSupportedExcitation(ref sensorWriter, sd,
|
|
se, scPreferred, sc, ref modelWriter,
|
|
ref calWriter);
|
|
|
|
if (!sc.IsProportional) { break; }//this works for all excitation
|
|
}
|
|
}
|
|
private void WriteSupportedExcitation(ref XmlWriter sensorWriter,
|
|
SensorData sd,
|
|
ExcitationVoltageOptions.ExcitationVoltageOption se,
|
|
SensorCalibration scPreferred,
|
|
SensorCalibration sc,
|
|
ref XmlWriter modelWriter,
|
|
ref XmlWriter calWriter)
|
|
{
|
|
sensorWriter.WriteStartElement("Sensor");
|
|
|
|
WriteElement(ref sensorWriter, "Version", "1");
|
|
|
|
var serialNumber = GetSanitizedSN(sd);
|
|
|
|
var model = GetSanitizedModel(sd);
|
|
|
|
if (1 < sd.SupportedExcitation.Length)
|
|
{
|
|
serialNumber = string.Concat(serialNumber, "_", se.ToString());
|
|
}
|
|
|
|
WriteElement(ref sensorWriter, "SerialNumber", serialNumber);
|
|
|
|
WriteElement(ref sensorWriter, "UserSerialNumber", sd.UserSerialNumber);
|
|
|
|
WriteElement(ref sensorWriter, "DiagnosticsMode", sd.DiagnosticsMode.ToString(CultureInfo.InvariantCulture));
|
|
|
|
WriteElement(ref sensorWriter, "Model", model);
|
|
|
|
WriteElement(ref sensorWriter, "Status", sd.Status.ToString());
|
|
|
|
WriteElement(ref sensorWriter, "MeasurementUnit", scPreferred.Records.Records[0].EngineeringUnits);
|
|
|
|
WriteElement(ref sensorWriter, "ID", sd.EID);
|
|
|
|
WriteElement(ref sensorWriter, "Capacity", $"{sd.Capacity:0}");
|
|
|
|
WriteElement(ref sensorWriter, "Comment", sd.Comment);
|
|
|
|
WriteElement(ref sensorWriter, "IsPropotional", scPreferred.IsProportional.ToString().ToLower());
|
|
|
|
WriteElement(ref sensorWriter, "Bridge", sd.Bridge.ToString());
|
|
|
|
WriteElement(ref sensorWriter, "Shunt", sd.Shunt.ToString());
|
|
|
|
WriteElement(ref sensorWriter, "CalSignal", sd.CalSignal.ToString().ToLower());
|
|
|
|
WriteElement(ref sensorWriter, "InternalShuntResistance", sd.InternalShuntResistance.ToString(CultureInfo.InvariantCulture));
|
|
|
|
WriteElement(ref sensorWriter, "ExternalShuntResistance", sd.ExternalShuntResistance.ToString(CultureInfo.InvariantCulture));
|
|
|
|
WriteElement(ref sensorWriter, "BridgeResistance", sd.BridgeResistance.ToString(CultureInfo.InvariantCulture));
|
|
|
|
WriteElement(ref sensorWriter, "BridgeLegMode", sd.BridgeLegMode.ToString());
|
|
|
|
sensorWriter.WriteStartElement("OffsetTolerance-LowHigh");
|
|
sensorWriter.WriteAttributeString("Low", sd.OffsetToleranceLow.ToString(CultureInfo.InvariantCulture));
|
|
sensorWriter.WriteAttributeString("High", sd.OffsetToleranceHigh.ToString(CultureInfo.InvariantCulture));
|
|
sensorWriter.WriteEndElement();
|
|
|
|
WriteElement(ref sensorWriter, "Invert", sd.Invert.ToString().ToLower());
|
|
|
|
|
|
var removeOffset = scPreferred.RemoveOffset.ToString().ToLower();
|
|
if (scPreferred.NonLinear && scPreferred.Records.Records[0].Poly.NonLinearSliceWareStyle == NonLinearSLICEWareStyles.DiagnosticZeroMMmV)
|
|
{
|
|
//SLICEWare expects true for remove offset in this case
|
|
removeOffset = "true";
|
|
}
|
|
WriteElement(ref sensorWriter, "RemoveOffset", removeOffset);
|
|
|
|
WriteElement(ref sensorWriter, "UserValue1", sd.UserValue1);
|
|
WriteElement(ref sensorWriter, "UserValue2", sd.UserValue2);
|
|
WriteElement(ref sensorWriter, "UserValue3", sd.UserValue3);
|
|
|
|
sensorWriter.WriteStartElement("Range-SensorRange");
|
|
sensorWriter.WriteAttributeString("Low", sd.RangeLow.ToString(CultureInfo.InvariantCulture));
|
|
sensorWriter.WriteAttributeString("Medium", sd.RangeMedium.ToString(CultureInfo.InvariantCulture));
|
|
sensorWriter.WriteAttributeString("High", sd.RangeHigh.ToString(CultureInfo.InvariantCulture));
|
|
sensorWriter.WriteEndElement();
|
|
|
|
WriteElement(ref sensorWriter, "Excitation", se.ToString());
|
|
|
|
sensorWriter.WriteStartElement("Filter-FilterClass");
|
|
var fc = sd.Filter.FClass;
|
|
var freq = sd.Filter.Frequency;
|
|
if ( fc == FilterClassType.Unfiltered)
|
|
{
|
|
fc = FilterClassType.None;
|
|
freq = 0;
|
|
}
|
|
sensorWriter.WriteAttributeString("Class", fc.ToString());
|
|
sensorWriter.WriteString(freq.ToString(CultureInfo.InvariantCulture));
|
|
sensorWriter.WriteEndElement();
|
|
|
|
sensorWriter.WriteStartElement("Zero-ZeroMethod");//TODO: linear/nonlinear
|
|
sensorWriter.WriteAttributeString("Start", scPreferred.ZeroMethods.Methods[0].Start.ToString(CultureInfo.InvariantCulture));
|
|
sensorWriter.WriteAttributeString("End", scPreferred.ZeroMethods.Methods[0].End.ToString(CultureInfo.InvariantCulture));
|
|
sensorWriter.WriteString(scPreferred.ZeroMethods.Methods[0].Method.ToString());
|
|
sensorWriter.WriteEndElement();
|
|
|
|
WriteElement(ref sensorWriter, "InitialEU", SensorData.GetInitialEUValue(scPreferred, scPreferred.Records.Records[0].Excitation, scPreferred.InitialOffsets.Offsets.First()).ToString(CultureInfo.InvariantCulture));
|
|
|
|
WriteElement(ref sensorWriter, "Created", sd.Created.ToString(CultureInfo.InvariantCulture));
|
|
|
|
WriteElement(ref sensorWriter, "TimesUsed", sd.TimesUsed.ToString(CultureInfo.InvariantCulture));
|
|
|
|
WriteElement(ref sensorWriter, "Zmo", "0");
|
|
|
|
WriteElement(ref sensorWriter, "ISOCode", sd.ISOCode);
|
|
|
|
WriteElement(ref sensorWriter, "CheckOffset", sd.CheckOffset.ToString());
|
|
|
|
WriteElement(ref sensorWriter, "IRTraccExponent", scPreferred.Records.Records.First().Poly.LinearizationExponent.ToString(CultureInfo.InvariantCulture));
|
|
|
|
WriteElement(ref sensorWriter, "SIFFile", "");
|
|
|
|
WriteElement(ref sensorWriter, "SensorCategory", sd.SensorCategory.ToString(CultureInfo.InvariantCulture));
|
|
|
|
WriteElement(ref sensorWriter, "FilterOption", sd.ByPassFilter.ToString());
|
|
|
|
WriteElement(ref sensorWriter, "OriginalShuntMode", sd.Shunt.ToString());
|
|
|
|
WriteElement(ref sensorWriter, "OriginalZeroMethod", scPreferred.ZeroMethods.Methods.First().Method.ToString());
|
|
|
|
WriteElement(ref sensorWriter, "Manufacturer", sd.Manufacturer);
|
|
|
|
WriteElement(ref sensorWriter, "CouplingMode", sd.CouplingMode.ToString());
|
|
|
|
WriteElement(ref sensorWriter, "IgnoreRange", sd.IgnoreRange.ToString());
|
|
|
|
WriteElement(ref sensorWriter, "UniPolar", sd.UniPolar.ToString().ToLower());
|
|
|
|
WriteElement(ref sensorWriter, "NonLinear", scPreferred.NonLinear.ToString().ToLower());
|
|
|
|
WriteElement(ref sensorWriter, "Dimension", sd.PhysicalDimension);
|
|
|
|
WriteElement(ref sensorWriter, "PolyStyle", "IRTRacc");
|
|
|
|
WriteElement(ref sensorWriter, "IRTraccFormat", scPreferred.Records.Records.First().Poly.NonLinearSliceWareStyle.ToString());
|
|
|
|
sensorWriter.WriteEndElement();//Sensor
|
|
|
|
WriteSensorModel(sd, ref modelWriter, scPreferred);
|
|
|
|
WriteSensorCalibrations(sc, se, ref calWriter, serialNumber);
|
|
}
|
|
private void WriteSensorCalibrations(SensorCalibration sc,
|
|
ExcitationVoltageOptions.ExcitationVoltageOption se, ref XmlWriter calWriter, string serialNumber)
|
|
{
|
|
foreach (var record in sc.Records.Records)
|
|
{
|
|
if (true == sc.IsProportional && record.Excitation != se) { continue; }
|
|
calWriter.WriteStartElement("Calibration");
|
|
|
|
WriteElement(ref calWriter, "Version", "1");
|
|
|
|
WriteElement(ref calWriter, "SerialNumber", serialNumber);
|
|
|
|
WriteElement(ref calWriter, "Date", sc.CalibrationDate.ToString(CultureInfo.InvariantCulture));
|
|
|
|
|
|
var SLICEWareSensitivity = record.Sensitivity;
|
|
|
|
if (sc.IsProportional && SensorConstants.SensUnits.mVperEU == record.SensitivityUnits)
|
|
{
|
|
// Need to process the sensitivity in this case.
|
|
SLICEWareSensitivity = record.Sensitivity / Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(se);
|
|
}
|
|
|
|
WriteElement(ref calWriter, "Sensitivity", SLICEWareSensitivity.ToString(CultureInfo.InvariantCulture));
|
|
|
|
WriteElement(ref calWriter, "Username", sc.Username);
|
|
|
|
WriteElement(ref calWriter, "DocumentID", "");
|
|
|
|
WriteElement(ref calWriter, "MeasurementUnit", record.EngineeringUnits);
|
|
|
|
WriteElement(ref calWriter, "Excitation", se.ToString());
|
|
|
|
WriteElement(ref calWriter, "Zmo", "0");
|
|
|
|
WriteElement(ref calWriter, "Poly", record.Poly.ToSLICEWareSerializeString());
|
|
calWriter.WriteEndElement();
|
|
}
|
|
}
|
|
private void WriteSensorModel(SensorData sd, ref XmlWriter modelWriter,
|
|
SensorCalibration scPreferred)
|
|
{
|
|
if (!string.IsNullOrEmpty(sd.Manufacturer) && !_modelStrings.Contains(string.Concat(sd.Manufacturer, ",", sd.Model)))
|
|
{
|
|
_modelStrings.Add(string.Concat(sd.Manufacturer, ",", sd.Model));
|
|
modelWriter.WriteStartElement("SensorModel");
|
|
WriteElement(ref modelWriter, "Model", sd.Model);
|
|
WriteElement(ref modelWriter, "Manufacturer", sd.Manufacturer);
|
|
WriteElement(ref modelWriter, "UserPartNumber", "");
|
|
WriteElement(ref modelWriter, "Capacity", sd.Capacity.ToString(CultureInfo.InvariantCulture));
|
|
WriteElement(ref modelWriter, "OffsetTolerance", string.Concat(sd.OffsetToleranceLow, ",", sd.OffsetToleranceHigh));
|
|
WriteElement(ref modelWriter, "MeasurementUnit", sd.DisplayUnit);
|
|
WriteElement(ref modelWriter, "SensorRange", string.Concat(sd.RangeLow, ",", sd.RangeMedium, ",", sd.RangeHigh));
|
|
WriteElement(ref modelWriter, "Sensitivity", scPreferred.Records.Records.First().Sensitivity.ToString(CultureInfo.InvariantCulture));
|
|
WriteElement(ref modelWriter, "Excitation", scPreferred.Records.Records.First().Excitation.ToString());
|
|
WriteElement(ref modelWriter, "IsProportional", scPreferred.IsProportional.ToString());
|
|
WriteElement(ref modelWriter, "Bridge", sd.Bridge.ToString());
|
|
WriteElement(ref modelWriter, "Shunt", sd.Shunt.ToString());
|
|
WriteElement(ref modelWriter, "BridgeResistance", sd.BridgeResistance.ToString(CultureInfo.InvariantCulture));
|
|
WriteElement(ref modelWriter, "RemoveOffset", scPreferred.RemoveOffset.ToString());
|
|
WriteElement(ref modelWriter, "FilterClass", sd.Filter.FClass.ToString());
|
|
WriteElement(ref modelWriter, "ZeroMethod", string.Concat(scPreferred.ZeroMethods.Methods.First().Method.ToString(), ",", scPreferred.ZeroMethods.Methods.First().Start, ",", scPreferred.ZeroMethods.Methods.First().End));
|
|
WriteElement(ref modelWriter, "InitialEU", scPreferred.InitialOffsets.Offsets.First().EU.ToString(CultureInfo.InvariantCulture));
|
|
WriteElement(ref modelWriter, "NonLinear", scPreferred.NonLinear.ToString());
|
|
WriteElement(ref modelWriter, "UniPolar", sd.UniPolar.ToString());
|
|
WriteElement(ref modelWriter, "PolynomialStyle", "Equation");
|
|
WriteElement(ref modelWriter, "IRTraccFormat", "DiagnosticZeroMMmV");
|
|
WriteElement(ref modelWriter, "LinearizationFormula", "");
|
|
WriteElement(ref modelWriter, "PhysicalDimension", sd.PhysicalDimension);
|
|
WriteElement(ref modelWriter, "IgnoreRange", sd.IgnoreRange.ToString());
|
|
WriteElement(ref modelWriter, "Invert", sd.Invert.ToString());
|
|
WriteElement(ref modelWriter, "CouplingMode", sd.CouplingMode.ToString());
|
|
WriteElement(ref modelWriter, "CheckOffset", sd.CheckOffset.ToString());
|
|
|
|
modelWriter.WriteEndElement();//Model
|
|
}
|
|
}
|
|
private void BackupAndDelete(string filename)
|
|
{
|
|
var backupFile = filename + ".bak";
|
|
if (File.Exists(backupFile)) { File.Delete(backupFile); }
|
|
File.Move(filename, backupFile);
|
|
}
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
public void ExportTDC()
|
|
{
|
|
try
|
|
{
|
|
if (!Directory.Exists(DefaultFolder))
|
|
{
|
|
Directory.CreateDirectory(DefaultFolder);
|
|
}
|
|
var di = new DirectoryInfo(DefaultFolder);
|
|
|
|
var listSeparator = DataModelSettings.TDCSensorDatabaseExportUseCurrentLocale ? CultureInfo.CurrentCulture.TextInfo.ListSeparator :
|
|
CultureInfo.InvariantCulture.TextInfo.ListSeparator;
|
|
|
|
var ec = DataModelSettings.TDCSensorDatabaseExportUseCurrentLocale ? CultureInfo.CurrentCulture :
|
|
CultureInfo.InvariantCulture;
|
|
|
|
|
|
var fullPathToCSVFile = Path.Combine(di.FullName, DefaultFile);
|
|
|
|
if (File.Exists(fullPathToCSVFile)) { BackupAndDelete(fullPathToCSVFile); }
|
|
|
|
var fieldLookup = new Dictionary<int, List<CSVImportTags.Tags>>();
|
|
var sb = new StringBuilder();
|
|
for (var i = CSVImportTags.MIN_VALID_VERSION; i <= CSVImportTags.MAX_VALID_VERSION; i++)
|
|
{
|
|
if (1 == i) { continue; }//1 only has test tags
|
|
if (3 == i) { continue; }//3 is only group tags for tests ...
|
|
if (i > 0 && TDCOnly) { continue; } //TDC only supports v0
|
|
var tags = CSVImportTags.GetVersionTags(i);
|
|
fieldLookup[i] = new List<CSVImportTags.Tags>(tags);
|
|
foreach (var tag in tags)
|
|
{
|
|
if (tag == CSVImportTags.Tags.Unknown) { continue; } //skip
|
|
if (sb.Length > 0) { sb.Append(listSeparator); }
|
|
sb.Append(EscapeCSV(CSVImportTags.GetStringForTag(tag), false, listSeparator));
|
|
}
|
|
}
|
|
sb.AppendLine();
|
|
|
|
//done with headers, now go through all sensors, if no sensors are explicetly selected, use all sensors
|
|
var currentNumber = 0;
|
|
if (null == Sensors || Sensors.Length == 0) { Sensors = SensorsCollection.SensorsList.GetAllSensors(true); }
|
|
|
|
ExportSensors(ref currentNumber, sb, fieldLookup, listSeparator, ec);
|
|
//we may infact want to force an encoding, but for now just use the default...
|
|
File.WriteAllText(fullPathToCSVFile, sb.ToString(), Encoding.GetEncoding(DataModelSettings.TDCSensorDatabaseImportEncoding));
|
|
OnDone?.Invoke(); Sensors = null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
OnError?.Invoke(ex.Message); APILogger.Log(ex);
|
|
}
|
|
}
|
|
|
|
private void ExportSensors(ref int currentNumber, StringBuilder sb, IReadOnlyDictionary<int, List<CSVImportTags.Tags>> columns,
|
|
string listSeparator, CultureInfo ec)
|
|
{
|
|
foreach (var sd in Sensors)
|
|
{
|
|
ExportSensor(sd, sb, ref currentNumber, columns, listSeparator, ec);
|
|
|
|
sb.AppendLine();
|
|
}
|
|
}
|
|
private void ExportSensor(SensorData sd, StringBuilder sb, ref int currentNumber,
|
|
IReadOnlyDictionary<int, List<CSVImportTags.Tags>> columns, string listSeparator,
|
|
CultureInfo ec)
|
|
{
|
|
//for TDC sensitivities we use the preferred excitation record, there could be multiple records that are currently valid for different excitations
|
|
//for this sensor ... but those are handled in the DataPRO only columns, if they are enabled
|
|
SensorCalibration scPreferred = null;
|
|
if (!sd.SupportedExcitation.Any())
|
|
{
|
|
//Set supported excitation(s) based on any found calibration records
|
|
var scPreferredList = SensorCalibrationList.GetCalibrationsBySerialNumber(sd);
|
|
var supportedExcitationList = new List<ExcitationVoltageOptions.ExcitationVoltageOption>();
|
|
for (var i = 0; i < scPreferredList.Length; i++)
|
|
{
|
|
foreach (var calRecord in scPreferredList[i].Records.Records)
|
|
{
|
|
if (!supportedExcitationList.Contains(calRecord.Excitation))
|
|
{
|
|
supportedExcitationList.Add(calRecord.Excitation);
|
|
}
|
|
}
|
|
}
|
|
if (!supportedExcitationList.Any())
|
|
{
|
|
//There are no calibration records, so give up
|
|
return;
|
|
}
|
|
sd.SupportedExcitation = supportedExcitationList.ToArray();
|
|
}
|
|
scPreferred = SensorCalibration.GetLatestCalibrationBySerialNumberAndExcitation(sd, sd.SupportedExcitation.First());
|
|
//Handle the off chance that we have no valid calibration for this sensor at this excitation.
|
|
if (null == scPreferred)
|
|
{
|
|
scPreferred = new SensorCalibration();
|
|
scPreferred.Records.Records.First().EngineeringUnits = sd.DisplayUnit;
|
|
scPreferred.Records.Records.First().Excitation = sd.SupportedExcitation.First();
|
|
}
|
|
if (TDCOnly && scPreferred.NonLinear &&
|
|
scPreferred.Records.Records.First().Poly.NonLinearStyle != NonLinearStyles.Polynomial)
|
|
{
|
|
//TDC can not consume this sensor type. lets give up.
|
|
return;
|
|
}
|
|
currentNumber++;
|
|
var euConversionFactor = MeasurementUnitList.GetMeasurementUnit(scPreferred.Records.Records.First().EngineeringUnits).GetScalerConversionFrom(sd.DisplayUnit);
|
|
var bNeedComma = false;
|
|
|
|
for (var i = CSVImportTags.MIN_VALID_VERSION; i <= CSVImportTags.MAX_VALID_VERSION; i++)
|
|
{
|
|
if (!columns.ContainsKey(i)) { continue; }
|
|
var tags = columns[i];
|
|
if (0 == tags.Count) { continue; }
|
|
foreach (var tag in tags)
|
|
{
|
|
ExportTag(sd, scPreferred, tag, sb, ref currentNumber, listSeparator, ref bNeedComma, euConversionFactor, i,
|
|
ec);
|
|
}
|
|
}
|
|
}
|
|
private void ExportVersion0(SensorData sd, SensorCalibration scPreferred, CSVImportTags.Tags tag, StringBuilder sb,
|
|
ref int currentNumber, string listSeparator, ref bool bNeedComma, double euConversionFactor,
|
|
CultureInfo ec)
|
|
{
|
|
string sVal = null;
|
|
var bTextField = false;
|
|
switch (tag)
|
|
{
|
|
case CSVImportTags.Tags.Axis: sVal = ""; break;
|
|
|
|
case CSVImportTags.Tags.BRIDGE: sVal = sd.Bridge == SensorConstants.BridgeType.HalfBridge ? "Half" : "Full"; break;
|
|
|
|
case CSVImportTags.Tags.BridgeResistance:
|
|
{
|
|
if (double.IsNaN(sd.BridgeResistance) || sd.BridgeResistance < 0)
|
|
{
|
|
sVal = "";
|
|
}
|
|
else { sVal = sd.BridgeResistance.ToString(ec); }
|
|
}
|
|
break;
|
|
case CSVImportTags.Tags.BypassAAFilter: sVal = sd.ByPassFilter ? "Yes" : "No"; break;
|
|
|
|
case CSVImportTags.Tags.Category:
|
|
{
|
|
if (scPreferred.NonLinear)
|
|
{
|
|
switch (scPreferred.Records.Records.First().Poly.NonLinearStyle)
|
|
{
|
|
case NonLinearStyles.Polynomial: sVal = ((int)SensorInformationFile.TDCSensorCategory.Polynomial).ToString(); break;
|
|
|
|
default: sVal = ((int)SensorInformationFile.TDCSensorCategory.IRTracc).ToString(); break;
|
|
}
|
|
}
|
|
else { sVal = ((int)SensorInformationFile.TDCSensorCategory.Normal).ToString(); }
|
|
}
|
|
break;
|
|
|
|
case CSVImportTags.Tags.ChannelName: sVal = sd.Comment; bTextField = true; break;
|
|
|
|
case CSVImportTags.Tags.CommentField: sVal = sd.UserValue1; bTextField = true; break;
|
|
|
|
case CSVImportTags.Tags.CustomerCode: sVal = sd.UserValue2; bTextField = true; break;
|
|
|
|
case CSVImportTags.Tags.DatabaseReferenceNumber: sVal = currentNumber.ToString(); break;
|
|
|
|
case CSVImportTags.Tags.DesiredRange: sVal = (sd.Capacity * euConversionFactor).ToString(ec); break;
|
|
|
|
case CSVImportTags.Tags.Dimension: sVal = ""; break;
|
|
|
|
case CSVImportTags.Tags.Due: sVal = ""; break;
|
|
|
|
case CSVImportTags.Tags.DueCal: sVal = sd.GetDueDate(scPreferred).ToString("d", ec); break;
|
|
|
|
case CSVImportTags.Tags.EquivalentEUShuntResistor: sVal = ""; break;
|
|
|
|
case CSVImportTags.Tags.EU: sVal = scPreferred.Records.Records.First().EngineeringUnits; bTextField = true; break;
|
|
|
|
case CSVImportTags.Tags.Exc:
|
|
{
|
|
try
|
|
{
|
|
sVal = Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(sd.SupportedExcitation.First()).ToString(ec);
|
|
}
|
|
catch
|
|
{
|
|
sVal = string.Empty;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CSVImportTags.Tags.FilterClass: sVal = sd.Filter.GetFilterClassNumericValue().ToString(ec); break;
|
|
|
|
case CSVImportTags.Tags.FullScale: sVal = (sd.Capacity * euConversionFactor).ToString(ec); break;
|
|
|
|
case CSVImportTags.Tags.Group1: sVal = ""; break;
|
|
case CSVImportTags.Tags.Group2: sVal = ""; break;
|
|
case CSVImportTags.Tags.Group3: sVal = ""; break;
|
|
case CSVImportTags.Tags.Group4: sVal = ""; break;
|
|
case CSVImportTags.Tags.Group5: sVal = ""; break;
|
|
|
|
case CSVImportTags.Tags.InvertSignal: sVal = sd.Invert ? "Yes" : "No"; break;
|
|
|
|
case CSVImportTags.Tags.IRTRACCExponent:
|
|
{
|
|
if (scPreferred.NonLinear && scPreferred.Records.Records.First().Poly.NonLinearStyle != NonLinearStyles.Polynomial)
|
|
{
|
|
sVal = scPreferred.Records.Records.First().Poly.LinearizationExponent.ToString(ec);
|
|
}
|
|
else { sVal = ""; }
|
|
}
|
|
break;
|
|
|
|
case CSVImportTags.Tags.LaboratoryCode: sVal = sd.UserValue3; bTextField = true; break;
|
|
|
|
case CSVImportTags.Tags.LastCal: sVal = scPreferred.CalibrationDate.ToString("d", ec); break;
|
|
|
|
case CSVImportTags.Tags.Location: sVal = ""; break;
|
|
|
|
case CSVImportTags.Tags.Manufacturer: sVal = sd.Manufacturer ?? ""; bTextField = true; break;
|
|
|
|
case CSVImportTags.Tags.Model: sVal = sd.Model ?? ""; bTextField = true; break;
|
|
|
|
case CSVImportTags.Tags.OffsetToleranceHigh: sVal = sd.OffsetToleranceHigh.ToString(ec); break;
|
|
|
|
case CSVImportTags.Tags.OffsetToleranceLow: sVal = sd.OffsetToleranceLow.ToString(ec); break;
|
|
|
|
case CSVImportTags.Tags.OutputAtEXCFSmV: sVal = ""; break;
|
|
|
|
case CSVImportTags.Tags.PartialISOCode: sVal = sd.ISOCode; bTextField = true; break;
|
|
|
|
case CSVImportTags.Tags.Proportional: sVal = scPreferred.IsProportional ? "Yes" : "No"; break;
|
|
|
|
case CSVImportTags.Tags.Received: sVal = ""; break;
|
|
|
|
case CSVImportTags.Tags.RemoveOffset: sVal = scPreferred.RemoveOffset ? "Yes" : "No"; break;
|
|
|
|
case CSVImportTags.Tags.Sensitivity:
|
|
{
|
|
sVal = "1";
|
|
if (scPreferred.NonLinear)
|
|
{
|
|
if (scPreferred.Records.Records.First().Poly.NonLinearStyle == NonLinearStyles.Polynomial)
|
|
{
|
|
sVal = scPreferred.Records.Records.First().Sensitivity.ToString(FormatScientificNotation(), ec);
|
|
}
|
|
else { sVal = scPreferred.Records.Records.First().Poly.MMPerV.ToString(ec); }
|
|
}
|
|
else
|
|
{
|
|
if (scPreferred.IsProportional)
|
|
{
|
|
foreach (var r in scPreferred.Records.Records)
|
|
{
|
|
try
|
|
{
|
|
if (r.Excitation != sd.SupportedExcitation.First()) continue;
|
|
sVal = r.Sensitivity.ToString(ec);
|
|
break;
|
|
}
|
|
catch { break; }
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sVal = scPreferred.Records.Records.First().Sensitivity.ToString(FormatScientificNotation(), ec);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CSVImportTags.Tags.SensorID: sVal = sd.EID; bTextField = true; break;
|
|
|
|
case CSVImportTags.Tags.SensorSN: sVal = sd.SerialNumber; bTextField = true; break;
|
|
|
|
case CSVImportTags.Tags.SensorType: sVal = ""; break;
|
|
|
|
case CSVImportTags.Tags.ShuntResistorValue: sVal = ""; break;
|
|
|
|
case CSVImportTags.Tags.SoftwareZeroEquivalentEU:
|
|
{
|
|
bTextField = true;
|
|
sVal = "";
|
|
switch (scPreferred.InitialOffsets.Offsets.First().Form)
|
|
{
|
|
case InitialOffsetTypes.EU:
|
|
case InitialOffsetTypes.None:
|
|
sVal = (scPreferred.InitialOffsets.Offsets.First().EU * euConversionFactor).ToString(ec);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CSVImportTags.Tags.SoftwareZeroReference:
|
|
{
|
|
switch (scPreferred.ZeroMethods.Methods.First().Method)
|
|
{
|
|
case ZeroMethodType.AverageOverTime: sVal = ZM_STRING_AVERAGE_OVER_TIME; break;
|
|
case ZeroMethodType.None: sVal = ZM_STRING_NONE; break;
|
|
case ZeroMethodType.UsePreEventDiagnosticsZero: sVal = ZM_STRING_DIAGNOSTICS; break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CSVImportTags.Tags.Tech: sVal = scPreferred.Username; bTextField = true; break;
|
|
|
|
case CSVImportTags.Tags.Unknown: break;
|
|
|
|
case CSVImportTags.Tags.UseShuntCal: sVal = sd.Shunt == ShuntMode.Emulation ? "Yes" : "No"; break;
|
|
}
|
|
if (null == sVal) { return; } //if we have a null it's not a field we expect to process or know how to process, so we skip those
|
|
|
|
if (bNeedComma) { sb.Append(listSeparator); }
|
|
else { bNeedComma = true; }
|
|
|
|
sb.Append(EscapeCSV(sVal, bTextField, listSeparator));
|
|
}
|
|
private void ExportVersion1(SensorData sd, SensorCalibration scPreferred, CSVImportTags.Tags tag, StringBuilder sb,
|
|
ref int currentNumber, string listSeparator, ref bool bNeedComma, double euConversionFactor,
|
|
CultureInfo ec)
|
|
{
|
|
}
|
|
private void ExportVersion2(SensorData sd, SensorCalibration scPreferred, CSVImportTags.Tags tag, StringBuilder sb,
|
|
ref int currentNumber, string listSeparator, ref bool bNeedComma, double euConversionFactor,
|
|
CultureInfo ec)
|
|
{
|
|
string sVal = null;
|
|
var bTextField = false;
|
|
switch (tag)
|
|
{
|
|
case CSVImportTags.Tags.FiveVoltExcSensitivity:
|
|
{
|
|
//if the default calibration is not propoprtional, it covers all supported excitations ...
|
|
if (scPreferred.IsProportional && sd.SupportedExcitation.Contains(ExcitationVoltageOptions.ExcitationVoltageOption.Volt5))
|
|
{
|
|
sVal = GetSensitivity(ExcitationVoltageOptions.ExcitationVoltageOption.Volt5, sd).ToString(ec);
|
|
}
|
|
else { sVal = ""; }
|
|
}
|
|
break;
|
|
|
|
case CSVImportTags.Tags.TenVoltExcSensitivity:
|
|
{
|
|
if (scPreferred.IsProportional && sd.SupportedExcitation.Contains(ExcitationVoltageOptions.ExcitationVoltageOption.Volt10))
|
|
{
|
|
sVal = GetSensitivity(ExcitationVoltageOptions.ExcitationVoltageOption.Volt10, sd).ToString(ec);
|
|
}
|
|
else { sVal = ""; }
|
|
}
|
|
break;
|
|
|
|
case CSVImportTags.Tags.TwoVoltExcSensitivity:
|
|
{
|
|
if (scPreferred.IsProportional && sd.SupportedExcitation.Contains(ExcitationVoltageOptions.ExcitationVoltageOption.Volt2))
|
|
{
|
|
sVal = GetSensitivity(ExcitationVoltageOptions.ExcitationVoltageOption.Volt2, sd).ToString(ec);
|
|
}
|
|
else { sVal = ""; }
|
|
}
|
|
break;
|
|
|
|
case CSVImportTags.Tags.Unknown: break;
|
|
case CSVImportTags.Tags.AxisNumber: sVal = sd.AxisNumber.ToString(); break;
|
|
case CSVImportTags.Tags.BridgeLegMode: sVal = sd.BridgeLegMode.ToString(); bTextField = true; break;
|
|
case CSVImportTags.Tags.BridgeType: sVal = sd.Bridge.ToString(); bTextField = true; break;
|
|
case CSVImportTags.Tags.CalInterval: sVal = sd.CalInterval.ToString(); break;
|
|
case CSVImportTags.Tags.CouplingMode: sVal = sd.CouplingMode.ToString(); bTextField = true; break;
|
|
case CSVImportTags.Tags.Created: sVal = sd.Created.ToString("F", ec); break;
|
|
case CSVImportTags.Tags.DelayMS: sVal = sd.DelayMS.ToString(ec); break;
|
|
case CSVImportTags.Tags.DigitalOutputDelayMS: sVal = sd.DigitalOutputDelayMS.ToString(ec); break;
|
|
case CSVImportTags.Tags.DigitalInputMode: sVal = sd.InputMode.ToString(); bTextField = true; break;
|
|
case CSVImportTags.Tags.NonLinearCalibration: sVal = scPreferred.Records.Records.First().Poly.ToSerializeString(); bTextField = true; break;
|
|
case CSVImportTags.Tags.AdditionalInitialOffsets:
|
|
if (scPreferred.InitialOffsets.Offsets.Length > 1)
|
|
{
|
|
var additionalInitalOffsets = new InitialOffsets(scPreferred.InitialOffsets, scPreferred.InitialOffsets.Offsets.Length - 1);
|
|
sVal = additionalInitalOffsets.ToSerializedString();
|
|
bTextField = true;
|
|
}
|
|
else
|
|
{
|
|
sVal = string.Empty; //In case there is no additional Initial Offsets
|
|
}
|
|
break;
|
|
case CSVImportTags.Tags.AdditionalLinearSensitivity:
|
|
if (scPreferred.NonLinear && scPreferred.LinearAdded)
|
|
{
|
|
if (scPreferred.IsProportional)
|
|
{
|
|
foreach (var r in scPreferred.LinearAddedRecords)
|
|
{
|
|
try
|
|
{
|
|
if (r.Excitation != sd.SupportedExcitation.First()) continue;
|
|
sVal = r.Sensitivity.ToString(ec);
|
|
break;
|
|
}
|
|
catch { break; }
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sVal = scPreferred.LinearAddedSensitivity.ToString(ec);
|
|
}
|
|
bTextField = true;
|
|
}
|
|
else
|
|
{
|
|
sVal = string.Empty; //In case there is no additional linear calibration (Sensitivity)
|
|
}
|
|
break;
|
|
case CSVImportTags.Tags.AdditionalLinearZeroMethod:
|
|
if (scPreferred.NonLinear && scPreferred.LinearAdded)
|
|
{
|
|
sVal = scPreferred.LinearAddedZeroMethodType.ToString();
|
|
bTextField = true;
|
|
}
|
|
else
|
|
{
|
|
sVal = string.Empty; //In case there is no additional linear calibration (Zero Method)
|
|
}
|
|
break;
|
|
case CSVImportTags.Tags.AdditionalLinearZeroMethodEnd:
|
|
if (scPreferred.NonLinear && scPreferred.LinearAdded &&
|
|
scPreferred.LinearAddedZeroMethodType == ZeroMethodType.AverageOverTime)
|
|
{
|
|
sVal = scPreferred.LinearAddedZeroMethodEnd.ToString(ec);
|
|
}
|
|
else
|
|
{
|
|
sVal = string.Empty; //In case there is no additional linear calibration (Zero Method End)
|
|
}
|
|
break;
|
|
case CSVImportTags.Tags.AdditionalLinearZeroMethodStart:
|
|
if (scPreferred.NonLinear && scPreferred.LinearAdded &&
|
|
scPreferred.LinearAddedZeroMethodType == ZeroMethodType.AverageOverTime)
|
|
{
|
|
sVal = scPreferred.LinearAddedZeroMethodStart.ToString(ec);
|
|
}
|
|
else
|
|
{
|
|
sVal = string.Empty; //In case there is no additional linear calibration (Zero Method Start)
|
|
}
|
|
break;
|
|
case CSVImportTags.Tags.DigitalOutputMode: sVal = sd.DigitalOutputMode.ToString(); bTextField = true; break;
|
|
case CSVImportTags.Tags.DigitalScaleMultiplier: sVal = sd.ScaleMultiplier.ToSerializeDbString(); bTextField = true; break;
|
|
case CSVImportTags.Tags.Direction: sVal = sd.Direction; bTextField = true; break;
|
|
case CSVImportTags.Tags.DisplayUnits: sVal = sd.DisplayUnit; bTextField = true; break;
|
|
case CSVImportTags.Tags.DurationMS: sVal = sd.DurationMS.ToString(ec); break;
|
|
case CSVImportTags.Tags.DigitalOutputDurationMS: sVal = sd.DigitalOutputDurationMS.ToString(ec); break;
|
|
case CSVImportTags.Tags.InitialOffset:
|
|
{
|
|
// Need to export nominal EU here. Scale the EU of the InitialOffset before Serializing to String
|
|
scPreferred.InitialOffsets.Offsets.First().EU = scPreferred.InitialOffsets.Offsets.First().EU * euConversionFactor;
|
|
sVal = scPreferred.InitialOffsets.Offsets.First().ToDbSerializeString();
|
|
bTextField = true;
|
|
break;
|
|
}
|
|
case CSVImportTags.Tags.LimitDuration: sVal = sd.LimitDuration ? "Yes" : "No"; break;
|
|
case CSVImportTags.Tags.NonLinear: sVal = scPreferred.NonLinear ? "Yes" : "No"; break;
|
|
case CSVImportTags.Tags.NumberOfAxes: sVal = sd.NumberOfAxes.ToString(); break;
|
|
case CSVImportTags.Tags.PhysicalDimension: sVal = sd.PhysicalDimension; bTextField = true; break;
|
|
case CSVImportTags.Tags.Polarity: sVal = sd.Polarity; bTextField = true; break;
|
|
case CSVImportTags.Tags.RangeHigh: sVal = (sd.RangeHigh * euConversionFactor).ToString(ec); break;
|
|
case CSVImportTags.Tags.RangeLow: sVal = (sd.RangeLow * euConversionFactor).ToString(ec); break;
|
|
case CSVImportTags.Tags.RangeMedium: sVal = (sd.RangeMedium * euConversionFactor).ToString(ec); break;
|
|
case CSVImportTags.Tags.SquibFireMode: sVal = sd.SquibFireMode.ToString(); bTextField = true; break;
|
|
case CSVImportTags.Tags.SquibMeasurementType: sVal = sd.SquibMeasurementType.ToString(); bTextField = true; break;
|
|
case CSVImportTags.Tags.SquibOutputCurrent: sVal = sd.SquibOutputCurrent.ToString(ec); break;
|
|
case CSVImportTags.Tags.SupportedExcitation: sVal = sd.GetSerializedSupportedExcitation(); bTextField = true; break;
|
|
case CSVImportTags.Tags.TimesUsed: sVal = sd.TimesUsed.ToString(); break;
|
|
case CSVImportTags.Tags.Unipolar: sVal = sd.UniPolar ? "Yes" : "No"; break;
|
|
case CSVImportTags.Tags.ZeroMethod: sVal = scPreferred.ZeroMethods.Methods.First().Method.ToString(); bTextField = true; break;//TODO: linear/nonlinear
|
|
case CSVImportTags.Tags.ZeroMethodEnd: sVal = scPreferred.ZeroMethods.Methods.First().End.ToString(ec); break;
|
|
case CSVImportTags.Tags.ZeroMethodStart: sVal = scPreferred.ZeroMethods.Methods.First().Start.ToString(ec); break;
|
|
case CSVImportTags.Tags.CapacityOutputIsBasedOn: sVal = scPreferred.Records.Records.First().CapacityOutputIsBasedOn.ToString("N3"); break;
|
|
case CSVImportTags.Tags.AtCapacity: sVal = scPreferred.Records.Records.First().AtCapacity ? "Yes" : "No"; break;
|
|
case CSVImportTags.Tags.SensitivityUnits: sVal = scPreferred.Records.Records.First().SensitivityUnits.ToString(); break;
|
|
case CSVImportTags.Tags.CheckOffset: sVal = sd.CheckOffset ? "Yes" : "No"; break;
|
|
case CSVImportTags.Tags.Broken: sVal = sd.Broken ? "Yes" : "No"; break;
|
|
case CSVImportTags.Tags.DoNotUse: sVal = sd.DoNotUse ? "Yes" : "No"; break;
|
|
case CSVImportTags.Tags.ISOChannelName: sVal = sd.ISOChannelName; break;
|
|
case CSVImportTags.Tags.UserCode: sVal = sd.UserCode; break;
|
|
case CSVImportTags.Tags.UserChannelName: sVal = sd.UserChannelName; break;
|
|
default: sVal = ""; break;
|
|
}
|
|
if (null == sVal) { return; }
|
|
|
|
if (bNeedComma) { sb.Append(listSeparator); }
|
|
else { bNeedComma = true; }
|
|
|
|
sb.Append(EscapeCSV(sVal, bTextField, listSeparator));
|
|
}
|
|
private void ExportVersion3(SensorData sd, SensorCalibration scPreferred, CSVImportTags.Tags tag, StringBuilder sb,
|
|
ref int currentNumber, string listSeparator, ref bool bNeedComma, double euConversionFactor,
|
|
CultureInfo ec)
|
|
{
|
|
|
|
}
|
|
private void ExportVersion4(SensorData sd, SensorCalibration scPreferred, CSVImportTags.Tags tag, StringBuilder sb,
|
|
ref int currentNumber, string listSeparator, ref bool bNeedComma, double euConversionFactor,
|
|
CultureInfo ec)
|
|
{
|
|
var sVal = string.Empty;
|
|
var bTextField = false;
|
|
switch (tag)
|
|
{
|
|
case CSVImportTags.Tags.DASSerialNumber: break;
|
|
case CSVImportTags.Tags.DASChannelIndex: break;
|
|
case CSVImportTags.Tags.StreamProfile:
|
|
sVal = sd.StreamOutUDPProfile.ToString();
|
|
bTextField = true;
|
|
break;
|
|
case CSVImportTags.Tags.UDPAddress:
|
|
if (sd.IsStreamInput()) { sVal = sd.StreamInUDPAddress; }
|
|
else { sVal = sd.StreamOutUDPAddress; }
|
|
bTextField = true;
|
|
break;
|
|
case CSVImportTags.Tags.TimeChannelId:
|
|
sVal = sd.StreamOutUDPTimeChannelId.ToString(ec);
|
|
break;
|
|
case CSVImportTags.Tags.DataChannelId:
|
|
sVal = sd.StreamOutUDPDataChannelId.ToString(ec);
|
|
break;
|
|
case CSVImportTags.Tags.TmNSConfig:
|
|
sVal = sd.StreamOutUDPTmNSConfig;
|
|
bTextField = true;
|
|
break;
|
|
case CSVImportTags.Tags.IRIGTimeDataPacketIntervalMS:
|
|
sVal = sd.StreamOutIRIGTimeDataPacketIntervalMs.ToString(ec);
|
|
break;
|
|
case CSVImportTags.Tags.TMATSIntervalMS:
|
|
sVal = sd.StreamOutTMATSIntervalMs.ToString(ec);
|
|
break;
|
|
case CSVImportTags.Tags.BaudRate:
|
|
sVal = sd.UartBaudRate.ToString(ec);
|
|
bTextField = true;
|
|
break;
|
|
case CSVImportTags.Tags.DataBits:
|
|
sVal = sd.UartDataBits.ToString(ec);
|
|
bTextField = true;
|
|
break;
|
|
case CSVImportTags.Tags.StopBits:
|
|
sVal = sd.UartStopBits.ToString();
|
|
bTextField = true;
|
|
break;
|
|
case CSVImportTags.Tags.Parity:
|
|
sVal = sd.UartParity.ToString();
|
|
bTextField = true;
|
|
break;
|
|
case CSVImportTags.Tags.DataFormat:
|
|
sVal = sd.UartDataFormat.ToString();
|
|
bTextField = true;
|
|
break;
|
|
case CSVImportTags.Tags.TestUserCode:
|
|
sVal = sd.UserCode.ToString();
|
|
bTextField = true;
|
|
break;
|
|
case CSVImportTags.Tags.TestUserChannelName:
|
|
sVal = sd.UserChannelName.ToString();
|
|
bTextField = true;
|
|
break;
|
|
case CSVImportTags.Tags.TestIsoCode:
|
|
sVal = sd.ISOCode.ToString();
|
|
bTextField = true;
|
|
break;
|
|
case CSVImportTags.Tags.TestIsoChannelName:
|
|
sVal = sd.ISOChannelName.ToString();
|
|
bTextField = true;
|
|
break;
|
|
}
|
|
if (bNeedComma) { sb.Append(listSeparator); }
|
|
else { bNeedComma = true; }
|
|
|
|
sb.Append(EscapeCSV(sVal, bTextField, listSeparator));
|
|
}
|
|
private void ExportTag(SensorData sd, SensorCalibration scPreferred, CSVImportTags.Tags tag, StringBuilder sb,
|
|
ref int currentNumber, string listSeparator, ref bool bNeedComma, double euConversionFactor, int version,
|
|
CultureInfo ec)
|
|
{
|
|
switch (version)
|
|
{
|
|
case 0: ExportVersion0(sd, scPreferred, tag, sb, ref currentNumber, listSeparator, ref bNeedComma, euConversionFactor, ec); break;
|
|
case 1: ExportVersion1(sd, scPreferred, tag, sb, ref currentNumber, listSeparator, ref bNeedComma, euConversionFactor, ec); break;
|
|
case 2: ExportVersion2(sd, scPreferred, tag, sb, ref currentNumber, listSeparator, ref bNeedComma, euConversionFactor, ec); break;
|
|
case 3: ExportVersion3(sd, scPreferred, tag, sb, ref currentNumber, listSeparator, ref bNeedComma, euConversionFactor, ec); break;
|
|
case 4: ExportVersion4(sd, scPreferred, tag, sb, ref currentNumber, listSeparator, ref bNeedComma, euConversionFactor, ec); break;
|
|
}
|
|
}
|
|
//FB 29478 Format that is used by ToString method from Scientific Notation if applicable to double
|
|
//https://stackoverflow.com/questions/1546113/double-to-string-conversion-without-scientific-notation/36204442#36204442
|
|
private string FormatScientificNotation() => $"0.{new string('#', 339)}";
|
|
|
|
|
|
// ReSharper disable once InconsistentNaming
|
|
public void ExportDataPRO()
|
|
{
|
|
try
|
|
{
|
|
if (!Directory.Exists(DefaultFolder))
|
|
{
|
|
Directory.CreateDirectory(DefaultFolder);
|
|
}
|
|
var di = new DirectoryInfo(DefaultFolder);
|
|
|
|
var fullPathToDataProFile = Path.Combine(di.FullName, DefaultFile);
|
|
|
|
if (File.Exists(fullPathToDataProFile)) { BackupAndDelete(fullPathToDataProFile); }
|
|
|
|
var includedSensors = new Dictionary<string, SensorData>();
|
|
var includedSensorModels = new Dictionary<string, SensorModel>();
|
|
var includedCalibrations = new Dictionary<string, SensorCalibration[]>();
|
|
var includedChanges = new Dictionary<SensorData, List<ISensorChange>>();
|
|
|
|
foreach (var sd in Sensors)
|
|
{
|
|
var scs = SensorCalibration.GetCalibrationsBySerialNumber(sd);
|
|
if (null == sd) { continue; }
|
|
var analog = sd.IsAnalog();
|
|
if (analog && (null == scs || !scs.Any())) { continue; }
|
|
if (null != scs && scs.Any())
|
|
{
|
|
includedCalibrations.Add(sd.SerialNumber, scs);
|
|
}
|
|
|
|
if (analog && sd.SupportedExcitation.Length == 0)
|
|
{
|
|
//Set supported excitation(s) based on any found calibration records
|
|
var supportedExcitationList = new List<ExcitationVoltageOptions.ExcitationVoltageOption>();
|
|
for (var i = 0; i < scs.Length; i++)
|
|
{
|
|
foreach (var calRecord in scs[i].Records.Records)
|
|
{
|
|
if (!supportedExcitationList.Contains(calRecord.Excitation))
|
|
{
|
|
supportedExcitationList.Add(calRecord.Excitation);
|
|
}
|
|
}
|
|
}
|
|
sd.SupportedExcitation = supportedExcitationList.ToArray();
|
|
}
|
|
|
|
includedSensors.Add(sd.SerialNumber, sd);
|
|
includedChanges.Add(sd, new List<ISensorChange>());
|
|
includedChanges[sd].AddRange(SensorChangeTypeHelper.GetAllSensorChanges(sd));
|
|
|
|
if (!analog) { continue; } //only care about sensormodel for analog sensors ..
|
|
|
|
var sm = SensorModelCollection.SensorModelList.GetSensorModel(sd.Manufacturer, sd.Model);
|
|
if (null == sm) continue;
|
|
var key = $"{sm.Manufacturer}x_x{sm.Model}";
|
|
if (!includedSensorModels.ContainsKey(key))
|
|
{
|
|
includedSensorModels.Add(key, sm);
|
|
}
|
|
}
|
|
ExportToFile(includedSensors, includedSensorModels, includedCalibrations, fullPathToDataProFile, includedChanges, ExportFirstUseDate);
|
|
OnDone?.Invoke();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
OnError?.Invoke(ex.Message); APILogger.Log(ex);
|
|
}
|
|
}
|
|
|
|
public void ExportEQX()
|
|
{
|
|
try
|
|
{
|
|
if (!Directory.Exists(DefaultFolder))
|
|
{
|
|
Directory.CreateDirectory(DefaultFolder);
|
|
}
|
|
var di = new DirectoryInfo(DefaultFolder);
|
|
|
|
var fullPathToDataProFile = Path.Combine(di.FullName, DefaultFile);
|
|
|
|
if (File.Exists(fullPathToDataProFile)) { BackupAndDelete(fullPathToDataProFile); }
|
|
|
|
var includedSensors = new Dictionary<string, SensorData>();
|
|
var includedCalibrations = new Dictionary<string, SensorCalibration[]>();
|
|
|
|
foreach (var sd in Sensors)
|
|
{
|
|
var scs = SensorCalibration.GetCalibrationsBySerialNumber(sd);
|
|
var sc = SensorCalibration.GetLatestCalibrationBySerialNumber(sd);
|
|
if (null == sd
|
|
|| null == scs
|
|
|| null == sc
|
|
|| scs.Length <= 0
|
|
|| sd.IsDigitalOutput()
|
|
|| (sc.NonLinear &&
|
|
sc.IRTraccCalculationType != NonLinearStyles.Polynomial &&
|
|
sc.IRTraccCalculationType != NonLinearStyles.IRTraccCalFactor &&
|
|
sc.IRTraccCalculationType != NonLinearStyles.IRTraccAverageOverTime)
|
|
//also export these types of non linear sensors?
|
|
//http://manuscript.dts.local/f/cases/edit/36885/EQX-requested-changes
|
|
)
|
|
{
|
|
//Should warn user that these sensors will not be exported
|
|
continue;
|
|
}
|
|
includedCalibrations.Add(sd.SerialNumber, scs);
|
|
|
|
if (sd.SupportedExcitation.Length == 0)
|
|
{
|
|
//Set supported excitation(s) based on any found calibration records
|
|
var supportedExcitationList = new List<ExcitationVoltageOptions.ExcitationVoltageOption>();
|
|
for (var i = 0; i < scs.Length; i++)
|
|
{
|
|
foreach (var calRecord in scs[i].Records.Records)
|
|
{
|
|
if (!supportedExcitationList.Contains(calRecord.Excitation))
|
|
{
|
|
supportedExcitationList.Add(calRecord.Excitation);
|
|
}
|
|
}
|
|
}
|
|
sd.SupportedExcitation = supportedExcitationList.ToArray();
|
|
}
|
|
|
|
includedSensors.Add(sd.SerialNumber, sd);
|
|
}
|
|
ExportToEQXFile(includedSensors, includedCalibrations, fullPathToDataProFile);
|
|
OnDone?.Invoke();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
OnError?.Invoke(ex.Message); APILogger.Log(ex);
|
|
}
|
|
}
|
|
private static void ExportToEQXFile(Dictionary<string, SensorData> includedSensors,
|
|
Dictionary<string, SensorCalibration[]> includedCalibration,
|
|
string exportFile)
|
|
{
|
|
EqxSensors eqxSensors = GetEQXSensorsFromSensorData(includedSensors, includedCalibration);
|
|
if (null == eqxSensors)
|
|
{
|
|
return;
|
|
}
|
|
var serializer = new XmlSerializer(typeof(EqxSensors));
|
|
if (File.Exists(exportFile))
|
|
{
|
|
File.Delete(exportFile);
|
|
}
|
|
using (var fs = new FileStream(exportFile, FileMode.CreateNew))
|
|
{
|
|
using (var writer = new StreamWriter(fs, Encoding.Unicode))
|
|
{
|
|
serializer.Serialize(writer, eqxSensors);
|
|
writer.Close();
|
|
}
|
|
fs.Close();
|
|
}
|
|
}
|
|
|
|
private static EqxSensors GetEQXSensorsFromSensorData(Dictionary<string, SensorData> includedSensors, Dictionary<string, SensorCalibration[]> includedCalibration)
|
|
{
|
|
EqxSensors rv = new EqxSensors();
|
|
|
|
|
|
|
|
List<EqxSensorGroup> eqxSensors = new List<EqxSensorGroup>();
|
|
foreach (var kvp in includedSensors)
|
|
{
|
|
var sd = kvp.Value as SensorData;
|
|
var scList = includedCalibration[kvp.Key];
|
|
// 34420: Add case for equal cal dates, to be then ordered by modify date
|
|
var sc = scList.Aggregate((curMax, x) => curMax == null ||
|
|
x.CalibrationDate > curMax.CalibrationDate ||
|
|
(x.CalibrationDate == curMax.CalibrationDate && x.ModifyDate > curMax.ModifyDate)
|
|
? x
|
|
: curMax);
|
|
var eqxScalingMethod = GetEqxScalingMethod(sc);
|
|
var eqxSensor = new EqxSensorGroup
|
|
{
|
|
Name = kvp.Value.SerialNumber,
|
|
SerialNumber = kvp.Value.SerialNumber,
|
|
UUID = string.IsNullOrEmpty(kvp.Value.UUID) ? Guid.NewGuid().ToString() : kvp.Value.UUID,
|
|
CalDate = includedCalibration[kvp.Key].First().CalibrationDate,
|
|
Sensor = new EqxSensorAxis[1]
|
|
{
|
|
GetSensorAxis(sd, scList, sc, eqxScalingMethod)
|
|
},
|
|
};
|
|
SetSensitivities(sc, eqxSensor.Sensor[0], eqxScalingMethod);
|
|
eqxSensors.Add(eqxSensor);
|
|
}
|
|
rv.SensorGroup = eqxSensors.ToArray();
|
|
rv.FileInfo = new EqxFileInfo();
|
|
rv.FileInfo.DataFormatEdition = "1.5";
|
|
rv.FileInfo.Software = System.Reflection.Assembly.GetEntryAssembly().GetName().Name;
|
|
rv.FileInfo.SoftwareVersion = System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString(4);
|
|
rv.FileInfo.CreationTime = DateTime.UtcNow;
|
|
return rv;
|
|
}
|
|
private static EqxSensorAxis GetSensorAxis(SensorData sd, SensorCalibration [] scList, SensorCalibration sc, EqxScalingMethod eqxScalingMethod)
|
|
{
|
|
var eqx = new EqxSensorAxis
|
|
{
|
|
Name = sd.SerialNumber,
|
|
ElectricalMethodSpecified = true,
|
|
ElectricalMethod = GetEqxElectricalMethod(sd.Bridge, scList.First().IsProportional),
|
|
SWFilterClassTypeSpecified = true,
|
|
SWFilterClassType = GetEqxSWFilterCLass(sd.FilterClass.FClass),
|
|
Supplier = sd.Manufacturer,
|
|
PhysicalUnit = sd.DisplayUnit,
|
|
Model = sd.Model,
|
|
IDModuleString = sd.EID,
|
|
LocationCode = sd.ISOCode,
|
|
LocationLongname = sd.ISOChannelName,
|
|
};
|
|
if (sd.IsDigitalInput()) { SetDigitalInputProperties(eqx, sd); }
|
|
else if (sd.IsSquib()) { SetSquibProperties(eqx, sd); }
|
|
else if (sd.IsAnalog()) { SetAnalogProperties(eqx, sd, eqxScalingMethod, sc); }
|
|
return eqx;
|
|
}
|
|
private static void SetAnalogProperties(EqxSensorAxis eqx, SensorData sd, EqxScalingMethod eqxScalingMethod,
|
|
SensorCalibration sc)
|
|
{
|
|
eqx.ShuntResistanceSpecified = true;
|
|
eqx.ShuntResistance = (float)sd.BridgeResistance;
|
|
eqx.OffsetTolSpecified = true;
|
|
eqx.OffsetTol = (float)sd.OffsetToleranceHigh;
|
|
eqx.CalDateSpecified = true;
|
|
eqx.CalDate = sc.CalibrationDate;
|
|
eqx.CalPeriodSpecified = true;
|
|
eqx.CalPeriod = sd.CalInterval;
|
|
eqx.CalPerson = sc.Username;
|
|
eqx.MaxRangeSpecified = true;
|
|
eqx.MaxRange = (float)sd.RangeHigh;
|
|
eqx.MinRangeSpecified = true;
|
|
eqx.MinRange = (float)sd.RangeLow;
|
|
eqx.PreferredRangeSpecified = true;
|
|
eqx.PreferredRange = (float)sd.Capacity;
|
|
eqx.OffsetCheckSpecified = true;
|
|
eqx.OffsetCheck = sd.CheckOffset;
|
|
eqx.Remark = sd.Comment;
|
|
eqx.CompanyLongname = sd.Manufacturer;
|
|
eqx.ExcitationVoltageSpecified = true;
|
|
eqx.ExcitationVoltage = (float)Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(sc.Records.Records.First().Excitation);
|
|
eqx.SensitivityVoltageSpecified = true;
|
|
eqx.SensitivityVoltage = sc.IsProportional ? 1F : (float)Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(sc.Records.Records.First().Excitation);
|
|
eqx.SWOffsetFixValueSpecified = true;
|
|
eqx.SWOffsetFixValue = (float)sc.InitialOffsets.Offsets.First().EU;
|
|
eqx.MountingPolaritySpecified = true;
|
|
eqx.MountingPolarity = sd.Invert ? EqxPolarity.Negative : EqxPolarity.Positive;
|
|
eqx.OffsetCompensationSpecified = true;
|
|
eqx.OffsetCompensation = sc.RemoveOffset;
|
|
eqx.ScalingMethodSpecified = true;
|
|
eqx.ScalingMethod = eqxScalingMethod;
|
|
eqx.SerialNumber = sd.SerialNumber;
|
|
eqx.ShuntCheckPosSpecified = true;
|
|
eqx.ShuntCheckPos = sd.PerformShuntEmulation;
|
|
eqx.SWOffsetCompensation = sc.RemoveOffset;
|
|
eqx.SWOffsetCompensationSpecified = true;
|
|
eqx.SWOffsetCompensationType = GetSWOffsetCompensationType(sc.ZeroMethods.Methods[0].Method);
|
|
eqx.SWOffsetCompensationSpecified = true;
|
|
|
|
if (sc.ZeroMethods.Methods[0].Method == ZeroMethodType.AverageOverTime)
|
|
{
|
|
eqx.SWOffsetCalculationStartSec = Convert.ToSingle(sc.ZeroMethods.Methods[0].Start);
|
|
eqx.SWOffsetCalculationStartSecSpecified = true;
|
|
eqx.SWOffsetCalculationEndSec = Convert.ToSingle(sc.ZeroMethods.Methods[0].End);
|
|
eqx.SWOffsetCalculationEndSecSpecified = true;
|
|
}
|
|
}
|
|
private static EqxSWOffsetCompensationType GetSWOffsetCompensationType(ZeroMethodType zeroMethod)
|
|
{
|
|
switch(zeroMethod)
|
|
{
|
|
case ZeroMethodType.AverageOverTime: return EqxSWOffsetCompensationType.Averagecalculation;
|
|
case ZeroMethodType.None: return EqxSWOffsetCompensationType.Fixvalue;
|
|
case ZeroMethodType.UsePreEventDiagnosticsZero: return EqxSWOffsetCompensationType.Pretestmeasurement;
|
|
default: throw new InvalidCastException($"Invalid offset type: {zeroMethod}");
|
|
}
|
|
}
|
|
private static void SetDigitalInputProperties(EqxSensorAxis eqx, SensorData sd)
|
|
{
|
|
eqx.InputMode = GetEqxInputMode(sd.InputMode);
|
|
eqx.InputModeSpecified = true;
|
|
}
|
|
private static void SetSquibProperties(EqxSensorAxis eqx, SensorData sd)
|
|
{
|
|
eqx.FiringModeSpecified = true;
|
|
eqx.FiringMode = GetEqxFiringMode(sd.SquibFireMode);
|
|
eqx.FiringDelaySpecified = true;
|
|
eqx.FiringDelay = Convert.ToSingle(sd.SquibFireDelayMS);
|
|
if (sd.LimitSquibFireDuration)
|
|
{
|
|
eqx.FiringDurationSpecified = true;
|
|
eqx.FiringDuration = Convert.ToInt32(sd.SquibFireDurationMS*1000);
|
|
}
|
|
eqx.FiringVoltageLimitSpecified = false;
|
|
eqx.FiringCurrentLimitSpecified = true;
|
|
eqx.FiringCurrentLimit = Convert.ToInt32(sd.SquibOutputCurrent*1000);
|
|
}
|
|
private static EqxFiringMode GetEqxFiringMode(SquibFireMode mode)
|
|
{
|
|
switch(mode)
|
|
{
|
|
case SquibFireMode.AC: return EqxFiringMode.AC;
|
|
case SquibFireMode.CAP: return EqxFiringMode.CapacitorDischarge;
|
|
case SquibFireMode.CONSTANT: return EqxFiringMode.ConstantCurrent;
|
|
case SquibFireMode.NONE: return EqxFiringMode.CapacitorDischarge;
|
|
default: throw new InvalidCastException($"Unknown squib firing mode: {mode}");
|
|
}
|
|
}
|
|
private static EqxInputModes GetEqxInputMode(DigitalInputModes inputMode)
|
|
{
|
|
switch(inputMode)
|
|
{
|
|
case DigitalInputModes.CCNC: return EqxInputModes.CCNC;
|
|
case DigitalInputModes.CCNO: return EqxInputModes.CCNO;
|
|
case DigitalInputModes.THL: return EqxInputModes.THL;
|
|
case DigitalInputModes.TLH: return EqxInputModes.TLH;
|
|
default: throw new InvalidCastException($"Unknown input mode: {inputMode}");
|
|
}
|
|
}
|
|
private static void SetSensitivities(SensorCalibration sc, EqxSensorAxis axis, EqxScalingMethod eqxScalingMethod)
|
|
{
|
|
if (eqxScalingMethod == EqxScalingMethod.IRTRACC)
|
|
{
|
|
if (sc.IRTraccCalculationType == NonLinearStyles.IRTraccCalFactor)
|
|
{
|
|
SetSensitivitiesCalFactor(sc, axis, eqxScalingMethod);
|
|
}
|
|
else
|
|
{
|
|
SetSensitivitiesIRTRACC(sc, axis);
|
|
}
|
|
}
|
|
else { SetSensitivitiesAllTheRest(sc, axis, eqxScalingMethod); }
|
|
}
|
|
private static void SetSensitivitiesIRTRACC(SensorCalibration sc, EqxSensorAxis axis)
|
|
{
|
|
var record = sc.Records.Records.FirstOrDefault();
|
|
if (null == record)
|
|
{
|
|
return;
|
|
}
|
|
//set EU to mV, set Sensitivity1 to 1000/Cal factor, set sensitivity 3 to (Intercept/calfactor)*1000?
|
|
axis.Sensitivity = Convert.ToSingle(record.Poly.MMPerV);
|
|
axis.SensitivitySpecified = true;
|
|
axis.Sensitivity2Specified = true;
|
|
axis.Sensitivity2 = record.Poly.LinearizationExponent;
|
|
axis.EngineeringUnit = EqxEngineeringUnit.mV;
|
|
}
|
|
private static void SetSensitivitiesCalFactor(SensorCalibration sc, EqxSensorAxis axis, EqxScalingMethod eqxScalingMethod)
|
|
{
|
|
var record = sc.Records.Records.FirstOrDefault();
|
|
if (null == record)
|
|
{
|
|
return;
|
|
}
|
|
//set EU to mV, set Sensitivity1 to 1000/Cal factor, set sensitivity 3 to (Intercept/calfactor)*1000?
|
|
axis.Sensitivity = Convert.ToSingle(1000D / record.Poly.CalibrationFactor);
|
|
axis.SensitivitySpecified = true;
|
|
axis.Sensitivity2Specified = true;
|
|
axis.Sensitivity2 = record.Poly.LinearizationExponent;
|
|
axis.Sensitivity3Specified = true;
|
|
axis.Sensitivity3 = 1000D * (record.Poly.ZeroPositionIntercept / record.Poly.CalibrationFactor);
|
|
axis.Sensitivity4Specified = false;
|
|
axis.Sensitivity5Specified = false;
|
|
axis.EngineeringUnit = EqxEngineeringUnit.mV;
|
|
}
|
|
private static void SetSensitivitiesAllTheRest(SensorCalibration sc, EqxSensorAxis axis, EqxScalingMethod eqxScalingMethod)
|
|
{
|
|
axis.SensitivitySpecified = true;
|
|
axis.Sensitivity = (float)GetEqxSensitivity(sc, 1);
|
|
axis.Sensitivity2Specified = eqxScalingMethod != EqxScalingMethod.Linear;
|
|
axis.Sensitivity2 = GetEqxSensitivity(sc, 2);
|
|
axis.Sensitivity3Specified = eqxScalingMethod != EqxScalingMethod.Linear;
|
|
axis.Sensitivity3 = GetEqxSensitivity(sc, 3);
|
|
axis.Sensitivity4Specified = eqxScalingMethod == EqxScalingMethod.CubicPolynomial;
|
|
axis.Sensitivity4 = GetEqxSensitivity(sc, 4);
|
|
axis.Sensitivity5Specified = eqxScalingMethod == EqxScalingMethod.CubicPolynomial;
|
|
axis.Sensitivity5 = GetEqxSensitivity(sc, 5);
|
|
}
|
|
private static double GetEqxSensitivity(SensorCalibration sc, int sensitivityIndex)
|
|
{
|
|
if (sensitivityIndex > 5) { return 0D; }
|
|
switch (GetEqxScalingMethod(sc))
|
|
{
|
|
case EqxScalingMethod.CubicPolynomial:
|
|
return sensitivityIndex >= 2 ? sc.Records.Records.First().Poly.PolynomialCoefficients[sensitivityIndex - 2] : 0D;
|
|
case EqxScalingMethod.IRTRACC:
|
|
case EqxScalingMethod.Linear:
|
|
return sc.Records.Records.First().Sensitivity;
|
|
default:
|
|
return 0D;
|
|
}
|
|
}
|
|
|
|
private static EqxScalingMethod GetEqxScalingMethod(SensorCalibration sc)
|
|
{
|
|
if (sc.NonLinear)
|
|
{
|
|
if (sc.Records.Records.First().Poly.NonLinearStyle == NonLinearStyles.Polynomial)
|
|
{
|
|
return EqxScalingMethod.CubicPolynomial;
|
|
}
|
|
return EqxScalingMethod.IRTRACC;
|
|
}
|
|
return EqxScalingMethod.Linear;
|
|
}
|
|
|
|
private static EqxFilterClassType GetEqxSWFilterCLass(FilterClassType filterClass)
|
|
{
|
|
switch (filterClass)
|
|
{
|
|
case FilterClassType.CFC10:
|
|
return EqxFilterClassType.CFC10;
|
|
case FilterClassType.CFC1000:
|
|
return EqxFilterClassType.CFC1000;
|
|
case FilterClassType.CFC180:
|
|
return EqxFilterClassType.CFC180;
|
|
case FilterClassType.CFC60:
|
|
return EqxFilterClassType.CFC60;
|
|
case FilterClassType.CFC600:
|
|
return EqxFilterClassType.CFC600;
|
|
case FilterClassType.AdHoc:
|
|
return EqxFilterClassType.AdHoc;
|
|
default:
|
|
return EqxFilterClassType.None;
|
|
}
|
|
}
|
|
|
|
private static EqxElectricalMethod GetEqxElectricalMethod(SensorConstants.BridgeType bridgeType, bool isProportional)
|
|
{
|
|
switch (bridgeType)
|
|
{
|
|
case SensorConstants.BridgeType.IEPE:
|
|
return EqxElectricalMethod.PiezoInput;
|
|
case SensorConstants.BridgeType.FullBridge:
|
|
if (isProportional)
|
|
{
|
|
return EqxElectricalMethod.FullBridge;
|
|
}
|
|
else
|
|
{
|
|
return EqxElectricalMethod.ActiveSensor;
|
|
}
|
|
case SensorConstants.BridgeType.HalfBridge:
|
|
if (isProportional)
|
|
{
|
|
return EqxElectricalMethod.HalfBridge;
|
|
}
|
|
else
|
|
{
|
|
return EqxElectricalMethod.HalfBridgeActive;
|
|
}
|
|
case SensorConstants.BridgeType.QuarterBridge:
|
|
if (isProportional)
|
|
{
|
|
return EqxElectricalMethod.QuarterBridge;
|
|
}
|
|
else
|
|
{
|
|
return EqxElectricalMethod.QuarterBridgeActive;
|
|
}
|
|
default:
|
|
return EqxElectricalMethod.FullBridge;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
private static void ExportToFile(Dictionary<string, SensorData> includedSensors,
|
|
Dictionary<string, SensorModel> includedSensorModels,
|
|
Dictionary<string, SensorCalibration[]> includedCalibration,
|
|
string exportFile,
|
|
Dictionary<SensorData, List<ISensorChange>> includedChanges = null,
|
|
bool bExportFirstUseDate = true)
|
|
{
|
|
using (TextWriter writer = new StreamWriter(exportFile, false))
|
|
{
|
|
XmlWriter xmlWriter = null;
|
|
try
|
|
{
|
|
xmlWriter = new XmlTextWriter(writer);
|
|
xmlWriter.WriteStartDocument();
|
|
xmlWriter.WriteStartElement("ExportFile");
|
|
xmlWriter.WriteAttributeString("Version", FileUtils.CurrentXmlVersion.ToString(CultureInfo.InvariantCulture));
|
|
|
|
var fields = Enum.GetValues(typeof(TopLevelFields)).Cast<TopLevelFields>().ToArray();
|
|
|
|
foreach (var f in fields)
|
|
{
|
|
switch (f)
|
|
{
|
|
case TopLevelFields.Calibrations:
|
|
if (includedCalibration.Count > 0)
|
|
{
|
|
xmlWriter.WriteStartElement(f.ToString());
|
|
foreach (var c in includedCalibration)
|
|
{
|
|
foreach (var sc in c.Value) { xmlWriter.Flush(); sc.WriteXML(ref xmlWriter); xmlWriter.Flush(); }
|
|
}
|
|
xmlWriter.WriteEndElement();
|
|
}
|
|
break;
|
|
case TopLevelFields.SensorModels:
|
|
if (includedSensorModels.Count > 0)
|
|
{
|
|
xmlWriter.WriteStartElement(f.ToString());
|
|
foreach (var sm in includedSensorModels)
|
|
{
|
|
xmlWriter.Flush(); sm.Value.WriteXML(ref xmlWriter); xmlWriter.Flush();
|
|
}
|
|
xmlWriter.WriteEndElement();
|
|
}
|
|
break;
|
|
case TopLevelFields.Sensors:
|
|
if (includedSensors.Count > 0)
|
|
{
|
|
xmlWriter.Flush();
|
|
xmlWriter.WriteStartElement(f.ToString());
|
|
foreach (var sd in includedSensors)
|
|
{
|
|
xmlWriter.Flush(); sd.Value.WriteXML(ref xmlWriter, bExportFirstUseDate); xmlWriter.Flush();
|
|
}
|
|
xmlWriter.WriteEndElement();
|
|
}
|
|
break;
|
|
case TopLevelFields.SensorChangeHistory:
|
|
if (null != includedChanges && includedChanges.Any())
|
|
{
|
|
WriteIncludedChanges(ref xmlWriter, includedChanges);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
xmlWriter.WriteEndElement();
|
|
}
|
|
finally
|
|
{
|
|
if (xmlWriter != null)
|
|
{
|
|
xmlWriter.Flush();
|
|
xmlWriter.Close();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// writes all sensor changes to xml
|
|
/// </summary>
|
|
private static void WriteIncludedChanges(ref XmlWriter writer,
|
|
IReadOnlyDictionary<SensorData, List<ISensorChange>> changes)
|
|
{
|
|
writer.WriteStartElement("SensorChangeHistory");
|
|
using (var eSensor = changes.GetEnumerator())
|
|
{
|
|
while (eSensor.MoveNext())
|
|
{
|
|
WriteIncludedChanges(ref writer, eSensor.Current.Key, eSensor.Current.Value);
|
|
}
|
|
}
|
|
writer.WriteEndElement();
|
|
}
|
|
|
|
/// <summary>
|
|
/// writes all changes for a given sensor to xml
|
|
/// </summary>
|
|
private static void WriteIncludedChanges(ref XmlWriter writer, ISensorData sensor,
|
|
IReadOnlyList<ISensorChange> changes)
|
|
{
|
|
writer.WriteStartElement("Sensor");
|
|
writer.WriteAttributeString("SensorId", sensor.DatabaseId.ToString(CultureInfo.InvariantCulture));
|
|
foreach (var change in changes)
|
|
{
|
|
writer.WriteStartElement("Change");
|
|
writer.WriteAttributeString("RecordId", change.RecordId.ToString(CultureInfo.InvariantCulture));
|
|
writer.WriteAttributeString("ChangeType", change.ChangeType.ToString());
|
|
writer.WriteAttributeString("Timestamp", change.TimeStamp.ToString("O", CultureInfo.InvariantCulture));
|
|
writer.WriteAttributeString("Username", change.UserName);
|
|
writer.WriteAttributeString("Value1", change.Value1);
|
|
writer.WriteAttributeString("Value2", change.Value2);
|
|
writer.WriteAttributeString("Value3", change.Value3);
|
|
writer.WriteAttributeString("Value4", change.Value4);
|
|
writer.WriteEndElement();
|
|
}
|
|
writer.WriteEndElement();
|
|
}
|
|
public const string ZM_STRING_AVERAGE_OVER_TIME = "Avg";
|
|
public const string ZM_STRING_DIAGNOSTICS = "Pre";
|
|
public const string ZM_STRING_NONE = "0mV";
|
|
/// <summary>
|
|
/// gets the latest sensitivity (as a double) for a given sensor and an excitation
|
|
/// </summary>
|
|
/// <param name="option"></param>
|
|
/// <param name="sd"></param>
|
|
/// <returns></returns>
|
|
private double GetSensitivity(ExcitationVoltageOptions.ExcitationVoltageOption option, SensorData sd)
|
|
{
|
|
var sc = SensorCalibration.GetLatestCalibrationBySerialNumberAndExcitation(sd, option);
|
|
if (null == sc) return double.NaN;
|
|
foreach (var r in sc.Records.Records)
|
|
{
|
|
if (r.Excitation == option) { return r.Sensitivity; }
|
|
}
|
|
return double.NaN;
|
|
}
|
|
|
|
/// <summary>
|
|
/// escape a string to CSV friendly string
|
|
/// </summary>
|
|
/// <param name="str"></param>
|
|
/// <param name="bTextField">whether the field is intended to be text and may need to be escaped (example, sensor serial of 6-1)</param>
|
|
/// <param name="listSeparator"></param>
|
|
/// <returns></returns>
|
|
public static string EscapeCSV(string str, bool bTextField, string listSeparator)
|
|
{
|
|
//find out if we need to escape string, if so
|
|
var quote = str.Contains(listSeparator) || str.Contains("\"") || str.Contains("\r") || str.Contains("\n");
|
|
|
|
if (!string.IsNullOrWhiteSpace(str) && bTextField &&
|
|
char.IsDigit(str[0]))
|
|
{
|
|
quote = true;
|
|
}
|
|
|
|
if (!quote) return str;
|
|
//then go character by character escaping as you go
|
|
var sb = new StringBuilder();
|
|
sb.Append("\"");
|
|
foreach (var nextChar in str)
|
|
{
|
|
sb.Append(nextChar);
|
|
if (nextChar == '"') { sb.Append("\""); }
|
|
}
|
|
sb.Append("\"");
|
|
str = sb.ToString();
|
|
|
|
return str;
|
|
}
|
|
public static string UnEscapeCSV(string str)
|
|
{
|
|
if (!str.StartsWith("\"") || !str.EndsWith("\""))
|
|
{
|
|
return str;
|
|
}
|
|
str = str.Substring(1, str.Length - 2);
|
|
var sb = new StringBuilder();
|
|
for (var i = 0; i < str.Length; i++)
|
|
{
|
|
var c = str[i];
|
|
if (i == str.Length - 2) { sb.Append(c); }
|
|
else
|
|
{
|
|
if (c == '"' && str[i + 1] == '"')
|
|
{
|
|
sb.Append(c);
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
str = sb.ToString();
|
|
return str;
|
|
}
|
|
}
|
|
}
|
|
|