FM2014TestBench: - initial setup to test multiple FM2014 - 5.Step

This commit is contained in:
Thomas Wiedebusch 2026-02-05 11:56:15 +01:00
parent 22b4cad5fc
commit 82cc3be1e8
6 changed files with 422 additions and 288 deletions

View File

@ -32,6 +32,7 @@
*/
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using Xylem.Common.CommonCore.Consts;
@ -63,10 +64,21 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Config
/// </summary>
public Int32? TolerancePercent { get; set; }
/// <summary>
/// Address of the FM2014
/// </summary>
public List<Int32?> IndividualTolerancePercent { get; set; }
/// <summary>
/// Serial baudrate for FM2014 serial bus
/// </summary>
public static Int32 Baudrate { get; set; } = 1200;
public Int32 Baudrate { get; set; } = 1200;
/// <summary>
/// Serial baudrate for FM2014 serial bus
/// </summary>
public List<Boolean?> SlotIsSelected { get; set; }
#endregion
@ -77,6 +89,9 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Config
/// <remarks date="2025-Nov-13" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2026-Feb-05" author="Thomas Wiedebusch">
/// - Support multiple FM2014 with shared port but slot selected and individual tolerance.
/// </remarks>
public Boolean ReadFM2014Config()
{
// Check for AppRoaming
@ -92,6 +107,8 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Config
SerialPort = null;
Address = null;
TolerancePercent = null;
SlotIsSelected = null;
IndividualTolerancePercent = null;
return false;
}
}
@ -102,6 +119,9 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Config
SerialPort = fm2014Setup.SerialPort;
Address = fm2014Setup.Address;
TolerancePercent = fm2014Setup.TolerancePercent;
Baudrate = fm2014Setup.Baudrate;
IndividualTolerancePercent = fm2014Setup.IndividualTolerancePercent;
SlotIsSelected = fm2014Setup.SlotIsSelected;
}
return true;
@ -124,7 +144,6 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Config
var configFile = Path.Combine(path, ProgramConfig.FM2014ConfigFileName);
File.WriteAllText(configFile, JsonConvert.SerializeObject(this));
File.WriteAllText(ProgramConfig.FM2014ConfigFileName, JsonConvert.SerializeObject(this));
}
#endregion
}

View File

