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.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading;
using Xylem.Common.Hardware.WaterMeter.Genesis.Applications; using Xylem.Common.Hardware.WaterMeter.Genesis.Applications;
using Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Const; using Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Const;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore; 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 // Text for caller to inform about actual process being carried out
private String _actualOperation; private String _actualOperation;
private FwUpdateState _fwUpdateState; private FwUpdateState _fwUpdateState;
private FwUpdateState _fwBackupUpdateState;
// Process counter for caller to monitor actual progress // Process counter for caller to monitor actual progress
private Int32 _processedBytesCtr; private Int32 _processedBytesCtr;
@@ -713,6 +715,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2019-Jun-29" author="Thomas Wiedebusch"> /// <remarks date="2019-Jun-29" author="Thomas Wiedebusch">
/// - Exit preparation added /// - Exit preparation added
/// </remarks> /// </remarks>
/// <remarks date="2022-Mar-04" author="Thomas Wiedebusch">
/// - Introduced lock for repeated execution of state machine
/// </remarks>
public Boolean UpdateMeterFw() public Boolean UpdateMeterFw()
{ {
if (!UpdatePreparation()) if (!UpdatePreparation())
@@ -721,6 +726,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
} }
_fwUpdateState = FwUpdateState.StartInitial; _fwUpdateState = FwUpdateState.StartInitial;
_fwBackupUpdateState = FwUpdateState.Idle;
while (_fwUpdateState != FwUpdateState.Idle && !StopUpdateProcess) while (_fwUpdateState != FwUpdateState.Idle && !StopUpdateProcess)
{ {
FwUpdateStateMachine(); FwUpdateStateMachine();
@@ -886,6 +892,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
//set state machine for automatic FW update //set state machine for automatic FW update
_fwUpdateState = FwUpdateState.Idle; _fwUpdateState = FwUpdateState.Idle;
_fwBackupUpdateState = FwUpdateState.Idle;
_actualOperation = ""; _actualOperation = "";
//update file information //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 /// useful as on increased size and number of applications needed to install in one run, the
/// file system is slowing down for write accesses. /// file system is slowing down for write accesses.
/// </remarks> /// </remarks>
/// <remarks date="2022-Mar-04" author="Thomas Wiedebusch">
/// - Introduced lock for repeated execution of state machine
/// </remarks>
private void FwUpdateStateMachine() private void FwUpdateStateMachine()
{ {
if (_fwBackupUpdateState == _fwUpdateState)
{
Thread.Sleep(1);
}
else
{
// remind backup state to avoid repeated execution and side effects
_fwBackupUpdateState = _fwUpdateState;
switch (_fwUpdateState) switch (_fwUpdateState)
{ {
case FwUpdateState.Idle: case FwUpdateState.Idle:
@@ -1108,6 +1126,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
{ {
_meterFile?.SetExtremeFileWriteTimeout(); _meterFile?.SetExtremeFileWriteTimeout();
} }
break; break;
case FwUpdateState.UpdateFailed: case FwUpdateState.UpdateFailed:
@@ -1131,6 +1150,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
break; break;
} }
}// lock repeated execution of identical state
} }
#endregion #endregion
@@ -1,9 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using Logic.ProductionToProductMapper.Cordonel; using Logic.ProductionToProductMapper.Cordonel;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore; 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.GenesisFile.Consts;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers; using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore.Consts; 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 // Text for caller to inform about actual process being carried out
private String _actualOperation; private String _actualOperation;
private LutUpdateState _lutUpdateState; private LutUpdateState _lutUpdateState;
private LutUpdateState _lutBackupUpdateState;
// Look up table file // Look up table file
public MeterLutFile LutFile; public MeterLutFile LutFile;
@@ -100,6 +104,17 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
// error message for display of error reason // error message for display of error reason
public String ErrorMessage; 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 #endregion
#region Events #region Events
@@ -154,6 +169,17 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
{ {
if (genesisMeter == null) return; if (genesisMeter == null) return;
AssignGenesis(genesisMeter); 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> /// <summary>
@@ -276,6 +302,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
_actualOperation = ""; _actualOperation = "";
ErrorMessage = ""; ErrorMessage = "";
_lutUpdateState = LutUpdateState.StartInitial; _lutUpdateState = LutUpdateState.StartInitial;
_lutBackupUpdateState = LutUpdateState.Idle;
while (_lutUpdateState != LutUpdateState.Idle && !StopUpdateProcess) while (_lutUpdateState != LutUpdateState.Idle && !StopUpdateProcess)
{ {
LutUpdateStateMachine(); LutUpdateStateMachine();
@@ -317,6 +344,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
//set state machine for automatic FW update //set state machine for automatic FW update
_lutUpdateState = LutUpdateState.Idle; _lutUpdateState = LutUpdateState.Idle;
_lutBackupUpdateState = LutUpdateState.Idle;
_actualOperation = ""; _actualOperation = "";
_operationCtr = 0; _operationCtr = 0;
@@ -349,6 +377,15 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
//set default timeout for file write operation //set default timeout for file write operation
_meterFile.SetDefaultFileWriteTimeout(); _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 //remove the update stop action
StopUpdateProcess = false; StopUpdateProcess = false;
return true; return true;
@@ -365,6 +402,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
if (_meterFile != null) _meterFile.OnProcessUpdate -= ProcessUpdate_Event; if (_meterFile != null) _meterFile.OnProcessUpdate -= ProcessUpdate_Event;
_meterFile = null; _meterFile = null;
ReestablishMeterFileSystem(); ReestablishMeterFileSystem();
foreach (var item in _registersAfterUpdate)
{
_genesisMeter.WriteRegister(item.Key, item.Value);
}
_genesisMeter?.Logout(); _genesisMeter?.Logout();
if (!StopUpdateProcess) if (!StopUpdateProcess)
{ {
@@ -385,8 +428,19 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2022-Feb-16" author="Thomas Wiedebusch"> /// <remarks date="2022-Feb-16" author="Thomas Wiedebusch">
/// - Initial /// - Initial
/// </remarks> /// </remarks>
/// <remarks date="2022-Mar-04" author="Thomas Wiedebusch">
/// - Introduced lock for repeated execution of state machine
/// </remarks>
private void LutUpdateStateMachine() private void LutUpdateStateMachine()
{ {
if (_lutBackupUpdateState == _lutUpdateState)
{
Thread.Sleep(1);
}
else
{
// remind backup state to avoid repeated execution and side effects
_lutBackupUpdateState = _lutUpdateState;
switch (_lutUpdateState) switch (_lutUpdateState)
{ {
case LutUpdateState.Idle: case LutUpdateState.Idle:
@@ -398,7 +452,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
break; break;
case LutUpdateState.PrepareLutDownload: case LutUpdateState.PrepareLutDownload:
_lutUpdateState = PrepareLutDownload() ? LutUpdateState.EraseLutFile : LutUpdateState.StepFailed; _lutUpdateState =
PrepareLutDownload() ? LutUpdateState.EraseLutFile : LutUpdateState.StepFailed;
break; break;
case LutUpdateState.EraseLutFile: case LutUpdateState.EraseLutFile:
@@ -418,7 +473,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
case LutUpdateState.StepFailed: case LutUpdateState.StepFailed:
_lutUpdateState = _updateProcedureRetryCtr++ < UpdateProcedureRetries _lutUpdateState = _updateProcedureRetryCtr++ < UpdateProcedureRetries
? LutUpdateState.RepeatLutUpdate : LutUpdateState.UpdateFailed; ? LutUpdateState.RepeatLutUpdate
: LutUpdateState.UpdateFailed;
break; break;
case LutUpdateState.RepeatLutUpdate: case LutUpdateState.RepeatLutUpdate:
@@ -443,6 +499,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
_lutUpdateState = LutUpdateState.Idle; _lutUpdateState = LutUpdateState.Idle;
break; break;
} }
}// lock for identical state
} }
#endregion #endregion
@@ -752,9 +809,10 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
LutFileReadBack = new MeterLutFile(fileToUpload); LutFileReadBack = new MeterLutFile(fileToUpload);
if (_meterFile.ReadMeterFile(fileToUpload, out LutFileReadBack.BinData, LutFile.BinData.Count)) 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; returnValue = false;
_operationCtr--; _operationCtr--;