common/Hardware/WaterMeter/Genesis/GenesisFile/MeterLutFile.cs
2026-04-23 17:50:07 +02:00

184 lines
6.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Text;
using Xylem.Common.Logic.ProductionOrderCore.OrderData;
using Xylem.Common.Utils.Crc16Ccitt;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
{
/// <summary>
/// File for metrology look up table
/// </summary>
public class MeterLutFile
{
/// <summary>
/// Meter response on invalid LUT file e.g. 0x8000FFFF
/// </summary>
public const String StrLutFileInvalidCrc = "0x8000";
/// <summary>
/// Disk number and name of meter LUT file
/// </summary>
public const String StrLutMeterFileName = "1\\mettbl";
/// <summary>
/// Disk number and name of meter LUT file
/// </summary>
public const String StrLutBackupMeterFileName = "1\\mettbl_b";
// identifier for Genesis lookup table
public const String StrLutMeterFileId = "GEN_LUT\0";
public const Int32 IndexLutFileId = 0;
public const Int32 LengthLutFileId = 8;
// data length, calculated from version field to the end of the data section
public const Int32 IndexDataLength = 8;
public const Int32 LengthDataLength = 4;
// CCITT-CRC-16 , calculated from version field to the end of the data section
public const Int32 IndexCrc = 12;
public const Int32 LengthCrc = 2;
// version
public const Int32 IndexVersion = 14;
public const Int32 LengthVersion = 2;
// meter size as enumeration
public const Int32 IndexMeterSize = 16;
// header size of file
public const Int32 LutFileHeaderLength = LengthLutFileId + LengthDataLength + LengthCrc + LengthVersion;
// 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 Int32 SizeLutFile;
/// <summary>
/// File name of the file on PC
/// </summary>
public String LutPcFileName;
/// <summary>
/// Standard Ctor without name
/// </summary>
public MeterLutFile()
{
}
/// <summary>
/// Ctor for meter lut file
/// </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>
private UInt32 _dataLength;
public UInt32 DataLength
{
get => _dataLength;
set
{
SizeLutFile = (Int32)value + LutFileHeaderLength;
_dataLength = value;
}
}
/// <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>
/// FileCRC and calculated CRC are different
/// </summary>
public Boolean CrcError;
/// <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;
/// <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 < LutFileHeaderLength)
return false;
// extract the identifier and check, if this is a LUT file
StrLutFileId = Encoding.UTF8.GetString(BinData.ToArray(), MeterLutFile.IndexLutFileId,
MeterLutFile.IndexDataLength);
if (StrLutFileId != MeterLutFile.StrLutMeterFileId)
return false;
MeterSize = (MeterSize)BinData[MeterLutFile.IndexMeterSize];
FileCrc = (UInt16)(BinData[MeterLutFile.IndexCrc] +
(BinData[MeterLutFile.IndexCrc + 1] << 8));
Version = (UInt16)(BinData[MeterLutFile.IndexVersion] +
(BinData[MeterLutFile.IndexVersion + 1] << 8));
DataLength = (UInt32)(BinData[MeterLutFile.IndexDataLength]
+ (BinData[MeterLutFile.IndexDataLength + 1] << 8)
+ (BinData[MeterLutFile.IndexDataLength + 2] << 16)
+ (BinData[MeterLutFile.IndexDataLength + 3] << 24));
// calculate CRC and compare this with the file CRC
var entireFile = new List<Byte>();
entireFile.AddRange(BinData);
var payload = new List<Byte>();
payload.AddRange(entireFile.GetRange(MeterLutFile.IndexVersion,
(Int32)DataLength + MeterLutFile.LengthVersion));
CalculatedCrc = Crc16Ccitt.CalculateMsb1021(payload.ToArray());
if (CalculatedCrc != FileCrc)
{
CrcError = true;
return false;
}
CrcError = false;
IsValid = true;
return true;
}
}
}