FM2014: - status decoder

This commit is contained in:
Thomas Wiedebusch 2026-02-25 16:54:54 +01:00
parent 0ab75f2235
commit 5e15654b7e
16 changed files with 810 additions and 281 deletions

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,13 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
public event EventHandler<ProcessExecEventArgs> OnRawRecordReceived;
#endregion ---------------------------------------- events ----------------------------------------------------
#region ------------------------------------------- static properties -----------------------------------------
/// <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 +343,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}";
}
}
@ -710,14 +717,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 +768,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 +868,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.
@ -932,23 +983,26 @@ 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();
if (firstActiveFm2014 == null)
return false;
// Setup status mask to ignore unimportant settings and feedbacks for the time and regulation measurement
StatusDecodingMask = GetBitMask(CyclicMeasSequ.PulseCounterMeasurement);
// Publish setting to all connected and logged in FM2014s as those will be delivered
// for all via broadcast
foreach (var fm2014 in RegisteredFm2014s.Where(fm2014 => fm2014.IsLoggedOn))
@ -1007,7 +1061,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
// Mark pulse counter measurement as active
SharedCyclicMeasSequ = CyclicMeasSequ.pulseCounterMeasurement;
SharedCyclicMeasSequ = CyclicMeasSequ.PulseCounterMeasurement;
do
{
@ -1034,7 +1088,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 +1099,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 +1110,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 +1130,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 +1173,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
@ -1148,6 +1192,9 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
if (firstActiveFm2014 == null)
return false;
// Setup status mask to ignore unimportant settings and feedbacks for the time measurement
StatusDecodingMask = GetBitMask(CyclicMeasSequ.RegulationMeasurement);
// Publish setting to all connected and logged in FM2014s as those will be delivered
// for all via broadcast
foreach (var fm2014 in RegisteredFm2014s.Where(fm2014 => fm2014.IsLoggedOn))
@ -1204,7 +1251,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
Task.Run(() =>
{
// Mark regulation measurement as active
SharedCyclicMeasSequ = CyclicMeasSequ.regulationMeasurement;
SharedCyclicMeasSequ = CyclicMeasSequ.RegulationMeasurement;
do
{
@ -1214,23 +1261,13 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
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 +1290,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 +1325,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 +1358,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 +1394,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 +1432,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-25" 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
@ -1423,6 +1460,9 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
return false;
}
// Setup status mask to ignore unimportant settings for this measurement 'T' and 'K'
StatusDecodingMask = GetBitMask(CyclicMeasSequ.TimeMeasurement);
// Publish setting to all connected and logged in FM2014s as those will be delivered
// for all via broadcast
foreach (var fm2014 in RegisteredFm2014s.Where(fm2014 => fm2014.IsLoggedOn))
@ -1486,7 +1526,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 :
@ -1500,24 +1540,14 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
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 +1579,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 +1619,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 +1641,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 +1663,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 +1707,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 +1849,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 +2141,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 +2157,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 +2220,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 GetBitMask(CyclicMeasSequ sequence)
{
if (sequence == CyclicMeasSequ.TimeMeasurement)
return 0xF8074D10;
if (sequence == CyclicMeasSequ.RegulationMeasurement)
return 0x83C04318;
if (sequence == CyclicMeasSequ.PulseCounterMeasurement)
return 0x80004010;
return 0xFFFFFFFF;
}
}
}

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

@ -266,8 +266,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);
}
@ -762,10 +765,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 +1215,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}");
@ -1366,7 +1372,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)
@ -1474,7 +1480,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)
@ -1531,7 +1537,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)
@ -2539,7 +2545,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.1.*")]