@ -69,39 +69,44 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// 'W' - 'REF pulses per volume'! The REF pulses/cm can then be restored using
/// 'Ref_pulses_per_cm = Dut_pulses_per_cm * RefToDutScale_norm'
/// </summary>
private const UInt32 RefPulsesPerVolumeRegulationSetupInvalidMarker = 1;
private const UInt32 REF_PULSES_PER_VOLUME_INVALID_MARKER = 1;
/// <summary>
/// fm2014 is the minimum value which can be stored to the FM2014 with commands
/// 'V' - 'DUT pulses per volume' and 'W' - 'REF pulses per volume'!
/// </summary>
private const UInt32 PulsesPerVolumeRegulationSetupMin = 1;
private const UInt32 PULSES_PER_CM_REGULATION_SETUP_MIN = 1;
/// <summary>
/// This is the maximum value which can be stored to the FM2014 with command
/// 'V' - 'DUT pulses per volume'!
/// </summary>
private const UInt32 PulsesPerVolumeRegulationSetupMax = 9999;
private const UInt32 PULSES_PER_CM_REGULATION_SETUP_MAX = 9999;
/// <summary>
/// This is the maximum input value for the REF which CANNOT be stored to FM2014
/// but will be used to calculate the 'RefToDutScale_norm'.
/// </summary>
private const UInt32 RefPulsesPerCmRegulationInputLimitMax = 100000000;
private const UInt32 REF_PULSES_PER_CM_REGULATION_INPUT_MAX = 100000000;
/// <summary>
/// Publish the FM2014 minimum REF to DUT scale for error display.
/// </summary>
public const Double RefToDutScaleMin = 0.0001;
public const Double REF_TO_DUT_SCALE_MIN = 0.0001;
/// <summary>
/// Publish the FM2014 maximum REF to DUT scale for error display.
/// </summary>
public const Double RefToDutScaleMax = 999.9;
public const Double REF_TO_DUT_SCALE_MAX = 999.9;
/// <summary>
/// The mantissa for the scale value has to be in the range from 1000 to 9999.
/// </summary>
private const UInt16 MantissaScaleMin = 1000;
private const UInt16 MANTISSA_SCALE_MIN = 1000;
/// <summary>
/// Default tolerance if not properly setup.
/// </summary>
public const Int32 DEFAULT_TOLERANCE_percent = 3;
#endregion ---------------------------------------- constants -------------------------------------------------
@ -204,7 +209,8 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// <summary>
/// Private tolerance percentage
/// </summary>
private Int32 _tolerance_percent = 3;
private Int32 _tolerance_percent = DEFAULT_TOLERANCE_percent;
/// <summary>
/// Actual tolerance scale to convert raw value from FM2014 to percent
/// </summary>
@ -222,7 +228,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
// Limit input to discrete setting of 3 or 5 %,
// internally those values are going to be scaled to 3.3 or 5.5
Single percentage;
if (value == 3)
if (value == DEFAULT_TOLERANCE_percent)
percentage = 3.3f;
else if (value == 5)
percentage = 5.5f;
@ -296,8 +302,8 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
set
{
// Check limits and equality
if (value < PulsesPerVolumeRegulationSetupMin ||
value > RefPulsesPerCmRegulationInputLimitMax ||
if (value < PULSES_PER_CM_REGULATION_SETUP_MIN ||
value > REF_PULSES_PER_CM_REGULATION_INPUT_MAX ||
value == _ref_pulse_per_cm)
return;
@ -318,8 +324,8 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
// Check limits and equality, the DUT max input is 9999 as this will be
// directly stored to FM2014'V' - 'DUT pulses per volume'
if (value < PulsesPerVolumeRegulationSetupMin ||
value > PulsesPerVolumeRegulationSetupMax ||
if (value < PULSES_PER_CM_REGULATION_SETUP_MIN ||
value > PULSES_PER_CM_REGULATION_SETUP_MAX ||
value == _dut_pulse_per_cm)
return;
@ -358,7 +364,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
get => _refToDutScale_norm;
private set
{
if (value > RefToDutScaleMax || value < RefToDutScaleMin)
if (value > REF_TO_DUT_SCALE_MAX || value < REF_TO_DUT_SCALE_MIN)
return;
_refToDutScale_norm = value;
@ -370,7 +376,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
number *= 10.0;
mantissa = (UInt16)(number + 0.5);
exponent--;
} while (mantissa < MantissaScaleMin);
} while (mantissa < MANTISSA_SCALE_MIN);
// The pre-generated string will be used to send it to the FM2014 directly
_refToDutScaleStr = $"{mantissa}{GetCmdStr(CmdName.CMD_REF_SET_SCALE)}{exponent}";
@ -422,22 +428,22 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// <summary>
/// Number of processing steps for this actual process progress
/// </summary>
private Int32 MaxActualProcessProgress { get; set; }
private static Int32 MaxActualProcessProgress { get; set; }
/// <summary>
/// Progress of actual process converted to percent
/// </summary>
private Double _actualProcessProgress_percent;
private static Double _actualProcessProgress_percent;
/// <summary>
/// Progress of actual process
/// </summary>
private Int32 _actualProcessProgress;
private static Int32 _actualProcessProgress;
/// <summary>
/// Actual process progress of subroutine
/// </summary>
private Int32 ActualProcessProgress
private static Int32 ActualProcessProgress
{
get => _actualProcessProgress;
set
@ -454,12 +460,51 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
#region ------------------------------------------- static methods --------------------------------------------
/// <summary>
/// Executes all StoreConfiguration and StoreCalibration for each application.
/// Executes all StoreConfiguration and StoreCalibration for each FM2014 which is logged on.
/// </summary>
/// <returns>true if all configurations are stored</returns>
/// <remarks date="2026-Feb-05" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
public static Boolean StoreAllConfigurations()
{
return false;
if (SharedCyclicMeasSequ == CyclicMeasSequ.IDLE)
return false;
var retVal = true;
InitActualProcessProgress();
foreach (var fm2014 in RegisteredFm2014s.Where(fm2014 => fm2014.IsLoggedOn))
{
retVal &= fm2014.SaveStandAloneMeasurement();
ActualProcessProgress++;
}
return retVal;
}
/// <summary>
/// Common routine to set up the counter for max process progress based on connected
/// and logged in devices and set the actual process progress to zero.
/// </summary>
/// <remarks date="2026-Feb-05" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private static void InitActualProcessProgress(Int32? maxInitProcesses = null)
{
MaxActualProcessProgress = 0;
ActualProcessProgress = 0;
if (maxInitProcesses != null)
{
MaxActualProcessProgress = (Int32)maxInitProcesses;
return;
}
foreach (var fm2014 in RegisteredFm2014s.Where(fm2014 => fm2014.IsLoggedOn))
{
MaxActualProcessProgress++;
}
}
/// <summary>
@ -776,7 +821,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// - REF and DUT counters together using the synchronized backup.
/// - Each FM2014 can use a different REF and/or DUT setting as the REF is parallel for all FM2014s.
/// Preconditions:
/// - The <see cref="ResetMeasurementAllDevices"/> has to be executed in advance.
/// - The <see cref="ResetHardwareAllDevices"/> has to be executed in advance.
/// Initial setup:
/// - Starts the pulse counter measurement of REF and/or DUT.
/// Cyclic:
@ -956,7 +1001,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// <summary>
/// The regulation measurement compares the DUT to REF tolerance:
/// Preconditions:
/// - The <see cref="ResetMeasurementAllDevices"/> has to be executed in advance,
/// - The <see cref="ResetHardwareAllDevices"/> has to be executed in advance,
/// - The <see cref="Ref_pulse_per_cm"/>REF pulses per cubic meter has to be preset,
/// - The <see cref="Dut_pulse_per_cm"/>DUT pulses per cubic meter has to be preset,
/// - The <see cref="RefToDutScale_norm"/>Scale for REF to DUT pulses has to be preset.
@ -983,8 +1028,8 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
if (Ref_pulse_per_cm == 0 ||
Dut_pulse_per_cm == 0 ||
RefToDutScale_norm < RefToDutScaleMin ||
RefToDutScale_norm > RefToDutScaleMax ||
RefToDutScale_norm < REF_TO_DUT_SCALE_MIN ||
RefToDutScale_norm > REF_TO_DUT_SCALE_MAX ||
!IsLoggedOn)
{
return false;
@ -1001,7 +1046,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
var cmdName = CmdName.CMD_NA;
var measurementInfo = Resources.StrMeasMsgRegulation;
InitActualProcessProgress(3);
// Prepare regulation measurement
try
{
@ -1010,18 +1055,19 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
return false;
}
ActualProcessProgress++;
cmdName = CmdName.CMD_MEAS_SET_ATTN;
if (!Write(cmdName, this, Attenuation))
{
return false;
}
ActualProcessProgress++;
cmdName = CmdName.CMD_REF_SET_SCALE;
if (!Write(cmdName, this, _refToDutScaleStr))
{
return false;
}
ActualProcessProgress++;
}
catch (Exception e)
{
@ -1039,6 +1085,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
do
{
InitActualProcessProgress();
foreach (var fm2014 in RegisteredFm2014s.Where(fm2014 => fm2014.IsLoggedOn))
{
try
@ -1218,8 +1265,8 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
{
// Set to zero if it doesn't fit to the limit which can be stored as indicator for invalid value
// which should be recovered by 'Ref_pulses_per_cm = Dut_pulses_per_cm * RefToDutScale_norm'
var limitedRefPulsesPerCm = Ref_pulse_per_cm <= PulsesPerVolumeRegulationSetupMax ?
Ref_pulse_per_cm : RefPulsesPerVolumeRegulationSetupInvalidMarker;
var limitedRefPulsesPerCm = Ref_pulse_per_cm <= PULSES_PER_CM_REGULATION_SETUP_MAX ?
Ref_pulse_per_cm : REF_PULSES_PER_VOLUME_INVALID_MARKER;
var retVal = Write(cmdName, this, (UInt16)limitedRefPulsesPerCm);
if (retVal)
@ -1422,11 +1469,12 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// <remarks date="2026-Jan-28..30" author="Thomas Wiedebusch">
/// - Support for multiple FM2014s.
/// </remarks>
public Boolean ResetMeasurementAllDevices()
public Boolean ResetHardwareAllDevices()
{
if (SharedCyclicMeasSequ == CyclicMeasSequ.IDLE)
return true;
InitActualProcessProgress();
// Exit tasks
SharedCyclicMeasSequ = CyclicMeasSequ.IDLE;
@ -1445,7 +1493,6 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
var resetDelayCtr_ms = 4000;
const Int32 loopTime_ms = 500;
MaxActualProcessProgress = resetDelayCtr_ms / loopTime_ms;
ActualProcessProgress = 0;
do
{
// Change the SI unit to ms instead of seconds
@ -1457,7 +1504,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
specificInfoObj: response));
Thread.Sleep(loopTime_ms);
resetDelayCtr_ms -= loopTime_ms;
ActualProcessProgress += 1;
ActualProcessProgress++;
} while (resetDelayCtr_ms >= 0);
}, SharedCancellationToken);
@ -1480,27 +1527,27 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// <summary>
/// Forcing to reset all measurements before the start of a new one:
/// - This will enable to keep the measurements and NOT clear those in the reset method,
/// <see cref="ResetMeasurementAllDevices"/> as this should be used to prepare the hardware for
/// <see cref="ResetHardwareAllDevices"/> as this should be used to prepare the hardware for
/// the new measurement after it being able to start the new measurement immediately!
/// </summary>
private static void ClearMeasurementResultsForAllDevices()
{
}
/// <summary>
/// Connect to individual FM2014:
/// - This is initially used to assign and set up the SharedSerialPort which will be shared upon
/// all devices.
/// - Additionally, it is going to log in to the individual device for early detection which one is
/// connected to the SharedSerialPort.
/// - Additionally, it is going to read out the individual device information for early detection
/// which one is responsive on the SharedSerialPort.
/// </summary>
/// <param name="comPort"></param>
/// <returns></returns>
/// <remarks date="2026-Jan-28" author="Thomas Wiedebusch">
/// - Support for multiple FM2014s.
/// </remarks>
/// <remarks date="2026-Feb-04" author="Thomas Wiedebusch">
/// <remarks date="2026-Feb-04..05" author="Thomas Wiedebusch">
/// - ´Login to individual FM2014.
/// </remarks>
public Boolean Connect(String comPort)
@ -1565,12 +1612,6 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
RegisteredFm2014s.Add(this);
// Reset pulse ratios to force a preset with 'standalone' settings from
// FM2014 wit '%D@' - Read 'Default Measurement Setup'
_ref_pulse_per_cm = 0;
_dut_pulse_per_cm = 0;
SharedCmdTypeReminderLastCmd = CmdType.NOT_INITIALIZED;
return IsLoggedOn;
}
@ -1598,7 +1639,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
public void Dispose()
{
Logout();
ResetMeasurementAllDevices();
ResetHardwareAllDevices();
RegisteredFm2014s?.Clear();
RegisteredFm2014s = null;
SharedSerialPort?.Dispose();

View File

@ -622,10 +622,10 @@ namespace Sensus.Ui.FM2014TestApp
// Display error if scale doesn't fit
var tempRefToDutScale_norm = (Double)Fm2014.Ref_pulse_per_cm / Fm2014.Dut_pulse_per_cm;
if (tempRefToDutScale_norm < FM2014.RefToDutScaleMin ||
tempRefToDutScale_norm > FM2014.RefToDutScaleMax ||
Fm2014.RefToDutScale_norm < FM2014.RefToDutScaleMin ||
Fm2014.RefToDutScale_norm > FM2014.RefToDutScaleMax)
if (tempRefToDutScale_norm < FM2014.REF_TO_DUT_SCALE_MIN ||
tempRefToDutScale_norm > FM2014.REF_TO_DUT_SCALE_MAX ||
Fm2014.RefToDutScale_norm < FM2014.REF_TO_DUT_SCALE_MIN ||
Fm2014.RefToDutScale_norm > FM2014.REF_TO_DUT_SCALE_MAX)
{
tbxScaleRefToDut.BackColor = ColorProcessFailed;
tbxScaleRefToDut.Text = Resources.StrError;
@ -788,7 +788,7 @@ namespace Sensus.Ui.FM2014TestApp
_autoProgressBar = false;
// Deactivate the button temporary to avoid repeated execution as the reset takes a certain time
btnDutToRefRegulation.Enabled = false;
Fm2014.ResetMeasurementAllDevices();
Fm2014.ResetHardwareAllDevices();
ActionControl(false);
btnDutToRefRegulation.Text = Resources.StrBtnStartRegulation;
}
@ -839,7 +839,7 @@ namespace Sensus.Ui.FM2014TestApp
_autoProgressBar = false;
// Deactivate the button temporary to avoid repeated execution as the reset takes a certain time
btnManualRefCalibration.Enabled = false;
Fm2014.ResetMeasurementAllDevices();
Fm2014.ResetHardwareAllDevices();
ActionControl(false);
btnManualRefCalibration.Text = Resources.StrBtnStartCalibration;
}

View File

@ -16,9 +16,12 @@
<!-- Menu -->
<MenuItem x:Name="optionsMenu" HorizontalAlignment="Right" Height="26" Width="60" Header="_Options" >
<MenuItem x:Name="optionsMenuLogin" Header="_Login" HorizontalAlignment="Left"/> <!--Click="OnLogin_Click"/-->
<MenuItem x:Name="optionsMenuLogout" Header="L_ogout" HorizontalAlignment="Left"/><!-- Click="OnLogout_Click"/-->
<MenuItem x:Name="optionsMenuChangePassword" Header="Change Password" HorizontalAlignment="Left"/> <!--Click="OnChangePassword_Click"/-->
<MenuItem x:Name="optionsMenuLogin" Header="_Login" HorizontalAlignment="Left"/>
<!--Click="OnLogin_Click"/-->
<MenuItem x:Name="optionsMenuLogout" Header="L_ogout" HorizontalAlignment="Left"/>
<!-- Click="OnLogout_Click"/-->
<MenuItem x:Name="optionsMenuChangePassword" Header="Change Password" HorizontalAlignment="Left"/>
<!--Click="OnChangePassword_Click"/-->
</MenuItem>
<Label Content="Serial Port:" Margin="2,2,2,2"/>
<ComboBox x:Name="cbxFM2014ComPort" Margin="2,2,2,2" SelectionChanged="cbxFM2014BaseSettings_SelectedValueChanged"/>
@ -203,9 +206,9 @@
<Label x:Name="lblFwVersionText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="9" Grid.Column="0" Grid.ColumnSpan="4" Content="FW Version:" />
<Label x:Name="lblSerialNumberText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="10" Grid.Column="0" Grid.ColumnSpan="4" Content="Serial Number:" />
<Label x:Name="lblLifeTimeText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="11" Grid.Column="0" Grid.ColumnSpan="4" Content="Lifetime:" />
<Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" 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="24" Stroke="LightGray"/>
<Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,-1,-1,0" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4" Stroke="LightGray"/>
@ -243,17 +246,17 @@
<Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="-1,0,0,0" Grid.Row="0" Grid.RowSpan="12" Grid.Column="18" Grid.ColumnSpan="2" Stroke="LightGray"/>
<Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="-1,0,0,0" Grid.Row="0" Grid.RowSpan="12" Grid.Column="20" Grid.ColumnSpan="2" Stroke="LightGray"/>
<Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="-1,0,0,0" Grid.Row="0" Grid.RowSpan="12" Grid.Column="22" Grid.ColumnSpan="2" Stroke="LightGray"/>
<CheckBox x:Name="cbxSlot1" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="4" Grid.ColumnSpan="2" Content="1" IsChecked="True"/>
<CheckBox x:Name="cbxSlot2" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="6" Grid.ColumnSpan="2" Content="2" IsChecked="True"/>
<CheckBox x:Name="cbxSlot3" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="8" Grid.ColumnSpan="2" Content="3" IsChecked="True"/>
<CheckBox x:Name="cbxSlot4" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="10" Grid.ColumnSpan="2" Content="4" IsChecked="True"/>
<CheckBox x:Name="cbxSlot5" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="12" Grid.ColumnSpan="2" Content="5" IsChecked="True"/>
<CheckBox x:Name="cbxSlot6" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="14" Grid.ColumnSpan="2" Content="6" IsChecked="True"/>
<CheckBox x:Name="cbxSlot7" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="16" Grid.ColumnSpan="2" Content="7" IsChecked="True"/>
<CheckBox x:Name="cbxSlot8" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="18" Grid.ColumnSpan="2" Content="8" IsChecked="True"/>
<CheckBox x:Name="cbxSlot9" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="20" Grid.ColumnSpan="2" Content="9" IsChecked="True"/>
<CheckBox x:Name="cbxSlot10" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="22" Grid.ColumnSpan="2" Content="10" IsChecked="True"/>
<CheckBox x:Name="cbxSlot1" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="4" Grid.ColumnSpan="2" Content="1" IsChecked="True" Click="cbxSlot1_Click"/>
<CheckBox x:Name="cbxSlot2" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="6" Grid.ColumnSpan="2" Content="2" IsChecked="True" Click="cbxSlot1_Click"/>
<CheckBox x:Name="cbxSlot3" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="8" Grid.ColumnSpan="2" Content="3" IsChecked="True" Click="cbxSlot1_Click"/>
<CheckBox x:Name="cbxSlot4" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="10" Grid.ColumnSpan="2" Content="4" IsChecked="True" Click="cbxSlot1_Click"/>
<CheckBox x:Name="cbxSlot5" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="12" Grid.ColumnSpan="2" Content="5" IsChecked="True" Click="cbxSlot1_Click"/>
<CheckBox x:Name="cbxSlot6" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="14" Grid.ColumnSpan="2" Content="6" IsChecked="True" Click="cbxSlot1_Click"/>
<CheckBox x:Name="cbxSlot7" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="16" Grid.ColumnSpan="2" Content="7" IsChecked="True" Click="cbxSlot1_Click"/>
<CheckBox x:Name="cbxSlot8" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="18" Grid.ColumnSpan="2" Content="8" IsChecked="True" Click="cbxSlot1_Click"/>
<CheckBox x:Name="cbxSlot9" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="20" Grid.ColumnSpan="2" Content="9" IsChecked="True" Click="cbxSlot1_Click"/>
<CheckBox x:Name="cbxSlot10" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" Grid.Row="0" Grid.Column="22" Grid.ColumnSpan="2" Content="10" IsChecked="True" Click="cbxSlot1_Click"/>
</Grid>
</GroupBox>
@ -272,8 +275,8 @@
<!--Progress Bars and Info-->
<ProgressBar x:Name="pbSubProgress" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,2,2,2" Grid.Row="25" Grid.Column="0" Grid.ColumnSpan="40" />
<ProgressBar x:Name="pbTotalProgress" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,2,2,2" Grid.Row="26" Grid.Column="0" Grid.ColumnSpan="40" />
<Label x:Name="lblSingleProgressText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,0,1,0" Grid.Row="25" Grid.Column="0" Grid.ColumnSpan="8" Content="Single Progress:" />
<Label x:Name="lblTotalProgressText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,0,1,0" Grid.Row="26" Grid.Column="0" Grid.ColumnSpan="8" Content="Total Progress:" />
<Label x:Name="lblSingleProgressText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,0,1,0" Grid.Row="25" Grid.Column="0" Grid.ColumnSpan="8" Content="Single Progress" />
<Label x:Name="lblTotalProgressText" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,0,1,0" Grid.Row="26" Grid.Column="0" Grid.ColumnSpan="8" Content="Total Progress" />
<Label x:Name="lblSingleProgressValue" HorizontalAlignment="Right" VerticalAlignment="Stretch" Margin="1,0,1,0" Grid.Row="25" Grid.Column="37" Grid.ColumnSpan="3" Content="0,0 %" />
<Label x:Name="lblTotalProgressValue" HorizontalAlignment="Right" VerticalAlignment="Stretch" Margin="1,0,1,0" Grid.Row="26" Grid.Column="37" Grid.ColumnSpan="3" Content="0,0 %" />

View File

@ -112,9 +112,9 @@ namespace Sensus.Ui.FM2014TestBench
private static readonly Brush ColorProcessFailed = Brushes.Red;
//private static readonly Color ColorOngoingProcess = Color.Blue;
//private static readonly Color ColorUnknownStatus = Color.Gray;
private static Brush ColorStandardInputField;
private static Brush ColorStandardDisplayField;
private static Brush ColorStandardTextColor;
//private static Brush ColorStandardInputField;
//private static Brush ColorStandardDisplayField;
//private static Brush ColorStandardTextColor;
//private const String SuccessSign = @"✔";
//private const String FailedSign = @"✘";
@ -127,19 +127,18 @@ namespace Sensus.Ui.FM2014TestBench
private readonly FM2014Config _fm2014Config = new FM2014Config();
// internal reminders of changed items to avoid write access on startup if items are preloaded
private Int32 _comPortIdx = 0;
private Int32 _addressIdx;
private Int32 _toleranceIdx;
private Int32 _comPortIdx;
// Backups of results from 'Manual REF Calibration' being able to restore those if a manual change
// of the REF pulses per cubic meter clears those fields. Bringing the last calibrated REF pulses
// per cubic meters back will automatically restore these results being able to adjust the measured
// volume in liters without a restart of the 'Manual REF Calibration'
private String _backupWeightScaleVolumeLitersStr;
private String _backupRefCalibrationResultPulsePerCmStr;
private String _backupMeasuredRefPulsesStr;
//private String _backupWeightScaleVolumeLitersStr;
//private String _backupRefCalibrationResultPulsePerCmStr;
//private String _backupMeasuredRefPulsesStr;
private Boolean _regulationSetupHasChanged;
//private Boolean _regulationSetupHasChanged;
private Boolean _setupHasChanged;
private String _lastLoggingTextToAvoidRepetition;
@ -219,7 +218,7 @@ namespace Sensus.Ui.FM2014TestBench
/// </summary>
/// <param name="sp"></param>
/// <param name="uc">new UserControl or null to remove it</param>
private void SetNewUserControl(StackPanel sp, UserControl uc = null)
private void SetNewUserControl(StackPanel sp, UserControl uc)
{
sp.Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(() =>
@ -363,11 +362,18 @@ namespace Sensus.Ui.FM2014TestBench
/// Clear object lists, initialize and assign all objects:
/// - 10 x FM2014 objects including address assignment based on the panel number,
/// - 10 x FM2014 user controls,
/// - Assign a common receive handler.
/// - Assign a common receive handler,
/// - Load configuration:
/// - ComPort,
/// - Slot selections,
/// - Individual hardware tolerance selection.
/// </summary>
/// <remarks date="2025-Nov-13" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2026-Feb-05" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void Init()
{
ActionControl(false);
@ -381,7 +387,9 @@ namespace Sensus.Ui.FM2014TestBench
}
_autoProgressBar = false;
_regulationSetupHasChanged = false;
// Load the configuration from the local file stored in AppData\FM2014
_fm2014Config.ReadFM2014Config();
// Clear and dispose all FM2014 objects
if (Fm2014s.Count != 0)
@ -389,7 +397,7 @@ namespace Sensus.Ui.FM2014TestBench
for (var ctr = 0; ctr < Fm2014s.Count; ctr++)
{
// Remove objects from user control panel
SetNewUserControl(PanelsForUcFM2014s[ctr]);
SetNewUserControl(PanelsForUcFM2014s[ctr], null);
// Kill FM2014
Fm2014s[ctr].OnRawRecordReceived -= DataReceived_Handler;
@ -410,24 +418,29 @@ namespace Sensus.Ui.FM2014TestBench
fm2014.OnRawRecordReceived += DataReceived_Handler;
Fm2014s.Add(fm2014);
var userControl = new UcFM2014Device(fm2014);
var userControl = new UcFM2014Device(fm2014, StoreFM2014Settings);
UcFM2014s.Add(userControl);
SetNewUserControl(PanelsForUcFM2014s[ctr], UcFM2014s[ctr]);
if (_fm2014Config?.SlotIsSelected?[ctr] != null &&
_fm2014Config.SlotIsSelected.Count == MaxFm2014s &&
SlotSelections.Count == MaxFm2014s)
SlotSelections[ctr].IsChecked = _fm2014Config?.SlotIsSelected[ctr] ?? false;
if (_fm2014Config?.IndividualTolerancePercent?[ctr] != null &&
_fm2014Config.IndividualTolerancePercent.Count == MaxFm2014s)
fm2014.Tolerance_percent = _fm2014Config?.IndividualTolerancePercent[ctr] ??
FM2014.DEFAULT_TOLERANCE_percent;
}
//grpBoxDebug.Visible = false;
//gbxDutToRefRegulation.Visible = true;
//gbxRegulationSetup.Visible = true;
// Load the configuration from the local file stored in AppData\FM2014
_fm2014Config.ReadFM2014Config();
// Display actual com-port, if not assigned use the '?'. This will be placed on Items[0]
if (_fm2014Config.SerialPort != null && !cbxFM2014ComPort.Items.Contains(_fm2014Config.SerialPort))
if (_fm2014Config?.SerialPort != null && !cbxFM2014ComPort.Items.Contains(_fm2014Config.SerialPort))
{
cbxFM2014ComPort.Items.Add(_fm2014Config.SerialPort);
}
else if (_fm2014Config.SerialPort == null && !cbxFM2014ComPort.Items.Contains("?"))
else if (_fm2014Config?.SerialPort == null && !cbxFM2014ComPort.Items.Contains("?"))
{
cbxFM2014ComPort.Items.Add("?");
}
@ -440,16 +453,6 @@ namespace Sensus.Ui.FM2014TestBench
cbxFM2014ComPort.Text = cbxFM2014ComPort.Items[_comPortIdx]?.ToString();
//itemContent = _fm2014Config?.TolerancePercent ?? 3;
//for (var idx = 0; idx < cbxFM2014TolerancePercent.MaxDropDownItems; idx++)
//{
// if (!cbxFM2014TolerancePercent.Items[idx].ToString().Equals(itemContent.ToString())) continue;
// _toleranceIdx = idx;
// cbxFM2014TolerancePercent.SelectedItem = cbxFM2014TolerancePercent.Items[idx];
// break;
//}
//// FM2014 group box
//lblConnectionStatus.Text = Resources.StrLblFM2014NotConnected;
//lblConnectionStatus.ForeColor = ColorProcessFailed;
@ -504,7 +507,7 @@ namespace Sensus.Ui.FM2014TestBench
}
/// <summary>
/// Store the settings adjusted by the UI
/// Store the settings adjusted by the UI or the UcFM2014Device
/// </summary>
/// <remarks date="2025-Nov-13" author="Thomas Wiedebusch">
/// - Initial.
@ -512,17 +515,33 @@ namespace Sensus.Ui.FM2014TestBench
/// <remarks date="2026-Jan-15" author="Thomas Wiedebusch">
/// - Update FM2014 properties.
/// </remarks>
/// <remarks date="2026-Feb-05" author="Thomas Wiedebusch">
/// - Store individual tolerances and test bench slot selections.
/// </remarks>
private void StoreFM2014Settings()
{
if (_fm2014Config == null)
return;
_setupHasChanged = false;
_fm2014Config.IndividualTolerancePercent?.Clear();
_fm2014Config.IndividualTolerancePercent = null;
_fm2014Config.IndividualTolerancePercent = new List<Int32?>();
_fm2014Config.SlotIsSelected?.Clear();
_fm2014Config.SlotIsSelected = null;
_fm2014Config.SlotIsSelected = new List<Boolean?>();
_fm2014Config.SerialPort = cbxFM2014ComPort.Text;
//if (int.TryParse(cbxFM2014TolerancePercent.SelectedItem.ToString(), out var tolerancePercent)
// && (tolerancePercent == 3 || tolerancePercent == 5))
//{
// _fm2014Config.TolerancePercent = tolerancePercent;
// if (Fm2014 != null)
// Fm2014.Tolerance_percent = tolerancePercent;
//}
for (var ctr = 0; ctr < MaxFm2014s; ctr++)
{
var fm2014 = Fm2014s[ctr];
if (fm2014 == null)
return;
_fm2014Config.IndividualTolerancePercent.Add(fm2014.Tolerance_percent);
_fm2014Config.SlotIsSelected.Add(SlotSelections[ctr].IsChecked);
}
_fm2014Config.Update();
}
@ -536,6 +555,9 @@ namespace Sensus.Ui.FM2014TestBench
{
try
{
if (_setupHasChanged)
StoreFM2014Settings();
Init();
if (string.IsNullOrEmpty(cbxFM2014ComPort?.SelectedItem?.ToString()) ||
cbxFM2014ComPort.SelectedItem.ToString().Equals("?"))
@ -877,6 +899,158 @@ namespace Sensus.Ui.FM2014TestBench
SetFM2014AccessEnabled();
}
#endregion ---------------------------------------- ActivationControls ----------------------------------------
#region ------------------------------------------- Event handler ---------------------------------------------
/// <summary>
/// Feedback from FM2014being parsed to GUI
/// </summary>
/// <remarks date="2023-Feb-02" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void DataReceived_Handler(Object sender, ProcessExecEventArgs e)
{
//var address = 0;
//if (sender is FM2014 fm2014)
//{
// address = fm2014.Address;
//}
// Progress info section
if (e.ActualProcessMessage != null)
{
UpdateContentControl(lblSingleProgressText, e.ActualProcessMessage);
}
if (e.ActualProcessPercent != null && !_autoProgressBar)
{
pbSubProgress.Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(() =>
{
pbSubProgress.Value = (Int32)e.ActualProcessPercent;
UpdateContentControl(lblTotalProgressValue, $@"{e.ActualProcessPercent:##0.0} %");
}
));
}
if (e.OverallProcessMessage != null)
{
UpdateContentControl(lblSingleProgressText, e.OverallProcessMessage);
}
if (e.OverallProcessPercent != null && !_autoProgressBar)
{
pbTotalProgress.Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(() =>
{
pbTotalProgress.Value = (Int32)e.OverallProcessPercent;
UpdateContentControl(lblTotalProgressValue, $@"{e.OverallProcessPercent:##0.0} %");
}
));
}
SetTimeDisplay();
// Data dispatcher
var resp = (CmdResponse)e.SpecificInfoObj;
if (e.StatusReturn == StatusReturn.Failed)
{
LogErrorText(resp.AnswerStr);
//ErrorHandler(resp.CmdName);
}
else if (resp.IntValue == null && resp.DoubleValue == null)
{
LogText(resp.AnswerStr);
}
else if (resp.IntValue != null)
{
LogText($"{resp.AnswerStr}: {resp.IntValue:D} {resp.SiUnit}");
//switch (resp.CmdName)
//{
//case FM2014CmdDef.CmdName.CMD_REF_GET_PLS_CTR:
//case FM2014CmdDef.CmdName.CMD_REF_GET_PLS_CTR_BU:
// tbxMeasuredRefPulses.Text = $@"{resp.IntValue:D}";
// break;
//case FM2014CmdDef.CmdName.CMD_DUT_GET_PLS_CTR:
//case FM2014CmdDef.CmdName.CMD_DUT_GET_PLS_CTR_BU:
// tbxMeasuredDutPulses.Text = $@"{resp.IntValue:D}";
// break;
//case FM2014CmdDef.CmdName.CMD_REF_LPP_SCALE:
// tbxRefPulsePerCm.Text = $@"{resp.IntValue:D}";
// break;
//case FM2014CmdDef.CmdName.CMD_DUT_LPP_SCALE:
// tbxDutPulsePerCm.Text = $@"{resp.IntValue:D}";
// break;
//case FM2014CmdDef.CmdName.CMD_MEAS_SET_ATTN:
// var idx = cbxAttenuation.FindString($@"{resp.IntValue}");
// cbxAttenuation.SelectedIndex = idx;
// break;
//case FM2014CmdDef.CmdName.CMD_GET_REF_FREQU:
// tbxRefFrequencyHz.Text = $@"{resp.IntValue:D}";
// tbxRefFrequencyDirectHz.Text = $@"{resp.IntValue:D}";
// if (resp.IntValue < 1 || resp.IntValue > 254)
// {
// tbxRefFrequencyHz.BackColor = ColorProcessFailed;
// tbxActualFlowRateCmPerHour.BackColor = ColorProcessFailed;
// }
// else
// {
// tbxRefFrequencyHz.BackColor = ColorStandardDisplayField;
// tbxActualFlowRateCmPerHour.BackColor = ColorStandardDisplayField;
// }
// break;
//}
}
else if (resp.DoubleValue != null)
{
LogText($"{resp.AnswerStr}: {resp.DoubleValue:F2} {resp.SiUnit}");
//switch (resp.CmdName)
//{
// case FM2014CmdDef.CmdName.CMD_GET_UDTLC:
// case FM2014CmdDef.CmdName.CMD_GET_DTLC:
// tbxActualMeasuredToleranceDutToRef.Text = $@"{resp.DoubleValue:F2}";
// if (resp.DoubleValue < -Fm2014.Tolerance_percent ||
// resp.DoubleValue > Fm2014.Tolerance_percent)
// {
// tbxActualMeasuredToleranceDutToRef.BackColor = ColorProcessFailed;
// }
// else
// {
// tbxActualMeasuredToleranceDutToRef.BackColor = ColorStandardDisplayField;
// }
// break;
// case FM2014CmdDef.CmdName.CMD_REF_SET_SCALE:
// tbxScaleRefToDut.Text = $@"{resp.DoubleValue:F4}";
// break;
// // DEBUG
// case FM2014CmdDef.CmdName.CMD_GET_REF_PERIOD:
// tbxRefPeriodMs.Text = $@"{resp.DoubleValue:F3}";
// break;
// case FM2014CmdDef.CmdName.CMD_GET_DUT_PERIOD:
// tbxDutPeriodMs.Text = $@"{resp.DoubleValue:F3}";
// break;
// case FM2014CmdDef.CmdName.CMD_CAL_FREQU_REF_PERIOD:
// tbxRefFrequencyFromRefPeriodHz.Text = $@"{resp.DoubleValue:F3}";
// break;
// case FM2014CmdDef.CmdName.CMD_CAL_FREQU_DUT_PERIOD:
// tbxDutFrequencyFromDutPeriodHz.Text = $@"{resp.DoubleValue:F3}";
// break;
// case FM2014CmdDef.CmdName.CMD_CAL_FLOW_REF_FREQU:
// tbxRefFlowRateFromRefFrequencyCmPerH.Text = $@"{resp.DoubleValue:F3}";
// // TODO THW Check if the actual flow shall be taken based on 'REF Frequency'
// tbxActualFlowRateCmPerHour.Text = $@"{resp.DoubleValue:F3}";
// break;
// case FM2014CmdDef.CmdName.CMD_CAL_FLOW_REF_PERIOD:
// tbxRefFlowRateFromRefPeriodCmPerH.Text = $@"{resp.DoubleValue:F3}";
// break;
// case FM2014CmdDef.CmdName.CMD_CAL_FLOW_DUT_PERIOD:
// tbxDutFlowRateFromDutPeriodCmPerH.Text = $@"{resp.DoubleValue:F3}";
// break;
//}
}
}
#endregion ---------------------------------------- Event handler ---------------------------------------------
#region ------------------------------------------- Buttons and Controls --------------------------------------
/// <summary>
/// Establish connection to FM2014 with individual address and read out FM2014 info.
@ -994,15 +1168,11 @@ namespace Sensus.Ui.FM2014TestBench
/// </remarks>
private void cbxFM2014BaseSettings_SelectedValueChanged(Object sender, EventArgs e)
{
//if (_toleranceIdx != cbxFM2014TolerancePercent.SelectedIndex ||
// _addressIdx != cbxFM2014Address.SelectedIndex ||
// _comPortIdx != cbxFM2014ComPort.SelectedIndex)
//{
// _toleranceIdx = cbxFM2014TolerancePercent.SelectedIndex;
// _addressIdx = cbxFM2014Address.SelectedIndex;
// _comPortIdx = cbxFM2014ComPort.SelectedIndex;
// StoreFM2014Settings();
//}
if (_comPortIdx != cbxFM2014ComPort.SelectedIndex)
{
_comPortIdx = cbxFM2014ComPort.SelectedIndex;
StoreFM2014Settings();
}
}
/// <summary>
@ -1341,22 +1511,6 @@ namespace Sensus.Ui.FM2014TestBench
//}
}
/// <summary>
/// Switch between DEBUG and regular operation
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void picFM2014_Click(Object sender, EventArgs e)
{
//grpBoxDebug.Visible = !grpBoxDebug.Visible;
//if (Fm2014 != null)
// Fm2014.RequestDebugInformation = grpBoxDebug.Visible;
////gbxDutToRefRegulation.Visible = !grpBoxDebug.Visible;
//gbxRegulationSetup.Visible = !grpBoxDebug.Visible;
}
/// <summary>
/// Select next control on enter key pressed
/// </summary>
@ -1369,159 +1523,12 @@ namespace Sensus.Ui.FM2014TestBench
// SelectNextControl(ActiveControl, true, true, true, true);
//}
}
#endregion ---------------------------------------- Buttons and Controls --------------------------------------
#region ------------------------------------------- Event handler ---------------------------------------------
/// <summary>
/// Feedback from FM2014being parsed to GUI
/// </summary>
/// <remarks date="2023-Feb-02" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void DataReceived_Handler(Object sender, ProcessExecEventArgs e)
private void cbxSlot1_Click(Object sender, RoutedEventArgs e)
{
var address = 0;
if (sender is FM2014 fm2014)
{
address = fm2014.Address;
}
// Progress info section
if (e.ActualProcessMessage != null)
{
UpdateContentControl(lblSingleProgressText, e.ActualProcessMessage);
}
if (e.ActualProcessPercent != null && !_autoProgressBar)
{
pbSubProgress.Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(() =>
{
pbSubProgress.Value = (Int32)e.ActualProcessPercent;
UpdateContentControl(lblTotalProgressValue, $@"{e.ActualProcessPercent:##0.0} %");
}
));
}
if (e.OverallProcessMessage != null)
{
UpdateContentControl(lblSingleProgressText, e.OverallProcessMessage);
}
if (e.OverallProcessPercent != null && !_autoProgressBar)
{
pbTotalProgress.Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(() =>
{
pbTotalProgress.Value = (Int32)e.OverallProcessPercent;
UpdateContentControl(lblTotalProgressValue, $@"{e.OverallProcessPercent:##0.0} %");
}
));
}
SetTimeDisplay();
// Data dispatcher
var resp = (FM2014CmdDef.CmdResponse)e.SpecificInfoObj;
if (e.StatusReturn == StatusReturn.Failed)
{
LogErrorText(resp.AnswerStr);
//ErrorHandler(resp.CmdName);
}
else if (resp.IntValue == null && resp.DoubleValue == null)
{
LogText(resp.AnswerStr);
}
else if (resp.IntValue != null)
{
LogText($"{resp.AnswerStr}: {resp.IntValue:D} {resp.SiUnit}");
//switch (resp.CmdName)
//{
//case FM2014CmdDef.CmdName.CMD_REF_GET_PLS_CTR:
//case FM2014CmdDef.CmdName.CMD_REF_GET_PLS_CTR_BU:
// tbxMeasuredRefPulses.Text = $@"{resp.IntValue:D}";
// break;
//case FM2014CmdDef.CmdName.CMD_DUT_GET_PLS_CTR:
//case FM2014CmdDef.CmdName.CMD_DUT_GET_PLS_CTR_BU:
// tbxMeasuredDutPulses.Text = $@"{resp.IntValue:D}";
// break;
//case FM2014CmdDef.CmdName.CMD_REF_LPP_SCALE:
// tbxRefPulsePerCm.Text = $@"{resp.IntValue:D}";
// break;
//case FM2014CmdDef.CmdName.CMD_DUT_LPP_SCALE:
// tbxDutPulsePerCm.Text = $@"{resp.IntValue:D}";
// break;
//case FM2014CmdDef.CmdName.CMD_MEAS_SET_ATTN:
// var idx = cbxAttenuation.FindString($@"{resp.IntValue}");
// cbxAttenuation.SelectedIndex = idx;
// break;
//case FM2014CmdDef.CmdName.CMD_GET_REF_FREQU:
// tbxRefFrequencyHz.Text = $@"{resp.IntValue:D}";
// tbxRefFrequencyDirectHz.Text = $@"{resp.IntValue:D}";
// if (resp.IntValue < 1 || resp.IntValue > 254)
// {
// tbxRefFrequencyHz.BackColor = ColorProcessFailed;
// tbxActualFlowRateCmPerHour.BackColor = ColorProcessFailed;
// }
// else
// {
// tbxRefFrequencyHz.BackColor = ColorStandardDisplayField;
// tbxActualFlowRateCmPerHour.BackColor = ColorStandardDisplayField;
// }
// break;
//}
}
else if (resp.DoubleValue != null)
{
LogText($"{resp.AnswerStr}: {resp.DoubleValue:F2} {resp.SiUnit}");
//switch (resp.CmdName)
//{
// case FM2014CmdDef.CmdName.CMD_GET_UDTLC:
// case FM2014CmdDef.CmdName.CMD_GET_DTLC:
// tbxActualMeasuredToleranceDutToRef.Text = $@"{resp.DoubleValue:F2}";
// if (resp.DoubleValue < -Fm2014.Tolerance_percent ||
// resp.DoubleValue > Fm2014.Tolerance_percent)
// {
// tbxActualMeasuredToleranceDutToRef.BackColor = ColorProcessFailed;
// }
// else
// {
// tbxActualMeasuredToleranceDutToRef.BackColor = ColorStandardDisplayField;
// }
// break;
// case FM2014CmdDef.CmdName.CMD_REF_SET_SCALE:
// tbxScaleRefToDut.Text = $@"{resp.DoubleValue:F4}";
// break;
// // DEBUG
// case FM2014CmdDef.CmdName.CMD_GET_REF_PERIOD:
// tbxRefPeriodMs.Text = $@"{resp.DoubleValue:F3}";
// break;
// case FM2014CmdDef.CmdName.CMD_GET_DUT_PERIOD:
// tbxDutPeriodMs.Text = $@"{resp.DoubleValue:F3}";
// break;
// case FM2014CmdDef.CmdName.CMD_CAL_FREQU_REF_PERIOD:
// tbxRefFrequencyFromRefPeriodHz.Text = $@"{resp.DoubleValue:F3}";
// break;
// case FM2014CmdDef.CmdName.CMD_CAL_FREQU_DUT_PERIOD:
// tbxDutFrequencyFromDutPeriodHz.Text = $@"{resp.DoubleValue:F3}";
// break;
// case FM2014CmdDef.CmdName.CMD_CAL_FLOW_REF_FREQU:
// tbxRefFlowRateFromRefFrequencyCmPerH.Text = $@"{resp.DoubleValue:F3}";
// // TODO THW Check if the actual flow shall be taken based on 'REF Frequency'
// tbxActualFlowRateCmPerHour.Text = $@"{resp.DoubleValue:F3}";
// break;
// case FM2014CmdDef.CmdName.CMD_CAL_FLOW_REF_PERIOD:
// tbxRefFlowRateFromRefPeriodCmPerH.Text = $@"{resp.DoubleValue:F3}";
// break;
// case FM2014CmdDef.CmdName.CMD_CAL_FLOW_DUT_PERIOD:
// tbxDutFlowRateFromDutPeriodCmPerH.Text = $@"{resp.DoubleValue:F3}";
// break;
//}
}
_setupHasChanged = true;
}
#endregion ---------------------------------------- Event handler ---------------------------------------------
#endregion ---------------------------------------- Buttons and Controls --------------------------------------
}
}

