laatzen/Common/Ui/GenesisToolBox/FrmLowLevelTools.cs

1870 lines
62 KiB
C#

using Logic.ProductionToProductMapper.Cordonel;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Const;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Consts;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisPwd;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers.DataTypes;
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
using Xylem.Common.Logic.SoftwareAccessHelper;
using Xylem.Common.Utils.ProcessExec.EventArguments;
using String = System.String;
namespace Xylem.Common.Ui.GenesisToolBox
{
/// <summary>
/// FW update form
/// </summary>
public partial class FrmLowLevelTools : Form
{
#region Variables
private readonly MeterBatch _meterBatch = new MeterBatch();
private GenesisMeter _currentGenesis;
private const String StrNotConnected = "NOT CONNECTED";
private const String StrPartPcbConnected = "PCB ID: ";
private const String StrBurnUpgrade = "Waiting for meter response";
private MeterFile _meterFile;
private MeterPowerCorrectionFile _meterPowCorrFile;
//private String _lastFwUpdateState;
//private Int32 _lastSingleProgress;
private Boolean _progressBarOn;
private DateTimeOffset _startTime;
private Boolean _resetTimeMeasurement;
private readonly Boolean _updateGui = true;
private MeterResetPsu _meterResetPsu;
private Boolean _meterResetProcessActive;
private Boolean _rebootSucceeded;
private Boolean _tryConnectPcb;
// 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 = "-----------------------------------------------------" +
"-----------------------------------------------------";
#endregion
#region FormControls
/// <summary>
/// Ctor FW update
/// </summary>
public FrmLowLevelTools()
{
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>
private void Init()
{
ViewProcessControl(false);
lblConnectPcb.Text = StrNotConnected;
lblConnectPcb.ForeColor = Color.Red;
lblWaitingForMeterResponse.Visible = false;
SetCordonelAccessLocked();
tbxPcbId.Visible = false;
}
private void FrmLowLevelTools_Load(Object sender, EventArgs e)
{
var version = Assembly.GetExecutingAssembly().GetName().Version;
lblFwUpdateInfo.Text = $@"Version: {version.Major}.{version.Minor}.{version.Build}";
_resetTimeMeasurement = true;
Init();
var xPosition = Location.X + Size.Width;
var yPosition = Location.Y;
if (_frmHistory != null)
{
_frmHistory.SetDesktopLocation(xPosition, yPosition);
_frmHistory.Show();
}
LogText($"GenesisToolBox: {_version.Major}.{_version.Minor}.{_version.Build}");
LogText(StrSeparator);
ddlLocation.SelectedIndex = 0;
}
private void FrmLowLevelTools_FormClosing(Object sender, FormClosingEventArgs e)
{
_frmHistory?.Close();
_currentGenesis?.Logout();
_meterBatch?.RemoveAllMeters();
_meterBatch?.Dispose();
if (_meterFile != null)
{
_meterFile.OnProcessUpdate -= ProcessUpdate_Event;
_meterFile = null;
}
Dispose();
}
private void cbComSlot_SelectedIndexChanged(Object sender, EventArgs e)
{
_resetTimeMeasurement = true;
Init();
}
#endregion
#region ActivationControls
/// <summary>
/// Disable all buttons except the connect button
/// </summary>
private void DisableToolButtons()
{
btnReadPowCorr.Enabled = false;
btnPulseModeOff.Enabled = false;
btnClearDisplay.Enabled = false;
btnSetDateTime.Enabled = false;
btnGetDateTime.Enabled = false;
btnFixBattery.Enabled = false;
btnRebootMeter.Enabled = false;
btnStoreConfiguration.Enabled = false;
btnUploadConfig.Enabled = false;
btnReadLogFiles.Enabled = false;
btnReadBatAndLog.Enabled = false;
btnListFileDetails.Enabled = false;
btnTidyFile.Enabled = false;
btnEraseFile.Enabled = false;
tbxFileToEraseName.Enabled = false;
tbxFileToEraseDrive.Enabled = false;
btnUploadPWFile.Enabled = false;
}
/// <summary>
/// Enable all buttons except the connect button
/// </summary>
private void EnableToolButtons()
{
btnReadPowCorr.Enabled = true;
btnPulseModeOff.Enabled = true;
btnClearDisplay.Enabled = true;
btnSetDateTime.Enabled = true;
btnGetDateTime.Enabled = true;
btnFixBattery.Enabled = true;
btnRebootMeter.Enabled = true;
btnStoreConfiguration.Enabled = true;
btnUploadConfig.Enabled = true;
btnReadLogFiles.Enabled = true;
btnReadBatAndLog.Enabled = true;
btnListFileDetails.Enabled = true;
btnTidyFile.Enabled = true;
btnEraseFile.Enabled = true;
tbxFileToEraseName.Enabled = true;
tbxFileToEraseDrive.Enabled = true;
btnUploadPWFile.Enabled = true;
}
/// <summary>
/// Lock all buttons, enable the connect button
/// </summary>
private void SetCordonelAccessLocked()
{
btnConnect.Enabled = true;
DisableToolButtons();
}
/// <summary>
/// Enable all buttons, Cordonel has to be connected
/// </summary>
private void SetCordonelAccessEnabled()
{
btnConnect.Enabled = true;
EnableToolButtons();
}
/// <summary>
/// Disable all buttons during operation with device
/// </summary>
private void SetControlsLowLevelOpOngoing()
{
btnConnect.Enabled = false;
DisableToolButtons();
}
/// <summary>
/// Restore setting of buttons and timeout after operation with device
/// </summary>
private void SetControlsLowLevelOpIsFinished()
{
if (_currentGenesis != null)
{
_currentGenesis.RequestProtocol.AdditionalRetryTimeoutMs = 0;
}
SetCordonelAccessEnabled();
}
#endregion
#region BoardControls
/// <summary>
/// Connect the Cordonel
/// </summary>
private void Connect()
{
try
{
Init();
if (string.IsNullOrEmpty(cbComSlot.SelectedItem.ToString()) ||
!int.TryParse(cbComSlot.SelectedItem.ToString(), out var slotNr))
{
return;
}
lblOverall.Text = @"Login to Cordonel...";
lblActualProcess.Text = @"Establish data base connection...";
Task.Factory.StartNew(() =>
{
ViewProgressPcb(true);
_currentGenesis?.DisposeMeter();
//dispose old meter
_meterBatch.RemoveAllMeters();
_currentGenesis = null;
//assign new meter and assign meter to FW update file if this exists
_currentGenesis = new GenesisMeter();
_currentGenesis.SetupFromConfigFile(slotNr);
_meterBatch.AddMeter(_currentGenesis);
_currentGenesis.Configuration.UseRegisterWatchService = false;
_currentGenesis.Configuration.UseMinMaxCheck = false;
Invoke(new Action(() => { lblActualProcess.Text = @"Connecting to PCB..."; }));
_meterBatch.MetersLogin();
if (!_currentGenesis.IsLoggedOn)
{
//this is needed from meter as an unsuccessfully login requires a delay for the next trial
Thread.Sleep(2000);
_meterBatch.MetersLogin();
}
if (!_currentGenesis.IsLoggedOn)
{
return;
}
_meterFile = new MeterFile(_currentGenesis);
Invoke(new Action(() =>
{
lblConnectPcb.Text = StrPartPcbConnected;
tbxPcbId.Text = _currentGenesis.PcbId;
tbxPcbId.Visible = true;
tbxMeterFw.Text = _currentGenesis.FwVersion;
tbxMeterMeterSize.Text = _currentGenesis.MeterSize;
tbxMeterLutCrc.Text = _currentGenesis.LutCrc;
tbxRegion.Text = _currentGenesis.Region;
LogText("Meter FW Version: " + _currentGenesis.FwVersion);
LogText("Meter LUT CRC: " + _currentGenesis.LutCrc);
LogText("Meter Size: " + _currentGenesis.MeterSize);
LogText("Meter Region: " + _currentGenesis.Region);
if (_currentGenesis.RadioFrequencyMhz != null)
{
tbxRadio.Text = $@"{_currentGenesis.RadioFrequencyMhz}";
LogText($"Meter radio frequency [MHz]: {_currentGenesis.RadioFrequencyMhz}");
}
lblConnectPcb.ForeColor = Color.Green;
CheckUpdateEnabled();
LogPcAndCordonelTime();
LogInstalledMeterFw();
}));
}).ContinueWith(delegate
{
ViewProgressPcb(false);
});
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
LogErrorText(ex.Message);
}
}
/// <summary>
/// Wait for reboot is completed by polling of PcbId
/// </summary>
private void WaitForReboot()
{
if (_currentGenesis == null)
{
return;
}
SetActualProcessAndLog(@"Update Applications and Restart Meter");
ViewProcessControl(true);
//wait until meter update is completed and meter is re-booted
const Double maxBootDelayMs = 10000.0;
const Double loopDelayMs = 200.0;
var bootDelayMs = 0.0;
var text = "";
while (bootDelayMs < maxBootDelayMs && string.IsNullOrEmpty(text))
{
SetTimeDisplay();
text = RegisterConverter.ByteArrayToValue<String>(
_currentGenesis.ReadRegister(Register.Configexchange.PcbSerialNumber, 12));
barOverallProgressUpdate.Value =
barOverallProgressUpdate.Value + 4 > 100 ? 0 : barOverallProgressUpdate.Value + 4;
var bootProcess = (Int32)(bootDelayMs * 100.0 / maxBootDelayMs);
barSingleProgressUpdate.Value = barSingleProgressUpdate.Value + bootProcess > 100
? 0
: barSingleProgressUpdate.Value + bootProcess;
Update();
bootDelayMs += loopDelayMs;
Thread.Sleep((Int32)loopDelayMs);
}
//add a blank line to separate next operation
LogText("");
ViewProcessControl(false);
}
#endregion
#region ProcessControls
private void LowLevelActionControl(Boolean isActive)
{
if (isActive)
{
Invoke(new Action(() =>
{
ViewProcessControl(true);
tmrProgressUpdate.Enabled = true;
_progressBarOn = true;
}));
}
else
{
Invoke(new Action(() =>
{
ViewProcessControl(false);
_progressBarOn = false;
}));
}
}
private void RebootControl(Boolean isActive)
{
if (isActive)
{
Invoke(new Action(() =>
{
ViewProcessControl(true);
tmrProgressUpdate.Enabled = true;
}));
}
else
{
Invoke(new Action(() =>
{
ViewProcessControl(false);
if (_rebootSucceeded)
{
WaitForReboot();
btnConnect_Click(this, null);
}
else
{
var msg = @"Reboot failed!";
LogText(msg);
MessageBoxShow(msg, @"FAILED", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}));
}
}
private void ViewProgressPcb(Boolean isActive)
{
if (_updateGui)
{
if (isActive)
{
Invoke(new Action(() =>
{
_tryConnectPcb = true;
ViewProcessControl(true);
}));
}
else
{
Invoke(new Action(() =>
{
_tryConnectPcb = false;
ViewProcessControl(false);
}));
}
}
}
/// <summary>
/// View all process bars and labels
/// </summary>
private void ViewProcessControl(Boolean view)
{
if (view)
{
lblActualProcess.Visible = true;
lblOverall.Visible = true;
barOverallProgressUpdate.Visible = true;
barSingleProgressUpdate.Visible = true;
//_lastFwUpdateState = "";
tmrProgressUpdate.Enabled = true;
SetControlsLowLevelOpOngoing();
}
else
{
lblActualProcess.Visible = false;
lblOverall.Visible = false;
barOverallProgressUpdate.Visible = false;
barSingleProgressUpdate.Visible = false;
tmrProgressUpdate.Enabled = false;
//_lastFwUpdateState = "";
lblWaitingForMeterResponse.Visible = false;
lblActualProcess.Text = "";
lblOverall.Text = "";
SetControlsLowLevelOpIsFinished();
}
//common actions and settings
lblActualProcess.Update();
lblOverall.Update();
barOverallProgressUpdate.Value = 0;
barOverallProgressUpdate.Update();
barSingleProgressUpdate.Value = 0;
barSingleProgressUpdate.Update();
Update();
}
private void StartStopDownload(Boolean isActive)
{
if (isActive)
{
Invoke(new Action(() =>
{
//_lastFwUpdateState = "";
ViewProcessControl(true);
tmrProgressUpdate.Enabled = true;
}));
}
else
{
Invoke(new Action(() => { ViewProcessControl(false); }));
}
}
/// <summary>
/// Display installed meter FW.
/// </summary>
/// <remarks date="2022-Mar-25" author="Thomas Wiedebusch">
/// - Init.
/// </remarks>
private void LogInstalledMeterFw()
{
if (_currentGenesis == null)
{
return;
}
LogText(StrSeparator);
LogText($"PCB ID: {_currentGenesis.PcbId}");
LogText($"Core Version: {_currentGenesis.StrCoreRevision}");
LogText("");
LogText("Installed Applications:");
foreach (var app in _currentGenesis.MeterAppListVersion)
{
var versionString =
app.IsInstalled ? $"V: {app.StrVersion} - CRC: 0x{app.Crc:X4}" : "App NOT Installed";
if (app.Status == MeterAppState.Unknown)
versionString = "COMMUNICATION ERROR";
LogText($"AppId: 0x{app.AppId:X2} - {versionString} - " + $"AppName: {app.AppName}");
if (app.IsInstalled)
{
var appVersion = new CordonelAppVersion(app.AppId, app.StrVersion);
// Copy metrology update permission
if (app.AppName == MetrologyDefinition.MetrologyName &&
_currentGenesis.MetrologyUpgradePermission != MetrologyDefinition.MetrologyUpgradePermitted)
{
appVersion.IsUpdateable = false;
}
}
}
LogText(StrSeparator);
}
/// <summary>
/// Calculate and log the PC and Cordonel time.
/// </summary>
/// <remarks date="2023-Jan-02" author="Thomas Wiedebusch">
/// - Init.
/// </remarks>
private void LogPcAndCordonelTime()
{
if (_currentGenesis == null)
{
return;
}
_currentGenesis.ReLogin();
var dt = DateTime.UtcNow;
var msg = $@"{dt:yyyy-MM-dd HH:mm:ss} UTC";
LogText($@"PC date time: {msg}");
CalculateMeterDateTime(RegisterConverter.ByteArrayToValue<Int32>(
_currentGenesis.ReadRegister("SYSTEM_CalendarSeconds")));
//add a blank line to separate next operation
LogText("");
_currentGenesis.Logout();
}
/// <summary>
/// Calculate and log Cordonel time.
/// </summary>
/// <remarks date="2023-Jan-06" author="Thomas Wiedebusch">
/// - Init.
/// </remarks>
/// <remarks date="2023-Jul-19" author="Thomas Wiedebusch">
/// - Used <see cref="TimeT"/> to calculate time in UTC based on 01. Jan 2000
/// and the given offset in seconds.
/// </remarks>
private void CalculateMeterDateTime(Int32 secSince2000)
{
var meterDateTime = new TimeT { SecondsSince2000 = secSince2000 };
var msg = meterDateTime.ToString();
Invoke(new Action(() => { tbxDateTime.Text = msg; }));
LogText($@"Meter date time: {msg}");
}
/// <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>
/// 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);
}
/// <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
#region Tools
private void CheckUpdateEnabled()
{
//this check has been placed here to force display update
if (_meterFile != null && _currentGenesis != null)
{
SetCordonelAccessEnabled();
return;
}
SetCordonelAccessLocked();
}
/// <summary>
/// List all meter files
/// </summary>
/// <remarks date="2023-Jan-14" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private List<String> ListMeterFiles()
{
SetActualProcessAndLog(@"List meter files drive 0");
_meterFile.ReadMeterFileCatalog(out var fileNamesDrive0, MeterFile.StrMeterDrive0);
if (fileNamesDrive0.Count == 0)
{
LogText(@"Could not read drive 0");
}
else
{
foreach (var fileName in fileNamesDrive0)
{
LogText(fileName);
}
}
SetActualProcessAndLog(@"List meter files drive 1");
_meterFile.ReadMeterFileCatalog(out var fileNamesDrive1, MeterFile.StrMeterDrive1);
if (fileNamesDrive1.Count == 0)
{
LogText(@"Could not read drive 1");
}
else
{
foreach (var fileName in fileNamesDrive1)
{
LogText(fileName);
}
}
var fileNames = new List<String>();
fileNames.AddRange(fileNamesDrive0);
fileNames.AddRange(fileNamesDrive1);
return fileNames;
}
/// <summary>
/// Read engineering log files from meter and analyzes the contents.
/// </summary>
/// <remarks date="2023-Aug-15" author="Roland Drabesch/Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void ReadLogFiles(String logFileName = null)
{
if (_currentGenesis == null)
{
return;
}
if (_meterFile == null)
{
_meterFile = new MeterFile(_currentGenesis);
}
var statusMap = new Dictionary<Int32, String>();
if (File.Exists("Status.json"))
{
var dict = JsonConvert.DeserializeObject<Dictionary<String, JObject>>(File.ReadAllText("Status.json"));
if (dict != null)
{
foreach (var item in dict)
{
if (item.Value.First != null)
{
statusMap.Add(int.Parse(item.Value.First.Values().First().ToString()), item.Key);
}
}
}
}
Task.Factory.StartNew(() =>
{
_currentGenesis.ReLogin();
var fileNames = ListLogFiles(logFileName);
var rawDic = new List<Tuple<string, string>>();
foreach (var fileName in fileNames)
{
SetActualProcessAndLog($@"Reading and analyzing {fileName}", logFileName);
var success = _meterFile.ReadMeterFile(fileName, out var data);
if (!success)
{
_currentGenesis.Logout();
_currentGenesis.ReLogin();
}
if (data.Count > 0)
{
LogText($"Data: {ByteArrayStyle.ByteStyler.ToString(data.ToArray())}", logFileName);
}
if (data.Count >= 5)
{
for (var ctr = 0; ctr < data.Count;)
{
var logType = data[ctr];
var status = (data[ctr + 2] << 8) + data[ctr + 1];
var count = data[ctr + 3] + 1;
var extraDataSize = data[ctr + 4];
String msg;
switch (logType)
{
case 0:
msg = $"({logType}) Informational";
break;
case 1:
msg = $"({logType}) Warning";
break;
case 2:
msg = $"({logType}) Critical";
break;
default:
msg = $"({logType}) Unknown log type";
break;
}
LogText($"Log type: {msg}", logFileName);
LogText(statusMap.ContainsKey(status)
? $"Status: ({status}) {statusMap[status]}"
: $"Status: {status}", logFileName);
LogText($"Count: {count}", logFileName);
LogText($"Extra data size: {extraDataSize}", logFileName);
//avoid access beyond the buffer and check for data to display
if (ctr + 5 + extraDataSize < data.Count && extraDataSize > 0)
{
var extraData = data.GetRange(ctr + 5, extraDataSize);
LogText($"Extra data: {ByteArrayStyle.ByteStyler.ToString(extraData.ToArray())}", logFileName);
if (status == 261)
{
rawDic.Add(new Tuple<string, string>(fileName, ByteArrayStyle.ByteStyler.ToString(extraData.ToArray())));
}
}
LogText("", logFileName);
ctr += (5 + extraDataSize);
//exit if index for next run is out of range
if (ctr + 5 >= data.Count)
{
break;
}
}
}
else
{
LogText("File is empty", logFileName);
}
//foreach (var rawBat in rawDic)
//{
//}
}
var sb = new StringBuilder();
foreach (var rawBat in rawDic)
{
var dateSec = Convert.ToInt32(rawBat.Item1.Substring(2, rawBat.Item1.Length - 2), 16);
var dt = new DateTime(2000, 01, 01).AddSeconds(dateSec);
//var dateByte = ByteArrayStyle.ByteStyler.Parse(,false);
sb.AppendLine($"{dt};{rawBat.Item2}");
}
File.AppendAllLines(logFileName + "BAT.CSV", new[] { sb.ToString() });
}).ContinueWith(delegate
{
//add a blank line to separate next operation
LogText("", logFileName);
_currentGenesis.Logout();
LowLevelActionControl(false);
});
}
/// <summary>
/// List all meter log files covered by the log index file
/// </summary>
/// <remarks date="2023-Jan-14" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private List<String> ListLogFiles(String logFileName = null)
{
SetActualProcessAndLog(@"Flushing the logger");
_currentGenesis.WriteRegister("LOGGER_TriggerLogFlush", 1);
CalculateMeterDateTime(RegisterConverter.ByteArrayToValue<Int32>(
_currentGenesis.ReadRegister("SYSTEM_CalendarSeconds")));
SetActualProcessAndLog(@"Reading log index file");
_meterFile.ReadMeterFile(MeterFile.StrMeterEngLogIndexFile, out var data);
var fileNames = new List<String>();
var rawData = data.ToArray();
var sample = new Byte[4];
for (var ctr = 0; ctr < data.Count; ctr += 4)
{
for (var x = 0; x < 4; x++)
{
sample[x] = rawData[ctr + x];
}
var name = $"1\\{RegisterConverter.ByteArrayToValue<Int32>(sample):X8}";
LogText($"Log file catalogue: {name}", logFileName);
fileNames.Add(name);
}
LogText("", logFileName);
fileNames.Sort();
return fileNames;
}
/// <summary>
/// Analyze all meter files
/// </summary>
/// <remarks date="2023-Jan-14" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void AnalyzeMeterFiles(List<String> meterFiles)
{
if (meterFiles.Count == 0)
{
return;
}
LogText("Analyzing meter files");
foreach (var fileName in meterFiles)
{
Invoke(new Action(() => { lblActualProcess.Text = $@"Analyze file {fileName}"; }));
var success = _meterFile.GetFileSize(fileName, out var fileSize);
LogText(success
? $@"File name: {fileName}, File size: {fileSize} byte"
: $@"File name: {fileName} Unable to access file");
if (success)
{
continue;
}
_currentGenesis.Logout();
_currentGenesis.ReLogin();
}
}
#endregion
#region Events
/// <summary>
/// Process update event for displaying messages in history window
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2020-Dec-10" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
public virtual void ProcessUpdate_Event(Object sender, ProcessExecEventArgs e)
{
LogText(e.OverallProcessMessage);
}
#endregion
#region TimerControls
private void tmrProgressUpdate_Tick(Object sender, EventArgs e)
{
//cbxManualControl.Visible = true;
if (_tryConnectPcb || _progressBarOn)
{
barOverallProgressUpdate.Value =
barOverallProgressUpdate.Value + 1 > 100 ? 0 : barOverallProgressUpdate.Value + 1;
barSingleProgressUpdate.Value =
barSingleProgressUpdate.Value + 4 > 100 ? 0 : barSingleProgressUpdate.Value + 4;
}
else if (_meterResetProcessActive)
{
lblActualProcess.Text = _meterResetPsu?.GetActualOperation();
barOverallProgressUpdate.Value =
barOverallProgressUpdate.Value + 1 > 100 ? 0 : barOverallProgressUpdate.Value + 1;
barOverallProgressUpdate.Update();
var singleProgress = (Int32)(_meterResetPsu?.SingleFileProcessCtrPercent ?? 0);
barSingleProgressUpdate.Value = singleProgress > 100 ? 100 : singleProgress;
//_lastSingleProgress = singleProgress;
barSingleProgressUpdate.Update();
}
SetTimeDisplay();
Update();
}
private void SetTimeDisplay()
{
var time = DateTimeOffset.UtcNow;
var timeSpan = time - _startTime;
lblUpdateTime.Text = $@"{(UInt32)timeSpan.TotalMinutes}:{timeSpan.Seconds:00}";
}
#endregion
#region ExternalCalls
/// <summary>
///
/// </summary>
public MsgEventArgs LastMsgEvent;
/// <inheritdoc />
public class MsgEventArgs : EventArgs
{
/// <summary>
/// Text to display
/// </summary>
public String Text;
/// <summary>
/// Headline
/// </summary>
public String Caption;
/// <summary>
/// Buttons
/// </summary>
public MessageBoxButtons Buttons;
/// <summary>
/// Icon
/// </summary>
public MessageBoxIcon Icon;
}
/// <summary>
/// Message pop up event handler
/// </summary>
public event EventHandler<MsgEventArgs> OnMsgPopUp;
private void MessageBoxShow(String text, String caption, MessageBoxButtons buttons, MessageBoxIcon icon)
{
if (_updateGui)
{
MessageBox.Show(text, caption, buttons, icon);
}
else
{
LastMsgEvent = new MsgEventArgs() { Text = text, Caption = caption, Buttons = buttons, Icon = icon };
OnMsgPopUp?.Invoke(this, LastMsgEvent);
}
}
#endregion
#region Buttons
private void btnConnect_Click(Object sender, EventArgs e)
{
if (_resetTimeMeasurement)
{
_startTime = DateTimeOffset.UtcNow;
_resetTimeMeasurement = false;
}
Connect();
}
/// <summary>
/// Releases the display to normal operation
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2022-Dec-20" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void btnClearDisplay_Click(Object sender, EventArgs e)
{
if (_currentGenesis == null)
{
return;
}
SetActualProcessAndLog(@"Set display of meter to normal operation");
LowLevelActionControl(true);
_currentGenesis.ReLogin();
_currentGenesis.SetLcdText(true, new Byte[] { 0x00, 0x00, 0x00, 0x00 });
_currentGenesis.WriteRegister(Register.Genesisflow.StoreConfiguration, 1);
//add a blank line to separate next operation
LogText("");
_currentGenesis.Logout();
LowLevelActionControl(false);
}
/// <summary>
/// Set battery dependencies
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2022-Dec-20" author="Roland Drabesch">
/// - Initial
/// </remarks>
/// <remarks date="2024-Aug-15" author="Roland Drabesch">
/// - Store configuration of POWERMON.
/// </remarks>
private void btnFixBattery_Click(Object sender, EventArgs e)
{
if (_currentGenesis == null)
{
return;
}
//reset timer
_startTime = DateTimeOffset.UtcNow;
var msg = @"Fix battery settings";
LogText(msg);
lblOverall.Text = msg;
LowLevelActionControl(true);
_currentGenesis.ReLogin();
SetActualProcessAndLog(@"Seal display for time of setup");
_currentGenesis.WriteRegister("GENESISFLOW_SealDisplay", (UInt32)0);
SetActualProcessAndLog(@"Reset alarms in meter");
_currentGenesis.ResetAlarm(GenesisMeter.Alarm.ALL);
SetActualProcessAndLog(@"Set project end time to meter");
_currentGenesis.WriteRegister("POWERMON_WarnFromClamp", (UInt32)630720000); // 20 years in seconds
SetActualProcessAndLog(@"Set meter battery quantity to 2");
_currentGenesis.WriteRegister("POWERMON_BatteryQuantity", (UInt32)2);
SetActualProcessAndLog(@"Store configuration POWERMON");
_currentGenesis.WriteRegister("POWERMON_StoreConfiguration", (UInt32)1);
SetActualProcessAndLog(@"Trigger idle to release function to normal operation");
_currentGenesis.WriteRegister("GENESISFLOW_TriggerIdle", (UInt32)0);
//add a blank line to separate next operation
LogText("");
_currentGenesis.Logout();
LowLevelActionControl(false);
// reboot the meter to take the new settings
btnRebootMeter_Click(this, null);
}
/// <summary>
/// Store all configurations
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2022-Dec-20" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void btnStoreConfiguration_Click(Object sender, EventArgs e)
{
if (_currentGenesis == null)
{
return;
}
//reset timer
_startTime = DateTimeOffset.UtcNow;
var msg = @"Store all configurations in meter";
LogText(msg);
lblActualProcess.Text = msg;
LowLevelActionControl(true);
_currentGenesis.ReLogin();
_currentGenesis.StoreAllConfigurations();
//add a blank line to separate next operation
LogText("");
_currentGenesis.Logout();
LowLevelActionControl(false);
}
/// <summary>
/// Reboot the meter
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2022-Aug-11" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void btnRebootMeter_Click(Object sender, EventArgs e)
{
if (_currentGenesis == null)
{
return;
}
//reset timer
_startTime = DateTimeOffset.UtcNow;
var msg = @"Reboot meter with pseudo FW update";
LogText(msg);
lblOverall.Text = msg;
// clear display before store configuration will include store all configurations
btnClearDisplay_Click(this, null);
_meterResetPsu = new MeterResetPsu(_currentGenesis)
{
StoreConfigEnable = false
};
_meterResetProcessActive = true;
SetControlsLowLevelOpOngoing();
RebootControl(true);
Task.Factory.StartNew(() =>
{
_rebootSucceeded = _meterResetPsu.MeterResetPsuExecute();
Thread.Sleep(1000);
_meterResetProcessActive = false;
}).ContinueWith(delegate
{
RebootControl(false);
_meterResetPsu.Dispose();
});
}
/// <summary>
/// Read config file from meter and store it to disk.
/// </summary>
/// <remarks date="2023-Jan-02" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void btnUploadConfig_Click(Object sender, EventArgs e)
{
if (_currentGenesis == null)
{
return;
}
if (_meterFile == null)
{
_meterFile = new MeterFile(_currentGenesis);
}
//reset timer
_startTime = DateTimeOffset.UtcNow;
LowLevelActionControl(true);
var msg = @"Upload configuration file from meter";
LogText(msg);
lblOverall.Text = msg;
lblActualProcess.Text = @"Read config file";
var rawData = new List<Byte>();
Task.Factory.StartNew(() =>
{
_currentGenesis.ReLogin();
_meterFile.ReadMeterFile(MeterFile.StrMeterConfigFile, out var data);
rawData.AddRange(data);
}).ContinueWith(delegate
{
Invoke(new Action(() =>
{
if (saveConfigFile.ShowDialog() == DialogResult.OK)
{
var fs = new FileStream(saveConfigFile.FileName, FileMode.OpenOrCreate);
var bw = new BinaryWriter(fs);
foreach (var t in rawData)
{
bw.Write(t);
}
fs.Close();
}
}));
//add a blank line to separate next operation
LogText("");
_currentGenesis.Logout();
LowLevelActionControl(false);
});
}
/// <summary>
/// Read power correction information.
/// </summary>
/// <remarks date="2024-May-15" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void btnReadPowCorr_Click(Object sender, EventArgs e)
{
if (_currentGenesis == null)
{
return;
}
if (_meterPowCorrFile == null)
{
_meterPowCorrFile = new MeterPowerCorrectionFile(_currentGenesis);
}
//reset timer
_startTime = DateTimeOffset.UtcNow;
LowLevelActionControl(true);
var msg = @"Upload power correction file from meter";
LogText(msg);
lblOverall.Text = msg;
lblActualProcess.Text = @"Read power correction file";
Task.Factory.StartNew(() =>
{
_currentGenesis.ReLogin();
if (_meterPowCorrFile.ReadPowCorrMeterFile())
{
foreach (var line in _meterPowCorrFile.FileContent)
{
LogText(line);
}
}
else
{
LogText(@"Power correction file not existing!");
}
}).ContinueWith(delegate
{
//add a blank line to separate next operation
LogText("");
_currentGenesis.Logout();
LowLevelActionControl(false);
});
}
/// <summary>
/// Read config file from meter and store it to disk.
/// </summary>
/// <remarks date="2024-Jan-?" author="Roland Drabesch">
/// - Initial
/// </remarks>
/// <remarks date="2024-Jun-03" author="Roland Drabesch">
/// - Redirect pwd hash to logging window.
/// </remarks>
private void btnUploadPasswordFile_Click(Object sender, EventArgs e)
{
if (_currentGenesis == null)
{
return;
}
if (_meterFile == null)
{
_meterFile = new MeterFile(_currentGenesis);
}
//reset timer
_startTime = DateTimeOffset.UtcNow;
LowLevelActionControl(true);
var msg = @"Upload hashed password file from meter:";
LogText(msg);
lblOverall.Text = msg;
lblActualProcess.Text = @"Read password file";
Task.Factory.StartNew(() =>
{
_currentGenesis.ReLogin();
var retVal = _meterFile.ReadMeterFile(MeterPwdFile.StrPasswordFileName, out var hashedMeterPwdFile);
// Separate all hashed passwords for logging each in an individual line
var hashedPwdList = new List<String>();
if (retVal && hashedMeterPwdFile != null && hashedMeterPwdFile.Count > 0)
{
for (var idx = 0; idx < hashedMeterPwdFile.Count; idx += MeterPwdDb.HashedPwdLength)
{
var hashedPwd = BitConverter.ToString(hashedMeterPwdFile.GetRange(idx,
MeterPwdDb.HashedPwdLength).ToArray());
hashedPwdList.Add(hashedPwd);
}
foreach (var line in hashedPwdList)
{
LogText(line);
}
}
else
{
LogText(@"Password file not existing!");
}
}).ContinueWith(delegate
{
//add a blank line to separate next operation
LogText("");
_currentGenesis.Logout();
LowLevelActionControl(false);
});
}
/// <summary>
/// Set date and time from PC to Cordonel
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2022-Dec-23" author="Roland Drabesch">
/// - Initial
/// </remarks>
private void btnSetDateTime_Click(Object sender, EventArgs e)
{
if (_currentGenesis == null)
{
return;
}
var msg = @"Set actual PC date and time in UTC";
LogText(msg);
lblOverall.Text = msg;
SetActualProcessAndLog(@"Set seconds since 2000-01-01 00:00:00 to meter");
LowLevelActionControl(true);
_currentGenesis.ReLogin();
var ts = DateTimeOffset.UtcNow - new DateTimeOffset(2000, 1, 1, 0, 0, 0, new TimeSpan(0));
_currentGenesis.WriteRegister("SYSTEM_CalendarSeconds", Convert.ToInt32(ts.TotalSeconds));
LogPcAndCordonelTime();
//add a blank line to separate next operation
LogText("");
// SYSTEM does not support store configuration, just logout
_currentGenesis.Logout();
LowLevelActionControl(false);
}
/// <summary>
/// Get date and time from PC and Cordonel and record it
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2022-Dec-23" author="Roland Drabesch">
/// - Initial
/// </remarks>
private void btnGetDateTime_Click(Object sender, EventArgs e)
{
LogPcAndCordonelTime();
}
/// <summary>
/// Read engineering log files from meter and analyzes the contents.
/// </summary>
/// <remarks date="2023-Jan-04" author="Roland Drabesch/Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void btnReadLogFiles_Click(Object sender, EventArgs e)
{
if (_currentGenesis == null)
{
return;
}
if (_meterFile == null)
{
_meterFile = new MeterFile(_currentGenesis);
}
//reset timer
_startTime = DateTimeOffset.UtcNow;
LowLevelActionControl(true);
var msg = @"Upload engineering log file from meter";
LogText(msg);
lblOverall.Text = msg;
ReadLogFiles();
}
/// <summary>
/// Collect life time information and production status.
/// </summary>
/// <remarks date="2023-Jan-04" author="Roland Drabesch/Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void btnReadLogFilesBattery_Click(Object sender, EventArgs e)
{
if (_currentGenesis == null)
{
return;
}
if (_meterFile == null)
{
_meterFile = new MeterFile(_currentGenesis);
}
//reset timer
_startTime = DateTimeOffset.UtcNow;
LowLevelActionControl(true);
var msg = @"Collect all information";
LogText(msg);
lblOverall.Text = msg;
var filename = $"LogAndCurrentBattery_{_currentGenesis.PcbId}_Station-{ddlLocation.Items[ddlLocation.SelectedIndex]}.log";
File.AppendAllLines(filename, _frmHistory.rtbHistory.Lines);
LogText($"Station: {ddlLocation.Items[ddlLocation.SelectedIndex]}", filename);
var dt = DateTime.UtcNow;
msg = $@"{dt:yyyy-MM-dd HH:mm:ss} UTC";
LogText($@"PC date time: {msg}", filename);
_currentGenesis.ReLogin();
var genesisStatus = new GenesisStatus();
if (GenesisStatusHandler.BuildLifeTimeInformation(_currentGenesis, genesisStatus))
{
var sbMSG = new StringBuilder();
sbMSG.AppendLine($"Pcb = {_currentGenesis.PcbId}");
sbMSG.AppendLine($"POWERMON_TotalUsedSeconds = {genesisStatus.ExceededLifeTime_s}");
sbMSG.AppendLine($"POWERMON_TotalUsedCharge = {genesisStatus.DrainedBatteryLoad_uAs}");
sbMSG.AppendLine($"POWERMON_BatteryQuantity = {genesisStatus.BatteryQuantity}");
sbMSG.AppendLine($"POWERMON_BatteryMilliAHrRating = {genesisStatus.InitialBatteryLoad_mAh}");
sbMSG.AppendLine("");
sbMSG.AppendLine($"Remaining life time in years {genesisStatus.RemainingLifeTimeYears:F2}");
sbMSG.AppendLine($"Totally drained battery load in % {genesisStatus.DrainedBatteryLoadPercent:F2}");
LogText(sbMSG.ToString(), filename);
}
ReadLogFiles(filename);
try
{
var resp = LocalWebRequest.GetRequest($"http://10.49.40.25/MeterProcessState/api/FinalCheck/GetKitronProductionResults?PcbID={_currentGenesis.PcbId}", 8000);
LogText(resp, filename);
var sbRegister = new StringBuilder();
var Ledmode = RegisterConverter.ByteArrayToValue<UInt16>(_currentGenesis.ReadRegister("GENESISFLOW_LedMode"));
var SampleRate = RegisterConverter.ByteArrayToValue<UInt16>(_currentGenesis.ReadRegister("GENESISFLOW_SampleRate"));
sbRegister.AppendLine($"LedMode is {Ledmode}");
sbRegister.AppendLine($"SampelRate is {SampleRate}");
if (Ledmode != 0)
{
_currentGenesis.WriteRegister("GENESISFLOW_LedMode", 0);
sbRegister.AppendLine($"Change Led mode to Customermode (0)");
}
if (SampleRate != 2)
{
_currentGenesis.WriteRegister("GENESISFLOW_SampleRate", 2);
sbRegister.AppendLine($"Change SampleRate mode to Customermode (2)");
}
}
catch (Exception exception)
{
_currentGenesis.WriteLog(exception.Message);
}
}
/// <summary>
/// List file details from meter.
/// </summary>
/// <remarks date="2023-Jan-14" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void btnListFileDetails_Click(Object sender, EventArgs e)
{
if (_currentGenesis == null)
{
return;
}
if (_meterFile == null)
{
_meterFile = new MeterFile(_currentGenesis);
}
//reset timer
_startTime = DateTimeOffset.UtcNow;
LowLevelActionControl(true);
var msg = @"List file details of meter";
LogText(msg);
lblOverall.Text = msg;
Task.Factory.StartNew(() =>
{
_currentGenesis.ReLogin();
var fileNames = ListMeterFiles();
AnalyzeMeterFiles(fileNames);
}).ContinueWith(delegate
{
//add a blank line to separate next operation
LogText("");
_currentGenesis.Logout();
LowLevelActionControl(false);
});
}
/// <summary>
/// Tidy the file system:
/// - Erasing upgrade files left over from unsuccessfully FW update,
/// - Erase logging files for versions not covered by the actual region as
/// during development a reprogramming from EMEA to NA and vice versa will
/// leave the logs for thr other version in,
/// - Remove the test file for EMEA, as this is the placeholder for the FW
/// update over the air to keep the space reserved for this process (250 kB),
/// - Keep important files listed in the log index.
/// </summary>
/// <remarks date="2023-Jan-14" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void btnTidyFile_Click(Object sender, EventArgs e)
{
if (_currentGenesis == null)
{
return;
}
if (_meterFile == null)
{
_meterFile = new MeterFile(_currentGenesis);
}
//reset timer
_startTime = DateTimeOffset.UtcNow;
LowLevelActionControl(true);
var msg = @"Tidy file system";
LogText(msg);
lblOverall.Text = msg;
Task.Factory.StartNew(() =>
{
_currentGenesis.ReLogin();
// catalogue before cleaning
SetActualProcessAndLog(@"List meter files before cleaning");
// build file erase candidates for all releases
var fileEraseCandidates = new List<String>();
// put initially all files in as erase candidates
var meterFiles = ListMeterFiles();
AnalyzeMeterFiles(meterFiles);
fileEraseCandidates.AddRange(meterFiles);
// build list of files needed to keep
var filesToKeep = new List<String>();
filesToKeep.AddRange(MeterFile.FilesToKeep);
// for EMEA the NALogs are waste
if (_currentGenesis.Region.Contains("EMEA"))
{
LogText("EMEA version detected");
filesToKeep.AddRange(MeterFile.EmeaLogs);
}
// for EMEA the EMEALogs are waste
if (_currentGenesis.Region.Contains("NA"))
{
LogText("NA version detected");
filesToKeep.AddRange(MeterFile.NaLogs);
}
// red the log files and leave it in
var logFiles = ListLogFiles();
filesToKeep.AddRange(logFiles);
// remove files which should be kept in place
foreach (var meterFile in meterFiles)
{
foreach (var fileToKeep in filesToKeep)
{
if (meterFile.Contains(fileToKeep))
{
fileEraseCandidates.Remove(meterFile);
}
}
}
// check if something to clean
if (fileEraseCandidates.Count == 0)
{
LogText("File system is clean");
}
else
{
// erase files
foreach (var fileToErase in fileEraseCandidates)
{
Invoke(new Action(() => { lblActualProcess.Text = $@"Erase {fileToErase}"; }));
_meterFile.UnlockEraseWriteMeterFile(fileToErase);
var success = _meterFile.EraseMeterFile(fileToErase);
LogText(success
? $@"File {fileToErase} successfully erased"
: $@"File {fileToErase} erasure failed");
if (success)
{
continue;
}
_currentGenesis.Logout();
_currentGenesis.ReLogin();
}
// catalogue after cleaning
SetActualProcessAndLog(@"List meter files after cleaning");
ListMeterFiles();
LogText("File system is cleaned up");
}
}).ContinueWith(delegate
{
//add a blank line to separate next operation
LogText("");
_currentGenesis.Logout();
LowLevelActionControl(false);
});
}
/// <summary>
/// Erase a specified file
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2022-Dec-20" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void btnEraseFile_Click(Object sender, EventArgs e)
{
if (_currentGenesis == null)
{
return;
}
if (_meterFile == null)
{
_meterFile = new MeterFile(_currentGenesis);
}
//reset timer
_startTime = DateTimeOffset.UtcNow;
LowLevelActionControl(true);
var file = $@"{tbxFileToEraseDrive.Text}\{tbxFileToEraseName.Text}";
var msg = $@"Erase file {file}";
LogText(msg);
lblOverall.Text = msg;
Task.Factory.StartNew(() =>
{
_currentGenesis.ReLogin();
// erase files
_meterFile.UnlockEraseWriteMeterFile(file);
var success = _meterFile.EraseMeterFile(file);
LogText(success
? $@"File {file} successfully erased"
: $@"File {file} erasure failed");
// catalogue after cleaning
SetActualProcessAndLog(@"List meter files");
ListMeterFiles();
}).ContinueWith(delegate
{
//add a blank line to separate next operation
LogText("");
_currentGenesis.Logout();
LowLevelActionControl(false);
Invoke(new Action(() => { tbxFileToEraseName.Focus(); }));
});
}
private void tbxFileToEraseName_KeyDown(Object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
btnEraseFile_Click(this, null);
}
}
/// <summary>
/// Switch pulse mode to OFF
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2023-Mar-08" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void btnPulseModeOff_Click(Object sender, EventArgs e)
{
if (_currentGenesis == null)
{
return;
}
//reset timer
_startTime = DateTimeOffset.UtcNow;
var msg = @"Switch pulse mode OFF";
LogText(msg);
lblActualProcess.Text = msg;
LowLevelActionControl(true);
_currentGenesis.ReLogin();
_currentGenesis.WriteRegister(Register.Metrologyasst.PulseMode, 0);
_currentGenesis.WriteRegister(Register.Metrologyasst.StoreConfiguration, 1);
//add a blank line to separate next operation
LogText("");
_currentGenesis.Logout();
LowLevelActionControl(false);
}
#endregion
}
}