This commit is contained in:
Stoyan Zlatev 2026-03-10 11:16:27 +01:00
commit c8ba81b1af
26 changed files with 943 additions and 318 deletions

View File

@ -38,6 +38,11 @@
/// <summary>
/// the measurement is out of range for threshold checks
/// </summary>
MeasurementOutOfRange
MeasurementOutOfRange,
/// <summary>
/// The setup value is out of range
/// </summary>
SetupOutOfRange
}
}

View File

@ -11,7 +11,7 @@
<AssemblyName>Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Config</AssemblyName>
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>false</Deterministic>
<Deterministic>true</Deterministic>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>

View File

@ -20,22 +20,22 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core.Co
/// <summary>
/// All measurements idle
/// </summary>
idle,
Idle,
/// <summary>
/// Pulse counter measurements
/// </summary>
pulseCounterMeasurement,
PulseCounterMeasurement,
/// <summary>
/// Regulation measurement ongoing
/// </summary>
regulationMeasurement,
RegulationMeasurement,
/// <summary>
/// Calibration measurement ongoing
/// </summary>
timeMeasurement
TimeMeasurement
}
}
/*********************************************** END OF FILE *********************************************************/

View File

@ -1,46 +0,0 @@
/*********************************************************************************************************************/
/*! @file ErrorStatus.cs
* @brief <i>FM2014 device error status</i>
*
* @author Thomas Wiedebusch
* @date 2026-Feb-24
*
* @details <i>.</i>
*
* @copyright © SENSUS GmbH 2026. All rights reserved.
*********************************************************************************************************************/
namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core.Consts
{
/// <summary>
/// Error status returned from FM2014 with command '0x41 ' or 'UNICODE_ACK' as MSB - 1
/// </summary>
public enum ErrorStatus
{
/// <summary>
/// REF signal timeout during the adjustment measurement for two consecutive pulses of 21.889 s
/// </summary>
AdjustMeasurementRefTimeout = 0x80,
/// <summary>
/// DUT signal timeout during the adjustment measurement for two consecutive pulses of 21.889 s
/// </summary>
AdjustMeasurementDutTimeout = 0x40,
/// <summary>
/// DUT double pulse detected during the time measurement
/// </summary>
TimeMeasurementDoublePulseDutDetected = 0x04,
/// <summary>
/// REF signal timeout during the time measurement for two consecutive pulses of 21.889 s
/// </summary>
TimeMeasurementRefTimeout = 0x02,
/// <summary>
/// REF signal timeout during the time measurement for two consecutive pulses of 21.889 s
/// </summary>
TimeMeasurementDutTimeout = 0x01
}
}
/*********************************************** END OF FILE *********************************************************/

View File

@ -1,47 +0,0 @@
/*********************************************************************************************************************/
/*! @file Fault1Status.cs
* @brief <i>FM2014 device fault1 status</i>
*
* @author Thomas Wiedebusch
* @date 2026-Feb-24
*
* @details <i>.</i>
*
* @copyright © SENSUS GmbH 2026. All rights reserved.
*********************************************************************************************************************/
namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core.Consts
{
/// <summary>
/// Fault1 status returned from FM2014 with command '0x43 ' or 'UNICODE_ACK' as LSB
/// </summary>
public enum Fault1Status
{
/// <summary>
/// Error for U/I converter for the current output of the tolerance DUT to REF display
/// </summary>
ErrorUiConverterCurrentOutput = 0x40,
/// <summary>
/// Setup of REF pulses is out of range command 'M'
/// </summary>
RefPulseSetupOor = 0x08,
/// <summary>
/// Setup of DUT pulses is out of range command 'H'
/// </summary>
DutPulseSetupOor = 0x04,
/// <summary>
/// Missing or out of range of the setup of the scale REF to DUT command 'K'
/// </summary>
MissingOrOorSetupScaleRefToDut = 0x02,
/// <summary>
/// Missing or out of range of double pulse ignorance deadtime command 'G' or 's' and 'S'
/// </summary>
MissingOrOorSetupDoublePulesDeadtime = 0x01
}
}
/*********************************************** END OF FILE *********************************************************/

View File

@ -1,31 +0,0 @@
/*********************************************************************************************************************/
/*! @file Fault2Status.cs
* @brief <i>FM2014 device fault2 status</i>
*
* @author Thomas Wiedebusch
* @date 2026-Feb-24
*
* @details <i>.</i>
*
* @copyright © SENSUS GmbH 2026. All rights reserved.
*********************************************************************************************************************/
namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core.Consts
{
/// <summary>
/// Fault2 status returned from FM2014 with command '0x43 ' or 'UNICODE_ACK' as LSB
/// </summary>
public enum Fault2Status
{
/// <summary>
/// FLASH access error causing parameters set to default
/// </summary>
FlashAccessError = 0x10,
/// <summary>
/// Missing the setup for current output attenuation of the DUT to REF tolerance command 'T'
/// </summary>
MissingCurrentOutputAttenuation = 0x08,
}
}
/*********************************************** END OF FILE *********************************************************/

View File

@ -1,56 +0,0 @@
/*********************************************************************************************************************/
/*! @file MeasureStatus.cs
* @brief <i>FM2014 device measurement status</i>
*
* @author Thomas Wiedebusch
* @date 2026-Feb-24
*
* @details <i>.</i>
*
* @copyright © SENSUS GmbH 2026. All rights reserved.
*********************************************************************************************************************/
namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core.Consts
{
/// <summary>
/// Measurement status returned from FM2014 with command '0x40 ' or 'UNICODE_ACK' as MSB
/// </summary>
public enum MeasureStatus
{
/// <summary>
/// Double pulse deadtime set to 0, means double pulse ignorance time is switched off
/// </summary>
DoublePulseDeadtimeInactive = 0x80,
/// <summary>
/// Time measurement of REF has finished
/// </summary>
TimeMeasureRefRdy = 0x40,
/// <summary>
/// Time measurement of DUT has finished
/// </summary>
TimeMeasureDutRdy = 0x20,
/// <summary>
/// Time measurement of REF is ongoing
/// </summary>
TimeMeasureRefActive = 0x10,
/// <summary>
/// Time measurement of DUT is ongoing
/// </summary>
TimeMeasureDutActive = 0x08,
/// <summary>
/// Adjustment measurement of REF is finished
/// </summary>
AdjustMeasureRefRdy = 0x02,
/// <summary>
/// Adjustment measurement of DUT is finished
/// </summary>
AdjustMeasureDutRdy = 0x01
}
}
/*********************************************** END OF FILE *********************************************************/

View File

