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

This commit is contained in:
Thomas Wiedebusch 2026-02-10 09:12:07 +01:00
parent b8c54f1c61
commit fa7128cd03
5 changed files with 257 additions and 282 deletions

View File

@ -102,19 +102,6 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Config
if (!File.Exists(configFile))
return false;
//{
// //// Take actual working directory
// //configFile = Path.Combine(ProgramConfig.FM2014ConfigFileName);
// //if (!File.Exists(configFile))
// //{
// // SerialPort = null;
// // Address = null;
// // TolerancePercent = null;
// // SlotIsSelected = null;
// // IndividualTolerancePercent = null;
// return false;
// //}
//}
using (var tr = new StreamReader(configFile))
{

View File

@ -293,12 +293,12 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// <summary>
/// REF pulse counter is switched active
/// </summary>
private Boolean RefPulseCtrOn { set; get; }
public Boolean RefPulseCtrOn { set; get; }
/// <summary>
/// DUT pulse counter is switched active
/// </summary>
private Boolean DutPulseCtrOn { set; get; }
public Boolean DutPulseCtrOn { set; get; }
/// <summary>
/// Serial number of the FM2014
@ -590,13 +590,12 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
get => _doublePulseDeadtime_ms;
set
{
if (value < DOUBLE_PULSE_DEADTIME_MIN_ms ||
value > DOUBLE_PULSE_DEADTIME_MAX_ms)
if (value > DOUBLE_PULSE_DEADTIME_MAX_ms)
return;
_doublePulseDeadtime_ms = value;
// Calculate and set up the values 'S' and 's' needed for the FM2014
var tempBase_ms = (UInt16)value;
var tempBase_ms = value;
var tempMultiplier = 1;
while (tempBase_ms > DOUBLE_PULSE_BASE_DEADTIME_MAX_ms &&
tempMultiplier < DOUBLE_PULSE_DEADTIME_MULTIPLIER_INPUT_MAX)
@ -844,9 +843,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// Exit:
/// - Set <see cref="SharedCyclicMeasSequ"/> to false.
/// </summary>
/// <param name="refCtrOn">request to count REF pulses</param>
/// <param name="dutCtrOn">request to count DUT pulses</param>
/// <returns>true if initialization successfully executed or
/// <returns>true if initialization successfully executed or
/// <see cref="SharedCyclicMeasSequ"/> marks the already started cyclic requests
/// for all registered FM2014s</returns>
/// <remarks date="2026-Jan-10..14" author="Thomas Wiedebusch">
@ -868,7 +865,7 @@ namespace Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch">
/// - Static.
/// </remarks>
public static Boolean PulseCounterMeasurement(Boolean refCtrOn = true, Boolean dutCtrOn = false)
public static Boolean PulseCounterMeasurement()
{
// If the cyclic task has already been started everything is fine
if (SharedCyclicMeasSequ == CyclicMeasSequ.PULSE_CTR)

View File

@ -50,8 +50,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Metrology", "Metrology", "{
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Measurements", "..\Common\Metrology\Measurements\Measurements.csproj", "{6CCDB656-C676-4360-BABA-C4596AAD175D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fm2014TestApp", "Ui\FM2014TestBenchWinFrms\Fm2014TestApp.csproj", "{09CBCD8A-C729-4AB6-9C39-1510774509D6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fm2014TestBench", "Ui\Fm2014sTest\Fm2014TestBench.csproj", "{ED34FACA-492B-44FD-B56C-A2BD83F33D8B}"
EndProject
Global
@ -88,10 +86,6 @@ Global
{6CCDB656-C676-4360-BABA-C4596AAD175D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6CCDB656-C676-4360-BABA-C4596AAD175D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6CCDB656-C676-4360-BABA-C4596AAD175D}.Release|Any CPU.Build.0 = Release|Any CPU
{09CBCD8A-C729-4AB6-9C39-1510774509D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{09CBCD8A-C729-4AB6-9C39-1510774509D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09CBCD8A-C729-4AB6-9C39-1510774509D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09CBCD8A-C729-4AB6-9C39-1510774509D6}.Release|Any CPU.Build.0 = Release|Any CPU
{ED34FACA-492B-44FD-B56C-A2BD83F33D8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ED34FACA-492B-44FD-B56C-A2BD83F33D8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ED34FACA-492B-44FD-B56C-A2BD83F33D8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -117,7 +111,7 @@ Global
{2E139F63-B6FE-4EA9-A098-85364FE9B26C} = {83A52B6E-DB81-4B43-B5C1-F9B637D135BE}
{2FD60CF1-45CD-4060-B8E5-4F39FBA7F1CB} = {DBC8FF8D-D0A2-4C55-B7D5-F7D17CCEE01F}
{6CCDB656-C676-4360-BABA-C4596AAD175D} = {6695522E-E681-434C-8006-5A92AABB9807}
{09CBCD8A-C729-4AB6-9C39-1510774509D6} = {BDA40851-F353-416A-A6A8-6BA33ACB7371}
{ED34FACA-492B-44FD-B56C-A2BD83F33D8B} = {BDA40851-F353-416A-A6A8-6BA33ACB7371}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B72A8444-29F9-4FA4-82BE-B6E230750911}

View File

@ -392,7 +392,6 @@
<TextBox x:Name="tbxDutToRefTolMax" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="4" Grid.Column="23" Grid.ColumnSpan="2" Text="1.1" MaxLines="1" HorizontalContentAlignment="Right" TabIndex="114" KeyDown="tbxDutToRefToleranceMax_KeyDown" LostFocus="tbxDutToRefToleranceMax_LostFocus" TextChanged="tbxDutToRefToleranceMax_TextChanged"/>
<TextBox x:Name="tbxDutToRefTolMin" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="5" Grid.Column="23" Grid.ColumnSpan="2" Text="-0.5" MaxLines="1" HorizontalContentAlignment="Right" TabIndex="115" KeyDown="tbxDutToRefToleranceMin_KeyDown" LostFocus="tbxDutToRefToleranceMin_LostFocus" TextChanged="tbxDutToRefToleranceMin_TextChanged"/>
<Button x:Name="btnDutToRefCalibration" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="4" Content="Start Calibration" TabIndex="110" Click="btnDutToRefCalibration_Click" />
<!--Button x:Name="btnTakeCalibrationSetup" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="6" Grid.Column="21" Grid.ColumnSpan="4" Content="Take It" TabIndex="116" Click="btnTakeCalibrationSettings_Click" /-->
</Grid>
</TabItem>
@ -442,8 +441,8 @@
<Label x:Name="lblRefPulsesPerCmScale" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="4" Grid.Column="17" Grid.ColumnSpan="6" Content="REF Pulse Ratio [pulses/m³]:" />
<TextBox x:Name="tbxRefPulsesMeasured" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="1" Grid.Column="23" Grid.ColumnSpan="2" Text="500" MaxLines="1" HorizontalContentAlignment="Right" />
<TextBox x:Name="tbxDutPulsesMeasured" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="2" Grid.Column="23" Grid.ColumnSpan="2" Text="50" MaxLines="1" HorizontalContentAlignment="Right" />
<TextBox x:Name="tbxVolumeMeasuredLiters" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="3" Grid.Column="23" Grid.ColumnSpan="2" Text="500" MaxLines="1" HorizontalContentAlignment="Right" TabIndex="122" KeyDown="tbxVolumeMeasuredLiters_KeyDown" LostFocus="tbxVolumeMeasuredLiters_LostFocus" TextChanged="tbxVolumeMeasuredLiters_LostFocus"/>
<TextBox x:Name="tbxRefPulsesPerCmScale" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="4" Grid.Column="23" Grid.ColumnSpan="2" Text="1000" MaxLines="1" HorizontalContentAlignment="Right" />
<TextBox x:Name="tbxVolumeMeasuredLiters" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="3" Grid.Column="23" Grid.ColumnSpan="2" Text="500" MaxLines="1" HorizontalContentAlignment="Right" TabIndex="122" KeyDown="tbxVolumeMeasuredLiters_KeyDown" LostFocus="tbxVolumeMeasuredLiters_LostFocus" TextChanged="tbxVolumeMeasuredLiters_TextChanged"/>
<TextBox x:Name="tbxRefPulsesPerCmCalib" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="4" Grid.Column="23" Grid.ColumnSpan="2" Text="1000" MaxLines="1" HorizontalContentAlignment="Right" />
<Button x:Name="btnRefToVolumeCalibration" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1,1,1,1" Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="4" Content="Start Calibration" TabIndex="120" Click="btnRefToVolumeCalibration_Click" />
</Grid>
</TabItem>

View File

@ -504,8 +504,6 @@ namespace Sensus.Ui.FM2014TestBench
{
fm2014.Tolerance_percent = _fm2014Config?.IndividualTolerancePercent[ctr] ??
FM2014.STANDARD_NOMINAL_TOLERANCE_INPUT_percent;
// Display on regulation page as common setup for ALL
cbxToleranceCalc.SelectedItem = fm2014.Tolerance_percent.ToString();
}
}
if (_fm2014Config != null)
@ -519,6 +517,9 @@ namespace Sensus.Ui.FM2014TestBench
tbxDoublePulseDeadtime.Text = $"{_fm2014Config.DoublePulseDeadtime:D}";
tbxDutToRefTolMax.Text = $"{_fm2014Config.DutToRefToleranceMax:F2}";
tbxDutToRefTolMin.Text = $"{_fm2014Config.DutToRefToleranceMin:F2}";
// Display on regulation page as common setup for ALL
cbxToleranceCalc.SelectedItem = _fm2014Config.TolerancePercent?.ToString();
}
// Disable and hide dynamic measurement labels
@ -595,8 +596,8 @@ namespace Sensus.Ui.FM2014TestBench
lblVolumeMeasuredLiters.Content = Properties.Resources.StrLblVolumeMeasured;
tbxVolumeMeasuredLiters.Text = "";
lblRefPulsesPerCmScale.Content = Properties.Resources.StrLblRefPulsesPerCmRatio;
tbxRefPulsesPerCmScale.Text = "";
tbxRefPulsesPerCmScale.IsReadOnly = true;
tbxRefPulsesPerCmCalib.Text = "";
tbxRefPulsesPerCmCalib.IsReadOnly = true;
btnRefToVolumeCalibration.Content = Properties.Resources.StrBtnStartCalibration;
//// Process status
@ -620,6 +621,9 @@ namespace Sensus.Ui.FM2014TestBench
/// <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)
@ -648,12 +652,15 @@ namespace Sensus.Ui.FM2014TestBench
}
// Restore Calibration settings for user convenience
tbxRefPulsesRequired.Text = $"{_fm2014Config.RefPulsesRequired:D}";
tbxDutPulsesRequired.Text = $"{_fm2014Config.DutPulsesRequired:D}";
tbxDoublePulseDeadtime.Text = $"{_fm2014Config.DoublePulseDeadtime:D}";
tbxDutToRefTolMax.Text = $"{_fm2014Config.DutToRefToleranceMax:F2}";
tbxDutToRefTolMin.Text = $"{_fm2014Config.DutToRefToleranceMin:F2}";
var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014();
if (null == firstFm2014)
return;
_fm2014Config.RefPulsesRequired = firstFm2014.RefPulsesRequired;
_fm2014Config.DutPulsesRequired = firstFm2014.DutPulsesRequired;
_fm2014Config.DoublePulseDeadtime = firstFm2014.DoublePulseDeadtime_ms;
_fm2014Config.DutToRefToleranceMax = firstFm2014.DutToRefCalibrationToleranceMax_percent;
_fm2014Config.DutToRefToleranceMin = firstFm2014.DutToRefCalibrationToleranceMin_percent;
});
_fm2014Config.Update();
@ -818,7 +825,7 @@ namespace Sensus.Ui.FM2014TestBench
tbxScaleRefToDut.Background = ColorStandardDisplayField;
tbxVolumeMeasuredLiters.Background = ColorStandardInputField;
tbxRefPulsesPerCmScale.Background = ColorStandardDisplayField;
tbxRefPulsesPerCmCalib.Background = ColorStandardDisplayField;
});
}
@ -993,7 +1000,7 @@ namespace Sensus.Ui.FM2014TestBench
UiElmEnable(chkDutPulsesMeasured, false);
UiElmEnable(tbxDutPulsesMeasured, false); // Additional scale is permanent read only
UiElmEnable(tbxVolumeMeasuredLiters, false);
UiElmEnable(tbxRefPulsesPerCmScale, false); // Additional scale is permanent read only
UiElmEnable(tbxRefPulsesPerCmCalib, false); // Additional scale is permanent read only
foreach (var slotSelector in SlotSelections)
{
UiElmEnable(slotSelector, false);
@ -1041,7 +1048,7 @@ namespace Sensus.Ui.FM2014TestBench
UiElmEnable(chkDutPulsesMeasured, true);
UiElmEnable(tbxDutPulsesMeasured, true); // Additional scale is permanent read only
UiElmEnable(tbxVolumeMeasuredLiters, true);
UiElmEnable(tbxRefPulsesPerCmScale, true); // Additional scale is permanent read only
UiElmEnable(tbxRefPulsesPerCmCalib, true); // Additional scale is permanent read only
foreach (var slotSelector in SlotSelections)
{
@ -1257,6 +1264,10 @@ namespace Sensus.Ui.FM2014TestBench
tbxDutToRefToleranceMax_LostFocus(this, null);
tbxDutToRefToleranceMin_LostFocus(this, null);
// Backup if meanwhile anything has changed
if (_configSetupHasChanged || _calibrationSetupHasChanged)
StoreFM2014SettingsToConfigFile();
// Set the measurement labels
UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_REF_REQ_PLS], Properties.Resources.StrLblRefPulsesRequired);
UpdateContentControl(MeasurementLabels[CAL_LBL_IDX_REF_RMN_PLS], Properties.Resources.StrLblRefPulsesRemaining);
@ -1330,7 +1341,6 @@ namespace Sensus.Ui.FM2014TestBench
cbxAttenuation_SelectedIndexChanged(this, null);
cbxToleranceCalc_SelectedIndexChanged(this, null);
// Set the measurement labels
UpdateContentControl(MeasurementLabels[CMN_LBL_IDX_REF_FREQU], Properties.Resources.StrLblRefFrequencyHz);
UpdateContentControl(MeasurementLabels[CMN_LBL_IDX_FLOW_RATE], Properties.Resources.StrLblFlowRateMeasured);
@ -1401,22 +1411,24 @@ namespace Sensus.Ui.FM2014TestBench
UpdateTextBox(tbxRefPulsesMeasured, "");
UpdateTextBox(tbxDutPulsesMeasured, "");
UpdateTextBox(tbxVolumeMeasuredLiters, "");
UpdateTextBox(tbxRefPulsesPerCmScale, "");
UpdateTextBox(tbxRefPulsesPerCmCalib, "");
if (FM2014.RegisteredFm2014s == null || FM2014.RegisteredFm2014s.Count == 0)
return;
var measureDutPulses = false;
Dispatcher.Invoke(() => measureDutPulses = chkDutPulsesMeasured.IsChecked ?? false);
// Adjust the user control
foreach (var fm2014 in FM2014.RegisteredFm2014s.Where(x => x.IsLoggedOn))
{
var idx = fm2014.Address - 1;
var ucFM2014 = (UcFM2014Device)UcFM2014s[idx];
ucFM2014.EnableMeasurements(CTR_MEASURE_COUNT);
fm2014.RefPulseCtrOn = true;
fm2014.DutPulseCtrOn = measureDutPulses;
}
var measureDutPulses = false;
Dispatcher.Invoke(() => measureDutPulses = chkDutPulsesMeasured.IsChecked ?? false);
if (FM2014.PulseCounterMeasurement(true, measureDutPulses))
if (FM2014.PulseCounterMeasurement())
{
_autoProgressBar = true;
UpdateContentControl(btnRefToVolumeCalibration, Properties.Resources.StrBtnStopCalibration);
@ -1704,7 +1716,6 @@ namespace Sensus.Ui.FM2014TestBench
if (string.IsNullOrEmpty(tbxRefPulsesRequired.Text))
{
tbxRefPulsesRequired.Background = ColorStandardInputField;
btnDutToRefCalibration.IsEnabled = false;
return;
}
// Check for change
@ -1716,16 +1727,14 @@ namespace Sensus.Ui.FM2014TestBench
FM2014.TIME_MEASUREMENT_INPUT_MAX_pulses >= pulses)
{
if (backupPulsesRequired != pulses)
{
_calibrationSetupHasChanged = true;
tbxRefPulsesRequired.Background = ColorStandardInputField;
firstFm2014.RefPulsesRequired = (UInt16)pulses;
// Dispatch settings to all connected FM2014!!!!
foreach (var fm2014 in FM2014.RegisteredFm2014s)
{
fm2014.RefPulsesRequired = firstFm2014.RefPulsesRequired;
}
tbxRefPulsesRequired.Background = ColorStandardInputField;
// Dispatch settings to all connected FM2014!!!!
foreach (var fm2014 in FM2014.RegisteredFm2014s)
{
fm2014.RefPulsesRequired = (UInt16)pulses;
}
}
else
@ -1807,7 +1816,6 @@ namespace Sensus.Ui.FM2014TestBench
if (string.IsNullOrEmpty(tbxDutPulsesRequired.Text))
{
tbxDutPulsesRequired.Background = ColorProcessFailed;
btnDutToRefCalibration.IsEnabled = false;
return;
}
@ -1820,16 +1828,14 @@ namespace Sensus.Ui.FM2014TestBench
FM2014.TIME_MEASUREMENT_INPUT_MAX_pulses >= pulses)
{
if (backupPulsesRequired != pulses)
{
_calibrationSetupHasChanged = true;
tbxDutPulsesRequired.Background = ColorStandardInputField;
firstFm2014.DutPulsesRequired = (UInt16)pulses;
// Dispatch settings to all connected FM2014!!!!
foreach (var fm2014 in FM2014.RegisteredFm2014s)
{
fm2014.DutPulsesRequired = firstFm2014.DutPulsesRequired;
}
tbxDutPulsesRequired.Background = ColorStandardInputField;
// Dispatch settings to all connected FM2014!!!!
foreach (var fm2014 in FM2014.RegisteredFm2014s)
{
fm2014.DutPulsesRequired = (UInt16)pulses;
}
}
else
@ -1902,7 +1908,6 @@ namespace Sensus.Ui.FM2014TestBench
if (string.IsNullOrEmpty(tbxDoublePulseDeadtime.Text))
{
tbxDoublePulseDeadtime.Background = ColorProcessFailed;
btnDutToRefCalibration.IsEnabled = false;
return;
}
@ -1915,16 +1920,14 @@ namespace Sensus.Ui.FM2014TestBench
FM2014.DOUBLE_PULSE_DEADTIME_MAX_ms >= deadtime)
{
if (backupDoublePulseDeadtime != deadtime)
{
_calibrationSetupHasChanged = true;
tbxDoublePulseDeadtime.Background = ColorStandardInputField;
firstFm2014.DoublePulseDeadtime_ms = (UInt16)deadtime;
// Dispatch settings to all connected FM2014!!!!
foreach (var fm2014 in FM2014.RegisteredFm2014s)
{
fm2014.DoublePulseDeadtime_ms = firstFm2014.DoublePulseDeadtime_ms;
}
tbxDoublePulseDeadtime.Background = ColorStandardInputField;
// Dispatch settings to all connected FM2014!!!!
foreach (var fm2014 in FM2014.RegisteredFm2014s)
{
fm2014.DoublePulseDeadtime_ms = (UInt16)deadtime;
}
}
else
@ -1934,6 +1937,193 @@ namespace Sensus.Ui.FM2014TestBench
});
}
/// <summary>
/// Redirect keystroke 'Enter' to leaving the cell event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxDutToRefToleranceMax_KeyDown(Object sender, KeyEventArgs e)
{
// Catch the enter key and tab key as indicator for leaving the cell
if (e.Key == Key.Enter || e.Key == Key.Tab)
{
tbxDutToRefToleranceMax_LostFocus(this, null);
Keyboard.Focus(tbxDutToRefTolMin);
TextBoxSelectAll(tbxDutToRefTolMin);
}
else if (!MaskEditDoubleInput(e.Key))
{
e.Handled = true;
}
}
/// <summary>
/// Changed test to cover the delete key which is not in the key-down event!?
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-06" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxDutToRefToleranceMax_TextChanged(Object sender, TextChangedEventArgs e)
{
// Take the new input and calculate the results after the input has been taken after this event!
Task.Factory.StartNew(() =>
{
Thread.Sleep(1);
}, _cancellationToken).ContinueWith(delegate
{
Dispatcher.Invoke(() => tbxDutToRefToleranceMax_LostFocus(this, null));
}, _cancellationToken);
}
/// <summary>
/// After manual input of measured weight scale or reservoir in liters this will calculate the
/// REF pulses per cubic meter and copy from REF pulses per cubic meter in 'Manual REF Calibration'
/// to 'Regulation Setup':
/// - This will dispatch the new value to all FM2014s.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxDutToRefToleranceMax_LostFocus(Object sender, EventArgs e)
{
var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014();
if (null == firstFm2014)
return;
Dispatcher.Invoke(() =>
{
if (string.IsNullOrEmpty(tbxDutToRefTolMax.Text))
{
tbxDutToRefTolMax.Background = ColorProcessFailed;
return;
}
// Check for change
var backupDutToRefTolerance = firstFm2014.DutToRefCalibrationToleranceMax_percent;
var englishNumberFormat = tbxDutToRefTolMax.Text.Replace(',', '.');
if (double.TryParse(englishNumberFormat, NumberStyles.Any, new CultureInfo("en"), out var tolerance))
{
if (Math.Abs(backupDutToRefTolerance - tolerance) > 0.05)
_calibrationSetupHasChanged = true;
tbxDutToRefTolMax.Background = ColorStandardInputField;
// Dispatch settings to all connected FM2014!!!!
foreach (var fm2014 in FM2014.RegisteredFm2014s)
{
fm2014.DutToRefCalibrationToleranceMax_percent = tolerance;
}
}
else
{
tbxDutToRefTolMax.Background = ColorProcessFailed;
}
});
}
/// <summary>
/// Redirect keystroke 'Enter' to leaving the cell event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxDutToRefToleranceMin_KeyDown(Object sender, KeyEventArgs e)
{
// Catch the enter key, recalculate all settings
if (e.Key == Key.Enter || e.Key == Key.Tab)
{
tbxDutToRefToleranceMin_LostFocus(this, null);
Keyboard.Focus(btnDutToRefCalibration);
}
else if (!MaskEditDoubleInput(e.Key))
{
e.Handled = true;
}
}
/// <summary>
/// Changed test to cover the delete key which is not in the key-down event!?
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-06" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxDutToRefToleranceMin_TextChanged(Object sender, TextChangedEventArgs e)
{
// Take the new input and calculate the results after the input has been taken after this event!
Task.Factory.StartNew(() =>
{
Thread.Sleep(1);
}, _cancellationToken).ContinueWith(delegate
{
Dispatcher.Invoke(() => tbxDutToRefToleranceMin_LostFocus(this, null));
}, _cancellationToken);
}
/// <summary>
/// After manual input of measured weight scale or reservoir in liters this will calculate the
/// REF pulses per cubic meter and copy from REF pulses per cubic meter in 'Manual REF Calibration'
/// to 'Regulation Setup':
/// - This will dispatch the new value to all FM2014s.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxDutToRefToleranceMin_LostFocus(Object sender, EventArgs e)
{
var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014();
if (null == firstFm2014)
return;
Dispatcher.Invoke(() =>
{
if (string.IsNullOrEmpty(tbxDutToRefTolMin.Text))
{
tbxDutToRefTolMin.Background = ColorProcessFailed;
return;
}
// Check for change
var backupDutToRefTolerance = firstFm2014.DutToRefCalibrationToleranceMin_percent;
var englishNumberFormat = tbxDutToRefTolMin.Text.Replace(',', '.');
if (double.TryParse(englishNumberFormat, NumberStyles.Any, new CultureInfo("en"), out var tolerance))
{
if (Math.Abs(backupDutToRefTolerance - tolerance) > 0.05)
_calibrationSetupHasChanged = true;
tbxDutToRefTolMin.Background = ColorStandardInputField;
// Dispatch settings to all connected FM2014!!!!
foreach (var fm2014 in FM2014.RegisteredFm2014s)
{
fm2014.DutToRefCalibrationToleranceMin_percent = tolerance;
}
}
else
{
tbxDutToRefTolMin.Background = ColorProcessFailed;
}
});
}
/// <summary>
/// Redirect keystroke 'Enter' to leaving the cell event
/// </summary>
@ -2012,15 +2202,10 @@ namespace Sensus.Ui.FM2014TestBench
FM2014.PULSES_PER_CM_REGULATION_SETUP_MIN <= pulses_per_cm &&
FM2014.REF_PULSES_PER_CM_REGULATION_INPUT_MAX >= pulses_per_cm)
{
// The value is much larger than possible to be stored to the FM2014, but if it is too large
// it will be marked as invalid and on readback restored using the DUT pulses per cubic-meter
// multiplied by the
firstFm2014.Ref_pulse_per_cm = (UInt32)pulses_per_cm;
// Dispatch settings to all connected FM2014!!!!
foreach (var fm2014 in FM2014.RegisteredFm2014s)
{
fm2014.Ref_pulse_per_cm = firstFm2014.Ref_pulse_per_cm;
fm2014.Ref_pulse_per_cm = (UInt32)pulses_per_cm;
}
// During setup of the 'Ref_pulse_per_cm' the 'RefToDutScaleStr' will be generated
if (!UpdateRefToDutScale())
@ -2119,13 +2304,10 @@ namespace Sensus.Ui.FM2014TestBench
FM2014.PULSES_PER_CM_REGULATION_SETUP_MIN <= pulses_per_cm &&
FM2014.PULSES_PER_CM_REGULATION_SETUP_MAX >= pulses_per_cm)
{
// Try to set the new calculated REF pulses limited by the property setter
firstFm2014.Dut_pulse_per_cm = (UInt16)pulses_per_cm;
// Dispatch settings to all connected FM2014!!!!
foreach (var fm2014 in FM2014.RegisteredFm2014s)
{
fm2014.Dut_pulse_per_cm = firstFm2014.Dut_pulse_per_cm;
fm2014.Dut_pulse_per_cm = (UInt16)pulses_per_cm;
}
// During setup of the 'Dut_pulse_per_cm' the 'RefToDutScaleStr' will be generated
if (!UpdateRefToDutScale())
@ -2198,7 +2380,7 @@ namespace Sensus.Ui.FM2014TestBench
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch">
/// <remarks date="2026-Feb-09..10" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxVolumeMeasuredLiters_LostFocus(Object sender, EventArgs e)
@ -2225,23 +2407,31 @@ namespace Sensus.Ui.FM2014TestBench
if (int.TryParse(tbxRefPulsesMeasured.Text, out var pulses) && pulses > 0 &&
int.TryParse(tbxVolumeMeasuredLiters.Text, out var liters) && liters > 0)
{
// Calculate the new pulse ratio based on the manual calibration
var pulses_per_cm = (UInt32)(pulses / (liters / 1000.0) + 0.5);
// Try to set the new calculated REF pulses limited by the property setter
firstFm2014.Ref_pulse_per_cm = pulses_per_cm;
// Dispatch settings to all connected FM2014!!!!
foreach (var fm2014 in FM2014.RegisteredFm2014s)
{
fm2014.Ref_pulse_per_cm = pulses_per_cm;
}
// If this succeeded, then update the new manual calibrated value
if (pulses_per_cm == firstFm2014.Ref_pulse_per_cm)
{
tbxRefPulsesPerCm.Text = $@"{firstFm2014.Ref_pulse_per_cm:D}";
tbxVolumeMeasuredLiters.Background = ColorStandardInputField;
tbxRefPulsesPerCm.Background = ColorStandardDisplayField;
tbxRefPulsesPerCmCalib.Text = $@"{firstFm2014.Ref_pulse_per_cm:D}";
tbxRefPulsesPerCmCalib.Background = ColorStandardDisplayField;
tbxVolumeMeasuredLiters.Background = ColorStandardInputField;
if (!UpdateRefToDutScale())
{
tbxVolumeMeasuredLiters.Background = ColorProcessFailed;
tbxRefPulsesPerCmCalib.Background = ColorProcessFailed;
return;
}
@ -2254,205 +2444,13 @@ namespace Sensus.Ui.FM2014TestBench
else
{
tbxVolumeMeasuredLiters.Background = ColorProcessFailed;
tbxRefPulsesPerCm.Background = ColorProcessFailed;
tbxRefPulsesPerCmCalib.Background = ColorProcessFailed;
tbxRefPulsesPerCm.Text = Properties.Resources.StrError;
}
}
});
}
/// <summary>
/// Redirect keystroke 'Enter' to leaving the cell event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxDutToRefToleranceMax_KeyDown(Object sender, KeyEventArgs e)
{
// Catch the enter key and tab key as indicator for leaving the cell
if (e.Key == Key.Enter || e.Key == Key.Tab)
{
tbxDutToRefToleranceMax_LostFocus(this, null);
Keyboard.Focus(tbxDutToRefTolMin);
TextBoxSelectAll(tbxDutToRefTolMin);
}
else if (!MaskEditDoubleInput(e.Key))
{
e.Handled = true;
}
}
/// <summary>
/// Changed test to cover the delete key which is not in the key-down event!?
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-06" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxDutToRefToleranceMax_TextChanged(Object sender, TextChangedEventArgs e)
{
// Take the new input and calculate the results after the input has been taken after this event!
Task.Factory.StartNew(() =>
{
Thread.Sleep(1);
}, _cancellationToken).ContinueWith(delegate
{
Dispatcher.Invoke(() => tbxDutToRefToleranceMax_LostFocus(this, null));
}, _cancellationToken);
}
/// <summary>
/// After manual input of measured weight scale or reservoir in liters this will calculate the
/// REF pulses per cubic meter and copy from REF pulses per cubic meter in 'Manual REF Calibration'
/// to 'Regulation Setup':
/// - This will dispatch the new value to all FM2014s.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxDutToRefToleranceMax_LostFocus(Object sender, EventArgs e)
{
var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014();
if (null == firstFm2014)
return;
Dispatcher.Invoke(() =>
{
if (string.IsNullOrEmpty(tbxDutToRefTolMax.Text))
{
tbxDutToRefTolMax.Background = ColorProcessFailed;
return;
}
// Check for change
var backupDutToRefTolerance = firstFm2014.DutToRefCalibrationToleranceMax_percent;
if (double.TryParse(tbxDutToRefTolMax.Text, NumberStyles.Any, new CultureInfo("de"), out var tolerance) ||
double.TryParse(tbxDutToRefTolMax.Text, NumberStyles.Any, new CultureInfo("en"), out tolerance))
{
if (Math.Abs(backupDutToRefTolerance - tolerance) > 0.05)
{
_calibrationSetupHasChanged = true;
// Try to set the new calculated REF pulses limited by the property setter
firstFm2014.DutToRefCalibrationToleranceMax_percent = tolerance;
tbxDutToRefTolMax.Background = ColorStandardInputField;
// Dispatch settings to all connected FM2014!!!!
foreach (var fm2014 in FM2014.RegisteredFm2014s)
{
fm2014.DutToRefCalibrationToleranceMax_percent = tolerance;
}
}
}
else
{
tbxDutToRefTolMax.Background = ColorProcessFailed;
}
});
}
/// <summary>
/// Redirect keystroke 'Enter' to leaving the cell event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxDutToRefToleranceMin_KeyDown(Object sender, KeyEventArgs e)
{
// Catch the enter key, recalculate all settings
if (e.Key == Key.Enter || e.Key == Key.Tab)
{
tbxDutToRefToleranceMin_LostFocus(this, null);
Keyboard.Focus(btnDutToRefCalibration);
}
else if (!MaskEditDoubleInput(e.Key))
{
e.Handled = true;
}
}
/// <summary>
/// Changed test to cover the delete key which is not in the key-down event!?
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-06" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxDutToRefToleranceMin_TextChanged(Object sender, TextChangedEventArgs e)
{
// Take the new input and calculate the results after the input has been taken after this event!
Task.Factory.StartNew(() =>
{
Thread.Sleep(1);
}, _cancellationToken).ContinueWith(delegate
{
Dispatcher.Invoke(() => tbxDutToRefToleranceMin_LostFocus(this, null));
}, _cancellationToken);
}
/// <summary>
/// After manual input of measured weight scale or reservoir in liters this will calculate the
/// REF pulses per cubic meter and copy from REF pulses per cubic meter in 'Manual REF Calibration'
/// to 'Regulation Setup':
/// - This will dispatch the new value to all FM2014s.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2026-Feb-09" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxDutToRefToleranceMin_LostFocus(Object sender, EventArgs e)
{
var firstFm2014 = FM2014.GetFirstConnectedAndLoggedInFm2014();
if (null == firstFm2014)
return;
Dispatcher.Invoke(() =>
{
if (string.IsNullOrEmpty(tbxDutToRefTolMin.Text))
{
tbxDutToRefTolMin.Background = ColorProcessFailed;
return;
}
// Check for change
var backupDutToRefTolerance = firstFm2014.DutToRefCalibrationToleranceMin_percent;
if (double.TryParse(tbxDutToRefTolMin.Text, NumberStyles.Any, new CultureInfo("en"), out var tolerance) ||
double.TryParse(tbxDutToRefTolMin.Text, NumberStyles.Any, new CultureInfo("de"), out tolerance))
{
if (Math.Abs(backupDutToRefTolerance - tolerance) > 0.05)
{
// Try to set the new calculated REF pulses limited by the property setter
firstFm2014.DutToRefCalibrationToleranceMin_percent = tolerance;
tbxDutToRefTolMin.Background = ColorStandardInputField;
// Dispatch settings to all connected FM2014!!!!
foreach (var fm2014 in FM2014.RegisteredFm2014s)
{
fm2014.DutToRefCalibrationToleranceMin_percent = tolerance;
}
}
}
else
{
tbxDutToRefTolMax.Background = ColorProcessFailed;
}
});
}
private void chkAnySlot_Click(Object sender, RoutedEventArgs e)
{
_configSetupHasChanged = true;