diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterLutFile.cs b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterLutFile.cs
index eeb640af..d65156fd 100644
--- a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterLutFile.cs
+++ b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterLutFile.cs
@@ -44,11 +44,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
// header size of file
public const Int32 LutFileHeaderLength = LengthLutFileId + LengthDataLength + LengthCrc + LengthVersion;
- // data size of file
- public const Int32 LutFileDataLength = 730;
+ // data size of file is variable found 730, 5840, 13140, so it has to be read using the header
+ // public const Int32 LutFileDataLength = 730;
// LUT file entire file size
- public const Int32 SizeLutFile = LutFileHeaderLength + LutFileDataLength;
+ public Int32 SizeLutFile;
+
///
/// File name of the file on PC
///
@@ -78,7 +79,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
///
/// Data length
///
- public UInt32 DataLength;
+ private UInt32 _dataLength;
+ public UInt32 DataLength
+ {
+ get => _dataLength;
+ set
+ {
+ SizeLutFile = (Int32)value + LutFileHeaderLength;
+ _dataLength = value;
+ }
+ }
///
/// Version of LUT file
@@ -116,14 +126,21 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
public MeterSize MeterSize;
///
+ /// ATTENTION: The file size is dynamic!
/// Verifies the LUT format based on its contents
///
/// true if valid
+ ///
+ /// - Initial.
+ ///
+ ///
+ /// - Removed constant size, instead using header to calculate the size of the file.
+ ///
public Boolean ValidateLutFormat()
{
IsValid = false;
- if (BinData == null || BinData.Count < SizeLutFile)
+ if (BinData == null || BinData.Count < LutFileHeaderLength)
return false;
// extract the identifier and check, if this is a LUT file
StrLutFileId = Encoding.UTF8.GetString(BinData.ToArray(), MeterLutFile.IndexLutFileId,
@@ -145,7 +162,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
entireFile.AddRange(BinData);
var payload = new List();
payload.AddRange(entireFile.GetRange(MeterLutFile.IndexVersion,
- MeterLutFile.LutFileDataLength + MeterLutFile.LengthVersion));
+ (Int32)DataLength + MeterLutFile.LengthVersion));
CalculatedCrc = Crc16Ccitt.CalculateMsb1021(payload.ToArray());
if (CalculatedCrc != FileCrc)
{
diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterLutUpdate.cs b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterLutUpdate.cs
index 395c213d..fa444a38 100644
--- a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterLutUpdate.cs
+++ b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterLutUpdate.cs
@@ -486,13 +486,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
///
private Boolean ValidateLutFile()
{
- // check if LUT file contains data
- if (LutFile?.BinData == null || LutFile.BinData.Count < MeterLutFile.SizeLutFile)
- {
- ErrorMessage = "File size mismatch!";
- return false;
- }
-
// Take the file content to validate the format based
var lutFileFormatValid = LutFile.ValidateLutFormat();
if (LutFile.CrcError)
@@ -501,6 +494,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
return false;
}
+ // check if LUT file contains data
+ if (LutFile?.BinData == null || LutFile.BinData.Count != LutFile.SizeLutFile)
+ {
+ ErrorMessage = "File size mismatch!";
+ return false;
+ }
+
return lutFileFormatValid;
}
diff --git a/ServiceFwUpdate/Ui/ServiceFwUpdateBuilder/FrmFwUpdateBuilder.Designer.cs b/ServiceFwUpdate/Ui/ServiceFwUpdateBuilder/FrmFwUpdateBuilder.Designer.cs
index 7d4cc8b8..888c8b76 100644
--- a/ServiceFwUpdate/Ui/ServiceFwUpdateBuilder/FrmFwUpdateBuilder.Designer.cs
+++ b/ServiceFwUpdate/Ui/ServiceFwUpdateBuilder/FrmFwUpdateBuilder.Designer.cs
@@ -433,7 +433,6 @@
this.tbxCordonelProductionOrdersSearch.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.tbxCordonelProductionOrdersSearch.Name = "tbxCordonelProductionOrdersSearch";
this.tbxCordonelProductionOrdersSearch.MouseClick += new System.Windows.Forms.MouseEventHandler(this.tbxCordonelProductionOrdersSearch_MouseClick);
- this.tbxCordonelProductionOrdersSearch.Enter += new System.EventHandler(this.tbxCordonelProductionOrdersSearch_Enter);
this.tbxCordonelProductionOrdersSearch.KeyDown += new System.Windows.Forms.KeyEventHandler(this.tbxCordonelProductionOrdersSearch_KeyDown);
//
// cbxCordonelProductionOrdersSearch
@@ -441,7 +440,6 @@
resources.ApplyResources(this.cbxCordonelProductionOrdersSearch, "cbxCordonelProductionOrdersSearch");
this.cbxCordonelProductionOrdersSearch.FormattingEnabled = true;
this.cbxCordonelProductionOrdersSearch.Name = "cbxCordonelProductionOrdersSearch";
- this.cbxCordonelProductionOrdersSearch.DropDownClosed += new System.EventHandler(this.btnCordonelSearch_Click);
//
// lblInfoSelectCustomer
//
diff --git a/ServiceFwUpdate/Ui/ServiceFwUpdateSw/FrmServiceFwUpdateSw.cs b/ServiceFwUpdate/Ui/ServiceFwUpdateSw/FrmServiceFwUpdateSw.cs
index 0f816d6f..fee69f87 100644
--- a/ServiceFwUpdate/Ui/ServiceFwUpdateSw/FrmServiceFwUpdateSw.cs
+++ b/ServiceFwUpdate/Ui/ServiceFwUpdateSw/FrmServiceFwUpdateSw.cs
@@ -88,8 +88,8 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
private const Int32 MaxPartialFileDataSize = 2 * 1024;
// boot variables, reboot timeout before stopping PCB ID readout trials
- private const Int32 RebootTimeoutMs = 120000;
- private Int32 _bootDelayCtrMs;
+ private const Int32 RebootTimeout_ms = 120000;
+ private Int32 _bootDelayCtr_ms;
private Boolean _timerIntervalExpired;
private Boolean _timerDisplayOn;
private Int32 _progressBarValueCounter;
@@ -133,7 +133,7 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
// license setup with start up check delay to end program if license is unknown
private SoftwareLicense _softwareLicense;
- private Int32 _licenseCheckTimerMs = 2000;
+ private Int32 _licenseCheckTimer_ms = 2000;
// extended information of safe for report
private FwUpdateSafeInfo _fwUpdateSafeInfo;
@@ -171,6 +171,11 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
//// directory information
//private String _currentDirectory;
+ // Login retry parameters to delay recurrent login trial after unsuccessfully trial to avoid lock
+ // of authentication by the meter
+ private Int32 _loginDelay_ms;
+ private const Int32 DefaultLoginDelay_ms = 1000;
+
// directory information
private List _readMeterFiles;
@@ -223,7 +228,7 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
/// Timer for progress update
///
private readonly System.Threading.Timer _tmrProgressUpdate;
- private const Int32 TimerIntervalMs = 200;
+ private const Int32 TimerInterval_ms = 200;
#endregion --------------------------------------- Variables --------------------------------------------------
@@ -545,7 +550,7 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
switch (_processState)
{
case ProcessState.Idle:
- if (_softwareLicense == null && (_licenseCheckTimerMs -= TimerIntervalMs) < 0)
+ if (_softwareLicense == null && (_licenseCheckTimer_ms -= TimerInterval_ms) < 0)
_processState = ProcessState.ValidateSoftware;
break;
case ProcessState.EraseMeterFiles:
@@ -1794,14 +1799,14 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
lutLineList.Add(lutLine);
if (lutFileFormatValid)
{
- if (_fwUpdateSafeLutFile == null || _fwUpdateSafeLutFile.BinData.Count != MeterLutFile.SizeLutFile)
+ if (_fwUpdateSafeLutFile == null || _fwUpdateSafeLutFile.BinData.Count != meterLutFile.SizeLutFile)
{
LogStringList(Resources.StrMessageLutFile, lutLineList,
Resources.StrLutFileFromMeterValid);
}
else
{
- for (var c = 0; c < MeterLutFile.SizeLutFile; c++)
+ for (var c = 0; c < meterLutFile.DataLength; c++)
{
// If one byte is different the comparison failed
if (_fwUpdateSafeLutFile.BinData[c] != meterLutFile.BinData[c])
@@ -3008,25 +3013,25 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
{
String text = null;
// var timerInterval = _tmrProgressUpdate.Interval;
- var timerInterval = TimerIntervalMs;
- _bootDelayCtrMs = 0;
- var internalCommunicationDelayMs = _bootDelayCtrMs + 10 * timerInterval;
+ var timerInterval = TimerInterval_ms;
+ _bootDelayCtr_ms = 0;
+ var internalCommunicationDelayMs = _bootDelayCtr_ms + 10 * timerInterval;
- while (_bootDelayCtrMs < RebootTimeoutMs && string.IsNullOrEmpty(text))
+ while (_bootDelayCtr_ms < RebootTimeout_ms && string.IsNullOrEmpty(text))
{
if (!_timerIntervalExpired)
continue;
_timerIntervalExpired = false;
// internal communication delay to avoid overload of Cordonel
- if (_bootDelayCtrMs % internalCommunicationDelayMs == 0)
+ if (_bootDelayCtr_ms % internalCommunicationDelayMs == 0)
{
text = RegisterConverter.ConvertTo(
_currentGenesis.ReadRegister(Register.Configexchange.PcbSerialNumber, 12));
}
ProcessUpdate_Event(this, new ProcessExecEventArgs(Resources.StrUpdateAppAndRestartMeter,
- _bootDelayCtrMs * 100.0 / RebootTimeoutMs));
- _bootDelayCtrMs += timerInterval;
+ _bootDelayCtr_ms * 100.0 / RebootTimeout_ms));
+ _bootDelayCtr_ms += timerInterval;
}
return !string.IsNullOrEmpty(text);
@@ -3358,6 +3363,9 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
///
/// - Enabled final connect with passwordLvl8 and skeletonKey to enable installation of password file.
///
+ ///
+ /// - LoginDelay dynamically based on trials, reset after successfully login.
+ ///
private Boolean ExecConnect()
{
// If the PCB ID is not set (read from meter) this is the first initial login.
@@ -3402,14 +3410,12 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
return false;
}
- // Delay needed if repeated login trial given by Cordonel, the next communication has to
- // wait that long, otherwise the Cordonel locks for 2s, 4s, 8s, 16s and so on on every retry!
- Thread.Sleep(3000);
-
// This login may be time consuming on readout of application information
// first try to login with password Level 8, this is needed if the password file is installed
if (LoginAndSpecialSetupProcedure(_passwordLvl8))
{
+ // Reset login delay as on successfully login the meter resets the retry-lock-in-delay
+ _loginDelay_ms = DefaultLoginDelay_ms;
LogText(Resources.StrLoginPwdLevel8);
_passwordFileIsCorrupted = false;
return true;
@@ -3417,11 +3423,14 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
// Delay needed if repeated login trial given by Cordonel, the next communication has to
// wait that long, otherwise the Cordonel locks for 2s, 4s, 8s, 16s and so on on every retry!
- Thread.Sleep(5000);
+ _loginDelay_ms *= 2;
+ Thread.Sleep(_loginDelay_ms);
// Use the skeleton key for login as the password file may not be installed or invalid
if (LoginAndSpecialSetupProcedure(_skeletonKey))
{
+ // Reset login delay as on successfully login the meter resets the retry-lock-in-delay
+ _loginDelay_ms = DefaultLoginDelay_ms;
LogText(Resources.StrLoginSkeletonKey);
return true;
}
@@ -3453,26 +3462,47 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
///
/// - Clean error collection messages on initial connect.
///
+ ///
+ /// - Retries on pulse mode switching off as this is very critical for a healthy communication and
+ /// may cause unpredictable behaviour if it fails.
+ ///
private Boolean LoginAndSpecialSetupProcedure(String password)
{
Boolean retVal;
+ var pulseModeOffRetryCtr = 2;
if (_initialConnect)
{
// Start with a fresh list of errors to decide after the entire procedure how to proceed
_errorCollectionMessages?.Clear();
- // Login without reading all registers and FW keeping the communication to a minimum to switch
- // the pulse mode OFF before reading all installed apps, which will be unpredictable on activated
- // pulse module.
- retVal = _currentGenesis.Login(password, skipReadMeterFwAndAssignRegisters: true);
+ do
+ {
+ // Login without reading all registers and FW keeping the communication to a minimum to switch
+ // the pulse mode OFF before reading all installed apps, which will be unpredictable on activated
+ // pulse module.
+ retVal = _currentGenesis.Login(password, skipReadMeterFwAndAssignRegisters: true);
+ if (retVal)
+ {
+ // Switch the pulse module inactive on initial login at first connect and log out
+ DeactivatePulseMode();
+ }
+ else
+ {
+ // Delay needed if repeated login trial given by Cordonel, the next communication has to
+ // wait that long, otherwise the Cordonel locks for 2s, 4s, 8s, 16s and so on on every retry!
+ _loginDelay_ms *= 2;
+ Thread.Sleep(_loginDelay_ms);
+ }
+
+ // Increase th login delay to avoid
+ } while (!retVal && pulseModeOffRetryCtr-- > 0);
+
+ // If the login couldn't be performed exit with error
if (!retVal)
{
return false;
}
-
- // Switch the pulse module inactive on initial login at first connect and log out
- DeactivatePulseMode();
}
// Second login if initial was executed including reading out all installed applications
@@ -4157,6 +4187,10 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
///
/// - Initial.
///
+ ///
+ /// - For FW version without LUT file needed return with success state,
+ /// - Reading initially the header to get the length of the LUT.
+ ///
private void RestoreLutFile(ProcessState successExitState, ProcessState errorExitState = ProcessState.Error)
{
// Remind the invoker being able to generate error messages based on the last state
@@ -4183,6 +4217,7 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
// 1. b) LUT file not installed and not delivered by the FW update safe
// This FW version does not require a LUT file
InfoProcessSuccess(lblLutFileCheck, Resources.StrLutFileNotNeeded);
+ _processState = successExitState;
LogText(Resources.StrLutFileNotNeeded);
return;
}