View File

@ -26,18 +26,22 @@ namespace Sensus.Ui.Fm2014TestBench.UserControls
private readonly List<UIElement> MeasurementLabels;
private readonly FM2014 _fM2014;
private readonly Action _selectedAction;
/// <summary>
/// Ctor
/// </summary>
/// <param name="fm2014"></param>
/// <param name="setupHasChanged">kick off storage of changed setting to configuration file</param>
/// <remarks date="2026-Feb-03" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
public UcFM2014Device(FM2014 fm2014)
public UcFM2014Device(FM2014 fm2014, Action setupHasChanged)
{
InitializeComponent();
_fM2014 = fm2014;
_selectedAction = setupHasChanged;
MeasurementBorders = new List<UIElement>();
MeasurementLabels = new List<UIElement>();
MeasurementBorders.Add(brdMeasurement1);
@ -65,12 +69,66 @@ namespace Sensus.Ui.Fm2014TestBench.UserControls
HideMeasurements();
}
//TODO THW Setup device based on selections
//itemContent = fm2014.TolerancePercent ?? FM2014.DEFAULT_TOLERANCE_percent;
//for (var idx = 0; idx < cbxFM2014TolerancePercent.MaxDropDownItems; idx++)
//{
// if (!cbxFM2014TolerancePercent.Items[idx].ToString().Equals(itemContent.ToString())) continue;
// _toleranceIdx = idx;
// cbxFM2014TolerancePercent.SelectedItem = cbxFM2014TolerancePercent.Items[idx];
// break;
//}
/// <summary>
/// Set a value to a label
/// Safe the settings to configuration file.
/// </summary>
/// <param name="labelNumber"></param>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-03" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void btnSaveSettings_Click(Object sender, EventArgs e)
{
//TODO THW check if settings have changed before firing the event
//grpBoxDebug.Visible = !grpBoxDebug.Visible;
//if (Fm2014 != null)
// Fm2014.RequestDebugInformation = grpBoxDebug.Visible;
////gbxDutToRefRegulation.Visible = !grpBoxDebug.Visible;
//gbxRegulationSetup.Visible = !grpBoxDebug.Visible;
_selectedAction?.Invoke();
}
/// <summary>
/// Open the setting window
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-03" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void picFM2014_Click(Object sender, EventArgs e)
{
//grpBoxDebug.Visible = !grpBoxDebug.Visible;
//if (Fm2014 != null)
// Fm2014.RequestDebugInformation = grpBoxDebug.Visible;
////gbxDutToRefRegulation.Visible = !grpBoxDebug.Visible;
//gbxRegulationSetup.Visible = !grpBoxDebug.Visible;
}
/// <summary>
/// Set a value to a label:
/// - Input values 1..7 !
/// </summary>
/// <param name="labelNumber">1 to 7</param>
/// <param name="valueStr"></param>
/// <returns></returns>
/// <remarks date="2026-Feb-03" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
public Boolean SetValue(Int32 labelNumber, String valueStr)
{
var index = labelNumber - 1;
@ -215,6 +273,12 @@ namespace Sensus.Ui.Fm2014TestBench.UserControls
/// <param name="elm"></param>
/// <param name="isEnabled"></param>
/// <param name="isVisible"></param>
/// <remarks date="????" author="Roland Drabesch">
/// - Initial
/// </remarks>
/// <remarks date="2023-07-11" author="Thomas Wiedebusch">
/// - Introduced multi line text with center alignment.
/// </remarks>
private static void UiElmEnable(UIElement elm, Boolean isEnabled, Boolean isVisible = true)
{
elm.Dispatcher.Invoke(DispatcherPriority.Normal,