From 17a73287c2bebb2973c70029f921932cf8fd74c6 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jun 2020 10:28:40 +0200 Subject: [PATCH] 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. --- mbus/mbus-protocol.c | 68 +++++++++++++------ mbus/mbus-protocol.h | 1 + test/test-frames/EFE_Engelmann-WaterStar.xml | 2 +- test/test-frames/ELS_Elster-F96-Plus.xml | 4 +- .../SLB_CF-Compact-Integral-MK-MaXX.xml | 2 +- test/test-frames/abb_f95.xml | 4 +- test/test-frames/electricity-meter-1.xml | 2 +- test/test-frames/electricity-meter-2.xml | 2 +- .../test-frames/landis+gyr_ultraheat_t230.xml | 2 +- test/test-frames/siemens_water.xml | 2 +- test/test-frames/siemens_wfh21.xml | 2 +- 11 files changed, 58 insertions(+), 33 deletions(-) diff --git a/mbus/mbus-protocol.c b/mbus/mbus-protocol.c index 7d9fca8..311abbb 100755 --- a/mbus/mbus-protocol.c +++ b/mbus/mbus-protocol.c @@ -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 @@ -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 @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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]); @@ -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)); @@ -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 { @@ -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 { @@ -4015,7 +4039,7 @@ mbus_data_variable_header_xml(mbus_data_variable_header *header) { len += snprintf(&buff[len], sizeof(buff) - len, " \n"); - len += snprintf(&buff[len], sizeof(buff) - len, " %lld\n", mbus_data_bcd_decode(header->id_bcd, 4)); + len += snprintf(&buff[len], sizeof(buff) - len, " %llX\n", mbus_data_bcd_decode_hex(header->id_bcd, 4)); len += snprintf(&buff[len], sizeof(buff) - len, " %s\n", mbus_decode_manufacturer(header->manufacturer[0], header->manufacturer[1])); len += snprintf(&buff[len], sizeof(buff) - len, " %d\n", header->version); @@ -4193,7 +4217,7 @@ mbus_data_fixed_xml(mbus_data_fixed *data) len += snprintf(&buff[len], buff_size - len, "\n\n"); len += snprintf(&buff[len], buff_size - len, " \n"); - len += snprintf(&buff[len], buff_size - len, " %lld\n", mbus_data_bcd_decode(data->id_bcd, 4)); + len += snprintf(&buff[len], buff_size - len, " %llX\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, " %s\n", str_encoded); @@ -4211,7 +4235,7 @@ mbus_data_fixed_xml(mbus_data_fixed *data) len += snprintf(&buff[len], buff_size - len, " %s\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, " %lld\n", mbus_data_bcd_decode(data->cnt1_val, 4)); + len += snprintf(&buff[len], buff_size - len, " %llX\n", mbus_data_bcd_decode_hex(data->cnt1_val, 4)); } else { @@ -4230,7 +4254,7 @@ mbus_data_fixed_xml(mbus_data_fixed *data) len += snprintf(&buff[len], buff_size - len, " %s\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, " %lld\n", mbus_data_bcd_decode(data->cnt2_val, 4)); + len += snprintf(&buff[len], buff_size - len, " %llX\n", mbus_data_bcd_decode_hex(data->cnt2_val, 4)); } else { @@ -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], diff --git a/mbus/mbus-protocol.h b/mbus/mbus-protocol.h index 1693264..2d4f5a1 100755 --- a/mbus/mbus-protocol.h +++ b/mbus/mbus-protocol.h @@ -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); diff --git a/test/test-frames/EFE_Engelmann-WaterStar.xml b/test/test-frames/EFE_Engelmann-WaterStar.xml index 278bbc1..2c4a536 100644 --- a/test/test-frames/EFE_Engelmann-WaterStar.xml +++ b/test/test-frames/EFE_Engelmann-WaterStar.xml @@ -6,7 +6,7 @@ EFE 0 Engelmann WaterStar - Hot water + Warm water (30-90°C) 12 27 0000 diff --git a/test/test-frames/ELS_Elster-F96-Plus.xml b/test/test-frames/ELS_Elster-F96-Plus.xml index 41b3e1f..1bcedc8 100644 --- a/test/test-frames/ELS_Elster-F96-Plus.xml +++ b/test/test-frames/ELS_Elster-F96-Plus.xml @@ -48,14 +48,14 @@ Value during error state 0 Power (W) - 144445223 + DDDDEBBD Value during error state 0 Volume flow (m m^3/h) - 1445223 + DDEBBD diff --git a/test/test-frames/SLB_CF-Compact-Integral-MK-MaXX.xml b/test/test-frames/SLB_CF-Compact-Integral-MK-MaXX.xml index 0502049..c249221 100644 --- a/test/test-frames/SLB_CF-Compact-Integral-MK-MaXX.xml +++ b/test/test-frames/SLB_CF-Compact-Integral-MK-MaXX.xml @@ -58,7 +58,7 @@ Instantaneous value 0 Temperature Difference (1e-2 deg C) - 1500018 + F00018 diff --git a/test/test-frames/abb_f95.xml b/test/test-frames/abb_f95.xml index 4ddaadf..2b14a58 100644 --- a/test/test-frames/abb_f95.xml +++ b/test/test-frames/abb_f95.xml @@ -30,14 +30,14 @@ Value during error state 0 Power (1e-1 W) - 144521543 + DDEBB4DD Value during error state 0 Volume flow (1e-4 m^3/h) - 1521543 + EBB4DD diff --git a/test/test-frames/electricity-meter-1.xml b/test/test-frames/electricity-meter-1.xml index 5a32f2e..98069b9 100644 --- a/test/test-frames/electricity-meter-1.xml +++ b/test/test-frames/electricity-meter-1.xml @@ -2,7 +2,7 @@ - 5000244 + 500023E SBC 18 diff --git a/test/test-frames/electricity-meter-2.xml b/test/test-frames/electricity-meter-2.xml index d5a1c47..810c9c1 100644 --- a/test/test-frames/electricity-meter-2.xml +++ b/test/test-frames/electricity-meter-2.xml @@ -2,7 +2,7 @@ - 5000345 + 50002E5 @@@ 18 diff --git a/test/test-frames/landis+gyr_ultraheat_t230.xml b/test/test-frames/landis+gyr_ultraheat_t230.xml index 1bd0ef3..ea3a879 100644 --- a/test/test-frames/landis+gyr_ultraheat_t230.xml +++ b/test/test-frames/landis+gyr_ultraheat_t230.xml @@ -72,7 +72,7 @@ Instantaneous value 0 Temperature Difference (1e-1 deg C) - 1500002 + F00002 diff --git a/test/test-frames/siemens_water.xml b/test/test-frames/siemens_water.xml index a8ec54a..8cc6c65 100644 --- a/test/test-frames/siemens_water.xml +++ b/test/test-frames/siemens_water.xml @@ -6,7 +6,7 @@ LSE 153 Siemens WFH21 - Hot water + Warm water (30-90°C) 235 00 0000 diff --git a/test/test-frames/siemens_wfh21.xml b/test/test-frames/siemens_wfh21.xml index 8f3b790..7bff369 100644 --- a/test/test-frames/siemens_wfh21.xml +++ b/test/test-frames/siemens_wfh21.xml @@ -6,7 +6,7 @@ LSE 153 Siemens WFH21 - Hot water + Warm water (30-90°C) 218 00 0000