MeterFwUpdate and MeterLutUpdate:
- Introduced lock for repeated execution of state machine
This commit is contained in:
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.Applications;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Const;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
|
||||
@@ -139,6 +140,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
// Text for caller to inform about actual process being carried out
|
||||
private String _actualOperation;
|
||||
private FwUpdateState _fwUpdateState;
|
||||
private FwUpdateState _fwBackupUpdateState;
|
||||
|
||||
// Process counter for caller to monitor actual progress
|
||||
private Int32 _processedBytesCtr;
|
||||
@@ -713,6 +715,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
/// <remarks date="2019-Jun-29" author="Thomas Wiedebusch">
|
||||
/// - Exit preparation added
|
||||
/// </remarks>
|
||||
/// <remarks date="2022-Mar-04" author="Thomas Wiedebusch">
|
||||
/// - Introduced lock for repeated execution of state machine
|
||||
/// </remarks>
|
||||
public Boolean UpdateMeterFw()
|
||||
{
|
||||
if (!UpdatePreparation())
|
||||
@@ -721,6 +726,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
}
|
||||
|
||||
_fwUpdateState = FwUpdateState.StartInitial;
|
||||
_fwBackupUpdateState = FwUpdateState.Idle;
|
||||
while (_fwUpdateState != FwUpdateState.Idle && !StopUpdateProcess)
|
||||
{
|
||||
FwUpdateStateMachine();
|
||||
@@ -886,6 +892,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
|
||||
//set state machine for automatic FW update
|
||||
_fwUpdateState = FwUpdateState.Idle;
|
||||
_fwBackupUpdateState = FwUpdateState.Idle;
|
||||
_actualOperation = "";
|
||||
|
||||
//update file information
|
||||
@@ -1040,97 +1047,110 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
/// useful as on increased size and number of applications needed to install in one run, the
|
||||
/// file system is slowing down for write accesses.
|
||||
/// </remarks>
|
||||
/// <remarks date="2022-Mar-04" author="Thomas Wiedebusch">
|
||||
/// - Introduced lock for repeated execution of state machine
|
||||
/// </remarks>
|
||||
private void FwUpdateStateMachine()
|
||||
{
|
||||
switch (_fwUpdateState)
|
||||
if (_fwBackupUpdateState == _fwUpdateState)
|
||||
{
|
||||
case FwUpdateState.Idle:
|
||||
break;
|
||||
|
||||
case FwUpdateState.StartInitial:
|
||||
_updateProcedureRetryCtr = 0;
|
||||
_fwUpdateState = FwUpdateState.BuildFileApps;
|
||||
break;
|
||||
|
||||
case FwUpdateState.BuildFileApps:
|
||||
if (!SingleFilePartsRetryEnable && !ConsecutiveFilePartsRetryEnable)
|
||||
{
|
||||
_remainingFileAppsParts.Clear();
|
||||
}
|
||||
|
||||
BuildFileApps();
|
||||
_fwUpdateState = FwUpdateState.DownloadFileApps;
|
||||
break;
|
||||
|
||||
case FwUpdateState.DownloadFileApps:
|
||||
_fwUpdateState = DownloadFileApps()
|
||||
? FwUpdateState.BuildUpgradeControlFile
|
||||
: FwUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case FwUpdateState.BuildUpgradeControlFile:
|
||||
//prepare the trigger to select all successfully downloaded applications
|
||||
PrepareTrigger();
|
||||
_fwUpdateState = BuildUpgradeCtrlFile()
|
||||
? FwUpdateState.DownloadUpgradeControlFile
|
||||
: FwUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case FwUpdateState.DownloadUpgradeControlFile:
|
||||
_fwUpdateState = DownloadUpgradeCtrlFile()
|
||||
? FwUpdateState.TriggerUpgrade
|
||||
: FwUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case FwUpdateState.TriggerUpgrade:
|
||||
_fwUpdateState = TriggerUpgrade() ? FwUpdateState.Idle : FwUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case FwUpdateState.StepFailed:
|
||||
_processedBytesCtr = 0;
|
||||
_overallBytesCtr = 0;
|
||||
//retry entire file if some partial file writes failed
|
||||
if (RetryEntireFileAfterFailedPartialRetries == _updateProcedureRetryCtr)
|
||||
{
|
||||
_remainingFileAppsParts.Clear();
|
||||
}
|
||||
|
||||
_fwUpdateState = _updateProcedureRetryCtr++ < UpdateProcedureRetries
|
||||
? FwUpdateState.RepeatFwUpdate
|
||||
: FwUpdateState.UpdateFailed;
|
||||
break;
|
||||
|
||||
case FwUpdateState.RepeatFwUpdate:
|
||||
_processedBytesCtr = 0;
|
||||
_overallBytesCtr = 0;
|
||||
_fwUpdateState = FwUpdateState.BuildFileApps;
|
||||
if (_updateProcedureRetryCtr >= IncreaseTimeoutUpdateProcedureRetries)
|
||||
{
|
||||
_meterFile?.SetExtremeFileWriteTimeout();
|
||||
}
|
||||
break;
|
||||
|
||||
case FwUpdateState.UpdateFailed:
|
||||
_processedBytesCtr = 0;
|
||||
_overallBytesCtr = 0;
|
||||
StopUpdateProcess = true;
|
||||
_fwUpdateState = FwUpdateState.Idle;
|
||||
break;
|
||||
|
||||
case FwUpdateState.UploadFileApps:
|
||||
break;
|
||||
|
||||
case FwUpdateState.CompareFileApps:
|
||||
break;
|
||||
|
||||
case FwUpdateState.EraseUpdateFile:
|
||||
break;
|
||||
|
||||
default:
|
||||
_fwUpdateState = FwUpdateState.Idle;
|
||||
break;
|
||||
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// remind backup state to avoid repeated execution and side effects
|
||||
_fwBackupUpdateState = _fwUpdateState;
|
||||
switch (_fwUpdateState)
|
||||
{
|
||||
case FwUpdateState.Idle:
|
||||
break;
|
||||
|
||||
case FwUpdateState.StartInitial:
|
||||
_updateProcedureRetryCtr = 0;
|
||||
_fwUpdateState = FwUpdateState.BuildFileApps;
|
||||
break;
|
||||
|
||||
case FwUpdateState.BuildFileApps:
|
||||
if (!SingleFilePartsRetryEnable && !ConsecutiveFilePartsRetryEnable)
|
||||
{
|
||||
_remainingFileAppsParts.Clear();
|
||||
}
|
||||
|
||||
BuildFileApps();
|
||||
_fwUpdateState = FwUpdateState.DownloadFileApps;
|
||||
break;
|
||||
|
||||
case FwUpdateState.DownloadFileApps:
|
||||
_fwUpdateState = DownloadFileApps()
|
||||
? FwUpdateState.BuildUpgradeControlFile
|
||||
: FwUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case FwUpdateState.BuildUpgradeControlFile:
|
||||
//prepare the trigger to select all successfully downloaded applications
|
||||
PrepareTrigger();
|
||||
_fwUpdateState = BuildUpgradeCtrlFile()
|
||||
? FwUpdateState.DownloadUpgradeControlFile
|
||||
: FwUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case FwUpdateState.DownloadUpgradeControlFile:
|
||||
_fwUpdateState = DownloadUpgradeCtrlFile()
|
||||
? FwUpdateState.TriggerUpgrade
|
||||
: FwUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case FwUpdateState.TriggerUpgrade:
|
||||
_fwUpdateState = TriggerUpgrade() ? FwUpdateState.Idle : FwUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case FwUpdateState.StepFailed:
|
||||
_processedBytesCtr = 0;
|
||||
_overallBytesCtr = 0;
|
||||
//retry entire file if some partial file writes failed
|
||||
if (RetryEntireFileAfterFailedPartialRetries == _updateProcedureRetryCtr)
|
||||
{
|
||||
_remainingFileAppsParts.Clear();
|
||||
}
|
||||
|
||||
_fwUpdateState = _updateProcedureRetryCtr++ < UpdateProcedureRetries
|
||||
? FwUpdateState.RepeatFwUpdate
|
||||
: FwUpdateState.UpdateFailed;
|
||||
break;
|
||||
|
||||
case FwUpdateState.RepeatFwUpdate:
|
||||
_processedBytesCtr = 0;
|
||||
_overallBytesCtr = 0;
|
||||
_fwUpdateState = FwUpdateState.BuildFileApps;
|
||||
if (_updateProcedureRetryCtr >= IncreaseTimeoutUpdateProcedureRetries)
|
||||
{
|
||||
_meterFile?.SetExtremeFileWriteTimeout();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case FwUpdateState.UpdateFailed:
|
||||
_processedBytesCtr = 0;
|
||||
_overallBytesCtr = 0;
|
||||
StopUpdateProcess = true;
|
||||
_fwUpdateState = FwUpdateState.Idle;
|
||||
break;
|
||||
|
||||
case FwUpdateState.UploadFileApps:
|
||||
break;
|
||||
|
||||
case FwUpdateState.CompareFileApps:
|
||||
break;
|
||||
|
||||
case FwUpdateState.EraseUpdateFile:
|
||||
break;
|
||||
|
||||
default:
|
||||
_fwUpdateState = FwUpdateState.Idle;
|
||||
break;
|
||||
|
||||
}
|
||||
}// lock repeated execution of identical state
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Logic.ProductionToProductMapper.Cordonel;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Consts;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.Consts;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
|
||||
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore.Consts;
|
||||
@@ -85,6 +88,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
// Text for caller to inform about actual process being carried out
|
||||
private String _actualOperation;
|
||||
private LutUpdateState _lutUpdateState;
|
||||
private LutUpdateState _lutBackupUpdateState;
|
||||
|
||||
// Look up table file
|
||||
public MeterLutFile LutFile;
|
||||
@@ -100,6 +104,17 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
|
||||
// error message for display of error reason
|
||||
public String ErrorMessage;
|
||||
|
||||
/// <summary>
|
||||
/// Register subset needed to adjust for update performance content before update
|
||||
/// </summary>
|
||||
private readonly Dictionary<String, Byte[]> _registersBeforeUpdate = new Dictionary<String, Byte[]>();
|
||||
|
||||
/// <summary>
|
||||
/// Register to restore after update
|
||||
/// </summary>
|
||||
private Dictionary<String, Byte[]> _registersAfterUpdate = new Dictionary<String, Byte[]>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
@@ -154,6 +169,17 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
{
|
||||
if (genesisMeter == null) return;
|
||||
AssignGenesis(genesisMeter);
|
||||
|
||||
if (genesisMeter.MeterAppListVersion.Any(f => f.AppName == "GENESISFLOW" && f.IsInstalled))
|
||||
{
|
||||
_registersBeforeUpdate.Add(Register.Genesisflow.LedMode, new[] {(Byte) LedMode.Off});
|
||||
_registersBeforeUpdate.Add(Register.Genesisflow.SampleRate, new Byte[] {1});
|
||||
}
|
||||
if (genesisMeter.MeterAppListVersion.Any(f => f.AppName == "METROLOGYASST" && f.IsInstalled))
|
||||
_registersBeforeUpdate.Add(Register.Mertrologyasst.PulseMode, new Byte[] { 0 });
|
||||
//deny access if NA product, because this does not have the radio app installed
|
||||
if (genesisMeter.MeterAppListVersion.Any(f => f.AppName == "SENSUSRADIO" && f.IsInstalled))
|
||||
_registersBeforeUpdate.Add(Register.Sensusradio.WakeupInterval, new Byte[] { 6 });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -276,6 +302,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
_actualOperation = "";
|
||||
ErrorMessage = "";
|
||||
_lutUpdateState = LutUpdateState.StartInitial;
|
||||
_lutBackupUpdateState = LutUpdateState.Idle;
|
||||
while (_lutUpdateState != LutUpdateState.Idle && !StopUpdateProcess)
|
||||
{
|
||||
LutUpdateStateMachine();
|
||||
@@ -317,6 +344,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
|
||||
//set state machine for automatic FW update
|
||||
_lutUpdateState = LutUpdateState.Idle;
|
||||
_lutBackupUpdateState = LutUpdateState.Idle;
|
||||
_actualOperation = "";
|
||||
_operationCtr = 0;
|
||||
|
||||
@@ -349,6 +377,15 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
//set default timeout for file write operation
|
||||
_meterFile.SetDefaultFileWriteTimeout();
|
||||
|
||||
//switch LED off set sample rate to 1 -> 1Hz to slow down CPU load
|
||||
_registersAfterUpdate = new Dictionary<String, Byte[]>();
|
||||
foreach (var item in _registersBeforeUpdate)
|
||||
{
|
||||
var writeBackValue = _genesisMeter.ReadRegister(item.Key);
|
||||
_registersAfterUpdate.Add(item.Key, writeBackValue);
|
||||
_genesisMeter.WriteRegister(item.Key, item.Value);
|
||||
|
||||
}
|
||||
//remove the update stop action
|
||||
StopUpdateProcess = false;
|
||||
return true;
|
||||
@@ -365,6 +402,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
if (_meterFile != null) _meterFile.OnProcessUpdate -= ProcessUpdate_Event;
|
||||
_meterFile = null;
|
||||
ReestablishMeterFileSystem();
|
||||
|
||||
foreach (var item in _registersAfterUpdate)
|
||||
{
|
||||
_genesisMeter.WriteRegister(item.Key, item.Value);
|
||||
}
|
||||
|
||||
_genesisMeter?.Logout();
|
||||
if (!StopUpdateProcess)
|
||||
{
|
||||
@@ -385,64 +428,78 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
/// <remarks date="2022-Feb-16" author="Thomas Wiedebusch">
|
||||
/// - Initial
|
||||
/// </remarks>
|
||||
/// <remarks date="2022-Mar-04" author="Thomas Wiedebusch">
|
||||
/// - Introduced lock for repeated execution of state machine
|
||||
/// </remarks>
|
||||
private void LutUpdateStateMachine()
|
||||
{
|
||||
switch (_lutUpdateState)
|
||||
if (_lutBackupUpdateState == _lutUpdateState)
|
||||
{
|
||||
case LutUpdateState.Idle:
|
||||
break;
|
||||
|
||||
case LutUpdateState.StartInitial:
|
||||
_updateProcedureRetryCtr = 0;
|
||||
_lutUpdateState = LutUpdateState.PrepareLutDownload;
|
||||
break;
|
||||
|
||||
case LutUpdateState.PrepareLutDownload:
|
||||
_lutUpdateState = PrepareLutDownload() ? LutUpdateState.EraseLutFile : LutUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case LutUpdateState.EraseLutFile:
|
||||
_lutUpdateState = EraseLutFiles() ? LutUpdateState.DownloadLutFile : LutUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case LutUpdateState.DownloadLutFile:
|
||||
_lutUpdateState = DownloadLutFiles() ? LutUpdateState.UploadLutFile : LutUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case LutUpdateState.UploadLutFile:
|
||||
_lutUpdateState = UploadAndCompareLutFiles() ? LutUpdateState.Idle : LutUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case LutUpdateState.CompareLutFile:
|
||||
break;
|
||||
|
||||
case LutUpdateState.StepFailed:
|
||||
_lutUpdateState = _updateProcedureRetryCtr++ < UpdateProcedureRetries
|
||||
? LutUpdateState.RepeatLutUpdate : LutUpdateState.UpdateFailed;
|
||||
break;
|
||||
|
||||
case LutUpdateState.RepeatLutUpdate:
|
||||
_lutUpdateState = LutUpdateState.DownloadLutFile;
|
||||
if (_updateProcedureRetryCtr >= IncreaseTimeoutUpdateProcedureRetries)
|
||||
{
|
||||
_meterFile?.SetExtremeFileWriteTimeout();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LutUpdateState.UpdateFailed:
|
||||
StopUpdateProcess = true;
|
||||
_lutUpdateState = LutUpdateState.Idle;
|
||||
break;
|
||||
|
||||
case LutUpdateState.LutUpdateStateListDelimiter:
|
||||
_lutUpdateState = LutUpdateState.Idle;
|
||||
break;
|
||||
|
||||
default:
|
||||
_lutUpdateState = LutUpdateState.Idle;
|
||||
break;
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// remind backup state to avoid repeated execution and side effects
|
||||
_lutBackupUpdateState = _lutUpdateState;
|
||||
switch (_lutUpdateState)
|
||||
{
|
||||
case LutUpdateState.Idle:
|
||||
break;
|
||||
|
||||
case LutUpdateState.StartInitial:
|
||||
_updateProcedureRetryCtr = 0;
|
||||
_lutUpdateState = LutUpdateState.PrepareLutDownload;
|
||||
break;
|
||||
|
||||
case LutUpdateState.PrepareLutDownload:
|
||||
_lutUpdateState =
|
||||
PrepareLutDownload() ? LutUpdateState.EraseLutFile : LutUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case LutUpdateState.EraseLutFile:
|
||||
_lutUpdateState = EraseLutFiles() ? LutUpdateState.DownloadLutFile : LutUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case LutUpdateState.DownloadLutFile:
|
||||
_lutUpdateState = DownloadLutFiles() ? LutUpdateState.UploadLutFile : LutUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case LutUpdateState.UploadLutFile:
|
||||
_lutUpdateState = UploadAndCompareLutFiles() ? LutUpdateState.Idle : LutUpdateState.StepFailed;
|
||||
break;
|
||||
|
||||
case LutUpdateState.CompareLutFile:
|
||||
break;
|
||||
|
||||
case LutUpdateState.StepFailed:
|
||||
_lutUpdateState = _updateProcedureRetryCtr++ < UpdateProcedureRetries
|
||||
? LutUpdateState.RepeatLutUpdate
|
||||
: LutUpdateState.UpdateFailed;
|
||||
break;
|
||||
|
||||
case LutUpdateState.RepeatLutUpdate:
|
||||
_lutUpdateState = LutUpdateState.DownloadLutFile;
|
||||
if (_updateProcedureRetryCtr >= IncreaseTimeoutUpdateProcedureRetries)
|
||||
{
|
||||
_meterFile?.SetExtremeFileWriteTimeout();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LutUpdateState.UpdateFailed:
|
||||
StopUpdateProcess = true;
|
||||
_lutUpdateState = LutUpdateState.Idle;
|
||||
break;
|
||||
|
||||
case LutUpdateState.LutUpdateStateListDelimiter:
|
||||
_lutUpdateState = LutUpdateState.Idle;
|
||||
break;
|
||||
|
||||
default:
|
||||
_lutUpdateState = LutUpdateState.Idle;
|
||||
break;
|
||||
}
|
||||
}// lock for identical state
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -752,9 +809,10 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
LutFileReadBack = new MeterLutFile(fileToUpload);
|
||||
if (_meterFile.ReadMeterFile(fileToUpload, out LutFileReadBack.BinData, LutFile.BinData.Count))
|
||||
{
|
||||
if (LutFileReadBack.BinData != LutFile.BinData)
|
||||
// compare the entire buffer which also includes the header of the file
|
||||
if (!LutFileReadBack.BinData.SequenceEqual(LutFile.BinData))
|
||||
{
|
||||
ErrorMessage += $"Verification of {fileToUpload} failed!\n";
|
||||
ErrorMessage += $"Meter LUT file is unequal to downloaded {fileToUpload}!\n";
|
||||
returnValue = false;
|
||||
_operationCtr--;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user