CUST: - FwUpdateSw: - Retries for pulse mode deactivation, - dynamic retry delay
common/.../GenesisFile/MeterLutFile: - dynamic file size based on LUT file header information
This commit is contained in:
parent
d62b55790c
commit
7727f8d18e
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// File name of the file on PC
|
||||
/// </summary>
|
||||
@ -78,7 +79,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
/// <summary>
|
||||
/// Data length
|
||||
/// </summary>
|
||||
public UInt32 DataLength;
|
||||
private UInt32 _dataLength;
|
||||
public UInt32 DataLength
|
||||
{
|
||||
get => _dataLength;
|
||||
set
|
||||
{
|
||||
SizeLutFile = (Int32)value + LutFileHeaderLength;
|
||||
_dataLength = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Version of LUT file
|
||||
@ -116,14 +126,21 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
public MeterSize MeterSize;
|
||||
|
||||
/// <summary>
|
||||
/// ATTENTION: The file size is dynamic!
|
||||
/// Verifies the LUT format based on its contents
|
||||
/// </summary>
|
||||
/// <returns>true if valid</returns>
|
||||
/// <remarks date="2023-Nov-13" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Nov-17" author="Thomas Wiedebusch">
|
||||
/// - Removed constant size, instead using header to calculate the size of the file.
|
||||
/// </remarks>
|
||||
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<Byte>();
|
||||
payload.AddRange(entireFile.GetRange(MeterLutFile.IndexVersion,
|
||||
MeterLutFile.LutFileDataLength + MeterLutFile.LengthVersion));
|
||||
(Int32)DataLength + MeterLutFile.LengthVersion));
|
||||
CalculatedCrc = Crc16Ccitt.CalculateMsb1021(payload.ToArray());
|
||||
if (CalculatedCrc != FileCrc)
|
||||
{
|
||||
|
||||
@ -486,13 +486,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
|
||||
/// </remarks>
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
//
|
||||
|
||||
@ -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<String> _readMeterFiles;
|
||||
|
||||
@ -223,7 +228,7 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
|
||||
/// Timer for progress update
|
||||
/// </summary>
|
||||
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<String>(
|
||||
_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
|
||||
/// <remarks date="2023-Nov-09" author="Thomas Wiedebusch">
|
||||
/// - Enabled final connect with passwordLvl8 and skeletonKey to enable installation of password file.
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Nov-17" author="Thomas Wiedebusch">
|
||||
/// - LoginDelay dynamically based on trials, reset after successfully login.
|
||||
/// </remarks>
|
||||
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
|
||||
/// <remarks date="2023-Nov-15" author="Thomas Wiedebusch">
|
||||
/// - Clean error collection messages on initial connect.
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Nov-17" author="Thomas Wiedebusch">
|
||||
/// - Retries on pulse mode switching off as this is very critical for a healthy communication and
|
||||
/// may cause unpredictable behaviour if it fails.
|
||||
/// </remarks>
|
||||
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
|
||||
/// <remarks date="2023-Nov-13" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Nov-17" author="Thomas Wiedebusch">
|
||||
/// - For FW version without LUT file needed return with success state,
|
||||
/// - Reading initially the header to get the length of the LUT.
|
||||
/// </remarks>
|
||||
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;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user