Improve BCD decoding (#167)

* Introduce mbus_data_bcd_decode_hex

The convert function mbus_data_bcd_decode (BCD to decimal) suffers from
information loss in case of hexacimal digits. So introduce a new function
mbus_data_bcd_decode_hex (BCD to hexadecimal), which isn't affected and
use this for default XML output. But keep mbus_data_bcd_decode for
normalized output.
This commit is contained in:
Stefan Wahren 2020-06-28 10:28:40 +02:00 committed by GitHub
parent 1e25cf1096
commit 17a73287c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 58 additions and 33 deletions

View File

@ -490,7 +490,7 @@ mbus_data_bcd_encode(unsigned char *bcd_data, size_t bcd_data_size, int value)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/// ///
/// Decode BCD data /// Decode BCD data (decimal)
/// ///
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
long long long long
@ -525,6 +525,30 @@ mbus_data_bcd_decode(unsigned char *bcd_data, size_t bcd_data_size)
return -1; return -1;
} }
//------------------------------------------------------------------------------
///
/// Decode BCD data (hexadecimal)
///
//------------------------------------------------------------------------------
long long
mbus_data_bcd_decode_hex(unsigned char *bcd_data, size_t bcd_data_size)
{
long long val = 0;
size_t i;
if (bcd_data)
{
for (i = bcd_data_size; i > 0; i--)
{
val = (val << 8) | bcd_data[i-1];
}
return val;
}
return -1;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/// ///
/// Decode INTEGER data /// Decode INTEGER data
@ -2730,8 +2754,8 @@ mbus_data_record_decode(mbus_data_record *record)
case 0x09: // 2 digit BCD (8 bit) case 0x09: // 2 digit BCD (8 bit)
int_val = (int)mbus_data_bcd_decode(record->data, 1); int_val = (int)mbus_data_bcd_decode_hex(record->data, 1);
snprintf(buff, sizeof(buff), "%d", int_val); snprintf(buff, sizeof(buff), "%X", int_val);
if (debug) if (debug)
printf("%s: DIF 0x%.2x was decoded using 2 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif); printf("%s: DIF 0x%.2x was decoded using 2 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif);
@ -2740,8 +2764,8 @@ mbus_data_record_decode(mbus_data_record *record)
case 0x0A: // 4 digit BCD (16 bit) case 0x0A: // 4 digit BCD (16 bit)
int_val = (int)mbus_data_bcd_decode(record->data, 2); int_val = (int)mbus_data_bcd_decode_hex(record->data, 2);
snprintf(buff, sizeof(buff), "%d", int_val); snprintf(buff, sizeof(buff), "%X", int_val);
if (debug) if (debug)
printf("%s: DIF 0x%.2x was decoded using 4 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif); printf("%s: DIF 0x%.2x was decoded using 4 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif);
@ -2750,8 +2774,8 @@ mbus_data_record_decode(mbus_data_record *record)
case 0x0B: // 6 digit BCD (24 bit) case 0x0B: // 6 digit BCD (24 bit)
int_val = (int)mbus_data_bcd_decode(record->data, 3); int_val = (int)mbus_data_bcd_decode_hex(record->data, 3);
snprintf(buff, sizeof(buff), "%d", int_val); snprintf(buff, sizeof(buff), "%X", int_val);
if (debug) if (debug)
printf("%s: DIF 0x%.2x was decoded using 6 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif); printf("%s: DIF 0x%.2x was decoded using 6 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif);
@ -2760,8 +2784,8 @@ mbus_data_record_decode(mbus_data_record *record)
case 0x0C: // 8 digit BCD (32 bit) case 0x0C: // 8 digit BCD (32 bit)
int_val = (int)mbus_data_bcd_decode(record->data, 4); int_val = (int)mbus_data_bcd_decode_hex(record->data, 4);
snprintf(buff, sizeof(buff), "%d", int_val); snprintf(buff, sizeof(buff), "%X", int_val);
if (debug) if (debug)
printf("%s: DIF 0x%.2x was decoded using 8 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif); printf("%s: DIF 0x%.2x was decoded using 8 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif);
@ -2770,8 +2794,8 @@ mbus_data_record_decode(mbus_data_record *record)
case 0x0E: // 12 digit BCD (48 bit) case 0x0E: // 12 digit BCD (48 bit)
long_long_val = mbus_data_bcd_decode(record->data, 6); long_long_val = mbus_data_bcd_decode_hex(record->data, 6);
snprintf(buff, sizeof(buff), "%lld", long_long_val); snprintf(buff, sizeof(buff), "%llX", long_long_val);
if (debug) if (debug)
printf("%s: DIF 0x%.2x was decoded using 12 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif); printf("%s: DIF 0x%.2x was decoded using 12 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif);
@ -3761,8 +3785,8 @@ mbus_data_variable_header_print(mbus_data_variable_header *header)
{ {
if (header) if (header)
{ {
printf("%s: ID = %lld\n", __PRETTY_FUNCTION__, printf("%s: ID = %llX\n", __PRETTY_FUNCTION__,
mbus_data_bcd_decode(header->id_bcd, 4)); mbus_data_bcd_decode_hex(header->id_bcd, 4));
printf("%s: Manufacturer = 0x%.2X%.2X\n", __PRETTY_FUNCTION__, printf("%s: Manufacturer = 0x%.2X%.2X\n", __PRETTY_FUNCTION__,
header->manufacturer[1], header->manufacturer[0]); header->manufacturer[1], header->manufacturer[0]);
@ -3863,7 +3887,7 @@ mbus_data_fixed_print(mbus_data_fixed *data)
if (data) if (data)
{ {
printf("%s: ID = %lld\n", __PRETTY_FUNCTION__, mbus_data_bcd_decode(data->id_bcd, 4)); printf("%s: ID = %llX\n", __PRETTY_FUNCTION__, mbus_data_bcd_decode_hex(data->id_bcd, 4));
printf("%s: Access # = 0x%.2X\n", __PRETTY_FUNCTION__, data->tx_cnt); printf("%s: Access # = 0x%.2X\n", __PRETTY_FUNCTION__, data->tx_cnt);
printf("%s: Status = 0x%.2X\n", __PRETTY_FUNCTION__, data->status); printf("%s: Status = 0x%.2X\n", __PRETTY_FUNCTION__, data->status);
printf("%s: Function = %s\n", __PRETTY_FUNCTION__, mbus_data_fixed_function(data->status)); printf("%s: Function = %s\n", __PRETTY_FUNCTION__, mbus_data_fixed_function(data->status));
@ -3872,7 +3896,7 @@ mbus_data_fixed_print(mbus_data_fixed *data)
printf("%s: Unit1 = %s\n", __PRETTY_FUNCTION__, mbus_data_fixed_unit(data->cnt1_type)); printf("%s: Unit1 = %s\n", __PRETTY_FUNCTION__, mbus_data_fixed_unit(data->cnt1_type));
if ((data->status & MBUS_DATA_FIXED_STATUS_FORMAT_MASK) == MBUS_DATA_FIXED_STATUS_FORMAT_BCD) if ((data->status & MBUS_DATA_FIXED_STATUS_FORMAT_MASK) == MBUS_DATA_FIXED_STATUS_FORMAT_BCD)
{ {
printf("%s: Counter1 = %lld\n", __PRETTY_FUNCTION__, mbus_data_bcd_decode(data->cnt1_val, 4)); printf("%s: Counter1 = %llX\n", __PRETTY_FUNCTION__, mbus_data_bcd_decode_hex(data->cnt1_val, 4));
} }
else else
{ {
@ -3884,7 +3908,7 @@ mbus_data_fixed_print(mbus_data_fixed *data)
printf("%s: Unit2 = %s\n", __PRETTY_FUNCTION__, mbus_data_fixed_unit(data->cnt2_type)); printf("%s: Unit2 = %s\n", __PRETTY_FUNCTION__, mbus_data_fixed_unit(data->cnt2_type));
if ((data->status & MBUS_DATA_FIXED_STATUS_FORMAT_MASK) == MBUS_DATA_FIXED_STATUS_FORMAT_BCD) if ((data->status & MBUS_DATA_FIXED_STATUS_FORMAT_MASK) == MBUS_DATA_FIXED_STATUS_FORMAT_BCD)
{ {
printf("%s: Counter2 = %lld\n", __PRETTY_FUNCTION__, mbus_data_bcd_decode(data->cnt2_val, 4)); printf("%s: Counter2 = %llX\n", __PRETTY_FUNCTION__, mbus_data_bcd_decode_hex(data->cnt2_val, 4));
} }
else else
{ {
@ -4015,7 +4039,7 @@ mbus_data_variable_header_xml(mbus_data_variable_header *header)
{ {
len += snprintf(&buff[len], sizeof(buff) - len, " <SlaveInformation>\n"); len += snprintf(&buff[len], sizeof(buff) - len, " <SlaveInformation>\n");
len += snprintf(&buff[len], sizeof(buff) - len, " <Id>%lld</Id>\n", mbus_data_bcd_decode(header->id_bcd, 4)); len += snprintf(&buff[len], sizeof(buff) - len, " <Id>%llX</Id>\n", mbus_data_bcd_decode_hex(header->id_bcd, 4));
len += snprintf(&buff[len], sizeof(buff) - len, " <Manufacturer>%s</Manufacturer>\n", len += snprintf(&buff[len], sizeof(buff) - len, " <Manufacturer>%s</Manufacturer>\n",
mbus_decode_manufacturer(header->manufacturer[0], header->manufacturer[1])); mbus_decode_manufacturer(header->manufacturer[0], header->manufacturer[1]));
len += snprintf(&buff[len], sizeof(buff) - len, " <Version>%d</Version>\n", header->version); len += snprintf(&buff[len], sizeof(buff) - len, " <Version>%d</Version>\n", header->version);
@ -4193,7 +4217,7 @@ mbus_data_fixed_xml(mbus_data_fixed *data)
len += snprintf(&buff[len], buff_size - len, "<MBusData>\n\n"); len += snprintf(&buff[len], buff_size - len, "<MBusData>\n\n");
len += snprintf(&buff[len], buff_size - len, " <SlaveInformation>\n"); len += snprintf(&buff[len], buff_size - len, " <SlaveInformation>\n");
len += snprintf(&buff[len], buff_size - len, " <Id>%lld</Id>\n", mbus_data_bcd_decode(data->id_bcd, 4)); len += snprintf(&buff[len], buff_size - len, " <Id>%llX</Id>\n", mbus_data_bcd_decode_hex(data->id_bcd, 4));
mbus_str_xml_encode(str_encoded, mbus_data_fixed_medium(data), sizeof(str_encoded)); mbus_str_xml_encode(str_encoded, mbus_data_fixed_medium(data), sizeof(str_encoded));
len += snprintf(&buff[len], buff_size - len, " <Medium>%s</Medium>\n", str_encoded); len += snprintf(&buff[len], buff_size - len, " <Medium>%s</Medium>\n", str_encoded);
@ -4211,7 +4235,7 @@ mbus_data_fixed_xml(mbus_data_fixed *data)
len += snprintf(&buff[len], buff_size - len, " <Unit>%s</Unit>\n", str_encoded); len += snprintf(&buff[len], buff_size - len, " <Unit>%s</Unit>\n", str_encoded);
if ((data->status & MBUS_DATA_FIXED_STATUS_FORMAT_MASK) == MBUS_DATA_FIXED_STATUS_FORMAT_BCD) if ((data->status & MBUS_DATA_FIXED_STATUS_FORMAT_MASK) == MBUS_DATA_FIXED_STATUS_FORMAT_BCD)
{ {
len += snprintf(&buff[len], buff_size - len, " <Value>%lld</Value>\n", mbus_data_bcd_decode(data->cnt1_val, 4)); len += snprintf(&buff[len], buff_size - len, " <Value>%llX</Value>\n", mbus_data_bcd_decode_hex(data->cnt1_val, 4));
} }
else else
{ {
@ -4230,7 +4254,7 @@ mbus_data_fixed_xml(mbus_data_fixed *data)
len += snprintf(&buff[len], buff_size - len, " <Unit>%s</Unit>\n", str_encoded); len += snprintf(&buff[len], buff_size - len, " <Unit>%s</Unit>\n", str_encoded);
if ((data->status & MBUS_DATA_FIXED_STATUS_FORMAT_MASK) == MBUS_DATA_FIXED_STATUS_FORMAT_BCD) if ((data->status & MBUS_DATA_FIXED_STATUS_FORMAT_MASK) == MBUS_DATA_FIXED_STATUS_FORMAT_BCD)
{ {
len += snprintf(&buff[len], buff_size - len, " <Value>%lld</Value>\n", mbus_data_bcd_decode(data->cnt2_val, 4)); len += snprintf(&buff[len], buff_size - len, " <Value>%llX</Value>\n", mbus_data_bcd_decode_hex(data->cnt2_val, 4));
} }
else else
{ {
@ -4589,9 +4613,9 @@ mbus_frame_get_secondary_address(mbus_frame *frame)
return NULL; return NULL;
} }
id = (unsigned long) mbus_data_bcd_decode(data->data_var.header.id_bcd, 4); id = (unsigned long) mbus_data_bcd_decode_hex(data->data_var.header.id_bcd, 4);
snprintf(addr, sizeof(addr), "%08lu%02X%02X%02X%02X", snprintf(addr, sizeof(addr), "%08lX%02X%02X%02X%02X",
id, id,
data->data_var.header.manufacturer[0], data->data_var.header.manufacturer[0],
data->data_var.header.manufacturer[1], data->data_var.header.manufacturer[1],

View File

@ -627,6 +627,7 @@ int mbus_data_bcd_encode(unsigned char *bcd_data, size_t bcd_data_size, int valu
int mbus_data_int_encode(unsigned char *int_data, size_t int_data_size, int value); int mbus_data_int_encode(unsigned char *int_data, size_t int_data_size, int value);
long long mbus_data_bcd_decode(unsigned char *bcd_data, size_t bcd_data_size); long long mbus_data_bcd_decode(unsigned char *bcd_data, size_t bcd_data_size);
long long mbus_data_bcd_decode_hex(unsigned char *bcd_data, size_t bcd_data_size);
int mbus_data_int_decode(unsigned char *int_data, size_t int_data_size, int *value); int mbus_data_int_decode(unsigned char *int_data, size_t int_data_size, int *value);
int mbus_data_long_decode(unsigned char *int_data, size_t int_data_size, long *value); int mbus_data_long_decode(unsigned char *int_data, size_t int_data_size, long *value);
int mbus_data_long_long_decode(unsigned char *int_data, size_t int_data_size, long long *value); int mbus_data_long_long_decode(unsigned char *int_data, size_t int_data_size, long long *value);

View File

@ -6,7 +6,7 @@
<Manufacturer>EFE</Manufacturer> <Manufacturer>EFE</Manufacturer>
<Version>0</Version> <Version>0</Version>
<ProductName>Engelmann WaterStar</ProductName> <ProductName>Engelmann WaterStar</ProductName>
<Medium>Hot water</Medium> <Medium>Warm water (30-90°C)</Medium>
<AccessNumber>12</AccessNumber> <AccessNumber>12</AccessNumber>
<Status>27</Status> <Status>27</Status>
<Signature>0000</Signature> <Signature>0000</Signature>

View File

@ -48,14 +48,14 @@
<Function>Value during error state</Function> <Function>Value during error state</Function>
<StorageNumber>0</StorageNumber> <StorageNumber>0</StorageNumber>
<Unit>Power (W)</Unit> <Unit>Power (W)</Unit>
<Value>144445223</Value> <Value>DDDDEBBD</Value>
</DataRecord> </DataRecord>
<DataRecord id="5"> <DataRecord id="5">
<Function>Value during error state</Function> <Function>Value during error state</Function>
<StorageNumber>0</StorageNumber> <StorageNumber>0</StorageNumber>
<Unit>Volume flow (m m^3/h)</Unit> <Unit>Volume flow (m m^3/h)</Unit>
<Value>1445223</Value> <Value>DDEBBD</Value>
</DataRecord> </DataRecord>
<DataRecord id="6"> <DataRecord id="6">

View File

@ -58,7 +58,7 @@
<Function>Instantaneous value</Function> <Function>Instantaneous value</Function>
<StorageNumber>0</StorageNumber> <StorageNumber>0</StorageNumber>
<Unit>Temperature Difference (1e-2 deg C)</Unit> <Unit>Temperature Difference (1e-2 deg C)</Unit>
<Value>1500018</Value> <Value>F00018</Value>
</DataRecord> </DataRecord>
<DataRecord id="7"> <DataRecord id="7">

View File

@ -30,14 +30,14 @@
<Function>Value during error state</Function> <Function>Value during error state</Function>
<StorageNumber>0</StorageNumber> <StorageNumber>0</StorageNumber>
<Unit>Power (1e-1 W)</Unit> <Unit>Power (1e-1 W)</Unit>
<Value>144521543</Value> <Value>DDEBB4DD</Value>
</DataRecord> </DataRecord>
<DataRecord id="3"> <DataRecord id="3">
<Function>Value during error state</Function> <Function>Value during error state</Function>
<StorageNumber>0</StorageNumber> <StorageNumber>0</StorageNumber>
<Unit>Volume flow (1e-4 m^3/h)</Unit> <Unit>Volume flow (1e-4 m^3/h)</Unit>
<Value>1521543</Value> <Value>EBB4DD</Value>
</DataRecord> </DataRecord>
<DataRecord id="4"> <DataRecord id="4">

View File

@ -2,7 +2,7 @@
<MBusData> <MBusData>
<SlaveInformation> <SlaveInformation>
<Id>5000244</Id> <Id>500023E</Id>
<Manufacturer>SBC</Manufacturer> <Manufacturer>SBC</Manufacturer>
<Version>18</Version> <Version>18</Version>
<ProductName></ProductName> <ProductName></ProductName>

View File

@ -2,7 +2,7 @@
<MBusData> <MBusData>
<SlaveInformation> <SlaveInformation>
<Id>5000345</Id> <Id>50002E5</Id>
<Manufacturer>@@@</Manufacturer> <Manufacturer>@@@</Manufacturer>
<Version>18</Version> <Version>18</Version>
<ProductName></ProductName> <ProductName></ProductName>

View File

@ -72,7 +72,7 @@
<Function>Instantaneous value</Function> <Function>Instantaneous value</Function>
<StorageNumber>0</StorageNumber> <StorageNumber>0</StorageNumber>
<Unit>Temperature Difference (1e-1 deg C)</Unit> <Unit>Temperature Difference (1e-1 deg C)</Unit>
<Value>1500002</Value> <Value>F00002</Value>
</DataRecord> </DataRecord>
<DataRecord id="9"> <DataRecord id="9">

View File

@ -6,7 +6,7 @@
<Manufacturer>LSE</Manufacturer> <Manufacturer>LSE</Manufacturer>
<Version>153</Version> <Version>153</Version>
<ProductName>Siemens WFH21</ProductName> <ProductName>Siemens WFH21</ProductName>
<Medium>Hot water</Medium> <Medium>Warm water (30-90°C)</Medium>
<AccessNumber>235</AccessNumber> <AccessNumber>235</AccessNumber>
<Status>00</Status> <Status>00</Status>
<Signature>0000</Signature> <Signature>0000</Signature>

View File

@ -6,7 +6,7 @@
<Manufacturer>LSE</Manufacturer> <Manufacturer>LSE</Manufacturer>
<Version>153</Version> <Version>153</Version>
<ProductName>Siemens WFH21</ProductName> <ProductName>Siemens WFH21</ProductName>
<Medium>Hot water</Medium> <Medium>Warm water (30-90°C)</Medium>
<AccessNumber>218</AccessNumber> <AccessNumber>218</AccessNumber>
<Status>00</Status> <Status>00</Status>
<Signature>0000</Signature> <Signature>0000</Signature>