diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFwUpdate.cs b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFwUpdate.cs index c65257fc..1b6cbcf8 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFwUpdate.cs +++ b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFwUpdate.cs @@ -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 /// /// - Exit preparation added /// + /// + /// - Introduced lock for repeated execution of state machine + /// 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. /// + /// + /// - Introduced lock for repeated execution of state machine + /// 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 diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterLutUpdate.cs b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterLutUpdate.cs index f224d0f6..75dbd293 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterLutUpdate.cs +++ b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterLutUpdate.cs @@ -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; + + /// + /// Register subset needed to adjust for update performance content before update + /// + private readonly Dictionary _registersBeforeUpdate = new Dictionary(); + + /// + /// Register to restore after update + /// + private Dictionary _registersAfterUpdate = new Dictionary(); + #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 }); } /// @@ -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(); + 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 /// /// - Initial /// + /// + /// - Introduced lock for repeated execution of state machine + /// 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--;