2217 lines
79 KiB
C#
2217 lines
79 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.Net;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using Xylem.Common.CommonCore.Configuration;
|
|
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 Register = Xylem.Common.Hardware.WaterMeter.Genesis.Registers.Register;
|
|
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 _repairPasswordEnabled;
|
|
|
|
|
|
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 = $@"GTB 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;
|
|
btnReadStatus.Enabled = false;
|
|
btnRepairPassword.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;
|
|
btnReadStatus.Enabled = true;
|
|
if (_repairPasswordEnabled)
|
|
btnRepairPassword.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;
|
|
if (!string.IsNullOrEmpty(_currentGenesis.PcbId))
|
|
SetCordonelAccessEnabled();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#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();
|
|
var sb = new StringBuilder();
|
|
if (string.IsNullOrEmpty(cbComSlot.SelectedItem.ToString()) ||
|
|
!int.TryParse(cbComSlot.SelectedItem.ToString(), out var slotNr))
|
|
{
|
|
return;
|
|
}
|
|
lblOverall.Text = @"Login to Cordonel...";
|
|
|
|
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.UseOfflinePasswords = cbxUseOfflinePwds.Checked;
|
|
_currentGenesis.SetupFromConfigFile(slotNr);
|
|
_meterBatch.AddMeter(_currentGenesis);
|
|
|
|
_currentGenesis.Configuration.UseRegisterWatchService = false;
|
|
_currentGenesis.Configuration.UseMinMaxCheck = false;
|
|
|
|
lblActualProcess.Text = @"Connecting to PCB...";
|
|
|
|
Task.Factory.StartNew(() =>
|
|
{
|
|
_meterBatch.MetersLogin();
|
|
|
|
var retValPwdBuild = MeterPwdHandlerDb.RequestPwdFileFromDb(_currentGenesis.PcbId, out var pwdContainer);
|
|
|
|
// CASE 1: - The 'production password' is the 'Lvl8 password' as the login succeeded.
|
|
|
|
if (retValPwdBuild && _currentGenesis.IsLoggedOn && pwdContainer.Skeleton.Equals(pwdContainer.Password))
|
|
{
|
|
// CASE 2: - Passwords are generated in database but password file is not installed or doesn't work.
|
|
// - The 'production password' is the 'SkeletonKey' as the login succeeded.
|
|
//
|
|
// If password file is initially not installed and the database password returned the SkeletonKey
|
|
// the login has been successfully executed with this SkeletonKey, so a repair of the password
|
|
// file needs to be enabled!
|
|
ShowPasswordRepairMessage(@"Password exists on database but the SkeletonKey is valid - [Repair Password] enabled");
|
|
}
|
|
|
|
if (!_currentGenesis.IsLoggedOn)
|
|
{
|
|
// This is needed from meter as an unsuccessful login requires a delay for the next trial
|
|
Thread.Sleep(2000);
|
|
// Try to log in with password level 8 which may not be published to the database
|
|
var retVal = _currentGenesis.Login(Encoding.UTF8.GetString(pwdContainer.ListOfPasswords.Last()));
|
|
|
|
// CASE 3: - Passwords are generated in database and correctly installed. The login check will be done
|
|
// with the generated password, but the 'production password' is still the 'SkeletonKey'.
|
|
// - The database update of the production password went wrong!
|
|
if (_currentGenesis.IsLoggedOn && retVal)
|
|
{
|
|
ShowPasswordRepairMessage(@"Password file is installed as login Lvl8 works, password in database not updated" +
|
|
"- [Repair Password] enabled");
|
|
}
|
|
else
|
|
{
|
|
sb.AppendLine("Login with LVL8 failed [M1]!");
|
|
}
|
|
|
|
if (!_currentGenesis.IsLoggedOn)
|
|
{
|
|
// This is needed from meter as an unsuccessful login requires a delay for the next trial
|
|
Thread.Sleep(4000);
|
|
// CASE 4: - The production password didn't work, so the SkeletonKey will be tried.
|
|
if (_currentGenesis.Login(pwdContainer.Skeleton))
|
|
{
|
|
ShowPasswordRepairMessage(@"Successfully logged in with SkeletonKey - [Repair Password] enabled");
|
|
}
|
|
else
|
|
{
|
|
sb.AppendLine(@"Login with Skeleton failed [M2]!");
|
|
}
|
|
|
|
if (!retValPwdBuild)
|
|
{
|
|
sb.AppendLine(@"Unable to build password file [E0]!");
|
|
}
|
|
else if (_currentGenesis.Region.Equals("NA"))
|
|
{
|
|
// var url = ServiceUrls.GetExportDataServiceUrl();
|
|
// var retStr = LocalWebRequest.GetRequestWithError(url + _currentGenesis.PcbId, out var errorCode, 30000);
|
|
// if (errorCode == HttpStatusCode.OK.GetHashCode())
|
|
// {
|
|
// var retExport = JsonConvert.DeserializeObject<List<PwdExport>>(retStr);
|
|
// if (retExport.Count == 0)
|
|
// {
|
|
// sb.AppendLine(@"Export entry hasn't been found [E1]");
|
|
// //request
|
|
// sb.AppendLine(@"Export returns no password [E2]");
|
|
// }
|
|
// else
|
|
// {
|
|
// if (retExport.Count == 1)
|
|
// {
|
|
// sb.AppendLine(@"Found export entry");
|
|
// }
|
|
// else
|
|
// {
|
|
// sb.AppendLine(@"More than one export entry was found [E4]");
|
|
// }
|
|
|
|
// foreach (var item in retExport)
|
|
// {
|
|
// if (item.PWD == pwdContainer.Password)
|
|
// {
|
|
// sb.AppendLine($"{item.ID} is Password LVL 8");
|
|
// }
|
|
// else if (item.PWD == pwdContainer.Skeleton)
|
|
// {
|
|
// sb.AppendLine($"{item.ID} is Skeleton [E3]");
|
|
// }
|
|
// else
|
|
// {
|
|
// sb.AppendLine($"{item.ID} is not LVL 8 or Skeleton [E3]");
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
//}
|
|
|
|
MessageBox.Show(sb.ToString());
|
|
}// use skeletonKey
|
|
// Retry login if not skeletonKey
|
|
else
|
|
{
|
|
_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:\t" + _currentGenesis.FwVersion);
|
|
LogText("Meter LUT CRC:\t" + _currentGenesis.LutCrc);
|
|
LogText("Meter Size:\t" + _currentGenesis.MeterSize);
|
|
LogText("Meter Region:\t" + _currentGenesis.Region);
|
|
if (_currentGenesis.RadioFrequencyMhz != null)
|
|
{
|
|
tbxRadio.Text = $@"{_currentGenesis.RadioFrequencyMhz}";
|
|
LogText("Radio frequency:\t" + $"{_currentGenesis.RadioFrequencyMhz} MHz");
|
|
}
|
|
|
|
LogText("");
|
|
LogText("'Configuration.json' version: " + _currentGenesis.InterfaceInfo.InterfaceVersion);
|
|
lblConfigVersion.Text = @"Interface Version: " + _currentGenesis.InterfaceInfo.InterfaceVersion;
|
|
lblConfigVersion.ForeColor = _currentGenesis.InterfaceSupportsFwVersion ?
|
|
Color.Green :
|
|
Color.Red;
|
|
if (!_currentGenesis.InterfaceSupportsFwVersion)
|
|
{
|
|
var text = "INTERFACE VERSION OUTDATED!\n" +
|
|
"The loaded \'configuration.json\' " +
|
|
$"version: {_currentGenesis.InterfaceInfo.InterfaceVersion}\n" +
|
|
$"does NOT support the Cordonel FW version: {_currentGenesis.FwVersion}!";
|
|
MessageBox.Show(text, @"FAILED", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
LogText(text);
|
|
}
|
|
else
|
|
{
|
|
LogText($"\'Configuration.json\' supports installed FW version: {_currentGenesis.FwVersion}");
|
|
}
|
|
|
|
LogText("");
|
|
lblConnectPcb.ForeColor = Color.Green;
|
|
CheckUpdateEnabled();
|
|
|
|
LogPcAndCordonelTime();
|
|
LogInstalledMeterFw();
|
|
}));
|
|
}).ContinueWith(delegate
|
|
{
|
|
ViewProgressPcb(false);
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ViewProgressPcb(false);
|
|
MessageBox.Show(ex.Message, @"FAILED", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
LogErrorText(ex.Message);
|
|
// Dispose meter
|
|
_meterBatch.RemoveAllMeters();
|
|
// If meter is not already assigned to batch as the config reader may fail
|
|
_currentGenesis?.DisposeMeter();
|
|
}
|
|
}
|
|
|
|
private void ShowPasswordRepairMessage(String msg)
|
|
{
|
|
LogText(msg);
|
|
MessageBox.Show(msg);
|
|
_repairPasswordEnabled = true;
|
|
}
|
|
|
|
/// <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 :\t{_currentGenesis.PcbId}");
|
|
LogText($"Core Version:\t{_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:\t{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:\t{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}, \tFile size: {fileSize:N0} byte"
|
|
: $"File name: {fileName} Unable to access file");
|
|
if (success)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
_currentGenesis.Logout();
|
|
_currentGenesis.ReLogin();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read status
|
|
/// </summary>
|
|
/// <param name="msg"></param>
|
|
/// <remarks date="2025-Mar-15" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2025-Aug-11" author="Thomas Wiedebusch">
|
|
/// - Added FW based calculation of lifetime in years.
|
|
/// </remarks>
|
|
private Boolean BuildGenesisStatus(out String msg)
|
|
{
|
|
msg = "";
|
|
if (_currentGenesis == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (_meterFile == null)
|
|
{
|
|
_meterFile = new MeterFile(_currentGenesis);
|
|
}
|
|
|
|
_currentGenesis.ReLogin();
|
|
var sbMSG = new StringBuilder();
|
|
|
|
var genesisStatus = new GenesisStatus();
|
|
if (GenesisStatusHandler.BuildLifeTimeInformation(_currentGenesis, genesisStatus, out _))
|
|
{
|
|
sbMSG.AppendLine($"POWERMON_TotalUsedSeconds = {genesisStatus.ExceededLifeTime_s:N0}");
|
|
sbMSG.AppendLine($"POWERMON_TotalUsedCharge = {genesisStatus.DrainedBatteryLoad_uAs:N0}");
|
|
sbMSG.AppendLine($"POWERMON_BatteryQuantity = {genesisStatus.BatteryQuantity}");
|
|
sbMSG.AppendLine($"POWERMON_BatteryMilliAHrRating = {genesisStatus.InitialBatteryLoad_mAh:N0}");
|
|
sbMSG.AppendLine(genesisStatus.FwCalculatedRemainingLifeTimeYears != null ?
|
|
$"POWERMON_RemainingSeconds = {genesisStatus.FwCalculatedRemainingLifeTime_s:N0}" :
|
|
"POWERMON_RemainingSeconds = unsupported");
|
|
sbMSG.AppendLine("");
|
|
sbMSG.AppendLine($"Actual storage time: {genesisStatus.StorageMonths:F1} months");
|
|
sbMSG.AppendLine("SW estimated remaining lifetime based on average power consumption: " +
|
|
$"{genesisStatus.RemainingLifeTimeYears:F2} years");
|
|
sbMSG.AppendLine(genesisStatus.FwCalculatedRemainingLifeTimeYears != null
|
|
? "FW calculated remaining lifetime based on 'remaining seconds': " +
|
|
$"{genesisStatus.FwCalculatedRemainingLifeTimeYears:F2} years"
|
|
: "FW calculated remaining lifetime based on 'remaining seconds' unsupported by FW: " +
|
|
$"{_currentGenesis.FwVersion}");
|
|
sbMSG.AppendLine($"Totally drained battery load: {genesisStatus.DrainedBatteryLoadPercent:F2} %");
|
|
|
|
msg = sbMSG.ToString();
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
_currentGenesis.Logout();
|
|
return true;
|
|
}
|
|
#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>
|
|
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(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("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 lifetime 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);
|
|
if (BuildGenesisStatus(out msg))
|
|
{
|
|
LogText(msg, 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($"SampleRate 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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read status
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
/// <remarks date="2025-Mar-15" author="Roland Drabesch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private void btnReadStatus_Click(Object sender, EventArgs e)
|
|
{
|
|
if (BuildGenesisStatus(out var msg))
|
|
{
|
|
LogText(msg);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read status
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
/// <remarks date="2025-Mar-15" author="Roland Drabesch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2025-Sep-29..30" author="Thomas Wiedebusch">
|
|
/// - Check if new password is in the meter with login level 8 even if the file write wasn't successful,
|
|
/// - Set new password in production database,
|
|
/// - Check password level 3 as all applications need to use this,
|
|
/// - Validate production password.
|
|
/// </remarks>
|
|
private void btnRepairPassword_Click(Object sender, EventArgs e)
|
|
{
|
|
if (_currentGenesis == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Reset timer
|
|
_startTime = DateTimeOffset.UtcNow;
|
|
LowLevelActionControl(true);
|
|
|
|
var msg = "Repair password";
|
|
LogText(msg);
|
|
lblOverall.Text = msg;
|
|
|
|
Task.Factory.StartNew(() =>
|
|
{
|
|
// Request password file and force generation
|
|
SetActualProcessAndLog("Request password files from database");
|
|
var ret = MeterPwdHandlerDb.RequestPwdFileFromDb(_currentGenesis.GetPcbId(), out var pwdContainer);
|
|
if (pwdContainer?.ListOfHashes == null || pwdContainer.ListOfPasswords == null || !ret)
|
|
{
|
|
LogText(@"Password file from server corrupted [M3]!");
|
|
LowLevelActionControl(false);
|
|
return;
|
|
}
|
|
|
|
// Build password file
|
|
SetActualProcessAndLog("Build password file");
|
|
var _meterPwdFile = new MeterPwdFile(_currentGenesis);
|
|
var retValBol = _meterPwdFile.BuildPwdFile(pwdContainer.ListOfPasswords, 1, pwdContainer.Skeleton);
|
|
if (!retValBol)
|
|
{
|
|
LogText(@"Unable to build password file [M3]!");
|
|
LowLevelActionControl(false);
|
|
return;
|
|
}
|
|
|
|
// Install password file and verify byte wise
|
|
SetActualProcessAndLog("Install and verify password file into meter");
|
|
_currentGenesis.ReLogin();
|
|
retValBol = _meterPwdFile.UnlockEraseWriteMeterPwdFile();
|
|
retValBol &= _meterPwdFile.WriteMeterPwdFile() && _meterPwdFile.VerifyMeterPwdFile();
|
|
|
|
if (!retValBol)
|
|
{
|
|
LogText(@"Installed password file check failed [M4]!");
|
|
return;
|
|
}
|
|
|
|
// Check if new password is in the meter with login level 8 even if the file write wasn't successful
|
|
SetActualProcessAndLog("Validate Lvl8 password from password file");
|
|
_currentGenesis.Logout();
|
|
retValBol = _currentGenesis.Login(Encoding.UTF8.GetString(pwdContainer.ListOfPasswords.Last()));
|
|
if (!retValBol)
|
|
{
|
|
LogText(@"Login with new password failed [M4]!");
|
|
return;
|
|
}
|
|
LogText(@"Password was successfully installed.");
|
|
|
|
// Set new password in production database
|
|
SetActualProcessAndLog("Replace SkeletonKey with Lvl8 password as production password in database");
|
|
retValBol = MeterPwdHandlerDb.SetPwdFromSkeletonToLvl8inDd(_currentGenesis.PcbId, pwdContainer);
|
|
if (!retValBol)
|
|
{
|
|
LogText(@"Update of production password in database failed [E3]!");
|
|
return;
|
|
}
|
|
LogText(@"Production password successfully updated in database");
|
|
|
|
// Check password level 3 as all applications need to use this
|
|
SetActualProcessAndLog("Validate Lv3 as SkeletonKey in meter");
|
|
retValBol = _currentGenesis.WriteRegister("SYSTEM_ExitReason", new Byte[] { 21 });
|
|
var exitResult = RegisterConverter.ByteArrayToValue<Int16>(_currentGenesis.ReadRegister("SYSTEM_ExitReason"));
|
|
if (exitResult != 0 || !retValBol)
|
|
{
|
|
LogText(@"Meter reports wrong SkeletonKey at Lvl3 [M4]!");
|
|
return;
|
|
}
|
|
LogText(@"Meter reports correct SkeletonKey at Lvl3.");
|
|
|
|
// Clear intermediate stored password to force password collection from DB on simple login without
|
|
// given new password. Then the password will be taken from the DB or offline file.
|
|
SetActualProcessAndLog("Crosscheck production password with meter password Lvl8");
|
|
_currentGenesis.Logout();
|
|
_currentGenesis.ClearPassword();
|
|
|
|
// If the password is not set (Meter.ClearPassword) the actual valid production password will be
|
|
// requested from the DB in the GenesisMeter Login() without parameter.
|
|
Thread.Sleep(1000);
|
|
// Validate production password
|
|
retValBol = _currentGenesis.Login();
|
|
|
|
if (!retValBol)
|
|
{
|
|
LogText(@"Invalid password in production database [E3]!");
|
|
return;
|
|
}
|
|
LogText(@"Password Lvl8 successfully validated with production database.");
|
|
_repairPasswordEnabled = false;
|
|
}).ContinueWith(delegate
|
|
{
|
|
//add a blank line to separate next operation
|
|
LogText("");
|
|
_currentGenesis.Logout();
|
|
LowLevelActionControl(false);
|
|
});
|
|
|
|
}
|
|
|
|
private void btnConnectSkeleton_Click(Object sender, EventArgs e)
|
|
{
|
|
//if (_resetTimeMeasurement)
|
|
//{
|
|
// _startTime = DateTimeOffset.UtcNow;
|
|
// _resetTimeMeasurement = false;
|
|
//}
|
|
|
|
//Connect(true);
|
|
}
|
|
#endregion
|
|
|
|
public class PwdExport
|
|
{
|
|
public Int32 ID;
|
|
public String PWD;
|
|
public DateTime ExportDate;
|
|
|
|
public PwdExport(Int32 id, String pwd, DateTime exportDate)
|
|
{
|
|
ID = id;
|
|
PWD = pwd;
|
|
ExportDate = exportDate;
|
|
}
|
|
}
|
|
|
|
private void cbxUseOfflinePwds_CheckedChanged(Object sender, EventArgs e)
|
|
{
|
|
cbxUseOfflinePwds.ForeColor = cbxUseOfflinePwds.Checked ? Color.Red : Color.Black;
|
|
}
|
|
}
|
|
}
|
|
|