MeterFwUpdate and MeterLutUpdate:

- Introduced lock for repeated execution of state machine
This commit is contained in:
Thomas Wiedebusch
2022-03-04 09:10:08 +01:00
parent 63121d7c41
commit 1ae56612ff
2 changed files with 221 additions and 143 deletions
@@ -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,8 +1047,19 @@ 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()
{
if (_fwBackupUpdateState == _fwUpdateState)
{
Thread.Sleep(1);
}
else
{
// remind backup state to avoid repeated execution and side effects
_fwBackupUpdateState = _fwUpdateState;
switch (_fwUpdateState)
{
case FwUpdateState.Idle:
@@ -1108,6 +1126,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
{
_meterFile?.SetExtremeFileWriteTimeout();
}
break;
case FwUpdateState.UpdateFailed:
@@ -1131,6 +1150,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
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,8 +428,19 @@ 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()
{
if (_lutBackupUpdateState == _lutUpdateState)
{
Thread.Sleep(1);
}
else
{
// remind backup state to avoid repeated execution and side effects
_lutBackupUpdateState = _lutUpdateState;
switch (_lutUpdateState)
{
case LutUpdateState.Idle:
@@ -398,7 +452,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
break;
case LutUpdateState.PrepareLutDownload:
_lutUpdateState = PrepareLutDownload() ? LutUpdateState.EraseLutFile : LutUpdateState.StepFailed;
_lutUpdateState =
PrepareLutDownload() ? LutUpdateState.EraseLutFile : LutUpdateState.StepFailed;
break;
case LutUpdateState.EraseLutFile:
@@ -418,7 +473,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
case LutUpdateState.StepFailed:
_lutUpdateState = _updateProcedureRetryCtr++ < UpdateProcedureRetries
? LutUpdateState.RepeatLutUpdate : LutUpdateState.UpdateFailed;
? LutUpdateState.RepeatLutUpdate
: LutUpdateState.UpdateFailed;
break;
case LutUpdateState.RepeatLutUpdate:
@@ -443,6 +499,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
_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--;