diff --git a/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/Consts/FM2014CmdDef.cs b/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/Consts/FM2014CmdDef.cs
index 5efacd9b..2443c152 100644
--- a/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/Consts/FM2014CmdDef.cs
+++ b/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/Consts/FM2014CmdDef.cs
@@ -277,7 +277,13 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core.Co
///
/// Broadcast command without answer to address 0 or individual without answer
///
- BROADCAST
+ BROADCAST,
+
+ ///
+ /// Uninitialized addressing command type
+ ///
+ NOT_INITIALIZED,
+
}
///
@@ -363,7 +369,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core.Co
///
/// Broadcast address definition
///
- public static readonly String BROADCAST_ADDRESS = $"{ADDR_RECORD_STR}{ADDR_RECORD_STR}0{ADDR_VALIDATION_STR}";
+ public static readonly String BROADCAST_ADDRESS = $"{ADDR_RECORD_STR}0{ADDR_VALIDATION_STR}";
// Unicode Strings for command table
private const String UNICODE_ACK = "\u0006";
diff --git a/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/FM2014.cs b/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/FM2014.cs
index c2b7cb67..a99f2d95 100644
--- a/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/FM2014.cs
+++ b/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/FM2014.cs
@@ -61,9 +61,9 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
#region properties
///
- /// Resolution of FM2014 timer for measurement of pulse width in seconds
+ /// Resolution of FM2014 timer for measurement of pulse width in seconds based on 2994 Hz
///
- public const Single TMR_RESOLUTION_s = 334e-6f;
+ private const Double TMR_RESOLUTION_s = 334.001336e-6;
///
public Boolean CyclicReceiveTaskLoopIsActive
@@ -109,14 +109,14 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
set
{
_address = value;
- AddressStr = $"{ADDR_RECORD_STR}{ADDR_RECORD_STR}{_address}{ADDR_VALIDATION_STR}";
+ AddressStr = $"{ADDR_RECORD_STR}{_address}{ADDR_VALIDATION_STR}";
}
}
///
/// Marker if broadcast connection was last communication
///
- private Boolean BroadcastCommIsActive
+ private CmdType CmdType
{
get;
set;
@@ -168,68 +168,85 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
///
/// Publish the FM2014 minimum pulses for REF and DUT time measurement.
///
- public const UInt16 TimeMeasurementPulsesSetupMin = 1;
+ public const UInt32 TimeMeasurementPulsesSetupMin = 1;
///
/// Publish the FM2014 maximum pulses for REF and DUT time measurement.
///
- public const UInt16 TimeMeasurementPulsesSetupMax = 0xFFFF;
+ public const UInt32 TimeMeasurementPulsesSetupMax = 0xFFFF;
///
- /// Publish the FM2014 minimum pulses for REF and DUT regulation measurement.
+ /// This is the invalid marker which can be stored to the FM2014 with command
+ /// 'W' - 'REF pulses per volume'! The REF pulses/cm can then be restored using
+ /// 'Ref_pulses_per_cm = Dut_pulses_per_cm * RefToDutScale_norm'
///
- public const UInt16 PulsesPerCmRegulationSetupMin = 1;
- ///
- /// Publish the FM2014 maximum pulses for REF and DUT regulation measurement.
- ///
- public const UInt16 PulsesPerCmRegulationSetupMax = 9999;
+ private const UInt32 RefPulsesPerVolumeRegulationSetupInvalidMarker = 1;
- private UInt16 _ref_pulse_per_cm = 1000;
+ ///
+ /// This is the minimum value which can be stored to the FM2014 with commands
+ /// 'V' - 'DUT pulses per volume' and 'W' - 'REF pulses per volume'!
+ ///
+ private const UInt32 PulsesPerVolumeRegulationSetupMin = 1;
+
+ ///
+ /// This is the maximum value which can be stored to the FM2014 with command
+ /// 'V' - 'DUT pulses per volume'!
+ ///
+ private const UInt32 PulsesPerVolumeRegulationSetupMax = 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 RefPulsesPerCmRegulationInputLimitMax = 100000000;
+
+ private UInt32 _ref_pulse_per_cm;
///
- public UInt16 Ref_pulse_per_cm
+ public UInt32 Ref_pulse_per_cm
{
get => _ref_pulse_per_cm;
set
{
// Check limits and equality
- if (value < PulsesPerCmRegulationSetupMin ||
- value > PulsesPerCmRegulationSetupMax ||
+ if (value < PulsesPerVolumeRegulationSetupMin ||
+ value > RefPulsesPerCmRegulationInputLimitMax ||
value == _ref_pulse_per_cm)
return;
_ref_pulse_per_cm = value;
- if (_dut_pulse_per_cm != 0)
- RefToDutScale_norm = (Single)_ref_pulse_per_cm / _dut_pulse_per_cm;
+ if (_dut_pulse_per_cm != 0 && _ref_pulse_per_cm != 0)
+ RefToDutScale_norm = Math.Round((Double)_ref_pulse_per_cm / _dut_pulse_per_cm, 2);
}
}
- private UInt16 _dut_pulse_per_cm = 100;
+ private UInt32 _dut_pulse_per_cm;
///
- public UInt16 Dut_pulse_per_cm
+ public UInt32 Dut_pulse_per_cm
{
get => _dut_pulse_per_cm;
set
{
- // Check limits and equality
- if (value < PulsesPerCmRegulationSetupMin ||
- value > PulsesPerCmRegulationSetupMax ||
+ // Check limits and equality, the DUT max input is 9999 as this will be
+ // directly stored to FM2014'V' - 'DUT pulses per volume'
+ if (value < PulsesPerVolumeRegulationSetupMin ||
+ value > PulsesPerVolumeRegulationSetupMax ||
value == _dut_pulse_per_cm)
return;
_dut_pulse_per_cm = value;
- if (_dut_pulse_per_cm != 0)
- RefToDutScale_norm = (Single)_ref_pulse_per_cm / _dut_pulse_per_cm;
+ if (_dut_pulse_per_cm != 0 && _ref_pulse_per_cm != 0)
+ RefToDutScale_norm = Math.Round((Double)_ref_pulse_per_cm / _dut_pulse_per_cm, 2);
}
}
///
/// Publish the FM2014 minimum REF to DUT scale for error display.
///
- public const Single RefToDutScaleMin = 0.0001f;
+ public const Double RefToDutScaleMin = 0.0001;
///
/// Publish the FM2014 maximum REF to DUT scale for error display.
///
- public const Single RefToDutScaleMax = 999.9f;
+ public const Double RefToDutScaleMax = 999.9;
///
/// As the scale needed to be sent to the FM2014 doesn't follow the standardized nomenclature
@@ -245,11 +262,14 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// "1000K3" = 100.0
/// Max value is "9999K3" = 999.9
///
- public String RefToDutScaleStr = "1000K+2";
- private Single _refToDutScale_norm = 10.0f;
+ private String _refToDutScaleStr = "1000K+2";
+ private Double _refToDutScale_norm = 10.0f;
///
- public Single RefToDutScale_norm
+ ///
+ /// - Initial.
+ ///
+ public Double RefToDutScale_norm
{
get => _refToDutScale_norm;
private set
@@ -267,7 +287,9 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
}
var mantissa = (UInt16)number;
- RefToDutScaleStr = $"{mantissa}{GetCmdStr(CmdName.CMD_REF_SET_SCALE)}{exponent}";
+
+ // The pre-generated string will be used to send it to the FM2014 directly
+ _refToDutScaleStr = $"{mantissa}{GetCmdStr(CmdName.CMD_REF_SET_SCALE)}{exponent}";
}
}
@@ -288,7 +310,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
///
/// The measured flow rate in cubic meters per hour using the REF
///
- public Single RefFlowRate_cm_per_h
+ public Double RefFlowRate_cm_per_h
{
internal set;
get;
@@ -375,6 +397,10 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
SerialPort.PortName = comPort;
SerialPort.ReadTimeout = 1000;
SerialPort.WriteTimeout = 1000;
+ // Reset pulse ratios to force a preset with 'standalone' settings from
+ // FM2014 wit '%D@' - Read 'Default Measurement Setup'
+ _ref_pulse_per_cm = 0;
+ _dut_pulse_per_cm = 0;
return true;
}
@@ -516,12 +542,13 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// - Set to false.
///
///
- ///
+ ///
/// - Initial.
///
public Boolean RegulationMeasurement()
{
- if (Ref_pulse_per_cm == 0 || Dut_pulse_per_cm == 0 || RefToDutScale_norm == 0.0f)
+ if (Ref_pulse_per_cm == 0 || Dut_pulse_per_cm == 0 ||
+ RefToDutScale_norm < RefToDutScaleMin || RefToDutScale_norm > RefToDutScaleMax)
{
return false;
}
@@ -543,7 +570,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
return false;
}
cmdName = CmdName.CMD_REF_SET_SCALE;
- if (!Write(cmdName, RefToDutScaleStr))
+ if (!Write(cmdName, _refToDutScaleStr))
{
return false;
}
@@ -598,7 +625,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
// Publish the period [ms]
var response = new CmdResponse(cmdName, info,
- doubleValue: TMR_RESOLUTION_s * 1000.0f * period,
+ doubleValue: TMR_RESOLUTION_s * 1000.0 * period,
siUnit: "m" + SiUnits.GetInfo(SiUnits.SiUnitName.TIME));
OnRawRecordReceived?.Invoke(this,
new ProcessExecEventArgs("", actualProcessMessage: measurementInfo,
@@ -608,14 +635,14 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
cmdName = CmdName.CMD_CAL_FREQU_REF_PERIOD;
info = GetCmdInfo(cmdName);
response = new CmdResponse(cmdName, info,
- doubleValue: 1.0f / (TMR_RESOLUTION_s * period),
+ doubleValue: 1.0 / (TMR_RESOLUTION_s * period),
siUnit: SiUnits.GetInfo(SiUnits.SiUnitName.FREQUENCY));
OnRawRecordReceived?.Invoke(this,
new ProcessExecEventArgs("", actualProcessMessage: measurementInfo,
specificInfoObj: response));
// Convert to m³/h (3600 s/h) based on REF pulse rate
- var flowRate_cm_per_h = 3600.0f / (period * TMR_RESOLUTION_s) / Ref_pulse_per_cm;
+ var flowRate_cm_per_h = 3600.0 / (period * TMR_RESOLUTION_s) / Ref_pulse_per_cm;
// Publish the calculated flow rate [m³/h]
cmdName = CmdName.CMD_CAL_FLOW_REF_PERIOD;
info = GetCmdInfo(cmdName);
@@ -638,7 +665,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
// Publish the period [ms]
var response = new CmdResponse(cmdName, info,
- doubleValue: TMR_RESOLUTION_s * 1000.0f * period,
+ doubleValue: TMR_RESOLUTION_s * 1000.0 * period,
siUnit: "m" + SiUnits.GetInfo(SiUnits.SiUnitName.TIME));
OnRawRecordReceived?.Invoke(this,
new ProcessExecEventArgs("", actualProcessMessage: measurementInfo,
@@ -648,14 +675,14 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
cmdName = CmdName.CMD_CAL_FREQU_DUT_PERIOD;
info = GetCmdInfo(cmdName);
response = new CmdResponse(cmdName, info,
- doubleValue: 1.0f / (TMR_RESOLUTION_s * period),
+ doubleValue: 1.0 / (TMR_RESOLUTION_s * period),
siUnit: SiUnits.GetInfo(SiUnits.SiUnitName.FREQUENCY));
OnRawRecordReceived?.Invoke(this,
new ProcessExecEventArgs("", actualProcessMessage: measurementInfo,
specificInfoObj: response));
// Convert to m³/h (3600 s/h) based on DUT pulse rate
- var flowRate_cm_per_h = 3600.0f / (period * TMR_RESOLUTION_s) / Dut_pulse_per_cm;
+ var flowRate_cm_per_h = 3600.0 / (period * TMR_RESOLUTION_s) / Dut_pulse_per_cm;
// Publish the calculated flow rate [m³/h]
cmdName = CmdName.CMD_CAL_FLOW_DUT_PERIOD;
info = GetCmdInfo(cmdName);
@@ -683,7 +710,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
specificInfoObj: response));
// Convert to m³/h (3600 s/h) and save the value
- RefFlowRate_cm_per_h = 3600.0f * refFrequency / Ref_pulse_per_cm;
+ RefFlowRate_cm_per_h = 3600.0 * refFrequency / Ref_pulse_per_cm;
// Publish the calculated flow rate [m³/h]
cmdName = CmdName.CMD_CAL_FLOW_REF_FREQU;
info = GetCmdInfo(cmdName);
@@ -716,24 +743,34 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// Transfer all standalone settings to FM2014 RAM and safe those to nonvolatile EEPROM
///
///
+ ///
+ /// - Initial.
+ ///
+ ///
+ /// - REF pulse rate can be 0 as 'invalid marker'.
+ ///
public Boolean SaveStandAloneMeasurement()
{
var cmdName = CmdName.CMD_REF_LPP_SCALE;
try
{
- var retVal = Write(cmdName, Ref_pulse_per_cm);
+ // Set to zero if it doesn't fit to the limit which can be stored as indicator for invalid value
+ // which should be recovered by 'Ref_pulses_per_cm = Dut_pulses_per_cm * RefToDutScale_norm'
+ var limitedRefPulsesPerCm = Ref_pulse_per_cm <= PulsesPerVolumeRegulationSetupMax ?
+ Ref_pulse_per_cm : RefPulsesPerVolumeRegulationSetupInvalidMarker;
+ var retVal = Write(cmdName, (UInt16)limitedRefPulsesPerCm);
if (retVal)
{
cmdName = CmdName.CMD_DUT_LPP_SCALE;
- retVal = Write(cmdName, Dut_pulse_per_cm);
+ retVal = Write(cmdName, (UInt16)Dut_pulse_per_cm);
}
if (retVal)
{
cmdName = CmdName.CMD_REF_SET_SCALE;
- // During setup of the 'Ref_pulse_per_cm' the 'RefToDutScaleStr' will be generated
- retVal = Write(cmdName, RefToDutScaleStr);
+ // During setup of the 'Ref_pulse_per_cm' the '_refToDutScaleStr' will be generated
+ retVal = Write(cmdName, _refToDutScaleStr);
}
if (retVal)
@@ -768,6 +805,11 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
///
/// - Initial.
///
+ ///
+ /// - 'Ref_pulse_per_cm' will be calculated by 'Ref_pulses_per_cm = Dut_pulses_per_cm * RefToDutScale_norm'
+ /// to avoid an overflow as the REF pulses per volume can store max 9999 pulses. As the Dut_pulse_per_cm
+ /// is for the smallest meter 1000 Impulses/m³
+ ///
private Boolean ReadAloneMeasurementControl(CmdName cmdName)
{
// Allow explicit standalone measurement commands
@@ -834,36 +876,46 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
cmdName = CmdName.CMD_REF_SET_SCALE;
var info = GetCmdInfo(cmdName);
- RefToDutScale_norm = (Single)value;
+ RefToDutScale_norm = value;
var response = new CmdResponse(cmdName, info, doubleValue: RefToDutScale_norm);
OnRawRecordReceived?.Invoke(this,
new ProcessExecEventArgs("", actualProcessMessage: measurementInfoStr,
specificInfoObj: response));
}
}
- if (str.Contains(StandAlonePartSearchRefPpvStr))
- {
- var strCleaned = Regex.Replace(str, "[^0-9]", string.Empty);
- if (ushort.TryParse(strCleaned, out var value))
- {
- cmdName = CmdName.CMD_REF_LPP_SCALE;
- var info = GetCmdInfo(cmdName);
- Ref_pulse_per_cm = value;
- var response = new CmdResponse(cmdName, info, Ref_pulse_per_cm);
- OnRawRecordReceived?.Invoke(this,
- new ProcessExecEventArgs("", actualProcessMessage: measurementInfoStr,
- specificInfoObj: response));
- }
- }
+ // REMOVED 2026-Jan-21
+ //if (str.Contains(StandAlonePartSearchRefPpvStr))
+ //{
+ // var strCleaned = Regex.Replace(str, "[^0-9]", string.Empty);
+ // if (ushort.TryParse(strCleaned, out var value))
+ // {
+ // cmdName = CmdName.CMD_REF_LPP_SCALE;
+ // var info = GetCmdInfo(cmdName);
+ // Ref_pulse_per_cm = value;
+ // var response = new CmdResponse(cmdName, info, Ref_pulse_per_cm);
+ // OnRawRecordReceived?.Invoke(this,
+ // new ProcessExecEventArgs("", actualProcessMessage: measurementInfoStr,
+ // specificInfoObj: response));
+ // }
+ //}
if (str.Contains(StandAlonePartSearchDutPpvStr))
{
var strCleaned = Regex.Replace(str, "[^0-9]", string.Empty);
- if (ushort.TryParse(strCleaned, out var value))
+ if (uint.TryParse(strCleaned, out var value))
{
cmdName = CmdName.CMD_DUT_LPP_SCALE;
var info = GetCmdInfo(cmdName);
Dut_pulse_per_cm = value;
- var response = new CmdResponse(cmdName, info, Dut_pulse_per_cm);
+ var response = new CmdResponse(cmdName, info, (Int32)Dut_pulse_per_cm);
+ OnRawRecordReceived?.Invoke(this,
+ new ProcessExecEventArgs("", actualProcessMessage: measurementInfoStr,
+ specificInfoObj: response));
+ // Added 2026-Jan-01 to overcome limitation of max 9999 Impulses per volume
+ cmdName = CmdName.CMD_REF_LPP_SCALE;
+ info = GetCmdInfo(cmdName);
+ // Calculate REF pulses per cubic meter
+ Ref_pulse_per_cm = (UInt32)Math.Round(Dut_pulse_per_cm * RefToDutScale_norm, 2);
+ response = new CmdResponse(cmdName, info, (Int32)Ref_pulse_per_cm);
OnRawRecordReceived?.Invoke(this,
new ProcessExecEventArgs("", actualProcessMessage: measurementInfoStr,
specificInfoObj: response));
@@ -881,8 +933,8 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
}
return true;
-
}
+
///
/// Login to individual address.
///
@@ -947,7 +999,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
OnRawRecordReceived?.Invoke(this, new ProcessExecEventArgs(Resources.StrError,
specificInfoObj: response,
statusReturn: StatusReturn.Failed));
- BroadcastCommIsActive = false;
+ CmdType = CmdType.NOT_INITIALIZED;
return false;
}
@@ -961,13 +1013,13 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
OnRawRecordReceived?.Invoke(this, new ProcessExecEventArgs(Resources.StrError,
specificInfoObj: response,
statusReturn: StatusReturn.Failed));
- BroadcastCommIsActive = false;
+ CmdType = CmdType.NOT_INITIALIZED;
return false;
}
}
// If broadcast communication is already active
- if (BroadcastCommIsActive)
+ if (CmdType == CmdType.BROADCAST)
{
return true;
}
@@ -981,7 +1033,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
var info = GetCmdInfo(cmdName) + ": " + BROADCAST_ADDRESS;
var response = new CmdResponse(cmdName, info);
OnRawRecordReceived?.Invoke(this, new ProcessExecEventArgs("", specificInfoObj: response));
- BroadcastCommIsActive = true;
+ CmdType = CmdType.BROADCAST;
return true;
}
catch (Exception e)
@@ -990,7 +1042,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
$"{Resources.StrCmdRespErrorBroadcast} - {e.Message}");
OnRawRecordReceived?.Invoke(this, new ProcessExecEventArgs(Resources.StrError, specificInfoObj: response,
statusReturn: StatusReturn.Failed));
- BroadcastCommIsActive = false;
+ CmdType = CmdType.NOT_INITIALIZED;
return false;
}
}
@@ -999,7 +1051,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// Initiate communication to individual node
///
///
- ///
+ ///
/// - Initial.
///
private Boolean InitiateIndividualComm()
@@ -1011,6 +1063,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
OnRawRecordReceived?.Invoke(this, new ProcessExecEventArgs(Resources.StrError,
specificInfoObj: response,
statusReturn: StatusReturn.Failed));
+ CmdType = CmdType.NOT_INITIALIZED;
return false;
}
@@ -1023,6 +1076,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
OnRawRecordReceived?.Invoke(this, new ProcessExecEventArgs(Resources.StrError,
specificInfoObj: response,
statusReturn: StatusReturn.Failed));
+ CmdType = CmdType.NOT_INITIALIZED;
return false;
}
}
@@ -1044,7 +1098,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
FullId = FullId.Replace(ADDR_RECORD_STR, "");
var fields = FullId.Split('.');
FwVersion = fields[1];
- BroadcastCommIsActive = false;
+ CmdType = GetCmdCmdType(cmdName);
return true;
}
}
@@ -1053,12 +1107,14 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
response = new CmdResponse(CmdName.CMD_CONNECT, $"{Resources.StrCmdRespErrorIndividual} - {e.Message}");
OnRawRecordReceived?.Invoke(this, new ProcessExecEventArgs(Resources.StrError,
specificInfoObj: response, statusReturn: StatusReturn.Failed));
+ CmdType = CmdType.NOT_INITIALIZED;
return false;
}
response = new CmdResponse(CmdName.CMD_CONNECT, $"{Resources.StrCmdRespErrorIndividual}");
OnRawRecordReceived?.Invoke(this, new ProcessExecEventArgs(Resources.StrError,
specificInfoObj: response, statusReturn: StatusReturn.Failed));
+ CmdType = CmdType.NOT_INITIALIZED;
return false;
}
@@ -1080,7 +1136,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
if (SerialPort == null || !SerialPort.IsOpen)
{
- BroadcastCommIsActive = false;
+ CmdType = CmdType.NOT_INITIALIZED;
IsLoggedOn = false;
CyclicReceiveTaskLoopIsActive = false;
return false;
@@ -1090,14 +1146,14 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
var retVal = true;
if (CmdType.BROADCAST == GetCmdCmdType(cmdName))
{
- if (!BroadcastCommIsActive)
+ if (CmdType != CmdType.BROADCAST)
{
retVal = InitiateBroadcastComm();
}
}
else
{
- if (BroadcastCommIsActive)
+ if (CmdType != CmdType.INDIVIDUAL_WA || CmdType != CmdType.INDIVIDUAL_WA)
{
retVal = InitiateIndividualComm();
}
@@ -1110,7 +1166,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
var cmdCodeStr = GetCmdStr(cmdName);
var info = GetCmdInfo(cmdName);
- var response = new CmdResponse();
+ CmdResponse response;
// Without data the command alone needs to be sent
if (dataObj == null)
{
@@ -1130,12 +1186,16 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
}
// The data contains the preceding setup, the command code and string delimiter will be added here
- if (dataObj is UInt16 || dataObj is Byte)
+ else if (dataObj is UInt16 || dataObj is Byte)
{
SerialPort.Write($"{dataObj}{cmdCodeStr}{END_OF_STR}");
response = new CmdResponse(cmdName, Resources.StrCommDirectionSetup + ": " + info +
$": {dataObj}{cmdCodeStr}");
}
+ else
+ {
+ return false;
+ }
}
OnRawRecordReceived?.Invoke(this, new ProcessExecEventArgs("", specificInfoObj: response));
@@ -1189,7 +1249,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
ResetMeasurement();
IsLoggedOn = false;
- BroadcastCommIsActive = false;
+ CmdType = CmdType.NOT_INITIALIZED;
SerialPort?.Close();
return SerialPort != null && !SerialPort.IsOpen;
}
diff --git a/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/IFM2014.cs b/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/IFM2014.cs
index d85ed81d..26494014 100644
--- a/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/IFM2014.cs
+++ b/Common/Hardware/WaterMeter/MechanicalMeter/FM2014/FM2014Core/IFM2014.cs
@@ -123,7 +123,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
///
/// Reference pulses per cubic-meter
///
- UInt16 Ref_pulse_per_cm
+ UInt32 Ref_pulse_per_cm
{
get;
}
@@ -131,12 +131,12 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
///
/// REF to DUT scale normalized
///
- Single RefToDutScale_norm { get; }
+ Double RefToDutScale_norm { get; }
///
/// Device under test pulses per cubic-meter
///
- UInt16 Dut_pulse_per_cm
+ UInt32 Dut_pulse_per_cm
{
get;
}
diff --git a/MiniPrf/Ui/FrmMainMiniPrf.cs b/MiniPrf/Ui/FrmMainMiniPrf.cs
index 89537f9f..cb204144 100644
--- a/MiniPrf/Ui/FrmMainMiniPrf.cs
+++ b/MiniPrf/Ui/FrmMainMiniPrf.cs
@@ -90,6 +90,9 @@ namespace Sensus.MiniPrf.Ui
private static readonly Color ColorProcessFailed = Color.Red;
//private static readonly Color ColorOngoingProcess = Color.Blue;
//private static readonly Color ColorUnknownStatus = Color.Gray;
+ private static Color ColorStandardInputField;
+ private static Color ColorStandardDisplayField;
+
//private const String SuccessSign = @"✔";
//private const String FailedSign = @"✘";
@@ -130,6 +133,9 @@ namespace Sensus.MiniPrf.Ui
//Thread.CurrentThread.CurrentUICulture = cultureInfo;
//Thread.CurrentThread.CurrentCulture = cultureInfo;
_version = Assembly.GetExecutingAssembly().GetName().Version;
+
+ ColorStandardDisplayField = lblFM2014SerialPort.BackColor;
+ ColorStandardInputField = cbxFM2014ComPort.BackColor;
}
///
@@ -140,7 +146,7 @@ namespace Sensus.MiniPrf.Ui
///
private void Init()
{
- ViewProcessControl(false);
+ ActionControl(false);
_autoProgressBar = false;
_regulationSetupHasChanged = false;
grpBoxDebug.Visible = false;
@@ -165,7 +171,7 @@ namespace Sensus.MiniPrf.Ui
{
cbxFM2014ComPort.Items.Add(comPort);
}
-
+
cbxFM2014ComPort.Text = cbxFM2014ComPort.Items[_comPortIdx].ToString();
var itemContent = _fm2014Config?.Address ?? 1;
for (var idx = 0; idx < cbxFM2014Address.MaxDropDownItems; idx++)
@@ -189,7 +195,7 @@ namespace Sensus.MiniPrf.Ui
// FM2014 group box
lblConnectFM2014.Text = Resources.StrLblFM2014NotConnected;
- lblConnectFM2014.ForeColor = Color.Red;
+ lblConnectFM2014.ForeColor = ColorProcessFailed;
tbxFM2014FullId.Text = "";
tbxFM2014ApplicationFwVersion.Text = "";
lblFM2014SerialNumber.Text = Resources.StrLblFM2014SerialNumber;
@@ -300,7 +306,6 @@ namespace Sensus.MiniPrf.Ui
#endregion FormControls
#region TimerControls
-
private void tmrProgressUpdate_Tick(Object sender, EventArgs e)
{
if (_autoProgressBar || barSingleProgressUpdate.Visible)
@@ -370,7 +375,6 @@ namespace Sensus.MiniPrf.Ui
cbxFM2014Address.Enabled = true;
cbxFM2014ComPort.Enabled = true;
cbxFM2014TolerancePercent.Enabled = true;
-
}
///
@@ -388,11 +392,9 @@ namespace Sensus.MiniPrf.Ui
}
SetFM2014AccessEnabled();
}
-
#endregion ActivationControls
#region BoardControls
-
///
/// Establish connection
///
@@ -508,94 +510,84 @@ namespace Sensus.MiniPrf.Ui
#region ProcessControls
+ ///
+ /// Common method to (de-)activate controls and timer.
+ ///
+ ///
+ /// - Initial.
+ ///
private void ActionControl(Boolean isActive)
{
- if (isActive)
+ Invoke(new Action(() =>
{
- Invoke(new Action(() =>
+ if (isActive)
{
- ViewProcessControl(true);
+ lblActualProcess.Visible = true;
+ barSingleProgressUpdate.Visible = true;
+ SetFM2014AccessLocked();
tmrProgressUpdate.Enabled = true;
- }));
- }
- else
- {
- Invoke(new Action(() =>
+ }
+ else
{
- ViewProcessControl(false);
+ lblActualProcess.Visible = false;
+ barSingleProgressUpdate.Visible = false;
+ tmrProgressUpdate.Enabled = false;
+ lblWaitingForMeterResponse.Visible = false;
+ lblActualProcess.Text = "";
CheckUpdateEnabled();
- }));
- }
- }
-
- ///
- /// View all process bars and labels
- ///
- private void ViewProcessControl(Boolean view)
- {
- if (view)
- {
- lblActualProcess.Visible = true;
- barSingleProgressUpdate.Visible = true;
- tmrProgressUpdate.Enabled = true;
- SetFM2014AccessLocked();
- }
- else
- {
- lblActualProcess.Visible = false;
- barSingleProgressUpdate.Visible = false;
- tmrProgressUpdate.Enabled = false;
- lblWaitingForMeterResponse.Visible = false;
- lblActualProcess.Text = "";
- SetFM2014AccessEnabled();
- }
-
- //common actions and settings
- lblActualProcess.Update();
- barSingleProgressUpdate.Value = 0;
- barSingleProgressUpdate.Update();
- Update();
+ }
+ //common actions and settings
+ lblActualProcess.Update();
+ barSingleProgressUpdate.Value = 0;
+ barSingleProgressUpdate.Update();
+ Update();
+ }));
}
///
/// Common method to prepare for changed setup.
///
+ ///
+ /// - Initial.
+ ///
private void SetupHasChanged()
{
_regulationSetupHasChanged = true;
btnSaveRegulationSetup.Enabled = true;
-
+
tbxRefFrequencyHz.Text = "";
- tbxRefFrequencyHz.BackColor = gbxDutToRefRegulation.BackColor;
+ tbxRefFrequencyHz.BackColor = ColorStandardDisplayField;
tbxActualFlowRateCmPerHour.Text = "";
- tbxActualFlowRateCmPerHour.BackColor = gbxDutToRefRegulation.BackColor;
+ tbxActualFlowRateCmPerHour.BackColor = ColorStandardDisplayField;
tbxActualMeasuredToleranceDutToRef.Text = "";
- tbxActualMeasuredToleranceDutToRef.BackColor = gbxDutToRefRegulation.BackColor;
-
- tbxRefPulsePerCm.BackColor = Color.White;
- tbxDutPulsePerCm.BackColor = Color.White;
- tbxScaleRefToDut.BackColor = lblRefPulsePerVolume.BackColor;
+ tbxActualMeasuredToleranceDutToRef.BackColor = ColorStandardDisplayField;
- tbxManualInputVolumeLiters.BackColor = Color.White;
- tbxRefCalibrationResultPulsePerCm.BackColor = lblRefPulsePerVolume.BackColor;
+ tbxRefPulsePerCm.BackColor = ColorStandardInputField;
+ tbxDutPulsePerCm.BackColor = ColorStandardInputField;
+ tbxScaleRefToDut.BackColor = ColorStandardDisplayField;
+ tbxManualInputVolumeLiters.BackColor = ColorStandardInputField;
+ tbxRefCalibrationResultPulsePerCm.BackColor = ColorStandardDisplayField;
}
///
/// Common routine for REF to DUT scale check and update
///
///
+ ///
+ /// - Initial.
+ ///
private Boolean UpdateRefToDutScale()
{
tbxScaleRefToDut.Text = $@"{Fm2014.RefToDutScale_norm:F4}";
-
+
// Display error if scale doesn't fit
- if (Math.Abs(Fm2014.RefToDutScale_norm -
+ if (Math.Abs(Fm2014.RefToDutScale_norm -
(Single)Fm2014.Ref_pulse_per_cm / Fm2014.Dut_pulse_per_cm) > FM2014.RefToDutScaleMin ||
- Fm2014.RefToDutScale_norm < FM2014.RefToDutScaleMin ||
- Fm2014.RefToDutScale_norm > FM2014.RefToDutScaleMax )
+ Fm2014.RefToDutScale_norm < FM2014.RefToDutScaleMin ||
+ Fm2014.RefToDutScale_norm > FM2014.RefToDutScaleMax)
{
- tbxScaleRefToDut.BackColor = Color.Red;
+ tbxScaleRefToDut.BackColor = ColorProcessFailed;
tbxScaleRefToDut.Text = Resources.StrError;
btnSaveRegulationSetup.Enabled = false;
return false;
@@ -888,14 +880,14 @@ namespace Sensus.MiniPrf.Ui
//Backup the actual setting to detect changes
var backupPulses_per_cm = Fm2014.Ref_pulse_per_cm;
- Fm2014.Ref_pulse_per_cm = (UInt16)pulses_per_cm;
+ Fm2014.Ref_pulse_per_cm = (UInt32)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!
tbxRefPulsePerCm.Text = $@"{Fm2014.Ref_pulse_per_cm:D}";
// During setup of the 'Ref_pulse_per_cm' the 'RefToDutScaleStr' will be generated
if (!UpdateRefToDutScale())
{
- tbxRefPulsePerCm.BackColor = Color.Red;
+ tbxRefPulsePerCm.BackColor = ColorProcessFailed;
return;
}
// Check if values have changed and need to be updated in the standalone setup
@@ -958,14 +950,14 @@ namespace Sensus.MiniPrf.Ui
//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 = (UInt16)pulses_per_cm;
+ Fm2014.Dut_pulse_per_cm = (UInt32)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}";
// During setup of the 'Dut_pulse_per_cm' the 'RefToDutScaleStr' will be generated
if (!UpdateRefToDutScale())
{
- tbxDutPulsePerCm.BackColor = Color.Red;
+ tbxDutPulsePerCm.BackColor = ColorProcessFailed;
return;
}
@@ -1022,12 +1014,12 @@ namespace Sensus.MiniPrf.Ui
{
tbxRefCalibrationResultPulsePerCm.Text = $@"{Fm2014.Ref_pulse_per_cm:D}";
tbxRefPulsePerCm.Text = $@"{Fm2014.Ref_pulse_per_cm:D}";
- tbxManualInputVolumeLiters.BackColor = Color.White;
- tbxRefCalibrationResultPulsePerCm.BackColor = lblRefPulsePerVolume.BackColor;
+ tbxManualInputVolumeLiters.BackColor = ColorStandardInputField;
+ tbxRefCalibrationResultPulsePerCm.BackColor = ColorStandardDisplayField;
if (!UpdateRefToDutScale())
{
- tbxManualInputVolumeLiters.BackColor = Color.Red;
+ tbxManualInputVolumeLiters.BackColor = ColorProcessFailed;
return;
}
@@ -1039,8 +1031,8 @@ namespace Sensus.MiniPrf.Ui
}
else
{
- tbxManualInputVolumeLiters.BackColor = Color.Red;
- tbxRefCalibrationResultPulsePerCm.BackColor = Color.Red;
+ tbxManualInputVolumeLiters.BackColor = ColorProcessFailed;
+ tbxRefCalibrationResultPulsePerCm.BackColor = ColorProcessFailed;
tbxRefCalibrationResultPulsePerCm.Text = Resources.StrError;
}
}
@@ -1069,7 +1061,7 @@ namespace Sensus.MiniPrf.Ui
///
/// Feedback from FM2014being parsed to GUI
///
- ///
+ ///
/// - Initial.
///
private void DataReceived_Handler(Object sender, ProcessExecEventArgs e)
@@ -1121,13 +1113,13 @@ namespace Sensus.MiniPrf.Ui
tbxRefFrequencyDirectHz.Text = $@"{resp.IntValue:D}";
if (resp.IntValue < 1 || resp.IntValue > 254)
{
- tbxRefFrequencyHz.BackColor = Color.Red;
- tbxActualFlowRateCmPerHour.BackColor = Color.Red;
+ tbxRefFrequencyHz.BackColor = ColorProcessFailed;
+ tbxActualFlowRateCmPerHour.BackColor = ColorProcessFailed;
}
else
{
- tbxRefFrequencyHz.BackColor = gbxDutToRefRegulation.BackColor;
- tbxActualFlowRateCmPerHour.BackColor = gbxDutToRefRegulation.BackColor;
+ tbxRefFrequencyHz.BackColor = ColorStandardDisplayField;
+ tbxActualFlowRateCmPerHour.BackColor = ColorStandardDisplayField;
}
break;
}
@@ -1143,15 +1135,15 @@ namespace Sensus.MiniPrf.Ui
if (resp.DoubleValue < -Fm2014.Tolerance_percent ||
resp.DoubleValue > Fm2014.Tolerance_percent)
{
- tbxActualMeasuredToleranceDutToRef.BackColor = Color.Red;
+ tbxActualMeasuredToleranceDutToRef.BackColor = ColorProcessFailed;
}
else
{
- tbxActualMeasuredToleranceDutToRef.BackColor = gbxDutToRefRegulation.BackColor;
+ tbxActualMeasuredToleranceDutToRef.BackColor = ColorStandardDisplayField;
}
break;
case FM2014CmdDef.CmdName.CMD_REF_SET_SCALE:
- tbxScaleRefToDut.Text = $@"{resp.DoubleValue:F4}" ;
+ tbxScaleRefToDut.Text = $@"{resp.DoubleValue:F4}";
break;
// DEBUG
case FM2014CmdDef.CmdName.CMD_GET_REF_PERIOD: