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
+1
View File
@@ -31,6 +31,7 @@
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=a44a776d_002Dd671_002D4675_002Dac7b_002Db6775ec7f289/@EntryIndexedValue">&lt;SessionState ContinuousTestingIsOn="True" ContinuousTestingMode="1" IsActive="True" Name="All tests from Solution" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD; <s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=a44a776d_002Dd671_002D4675_002Dac7b_002Db6775ec7f289/@EntryIndexedValue">&lt;SessionState ContinuousTestingIsOn="True" ContinuousTestingMode="1" IsActive="True" Name="All tests from Solution" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;Solution /&gt;&#xD; &lt;Solution /&gt;&#xD;
&lt;/SessionState&gt;</s:String> &lt;/SessionState&gt;</s:String>
@@ -45,7 +45,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig
/// <summary> /// <summary>
/// Limit retries to this value. /// Limit retries to this value.
/// </summary> /// </summary>
public const Int32 MaxRequestRetries = 6; private const Int32 MaxRequestRetries = 6;
/// <summary> /// <summary>
/// Send delay between records in milliseconds before /// Send delay between records in milliseconds before
@@ -55,6 +55,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig
/// response from meter. /// response from meter.
/// </summary> /// </summary>
public const Int32 InterRecordSendDelayMs = 5; public const Int32 InterRecordSendDelayMs = 5;
//public const Int32 InterRecordSendDelayMs = 50;
/// <summary> /// <summary>
/// Timeout before retry will be initiated in milliseconds /// 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 regDef = _configRegister.GetRegisterDefinitionByName(reg);
var data = RegisterConverter.ConvertFrom(value); var data = RegisterConverter.ConvertFrom(value);
_logger.Info($"Slot:{Slot} - Write register({regDef.RegisterName}), " + _logger.Info( $"Slot:{Slot} - Write register({regDef.RegisterName}), " +
$"record({BitConverter.ToString(data.ToArray())})"); $"record({BitConverter.ToString(data.ToArray())})");
PreRegisterWrite(regDef, data); PreRegisterWrite(regDef, data);
var command = data.Length > RegisterDefinition.ChunkSize ? 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!!!! //package file search string for applications including blank!!!!
private const String StrPackageFileAppId = "Id "; private const String StrPackageFileAppId = "Id ";
private const String StrPackageFileAppCrc = "CRC "; private const String StrPackageFileAppCrc = "CRC ";
private const String StrPackageFileAppCrc16 = "CRC16 ";
private const String StrPackageFileAppVersion = "version "; private const String StrPackageFileAppVersion = "version ";
//binary file name is a combination of "binfile" application ID underline 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> /// </summary>
public Double? CoreRevisionMinimum public Double? CoreRevisionMinimum
{ {
get; private set; get; set;
} }
/// <summary> /// <summary>
/// Core revision maximum as double for comparison /// 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"> /// <remarks date="2020-Dec-02" author="Thomas Wiedebusch">
/// - Extraction of valid core revisions min/max. /// - Extraction of valid core revisions min/max.
/// </remarks> /// </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() public Boolean ValidateFileAppsWithPackageFile()
{ {
if (string.IsNullOrEmpty(_packageDescriptionFile) || FileApps.Count == 0 || 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 //find a line which contains all required information
validAppsCtr += packageFileLines.Count(line => validAppsCtr += packageFileLines.Count(line =>
line.Contains($"{StrPackageFileAppId}{ConvertAppIdToString(fileApp.AppId)}") && line.Contains($"{StrPackageFileAppId}") &&
line.Contains($"{StrPackageFileAppCrc}{ConvertCrcToString(fileApp.Crc)}") && line.Contains($"{ConvertAppIdToString(fileApp.AppId)}") &&
line.Contains($"{StrPackageFileAppVersion}{fileApp.StrVersion}")); (line.Contains($"{StrPackageFileAppCrc}") ||
line.Contains($"{StrPackageFileAppCrc16}")) &&
line.Contains($"{ConvertCrcToString(fileApp.Crc)}") &&
line.Contains($"{StrPackageFileAppVersion}") &&
line.Contains($"{fileApp.StrVersion}"));
} }
//extract the core revision fields //extract the core revision fields
@@ -5,6 +5,14 @@
/// </summary> /// </summary>
public enum RequestAcknowledgeState public enum RequestAcknowledgeState
{ {
/// <summary>
/// Acknowledge code for unassigned command
/// </summary>
CommandNotAssigned,
/// <summary>
/// Acknowledge code not set, will be used initially
/// </summary>
NotDecoded,
/// <summary> /// <summary>
/// Response missing /// Response missing
/// </summary> /// </summary>
@@ -166,24 +166,43 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
/// <remarks date="2021-Feb-02" author="T.Wiedebusch"> /// <remarks date="2021-Feb-02" author="T.Wiedebusch">
/// - Avoid enqueue of _recordInProcess if retry counter is 0. /// - Avoid enqueue of _recordInProcess if retry counter is 0.
/// </remarks> /// </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() 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 //The inter record send delay has to be hold before trying to communicate again
const Int32 interRecordSendDelayMs = CommunicationConfig.InterRecordSendDelayMs; 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 //check if FIFO is empty and get the actual record to process out of it
while (_recordsSendFifo.TryDequeue(out var internalRecord)) 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; _recordInProcess = internalRecord;
if (_recordInProcess == null) return RequestAcknowledgeState.CommandNotAssigned;
//mark record as answer outstanding
_recordInProcess.Acknowledge = RequestAcknowledgeState.NotDecoded;
do do
{ {
_logger.Trace(" 1 TryDequeue DO ProcessRecordList"); _logger.Trace($"Record({loopCounter}) - Processing");
//log retries //log retries
if (_recordInProcess.RetryCtr > 0) if (_recordInProcess.RetryCtr > 0)
{ {
_logger.Debug($"{_ident} Retry({_recordInProcess.RetryCtr})"); _logger.Debug($"{_ident} Retry({_recordInProcess.RetryCtr})");
_logger.Trace($"Record({loopCounter}) - Retry({_recordInProcess.RetryCtr})");
} }
//log request protocol content //log request protocol content
@@ -216,6 +235,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
requestTimeUtc = DateTimeOffset.UtcNow; requestTimeUtc = DateTimeOffset.UtcNow;
} }
responseTimeMs = (Int32)timeSpan.TotalMilliseconds; responseTimeMs = (Int32)timeSpan.TotalMilliseconds;
} while (_recordInProcess.Acknowledge != RequestAcknowledgeState.Ok && } while (_recordInProcess.Acknowledge != RequestAcknowledgeState.Ok &&
_recordInProcess.SkipRetryErrorCode != _recordInProcess.ResponseErrorCode && _recordInProcess.SkipRetryErrorCode != _recordInProcess.ResponseErrorCode &&
_timeOutMs > responseTimeMs); _timeOutMs > responseTimeMs);
@@ -249,6 +269,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
_recordInProcess.SkipRetryErrorCode != _recordInProcess.ResponseErrorCode); _recordInProcess.SkipRetryErrorCode != _recordInProcess.ResponseErrorCode);
} }
return _recordInProcess.Acknowledge; return _recordInProcess.Acknowledge;
} }
@@ -371,8 +392,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
/// <remarks date="2022-Oct-02" author="T.Wiedebusch"> /// <remarks date="2022-Oct-02" author="T.Wiedebusch">
/// - On wakeup message 5 retires are allowed to avoid an infinite loop. /// - On wakeup message 5 retires are allowed to avoid an infinite loop.
/// </remarks> /// </remarks>
/// <remarks date="2022-Oct-04" author="T.Wiedebusch">
/// - On wakeup message exit this routine.
/// </remarks>
public override void DecodeRecord(IPortDataEventArgs data) 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 //the request response record covers the entire request protocol
var responseRecord = GetTransmitProtocol().DecodeDataForLogicLayer((List<Byte>)data.GetData()); var responseRecord = GetTransmitProtocol().DecodeDataForLogicLayer((List<Byte>)data.GetData());
@@ -405,10 +431,18 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
{ {
_recordInProcess.Acknowledge = RequestAcknowledgeState.WakeupMessage; _recordInProcess.Acknowledge = RequestAcknowledgeState.WakeupMessage;
//initiate a single retry on wakeup message response //initiate a single retry on wakeup message response
if ( _recordInProcess.WakeupMessageRetryCtr < 10) if ( _recordInProcess.WakeupMessageRetryCtr < 5)
{ {
_logger.Debug($"{_ident} Wakeup message received");
_recordInProcess.WakeupMessageRetryCtr++; _recordInProcess.WakeupMessageRetryCtr++;
_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 // reset retry counter to get all required retries
_recordInProcess.RetryCtr = -1; _recordInProcess.RetryCtr = -1;
//reset timeout to a normal value if timeout is extremely high but response received //reset timeout to a normal value if timeout is extremely high but response received
@@ -416,8 +450,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
_timeOutMs = CommunicationConfig.BusyTimeoutMs; _timeOutMs = CommunicationConfig.BusyTimeoutMs;
return; return;
} }
}
}
//log request protocol content //log request protocol content
@@ -550,6 +582,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
if (command == Commands.MultipleReadData && meterRegister != null && meterRegister.DataType == typeof(String)) if (command == Commands.MultipleReadData && meterRegister != null && meterRegister.DataType == typeof(String))
{ {
var completeResponse = new List<Byte>(); var completeResponse = new List<Byte>();
//TODO THW check this including the recursive call CommandToMeter
while (true) while (true)
{ {
var cRecord = CommandToMeter(Commands.ReadData, meterRegister, payload, expectedLength, var cRecord = CommandToMeter(Commands.ReadData, meterRegister, payload, expectedLength,
@@ -668,7 +701,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
/// <summary> /// <summary>
/// Analyzes the error code /// Analyzes the error code
/// </summary> /// </summary>
public void CheckErrorCode() private void CheckErrorCode()
{ {
if (_recordInProcess.ResponseErrorBase == (Byte)ConfigExErrors.Base) if (_recordInProcess.ResponseErrorBase == (Byte)ConfigExErrors.Base)
{ {
@@ -709,7 +742,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
/// <returns></returns> /// <returns></returns>
public Boolean ContainsRegisterIdent(String registerName) 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> /// </summary>
public class RequestRecord public class RequestRecord
{ {
/// <summary>
/// Indicates the base command <see cref="Commands" />
/// </summary>
public readonly Byte Command;
/// <summary> /// <summary>
/// Indicates the base command <see cref="Commands" /> /// Indicates the base command <see cref="Commands" />
/// </summary> /// </summary>
@@ -65,12 +60,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
/// <summary> /// <summary>
/// Data containing the request protocol /// Data containing the request protocol
/// </summary> /// </summary>
public List<Byte> RequestProtocolData; public readonly List<Byte> RequestProtocolData;
/// <summary> /// <summary>
/// Encoded with transmit protocol, ready to stream to port as is /// Encoded with transmit protocol, ready to stream to port as is
/// </summary> /// </summary>
public List<Byte> EncodedRequestData { get; internal set; } public List<Byte> EncodedRequestData { get; }
/// <summary> /// <summary>
/// Extracted payload of response /// Extracted payload of response
@@ -85,12 +80,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol
/// <summary> /// <summary>
/// avoid logging for e.g. password /// avoid logging for e.g. password
/// </summary> /// </summary>
public Boolean HideDataInLog; public readonly Boolean HideDataInLog;
/// <summary> /// <summary>
/// error mask to skip retries for functional errors <see cref="ResponseErrorCode"/> /// error mask to skip retries for functional errors <see cref="ResponseErrorCode"/>
/// </summary> /// </summary>
public UInt16 SkipRetryErrorCode; public readonly UInt16 SkipRetryErrorCode;
/// <summary> /// <summary>
/// Ctor for an base command <see cref="Commands" /> /// 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, Int32 responseTimeoutMs = 100, RegisterDefinition register = null, Boolean hideDataInLog = false,
UInt16 skipRetryErrorCode = CommunicationConfig.SkipRetryErrorCode) UInt16 skipRetryErrorCode = CommunicationConfig.SkipRetryErrorCode)
{ {
Command = command;
ResponseCommand = (Byte)(command + 1); ResponseCommand = (Byte)(command + 1);
Register = register; Register = register;
RequestProtocolData = requestProtocolData; RequestProtocolData = requestProtocolData;
+13
View File
@@ -1589,6 +1589,13 @@ namespace Xylem.Common.Ui.GenesisToolBox
#region ExternalCalls #region ExternalCalls
/// <summary>
///
/// </summary>
/// <param name="slot"></param>
/// <param name="binaryPath"></param>
/// <param name="packageInfoPath"></param>
/// <returns></returns>
public Boolean Prepare(Int32 slot, String binaryPath, String packageInfoPath) public Boolean Prepare(Int32 slot, String binaryPath, String packageInfoPath)
{ {
_updateGui = false; _updateGui = false;
@@ -1675,7 +1682,13 @@ namespace Xylem.Common.Ui.GenesisToolBox
} }
/// <summary>
///
/// </summary>
public MsgEventargs LastMsgEvent; public MsgEventargs LastMsgEvent;
/// <summary>
///
/// </summary>
public class MsgEventargs : EventArgs public class MsgEventargs : EventArgs
{ {
public String Text; public String Text;