Skip to content

Commit

Permalink
Improve BCD decoding (rscada#167)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
lategoodbye authored Jun 28, 2020
1 parent 1e25cf1 commit 17a7328
Show file tree
Hide file tree
Showing 11 changed files with 58 additions and 33 deletions.
68 changes: 46 additions & 22 deletions mbus/mbus-protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -525,6 +525,30 @@ mbus_data_bcd_decode(unsigned char *bcd_data, size_t bcd_data_size)
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
Expand Down Expand Up @@ -2730,8 +2754,8 @@ mbus_data_record_decode(mbus_data_record *record)

case 0x09: // 2 digit BCD (8 bit)

int_val = (int)mbus_data_bcd_decode(record->data, 1);
snprintf(buff, sizeof(buff), "%d", int_val);
int_val = (int)mbus_data_bcd_decode_hex(record->data, 1);
snprintf(buff, sizeof(buff), "%X", int_val);

if (debug)
printf("%s: DIF 0x%.2x was decoded using 2 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif);
Expand All @@ -2740,8 +2764,8 @@ mbus_data_record_decode(mbus_data_record *record)

case 0x0A: // 4 digit BCD (16 bit)

int_val = (int)mbus_data_bcd_decode(record->data, 2);
snprintf(buff, sizeof(buff), "%d", int_val);
int_val = (int)mbus_data_bcd_decode_hex(record->data, 2);
snprintf(buff, sizeof(buff), "%X", int_val);

if (debug)
printf("%s: DIF 0x%.2x was decoded using 4 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif);
Expand All @@ -2750,8 +2774,8 @@ mbus_data_record_decode(mbus_data_record *record)

case 0x0B: // 6 digit BCD (24 bit)

int_val = (int)mbus_data_bcd_decode(record->data, 3);
snprintf(buff, sizeof(buff), "%d", int_val);
int_val = (int)mbus_data_bcd_decode_hex(record->data, 3);
snprintf(buff, sizeof(buff), "%X", int_val);

if (debug)
printf("%s: DIF 0x%.2x was decoded using 6 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif);
Expand All @@ -2760,8 +2784,8 @@ mbus_data_record_decode(mbus_data_record *record)

case 0x0C: // 8 digit BCD (32 bit)

int_val = (int)mbus_data_bcd_decode(record->data, 4);
snprintf(buff, sizeof(buff), "%d", int_val);
int_val = (int)mbus_data_bcd_decode_hex(record->data, 4);
snprintf(buff, sizeof(buff), "%X", int_val);

if (debug)
printf("%s: DIF 0x%.2x was decoded using 8 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif);
Expand All @@ -2770,8 +2794,8 @@ mbus_data_record_decode(mbus_data_record *record)

case 0x0E: // 12 digit BCD (48 bit)

long_long_val = mbus_data_bcd_decode(record->data, 6);
snprintf(buff, sizeof(buff), "%lld", long_long_val);
long_long_val = mbus_data_bcd_decode_hex(record->data, 6);
snprintf(buff, sizeof(buff), "%llX", long_long_val);

if (debug)
printf("%s: DIF 0x%.2x was decoded using 12 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif);
Expand Down Expand Up @@ -3761,8 +3785,8 @@ mbus_data_variable_header_print(mbus_data_variable_header *header)
{
if (header)
{
printf("%s: ID = %lld\n", __PRETTY_FUNCTION__,
mbus_data_bcd_decode(header->id_bcd, 4));
printf("%s: ID = %llX\n", __PRETTY_FUNCTION__,
mbus_data_bcd_decode_hex(header->id_bcd, 4));

printf("%s: Manufacturer = 0x%.2X%.2X\n", __PRETTY_FUNCTION__,
header->manufacturer[1], header->manufacturer[0]);
Expand Down Expand Up @@ -3863,7 +3887,7 @@ mbus_data_fixed_print(mbus_data_fixed *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: Status = 0x%.2X\n", __PRETTY_FUNCTION__, data->status);
printf("%s: Function = %s\n", __PRETTY_FUNCTION__, mbus_data_fixed_function(data->status));
Expand All @@ -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));
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
{
Expand All @@ -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));
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
{
Expand Down Expand Up @@ -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, " <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",
mbus_decode_manufacturer(header->manufacturer[0], header->manufacturer[1]));
len += snprintf(&buff[len], sizeof(buff) - len, " <Version>%d</Version>\n", header->version);
Expand Down Expand Up @@ -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, " <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));
len += snprintf(&buff[len], buff_size - len, " <Medium>%s</Medium>\n", str_encoded);
Expand All @@ -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);
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
{
Expand All @@ -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);
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
{
Expand Down Expand Up @@ -4589,9 +4613,9 @@ mbus_frame_get_secondary_address(mbus_frame *frame)
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,
data->data_var.header.manufacturer[0],
data->data_var.header.manufacturer[1],
Expand Down
1 change: 1 addition & 0 deletions mbus/mbus-protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

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_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);
Expand Down
2 changes: 1 addition & 1 deletion test/test-frames/EFE_Engelmann-WaterStar.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<Manufacturer>EFE</Manufacturer>
<Version>0</Version>
<ProductName>Engelmann WaterStar</ProductName>
<Medium>Hot water</Medium>
<Medium>Warm water (30-90°C)</Medium>
<AccessNumber>12</AccessNumber>
<Status>27</Status>
<Signature>0000</Signature>
Expand Down
4 changes: 2 additions & 2 deletions test/test-frames/ELS_Elster-F96-Plus.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@
<Function>Value during error state</Function>
<StorageNumber>0</StorageNumber>
<Unit>Power (W)</Unit>
<Value>144445223</Value>
<Value>DDDDEBBD</Value>
</DataRecord>

<DataRecord id="5">
<Function>Value during error state</Function>
<StorageNumber>0</StorageNumber>
<Unit>Volume flow (m m^3/h)</Unit>
<Value>1445223</Value>
<Value>DDEBBD</Value>
</DataRecord>

<DataRecord id="6">
Expand Down
2 changes: 1 addition & 1 deletion test/test-frames/SLB_CF-Compact-Integral-MK-MaXX.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
<Function>Instantaneous value</Function>
<StorageNumber>0</StorageNumber>
<Unit>Temperature Difference (1e-2 deg C)</Unit>
<Value>1500018</Value>
<Value>F00018</Value>
</DataRecord>

<DataRecord id="7">
Expand Down
4 changes: 2 additions & 2 deletions test/test-frames/abb_f95.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@
<Function>Value during error state</Function>
<StorageNumber>0</StorageNumber>
<Unit>Power (1e-1 W)</Unit>
<Value>144521543</Value>
<Value>DDEBB4DD</Value>
</DataRecord>

<DataRecord id="3">
<Function>Value during error state</Function>
<StorageNumber>0</StorageNumber>
<Unit>Volume flow (1e-4 m^3/h)</Unit>
<Value>1521543</Value>
<Value>EBB4DD</Value>
</DataRecord>

<DataRecord id="4">
Expand Down
2 changes: 1 addition & 1 deletion test/test-frames/electricity-meter-1.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<MBusData>

<SlaveInformation>
<Id>5000244</Id>
<Id>500023E</Id>
<Manufacturer>SBC</Manufacturer>
<Version>18</Version>
<ProductName></ProductName>
Expand Down
2 changes: 1 addition & 1 deletion test/test-frames/electricity-meter-2.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<MBusData>

<SlaveInformation>
<Id>5000345</Id>
<Id>50002E5</Id>
<Manufacturer>@@@</Manufacturer>
<Version>18</Version>
<ProductName></ProductName>
Expand Down
2 changes: 1 addition & 1 deletion test/test-frames/landis+gyr_ultraheat_t230.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
<Function>Instantaneous value</Function>
<StorageNumber>0</StorageNumber>
<Unit>Temperature Difference (1e-1 deg C)</Unit>
<Value>1500002</Value>
<Value>F00002</Value>
</DataRecord>

<DataRecord id="9">
Expand Down
2 changes: 1 addition & 1 deletion test/test-frames/siemens_water.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<Manufacturer>LSE</Manufacturer>
<Version>153</Version>
<ProductName>Siemens WFH21</ProductName>
<Medium>Hot water</Medium>
<Medium>Warm water (30-90°C)</Medium>
<AccessNumber>235</AccessNumber>
<Status>00</Status>
<Signature>0000</Signature>
Expand Down
2 changes: 1 addition & 1 deletion test/test-frames/siemens_wfh21.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<Manufacturer>LSE</Manufacturer>
<Version>153</Version>
<ProductName>Siemens WFH21</ProductName>
<Medium>Hot water</Medium>
<Medium>Warm water (30-90°C)</Medium>
<AccessNumber>218</AccessNumber>
<Status>00</Status>
<Signature>0000</Signature>
Expand Down

0 comments on commit 17a7328

Please sign in to comment.