From c6d8cefc62311fef28c532f181578d54795e5e08 Mon Sep 17 00:00:00 2001 From: Thomas Wiedebusch Date: Mon, 9 Feb 2026 20:42:00 +0100 Subject: [PATCH] FM2014TestBench: - initial setup to test multiple FM2014 - 9.Step --- .../FM2014/FM2014Core/Consts/FM2014CmdDef.cs | 11 +- .../FM2014/FM2014Core/FM2014.cs | 565 +++++---- .../Metrology/Measurements/Consts/SiUnits.cs | 173 --- Common/Metrology/Measurements/Consts/Units.cs | 157 +++ .../Measurements/Measurements.csproj | 2 +- .../FrmFm2014TestApp.cs | 12 +- .../Ui/Fm2014sTest/FM2014TestBenchWindow.xaml | 131 ++- .../Fm2014sTest/FM2014TestBenchWindow.xaml.cs | 1040 +++++++++++++---- .../Properties/Resources.Designer.cs | 225 ++-- .../Fm2014sTest/Properties/Resources.de.resx | 37 +- .../Ui/Fm2014sTest/Properties/Resources.resx | 35 +- .../UserControls/UcFM2014Device.xaml.cs | 9 +- 12 files changed, 1564 insertions(+), 833 deletions(-) delete mode 100644 Common/Metrology/Measurements/Consts/SiUnits.cs create mode 100644 Common/Metrology/Measurements/Consts/Units.cs diff --git a/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/Consts/FM2014CmdDef.cs b/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/Consts/FM2014CmdDef.cs index 3aa19e6a..e74d910a 100644 --- a/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/Consts/FM2014CmdDef.cs +++ b/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/Consts/FM2014CmdDef.cs @@ -8,8 +8,7 @@ * @details Implements the command table and interprocess-communication structs for the FM2014. * * @copyright © SENSUS GmbH 2026. All rights reserved. - *********************************************************************************************************************/using Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core; - + *********************************************************************************************************************/ using System; using System.Collections.Generic; using System.Linq; @@ -642,7 +641,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core.Co /// /// Measurement SI unit /// - public String SiUnit { get; private set; } + public String Unit { get; private set; } /// /// Ctor @@ -651,15 +650,15 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core.Co /// /// /// - /// + /// public CmdResponse(CmdName cmdName, String answerStr, Int32? intValue = null, Double? doubleValue = null, - String siUnit = "") + String unit = "") { CmdName = cmdName; AnswerStr = answerStr; IntValue = intValue; DoubleValue = doubleValue; - SiUnit = siUnit; + Unit = unit; } } diff --git a/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/FM2014.cs b/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/FM2014.cs index 2878c1bf..d334f16c 100644 --- a/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/FM2014.cs +++ b/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/FM2014.cs @@ -51,19 +51,19 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core /// Minimal value which can be stored to the FM2014 with commands /// 'V' - 'DUT pulses per volume' and 'W' - 'REF pulses per volume'! /// - private const UInt32 PULSES_PER_CM_REGULATION_SETUP_MIN = 1; + public const UInt32 PULSES_PER_CM_REGULATION_SETUP_MIN = 1; /// /// Maximal value which can be stored to the FM2014 with command /// 'V' - 'DUT pulses per volume' and 'W' - 'REF pulses per volume'! /// - private const UInt32 PULSES_PER_CM_REGULATION_SETUP_MAX = 9999; + public const UInt32 PULSES_PER_CM_REGULATION_SETUP_MAX = 9999; /// /// This is the maximum input value for the REF which CANNOT be stored to FM2014 /// but will be used to calculate the 'RefToDutScale_norm'. /// - private const UInt32 REF_PULSES_PER_CM_REGULATION_INPUT_MAX = 100000000; + public const UInt32 REF_PULSES_PER_CM_REGULATION_INPUT_MAX = 100000000; /// /// FM2014 minimum REF to DUT scale for error display. @@ -370,67 +370,67 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core /// public Boolean UseDampedTolerance { get; set; } - private UInt16 _refRequiredTimeMeasurement_pulses; + private UInt16 _refPulsesRequired; /// /// Required REF pulses for time measurement. /// - public UInt16 RefRequiredTimeMeasurement_pulses + public UInt16 RefPulsesRequired { - get => _refRequiredTimeMeasurement_pulses; + get => _refPulsesRequired; set { // Check limits and equality if (value < TIME_MEASUREMENT_INPUT_MIN_pulses || - value == _refRequiredTimeMeasurement_pulses) + value == _refPulsesRequired) return; - _refRequiredTimeMeasurement_pulses = value; + _refPulsesRequired = value; } } - private UInt16 _dutRequiredTimeMeasurement_pulses; + private UInt16 _dutPulsesRequired; /// /// Required DUT pulses for time measurement. /// - public UInt16 DutRequiredTimeMeasurement_pulses + public UInt16 DutPulsesRequired { - get => _dutRequiredTimeMeasurement_pulses; + get => _dutPulsesRequired; set { // Check limits and equality if (value < TIME_MEASUREMENT_INPUT_MIN_pulses || - value == _dutRequiredTimeMeasurement_pulses) + value == _dutPulsesRequired) return; - _dutRequiredTimeMeasurement_pulses = value; + _dutPulsesRequired = value; } } - private UInt32 _refMeasuredTimer_ticks; + private UInt32 _refTimerTicksMeasured; /// /// REF timer ticks of measured pulses /// - public UInt32 RefMeasuredTimer_ticks + public UInt32 RefTimerTicksMeasured { - get => _refMeasuredTimer_ticks; + get => _refTimerTicksMeasured; private set { - _refMeasuredTimer_ticks = value; - RefMeasuredTime_s = value * TMR_RESOLUTION_s; + _refTimerTicksMeasured = value; + RefTimeMeasured_s = value * TMR_RESOLUTION_s; } } - private UInt32 _dutMeasuredTimer_ticks; + private UInt32 _dutTimerTicksMeasured; /// /// DUT timer ticks of measured pulses /// - public UInt32 DutMeasuredTimer_ticks + public UInt32 DutTimerTicksMeasured { - get => _dutMeasuredTimer_ticks; + get => _dutTimerTicksMeasured; private set { - _dutMeasuredTimer_ticks = value; - DutMeasuredTime_s = value * TMR_RESOLUTION_s; + _dutTimerTicksMeasured = value; + DutTimeMeasured_s = value * TMR_RESOLUTION_s; } } @@ -448,22 +448,22 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core /// /// Remaining REF pulses for time measurement. /// - public UInt16 RefRemainingTimeMeasurement_pulses { get; private set; } + public UInt16 RefPulsesRemaining { get; private set; } /// /// Remaining DT pulses for time measurement. /// - public UInt16 DutRemainingTimeMeasurement_pulses { get; private set; } + public UInt16 DutPulsesRemaining { get; private set; } /// /// Measured REF time of required pulses. /// - public Double RefMeasuredTime_s { get; private set; } + public Double RefTimeMeasured_s { get; private set; } /// /// Measured DUT time of required pulses. /// - public Double DutMeasuredTime_s { get; private set; } + public Double DutTimeMeasured_s { get; private set; } private UInt32 _ref_pulse_per_cm; /// @@ -577,7 +577,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core } } - private Double _doublePulseDeadtime_ms = 0.0; + private Double _doublePulseDeadtime_ms; /// /// Double pulse deadtime in milliseconds to avoid on small oscillating input a repeated pulse. /// @@ -592,14 +592,14 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core _doublePulseDeadtime_ms = value; // Calculate and set up the values 'S' and 's' needed for the FM2014 - var tempBase_ms = (UInt16) value; + var tempBase_ms = (UInt16)value; var tempMultiplier = 1; - while (tempBase_ms > DOUBLE_PULSE_BASE_DEADTIME_MAX_ms && + while (tempBase_ms > DOUBLE_PULSE_BASE_DEADTIME_MAX_ms && tempMultiplier < DOUBLE_PULSE_DEADTIME_MULTIPLIER_INPUT_MAX) { tempMultiplier++; tempBase_ms = (UInt16)(value / tempMultiplier); - } + } DoublePulseBaseDeadTime_ms = tempBase_ms; DoublePulseMultiplier = (Byte)tempMultiplier; } @@ -665,6 +665,11 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core /// public Boolean RequestDebugInformation { get; set; } + /// + /// Measured tolerance during calibration + /// + public Double DutToRefToleranceMeasured_percent { get; private set; } + #endregion ---------------------------------------- object properties ----------------------------------------- #region ------------------------------------------- static methods -------------------------------------------- @@ -718,7 +723,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core { // Change the SI unit to ms instead of seconds var response = new CmdResponse(CmdName.CMD_RST_MEAS, infoStr, - resetDelayCtr_ms, siUnit: "m" + SiUnits.GetInfo(SiUnits.SiUnitName.TIME)); + resetDelayCtr_ms, unit: "m" + Units.GetInfo(Units.Name.TIME_s)); PublishResponse(firstActiveFm2014, new ProcessExecEventArgs(infoStr, actualProcessMessage: infoStr, actualProcessPercent: _actualProcessProgress_percent, @@ -820,6 +825,195 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core fm2014?.OnRawRecordReceived?.Invoke(fm2014, processExecEventArgs); } + /// + /// Pulse counter measurement: + /// - REF counter (default ON), + /// - DUT counter (default OFF), + /// - REF and DUT counters together using the synchronized backup. + /// - Each FM2014 can use a different REF and/or DUT setting as the REF is parallel for all FM2014s. + /// Preconditions: + /// - The has to be executed in advance. + /// Initial setup: + /// - Starts the pulse counter measurement of REF and/or DUT. + /// Cyclic: + /// - Request REF and/or DUT pulse counter value(s). + /// Exit: + /// - Set to false. + /// + /// request to count REF pulses + /// request to count DUT pulses + /// true if initialization successfully executed or + /// marks the already started cyclic requests + /// for all registered FM2014s + /// + /// - Initial. + /// + /// + /// - If REF and DUT pulse counters are on the cyclic sequence: + /// - 'q' synchronized backup of both pulse counters, + /// - 'l' read REF backup pulses, + /// - 'u' read DUT backup pulses + /// will be used. + /// + /// + /// - Support for multiple FM2014s. + /// + /// + /// - If any FM2014 has REF and DUT pulse counter on then use for ALL the synchronized readout. + /// + /// + /// - Static. + /// + public static Boolean PulseCounterMeasurement(Boolean refCtrOn = true, Boolean dutCtrOn = false) + { + // If the cyclic task has already been started everything is fine + if (SharedCyclicMeasSequ == CyclicMeasSequ.PULSE_CTR) + return true; + + // Marked measurement isn't pulse counter measurement, other FM2014s cannot activate this + if (SharedCyclicMeasSequ != CyclicMeasSequ.IDLE) + return false; + + var firstActiveFm2014 = GetFirstConnectedAndLoggedInFm2014(); + if (firstActiveFm2014 == null) + return false; + + // Check if any pulse counter is required + if (!firstActiveFm2014.RefPulseCtrOn && !firstActiveFm2014.DutPulseCtrOn) + { + return false; + } + + var cmdName = CmdName.CMD_NA; + String measurementInfoStr; + + // Prepare REF and/or DUT pulse counter measurement, the first call activates if one or both are started! + try + { + switch (firstActiveFm2014.RefPulseCtrOn) + { + case true when firstActiveFm2014.DutPulseCtrOn: + cmdName = CmdName.CMD_REF_DUT_STR_PLS_CTR; + measurementInfoStr = Resources.StrMeasMsgPulseCtrRefDut; + break; + case true: + cmdName = CmdName.CMD_REF_STR_PLS_CTR; + measurementInfoStr = Resources.StrMeasMsgPulseCtrRef; + break; + default: + cmdName = CmdName.CMD_DUT_STR_PLS_CTR; + measurementInfoStr = Resources.StrMeasMsgPulseCtrDut; + break; + } + + // Start the pulse counter measurement + if (!Write(cmdName, firstActiveFm2014)) + { + return false; + } + } + catch (Exception e) + { + var response = new CmdResponse(cmdName, e.Message); + PublishResponse(firstActiveFm2014, new ProcessExecEventArgs(Resources.StrError, specificInfoObj: response, + statusReturn: StatusReturn.Failed)); + return false; + } + + // Measurement Loop + Task.Run(() => + { + + // Mark pulse counter measurement as active + SharedCyclicMeasSequ = CyclicMeasSequ.PULSE_CTR; + + do + { + CmdName cmdNameRef; + CmdName cmdNameDut; + Boolean syncPulseCtr; + + // Check if any FM2014 has a synchronized request to synchronize all FM2014 pulse counter values + if (RegisteredFm2014s.Any(x => x.RefPulseCtrOn && x.DutPulseCtrOn)) + { + cmdNameDut = CmdName.CMD_DUT_GET_PLS_CTR_BU; + cmdNameRef = CmdName.CMD_REF_GET_PLS_CTR_BU; + syncPulseCtr = true; + } + else + { + cmdNameDut = CmdName.CMD_DUT_GET_PLS_CTR; + cmdNameRef = CmdName.CMD_REF_GET_PLS_CTR; + syncPulseCtr = false; + } + + // Get the process information + var infoRef = GetCmdInfo(cmdNameRef); + var infoDut = GetCmdInfo(cmdNameDut); + + // Make a backup of the pulse counters to synchronize those and read out the backups + if (SharedCyclicMeasSequ != CyclicMeasSequ.IDLE && syncPulseCtr) + { + // Synchronized backup of REF and DUT pulse counter + Write(CmdName.CMD_REF_DUT_BU_PLS_CTR, firstActiveFm2014); + } + + foreach (var fm2014 in RegisteredFm2014s.Where(fm2014 => fm2014.IsLoggedOn)) + { + try + { + if (SharedCyclicMeasSequ != CyclicMeasSequ.IDLE) + { + if (fm2014.RefPulseCtrOn && Write(cmdNameRef, fm2014)) + { + if (Read(cmdNameRef, fm2014, out var responseStr) && + int.TryParse(responseStr, NumberStyles.HexNumber, new CultureInfo("en"), + out var intValue)) + { + var response = new CmdResponse(cmdNameRef, infoRef, intValue); + PublishResponse(fm2014, + new ProcessExecEventArgs("", actualProcessMessage: measurementInfoStr, + specificInfoObj: response)); + } + } + + if (fm2014.DutPulseCtrOn && Write(cmdNameDut, fm2014)) + { + if (Read(cmdNameDut, fm2014, out var responseStr) && + int.TryParse(responseStr, NumberStyles.HexNumber, new CultureInfo("en"), + out var intValue)) + { + var response = new CmdResponse(cmdNameDut, infoDut, intValue); + PublishResponse(fm2014, + new ProcessExecEventArgs("", actualProcessMessage: measurementInfoStr, + specificInfoObj: response)); + } + } + } + } + catch (Exception e) + { + var response = new CmdResponse(cmdName, e.Message); + PublishResponse(fm2014, new ProcessExecEventArgs(Resources.StrError, + specificInfoObj: response, statusReturn: StatusReturn.Failed)); + } + } + } while (SharedCyclicMeasSequ != CyclicMeasSequ.IDLE); + }, SharedCancellationToken).ContinueWith(delegate + { + foreach (var fm2014 in RegisteredFm2014s) + { + if (fm2014 != null) + { + fm2014.DutPulseCtrOn = false; + fm2014.RefPulseCtrOn = false; + } + } + }); + + return true; + } + /// /// The regulation measurement compares the DUT to REF tolerance /// @@ -943,7 +1137,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core { var response = new CmdResponse(cmdName, info, doubleValue: measTolerance * fm2014.ToleranceRawToPercentScale * signMultiplier, - siUnit: SiUnits.GetInfo(SiUnits.SiUnitName.PERCENTAGE_NON_SI)); + unit: Units.GetInfo(Units.Name.PERCENT)); PublishResponse(fm2014, new ProcessExecEventArgs("", actualProcessMessage: measurementInfo, specificInfoObj: response)); @@ -963,7 +1157,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core // Publish the period [ms] var response = new CmdResponse(cmdName, info, doubleValue: TMR_RESOLUTION_s * 1000.0 * period, - siUnit: "m" + SiUnits.GetInfo(SiUnits.SiUnitName.TIME)); + unit: "m" + Units.GetInfo(Units.Name.TIME_s)); PublishResponse(fm2014, new ProcessExecEventArgs("", actualProcessMessage: measurementInfo, specificInfoObj: response)); @@ -973,7 +1167,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core info = GetCmdInfo(cmdName); response = new CmdResponse(cmdName, info, doubleValue: 1.0 / (TMR_RESOLUTION_s * period), - siUnit: SiUnits.GetInfo(SiUnits.SiUnitName.FREQUENCY)); + unit: Units.GetInfo(Units.Name.FREQUENCY_Hz)); PublishResponse(fm2014, new ProcessExecEventArgs("", actualProcessMessage: measurementInfo, specificInfoObj: response)); @@ -984,7 +1178,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core cmdName = CmdName.CMD_CAL_FLOW_REF_PERIOD; info = GetCmdInfo(cmdName); response = new CmdResponse(cmdName, info, doubleValue: fm2014.RefFlowRate_cm_per_h, - siUnit: SiUnits.GetInfo(SiUnits.SiUnitName.FLOW_RATE_NON_SI)); + unit: Units.GetInfo(Units.Name.FLOW_RATE_cm_per_h)); PublishResponse(fm2014, new ProcessExecEventArgs("", actualProcessMessage: measurementInfo, specificInfoObj: response)); @@ -1005,7 +1199,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core // Publish the period [ms] var response = new CmdResponse(cmdName, info, doubleValue: TMR_RESOLUTION_s * 1000.0 * period, - siUnit: "m" + SiUnits.GetInfo(SiUnits.SiUnitName.TIME)); + unit: "m" + Units.GetInfo(Units.Name.TIME_s)); PublishResponse(fm2014, new ProcessExecEventArgs("", actualProcessMessage: measurementInfo, specificInfoObj: response)); @@ -1015,7 +1209,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core info = GetCmdInfo(cmdName); response = new CmdResponse(cmdName, info, doubleValue: 1.0 / (TMR_RESOLUTION_s * period), - siUnit: SiUnits.GetInfo(SiUnits.SiUnitName.FREQUENCY)); + unit: Units.GetInfo(Units.Name.FREQUENCY_Hz)); PublishResponse(fm2014, new ProcessExecEventArgs("", actualProcessMessage: measurementInfo, specificInfoObj: response)); @@ -1026,7 +1220,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core cmdName = CmdName.CMD_CAL_FLOW_DUT_PERIOD; info = GetCmdInfo(cmdName); response = new CmdResponse(cmdName, info, doubleValue: fm2014.DutFlowRate_cm_per_h, - siUnit: SiUnits.GetInfo(SiUnits.SiUnitName.FLOW_RATE_NON_SI)); + unit: Units.GetInfo(Units.Name.FLOW_RATE_cm_per_h)); PublishResponse(fm2014, new ProcessExecEventArgs("", actualProcessMessage: measurementInfo, specificInfoObj: response)); @@ -1045,7 +1239,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core { // Publish the frequency in [Hz] var response = new CmdResponse(cmdName, info, refFrequency, - siUnit: SiUnits.GetInfo(SiUnits.SiUnitName.FREQUENCY)); + unit: Units.GetInfo(Units.Name.FREQUENCY_Hz)); PublishResponse(fm2014, new ProcessExecEventArgs("", actualProcessMessage: measurementInfo, specificInfoObj: response)); @@ -1056,7 +1250,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core cmdName = CmdName.CMD_CAL_FLOW_REF_FREQU; info = GetCmdInfo(cmdName); response = new CmdResponse(cmdName, info, doubleValue: fm2014.RefFlowRate_cm_per_h, - siUnit: SiUnits.GetInfo(SiUnits.SiUnitName.FLOW_RATE_NON_SI)); + unit: Units.GetInfo(Units.Name.FLOW_RATE_cm_per_h)); PublishResponse(fm2014, new ProcessExecEventArgs("", actualProcessMessage: measurementInfo, specificInfoObj: response)); @@ -1086,8 +1280,8 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core /// /// Preconditions: /// - The has to be executed in advance, - /// - The REF pulses to count has to be preset, - /// - The DUT pulses to count has to be preset, + /// - The REF pulses to count has to be preset, + /// - The DUT pulses to count has to be preset, /// - Setup double impulse deadtime using the whichautomatically /// calculates the and . /// Initial setup: @@ -1108,7 +1302,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core /// /// - Support for multiple FM2014s. /// - /// + /// /// - Static. /// public static Boolean CalibrationMeasurement() @@ -1126,8 +1320,8 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core return false; // Check if regulation can be done - if (firstActiveFm2014.RefRequiredTimeMeasurement_pulses < TIME_MEASUREMENT_INPUT_MIN_pulses || - firstActiveFm2014.DutRequiredTimeMeasurement_pulses < TIME_MEASUREMENT_INPUT_MIN_pulses) + if (firstActiveFm2014.RefPulsesRequired < TIME_MEASUREMENT_INPUT_MIN_pulses || + firstActiveFm2014.DutPulsesRequired < TIME_MEASUREMENT_INPUT_MIN_pulses) { return false; } @@ -1135,7 +1329,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core var cmdName = CmdName.CMD_NA; var measurementInfo = Resources.StrMeasMsgCalibration; InitActualProcessProgress(3); - + // Prepare calibration measurement try { @@ -1165,13 +1359,13 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core ActualProcessProgress++; cmdName = CmdName.CMD_REF_SET_PLS; - if (!Write(cmdName, firstActiveFm2014, firstActiveFm2014.RefRequiredTimeMeasurement_pulses, true)) + if (!Write(cmdName, firstActiveFm2014, firstActiveFm2014.RefPulsesRequired, true)) { return false; } ActualProcessProgress++; cmdName = CmdName.CMD_DUT_SET_PLS; - if (!Write(cmdName, firstActiveFm2014, firstActiveFm2014.DutRequiredTimeMeasurement_pulses, true)) + if (!Write(cmdName, firstActiveFm2014, firstActiveFm2014.DutPulsesRequired, true)) { return false; } @@ -1190,31 +1384,33 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core { // Mark calibration measurement as active SharedCyclicMeasSequ = CyclicMeasSequ.CALIBRATION; - InitActualProcessProgress(firstActiveFm2014.RefRequiredTimeMeasurement_pulses); + InitActualProcessProgress(firstActiveFm2014.RefPulsesRequired); do { + String responseStr; + String info; foreach (var fm2014 in RegisteredFm2014s.Where(fm2014 => fm2014.IsLoggedOn)) { try { - String responseStr; cmdName = CmdName.CMD_REF_GET_PLS_RMN; - var info = GetCmdInfo(cmdName); + info = GetCmdInfo(cmdName); if (SharedCyclicMeasSequ != CyclicMeasSequ.IDLE && Write(cmdName, fm2014)) { if (Read(cmdName, fm2014, out responseStr) && ushort.TryParse(responseStr, NumberStyles.HexNumber, new CultureInfo("en"), out var pulses)) { - fm2014.RefRequiredTimeMeasurement_pulses = pulses; + fm2014.RefPulsesRemaining = pulses; var response = new CmdResponse(cmdName, info, pulses); PublishResponse(fm2014, new ProcessExecEventArgs("", actualProcessMessage: measurementInfo, specificInfoObj: response)); - ActualProcessProgress = fm2014.RefRequiredTimeMeasurement_pulses - - fm2014.RefRemainingTimeMeasurement_pulses; + ActualProcessProgress = fm2014.RefPulsesRequired - + fm2014.RefPulsesRemaining; } } + cmdName = CmdName.CMD_DUT_GET_PLS_RMN; info = GetCmdInfo(cmdName); if (SharedCyclicMeasSequ != CyclicMeasSequ.IDLE && Write(cmdName, fm2014)) @@ -1222,7 +1418,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core if (Read(cmdName, fm2014, out responseStr) && ushort.TryParse(responseStr, NumberStyles.HexNumber, new CultureInfo("en"), out var pulses)) { - fm2014.DutRemainingTimeMeasurement_pulses = pulses; + fm2014.DutPulsesRemaining = pulses; var response = new CmdResponse(cmdName, info, pulses); PublishResponse(fm2014, new ProcessExecEventArgs("", actualProcessMessage: measurementInfo, @@ -1237,12 +1433,75 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core specificInfoObj: response, statusReturn: StatusReturn.Failed)); } } + // Check all remaining DUT and REF pulses are counted on all connected devices and finalize process by // reading out all results - if (RegisteredFm2014s.All(fm2014 => fm2014.RefRemainingTimeMeasurement_pulses == 0 && - fm2014.DutRemainingTimeMeasurement_pulses == 0)) + if (RegisteredFm2014s.All(fm2014 => fm2014.RefPulsesRemaining == 0 && + fm2014.DutPulsesRemaining == 0)) { - // Read out the result + foreach (var fm2014 in RegisteredFm2014s.Where(fm2014 => fm2014.IsLoggedOn)) + { + try + { + // Read out the result + cmdName = CmdName.CMD_REF_GET_TMR; + info = GetCmdInfo(cmdName); + if (SharedCyclicMeasSequ != CyclicMeasSequ.IDLE && Write(cmdName, fm2014)) + { + if (Read(cmdName, fm2014, out responseStr) && + uint.TryParse(responseStr, NumberStyles.HexNumber, new CultureInfo("en"), out var timerTicks)) + { + // Is converting to a real time in seconds + fm2014.RefTimerTicksMeasured = timerTicks; + var response = new CmdResponse(cmdName, info, doubleValue: fm2014.RefTimeMeasured_s, + unit: Units.GetInfo(Units.Name.TIME_s)); + PublishResponse(fm2014, new ProcessExecEventArgs("", + actualProcessMessage: measurementInfo, + specificInfoObj: response)); + } + } + + cmdName = CmdName.CMD_DUT_GET_TMR; + info = GetCmdInfo(cmdName); + if (SharedCyclicMeasSequ != CyclicMeasSequ.IDLE && Write(cmdName, fm2014)) + { + if (Read(cmdName, fm2014, out responseStr) && + uint.TryParse(responseStr, NumberStyles.HexNumber, new CultureInfo("en"), out var timerTicks)) + { + // Is converting to a real time in seconds + fm2014.DutTimerTicksMeasured = timerTicks; + var response = new CmdResponse(cmdName, info, doubleValue: fm2014.DutTimeMeasured_s, + unit: Units.GetInfo(Units.Name.TIME_s)); + PublishResponse(fm2014, new ProcessExecEventArgs("", + actualProcessMessage: measurementInfo, + specificInfoObj: response)); + } + } + cmdName = CmdName.CMD_CAL_DUT_TO_REF_TOL; + info = GetCmdInfo(cmdName); + // Is converting to a real time in seconds + if (fm2014.RefTimeMeasured_s > 0.0) + { + fm2014.DutToRefToleranceMeasured_percent = + (1.0 - fm2014.DutTimeMeasured_s / fm2014.RefTimeMeasured_s) * 100.0; + var response = new CmdResponse(cmdName, info, + doubleValue: fm2014.DutToRefToleranceMeasured_percent, + unit: Units.GetInfo(Units.Name.PERCENT)); + PublishResponse(fm2014, new ProcessExecEventArgs("", + actualProcessMessage: measurementInfo, + specificInfoObj: response)); + } + } + catch (Exception e) + { + var response = new CmdResponse(cmdName, e.Message); + PublishResponse(fm2014, new ProcessExecEventArgs(Resources.StrError, + specificInfoObj: response, statusReturn: StatusReturn.Failed)); + } + } + + ResetHardwareAllDevices(); + // Exit this task SharedCyclicMeasSequ = CyclicMeasSequ.IDLE; } } while (SharedCyclicMeasSequ != CyclicMeasSequ.IDLE); @@ -1567,190 +1826,6 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core #endregion ---------------------------------------- static methods -------------------------------------------- #region ------------------------------------------- object methods -------------------------------------------- - /// - /// Pulse counter measurement: - /// - REF counter (default ON), - /// - DUT counter (default OFF), - /// - REF and DUT counters together using the synchronized backup. - /// - Each FM2014 can use a different REF and/or DUT setting as the REF is parallel for all FM2014s. - /// Preconditions: - /// - The has to be executed in advance. - /// Initial setup: - /// - Starts the pulse counter measurement of REF and/or DUT. - /// Cyclic: - /// - Request REF and/or DUT pulse counter value(s). - /// Exit: - /// - Set to false. - /// - /// request to count REF pulses - /// request to count DUT pulses - /// true if initialization successfully executed or - /// marks the already started cyclic requests - /// for all registered FM2014s - /// - /// - Initial. - /// - /// - /// - If REF and DUT pulse counters are on the cyclic sequence: - /// - 'q' synchronized backup of both pulse counters, - /// - 'l' read REF backup pulses, - /// - 'u' read DUT backup pulses - /// will be used. - /// - /// - /// - Support for multiple FM2014s. - /// - /// - /// - If any FM2014 has REF and DUT pulse counter on then use for ALL the synchronized readout. - /// - public Boolean PulseCounterMeasurement(Boolean refCtrOn = true, Boolean dutCtrOn = false) - { - if (!IsLoggedOn || (!refCtrOn && !dutCtrOn)) - return false; - - // Init pulse counter settings, important to select different settings for other FM2014s than the first - // one e.g. The first may count the REF and DUT while the others need only the DUT as the REF is parallel - // as input for all devices. - RefPulseCtrOn = refCtrOn; - DutPulseCtrOn = dutCtrOn; - - // If the cyclic task has already been started everything is fine - if (SharedCyclicMeasSequ == CyclicMeasSequ.PULSE_CTR) - return true; - - // Marked measurement isn't pulse counter measurement, other FM2014s cannot activate this - if (SharedCyclicMeasSequ != CyclicMeasSequ.IDLE) - return false; - - var cmdName = CmdName.CMD_NA; - String measurementInfoStr; - - // Prepare REF and/or DUT pulse counter measurement, the first call activates if one or both are started! - try - { - switch (RefPulseCtrOn) - { - case true when DutPulseCtrOn: - cmdName = CmdName.CMD_REF_DUT_STR_PLS_CTR; - measurementInfoStr = Resources.StrMeasMsgPulseCtrRefDut; - break; - case true: - cmdName = CmdName.CMD_REF_STR_PLS_CTR; - measurementInfoStr = Resources.StrMeasMsgPulseCtrRef; - break; - default: - cmdName = CmdName.CMD_DUT_STR_PLS_CTR; - measurementInfoStr = Resources.StrMeasMsgPulseCtrDut; - break; - } - - // Start the pulse counter measurement - if (!Write(cmdName, this)) - { - return false; - } - } - catch (Exception e) - { - var response = new CmdResponse(cmdName, e.Message); - PublishResponse(this, new ProcessExecEventArgs(Resources.StrError, specificInfoObj: response, - statusReturn: StatusReturn.Failed)); - return false; - } - - // Measurement Loop - Task.Run(() => - { - - // Mark pulse counter measurement as active - SharedCyclicMeasSequ = CyclicMeasSequ.PULSE_CTR; - - do - { - CmdName cmdNameRef; - CmdName cmdNameDut; - Boolean syncPulseCtr; - - // Check if any FM2014 has a synchronized request to synchronize all FM2014 pulse counter values - if (RegisteredFm2014s.Any(x => x.RefPulseCtrOn && x.DutPulseCtrOn)) - { - cmdNameDut = CmdName.CMD_DUT_GET_PLS_CTR_BU; - cmdNameRef = CmdName.CMD_REF_GET_PLS_CTR_BU; - syncPulseCtr = true; - } - else - { - cmdNameDut = CmdName.CMD_DUT_GET_PLS_CTR; - cmdNameRef = CmdName.CMD_REF_GET_PLS_CTR; - syncPulseCtr = false; - } - // Get the process information - var infoRef = GetCmdInfo(cmdNameRef); - var infoDut = GetCmdInfo(cmdNameDut); - - try - { - // Make a backup of the pulse counters to synchronize those and read out the backups - if (SharedCyclicMeasSequ != CyclicMeasSequ.IDLE && syncPulseCtr) - { - // Synchronized backup of REF and DUT pulse counter - Write(CmdName.CMD_REF_DUT_BU_PLS_CTR, this); - } - - foreach (var fm2014 in RegisteredFm2014s.Where(fm2014 => fm2014.IsLoggedOn)) - { - if (SharedCyclicMeasSequ != CyclicMeasSequ.IDLE) - { - if (fm2014.RefPulseCtrOn && Write(cmdNameRef, fm2014)) - { - if (Read(cmdNameRef, fm2014, out var responseStr) && - int.TryParse(responseStr, NumberStyles.HexNumber, new CultureInfo("en"), - out var intValue)) - { - var response = new CmdResponse(cmdNameRef, infoRef, intValue); - PublishResponse(fm2014, - new ProcessExecEventArgs("", actualProcessMessage: measurementInfoStr, - specificInfoObj: response)); - } - } - - if (fm2014.DutPulseCtrOn && Write(cmdNameDut, fm2014)) - { - if (Read(cmdNameDut, fm2014, out var responseStr) && - int.TryParse(responseStr, NumberStyles.HexNumber, new CultureInfo("en"), - out var intValue)) - { - var response = new CmdResponse(cmdNameDut, infoDut, intValue); - PublishResponse(fm2014, - new ProcessExecEventArgs("", actualProcessMessage: measurementInfoStr, - specificInfoObj: response)); - } - } - } - } - } - catch (Exception e) - { - var response = new CmdResponse(cmdName, e.Message); - PublishResponse(this, new ProcessExecEventArgs(Resources.StrError, - specificInfoObj: response, statusReturn: StatusReturn.Failed)); - } - } while (SharedCyclicMeasSequ != CyclicMeasSequ.IDLE); - }, SharedCancellationToken).ContinueWith(delegate - { - foreach (var fm2014 in RegisteredFm2014s) - { - if (fm2014 != null) - { - fm2014.DutPulseCtrOn = false; - fm2014.RefPulseCtrOn = false; - } - } - }); - - return true; - } - /// /// Transfer all standalone settings to FM2014 RAM and safe those to nonvolatile EEPROM /// @@ -1990,8 +2065,8 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core { foreach (var fm2014 in RegisteredFm2014s.Where(fm2014 => fm2014.IsLoggedOn)) { - fm2014.RefMeasuredTimer_ticks = 0; - fm2014.DutMeasuredTimer_ticks = 0; + fm2014.RefTimerTicksMeasured = 0; + fm2014.DutTimerTicksMeasured = 0; fm2014.RefFlowRate_cm_per_h = 0; fm2014.DutFlowRate_cm_per_h = 0; } diff --git a/Common/Metrology/Measurements/Consts/SiUnits.cs b/Common/Metrology/Measurements/Consts/SiUnits.cs deleted file mode 100644 index fceb24b3..00000000 --- a/Common/Metrology/Measurements/Consts/SiUnits.cs +++ /dev/null @@ -1,173 +0,0 @@ -/****************************************************************************************/ -/*!@file FM2014Commands.cs - * @brief Command list of the FM2014. - * - *=======================================================================================\n - * @copyright - * - *_______________________________________________________________________________________\n - * Copyright (c) 2026 SENSUS GmbH.\n - * All Rights Reserved.\n - * \n - * Confidential property of\n - * SENSUS GmbH,\n - * Meineckestr. 10, 30880 LAATZEN, GERMANY\n - * \n - *=======================================================================================\n - * @authors - * - *_______________________________________________________________________________________\n - * Thomas Wiedebusch\n - * - * - *=======================================================================================\n - * @version - * - *_______________________________________________________________________________________\n - * V1.00 10-Jan-2026 by Thomas Wiedebusch\n - * - Initial. - * - * - *=======================================================================================\n - */ - -using System; -using System.Linq; - -namespace Xylem.Common.Metrology.Measurements.Consts -{ - - /// - /// SI Units - /// - public static class SiUnits - { - /// - /// Unit definitions based on SI or derived SI or NON SI - /// - public enum SiUnitName - { - /// - /// - /// - UNITLESS_NON_SI, - - /// - /// - /// - PERCENTAGE_NON_SI, - - /// - /// - /// - VOLTAGE, - - /// - /// - /// - CURRENT, - - /// - /// - /// - ELECTRICAL_POWER, - - /// - /// - /// - ELECTRICAL_LOAD, - - /// - /// - /// - DISTANCE, - - /// - /// - /// - FLOW_RATE_NON_SI, - - /// - /// - /// - TEMPERATURE, - - /// - /// - /// - TIME, - - /// - /// - /// - PRESSURE, - - /// - /// - /// - FREQUENCY - - } - - /// - /// Combine SI unit names with string value - /// - public struct SiUnit - { - /// - /// Hard coded return string from FM2014 - /// - public readonly SiUnitName SiUnitName; - - /// - /// SI unit string - /// - public readonly String SiUnitAbbreviationStr; - - /// - /// Ctor - /// - /// - /// - public SiUnit(SiUnitName siUnitName, String siUnitAbbreviationStr) - { - SiUnitName = siUnitName; - SiUnitAbbreviationStr = siUnitAbbreviationStr; - } - } - - /// - /// Table of SI and NON-SI units - /// - public static readonly SiUnit[] SiUnitTbl = - { - new SiUnit(SiUnitName.UNITLESS_NON_SI, ""), - new SiUnit(SiUnitName.PERCENTAGE_NON_SI, "%"), - new SiUnit(SiUnitName.VOLTAGE, "V"), - new SiUnit(SiUnitName.CURRENT, "A"), - new SiUnit(SiUnitName.ELECTRICAL_POWER, "W"), - new SiUnit(SiUnitName.ELECTRICAL_LOAD, "Ah"), - new SiUnit(SiUnitName.DISTANCE, "m"), - new SiUnit(SiUnitName.FLOW_RATE_NON_SI, "m³/h"), - new SiUnit(SiUnitName.TEMPERATURE, "°C"), - new SiUnit(SiUnitName.TIME, "s"), - new SiUnit(SiUnitName.PRESSURE, "Pa"), - new SiUnit(SiUnitName.FREQUENCY, "Hz"), - }; - - /// - /// Get the information string - /// - /// - /// Unit string - /// - /// - Initial. - /// - public static String GetInfo(SiUnitName siUnitName) - { - return (from sit in SiUnitTbl - where sit.SiUnitName == siUnitName - select sit.SiUnitAbbreviationStr).FirstOrDefault(); - } - } -} diff --git a/Common/Metrology/Measurements/Consts/Units.cs b/Common/Metrology/Measurements/Consts/Units.cs new file mode 100644 index 00000000..202d662b --- /dev/null +++ b/Common/Metrology/Measurements/Consts/Units.cs @@ -0,0 +1,157 @@ +/*********************************************************************************************************************/ +/*! @file Unit.cs + * @brief Units for measurements + * + * @author Thomas Wiedebusch + * @date 2026-Jan-08 + * + * @details Implements the command table and interprocess-communication structs for the FM2014. + * + * @copyright © SENSUS GmbH 2026. All rights reserved. + *********************************************************************************************************************/ +using System; +using System.Linq; + +namespace Xylem.Common.Metrology.Measurements.Consts +{ + + /// + /// SI Units + /// + public static class Units + { + /// + /// Unit definitions based on SI or derived SI or NON SI + /// + public enum Name + { + /// + /// Value without any attachable unit [] + /// + UNITLESS, + + /// + /// Normalized to +/- 1.000 [norm] + /// + NORMALIZED, + + /// + /// Percent [%] + /// + PERCENT, + + /// + /// Voltage in Volts [V] + /// + VOLTAGE_V, + + /// + /// Current in Amperes [A] + /// + CURRENT_A, + + /// + /// Electrical Power in Watts [W] + /// + ELECTRICAL_POWER_W, + + /// + /// Electrical Load in Ampere hours [Ah] + /// + ELECTRICAL_LOAD_Ah, + + /// + /// Distance in Meters [m] + /// + DISTANCE_m, + + /// + /// Flow rate in cubic-meters per hour [m³/h] + /// + FLOW_RATE_cm_per_h, + + /// + /// Temperature in degree Celsius [°C] + /// + TEMPERATURE_degC, + + /// + /// Time in seconds [s] + /// + TIME_s, + + /// + /// Pressure in Pascal [Pa] + /// + PRESSURE_Pa, + + /// + /// Frequency in Hertz [Hz] + /// + FREQUENCY_Hz + + } + + /// + /// Combine SI unit names with string value + /// + public struct SiUnit + { + /// + /// Hard coded return string from FM2014 + /// + public readonly Name Name; + + /// + /// SI unit string + /// + public readonly String AbbreviationStr; + + /// + /// Ctor + /// + /// + /// + public SiUnit(Name name, String abbreviationStr) + { + Name = name; + AbbreviationStr = abbreviationStr; + } + } + + /// + /// Table of SI and NON-SI units + /// + public static readonly SiUnit[] SiUnitTbl = + { + new SiUnit(Name.UNITLESS, ""), + new SiUnit(Name.NORMALIZED, "norm"), + new SiUnit(Name.PERCENT, "%"), + new SiUnit(Name.VOLTAGE_V, "V"), + new SiUnit(Name.CURRENT_A, "A"), + new SiUnit(Name.ELECTRICAL_POWER_W, "W"), + new SiUnit(Name.ELECTRICAL_LOAD_Ah, "Ah"), + new SiUnit(Name.DISTANCE_m, "m"), + new SiUnit(Name.FLOW_RATE_cm_per_h, "m³/h"), + new SiUnit(Name.TEMPERATURE_degC, "°C"), + new SiUnit(Name.TIME_s, "s"), + new SiUnit(Name.PRESSURE_Pa, "Pa"), + new SiUnit(Name.FREQUENCY_Hz, "Hz"), + }; + + /// + /// Get the information string + /// + /// + /// Unit string + /// + /// - Initial. + /// + public static String GetInfo(Name name) + { + return (from sit in SiUnitTbl + where sit.Name == name + select sit.AbbreviationStr).FirstOrDefault(); + } + } +} diff --git a/Common/Metrology/Measurements/Measurements.csproj b/Common/Metrology/Measurements/Measurements.csproj index 3e0ead2c..c7bc1ef6 100644 --- a/Common/Metrology/Measurements/Measurements.csproj +++ b/Common/Metrology/Measurements/Measurements.csproj @@ -212,7 +212,7 @@ - + diff --git a/FM2014TestApp/Ui/FM2014TestBenchWinFrms/FrmFm2014TestApp.cs b/FM2014TestApp/Ui/FM2014TestBenchWinFrms/FrmFm2014TestApp.cs index 9348cd2a..9c3c0403 100644 --- a/FM2014TestApp/Ui/FM2014TestBenchWinFrms/FrmFm2014TestApp.cs +++ b/FM2014TestApp/Ui/FM2014TestBenchWinFrms/FrmFm2014TestApp.cs @@ -1092,12 +1092,12 @@ namespace Sensus.Ui.FM2014TestApp tbxDutPulsePerCm.Text = $@"{Fm2014.Dut_pulse_per_cm:D}"; } // Setup FM2014 - if (int.TryParse(tbxDutPulsePerCm.Text, out var pulses_per_cm)) + if (ushort.TryParse(tbxDutPulsePerCm.Text, out var pulses_per_cm)) { //Backup the actual setting to detect changes var backupPulses_per_cm = Fm2014.Dut_pulse_per_cm; // Try to set the new calculated REF pulses limited by the property setter - Fm2014.Dut_pulse_per_cm = (UInt32)pulses_per_cm; + Fm2014.Dut_pulse_per_cm = pulses_per_cm; // Output the Fm2014 setting to avoid wrong display of invalid ranges as this will be // limited during the setup of the FM2014 property! tbxDutPulsePerCm.Text = $@"{Fm2014.Dut_pulse_per_cm:D}"; @@ -1280,7 +1280,7 @@ namespace Sensus.Ui.FM2014TestApp } else if (resp.IntValue != null) { - LogText($"{resp.AnswerStr}: {resp.IntValue:D} {resp.SiUnit}"); + LogText($"{resp.AnswerStr}: {resp.IntValue:D} {resp.Unit}"); switch (resp.CmdName) { case FM2014CmdDef.CmdName.CMD_REF_GET_PLS_CTR: @@ -1320,7 +1320,7 @@ namespace Sensus.Ui.FM2014TestApp } else if (resp.DoubleValue != null) { - LogText($"{resp.AnswerStr}: {resp.DoubleValue:F2} {resp.SiUnit}"); + LogText($"{resp.AnswerStr}: {resp.DoubleValue:F2} {resp.Unit}"); switch (resp.CmdName) { case FM2014CmdDef.CmdName.CMD_GET_UDTLC: @@ -1399,11 +1399,11 @@ namespace Sensus.Ui.FM2014TestApp } else if (resp.IntValue != null) { - LogText($"{resp.AnswerStr}: {resp.IntValue:D} {resp.SiUnit}"); + LogText($"{resp.AnswerStr}: {resp.IntValue:D} {resp.Unit}"); } else if (resp.DoubleValue != null) { - LogText($"{resp.AnswerStr}: {resp.DoubleValue:F2} {resp.SiUnit}"); + LogText($"{resp.AnswerStr}: {resp.DoubleValue:F2} {resp.Unit}"); } })); } diff --git a/FM2014TestApp/Ui/Fm2014sTest/FM2014TestBenchWindow.xaml b/FM2014TestApp/Ui/Fm2014sTest/FM2014TestBenchWindow.xaml index 24c01657..28c028ea 100644 --- a/FM2014TestApp/Ui/Fm2014sTest/FM2014TestBenchWindow.xaml +++ b/FM2014TestApp/Ui/Fm2014sTest/FM2014TestBenchWindow.xaml @@ -72,10 +72,11 @@ - + + @@ -89,6 +90,8 @@ + + @@ -98,12 +101,10 @@ - - - + @@ -146,8 +147,8 @@ - - + + @@ -207,7 +208,7 @@ - /// - /// - Initial. - /// - /// + /// /// - Initial. /// private void Init() @@ -492,8 +497,12 @@ namespace Sensus.Ui.FM2014TestBench // Restore individual tolerance selection if (_fm2014Config?.IndividualTolerancePercent?[ctr] != null && _fm2014Config.IndividualTolerancePercent.Count == MaxFm2014s) + { fm2014.Tolerance_percent = _fm2014Config?.IndividualTolerancePercent[ctr] ?? - FM2014.STANDARD_NOMINAL_TOLERANCE_INPUT_percent; + FM2014.STANDARD_NOMINAL_TOLERANCE_INPUT_percent; + // Display on regulation page as common setup for ALL + cbxToleranceCalc.SelectedItem = fm2014.Tolerance_percent.ToString(); + } } // Disable and hide dynamic measurement labels @@ -539,38 +548,46 @@ namespace Sensus.Ui.FM2014TestBench lblLifeTimeText.Content = Properties.Resources.StrLblLifetime; lblSlotSelection.Content = Properties.Resources.StrLblSlotSelection; - // Regulation Setup - lblRefPulsesPerCm.Content = Properties.Resources.StrLblRatioRefPulsesPerCm; + // DUT to REF Regulation Setup + lblRefPulsesPerCm.Content = Properties.Resources.StrLblRefPulsesPerCmRatio; tbxRefPulsesPerCm.Text = ""; - lblDutPulsesPerCm.Content = Properties.Resources.StrLblRatioDutPulsesPerCm; + lblDutPulsesPerCm.Content = Properties.Resources.StrLblDutPulsesPerCmRatio; tbxDutPulsesPerCm.Text = ""; - lblScaleRefToDut.Content = Properties.Resources.StrLblScaleRefToDut; + lblScaleRefToDut.Content = Properties.Resources.StrLblRefToDutScale; tbxScaleRefToDut.Text = ""; tbxScaleRefToDut.IsReadOnly = true; - lblAttenuation.Content = Properties.Resources.StrLblAttenuation; + lblDisplayAttenuation.Content = Properties.Resources.StrLblDisplayAttenuation; btnSaveRegulationSetup.Content = Properties.Resources.StrBtnSaveRegulationSetup; - - //// DUT to REF Regulation group box - //tabDutToRefRegulation.Content = Properties.Resources.StrGbxDutToRefRegulation; - //lblActualFlowRateCmPerHour.Text = Properties.Resources.StrLblActualMeasuredFlowRate; - //tbxActualFlowRateCmPerHour.Text = ""; - //lblActualMeasuredTolerance.Text = Properties.Resources.StrLblActualMeasuredToleranceDutToRef; - //tbxActualMeasuredToleranceDutToRef.Text = ""; + lblToleranceCalc.Content = Properties.Resources.StrLblFM2014Tolerance; chkUseDampedTolerance.Content = Properties.Resources.StrChkUseDampedTolerance; btnDutToRefRegulation.Content = Properties.Resources.StrBtnStartRegulation; - //tbxRefFrequencyHz.Text = ""; - //// Manual REF Calibration group box - //gbxManualRefCalibration.Text = Properties.Resources.StrGbxManualRefCalibration; - //lblMeasuredRefPulses.Text = Properties.Resources.StrLblMeasuredRefPulses; - //tbxMeasuredRefPulses.Text = ""; - //cbxMeasuredDutPulses.Text = Resources.StrLblMeasuredDutPulses; - //tbxMeasuredDutPulses.Text = ""; - //lblWeightScaleVolume.Text = Properties.Resources.StrLblMeasuredWeightScaleVolume; - //tbxManualInputVolumeLiters.Text = ""; - //lblPulseVolumeCmRelation.Text = Properties.Resources.StrLblRefPulsesPerCm; - //tbxRefCalibrationResultPulsePerCm.Text = ""; - //btnManualRefCalibration.Text = Properties.Resources.StrBtnStartCalibration; + // DUT to REF Calibration + lblRefPulsesRequired.Content = Properties.Resources.StrLblRefPulsesRequired; + tbxRefPulsesRequired.Text = "200"; + lblDutPulsesRequired.Content = Properties.Resources.StrLblDutPulsesRequired; + tbxDutPulsesRequired.Text = "20"; + lblDoublePulseDeadtime.Content = Properties.Resources.StrLblDoublePulseDeadTime; + tbxDoublePulseDeadtime.Text = "0"; + lblDutToRefTolMax.Content = Properties.Resources.StrLblDutToRefToleranceMax; + tbxDutToRefTolMax.Text = "1.0"; + lblDutToRefTolMin.Content = Properties.Resources.StrLblDutToRefToleranceMin; + tbxDutToRefTolMin.Text = "-0.5"; + btnTakeCalibrationSetup.Content = Properties.Resources.StrBtnTakeCalibrationSetup; + + // Manual REF to Volume Calibration + lblRefPulsesMeasured.Content = Properties.Resources.StrLblRefPulsesMeasured; + tbxRefPulsesMeasured.Text = ""; + tbxRefPulsesMeasured.IsReadOnly = true; + chkDutPulsesMeasured.Content = Properties.Resources.StrLblDutPulsesMeasured; + tbxDutPulsesMeasured.Text = ""; + tbxDutPulsesMeasured.IsReadOnly = true; + lblVolumeMeasured.Content = Properties.Resources.StrLblVolumeMeasured; + tbxVolumeMeasured.Text = ""; + lblRefPulsesPerCmScale.Content = Properties.Resources.StrLblRefPulsesPerCmRatio; + tbxRefPulsesPerCmScale.Text = ""; + tbxRefPulsesPerCmScale.IsReadOnly = true; + btnRefToVolumeCalibration.Content = Properties.Resources.StrBtnStartCalibration; //// Process status lblActualProcessLabel.Content = Properties.Resources.StrLblActualProcessStatus; @@ -773,19 +790,13 @@ namespace Sensus.Ui.FM2014TestBench { btnSaveRegulationSetup.IsEnabled = true; btnDutToRefRegulation.IsEnabled = true; - //tbxRefFrequencyHz.Text = ""; - //tbxRefFrequencyHz.BackColor = ColorStandardDisplayField; - //tbxActualFlowRateCmPerHour.Text = ""; - //tbxActualFlowRateCmPerHour.BackColor = ColorStandardDisplayField; - //tbxActualMeasuredToleranceDutToRef.Text = ""; - //tbxActualMeasuredToleranceDutToRef.BackColor = ColorStandardDisplayField; tbxRefPulsesPerCm.Background = ColorStandardInputField; tbxDutPulsesPerCm.Background = ColorStandardInputField; tbxScaleRefToDut.Background = ColorStandardDisplayField; - //tbxManualInputVolumeLiters.BackColor = ColorStandardInputField; - //tbxRefCalibrationResultPulsePerCm.BackColor = ColorStandardDisplayField; + tbxVolumeMeasured.Background = ColorStandardInputField; + tbxRefPulsesPerCmScale.Background = ColorStandardDisplayField; }); } @@ -932,10 +943,12 @@ namespace Sensus.Ui.FM2014TestBench private void SetFM2014AccessLocked() { // Disable all buttons + UiElmEnable(btnDutToRefCalibration, false); UiElmEnable(btnSaveRegulationSetup, false); UiElmEnable(btnDutToRefRegulation, false); UiElmEnable(btnFM2014Connect, false); - //btnManualRefCalibration.Enabled = false; + UiElmEnable(btnRefToVolumeCalibration, false); + UiElmEnable(btnTakeCalibrationSetup, false); // Disable manual input Dispatcher.Invoke(() => @@ -944,18 +957,26 @@ namespace Sensus.Ui.FM2014TestBench tbxRefPulsesPerCm.IsReadOnly = true; tbxDutPulsesPerCm.IsReadOnly = true; }); + UiElmEnable(tbxRefPulsesRequired, false); + UiElmEnable(tbxDutPulsesRequired, false); + UiElmEnable(tbxDoublePulseDeadtime, false); + UiElmEnable(tbxDutToRefTolMax, false); + UiElmEnable(tbxDutToRefTolMin, false); UiElmEnable(tbxRefPulsesPerCm, false); UiElmEnable(tbxDutPulsesPerCm, false); UiElmEnable(tbxScaleRefToDut, false); // Additional scale is permanent read only - UiElmEnable(cbxAttenuation, false); + UiElmEnable(cbxDisplayAttenuation, false); + UiElmEnable(cbxToleranceCalc, false); UiElmEnable(cbxFM2014ComPort, false); + UiElmEnable(tbxRefPulsesMeasured, false); // Additional scale is permanent read only + UiElmEnable(chkDutPulsesMeasured, false); + UiElmEnable(tbxDutPulsesMeasured, false); // Additional scale is permanent read only + UiElmEnable(tbxVolumeMeasured, false); + UiElmEnable(tbxRefPulsesPerCmScale, false); // Additional scale is permanent read only foreach (var slotSelector in SlotSelections) { UiElmEnable(slotSelector, false); } - - //cbxFM2014TolerancePercent.Enabled = false; - //tbxMeasuredDutPulses.Enabled = false; } /// @@ -963,14 +984,17 @@ namespace Sensus.Ui.FM2014TestBench /// private void SetFM2014AccessEnabled() { - // Enable save setup depending on changed properties - UiElmEnable(btnSaveRegulationSetup, _regulationSetupHasChanged); - // Enable buttons and display correct information + UiElmEnable(btnDutToRefCalibration, true); + UiElmEnable(btnSaveRegulationSetup, _regulationSetupHasChanged); // activate if setup has changed UiElmEnable(btnDutToRefRegulation, true); UiElmEnable(btnFM2014Connect, true); - //btnManualRefCalibration.Enabled = true; - //btnManualRefCalibration.Text = Resources.StrBtnStartCalibration; + UiElmEnable(btnRefToVolumeCalibration, true); + UiElmEnable(btnTakeCalibrationSetup, true); + + // Prepare test output to start as it is used for strat and stop + UpdateContentControl(btnRefToVolumeCalibration, Properties.Resources.StrBtnStartCalibration); + UpdateContentControl(btnDutToRefCalibration, Properties.Resources.StrBtnStartCalibration); UpdateContentControl(btnDutToRefRegulation, Properties.Resources.StrBtnStartRegulation); // Enable manual input @@ -982,19 +1006,27 @@ namespace Sensus.Ui.FM2014TestBench }); //// Enable setting selections + UiElmEnable(tbxRefPulsesRequired, true); + UiElmEnable(tbxDutPulsesRequired, true); + UiElmEnable(tbxDoublePulseDeadtime, true); + UiElmEnable(tbxDutToRefTolMax, true); + UiElmEnable(tbxDutToRefTolMin, true); UiElmEnable(tbxRefPulsesPerCm, true); UiElmEnable(tbxDutPulsesPerCm, true); UiElmEnable(tbxScaleRefToDut, true); // Additional scale is permanent read only - UiElmEnable(cbxAttenuation, true); + UiElmEnable(cbxDisplayAttenuation, true); + UiElmEnable(cbxToleranceCalc, true); UiElmEnable(cbxFM2014ComPort, true); + UiElmEnable(tbxRefPulsesMeasured, true); // Additional scale is permanent read only + UiElmEnable(chkDutPulsesMeasured, true); + UiElmEnable(tbxDutPulsesMeasured, true); // Additional scale is permanent read only + UiElmEnable(tbxVolumeMeasured, true); + UiElmEnable(tbxRefPulsesPerCmScale, true); // Additional scale is permanent read only foreach (var slotSelector in SlotSelections) { UiElmEnable(slotSelector, true); } - - //cbxFM2014TolerancePercent.Enabled = true; - //tbxMeasuredDutPulses.Enabled = true; } #endregion ---------------------------------------- ActivationControls ---------------------------------------- @@ -1019,7 +1051,7 @@ namespace Sensus.Ui.FM2014TestBench } else return; - // Progress info section + // Progress info section if (e.ActualProcessMessage != null) { UpdateContentControl(lblActualProcessText, e.ActualProcessMessage); @@ -1059,7 +1091,7 @@ namespace Sensus.Ui.FM2014TestBench } else if (resp.IntValue != null) { - LogText($"{resp.AnswerStr}: {resp.IntValue:D} {resp.SiUnit}"); + LogText($"{resp.AnswerStr}: {resp.IntValue:D} {resp.Unit}"); switch (resp.CmdName) { case CmdName.CMD_REF_GET_PLS_RMN: @@ -1070,11 +1102,13 @@ namespace Sensus.Ui.FM2014TestBench break; case CmdName.CMD_REF_GET_PLS_CTR: case CmdName.CMD_REF_GET_PLS_CTR_BU: - //UpdateTextBox(tbxMeasuredRefPulses, $"{resp.IntValue:D}"); + UpdateTextBox(tbxRefPulsesMeasured, $"{resp.IntValue:D}"); + ucFm2014.SetValue(CTR_LBL_IDX_REF_PLS, $"{resp.IntValue:D}"); break; case CmdName.CMD_DUT_GET_PLS_CTR: case CmdName.CMD_DUT_GET_PLS_CTR_BU: - //UpdateTextBox(tbxMeasuredDutPulses, $"{resp.IntValue:D}"); + UpdateTextBox(tbxDutPulsesMeasured, $"{resp.IntValue:D}"); + ucFm2014.SetValue(CTR_LBL_IDX_DUT_PLS, $"{resp.IntValue:D}"); break; case CmdName.CMD_REF_LPP_SCALE: UpdateTextBox(tbxRefPulsesPerCm, $"{resp.IntValue:D}"); @@ -1083,20 +1117,24 @@ namespace Sensus.Ui.FM2014TestBench UpdateTextBox(tbxDutPulsesPerCm, $"{resp.IntValue:D}"); break; case CmdName.CMD_MEAS_SET_ATTN: - Dispatcher.Invoke(() => cbxAttenuation.SelectedItem = $"{resp.IntValue}"); + Dispatcher.Invoke(() => cbxDisplayAttenuation.SelectedItem = $"{resp.IntValue}"); break; case CmdName.CMD_GET_REF_FREQU: valueStr = $"{resp.IntValue:D}"; if (resp.IntValue < FM2014.REF_FREQU_MIN || resp.IntValue > FM2014.REF_FREQU_MAX) - ucFm2014.SetValue(REG_LBL_IDX_REF_FREQU, valueStr, ColorProcessFailed); + ucFm2014.SetValue(CMN_LBL_IDX_REF_FREQU, valueStr, ColorProcessFailed); else - ucFm2014.SetValue(REG_LBL_IDX_REF_FREQU, valueStr); + ucFm2014.SetValue(CMN_LBL_IDX_REF_FREQU, valueStr); + break; + case CmdName.CMD_RST_MEAS: + if (resp.IntValue == 0) + ActionControl(false); break; } } else if (resp.DoubleValue != null) { - LogText($"{resp.AnswerStr}: {resp.DoubleValue:F2} {resp.SiUnit}"); + LogText($"{resp.AnswerStr}: {resp.DoubleValue:F2} {resp.Unit}"); switch (resp.CmdName) { case CmdName.CMD_REF_GET_TMR: @@ -1108,12 +1146,12 @@ namespace Sensus.Ui.FM2014TestBench ucFm2014.SetValue(CAL_LBL_IDX_DUT_MEAS_TMR, valueStr); break; case CmdName.CMD_CAL_DUT_TO_REF_TOL: - valueStr = $"{resp.DoubleValue:F2}"; - if ((Double)resp.DoubleValue > fm2014.DutToRefCalibrationToleranceMax_percent || - (Double)resp.DoubleValue < fm2014.DutToRefCalibrationToleranceMin_percent) - ucFm2014.SetValue(CAL_LBL_IDX_DUT_TO_REF_TOL, valueStr, ColorProcessFailed); - else + valueStr = $"{resp.DoubleValue:F3}"; + if ((Double)resp.DoubleValue <= fm2014.DutToRefCalibrationToleranceMax_percent && + (Double)resp.DoubleValue >= fm2014.DutToRefCalibrationToleranceMin_percent) ucFm2014.SetValue(CAL_LBL_IDX_DUT_TO_REF_TOL, valueStr, ColorSuccess); + else + ucFm2014.SetValue(CAL_LBL_IDX_DUT_TO_REF_TOL, valueStr, ColorProcessFailed); break; case CmdName.CMD_GET_UDTLC: case CmdName.CMD_GET_DTLC: @@ -1141,7 +1179,7 @@ namespace Sensus.Ui.FM2014TestBench // break; case CmdName.CMD_CAL_FLOW_REF_FREQU: valueStr = $"{resp.DoubleValue:F3}"; - ucFm2014.SetValue(REG_LBL_IDX_FLOW_RATE, valueStr); + ucFm2014.SetValue(CMN_LBL_IDX_FLOW_RATE, valueStr); //UpdateTextBox(tbxRefFlowRateFromRefFrequencyCmPerH, valueStr); // TODO THW Check if the actual flow shall be taken based on 'REF Frequency' //UpdateTextBox(tbxActualFlowRateCmPerHour, valueStr); @@ -1193,13 +1231,13 @@ namespace Sensus.Ui.FM2014TestBench UiElmEnable(measLbl, false, false); // Set the measurement labels - UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_REF_REQ_PLS], Properties.Resources.StrLblRequiredRefPulses); - UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_REF_RMN_PLS], Properties.Resources.StrLblRemainingRefPulses); - UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_DUT_REQ_PLS], Properties.Resources.StrLblRequiredDutPulses); - UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_DUT_RMN_PLS], Properties.Resources.StrLblRemainingDutPulses); - UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_REF_MEAS_TMR], Properties.Resources.StrLblMeasuredRefTime); - UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_DUT_MEAS_TMR], Properties.Resources.StrLblMeasuredDutTime); - UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_DUT_TO_REF_TOL], Properties.Resources.StrLblMeasuredDutToRefTolerance); + UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_REF_REQ_PLS], Properties.Resources.StrLblRefPulsesRequired); + UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_REF_RMN_PLS], Properties.Resources.StrLblRefPulsesRemaining); + UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_DUT_REQ_PLS], Properties.Resources.StrLblDutPulsesRequired); + UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_DUT_RMN_PLS], Properties.Resources.StrLblDutPulsesRemaining); + UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_REF_MEAS_TMR], Properties.Resources.StrLblRefTimeMeasured); + UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_DUT_MEAS_TMR], Properties.Resources.StrLblDutTimeMeasured); + UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_DUT_TO_REF_TOL], Properties.Resources.StrLblDutToRefToleranceMeasured); UiElmEnable(MeasurementLabels[CAL_LBL_IDX_REF_REQ_PLS], true); UiElmEnable(MeasurementLabels[CAL_LBL_IDX_REF_RMN_PLS], true); UiElmEnable(MeasurementLabels[CAL_LBL_IDX_DUT_REQ_PLS], true); @@ -1216,36 +1254,29 @@ namespace Sensus.Ui.FM2014TestBench var idx = fm2014.Address - 1; var ucFM2014 = (UcFM2014Device)UcFM2014s[idx]; ucFM2014.EnableMeasurements(CAL_MEASURE_COUNT); - - //TODO THW test assignment - fm2014.RefRequiredTimeMeasurement_pulses = 500; - fm2014.DutRequiredTimeMeasurement_pulses = 500; - fm2014.DutToRefCalibrationToleranceMax_percent = 1.1; - fm2014.DutToRefCalibrationToleranceMin_percent = -0.5; - fm2014.DoublePulseDeadtime_ms = 0.0; - //TODO THW Test assignment // Set initial required pulses as those are static upon the entire measurement - ucFM2014.SetValue(CAL_LBL_IDX_REF_REQ_PLS, $"{fm2014.RefRequiredTimeMeasurement_pulses}"); - ucFM2014.SetValue(CAL_LBL_IDX_DUT_REQ_PLS, $"{fm2014.DutRequiredTimeMeasurement_pulses}"); + ucFM2014.SetValue(CAL_LBL_IDX_REF_REQ_PLS, $"{fm2014.RefPulsesRequired}"); + ucFM2014.SetValue(CAL_LBL_IDX_DUT_REQ_PLS, $"{fm2014.DutPulsesRequired}"); } if (FM2014.CalibrationMeasurement()) { // Progress will be fed by the calibration routine - _autoProgressBar = false; UpdateContentControl(btnDutToRefCalibration, Properties.Resources.StrBtnStopCalibration); UiElmEnable(btnDutToRefCalibration, true); } + else + { + ActionControl(false); + } } else { - _autoProgressBar = false; // Deactivate the button temporary to avoid repeated execution as the reset takes a certain time UiElmEnable(btnDutToRefCalibration, false); FM2014.ResetHardwareAllDevices(); ActionControl(false); - UpdateContentControl(btnDutToRefCalibration, Properties.Resources.StrBtnStartCalibration); } } @@ -1267,15 +1298,12 @@ namespace Sensus.Ui.FM2014TestBench UiElmEnable(measLbl, false, false); // Set the measurement labels - UpdateContentControl(MeasurementLabels[REG_LBL_IDX_DUT_TO_REF_TOL], - Properties.Resources.StrLblMeasuredDutToRefTolerance); - UpdateContentControl(MeasurementLabels[REG_LBL_IDX_REF_FREQU], - Properties.Resources.StrLblRefFrequencyHz); - UpdateContentControl(MeasurementLabels[REG_LBL_IDX_FLOW_RATE], - Properties.Resources.StrLblMeasuredFlowRate); + UpdateContentControl(MeasurementLabels[CMN_LBL_IDX_REF_FREQU], Properties.Resources.StrLblRefFrequencyHz); + UpdateContentControl(MeasurementLabels[CMN_LBL_IDX_FLOW_RATE], Properties.Resources.StrLblFlowRateMeasured); + UpdateContentControl(MeasurementLabels[REG_LBL_IDX_DUT_TO_REF_TOL], Properties.Resources.StrLblDutToRefToleranceMeasured); + UiElmEnable(MeasurementLabels[CMN_LBL_IDX_REF_FREQU], true); + UiElmEnable(MeasurementLabels[CMN_LBL_IDX_FLOW_RATE], true); UiElmEnable(MeasurementLabels[REG_LBL_IDX_DUT_TO_REF_TOL], true); - UiElmEnable(MeasurementLabels[REG_LBL_IDX_REF_FREQU], true); - UiElmEnable(MeasurementLabels[REG_LBL_IDX_FLOW_RATE], true); if (FM2014.RegisteredFm2014s == null || FM2014.RegisteredFm2014s.Count == 0) return; @@ -1294,6 +1322,11 @@ namespace Sensus.Ui.FM2014TestBench UpdateContentControl(btnDutToRefRegulation, Properties.Resources.StrBtnStopRegulation); UiElmEnable(btnDutToRefRegulation, true); } + else + { + _autoProgressBar = false; + ActionControl(false); + } } else { @@ -1302,7 +1335,6 @@ namespace Sensus.Ui.FM2014TestBench UiElmEnable(btnDutToRefRegulation, false); FM2014.ResetHardwareAllDevices(); ActionControl(false); - UpdateContentControl(btnDutToRefRegulation, Properties.Resources.StrBtnStartRegulation); } } @@ -1312,41 +1344,131 @@ namespace Sensus.Ui.FM2014TestBench /// /// - Initial. /// - private void btnManualRefCalibration_Click(Object sender, EventArgs e) + private void btnRefToVolumeCalibration_Click(Object sender, EventArgs e) { - //_startTime = DateTimeOffset.UtcNow; - //if (FM2014.SharedCyclicMeasSequ == FM2014CmdDef.CyclicMeasSequ.IDLE) - //{ - // ActionControl(true); - // tbxMeasuredRefPulses.Text = ""; - // tbxMeasuredDutPulses.Text = ""; - // tbxManualInputVolumeLiters.Text = ""; - // tbxRefCalibrationResultPulsePerCm.Text = ""; - // tbxActualFlowRateCmPerHour.Text = ""; - // tbxActualMeasuredToleranceDutToRef.Text = ""; - // tbxRefFrequencyHz.Text = ""; + _startTime = DateTimeOffset.UtcNow; + if (FM2014.SharedCyclicMeasSequ == CyclicMeasSequ.IDLE) + { + ActionControl(true); + // Disable and hide dynamic measurement labels + foreach (var measLbl in MeasurementLabels) + UiElmEnable(measLbl, false, false); - // _backupMeasuredRefPulsesStr = ""; - // _backupRefCalibrationResultPulsePerCmStr = ""; - // _backupWeightScaleVolumeLitersStr = ""; + // Set the measurement labels + UpdateContentControl(MeasurementLabels[CMN_LBL_IDX_REF_FREQU], Properties.Resources.StrLblRefFrequencyHz); + UpdateContentControl(MeasurementLabels[CMN_LBL_IDX_FLOW_RATE], Properties.Resources.StrLblFlowRateMeasured); + UpdateContentControl(MeasurementLabels[CTR_LBL_IDX_REF_PLS], Properties.Resources.StrLblRefPulsesMeasured); + UpdateContentControl(MeasurementLabels[CTR_LBL_IDX_DUT_PLS], Properties.Resources.StrLblDutPulsesMeasured); + UiElmEnable(MeasurementLabels[CMN_LBL_IDX_REF_FREQU], true); + UiElmEnable(MeasurementLabels[CMN_LBL_IDX_FLOW_RATE], true); + UiElmEnable(MeasurementLabels[CTR_LBL_IDX_REF_PLS], true); + UiElmEnable(MeasurementLabels[CTR_LBL_IDX_DUT_PLS], true); + + UpdateTextBox(tbxRefPulsesMeasured, ""); + UpdateTextBox(tbxDutPulsesMeasured, ""); + UpdateTextBox(tbxVolumeMeasured, ""); + UpdateTextBox(tbxRefPulsesPerCmScale, ""); - // _autoProgressBar = true; + if (FM2014.RegisteredFm2014s == null || FM2014.RegisteredFm2014s.Count == 0) + return; - // if (Fm2014.PulseCounterMeasurement(true, cbxMeasuredDutPulses.Checked)) - // { - // btnManualRefCalibration.Text = Resources.StrBtnStopCalibration; - // btnManualRefCalibration.Enabled = true; - // } - //} - //else - //{ - // _autoProgressBar = false; - // // Deactivate the button temporary to avoid repeated execution as the reset takes a certain time - // btnManualRefCalibration.Enabled = false; - // Fm2014.ResetMeasurement(); - // ActionControl(false); - // btnManualRefCalibration.Text = Resources.StrBtnStartCalibration; - //} + // Adjust the user control + foreach (var fm2014 in FM2014.RegisteredFm2014s.Where(x => x.IsLoggedOn)) + { + var idx = fm2014.Address - 1; + var ucFM2014 = (UcFM2014Device)UcFM2014s[idx]; + ucFM2014.EnableMeasurements(CTR_MEASURE_COUNT); + } + + var measureDutPulses = false; + Dispatcher.Invoke(() => measureDutPulses = chkDutPulsesMeasured.IsChecked ?? false); + if (FM2014.PulseCounterMeasurement(true, measureDutPulses)) + { + _autoProgressBar = true; + UpdateContentControl(btnRefToVolumeCalibration, Properties.Resources.StrBtnStopCalibration); + UiElmEnable(btnRefToVolumeCalibration, true); + } + else + { + _autoProgressBar = false; + ActionControl(false); + } + } + else + { + _autoProgressBar = false; + // Deactivate the button temporary to avoid repeated execution as the reset takes a certain time + UiElmEnable(btnRefToVolumeCalibration, false); + FM2014.ResetHardwareAllDevices(); + ActionControl(false); + } + } + + /// + /// Select next control on enter key pressed + /// + /// + /// + /// + /// - Initial. + /// + private void cbxToleranceCalc_KeyDown(Object sender, KeyEventArgs e) + { + // Catch the enter key, recalculate all settings + if (e.Key == Key.Enter || e.Key == Key.Tab) + { + Keyboard.Focus(btnSaveRegulationSetup); + } + } + + /// + /// FM2014 tolerance setup for calculation of it item has changed: + /// - This will dispatch the new value to all FM2014s. + /// + /// + /// - Initial. + /// + private void cbxToleranceCalc_SelectedIndexChanged(Object sender, EventArgs e) + { + + var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014(); + if (null == firstFm2014) + return; + + Dispatcher.Invoke(() => + { + if (byte.TryParse(cbxToleranceCalc.SelectedItem.ToString(), out var tolerance) && + (tolerance == FM2014.STANDARD_NOMINAL_TOLERANCE_INPUT_percent || + tolerance == FM2014.EXTENDED_NOMINAL_TOLERANCE_INPUT_percent) && + firstFm2014.Tolerance_percent != tolerance) + { + firstFm2014.Tolerance_percent = tolerance; + // Dispatch settings to all connected FM2014 + foreach (var fm2014 in FM2014.RegisteredFm2014s) + { + fm2014.Tolerance_percent = tolerance; + } + _regulationSetupHasChanged = true; + btnSaveRegulationSetup.IsEnabled = true; + } + }); + } + + /// + /// Select next control on enter key pressed + /// + /// + /// + /// + /// - Initial. + /// + private void cbxAttenuation_KeyDown(Object sender, KeyEventArgs e) + { + // Catch the enter key, recalculate all settings + if (e.Key == Key.Enter || e.Key == Key.Tab) + { + Keyboard.Focus(cbxToleranceCalc); + } } /// @@ -1365,9 +1487,9 @@ namespace Sensus.Ui.FM2014TestBench Dispatcher.Invoke(() => { - if (byte.TryParse(cbxAttenuation.SelectedItem.ToString(), out var attenuation) && - attenuation >= FM2014.ATTENUATION_MIN && - attenuation <= FM2014.ATTENUATION_MAX && + if (byte.TryParse(cbxDisplayAttenuation.SelectedItem.ToString(), out var attenuation) && + attenuation >= FM2014.ATTENUATION_MIN && + attenuation <= FM2014.ATTENUATION_MAX && firstFm2014.FM2014CurrentOutputAttenuation != attenuation) { firstFm2014.FM2014CurrentOutputAttenuation = attenuation; @@ -1399,6 +1521,24 @@ namespace Sensus.Ui.FM2014TestBench } } + /// + /// Safe standalone measurement setup: + /// - This will save the setup in all FM2014s. + /// + /// + /// + /// + /// - Initial. + /// + private void btnTakeCalibrationSettings_Click(Object sender, EventArgs e) + { + tbxRefPulsesRequired_LostFocus(this, null); + tbxDutPulsesRequired_LostFocus(this, null); + tbxDoublePulseDeadtime_LostFocus(this, null); + tbxDutToRefToleranceMax_LostFocus(this, null); + tbxDutToRefToleranceMin_LostFocus(this, null); + } + /// /// Safe standalone measurement setup: /// - This will save the setup in all FM2014s. @@ -1436,7 +1576,6 @@ namespace Sensus.Ui.FM2014TestBench if (FM2014.RegisteredFm2014s == null || FM2014.RegisteredFm2014s.Count <= 0) return; - foreach (var fm2014 in FM2014.RegisteredFm2014s) { if (fm2014 != null && chkUseDampedTolerance.IsChecked != null) @@ -1445,6 +1584,29 @@ namespace Sensus.Ui.FM2014TestBench })); } + /// + /// Common check for key input to edit an integer field: + /// - Allows Left, Right, Back, Delete and 0-9 keys . and , + /// + /// + /// true an allowed key-code + /// + /// - Initial. + /// + private static Boolean MaskEditDoubleInput(Key keyCode) + { + return keyCode == Key.Back || + keyCode == Key.Left || + keyCode == Key.Right || + keyCode == Key.Delete || + keyCode == Key.Decimal || + keyCode == Key.OemComma || + keyCode == Key.OemPeriod || + keyCode == Key.OemMinus || + keyCode == Key.OemPlus || + Regex.IsMatch($"{keyCode}", @"[0-9]"); + } + /// /// Common check for key input to edit an integer field: /// - Allows Left, Right, Back, Delete and 0-9 keys. @@ -1463,6 +1625,267 @@ namespace Sensus.Ui.FM2014TestBench Regex.IsMatch($"{keyCode}", @"[0-9]"); } + /// + /// Redirect keystroke 'Enter' to leaving the cell event + /// + /// + /// + /// + /// - Initial. + /// + private void tbxRefPulsesRequired_KeyDown(Object sender, KeyEventArgs e) + { + // Catch the enter key, recalculate all settings + if (e.Key == Key.Enter || e.Key == Key.Tab) + { + tbxRefPulsesRequired_LostFocus(this, null); + Keyboard.Focus(tbxDutPulsesRequired); + } + else if (!MaskEditIntegerInput(e.Key)) + { + e.Handled = true; + } + } + + /// + /// Changed test to cover the delete key which is not in the key-down event!? + /// + /// + /// + /// + /// - Initial. + /// + private void tbxRefPulsesRequired_TextChanged(Object sender, TextChangedEventArgs e) + { + // Take the new input and calculate the results after the input has been taken after this event! + Task.Factory.StartNew(() => + { + Thread.Sleep(1); + }, _cancellationToken).ContinueWith(delegate + { + Dispatcher.Invoke(() => tbxRefPulsesRequired_LostFocus(this, null)); + }, _cancellationToken); + } + + /// + /// After manual input of the required REF pulses for the calibration measurement: + /// - This will dispatch the new value to all FM2014s. + /// + /// + /// + /// + /// - Initial. + /// + private void tbxRefPulsesRequired_LostFocus(Object sender, EventArgs e) + { + var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014(); + if (null == firstFm2014) + return; + + Dispatcher.Invoke(() => + { + if (string.IsNullOrEmpty(tbxRefPulsesRequired.Text)) + { + tbxRefPulsesRequired.Background = ColorStandardInputField; + btnDutToRefCalibration.IsEnabled = false; + return; + } + + // Convert the input and check limits + if (int.TryParse(tbxRefPulsesRequired.Text, out var pulses) && + FM2014.TIME_MEASUREMENT_INPUT_MIN_pulses <= pulses && + FM2014.TIME_MEASUREMENT_INPUT_MAX_pulses >= pulses) + { + tbxRefPulsesRequired.Background = ColorStandardInputField; + firstFm2014.RefPulsesRequired = (UInt16)pulses; + + // Dispatch settings to all connected FM2014!!!! + foreach (var fm2014 in FM2014.RegisteredFm2014s) + { + fm2014.RefPulsesRequired = firstFm2014.RefPulsesRequired; + } + } + else + { + tbxRefPulsesRequired.Background = ColorProcessFailed; + } + }); + } + + /// + /// Redirect keystroke 'Enter' to leaving the cell event + /// + /// + /// + /// + /// - Initial. + /// + private void tbxDutPulsesRequired_KeyDown(Object sender, KeyEventArgs e) + { + // Catch the enter key, recalculate all settings + if (e.Key == Key.Enter || e.Key == Key.Tab) + { + tbxDutPulsesRequired_LostFocus(this, null); + Keyboard.Focus(tbxDoublePulseDeadtime); + } + else if (!MaskEditIntegerInput(e.Key)) + { + e.Handled = true; + } + } + + /// + /// Changed test to cover the delete key which is not in the key-down event!? + /// + /// + /// + /// + /// - Initial. + /// + private void tbxDutPulsesRequired_TextChanged(Object sender, TextChangedEventArgs e) + { + // Take the new input and calculate the results after the input has been taken after this event! + Task.Factory.StartNew(() => + { + Thread.Sleep(1); + }, _cancellationToken).ContinueWith(delegate + { + Dispatcher.Invoke(() => tbxDutPulsesRequired_LostFocus(this, null)); + }, _cancellationToken); + } + + /// + /// After manual input of the required DUT pulses for the calibration measurement: + /// - This will dispatch the new value to all FM2014s. + /// + /// + /// + /// + /// - Initial. + /// + private void tbxDutPulsesRequired_LostFocus(Object sender, EventArgs e) + { + var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014(); + if (null == firstFm2014) + return; + + Dispatcher.Invoke(() => + { + if (string.IsNullOrEmpty(tbxDutPulsesRequired.Text)) + { + tbxDutPulsesRequired.Background = ColorProcessFailed; + btnDutToRefCalibration.IsEnabled = false; + return; + } + + // Convert the input and check limits + if (int.TryParse(tbxDutPulsesRequired.Text, out var pulses) && + FM2014.TIME_MEASUREMENT_INPUT_MIN_pulses <= pulses && + FM2014.TIME_MEASUREMENT_INPUT_MAX_pulses >= pulses) + { + tbxDutPulsesRequired.Background = ColorStandardInputField; + firstFm2014.DutPulsesRequired = (UInt16)pulses; + + // Dispatch settings to all connected FM2014!!!! + foreach (var fm2014 in FM2014.RegisteredFm2014s) + { + fm2014.DutPulsesRequired = firstFm2014.DutPulsesRequired; + } + } + else + { + tbxDutPulsesRequired.Background = ColorProcessFailed; + } + }); + } + + /// + /// Redirect keystroke 'Enter' to leaving the cell event + /// + /// + /// + /// + /// - Initial. + /// + private void tbxDoublePulseDeadtime_KeyDown(Object sender, KeyEventArgs e) + { + // Catch the enter key, recalculate all settings + if (e.Key == Key.Enter || e.Key == Key.Tab) + { + tbxDoublePulseDeadtime_LostFocus(this, null); + Keyboard.Focus(tbxDutToRefTolMax); + } + else if (!MaskEditIntegerInput(e.Key)) + { + e.Handled = true; + } + } + + /// + /// Changed test to cover the delete key which is not in the key-down event!? + /// + /// + /// + /// + /// - Initial. + /// + private void tbxDoublePulseDeadtime_TextChanged(Object sender, TextChangedEventArgs e) + { + // Take the new input and calculate the results after the input has been taken after this event! + Task.Factory.StartNew(() => + { + Thread.Sleep(1); + }, _cancellationToken).ContinueWith(delegate + { + Dispatcher.Invoke(() => tbxDoublePulseDeadtime_LostFocus(this, null)); + }, _cancellationToken); + } + + /// + /// After manual input of the double pulse detection deadtime: + /// - This will dispatch the new value to all FM2014s. + /// + /// + /// + /// + /// - Initial. + /// + private void tbxDoublePulseDeadtime_LostFocus(Object sender, EventArgs e) + { + var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014(); + if (null == firstFm2014) + return; + + Dispatcher.Invoke(() => + { + if (string.IsNullOrEmpty(tbxDoublePulseDeadtime.Text)) + { + tbxDoublePulseDeadtime.Background = ColorProcessFailed; + btnDutToRefCalibration.IsEnabled = false; + return; + } + + // Convert the input and check limits + if (double.TryParse(tbxDoublePulseDeadtime.Text, out var deadtime) && + FM2014.DOUBLE_PULSE_DEADTIME_MIN_ms <= deadtime && + FM2014.DOUBLE_PULSE_DEADTIME_MAX_ms >= deadtime) + { + tbxDoublePulseDeadtime.Background = ColorStandardInputField; + firstFm2014.DoublePulseDeadtime_ms = deadtime; + + // Dispatch settings to all connected FM2014!!!! + foreach (var fm2014 in FM2014.RegisteredFm2014s) + { + fm2014.DoublePulseDeadtime_ms = firstFm2014.DoublePulseDeadtime_ms; + } + } + else + { + tbxDoublePulseDeadtime.Background = ColorProcessFailed; + } + }); + } + /// /// Redirect keystroke 'Enter' to leaving the cell event /// @@ -1530,15 +1953,19 @@ namespace Sensus.Ui.FM2014TestBench btnSaveRegulationSetup.IsEnabled = false; btnDutToRefRegulation.IsEnabled = false; return; - // tbxRefPulsesPerCm.Text = $@"{firstFm2014.Ref_pulse_per_cm:D}"; } //Backup the actual setting to detect changes var backupPulses_per_cm = firstFm2014.Ref_pulse_per_cm; - // Setup all FM2014s - if (int.TryParse(tbxRefPulsesPerCm.Text, out var pulses_per_cm)) + // Parse and check limits + if (int.TryParse(tbxRefPulsesPerCm.Text, out var pulses_per_cm) && + FM2014.PULSES_PER_CM_REGULATION_SETUP_MIN <= pulses_per_cm && + FM2014.REF_PULSES_PER_CM_REGULATION_INPUT_MAX >= pulses_per_cm) { + // The value is much larger than possible to be stored to the FM2014, but if it is too large + // it will be marked as invalid and on readback restored using the DUT pulses per cubic-meter + // multiplied by the firstFm2014.Ref_pulse_per_cm = (UInt32)pulses_per_cm; // Dispatch settings to all connected FM2014!!!! @@ -1559,6 +1986,10 @@ namespace Sensus.Ui.FM2014TestBench DutToRefRegulationSetupHasChanged(); } } + else + { + tbxRefPulsesPerCm.Background = ColorProcessFailed; + } }); } @@ -1576,7 +2007,7 @@ namespace Sensus.Ui.FM2014TestBench if (e.Key == Key.Enter || e.Key == Key.Tab) { tbxDutPulsesPerCm_LostFocus(this, null); - Keyboard.Focus(cbxAttenuation); + Keyboard.Focus(cbxDisplayAttenuation); } else if (!MaskEditIntegerInput(e.Key)) { @@ -1634,11 +2065,13 @@ namespace Sensus.Ui.FM2014TestBench //Backup the actual setting to detect changes var backupPulses_per_cm = firstFm2014.Dut_pulse_per_cm; - // Setup all FM2014s - if (ushort.TryParse(tbxDutPulsesPerCm.Text, out var pulses_per_cm)) + // Parse and check limits + if (int.TryParse(tbxDutPulsesPerCm.Text, out var pulses_per_cm) && + FM2014.PULSES_PER_CM_REGULATION_SETUP_MIN <= pulses_per_cm && + FM2014.PULSES_PER_CM_REGULATION_SETUP_MAX >= pulses_per_cm) { // Try to set the new calculated REF pulses limited by the property setter - firstFm2014.Dut_pulse_per_cm = pulses_per_cm; + firstFm2014.Dut_pulse_per_cm = (UInt16)pulses_per_cm; // Dispatch settings to all connected FM2014!!!! foreach (var fm2014 in FM2014.RegisteredFm2014s) @@ -1658,9 +2091,35 @@ namespace Sensus.Ui.FM2014TestBench DutToRefRegulationSetupHasChanged(); } } + else + { + tbxDutPulsesPerCm.Background = ColorProcessFailed; + } }); } + /// + /// Redirect keystroke 'Enter' to leaving the cell event + /// + /// + /// + /// + /// - Initial. + /// + private void tbxVolumeMeasuredLiters_KeyDown(Object sender, KeyEventArgs e) + { + // Catch the enter key, recalculate all settings + if (e.Key == Key.Enter || e.Key == Key.Tab) + { + tbxVolumeMeasuredLiters_LostFocus(this, null); + Keyboard.Focus(tbxDutToRefTolMax); + } + else if (!MaskEditIntegerInput(e.Key)) + { + e.Handled = true; + } + } + /// /// Changed test to cover the delete key which is not in the key-down event!? /// @@ -1669,7 +2128,7 @@ namespace Sensus.Ui.FM2014TestBench /// /// - Initial. /// - private void tbxManualInputVolumeLiters_TextChanged(Object sender, TextChangedEventArgs e) + private void tbxVolumeMeasuredLiters_TextChanged(Object sender, TextChangedEventArgs e) { // Take the new input and calculate the results after the input has been taken after this event! Task.Factory.StartNew(() => @@ -1677,31 +2136,10 @@ namespace Sensus.Ui.FM2014TestBench Thread.Sleep(1); }, _cancellationToken).ContinueWith(delegate { - Dispatcher.Invoke(() => tbxManualInputVolumeLiters_LostFocus(this, null)); + Dispatcher.Invoke(() => tbxVolumeMeasuredLiters_LostFocus(this, null)); }, _cancellationToken); } - /// - /// Redirect keystroke 'Enter' to leaving the cell event - /// - /// - /// - /// - /// - Initial. - /// - private void tbxManualInputVolumeLiters_KeyDown(Object sender, KeyEventArgs e) - { - //// Catch the enter key, recalculate all settings - //if (e.KeyCode == Keys.Enter) - //{ - // tbxManualInputVolumeLiters_Leave(this, null); - //} - //else if (!MaskEditIntegerInput(e.KeyCode)) - //{ - // e.SuppressKeyPress = true; - //} - } - /// /// After manual input of measured weight scale or reservoir in liters this will calculate the /// REF pulses per cubic meter and copy from REF pulses per cubic meter in 'Manual REF Calibration' @@ -1710,10 +2148,10 @@ namespace Sensus.Ui.FM2014TestBench /// /// /// - /// + /// /// - Initial. /// - private void tbxManualInputVolumeLiters_LostFocus(Object sender, EventArgs e) + private void tbxVolumeMeasuredLiters_LostFocus(Object sender, EventArgs e) { var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014(); if (null == firstFm2014) @@ -1722,69 +2160,233 @@ namespace Sensus.Ui.FM2014TestBench Dispatcher.Invoke(() => { - //if (string.IsNullOrEmpty(tbxRefPulsePerCm.Text)) - //{ - // tbxManualInputVolumeLiters.Text = @"0"; - //} + // If REF pulses have been acquired the volume field has to contain a value + if (!string.IsNullOrEmpty(tbxRefPulsesMeasured.Text) && + string.IsNullOrEmpty(tbxVolumeMeasured.Text)) + { + tbxVolumeMeasured.Background = ColorProcessFailed; + return; + } - // //Backup the actual setting to detect changes - // var backupPulses_per_cm = firstFm2014.Ref_pulse_per_cm; - //// Calculate REF pulses per cubic meter - //if (int.TryParse(tbxMeasuredRefPulses.Text, out var pulses) && pulses > 0 && - // int.TryParse(tbxManualInputVolumeLiters.Text, out var liters) && liters > 0) - //{ + // Backup the old value + var backup_pulses_per_cm = firstFm2014.Dut_pulse_per_cm; - // // Calculate the new pulse ratio based on the manual calibration - // var pulses_per_cm = (UInt32)(pulses / (liters / 1000.0) + 0.5); + // Calculate REF pulses per cubic meter + if (int.TryParse(tbxRefPulsesMeasured.Text, out var pulses) && pulses > 0 && + int.TryParse(tbxVolumeMeasured.Text, out var liters) && liters > 0) + { - // // Try to set the new calculated REF pulses limited by the property setter - // firstFm2014.Ref_pulse_per_cm = pulses_per_cm; + // Calculate the new pulse ratio based on the manual calibration + var pulses_per_cm = (UInt32)(pulses / (liters / 1000.0) + 0.5); - // // If this succeeded, then update the new manual calibrated value - // if (pulses_per_cm == firstFm2014.Ref_pulse_per_cm) - // { - // tbxRefCalibrationResultPulsePerCm.Text = $@"{firstFm2014.Ref_pulse_per_cm:D}"; - // tbxRefPulsePerCm.Text = $@"{firstFm2014.Ref_pulse_per_cm:D}"; - // tbxManualInputVolumeLiters.BackColor = ColorStandardInputField; - // tbxRefCalibrationResultPulsePerCm.BackColor = ColorStandardDisplayField; + // Try to set the new calculated REF pulses limited by the property setter + firstFm2014.Ref_pulse_per_cm = pulses_per_cm; - // if (!UpdateRefToDutScale()) - // { - // tbxManualInputVolumeLiters.BackColor = ColorProcessFailed; - // return; - // } + // If this succeeded, then update the new manual calibrated value + if (pulses_per_cm == firstFm2014.Ref_pulse_per_cm) + { + tbxRefPulsesPerCm.Text = $@"{firstFm2014.Ref_pulse_per_cm:D}"; + tbxVolumeMeasured.Background = ColorStandardInputField; + tbxRefPulsesPerCm.Background = ColorStandardDisplayField; - // // Check if values have changed and need to be updated in the standalone setup - // if (backupPulses_per_cm != firstFm2014.Ref_pulse_per_cm) - // { - // DutToRefRegulationSetupHasChanged(); - // } - // } - // else - // { - // tbxManualInputVolumeLiters.BackColor = ColorProcessFailed; - // tbxRefCalibrationResultPulsePerCm.BackColor = ColorProcessFailed; - // tbxRefCalibrationResultPulsePerCm.Text = Resources.StrError; - // } - //} + if (!UpdateRefToDutScale()) + { + tbxVolumeMeasured.Background = ColorProcessFailed; + return; + } + + // Check if values have changed and need to be updated in the standalone setup + if (backup_pulses_per_cm != firstFm2014.Ref_pulse_per_cm) + { + DutToRefRegulationSetupHasChanged(); + } + } + else + { + tbxVolumeMeasured.Background = ColorProcessFailed; + tbxRefPulsesPerCm.Background = ColorProcessFailed; + tbxRefPulsesPerCm.Text = Properties.Resources.StrError; + } + } }); } /// - /// Select next control on enter key pressed + /// Redirect keystroke 'Enter' to leaving the cell event /// /// /// - /// + /// /// - Initial. /// - private void cbxAttenuation_KeyDown(Object sender, KeyEventArgs e) + private void tbxDutToRefToleranceMax_KeyDown(Object sender, KeyEventArgs e) + { + // Catch the enter key and tab key as indicator for leaving the cell + if (e.Key == Key.Enter || e.Key == Key.Tab) + { + tbxDutToRefToleranceMax_LostFocus(this, null); + Keyboard.Focus(tbxDutToRefTolMin); + } + else if (!MaskEditDoubleInput(e.Key)) + { + e.Handled = true; + } + } + + /// + /// Changed test to cover the delete key which is not in the key-down event!? + /// + /// + /// + /// + /// - Initial. + /// + private void tbxDutToRefToleranceMax_TextChanged(Object sender, TextChangedEventArgs e) + { + // Take the new input and calculate the results after the input has been taken after this event! + Task.Factory.StartNew(() => + { + Thread.Sleep(1); + }, _cancellationToken).ContinueWith(delegate + { + Dispatcher.Invoke(() => tbxDutToRefToleranceMax_LostFocus(this, null)); + }, _cancellationToken); + } + + /// + /// After manual input of measured weight scale or reservoir in liters this will calculate the + /// REF pulses per cubic meter and copy from REF pulses per cubic meter in 'Manual REF Calibration' + /// to 'Regulation Setup': + /// - This will dispatch the new value to all FM2014s. + /// + /// + /// + /// + /// - Initial. + /// + private void tbxDutToRefToleranceMax_LostFocus(Object sender, EventArgs e) + { + var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014(); + if (null == firstFm2014) + return; + + Dispatcher.Invoke(() => + { + + if (string.IsNullOrEmpty(tbxDutToRefTolMax.Text)) + { + tbxDutToRefTolMax.Background = ColorProcessFailed; + return; + } + + if (double.TryParse(tbxDutToRefTolMax.Text, NumberStyles.Any, new CultureInfo("de"), out var tolerance) || + double.TryParse(tbxDutToRefTolMax.Text, NumberStyles.Any, new CultureInfo("en"), out tolerance)) + { + // Try to set the new calculated REF pulses limited by the property setter + firstFm2014.DutToRefCalibrationToleranceMax_percent = tolerance; + tbxDutToRefTolMax.Background = ColorStandardInputField; + + // Dispatch settings to all connected FM2014!!!! + foreach (var fm2014 in FM2014.RegisteredFm2014s) + { + fm2014.DutToRefCalibrationToleranceMax_percent = tolerance; + } + } + else + { + tbxDutToRefTolMax.Background = ColorProcessFailed; + } + + + }); + } + + /// + /// Redirect keystroke 'Enter' to leaving the cell event + /// + /// + /// + /// + /// - Initial. + /// + private void tbxDutToRefToleranceMin_KeyDown(Object sender, KeyEventArgs e) { // Catch the enter key, recalculate all settings if (e.Key == Key.Enter || e.Key == Key.Tab) { - Keyboard.Focus(btnSaveRegulationSetup); + tbxDutToRefToleranceMin_LostFocus(this, null); + Keyboard.Focus(btnRefToVolumeCalibration); } + else if (!MaskEditDoubleInput(e.Key)) + { + e.Handled = true; + } + } + + /// + /// Changed test to cover the delete key which is not in the key-down event!? + /// + /// + /// + /// + /// - Initial. + /// + private void tbxDutToRefToleranceMin_TextChanged(Object sender, TextChangedEventArgs e) + { + // Take the new input and calculate the results after the input has been taken after this event! + Task.Factory.StartNew(() => + { + Thread.Sleep(1); + }, _cancellationToken).ContinueWith(delegate + { + Dispatcher.Invoke(() => tbxDutToRefToleranceMin_LostFocus(this, null)); + }, _cancellationToken); + } + + /// + /// After manual input of measured weight scale or reservoir in liters this will calculate the + /// REF pulses per cubic meter and copy from REF pulses per cubic meter in 'Manual REF Calibration' + /// to 'Regulation Setup': + /// - This will dispatch the new value to all FM2014s. + /// + /// + /// + /// + /// - Initial. + /// + private void tbxDutToRefToleranceMin_LostFocus(Object sender, EventArgs e) + { + var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014(); + if (null == firstFm2014) + return; + + Dispatcher.Invoke(() => + { + + if (string.IsNullOrEmpty(tbxDutToRefTolMin.Text)) + { + tbxDutToRefTolMin.Background = ColorProcessFailed; + return; + } + + if (double.TryParse(tbxDutToRefTolMin.Text, NumberStyles.Any, new CultureInfo("en"), out var tolerance) || + double.TryParse(tbxDutToRefTolMin.Text, NumberStyles.Any, new CultureInfo("de"), out tolerance)) + { + // Try to set the new calculated REF pulses limited by the property setter + firstFm2014.DutToRefCalibrationToleranceMin_percent = tolerance; + tbxDutToRefTolMin.Background = ColorStandardInputField; + + // Dispatch settings to all connected FM2014!!!! + foreach (var fm2014 in FM2014.RegisteredFm2014s) + { + fm2014.DutToRefCalibrationToleranceMin_percent = tolerance; + } + } + else + { + tbxDutToRefTolMax.Background = ColorProcessFailed; + } + }); } private void chkAnySlot_Click(Object sender, RoutedEventArgs e) diff --git a/FM2014TestApp/Ui/Fm2014sTest/Properties/Resources.Designer.cs b/FM2014TestApp/Ui/Fm2014sTest/Properties/Resources.Designer.cs index c185a573..6d931157 100644 --- a/FM2014TestApp/Ui/Fm2014sTest/Properties/Resources.Designer.cs +++ b/FM2014TestApp/Ui/Fm2014sTest/Properties/Resources.Designer.cs @@ -114,6 +114,15 @@ namespace Sensus.Ui.Fm2014TestBench.Properties { } } + /// + /// Looks up a localized string similar to Use Settings. + /// + internal static string StrBtnTakeCalibrationSetup { + get { + return ResourceManager.GetString("StrBtnTakeCalibrationSetup", resourceCulture); + } + } + /// /// Looks up a localized string similar to Damped Tolerance On. /// @@ -213,15 +222,6 @@ namespace Sensus.Ui.Fm2014TestBench.Properties { } } - /// - /// Looks up a localized string similar to Attenuation []:. - /// - internal static string StrLblAttenuation { - get { - return ResourceManager.GetString("StrLblAttenuation", resourceCulture); - } - } - /// /// Looks up a localized string similar to Serial Port:. /// @@ -231,6 +231,15 @@ namespace Sensus.Ui.Fm2014TestBench.Properties { } } + /// + /// Looks up a localized string similar to Display Attenuation []:. + /// + internal static string StrLblDisplayAttenuation { + get { + return ResourceManager.GetString("StrLblDisplayAttenuation", resourceCulture); + } + } + /// /// Looks up a localized string similar to Double Pulses Deadtime:. /// @@ -240,6 +249,51 @@ namespace Sensus.Ui.Fm2014TestBench.Properties { } } + /// + /// Looks up a localized string similar to DUT Captured Pulses: . + /// + internal static string StrLblDutPulsesMeasured { + get { + return ResourceManager.GetString("StrLblDutPulsesMeasured", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DUT Pulse Ratio [pulses/m³]:. + /// + internal static string StrLblDutPulsesPerCmRatio { + get { + return ResourceManager.GetString("StrLblDutPulsesPerCmRatio", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DUT Remaining Pulses:. + /// + internal static string StrLblDutPulsesRemaining { + get { + return ResourceManager.GetString("StrLblDutPulsesRemaining", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DUT Required Pulses:. + /// + internal static string StrLblDutPulsesRequired { + get { + return ResourceManager.GetString("StrLblDutPulsesRequired", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DUT Measured Time [s]:. + /// + internal static string StrLblDutTimeMeasured { + get { + return ResourceManager.GetString("StrLblDutTimeMeasured", resourceCulture); + } + } + /// /// Looks up a localized string similar to DUT/REF Tolerance max [%]:. /// @@ -249,6 +303,15 @@ namespace Sensus.Ui.Fm2014TestBench.Properties { } } + /// + /// Looks up a localized string similar to DUT/REF Tolerance [%]:. + /// + internal static string StrLblDutToRefToleranceMeasured { + get { + return ResourceManager.GetString("StrLblDutToRefToleranceMeasured", resourceCulture); + } + } + /// /// Looks up a localized string similar to DUT/REF Tolerance min [%]:. /// @@ -258,6 +321,15 @@ namespace Sensus.Ui.Fm2014TestBench.Properties { } } + /// + /// Looks up a localized string similar to Flow Rate [m³/h]:. + /// + internal static string StrLblFlowRateMeasured { + get { + return ResourceManager.GetString("StrLblFlowRateMeasured", resourceCulture); + } + } + /// /// Looks up a localized string similar to Address:. /// @@ -330,69 +402,6 @@ namespace Sensus.Ui.Fm2014TestBench.Properties { } } - /// - /// Looks up a localized string similar to DUT Captured Pulses: . - /// - internal static string StrLblMeasuredDutPulses { - get { - return ResourceManager.GetString("StrLblMeasuredDutPulses", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to DUT Measured Time [s]:. - /// - internal static string StrLblMeasuredDutTime { - get { - return ResourceManager.GetString("StrLblMeasuredDutTime", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to DUT/REF Tolerance [%]:. - /// - internal static string StrLblMeasuredDutToRefTolerance { - get { - return ResourceManager.GetString("StrLblMeasuredDutToRefTolerance", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Flow Rate [m³/h]:. - /// - internal static string StrLblMeasuredFlowRate { - get { - return ResourceManager.GetString("StrLblMeasuredFlowRate", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to REF Captured Pulses:. - /// - internal static string StrLblMeasuredRefPulses { - get { - return ResourceManager.GetString("StrLblMeasuredRefPulses", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to REF Measured Time [s]:. - /// - internal static string StrLblMeasuredRefTime { - get { - return ResourceManager.GetString("StrLblMeasuredRefTime", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Volume [liters]:. - /// - internal static string StrLblMeasuredVolume { - get { - return ResourceManager.GetString("StrLblMeasuredVolume", resourceCulture); - } - } - /// /// Looks up a localized string similar to _Options. /// @@ -438,24 +447,6 @@ namespace Sensus.Ui.Fm2014TestBench.Properties { } } - /// - /// Looks up a localized string similar to DUT Pulse Ratio [pulses/m³]:. - /// - internal static string StrLblRatioDutPulsesPerCm { - get { - return ResourceManager.GetString("StrLblRatioDutPulsesPerCm", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to REF Pulse Ratio [pulses/m³]:. - /// - internal static string StrLblRatioRefPulsesPerCm { - get { - return ResourceManager.GetString("StrLblRatioRefPulsesPerCm", resourceCulture); - } - } - /// /// Looks up a localized string similar to REF Frequency [Hz]:. /// @@ -466,47 +457,56 @@ namespace Sensus.Ui.Fm2014TestBench.Properties { } /// - /// Looks up a localized string similar to DUT Remaining Pulses:. + /// Looks up a localized string similar to REF Captured Pulses:. /// - internal static string StrLblRemainingDutPulses { + internal static string StrLblRefPulsesMeasured { get { - return ResourceManager.GetString("StrLblRemainingDutPulses", resourceCulture); + return ResourceManager.GetString("StrLblRefPulsesMeasured", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to REF Pulse Ratio [pulses/m³]:. + /// + internal static string StrLblRefPulsesPerCmRatio { + get { + return ResourceManager.GetString("StrLblRefPulsesPerCmRatio", resourceCulture); } } /// /// Looks up a localized string similar to REF Remaining Pulses:. /// - internal static string StrLblRemainingRefPulses { + internal static string StrLblRefPulsesRemaining { get { - return ResourceManager.GetString("StrLblRemainingRefPulses", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to DUT Required Pulses:. - /// - internal static string StrLblRequiredDutPulses { - get { - return ResourceManager.GetString("StrLblRequiredDutPulses", resourceCulture); + return ResourceManager.GetString("StrLblRefPulsesRemaining", resourceCulture); } } /// /// Looks up a localized string similar to REF Required Pulses:. /// - internal static string StrLblRequiredRefPulses { + internal static string StrLblRefPulsesRequired { get { - return ResourceManager.GetString("StrLblRequiredRefPulses", resourceCulture); + return ResourceManager.GetString("StrLblRefPulsesRequired", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to REF Measured Time [s]:. + /// + internal static string StrLblRefTimeMeasured { + get { + return ResourceManager.GetString("StrLblRefTimeMeasured", resourceCulture); } } /// /// Looks up a localized string similar to REF/DUT Ratio [norm]:. /// - internal static string StrLblScaleRefToDut { + internal static string StrLblRefToDutScale { get { - return ResourceManager.GetString("StrLblScaleRefToDut", resourceCulture); + return ResourceManager.GetString("StrLblRefToDutScale", resourceCulture); } } @@ -528,6 +528,15 @@ namespace Sensus.Ui.Fm2014TestBench.Properties { } } + /// + /// Looks up a localized string similar to Volume [liters]:. + /// + internal static string StrLblVolumeMeasured { + get { + return ResourceManager.GetString("StrLblVolumeMeasured", resourceCulture); + } + } + /// /// Looks up a localized string similar to WAITING FOR FM2014 RESPONSE. /// diff --git a/FM2014TestApp/Ui/Fm2014sTest/Properties/Resources.de.resx b/FM2014TestApp/Ui/Fm2014sTest/Properties/Resources.de.resx index ad66980b..07057e34 100644 --- a/FM2014TestApp/Ui/Fm2014sTest/Properties/Resources.de.resx +++ b/FM2014TestApp/Ui/Fm2014sTest/Properties/Resources.de.resx @@ -168,20 +168,20 @@ ONLINE - + REF Pulsratio [Pulse/m³]: Regulierungseinstellungen - + DUT Pulsratio [Pulse/m³]: - + REF/DUT Ratio [norm]: - - Dämpfung []: + + Anzeigestabilisierung []: Speichern @@ -189,19 +189,19 @@ REF zu Volumen Kalibrierung - + REF Erfaßte Imulse: - + Volumen [Liter]: DUT zu REF Regulierung - + Durchfluß [m³/h]: - + DUT/REF Toleranz [%]: @@ -222,7 +222,7 @@ REF Frequenz [Hz]: - + DUT Erfaßte Impulse: @@ -252,26 +252,26 @@ Einbauplatz: - + REF Erfordeliche Pulse: - + REF Verbleibende Pulse: - + DUT Erforderliche Pulse: - + DUT Verbleibende Pulse: - + REF Gemessene Zeit [s]: - + DUT Gemessene Zeit [s]: - Doppelimpulstotozeit: + Doppelimpulstotzeit: DUT/REF Toleranz min [%]: @@ -282,4 +282,7 @@ Gesamtprozeß: + + Anwenden + \ No newline at end of file diff --git a/FM2014TestApp/Ui/Fm2014sTest/Properties/Resources.resx b/FM2014TestApp/Ui/Fm2014sTest/Properties/Resources.resx index 405e226b..9fac0b3a 100644 --- a/FM2014TestApp/Ui/Fm2014sTest/Properties/Resources.resx +++ b/FM2014TestApp/Ui/Fm2014sTest/Properties/Resources.resx @@ -168,20 +168,20 @@ ONLINE - + REF Pulse Ratio [pulses/m³]: Regulation Setup - + DUT Pulse Ratio [pulses/m³]: - + REF/DUT Ratio [norm]: - - Attenuation []: + + Display Attenuation []: Save @@ -189,19 +189,19 @@ REF to Volume Calibration - + REF Captured Pulses: - + Volume [liters]: DUT to REF Regulation - + Flow Rate [m³/h]: - + DUT/REF Tolerance [%]: @@ -222,7 +222,7 @@ REF Frequency [Hz]: - + DUT Captured Pulses: @@ -252,22 +252,22 @@ Slot Selection: - + REF Required Pulses: - + REF Remaining Pulses: - + DUT Required Pulses: - + DUT Remaining Pulses: - + REF Measured Time [s]: - + DUT Measured Time [s]: @@ -282,4 +282,7 @@ Overall Process: + + Use Settings + \ No newline at end of file diff --git a/FM2014TestApp/Ui/Fm2014sTest/UserControls/UcFM2014Device.xaml.cs b/FM2014TestApp/Ui/Fm2014sTest/UserControls/UcFM2014Device.xaml.cs index 1b1cf583..5e7807d4 100644 --- a/FM2014TestApp/Ui/Fm2014sTest/UserControls/UcFM2014Device.xaml.cs +++ b/FM2014TestApp/Ui/Fm2014sTest/UserControls/UcFM2014Device.xaml.cs @@ -143,11 +143,17 @@ namespace Sensus.Ui.Fm2014TestBench.UserControls /// /// 0 = Off, 1..7 measurements active /// - /// + /// /// - Initial. /// public Boolean EnableMeasurements(UInt32 numberOfMeasurementFields) { + // Rest all labels to 0 + for (var idx = 0; idx < MeasurementLabels.Count; idx++) + { + SetValue(idx, "0", ColorStandardDisplayField); + } + // Check if device is connected and logged in if (!lblStatus.Content.Equals(GetConnectionStatusInfo(ConnectionStatusName.ONLINE))) return false; @@ -158,7 +164,6 @@ namespace Sensus.Ui.Fm2014TestBench.UserControls return true; } - //MeasurementIsActive = true; // Hide the picture and the border of it UiElmEnable(picFM2014, false, false); UiElmEnable(brdFM2014Pic, false, false);