Cordonel ReBoot with "Pseudo FW Update" PSU:
- Taking the installed FLEXNETVERSION, rebuilding it, download and reinstall it, send trigger upgrade to finalize.
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.Consts
|
||||
{
|
||||
/// <summary>
|
||||
/// Genesis meter reset via PSU (pseudo update) states
|
||||
/// </summary>
|
||||
public enum MeterResetPsuState
|
||||
{
|
||||
/// <summary>
|
||||
/// FW Update State Idle
|
||||
/// </summary>
|
||||
Idle,
|
||||
/// <summary>
|
||||
/// FW update single step failed
|
||||
/// </summary>
|
||||
StepFailed,
|
||||
/// <summary>
|
||||
/// Try it again
|
||||
/// </summary>
|
||||
RepeatReset,
|
||||
/// <summary>
|
||||
/// Reset failed
|
||||
/// </summary>
|
||||
ResetFailed,
|
||||
/// <summary>
|
||||
/// Reset succeeded
|
||||
/// </summary>
|
||||
ResetSucceeded,
|
||||
/// <summary>
|
||||
/// Start initial FW update
|
||||
/// </summary>
|
||||
StartInitial,
|
||||
/// <summary>
|
||||
/// Build the FLEXNETVERSION file upg18
|
||||
/// </summary>
|
||||
BuildUpgradeFile,
|
||||
/// <summary>
|
||||
/// Download upgrade file upg18
|
||||
/// </summary>
|
||||
DownloadUpgradeFile,
|
||||
/// <summary>
|
||||
/// Download upgrade file upg18
|
||||
/// </summary>
|
||||
DownloadUpgradeCtrlFile,
|
||||
/// <summary>
|
||||
/// Trigger Upgrade
|
||||
/// </summary>
|
||||
TriggerUpgrade,
|
||||
/// <summary>
|
||||
/// Delimiter for list
|
||||
/// </summary>
|
||||
ResetStateListDelimiter
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.Consts
|
||||
{
|
||||
/// <summary>
|
||||
/// Concatenation of state and string
|
||||
/// </summary>
|
||||
public static class MeterResetPsuStateInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Build state information
|
||||
/// </summary>
|
||||
private static readonly MeterResetPsuStateText[] StateInfos;
|
||||
|
||||
/// <summary>
|
||||
/// Ctor
|
||||
/// </summary>
|
||||
static MeterResetPsuStateInfo()
|
||||
{
|
||||
StateInfos = new MeterResetPsuStateText[(Int32)MeterResetPsuState.ResetStateListDelimiter];
|
||||
StateInfos[0].State = MeterResetPsuState.Idle;
|
||||
StateInfos[0].Message = "";
|
||||
|
||||
StateInfos[1].State = MeterResetPsuState.StepFailed;
|
||||
StateInfos[1].Message = "Processing Step Failed";
|
||||
|
||||
StateInfos[2].State = MeterResetPsuState.RepeatReset;
|
||||
StateInfos[2].Message = "Repeat reset";
|
||||
|
||||
StateInfos[3].State = MeterResetPsuState.ResetFailed;
|
||||
StateInfos[3].Message = "Reset Failed";
|
||||
|
||||
StateInfos[4].State = MeterResetPsuState.ResetSucceeded;
|
||||
StateInfos[4].Message = "Reset succeeded";
|
||||
|
||||
StateInfos[5].State = MeterResetPsuState.StartInitial;
|
||||
StateInfos[5].Message = "Initial start";
|
||||
|
||||
StateInfos[6].State = MeterResetPsuState.BuildUpgradeFile;
|
||||
StateInfos[6].Message = "Build flexnetversion upgrade file";
|
||||
|
||||
StateInfos[7].State = MeterResetPsuState.DownloadUpgradeFile;
|
||||
StateInfos[7].Message = "Download flexnetversion upgrade file";
|
||||
|
||||
StateInfos[8].State = MeterResetPsuState.DownloadUpgradeCtrlFile;
|
||||
StateInfos[8].Message = "Download upgrade control file";
|
||||
|
||||
StateInfos[9].State = MeterResetPsuState.TriggerUpgrade;
|
||||
StateInfos[9].Message = "Trigger upgrade";
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current information
|
||||
/// </summary>
|
||||
/// <param name="state">state to search for information text</param>
|
||||
public static String GetTextFromState(MeterResetPsuState state)
|
||||
{
|
||||
return (from stateInfo in StateInfos
|
||||
where stateInfo.State == state select stateInfo.Message).FirstOrDefault();
|
||||
}
|
||||
/// <summary>
|
||||
/// Get the state of the text
|
||||
/// </summary>
|
||||
/// <param name="text">information text to search if state is assigned</param>
|
||||
public static MeterResetPsuState GetStateFromText(String text)
|
||||
{
|
||||
return (from stateInfo in StateInfos
|
||||
where stateInfo.Message == text select stateInfo.State).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.Consts
|
||||
{
|
||||
/// <summary>
|
||||
/// Concatenation between lokup table update state and text
|
||||
/// </summary>
|
||||
public struct MeterResetPsuStateText
|
||||
{
|
||||
/// <summary>
|
||||
/// The state of the firmware update
|
||||
/// </summary>
|
||||
public MeterResetPsuState State;
|
||||
/// <summary>
|
||||
/// The message text of the lookup table update state
|
||||
/// </summary>
|
||||
public String Message;
|
||||
}
|
||||
}
|
||||
@@ -99,6 +99,9 @@
|
||||
<Compile Include="..\..\..\..\.shared\SharedAssemblyInfo.cs">
|
||||
<Link>Properties\SharedAssemblyInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Consts\MeterResetPsuStateInfo.cs" />
|
||||
<Compile Include="Consts\MeterResetPsuStateText.cs" />
|
||||
<Compile Include="Consts\MeterResetPsuState.cs" />
|
||||
<Compile Include="Consts\LutUpdateStateText.cs" />
|
||||
<Compile Include="Consts\LutUpdateStateInfo.cs" />
|
||||
<Compile Include="Consts\LutUpdateState.cs" />
|
||||
@@ -109,6 +112,7 @@
|
||||
<Compile Include="MeterLutFile.cs" />
|
||||
<Compile Include="MeterFileRestore.cs" />
|
||||
<Compile Include="MeterFilesEraseRestore.cs" />
|
||||
<Compile Include="MeterResetPsu.cs" />
|
||||
<Compile Include="MeterLutUpdate.cs" />
|
||||
<Compile Include="MeterFwUpdate.cs" />
|
||||
<Compile Include="MeterFwUpdateCapability.cs" />
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.ProductionToProductMapper.Cordonel;
|
||||
|
||||
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
{
|
||||
|
||||
@@ -37,28 +37,28 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
private const String StrConfigMeterFileName = "0\\config";
|
||||
|
||||
//name for upgrade control file
|
||||
private const String StrUpgradeCtrlFileName = "1\\upgrade";
|
||||
public const String StrUpgradeCtrlFileName = "1\\upgrade";
|
||||
|
||||
//erase application
|
||||
private const String StrEraseAppCtrlFilePost = "*\r";
|
||||
|
||||
//upgrade application
|
||||
private const String StrInstallAppCtrlFilePost = ":\r";
|
||||
public const String StrInstallAppCtrlFilePost = ":\r";
|
||||
|
||||
//start identifier for upgrade file name (full name is "1\\upg02")
|
||||
private const String StrUpgradeAppPartialFileName = "1\\upg";
|
||||
|
||||
//start of binary application file
|
||||
private const String StrFileAppStartId = "APP>";
|
||||
public const String StrFileAppStartId = "APP>";
|
||||
|
||||
//position of CRC (LSB first) in binary file
|
||||
private const Int32 FileAppCrcIndex = 0x04;
|
||||
public const Int32 FileAppCrcIndex = 0x04;
|
||||
|
||||
//position of version in binary file
|
||||
private const Int32 FileAppVersionIndex = 0x06;
|
||||
public const Int32 FileAppVersionIndex = 0x06;
|
||||
|
||||
//position of application ID in binary file
|
||||
private const Int32 FileAppAppIdIndex = 0x28;
|
||||
public const Int32 FileAppAppIdIndex = 0x28;
|
||||
|
||||
//package file search string for applications including blank!!!!
|
||||
private const String StrPackageFileAppId = "Id ";
|
||||
|
||||
@@ -0,0 +1,645 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
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[] TemplateUpg18File =
|
||||
{
|
||||
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[] _upg18File;
|
||||
|
||||
// FLEXNETVERSION application Id
|
||||
private const Byte FlexnetVersionAppId = 0x18;
|
||||
|
||||
// upgrade control file content to force an update of exclusively FLEXNETVERSION
|
||||
private static readonly String UpgradeCtrlFile = $"{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 const String StrFlexnetUpgradeFileName = "1\\upg18";
|
||||
|
||||
//update reties for files
|
||||
private const Int32 FileWriteRetries = 1;
|
||||
|
||||
//trigger update retries
|
||||
private const Int32 TriggerWriteRetries = 2;
|
||||
|
||||
//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;
|
||||
|
||||
// size of version string e.g. R1.2.47
|
||||
private const Int32 FlexVersionStringSize = 7;
|
||||
|
||||
// retry counter
|
||||
private Int32 _processRetryCtr;
|
||||
|
||||
private GenesisMeter _genesisMeter;
|
||||
private MeterFile _meterFile;
|
||||
|
||||
// Text for caller to inform about actual process being carried out
|
||||
private String _actualOperation;
|
||||
|
||||
private MeterResetPsuState _meterResetPsuState;
|
||||
private MeterResetPsuState _backupMeterResetPsuState;
|
||||
|
||||
// Look up table file
|
||||
public MeterLutFile LutFile;
|
||||
|
||||
// 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;
|
||||
|
||||
#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>
|
||||
public 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(_overallOperation,
|
||||
// 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(GenesisMeter 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(GenesisMeter 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>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
public Boolean MeterResetPsuExecute()
|
||||
{
|
||||
if (!ResetPreparation())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_operationCtr = 0;
|
||||
_actualOperation = "";
|
||||
ErrorMessage = "";
|
||||
_meterResetPsuState = MeterResetPsuState.StartInitial;
|
||||
_backupMeterResetPsuState = MeterResetPsuState.Idle;
|
||||
while (_meterResetPsuState != MeterResetPsuState.Idle && !StopUpdateProcess)
|
||||
{
|
||||
MeterResetPsuStateMachine();
|
||||
}
|
||||
|
||||
return ExitPreparation(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset process and all lists and counters
|
||||
/// </summary>
|
||||
/// <remarks date="2022-Aug-10" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
private void ResetAll()
|
||||
{
|
||||
LutFile = null;
|
||||
//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>
|
||||
private void MeterResetPsuStateMachine()
|
||||
{
|
||||
if (_backupMeterResetPsuState == _meterResetPsuState)
|
||||
{
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// remind backup state to avoid repeated execution and side effects
|
||||
_backupMeterResetPsuState = _meterResetPsuState;
|
||||
switch (_meterResetPsuState)
|
||||
{
|
||||
case MeterResetPsuState.Idle:
|
||||
break;
|
||||
|
||||
case MeterResetPsuState.StartInitial:
|
||||
_processRetryCtr = 0;
|
||||
_meterResetPsuState = MeterResetPsuState.BuildUpgradeFile;
|
||||
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.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>
|
||||
/// Build the upgrade for FLEXNETVERSION
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2022-Aug-11" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
private Boolean BuildUpgradeFile()
|
||||
{
|
||||
if (_genesisMeter == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// search FLEXNETVERSION
|
||||
var flexnetversionFound = false;
|
||||
var strVersion = "";
|
||||
UInt16 fileAppCrc = 0;
|
||||
foreach (var app in _genesisMeter.MeterAppListVersion.Where(app => app.AppName == "FLEXNETVERSION"))
|
||||
{
|
||||
strVersion = app.StrVersion;
|
||||
fileAppCrc = (UInt16)app.Crc;
|
||||
flexnetversionFound = true;
|
||||
}
|
||||
|
||||
if (!flexnetversionFound)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// generate the upgrade file based on the template
|
||||
_upg18File = new Byte[TemplateUpg18File.Length];
|
||||
Buffer.BlockCopy(TemplateUpg18File, 0, _upg18File, 0, _upg18File.Length);
|
||||
|
||||
// rebuild numerical version out of the string because the FLEXNETVERSION version cannot be used
|
||||
// as it does lose the "B" information on conversion which is represented with the mask 0x80.
|
||||
// Later the file contains the preceding "B" or "R" instead of a number higher than 0x80.
|
||||
// The expected version string is 12.47 or 92.47 from app.StrVersion. Convert to R1.2.47 or B.2.47
|
||||
var version = new Char[strVersion.Length];
|
||||
version = strVersion.ToCharArray();
|
||||
int.TryParse(version[0].ToString(), out var digit);
|
||||
// add the "B" for test versions and the "R" for release versions
|
||||
strVersion = (version[0] & 0x80) == 0x80 ? "B" : "R";
|
||||
// Mask out the 0x80 to get the number behind
|
||||
if (digit >= 8)
|
||||
{
|
||||
digit -= 8;
|
||||
}
|
||||
|
||||
strVersion += $"{digit}.";
|
||||
var versionMsb = digit << 4;
|
||||
int.TryParse(version[1].ToString(), out digit);
|
||||
strVersion += $"{digit}.";
|
||||
versionMsb += digit;
|
||||
int.TryParse(version[3].ToString(), out digit);
|
||||
var versionLsb = digit << 4;
|
||||
strVersion += digit;
|
||||
int.TryParse(version[4].ToString(), out digit);
|
||||
versionLsb += digit;
|
||||
strVersion += digit;
|
||||
strVersion += "";
|
||||
|
||||
_upg18File[MeterFwUpdate.FileAppVersionIndex] = (Byte)versionLsb;
|
||||
_upg18File[MeterFwUpdate.FileAppVersionIndex + 1] = (Byte)versionMsb;
|
||||
|
||||
// build the version string and copy it to the upgrade file
|
||||
var upg18Idx = FlexVersionStringIndex;
|
||||
foreach (var t in strVersion)
|
||||
{
|
||||
_upg18File[upg18Idx] = Convert.ToByte(t);
|
||||
upg18Idx++;
|
||||
}
|
||||
|
||||
// take the payload starting with version index
|
||||
var payload = new Byte[_upg18File.Length - MeterFwUpdate.FileAppVersionIndex];
|
||||
Buffer.BlockCopy(_upg18File, 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
|
||||
_upg18File[MeterFwUpdate.FileAppCrcIndex] = (Byte)(calculatedCrc & 0xFF);
|
||||
_upg18File[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 (_upg18File == null || _upg18File.Length != TemplateUpg18File.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, _upg18File);
|
||||
|
||||
if (!returnValue)
|
||||
{
|
||||
ReestablishMeterFileSystem();
|
||||
}
|
||||
} while (!returnValue && retryCtr++ < FileWriteRetries && !StopUpdateProcess);
|
||||
|
||||
_upg18File = 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;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user