Initial version of LUT file write GTB2.2.0

This commit is contained in:
Thomas Wiedebusch
2022-03-03 00:31:58 +01:00
parent 14eda41bdd
commit a281e753c4
8 changed files with 331 additions and 85 deletions
@@ -1047,6 +1047,11 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// </summary>
public String CoreRevision;
/// <summary>
/// This is the FLEXNET version which describes the entire packet.
/// </summary>
public String FwVersion;
/// <summary>
/// Region (EMEA or NA) and Radio frequency (433 or 868 or null).
/// </summary>
@@ -1102,6 +1107,8 @@ 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 (readFwVersion != 0)
{
@@ -70,6 +70,7 @@
<Compile Include="Consts\FwUpdateState.cs" />
<Compile Include="Consts\FwUpdateStateInfo.cs" />
<Compile Include="Consts\FwUpdateStateText.cs" />
<Compile Include="MeterLutFile.cs" />
<Compile Include="MeterFileRestore.cs" />
<Compile Include="MeterFilesEraseRestore.cs" />
<Compile Include="MeterLutUpdate.cs" />
@@ -91,6 +92,14 @@
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\Logic.PrdoctionToProductMapper\Logic.ProductionToProductMapper.csproj">
<Project>{D0C859D9-D55E-4E85-AC50-0FF31B1CE50D}</Project>
<Name>Logic.ProductionToProductMapper</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Utils\Crc16Ccitt\Crc16Ccitt.csproj">
<Project>{91DEF0C0-AA4F-40AE-8F18-CB717FDE7E7F}</Project>
<Name>Crc16Ccitt</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Utils\Logging\Logging.csproj">
<Project>{4B88B0D3-E791-4774-9521-EABEACDC420E}</Project>
<Name>Logging</Name>
@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using Logic.ProductionToProductMapper.Cordonel;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
{
/// <summary>
/// File for metrology look up table
/// </summary>
public class MeterLutFile
{
/// <summary>
/// File name of the file on PC
/// </summary>
public String LutPcFileName;
/// <summary>
/// Ctor file applications
/// </summary>
/// <param name="lutPcFileName"></param>
public MeterLutFile(String lutPcFileName)
{
LutPcFileName = lutPcFileName;
}
/// <summary>
/// File ID for LUT file
/// </summary>
public String StrLutFileId;
/// <summary>
/// Data length
/// </summary>
public UInt32 DataLength;
/// <summary>
/// Version of LUT file
/// </summary>
public UInt16 Version;
/// <summary>
/// Check of LUT file for verification and register write, read from file
/// </summary>
public UInt16 FileCrc;
/// <summary>
/// Calculated during file processing for verification
/// </summary>
public UInt16 CalculatedCrc;
/// <summary>
/// Validation of LUT file
/// </summary>
public Boolean IsValid;
/// <summary>
/// Binary file content
/// </summary>
public List<Byte> BinData = new List<Byte>();
/// <summary>
/// Meter size
/// </summary>
public MeterSize MeterSize;
}
}
@@ -2,12 +2,13 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using Xylem.Common.Hardware.WaterMeter.Genesis.Applications;
using Logic.ProductionToProductMapper.Cordonel;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.Consts;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.Properties;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore.Consts;
using Xylem.Common.Utils.Crc16Ccitt;
using Xylem.Common.Utils.ProcessExec;
using Xylem.Common.Utils.ProcessExec.EventArguments;
@@ -26,14 +27,43 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
public event EventHandler<ProcessExecEventArgs> OnProcessUpdate;
//disk and name of lookup file
private const String StrLutFileName = "1\\mettbl";
private const String StrLutMeterFileName = "1\\mettbl";
//disk and name of lookup file
private const String StrLutBackupFileName = "1\\mettbl_b";
private const String StrLutBackupMeterFileName = "1\\mettbl_b";
// string as identifier for Genesis lookup table
private const String TablesFileMagic = "GEN_LUT";
// identifier for Genesis lookup table
private const String StrLutFileId = "GEN_LUT\0";
private const Int32 IndexLutFileId = 0;
private const UInt32 LengthLutFileId = 8;
// data length, calculated from version field to the end of the data section
private const Int32 IndexDataLength = 8;
private const Int32 LengthDataLength = 4;
// CCITT-CRC-16 , calculated from version field to the end of the data section
private const Int32 IndexCrc = 12;
private const UInt32 LengthCrc = 2;
// version
private const Int32 IndexVersion = 14;
private const Int32 LengthVersion = 2;
// meter size as enumeration
private const Int32 IndexMeterSize = 16;
// header size of file
private const UInt32 LutFileHeaderLength =
LengthLutFileId + LengthDataLength + LengthCrc + LengthVersion;
// data size of file
private const Int32 LutFileDataLength = 730;
// LUT file entire file size
private const UInt32 SizeLutFile = LutFileHeaderLength + LutFileDataLength;
// process display message
private const String StrProcessLut = "Processing metrology lookup table";
//trigger update retries
@@ -62,9 +92,10 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
private Int32 _overallBytesCtr;
// Look up table file
private Int32 _lutCrc;
private Byte _meterSize;
public FileApplications LutFile;
public MeterLutFile LutFile;
// actual processed file
private String _actualFileName;
#endregion
@@ -142,7 +173,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
{
_genesisMeter = genesisMeter;
_actualOperation = "";
LutFile = null;
_lutUpdateState = LutUpdateState.Idle;
}
@@ -181,7 +211,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// </remarks>
public String GetLutUpdateStateOperation()
{
return _lutUpdateState == LutUpdateState.Idle ? "" : "Downloading...";
return _lutUpdateState == LutUpdateState.Idle ? "" : $"Downloading {_actualFileName}...";
}
#endregion
@@ -299,7 +329,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
/// </remarks>
public Boolean UpdatePreparation()
{
_actualOperation = "";
_actualOperation = "Update preparation";
_lutUpdateState = LutUpdateState.Idle;
_meterFile = new MeterFile(_genesisMeter);
@@ -418,41 +448,43 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
#region LutFile
/// <summary>
/// Check the content of the metrology lookup table file:
/// - begins with "APP>",
/// - Application ID at position 0x28,
/// - CRC at position 0x04 LSB, 0x05 MSB
/// - Version at position 0x06 and 0x07 decimal
/// - Build upgrade meter file name
/// Check the content of the metrology lookup table file
/// </summary>
/// <returns></returns>
/// <remarks date="2022-Feb-25" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private static Boolean ValidateLutFile()
private Boolean ValidateLutFile()
{
//var fileApp = new FileApplications();
//fileApp.AppId = fileApp.BinData[FileAppAppIdIndex];
//fileApp.Crc = (UInt16)(fileApp.BinData[FileAppCrcIndex] + (fileApp.BinData[FileAppCrcIndex + 1] << 8));
//fileApp.Version = (UInt32)((fileApp.BinData[FileAppVersionIndex] & 0x0F)
// + ((fileApp.BinData[FileAppVersionIndex] & 0xF0) >> 4) * 10
// + (fileApp.BinData[FileAppVersionIndex + 1] & 0x0F) * 100
// + ((fileApp.BinData[FileAppVersionIndex + 1] & 0xF0) >> 4) * 1000);
// check if LUT file contains data
if (LutFile?.BinData == null || LutFile.BinData.Count < SizeLutFile) return false;
//fileApp.StrVersion = GenesisMeter.BuildFwVersionString(fileApp.BinData[FileAppVersionIndex + 1],
// fileApp.BinData[FileAppVersionIndex]);
//var fileAppStartId = Encoding.UTF8.GetString(fileApp.BinData.ToArray(), 0, 4);
////check update file start identifier
//if (fileAppStartId != StrFileAppStartId)
//{
// return false;
//}
LutFile.IsValid = false;
// extract the identifier and check, if this is a LUT file
LutFile.StrLutFileId =
Encoding.UTF8.GetString(LutFile.BinData.ToArray(), IndexLutFileId, IndexDataLength);
if (LutFile.StrLutFileId != StrLutFileId) return false;
////TODO THW check CRC
////TODO THW check upgrade file name against content to select a valid package
////the meter file name is needed for writing the file to the meter or reading it back
//fileApp.MeterFilename = StrUpgradeAppPartialFileName + $"{fileApp.AppId:X2}";
return true;
LutFile.MeterSize = (MeterSize)LutFile.BinData[IndexMeterSize];
LutFile.FileCrc = (UInt16)(LutFile.BinData[IndexCrc] + (LutFile.BinData[IndexCrc + 1] << 8));
LutFile.Version = (UInt16)(LutFile.BinData[IndexVersion] + (LutFile.BinData[IndexVersion + 1] << 8));
LutFile.DataLength = (UInt32)(LutFile.BinData[IndexDataLength]
+ (LutFile.BinData[IndexDataLength + 1] << 8)
+ (LutFile.BinData[IndexDataLength + 2] << 16)
+ (LutFile.BinData[IndexDataLength + 3] << 24));
// calculate CRC and compare this with the file CRC
var entireFile = new List<Byte>();
entireFile.AddRange(LutFile.BinData);
var payload = new List<Byte>();
payload.AddRange(entireFile.GetRange(IndexVersion, LutFileDataLength + LengthVersion));
var calculatedCrc = Crc16Ccitt.CalculateMsb1021(payload.ToArray());
if (calculatedCrc == LutFile.FileCrc)
{
LutFile.CalculatedCrc = calculatedCrc;
LutFile.IsValid = true;
return true;
}
return false;
}
/// <summary>
@@ -465,15 +497,19 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
private Boolean PrepareLutDownload()
{
Boolean returnValue;
_actualOperation = "Write Meter Size";
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
{
returnValue = _genesisMeter.WriteRegister<Byte>(Register.Genesisflow.MeterSize, _meterSize);
returnValue &= _genesisMeter.WriteRegister<Int32>(Register.Genesisflow.LookupFileCrc, _lutCrc);
_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);
if (!returnValue)
@@ -504,11 +540,27 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
var retryCtr = 0;
Boolean returnValue;
if (LutFile == null) return false;
//write file portion and retry if not successful
do
{
returnValue = _meterFile.WriteMeterFile(StrLutFileName, LutFile.BinData.ToArray());
returnValue &= _meterFile.WriteMeterFile(StrLutBackupFileName, LutFile.BinData.ToArray());
_actualFileName = StrLutMeterFileName;
// unlock, erase and write original
returnValue = _meterFile.UnlockEraseWriteMeterFile(_actualFileName);
_actualOperation = $"Erase {_actualFileName}";
returnValue &= _meterFile.EraseMeterFile(_actualFileName);
_actualOperation = $"Write {_actualFileName}";
returnValue &= _meterFile.WriteMeterFile(_actualFileName, LutFile.BinData.ToArray());
_actualFileName = StrLutBackupMeterFileName;
// write backup
returnValue &= _meterFile.UnlockEraseWriteMeterFile(_actualFileName);
_actualOperation = $"Erase {_actualFileName}";
returnValue &= _meterFile.EraseMeterFile(_actualFileName);
_actualOperation = $"Write {_actualFileName}";
returnValue &= _meterFile.WriteMeterFile(_actualFileName, LutFile.BinData.ToArray());
if (!returnValue)
{
@@ -540,7 +592,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
}
LutFile = null;
LutFile = new FileApplications(filePathName)
LutFile = new MeterLutFile(filePathName)
{
BinData = new List<Byte>(File.ReadAllBytes(filePathName))
};