RegisterConverter: - accept raw byte arrays which are to small for the required data type - padding

This commit is contained in:
Thomas Wiedebusch 2025-06-16 14:18:10 +02:00
parent bae922b8f1
commit 0852b0559b
2 changed files with 74 additions and 43 deletions

View File

@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
@ -51,7 +52,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
String strRawResult;
if (registerName.Contains("EncryptionKey") || registerName.Contains("Password"))
{
strRawResult = GetRegisterRawText(registerDefinition, regRawByteArray, encryptData:true);
strRawResult = GetRegisterRawText(registerDefinition, regRawByteArray, encryptData: true);
msg = $"{registerName}: ({strRawResult})h";
}
else
@ -64,7 +65,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
{
throw new ApplicationException($"Cannot convert register {registerName}");
}
return msg;
}
@ -86,7 +87,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
/// <remarks date="2024-Mar-20" author="Thomas Wiedebusch">
/// - Hash password and encryption key with SHA256.
/// </remarks>
public static String GetRegisterRawText(RegisterDefinition registerDefinition, Byte[] regRawByteArray,
public static String GetRegisterRawText(RegisterDefinition registerDefinition, Byte[] regRawByteArray,
Boolean encryptData = false)
{
String msg;
@ -146,8 +147,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
regRawByteArray = ValueToByteArray(registerDefinition.Default);
return true;
}
regRawByteArray = new Byte[] {0};
regRawByteArray = new Byte[] { 0 };
return false;
}
@ -291,7 +292,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
}
else if (registerDefinition.DataType == typeof(UInt48))
{
{
// 48 Bits / 8 Bits/Byte
size = 6;
}
@ -436,6 +437,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
/// <remarks date="2025-Mar-31" author="Thomas Wiedebusch/Roland Drabesch">
/// - Return default (T) on input == null;
/// </remarks>
/// <remarks date="2025-Jun-16" author="Thomas Wiedebusch/Roland Drabesch">
/// - Padding bytes if input doesn't fit the required size;
/// </remarks>
public static T ByteArrayToValue<T>(Byte[] rawByteArray)
{
if (rawByteArray == null)
@ -443,61 +447,39 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
try
{
Object convertedObj;
Object convertedObj = null;
var type = typeof(T);
if (type == typeof(Boolean))
{
convertedObj = BitConverter.ToBoolean(rawByteArray, 0);
}
else if (type == typeof(UInt16))
{
convertedObj = BitConverter.ToUInt16(rawByteArray, 0);
}
else if (type == typeof(UInt32))
{
convertedObj = BitConverter.ToUInt32(rawByteArray, 0);
}
else if (type == typeof(UInt64))
{
convertedObj = BitConverter.ToUInt64(rawByteArray, 0);
}
else if (type == typeof(UInt48))
// For non-numerical or single byte values use the standard implementation
if (type == typeof(UInt48))
{
return default(T);
}
else if (type == typeof(UInt72))
if (type == typeof(UInt72))
{
return default(T);
}
else if (type == typeof(UInt88))
if (type == typeof(UInt88))
{
return default(T);
}
else if (type == typeof(UInt96))
if (type == typeof(UInt96))
{
return default(T);
}
else if (type == typeof(UInt128))
if (type == typeof(UInt128))
{
return default(T);
}
else if (type == typeof(Int16))
{
convertedObj = BitConverter.ToInt16(rawByteArray, 0);
}
else if (type == typeof(Int32))
{
convertedObj = BitConverter.ToInt32(rawByteArray, 0);
}
else if (type == typeof(Int64))
{
convertedObj = BitConverter.ToInt64(rawByteArray, 0);
}
else if (type == typeof(Byte) || type == typeof(Enum8))
if (type == typeof(Byte) || type == typeof(Enum8))
{
convertedObj = rawByteArray[0];
}
else if (type == typeof(Boolean))
{
convertedObj = BitConverter.ToBoolean(rawByteArray, 0);
}
else if (type == typeof(SByte))
{
// set all others to 0 as only the LSB is of interest
@ -545,6 +527,54 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
// the value contains always the seconds since 01.Jan 2000
convertedObj = new TimeT { SecondsSince2000 = ByteArrayToValue<Int32>(rawByteArray) };
}
if (convertedObj != null)
{
return (T)Convert.ChangeType(convertedObj, type);
}
// Padding byte array to required byte size will be used for numerical values
var requiredSize = Marshal.SizeOf(typeof(T));
var paddedRawByteArray = new Byte[requiredSize];
var inputArraySize = rawByteArray.Length;
for (var ctr = 0; ctr < requiredSize; ctr++)
{
if (inputArraySize > 0)
{
paddedRawByteArray[ctr] = rawByteArray[ctr];
inputArraySize--;
}
else
{
paddedRawByteArray[ctr] = 0x00;
}
}
// For all numerical values the padded raw byte array will be used
if (type == typeof(UInt16))
{
convertedObj = BitConverter.ToUInt16(paddedRawByteArray, 0);
}
else if (type == typeof(UInt32))
{
convertedObj = BitConverter.ToUInt32(paddedRawByteArray, 0);
}
else if (type == typeof(UInt64))
{
convertedObj = BitConverter.ToUInt64(paddedRawByteArray, 0);
}
else if (type == typeof(Int16))
{
convertedObj = BitConverter.ToInt16(paddedRawByteArray, 0);
}
else if (type == typeof(Int32))
{
convertedObj = BitConverter.ToInt32(paddedRawByteArray, 0);
}
else if (type == typeof(Int64))
{
convertedObj = BitConverter.ToInt64(paddedRawByteArray, 0);
}
else
{
throw new ApplicationException($"Data type {type} not implemented");
@ -552,9 +582,10 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
return (T)Convert.ChangeType(convertedObj, type);
}
catch (Exception)
catch (Exception ex)
{
return default(T);
throw new ApplicationException($"Data type {typeof(T)} not implemented. Message: {ex.Message}");
//return default(T);
}
}
}