@ -198,6 +198,18 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
public event EventHandler<ProcessExecEventArgs> OnRawRecordReceived;
#endregion ---------------------------------------- events ----------------------------------------------------
#region ------------------------------------------- static properties -----------------------------------------
/// <summary>
/// Force to decode the entire status even if it is not important for this measurement sequence.
/// </summary>
public static Boolean DecodeEntireStatus { get; set; }
/// <summary>
/// Reminder of actual ongoing measurement information
/// </summary>
private static UInt32 StatusDecodingMask { get; set; } = STATUS_MEASURE_MASK | STATUS_ERROR_MASK |
STATUS_FAULT1_MASK | STATUS_FAULT2_MASK;
/// <summary>
/// Reminder of actual ongoing measurement information
/// </summary>
@ -336,7 +348,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
set
{
_address = value;
AddressStr = $"{ADDR_RECORD_STR}{_address}{ADDR_VALIDATION_STR}";
AddressStr = $"{ADDR_RECORD_STR}{_address}{VALIDATION_STR}";
}
}
@ -604,8 +616,13 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
get => _doublePulseDeadtime_ms;
set
{
// Fire an event if setup is OOR
if (value > DOUBLE_PULSE_DEADTIME_MAX_ms)
{
return;
}
_doublePulseDeadtime_ms = value;
// Calculate and set up the values 'S' and 's' needed for the FM2014
@ -710,14 +727,14 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// </remarks>
public static Boolean ResetHardwareAllDevices()
{
if (SharedCyclicMeasSequ == CyclicMeasSequ.idle)
if (SharedCyclicMeasSequ == CyclicMeasSequ.Idle)
return true;
if (BroadcastFm2014 == null)
return false;
// Exit tasks
SharedCyclicMeasSequ = CyclicMeasSequ.idle;
SharedCyclicMeasSequ = CyclicMeasSequ.Idle;
// Schedule to other tasks to avoid side effects through the reset command
Task.Factory.StartNew(() =>
@ -761,7 +778,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// </remarks>
public static Boolean StoreAllConfigurations()
{
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle ||
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle ||
RegisteredFm2014s == null ||
RegisteredFm2014s.Count == 0 ||
RegisteredFm2014s.All(x => !x.IsLoggedOn))
@ -861,6 +878,50 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
fm2014?.OnRawRecordReceived?.Invoke(fm2014, processExecEventArgs);
}
/// <summary>
/// Set the mask for the FM2014 status decoding to multilingual output
/// </summary>
/// <param name="measMaskOn"></param>
/// <param name="errorMaskOn"></param>
/// <param name="faultMaskOn"></param>
public static void SetStatusDecodingMask(Boolean measMaskOn = true, Boolean errorMaskOn = true,
Boolean faultMaskOn = true)
{
StatusDecodingMask = 0;
if (measMaskOn) StatusDecodingMask += STATUS_MEASURE_MASK;
if (errorMaskOn) StatusDecodingMask += STATUS_ERROR_MASK;
if (faultMaskOn) StatusDecodingMask += STATUS_FAULT1_MASK + STATUS_FAULT2_MASK;
}
/// <summary>
/// Read, decoding and publish status to multilingual messages based on status decoding mask
/// </summary>
/// <param name="fm2014"></param>
/// <remarks date="2026-Feb-25" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private static void ReadDecodeAndPublishStatus(FM2014 fm2014)
{
var cmdName = CmdName.CmdGetStatus;
var cmdInfo = GetCmdInfo(cmdName);
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle && Write(cmdName, fm2014))
{
if (Read(cmdName, fm2014, out _, out var status, out _))
{
if (status != null)
{
var statusStrs = GetDecodedStatusInfos((UInt32)status, StatusDecodingMask);
foreach (var statusStr in statusStrs)
{
var info = $"{cmdInfo}: {statusStr}";
var response = new FM2014CmdResponse(cmdName, info);
ResponseEvent(fm2014, response);
}
}
}
}
}
/// <summary>
/// Common method to check and dispatch the double impulse deadtime to the FM2014.
/// The commands will be dispatched as broadcast.
@ -876,7 +937,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
var cmdName = CmdName.CmdSwitchDoublePulseDeadtimeOff;
var actualFm2014 = CmdType.broadcast == GetCmdType(cmdName) ? BroadcastFm2014 : fm2014;
// Check if double pulse deadtime has been set or si switched off
// Check if double pulse deadtime has been set or is switched off
if (DOUBLE_PULSE_DEADTIME_MIN_ms == fm2014.DoublePulseDeadtime_ms)
{
// This is a command without parameter
@ -932,17 +993,17 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// <returns>true if initialization successfully executed or
/// <see cref="SharedCyclicMeasSequ"/> marks the already started cyclic requests
/// for all registered FM2014s</returns>
/// <remarks date="2026-Jan-10..Feb-19" author="Thomas Wiedebusch">
/// <remarks date="2026-Jan-10..Feb-25" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
public static Boolean PulseCounterMeasurement(Boolean refPulseCtrOn, Boolean dutPulseCtrOn)
{
// If the cyclic task has already been started everything is fine
if (SharedCyclicMeasSequ == CyclicMeasSequ.pulseCounterMeasurement)
if (SharedCyclicMeasSequ == CyclicMeasSequ.PulseCounterMeasurement)
return true;
// Marked measurement isn't pulse counter measurement, other FM2014s cannot activate this
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle)
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle)
return false;
var firstActiveFm2014 = GetFirstConnectedAndLoggedInFm2014();
@ -1007,10 +1068,14 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
// Mark pulse counter measurement as active
SharedCyclicMeasSequ = CyclicMeasSequ.pulseCounterMeasurement;
SharedCyclicMeasSequ = CyclicMeasSequ.PulseCounterMeasurement;
do
{
// Setup status mask to ignore unimportant settings and feedbacks for the time and regulation measurement
StatusDecodingMask = GetBitMaskForSequence(DecodeEntireStatus ? CyclicMeasSequ.Idle :
CyclicMeasSequ.PulseCounterMeasurement);
CmdName cmdNameRef;
CmdName cmdNameDut;
Boolean syncPulseCtr;
@ -1034,7 +1099,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
var infoDut = GetCmdInfo(cmdNameDut);
// Make a backup of the pulse counters to synchronize those and read out the backups
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle && syncPulseCtr)
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle && syncPulseCtr)
{
// Synchronized backup of REF and DUT pulse counter
Write(CmdName.CmdBackupRefAndDutPulses, firstActiveFm2014);
@ -1045,19 +1110,9 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
try
{
// Read the device status to check for timeout between pulses
cmdName = CmdName.CmdGetStatus;
var info = GetCmdInfo(cmdName);
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle && Write(cmdName, fm2014))
{
if (Read(cmdName, fm2014, out var responseStr, out var status, out _))
{
info += $": {responseStr}";
var response = new FM2014CmdResponse(cmdName, info, status);
ResponseEvent(fm2014, response);
}
}
ReadDecodeAndPublishStatus(fm2014);
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle && fm2014.RefPulseCtrOn && Write(cmdNameRef, fm2014))
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle && fm2014.RefPulseCtrOn && Write(cmdNameRef, fm2014))
{
if (Read(cmdNameRef, fm2014, out _, out var intValue, out _))
{
@ -1066,7 +1121,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
}
}
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle && fm2014.DutPulseCtrOn && Write(cmdNameDut, fm2014))
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle && fm2014.DutPulseCtrOn && Write(cmdNameDut, fm2014))
{
if (Read(cmdNameDut, fm2014, out _, out var intValue, out _))
{
@ -1086,7 +1141,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
Thread.Sleep(THREAD_SLEEP_TIME_ms);
} // loop all FM2014s
} while (SharedCyclicMeasSequ != CyclicMeasSequ.idle);
} while (SharedCyclicMeasSequ != CyclicMeasSequ.Idle);
}, SharedCancellationToken).ContinueWith(delegate
{
foreach (var fm2014 in RegisteredFm2014s)
@ -1129,18 +1184,18 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// <param name="doublePulseDeadtime_ms"></param>
/// <param name="currentOutputAttenuation"></param>
/// <returns></returns>
/// <remarks date="2026-Jan-14..Feb-21" author="Thomas Wiedebusch">
/// <remarks date="2026-Jan-14..Feb-25" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
public static Boolean RegulationMeasurement(UInt32 refPulses_per_cm, UInt16 dutPulses_per_cm,
UInt16 doublePulseDeadtime_ms, Byte currentOutputAttenuation)
{
// If the cyclic task has already been started everything is fine
if (SharedCyclicMeasSequ == CyclicMeasSequ.regulationMeasurement)
if (SharedCyclicMeasSequ == CyclicMeasSequ.RegulationMeasurement)
return true;
// Marked measurement isn't pulse counter measurement, other FM2014s cannot activate this
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle)
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle)
return false;
// Initially, check if any device is connected and logged in, if not => exit
@ -1204,33 +1259,27 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
Task.Run(() =>
{
// Mark regulation measurement as active
SharedCyclicMeasSequ = CyclicMeasSequ.regulationMeasurement;
SharedCyclicMeasSequ = CyclicMeasSequ.RegulationMeasurement;
do
{
// Setup status mask to ignore unimportant settings and feedbacks for the time measurement
StatusDecodingMask = GetBitMaskForSequence(DecodeEntireStatus ? CyclicMeasSequ.Idle :
CyclicMeasSequ.RegulationMeasurement);
foreach (var fm2014 in RegisteredFm2014s.Where(fm2014 => fm2014.IsLoggedOn))
{
try
{
StatusReturn statusReturn;
// Read the device status to check for timeout between pulses
cmdName = CmdName.CmdGetStatus;
var info = GetCmdInfo(cmdName);
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle && Write(cmdName, fm2014))
{
if (Read(cmdName, fm2014, out var responseStr, out var status, out _))
{
info += $": {responseStr}";
var response = new FM2014CmdResponse(cmdName, info, status);
ResponseEvent(fm2014, response);
}
}
ReadDecodeAndPublishStatus(fm2014);
// Read out the damped/undamped tolerance and convert the raw value (0, +/-1..255 digits) to the
// tolerance in percent depending on the setup to 3 % (3.3) of 5 % (5.5)
cmdName = fm2014.UseDampedTolerance ? CmdName.CmdGetDutToRefToleranceDamped : CmdName.CmdGetDutToRefToleranceUndamped;
info = GetCmdInfo(cmdName);
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle && Write(cmdName, fm2014))
var info = GetCmdInfo(cmdName);
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle && Write(cmdName, fm2014))
{
if (Read(cmdName, fm2014, out _, out _, out var doubleValue))
{
@ -1253,7 +1302,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
// Read the REF period and calculate the frequency [Hz] and flow rate [m³/h] based on this period
cmdName = CmdName.CmdGetRefPeriod;
info = GetCmdInfo(cmdName);
if (fm2014.RequestDebugInformation && SharedCyclicMeasSequ != CyclicMeasSequ.idle &&
if (fm2014.RequestDebugInformation && SharedCyclicMeasSequ != CyclicMeasSequ.Idle &&
Write(cmdName, fm2014))
{
if (Read(cmdName, fm2014, out _, out var period, out _))
@ -1288,7 +1337,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
cmdName = CmdName.CmdGetDutPeriod;
info = GetCmdInfo(cmdName);
if (fm2014.RequestDebugInformation &&
SharedCyclicMeasSequ != CyclicMeasSequ.idle &&
SharedCyclicMeasSequ != CyclicMeasSequ.Idle &&
Write(cmdName, fm2014))
{
if (Read(cmdName, fm2014, out _, out var period, out _))
@ -1321,7 +1370,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
// Read the REF frequency [Hz] directly and calculate the flow rate [m³/h] based on this frequency
cmdName = CmdName.CmdGetRefFrequency;
info = GetCmdInfo(cmdName);
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle && Write(cmdName, fm2014))
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle && Write(cmdName, fm2014))
{
if (Read(cmdName, fm2014, out _, out var refFrequency, out _))
{
@ -1357,7 +1406,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
Thread.Sleep(THREAD_SLEEP_TIME_ms);
} // loop all FM2014s
} while (SharedCyclicMeasSequ != CyclicMeasSequ.idle);
} while (SharedCyclicMeasSequ != CyclicMeasSequ.Idle);
}, SharedCancellationToken);
@ -1395,18 +1444,18 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// <param name="doublePulseDeadtime_ms">0 if double impulse deadtime detection is off</param>
/// </summary>
/// <returns></returns>
/// <remarks date="2026-Jan-14..Feb-24" author="Thomas Wiedebusch">
/// <remarks date="2026-Jan-14..Feb-26" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
public static Boolean PulseTimeMeasurement(UInt16? refPulsesRequired = null, UInt16? dutPulsesRequired = null,
UInt16 doublePulseDeadtime_ms = 0)
{
// If the cyclic task has already been started everything is fine
if (SharedCyclicMeasSequ == CyclicMeasSequ.timeMeasurement)
if (SharedCyclicMeasSequ == CyclicMeasSequ.TimeMeasurement)
return true;
// Marked measurement isn't pulse counter measurement, other FM2014s cannot activate this
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle)
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle)
return false;
// Initially, check if any device is connected and logged in, if not => exit
@ -1446,6 +1495,21 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
if (!BuildAndWriteDoubleImpulseDeadtime(firstActiveFm2014))
return false;
// START FAKE setup for time measurement!
// Setup to get rid of the status message for missing 'Tolerance display attenuation missing' 'T' and
// missing 'Scale REF to DUT missing or out of range' 'K' even if these setting don't have any function
cmdName = CmdName.CmdSetCurrentOutputAttenuation;
if (!Write(cmdName, firstActiveFm2014, firstActiveFm2014.CurrentOutputAttenuation))
{
return false;
}
cmdName = CmdName.CmdRefToDutScale;
if (!Write(cmdName, firstActiveFm2014, firstActiveFm2014.RefToDutScaleStr))
{
return false;
}
// END FAKE setup for time measurement!
if (refPulsesRequired != null)
{
cmdName = CmdName.CmdSetRefPulsesRequired;
@ -1486,7 +1550,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
Task.Run(() =>
{
// Mark calibration measurement as active
SharedCyclicMeasSequ = CyclicMeasSequ.timeMeasurement;
SharedCyclicMeasSequ = CyclicMeasSequ.TimeMeasurement;
// Set up the progress maximal counter value base on required pulses for REF or DUT
InitActualProcessProgress(refPulsesRequired != null ? (Int32)firstActiveFm2014.RefPulsesRequired :
@ -1494,30 +1558,24 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
do
{
// Setup status mask to ignore unimportant settings for this measurement 'T' and 'K'
StatusDecodingMask = GetBitMaskForSequence(DecodeEntireStatus ? CyclicMeasSequ.Idle :
CyclicMeasSequ.TimeMeasurement);
foreach (var fm2014 in RegisteredFm2014s.Where(fm2014 => fm2014.IsLoggedOn && !fm2014.MeasurementIsReady))
{
try
{
StatusReturn statusReturn;
// Read the device status to check for timeout between pulses
cmdName = CmdName.CmdGetStatus;
var info = GetCmdInfo(cmdName);
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle && Write(cmdName, fm2014))
{
if (Read(cmdName, fm2014, out var responseStr, out var status, out _))
{
info += $": {responseStr}";
var response = new FM2014CmdResponse(cmdName, info, status);
ResponseEvent(fm2014, response);
}
}
ReadDecodeAndPublishStatus(fm2014);
// Read the remaining REF pulses if required
if (refPulsesRequired != null)
{
cmdName = CmdName.CmdGetRefPulsesRemaining;
info = GetCmdInfo(cmdName);
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle && Write(cmdName, fm2014))
var info = GetCmdInfo(cmdName);
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle && Write(cmdName, fm2014))
{
if (Read(cmdName, fm2014, out _, out var pulses, out _))
{
@ -1549,8 +1607,8 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
if (dutPulsesRequired != null)
{
cmdName = CmdName.CmdGetDutPulsesRemaining;
info = GetCmdInfo(cmdName);
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle && Write(cmdName, fm2014))
var info = GetCmdInfo(cmdName);
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle && Write(cmdName, fm2014))
{
if (Read(cmdName, fm2014, out _, out var pulses, out _))
{
@ -1589,8 +1647,8 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
if (refPulsesRequired != null)
{
cmdName = CmdName.CmdGetRefTimerTicks;
info = GetCmdInfo(cmdName);
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle && Write(cmdName, fm2014))
var info = GetCmdInfo(cmdName);
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle && Write(cmdName, fm2014))
{
if (Read(cmdName, fm2014, out _, out var timerTicks, out _))
{
@ -1611,8 +1669,8 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
if (dutPulsesRequired != null)
{
cmdName = CmdName.CmdGetDutTimerTicks;
info = GetCmdInfo(cmdName);
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle && Write(cmdName, fm2014))
var info = GetCmdInfo(cmdName);
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle && Write(cmdName, fm2014))
{
if (Read(cmdName, fm2014, out _, out var timerTicks, out _))
{
@ -1633,7 +1691,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
if (refPulsesRequired != null && dutPulsesRequired != null)
{
cmdName = CmdName.CmdCalculatedDutToRefTolerance;
info = GetCmdInfo(cmdName);
var info = GetCmdInfo(cmdName);
// Is converting to a real time in seconds
if (fm2014.RefTimeMeasured_s > 0.0)
{
@ -1677,9 +1735,9 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
ResetHardwareAllDevices();
// Exit this task
SharedCyclicMeasSequ = CyclicMeasSequ.idle;
SharedCyclicMeasSequ = CyclicMeasSequ.Idle;
}
} while (SharedCyclicMeasSequ != CyclicMeasSequ.idle);
} while (SharedCyclicMeasSequ != CyclicMeasSequ.Idle);
}, SharedCancellationToken);
@ -1819,7 +1877,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
SharedCmdTypeReminderLastCmd = CmdType.uninitialized;
fm2014.IsLoggedOn = false;
SharedCyclicMeasSequ = CyclicMeasSequ.idle;
SharedCyclicMeasSequ = CyclicMeasSequ.Idle;
return false;
}
if (!DisableWriteReadActualProcessIncreasing)
@ -2111,7 +2169,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
// If the cyclic task has already been started the login isn't allowed anymore
// until this has been finished
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle)
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle)
return false;
return InitiateIndividualComm(this);
@ -2127,7 +2185,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
private Boolean SaveStandAloneMeasurement()
{
// If the cyclic task has already been started everything is fine
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle || !IsLoggedOn)
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle || !IsLoggedOn)
return false;
var cmdName = CmdName.CmdSetRefPulsesPerCm;
@ -2190,7 +2248,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
private Boolean ReadStandAloneMeasurement(CmdName cmdName)
{
// If the cyclic task has already been started everything is fine
if (SharedCyclicMeasSequ != CyclicMeasSequ.idle || !IsLoggedOn)
if (SharedCyclicMeasSequ != CyclicMeasSequ.Idle || !IsLoggedOn)
return false;
// Allow explicit standalone measurement commands

View File

@ -36,7 +36,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// <summary>
/// Address assignment validation behind the address number
/// </summary>
public const String ADDR_VALIDATION_STR = "@";
public const String VALIDATION_STR = "@";
/// <summary>
/// Partial search string for <see cref="CmdName.CmdReadEepMeasSetup"/>
@ -65,7 +65,25 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// <summary>
/// Broadcast address definition
/// </summary>
public static readonly String BROADCAST_ADDRESS = $"{ADDR_RECORD_STR}0{ADDR_VALIDATION_STR}";
public static readonly String BROADCAST_ADDRESS = $"{ADDR_RECORD_STR}0{VALIDATION_STR}";
/// <summary>
/// Status mask for measurement
/// </summary>
public const UInt32 STATUS_MEASURE_MASK = 0xFF000000;
/// <summary>
/// Status mask for error
/// </summary>
public const UInt32 STATUS_ERROR_MASK = 0x00FF0000;
/// <summary>
/// Status mask for fault1
/// </summary>
public const UInt32 STATUS_FAULT1_MASK = 0x0000FF00;
/// <summary>
/// Status mask for fault2
/// </summary>
public const UInt32 STATUS_FAULT2_MASK = 0x000000FF;
// Unicode Strings for command table
private const String UNICODE_ACK = "\u0006";
@ -175,6 +193,233 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
InfoStr = statusInfoStr;
}
}
/// <summary>
/// Measurement status returned from FM2014 with command '0x40 ' or 'UNICODE_ACK' as MSB
/// </summary>
internal enum MeasureStatusName
{
/// <summary>
/// Double pulse deadtime set to 0, means double pulse ignorance time is switched off
/// </summary>
DoublePulseDeadtimeInactive = 0x80,
/// <summary>
/// Time measurement of REF has finished
/// </summary>
TimeMeasureRefRdy = 0x40,
/// <summary>
/// Time measurement of DUT has finished
/// </summary>
TimeMeasureDutRdy = 0x20,
/// <summary>
/// Time measurement of REF is ongoing
/// </summary>
TimeMeasureRefActive = 0x10,
/// <summary>
/// Time measurement of DUT is ongoing
/// </summary>
TimeMeasureDutActive = 0x08,
/// <summary>
/// Adjustment measurement of REF is finished
/// </summary>
AdjustMeasureRefRdy = 0x02,
/// <summary>
/// Adjustment measurement of DUT is finished
/// </summary>
AdjustMeasureDutRdy = 0x01
}
/// <summary>
/// Combine measure status name from FM2014 firmware to multilingual information
/// </summary>
internal struct MeasureStatus
{
/// <summary>
/// Hard coded measure status returned from FM2014
/// </summary>
internal readonly MeasureStatusName StatusName;
/// <summary>
/// Multilingual forwarded string to GUI
/// </summary>
internal readonly String MultilingualStr;
/// <summary>
/// Ctor
/// </summary>
/// <param name="statusName"></param>
/// <param name="multilingualFeedback"></param>
internal MeasureStatus(MeasureStatusName statusName, String multilingualFeedback)
{
StatusName = statusName;
MultilingualStr = multilingualFeedback;
}
}
/// <summary>
/// Error status returned from FM2014 with command '0x41 ' or 'UNICODE_ACK' as MSB - 1
/// </summary>
internal enum ErrorStatusName
{
/// <summary>
/// REF signal timeout during the adjustment measurement for two consecutive pulses of 21.889 s
/// </summary>
AdjustMeasurementRefTimeout = 0x80,
/// <summary>
/// DUT signal timeout during the adjustment measurement for two consecutive pulses of 21.889 s
/// </summary>
AdjustMeasurementDutTimeout = 0x40,
/// <summary>
/// DUT double pulse detected during the time measurement
/// </summary>
TimeMeasurementDoublePulseDutDetected = 0x04,
/// <summary>
/// REF signal timeout during the time measurement for two consecutive pulses of 21.889 s
/// </summary>
TimeMeasurementRefTimeout = 0x02,
/// <summary>
/// REF signal timeout during the time measurement for two consecutive pulses of 21.889 s
/// </summary>
TimeMeasurementDutTimeout = 0x01
}
/// <summary>
/// Combine error status name from FM2014 firmware to multilingual information
/// </summary>
internal struct ErrorStatus
{
/// <summary>
/// Hard coded error status returned from FM2014
/// </summary>
internal readonly ErrorStatusName StatusName;
/// <summary>
/// Multilingual forwarded string to GUI
/// </summary>
internal readonly String MultilingualStr;
/// <summary>
/// Ctor
/// </summary>
/// <param name="statusName"></param>
/// <param name="multilingualFeedback"></param>
internal ErrorStatus(ErrorStatusName statusName, String multilingualFeedback)
{
StatusName = statusName;
MultilingualStr = multilingualFeedback;
}
}
/// <summary>
/// Fault1 status returned from FM2014 with command '0x43 ' or 'UNICODE_ACK' as LSB
/// </summary>
internal enum Fault1StatusName
{
/// <summary>
/// Error for U/I converter for the current output of the tolerance DUT to REF display
/// </summary>
ErrorUiConverterCurrentOutput = 0x40,
/// <summary>
/// Setup of REF pulses is out of range command 'M'
/// </summary>
RefPulseSetupOor = 0x08,
/// <summary>
/// Setup of DUT pulses is out of range command 'H'
/// </summary>
DutPulseSetupOor = 0x04,
/// <summary>
/// Missing or out of range of the setup of the scale REF to DUT command 'K'
/// </summary>
MissingOrOorSetupScaleRefToDut = 0x02,
/// <summary>
/// Missing or out of range of double pulse ignorance deadtime command 'G' or 's' and 'S'
/// </summary>
MissingOrOorSetupDoublePulesDeadtime = 0x01
}
/// <summary>
/// Combine fault1 status name from FM2014 firmware to multilingual information
/// </summary>
internal struct Fault1Status
{
/// <summary>
/// Hard coded fault1 status returned from FM2014
/// </summary>
internal readonly Fault1StatusName StatusName;
/// <summary>
/// Multilingual forwarded string to GUI
/// </summary>
internal readonly String MultilingualStr;
/// <summary>
/// Ctor
/// </summary>
/// <param name="statusName"></param>
/// <param name="multilingualFeedback"></param>
internal Fault1Status(Fault1StatusName statusName, String multilingualFeedback)
{
StatusName = statusName;
MultilingualStr = multilingualFeedback;
}
}
/// <summary>
/// Fault2 status returned from FM2014 with command '0x43 ' or 'UNICODE_ACK' as LSB
/// </summary>
internal enum Fault2StatusName
{
/// <summary>
/// FLASH access error causing parameters set to default
/// </summary>
FlashAccessError = 0x10,
/// <summary>
/// Missing the setup for current output attenuation of the DUT to REF tolerance command 'T'
/// </summary>
MissingToleranceDisplayAttenuation = 0x08,
}
/// <summary>
/// Combine fault2 status name from FM2014 firmware to multilingual information
/// </summary>
internal struct Fault2Status
{
/// <summary>
/// Hard coded fault2 status returned from FM2014
/// </summary>
internal readonly Fault2StatusName StatusName;
/// <summary>
/// Multilingual forwarded string to GUI
/// </summary>
internal readonly String MultilingualStr;
/// <summary>
/// Ctor
/// </summary>
/// <param name="statusName"></param>
/// <param name="multilingualFeedback"></param>
internal Fault2Status(Fault2StatusName statusName, String multilingualFeedback)
{
StatusName = statusName;
MultilingualStr = multilingualFeedback;
}
}
/// <summary>
/// Command table for communication with FM2014 combines the name with the command code and additional info.
@ -268,6 +513,57 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
new ConnectStatus(ConnectStatusName.error, Resources.StrError)
};
/// <summary>
/// Measurement status collection to return multilingual answer
/// </summary>
internal static readonly MeasureStatus[] MeasureStati =
{
new MeasureStatus(MeasureStatusName.DoublePulseDeadtimeInactive, Resources.StrStatusMeasDoublePulseDeadtimeInactive),
new MeasureStatus(MeasureStatusName.TimeMeasureRefRdy, Resources.StrStatusMeasTimeMeasureRefRdy),
new MeasureStatus(MeasureStatusName.TimeMeasureDutRdy, Resources.StrStatusMeasTimeMeasureDutRdy),
new MeasureStatus(MeasureStatusName.TimeMeasureRefActive, Resources.StrStatusMeasTimeMeasureRefActive),
new MeasureStatus(MeasureStatusName.TimeMeasureDutActive, Resources.StrStatusMeasTimeMeasureDutActive),
new MeasureStatus(MeasureStatusName.AdjustMeasureRefRdy, Resources.StrStatusMeasAdjustMeasureRefRdy),
new MeasureStatus(MeasureStatusName.AdjustMeasureDutRdy, Resources.StrStatusMeasAdjustMeasureDutRdy)
};
/// <summary>
/// Error status collection to return multilingual answer
/// </summary>
internal static readonly ErrorStatus[] ErrorStati =
{
new ErrorStatus(ErrorStatusName.AdjustMeasurementRefTimeout, Resources.StrStatusErrorAdjustMeasureRefTimeout),
new ErrorStatus(ErrorStatusName.AdjustMeasurementDutTimeout, Resources.StrStatusErrorAdjustMeasureDutTimeout),
new ErrorStatus(ErrorStatusName.TimeMeasurementDoublePulseDutDetected,
Resources.StrStatusErrorDoublePulseOnDutDetected),
new ErrorStatus(ErrorStatusName.TimeMeasurementRefTimeout, Resources.StrStatusErrorTimeMeasureRefTimeout),
new ErrorStatus(ErrorStatusName.TimeMeasurementDutTimeout, Resources.StrStatusErrorTimeMeasureRefTimeout)
};
/// <summary>
/// Fault1 status collection to return multilingual answer
/// </summary>
internal static readonly Fault1Status[] Fault1Stati =
{
new Fault1Status(Fault1StatusName.ErrorUiConverterCurrentOutput, Resources.StrStatusFault1UiConverter),
new Fault1Status(Fault1StatusName.RefPulseSetupOor, Resources.StrStatusFault1RefPulseSetupOor),
new Fault1Status(Fault1StatusName.DutPulseSetupOor, Resources.StrStatusFault1DutPulseSetupOor),
new Fault1Status(Fault1StatusName.MissingOrOorSetupScaleRefToDut,
Resources.StrStatusFault1ScaleRefToDutMissingOrOor),
new Fault1Status(Fault1StatusName.MissingOrOorSetupDoublePulesDeadtime,
Resources.StrStatusFault1DoublePulseDeadtimeMissingOrOor)
};
/// <summary>
/// Fault1 status collection to return multilingual answer
/// </summary>
internal static readonly Fault2Status[] Fault2Stati =
{
new Fault2Status(Fault2StatusName.FlashAccessError, Resources.StrStatusFault2FlashAccessError),
new Fault2Status(Fault2StatusName.MissingToleranceDisplayAttenuation,
Resources.StrStatusFault2MissingToleranceAttenuation)
};
/// <summary>
/// Get String command code from command name
/// </summary>
@ -342,5 +638,75 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
where ct.CmdName == cmdName
select ct.ParamFormat).FirstOrDefault();
}
/// <summary>
/// Decoding the status unsigned double word using the mask to select the appropriate fields
/// </summary>
/// <param name="status"></param>
/// <param name="statusMask"></param>
/// <returns></returns>
public static List<String> GetDecodedStatusInfos(UInt32 status, UInt32 statusMask = 0xFFFFFFFF)
{
var responseStrs = new List<String>();
status &= statusMask;
var measureStati = (status >> 24) & 0xFF;
var errorStati = (status >> 16) & 0xFF;
var fault1Stati = (status >> 8) & 0xFF;
var fault2Stati = status & 0xFF;
foreach (var s in MeasureStati)
{
if (((UInt32)s.StatusName & measureStati) == (UInt32)s.StatusName)
{
responseStrs.Add(s.MultilingualStr);
}
}
foreach (var s in ErrorStati)
{
if (((UInt32)s.StatusName & errorStati) == (UInt32)s.StatusName)
{
responseStrs.Add(s.MultilingualStr);
}
}
foreach (var s in Fault1Stati)
{
if (((UInt32)s.StatusName & fault1Stati) == (UInt32)s.StatusName)
{
responseStrs.Add(s.MultilingualStr);
}
}
foreach (var s in Fault2Stati)
{
if (((UInt32)s.StatusName & fault2Stati) == (UInt32)s.StatusName)
{
responseStrs.Add(s.MultilingualStr);
}
}
return responseStrs;
}
/// <summary>
/// Get the required status mask for different measurement sequences to ignore unimportant
/// stati feedback of unused setting.
/// </summary>
/// <param name="sequence"></param>
/// <returns></returns>
public static UInt32 GetBitMaskForSequence(CyclicMeasSequ sequence)
{
if (sequence == CyclicMeasSequ.TimeMeasurement)
return 0xF8074D10;
if (sequence == CyclicMeasSequ.RegulationMeasurement)
return 0x83C04318;
if (sequence == CyclicMeasSequ.PulseCounterMeasurement)
return 0x80004010;
return 0xFFFFFFFF;
}
}
}

