723 lines
26 KiB
C#
723 lines
26 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using Xylem.Common.CommonCore.Consts;
|
|
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
|
|
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.Consts;
|
|
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.Properties;
|
|
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
|
|
using Xylem.Common.Utils.Crc16Ccitt;
|
|
using Xylem.Common.Utils.ProcessExec;
|
|
using Xylem.Common.Utils.ProcessExec.EventArguments;
|
|
|
|
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
|
{
|
|
/// <summary>
|
|
/// Forcing a meter reset with a PSU (pseudo update):
|
|
/// 1. Taking the FLEXNETVERSION from <see cref="GenesisMeter.MeterAppListVersion"/>
|
|
/// 2. Build the file upg18 with the FLEXNETVERSION string
|
|
/// 3. Download upg18
|
|
/// 4. Build upgrade ctrl file forcing update of FLEXNETVERSION
|
|
/// 5. TriggerUpgrade
|
|
/// </summary>
|
|
public class MeterResetPsu : IProcessState
|
|
{
|
|
#region Variables
|
|
|
|
// Template of FLEXNETVERSION has to be modified for version, version string and CRC
|
|
private static readonly Byte[] TemplateUpgradeFile =
|
|
{
|
|
0x41, 0x50, 0x50, 0x3E, 0x83, 0xBA, 0x47, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x04, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,
|
|
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,
|
|
0x70, 0x47, 0x00, 0x00, 0x02, 0x49, 0x79, 0x44, 0x01, 0x60, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00,
|
|
0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x31, 0x2E, 0x32, 0x2E, 0x34, 0x37, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
// upgrade file for FLEXNETVERSION
|
|
private Byte[] _upgradeFile;
|
|
|
|
// upgrade control file content to force an update of exclusively FLEXNETVERSION
|
|
private static readonly String UpgradeCtrlFile = $"{MeterFwUpdate.FlexnetVersionAppId:X2}" +
|
|
MeterFwUpdate.StrInstallAppCtrlFilePost;
|
|
|
|
/// <summary>
|
|
/// Port scan result event for message dispatcher to caller
|
|
/// </summary>
|
|
public event EventHandler<ProcessExecEventArgs> OnProcessUpdate;
|
|
|
|
//disk and name of lookup file
|
|
private static readonly String StrFlexnetUpgradeFileName = $"1\\upg{MeterFwUpdate.FlexnetVersionAppId:X2}";
|
|
|
|
//update reties for files
|
|
private const Int32 FileWriteRetries = 1;
|
|
|
|
//trigger update retries
|
|
private const Int32 TriggerWriteRetries = 2;
|
|
|
|
//time to wait until next trial of communication during reboot
|
|
private const Int32 RebootWaitTimeMs = 250;
|
|
|
|
//reboot wait cycles to be multiplied with reboot wait time for maximum overall time if unsuccessful
|
|
private const Int32 RebootWaitCycles = 4 * 90;
|
|
|
|
//retry of entire update procedure
|
|
private const Int32 UpdateProcedureRetries = 1;
|
|
|
|
//threshold to increase the file write timing
|
|
private const Int32 IncreaseTimeoutUpdateProcedureRetries = 4;
|
|
|
|
// position of version string
|
|
private const Int32 FlexVersionStringIndex = 0x66;
|
|
|
|
private Int32 _processRetryCtr;
|
|
|
|
private IGenesisMeter _genesisMeter;
|
|
private MeterFile _meterFile;
|
|
|
|
// Text for caller to inform about actual process being carried out
|
|
private String _actualOperation;
|
|
|
|
private MeterResetPsuState _meterResetPsuState;
|
|
private MeterResetPsuState _backupMeterResetPsuState;
|
|
|
|
// number of operations for over all access
|
|
private const Int32 NumberOfOperations = 11;
|
|
private Int32 _operationCtr;
|
|
|
|
// error message for display of error reason
|
|
public String ErrorMessage;
|
|
|
|
// manual stop of update process
|
|
private Boolean _stopUpdateProcess;
|
|
|
|
/// <summary>
|
|
/// Store configuration in advance to the update
|
|
/// </summary>
|
|
public Boolean StoreConfigEnable = true;
|
|
|
|
/// <summary>
|
|
/// Threshold to waste the HW if reboots too high
|
|
/// </summary>
|
|
public const Int32 MAX_REBOOTS_FOR_HEALTHY_HW = 0;
|
|
|
|
#endregion
|
|
|
|
#region Events
|
|
|
|
/// <summary>
|
|
/// Process update event
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
protected virtual void ProcessUpdate_Event(Object sender, ProcessExecEventArgs e)
|
|
{
|
|
// copy text from overall messages to actual, because this is from sub-routine
|
|
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("reboot",
|
|
OverallProcessCtrPercent, _actualOperation, e.OverallProcessPercent));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Information
|
|
|
|
/// <summary>
|
|
/// Process counter in percent
|
|
/// </summary>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
public Double OverallProcessCtrPercent => 100.0 * _operationCtr / NumberOfOperations;
|
|
|
|
/// <summary>
|
|
/// Single file process counter in percent
|
|
/// </summary>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
public Double SingleFileProcessCtrPercent => _meterFile?.ProcessCtrPercent ?? 0;
|
|
|
|
#endregion
|
|
|
|
#region CtorAssignment
|
|
|
|
/// <summary>
|
|
/// Ctor
|
|
/// </summary>
|
|
/// <param name="genesisMeter"></param>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
public MeterResetPsu(IGenesisMeter genesisMeter)
|
|
{
|
|
if (genesisMeter == null)
|
|
return;
|
|
AssignGenesis(genesisMeter);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Assign new genesis
|
|
/// </summary>
|
|
/// <param name="genesisMeter"></param>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
public void AssignGenesis(IGenesisMeter genesisMeter)
|
|
{
|
|
_genesisMeter = genesisMeter;
|
|
_actualOperation = "";
|
|
_meterResetPsuState = MeterResetPsuState.Idle;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dispose
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
if (_meterFile == null)
|
|
return;
|
|
_meterFile.OnProcessUpdate -= ProcessUpdate_Event;
|
|
_meterFile = null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ProcessInformation
|
|
|
|
/// <summary>
|
|
/// Returns the actual file in process for update
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
public String GetActualOperation()
|
|
{
|
|
return _actualOperation;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the LUT Update state
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
public String GetResetStateOperation()
|
|
{
|
|
// search text assigned to current state
|
|
var text = MeterResetPsuStateInfo.GetTextFromState(_meterResetPsuState);
|
|
if (_meterResetPsuState == MeterResetPsuState.Idle)
|
|
{
|
|
return text;
|
|
}
|
|
|
|
text += _processRetryCtr > 0 ? $"Retry {_processRetryCtr}" : "";
|
|
return text;
|
|
}
|
|
#endregion
|
|
|
|
#region Actions
|
|
|
|
/// <summary>
|
|
/// Try to re-establish the file system, therefor logout to close all open files
|
|
/// and login again.
|
|
/// </summary>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
public void ReestablishMeterFileSystem()
|
|
{
|
|
_genesisMeter?.Logout();
|
|
_genesisMeter?.ReLogin();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stop the update process
|
|
/// </summary>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private Boolean StopUpdateProcess
|
|
{
|
|
get => _stopUpdateProcess;
|
|
set
|
|
{
|
|
_stopUpdateProcess = value;
|
|
if (_meterFile != null)
|
|
{
|
|
_meterFile.StopProcess = value;
|
|
}
|
|
|
|
_meterResetPsuState = MeterResetPsuState.ResetFailed;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update meter lookup table
|
|
/// </summary>
|
|
/// <param name="cancellationToken"></param>
|
|
/// <returns></returns>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2024-Dec-10" author="Thomas Wiedebusch">
|
|
/// - Initial MockGenesis support.
|
|
/// </remarks>
|
|
/// <remarks date="2024-Dec-16" author="Thomas Wiedebusch">
|
|
/// - Check reboot counter to verify reboot being done.
|
|
/// </remarks>
|
|
/// <remarks date="2025-Apr-07" author="Thomas Wiedebusch">
|
|
/// - CancellationToken.
|
|
/// </remarks>
|
|
public Boolean MeterResetPsuExecute(CancellationToken cancellationToken = default(CancellationToken))
|
|
{
|
|
var statusReturn = _genesisMeter.RebootGenesis();
|
|
// Status return "Unknown" is from the real Genesis
|
|
if (StatusReturn.Unknown != statusReturn)
|
|
return StatusReturn.Okay == statusReturn;
|
|
|
|
if (!ResetPreparation())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
_operationCtr = 0;
|
|
_actualOperation = "";
|
|
ErrorMessage = "";
|
|
_meterResetPsuState = MeterResetPsuState.StartInitial;
|
|
_backupMeterResetPsuState = MeterResetPsuState.Idle;
|
|
var registerName = "CUSTOMER_RebootCount";
|
|
var rebootCountBeforeReboot = RegisterConverter.ByteArrayToValue<UInt32>(
|
|
_genesisMeter.ReadRegister(registerName));
|
|
while (_meterResetPsuState != MeterResetPsuState.Idle && !StopUpdateProcess)
|
|
{
|
|
if (cancellationToken.IsCancellationRequested)
|
|
StopUpdateProcess = true;
|
|
MeterResetPsuStateMachine();
|
|
}
|
|
var rebootCountAfterReboot = RegisterConverter.ByteArrayToValue<UInt32>(
|
|
_genesisMeter.ReadRegister(registerName));
|
|
|
|
// The reboot counter will only be increased if reboot executed
|
|
if (rebootCountAfterReboot == rebootCountBeforeReboot)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return ExitPreparation(true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reset process and all lists and counters
|
|
/// </summary>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
public void ResetAll()
|
|
{
|
|
//remove the update stop action
|
|
StopUpdateProcess = false;
|
|
|
|
//reset all counters
|
|
_processRetryCtr = 0;
|
|
|
|
//set state machine for automatic FW update
|
|
_meterResetPsuState = MeterResetPsuState.Idle;
|
|
_backupMeterResetPsuState = MeterResetPsuState.Idle;
|
|
_actualOperation = "";
|
|
_operationCtr = 0;
|
|
|
|
//logout/login/auto-login
|
|
ReestablishMeterFileSystem();
|
|
_genesisMeter?.Logout();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Common update preparation and check
|
|
/// </summary>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private Boolean ResetPreparation()
|
|
{
|
|
_actualOperation = "Reset preparation";
|
|
_meterResetPsuState = MeterResetPsuState.Idle;
|
|
|
|
_meterFile = new MeterFile(_genesisMeter);
|
|
if (_meterFile != null)
|
|
_meterFile.OnProcessUpdate += ProcessUpdate_Event;
|
|
_genesisMeter?.ReLogin();
|
|
|
|
if (_genesisMeter == null || !_genesisMeter.IsLoggedOn)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//set default timeout for file write operation
|
|
_meterFile.SetDefaultFileWriteTimeout();
|
|
|
|
//remove the update stop action
|
|
StopUpdateProcess = false;
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Common exit routine
|
|
/// </summary>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private Boolean ExitPreparation(Boolean returnValue)
|
|
{
|
|
if (_meterFile != null)
|
|
_meterFile.OnProcessUpdate -= ProcessUpdate_Event;
|
|
_meterFile = null;
|
|
ReestablishMeterFileSystem();
|
|
|
|
_genesisMeter?.Logout();
|
|
if (!StopUpdateProcess)
|
|
{
|
|
return returnValue;
|
|
}
|
|
|
|
_actualOperation = "";
|
|
return false;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region StateMachine
|
|
|
|
/// <summary>
|
|
/// State machine for reset PSU (pseudo update)
|
|
/// </summary>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2022-Aug-16" author="Thomas Wiedebusch">
|
|
/// - Store configurations added
|
|
/// </remarks>
|
|
/// <remarks date="2022-Dec-12" author="Thomas Wiedebusch">
|
|
/// - Wait re-boot introduced.
|
|
/// </remarks>
|
|
private void MeterResetPsuStateMachine()
|
|
{
|
|
if (_backupMeterResetPsuState == _meterResetPsuState)
|
|
{
|
|
Thread.Sleep(1);
|
|
}
|
|
else
|
|
{
|
|
// remind backup state to avoid repeated execution and side effects
|
|
_backupMeterResetPsuState = _meterResetPsuState;
|
|
// set actual state info text, this can be overwritten by each routine
|
|
_actualOperation = MeterResetPsuStateInfo.GetTextFromState(_meterResetPsuState);
|
|
switch (_meterResetPsuState)
|
|
{
|
|
case MeterResetPsuState.Idle:
|
|
break;
|
|
|
|
case MeterResetPsuState.StartInitial:
|
|
_processRetryCtr = 0;
|
|
_meterResetPsuState = MeterResetPsuState.StoreConfigurations;
|
|
break;
|
|
|
|
case MeterResetPsuState.StoreConfigurations:
|
|
_meterResetPsuState = StoreConfigurations() ? MeterResetPsuState.BuildUpgradeFile :
|
|
MeterResetPsuState.StepFailed;
|
|
break;
|
|
|
|
case MeterResetPsuState.BuildUpgradeFile:
|
|
_meterResetPsuState = BuildUpgradeFile() ? MeterResetPsuState.DownloadUpgradeFile :
|
|
MeterResetPsuState.StepFailed;
|
|
break;
|
|
|
|
case MeterResetPsuState.DownloadUpgradeFile:
|
|
_meterResetPsuState = DownloadUpgradeFile() ? MeterResetPsuState.DownloadUpgradeCtrlFile :
|
|
MeterResetPsuState.StepFailed;
|
|
break;
|
|
|
|
case MeterResetPsuState.DownloadUpgradeCtrlFile:
|
|
_meterResetPsuState = DownloadUpgradeCtrlFile() ? MeterResetPsuState.TriggerUpgrade :
|
|
MeterResetPsuState.StepFailed;
|
|
break;
|
|
|
|
case MeterResetPsuState.TriggerUpgrade:
|
|
_meterResetPsuState = TriggerUpgrade() ? MeterResetPsuState.WaitReboot :
|
|
MeterResetPsuState.StepFailed;
|
|
break;
|
|
|
|
case MeterResetPsuState.WaitReboot:
|
|
_meterResetPsuState = WaitReboot() ? MeterResetPsuState.ResetSucceeded :
|
|
MeterResetPsuState.StepFailed;
|
|
break;
|
|
|
|
case MeterResetPsuState.StepFailed:
|
|
_meterResetPsuState = _processRetryCtr++ < UpdateProcedureRetries
|
|
? MeterResetPsuState.RepeatReset
|
|
: MeterResetPsuState.ResetFailed;
|
|
break;
|
|
|
|
case MeterResetPsuState.RepeatReset:
|
|
_meterResetPsuState = MeterResetPsuState.DownloadUpgradeFile;
|
|
if (_processRetryCtr >= IncreaseTimeoutUpdateProcedureRetries)
|
|
{
|
|
_meterFile?.SetExtremeFileWriteTimeout();
|
|
}
|
|
|
|
break;
|
|
|
|
case MeterResetPsuState.ResetFailed:
|
|
StopUpdateProcess = true;
|
|
_meterResetPsuState = MeterResetPsuState.Idle;
|
|
break;
|
|
|
|
case MeterResetPsuState.ResetSucceeded:
|
|
_meterResetPsuState = MeterResetPsuState.Idle;
|
|
break;
|
|
|
|
case MeterResetPsuState.ResetStateListDelimiter:
|
|
_meterResetPsuState = MeterResetPsuState.Idle;
|
|
break;
|
|
|
|
default:
|
|
_meterResetPsuState = MeterResetPsuState.Idle;
|
|
break;
|
|
}
|
|
}// lock for identical state
|
|
}
|
|
|
|
#endregion
|
|
#region Operation
|
|
|
|
/// <summary>
|
|
/// Store configurations before reset, because reboot will use the values
|
|
/// of the non-volatile memory.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <remarks date="2022-Aug-16" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private Boolean StoreConfigurations()
|
|
{
|
|
if (_genesisMeter == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return !StoreConfigEnable || _genesisMeter.StoreAllConfigurations();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Build the upgrade for FLEXNETVERSION
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <remarks date="2022-Aug-11" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2024-May-07" author="Thomas Wiedebusch">
|
|
/// - Changed to take the new hexadecimal version into account as
|
|
/// version is already preprocessed at connection time.
|
|
/// </remarks>
|
|
private Boolean BuildUpgradeFile()
|
|
{
|
|
if (_genesisMeter == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// search FLEXNETVERSION
|
|
var flexnetversionFound = false;
|
|
var strVersion = "";
|
|
UInt32 version = 0;
|
|
UInt16 fileAppCrc = 0;
|
|
foreach (var app in _genesisMeter.MeterAppListVersion.Where(app => app.AppId == MeterFwUpdate.FlexnetVersionAppId))
|
|
{
|
|
strVersion = app.StrVersion;
|
|
fileAppCrc = app.Crc;
|
|
version = app.Version;
|
|
flexnetversionFound = true;
|
|
}
|
|
|
|
if (!flexnetversionFound)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// generate the upgrade file based on the template
|
|
_upgradeFile = new Byte[TemplateUpgradeFile.Length];
|
|
Buffer.BlockCopy(TemplateUpgradeFile, 0, _upgradeFile, 0, _upgradeFile.Length);
|
|
|
|
_upgradeFile[MeterFwUpdate.FileAppVersionIndex] = (Byte)(version & 0xFF);
|
|
_upgradeFile[MeterFwUpdate.FileAppVersionIndex + 1] = (Byte)((version & 0xFF00) >> 8);
|
|
|
|
// build the version string and copy it to the upgrade file
|
|
var upg18Idx = FlexVersionStringIndex;
|
|
foreach (var t in strVersion)
|
|
{
|
|
_upgradeFile[upg18Idx] = Convert.ToByte(t);
|
|
upg18Idx++;
|
|
}
|
|
|
|
// take the payload starting with version index
|
|
var payload = new Byte[_upgradeFile.Length - MeterFwUpdate.FileAppVersionIndex];
|
|
Buffer.BlockCopy(_upgradeFile, MeterFwUpdate.FileAppVersionIndex, payload, 0, payload.Length);
|
|
var calculatedCrc = Crc16Ccitt.CalculateMsb1021(payload);
|
|
|
|
// avoid replacement wit invalid generated FLEXNETVERSION
|
|
if (fileAppCrc != calculatedCrc)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// replace the CRC
|
|
_upgradeFile[MeterFwUpdate.FileAppCrcIndex] = (Byte)(calculatedCrc & 0xFF);
|
|
_upgradeFile[MeterFwUpdate.FileAppCrcIndex + 1] = (Byte)((calculatedCrc & 0xFF00) >> 8);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Send the upgrade file to the meter
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private Boolean DownloadUpgradeFile()
|
|
{
|
|
//initiate upgrade by writing the upgrade control file
|
|
if (_upgradeFile == null || _upgradeFile.Length != TemplateUpgradeFile.Length ||
|
|
!_meterFile.UnlockEraseWriteMeterFile(StrFlexnetUpgradeFileName))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
_actualOperation = $"{Resources.StrProcessDownload} FLEXNETVERSION";
|
|
|
|
var retryCtr = 0;
|
|
Boolean returnValue;
|
|
//write file and retry if not successful
|
|
do
|
|
{
|
|
returnValue = _meterFile.WriteMeterFile(StrFlexnetUpgradeFileName, _upgradeFile);
|
|
|
|
if (!returnValue)
|
|
{
|
|
ReestablishMeterFileSystem();
|
|
}
|
|
} while (!returnValue && retryCtr++ < FileWriteRetries && !StopUpdateProcess);
|
|
|
|
_upgradeFile = null;
|
|
return !StopUpdateProcess && returnValue;
|
|
}
|
|
/// <summary>
|
|
/// Send the upgrade control file to the meter
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private Boolean DownloadUpgradeCtrlFile()
|
|
{
|
|
//initiate upgrade by writing the upgrade control file
|
|
if (!_meterFile.UnlockEraseWriteMeterFile(MeterFwUpdate.StrUpgradeCtrlFileName))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
_actualOperation = Resources.StrFwUpdateStateDownloadUpgradeControlFile;
|
|
|
|
var retryCtr = 0;
|
|
Boolean returnValue;
|
|
//write file and retry if not successful
|
|
do
|
|
{
|
|
returnValue = _meterFile.WriteMeterFile(MeterFwUpdate.StrUpgradeCtrlFileName,
|
|
Encoding.ASCII.GetBytes(UpgradeCtrlFile));
|
|
|
|
if (!returnValue)
|
|
{
|
|
ReestablishMeterFileSystem();
|
|
}
|
|
} while (!returnValue && retryCtr++ < FileWriteRetries && !StopUpdateProcess);
|
|
|
|
return !StopUpdateProcess && returnValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Send the trigger update
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private Boolean TriggerUpgrade()
|
|
{
|
|
Boolean returnValue;
|
|
//trigger upgrade
|
|
_actualOperation = Resources.StrFwUpdateStateTriggerUpgrade;
|
|
var triggerCtr = 0;
|
|
|
|
//set extended timeout for trigger upgrade response delay
|
|
_genesisMeter.TransmitProtocol.SetResponseTimeout(5000);
|
|
do
|
|
{
|
|
returnValue = _genesisMeter.WriteRegister<Byte>(Register.System.TriggerFwUpgrade, 1);
|
|
|
|
if (!returnValue)
|
|
{
|
|
ReestablishMeterFileSystem();
|
|
}
|
|
} while (!returnValue && triggerCtr++ < TriggerWriteRetries && !StopUpdateProcess);
|
|
|
|
//set timeout back to default value
|
|
_genesisMeter.TransmitProtocol.SetDefaultResponseTimeout();
|
|
_actualOperation = returnValue ? Resources.StrMeterAppTriggerAccepted : Resources.StrMeterAppTriggerFailed;
|
|
|
|
return returnValue && !StopUpdateProcess;
|
|
}
|
|
/// <summary>
|
|
/// Wait for reboot of meter
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2024-Feb-20" author="Thomas Wiedebusch">
|
|
/// - Signal event during waiting loop to feed the process bar.
|
|
/// </remarks>
|
|
private Boolean WaitReboot()
|
|
{
|
|
_actualOperation = Resources.StrWaitingForReboot;
|
|
var rebootCtr = 0;
|
|
String pcbId;
|
|
do
|
|
{
|
|
pcbId = RegisterConverter.ByteArrayToValue<String>(
|
|
_genesisMeter.ReadRegister(Register.Configexchange.PcbSerialNumber, 12));
|
|
|
|
if (string.IsNullOrEmpty(pcbId))
|
|
{
|
|
var overallProcessCtrPercent = 100.0 * rebootCtr / RebootWaitCycles;
|
|
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("reboot", overallProcessCtrPercent));
|
|
Thread.Sleep(RebootWaitTimeMs);
|
|
}
|
|
|
|
} while (string.IsNullOrEmpty(pcbId) && rebootCtr++ < RebootWaitCycles && !StopUpdateProcess);
|
|
|
|
return !string.IsNullOrEmpty(pcbId) && !StopUpdateProcess;
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
} |