916 lines
35 KiB
C#
916 lines
35 KiB
C#
/****************************************************************************************/
|
|
/*!@file FrmMainMiniPrf.cs
|
|
* @brief Main form for 'MiniPrf' - Single FM2014 Manual Flow Test Station:
|
|
* - Used to regulate one mechanical flow meter - 'DUT - Device under test',
|
|
* - Can be used to calibrate the 'REF - Reference meter'
|
|
*
|
|
*=======================================================================================\n
|
|
* @copyright
|
|
*
|
|
*_______________________________________________________________________________________\n
|
|
* Copyright (c) 2025..2026 SENSUS GmbH.\n
|
|
* All Rights Reserved.\n
|
|
* \n
|
|
* Confidential property of\n
|
|
* SENSUS GmbH,\n
|
|
* Meineckestr. 10, 30880 LAATZEN, GERMANY\n
|
|
* \n
|
|
*=======================================================================================\n
|
|
* @authors
|
|
*
|
|
*_______________________________________________________________________________________\n
|
|
* Thomas Wiedebusch\n
|
|
*
|
|
*
|
|
*=======================================================================================\n
|
|
* @version
|
|
*
|
|
*_______________________________________________________________________________________\n
|
|
* V1.00 13-Nov-2025..22-Dec-2025 by Thomas Wiedebusch\n
|
|
* - Initial.
|
|
*
|
|
*
|
|
*=======================================================================================\n
|
|
*/
|
|
|
|
using Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Config;
|
|
using Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core;
|
|
using Sensus.MiniPrf.Ui.Properties;
|
|
using System;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using System.IO.Ports;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using Sensus.Common.Hardware.WaterMeter.MechanicalMeter.FM2014.FM2014Core.Consts;
|
|
using Xylem.Common.Utils.ProcessExec.EventArguments;
|
|
|
|
namespace Sensus.MiniPrf.Ui
|
|
{
|
|
/// <summary>
|
|
/// Main form for 'MiniPrf'
|
|
/// </summary>
|
|
public partial class FrmMainMiniPrf : Form
|
|
{
|
|
#region Properties
|
|
|
|
/// <summary>
|
|
/// The single FM2014 for this program
|
|
/// </summary>
|
|
private FM2014 Fm2014
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The start time is going to be used for time measurements of processes. It has to be set to
|
|
/// the actual time if the measurement should be (re)started.
|
|
/// </summary>
|
|
private DateTimeOffset _startTime;
|
|
|
|
/// <summary>
|
|
/// The auto progress bar enabled is for infinite processes or if the process doesn't feed
|
|
/// the progress bar with information (e.g. Connect()).
|
|
/// </summary>
|
|
private Boolean _autoProgressBar;
|
|
|
|
// external update remarks form
|
|
private readonly FrmHistory _frmHistory = new FrmHistory();
|
|
|
|
private readonly Version _version;
|
|
|
|
// status information
|
|
private static readonly Color ColorDefault = Color.Black;
|
|
private static readonly Color ColorSuccess = Color.Green;
|
|
|
|
private static readonly Color ColorProcessFailed = Color.Red;
|
|
//private static readonly Color ColorOngoingProcess = Color.Blue;
|
|
//private static readonly Color ColorUnknownStatus = Color.Gray;
|
|
//private const String SuccessSign = @"✔";
|
|
//private const String FailedSign = @"✘";
|
|
|
|
private const String StrSeparator = "--------------------------------------------------" +
|
|
"--------------------------------------------------" +
|
|
"--------------------------------------------------";
|
|
|
|
//private readonly ILogger _logger = NLogHelper.CreateOrGetLogger("FM2014");
|
|
private readonly FM2014Config _fm2014Config = new FM2014Config();
|
|
|
|
// internal reminders of changed items to avoid write access on startup if items are preloaded
|
|
private Int32 _comPortIdx;
|
|
private Int32 _addressIdx;
|
|
private Int32 _toleranceIdx;
|
|
private Boolean _regulationSetupHasChanged;
|
|
#endregion Properties
|
|
|
|
#region FormControls
|
|
/// <summary>
|
|
/// Ctor
|
|
/// </summary>
|
|
/// <remarks date="2025-Nov-13" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
public FrmMainMiniPrf()
|
|
{
|
|
InitializeComponent();
|
|
//var cultureInfo = new CultureInfo("en-GB");
|
|
//Thread.CurrentThread.CurrentUICulture = cultureInfo;
|
|
//Thread.CurrentThread.CurrentCulture = cultureInfo;
|
|
_version = Assembly.GetExecutingAssembly().GetName().Version;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clear data table and set genesis to not connected
|
|
/// </summary>
|
|
/// <remarks date="2025-Nov-13" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
private void Init()
|
|
{
|
|
ViewProcessControl(false);
|
|
_autoProgressBar = false;
|
|
_regulationSetupHasChanged = false;
|
|
|
|
// 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);
|
|
}
|
|
//_comPortIdx = 0;
|
|
//cbxFM2014ComPort.Text = cbxFM2014ComPort.Items[0].ToString();
|
|
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;
|
|
}
|
|
|
|
// FM2014 group box
|
|
lblConnectFM2014.Text = Resources.StrLblFM2014NotConnected;
|
|
lblConnectFM2014.ForeColor = Color.Red;
|
|
tbxFM2014FullId.Text = "";
|
|
tbxFM2014ApplicationFwVersion.Text = "";
|
|
lblFM2014SerialNumber.Text = Resources.StrLblFM2014SerialNumber;
|
|
tbxFM2014SerialNumber.Text = "";
|
|
lblFM2014SerialPort.Text = Resources.StrLblFM2014SerialPort;
|
|
lblFM2014Address.Text = Resources.StrLblFM2014Address;
|
|
lblFM2014Tolerance.Text = Resources.StrLblFM2014Tolerance;
|
|
btnFM2014Connect.Text = Resources.StrBtnConnect;
|
|
|
|
// Regulation Setup group box
|
|
gbxRegulationSetup.Text = Resources.StrGbxRegulationSetup;
|
|
lblRefPulsePerVolume.Text = Resources.StrLblRefPulsesPerCm;
|
|
tbxRefPulsePerCm.Text = "";
|
|
lblDutPulsePerVolume.Text = Resources.StrLblDutPulsesPerCm;
|
|
tbxDutPulsePerCm.Text = "";
|
|
lblScaleRefToDut.Text = Resources.StrLblScaleRefToDut;
|
|
tbxScaleRefToDut.Text = "";
|
|
lblAttenuation.Text = Resources.StrLblAttenuation;
|
|
btnSaveRegulationSetup.Text = Resources.StrBtnSaveRegulationSetup;
|
|
|
|
// Manual REF Calibration group box
|
|
gbxManualRefCalibration.Text = Resources.StrGbxManualRefCalibration;
|
|
lblMeasuredRefPulses.Text = Resources.StrLblMeasuredRefPulses;
|
|
tbxMeasuredRefPulses.Text = "";
|
|
lblWeightScaleVolume.Text = Resources.StrLblMeasuredWeightScaleVolume;
|
|
tbxWeightScaleVolumeLiters.Text = "";
|
|
lblPulseVolumeCmRelation.Text = Resources.StrLblRefPulsesPerCm;
|
|
tbxRefCalibrationResultPulsePerCm.Text = "";
|
|
btnManualRefCalibration.Text = Resources.StrBtnStartCalibration;
|
|
|
|
// DUT to REF Regulation group box
|
|
gbxDutToRefRegulation.Text = Resources.StrGbxDutToRefRegulation;
|
|
lblActualFlowRateCmPerHour.Text = Resources.StrLblActualMeasuredFlowRate;
|
|
tbxActualFlowRateCmPerHour.Text = "";
|
|
lblActualMeasuredTolerance.Text = Resources.StrLblActualMeasuredToleranceDutToRef;
|
|
tbxActualMeasuredToleranceDutToRef.Text = "";
|
|
chkUseDampedTolerance.Text = Resources.StrChkUseDampedTolerance;
|
|
btnDutToRefRegulation.Text = Resources.StrBtnStartRegulation;
|
|
|
|
// Process status
|
|
lblActualProcess.Text = Resources.StrLblProcessStatus;
|
|
lblTimeText.Text = Resources.StrLblTime;
|
|
lblWaitingForMeterResponse.Text = Resources.StrLblWaitingForMeterResponse;
|
|
lblWaitingForMeterResponse.Visible = false;
|
|
|
|
SetFM2014AccessLocked();
|
|
btnFM2014Connect.Enabled = true;
|
|
cbxFM2014Address.Enabled = true;
|
|
cbxFM2014ComPort.Enabled = true;
|
|
btnFM2014Connect.Focus();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Store the settings adjusted by the UI
|
|
/// </summary>
|
|
/// <remarks date="2025-Nov-13" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
/// <remarks date="2026-Jan-15" author="Thomas Wiedebusch">
|
|
/// - Update FM2014 properties.
|
|
/// </remarks>
|
|
private void StoreFM2014Settings()
|
|
{
|
|
_fm2014Config.SerialPort = cbxFM2014ComPort.Text;
|
|
if (int.TryParse(cbxFM2014Address.SelectedItem.ToString(), out var address))
|
|
{
|
|
_fm2014Config.Address = address;
|
|
if (Fm2014 != null)
|
|
Fm2014.Address = address;
|
|
|
|
}
|
|
|
|
if (int.TryParse(cbxFM2014TolerancePercent.SelectedItem.ToString(), out var tolerancePercent)
|
|
&& (tolerancePercent == 3 || tolerancePercent == 5))
|
|
{
|
|
_fm2014Config.TolerancePercent = tolerancePercent;
|
|
if (Fm2014 != null)
|
|
Fm2014.Tolerance_percent = tolerancePercent;
|
|
}
|
|
|
|
_fm2014Config.Update();
|
|
}
|
|
|
|
private void FrmMainMiniPrf_Load(Object sender, EventArgs e)
|
|
{
|
|
Init();
|
|
|
|
var xPosition = Location.X + Size.Width;
|
|
var yPosition = Location.Y;
|
|
if (_frmHistory != null)
|
|
{
|
|
_frmHistory.SetDesktopLocation(xPosition, yPosition);
|
|
_frmHistory.Show();
|
|
}
|
|
|
|
var version = $"Version: {_version.Major}.{_version.Minor}.{_version.Build}";
|
|
Text = $@"MiniPrf - {version}";
|
|
LogText($"MiniPrf: {version}");
|
|
LogText(StrSeparator);
|
|
}
|
|
|
|
private void FrmMainMiniPrf_FormClosed(Object sender, FormClosedEventArgs e)
|
|
{
|
|
_frmHistory?.Close();
|
|
Fm2014?.Dispose();
|
|
Dispose();
|
|
}
|
|
#endregion FormControls
|
|
|
|
#region TimerControls
|
|
|
|
private void tmrProgressUpdate_Tick(Object sender, EventArgs e)
|
|
{
|
|
if (_autoProgressBar || barSingleProgressUpdate.Visible)
|
|
{
|
|
barSingleProgressUpdate.Value =
|
|
barSingleProgressUpdate.Value + 4 > 100 ? 0 : barSingleProgressUpdate.Value + 4;
|
|
}
|
|
|
|
SetTimeDisplay();
|
|
Update();
|
|
}
|
|
|
|
private void SetTimeDisplay()
|
|
{
|
|
var time = DateTimeOffset.UtcNow;
|
|
var timeSpan = time - _startTime;
|
|
lblUpdateTimeValue.Text = $@"{(UInt32)timeSpan.TotalMinutes}:{timeSpan.Seconds:00}";
|
|
}
|
|
#endregion TimerControls
|
|
|
|
#region ActivationControls
|
|
/// <summary>
|
|
/// Lock all buttons
|
|
/// </summary>
|
|
private void SetFM2014AccessLocked()
|
|
{
|
|
// Disable all buttons
|
|
btnSaveRegulationSetup.Enabled = false;
|
|
btnManualRefCalibration.Enabled = false;
|
|
btnDutToRefRegulation.Enabled = false;
|
|
btnFM2014Connect.Enabled = false;
|
|
|
|
// Disable manual input
|
|
tbxWeightScaleVolumeLiters.ReadOnly = true;
|
|
tbxRefPulsePerCm.ReadOnly = true;
|
|
tbxDutPulsePerCm.ReadOnly = true;
|
|
|
|
// Disable setting selections
|
|
cbxAttenuation.Enabled = false;
|
|
cbxFM2014Address.Enabled = false;
|
|
cbxFM2014ComPort.Enabled = false;
|
|
cbxFM2014TolerancePercent.Enabled = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enable all buttons, FM2014 has to be connected
|
|
/// </summary>
|
|
private void SetFM2014AccessEnabled()
|
|
{
|
|
// Enable save setup depending on changed properties
|
|
btnSaveRegulationSetup.Enabled = _regulationSetupHasChanged;
|
|
|
|
// Enable buttons and display correct information
|
|
btnManualRefCalibration.Enabled = true;
|
|
btnDutToRefRegulation.Enabled = true;
|
|
btnFM2014Connect.Enabled = true;
|
|
btnManualRefCalibration.Text = Resources.StrBtnStartCalibration;
|
|
btnDutToRefRegulation.Text = Resources.StrBtnStartRegulation;
|
|
|
|
// Enable manual input
|
|
tbxWeightScaleVolumeLiters.ReadOnly = false;
|
|
tbxRefPulsePerCm.ReadOnly = false;
|
|
tbxDutPulsePerCm.ReadOnly = false;
|
|
|
|
// Enable setting selections
|
|
cbxAttenuation.Enabled = true;
|
|
cbxFM2014Address.Enabled = true;
|
|
cbxFM2014ComPort.Enabled = true;
|
|
cbxFM2014TolerancePercent.Enabled = true;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restore setting of buttons and timeout after operation with device
|
|
/// </summary>
|
|
private void CheckUpdateEnabled()
|
|
{
|
|
if (Fm2014 == null || !Fm2014.IsLoggedOn)
|
|
{
|
|
SetFM2014AccessLocked();
|
|
btnFM2014Connect.Enabled = true;
|
|
return;
|
|
}
|
|
SetFM2014AccessEnabled();
|
|
}
|
|
|
|
#endregion ActivationControls
|
|
|
|
#region BoardControls
|
|
|
|
/// <summary>
|
|
/// Establish connection
|
|
/// </summary>
|
|
/// <remarks date="2025-Aug-07" author="Thomas Wiedebusch">
|
|
/// - Compare the max supported FW versions of the configuration.json.
|
|
/// </remarks>
|
|
/// <remarks date="2025-Oct-02" author="Thomas Wiedebusch">
|
|
/// - Catch error message on unknown data type and kill meter.
|
|
/// </remarks>
|
|
private void Connect()
|
|
{
|
|
try
|
|
{
|
|
Init();
|
|
if (string.IsNullOrEmpty(cbxFM2014ComPort?.SelectedItem?.ToString()) ||
|
|
cbxFM2014ComPort.SelectedItem.ToString().Equals("?"))
|
|
{
|
|
var text = Resources.StrErrorMsgComPortNotAssigned;
|
|
MessageBox.Show(text, Resources.StrError, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
LogText(text);
|
|
return;
|
|
}
|
|
|
|
StoreFM2014Settings();
|
|
|
|
ActionControl(true);
|
|
|
|
if (Fm2014 != null)
|
|
{
|
|
Fm2014.OnRawRecordReceived -= DataReceived_Handler;
|
|
Fm2014.Dispose();
|
|
//dispose old meter
|
|
Fm2014 = null;
|
|
}
|
|
|
|
//assign new meter
|
|
Fm2014 = new FM2014();
|
|
Fm2014.OnRawRecordReceived += DataReceived_Handler;
|
|
if (int.TryParse(cbxFM2014Address.SelectedItem.ToString(), out var address))
|
|
{
|
|
Fm2014.Address = address;
|
|
}
|
|
else
|
|
{
|
|
ActionControl(false);
|
|
LogErrorText(Resources.StrErrorMsgFM2014AddressInvalid);
|
|
}
|
|
if (int.TryParse(cbxFM2014TolerancePercent.SelectedItem.ToString(), out var tolerancePercent)
|
|
&& (tolerancePercent == 3 || tolerancePercent == 5))
|
|
{
|
|
Fm2014.Tolerance_percent = tolerancePercent;
|
|
}
|
|
else
|
|
{
|
|
ActionControl(false);
|
|
LogErrorText(Resources.StrErrorMsgFM2014ToleranceInvalid);
|
|
}
|
|
|
|
lblActualProcess.Text = Resources.StrMsgConnecting;
|
|
Fm2014.Connect(cbxFM2014ComPort.SelectedItem.ToString());
|
|
|
|
Task.Factory.StartNew(() =>
|
|
{
|
|
Fm2014.Login();
|
|
|
|
if (!Fm2014.IsLoggedOn)
|
|
{
|
|
LogErrorText(Resources.StrErrorMsgFM2014AccessDenied);
|
|
Fm2014.Logout();
|
|
ActionControl(false);
|
|
return;
|
|
}
|
|
|
|
if (Fm2014.IsLoggedOn)
|
|
{
|
|
Invoke(new Action(() =>
|
|
{
|
|
lblConnectFM2014.Text = Resources.StrLblFM2014Connected;
|
|
lblConnectFM2014.ForeColor = Color.Green;
|
|
tbxFM2014FullId.Text = Fm2014.FullId;
|
|
tbxFM2014FullId.Visible = true;
|
|
tbxFM2014ApplicationFwVersion.Text = Fm2014.FwVersion;
|
|
tbxFM2014SerialNumber.Text = Fm2014.SerialNumber;
|
|
|
|
// Logging to history window
|
|
LogText("FM2014 ID:\t\t" + Fm2014.FullId);
|
|
LogText("FM2014 Firmware Version:\t" + Fm2014.FwVersion);
|
|
LogText($"FM2014 {Resources.StrLblFM2014SerialNumber}\t" + Fm2014.SerialNumber);
|
|
LogText($"FW2014 {Resources.StrLblFM2014Address}\t\t" + Fm2014.Address);
|
|
var dt = DateTime.UtcNow;
|
|
var msg = $"{dt:yyyy-MM-dd HH:mm:ss} UTC";
|
|
LogText($"{Resources.StrMsgPcDateTime}\t{msg}");
|
|
|
|
CheckUpdateEnabled();
|
|
}));
|
|
}
|
|
}).ContinueWith(delegate
|
|
{
|
|
ActionControl(false);
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ActionControl(false);
|
|
MessageBox.Show(ex.Message, Resources.StrError, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
LogErrorText(ex.Message);
|
|
Fm2014?.Dispose();
|
|
}
|
|
}
|
|
|
|
#endregion BoardControls
|
|
|
|
#region ProcessControls
|
|
|
|
private void ActionControl(Boolean isActive)
|
|
{
|
|
if (isActive)
|
|
{
|
|
Invoke(new Action(() =>
|
|
{
|
|
ViewProcessControl(true);
|
|
tmrProgressUpdate.Enabled = true;
|
|
}));
|
|
}
|
|
else
|
|
{
|
|
Invoke(new Action(() =>
|
|
{
|
|
ViewProcessControl(false);
|
|
CheckUpdateEnabled();
|
|
}));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// View all process bars and labels
|
|
/// </summary>
|
|
private void ViewProcessControl(Boolean view)
|
|
{
|
|
if (view)
|
|
{
|
|
lblActualProcess.Visible = true;
|
|
barSingleProgressUpdate.Visible = true;
|
|
tmrProgressUpdate.Enabled = true;
|
|
SetFM2014AccessLocked();
|
|
}
|
|
else
|
|
{
|
|
lblActualProcess.Visible = false;
|
|
barSingleProgressUpdate.Visible = false;
|
|
tmrProgressUpdate.Enabled = false;
|
|
lblWaitingForMeterResponse.Visible = false;
|
|
lblActualProcess.Text = "";
|
|
SetFM2014AccessEnabled();
|
|
}
|
|
|
|
//common actions and settings
|
|
lblActualProcess.Update();
|
|
barSingleProgressUpdate.Value = 0;
|
|
barSingleProgressUpdate.Update();
|
|
Update();
|
|
}
|
|
|
|
#endregion ProcessControls
|
|
|
|
#region InfoWindow
|
|
|
|
/// <summary>
|
|
/// Clear history window.
|
|
/// </summary>
|
|
/// <remarks date="2021-Jan-05" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private void ClearHistoryWindow()
|
|
{
|
|
if (_frmHistory != null && _frmHistory.rtbHistory.InvokeRequired)
|
|
{
|
|
_frmHistory.rtbHistory.Invoke(new Action(() => { _frmHistory.rtbHistory.Clear(); }));
|
|
}
|
|
else
|
|
{
|
|
_frmHistory?.rtbHistory.Clear();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Output exclusively to user update remarks text window.
|
|
/// </summary>
|
|
/// <remarks date="2021-Apr-26" author="Thomas Wiedebusch">
|
|
/// - Color added.
|
|
/// </remarks>
|
|
/// <remarks date="2023-Aug-15" author="Thomas Wiedebusch">
|
|
/// - File output added.
|
|
/// </remarks>
|
|
private void LogText(String txtHistory, String filename = null)
|
|
{
|
|
InfoWindowColoredText(txtHistory, ColorDefault);
|
|
if (!string.IsNullOrEmpty(filename))
|
|
{
|
|
File.AppendAllLines(filename, new[] { txtHistory });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Output exclusively to user update remarks text window.
|
|
/// </summary>
|
|
private void LogErrorText(String txtHistory)
|
|
{
|
|
InfoWindowColoredText(txtHistory, ColorProcessFailed);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Output exclusively to user update remarks text window.
|
|
/// </summary>
|
|
private void LogSuccessText(String txtHistory)
|
|
{
|
|
InfoWindowColoredText(txtHistory, ColorSuccess);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Output exclusively to user update remarks text window.
|
|
/// </summary>
|
|
private void InfoWindowColoredText(String txtHistory, Color color)
|
|
{
|
|
if (_frmHistory?.rtbHistory == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Invoke(new Action(() =>
|
|
{
|
|
_frmHistory.rtbHistory.SuspendLayout();
|
|
_frmHistory.rtbHistory.SelectionStart = _frmHistory.rtbHistory.Text.Length;
|
|
_frmHistory.rtbHistory.SelectionLength = 0;
|
|
_frmHistory.rtbHistory.SelectionColor = color;
|
|
_frmHistory.rtbHistory.AppendText($"{txtHistory}{Environment.NewLine}");
|
|
_frmHistory.rtbHistory.SelectionColor = _frmHistory.rtbHistory.ForeColor;
|
|
_frmHistory.rtbHistory.ScrollToCaret();
|
|
_frmHistory.rtbHistory.ResumeLayout();
|
|
}));
|
|
}
|
|
|
|
#endregion HistoryWindow
|
|
|
|
#region Tools
|
|
/// <summary>
|
|
/// Set the actual process and log the text.
|
|
/// </summary>
|
|
/// <remarks date="2023-Jan-04" author="Thomas Wiedebusch">
|
|
/// - Color added.
|
|
/// </remarks>
|
|
private void SetActualProcessAndLog(String message, String logFileName = null)
|
|
{
|
|
Invoke(new Action(() => { lblActualProcess.Text = message; }));
|
|
LogText(message, logFileName);
|
|
}
|
|
#endregion
|
|
|
|
#region Buttons and Controls
|
|
/// <summary>
|
|
/// Establish connection to FM2014 with individual address and read out FM2014 info.
|
|
/// </summary>
|
|
/// <remarks date="2023-Jan-04" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
private void btnConnect_Click(Object sender, EventArgs e)
|
|
{
|
|
_startTime = DateTimeOffset.UtcNow;
|
|
Connect();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Start and stop the DUT to REF regulation measurement.
|
|
/// </summary>
|
|
/// <remarks date="2023-Jan-14" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
private void btnDutToRefRegulation_Click(Object sender, EventArgs e)
|
|
{
|
|
_startTime = DateTimeOffset.UtcNow;
|
|
if (!Fm2014.CyclicReceiveTaskLoopIsActive)
|
|
{
|
|
ActionControl(true);
|
|
_autoProgressBar = true;
|
|
if (Fm2014.RegulationMeasurement())
|
|
{
|
|
btnDutToRefRegulation.Text = Resources.StrBtnStopRegulation;
|
|
btnDutToRefRegulation.Enabled = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_autoProgressBar = false;
|
|
// Deactivate the button temporary to avoid repeated execution as the reset takes a certain time
|
|
btnDutToRefRegulation.Enabled = false;
|
|
Fm2014.ResetMeasurement();
|
|
ActionControl(false);
|
|
btnDutToRefRegulation.Text = Resources.StrBtnStartRegulation;
|
|
}
|
|
|
|
}
|
|
/// <summary>
|
|
/// Start and stop the manual REF calibration measurement.
|
|
/// </summary>
|
|
/// <remarks date="2023-Jan-04..12" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
private void btnManualRefCalibration_Click(Object sender, EventArgs e)
|
|
{
|
|
_startTime = DateTimeOffset.UtcNow;
|
|
if (!Fm2014.CyclicReceiveTaskLoopIsActive)
|
|
{
|
|
ActionControl(true);
|
|
_autoProgressBar = true;
|
|
if (Fm2014.PulseCounterMeasurement())
|
|
{
|
|
btnManualRefCalibration.Text = Resources.StrBtnStopCalibration;
|
|
btnManualRefCalibration.Enabled = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_autoProgressBar = false;
|
|
// Deactivate the button temporary to avoid repeated execution as the reset takes a certain time
|
|
btnManualRefCalibration.Enabled = false;
|
|
Fm2014.ResetMeasurement();
|
|
ActionControl(false);
|
|
btnManualRefCalibration.Text = Resources.StrBtnStartCalibration;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Selected COM port item has changed.
|
|
/// </summary>
|
|
/// <remarks date="2023-Jan-04" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
private void cbxFM2014BaseSettings_SelectedValueChanged(Object sender, EventArgs e)
|
|
{
|
|
if (_toleranceIdx != cbxFM2014TolerancePercent.SelectedIndex ||
|
|
_addressIdx != cbxFM2014Address.SelectedIndex ||
|
|
_comPortIdx != cbxFM2014ComPort.SelectedIndex)
|
|
{
|
|
_toleranceIdx = cbxFM2014TolerancePercent.SelectedIndex;
|
|
_addressIdx = cbxFM2014Address.SelectedIndex;
|
|
_comPortIdx = cbxFM2014ComPort.SelectedIndex;
|
|
StoreFM2014Settings();
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Switch between damped or undamped tolerance display. This can be changed during the 'Regulation Measurement'
|
|
/// as it will just collect a different dataset and not change anything on the measurement setup.
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void chkUseDampedTolerance_CheckedChanged(Object sender, EventArgs e)
|
|
{
|
|
if (Fm2014 != null)
|
|
Fm2014.UseDampedTolerance = chkUseDampedTolerance.Checked;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Redirect keystroke 'Enter' to leaving the cell event
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void tbxRefPulsePerVolume_KeyDown(Object sender, KeyEventArgs e)
|
|
{
|
|
if (e.KeyCode == Keys.Enter)
|
|
{
|
|
tbxRefPulsePerVolume_Leave(this, null);
|
|
}
|
|
}
|
|
|
|
private String _backupWeightScaleVolumeLitersStr;
|
|
private String _backupRefCalibrationResultPulsePerCmStr;
|
|
private String _backupMeasuredRefPulsesStr;
|
|
/// <summary>
|
|
/// After manual input of the REF pulses per cubic meter the scale REF to DUT has to be recalculated
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void tbxRefPulsePerVolume_Leave(Object sender, EventArgs e)
|
|
{
|
|
_regulationSetupHasChanged = true;
|
|
// Setup FM2014
|
|
if (Fm2014 != null && int.TryParse(tbxRefPulsePerCm.Text, out var pulses_per_cm))
|
|
{
|
|
Fm2014.Ref_pulse_per_cm = (UInt16)pulses_per_cm;
|
|
tbxScaleRefToDut.Text = $@"{Fm2014.RefToDutScale_norm:F3}";
|
|
// If the REF pulses per cubic meter have been changed manually, the 'Manual REF Calibration'
|
|
// fields have to be cleared if those are different. A backup to restore it may be useful.
|
|
if (!tbxRefPulsePerCm.Text.Equals(tbxRefCalibrationResultPulsePerCm.Text) &&
|
|
!string.IsNullOrEmpty(tbxRefCalibrationResultPulsePerCm.Text))
|
|
{
|
|
_backupMeasuredRefPulsesStr = tbxMeasuredRefPulses.Text;
|
|
tbxMeasuredRefPulses.Text = "";
|
|
_backupRefCalibrationResultPulsePerCmStr = tbxRefCalibrationResultPulsePerCm.Text;
|
|
tbxRefCalibrationResultPulsePerCm.Text = "";
|
|
_backupWeightScaleVolumeLitersStr = tbxWeightScaleVolumeLiters.Text;
|
|
tbxWeightScaleVolumeLiters.Text = "";
|
|
}
|
|
// Restore values if REF pulses per cubic meters is back to the calibrated one
|
|
else if (tbxRefPulsePerCm.Text.Equals(_backupRefCalibrationResultPulsePerCmStr))
|
|
{
|
|
tbxMeasuredRefPulses.Text = _backupMeasuredRefPulsesStr;
|
|
tbxRefCalibrationResultPulsePerCm.Text = _backupRefCalibrationResultPulsePerCmStr;
|
|
tbxWeightScaleVolumeLiters.Text = _backupWeightScaleVolumeLitersStr;
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Redirect keystroke 'Enter' to leaving the cell event
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void tbxDutPulsePerVolume_KeyDown(Object sender, KeyEventArgs e)
|
|
{
|
|
if (e.KeyCode == Keys.Enter)
|
|
{
|
|
tbxDutPulsePerVolume_Leave(this, null);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// After manual input of the DUT pulses per cubic meter the scale REF to DUT has to be recalculated
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void tbxDutPulsePerVolume_Leave(Object sender, EventArgs e)
|
|
{
|
|
_regulationSetupHasChanged = true;
|
|
// Setup FM2014
|
|
if (Fm2014 != null && int.TryParse(tbxDutPulsePerCm.Text, out var pulses_per_cm))
|
|
{
|
|
Fm2014.Dut_pulse_per_cm = (UInt16)pulses_per_cm;
|
|
tbxScaleRefToDut.Text = $@"{Fm2014.RefToDutScale_norm:F3}";
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Redirect keystroke 'Enter' to leaving the cell event
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void tbxWeightScaleMass_KeyStoke(Object sender, KeyEventArgs e)
|
|
{
|
|
if (e.KeyCode == Keys.Enter)
|
|
{
|
|
tbxWeightScaleMass_Leave(this, null);
|
|
}
|
|
}
|
|
/// <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'.
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void tbxWeightScaleMass_Leave(Object sender, EventArgs e)
|
|
{
|
|
// Calculate REF pulses per cubic meter
|
|
if (int.TryParse(tbxMeasuredRefPulses.Text, out var pulses) && pulses > 0 &&
|
|
int.TryParse(tbxWeightScaleVolumeLiters.Text, out var liters) && liters > 0)
|
|
{
|
|
tbxRefCalibrationResultPulsePerCm.Text = $@"{(UInt16)(pulses / (liters / 1000.0f))}";
|
|
// Copy from REF pulses per cubic meter in 'Manual REF Calibration' to 'Regulation Setup'
|
|
if (!tbxRefCalibrationResultPulsePerCm.Text.Equals(tbxRefPulsePerCm.Text))
|
|
{
|
|
_regulationSetupHasChanged = true;
|
|
tbxRefPulsePerCm.Text = tbxRefCalibrationResultPulsePerCm.Text;
|
|
// Setup FM2014
|
|
if (Fm2014 != null && int.TryParse(tbxRefCalibrationResultPulsePerCm.Text, out var pulses_per_cm))
|
|
{
|
|
Fm2014.Ref_pulse_per_cm = (UInt16)pulses_per_cm;
|
|
tbxScaleRefToDut.Text = $@"{Fm2014.RefToDutScale_norm:F3}";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion Buttons and Controls
|
|
|
|
#region Event handler
|
|
|
|
/// <summary>
|
|
/// Feedback from FM2014being parsed to GUI
|
|
/// </summary>
|
|
/// <remarks date="2023-Jan-04..14" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
private void DataReceived_Handler(Object sender, ProcessExecEventArgs e)
|
|
{
|
|
Invoke(new Action(() =>
|
|
{
|
|
// Process info
|
|
lblActualProcess.Text = e.ActualProcessMessage;
|
|
lblActualProcess.Update();
|
|
SetTimeDisplay();
|
|
lblUpdateTimeValue.Update();
|
|
if (e.ActualProcessPercent != null && !_autoProgressBar && barSingleProgressUpdate.Visible)
|
|
barSingleProgressUpdate.Value = (Int32)e.ActualProcessPercent;
|
|
|
|
// Data dispatcher
|
|
var resp = (FM2014CmdDef.CmdResponse)e.SpecificInfoObj;
|
|
if (resp.IntValue != null)
|
|
{
|
|
LogText($"{resp.AnswerStr}: {resp.IntValue:D} {resp.SiUnit}");
|
|
switch (resp.CmdName)
|
|
{
|
|
case FM2014CmdDef.CmdName.CMD_REF_GET_PLS_CTR:
|
|
tbxMeasuredRefPulses.Text = $@"{resp.IntValue:D}";
|
|
break;
|
|
|
|
}
|
|
}
|
|
if (resp.DoubleValue != null)
|
|
{
|
|
LogText($"{resp.AnswerStr}: {resp.DoubleValue:F2} {resp.SiUnit}");
|
|
switch (resp.CmdName)
|
|
{
|
|
case FM2014CmdDef.CmdName.CMD_GET_UDTLC:
|
|
case FM2014CmdDef.CmdName.CMD_GET_DTLC:
|
|
tbxActualMeasuredToleranceDutToRef.Text = $@"{resp.DoubleValue:F2}";
|
|
break;
|
|
|
|
}
|
|
}
|
|
}));
|
|
|
|
}
|
|
#endregion
|
|
}
|
|
}
|