ReSharper: RequestProtocol, MeterFwUpdate

This commit is contained in:
Thomas Wiedebusch
2022-11-07 13:57:59 +01:00
parent 693463c689
commit 9d8e168303
8 changed files with 93 additions and 30 deletions
@@ -45,7 +45,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig
/// <summary>
/// Limit retries to this value.
/// </summary>
public const Int32 MaxRequestRetries = 6;
private const Int32 MaxRequestRetries = 6;
/// <summary>
/// Send delay between records in milliseconds before
@@ -55,6 +55,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig
/// response from meter.
/// </summary>
public const Int32 InterRecordSendDelayMs = 5;
//public const Int32 InterRecordSendDelayMs = 50;
/// <summary>
/// Timeout before retry will be initiated in milliseconds
@@ -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 ?
@@ -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
/// </summary>
public Double? CoreRevisionMinimum
{
get; private set;
get; set;
}
/// <summary>
/// Core revision maximum as double for comparison
@@ -2017,6 +2018,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <remarks date="2020-Dec-02" author="Thomas Wiedebusch">
/// - Extraction of valid core revisions min/max.
/// </remarks>
/// <remarks date="2022-Nov-07" author="Thomas Wiedebusch">
/// - 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.
/// </remarks>
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
@@ -5,6 +5,14 @@
/// </summary>
public enum RequestAcknowledgeState
{
/// <summary>
/// Acknowledge code for unassigned command
/// </summary>
CommandNotAssigned,
/// <summary>
/// Acknowledge code not set, will be used initially
/// </summary>
NotDecoded,
/// <summary>
/// Response missing
/// </summary>
@@ -166,24 +166,43 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
/// <remarks date="2021-Feb-02" author="T.Wiedebusch">
/// - Avoid enqueue of _recordInProcess if retry counter is 0.
/// </remarks>
/// <remarks date="2022-Nov-04" author="T.Wiedebusch">
/// - Additional DEBUG information included about FIFO and loops.
/// </remarks>
/// <remarks date="2022-Nov-07" author="T.Wiedebusch">
/// - Command not assigned response for recordInProcess == null.
/// </remarks>
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
/// <remarks date="2022-Oct-02" author="T.Wiedebusch">
/// - On wakeup message 5 retires are allowed to avoid an infinite loop.
/// </remarks>
/// <remarks date="2022-Oct-04" author="T.Wiedebusch">
/// - On wakeup message exit this routine.
/// </remarks>
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<Byte>)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<Byte>();
//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
/// <summary>
/// Analyzes the error code
/// </summary>
public void CheckErrorCode()
private void CheckErrorCode()
{
if (_recordInProcess.ResponseErrorBase == (Byte)ConfigExErrors.Base)
{
@@ -709,7 +742,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
/// <returns></returns>
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));
}
}
}
@@ -11,11 +11,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
/// </summary>
public class RequestRecord
{
/// <summary>
/// Indicates the base command <see cref="Commands" />
/// </summary>
public readonly Byte Command;
/// <summary>
/// Indicates the base command <see cref="Commands" />
/// </summary>
@@ -65,12 +60,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
/// <summary>
/// Data containing the request protocol
/// </summary>
public List<Byte> RequestProtocolData;
public readonly List<Byte> RequestProtocolData;
/// <summary>
/// Encoded with transmit protocol, ready to stream to port as is
/// </summary>
public List<Byte> EncodedRequestData { get; internal set; }
public List<Byte> EncodedRequestData { get; }
/// <summary>
/// Extracted payload of response
@@ -85,12 +80,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
/// <summary>
/// avoid logging for e.g. password
/// </summary>
public Boolean HideDataInLog;
public readonly Boolean HideDataInLog;
/// <summary>
/// error mask to skip retries for functional errors <see cref="ResponseErrorCode"/>
/// </summary>
public UInt16 SkipRetryErrorCode;
public readonly UInt16 SkipRetryErrorCode;
/// <summary>
/// Ctor for an base command <see cref="Commands" />
@@ -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;