using DTS.Common.Classes.Sensors; using DTS.Common.DAS.Concepts; using DTS.Common.DAS.Concepts.DAS.Channel; using DTS.Common.Enums; using DTS.Common.Enums.Sensors; using DTS.Common.Interface.DASFactory; using DTS.Common.Interface.DASFactory.Diagnostics; using DTS.Common.Interface.Sensors.SoftwareFilters; using DTS.Common.Utilities.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; namespace DTS.DASLib.Service { /// /// Analog input channel. This class contains the properties of a channel /// connected to an analog sensor. Casting a channel as this type will provide /// access to the Analog Sensor specific properties of the channel. /// [Serializable] public class AnalogInputDASChannel : InputDASChannel, IAnalogInputDASChannel, ILevelTriggerable, IEngineeringUnitAware, ILinearized, IInversionAware { public enum Fields { TypeOfBridge = 0, BridgeResistanceOhms, SensorCapacityEU, SensorPolarity, DesiredRangeWithHeadroomEU, SensitivityMilliVoltsPerEU, IsProportionalToExcitation, IsInverted, Excitation, EngineeringUnits, SerialNumber, Description, ZeroMethod, ZeroAverageStartSeconds, ZeroAverageStopSeconds, InitialEU, ShuntIsEnabled, VoltageInsertCheckEnabled, CalSignalIsEnabled, RemoveOffset, VerifyOffset, OffsetToleranceLowMv, OffsetToleranceHighMv, ISOCode, LevelTrigger, SoftwareFrequency, IEPEChannel, Unipolar, UnsupersampledSampleRate }; [NonSerialized] public const Fields FIRST_FIELD = Fields.TypeOfBridge; [NonSerialized] public const Fields LAST_FIELD = Fields.IEPEChannel; /// /// Type of Wheatstone Bridge in the sensor; half, full, etc. /// public SensorConstants.BridgeType TypeOfBridge { get; set; } /// /// 14042 Flash Clear turns of excitation for s6 /// this allows for ILevelTriggerable channels to store and cache a sample average for checking /// level triggered /// double? ILevelTriggerable.SampleAverageADC { get; set; } = null; /// /// used during TDAS diagnostics, it's a throw away value that's computed during configuration /// then compared to during measure shunt. /// public int ShuntTargetADC { get; set; } = Convert.ToInt32(.8D * short.MaxValue); public SensorConstants.BridgeType[] SupportedBridges { get; set; } /// /// the types of digital input modes supported by the channel. /// by default all digital modes are supported, and some hardware restrict the list (notably the g5) /// public DigitalInputModes[] SupportedDigitalInputModes { get; set; } /// /// IEPE Coupling mode (AC, AC/DC) /// correct voltage base on this property. /// public SensorConstants.CouplingModes CouplingMode { get; set; } /// /// whether to use AC coupling when a bridge mode is on channel (full/half/quarter bridges) /// 18294 Implement Bridge AC/DC coupling(fw update dependent) /// public bool ACCouplingModeEnabled { get; set; } /// /// Resistance of the Bridge in the sensor. /// public double BridgeResistanceOhms { get; set; } /// /// used to store 2D/3D IR-TRACC ZeroPoint Voltage data /// public double ZeroPoint { get; set; } /// /// Bi-Polar maximum tolerance of sensor in Engineering Units. /// public double SensorCapacityEU { get; set; } /// /// Sensor capacity specified in sensor database. /// public double SensorCapacity { get; set; } /// /// Sensor polarity specified in sensor database. /// public string SensorPolarity { get; set; } /// /// The desired Bi-Polar range of readings (in Engineering Units) /// from this sensor for this test or event. This must be /// within the SensorCapacityEU of the sensor. /// public double DesiredRangeWithHeadroomEU { get; set; } /// /// Sensitivity of the sensor in Millivots per Engineering Unit /// as specified by the sensor's manufacturer or hardware settings. /// public double SensitivityMilliVoltsPerEU { get; set; } = 0D; public double SensitivityMilliVoltsPerEUNormalized => SensitivityMilliVoltsPerEU * (IsProportionalToExcitation && SensitivityUnits != SensorConstants.SensUnits.mVperEU ? Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(Excitation) : 1.0) / (AtCapacity ? CapacityOutputIsBasedOn : 1.0); /// /// Are sensor readings proportional to excitation voltage? /// public bool IsProportionalToExcitation { get; set; } public bool IsSupported(ExcitationVoltageOptions.ExcitationVoltageOption o) { foreach (var se in SupportedExcitation) { if (se == o) { return true; } } return false; } /// /// Is this sensor's output inverted? /// public bool IsInverted { get; set; } public string OriginalChannelName { get; set; } public string ChannelName2 { get; set; } /// /// refers to a unique id for a logical channel in the test /// for now this is using TestObjectChannel.GetId() /// which is in the form of TestObjectSerial_ChannelType_ChannelId /// public string ChannelId { get; set; } public string HardwareChannelName { get; set; } public string DIUnits { get; set; } public DigitalInputModes DigitalMode { get; set; } private DigitalInputScaleMultiplier _digitalScaleMultiplier = new DigitalInputScaleMultiplier(); public DigitalInputScaleMultiplier DigitalMultiplier { get => _digitalScaleMultiplier ?? (_digitalScaleMultiplier = new DigitalInputScaleMultiplier()); set => _digitalScaleMultiplier = value; } public DTS.Common.Classes.Sensors.LinearizationFormula LinearizationFormula { get; set; } /// /// The excitation voltage to apply to the sensor. Firmware will provide the /// correct voltage base on this property. /// public ExcitationVoltageOptions.ExcitationVoltageOption Excitation { get; set; } public ExcitationVoltageOptions.ExcitationVoltageOption[] SupportedExcitation { get; set; } /// /// String representation of the Engineering Units this sensor reads, for example /// "g" or "m/s/s" or "meters per second", etc. Not mathematically relevant, only /// used for display. /// public string EngineeringUnits { get; set; } /// /// Serial number of the sensor. /// public string SerialNumber { get; set; } /// /// Manufacturer of the sensor. /// public string Manufacturer { get; set; } /// /// Model of the sensor. /// public string Model { get; set; } /// /// A text description of the sensor. /// public string Description { get; set; } /// /// How will this sensor be zeroed? /// public ZeroMethodType ZeroMethod { get; set; } /// /// Start time for the zero window relative to T=0 /// used if ZeroMethod is AverageOverTime. /// public double ZeroAverageStartSeconds { get; set; } /// /// Stop time for the zero window relative to T=0 /// used if ZeroMethod is AverageOverTime. /// public double ZeroAverageStopSeconds { get; set; } /// /// The initial EU value /// public double InitialEU { get; set; } public string InitialOffset { get; set; } public bool Unipolar { get; set; } /// /// Should the shunt be enabled? /// public bool ShuntIsEnabled { get; set; } /// /// some DAS require holding zeromV in adc in the xml configuration (slice2) /// this is here to hold that information /// public short ZeromVInADC { get; set; } /// /// should voltage insertion (gain) check be enabled? /// public bool VoltageInsertionCheckEnabled { get; set; } public bool IEPEChannel { get; set; } public bool DigitalInputChannel { get; set; } public bool CalSignalIsEnabled { get; set; } /// /// Setting this true will flag the hardware to compensate for the offset of the sensor /// during a call to DiagnosticsService.Diagnose(...). /// public bool RemoveOffset { get; set; } /// /// Should we verify the measured offset to the limits? /// public bool VerifyOffset { get; set; } /// /// The lower limit on allowed offset for the connected sensor. /// public double OffsetToleranceLowMilliVolts { get; set; } /// /// The upper limit on allowed offset for the connected sensor. /// public double OffsetToleranceHighMilliVolts { get; set; } public DateTime LastCalibrationDate { get; set; } public DateTime CalDueDate { get; set; } /// /// The ISO code for this channel. /// public string ISOCode { get; set; } /// /// Not available on slice or G5. Remove for now? /// public bool BypassAAFilter { get; set; } public string SensorID { get; set; } /// /// Get the channel diagnostics results (if available) for this channel. /// public IDiagnosticResult Diagnostics { get { try { IDiagnosticResult[] allChannelDiagnostics; IEnumerable theseChannelDiagnostics; if (null == (allChannelDiagnostics = OwningModule.OwningDAS.ChannelDiagnosticsResults)) throw new NoDiagnosticsAvailable("No diagnostics available (for any channel)"); if (null == (theseChannelDiagnostics = (allChannelDiagnostics.Where(r => r.DASChannelNumber == Number)))) throw new NoDiagnosticsAvailable("No diagnostics available (for this channel)"); if (theseChannelDiagnostics.Count() > 1) throw new TooManyDiagnosticsAvailable("Several diagnostics results were found for the specified channel; only one was expected"); if (theseChannelDiagnostics.Count() < 1) { throw new NoDiagnosticsAvailable("No diagnostics available (for this channel)"); } return theseChannelDiagnostics.First(); } catch (Exception ex) { throw new ApplicationException("encountered problem getting diagnostics for channel " + (Description ?? ""), ex); } } } /// /// some channels should not be refreshed from the database prior to running configuration, for example sensors that are part of a group /// should not be updated from database /// public bool UpdateChannelFromDatabase { get; set; } = true; /// /// /// Get/set the "trigger below" threshold. Set to "null" to deactivate. /// public double? TriggerBelowThresholdEu { get; set; } /// /// /// Get/set the "trigger above" threshold. Set to "null" to deactivate. /// public double? TriggerAboveThresholdEu { get; set; } public bool AlreadyLevelTriggered { get; set; } public LevelTriggerTypes LevelTriggerType { get; set; } public double MeasuredEULevelTriggerCheck { get; set; } /// /// Temporary fix that'll be addressed in 1.1 /// public double SoftwareFilterFrequency { get; set; } /// /// Fb 13120 For now continue using SoftwareFilterFrequency needs to be refactored to use SoftwareFilterClass instead /// public IFilterClass SoftwareFilterClass { get; set; } /// /// Get/set the for this channel. /// public IDiagnosticResult DiagnosticInformation { get { try { var cals = from cal in OwningModule.OwningDAS.ChannelDiagnosticsResults where cal.DASChannelNumber == Number select cal; // make sure we only got one var diagnosticsResults = cals as IDiagnosticResult[] ?? cals.ToArray(); if (diagnosticsResults.Length > 1) { // "SensorDBTables.GetCalibrationBySerialNumberAndDate: Duplicate entries for {0} and {1}" throw new ApplicationException("found duplicate calibration records for channel"); } return diagnosticsResults.Any() ? diagnosticsResults.ToArray()[0] : null; } catch (Exception ex) { throw new ApplicationException("encountered problem getting value for " + GetType().FullName + ".CalibrationInformation property", ex); } } } /// /// Get/set the measured excitation voltage. /// public double? MeasuredExcitationVolts { get { try { return DiagnosticInformation.MeasuredExcitationMilliVolts / 1000.0; } catch (Exception ex) { throw new ApplicationException("encountered problem getting " + GetType().FullName + ".MeasuredExcitationVoltage property value", ex); } } } /// /// Get/set the factory excitation voltage. /// public double? FactoryExcitationVolts { get { try { return DiagnosticInformation.ExpectedExcitationMilliVolts / 1000.0; } catch (Exception ex) { throw new ApplicationException("encountered problem getting " + GetType().FullName + ".FactoryExcitationVoltage property value", ex); } } } public double ScalefactorMilliVoltsPerADC { get; set; } public double ScalefactorEngineeringUnitsPerADC { get; set; } public double NoiseAsPercentOfFullScale { get; set; } /// /// If this channel is supersampled, what the regular sampling rate is /// public double UnsupersampledSampleRate { get; set; } /// /// A string representation of the channel object. /// /// Checks the description and serial number, in that order, and returns as a string the first /// of those that is not null or empty. If both are bad it calls the ToString() method of /// the base class. This will result in the ModuleChannelNumber being returned as a string. public override string ToString() { if (!string.IsNullOrEmpty(Description.Trim())) return Description.Trim(); if (!string.IsNullOrEmpty(SerialNumber.Trim())) return SerialNumber.Trim(); return base.ToString(); } /// /// A constructor to initialize this object with a containing module and a channel number. /// /// /// public AnalogInputDASChannel(DASModule owner, int channelNumber) : base(owner, channelNumber) { VoltageInsertionCheckEnabled = true; TypeOfBridge = SensorConstants.BridgeType.FullBridge; BridgeResistanceOhms = 350; ZeroPoint = 0; DesiredRangeWithHeadroomEU = 0; SensitivityMilliVoltsPerEU = 1; IsProportionalToExcitation = true; IsInverted = false; LinearizationFormula = new DTS.Common.Classes.Sensors.LinearizationFormula(); DigitalMode = DigitalInputModes.CCNC; DigitalMultiplier = new DigitalInputScaleMultiplier(); Excitation = ExcitationVoltageOptions.ExcitationVoltageOption.Volt5; SupportedExcitation = new[] { ExcitationVoltageOptions.ExcitationVoltageOption.Volt5 }; SupportedBridges = new[] { SensorConstants.BridgeType.FullBridge, SensorConstants.BridgeType.HalfBridge}; SupportedDigitalInputModes = new[] { DigitalInputModes.CCNC, DigitalInputModes.CCNO, DigitalInputModes.THL, DigitalInputModes.TLH}; EngineeringUnits = "g"; SerialNumber = ""; Description = ""; ZeroMethod = ZeroMethodType.UsePreEventDiagnosticsZero; ZeroAverageStartSeconds = 0; ZeroAverageStopSeconds = 0; InitialEU = 0; InitialOffset = ""; ShuntIsEnabled = true; VoltageInsertionCheckEnabled = true; CalSignalIsEnabled = false; IEPEChannel = false; RemoveOffset = false; VerifyOffset = false; OffsetToleranceLowMilliVolts = -100; OffsetToleranceHighMilliVolts = 100; ISOCode = ""; IsoChannelName = ""; UserCode = ""; UserChannelName = ""; BypassAAFilter = false; ScalefactorMilliVoltsPerADC = 1.0; ScalefactorEngineeringUnitsPerADC = 1.0; UnitConverision = 1.0; NoiseAsPercentOfFullScale = 0.0; LastCalibrationDate = (DateTime)System.Data.SqlTypes.SqlDateTime.MinValue; CalDueDate = (DateTime)System.Data.SqlTypes.SqlDateTime.MinValue; SensorID = ""; CouplingMode = SensorConstants.CouplingModes.AC; ACCouplingModeEnabled = false; Unipolar = false; AtCapacity = false; CapacityOutputIsBasedOn = 1.000; SensitivityUnits = SensorConstants.SensUnits.NONE; UnsupersampledSampleRate = 0; //http://manuscript.dts.local/f/cases/19006/StatusInvalidCommand-error-running-diagnostics-with-SLICE-PRO-DIM // Need to confirm configuration if POST test Diag because the DAS could have been disconnected. DigitalInputChannel = false; } /// /// Basic constructor for this object. /// public AnalogInputDASChannel() { SupportedExcitation = new[] { ExcitationVoltageOptions.ExcitationVoltageOption.Volt5 }; SupportedBridges = new[] { SensorConstants.BridgeType.FullBridge, SensorConstants.BridgeType.HalfBridge}; SupportedDigitalInputModes = new[] { DigitalInputModes.CCNC, DigitalInputModes.CCNO, DigitalInputModes.THL, DigitalInputModes.TLH }; } /// /// If the channel has a serial number in the SerialNumber field, it is "Configured". /// public override bool IsConfigured() { return !string.IsNullOrEmpty(SerialNumber); } public override void WriteElementEnd(XmlWriter writer) { writer.WriteEndElement(); } public override void WriteXml(XmlWriter writer) { base.WriteXml(writer); // TypeOfBridge XMLHelper.PutString(writer, "TypeOfBridge", TypeOfBridge.ToString()); // BridgeResistanceOhms XMLHelper.PutDouble(writer, "BridgeResistanceOhms", BridgeResistanceOhms); // ZeroPoint XMLHelper.PutDouble(writer, "ZeroPoint", ZeroPoint); // SensorCapacityEU XMLHelper.PutDouble(writer, "SensorCapacityEU", SensorCapacityEU); // DesiredRangeWithHeadroomEU XMLHelper.PutDouble(writer, "DesiredRangeWithHeadroomEU", DesiredRangeWithHeadroomEU); // SensitivityMilliVoltsPerEU XMLHelper.PutDouble(writer, "SensitivityMilliVoltsPerEU", SensitivityMilliVoltsPerEU); // IsProportionalToExcitation XMLHelper.PutBool(writer, "IsProportionalToExcitation", IsProportionalToExcitation); // IsInverted XMLHelper.PutBool(writer, "IsInverted", IsInverted); //LinearizationFormula if (null != LinearizationFormula) { XMLHelper.PutString(writer, "LinearizationFormula", LinearizationFormula.ToSerializeString()); } XMLHelper.PutString(writer, "DigitalMultiplier", DigitalMultiplier.ToSerializeDbString()); XMLHelper.PutString(writer, "DigitalMode", DigitalMode.ToString()); // Excitation XMLHelper.PutString(writer, "Excitation", Excitation.ToString()); XMLHelper.PutString(writer, "SupportedExcitation", GetSupportedExcitationSerialized()); XMLHelper.PutString(writer, "SupportedBridges", GetSupportedBridgesSerialized()); // EngineeringUnits XMLHelper.PutString(writer, "EngineeringUnits", EngineeringUnits); // SerialNumber XMLHelper.PutString(writer, "SerialNumber", SerialNumber); // Description XMLHelper.PutString(writer, "Description", Description); // Manufacturer XMLHelper.PutString(writer, "Manufacturer", Manufacturer); // Model XMLHelper.PutString(writer, "Model", Model); // ZeroMethod //XMLHelper.PutString(writer, "ZeroMethod", ZeroMethod.ToString()); switch (ZeroMethod) { case ZeroMethodType.UsePreEventDiagnosticsZero: XMLHelper.PutString(writer, "ZeroMethod", "UsePreCalZero"); break; default: XMLHelper.PutString(writer, "ZeroMethod", ZeroMethod.ToString()); break; } // ZeroAverageStartSeconds XMLHelper.PutDouble(writer, "ZeroAverageStartSeconds", ZeroAverageStartSeconds); // ZeroAverageStopSeconds XMLHelper.PutDouble(writer, "ZeroAverageStopSeconds", ZeroAverageStopSeconds); // InitialEU XMLHelper.PutDouble(writer, "InitialEU", InitialEU); XMLHelper.PutInt(writer, "ZeromVInADC", ZeromVInADC); XMLHelper.PutString(writer, "InitialOffset", InitialOffset); XMLHelper.PutBool(writer, "Unipolar", Unipolar); // ShuntIsEnabled XMLHelper.PutBool(writer, "ShuntIsEnabled", ShuntIsEnabled); //VoltageInsertionCheckIsEnabled XMLHelper.PutBool(writer, "VoltageInsertionCheckEnabled", VoltageInsertionCheckEnabled); // CalSignalIsEnabled XMLHelper.PutBool(writer, "CalSignalIsEnabled", CalSignalIsEnabled); // IEPEChannel XMLHelper.PutBool(writer, "IEPEChannel", IEPEChannel); // DigitalInputChannel //http://manuscript.dts.local/f/cases/19006/StatusInvalidCommand-error-running-diagnostics-with-SLICE-PRO-DIM // Need to confirm configuration if POST test Diag because the DAS could have been disconnected. XMLHelper.PutBool(writer, DIGITIALINPUTCHANNEL_TAG, DigitalInputChannel); XMLHelper.PutString(writer, "CouplingMode", CouplingMode.ToString()); //18294 Implement Bridge AC / DC coupling(fw update dependent) XMLHelper.PutBool(writer, ACCOUPLINGMODEENABLED_TAG, ACCouplingModeEnabled); // RemoveOffset XMLHelper.PutBool(writer, "RemoveOffset", RemoveOffset); // VerifyOffset XMLHelper.PutBool(writer, "VerifyOffset", VerifyOffset); // OffsetToleranceLowMilliVolts XMLHelper.PutDouble(writer, "OffsetToleranceLowMilliVolts", OffsetToleranceLowMilliVolts); // OffsetToleranceHighMilliVolts XMLHelper.PutDouble(writer, "OffsetToleranceHighMilliVolts", OffsetToleranceHighMilliVolts); // ISOCode XMLHelper.PutString(writer, "ISOCode", ISOCode); // BypassAAFilter XMLHelper.PutBool(writer, "BypassAAFilter", BypassAAFilter); // TriggerAboveThresholdEu XMLHelper.PutOptionalDouble(writer, "TriggerAboveThresholdEu", TriggerAboveThresholdEu); // TriggerBelowThresholdEu XMLHelper.PutOptionalDouble(writer, "TriggerBelowThresholdEu", TriggerBelowThresholdEu); XMLHelper.PutString(writer, "LevelTriggerType", LevelTriggerType.ToString()); // SoftwareFilterFrequency XMLHelper.PutDouble(writer, "SoftwareFilterFrequency", SoftwareFilterFrequency); // ScalefactorMilliVoltsPerADC XMLHelper.PutDouble(writer, "ScalefactorMilliVoltsPerADC", ScalefactorMilliVoltsPerADC); // UnitConversion XMLHelper.PutDouble(writer, "UnitConversion", UnitConverision); // AtCapacity XMLHelper.PutBool(writer, "AtCapacity", AtCapacity); //IsoChannelName XMLHelper.PutString(writer, "IsoChannelName", IsoChannelName); //UserCode XMLHelper.PutString(writer, "UserCode", UserCode); //UserChannelName XMLHelper.PutString(writer, "UserChannelName", UserChannelName); // CapacityOutputIsBasedOn XMLHelper.PutDouble(writer, "CapacityOutputIsBasedOn", CapacityOutputIsBasedOn); // SensitivityUnits XMLHelper.PutString(writer, "SensitivityUnits", SensitivityUnits.ToString()); //NoiseAsPercentOfFullScale XMLHelper.PutDouble(writer, NOISEASPERCENTOFFULLSCALE_TAG, NoiseAsPercentOfFullScale); XMLHelper.PutString(writer, "LastCalibrationDate", LastCalibrationDate.ToString(System.Globalization.CultureInfo.InvariantCulture)); XMLHelper.PutString(writer, "CalDueDate", CalDueDate.ToString(System.Globalization.CultureInfo.InvariantCulture)); XMLHelper.PutString(writer, "SensorID", SensorID); XMLHelper.PutString(writer, "OriginalChannelName", OriginalChannelName); XMLHelper.PutString(writer, "ChannelName2", ChannelName2); XMLHelper.PutString(writer, "ChannelId", ChannelId); XMLHelper.PutString(writer, "ChannelGroupName", ChannelGroupName); XMLHelper.PutString(writer, "HardwareChannelName", HardwareChannelName); // SensorCapacity XMLHelper.PutDouble(writer, "SensorCapacity", SensorCapacity); // SensorPolarity XMLHelper.PutString(writer, "SensorPolarity", SensorPolarity); // UnsupersampledSampleRate XMLHelper.PutDouble(writer, "UnsupersampledSampleRate", UnsupersampledSampleRate); } public string GetSupportedExcitationSerialized() { var sb = new StringBuilder(); foreach (var e in SupportedExcitation) { if (sb.Length > 0) { sb.Append(_SEPARATOR); } sb.Append(e); } return sb.ToString(); } private const string _SEPARATOR = "@"; public string GetSupportedDigitalInputModesSerialized() { var sb = new StringBuilder(); foreach (var s in SupportedDigitalInputModes) { if (sb.Length > 0) { sb.Append(_SEPARATOR); } sb.Append(s); } return sb.ToString(); } public string GetSupportedBridgesSerialized() { var sb = new StringBuilder(); foreach (var e in SupportedBridges) { if (sb.Length > 0) { sb.Append(_SEPARATOR); } sb.Append(e); } return sb.ToString(); } public override void WriteXmlCRC32(XmlWriter writer) { base.WriteXmlCRC32(writer); // TypeOfBridge XMLHelper.PutString(writer, "TypeOfBridge", TypeOfBridge.ToString()); // BridgeResistanceOhms XMLHelper.PutDouble(writer, "BridgeResistanceOhms", BridgeResistanceOhms); // ZeroPoint XMLHelper.PutDouble(writer, "ZeroPoint", ZeroPoint); // SensorCapacityEU XMLHelper.PutDouble(writer, "SensorCapacityEU", SensorCapacityEU); // DesiredRangeWithHeadroomEU XMLHelper.PutDouble(writer, "DesiredRangeWithHeadroomEU", DesiredRangeWithHeadroomEU); // SensitivityMilliVoltsPerEU XMLHelper.PutDouble(writer, "SensitivityMilliVoltsPerEU", SensitivityMilliVoltsPerEU); // IsProportionalToExcitation XMLHelper.PutBool(writer, "IsProportionalToExcitation", IsProportionalToExcitation); if (null != LinearizationFormula) { XMLHelper.PutString(writer, "LinearizationFormula", LinearizationFormula.ToSerializeString()); } XMLHelper.PutString(writer, "DigitalMultiplier", DigitalMultiplier.ToSerializeDbString()); XMLHelper.PutString(writer, "DigitalMode", DigitalMode.ToString()); // IsInverted XMLHelper.PutBool(writer, "IsInverted", IsInverted); // Excitation XMLHelper.PutString(writer, "Excitation", Excitation.ToString()); XMLHelper.PutString(writer, "SupportedExcitation", GetSupportedExcitationSerialized()); XMLHelper.PutString(writer, "SupportedBridges", GetSupportedBridgesSerialized()); // EngineeringUnits XMLHelper.PutString(writer, "EngineeringUnits", EngineeringUnits); // SerialNumber XMLHelper.PutString(writer, "SerialNumber", SerialNumber); // Description XMLHelper.PutString(writer, "Description", Description); // ZeroMethod //XMLHelper.PutString(writer, "ZeroMethod", ZeroMethod.ToString()); switch (ZeroMethod) { case ZeroMethodType.UsePreEventDiagnosticsZero: XMLHelper.PutString(writer, "ZeroMethod", "UsePreCalZero"); break; default: XMLHelper.PutString(writer, "ZeroMethod", ZeroMethod.ToString()); break; } // ZeroAverageStartSeconds XMLHelper.PutDouble(writer, "ZeroAverageStartSeconds", ZeroAverageStartSeconds); // ZeroAverageStopSeconds XMLHelper.PutDouble(writer, "ZeroAverageStopSeconds", ZeroAverageStopSeconds); XMLHelper.PutString(writer, "InitialOffset", InitialOffset); // InitialEU XMLHelper.PutDouble(writer, "InitialEU", InitialEU); XMLHelper.PutInt(writer, "ZeromVInADC", ZeromVInADC); XMLHelper.PutBool(writer, "Unipolar", Unipolar); // ShuntIsEnabled XMLHelper.PutBool(writer, "ShuntIsEnabled", ShuntIsEnabled); //VoltageInsertionCheckEnabled XMLHelper.PutBool(writer, "VoltageInsertionCheckEnabled", VoltageInsertionCheckEnabled); // CalSignalIsEnabled XMLHelper.PutBool(writer, "CalSignalIsEnabled", CalSignalIsEnabled); // RemoveOffset XMLHelper.PutBool(writer, "RemoveOffset", RemoveOffset); XMLHelper.PutBool(writer, "IEPEChannel", IEPEChannel); // DigitalInputChannel //http://manuscript.dts.local/f/cases/19006/StatusInvalidCommand-error-running-diagnostics-with-SLICE-PRO-DIM // Need to confirm configuration if POST test Diag because the DAS could have been disconnected. XMLHelper.PutBool(writer, DIGITIALINPUTCHANNEL_TAG, DigitalInputChannel); XMLHelper.PutString(writer, "CouplingMode", CouplingMode.ToString()); //18294 Implement Bridge AC / DC coupling(fw update dependent) XMLHelper.PutBool(writer, ACCOUPLINGMODEENABLED_TAG, ACCouplingModeEnabled); // VerifyOffset XMLHelper.PutBool(writer, "VerifyOffset", VerifyOffset); // OffsetToleranceLowMilliVolts XMLHelper.PutDouble(writer, "OffsetToleranceLowMilliVolts", OffsetToleranceLowMilliVolts); // OffsetToleranceHighMilliVolts XMLHelper.PutDouble(writer, "OffsetToleranceHighMilliVolts", OffsetToleranceHighMilliVolts); // ISOCode XMLHelper.PutString(writer, "ISOCode", ISOCode); // BypassAAFilter XMLHelper.PutBool(writer, "BypassAAFilter", BypassAAFilter); // TriggerAboveThresholdEu XMLHelper.PutOptionalDouble(writer, "TriggerAboveThresholdEu", TriggerAboveThresholdEu); // TriggerBelowThresholdEu XMLHelper.PutOptionalDouble(writer, "TriggerBelowThresholdEu", TriggerBelowThresholdEu); XMLHelper.PutString(writer, "LevelTriggerType", LevelTriggerType.ToString()); // SoftwareFilterFrequency //XMLHelper.PutDouble(writer, "SoftwareFilterFrequency", SoftwareFilterFrequency); // ScalefactorMilliVoltsPerADC //XMLHelper.PutDouble(writer, "ScalefactorMilliVoltsPerADC", ScalefactorMilliVoltsPerADC); //NoiseAsPercentOfFullScale //XMLHelper.PutDouble(writer, NOISEASPERCENTOFFULLSCALE_TAG, NoiseAsPercentOfFullScale); XMLHelper.PutString(writer, "LastCalibrationDate", LastCalibrationDate.ToString(System.Globalization.CultureInfo.InvariantCulture)); XMLHelper.PutString(writer, "CalDueDate", CalDueDate.ToString(System.Globalization.CultureInfo.InvariantCulture)); XMLHelper.PutString(writer, "SensorID", SensorID); XMLHelper.PutString(writer, "OriginalChannelName", OriginalChannelName); XMLHelper.PutString(writer, "ChannelName2", ChannelName2); XMLHelper.PutString(writer, "ChannelId", ChannelId); XMLHelper.PutString(writer, "ChannelGroupName", ChannelGroupName); XMLHelper.PutString(writer, "HardwareChannelName", HardwareChannelName); // SensorCapacity XMLHelper.PutDouble(writer, "SensorCapacity", SensorCapacity); // SensorPolarity XMLHelper.PutString(writer, "SensorPolarity", SensorPolarity); } private const string NOISEASPERCENTOFFULLSCALE_TAG = "NoiseAsPercentOfFullScale"; private ExcitationVoltageOptions.ExcitationVoltageOption[] DeserializeSupportedExcitation(string s) { var options = new List(); var tokens = s.Split('@'); foreach (var token in tokens) { options.Add((ExcitationVoltageOptions.ExcitationVoltageOption)Enum.Parse(typeof(ExcitationVoltageOptions.ExcitationVoltageOption), token)); } return options.ToArray(); } private DigitalInputModes[] DeserializeSupportedDigitalInputModes(string s) { var options = new List(); var tokens = s.Split('@'); foreach (var token in tokens) { options.Add((DigitalInputModes)Enum.Parse(typeof(DigitalInputModes), token)); } return options.ToArray(); } private SensorConstants.BridgeType[] DeserializeSupportedBridges(string s) { var options = new List(); var tokens = s.Split('@'); foreach (var token in tokens) { options.Add((SensorConstants.BridgeType)Enum.Parse(typeof(SensorConstants.BridgeType), token)); } return options.ToArray(); } private const string TYPEOFBRIDGE_TAG = "TypeOfBridge"; private const string BRIDGERESISTANCE_TAG = "BridgeResistanceOhms"; private const string ZEROPOINT_TAG = "ZeroPoint"; private const string SENSORCAPACITYEU_TAG = "SensorCapacityEU"; private const string SENSORCAPACITY_TAG = "SensorCapacity"; private const string SENSORPOLARITY_TAG = "SensorPolarity"; private const string DIGITALMULTIPLIER_TAG = "DigitalMultiplier"; private const string DIGITALMODE_TAG = "DigitalMode"; private const string DESIREDRANGEWITHHEADROOM_TAG = "DesiredRangeWithHeadroomEU"; private const string DESIREDRANGEEU_TAG = "DesiredRangeEU"; private const string LINEARIZATIONFORMULA_TAG = "LinearizationFormula"; private const string SENSITIVITYMILLIVOLTSPEREU_TAG = "SensitivityMilliVoltsPerEU"; private const string ISPROPORTIONAL_TAG = "IsProportionalToExcitation"; private const string ISINVERTED_TAG = "IsInverted"; private const string EXCITATION_TAG = "Excitation"; private const string SUPPORTEDEXCITATION_TAG = "SupportedExcitation"; private const string SUPPORTEDDIGITALINPUTMODES_TAG = "SupportedDigitalInputModes"; private const string SUPPORTEDBRIDGES_TAG = "SupportedBridges"; private const string ENGINEERINGUNITS_TAG = "EngineeringUnits"; private const string SERIALNUMBER_TAG = "SerialNumber"; private const string DESCRIPTION_TAG = "Description"; private const string MANUFACTURER_TAG = "Manufacturer"; private const string MODEL_TAG = "Model"; private const string ZEROMETHOD_TAG = "ZeroMethod"; private const string ZEROAVERAGESTARTSECONDS_TAG = "ZeroAverageStartSeconds"; private const string ZEROAVERAGESTOPSECONDS_TAG = "ZeroAverageStopSeconds"; private const string INITIALOFFSET_TAG = "InitialOffset"; private const string INITIALEU_TAG = "InitialEU"; private const string ZEROMVINADC_TAG = "ZeromVInADC"; private const string UNIPOLAR_TAG = "Unipolar"; private const string SHUNTISENABLED_TAG = "ShuntIsEnabled"; private const string IEPECHANNEL_TAG = "IEPEChannel"; //http://manuscript.dts.local/f/cases/19006/StatusInvalidCommand-error-running-diagnostics-with-SLICE-PRO-DIM // Need to confirm configuration if POST test Diag because the DAS could have been disconnected. private const string DIGITIALINPUTCHANNEL_TAG = "DigitalInputChannel"; private const string COUPLINGMODE_TAG = "CouplingMode"; private const string ACCOUPLINGMODEENABLED_TAG = "ACCouplingModeEnabled"; private const string VOLTAGEINSERTIONCHECKENABLED_TAG = "VoltageInsertionCheckEnabled"; private const string CALSIGNALISENABLED_TAG = "CalSignalIsEnabled"; private const string REMOVEOFFSET_TAG = "RemoveOffset"; private const string VERIFYOFFSET_TAG = "VerifyOffset"; private const string OFFSETTOLERANCELOWMV_TAG = "OffsetToleranceLowMilliVolts"; private const string OFFSETTOLERANCEHIGHMV_TAG = "OffsetToleranceHighMilliVolts"; private const string ISOCODE_TAG = "ISOCode"; private const string BYPASSAAFILTER_TAG = "BypassAAFilter"; private const string ISOCHANNELNAME_TAG = "IsoChannelName"; private const string USERCODE_TAG = "UserCode"; private const string USERCHANNELNAME_TAG = "UserChannelName"; private const string LEVELTRIGGERTYPE_TAG = "LevelTriggerType"; private const string TRIGGERABOVEEU_TAG = "TriggerAboveThresholdEu"; private const string TRIGGERBELOWEU_TAG = "TriggerBelowThresholdEu"; private const string SOFTWAREFILTERHZ_TAG = "SoftwareFilterFrequency"; private const string SCALEFACTORMVPERADC_TAG = "ScalefactorMilliVoltsPerADC"; private const string UNITCONVERSION_TAG = "UnitConversion"; private const string ATCAPACITY_TAG = "AtCapacity"; private const string CAPACITYOUTPUT_TAG = "CapacityOutputIsBasedOn"; private const string SENSITIVITY_TAG = "SensitivityUnits"; private const string LASTCALIBRATIONDATE_TAG = "LastCalibrationDate"; private const string CALDUEDATE_TAG = "CalDueDate"; private const string SENSORID_TAG = "SensorID"; private const string CHANNELID_TAG = "ChannelId"; private const string CHANNELGROUPNAME_TAG = "ChannelGroupName"; private const string ORIGINALCHANNELNAME_TAG = "OriginalChannelName"; private const string CHANNELNAME2_TAG = "ChannelName2"; private const string HARDWARECHANNELNAME_TAG = "HardwareChannelName"; private const string UNSUPERSAMPLEDSAMPLERATE_TAG = "UnsupersampledSampleRate"; protected override void HandleElement(XmlReader reader) { base.HandleElement(reader); if (reader.NodeType == XmlNodeType.Element) { var value = string.Empty; switch (reader.Name) { case TYPEOFBRIDGE_TAG: value = XMLHelper.GetString(reader); TypeOfBridge = (SensorConstants.BridgeType)Enum.Parse(typeof(SensorConstants.BridgeType), value); break; case BRIDGERESISTANCE_TAG: BridgeResistanceOhms = XMLHelper.GetDouble(reader); break; case ZEROPOINT_TAG: ZeroPoint = XMLHelper.GetDouble(reader); break; case SENSORCAPACITYEU_TAG: SensorCapacityEU = XMLHelper.GetDouble(reader); break; case SENSORCAPACITY_TAG: SensorCapacity = XMLHelper.GetDouble(reader); break; case SENSORPOLARITY_TAG: SensorPolarity = XMLHelper.GetString(reader); break; case DIGITALMULTIPLIER_TAG: try { DigitalMultiplier = new DigitalInputScaleMultiplier(); DigitalMultiplier.FromDbSerializeString(XMLHelper.GetString(reader)); } catch (Exception) { } break; case DIGITALMODE_TAG: { DigitalInputModes mode; Enum.TryParse(XMLHelper.GetString(reader), out mode); DigitalMode = mode; } break; case DESIREDRANGEEU_TAG: case DESIREDRANGEWITHHEADROOM_TAG: // old DesiredRangeWithHeadroomEU = XMLHelper.GetDouble(reader); break; case LINEARIZATIONFORMULA_TAG: LinearizationFormula = new DTS.Common.Classes.Sensors.LinearizationFormula(); LinearizationFormula.FromSerializeString(XMLHelper.GetString(reader)); break; case SENSITIVITYMILLIVOLTSPEREU_TAG: SensitivityMilliVoltsPerEU = XMLHelper.GetDouble(reader); break; case ISPROPORTIONAL_TAG: IsProportionalToExcitation = XMLHelper.GetBool(reader); break; case ISINVERTED_TAG: IsInverted = XMLHelper.GetBool(reader); break; case EXCITATION_TAG: value = XMLHelper.GetString(reader); Excitation = (ExcitationVoltageOptions.ExcitationVoltageOption)Enum.Parse(typeof(ExcitationVoltageOptions.ExcitationVoltageOption), value); break; case SUPPORTEDEXCITATION_TAG: SupportedExcitation = DeserializeSupportedExcitation(XMLHelper.GetString(reader)); break; case SUPPORTEDDIGITALINPUTMODES_TAG: SupportedDigitalInputModes = DeserializeSupportedDigitalInputModes(XMLHelper.GetString(reader)); break; case SUPPORTEDBRIDGES_TAG: SupportedBridges = DeserializeSupportedBridges(XMLHelper.GetString(reader)); break; case ENGINEERINGUNITS_TAG: EngineeringUnits = XMLHelper.GetString(reader); break; case SERIALNUMBER_TAG: SerialNumber = XMLHelper.GetString(reader); break; case DESCRIPTION_TAG: Description = XMLHelper.GetString(reader); break; case MANUFACTURER_TAG: Manufacturer = XMLHelper.GetString(reader); break; case MODEL_TAG: Model = XMLHelper.GetString(reader); break; case ZEROMETHOD_TAG: value = XMLHelper.GetString(reader); // support older version if (value == "UsePreCalZero") { ZeroMethod = ZeroMethodType.UsePreEventDiagnosticsZero; } else { ZeroMethod = (ZeroMethodType)Enum.Parse(typeof(ZeroMethodType), value); } break; case ZEROAVERAGESTARTSECONDS_TAG: ZeroAverageStartSeconds = XMLHelper.GetDouble(reader); break; case ZEROAVERAGESTOPSECONDS_TAG: ZeroAverageStopSeconds = XMLHelper.GetDouble(reader); break; case INITIALOFFSET_TAG: InitialOffset = XMLHelper.GetString(reader); break; case INITIALEU_TAG: InitialEU = XMLHelper.GetDouble(reader); break; case ZEROMVINADC_TAG: ZeromVInADC = Convert.ToInt16(XMLHelper.GetInt(reader)); break; case UNIPOLAR_TAG: Unipolar = XMLHelper.GetBool(reader); break; case SHUNTISENABLED_TAG: ShuntIsEnabled = XMLHelper.GetBool(reader); break; case IEPECHANNEL_TAG: IEPEChannel = XMLHelper.GetBool(reader); break; //http://manuscript.dts.local/f/cases/19006/StatusInvalidCommand-error-running-diagnostics-with-SLICE-PRO-DIM // Need to confirm configuration if POST test Diag because the DAS could have been disconnected. case DIGITIALINPUTCHANNEL_TAG: DigitalInputChannel = XMLHelper.GetBool(reader); break; case COUPLINGMODE_TAG: CouplingMode = (SensorConstants.CouplingModes)Enum.Parse(typeof(SensorConstants.CouplingModes), XMLHelper.GetString(reader)); break; case VOLTAGEINSERTIONCHECKENABLED_TAG: VoltageInsertionCheckEnabled = true; XMLHelper.GetBool(reader);//we ignore the result for now. break; case CALSIGNALISENABLED_TAG: CalSignalIsEnabled = XMLHelper.GetBool(reader); break; case REMOVEOFFSET_TAG: RemoveOffset = XMLHelper.GetBool(reader); break; case VERIFYOFFSET_TAG: VerifyOffset = XMLHelper.GetBool(reader); break; case OFFSETTOLERANCELOWMV_TAG: OffsetToleranceLowMilliVolts = XMLHelper.GetDouble(reader); break; case OFFSETTOLERANCEHIGHMV_TAG: OffsetToleranceHighMilliVolts = XMLHelper.GetDouble(reader); break; case ISOCODE_TAG: ISOCode = XMLHelper.GetString(reader); break; case BYPASSAAFILTER_TAG: BypassAAFilter = XMLHelper.GetBool(reader); break; case ISOCHANNELNAME_TAG: IsoChannelName = XMLHelper.GetString(reader); break; case USERCODE_TAG: UserCode = XMLHelper.GetString(reader); break; case USERCHANNELNAME_TAG: UserChannelName = XMLHelper.GetString(reader); break; case LEVELTRIGGERTYPE_TAG: try { LevelTriggerType = (LevelTriggerTypes)Enum.Parse(typeof(LevelTriggerTypes), XMLHelper.GetString(reader)); } catch (Exception ex) { APILogger.Log(ex); } break; case TRIGGERABOVEEU_TAG: TriggerAboveThresholdEu = XMLHelper.GetOptionalDouble(reader); break; case TRIGGERBELOWEU_TAG: TriggerBelowThresholdEu = XMLHelper.GetOptionalDouble(reader); break; case SOFTWAREFILTERHZ_TAG: SoftwareFilterFrequency = XMLHelper.GetDouble(reader); break; case SCALEFACTORMVPERADC_TAG: ScalefactorMilliVoltsPerADC = XMLHelper.GetDouble(reader); break; case UNITCONVERSION_TAG: UnitConverision = XMLHelper.GetDouble(reader); break; case ATCAPACITY_TAG: AtCapacity = XMLHelper.GetBool(reader); break; case CAPACITYOUTPUT_TAG: CapacityOutputIsBasedOn = XMLHelper.GetDouble(reader); break; case SENSITIVITY_TAG: var su = XMLHelper.GetString(reader); SensitivityUnits = (SensorConstants.SensUnits)Enum.Parse(typeof(SensorConstants.SensUnits), su); break; case LASTCALIBRATIONDATE_TAG: { DateTime d; if (DateTime.TryParse(XMLHelper.GetString(reader), System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out d)) { LastCalibrationDate = d; } } break; case CALDUEDATE_TAG: { DateTime d; if (DateTime.TryParse(XMLHelper.GetString(reader), System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out d)) { CalDueDate = d; } } break; case NOISEASPERCENTOFFULLSCALE_TAG: NoiseAsPercentOfFullScale = XMLHelper.GetDouble(reader); break; case SENSORID_TAG: SensorID = XMLHelper.GetString(reader); break; case CHANNELID_TAG: ChannelId = XMLHelper.GetString(reader); break; case CHANNELGROUPNAME_TAG: ChannelGroupName = XMLHelper.GetString(reader); break; case ORIGINALCHANNELNAME_TAG: OriginalChannelName = XMLHelper.GetString(reader); break; case CHANNELNAME2_TAG: ChannelName2 = XMLHelper.GetString(reader); break; case HARDWARECHANNELNAME_TAG: HardwareChannelName = XMLHelper.GetString(reader); break; case UNSUPERSAMPLEDSAMPLERATE_TAG: UnsupersampledSampleRate = XMLHelper.GetDouble(reader); break; //18294 Implement Bridge AC/DC coupling (fw update dependent) //default here is false, we shouldn't get here unless the tag is found, //but just for safety don't trust the getbool case ACCOUPLINGMODEENABLED_TAG: try { ACCouplingModeEnabled = XMLHelper.GetBool(reader); } catch (System.Exception ex) { APILogger.Log($"Failed to retrieve ACCouplingModeEnabled from xml, {ex.Message}"); ACCouplingModeEnabled = false; } break; default: // let child handle it return; } } } /// /// Get Datascaler object for this AnalogInputDASChannel; should already have diagnostic information by time of use. /// /// public DataScaler GetDataScaler() { var ds = new DataScaler(); if (null != DiagnosticInformation) { //hardware with diagnostics stuff if (ZeroMethod == ZeroMethodType.None) { if (RemoveOffset && TypeOfBridge != SensorConstants.BridgeType.IEPE) { if (null != DiagnosticInformation.FinalOffsetADC) { ds.SetDataZeroLevelADC((short)DiagnosticInformation.FinalOffsetADC); } } else { ds.SetDataZeroLevelADC(LinearizationFormula.IsValid() ? (short)0 : DiagnosticInformation.ZeroMVInADC); } } else { if (null != DiagnosticInformation.FinalOffsetADC) { ds.SetDataZeroLevelADC((short)DiagnosticInformation.FinalOffsetADC); } else { ds.SetDataZeroLevelADC(DiagnosticInformation.ZeroMVInADC); } } if (null != DiagnosticInformation.RemovedOffsetADC) { ds.SetRemovedADC((int)DiagnosticInformation.RemovedOffsetADC); } if (null != DiagnosticInformation.RemovedInternalOffsetADC) { ds.SetRemovedInternalADC((int)DiagnosticInformation.RemovedInternalOffsetADC); } ds.SetScaleFactorMv(DiagnosticInformation.ScalefactorMilliVoltsPerADC); ds.SetScaleFactorEU(DiagnosticInformation.ScalefactorEngineeringUnitsPerADC); if (OwningModule?.OwningDAS?.IsTSRAIR() ?? false) { //is a tsrair ds.SetUseEUScaleFactors(true); } ds.SetZeroMvInADC(DiagnosticInformation.ZeroMVInADC); ds.MeasuredExcitationVoltage = null == DiagnosticInformation.MeasuredExcitationMilliVolts ? 0D : (double)DiagnosticInformation.MeasuredExcitationMilliVolts / 1000D; ds.FactoryExcitationVoltage = DiagnosticInformation.ExpectedExcitationMilliVolts / 1000D; } else { //no hardware channel specific stuff if (IsProportionalToExcitation) { ds.FactoryExcitationVoltage = DiagnosticInformation.ExpectedExcitationMilliVolts / 1000D; ds.MeasuredExcitationVoltage = ds.FactoryExcitationVoltage; } } //common initialization stuff // first set the scaler initial offset using the new offset property present on a channel // it's possible the channel has the old form though, so we might have to add that too // so if it's a different value add it - this gets complicated because there's a third // offset property (InitialEU, InitialOffset, UserOffset) on sensors and datascaler and // channel both have two, so we may lose out on one or more here ds.SetInitialOffset(InitialOffset); if ( !InitialEU.Equals(ds.GetInitialEU())) { ds.UserOffsetEU = InitialEU; } ds.ZeroMethodType = ZeroMethod; ds.UnitConversion = UnitConverision; ds.SensitivityUnits = SensitivityUnits; ds.SetMvPerEu(SensitivityMilliVoltsPerEU); //data scaler needs to get inverted or not only from polarity as negative sensitivity //shows up through scale factor ds.IsInverted = IsInverted; ds.ProportionalToExcitation = IsProportionalToExcitation; ds.BasedOnOutputAtCapacity = AtCapacity; ds.CapacityOutputIsBasedOn = CapacityOutputIsBasedOn; ds.IEPE = TypeOfBridge == SensorConstants.BridgeType.IEPE; #region Digital //ds.Digital = sensor.IsDigitalInput(); //ds.DigitalOutput = sensor.IsDigitalOutput(); //if (sensor is SensorData sd) //{ // ds.DigitalMode = sd.InputMode; // ds.SetDigitalMultiplier(sd.ScaleMultiplier); //} #endregion Digital //if (clearEUAdjustmentParams) //{ // ds.SetInitialOffset(new DTS.Common.Classes.Sensors.InitialOffset(0)); // ds.UserOffsetEU = 0D; // ds.SetDataZeroLevelADC(0); //} return ds; } } }