View File

@ -46,7 +46,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
public Double? DoubleValue { get; private set; }
/// <summary>
/// Measurement SI unit
/// Unit of the measurement
/// </summary>
public String Unit { get; private set; }

View File

@ -288,10 +288,6 @@
<Compile Include="Consts\ConnectStatusName.cs" />
<Compile Include="Consts\CyclicMeasSequ.cs" />
<Compile Include="Consts\CmdParaFormat.cs" />
<Compile Include="Consts\ErrorStatus.cs" />
<Compile Include="Consts\Fault1Status.cs" />
<Compile Include="Consts\Fault2Status.cs" />
<Compile Include="Consts\MeasureStatus.cs" />
<Compile Include="FM2014CmdDef.cs" />
<Compile Include="FM2014.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View File

@ -708,5 +708,176 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core.Pr
return ResourceManager.GetString("StrMeasMsgStanaloneRegulation", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Regulation measurement DUT signal timeout.
/// </summary>
internal static string StrStatusErrorAdjustMeasureDutTimeout {
get {
return ResourceManager.GetString("StrStatusErrorAdjustMeasureDutTimeout", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Regulation measurement REF signal timeout.
/// </summary>
internal static string StrStatusErrorAdjustMeasureRefTimeout {
get {
return ResourceManager.GetString("StrStatusErrorAdjustMeasureRefTimeout", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Time measurement double pulse on DUT detected.
/// </summary>
internal static string StrStatusErrorDoublePulseOnDutDetected {
get {
return ResourceManager.GetString("StrStatusErrorDoublePulseOnDutDetected", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Time measurement DUT signal timeout.
/// </summary>
internal static string StrStatusErrorTimeMeasureDutTimeout {
get {
return ResourceManager.GetString("StrStatusErrorTimeMeasureDutTimeout", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Time measurement REF signal timeout.
/// </summary>
internal static string StrStatusErrorTimeMeasureRefTimeout {
get {
return ResourceManager.GetString("StrStatusErrorTimeMeasureRefTimeout", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Double pulse deadtime missing or out of range.
/// </summary>
internal static string StrStatusFault1DoublePulseDeadtimeMissingOrOor {
get {
return ResourceManager.GetString("StrStatusFault1DoublePulseDeadtimeMissingOrOor", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Required pulses DUT setup out of range.
/// </summary>
internal static string StrStatusFault1DutPulseSetupOor {
get {
return ResourceManager.GetString("StrStatusFault1DutPulseSetupOor", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Required pulses REF setup out of range.
/// </summary>
internal static string StrStatusFault1RefPulseSetupOor {
get {
return ResourceManager.GetString("StrStatusFault1RefPulseSetupOor", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Scale REF to DUT missing or out of range.
/// </summary>
internal static string StrStatusFault1ScaleRefToDutMissingOrOor {
get {
return ResourceManager.GetString("StrStatusFault1ScaleRefToDutMissingOrOor", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Tolerance display error.
/// </summary>
internal static string StrStatusFault1UiConverter {
get {
return ResourceManager.GetString("StrStatusFault1UiConverter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to FLASH access error, setups set to default.
/// </summary>
internal static string StrStatusFault2FlashAccessError {
get {
return ResourceManager.GetString("StrStatusFault2FlashAccessError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Tolerance display attenuation missing.
/// </summary>
internal static string StrStatusFault2MissingToleranceAttenuation {
get {
return ResourceManager.GetString("StrStatusFault2MissingToleranceAttenuation", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Regulation measurement DUT ready.
/// </summary>
internal static string StrStatusMeasAdjustMeasureDutRdy {
get {
return ResourceManager.GetString("StrStatusMeasAdjustMeasureDutRdy", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Regulation measurement REF ready.
/// </summary>
internal static string StrStatusMeasAdjustMeasureRefRdy {
get {
return ResourceManager.GetString("StrStatusMeasAdjustMeasureRefRdy", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Double pulse deadtime inactive.
/// </summary>
internal static string StrStatusMeasDoublePulseDeadtimeInactive {
get {
return ResourceManager.GetString("StrStatusMeasDoublePulseDeadtimeInactive", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Time measurement DUT active.
/// </summary>
internal static string StrStatusMeasTimeMeasureDutActive {
get {
return ResourceManager.GetString("StrStatusMeasTimeMeasureDutActive", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Time measurement DUT ready.
/// </summary>
internal static string StrStatusMeasTimeMeasureDutRdy {
get {
return ResourceManager.GetString("StrStatusMeasTimeMeasureDutRdy", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Time measurement REF active.
/// </summary>
internal static string StrStatusMeasTimeMeasureRefActive {
get {
return ResourceManager.GetString("StrStatusMeasTimeMeasureRefActive", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Time measurement REF ready.
/// </summary>
internal static string StrStatusMeasTimeMeasureRefRdy {
get {
return ResourceManager.GetString("StrStatusMeasTimeMeasureRefRdy", resourceCulture);
}
}
}
}

View File

@ -333,4 +333,61 @@
<data name="StrInputMsgDoublePulseDeadTime" xml:space="preserve">
<value>Doppelimpulstotzeit</value>
</data>
<data name="StrStatusMeasDoublePulseDeadtimeInactive" xml:space="preserve">
<value>Doppelimpulstotzeit inaktiv</value>
</data>
<data name="StrStatusMeasTimeMeasureRefRdy" xml:space="preserve">
<value>Zeitmessungsmessung REF fertig</value>
</data>
<data name="StrStatusMeasTimeMeasureDutRdy" xml:space="preserve">
<value>Zeitmessungsmessung DUT fertig</value>
</data>
<data name="StrStatusMeasTimeMeasureRefActive" xml:space="preserve">
<value>Zeitmessungsmessung REF aktiv</value>
</data>
<data name="StrStatusMeasTimeMeasureDutActive" xml:space="preserve">
<value>Zeitmessungsmessung DUT aktiv</value>
</data>
<data name="StrStatusMeasAdjustMeasureRefRdy" xml:space="preserve">
<value>Regulierungsmessung REF fertig</value>
</data>
<data name="StrStatusMeasAdjustMeasureDutRdy" xml:space="preserve">
<value>Regulierungsmessung DUT fertig</value>
</data>
<data name="StrStatusFault2FlashAccessError" xml:space="preserve">
<value>FLASH Zugriffsfehler, Einstellungen auf Standard</value>
</data>
<data name="StrStatusFault2MissingToleranceAttenuation" xml:space="preserve">
<value>Fehlende oder falsche Toleranzanzeigendämpfungseinstellung</value>
</data>
<data name="StrStatusFault1UiConverter" xml:space="preserve">
<value>Toleranzanzeigenfehler</value>
</data>
<data name="StrStatusFault1RefPulseSetupOor" xml:space="preserve">
<value>Bereichsüberschreitung Impulszähler REF</value>
</data>
<data name="StrStatusFault1DutPulseSetupOor" xml:space="preserve">
<value>Bereichsüberschreitung Impulszähler DUT </value>
</data>
<data name="StrStatusFault1ScaleRefToDutMissingOrOor" xml:space="preserve">
<value>Falsche oder fehlende Skalierung REF zu DUT</value>
</data>
<data name="StrStatusFault1DoublePulseDeadtimeMissingOrOor" xml:space="preserve">
<value>Fehlerhafte Doppelimpulstotzeit</value>
</data>
<data name="StrStatusErrorAdjustMeasureRefTimeout" xml:space="preserve">
<value>Regulierungsmessung REF Signaltimeout</value>
</data>
<data name="StrStatusErrorAdjustMeasureDutTimeout" xml:space="preserve">
<value>Regulierungsmessung DUT Signaltimeout</value>
</data>
<data name="StrStatusErrorTimeMeasureRefTimeout" xml:space="preserve">
<value>Zeitmessung REF Signaltimeout</value>
</data>
<data name="StrStatusErrorTimeMeasureDutTimeout" xml:space="preserve">
<value>Zeitmessung DUT Signaltimeout</value>
</data>
<data name="StrStatusErrorDoublePulseOnDutDetected" xml:space="preserve">
<value>Zeitmessung Doppelimpuls DUT erkannt</value>
</data>
</root>

View File

@ -333,4 +333,61 @@
<data name="StrInputMsgDoublePulseDeadTime" xml:space="preserve">
<value>Double pulse daedtime</value>
</data>
<data name="StrStatusMeasDoublePulseDeadtimeInactive" xml:space="preserve">
<value>Double pulse deadtime inactive</value>
</data>
<data name="StrStatusMeasTimeMeasureRefRdy" xml:space="preserve">
<value>Time measurement REF ready</value>
</data>
<data name="StrStatusMeasTimeMeasureDutRdy" xml:space="preserve">
<value>Time measurement DUT ready</value>
</data>
<data name="StrStatusMeasTimeMeasureRefActive" xml:space="preserve">
<value>Time measurement REF active</value>
</data>
<data name="StrStatusMeasTimeMeasureDutActive" xml:space="preserve">
<value>Time measurement DUT active</value>
</data>
<data name="StrStatusMeasAdjustMeasureRefRdy" xml:space="preserve">
<value>Regulation measurement REF ready</value>
</data>
<data name="StrStatusMeasAdjustMeasureDutRdy" xml:space="preserve">
<value>Regulation measurement DUT ready</value>
</data>
<data name="StrStatusFault2FlashAccessError" xml:space="preserve">
<value>FLASH access error, setups set to default</value>
</data>
<data name="StrStatusFault2MissingToleranceAttenuation" xml:space="preserve">
<value>Tolerance display attenuation missing</value>
</data>
<data name="StrStatusFault1UiConverter" xml:space="preserve">
<value>Tolerance display error</value>
</data>
<data name="StrStatusFault1RefPulseSetupOor" xml:space="preserve">
<value>Required pulses REF setup out of range</value>
</data>
<data name="StrStatusFault1DutPulseSetupOor" xml:space="preserve">
<value>Required pulses DUT setup out of range</value>
</data>
<data name="StrStatusFault1ScaleRefToDutMissingOrOor" xml:space="preserve">
<value>Scale REF to DUT missing or out of range</value>
</data>
<data name="StrStatusFault1DoublePulseDeadtimeMissingOrOor" xml:space="preserve">
<value>Double pulse deadtime missing or out of range</value>
</data>
<data name="StrStatusErrorAdjustMeasureRefTimeout" xml:space="preserve">
<value>Regulation measurement REF signal timeout</value>
</data>
<data name="StrStatusErrorAdjustMeasureDutTimeout" xml:space="preserve">
<value>Regulation measurement DUT signal timeout</value>
</data>
<data name="StrStatusErrorTimeMeasureRefTimeout" xml:space="preserve">
<value>Time measurement REF signal timeout</value>
</data>
<data name="StrStatusErrorTimeMeasureDutTimeout" xml:space="preserve">
<value>Time measurement DUT signal timeout</value>
</data>
<data name="StrStatusErrorDoublePulseOnDutDetected" xml:space="preserve">
<value>Time measurement double pulse on DUT detected</value>
</data>
</root>

View File

@ -43,6 +43,12 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Gener
/// <remarks date="2025-Dec-15" author="Thomas Wiedebusch">
/// - Reboot counter temporary deactivated with WARNING.
/// </remarks>
/// <remarks date="2026-Feb-12" author="Thomas Wiedebusch">
/// - Reboot counter reactivated.
/// </remarks>
/// <remarks date="2026-Mar-05" author="Thomas Wiedebusch">
/// - Reboot counter for NA region temporary deactivated.
/// </remarks>
public override StatusReturn ExecuteProcess()
{
Boolean retVal;
@ -79,10 +85,18 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Gener
{
if (rebootCount > MeterResetPsu.MAX_REBOOTS_FOR_HEALTHY_HW)
{
ErrorMsgDispatcher(Resources.StrErrorMsgTooManyReboots +
$" - {Resources.StrProcessStateAllowed}: {MeterResetPsu.MAX_REBOOTS_FOR_HEALTHY_HW}" +
$" - {Resources.StrProcessStateDetected}: {rebootCount}");
return StatusReturn.Failed;
if (Meter.Region.Equals("NA"))
{
WarningMsgDispatcher(Resources.StrWarningRebootCounterCheckSkipped +
$" - {Resources.StrProcessStateDetected}: {rebootCount}");
}
else // EMEA
{
ErrorMsgDispatcher(Resources.StrErrorMsgTooManyReboots +
$" - {Resources.StrProcessStateAllowed}: {MeterResetPsu.MAX_REBOOTS_FOR_HEALTHY_HW}" +
$" - {Resources.StrProcessStateDetected}: {rebootCount}");
return StatusReturn.Failed;
}
}
// Skip reboot counter check on reties as it passed here the initial phase as a retry may follow an

View File

@ -2718,9 +2718,9 @@ namespace Xylem.Common.Production.ProductionUiCordonel.Properties {
/// <summary>
/// Looks up a localized string similar to WARNING: Reboot counter check skipped.
/// </summary>
internal static string StrWarningRebbotCounterCheckSkipped {
internal static string StrWarningRebootCounterCheckSkipped {
get {
return ResourceManager.GetString("StrWarningRebbotCounterCheckSkipped", resourceCulture);
return ResourceManager.GetString("StrWarningRebootCounterCheckSkipped", resourceCulture);
}
}
}

View File

@ -682,7 +682,7 @@
<data name="StrWarningMsgProcess" xml:space="preserve">
<value>WARNUNG: Ergebnis muß überprüft werden! Prozeß </value>
</data>
<data name="StrWarningRebbotCounterCheckSkipped" xml:space="preserve">
<data name="StrWarningRebootCounterCheckSkipped" xml:space="preserve">
<value>WARNUNG: Hardwareneustartüberprüfung (Reboot) ausgelassen</value>
</data>
<data name="StrErrorMsgTooManyReboots" xml:space="preserve">

View File

@ -682,7 +682,7 @@
<data name="StrWarningMsgProcess" xml:space="preserve">
<value>WARNING: Result needs inspection! Process</value>
</data>
<data name="StrWarningRebbotCounterCheckSkipped" xml:space="preserve">
<data name="StrWarningRebootCounterCheckSkipped" xml:space="preserve">
<value>WARNING: Reboot counter check skipped</value>
</data>
<data name="StrErrorMsgTooManyReboots" xml:space="preserve">

View File

@ -193,20 +193,21 @@
</Grid.ColumnDefinitions>
<!-- Common labels for all devices -->
<Label x:Name="lblSlotSelection" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="5" Content="Slot Selection:" />
<Label x:Name="lblConnectStatusText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="5" Content="Status:" />
<Label x:Name="lblMeasurement1Text" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="5" Content="Measurement1:" />
<Label x:Name="lblMeasurement2Text" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="5" Content="Measurement2:" />
<Label x:Name="lblMeasurement3Text" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="5" Content="Measurement3:" />
<Label x:Name="lblMeasurement4Text" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="5" Content="Measurement4:" />
<Label x:Name="lblMeasurement5Text" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="5" Content="Measurement5:" />
<Label x:Name="lblMeasurement6Text" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="5" Content="Measurement6:" />
<Label x:Name="lblMeasurement7Text" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="8" Grid.Column="0" Grid.ColumnSpan="5" Content="Measurement7:" />
<Label x:Name="lblFwVersionText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="9" Grid.Column="0" Grid.ColumnSpan="5" Content="FW Version:" />
<Label x:Name="lblSerialNumberText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="10" Grid.Column="0" Grid.ColumnSpan="5" Content="Serial Number:" />
<Label x:Name="lblLifeTimeText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="11" Grid.Column="0" Grid.ColumnSpan="5" Content="Lifetime:" />
<Label x:Name="lblSlotSelection" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="5" Content="Slot Selection:" />
<Label x:Name="lblConnectStatusText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="5" Content="Status:" />
<Label x:Name="lblMeasurement1Text" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="5" Content="Measurement1:" />
<Label x:Name="lblMeasurement2Text" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="5" Content="Measurement2:" />
<Label x:Name="lblMeasurement3Text" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="5" Content="Measurement3:" />
<Label x:Name="lblMeasurement4Text" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="5" Content="Measurement4:" />
<Label x:Name="lblMeasurement5Text" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="5" Content="Measurement5:" />
<Label x:Name="lblMeasurement6Text" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="5" Content="Measurement6:" />
<Label x:Name="lblMeasurement7Text" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="8" Grid.Column="0" Grid.ColumnSpan="5" Content="Measurement7:" />
<Label x:Name="lblFwVersionText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="9" Grid.Column="0" Grid.ColumnSpan="5" Content="FW Version:" />
<Label x:Name="lblSerialNumberText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="10" Grid.Column="0" Grid.ColumnSpan="5" Content="Serial Number:" />
<Label x:Name="lblLifeTimeText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="11" Grid.Column="0" Grid.ColumnSpan="5" Content="Lifetime:" />
<CheckBox x:Name="chkDecodeEntireStatus" HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="1,1,1,1" Grid.Row="13" Grid.Column="5" Grid.ColumnSpan="6" Content="Decode Entire Status" Click="chkDecodeEntireStatus_CheckChanged"/>
<Button x:Name="btnFM2014Connect" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="13" Grid.Column="0" Grid.ColumnSpan="4" Content="Connect" Click="btnConnect_Click" />
<Button x:Name="btnFM2014Connect" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="13" Grid.Column="0" Grid.ColumnSpan="4" Content="Connect" Click="btnConnect_Click" />
<!-- Rectangle for common measurement labels for all devices -->
<Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="25" Stroke="LightGray"/>
@ -266,8 +267,8 @@
<!--Process Information-->
<GroupBox Header="Info" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,0" Grid.Row="2" Grid.RowSpan="23" Grid.Column="26" Grid.ColumnSpan="14" >
<RichTextBox x:Name="rtbLog" Margin="0,0,0,0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" AcceptsTab="True" Width="Auto" UseLayoutRounding="False" HorizontalAlignment="Left" FontSize="9" >
<FlowDocument PageWidth="1000"/>
<RichTextBox x:Name="rtbLog" Margin="0,0,0,0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" AcceptsTab="True" Width="Auto" UseLayoutRounding="False" HorizontalAlignment="Left" FontSize="9" MouseWheel="rtbLog_MouseWheel" PreviewMouseWheel="rtbLog_MouseWheel" >
<FlowDocument PageWidth="1200"/>
</RichTextBox>
</GroupBox>

View File

@ -464,9 +464,12 @@ namespace Sensus.Ui.FM2014TestBench
ClearInfoWindow();
if (_version != null)
{
var version = $"Version: {_version.Major}.{_version.Minor}.{_version.Build}";
// Logging to history window
var timeUtc = DateTime.UtcNow;
var timeUtcStr = $"{timeUtc:yyyy-MM-dd HH:mm:ss:fff} UTC";
var version = $"Version: {_version}";
Title = $@"FM2014 Test Bench - {version}";
LogText($"FM2014 Test Bench: {version}");
LogText($"{timeUtcStr} - FM2014 Test Bench: {version}");
LogText(StrSeparator);
}
@ -581,6 +584,7 @@ namespace Sensus.Ui.FM2014TestBench
// Dispatch multilingual denotation to GUI elements
btnFM2014Connect.Content = StrBtnConnect;
chkDecodeEntireStatus.Content = StrChkDecodeEntireStatus;
// Measurement selection tab setup
tabDutToRefRegulation.Header = StrGbxDutToRefRegulation;
@ -762,10 +766,13 @@ namespace Sensus.Ui.FM2014TestBench
if (fm2014.IsLoggedOn)
{
// Logging to history window
var timeUtc = DateTime.UtcNow;
var timeUtcStr = $"{timeUtc:yyyy-MM-dd HH:mm:ss:fff} UTC";
LogText(StrSeparator);
LogText($"Ad: {fm2014.Address} - FM2014 ID: {fm2014.ConnectResponse}");
LogText($"Ad: {fm2014.Address} - FM2014 Firmware Version: {fm2014.FwVersion}");
LogText($"Ad: {fm2014.Address} - FM2014 {StrLblFM2014SerialNumber} {fm2014.SerialNumber}");
LogText($"{timeUtcStr} - Ad: {fm2014.Address} - FM2014 ID: {fm2014.ConnectResponse}");
LogText($"{timeUtcStr} - Ad: {fm2014.Address} - FM2014 Firmware Version: {fm2014.FwVersion}");
LogText($"{timeUtcStr} - Ad: {fm2014.Address} - FM2014 {StrLblFM2014SerialNumber} {fm2014.SerialNumber}");
LogText(StrSeparator);
}
}
@ -1209,7 +1216,7 @@ namespace Sensus.Ui.FM2014TestBench
else if (e.StatusReturn == StatusReturn.MeasurementInRange)
statusColor = ColorSuccess;
var timeUtcStr = $"{resp.TimestampUtc:yyyy-MM-dd HH:mm:ss} UTC";
var timeUtcStr = $"{resp.TimestampUtc:yyyy-MM-dd HH:mm:ss:fff} UTC";
if (e.StatusReturn == StatusReturn.Failed)
{
LogErrorText($"{timeUtcStr} - Ad: {fm2014.Address} - {resp.AnswerStr}");
@ -1283,19 +1290,19 @@ namespace Sensus.Ui.FM2014TestBench
}
else if (resp.DoubleValue != null)
{
LogText($"{timeUtcStr} - Ad: {fm2014.Address} - {resp.AnswerStr}: {resp.DoubleValue:F4} {resp.Unit}");
LogText($"{timeUtcStr} - Ad: {fm2014.Address} - {resp.AnswerStr}: {resp.DoubleValue:F6} {resp.Unit}");
switch (resp.CmdName)
{
case CmdName.CmdGetRefTimerTicks:
valueStr = $"{resp.DoubleValue:F4}";
valueStr = $"{resp.DoubleValue:F3}";
ucFm2014?.SetValue(CAL_LBL_IDX_REF_MEAS_TMR, valueStr, statusColor);
break;
case CmdName.CmdGetDutTimerTicks:
valueStr = $"{resp.DoubleValue:F4}";
valueStr = $"{resp.DoubleValue:F3}";
ucFm2014?.SetValue(CAL_LBL_IDX_DUT_MEAS_TMR, valueStr, statusColor);
break;
case CmdName.CmdCalculatedDutToRefTolerance:
valueStr = $"{resp.DoubleValue:F4}";
valueStr = $"{resp.DoubleValue:F3}";
ucFm2014?.SetValue(CAL_LBL_IDX_DUT_TO_REF_TOL, valueStr, statusColor);
break;
case CmdName.CmdGetDutToRefToleranceUndamped:
@ -1366,7 +1373,7 @@ namespace Sensus.Ui.FM2014TestBench
private void btnDutToRefCalibration_Click(Object sender, EventArgs e)
{
_startTime = DateTimeOffset.UtcNow;
if (FM2014.SharedCyclicMeasSequ == CyclicMeasSequ.idle)
if (FM2014.SharedCyclicMeasSequ == CyclicMeasSequ.Idle)
{
// Disable and hide dynamic measurement labels
foreach (var measLbl in MeasurementLabels)
@ -1411,7 +1418,6 @@ namespace Sensus.Ui.FM2014TestBench
if (refPulsesRequired != null && dutPulsesRequired != null)
{
UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_DUT_TO_REF_TOL],
StrLblDutToRefToleranceMeasured);
}
@ -1436,9 +1442,21 @@ namespace Sensus.Ui.FM2014TestBench
// Set initial required pulses as those are static upon the entire measurement
if (refPulsesRequired != null)
{
ucFM2014.SetValue(CAL_LBL_IDX_REF_REQ_PLS, $"{_fm2014Common.RefPulsesRequired:D}");
ucFM2014.SetValue(CAL_LBL_IDX_REF_MEAS_TMR, "---");
}
if (dutPulsesRequired != null)
{
ucFM2014.SetValue(CAL_LBL_IDX_DUT_REQ_PLS, $"{_fm2014Common.DutPulsesRequired:D}");
ucFM2014.SetValue(CAL_LBL_IDX_DUT_MEAS_TMR, "---");
}
if (refPulsesRequired != null && dutPulsesRequired != null)
{
ucFM2014.SetValue(CAL_LBL_IDX_DUT_TO_REF_TOL, "---");
}
// Set thresholds for tolerance verification
fm2014.DutToRefCalibrationToleranceMax_percent = _fm2014Common.DutToRefCalibrationToleranceMax_percent;
@ -1474,7 +1492,7 @@ namespace Sensus.Ui.FM2014TestBench
private void btnDutToRefRegulation_Click(Object sender, EventArgs e)
{
_startTime = DateTimeOffset.UtcNow;
if (FM2014.SharedCyclicMeasSequ == CyclicMeasSequ.idle)
if (FM2014.SharedCyclicMeasSequ == CyclicMeasSequ.Idle)
{
// Disable and hide dynamic measurement labels
foreach (var measLbl in MeasurementLabels)
@ -1498,6 +1516,9 @@ namespace Sensus.Ui.FM2014TestBench
var ucFM2014 = (UcFM2014Device)UcFM2014s[idx];
ucFM2014.EnableMeasurements(REG_MEASURE_COUNT);
fm2014.CurrentOutputDisplayRangeNominal_percent = _fm2014Common.CurrentOutputDisplayRangeNominal_percent;
ucFM2014.SetValue(REG_LBL_IDX_REF_FREQU, "---");
ucFM2014.SetValue(REG_LBL_IDX_FLOW_RATE, "---");
ucFM2014.SetValue(REG_LBL_IDX_DUT_TO_REF_TOL, "---");
}
// Backup if meanwhile anything has changed
@ -1531,7 +1552,7 @@ namespace Sensus.Ui.FM2014TestBench
private void btnRefToVolumeCalibration_Click(Object sender, EventArgs e)
{
_startTime = DateTimeOffset.UtcNow;
if (FM2014.SharedCyclicMeasSequ == CyclicMeasSequ.idle)
if (FM2014.SharedCyclicMeasSequ == CyclicMeasSequ.Idle)
{
// Disable and hide dynamic measurement labels
foreach (var measLbl in MeasurementLabels)
@ -1729,6 +1750,24 @@ namespace Sensus.Ui.FM2014TestBench
}));
}
/// <summary>
/// Enable/Disable input
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void chkDecodeEntireStatus_CheckChanged(Object sender, EventArgs e)
{
Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(() =>
{
if (FM2014.RegisteredFm2014s == null || FM2014.RegisteredFm2014s.Count <= 0)
return;
if (chkDecodeEntireStatus.IsChecked != null)
FM2014.DecodeEntireStatus = (Boolean)chkDecodeEntireStatus.IsChecked;
}));
}
/// <summary>
/// Enable/Disable input
/// </summary>
@ -2491,7 +2530,7 @@ namespace Sensus.Ui.FM2014TestBench
{
// Calculate the new pulse ratio based on the manual calibration
var pulses_per_cm = FM2014.CalculatePulsesPerCm(pulses, liters);
// Try to set the new calculated REF pulses limited by the property setter
_fm2014Common.RefPulses_per_cm = pulses_per_cm;
@ -2539,7 +2578,34 @@ namespace Sensus.Ui.FM2014TestBench
}
/// <summary>
/// Change the font size on mouse wheel and [Ctrl] button.
/// Needs to be registered for:
/// 1. MouseWheel="rtbLog_MouseWheel" and
/// 2. PreviewMouseWheel="rtbLog_MouseWheel",
/// otherwise the window will first scroll up/down and only reaching the limits (fully up/down) firing the
/// MouseWheel event!
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-25" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void rtbLog_MouseWheel(Object sender, MouseWheelEventArgs e)
{
if (Keyboard.IsKeyDown(Key.RightCtrl) || Keyboard.IsKeyDown(Key.LeftCtrl))
{
e.Handled = true;
if (e.Delta > 0)
{
Dispatcher.Invoke(() => rtbLog.FontSize += 1);
}
else
{
Dispatcher.Invoke(() => rtbLog.FontSize -= 1);
}
}
}
#endregion ---------------------------------------- Buttons and Controls --------------------------------------
}
}

View File

@ -13,7 +13,7 @@
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<Deterministic>false</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>

View File

@ -26,7 +26,7 @@ using System.Windows;
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
//[assembly: NeutralResourcesLanguage("en", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
@ -46,5 +46,4 @@ using System.Windows;
// Build Number
// Revision
//
[assembly: AssemblyVersion("1.0.1.0")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyVersion("1.0.2.*")]

View File

@ -123,6 +123,15 @@ namespace Sensus.Ui.Fm2014TestBench.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Decode Entire Status.
/// </summary>
internal static string StrChkDecodeEntireStatus {
get {
return ResourceManager.GetString("StrChkDecodeEntireStatus", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Damped Tolerance On.
/// </summary>

View File

@ -294,4 +294,7 @@
<data name="StrSelectDutTimeMeasurement" xml:space="preserve">
<value>DUT Impulszeitmessung</value>
</data>
<data name="StrChkDecodeEntireStatus" xml:space="preserve">
<value>Alle Statusbits Decodieren</value>
</data>
</root>

View File

@ -294,4 +294,7 @@
<data name="StrSelectDutTimeMeasurement" xml:space="preserve">
<value>DUT Pulse Time Measurement</value>
</data>
<data name="StrChkDecodeEntireStatus" xml:space="preserve">
<value>Decode Entire Status</value>
</data>
</root>

View File

@ -23,13 +23,13 @@
<!-- Bordered Static Labels -->
<Label Name="lblStatus" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="OFFLINE" />
<Label Name="lblMeasurement1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="0" />
<Label Name="lblMeasurement2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="0" />
<Label Name="lblMeasurement3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="0" />
<Label Name="lblMeasurement4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="0" />
<Label Name="lblMeasurement5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="0" />
<Label Name="lblMeasurement6" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="0" />
<Label Name="lblMeasurement7" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="0" />
<Label Name="lblMeasurement1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="---" />
<Label Name="lblMeasurement2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="---" />
<Label Name="lblMeasurement3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="---" />
<Label Name="lblMeasurement4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="---" />
<Label Name="lblMeasurement5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="---" />
<Label Name="lblMeasurement6" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="---" />
<Label Name="lblMeasurement7" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="---" />
<Label Name="lblFirmwareVersion" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="8" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="---" />
<Label Name="lblSerialNumber" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="9" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="---" />
<Label Name="lblLifetime_h" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="10" Grid.Column="0" Grid.ColumnSpan="2" HorizontalContentAlignment="Center" Content="---" />