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;