From 9d8e1683036cc460b12df95f79a5b44b1da7db7e Mon Sep 17 00:00:00 2001 From: Thomas Wiedebusch Date: Mon, 7 Nov 2022 13:57:59 +0100 Subject: [PATCH] ReSharper: RequestProtocol, MeterFwUpdate --- Common/Common.sln.DotSettings.user | 1 + .../GenesisConfig/CommunicationConfig.cs | 3 +- .../Genesis/GenesisCore/GenesisMeter.cs | 5 +- .../Genesis/GenesisFile/MeterFwUpdate.cs | 19 ++++-- .../Consts/RequestAcknowledgeState.cs | 8 +++ .../RequestProtocol/RequestProtocol.cs | 60 +++++++++++++++---- .../RequestProtocol/RequestRecord.cs | 14 ++--- Common/Ui/GenesisToolBox/FrmFwUpdate.cs | 13 ++++ 8 files changed, 93 insertions(+), 30 deletions(-) diff --git a/Common/Common.sln.DotSettings.user b/Common/Common.sln.DotSettings.user index bbc41c3d..83a49bf8 100644 --- a/Common/Common.sln.DotSettings.user +++ b/Common/Common.sln.DotSettings.user @@ -31,6 +31,7 @@ + <SessionState ContinuousTestingIsOn="True" ContinuousTestingMode="1" IsActive="True" Name="All tests from Solution" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> <Solution /> </SessionState> diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisConfig/CommunicationConfig.cs b/Common/Hardware/WaterMeter/Genesis/GenesisConfig/CommunicationConfig.cs index 51b80571..d3baac49 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisConfig/CommunicationConfig.cs +++ b/Common/Hardware/WaterMeter/Genesis/GenesisConfig/CommunicationConfig.cs @@ -45,7 +45,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig /// /// Limit retries to this value. /// - public const Int32 MaxRequestRetries = 6; + private const Int32 MaxRequestRetries = 6; /// /// Send delay between records in milliseconds before @@ -55,6 +55,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig /// response from meter. /// public const Int32 InterRecordSendDelayMs = 5; + //public const Int32 InterRecordSendDelayMs = 50; /// /// Timeout before retry will be initiated in milliseconds diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisCore/GenesisMeter.cs b/Common/Hardware/WaterMeter/Genesis/GenesisCore/GenesisMeter.cs index 7bd177b2..006958ba 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisCore/GenesisMeter.cs +++ b/Common/Hardware/WaterMeter/Genesis/GenesisCore/GenesisMeter.cs @@ -1744,8 +1744,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore { var regDef = _configRegister.GetRegisterDefinitionByName(reg); var data = RegisterConverter.ConvertFrom(value); - _logger.Info($"Slot:{Slot} - Write register({regDef.RegisterName}), " + - $"record({BitConverter.ToString(data.ToArray())})"); + _logger.Info( $"Slot:{Slot} - Write register({regDef.RegisterName}), " + + $"record({BitConverter.ToString(data.ToArray())})"); + PreRegisterWrite(regDef, data); var command = data.Length > RegisterDefinition.ChunkSize ? diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFwUpdate.cs b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFwUpdate.cs index 911af1cb..abf9ef50 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFwUpdate.cs +++ b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterFwUpdate.cs @@ -63,6 +63,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile //package file search string for applications including blank!!!! private const String StrPackageFileAppId = "Id "; private const String StrPackageFileAppCrc = "CRC "; + private const String StrPackageFileAppCrc16 = "CRC16 "; private const String StrPackageFileAppVersion = "version "; //binary file name is a combination of "binfile" application ID underline version @@ -102,7 +103,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile /// public Double? CoreRevisionMinimum { - get; private set; + get; set; } /// /// Core revision maximum as double for comparison @@ -2017,6 +2018,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile /// /// - Extraction of valid core revisions min/max. /// + /// + /// - CRC16 added: + /// old versions will contain CRC without a number, + /// new versions starting with 2022-11-04_NA_B122B contain a CRC16 and CRC32 identifier. + /// - File line check modified to be immune against multiple blanks behind the field identifier. + /// public Boolean ValidateFileAppsWithPackageFile() { if (string.IsNullOrEmpty(_packageDescriptionFile) || FileApps.Count == 0 || @@ -2031,9 +2038,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile { //find a line which contains all required information validAppsCtr += packageFileLines.Count(line => - line.Contains($"{StrPackageFileAppId}{ConvertAppIdToString(fileApp.AppId)}") && - line.Contains($"{StrPackageFileAppCrc}{ConvertCrcToString(fileApp.Crc)}") && - line.Contains($"{StrPackageFileAppVersion}{fileApp.StrVersion}")); + line.Contains($"{StrPackageFileAppId}") && + line.Contains($"{ConvertAppIdToString(fileApp.AppId)}") && + (line.Contains($"{StrPackageFileAppCrc}") || + line.Contains($"{StrPackageFileAppCrc16}")) && + line.Contains($"{ConvertCrcToString(fileApp.Crc)}") && + line.Contains($"{StrPackageFileAppVersion}") && + line.Contains($"{fileApp.StrVersion}")); } //extract the core revision fields diff --git a/Common/Hardware/WaterMeter/Genesis/Protocols/RequestProtocol/Consts/RequestAcknowledgeState.cs b/Common/Hardware/WaterMeter/Genesis/Protocols/RequestProtocol/Consts/RequestAcknowledgeState.cs index 297cc0ca..af2193ec 100644 --- a/Common/Hardware/WaterMeter/Genesis/Protocols/RequestProtocol/Consts/RequestAcknowledgeState.cs +++ b/Common/Hardware/WaterMeter/Genesis/Protocols/RequestProtocol/Consts/RequestAcknowledgeState.cs @@ -5,6 +5,14 @@ /// public enum RequestAcknowledgeState { + /// + /// Acknowledge code for unassigned command + /// + CommandNotAssigned, + /// + /// Acknowledge code not set, will be used initially + /// + NotDecoded, /// /// Response missing /// diff --git a/Common/Hardware/WaterMeter/Genesis/Protocols/RequestProtocol/RequestProtocol.cs b/Common/Hardware/WaterMeter/Genesis/Protocols/RequestProtocol/RequestProtocol.cs index 104032aa..73d044e7 100644 --- a/Common/Hardware/WaterMeter/Genesis/Protocols/RequestProtocol/RequestProtocol.cs +++ b/Common/Hardware/WaterMeter/Genesis/Protocols/RequestProtocol/RequestProtocol.cs @@ -166,24 +166,43 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol /// /// - Avoid enqueue of _recordInProcess if retry counter is 0. /// + /// + /// - Additional DEBUG information included about FIFO and loops. + /// + /// + /// - Command not assigned response for recordInProcess == null. + /// public RequestAcknowledgeState ProcessRecordList() { - _logger.Trace(" 1 ProcessRecordList"); + _logger.Trace($" Enry to ProcessRecordList, FIFO contains ({_recordsSendFifo.Count}) records"); + //The inter record send delay has to be hold before trying to communicate again const Int32 interRecordSendDelayMs = CommunicationConfig.InterRecordSendDelayMs; + //remind counter for FIFO and therefore execution loops + var loopCounter = 0; + //check if FIFO is empty and get the actual record to process out of it while (_recordsSendFifo.TryDequeue(out var internalRecord)) { - _logger.Trace(" 1 TryDequeue ProcessRecordList"); + // Starting with record number 1 + loopCounter++; + _logger.Trace($"Record({loopCounter}) - Dequeued from FIFO"); + + //pointer to new record _recordInProcess = internalRecord; + if (_recordInProcess == null) return RequestAcknowledgeState.CommandNotAssigned; + + //mark record as answer outstanding + _recordInProcess.Acknowledge = RequestAcknowledgeState.NotDecoded; do { - _logger.Trace(" 1 TryDequeue DO ProcessRecordList"); + _logger.Trace($"Record({loopCounter}) - Processing"); //log retries if (_recordInProcess.RetryCtr > 0) { _logger.Debug($"{_ident} Retry({_recordInProcess.RetryCtr})"); + _logger.Trace($"Record({loopCounter}) - Retry({_recordInProcess.RetryCtr})"); } //log request protocol content @@ -216,6 +235,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol requestTimeUtc = DateTimeOffset.UtcNow; } responseTimeMs = (Int32)timeSpan.TotalMilliseconds; + } while (_recordInProcess.Acknowledge != RequestAcknowledgeState.Ok && _recordInProcess.SkipRetryErrorCode != _recordInProcess.ResponseErrorCode && _timeOutMs > responseTimeMs); @@ -249,6 +269,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol _recordInProcess.SkipRetryErrorCode != _recordInProcess.ResponseErrorCode); } + return _recordInProcess.Acknowledge; } @@ -371,8 +392,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol /// /// - On wakeup message 5 retires are allowed to avoid an infinite loop. /// + /// + /// - On wakeup message exit this routine. + /// public override void DecodeRecord(IPortDataEventArgs data) { + //new request has to be analyzed + _recordInProcess.Acknowledge = RequestAcknowledgeState.NotDecoded; //the request response record covers the entire request protocol var responseRecord = GetTransmitProtocol().DecodeDataForLogicLayer((List)data.GetData()); @@ -405,18 +431,24 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol { _recordInProcess.Acknowledge = RequestAcknowledgeState.WakeupMessage; //initiate a single retry on wakeup message response - if ( _recordInProcess.WakeupMessageRetryCtr < 10) + if ( _recordInProcess.WakeupMessageRetryCtr < 5) { - _logger.Debug($"{_ident} Wakeup message received"); _recordInProcess.WakeupMessageRetryCtr++; - // reset retry counter to get all required retries - _recordInProcess.RetryCtr = -1; - //reset timeout to a normal value if timeout is extremely high but response received - if (_timeOutMs > CommunicationConfig.BusyTimeoutMs) - _timeOutMs = CommunicationConfig.BusyTimeoutMs; - return; + _logger.Debug($"{_ident} Wakeup message({_recordInProcess.WakeupMessageRetryCtr}) received"); } } + else + { + //if it is not identified as valid wakeup message it is something unknown + _recordInProcess.Acknowledge = RequestAcknowledgeState.DecodingError; + _logger.Debug($"{_ident} Message decoding error."); + } + // reset retry counter to get all required retries + _recordInProcess.RetryCtr = -1; + //reset timeout to a normal value if timeout is extremely high but response received + if (_timeOutMs > CommunicationConfig.BusyTimeoutMs) + _timeOutMs = CommunicationConfig.BusyTimeoutMs; + return; } @@ -550,6 +582,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol if (command == Commands.MultipleReadData && meterRegister != null && meterRegister.DataType == typeof(String)) { var completeResponse = new List(); + //TODO THW check this including the recursive call CommandToMeter while (true) { var cRecord = CommandToMeter(Commands.ReadData, meterRegister, payload, expectedLength, @@ -668,7 +701,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol /// /// Analyzes the error code /// - public void CheckErrorCode() + private void CheckErrorCode() { if (_recordInProcess.ResponseErrorBase == (Byte)ConfigExErrors.Base) { @@ -709,7 +742,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol /// public Boolean ContainsRegisterIdent(String registerName) { - return _recordsSendFifo.Any(a => a.Register.GetIdent().ToLower() == registerName.ToLower()); + return _recordsSendFifo.Any(a => string.Equals(a.Register.GetIdent(), + registerName, StringComparison.CurrentCultureIgnoreCase)); } } } diff --git a/Common/Hardware/WaterMeter/Genesis/Protocols/RequestProtocol/RequestRecord.cs b/Common/Hardware/WaterMeter/Genesis/Protocols/RequestProtocol/RequestRecord.cs index 6bf0d551..b844e5e9 100644 --- a/Common/Hardware/WaterMeter/Genesis/Protocols/RequestProtocol/RequestRecord.cs +++ b/Common/Hardware/WaterMeter/Genesis/Protocols/RequestProtocol/RequestRecord.cs @@ -11,11 +11,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol /// public class RequestRecord { - /// - /// Indicates the base command - /// - public readonly Byte Command; - /// /// Indicates the base command /// @@ -65,12 +60,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol /// /// Data containing the request protocol /// - public List RequestProtocolData; + public readonly List RequestProtocolData; /// /// Encoded with transmit protocol, ready to stream to port as is /// - public List EncodedRequestData { get; internal set; } + public List EncodedRequestData { get; } /// /// Extracted payload of response @@ -85,12 +80,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol /// /// avoid logging for e.g. password /// - public Boolean HideDataInLog; + public readonly Boolean HideDataInLog; /// /// error mask to skip retries for functional errors /// - public UInt16 SkipRetryErrorCode; + public readonly UInt16 SkipRetryErrorCode; /// /// Ctor for an base command @@ -106,7 +101,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol Int32 responseTimeoutMs = 100, RegisterDefinition register = null, Boolean hideDataInLog = false, UInt16 skipRetryErrorCode = CommunicationConfig.SkipRetryErrorCode) { - Command = command; ResponseCommand = (Byte)(command + 1); Register = register; RequestProtocolData = requestProtocolData; diff --git a/Common/Ui/GenesisToolBox/FrmFwUpdate.cs b/Common/Ui/GenesisToolBox/FrmFwUpdate.cs index 6289a737..1861f65f 100644 --- a/Common/Ui/GenesisToolBox/FrmFwUpdate.cs +++ b/Common/Ui/GenesisToolBox/FrmFwUpdate.cs @@ -1589,6 +1589,13 @@ namespace Xylem.Common.Ui.GenesisToolBox #region ExternalCalls + /// + /// + /// + /// + /// + /// + /// public Boolean Prepare(Int32 slot, String binaryPath, String packageInfoPath) { _updateGui = false; @@ -1675,7 +1682,13 @@ namespace Xylem.Common.Ui.GenesisToolBox } + /// + /// + /// public MsgEventargs LastMsgEvent; + /// + /// + /// public class MsgEventargs : EventArgs { public String Text;