FM2014: - measurement check with positive feedback

This commit is contained in:
Thomas Wiedebusch 2026-02-16 16:47:10 +01:00
parent 312195ef86
commit d478d4dd5f
9 changed files with 469 additions and 424 deletions

View File

@ -31,7 +31,12 @@
Warning, Warning,
/// <summary> /// <summary>
/// the measurement is out of range /// the measurement is 'in-range' for threshold cheks
/// </summary>
MeasurementInRange,
/// <summary>
/// the measurement is out of range for threshold checks
/// </summary> /// </summary>
MeasurementOutOfRange MeasurementOutOfRange
} }

View File

@ -18,10 +18,23 @@ using Xylem.Common.CommonCore.Consts;
namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Config namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Config
{ {
/// <summary> /// <summary>
/// Configuration of the FM2014 on local machine: /// Configuration of the FM2014 on local machine to survive a restart of the FM2014 programs:
/// - Setup communication with serial com-port. /// - Access or create the FM2014 configuration file from the 'C:\ProgramData\FM2014' directory as this is depending
/// on the setup of the test-bench and should be accessible for every user without the need of re-adjustment of
/// these settings,
/// - Set up the shared communication port number,
/// - Set up the baudrate,
/// - Set up the last used address for the 'MiniPrf',
/// - Set up a common current-output-tolerance-display-range ( 3 % or 5 %),
/// - Set up an individual current-output-tolerance-display-range ( 3 % or 5 %) for the 'FM2014TestApp',
/// - Set up the selected (active) slots for the 'FM2014TestApp',
/// - Set up the 'RefPulsesRequired' for the calibration measurement the 'FM2014TestApp' for user convenience,
/// - Set up the 'DefPulsesRequired' for the calibration measurement the 'FM2014TestApp' for user convenience,
/// - Set up the 'DutToRefToleranceMax' for the calibration measurement the 'FM2014TestApp' for user convenience,
/// - Set up the 'DutToRefToleranceMin' for the calibration measurement the 'FM2014TestApp' for user convenience,
/// - Set up the 'DoublePulseDeadtime' for the calibration measurement the 'FM2014TestApp' for user convenience.
/// </summary> /// </summary>
/// <remarks date="2025-Nov-13" author="Thomas Wiedebusch"> /// <remarks date="2025-Nov-13..2026-Feb-16" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
public class FM2014Config public class FM2014Config
@ -30,22 +43,23 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Config
/// <summary> /// <summary>
/// Comport for the FM2014 /// Comport for the FM2014
/// </summary> /// </summary>
public String SerialPort { get; set; } public String SharedSerialPort { get; set; }
/// <summary>
/// Address of the FM2014
/// </summary>
public Int32? Address { get; set; }
/// <summary>
/// Address of the FM2014
/// </summary>
public Int32? TolerancePercent { get; set; }
/// <summary> /// <summary>
/// Address of the FM2014 /// Address of the FM2014
/// </summary> /// </summary>
public List<Int32?> IndividualTolerancePercent { get; set; } public Int32? Address { get; set; }
/// <summary>
/// Address of the FM2014
/// </summary>
public Int32 CommonCurrentOutputDisplayRangeNominal_percent { get; set; } = 3;
/// <summary>
/// Address of the FM2014
/// </summary>
public List<Int32?> IndividualCurrentOutputDisplayRangeNominal_percent { get; set; }
/// <summary> /// <summary>
@ -67,11 +81,11 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Config
/// Backup DUT pulses for calibration measurement to simplify manual setup /// Backup DUT pulses for calibration measurement to simplify manual setup
/// </summary> /// </summary>
public UInt16 DutPulsesRequired { get; set; } = 50; public UInt16 DutPulsesRequired { get; set; } = 50;
/// <summary> /// <summary>
/// Backup double pulses detection deadtime for calibration measurement to simplify manual setup /// Backup double pulses detection deadtime for calibration measurement to simplify manual setup
/// </summary> /// </summary>
public UInt16 DoublePulseDeadtime { get; set; } public UInt16 DoublePulseDeadtime { get; set; }
/// <summary> /// <summary>
/// Backup tolerance maximal value for calibration measurement threshold check to simplify manual setup /// Backup tolerance maximal value for calibration measurement threshold check to simplify manual setup
@ -86,18 +100,15 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Config
#region methods #region methods
/// <summary> /// <summary>
/// Load FM2014 configuration file from AppRoaming or working directory /// Load the FM2014 configuration file from the 'C:\ProgramData\FM2014' directory
/// </summary> /// </summary>
/// <remarks date="2025-Nov-13" author="Thomas Wiedebusch"> /// <remarks date="2025-Nov-13..2026-F3b-16" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </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() public Boolean ReadFM2014Config()
{ {
// Check for AppRoaming // Check for AppRoaming
var configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), var configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
nameof(FM2014), ProgramConfig.FM2014ConfigFileName); nameof(FM2014), ProgramConfig.FM2014ConfigFileName);
if (!File.Exists(configFile)) if (!File.Exists(configFile))
@ -106,11 +117,13 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Config
using (var tr = new StreamReader(configFile)) using (var tr = new StreamReader(configFile))
{ {
var fm2014Setup = JsonConvert.DeserializeObject<FM2014Config>(tr.ReadToEnd()); var fm2014Setup = JsonConvert.DeserializeObject<FM2014Config>(tr.ReadToEnd());
SerialPort = fm2014Setup.SerialPort; SharedSerialPort = fm2014Setup.SharedSerialPort;
Address = fm2014Setup.Address; Address = fm2014Setup.Address;
TolerancePercent = fm2014Setup.TolerancePercent; CommonCurrentOutputDisplayRangeNominal_percent =
fm2014Setup.CommonCurrentOutputDisplayRangeNominal_percent;
Baudrate = fm2014Setup.Baudrate; Baudrate = fm2014Setup.Baudrate;
IndividualTolerancePercent = fm2014Setup.IndividualTolerancePercent; IndividualCurrentOutputDisplayRangeNominal_percent =
fm2014Setup.IndividualCurrentOutputDisplayRangeNominal_percent;
SlotIsSelected = fm2014Setup.SlotIsSelected; SlotIsSelected = fm2014Setup.SlotIsSelected;
RefPulsesRequired = fm2014Setup.RefPulsesRequired; RefPulsesRequired = fm2014Setup.RefPulsesRequired;
DutPulsesRequired = fm2014Setup.DutPulsesRequired; DutPulsesRequired = fm2014Setup.DutPulsesRequired;
@ -123,19 +136,19 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Config
} }
/// <summary> /// <summary>
/// Write file to AppRoaming /// Store the FM2014 configuration file from the 'C:\ProgramData\FM2014' directory
/// </summary> /// </summary>
/// <remarks date="2025-Nov-13" author="Thomas Wiedebusch"> /// <remarks date="2025-Nov-13..2026-Feb-16" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
public void Update() public void Update()
{ {
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
nameof(FM2014)); nameof(FM2014));
if (!Directory.Exists(path)) if (!Directory.Exists(path))
Directory.CreateDirectory(path); Directory.CreateDirectory(path);
var configFile = Path.Combine(path, ProgramConfig.FM2014ConfigFileName); var configFile = Path.Combine(path, ProgramConfig.FM2014ConfigFileName);
File.WriteAllText(configFile, JsonConvert.SerializeObject(this)); File.WriteAllText(configFile, JsonConvert.SerializeObject(this));

View File

@ -87,24 +87,12 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// <summary> /// <summary>
/// Default tolerance if not properly setup. /// Default tolerance if not properly setup.
/// </summary> /// </summary>
public const Int32 CURRENT_OUTPUT_TOLERANCE_STANDARD_NOMINAL_INT_percent = 3; public const Int32 CURRENT_OUTPUT_DISPLAY_RANGE_STANDARD_NOMINAL_percent = 3;
/// <summary> /// <summary>
/// Default tolerance if not properly setup. /// Default tolerance if not properly setup.
/// </summary> /// </summary>
public const Int32 CURRENT_OUTPUT_TOLERANCE_EXTENDED_VALUE_INT_percent = 5; public const Int32 CURRENT_OUTPUT_DISPLAY_RANGE_EXTENDED_NOMINAL_percent = 5;
/// <summary>
/// Standard tolerance (nominal 3 %) multiplicator for calculation of value based on feedback from FM2014
/// (+/- 255 digits).
/// </summary>
private const Double CURRENT_OUTPUT_TOLERANCE_STANDARD_VALUE_DOUBLE_percent = 3.3;
/// <summary>
/// Extended tolerance (nominal 5 %) multiplicator for calculation of value based on feedback from FM2014
/// (+/- 255 digits).
/// </summary>
private const Double CURRENT_OUTPUT_TOLERANCE_EXTENDED_VALUE_DOUBLE_percent = 5.5;
/// <summary> /// <summary>
/// Resolution of tolerance raw value feedback from FM2014 (+/- 255 digits). /// Resolution of tolerance raw value feedback from FM2014 (+/- 255 digits).
@ -349,35 +337,35 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// <summary> /// <summary>
/// Private tolerance percentage /// Private tolerance percentage
/// </summary> /// </summary>
private Int32 _currentOutputToleranceNominalInt_percent = CURRENT_OUTPUT_TOLERANCE_STANDARD_NOMINAL_INT_percent; private Int32 _currentOutputDisplayRangeNominal_percent = CURRENT_OUTPUT_DISPLAY_RANGE_STANDARD_NOMINAL_percent;
/// <summary> /// <summary>
/// Actual tolerance scale to convert raw value from FM2014 to percent /// Actual tolerance scale to convert raw value from FM2014 to percent
/// </summary> /// </summary>
private Double CurrentOutputToleranceNominalToRealScale { set; get; } = private Double CurrentOutputDisplayRangeNominalToRealScale { set; get; } =
CURRENT_OUTPUT_TOLERANCE_STANDARD_VALUE_DOUBLE_percent / CURRENT_OUTPUT_TOLERANCE_RESOLUTION_PLUS_MINUS_BYTE; 1.1 * CURRENT_OUTPUT_DISPLAY_RANGE_STANDARD_NOMINAL_percent / CURRENT_OUTPUT_TOLERANCE_RESOLUTION_PLUS_MINUS_BYTE;
/// <summary> /// <summary>
/// Nominal tolerance output of current loop in percent: /// Nominal tolerance output of current loop in percent:
/// - hardware dependent 3% or 5% /// - hardware dependent 3% or 5%
/// </summary> /// </summary>
public Int32 CurrentOutputToleranceNominalInt_percent public Int32 CurrentOutputDisplayRangeNominal_percent
{ {
get => _currentOutputToleranceNominalInt_percent; get => _currentOutputDisplayRangeNominal_percent;
set set
{ {
// Limit input to discrete nominal setting of 3 or 5 %, // Limit input to discrete nominal setting of 3 or 5 %,
// Internally those values are going to be scaled for higher resolution to 3.3 or 5.5 // Internally those values are going to be scaled for higher resolution to 3.3 or 5.5
Double percentage; Double percentage;
if (value == CURRENT_OUTPUT_TOLERANCE_STANDARD_NOMINAL_INT_percent) if (value == CURRENT_OUTPUT_DISPLAY_RANGE_STANDARD_NOMINAL_percent)
percentage = CURRENT_OUTPUT_TOLERANCE_STANDARD_VALUE_DOUBLE_percent; percentage = 1.1 * CURRENT_OUTPUT_DISPLAY_RANGE_STANDARD_NOMINAL_percent;
else if (value == CURRENT_OUTPUT_TOLERANCE_EXTENDED_VALUE_INT_percent) else if (value == CURRENT_OUTPUT_DISPLAY_RANGE_EXTENDED_NOMINAL_percent)
percentage = CURRENT_OUTPUT_TOLERANCE_EXTENDED_VALUE_DOUBLE_percent; percentage = 1.1 * CURRENT_OUTPUT_DISPLAY_RANGE_EXTENDED_NOMINAL_percent;
else else
percentage = CURRENT_OUTPUT_TOLERANCE_STANDARD_VALUE_DOUBLE_percent; percentage = 1.1 * CURRENT_OUTPUT_DISPLAY_RANGE_STANDARD_NOMINAL_percent;
_currentOutputToleranceNominalInt_percent = value; _currentOutputDisplayRangeNominal_percent = value;
CurrentOutputToleranceNominalToRealScale = percentage / CURRENT_OUTPUT_TOLERANCE_RESOLUTION_PLUS_MINUS_BYTE; CurrentOutputDisplayRangeNominalToRealScale = percentage / CURRENT_OUTPUT_TOLERANCE_RESOLUTION_PLUS_MINUS_BYTE;
} }
} }
@ -393,7 +381,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
public UInt32 RefPulsesRequired public UInt32 RefPulsesRequired
{ {
get => _refPulsesRequired; get => _refPulsesRequired;
private set set
{ {
// Check limits and equality // Check limits and equality
if (value < PULSES_TIME_MEASUREMENT_INPUT_MIN || if (value < PULSES_TIME_MEASUREMENT_INPUT_MIN ||
@ -412,7 +400,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
public UInt32 DutPulsesRequired public UInt32 DutPulsesRequired
{ {
get => _dutPulsesRequired; get => _dutPulsesRequired;
private set set
{ {
// Check limits and equality // Check limits and equality
if (value < PULSES_TIME_MEASUREMENT_INPUT_MIN || if (value < PULSES_TIME_MEASUREMENT_INPUT_MIN ||
@ -586,7 +574,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
public Byte CurrentOutputAttenuation public Byte CurrentOutputAttenuation
{ {
get => _currentOutputAttenuation; get => _currentOutputAttenuation;
private set set
{ {
if (value < CURRENT_OUTPUT_ATTENUATION_MIN || if (value < CURRENT_OUTPUT_ATTENUATION_MIN ||
value > CURRENT_OUTPUT_ATTENUATION_MAX) value > CURRENT_OUTPUT_ATTENUATION_MAX)
@ -603,7 +591,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
public UInt16 DoublePulseDeadtime_ms public UInt16 DoublePulseDeadtime_ms
{ {
get => _doublePulseDeadtime_ms; get => _doublePulseDeadtime_ms;
private set set
{ {
if (value > DOUBLE_PULSE_DEADTIME_MAX_ms) if (value > DOUBLE_PULSE_DEADTIME_MAX_ms)
return; return;
@ -1167,14 +1155,14 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
if (Read(cmdName, fm2014, out _, out _, out var doubleValue)) if (Read(cmdName, fm2014, out _, out _, out var doubleValue))
{ {
fm2014.DutToRefToleranceMeasured_percent = doubleValue * fm2014.DutToRefToleranceMeasured_percent = doubleValue *
fm2014.CurrentOutputToleranceNominalToRealScale; fm2014.CurrentOutputDisplayRangeNominalToRealScale;
var response = new CmdResponse(cmdName, info, var response = new CmdResponse(cmdName, info,
doubleValue: fm2014.DutToRefToleranceMeasured_percent, doubleValue: fm2014.DutToRefToleranceMeasured_percent,
unit: Units.GetInfo(Units.Name.PERCENT)); unit: Units.GetInfo(Units.Name.PERCENT));
// Check the threshold for OOR // Check the threshold for OOR
if (Math.Abs((Double)fm2014.DutToRefToleranceMeasured_percent) > if (Math.Abs((Double)fm2014.DutToRefToleranceMeasured_percent) >
fm2014.CurrentOutputToleranceNominalInt_percent) fm2014.CurrentOutputDisplayRangeNominal_percent)
statusReturn = StatusReturn.MeasurementOutOfRange; statusReturn = StatusReturn.MeasurementOutOfRange;
else statusReturn = StatusReturn.Okay; else statusReturn = StatusReturn.Okay;
@ -1590,7 +1578,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
fm2014.DutToRefToleranceMeasured_percent < fm2014.DutToRefToleranceMeasured_percent <
fm2014.DutToRefCalibrationToleranceMin_percent) fm2014.DutToRefCalibrationToleranceMin_percent)
statusReturn = StatusReturn.MeasurementOutOfRange; statusReturn = StatusReturn.MeasurementOutOfRange;
else statusReturn = StatusReturn.Okay; else statusReturn = StatusReturn.MeasurementInRange;
var response = new CmdResponse(cmdName, info, var response = new CmdResponse(cmdName, info,
doubleValue: fm2014.DutToRefToleranceMeasured_percent, doubleValue: fm2014.DutToRefToleranceMeasured_percent,

View File

@ -23,7 +23,7 @@
<!--Click="OnChangePassword_Click"/--> <!--Click="OnChangePassword_Click"/-->
</MenuItem> </MenuItem>
<Label x:Name="portMenu" Content="Serial Port:" Margin="2,2,2,2"/> <Label x:Name="portMenu" Content="Serial Port:" Margin="2,2,2,2"/>
<ComboBox x:Name="cbxFM2014ComPort" Margin="2,2,2,2" SelectionChanged="cbxFM2014BaseSettings_SelectedValueChanged"/> <ComboBox x:Name="cbxProgramComPort" Margin="2,2,2,2" SelectionChanged="cbxProgramComPort_SelectedValueChanged"/>
<MenuItem x:Name="hlpMenu" HorizontalAlignment="Right" Height="26" Width="40" FontSize="12" Header="Help" Click="HlpMenu_Click" /> <MenuItem x:Name="hlpMenu" HorizontalAlignment="Right" Height="26" Width="40" FontSize="12" Header="Help" Click="HlpMenu_Click" />
<!--Special approval / requirement--> <!--Special approval / requirement-->
</Menu> </Menu>
@ -326,19 +326,19 @@
<ColumnDefinition Width="30"/> <ColumnDefinition Width="30"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label x:Name="lblRefPulsesPerCm" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="1" Grid.Column="17" Grid.ColumnSpan="6" Content="REF Pulse Ratio [pulses/m³]:" /> <Label x:Name="lblRefPulsesPerCm" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="1" Grid.Column="17" Grid.ColumnSpan="6" Content="REF Pulse Ratio [pulses/m³]:" />
<Label x:Name="lblDutPulsesPerCm" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="2" Grid.Column="17" Grid.ColumnSpan="6" Content="DUT Pulse Ratio [pulses/m³]:" /> <Label x:Name="lblDutPulsesPerCm" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="2" Grid.Column="17" Grid.ColumnSpan="6" Content="DUT Pulse Ratio [pulses/m³]:" />
<Label x:Name="lblScaleRefToDut" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="3" Grid.Column="17" Grid.ColumnSpan="6" Content="REF/DUT Scale [norm]:" /> <Label x:Name="lblScaleRefToDut" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="3" Grid.Column="17" Grid.ColumnSpan="6" Content="REF/DUT Scale [norm]:" />
<Label x:Name="lblDisplayAttenuation" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="4" Grid.Column="17" Grid.ColumnSpan="6" Content="Display Attenuation []:" /> <Label x:Name="lblToleranceDisplayAttenuation" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="4" Grid.Column="17" Grid.ColumnSpan="6" Content="Display Attenuation []:" />
<Label x:Name="lblToleranceCalc" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="5" Grid.Column="17" Grid.ColumnSpan="6" Content="Tolerance Setup [%]:" /> <Label x:Name="lblToleranceDisplayRange" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="5" Grid.Column="17" Grid.ColumnSpan="6" Content="Tolerance Range [%]:" />
<TextBox x:Name="tbxRefPulsesPerCm" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="1" Grid.Column="23" Grid.ColumnSpan="2" Text="10000" MaxLines="1" TabIndex="102" HorizontalContentAlignment="Right" KeyDown="tbxRefPulsesPerCm_KeyDown" LostFocus="tbxRefPulsesPerCm_LostFocus" TextChanged="tbxRefPulsesPerCm_TextChanged" /> <TextBox x:Name="tbxRefPulsesPerCm" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="1" Grid.Column="23" Grid.ColumnSpan="2" Text="10000" MaxLines="1" TabIndex="102" HorizontalContentAlignment="Right" KeyDown="tbxRefPulsesPerCm_KeyDown" LostFocus="tbxRefPulsesPerCm_LostFocus" TextChanged="tbxRefPulsesPerCm_TextChanged" />
<TextBox x:Name="tbxDutPulsesPerCm" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="2" Grid.Column="23" Grid.ColumnSpan="2" Text="1000" MaxLines="1" TabIndex="103" HorizontalContentAlignment="Right" KeyDown="tbxDutPulsesPerCm_KeyDown" LostFocus="tbxDutPulsesPerCm_LostFocus" TextChanged="tbxDutPulsesPerCm_TextChanged"/> <TextBox x:Name="tbxDutPulsesPerCm" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="2" Grid.Column="23" Grid.ColumnSpan="2" Text="1000" MaxLines="1" TabIndex="103" HorizontalContentAlignment="Right" KeyDown="tbxDutPulsesPerCm_KeyDown" LostFocus="tbxDutPulsesPerCm_LostFocus" TextChanged="tbxDutPulsesPerCm_TextChanged"/>
<TextBox x:Name="tbxScaleRefToDut" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="3" Grid.Column="23" Grid.ColumnSpan="2" Text="10.0" MaxLines="1" HorizontalContentAlignment="Right" IsTabStop="False"/> <TextBox x:Name="tbxScaleRefToDut" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="3" Grid.Column="23" Grid.ColumnSpan="2" Text="10.0" MaxLines="1" HorizontalContentAlignment="Right" IsTabStop="False"/>
<ComboBox x:Name="cbxDisplayAttenuation" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="4" Grid.Column="23" Grid.ColumnSpan="2" TabIndex="104" HorizontalContentAlignment="Right" KeyDown="cbxAttenuation_KeyDown" SelectionChanged="cbxAttenuation_SelectedIndexChanged" /> <ComboBox x:Name="cbxToleranceDisplayAttenuation" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="4" Grid.Column="23" Grid.ColumnSpan="2" TabIndex="104" HorizontalContentAlignment="Right" KeyDown="cbxToleranceDisplayAttenuation_KeyDown" SelectionChanged="cbxToleranceDisplayAttenuation_SelectedIndexChanged" />
<ComboBox x:Name="cbxToleranceCalc" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="5" Grid.Column="23" Grid.ColumnSpan="2" TabIndex="105" HorizontalContentAlignment="Right" KeyDown="cbxToleranceCalc_KeyDown" SelectionChanged="cbxToleranceCalc_SelectedIndexChanged"/> <ComboBox x:Name="cbxToleranceDisplayRange" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="5" Grid.Column="23" Grid.ColumnSpan="2" TabIndex="105" HorizontalContentAlignment="Right" KeyDown="cbxToleranceDisplayRange_KeyDown" SelectionChanged="cbxToleranceDisplayRange_SelectedIndexChanged"/>
<CheckBox x:Name="chkUseDampedTolerance" HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="1,1,1,1" Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="6" Content="Damped Tolerance ON" TabIndex="101" Click="chkUseDampedTolerance_CheckedChanged" /> <CheckBox x:Name="chkUseDampedTolerance" HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="1,1,1,1" Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="6" Content="Damped Tolerance ON" TabIndex="101" Click="chkUseDampedTolerance_CheckedChanged" />
<Button x:Name="btnDutToRefRegulation" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="4" Content="Start Regulation" TabIndex="100" Click="btnDutToRefRegulation_Click" /> <Button x:Name="btnDutToRefRegulation" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="4" Content="Start Regulation" TabIndex="100" Click="btnDutToRefRegulation_Click" />
<Button x:Name="btnSaveRegulationSetup" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="6" Grid.Column="21" Grid.ColumnSpan="4" Content="Save to FM2014" TabIndex="106" Click="btnSaveRegulationSetup_Click" /> <Button x:Name="btnSaveSetupToFm2014" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="6" Grid.Column="21" Grid.ColumnSpan="4" Content="Save to FM2014" TabIndex="106" Click="btnSaveSetupToFm2014_Click" />
</Grid> </Grid>
</TabItem> </TabItem>

View File

@ -128,9 +128,21 @@ namespace Sensus.Ui.FM2014TestBench
//private String _backupRefCalibrationResultPulsePerCmStr; //private String _backupRefCalibrationResultPulsePerCmStr;
//private String _backupMeasuredRefPulsesStr; //private String _backupMeasuredRefPulsesStr;
private Boolean _regulationSetupHasChanged; /// <summary>
private Boolean _configSetupHasChanged; /// The regulation setup will be stored directly to the FM2014 being able to use it at startup
private Boolean _calibrationSetupHasChanged; /// </summary>
private Boolean _fm2014RegulationSetupHasChanged;
/// <summary>
/// If the program configuration has changed, this shall be stored to the configuration file
/// </summary>
private Boolean _programConfigSetupHasChanged;
/// <summary>
/// If the program configuration for the calibration measurement has changed, this shall be stored to the
/// configuration file
/// </summary>
private Boolean _programCalibrationSetupHasChanged;
private String _lastLoggingTextToAvoidRepetition; private String _lastLoggingTextToAvoidRepetition;
@ -240,15 +252,15 @@ namespace Sensus.Ui.FM2014TestBench
// Preset attenuation // Preset attenuation
var attenuation = FM2014.CURRENT_OUTPUT_ATTENUATION_MIN; var attenuation = FM2014.CURRENT_OUTPUT_ATTENUATION_MIN;
for (var idx = 0; idx < FM2014.CURRENT_OUTPUT_ATTENUATION_MAX - FM2014.CURRENT_OUTPUT_ATTENUATION_MIN; idx++) for (var idx = 0; idx <= FM2014.CURRENT_OUTPUT_ATTENUATION_MAX - FM2014.CURRENT_OUTPUT_ATTENUATION_MIN; idx++)
{ {
cbxDisplayAttenuation.Items.Add(attenuation.ToString()); cbxToleranceDisplayAttenuation.Items.Add(attenuation.ToString());
attenuation++; attenuation++;
} }
// Preset tolerance setup for feedback calculation of DUT to REF tolerance // Preset tolerance setup for feedback calculation of DUT to REF tolerance
cbxToleranceCalc.Items.Add("3"); cbxToleranceDisplayRange.Items.Add(FM2014.CURRENT_OUTPUT_DISPLAY_RANGE_STANDARD_NOMINAL_percent.ToString());
cbxToleranceCalc.Items.Add("5"); cbxToleranceDisplayRange.Items.Add(FM2014.CURRENT_OUTPUT_DISPLAY_RANGE_EXTENDED_NOMINAL_percent.ToString());
Init(); Init();
} }
@ -455,8 +467,8 @@ namespace Sensus.Ui.FM2014TestBench
LogText(StrSeparator); LogText(StrSeparator);
} }
_regulationSetupHasChanged = false; _fm2014RegulationSetupHasChanged = false;
_calibrationSetupHasChanged = false; _programCalibrationSetupHasChanged = false;
// Load the configuration from the local file stored in AppData\FM2014 // Load the configuration from the local file stored in AppData\FM2014
_fm2014Config.ReadFM2014Config(); _fm2014Config.ReadFM2014Config();
@ -491,7 +503,7 @@ namespace Sensus.Ui.FM2014TestBench
fm2014.OnRawRecordReceived += DataReceived_Handler; fm2014.OnRawRecordReceived += DataReceived_Handler;
Fm2014s.Add(fm2014); Fm2014s.Add(fm2014);
var userControl = new UcFM2014Device(fm2014, StoreFM2014SettingsToConfigFile); var userControl = new UcFM2014Device(fm2014, StoreProgramConfiguration);
UcFM2014s.Add(userControl); UcFM2014s.Add(userControl);
SetNewUserControl(PanelsForUcFM2014[ctr], UcFM2014s[ctr]); SetNewUserControl(PanelsForUcFM2014[ctr], UcFM2014s[ctr]);
// Restore previous slot selection // Restore previous slot selection
@ -500,11 +512,11 @@ namespace Sensus.Ui.FM2014TestBench
SlotSelections.Count == MaxFm2014s) SlotSelections.Count == MaxFm2014s)
SlotSelections[ctr].IsChecked = _fm2014Config?.SlotIsSelected[ctr] ?? false; SlotSelections[ctr].IsChecked = _fm2014Config?.SlotIsSelected[ctr] ?? false;
// Restore individual tolerance selection // Restore individual tolerance selection
if (_fm2014Config?.IndividualTolerancePercent?[ctr] != null && if (_fm2014Config?.IndividualCurrentOutputDisplayRangeNominal_percent?[ctr] != null &&
_fm2014Config.IndividualTolerancePercent.Count == MaxFm2014s) _fm2014Config.IndividualCurrentOutputDisplayRangeNominal_percent.Count == MaxFm2014s)
{ {
fm2014.CurrentOutputToleranceNominalInt_percent = _fm2014Config?.IndividualTolerancePercent[ctr] ?? fm2014.CurrentOutputDisplayRangeNominal_percent = _fm2014Config?.IndividualCurrentOutputDisplayRangeNominal_percent[ctr] ??
FM2014.CURRENT_OUTPUT_TOLERANCE_STANDARD_NOMINAL_INT_percent; FM2014.CURRENT_OUTPUT_DISPLAY_RANGE_STANDARD_NOMINAL_percent;
} }
} }
if (_fm2014Config != null) if (_fm2014Config != null)
@ -520,7 +532,7 @@ namespace Sensus.Ui.FM2014TestBench
tbxDutToRefTolMin.Text = $"{_fm2014Config.DutToRefToleranceMin:F2}"; tbxDutToRefTolMin.Text = $"{_fm2014Config.DutToRefToleranceMin:F2}";
// Display on regulation page as common setup for ALL // Display on regulation page as common setup for ALL
cbxToleranceCalc.SelectedItem = _fm2014Config.TolerancePercent?.ToString(); cbxToleranceDisplayRange.SelectedItem = _fm2014Config.CommonCurrentOutputDisplayRangeNominal_percent.ToString();
} }
// Disable and hide dynamic measurement labels // Disable and hide dynamic measurement labels
@ -528,22 +540,22 @@ namespace Sensus.Ui.FM2014TestBench
UiElmEnable(measLbl, false, false); UiElmEnable(measLbl, false, false);
// Display actual com-port, if not assigned use the '?'. This will be placed on Items[0] // 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?.SharedSerialPort != null && !cbxProgramComPort.Items.Contains(_fm2014Config.SharedSerialPort))
{ {
cbxFM2014ComPort.Items.Add(_fm2014Config.SerialPort); cbxProgramComPort.Items.Add(_fm2014Config.SharedSerialPort);
} }
else if (_fm2014Config?.SerialPort == null && !cbxFM2014ComPort.Items.Contains("?")) else if (_fm2014Config?.SharedSerialPort == null && !cbxProgramComPort.Items.Contains("?"))
{ {
cbxFM2014ComPort.Items.Add("?"); cbxProgramComPort.Items.Add("?");
} }
// Collect and add all com-ports from device manager to items // Collect and add all com-ports from device manager to items
var comPorts = SerialPort.GetPortNames().ToList(); var comPorts = SerialPort.GetPortNames().ToList();
foreach (var comPort in comPorts.Where(comPort => !cbxFM2014ComPort.Items.Contains(comPort))) foreach (var comPort in comPorts.Where(comPort => !cbxProgramComPort.Items.Contains(comPort)))
{ {
cbxFM2014ComPort.Items.Add(comPort); cbxProgramComPort.Items.Add(comPort);
} }
cbxFM2014ComPort.Text = cbxFM2014ComPort.Items[_comPortIdx]?.ToString(); cbxProgramComPort.Text = cbxProgramComPort.Items[_comPortIdx]?.ToString();
// Dispatch multilingual denotation to GUI elements // Dispatch multilingual denotation to GUI elements
btnFM2014Connect.Content = Properties.Resources.StrBtnConnect; btnFM2014Connect.Content = Properties.Resources.StrBtnConnect;
@ -574,9 +586,9 @@ namespace Sensus.Ui.FM2014TestBench
lblScaleRefToDut.Content = Properties.Resources.StrLblRefToDutScale; lblScaleRefToDut.Content = Properties.Resources.StrLblRefToDutScale;
tbxScaleRefToDut.Text = ""; tbxScaleRefToDut.Text = "";
tbxScaleRefToDut.IsReadOnly = true; tbxScaleRefToDut.IsReadOnly = true;
lblDisplayAttenuation.Content = Properties.Resources.StrLblDisplayAttenuation; lblToleranceDisplayAttenuation.Content = Properties.Resources.StrLblDisplayAttenuation;
btnSaveRegulationSetup.Content = Properties.Resources.StrBtnSaveRegulationSetup; btnSaveSetupToFm2014.Content = Properties.Resources.StrBtnSaveRegulationSetup;
lblToleranceCalc.Content = Properties.Resources.StrLblFM2014Tolerance; lblToleranceDisplayRange.Content = Properties.Resources.StrLblFM2014Tolerance;
chkUseDampedTolerance.Content = Properties.Resources.StrChkUseDampedTolerance; chkUseDampedTolerance.Content = Properties.Resources.StrChkUseDampedTolerance;
btnDutToRefRegulation.Content = Properties.Resources.StrBtnStartRegulation; btnDutToRefRegulation.Content = Properties.Resources.StrBtnStartRegulation;
@ -611,42 +623,35 @@ namespace Sensus.Ui.FM2014TestBench
/// <summary> /// <summary>
/// Store the settings adjusted by the UI or the UcFM2014Device to a configuration file! /// Store the settings adjusted by the UI or the UcFM2014Device to a configuration file!
/// </summary> /// </summary>
/// <remarks date="2025-Nov-13" author="Thomas Wiedebusch"> /// <remarks date="2025-Nov-13..2026-Feb-16" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
/// <remarks date="2026-Jan-15" author="Thomas Wiedebusch"> private void StoreProgramConfiguration()
/// - Update FM2014 properties.
/// </remarks>
/// <remarks date="2026-Feb-05" author="Thomas Wiedebusch">
/// - Store individual tolerances and test bench slot selections.
/// </remarks>
/// <remarks date="2026-Feb-10" author="Thomas Wiedebusch">
/// - Store calibration settings for user convenience.
/// </remarks>
private void StoreFM2014SettingsToConfigFile()
{ {
if (_fm2014Config == null) if (_fm2014Config == null)
return; return;
Dispatcher.Invoke(() => Dispatcher.Invoke(() =>
{ {
_configSetupHasChanged = false; _programConfigSetupHasChanged = false;
_calibrationSetupHasChanged = false; _programCalibrationSetupHasChanged = false;
_fm2014Config.IndividualTolerancePercent?.Clear(); _fm2014Config.IndividualCurrentOutputDisplayRangeNominal_percent?.Clear();
_fm2014Config.IndividualTolerancePercent = null; _fm2014Config.IndividualCurrentOutputDisplayRangeNominal_percent = null;
_fm2014Config.IndividualTolerancePercent = new List<Int32?>(); _fm2014Config.IndividualCurrentOutputDisplayRangeNominal_percent = new List<Int32?>();
_fm2014Config.SlotIsSelected?.Clear(); _fm2014Config.SlotIsSelected?.Clear();
_fm2014Config.SlotIsSelected = null; _fm2014Config.SlotIsSelected = null;
_fm2014Config.SlotIsSelected = new List<Boolean?>(); _fm2014Config.SlotIsSelected = new List<Boolean?>();
_fm2014Config.SerialPort = cbxFM2014ComPort.Text; _fm2014Config.SharedSerialPort = cbxProgramComPort.Text;
for (var ctr = 0; ctr < MaxFm2014s; ctr++) for (var ctr = 0; ctr < MaxFm2014s; ctr++)
{ {
var fm2014 = Fm2014s[ctr]; var fm2014 = Fm2014s[ctr];
if (fm2014 == null) if (fm2014 == null)
return; return;
_fm2014Config.IndividualTolerancePercent.Add(fm2014.CurrentOutputToleranceNominalInt_percent); _fm2014Config.IndividualCurrentOutputDisplayRangeNominal_percent.Add(
fm2014.CurrentOutputDisplayRangeNominal_percent);
_fm2014Config.SlotIsSelected.Add(SlotSelections[ctr].IsChecked); _fm2014Config.SlotIsSelected.Add(SlotSelections[ctr].IsChecked);
} }
@ -655,6 +660,15 @@ namespace Sensus.Ui.FM2014TestBench
if (null == firstFm2014) if (null == firstFm2014)
return; return;
// Preset the 'firstFm2014' with all items
tbxRefPulsesRequired_LostFocus(this, null);
tbxDutPulsesRequired_LostFocus(this, null);
tbxDoublePulseDeadtime_LostFocus(this, null);
tbxDutToRefToleranceMax_LostFocus(this, null);
tbxDutToRefToleranceMin_LostFocus(this, null);
_fm2014Config.CommonCurrentOutputDisplayRangeNominal_percent =
firstFm2014.CurrentOutputDisplayRangeNominal_percent;
_fm2014Config.RefPulsesRequired = (UInt16)firstFm2014.RefPulsesRequired; _fm2014Config.RefPulsesRequired = (UInt16)firstFm2014.RefPulsesRequired;
_fm2014Config.DutPulsesRequired = (UInt16)firstFm2014.DutPulsesRequired; _fm2014Config.DutPulsesRequired = (UInt16)firstFm2014.DutPulsesRequired;
_fm2014Config.DoublePulseDeadtime = firstFm2014.DoublePulseDeadtime_ms; _fm2014Config.DoublePulseDeadtime = firstFm2014.DoublePulseDeadtime_ms;
@ -674,12 +688,12 @@ namespace Sensus.Ui.FM2014TestBench
{ {
try try
{ {
if (_configSetupHasChanged || _calibrationSetupHasChanged) if (_programConfigSetupHasChanged || _programCalibrationSetupHasChanged)
StoreFM2014SettingsToConfigFile(); StoreProgramConfiguration();
Init(); Init();
if (string.IsNullOrEmpty(cbxFM2014ComPort?.SelectedItem?.ToString()) || if (string.IsNullOrEmpty(cbxProgramComPort?.SelectedItem?.ToString()) ||
cbxFM2014ComPort.SelectedItem.ToString().Equals("?")) cbxProgramComPort.SelectedItem.ToString().Equals("?"))
{ {
var text = Properties.Resources.StrErrorMsgComPortNotAssigned; var text = Properties.Resources.StrErrorMsgComPortNotAssigned;
//MessageBox.Show(text, Properties.Resources.StrError, MessageBoxButtons.OK, MessageBoxIcon.Error); //MessageBox.Show(text, Properties.Resources.StrError, MessageBoxButtons.OK, MessageBoxIcon.Error);
@ -695,7 +709,7 @@ namespace Sensus.Ui.FM2014TestBench
UpdateContentControl(lblActualProcessText, Properties.Resources.StrMsgConnecting); UpdateContentControl(lblActualProcessText, Properties.Resources.StrMsgConnecting);
var comPort = cbxFM2014ComPort.SelectedItem.ToString(); var comPort = cbxProgramComPort.SelectedItem.ToString();
Task.Factory.StartNew(() => Task.Factory.StartNew(() =>
{ {
@ -802,7 +816,7 @@ namespace Sensus.Ui.FM2014TestBench
{ {
SetFM2014AccessLocked(); SetFM2014AccessLocked();
UiElmEnable(btnFM2014Connect, true); UiElmEnable(btnFM2014Connect, true);
UiElmEnable(cbxFM2014ComPort, true); UiElmEnable(cbxProgramComPort, true);
foreach (var slotSelector in SlotSelections) foreach (var slotSelector in SlotSelections)
{ {
UiElmEnable(slotSelector, true); UiElmEnable(slotSelector, true);
@ -821,11 +835,11 @@ namespace Sensus.Ui.FM2014TestBench
/// </remarks> /// </remarks>
private void DutToRefRegulationSetupHasChanged() private void DutToRefRegulationSetupHasChanged()
{ {
_regulationSetupHasChanged = true; _fm2014RegulationSetupHasChanged = true;
Dispatcher.Invoke(() => Dispatcher.Invoke(() =>
{ {
btnSaveRegulationSetup.IsEnabled = true; btnSaveSetupToFm2014.IsEnabled = true;
btnDutToRefRegulation.IsEnabled = true; btnDutToRefRegulation.IsEnabled = true;
tbxRefPulsesPerCm.Background = ColorStandardInputField; tbxRefPulsesPerCm.Background = ColorStandardInputField;
@ -864,7 +878,7 @@ namespace Sensus.Ui.FM2014TestBench
{ {
tbxScaleRefToDut.Background = ColorProcessFailed; tbxScaleRefToDut.Background = ColorProcessFailed;
tbxScaleRefToDut.Text = Properties.Resources.StrError; tbxScaleRefToDut.Text = Properties.Resources.StrError;
btnSaveRegulationSetup.IsEnabled = false; btnSaveSetupToFm2014.IsEnabled = false;
btnDutToRefRegulation.IsEnabled = false; btnDutToRefRegulation.IsEnabled = false;
}); });
return false; return false;
@ -985,7 +999,7 @@ namespace Sensus.Ui.FM2014TestBench
{ {
// Disable all buttons // Disable all buttons
UiElmEnable(btnDutToRefCalibration, false); UiElmEnable(btnDutToRefCalibration, false);
UiElmEnable(btnSaveRegulationSetup, false); UiElmEnable(btnSaveSetupToFm2014, false);
UiElmEnable(btnDutToRefRegulation, false); UiElmEnable(btnDutToRefRegulation, false);
UiElmEnable(btnFM2014Connect, false); UiElmEnable(btnFM2014Connect, false);
UiElmEnable(btnRefToVolumeCalibration, false); UiElmEnable(btnRefToVolumeCalibration, false);
@ -1005,9 +1019,9 @@ namespace Sensus.Ui.FM2014TestBench
UiElmEnable(tbxRefPulsesPerCm, false); UiElmEnable(tbxRefPulsesPerCm, false);
UiElmEnable(tbxDutPulsesPerCm, false); UiElmEnable(tbxDutPulsesPerCm, false);
UiElmEnable(tbxScaleRefToDut, false); // Is permanent read only UiElmEnable(tbxScaleRefToDut, false); // Is permanent read only
UiElmEnable(cbxDisplayAttenuation, false); UiElmEnable(cbxToleranceDisplayAttenuation, false);
UiElmEnable(cbxToleranceCalc, false); UiElmEnable(cbxToleranceDisplayRange, false);
UiElmEnable(cbxFM2014ComPort, false); UiElmEnable(cbxProgramComPort, false);
UiElmEnable(tbxRefPulsesMeasured, false); // Is permanent read only UiElmEnable(tbxRefPulsesMeasured, false); // Is permanent read only
UiElmEnable(chkDutPulsesMeasured, false); UiElmEnable(chkDutPulsesMeasured, false);
UiElmEnable(tbxDutPulsesMeasured, false); // Is permanent read only UiElmEnable(tbxDutPulsesMeasured, false); // Is permanent read only
@ -1026,7 +1040,7 @@ namespace Sensus.Ui.FM2014TestBench
{ {
// Enable buttons and display correct information // Enable buttons and display correct information
UiElmEnable(btnDutToRefCalibration, true); UiElmEnable(btnDutToRefCalibration, true);
UiElmEnable(btnSaveRegulationSetup, _regulationSetupHasChanged); // Activate if setup has changed UiElmEnable(btnSaveSetupToFm2014, _fm2014RegulationSetupHasChanged); // Activate if setup has changed
UiElmEnable(btnDutToRefRegulation, true); UiElmEnable(btnDutToRefRegulation, true);
UiElmEnable(btnFM2014Connect, true); UiElmEnable(btnFM2014Connect, true);
UiElmEnable(btnRefToVolumeCalibration, true); UiElmEnable(btnRefToVolumeCalibration, true);
@ -1056,9 +1070,9 @@ namespace Sensus.Ui.FM2014TestBench
UiElmEnable(tbxRefPulsesPerCm, true); UiElmEnable(tbxRefPulsesPerCm, true);
UiElmEnable(tbxDutPulsesPerCm, true); UiElmEnable(tbxDutPulsesPerCm, true);
UiElmEnable(tbxScaleRefToDut, true); // Is permanent read only UiElmEnable(tbxScaleRefToDut, true); // Is permanent read only
UiElmEnable(cbxDisplayAttenuation, true); UiElmEnable(cbxToleranceDisplayAttenuation, true);
UiElmEnable(cbxToleranceCalc, true); UiElmEnable(cbxToleranceDisplayRange, true);
UiElmEnable(cbxFM2014ComPort, true); UiElmEnable(cbxProgramComPort, true);
UiElmEnable(tbxRefPulsesMeasured, true); // Is permanent read only UiElmEnable(tbxRefPulsesMeasured, true); // Is permanent read only
UiElmEnable(chkDutPulsesMeasured, true); UiElmEnable(chkDutPulsesMeasured, true);
UiElmEnable(tbxDutPulsesMeasured, dutPulseMeasurementIsActive); // Is permanent read only UiElmEnable(tbxDutPulsesMeasured, dutPulseMeasurementIsActive); // Is permanent read only
@ -1115,9 +1129,16 @@ namespace Sensus.Ui.FM2014TestBench
// Data dispatcher // Data dispatcher
var resp = (CmdResponse)e.SpecificInfoObj; var resp = (CmdResponse)e.SpecificInfoObj;
String valueStr; String valueStr;
// Used as marker for error, null means measurement is in range or status or health is good // Used as marker for error, null means measurement is in range or status or health is good
Brush statusColor = null; Brush statusColor = null;
// Color the output for the user display for quick check capability
if (e.StatusReturn == StatusReturn.MeasurementOutOfRange)
statusColor = ColorProcessFailed;
else if (e.StatusReturn == StatusReturn.MeasurementInRange)
statusColor = ColorSuccess;
if (e.StatusReturn == StatusReturn.Failed) if (e.StatusReturn == StatusReturn.Failed)
{ {
LogErrorText(resp.AnswerStr); LogErrorText(resp.AnswerStr);
@ -1129,8 +1150,6 @@ namespace Sensus.Ui.FM2014TestBench
} }
else if (resp.IntValue != null) else if (resp.IntValue != null)
{ {
if (e.StatusReturn == StatusReturn.MeasurementOutOfRange)
statusColor = ColorProcessFailed;
LogText($"{resp.AnswerStr}: {resp.IntValue:D} {resp.Unit}"); LogText($"{resp.AnswerStr}: {resp.IntValue:D} {resp.Unit}");
switch (resp.CmdName) switch (resp.CmdName)
{ {
@ -1159,7 +1178,7 @@ namespace Sensus.Ui.FM2014TestBench
UpdateTextBox(tbxDutPulsesPerCm, $"{resp.IntValue:D}", statusColor); UpdateTextBox(tbxDutPulsesPerCm, $"{resp.IntValue:D}", statusColor);
break; break;
case CmdName.CMD_MEAS_SET_ATTN: case CmdName.CMD_MEAS_SET_ATTN:
Dispatcher.Invoke(() => cbxDisplayAttenuation.SelectedItem = $"{resp.IntValue}"); Dispatcher.Invoke(() => cbxToleranceDisplayAttenuation.SelectedItem = $"{resp.IntValue}");
break; break;
case CmdName.CMD_GET_REF_FREQU: case CmdName.CMD_GET_REF_FREQU:
valueStr = $"{resp.IntValue:D}"; valueStr = $"{resp.IntValue:D}";
@ -1177,8 +1196,6 @@ namespace Sensus.Ui.FM2014TestBench
} }
else if (resp.DoubleValue != null) else if (resp.DoubleValue != null)
{ {
if (e.StatusReturn == StatusReturn.MeasurementOutOfRange)
statusColor = ColorProcessFailed;
LogText($"{resp.AnswerStr}: {resp.DoubleValue:F2} {resp.Unit}"); LogText($"{resp.AnswerStr}: {resp.DoubleValue:F2} {resp.Unit}");
switch (resp.CmdName) switch (resp.CmdName)
{ {
@ -1341,12 +1358,12 @@ namespace Sensus.Ui.FM2014TestBench
fm2014.DutToRefCalibrationToleranceMin_percent = toleranceThresholdMin_percent; fm2014.DutToRefCalibrationToleranceMin_percent = toleranceThresholdMin_percent;
} }
// Backup if meanwhile anything has changed
if (_programConfigSetupHasChanged || _programCalibrationSetupHasChanged)
StoreProgramConfiguration();
if (FM2014.PulseTimeMeasurement(refPulsesRequired, dutPulsesRequired, doublePulseDeadtime_ms)) if (FM2014.PulseTimeMeasurement(refPulsesRequired, dutPulsesRequired, doublePulseDeadtime_ms))
{ {
// Backup if meanwhile anything has changed
if (_configSetupHasChanged || _calibrationSetupHasChanged)
StoreFM2014SettingsToConfigFile();
_autoProgressBar = false; _autoProgressBar = false;
ActionControl(true); ActionControl(true);
UpdateContentControl(btnDutToRefCalibration, Properties.Resources.StrBtnStopCalibration); UpdateContentControl(btnDutToRefCalibration, Properties.Resources.StrBtnStopCalibration);
@ -1416,16 +1433,16 @@ namespace Sensus.Ui.FM2014TestBench
doublePulseDeadtime_ms = (UInt16)deadtime_ms; doublePulseDeadtime_ms = (UInt16)deadtime_ms;
} }
if (byte.TryParse(cbxDisplayAttenuation.SelectedItem.ToString(), out var attenuation) && if (byte.TryParse(cbxToleranceDisplayAttenuation.SelectedItem.ToString(), out var attenuation) &&
attenuation >= FM2014.CURRENT_OUTPUT_ATTENUATION_MIN && attenuation >= FM2014.CURRENT_OUTPUT_ATTENUATION_MIN &&
attenuation <= FM2014.CURRENT_OUTPUT_ATTENUATION_MAX) attenuation <= FM2014.CURRENT_OUTPUT_ATTENUATION_MAX)
{ {
currentOutputAttenuation = attenuation; currentOutputAttenuation = attenuation;
} }
if (int.TryParse(cbxToleranceCalc.SelectedItem.ToString(), out var tolerance) && if (int.TryParse(cbxToleranceDisplayRange.SelectedItem.ToString(), out var tolerance) &&
(tolerance == FM2014.CURRENT_OUTPUT_TOLERANCE_STANDARD_NOMINAL_INT_percent || (tolerance == FM2014.CURRENT_OUTPUT_DISPLAY_RANGE_STANDARD_NOMINAL_percent ||
tolerance == FM2014.CURRENT_OUTPUT_TOLERANCE_EXTENDED_VALUE_INT_percent)) tolerance == FM2014.CURRENT_OUTPUT_DISPLAY_RANGE_EXTENDED_NOMINAL_percent))
{ {
toleranceSetup = tolerance; toleranceSetup = tolerance;
} }
@ -1437,9 +1454,13 @@ namespace Sensus.Ui.FM2014TestBench
var idx = fm2014.Address - 1; var idx = fm2014.Address - 1;
var ucFM2014 = (UcFM2014Device)UcFM2014s[idx]; var ucFM2014 = (UcFM2014Device)UcFM2014s[idx];
ucFM2014.EnableMeasurements(REG_MEASURE_COUNT); ucFM2014.EnableMeasurements(REG_MEASURE_COUNT);
fm2014.CurrentOutputToleranceNominalInt_percent = toleranceSetup; fm2014.CurrentOutputDisplayRangeNominal_percent = toleranceSetup;
} }
// Backup if meanwhile anything has changed
if (_programConfigSetupHasChanged || _programCalibrationSetupHasChanged)
StoreProgramConfiguration();
if (FM2014.RegulationMeasurement(refPulses_per_cm, dutPulses_per_cm, doublePulseDeadtime_ms, if (FM2014.RegulationMeasurement(refPulses_per_cm, dutPulses_per_cm, doublePulseDeadtime_ms,
currentOutputAttenuation)) currentOutputAttenuation))
{ {
@ -1498,6 +1519,10 @@ namespace Sensus.Ui.FM2014TestBench
ucFM2014.EnableMeasurements(CTR_MEASURE_COUNT); ucFM2014.EnableMeasurements(CTR_MEASURE_COUNT);
} }
// Backup if meanwhile anything has changed
if (_programConfigSetupHasChanged || _programCalibrationSetupHasChanged)
StoreProgramConfiguration();
if (FM2014.PulseCounterMeasurement(true, measureDutPulses)) if (FM2014.PulseCounterMeasurement(true, measureDutPulses))
{ {
_autoProgressBar = true; _autoProgressBar = true;
@ -1523,12 +1548,12 @@ namespace Sensus.Ui.FM2014TestBench
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch"> /// <remarks date="2026-Feb-09" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
private void cbxToleranceCalc_KeyDown(Object sender, KeyEventArgs e) private void cbxToleranceDisplayRange_KeyDown(Object sender, KeyEventArgs e)
{ {
// Catch the enter key, recalculate all settings // Catch the enter key, recalculate all settings
if (e.Key == Key.Enter || e.Key == Key.Tab) if (e.Key == Key.Enter || e.Key == Key.Tab)
{ {
Keyboard.Focus(btnSaveRegulationSetup); Keyboard.Focus(btnSaveSetupToFm2014);
} }
} }
@ -1536,10 +1561,10 @@ namespace Sensus.Ui.FM2014TestBench
/// FM2014 tolerance setup for calculation of it item has changed: /// FM2014 tolerance setup for calculation of it item has changed:
/// - This will dispatch the new value to all FM2014s. /// - This will dispatch the new value to all FM2014s.
/// </summary> /// </summary>
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch"> /// <remarks date="2026-Feb-09..Feb-16" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
private void cbxToleranceCalc_SelectedIndexChanged(Object sender, EventArgs e) private void cbxToleranceDisplayRange_SelectedIndexChanged(Object sender, EventArgs e)
{ {
var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014(); var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014();
@ -1548,13 +1573,13 @@ namespace Sensus.Ui.FM2014TestBench
Dispatcher.Invoke(() => Dispatcher.Invoke(() =>
{ {
if (byte.TryParse(cbxToleranceCalc.SelectedItem.ToString(), out var tolerance) && if (byte.TryParse(cbxToleranceDisplayRange.SelectedItem.ToString(), out var tolerance) &&
(tolerance == FM2014.CURRENT_OUTPUT_TOLERANCE_STANDARD_NOMINAL_INT_percent || (tolerance == FM2014.CURRENT_OUTPUT_DISPLAY_RANGE_STANDARD_NOMINAL_percent ||
tolerance == FM2014.CURRENT_OUTPUT_TOLERANCE_EXTENDED_VALUE_INT_percent) && tolerance == FM2014.CURRENT_OUTPUT_DISPLAY_RANGE_EXTENDED_NOMINAL_percent) &&
firstFm2014.CurrentOutputToleranceNominalInt_percent != tolerance) firstFm2014.CurrentOutputDisplayRangeNominal_percent != tolerance)
{ {
_regulationSetupHasChanged = true; _programConfigSetupHasChanged = true;
btnSaveRegulationSetup.IsEnabled = true; firstFm2014.CurrentOutputDisplayRangeNominal_percent = tolerance;
} }
}); });
} }
@ -1567,12 +1592,12 @@ namespace Sensus.Ui.FM2014TestBench
/// <remarks date="2026-Jan-24" author="Thomas Wiedebusch"> /// <remarks date="2026-Jan-24" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
private void cbxAttenuation_KeyDown(Object sender, KeyEventArgs e) private void cbxToleranceDisplayAttenuation_KeyDown(Object sender, KeyEventArgs e)
{ {
// Catch the enter key, recalculate all settings // Catch the enter key, recalculate all settings
if (e.Key == Key.Enter || e.Key == Key.Tab) if (e.Key == Key.Enter || e.Key == Key.Tab)
{ {
Keyboard.Focus(cbxToleranceCalc); Keyboard.Focus(cbxToleranceDisplayRange);
} }
} }
@ -1583,7 +1608,7 @@ namespace Sensus.Ui.FM2014TestBench
/// <remarks date="2026-Jan-18" author="Thomas Wiedebusch"> /// <remarks date="2026-Jan-18" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
private void cbxAttenuation_SelectedIndexChanged(Object sender, EventArgs e) private void cbxToleranceDisplayAttenuation_SelectedIndexChanged(Object sender, EventArgs e)
{ {
var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014(); var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014();
@ -1592,13 +1617,17 @@ namespace Sensus.Ui.FM2014TestBench
Dispatcher.Invoke(() => Dispatcher.Invoke(() =>
{ {
if (byte.TryParse(cbxDisplayAttenuation.SelectedItem.ToString(), out var attenuation) && if (byte.TryParse(cbxToleranceDisplayAttenuation.SelectedItem.ToString(), out var attenuation) &&
attenuation >= FM2014.CURRENT_OUTPUT_ATTENUATION_MIN && attenuation >= FM2014.CURRENT_OUTPUT_ATTENUATION_MIN &&
attenuation <= FM2014.CURRENT_OUTPUT_ATTENUATION_MAX && attenuation <= FM2014.CURRENT_OUTPUT_ATTENUATION_MAX &&
firstFm2014.CurrentOutputAttenuation != attenuation) firstFm2014.CurrentOutputAttenuation != attenuation)
{ {
_regulationSetupHasChanged = true; foreach (var fm2014 in FM2014.RegisteredFm2014s)
btnSaveRegulationSetup.IsEnabled = true; {
fm2014.CurrentOutputAttenuation = attenuation;
}
_fm2014RegulationSetupHasChanged = true;
UiElmEnable(btnSaveSetupToFm2014, true);
} }
}); });
} }
@ -1608,15 +1637,15 @@ namespace Sensus.Ui.FM2014TestBench
/// These values can be setup before any connection to the FM2014 has been established. Therefore, those /// These values can be setup before any connection to the FM2014 has been established. Therefore, those
/// settings have to be remembered within this object. /// settings have to be remembered within this object.
/// </summary> /// </summary>
/// <remarks date="2026-Jan-04" author="Thomas Wiedebusch"> /// <remarks date="2026-Jan-04..Feb-16" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
private void cbxFM2014BaseSettings_SelectedValueChanged(Object sender, EventArgs e) private void cbxProgramComPort_SelectedValueChanged(Object sender, EventArgs e)
{ {
if (_comPortIdx != cbxFM2014ComPort.SelectedIndex) if (_comPortIdx != cbxProgramComPort.SelectedIndex)
{ {
_comPortIdx = cbxFM2014ComPort.SelectedIndex; _comPortIdx = cbxProgramComPort.SelectedIndex;
StoreFM2014SettingsToConfigFile(); _programConfigSetupHasChanged = true;
} }
} }
@ -1629,12 +1658,12 @@ namespace Sensus.Ui.FM2014TestBench
/// <remarks date="2026-Jan-18" author="Thomas Wiedebusch"> /// <remarks date="2026-Jan-18" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
private void btnSaveRegulationSetup_Click(Object sender, EventArgs e) private void btnSaveSetupToFm2014_Click(Object sender, EventArgs e)
{ {
if (FM2014.StoreAllConfigurations()) if (FM2014.StoreAllConfigurations())
{ {
_regulationSetupHasChanged = false; _fm2014RegulationSetupHasChanged = false;
UiElmEnable(btnSaveRegulationSetup, false); UiElmEnable(btnSaveSetupToFm2014, false);
} }
} }
@ -1770,7 +1799,7 @@ namespace Sensus.Ui.FM2014TestBench
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch"> /// <remarks date="2026-Feb-09..Feb-16" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
private void tbxRefPulsesRequired_LostFocus(Object sender, EventArgs e) private void tbxRefPulsesRequired_LostFocus(Object sender, EventArgs e)
@ -1795,7 +1824,11 @@ namespace Sensus.Ui.FM2014TestBench
FM2014.PULSES_TIME_MEASUREMENT_INPUT_MAX >= pulses) FM2014.PULSES_TIME_MEASUREMENT_INPUT_MAX >= pulses)
{ {
if (backupPulsesRequired != pulses) if (backupPulsesRequired != pulses)
_calibrationSetupHasChanged = true; {
_programCalibrationSetupHasChanged = true;
// Preset to fill the configuration file storage ability
firstFm2014.RefPulsesRequired = (UInt32)pulses;
}
tbxRefPulsesRequired.Background = ColorStandardInputField; tbxRefPulsesRequired.Background = ColorStandardInputField;
} }
@ -1864,7 +1897,7 @@ namespace Sensus.Ui.FM2014TestBench
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch"> /// <remarks date="2026-Feb-09..Feb-16" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
private void tbxDutPulsesRequired_LostFocus(Object sender, EventArgs e) private void tbxDutPulsesRequired_LostFocus(Object sender, EventArgs e)
@ -1889,8 +1922,11 @@ namespace Sensus.Ui.FM2014TestBench
FM2014.PULSES_TIME_MEASUREMENT_INPUT_MIN <= pulses && FM2014.PULSES_TIME_MEASUREMENT_INPUT_MIN <= pulses &&
FM2014.PULSES_TIME_MEASUREMENT_INPUT_MAX >= pulses) FM2014.PULSES_TIME_MEASUREMENT_INPUT_MAX >= pulses)
{ {
if (backupPulsesRequired != pulses) if (backupPulsesRequired != pulses){
_calibrationSetupHasChanged = true; _programCalibrationSetupHasChanged = true;
// Preset to fill the configuration file storage ability
firstFm2014.DutPulsesRequired = (UInt32)pulses;
}
tbxDutPulsesRequired.Background = ColorStandardInputField; tbxDutPulsesRequired.Background = ColorStandardInputField;
} }
@ -1950,7 +1986,7 @@ namespace Sensus.Ui.FM2014TestBench
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch"> /// <remarks date="2026-Feb-09..Feb-16" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
private void tbxDoublePulseDeadtime_LostFocus(Object sender, EventArgs e) private void tbxDoublePulseDeadtime_LostFocus(Object sender, EventArgs e)
@ -1976,7 +2012,11 @@ namespace Sensus.Ui.FM2014TestBench
FM2014.DOUBLE_PULSE_DEADTIME_MAX_ms >= deadtime) FM2014.DOUBLE_PULSE_DEADTIME_MAX_ms >= deadtime)
{ {
if (backupDoublePulseDeadtime != deadtime) if (backupDoublePulseDeadtime != deadtime)
_calibrationSetupHasChanged = true; {
_programCalibrationSetupHasChanged = true;
// Preset to fill the configuration file storage ability
firstFm2014.DoublePulseDeadtime_ms = (UInt16)deadtime;
}
tbxDoublePulseDeadtime.Background = ColorStandardInputField; tbxDoublePulseDeadtime.Background = ColorStandardInputField;
} }
@ -2038,7 +2078,7 @@ namespace Sensus.Ui.FM2014TestBench
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch"> /// <remarks date="2026-Feb-09..Feb-16" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
private void tbxDutToRefToleranceMax_LostFocus(Object sender, EventArgs e) private void tbxDutToRefToleranceMax_LostFocus(Object sender, EventArgs e)
@ -2063,7 +2103,11 @@ namespace Sensus.Ui.FM2014TestBench
if (double.TryParse(englishNumberFormat, NumberStyles.Any, new CultureInfo("en"), out var tolerance)) if (double.TryParse(englishNumberFormat, NumberStyles.Any, new CultureInfo("en"), out var tolerance))
{ {
if (Math.Abs(backupDutToRefTolerance - tolerance) > 0.05) if (Math.Abs(backupDutToRefTolerance - tolerance) > 0.05)
_calibrationSetupHasChanged = true; {
_programCalibrationSetupHasChanged = true;
// Preset to fill the configuration file storage ability
firstFm2014.DutToRefCalibrationToleranceMax_percent = tolerance;
}
tbxDutToRefTolMax.Background = ColorStandardInputField; tbxDutToRefTolMax.Background = ColorStandardInputField;
@ -2132,7 +2176,7 @@ namespace Sensus.Ui.FM2014TestBench
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch"> /// <remarks date="2026-Feb-09..Feb-16" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
private void tbxDutToRefToleranceMin_LostFocus(Object sender, EventArgs e) private void tbxDutToRefToleranceMin_LostFocus(Object sender, EventArgs e)
@ -2157,7 +2201,11 @@ namespace Sensus.Ui.FM2014TestBench
if (double.TryParse(englishNumberFormat, NumberStyles.Any, new CultureInfo("en"), out var tolerance)) if (double.TryParse(englishNumberFormat, NumberStyles.Any, new CultureInfo("en"), out var tolerance))
{ {
if (Math.Abs(backupDutToRefTolerance - tolerance) > 0.05) if (Math.Abs(backupDutToRefTolerance - tolerance) > 0.05)
_calibrationSetupHasChanged = true; {
_programCalibrationSetupHasChanged = true;
// Preset to fill the configuration file storage ability
firstFm2014.DutToRefCalibrationToleranceMin_percent = tolerance;
}
tbxDutToRefTolMin.Background = ColorStandardInputField; tbxDutToRefTolMin.Background = ColorStandardInputField;
@ -2237,7 +2285,7 @@ namespace Sensus.Ui.FM2014TestBench
if (string.IsNullOrEmpty(tbxRefPulsesPerCm.Text)) if (string.IsNullOrEmpty(tbxRefPulsesPerCm.Text))
{ {
tbxRefPulsesPerCm.Background = ColorProcessFailed; tbxRefPulsesPerCm.Background = ColorProcessFailed;
btnSaveRegulationSetup.IsEnabled = false; btnSaveSetupToFm2014.IsEnabled = false;
btnDutToRefRegulation.IsEnabled = false; btnDutToRefRegulation.IsEnabled = false;
return; return;
} }
@ -2289,7 +2337,7 @@ namespace Sensus.Ui.FM2014TestBench
if (e.Key == Key.Enter || e.Key == Key.Tab) if (e.Key == Key.Enter || e.Key == Key.Tab)
{ {
tbxDutPulsesPerCm_LostFocus(this, null); tbxDutPulsesPerCm_LostFocus(this, null);
Keyboard.Focus(cbxDisplayAttenuation); Keyboard.Focus(cbxToleranceDisplayAttenuation);
} }
else if (!MaskEditIntegerInput(e.Key)) else if (!MaskEditIntegerInput(e.Key))
{ {
@ -2337,7 +2385,7 @@ namespace Sensus.Ui.FM2014TestBench
if (string.IsNullOrEmpty(tbxDutPulsesPerCm.Text)) if (string.IsNullOrEmpty(tbxDutPulsesPerCm.Text))
{ {
tbxDutPulsesPerCm.Background = ColorProcessFailed; tbxDutPulsesPerCm.Background = ColorProcessFailed;
btnSaveRegulationSetup.IsEnabled = false; btnSaveSetupToFm2014.IsEnabled = false;
btnDutToRefRegulation.IsEnabled = false; btnDutToRefRegulation.IsEnabled = false;
return; return;
} }
@ -2493,7 +2541,7 @@ namespace Sensus.Ui.FM2014TestBench
private void chkAnySlot_Click(Object sender, RoutedEventArgs e) private void chkAnySlot_Click(Object sender, RoutedEventArgs e)
{ {
_configSetupHasChanged = true; _programConfigSetupHasChanged = true;
} }
/// <summary> /// <summary>

View File

@ -376,7 +376,7 @@ namespace Sensus.Ui.Fm2014TestBench.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Tolerance Display [%]:. /// Looks up a localized string similar to Tolerance Range [%]:.
/// </summary> /// </summary>
internal static string StrLblFM2014Tolerance { internal static string StrLblFM2014Tolerance {
get { get {

View File

@ -145,7 +145,7 @@
<value>Address:</value> <value>Address:</value>
</data> </data>
<data name="StrLblFM2014Tolerance" xml:space="preserve"> <data name="StrLblFM2014Tolerance" xml:space="preserve">
<value>Tolerance Display [%]:</value> <value>Tolerance Range [%]:</value>
</data> </data>
<data name="StrBtnConnect" xml:space="preserve"> <data name="StrBtnConnect" xml:space="preserve">
<value>Connect</value> <value>Connect</value>

View File

@ -32,7 +32,7 @@
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmMainMiniPrf)); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmMainMiniPrf));
this.gbxFM2014Setup = new System.Windows.Forms.GroupBox(); this.gbxFM2014Setup = new System.Windows.Forms.GroupBox();
this.lblFM2014SerialNumber = new System.Windows.Forms.Label(); this.lblFM2014SerialNumber = new System.Windows.Forms.Label();
this.cbxFM2014TolerancePercent = new System.Windows.Forms.ComboBox(); this.cbxToleranceDisplayRange = new System.Windows.Forms.ComboBox();
this.picFM2014 = new System.Windows.Forms.PictureBox(); this.picFM2014 = new System.Windows.Forms.PictureBox();
this.tbxFM2014SerialNumber = new System.Windows.Forms.TextBox(); this.tbxFM2014SerialNumber = new System.Windows.Forms.TextBox();
this.lblFM2014Tolerance = new System.Windows.Forms.Label(); this.lblFM2014Tolerance = new System.Windows.Forms.Label();
@ -40,17 +40,17 @@
this.lblFM2014Address = new System.Windows.Forms.Label(); this.lblFM2014Address = new System.Windows.Forms.Label();
this.lblFwVersion = new System.Windows.Forms.Label(); this.lblFwVersion = new System.Windows.Forms.Label();
this.btnFM2014Connect = new System.Windows.Forms.Button(); this.btnFM2014Connect = new System.Windows.Forms.Button();
this.cbxFM2014ComPort = new System.Windows.Forms.ComboBox(); this.cbxProgramComPort = new System.Windows.Forms.ComboBox();
this.lblFM2014SerialPort = new System.Windows.Forms.Label(); this.lblFM2014SerialPort = new System.Windows.Forms.Label();
this.lblConnectFM2014 = new System.Windows.Forms.Label(); this.lblConnectFM2014 = new System.Windows.Forms.Label();
this.tbxFM2014FullId = new System.Windows.Forms.TextBox(); this.tbxFM2014FullId = new System.Windows.Forms.TextBox();
this.tbxFM2014ApplicationFwVersion = new System.Windows.Forms.TextBox(); this.tbxFM2014ApplicationFwVersion = new System.Windows.Forms.TextBox();
this.gbxRegulationSetup = new System.Windows.Forms.GroupBox(); this.gbxRegulationSetup = new System.Windows.Forms.GroupBox();
this.btnSaveRegulationSetup = new System.Windows.Forms.Button(); this.btnSaveSetupToFm2014 = new System.Windows.Forms.Button();
this.cbxAttenuation = new System.Windows.Forms.ComboBox(); this.cbxToleranceDisplayAttenuation = new System.Windows.Forms.ComboBox();
this.lblRefPulsePerVolume = new System.Windows.Forms.Label(); this.lblRefPulsePerVolume = new System.Windows.Forms.Label();
this.lblDutPulsePerVolume = new System.Windows.Forms.Label(); this.lblDutPulsePerVolume = new System.Windows.Forms.Label();
this.lblAttenuation = new System.Windows.Forms.Label(); this.lblToleranceDisplayAttenuation = new System.Windows.Forms.Label();
this.lblScaleRefToDut = new System.Windows.Forms.Label(); this.lblScaleRefToDut = new System.Windows.Forms.Label();
this.tbxRefPulsesPerCm = new System.Windows.Forms.TextBox(); this.tbxRefPulsesPerCm = new System.Windows.Forms.TextBox();
this.tbxDutPulsesPerCm = new System.Windows.Forms.TextBox(); this.tbxDutPulsesPerCm = new System.Windows.Forms.TextBox();
@ -110,7 +110,7 @@
// gbxFM2014Setup // gbxFM2014Setup
// //
this.gbxFM2014Setup.Controls.Add(this.lblFM2014SerialNumber); this.gbxFM2014Setup.Controls.Add(this.lblFM2014SerialNumber);
this.gbxFM2014Setup.Controls.Add(this.cbxFM2014TolerancePercent); this.gbxFM2014Setup.Controls.Add(this.cbxToleranceDisplayRange);
this.gbxFM2014Setup.Controls.Add(this.picFM2014); this.gbxFM2014Setup.Controls.Add(this.picFM2014);
this.gbxFM2014Setup.Controls.Add(this.tbxFM2014SerialNumber); this.gbxFM2014Setup.Controls.Add(this.tbxFM2014SerialNumber);
this.gbxFM2014Setup.Controls.Add(this.lblFM2014Tolerance); this.gbxFM2014Setup.Controls.Add(this.lblFM2014Tolerance);
@ -118,7 +118,7 @@
this.gbxFM2014Setup.Controls.Add(this.lblFM2014Address); this.gbxFM2014Setup.Controls.Add(this.lblFM2014Address);
this.gbxFM2014Setup.Controls.Add(this.lblFwVersion); this.gbxFM2014Setup.Controls.Add(this.lblFwVersion);
this.gbxFM2014Setup.Controls.Add(this.btnFM2014Connect); this.gbxFM2014Setup.Controls.Add(this.btnFM2014Connect);
this.gbxFM2014Setup.Controls.Add(this.cbxFM2014ComPort); this.gbxFM2014Setup.Controls.Add(this.cbxProgramComPort);
this.gbxFM2014Setup.Controls.Add(this.lblFM2014SerialPort); this.gbxFM2014Setup.Controls.Add(this.lblFM2014SerialPort);
this.gbxFM2014Setup.Controls.Add(this.lblConnectFM2014); this.gbxFM2014Setup.Controls.Add(this.lblConnectFM2014);
this.gbxFM2014Setup.Controls.Add(this.tbxFM2014FullId); this.gbxFM2014Setup.Controls.Add(this.tbxFM2014FullId);
@ -139,18 +139,18 @@
this.lblFM2014SerialNumber.TabIndex = 27; this.lblFM2014SerialNumber.TabIndex = 27;
this.lblFM2014SerialNumber.Text = "Serial Number:"; this.lblFM2014SerialNumber.Text = "Serial Number:";
// //
// cbxFM2014TolerancePercent // cbxToleranceDisplayRange
// //
this.cbxFM2014TolerancePercent.FormattingEnabled = true; this.cbxToleranceDisplayRange.FormattingEnabled = true;
this.cbxFM2014TolerancePercent.Items.AddRange(new object[] { this.cbxToleranceDisplayRange.Items.AddRange(new object[] {
"3", "3",
"5"}); "5"});
this.cbxFM2014TolerancePercent.Location = new System.Drawing.Point(220, 150); this.cbxToleranceDisplayRange.Location = new System.Drawing.Point(220, 150);
this.cbxFM2014TolerancePercent.Name = "cbxFM2014TolerancePercent"; this.cbxToleranceDisplayRange.Name = "cbxToleranceDisplayRange";
this.cbxFM2014TolerancePercent.Size = new System.Drawing.Size(60, 21); this.cbxToleranceDisplayRange.Size = new System.Drawing.Size(60, 21);
this.cbxFM2014TolerancePercent.TabIndex = 3; this.cbxToleranceDisplayRange.TabIndex = 3;
this.cbxFM2014TolerancePercent.Text = "3"; this.cbxToleranceDisplayRange.Text = "3";
this.cbxFM2014TolerancePercent.SelectedValueChanged += new System.EventHandler(this.cbxFM2014BaseSettings_SelectedValueChanged); this.cbxToleranceDisplayRange.SelectedValueChanged += new System.EventHandler(this.cbxFM2014BaseSettings_SelectedValueChanged);
// //
// picFM2014 // picFM2014
// //
@ -237,15 +237,15 @@
this.btnFM2014Connect.UseVisualStyleBackColor = true; this.btnFM2014Connect.UseVisualStyleBackColor = true;
this.btnFM2014Connect.Click += new System.EventHandler(this.btnConnect_Click); this.btnFM2014Connect.Click += new System.EventHandler(this.btnConnect_Click);
// //
// cbxFM2014ComPort // cbxProgramComPort
// //
this.cbxFM2014ComPort.FormattingEnabled = true; this.cbxProgramComPort.FormattingEnabled = true;
this.cbxFM2014ComPort.Location = new System.Drawing.Point(220, 100); this.cbxProgramComPort.Location = new System.Drawing.Point(220, 100);
this.cbxFM2014ComPort.Name = "cbxFM2014ComPort"; this.cbxProgramComPort.Name = "cbxProgramComPort";
this.cbxFM2014ComPort.Size = new System.Drawing.Size(60, 21); this.cbxProgramComPort.Size = new System.Drawing.Size(60, 21);
this.cbxFM2014ComPort.TabIndex = 1; this.cbxProgramComPort.TabIndex = 1;
this.cbxFM2014ComPort.Text = "NA"; this.cbxProgramComPort.Text = "NA";
this.cbxFM2014ComPort.SelectedValueChanged += new System.EventHandler(this.cbxFM2014BaseSettings_SelectedValueChanged); this.cbxProgramComPort.SelectedValueChanged += new System.EventHandler(this.cbxFM2014BaseSettings_SelectedValueChanged);
// //
// lblFM2014SerialPort // lblFM2014SerialPort
// //
@ -286,11 +286,11 @@
// //
// gbxRegulationSetup // gbxRegulationSetup
// //
this.gbxRegulationSetup.Controls.Add(this.btnSaveRegulationSetup); this.gbxRegulationSetup.Controls.Add(this.btnSaveSetupToFm2014);
this.gbxRegulationSetup.Controls.Add(this.cbxAttenuation); this.gbxRegulationSetup.Controls.Add(this.cbxToleranceDisplayAttenuation);
this.gbxRegulationSetup.Controls.Add(this.lblRefPulsePerVolume); this.gbxRegulationSetup.Controls.Add(this.lblRefPulsePerVolume);
this.gbxRegulationSetup.Controls.Add(this.lblDutPulsePerVolume); this.gbxRegulationSetup.Controls.Add(this.lblDutPulsePerVolume);
this.gbxRegulationSetup.Controls.Add(this.lblAttenuation); this.gbxRegulationSetup.Controls.Add(this.lblToleranceDisplayAttenuation);
this.gbxRegulationSetup.Controls.Add(this.lblScaleRefToDut); this.gbxRegulationSetup.Controls.Add(this.lblScaleRefToDut);
this.gbxRegulationSetup.Controls.Add(this.tbxRefPulsesPerCm); this.gbxRegulationSetup.Controls.Add(this.tbxRefPulsesPerCm);
this.gbxRegulationSetup.Controls.Add(this.tbxDutPulsesPerCm); this.gbxRegulationSetup.Controls.Add(this.tbxDutPulsesPerCm);
@ -302,20 +302,20 @@
this.gbxRegulationSetup.TabStop = false; this.gbxRegulationSetup.TabStop = false;
this.gbxRegulationSetup.Text = "Regulation Setup"; this.gbxRegulationSetup.Text = "Regulation Setup";
// //
// btnSaveRegulationSetup // btnSaveSetupToFm2014
// //
this.btnSaveRegulationSetup.Location = new System.Drawing.Point(173, 144); this.btnSaveSetupToFm2014.Location = new System.Drawing.Point(173, 144);
this.btnSaveRegulationSetup.Name = "btnSaveRegulationSetup"; this.btnSaveSetupToFm2014.Name = "btnSaveSetupToFm2014";
this.btnSaveRegulationSetup.Size = new System.Drawing.Size(110, 25); this.btnSaveSetupToFm2014.Size = new System.Drawing.Size(110, 25);
this.btnSaveRegulationSetup.TabIndex = 7; this.btnSaveSetupToFm2014.TabIndex = 7;
this.btnSaveRegulationSetup.Text = "Save"; this.btnSaveSetupToFm2014.Text = "Save";
this.btnSaveRegulationSetup.UseVisualStyleBackColor = true; this.btnSaveSetupToFm2014.UseVisualStyleBackColor = true;
this.btnSaveRegulationSetup.Click += new System.EventHandler(this.btnSaveRegulationSetup_Click); this.btnSaveSetupToFm2014.Click += new System.EventHandler(this.btnSaveRegulationSetup_Click);
// //
// cbxAttenuation // cbxToleranceDisplayAttenuation
// //
this.cbxAttenuation.FormattingEnabled = true; this.cbxToleranceDisplayAttenuation.FormattingEnabled = true;
this.cbxAttenuation.Items.AddRange(new object[] { this.cbxToleranceDisplayAttenuation.Items.AddRange(new object[] {
"1", "1",
"2", "2",
"3", "3",
@ -325,13 +325,13 @@
"7", "7",
"8", "8",
"9"}); "9"});
this.cbxAttenuation.Location = new System.Drawing.Point(220, 101); this.cbxToleranceDisplayAttenuation.Location = new System.Drawing.Point(220, 101);
this.cbxAttenuation.Name = "cbxAttenuation"; this.cbxToleranceDisplayAttenuation.Name = "cbxToleranceDisplayAttenuation";
this.cbxAttenuation.Size = new System.Drawing.Size(60, 21); this.cbxToleranceDisplayAttenuation.Size = new System.Drawing.Size(60, 21);
this.cbxAttenuation.TabIndex = 6; this.cbxToleranceDisplayAttenuation.TabIndex = 6;
this.cbxAttenuation.Text = "3"; this.cbxToleranceDisplayAttenuation.Text = "3";
this.cbxAttenuation.SelectedIndexChanged += new System.EventHandler(this.cbxAttenuation_SelectedIndexChanged); this.cbxToleranceDisplayAttenuation.SelectedIndexChanged += new System.EventHandler(this.cbxToleranceDisplayAttenuation_SelectedIndexChanged);
this.cbxAttenuation.KeyDown += new System.Windows.Forms.KeyEventHandler(this.cbxAttenuation_KeyDown); this.cbxToleranceDisplayAttenuation.KeyDown += new System.Windows.Forms.KeyEventHandler(this.cbxToleranceDisplayAttenuation_KeyDown);
// //
// lblRefPulsePerVolume // lblRefPulsePerVolume
// //
@ -351,14 +351,14 @@
this.lblDutPulsePerVolume.TabIndex = 63; this.lblDutPulsePerVolume.TabIndex = 63;
this.lblDutPulsePerVolume.Text = "DUT [pulses/m³]:"; this.lblDutPulsePerVolume.Text = "DUT [pulses/m³]:";
// //
// lblAttenuation // lblToleranceDisplayAttenuation
// //
this.lblAttenuation.AutoSize = true; this.lblToleranceDisplayAttenuation.AutoSize = true;
this.lblAttenuation.Location = new System.Drawing.Point(10, 103); this.lblToleranceDisplayAttenuation.Location = new System.Drawing.Point(10, 103);
this.lblAttenuation.Name = "lblAttenuation"; this.lblToleranceDisplayAttenuation.Name = "lblToleranceDisplayAttenuation";
this.lblAttenuation.Size = new System.Drawing.Size(73, 13); this.lblToleranceDisplayAttenuation.Size = new System.Drawing.Size(73, 13);
this.lblAttenuation.TabIndex = 68; this.lblToleranceDisplayAttenuation.TabIndex = 68;
this.lblAttenuation.Text = "Attenuation []:"; this.lblToleranceDisplayAttenuation.Text = "Attenuation []:";
// //
// lblScaleRefToDut // lblScaleRefToDut
// //
@ -817,7 +817,7 @@
// //
this.menuStrip1.Location = new System.Drawing.Point(0, 0); this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1"; this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(538, 24); this.menuStrip1.Size = new System.Drawing.Size(543, 24);
this.menuStrip1.TabIndex = 85; this.menuStrip1.TabIndex = 85;
this.menuStrip1.Text = "menuStrip1"; this.menuStrip1.Text = "menuStrip1";
// //
@ -825,7 +825,7 @@
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(538, 467); this.ClientSize = new System.Drawing.Size(543, 461);
this.Controls.Add(this.grpBoxDebug); this.Controls.Add(this.grpBoxDebug);
this.Controls.Add(this.gbxRegulationSetup); this.Controls.Add(this.gbxRegulationSetup);
this.Controls.Add(this.gbxDutToRefRegulation); this.Controls.Add(this.gbxDutToRefRegulation);
@ -868,14 +868,14 @@
private System.Windows.Forms.GroupBox gbxFM2014Setup; private System.Windows.Forms.GroupBox gbxFM2014Setup;
private System.Windows.Forms.Button btnFM2014Connect; private System.Windows.Forms.Button btnFM2014Connect;
private System.Windows.Forms.ComboBox cbxFM2014ComPort; private System.Windows.Forms.ComboBox cbxProgramComPort;
private System.Windows.Forms.Label lblFM2014SerialPort; private System.Windows.Forms.Label lblFM2014SerialPort;
private System.Windows.Forms.Label lblConnectFM2014; private System.Windows.Forms.Label lblConnectFM2014;
private System.Windows.Forms.TextBox tbxFM2014FullId; private System.Windows.Forms.TextBox tbxFM2014FullId;
private System.Windows.Forms.GroupBox gbxRegulationSetup; private System.Windows.Forms.GroupBox gbxRegulationSetup;
private System.Windows.Forms.Label lblRefPulsePerVolume; private System.Windows.Forms.Label lblRefPulsePerVolume;
private System.Windows.Forms.Label lblDutPulsePerVolume; private System.Windows.Forms.Label lblDutPulsePerVolume;
private System.Windows.Forms.Label lblAttenuation; private System.Windows.Forms.Label lblToleranceDisplayAttenuation;
private System.Windows.Forms.Label lblScaleRefToDut; private System.Windows.Forms.Label lblScaleRefToDut;
private System.Windows.Forms.TextBox tbxRefPulsesPerCm; private System.Windows.Forms.TextBox tbxRefPulsesPerCm;
private System.Windows.Forms.TextBox tbxDutPulsesPerCm; private System.Windows.Forms.TextBox tbxDutPulsesPerCm;
@ -890,11 +890,11 @@
private System.Windows.Forms.Label lblWaitingForMeterResponse; private System.Windows.Forms.Label lblWaitingForMeterResponse;
private System.Windows.Forms.ProgressBar barSingleProgressUpdate; private System.Windows.Forms.ProgressBar barSingleProgressUpdate;
private System.Windows.Forms.Label lblActualProcess; private System.Windows.Forms.Label lblActualProcess;
private System.Windows.Forms.ComboBox cbxFM2014TolerancePercent; private System.Windows.Forms.ComboBox cbxToleranceDisplayRange;
private System.Windows.Forms.Label lblFM2014Tolerance; private System.Windows.Forms.Label lblFM2014Tolerance;
private System.Windows.Forms.ComboBox cbxFM2014Address; private System.Windows.Forms.ComboBox cbxFM2014Address;
private System.Windows.Forms.Label lblFM2014Address; private System.Windows.Forms.Label lblFM2014Address;
private System.Windows.Forms.ComboBox cbxAttenuation; private System.Windows.Forms.ComboBox cbxToleranceDisplayAttenuation;
private System.Windows.Forms.Button btnDutToRefRegulation; private System.Windows.Forms.Button btnDutToRefRegulation;
private System.Windows.Forms.GroupBox gbxManualRefCalibration; private System.Windows.Forms.GroupBox gbxManualRefCalibration;
private System.Windows.Forms.GroupBox gbxDutToRefRegulation; private System.Windows.Forms.GroupBox gbxDutToRefRegulation;
@ -909,7 +909,7 @@
private System.Windows.Forms.Label lblActualFlowRateCmPerHour; private System.Windows.Forms.Label lblActualFlowRateCmPerHour;
private System.Windows.Forms.TextBox tbxActualFlowRateCmPerHour; private System.Windows.Forms.TextBox tbxActualFlowRateCmPerHour;
private System.Windows.Forms.CheckBox chkUseDampedTolerance; private System.Windows.Forms.CheckBox chkUseDampedTolerance;
private System.Windows.Forms.Button btnSaveRegulationSetup; private System.Windows.Forms.Button btnSaveSetupToFm2014;
private System.Windows.Forms.PictureBox pictureBox1; private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.PictureBox picFM2014; private System.Windows.Forms.PictureBox picFM2014;
private System.Windows.Forms.TextBox tbxRefFrequencyHz; private System.Windows.Forms.TextBox tbxRefFrequencyHz;

View File

@ -90,9 +90,19 @@ namespace Sensus.MiniPrf.Ui
// internal reminders of changed items to avoid write access on startup if items are preloaded // internal reminders of changed items to avoid write access on startup if items are preloaded
private Int32 _comPortIdx; private Int32 _comPortIdx;
private Int32 _addressIdx; private Int32 _addressIdx;
private Int32 _toleranceIdx; private Int32 _currentOutputDisplayRange_percent;
private Byte _toleranceDisplayAttenuation;
/// <summary>
/// The regulation setup will be stored directly to the FM2014 being able to use it at startup
/// </summary>
private Boolean _fm2014RegulationSetupHasChanged;
/// <summary>
/// If the program configuration has changed, this shall be stored to the configuration file
/// </summary>
private Boolean _programConfigSetupHasChanged;
private Boolean _regulationSetupHasChanged;
#endregion Properties #endregion Properties
#region FormControls #region FormControls
@ -111,7 +121,7 @@ namespace Sensus.MiniPrf.Ui
_version = Assembly.GetExecutingAssembly().GetName().Version; _version = Assembly.GetExecutingAssembly().GetName().Version;
ColorStandardDisplayField = lblFM2014SerialPort.BackColor; ColorStandardDisplayField = lblFM2014SerialPort.BackColor;
ColorStandardInputField = cbxFM2014ComPort.BackColor; ColorStandardInputField = cbxProgramComPort.BackColor;
_cancellationTokenSource = new CancellationTokenSource(); _cancellationTokenSource = new CancellationTokenSource();
_cancellationToken = _cancellationTokenSource.Token; _cancellationToken = _cancellationTokenSource.Token;
@ -127,53 +137,56 @@ namespace Sensus.MiniPrf.Ui
{ {
ActionControl(false); ActionControl(false);
_autoProgressBar = false; _autoProgressBar = false;
_regulationSetupHasChanged = false; _fm2014RegulationSetupHasChanged = false;
_programConfigSetupHasChanged = false;
grpBoxDebug.Visible = false; grpBoxDebug.Visible = false;
gbxDutToRefRegulation.Visible = true; gbxDutToRefRegulation.Visible = true;
gbxRegulationSetup.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))
{
cbxFM2014ComPort.Items.Add(_fm2014Config.SerialPort);
}
else if (_fm2014Config?.SerialPort == null && !cbxFM2014ComPort.Items.Contains("?"))
{
cbxFM2014ComPort.Items.Add("?");
}
// Collect and add all com-ports from device manager to items
var comPorts = SerialPort.GetPortNames().ToList();
foreach (var comPort in comPorts.Where(comPort => !cbxFM2014ComPort.Items.Contains(comPort)))
{
cbxFM2014ComPort.Items.Add(comPort);
}
cbxFM2014ComPort.Text = cbxFM2014ComPort.Items[_comPortIdx].ToString();
var itemContent = _fm2014Config?.Address ?? 1;
for (var idx = 0; idx < cbxFM2014Address.MaxDropDownItems; idx++)
{
if (!cbxFM2014Address.Items[idx].ToString().Equals(itemContent.ToString())) continue;
_addressIdx = idx;
cbxFM2014Address.SelectedItem = cbxFM2014Address.Items[idx];
break;
}
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;
}
if (_fm2014Config != null) if (_fm2014Config != null)
{ {
// 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.SharedSerialPort != null && !cbxProgramComPort.Items.Contains(_fm2014Config.SharedSerialPort))
{
cbxProgramComPort.Items.Add(_fm2014Config.SharedSerialPort);
}
else if (_fm2014Config.SharedSerialPort == null && !cbxProgramComPort.Items.Contains("?"))
{
cbxProgramComPort.Items.Add("?");
}
// Collect and add all com-ports from device manager to items
var comPorts = SerialPort.GetPortNames().ToList();
foreach (var comPort in comPorts.Where(comPort => !cbxProgramComPort.Items.Contains(comPort)))
{
cbxProgramComPort.Items.Add(comPort);
}
cbxProgramComPort.Text = cbxProgramComPort.Items[_comPortIdx].ToString();
var itemContent = _fm2014Config.Address ?? 1;
for (var idx = 0; idx < cbxFM2014Address.MaxDropDownItems; idx++)
{
if (!cbxFM2014Address.Items[idx].ToString().Equals(itemContent.ToString())) continue;
_addressIdx = idx;
cbxFM2014Address.SelectedItem = cbxFM2014Address.Items[idx];
break;
}
itemContent = _fm2014Config.CommonCurrentOutputDisplayRangeNominal_percent;
for (var idx = 0; idx < cbxToleranceDisplayRange.MaxDropDownItems; idx++)
{
if (!cbxToleranceDisplayRange.Items[idx].ToString().Equals(itemContent.ToString())) continue;
_currentOutputDisplayRange_percent = idx;
cbxToleranceDisplayRange.SelectedItem = cbxToleranceDisplayRange.Items[idx];
break;
}
// Restore baudrate // Restore baudrate
FM2014.Baudrate = _fm2014Config.Baudrate; FM2014.Baudrate = _fm2014Config.Baudrate;
} }
@ -198,8 +211,8 @@ namespace Sensus.MiniPrf.Ui
tbxDutPulsesPerCm.Text = ""; tbxDutPulsesPerCm.Text = "";
lblScaleRefToDut.Text = Resources.StrLblScaleRefToDut; lblScaleRefToDut.Text = Resources.StrLblScaleRefToDut;
tbxScaleRefToDut.Text = ""; tbxScaleRefToDut.Text = "";
lblAttenuation.Text = Resources.StrLblAttenuation; lblToleranceDisplayAttenuation.Text = Resources.StrLblAttenuation;
btnSaveRegulationSetup.Text = Resources.StrBtnSaveRegulationSetup; btnSaveSetupToFm2014.Text = Resources.StrBtnSaveRegulationSetup;
// Manual REF Calibration group box // Manual REF Calibration group box
gbxManualRefCalibration.Text = Resources.StrGbxManualRefCalibration; gbxManualRefCalibration.Text = Resources.StrGbxManualRefCalibration;
@ -240,29 +253,25 @@ namespace Sensus.MiniPrf.Ui
/// <remarks date="2025-Nov-13" author="Thomas Wiedebusch"> /// <remarks date="2025-Nov-13" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
/// <remarks date="2026-Jan-15" author="Thomas Wiedebusch"> /// <remarks date="2026-Jan-15..Feb-16" author="Thomas Wiedebusch">
/// - Update FM2014 properties. /// - Update FM2014 properties.
/// </remarks> /// </remarks>
private void StoreFM2014Settings() private void StoreProgramConfiguration()
{ {
_fm2014Config.SerialPort = cbxFM2014ComPort.Text;
if (int.TryParse(cbxFM2014Address.SelectedItem.ToString(), out var address)) if (_fm2014Config == null)
return;
Invoke(new Action(() =>
{ {
_fm2014Config.Address = address; _programConfigSetupHasChanged = false;
if (Fm2014 != null)
Fm2014.Address = address;
} _fm2014Config.SharedSerialPort = cbxProgramComPort.Text;
_fm2014Config.Address = _addressIdx;
_fm2014Config.CommonCurrentOutputDisplayRangeNominal_percent = _currentOutputDisplayRange_percent;
if (int.TryParse(cbxFM2014TolerancePercent.SelectedItem.ToString(), out var tolerancePercent) _fm2014Config.Update();
&& (tolerancePercent == 3 || tolerancePercent == 5)) }));
{
_fm2014Config.TolerancePercent = tolerancePercent;
if (Fm2014 != null)
Fm2014.Tolerance_percent = tolerancePercent;
}
_fm2014Config.Update();
} }
private void FrmMainMiniPrf_Load(Object sender, EventArgs e) private void FrmMainMiniPrf_Load(Object sender, EventArgs e)
@ -321,7 +330,7 @@ namespace Sensus.MiniPrf.Ui
private void SetFM2014AccessLocked() private void SetFM2014AccessLocked()
{ {
// Disable all buttons // Disable all buttons
btnSaveRegulationSetup.Enabled = false; btnSaveSetupToFm2014.Enabled = false;
btnManualRefCalibration.Enabled = false; btnManualRefCalibration.Enabled = false;
btnDutToRefRegulation.Enabled = false; btnDutToRefRegulation.Enabled = false;
btnFM2014Connect.Enabled = false; btnFM2014Connect.Enabled = false;
@ -332,10 +341,10 @@ namespace Sensus.MiniPrf.Ui
tbxDutPulsesPerCm.ReadOnly = true; tbxDutPulsesPerCm.ReadOnly = true;
// Disable setting selections // Disable setting selections
cbxAttenuation.Enabled = false; cbxToleranceDisplayAttenuation.Enabled = false;
cbxFM2014Address.Enabled = false; cbxFM2014Address.Enabled = false;
cbxFM2014ComPort.Enabled = false; cbxProgramComPort.Enabled = false;
cbxFM2014TolerancePercent.Enabled = false; cbxToleranceDisplayRange.Enabled = false;
cbxMeasuredDutPulses.Enabled = false; cbxMeasuredDutPulses.Enabled = false;
} }
@ -344,27 +353,30 @@ namespace Sensus.MiniPrf.Ui
/// </summary> /// </summary>
private void SetFM2014AccessEnabled() private void SetFM2014AccessEnabled()
{ {
// Enable save setup depending on changed properties Invoke(new Action(() =>
btnSaveRegulationSetup.Enabled = _regulationSetupHasChanged; {
// Enable save setup depending on changed properties
btnSaveSetupToFm2014.Enabled = _fm2014RegulationSetupHasChanged;
// Enable buttons and display correct information // Enable buttons and display correct information
btnManualRefCalibration.Enabled = true; btnManualRefCalibration.Enabled = true;
btnDutToRefRegulation.Enabled = true; btnDutToRefRegulation.Enabled = true;
btnFM2014Connect.Enabled = true; btnFM2014Connect.Enabled = true;
btnManualRefCalibration.Text = Resources.StrBtnStartCalibration; btnManualRefCalibration.Text = Resources.StrBtnStartCalibration;
btnDutToRefRegulation.Text = Resources.StrBtnStartRegulation; btnDutToRefRegulation.Text = Resources.StrBtnStartRegulation;
// Enable manual input // Enable manual input
tbxVolumeMeasuredLiters.ReadOnly = false; tbxVolumeMeasuredLiters.ReadOnly = false;
tbxRefPulsesPerCm.ReadOnly = false; tbxRefPulsesPerCm.ReadOnly = false;
tbxDutPulsesPerCm.ReadOnly = false; tbxDutPulsesPerCm.ReadOnly = false;
// Enable setting selections // Enable setting selections
cbxAttenuation.Enabled = true; cbxToleranceDisplayAttenuation.Enabled = true;
cbxFM2014Address.Enabled = true; cbxFM2014Address.Enabled = true;
cbxFM2014ComPort.Enabled = true; cbxProgramComPort.Enabled = true;
cbxFM2014TolerancePercent.Enabled = true; cbxToleranceDisplayRange.Enabled = true;
cbxMeasuredDutPulses.Enabled = true; cbxMeasuredDutPulses.Enabled = true;
}));
} }
/// <summary> /// <summary>
@ -377,7 +389,7 @@ namespace Sensus.MiniPrf.Ui
SetFM2014AccessLocked(); SetFM2014AccessLocked();
btnFM2014Connect.Enabled = true; btnFM2014Connect.Enabled = true;
cbxFM2014Address.Enabled = true; cbxFM2014Address.Enabled = true;
cbxFM2014ComPort.Enabled = true; cbxProgramComPort.Enabled = true;
return; return;
} }
SetFM2014AccessEnabled(); SetFM2014AccessEnabled();
@ -398,9 +410,13 @@ namespace Sensus.MiniPrf.Ui
{ {
try try
{ {
if (_programConfigSetupHasChanged)
StoreProgramConfiguration();
Init(); Init();
if (string.IsNullOrEmpty(cbxFM2014ComPort?.SelectedItem?.ToString()) ||
cbxFM2014ComPort.SelectedItem.ToString().Equals("?")) if (string.IsNullOrEmpty(cbxProgramComPort?.SelectedItem?.ToString()) ||
cbxProgramComPort.SelectedItem.ToString().Equals("?"))
{ {
var text = Resources.StrErrorMsgComPortNotAssigned; var text = Resources.StrErrorMsgComPortNotAssigned;
MessageBox.Show(text, Resources.StrError, MessageBoxButtons.OK, MessageBoxIcon.Error); MessageBox.Show(text, Resources.StrError, MessageBoxButtons.OK, MessageBoxIcon.Error);
@ -408,8 +424,6 @@ namespace Sensus.MiniPrf.Ui
return; return;
} }
StoreFM2014Settings();
ActionControl(true); ActionControl(true);
if (Fm2014 != null) if (Fm2014 != null)
@ -435,10 +449,11 @@ namespace Sensus.MiniPrf.Ui
ActionControl(false); ActionControl(false);
LogErrorText(Resources.StrErrorMsgFM2014AddressInvalid); LogErrorText(Resources.StrErrorMsgFM2014AddressInvalid);
} }
if (int.TryParse(cbxFM2014TolerancePercent.SelectedItem.ToString(), out var tolerancePercent) if (int.TryParse(cbxToleranceDisplayRange.SelectedItem.ToString(), out var tolerancePercent)
&& (tolerancePercent == 3 || tolerancePercent == 5)) && (tolerancePercent == FM2014.CURRENT_OUTPUT_DISPLAY_RANGE_STANDARD_NOMINAL_percent ||
tolerancePercent == FM2014.CURRENT_OUTPUT_DISPLAY_RANGE_EXTENDED_NOMINAL_percent))
{ {
Fm2014.Tolerance_percent = tolerancePercent; Fm2014.CurrentOutputDisplayRangeNominal_percent = tolerancePercent;
} }
else else
{ {
@ -447,7 +462,7 @@ namespace Sensus.MiniPrf.Ui
} }
lblActualProcess.Text = Resources.StrMsgConnecting; lblActualProcess.Text = Resources.StrMsgConnecting;
Fm2014.Connect(cbxFM2014ComPort.SelectedItem.ToString()); Fm2014.Connect(cbxProgramComPort.SelectedItem.ToString());
Task.Factory.StartNew(() => Task.Factory.StartNew(() =>
{ {
@ -546,11 +561,11 @@ namespace Sensus.MiniPrf.Ui
/// </remarks> /// </remarks>
private void DutToRefRegulationSetupHasChanged() private void DutToRefRegulationSetupHasChanged()
{ {
_regulationSetupHasChanged = true; _fm2014RegulationSetupHasChanged = true;
Invoke(new Action(() => Invoke(new Action(() =>
{ {
btnSaveRegulationSetup.Enabled = true; btnSaveSetupToFm2014.Enabled = true;
btnDutToRefRegulation.Enabled = true; btnDutToRefRegulation.Enabled = true;
tbxRefFrequencyHz.BackColor = ColorStandardDisplayField; tbxRefFrequencyHz.BackColor = ColorStandardDisplayField;
@ -589,7 +604,7 @@ namespace Sensus.MiniPrf.Ui
{ {
tbxScaleRefToDut.BackColor = ColorProcessFailed; tbxScaleRefToDut.BackColor = ColorProcessFailed;
tbxScaleRefToDut.Text = Resources.StrError; tbxScaleRefToDut.Text = Resources.StrError;
btnSaveRegulationSetup.Enabled = false; btnSaveSetupToFm2014.Enabled = false;
btnDutToRefRegulation.Enabled = false; btnDutToRefRegulation.Enabled = false;
retVal = false; retVal = false;
} }
@ -702,7 +717,7 @@ namespace Sensus.MiniPrf.Ui
/// <summary> /// <summary>
/// Feedback from FM2014being parsed to GUI /// Feedback from FM2014being parsed to GUI
/// </summary> /// </summary>
/// <remarks date="2023-Jan-04..21" author="Thomas Wiedebusch"> /// <remarks date="2023-Jan-04..Feb-16" author="Thomas Wiedebusch">
/// - Initial. /// - Initial.
/// </remarks> /// </remarks>
private void DataReceived_Handler(Object sender, ProcessExecEventArgs e) private void DataReceived_Handler(Object sender, ProcessExecEventArgs e)
@ -721,12 +736,20 @@ namespace Sensus.MiniPrf.Ui
// Data dispatcher // Data dispatcher
var resp = (CmdResponse)e.SpecificInfoObj; var resp = (CmdResponse)e.SpecificInfoObj;
// Used as marker for error, null means measurement is in range or status or health is good
var statusColor = ColorStandardInputField;
// Color the output for the user display for quick check capability
if (e.StatusReturn == StatusReturn.MeasurementOutOfRange)
statusColor = ColorProcessFailed;
else if (e.StatusReturn == StatusReturn.MeasurementInRange)
statusColor = ColorSuccess;
if (e.StatusReturn == StatusReturn.Failed) if (e.StatusReturn == StatusReturn.Failed)
{ {
LogErrorText(resp.AnswerStr); LogErrorText(resp.AnswerStr);
//ErrorHandler(resp.CmdName); //ErrorHandler(resp.CmdName);
} }
else if (resp.IntValue == null && resp.DoubleValue == null) else if (resp.IntValue == null && resp.DoubleValue == null)
{ {
LogText(resp.AnswerStr); LogText(resp.AnswerStr);
@ -751,22 +774,14 @@ namespace Sensus.MiniPrf.Ui
tbxDutPulsesPerCm.Text = $@"{resp.IntValue:D}"; tbxDutPulsesPerCm.Text = $@"{resp.IntValue:D}";
break; break;
case CmdName.CMD_MEAS_SET_ATTN: case CmdName.CMD_MEAS_SET_ATTN:
var idx = cbxAttenuation.FindString($@"{resp.IntValue}"); var idx = cbxToleranceDisplayAttenuation.FindString($@"{resp.IntValue}");
cbxAttenuation.SelectedIndex = idx; cbxToleranceDisplayAttenuation.SelectedIndex = idx;
break; break;
case CmdName.CMD_GET_REF_FREQU: case CmdName.CMD_GET_REF_FREQU:
tbxRefFrequencyHz.Text = $@"{resp.IntValue:D}"; tbxRefFrequencyHz.Text = $@"{resp.IntValue:D}";
tbxRefFrequencyDirectHz.Text = $@"{resp.IntValue:D}"; tbxRefFrequencyDirectHz.Text = $@"{resp.IntValue:D}";
if (resp.IntValue < 1 || resp.IntValue > 254) tbxRefFrequencyHz.BackColor = statusColor;
{ tbxActualFlowRateCmPerHour.BackColor = statusColor;
tbxRefFrequencyHz.BackColor = ColorProcessFailed;
tbxActualFlowRateCmPerHour.BackColor = ColorProcessFailed;
}
else
{
tbxRefFrequencyHz.BackColor = ColorStandardDisplayField;
tbxActualFlowRateCmPerHour.BackColor = ColorStandardDisplayField;
}
break; break;
case CmdName.CMD_RST_MEAS: case CmdName.CMD_RST_MEAS:
// Immediately lock all buttons and input fields until reset is finished // Immediately lock all buttons and input fields until reset is finished
@ -786,16 +801,7 @@ namespace Sensus.MiniPrf.Ui
case CmdName.CMD_GET_UDTLC: case CmdName.CMD_GET_UDTLC:
case CmdName.CMD_GET_DTLC: case CmdName.CMD_GET_DTLC:
tbxActualMeasuredToleranceDutToRef.Text = $@"{resp.DoubleValue:F2}"; tbxActualMeasuredToleranceDutToRef.Text = $@"{resp.DoubleValue:F2}";
if (resp.DoubleValue < -Fm2014.Tolerance_percent || tbxActualMeasuredToleranceDutToRef.BackColor = statusColor;
resp.DoubleValue > Fm2014.Tolerance_percent)
{
tbxActualMeasuredToleranceDutToRef.BackColor = ColorProcessFailed;
}
else
{
tbxActualMeasuredToleranceDutToRef.BackColor = ColorStandardDisplayField;
}
break; break;
case CmdName.CMD_REF_SET_SCALE: case CmdName.CMD_REF_SET_SCALE:
tbxScaleRefToDut.Text = $@"{resp.DoubleValue:F4}"; tbxScaleRefToDut.Text = $@"{resp.DoubleValue:F4}";
@ -882,7 +888,6 @@ namespace Sensus.MiniPrf.Ui
UInt32 refPulses_per_cm = 1000; UInt32 refPulses_per_cm = 1000;
UInt16 dutPulses_per_cm = 100; UInt16 dutPulses_per_cm = 100;
UInt16 doublePulseDeadtime_ms = 0; UInt16 doublePulseDeadtime_ms = 0;
Byte currentOutputAttenuation = 1;
if (int.TryParse(tbxRefPulsesPerCm.Text, out var pulses_per_cm) && if (int.TryParse(tbxRefPulsesPerCm.Text, out var pulses_per_cm) &&
FM2014.PULSES_PER_CM_REGULATION_SETUP_MIN <= pulses_per_cm && FM2014.PULSES_PER_CM_REGULATION_SETUP_MIN <= pulses_per_cm &&
FM2014.REF_PULSES_PER_CM_REGULATION_INPUT_MAX >= pulses_per_cm) FM2014.REF_PULSES_PER_CM_REGULATION_INPUT_MAX >= pulses_per_cm)
@ -896,22 +901,8 @@ namespace Sensus.MiniPrf.Ui
dutPulses_per_cm = (UInt16)pulses_per_cm; dutPulses_per_cm = (UInt16)pulses_per_cm;
} }
//if (int.TryParse(tbxDoublePulseDeadtime.Text, out var deadtime_ms) &&
// FM2014.DOUBLE_PULSE_DEADTIME_MIN_ms <= deadtime_ms &&
// FM2014.DOUBLE_PULSE_DEADTIME_MAX_ms >= deadtime_ms)
//{
// doublePulseDeadtime_ms = (UInt16)deadtime_ms;
//}
if (byte.TryParse(cbxAttenuation.SelectedItem.ToString(), out var attenuation) &&
attenuation >= FM2014.CURRENT_OUTPUT_ATTENUATION_MIN &&
attenuation <= FM2014.CURRENT_OUTPUT_ATTENUATION_MAX)
{
currentOutputAttenuation = attenuation;
}
if (FM2014.RegulationMeasurement(refPulses_per_cm, dutPulses_per_cm, doublePulseDeadtime_ms, if (FM2014.RegulationMeasurement(refPulses_per_cm, dutPulses_per_cm, doublePulseDeadtime_ms,
currentOutputAttenuation)) _toleranceDisplayAttenuation))
{ {
_autoProgressBar = true; _autoProgressBar = true;
ActionControl(true); ActionControl(true);
@ -970,31 +961,6 @@ namespace Sensus.MiniPrf.Ui
})); }));
} }
/// <summary>
/// Attenuation item has changed.
/// </summary>
/// <remarks date="2023-Jan-18" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void cbxAttenuation_SelectedIndexChanged(Object sender, EventArgs e)
{
Invoke(new Action(() =>
{
if (Fm2014 != null)
{
if (byte.TryParse(cbxAttenuation.SelectedItem.ToString(), out var attenuation) &&
attenuation >= FM2014.CURRENT_OUTPUT_ATTENUATION_MIN &&
attenuation <= FM2014.CURRENT_OUTPUT_ATTENUATION_MAX &&
Fm2014.CurrentOutputAttenuation != attenuation)
{
_regulationSetupHasChanged = true;
btnSaveRegulationSetup.Enabled = true;
}
}
}));
}
/// <summary> /// <summary>
/// Selected COM port, tolerance display settings or address item has changed. /// Selected COM port, tolerance display settings or address item has changed.
/// These values can be setup before any connection to the FM2014 has been established. Therefore, those /// These values can be setup before any connection to the FM2014 has been established. Therefore, those
@ -1007,14 +973,14 @@ namespace Sensus.MiniPrf.Ui
{ {
Invoke(new Action(() => Invoke(new Action(() =>
{ {
if (_toleranceIdx != cbxFM2014TolerancePercent.SelectedIndex || if (_currentOutputDisplayRange_percent != cbxToleranceDisplayRange.SelectedIndex ||
_addressIdx != cbxFM2014Address.SelectedIndex || _addressIdx != cbxFM2014Address.SelectedIndex ||
_comPortIdx != cbxFM2014ComPort.SelectedIndex) _comPortIdx != cbxProgramComPort.SelectedIndex)
{ {
_toleranceIdx = cbxFM2014TolerancePercent.SelectedIndex; _currentOutputDisplayRange_percent = cbxToleranceDisplayRange.SelectedIndex;
_addressIdx = cbxFM2014Address.SelectedIndex; _addressIdx = cbxFM2014Address.SelectedIndex;
_comPortIdx = cbxFM2014ComPort.SelectedIndex; _comPortIdx = cbxProgramComPort.SelectedIndex;
StoreFM2014Settings(); StoreProgramConfiguration();
} }
})); }));
} }
@ -1031,8 +997,8 @@ namespace Sensus.MiniPrf.Ui
{ {
if (Fm2014 != null && FM2014.StoreAllConfigurations()) if (Fm2014 != null && FM2014.StoreAllConfigurations())
{ {
_regulationSetupHasChanged = false; _fm2014RegulationSetupHasChanged = false;
btnSaveRegulationSetup.Enabled = false; btnSaveSetupToFm2014.Enabled = false;
} }
} }
@ -1126,7 +1092,7 @@ namespace Sensus.MiniPrf.Ui
if (string.IsNullOrEmpty(tbxRefPulsesPerCm.Text)) if (string.IsNullOrEmpty(tbxRefPulsesPerCm.Text))
{ {
tbxRefPulsesPerCm.BackColor = ColorProcessFailed; tbxRefPulsesPerCm.BackColor = ColorProcessFailed;
btnSaveRegulationSetup.Enabled = false; btnSaveSetupToFm2014.Enabled = false;
btnDutToRefRegulation.Enabled = false; btnDutToRefRegulation.Enabled = false;
return; return;
} }
@ -1215,7 +1181,7 @@ namespace Sensus.MiniPrf.Ui
if (string.IsNullOrEmpty(tbxDutPulsesPerCm.Text)) if (string.IsNullOrEmpty(tbxDutPulsesPerCm.Text))
{ {
tbxDutPulsesPerCm.BackColor = ColorProcessFailed; tbxDutPulsesPerCm.BackColor = ColorProcessFailed;
btnSaveRegulationSetup.Enabled = false; btnSaveSetupToFm2014.Enabled = false;
btnDutToRefRegulation.Enabled = false; btnDutToRefRegulation.Enabled = false;
return; return;
} }
@ -1375,12 +1341,37 @@ namespace Sensus.MiniPrf.Ui
})); }));
} }
/// <summary>
/// FM2014 current attenuation item has changed:
/// - This will dispatch the new value to all FM2014s.
/// </summary>
/// <remarks date="2026-Jan-18" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void cbxToleranceDisplayAttenuation_SelectedIndexChanged(Object sender, EventArgs e)
{
Invoke(new Action(() =>
{
if (byte.TryParse(cbxToleranceDisplayAttenuation.SelectedItem.ToString(), out var attenuation) &&
attenuation >= FM2014.CURRENT_OUTPUT_ATTENUATION_MIN &&
attenuation <= FM2014.CURRENT_OUTPUT_ATTENUATION_MAX &&
_toleranceDisplayAttenuation != attenuation)
{
_fm2014RegulationSetupHasChanged = true;
_toleranceDisplayAttenuation = attenuation;
Fm2014.CurrentOutputAttenuation = attenuation;
btnSaveSetupToFm2014.Enabled = true;
}
}));
}
/// <summary> /// <summary>
/// Select next control on enter key pressed /// Select next control on enter key pressed
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
private void cbxAttenuation_KeyDown(Object sender, KeyEventArgs e) private void cbxToleranceDisplayAttenuation_KeyDown(Object sender, KeyEventArgs e)
{ {
if (e.KeyCode == Keys.Enter) if (e.KeyCode == Keys.Enter)
{ {