LUT update improvements

This commit is contained in:
Thomas Wiedebusch
2022-03-03 21:47:54 +01:00
parent a281e753c4
commit 4d9186a322
9 changed files with 367 additions and 140 deletions
@@ -1052,6 +1052,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// </summary>
public String FwVersion;
/// <summary>
/// This is the Metrology Lookup Table CRC.
/// </summary>
public String LutCrc;
/// <summary>
/// This is the meter size.
/// </summary>
public String MeterSize;
/// <summary>
/// Region (EMEA or NA) and Radio frequency (433 or 868 or null).
/// </summary>
@@ -1107,8 +1117,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
//build the version string, because e.g. FLEXNETVERSION is one application which does not
//follow the same rule. After the upper conversion, the hexadecimal outline will be lost
versionString = BuildFwVersionString(readFwVersionBytes[1], readFwVersionBytes[0]);
if (appVersionToRead.AppName == "FLEXNETVERSION")
FwVersion = versionString;
if (appVersionToRead.AppName == "FLEXNETVERSION") FwVersion = versionString;
if (readFwVersion != 0)
{
@@ -1139,6 +1148,15 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
MetrologyUpgradePermission = RegisterConverter.ConvertTo<Byte>(
ReadRegister(Register.System.MetrologyUpgradePermission));
//read metrology lookup table CRC
var lutCrc = RegisterConverter.ConvertTo<UInt32>(ReadRegister(Register.Genesisflow.LookupFileCrc));
LutCrc = $@"0x{lutCrc:X4}";
//read meter size
MeterSize = MeterSizeConverter.ConvertMeterSizeEnumToSizeName((MeterSize)RegisterConverter.ConvertTo<Byte>(
ReadRegister(Register.Genesisflow.MeterSize)));
//read core revision
var coreRegisterRead = RegisterConverter.ConvertTo<String>(ReadRegister(Register.System.CoreRevision, 16));
var coreRevision = coreRegisterRead?.Split('\0');
@@ -560,7 +560,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
//set extended timeout for file operations
_currentGenesis.TransmitProtocol.SetResponseTimeout(ExtendedFileIoTimeoutMs);
CommunicationConfig.RequestRetries = 0;
//write "remove-command" to meter, wait for result and read back (read back returns false because of unreadable content)
//write "remove-command" to meter, wait for result and read back
//ATTENTION: read back returns FALSE because of unreadable content
_currentGenesis.WriteRegister(Register.Configexchange.FileRemove, fileName, true, true);
//set timeout back to default value
_currentGenesis.TransmitProtocol.SetDefaultResponseTimeout();
@@ -67,13 +67,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
private const String StrProcessLut = "Processing metrology lookup table";
//trigger update retries
private const Int32 RegisterWriteRetries = 2;
private const Int32 RegisterWriteRetries = 0;
//update reties for files
private const Int32 FileWriteRetries = 0;
//retry of entire update procedure
private const Int32 UpdateProcedureRetries = 5;
private const Int32 UpdateProcedureRetries = 0;
//threshold to increase the file write timing
private const Int32 IncreaseTimeoutUpdateProcedureRetries = 4;
@@ -87,17 +87,22 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
private String _actualOperation;
private LutUpdateState _lutUpdateState;
// Process counter for caller to monitor actual progress
private Int32 _processedBytesCtr;
private Int32 _overallBytesCtr;
// Look up table file
public MeterLutFile LutFile;
// actual processed file
private String _actualFileName;
// list of names of installed meter files on drive 1
private List<String> _meterFilesDrive1;
// number of operations for over all access
private const Int32 NumberOfOperations = 11;
private Int32 _operationCtr;
// error message for display of error reason
public String ErrorMessage;
#endregion
#region Events
@@ -124,18 +129,10 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// <summary>
/// Process counter in percent
/// </summary>
/// <remarks date="2019-Jun-20" author="Thomas Wiedebusch">
/// <remarks date="2022-Mar-03" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
public Double OverallProcessCtrPercent
{
get
{
var processFileBytes = _meterFile?.ProcessedBytesCtr ?? 0;
return 100.0 * (processFileBytes + _processedBytesCtr) /
(_overallBytesCtr > 0 ? _overallBytesCtr : 1);
}
}
public Double OverallProcessCtrPercent => 100.0 * _operationCtr / NumberOfOperations;
/// <summary>
/// Single file process counter in percent
@@ -211,7 +208,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// </remarks>
public String GetLutUpdateStateOperation()
{
return _lutUpdateState == LutUpdateState.Idle ? "" : $"Downloading {_actualFileName}...";
return _lutUpdateState == LutUpdateState.Idle ? "" : "Processing...";
}
#endregion
@@ -270,6 +267,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
return false;
}
_operationCtr = 0;
_actualOperation = "";
ErrorMessage = "";
_lutUpdateState = LutUpdateState.StartInitial;
while (_lutUpdateState != LutUpdateState.Idle && !StopUpdateProcess)
{
@@ -308,13 +308,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
StopUpdateProcess = false;
//reset all counters
_processedBytesCtr = 0;
_overallBytesCtr = 0;
_updateProcedureRetryCtr = 0;
//set state machine for automatic FW update
_lutUpdateState = LutUpdateState.Idle;
_actualOperation = "";
_operationCtr = 0;
//logout/login/auto-login
ReestablishMeterFileSystem();
@@ -402,8 +401,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
break;
case LutUpdateState.StepFailed:
_processedBytesCtr = 0;
_overallBytesCtr = 0;
_lutUpdateState = _updateProcedureRetryCtr++ < UpdateProcedureRetries
? LutUpdateState.RepeatLutUpdate
@@ -411,8 +408,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
break;
case LutUpdateState.RepeatLutUpdate:
_processedBytesCtr = 0;
_overallBytesCtr = 0;
_lutUpdateState = LutUpdateState.DownloadLutFile;
if (_updateProcedureRetryCtr >= IncreaseTimeoutUpdateProcedureRetries)
{
@@ -422,8 +417,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
break;
case LutUpdateState.UpdateFailed:
_processedBytesCtr = 0;
_overallBytesCtr = 0;
StopUpdateProcess = true;
_lutUpdateState = LutUpdateState.Idle;
break;
@@ -457,7 +450,11 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
private Boolean ValidateLutFile()
{
// check if LUT file contains data
if (LutFile?.BinData == null || LutFile.BinData.Count < SizeLutFile) return false;
if (LutFile?.BinData == null || LutFile.BinData.Count < SizeLutFile)
{
ErrorMessage += "File size mismatch!";
return false;
}
LutFile.IsValid = false;
// extract the identifier and check, if this is a LUT file
@@ -478,13 +475,15 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
var payload = new List<Byte>();
payload.AddRange(entireFile.GetRange(IndexVersion, LutFileDataLength + LengthVersion));
var calculatedCrc = Crc16Ccitt.CalculateMsb1021(payload.ToArray());
if (calculatedCrc == LutFile.FileCrc)
if (calculatedCrc != LutFile.FileCrc)
{
LutFile.CalculatedCrc = calculatedCrc;
LutFile.IsValid = true;
return true;
ErrorMessage += "CRC Mismatch!";
return false;
}
return false;
LutFile.CalculatedCrc = calculatedCrc;
LutFile.IsValid = true;
return true;
}
/// <summary>
@@ -496,21 +495,44 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// </remarks>
private Boolean PrepareLutDownload()
{
Boolean returnValue;
_actualOperation = "Write Meter Size";
var returnValue = true;
var retryCtr = 0;
if (LutFile == null || _genesisMeter == null || _meterFile == null) return false;
//set extended timeout for trigger upgrade response delay
_genesisMeter.TransmitProtocol.SetResponseTimeout(5000);
do
{
_actualOperation = "Write Meter Size";
returnValue = _genesisMeter.WriteRegister(Register.Genesisflow.MeterSize, (Byte)LutFile.MeterSize);
_actualOperation = "Write CRC";
returnValue &= _genesisMeter.WriteRegister<UInt32>(Register.Genesisflow.LookupFileCrc, LutFile.FileCrc);
_actualOperation = "Store calibration";
returnValue &= _genesisMeter.WriteRegister<Byte>(Register.Genesisflow.StoreCalibration, 1);
_actualOperation = "Write meter size";
_operationCtr++;
if (!_genesisMeter.WriteRegister(Register.Genesisflow.MeterSize, (Byte)LutFile.MeterSize))
{
ErrorMessage = "Meter size could not be set!\n";
_operationCtr--;
returnValue = false;
}
else
{
_operationCtr++;
_actualOperation = "Write Lut CRC to meter";
if (!_genesisMeter.WriteRegister<UInt32>(Register.Genesisflow.LookupFileCrc, LutFile.FileCrc))
{
ErrorMessage += "Meter LUT CRC could not be set!\n";
_operationCtr--;
returnValue = false;
}
else
{
_operationCtr++;
_actualOperation = "Store calibration to meter";
if (!_genesisMeter.WriteRegister(Register.Genesisflow.StoreCalibration, 1))
{
ErrorMessage += "Meter store calibration failed!\n";
_operationCtr--;
returnValue = false;
}
}
}
if (!returnValue)
{
@@ -525,7 +547,36 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
}
/// <summary>
/// Download the metrology lookup table files
/// Erase file and check if done!
/// </summary>
/// <returns></returns>
/// <remarks date="2022-Mar-03" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private Boolean EraseFile(String fileDriveName)
{
var returnValue = _meterFile.UnlockEraseWriteMeterFile(fileDriveName);
//erase returns always TRUE, even if the erasure failed! Check with catalogue
_meterFile.EraseMeterFile(fileDriveName);
_meterFilesDrive1.Clear();
if (_meterFile.ReadMeterFileCatalog(out var meterFilesDrive1, MeterFile.StrMeterDrive1,
MeterFile.WildcardAll.ToString()))
{
_meterFilesDrive1.AddRange(meterFilesDrive1);
if (_meterFilesDrive1.Contains(fileDriveName))
{
returnValue = false;
}
}
else
{
returnValue = false;
}
return returnValue;
}
/// <summary>
/// Download the metrology lookup table files and read the catalog of drive 1
/// </summary>
/// <returns></returns>
/// <remarks date="2022-Feb-16" author="Thomas Wiedebusch">
@@ -535,32 +586,97 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
{
//counters for actual process information
_processedBytesCtr = 0;
_overallBytesCtr = 0;
var retryCtr = 0;
Boolean returnValue;
if (LutFile == null) return false;
//set extended timeout for trigger upgrade response delay
_genesisMeter.TransmitProtocol.SetResponseTimeout(5000);
var returnValue = true;
//write file portion and retry if not successful
do
{
// read all files which are already installed
_actualOperation = "Read installed meter files drive 1";
_operationCtr++;
if (_meterFilesDrive1 == null)
{
_meterFilesDrive1 = new List<String>();
}
_meterFilesDrive1.Clear();
if (_meterFile.ReadMeterFileCatalog(out var meterFilesDrive1, MeterFile.StrMeterDrive1,
MeterFile.WildcardAll.ToString()))
{
_meterFilesDrive1.AddRange(meterFilesDrive1);
}
// erase file
_operationCtr++;
_actualFileName = StrLutMeterFileName;
// unlock, erase and write original
returnValue = _meterFile.UnlockEraseWriteMeterFile(_actualFileName);
_actualOperation = $"Erase {_actualFileName}";
returnValue &= _meterFile.EraseMeterFile(_actualFileName);
if (!EraseFile(_actualFileName))
{
ErrorMessage += $"LUT file {_actualFileName} not erased!\n";
returnValue = false;
}
_operationCtr++;
_actualOperation = $"Write {_actualFileName}";
returnValue &= _meterFile.WriteMeterFile(_actualFileName, LutFile.BinData.ToArray());
if (!_meterFile.WriteMeterFile(_actualFileName, LutFile.BinData.ToArray()))
{
ErrorMessage += $"Writing of {_actualFileName} failed!\n";
returnValue = false;
}
// erase file
_operationCtr++;
_actualFileName = StrLutBackupMeterFileName;
// write backup
returnValue &= _meterFile.UnlockEraseWriteMeterFile(_actualFileName);
_actualOperation = $"Erase {_actualFileName}";
returnValue &= _meterFile.EraseMeterFile(_actualFileName);
if (!EraseFile(_actualFileName))
{
ErrorMessage += $"LUT file {_actualFileName} not erased!\n";
returnValue = false;
}
_operationCtr++;
_actualOperation = $"Write {_actualFileName}";
returnValue &= _meterFile.WriteMeterFile(_actualFileName, LutFile.BinData.ToArray());
if (!_meterFile.WriteMeterFile(_actualFileName, LutFile.BinData.ToArray()))
{
ErrorMessage += $"Writing of {_actualFileName} failed!\n";
returnValue = false;
}
_operationCtr++;
_actualOperation = $"Write {_actualFileName}";
if (!_meterFile.WriteMeterFile(_actualFileName, LutFile.BinData.ToArray()))
{
ErrorMessage += $"Writing of {_actualFileName} failed!\n";
returnValue = false;
}
_operationCtr++;
_actualOperation = "Read installed meter files drive 1";
_meterFilesDrive1.Clear();
if (!_meterFile.ReadMeterFileCatalog(out meterFilesDrive1, MeterFile.StrMeterDrive1,
MeterFile.WildcardAll.ToString()))
{
returnValue = false;
}
else
{
_meterFilesDrive1.AddRange(meterFilesDrive1);
if (!_meterFilesDrive1.Contains(StrLutMeterFileName))
{
ErrorMessage += $"LUT file {StrLutMeterFileName} not installed!\n";
returnValue = false;
}
if (!_meterFilesDrive1.Contains(StrLutBackupMeterFileName))
{
ErrorMessage += $"LUT file {StrLutBackupMeterFileName} not installed!\n";
returnValue = false;
}
}
if (!returnValue)
{
@@ -568,10 +684,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
}
} while (!returnValue && retryCtr++ < FileWriteRetries && !StopUpdateProcess);
returnValue &= retryCtr <= FileWriteRetries;
//update information for process bar
_processedBytesCtr += LutFile.BinData.Count;
//set timeout back to default value
_genesisMeter.TransmitProtocol.SetDefaultResponseTimeout();
return !StopUpdateProcess && returnValue;
}
@@ -83,7 +83,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
public static readonly String NumFirePulses = "GENESISFLOW_NumFirePulses";
public static readonly String LookupFileCrc = "GENESISFLOW_LookupFileCrc";
};
public static class Powermon
@@ -122,6 +121,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
Configexchange.FileClose,
Configexchange.FileWrite,
Configexchange.FileRead,
Configexchange.Catalogue,
Configexchange.GetFilePointerOffset,
Configexchange.SetFilePointerOffset,
Configexchange.FileRemove,
@@ -136,6 +136,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
Genesisflow.TriggerIdle,
Genesisflow.LedMode,
Genesisflow.SampleRate,
Genesisflow.MeterSize,
Genesisflow.LookupFileCrc,
Genesisflow.StoreCalibration,
Sensusradio.WakeupInterval,
Sensusradio.FrequencyIndicator