diff --git a/bin/mbus-serial-request-data.c b/bin/mbus-serial-request-data.c index 1152a04..20e3fa6 100755 --- a/bin/mbus-serial-request-data.c +++ b/bin/mbus-serial-request-data.c @@ -15,6 +15,35 @@ static int debug = 0; +// +// init slave to get really the beginning of the records +// +static int +init_slaves(mbus_handle *handle) +{ + if (debug) + printf("%s: debug: sending init frame #1\n", __PRETTY_FUNCTION__); + + if (mbus_send_ping_frame(handle, MBUS_ADDRESS_NETWORK_LAYER, 1) == -1) + { + return 0; + } + + // + // resend SND_NKE, maybe the first get lost + // + + if (debug) + printf("%s: debug: sending init frame #2\n", __PRETTY_FUNCTION__); + + if (mbus_send_ping_frame(handle, MBUS_ADDRESS_NETWORK_LAYER, 1) == -1) + { + return 0; + } + + return 1; +} + //------------------------------------------------------------------------------ // Scan for devices using secondary addressing. //------------------------------------------------------------------------------ @@ -79,15 +108,24 @@ main(int argc, char **argv) if (mbus_connect(handle) == -1) { fprintf(stderr,"Failed to setup connection to M-bus gateway\n"); + mbus_context_free(handle); return 1; } if (mbus_serial_set_baudrate(handle, baudrate) == -1) { fprintf(stderr,"Failed to set baud rate.\n"); + mbus_disconnect(handle); + mbus_context_free(handle); return 1; } + if (init_slaves(handle) == 0) + { + mbus_disconnect(handle); + mbus_context_free(handle); + return 1; + } if (mbus_is_secondary_address(addr_str)) { @@ -100,36 +138,40 @@ main(int argc, char **argv) if (ret == MBUS_PROBE_COLLISION) { fprintf(stderr, "%s: Error: The address mask [%s] matches more than one device.\n", __PRETTY_FUNCTION__, addr_str); + mbus_disconnect(handle); + mbus_context_free(handle); return 1; } else if (ret == MBUS_PROBE_NOTHING) { fprintf(stderr, "%s: Error: The selected secondary address does not match any device [%s].\n", __PRETTY_FUNCTION__, addr_str); + mbus_disconnect(handle); + mbus_context_free(handle); return 1; } else if (ret == MBUS_PROBE_ERROR) { fprintf(stderr, "%s: Error: Failed to select secondary address [%s].\n", __PRETTY_FUNCTION__, addr_str); + mbus_disconnect(handle); + mbus_context_free(handle); return 1; } // else MBUS_PROBE_SINGLE - - if (mbus_send_request_frame(handle, MBUS_ADDRESS_NETWORK_LAYER) == -1) - { - fprintf(stderr, "Failed to send M-Bus request frame.\n"); - return 1; - } + + address = MBUS_ADDRESS_NETWORK_LAYER; } else { // primary addressing - address = atoi(addr_str); - if (mbus_send_request_frame(handle, address) == -1) - { - fprintf(stderr, "Failed to send M-Bus request frame.\n"); - return 1; - } + } + + if (mbus_send_request_frame(handle, address) == -1) + { + fprintf(stderr, "Failed to send M-Bus request frame.\n"); + mbus_disconnect(handle); + mbus_context_free(handle); + return 1; } if (mbus_recv_frame(handle, &reply) != MBUS_RECV_RESULT_OK) @@ -139,22 +181,32 @@ main(int argc, char **argv) } // - // parse data and print in XML format + // dump hex data if debug is true // if (debug) { mbus_frame_print(&reply); } + // + // parse data + // if (mbus_frame_data_parse(&reply, &reply_data) == -1) { fprintf(stderr, "M-bus data parse error: %s\n", mbus_error_str()); + mbus_disconnect(handle); + mbus_context_free(handle); return 1; } + // + // generate XML and print to standard output + // if ((xml_result = mbus_frame_data_xml(&reply_data)) == NULL) { fprintf(stderr, "Failed to generate XML representation of MBUS frame: %s\n", mbus_error_str()); + mbus_disconnect(handle); + mbus_context_free(handle); return 1; } diff --git a/bin/mbus-serial-scan.c b/bin/mbus-serial-scan.c index 8a935c9..e7babd7 100755 --- a/bin/mbus-serial-scan.c +++ b/bin/mbus-serial-scan.c @@ -21,7 +21,7 @@ int ping_address(mbus_handle *handle, mbus_frame *reply, int address) memset((void *)reply, 0, sizeof(mbus_frame)); - for (i = 0; i <= handle->max_retry; i++) + for (i = 0; i <= handle->max_search_retry; i++) { if (debug) { @@ -126,7 +126,7 @@ main(int argc, char **argv) return 1; } - if (mbus_context_set_option(handle, MBUS_OPTION_MAX_RETRY, retries) == -1) + if (mbus_context_set_option(handle, MBUS_OPTION_MAX_SEARCH_RETRY, retries) == -1) { fprintf(stderr,"Failed to set retry count\n"); return 1; diff --git a/bin/mbus-tcp-scan.c b/bin/mbus-tcp-scan.c index 70ed102..3d96194 100755 --- a/bin/mbus-tcp-scan.c +++ b/bin/mbus-tcp-scan.c @@ -21,7 +21,7 @@ int ping_address(mbus_handle *handle, mbus_frame *reply, int address) memset((void *)reply, 0, sizeof(mbus_frame)); - for (i = 0; i <= handle->max_retry; i++) + for (i = 0; i <= handle->max_search_retry; i++) { if (debug) { @@ -112,7 +112,7 @@ main(int argc, char **argv) return 1; } - if (mbus_context_set_option(handle, MBUS_OPTION_MAX_RETRY, retries) == -1) + if (mbus_context_set_option(handle, MBUS_OPTION_MAX_SEARCH_RETRY, retries) == -1) { fprintf(stderr,"Failed to set retry count\n"); return 1; diff --git a/mbus/mbus-protocol-aux.c b/mbus/mbus-protocol-aux.c index be7312d..d78e187 100755 --- a/mbus/mbus-protocol-aux.c +++ b/mbus/mbus-protocol-aux.c @@ -214,9 +214,17 @@ mbus_variable_vif vif_table[] = { /* E111 1010 Bus Address */ { 0x7A, 1.0, "", "Bus Address" }, - - /* Manufacturer specific: 7Fh / FF */ + + /* Any VIF: 7Eh */ + { 0x7E, 1.0, "", "Any VIF" }, + + /* Manufacturer specific: 7Fh */ { 0x7F, 1.0, "", "Manufacturer specific" }, + + /* Any VIF: 7Eh */ + { 0xFE, 1.0, "", "Any VIF" }, + + /* Manufacturer specific: FFh */ { 0xFF, 1.0, "", "Manufacturer specific" }, @@ -567,32 +575,22 @@ mbus_variable_vif vif_table[] = { { 0x235, 1.0e0, "Reserved", "Reserved" }, { 0x236, 1.0e0, "Reserved", "Reserved" }, { 0x237, 1.0e0, "Reserved", "Reserved" }, - - /* E101 10nn Flow Temperature 10(nn-3) °F 0.001°F to 1°F */ - { 0x238, 1.0e-3, "°F", "Flow temperature" }, - { 0x239, 1.0e-2, "°F", "Flow temperature" }, - { 0x23A, 1.0e-1, "°F", "Flow temperature" }, - { 0x23B, 1.0e0, "°F", "Flow temperature" }, - - /* E101 11nn Return Temperature 10(nn-3) °F 0.001°F to 1°F */ - { 0x23C, 1.0e-3, "°F", "Return temperature" }, - { 0x23D, 1.0e-2, "°F", "Return temperature" }, - { 0x23E, 1.0e-1, "°F", "Return temperature" }, - { 0x23F, 1.0e0, "°F", "Return temperature" }, - - /* E110 00nn Temperature Difference 10(nn-3) °F 0.001°F to 1°F */ - { 0x240, 1.0e-3, "°F", "Temperature difference" }, - { 0x241, 1.0e-2, "°F", "Temperature difference" }, - { 0x242, 1.0e-1, "°F", "Temperature difference" }, - { 0x243, 1.0e0, "°F", "Temperature difference" }, - - /* E110 01nn External Temperature 10(nn-3) °F 0.001°F to 1°F */ - { 0x244, 1.0e-3, "°F", "External temperature" }, - { 0x245, 1.0e-2, "°F", "External temperature" }, - { 0x246, 1.0e-1, "°F", "External temperature" }, - { 0x247, 1.0e0, "°F", "External temperature" }, - - /* E110 1nnn Reserved */ + { 0x238, 1.0e0, "Reserved", "Reserved" }, + { 0x239, 1.0e0, "Reserved", "Reserved" }, + { 0x23A, 1.0e0, "Reserved", "Reserved" }, + { 0x23B, 1.0e0, "Reserved", "Reserved" }, + { 0x23C, 1.0e0, "Reserved", "Reserved" }, + { 0x23D, 1.0e0, "Reserved", "Reserved" }, + { 0x23E, 1.0e0, "Reserved", "Reserved" }, + { 0x23F, 1.0e0, "Reserved", "Reserved" }, + { 0x240, 1.0e0, "Reserved", "Reserved" }, + { 0x241, 1.0e0, "Reserved", "Reserved" }, + { 0x242, 1.0e0, "Reserved", "Reserved" }, + { 0x243, 1.0e0, "Reserved", "Reserved" }, + { 0x244, 1.0e0, "Reserved", "Reserved" }, + { 0x245, 1.0e0, "Reserved", "Reserved" }, + { 0x246, 1.0e0, "Reserved", "Reserved" }, + { 0x247, 1.0e0, "Reserved", "Reserved" }, { 0x248, 1.0e0, "Reserved", "Reserved" }, { 0x249, 1.0e0, "Reserved", "Reserved" }, { 0x24A, 1.0e0, "Reserved", "Reserved" }, @@ -601,28 +599,70 @@ mbus_variable_vif vif_table[] = { { 0x24D, 1.0e0, "Reserved", "Reserved" }, { 0x24E, 1.0e0, "Reserved", "Reserved" }, { 0x24F, 1.0e0, "Reserved", "Reserved" }, + { 0x250, 1.0e0, "Reserved", "Reserved" }, + { 0x251, 1.0e0, "Reserved", "Reserved" }, + { 0x252, 1.0e0, "Reserved", "Reserved" }, + { 0x253, 1.0e0, "Reserved", "Reserved" }, + { 0x254, 1.0e0, "Reserved", "Reserved" }, + { 0x255, 1.0e0, "Reserved", "Reserved" }, + { 0x256, 1.0e0, "Reserved", "Reserved" }, + { 0x257, 1.0e0, "Reserved", "Reserved" }, + + /* E101 10nn Flow Temperature 10(nn-3) °F 0.001°F to 1°F */ + { 0x258, 1.0e-3, "°F", "Flow temperature" }, + { 0x259, 1.0e-2, "°F", "Flow temperature" }, + { 0x25A, 1.0e-1, "°F", "Flow temperature" }, + { 0x25B, 1.0e0, "°F", "Flow temperature" }, + + /* E101 11nn Return Temperature 10(nn-3) °F 0.001°F to 1°F */ + { 0x25C, 1.0e-3, "°F", "Return temperature" }, + { 0x25D, 1.0e-2, "°F", "Return temperature" }, + { 0x25E, 1.0e-1, "°F", "Return temperature" }, + { 0x25F, 1.0e0, "°F", "Return temperature" }, + + /* E110 00nn Temperature Difference 10(nn-3) °F 0.001°F to 1°F */ + { 0x260, 1.0e-3, "°F", "Temperature difference" }, + { 0x261, 1.0e-2, "°F", "Temperature difference" }, + { 0x262, 1.0e-1, "°F", "Temperature difference" }, + { 0x263, 1.0e0, "°F", "Temperature difference" }, + + /* E110 01nn External Temperature 10(nn-3) °F 0.001°F to 1°F */ + { 0x264, 1.0e-3, "°F", "External temperature" }, + { 0x265, 1.0e-2, "°F", "External temperature" }, + { 0x266, 1.0e-1, "°F", "External temperature" }, + { 0x267, 1.0e0, "°F", "External temperature" }, + + /* E110 1nnn Reserved */ + { 0x268, 1.0e0, "Reserved", "Reserved" }, + { 0x269, 1.0e0, "Reserved", "Reserved" }, + { 0x26A, 1.0e0, "Reserved", "Reserved" }, + { 0x26B, 1.0e0, "Reserved", "Reserved" }, + { 0x26C, 1.0e0, "Reserved", "Reserved" }, + { 0x26D, 1.0e0, "Reserved", "Reserved" }, + { 0x26E, 1.0e0, "Reserved", "Reserved" }, + { 0x26F, 1.0e0, "Reserved", "Reserved" }, /* E111 00nn Cold / Warm Temperature Limit 10(nn-3) °F 0.001°F to 1°F */ - { 0x250, 1.0e-3, "°F", "Cold / Warm Temperature Limit" }, - { 0x251, 1.0e-2, "°F", "Cold / Warm Temperature Limit" }, - { 0x252, 1.0e-1, "°F", "Cold / Warm Temperature Limit" }, - { 0x253, 1.0e0, "°F", "Cold / Warm Temperature Limit" }, + { 0x270, 1.0e-3, "°F", "Cold / Warm Temperature Limit" }, + { 0x271, 1.0e-2, "°F", "Cold / Warm Temperature Limit" }, + { 0x272, 1.0e-1, "°F", "Cold / Warm Temperature Limit" }, + { 0x273, 1.0e0, "°F", "Cold / Warm Temperature Limit" }, /* E111 01nn Cold / Warm Temperature Limit 10(nn-3) °C 0.001°C to 1°C */ - { 0x254, 1.0e-3, "°C", "Cold / Warm Temperature Limit" }, - { 0x255, 1.0e-2, "°C", "Cold / Warm Temperature Limit" }, - { 0x256, 1.0e-1, "°C", "Cold / Warm Temperature Limit" }, - { 0x257, 1.0e0, "°C", "Cold / Warm Temperature Limit" }, + { 0x274, 1.0e-3, "°C", "Cold / Warm Temperature Limit" }, + { 0x275, 1.0e-2, "°C", "Cold / Warm Temperature Limit" }, + { 0x276, 1.0e-1, "°C", "Cold / Warm Temperature Limit" }, + { 0x277, 1.0e0, "°C", "Cold / Warm Temperature Limit" }, /* E111 1nnn cumul. count max power § 10(nnn-3) W 0.001W to 10000W */ - { 0x258, 1.0e-3, "W", "Cumul count max power" }, - { 0x259, 1.0e-3, "W", "Cumul count max power" }, - { 0x25A, 1.0e-1, "W", "Cumul count max power" }, - { 0x25B, 1.0e0, "W", "Cumul count max power" }, - { 0x25C, 1.0e1, "W", "Cumul count max power" }, - { 0x25D, 1.0e2, "W", "Cumul count max power" }, - { 0x25E, 1.0e3, "W", "Cumul count max power" }, - { 0x25F, 1.0e4, "W", "Cumul count max power" }, + { 0x278, 1.0e-3, "W", "Cumul count max power" }, + { 0x279, 1.0e-3, "W", "Cumul count max power" }, + { 0x27A, 1.0e-1, "W", "Cumul count max power" }, + { 0x27B, 1.0e0, "W", "Cumul count max power" }, + { 0x27C, 1.0e1, "W", "Cumul count max power" }, + { 0x27D, 1.0e2, "W", "Cumul count max power" }, + { 0x27E, 1.0e3, "W", "Cumul count max power" }, + { 0x27F, 1.0e4, "W", "Cumul count max power" }, /* End of array */ { 0xFFFF, 0.0, "", "" }, @@ -794,6 +834,9 @@ int mbus_variable_value_decode(mbus_data_record *record, double *value_out_real, int result = 0; unsigned char vif, vife; struct tm time; + int value_out_int; + long value_out_long; + long long value_out_long_long; *value_out_real = 0.0; *value_out_str = NULL; *value_out_str_size = 0; @@ -806,7 +849,7 @@ int mbus_variable_value_decode(mbus_data_record *record, double *value_out_real, vif = (record->drh.vib.vif & MBUS_DIB_VIF_WITHOUT_EXTENSION); vife = (record->drh.vib.vife[0] & MBUS_DIB_VIF_WITHOUT_EXTENSION); - switch (record->drh.dib.dif & 0x0F) + switch (record->drh.dib.dif & MBUS_DATA_RECORD_DIF_MASK_DATA) { case 0x00: /* no data */ if ((*value_out_str = (char*) malloc(1)) == NULL) @@ -819,8 +862,8 @@ int mbus_variable_value_decode(mbus_data_record *record, double *value_out_real, break; case 0x01: /* 1 byte integer (8 bit) */ - *value_out_real = mbus_data_int_decode(record->data, 1); - result = 0; + result = mbus_data_int_decode(record->data, 1, &value_out_int); + *value_out_real = value_out_int; break; case 0x02: /* 2 byte integer (16 bit) */ @@ -837,18 +880,18 @@ int mbus_variable_value_decode(mbus_data_record *record, double *value_out_real, (time.tm_year + 2000), (time.tm_mon + 1), time.tm_mday); + result = 0; } else // normal integer { - *value_out_real = mbus_data_int_decode(record->data, 2); + result = mbus_data_int_decode(record->data, 2, &value_out_int); + *value_out_real = value_out_int; } - - result = 0; break; case 0x03: /* 3 byte integer (24 bit) */ - *value_out_real = mbus_data_int_decode(record->data, 3); - result = 0; + result = mbus_data_int_decode(record->data, 3, &value_out_int); + *value_out_real = value_out_int; break; case 0x04: /* 4 byte integer (32 bit) */ @@ -872,12 +915,13 @@ int mbus_variable_value_decode(mbus_data_record *record, double *value_out_real, time.tm_hour, time.tm_min, time.tm_sec); + result = 0; } else // normal integer { - *value_out_real = mbus_data_int_decode(record->data, 4); + result = mbus_data_int_decode(record->data, 4, &value_out_int); + *value_out_real = value_out_int; } - result = 0; break; case 0x05: /* 32b real */ @@ -886,13 +930,13 @@ int mbus_variable_value_decode(mbus_data_record *record, double *value_out_real, break; case 0x06: /* 6 byte integer (48 bit) */ - *value_out_real = mbus_data_long_long_decode(record->data, 6); - result = 0; + result = mbus_data_long_long_decode(record->data, 6, &value_out_long_long); + *value_out_real = value_out_long_long; break; case 0x07: /* 8 byte integer (64 bit) */ - *value_out_real = mbus_data_long_long_decode(record->data, 8); - result = 0; + result = mbus_data_long_long_decode(record->data, 8, &value_out_long_long); + *value_out_real = value_out_long_long; break; case 0x09: /* 2 digit BCD (8 bit) */ @@ -1112,6 +1156,9 @@ mbus_record_new() record->unit = NULL; record->function_medium = NULL; record->quantity = NULL; + record->device = -1; + record->tariff = -1; + record->storage_number = 0; return record; } @@ -1177,7 +1224,7 @@ mbus_parse_fixed_record(char status_byte, char medium_unit, unsigned char *data) } else { - value = mbus_data_int_decode(data, 4); + mbus_data_long_decode(data, 4, &value); } record->unit = NULL; @@ -1213,6 +1260,10 @@ mbus_parse_variable_record(mbus_data_record *data) MBUS_ERROR("%s: memory allocation error\n", __PRETTY_FUNCTION__); return NULL; } + + record->storage_number = mbus_data_record_storage_number(data); + record->tariff = mbus_data_record_tariff(data); + record->device = mbus_data_record_device(data); if ((data->drh.dib.dif == MBUS_DIB_DIF_MANUFACTURER_SPECIFIC) || (data->drh.dib.dif == MBUS_DIB_DIF_MORE_RECORDS_FOLLOW)) /* MBUS_DIB_DIF_VENDOR_SPECIFIC */ @@ -1351,6 +1402,14 @@ mbus_data_variable_xml_normalized(mbus_data_variable *data) { mbus_str_xml_encode(str_encoded, norm_record->function_medium, sizeof(str_encoded)); len += snprintf(&buff[len], buff_size - len, " %s\n", str_encoded); + + len += snprintf(&buff[len], buff_size - len, " %ld\n", norm_record->storage_number); + + if (norm_record->tariff >= 0) + { + len += snprintf(&buff[len], buff_size - len, " %ld\n", norm_record->tariff); + len += snprintf(&buff[len], buff_size - len, " %d\n", norm_record->device); + } mbus_str_xml_encode(str_encoded, norm_record->unit, sizeof(str_encoded)); @@ -1430,7 +1489,8 @@ mbus_context_serial(const char *device) return NULL; } - handle->max_retry = 3; + handle->max_data_retry = 3; + handle->max_search_retry = 1; handle->is_serial = 1; handle->purge_first_frame = MBUS_FRAME_PURGE_M2S; handle->auxdata = serial_data; @@ -1477,7 +1537,8 @@ mbus_context_tcp(const char *host, uint16_t port) return NULL; } - handle->max_retry = 3; + handle->max_data_retry = 3; + handle->max_search_retry = 1; handle->is_serial = 0; handle->purge_first_frame = MBUS_FRAME_PURGE_M2S; handle->auxdata = tcp_data; @@ -1549,10 +1610,17 @@ mbus_context_set_option(mbus_handle * handle, mbus_context_option option, long v switch (option) { - case MBUS_OPTION_MAX_RETRY: + case MBUS_OPTION_MAX_DATA_RETRY: if ((value >= 0) && (value <= 9)) { - handle->max_retry = value; + handle->max_data_retry = value; + return 0; + } + break; + case MBUS_OPTION_MAX_SEARCH_RETRY: + if ((value >= 0) && (value <= 9)) + { + handle->max_search_retry = value; return 0; } break; @@ -1934,7 +2002,7 @@ mbus_sendrecv_request(mbus_handle *handle, int address, mbus_frame *reply, int m while (more_frames) { - if (retry > handle->max_retry) + if (retry > handle->max_data_retry) { // Give up retval = 1; @@ -2155,7 +2223,7 @@ mbus_select_secondary_address(mbus_handle * handle, const char *mask) int mbus_probe_secondary_address(mbus_handle *handle, const char *mask, char *matching_addr) { - int ret; + int ret, i; mbus_frame reply; if (mask == NULL || matching_addr == NULL || strlen(mask) != 16) @@ -2164,68 +2232,77 @@ mbus_probe_secondary_address(mbus_handle *handle, const char *mask, char *matchi return MBUS_PROBE_ERROR; } - ret = mbus_select_secondary_address(handle, mask); - - if (ret == MBUS_PROBE_SINGLE) + for (i = 0; i <= handle->max_search_retry; i++) { - /* send a data request command to find out the full address */ - if (mbus_send_request_frame(handle, MBUS_ADDRESS_NETWORK_LAYER) == -1) - { - MBUS_ERROR("%s: Failed to send request to selected secondary device [mask %s]: %s.\n", - __PRETTY_FUNCTION__, - mask, - mbus_error_str()); - return MBUS_PROBE_ERROR; - } + ret = mbus_select_secondary_address(handle, mask); - memset((void *)&reply, 0, sizeof(mbus_frame)); - ret = mbus_recv_frame(handle, &reply); + if (ret == MBUS_PROBE_SINGLE) + { + /* send a data request command to find out the full address */ + if (mbus_send_request_frame(handle, MBUS_ADDRESS_NETWORK_LAYER) == -1) + { + MBUS_ERROR("%s: Failed to send request to selected secondary device [mask %s]: %s.\n", + __PRETTY_FUNCTION__, + mask, + mbus_error_str()); + return MBUS_PROBE_ERROR; + } - if (ret == MBUS_RECV_RESULT_TIMEOUT) - { - return MBUS_PROBE_NOTHING; - } + memset((void *)&reply, 0, sizeof(mbus_frame)); + ret = mbus_recv_frame(handle, &reply); - if (ret == MBUS_RECV_RESULT_INVALID) - { - /* check for more data (collision) */ - mbus_purge_frames(handle); - return MBUS_PROBE_COLLISION; - } - - /* check for more data (collision) */ - if (mbus_purge_frames(handle)) - { - return MBUS_PROBE_COLLISION; - } - - if (mbus_frame_type(&reply) == MBUS_FRAME_TYPE_LONG) - { - char *addr = mbus_frame_get_secondary_address(&reply); - - if (addr == NULL) + if (ret == MBUS_RECV_RESULT_TIMEOUT) { - // show error message, but procede with scan - MBUS_ERROR("Failed to generate secondary address from M-Bus reply frame: %s\n", mbus_error_str()); return MBUS_PROBE_NOTHING; } - snprintf(matching_addr, 17, "%s", addr); - - if (handle->found_event) + if (ret == MBUS_RECV_RESULT_INVALID) { - handle->found_event(handle,&reply); - } + /* check for more data (collision) */ + mbus_purge_frames(handle); + return MBUS_PROBE_COLLISION; + } - return MBUS_PROBE_SINGLE; - } - else - { - MBUS_ERROR("%s: Unexpected reply for address [mask %s]. Expected long frame.\n", - __PRETTY_FUNCTION__, mask); - return MBUS_PROBE_NOTHING; - } - } + /* check for more data (collision) */ + if (mbus_purge_frames(handle)) + { + return MBUS_PROBE_COLLISION; + } + + if (mbus_frame_type(&reply) == MBUS_FRAME_TYPE_LONG) + { + char *addr = mbus_frame_get_secondary_address(&reply); + + if (addr == NULL) + { + // show error message, but procede with scan + MBUS_ERROR("Failed to generate secondary address from M-Bus reply frame: %s\n", + mbus_error_str()); + return MBUS_PROBE_NOTHING; + } + + snprintf(matching_addr, 17, "%s", addr); + + if (handle->found_event) + { + handle->found_event(handle,&reply); + } + + return MBUS_PROBE_SINGLE; + } + else + { + MBUS_ERROR("%s: Unexpected reply for address [mask %s]. Expected long frame.\n", + __PRETTY_FUNCTION__, mask); + return MBUS_PROBE_NOTHING; + } + } + else if ((ret == MBUS_PROBE_ERROR) || + (ret == MBUS_PROBE_COLLISION)) + { + break; + } + } return ret; } @@ -2252,7 +2329,6 @@ int mbus_read_slave(mbus_handle * handle, mbus_address *address, mbus_frame * re { /* secondary addressing */ int probe_ret; - char matching_addr[16]; if (address->secondary == NULL) { @@ -2261,7 +2337,7 @@ int mbus_read_slave(mbus_handle * handle, mbus_address *address, mbus_frame * re return -1; } - probe_ret = mbus_probe_secondary_address(handle, address->secondary, matching_addr); + probe_ret = mbus_select_secondary_address(handle, address->secondary); if (probe_ret == MBUS_PROBE_COLLISION) { @@ -2338,6 +2414,7 @@ mbus_scan_2nd_address_range(mbus_handle * handle, int pos, char *addr_mask) if (mask[pos] == 'f' || mask[pos] == 'F') { + // mask[pos] is a wildcard -> enumerate all 0..9 at this position i_start = 0; i_end = 9; } @@ -2345,44 +2422,50 @@ mbus_scan_2nd_address_range(mbus_handle * handle, int pos, char *addr_mask) { if (pos < 15) { + // mask[pos] is not a wildcard -> don't iterate, recursively check pos+1 mbus_scan_2nd_address_range(handle, pos+1, mask); } else { + // .. except if we're at the last pos (==15) and this isn't a wildcard we still need to send the probe i_start = (int)(mask[pos] - '0'); i_end = (int)(mask[pos] - '0'); } } - for (i = 0; i <= 9; i++) + // skip the scanning if we're returning from the (pos < 15) case above + if (mask[pos] == 'f' || mask[pos] == 'F' || pos == 15) { - mask[pos] = '0'+i; - - if (handle->scan_progress) - handle->scan_progress(handle,mask); - - probe_ret = mbus_probe_secondary_address(handle, mask, matching_mask); - - if (probe_ret == MBUS_PROBE_SINGLE) + for (i = i_start; i <= i_end; i++) { - if (!handle->found_event) + mask[pos] = '0'+i; + + if (handle->scan_progress) + handle->scan_progress(handle,mask); + + probe_ret = mbus_probe_secondary_address(handle, mask, matching_mask); + + if (probe_ret == MBUS_PROBE_SINGLE) { - printf("Found a device on secondary address %s [using address mask %s]\n", matching_mask, mask); + if (!handle->found_event) + { + printf("Found a device on secondary address %s [using address mask %s]\n", matching_mask, mask); + } + } + else if (probe_ret == MBUS_PROBE_COLLISION) + { + // collision, more than one device matching, restrict the search mask further + mbus_scan_2nd_address_range(handle, pos+1, mask); + } + else if (probe_ret == MBUS_PROBE_NOTHING) + { + // nothing... move on to next address mask + } + else // MBUS_PROBE_ERROR + { + MBUS_ERROR("%s: Failed to probe secondary address [%s].\n", __PRETTY_FUNCTION__, mask); + return -1; } - } - else if (probe_ret == MBUS_PROBE_COLLISION) - { - // collision, more than one device matching, restrict the search mask further - mbus_scan_2nd_address_range(handle, pos+1, mask); - } - else if (probe_ret == MBUS_PROBE_NOTHING) - { - // nothing... move on to next address mask - } - else // MBUS_PROBE_ERROR - { - MBUS_ERROR("%s: Failed to probe secondary address [%s].\n", __PRETTY_FUNCTION__, mask); - return -1; } } diff --git a/mbus/mbus-protocol-aux.h b/mbus/mbus-protocol-aux.h index 2cb61ec..52cfc54 100755 --- a/mbus/mbus-protocol-aux.h +++ b/mbus/mbus-protocol-aux.h @@ -85,7 +85,8 @@ extern "C" { */ typedef struct _mbus_handle { int fd; - int max_retry; + int max_data_retry; + int max_search_retry; char purge_first_frame; char is_serial; /**< _handle type (non zero for serial) */ int (*open) (struct _mbus_handle *handle); @@ -142,13 +143,17 @@ typedef struct _mbus_record { char *unit; /**< Quantity unit (e.g. Wh) */ char *function_medium; /**< Quantity medium or function (e.g. Electricity) */ char *quantity; /**< Quantity type (e.g. Energy) */ + int device; /**< Quantity device */ + long tariff; /**< Quantity tariff */ + long storage_number; /**< Quantity storage number */ } mbus_record; /** * MBus handle option enumeration */ typedef enum _mbus_context_option { - MBUS_OPTION_MAX_RETRY, /**< option defines the maximum attempts of data retransmission */ + MBUS_OPTION_MAX_DATA_RETRY, /**< option defines the maximum attempts of data request retransmission */ + MBUS_OPTION_MAX_SEARCH_RETRY, /**< option defines the maximum attempts of search request retransmission */ MBUS_OPTION_PURGE_FIRST_FRAME /**< option controls the echo cancelation for mbus_recv_frame */ } mbus_context_option; diff --git a/mbus/mbus-protocol.c b/mbus/mbus-protocol.c index 8ec3130..27b0354 100755 --- a/mbus/mbus-protocol.c +++ b/mbus/mbus-protocol.c @@ -480,60 +480,105 @@ mbus_data_bcd_decode(unsigned char *bcd_data, size_t bcd_data_size) /// //------------------------------------------------------------------------------ int -mbus_data_int_decode(unsigned char *int_data, size_t int_data_size) +mbus_data_int_decode(unsigned char *int_data, size_t int_data_size, int *value) { - int val = 0; size_t i; + int neg; + *value = 0; - if (int_data) + if (!int_data || (int_data_size < 1)) { - for (i = int_data_size; i > 0; i--) - { - val = (val << 8) + int_data[i-1]; - } - - return val; + return -1; + } + + neg = int_data[int_data_size-1] & 0x80; + + for (i = int_data_size; i > 0; i--) + { + if (neg) + { + *value = (*value << 8) + (int_data[i-1] ^ 0xFF); + } + else + { + *value = (*value << 8) + int_data[i-1]; + } } - return -1; + if (neg) + { + *value = *value * -1 - 1; + } + + return 0; } -long -mbus_data_long_decode(unsigned char *int_data, size_t int_data_size) +int +mbus_data_long_decode(unsigned char *int_data, size_t int_data_size, long *value) { - long val = 0; size_t i; + int neg; + *value = 0; - if (int_data) + if (!int_data || (int_data_size < 1)) { - for (i = int_data_size; i > 0; i--) - { - val = (val << 8) + int_data[i-1]; - } - - return val; + return -1; + } + + neg = int_data[int_data_size-1] & 0x80; + + for (i = int_data_size; i > 0; i--) + { + if (neg) + { + *value = (*value << 8) + (int_data[i-1] ^ 0xFF); + } + else + { + *value = (*value << 8) + int_data[i-1]; + } } - return -1; + if (neg) + { + *value = *value * -1 - 1; + } + + return 0; } -long long -mbus_data_long_long_decode(unsigned char *int_data, size_t int_data_size) +int +mbus_data_long_long_decode(unsigned char *int_data, size_t int_data_size, long long *value) { - long long val = 0; size_t i; + int neg; + *value = 0; - if (int_data) + if (!int_data || (int_data_size < 1)) { - for (i = int_data_size; i > 0; i--) - { - val = (val << 8) + int_data[i-1]; - } - - return val; + return -1; + } + + neg = int_data[int_data_size-1] & 0x80; + + for (i = int_data_size; i > 0; i--) + { + if (neg) + { + *value = (*value << 8) + (int_data[i-1] ^ 0xFF); + } + else + { + *value = (*value << 8) + int_data[i-1]; + } } - return -1; + if (neg) + { + *value = *value * -1 - 1; + } + + return 0; } //------------------------------------------------------------------------------ @@ -742,7 +787,7 @@ mbus_decode_manufacturer(unsigned char byte1, unsigned char byte2) m_str[0] = byte1; m_str[1] = byte2; - m_id = mbus_data_int_decode(m_str, 2); + mbus_data_int_decode(m_str, 2, &m_id); m_str[0] = (char)(((m_id>>10) & 0x001F) + 64); m_str[1] = (char)(((m_id>>5) & 0x001F) + 64); @@ -830,6 +875,15 @@ mbus_data_product_name(mbus_data_variable_header *header) break; } } + else if (manufacturer == MBUS_VARIABLE_DATA_MAN_GMC) + { + switch (header->version) + { + case 0xE6: + strcpy(buff,"GMC-I A230 EMMOD 206"); + break; + } + } else if (manufacturer == MBUS_VARIABLE_DATA_MAN_SLB) { switch (header->version) @@ -869,6 +923,15 @@ mbus_data_product_name(mbus_data_variable_header *header) break; } } + else if (manufacturer == MBUS_VARIABLE_DATA_MAN_RAM) + { + switch (header->version) + { + case 0x03: + strcpy(buff, "Rossweiner ETK/ETW Modularis"); + break; + } + } else if (manufacturer == MBUS_VARIABLE_DATA_MAN_RKE) { switch (header->version) @@ -1540,14 +1603,14 @@ mbus_unit_prefix(int exp) } //------------------------------------------------------------------------------ -/// Look up the data lenght from a VIF field in the data record. +/// Look up the data length from a DIF field in the data record. /// /// See the table on page 41 the M-BUS specification. //------------------------------------------------------------------------------ unsigned char mbus_dif_datalength_lookup(unsigned char dif) { - switch (dif&0x0F) + switch (dif & MBUS_DATA_RECORD_DIF_MASK_DATA) { case 0x0: return 0; @@ -2149,16 +2212,16 @@ mbus_data_record_decode(mbus_data_record *record) if (record) { - int val; - float val3; - long long val4; + int int_val; + float float_val; + long long long_long_val; struct tm time; // ignore extension bit vif = (record->drh.vib.vif & MBUS_DIB_VIF_WITHOUT_EXTENSION); vife = (record->drh.vib.vife[0] & MBUS_DIB_VIF_WITHOUT_EXTENSION); - switch (record->drh.dib.dif & 0x0F) + switch (record->drh.dib.dif & MBUS_DATA_RECORD_DIF_MASK_DATA) { case 0x00: // no data @@ -2168,9 +2231,9 @@ mbus_data_record_decode(mbus_data_record *record) case 0x01: // 1 byte integer (8 bit) - val = mbus_data_int_decode(record->data, 1); + mbus_data_int_decode(record->data, 1, &int_val); - snprintf(buff, sizeof(buff), "%d", val); + snprintf(buff, sizeof(buff), "%d", int_val); if (debug) printf("%s: DIF 0x%.2x was decoded using 1 byte integer\n", __PRETTY_FUNCTION__, record->drh.dib.dif); @@ -2191,8 +2254,8 @@ mbus_data_record_decode(mbus_data_record *record) } else // 2 byte integer { - val = mbus_data_int_decode(record->data, 2); - snprintf(buff, sizeof(buff), "%d", val); + mbus_data_int_decode(record->data, 2, &int_val); + snprintf(buff, sizeof(buff), "%d", int_val); if (debug) printf("%s: DIF 0x%.2x was decoded using 2 byte integer\n", __PRETTY_FUNCTION__, record->drh.dib.dif); @@ -2202,9 +2265,9 @@ mbus_data_record_decode(mbus_data_record *record) case 0x03: // 3 byte integer (24 bit) - val = mbus_data_int_decode(record->data, 3); + mbus_data_int_decode(record->data, 3, &int_val); - snprintf(buff, sizeof(buff), "%d", val); + snprintf(buff, sizeof(buff), "%d", int_val); if (debug) printf("%s: DIF 0x%.2x was decoded using 3 byte integer\n", __PRETTY_FUNCTION__, record->drh.dib.dif); @@ -2231,8 +2294,8 @@ mbus_data_record_decode(mbus_data_record *record) } else // 4 byte integer { - val = mbus_data_int_decode(record->data, 4); - snprintf(buff, sizeof(buff), "%d", val); + mbus_data_int_decode(record->data, 4, &int_val); + snprintf(buff, sizeof(buff), "%d", int_val); } if (debug) @@ -2242,9 +2305,9 @@ mbus_data_record_decode(mbus_data_record *record) case 0x05: // 4 Byte Real (32 bit) - val3 = mbus_data_float_decode(record->data); + float_val = mbus_data_float_decode(record->data); - snprintf(buff, sizeof(buff), "%f", val3); + snprintf(buff, sizeof(buff), "%f", float_val); if (debug) printf("%s: DIF 0x%.2x was decoded using 4 byte Real\n", __PRETTY_FUNCTION__, record->drh.dib.dif); @@ -2253,9 +2316,9 @@ mbus_data_record_decode(mbus_data_record *record) case 0x06: // 6 byte integer (48 bit) - val4 = mbus_data_long_long_decode(record->data, 6); + mbus_data_long_long_decode(record->data, 6, &long_long_val); - snprintf(buff, sizeof(buff), "%lld", val4); + snprintf(buff, sizeof(buff), "%lld", long_long_val); if (debug) printf("%s: DIF 0x%.2x was decoded using 6 byte integer\n", __PRETTY_FUNCTION__, record->drh.dib.dif); @@ -2264,9 +2327,9 @@ mbus_data_record_decode(mbus_data_record *record) case 0x07: // 8 byte integer (64 bit) - val4 = mbus_data_long_long_decode(record->data, 8); + mbus_data_long_long_decode(record->data, 8, &long_long_val); - snprintf(buff, sizeof(buff), "%lld", val4); + snprintf(buff, sizeof(buff), "%lld", long_long_val); if (debug) printf("%s: DIF 0x%.2x was decoded using 8 byte integer\n", __PRETTY_FUNCTION__, record->drh.dib.dif); @@ -2277,8 +2340,8 @@ mbus_data_record_decode(mbus_data_record *record) case 0x09: // 2 digit BCD (8 bit) - val = (int)mbus_data_bcd_decode(record->data, 1); - snprintf(buff, sizeof(buff), "%d", val); + int_val = (int)mbus_data_bcd_decode(record->data, 1); + snprintf(buff, sizeof(buff), "%d", int_val); if (debug) printf("%s: DIF 0x%.2x was decoded using 2 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif); @@ -2287,8 +2350,8 @@ mbus_data_record_decode(mbus_data_record *record) case 0x0A: // 4 digit BCD (16 bit) - val = (int)mbus_data_bcd_decode(record->data, 2); - snprintf(buff, sizeof(buff), "%d", val); + int_val = (int)mbus_data_bcd_decode(record->data, 2); + snprintf(buff, sizeof(buff), "%d", int_val); if (debug) printf("%s: DIF 0x%.2x was decoded using 4 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif); @@ -2297,8 +2360,8 @@ mbus_data_record_decode(mbus_data_record *record) case 0x0B: // 6 digit BCD (24 bit) - val = (int)mbus_data_bcd_decode(record->data, 3); - snprintf(buff, sizeof(buff), "%d", val); + int_val = (int)mbus_data_bcd_decode(record->data, 3); + snprintf(buff, sizeof(buff), "%d", int_val); if (debug) printf("%s: DIF 0x%.2x was decoded using 6 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif); @@ -2307,8 +2370,8 @@ mbus_data_record_decode(mbus_data_record *record) case 0x0C: // 8 digit BCD (32 bit) - val = (int)mbus_data_bcd_decode(record->data, 4); - snprintf(buff, sizeof(buff), "%d", val); + int_val = (int)mbus_data_bcd_decode(record->data, 4); + snprintf(buff, sizeof(buff), "%d", int_val); if (debug) printf("%s: DIF 0x%.2x was decoded using 8 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif); @@ -2317,8 +2380,8 @@ mbus_data_record_decode(mbus_data_record *record) case 0x0E: // 12 digit BCD (48 bit) - val4 = mbus_data_bcd_decode(record->data, 6); - snprintf(buff, sizeof(buff), "%lld", val4); + long_long_val = mbus_data_bcd_decode(record->data, 6); + snprintf(buff, sizeof(buff), "%lld", long_long_val); if (debug) printf("%s: DIF 0x%.2x was decoded using 12 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif); @@ -2385,6 +2448,78 @@ mbus_data_record_value(mbus_data_record *record) return NULL; } +//------------------------------------------------------------------------------ +/// Return the storage number for a variable-length data record +//------------------------------------------------------------------------------ +long mbus_data_record_storage_number(mbus_data_record *record) +{ + int bit_index; + long result = 0; + int i; + + if (record) + { + result |= (record->drh.dib.dif & MBUS_DATA_RECORD_DIF_MASK_STORAGE_NO) >> 6; + bit_index++; + + for (i=0; idrh.dib.ndife; i++) + { + result |= (record->drh.dib.dife[i] & MBUS_DATA_RECORD_DIFE_MASK_STORAGE_NO) << bit_index; + bit_index += 4; + } + + return result; + } + + return 0; +} + +//------------------------------------------------------------------------------ +/// Return the tariff for a variable-length data record +//------------------------------------------------------------------------------ +long mbus_data_record_tariff(mbus_data_record *record) +{ + int bit_index; + long result = 0; + int i; + + if (record && (record->drh.dib.ndife > 0)) + { + for (i=0; idrh.dib.ndife; i++) + { + result |= ((record->drh.dib.dife[i] & MBUS_DATA_RECORD_DIFE_MASK_TARIFF) >> 4) << bit_index; + bit_index += 2; + } + + return result; + } + + return -1; +} + +//------------------------------------------------------------------------------ +/// Return device unit for a variable-length data record +//------------------------------------------------------------------------------ +int mbus_data_record_device(mbus_data_record *record) +{ + int bit_index; + int result = 0; + int i; + + if (record && (record->drh.dib.ndife > 0)) + { + for (i=0; idrh.dib.ndife; i++) + { + result |= ((record->drh.dib.dife[i] & MBUS_DATA_RECORD_DIFE_MASK_DEVICE) >> 6) << bit_index; + bit_index++; + } + + return result; + } + + return -1; +} + //------------------------------------------------------------------------------ /// Return a string containing the function description //------------------------------------------------------------------------------ @@ -2827,7 +2962,7 @@ mbus_data_variable_parse(mbus_frame *frame, mbus_data_variable *data) } // re-calculate data length, if of variable length type - if ((record->drh.dib.dif & 0x0F) == 0x0D) // flag for variable length data + if ((record->drh.dib.dif & MBUS_DATA_RECORD_DIF_MASK_DATA) == 0x0D) // flag for variable length data { if(frame->data[i] <= 0xBF) record->data_len = frame->data[i++]; @@ -3270,10 +3405,11 @@ mbus_data_variable_print(mbus_data_variable *data) for (record = data->record; record; record = record->next) { // DIF - printf("DIF = %.2X\n", record->drh.dib.dif); - printf("DIF.Extension = %s\n", (record->drh.dib.dif & MBUS_DIB_DIF_EXTENSION_BIT) ? "Yes":"No"); - printf("DIF.Function = %s\n", (record->drh.dib.dif & 0x30) ? "Minimum value" : "Instantaneous value" ); - printf("DIF.Data = %.2X\n", record->drh.dib.dif & 0x0F); + printf("DIF = %.2X\n", record->drh.dib.dif); + printf("DIF.Extension = %s\n", (record->drh.dib.dif & MBUS_DIB_DIF_EXTENSION_BIT) ? "Yes":"No"); + printf("DIF.StorageNumber = %d\n", (record->drh.dib.dif & MBUS_DATA_RECORD_DIF_MASK_STORAGE_NO) >> 6); + printf("DIF.Function = %s\n", (record->drh.dib.dif & 0x30) ? "Minimum value" : "Instantaneous value" ); + printf("DIF.Data = %.2X\n", record->drh.dib.dif & 0x0F); // VENDOR SPECIFIC if ((record->drh.dib.dif == MBUS_DIB_DIF_MANUFACTURER_SPECIFIC) || @@ -3301,10 +3437,11 @@ mbus_data_variable_print(mbus_data_variable *data) { unsigned char dife = record->drh.dib.dife[j]; - printf("DIFE[%zd] = %.2X\n", j, dife); - printf("DIFE[%zd].Extension = %s\n", j, (dife & MBUS_DIB_DIF_EXTENSION_BIT) ? "Yes" : "No"); - printf("DIFE[%zd].Function = %s\n", j, (dife & 0x30) ? "Minimum value" : "Instantaneous value" ); - printf("DIFE[%zd].Data = %.2X\n", j, dife & 0x0F); + printf("DIFE[%zd] = %.2X\n", j, dife); + printf("DIFE[%zd].Extension = %s\n", j, (dife & MBUS_DATA_RECORD_DIFE_MASK_EXTENSION) ? "Yes" : "No"); + printf("DIFE[%zd].Device = %d\n", j, (dife & MBUS_DATA_RECORD_DIFE_MASK_DEVICE) >> 6 ); + printf("DIFE[%zd].Tariff = %d\n", j, (dife & MBUS_DATA_RECORD_DIFE_MASK_TARIFF) >> 4 ); + printf("DIFE[%zd].StorageNumber = %.2X\n", j, dife & MBUS_DATA_RECORD_DIFE_MASK_STORAGE_NO); } // VIF @@ -3332,6 +3469,8 @@ mbus_data_variable_print(mbus_data_variable *data) int mbus_data_fixed_print(mbus_data_fixed *data) { + int val; + if (data) { printf("%s: ID = %d\n", __PRETTY_FUNCTION__, (int)mbus_data_bcd_decode(data->id_bcd, 4)); @@ -3343,23 +3482,26 @@ 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 = %d\n", __PRETTY_FUNCTION__, (int)mbus_data_bcd_decode(data->cnt1_val, 4)); + val = mbus_data_bcd_decode(data->cnt1_val, 4); } else { - printf("%s: Counter1 = %d\n", __PRETTY_FUNCTION__, mbus_data_int_decode(data->cnt1_val, 4)); + mbus_data_int_decode(data->cnt1_val, 4, &val); + } + printf("%s: Counter1 = %d\n", __PRETTY_FUNCTION__, val); printf("%s: Medium2 = %s\n", __PRETTY_FUNCTION__, mbus_data_fixed_medium(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 = %d\n", __PRETTY_FUNCTION__, (int)mbus_data_bcd_decode(data->cnt2_val, 4)); + val = mbus_data_bcd_decode(data->cnt2_val, 4); } else { - printf("%s: Counter2 = %d\n", __PRETTY_FUNCTION__, mbus_data_int_decode(data->cnt2_val, 4)); + mbus_data_int_decode(data->cnt2_val, 4, &val); } + printf("%s: Counter2 = %d\n", __PRETTY_FUNCTION__, val); } return -1; @@ -3515,6 +3657,7 @@ mbus_data_variable_record_xml(mbus_data_record *record, int record_cnt, int fram size_t len = 0; struct tm * timeinfo; char timestamp[21]; + long tariff; if (record) { @@ -3545,6 +3688,19 @@ mbus_data_variable_record_xml(mbus_data_record *record, int record_cnt, int fram mbus_str_xml_encode(str_encoded, mbus_data_record_function(record), sizeof(str_encoded)); len += snprintf(&buff[len], sizeof(buff) - len, " %s\n", str_encoded); + + len += snprintf(&buff[len], sizeof(buff) - len, + " %ld\n", + mbus_data_record_storage_number(record)); + + + if ((tariff = mbus_data_record_tariff(record)) >= 0) + { + len += snprintf(&buff[len], sizeof(buff) - len, " %ld\n", + tariff); + len += snprintf(&buff[len], sizeof(buff) - len, " %d\n", + mbus_data_record_device(record)); + } mbus_str_xml_encode(str_encoded, mbus_data_record_unit(record), sizeof(str_encoded)); len += snprintf(&buff[len], sizeof(buff) - len, @@ -3629,6 +3785,7 @@ mbus_data_fixed_xml(mbus_data_fixed *data) char *buff = NULL; char str_encoded[256]; size_t len = 0, buff_size = 8192; + int val; if (data) { @@ -3658,12 +3815,14 @@ 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, " %d\n", (int)mbus_data_bcd_decode(data->cnt1_val, 4)); + val = mbus_data_bcd_decode(data->cnt1_val, 4); } else { - len += snprintf(&buff[len], buff_size - len, " %d\n", mbus_data_int_decode(data->cnt1_val, 4)); + mbus_data_int_decode(data->cnt1_val, 4, &val); } + len += snprintf(&buff[len], buff_size - len, " %d\n", val); + len += snprintf(&buff[len], buff_size - len, " \n\n"); len += snprintf(&buff[len], buff_size - len, " \n"); @@ -3675,12 +3834,14 @@ 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, " %d\n", (int)mbus_data_bcd_decode(data->cnt2_val, 4)); + val = mbus_data_bcd_decode(data->cnt2_val, 4); } else { - len += snprintf(&buff[len], buff_size - len, " %d\n", mbus_data_int_decode(data->cnt2_val, 4)); + mbus_data_int_decode(data->cnt2_val, 4, &val); } + len += snprintf(&buff[len], buff_size - len, " %d\n", val); + len += snprintf(&buff[len], buff_size - len, " \n\n"); len += snprintf(&buff[len], buff_size - len, "\n"); diff --git a/mbus/mbus-protocol.h b/mbus/mbus-protocol.h index 8c8edde..c63e089 100755 --- a/mbus/mbus-protocol.h +++ b/mbus/mbus-protocol.h @@ -445,6 +445,11 @@ typedef struct _mbus_data_secondary_address { #define MBUS_DATA_RECORD_DIF_MASK_EXTENTION 0x80 #define MBUS_DATA_RECORD_DIF_MASK_NON_DATA 0xF0 +#define MBUS_DATA_RECORD_DIFE_MASK_STORAGE_NO 0x0F +#define MBUS_DATA_RECORD_DIFE_MASK_TARIFF 0x30 +#define MBUS_DATA_RECORD_DIFE_MASK_DEVICE 0x40 +#define MBUS_DATA_RECORD_DIFE_MASK_EXTENSION 0x80 + // // GENERAL APPLICATION ERRORS // @@ -494,6 +499,7 @@ typedef struct _mbus_data_secondary_address { #define MBUS_VARIABLE_DATA_MAN_ELS 0x1593 #define MBUS_VARIABLE_DATA_MAN_ELV 0x1596 #define MBUS_VARIABLE_DATA_MAN_EMH 0x15A8 +#define MBUS_VARIABLE_DATA_MAN_GMC 0x1DA3 #define MBUS_VARIABLE_DATA_MAN_HYD 0x2324 #define MBUS_VARIABLE_DATA_MAN_KAM 0x2C2D #define MBUS_VARIABLE_DATA_MAN_LSE 0x3265 @@ -501,6 +507,7 @@ typedef struct _mbus_data_secondary_address { #define MBUS_VARIABLE_DATA_MAN_NZR 0x3B52 #define MBUS_VARIABLE_DATA_MAN_PAD 0x4024 #define MBUS_VARIABLE_DATA_MAN_QDS 0x4493 +#define MBUS_VARIABLE_DATA_MAN_RAM 0x482D #define MBUS_VARIABLE_DATA_MAN_RKE 0x4965 #define MBUS_VARIABLE_DATA_MAN_SEN 0x4CAE #define MBUS_VARIABLE_DATA_MAN_SLB 0x4D82 @@ -559,6 +566,9 @@ int mbus_frame_internal_pack(mbus_frame *frame, mbus_frame_data *frame_data); // const char *mbus_data_record_function(mbus_data_record *record); const char *mbus_data_fixed_function(int status); +long mbus_data_record_storage_number(mbus_data_record *record); +long mbus_data_record_tariff(mbus_data_record *record); +int mbus_data_record_device(mbus_data_record *record); // // M-Bus frame data struct access/write functions @@ -613,9 +623,9 @@ 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); -int mbus_data_int_decode(unsigned char *int_data, size_t int_data_size); -long mbus_data_long_decode(unsigned char *int_data, size_t int_data_size); -long long mbus_data_long_long_decode(unsigned char *int_data, size_t int_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); float mbus_data_float_decode(unsigned char *float_data); diff --git a/test/test-frames/Elster-F2.xml b/test/test-frames/Elster-F2.xml index 7fea60b..e020ffb 100644 --- a/test/test-frames/Elster-F2.xml +++ b/test/test-frames/Elster-F2.xml @@ -13,78 +13,97 @@ Instantaneous value + 0 Energy (kWh) 5272 Instantaneous value + 0 Volume (1e-2 m^3) 120427 Instantaneous value + 0 + 0 + 1 Volume (1e-2 m^3) 91769 Instantaneous value + 0 Flow temperature (deg C) 28 Instantaneous value + 0 Return temperature (deg C) 34 Instantaneous value + 0 Temperature Difference (1e-1 deg C) 0 Instantaneous value + 0 On time (hours) 41393 Instantaneous value + 0 Operating time (hours) 41393 Instantaneous value + 0 Volume flow (m m^3/h) 0 Instantaneous value + 0 Power (10 W) 0 Instantaneous value + 0 Time Point (time & date) 2013-06-29T12:12:00 Instantaneous value + 0 + 0 + 1 Units for H.C.A. 0 Instantaneous value + 0 + 0 + 2 Units for H.C.A. 0 diff --git a/test/test-frames/abb_f95.xml b/test/test-frames/abb_f95.xml index 2db805d..7c29d3a 100644 --- a/test/test-frames/abb_f95.xml +++ b/test/test-frames/abb_f95.xml @@ -91,6 +91,7 @@ Instantaneous value + 0 Operating time (hours) 86553 diff --git a/test/test-frames/allmess_cf50.xml b/test/test-frames/allmess_cf50.xml index c16a2c1..612bdd9 100644 --- a/test/test-frames/allmess_cf50.xml +++ b/test/test-frames/allmess_cf50.xml @@ -13,54 +13,63 @@ Instantaneous value + 0 Energy (10 kWh) 0 Instantaneous value + 0 Volume (1e-1 m^3) 3 Instantaneous value + 0 Power (kW) 0 Instantaneous value + 0 Volume flow (m m^3/h) 0 Instantaneous value + 0 Flow temperature (1e-1 deg C) 1288 Instantaneous value + 0 Return temperature (1e-1 deg C) 516 Instantaneous value + 0 Temperature Difference (1e-2 deg C) 7723 Instantaneous value + 0 Time Point (date) 2012-01-12 Instantaneous value + 0 Operating time (days) 3383 diff --git a/test/test-frames/electricity-meter-1.xml b/test/test-frames/electricity-meter-1.xml index 10c83d5..8d25237 100644 --- a/test/test-frames/electricity-meter-1.xml +++ b/test/test-frames/electricity-meter-1.xml @@ -13,120 +13,156 @@ Instantaneous value + 0 + 1 + 0 Energy (10 Wh) 1252 Instantaneous value + 2 + 1 + 0 Energy (10 Wh) 1252 Instantaneous value + 0 + 2 + 0 Energy (10 Wh) 1774433 Instantaneous value + 2 + 2 + 0 Energy (10 Wh) 1774433 Instantaneous value + 0 V 237 Instantaneous value + 0 1e-1 A 32 Instantaneous value + 0 Power (10 W) 79 Instantaneous value + 0 + 0 + 1 Power (10 W) - 65518 + -18 Instantaneous value + 0 V 231 Instantaneous value + 0 1e-1 A 35 Instantaneous value + 0 Power (10 W) 81 Instantaneous value + 0 + 0 + 1 Power (10 W) - 65521 + -15 Instantaneous value + 0 V 228 Instantaneous value + 0 1e-1 A 69 Instantaneous value + 0 Power (10 W) 160 Instantaneous value + 0 + 0 + 1 Power (10 W) - 65504 + -32 Instantaneous value + 0 Manufacturer specific 0 Instantaneous value + 0 Power (10 W) 320 Instantaneous value + 0 + 0 + 1 Power (10 W) - 65471 + -65 Instantaneous value + 0 Manufacturer specific 4 diff --git a/test/test-frames/electricity-meter-2.xml b/test/test-frames/electricity-meter-2.xml index ff07f0d..1045933 100644 --- a/test/test-frames/electricity-meter-2.xml +++ b/test/test-frames/electricity-meter-2.xml @@ -13,120 +13,156 @@ Instantaneous value + 0 + 1 + 0 Energy (10 Wh) 254 Instantaneous value + 2 + 1 + 0 Energy (10 Wh) 254 Instantaneous value + 0 + 2 + 0 Energy (10 Wh) 444128 Instantaneous value + 2 + 2 + 0 Energy (10 Wh) 444128 Instantaneous value + 0 V 233 Instantaneous value + 0 1e-1 A 1 Instantaneous value + 0 Power (10 W) 0 Instantaneous value + 0 + 0 + 1 Power (10 W) 0 Instantaneous value + 0 V 234 Instantaneous value + 0 1e-1 A 0 Instantaneous value + 0 Power (10 W) 0 Instantaneous value + 0 + 0 + 1 Power (10 W) 0 Instantaneous value + 0 V 235 Instantaneous value + 0 1e-1 A 1 Instantaneous value + 0 Power (10 W) 0 Instantaneous value + 0 + 0 + 1 Power (10 W) 0 Instantaneous value + 0 Manufacturer specific 0 Instantaneous value + 0 Power (10 W) 0 Instantaneous value + 0 + 0 + 1 Power (10 W) 0 Instantaneous value + 0 Manufacturer specific 4 diff --git a/test/test-frames/els_tmpa_telegramm1.xml b/test/test-frames/els_tmpa_telegramm1.xml index d0b4fa9..4a22242 100644 --- a/test/test-frames/els_tmpa_telegramm1.xml +++ b/test/test-frames/els_tmpa_telegramm1.xml @@ -13,30 +13,35 @@ Instantaneous value + 0 Volume (m m^3) 1234567 Instantaneous value + 0 Time Point (time & date) 2007-02-06T13:58:00 Instantaneous value + 1 Time Point (date) 2007-01-01 Instantaneous value + 1 Volume (m m^3) 456951 Instantaneous value + 1 Time Point (date) 2008-01-01 diff --git a/test/test-frames/elv_temp_humid.xml b/test/test-frames/elv_temp_humid.xml index c02fcc3..6ebb57a 100644 --- a/test/test-frames/elv_temp_humid.xml +++ b/test/test-frames/elv_temp_humid.xml @@ -13,72 +13,86 @@ Instantaneous value + 0 Digital input (binary) 0 Instantaneous value + 0 1e-2 %RH 4564 Minimum value + 0 1e-2 %RH 4552 Maximum value + 0 1e-2 %RH 5812 Instantaneous value + 0 External temperature (1e-2 deg C) 2256 Minimum value + 0 External temperature (1e-2 deg C) 2160 Maximum value + 0 External temperature (1e-2 deg C) 2339 Instantaneous value + 0 Averaging Duration (hours) 24 Instantaneous value + 1 External temperature (1e-2 deg C) 2276 Instantaneous value + 2 + 0 + 0 External temperature (1e-2 deg C) 2269 Instantaneous value + 0 Fabrication number 54000834 Instantaneous value + 0 Software version 262144 diff --git a/test/test-frames/emh_diz.xml b/test/test-frames/emh_diz.xml index 78117ee..46dc68a 100644 --- a/test/test-frames/emh_diz.xml +++ b/test/test-frames/emh_diz.xml @@ -13,18 +13,25 @@ Instantaneous value + 0 + 1 + 0 Energy (10 Wh) 409 Instantaneous value + 1 + 0 + 0 Power (1e-1 W) 0 Instantaneous value + 0 Error flags 0 diff --git a/test/test-frames/gmc_emmod206.hex b/test/test-frames/gmc_emmod206.hex new file mode 100644 index 0000000..0c9cdd0 --- /dev/null +++ b/test/test-frames/gmc_emmod206.hex @@ -0,0 +1 @@ +68 91 91 68 08 03 72 78 56 34 12 A3 1D E6 02 02 00 00 00 82 40 FD 48 60 03 82 80 40 FD 48 BF 03 82 C0 40 FD 48 20 04 82 40 FD 59 BD 03 82 80 40 FD 59 1F 04 82 C0 40 FD 59 7E 04 82 40 2B E0 00 82 40 2B 36 FF 84 10 04 94 28 00 00 84 20 04 98 3A 00 00 84 50 04 BF 4E 00 00 84 60 04 A8 61 00 00 84 90 40 04 8B 75 00 00 84 A0 40 04 B8 88 00 00 84 D0 40 04 2D 9D 00 00 84 E0 40 04 C8 AF 00 00 82 41 2B E0 00 82 42 2B 00 00 82 43 2B 00 00 82 44 2B CA 00 42 16 diff --git a/test/test-frames/gmc_emmod206.xml b/test/test-frames/gmc_emmod206.xml new file mode 100644 index 0000000..ab18ed2 --- /dev/null +++ b/test/test-frames/gmc_emmod206.xml @@ -0,0 +1,194 @@ + + + + 12345678 + GMC + 230 + GMC-I A230 EMMOD 206 + Electricity + 2 + 00 + 0000 + + + + Instantaneous value + 0 + 0 + 1 + 1e-1 V + 864 + + + + Instantaneous value + 0 + 0 + 2 + 1e-1 V + 959 + + + + Instantaneous value + 0 + 0 + 3 + 1e-1 V + 1056 + + + + Instantaneous value + 0 + 0 + 1 + m A + 957 + + + + Instantaneous value + 0 + 0 + 2 + m A + 1055 + + + + Instantaneous value + 0 + 0 + 3 + m A + 1150 + + + + Instantaneous value + 0 + 0 + 1 + Power (W) + 224 + + + + Instantaneous value + 0 + 0 + 1 + Power (W) + -202 + + + + Instantaneous value + 0 + 1 + 0 + Energy (10 Wh) + 10388 + + + + Instantaneous value + 0 + 2 + 0 + Energy (10 Wh) + 15000 + + + + Instantaneous value + 0 + 1 + 1 + Energy (10 Wh) + 20159 + + + + Instantaneous value + 0 + 2 + 1 + Energy (10 Wh) + 25000 + + + + Instantaneous value + 0 + 1 + 2 + Energy (10 Wh) + 30091 + + + + Instantaneous value + 0 + 2 + 2 + Energy (10 Wh) + 35000 + + + + Instantaneous value + 0 + 1 + 3 + Energy (10 Wh) + 40237 + + + + Instantaneous value + 0 + 2 + 3 + Energy (10 Wh) + 45000 + + + + Instantaneous value + 2 + 0 + 1 + Power (W) + 224 + + + + Instantaneous value + 4 + 0 + 1 + Power (W) + 0 + + + + Instantaneous value + 6 + 0 + 1 + Power (W) + 0 + + + + Instantaneous value + 8 + 0 + 1 + Power (W) + 202 + + + diff --git a/test/test-frames/kamstrup_multical_601.xml b/test/test-frames/kamstrup_multical_601.xml index 856f7dc..5b74577 100644 --- a/test/test-frames/kamstrup_multical_601.xml +++ b/test/test-frames/kamstrup_multical_601.xml @@ -13,162 +13,209 @@ Instantaneous value + 0 Fabrication number 6855817 Instantaneous value + 0 Energy (kWh) 37351 Instantaneous value + 0 Volume (1e-2 m^3) 56108 Instantaneous value + 0 On time (hours) 985 Instantaneous value + 0 Flow temperature (1e-2 deg C) 10169 Instantaneous value + 0 Return temperature (1e-2 deg C) 4616 Instantaneous value + 0 Temperature Difference (1e-2 deg C) 5553 Instantaneous value + 0 Power (100 W) 347 Maximum value + 0 Power (100 W) 448 Instantaneous value + 0 Volume flow (m m^3/h) 543 Maximum value + 0 Volume flow (m m^3/h) 628 Instantaneous value + 0 + 1 + 0 Energy (kWh) 0 Instantaneous value + 0 + 2 + 0 Energy (kWh) 0 Instantaneous value + 0 + 0 + 1 Volume (1e-2 m^3) 0 Instantaneous value + 0 + 0 + 2 Volume (1e-2 m^3) 0 Instantaneous value + 0 + 0 + 3 Energy (kWh) 0 Instantaneous value + 0 Time Point (time & date) 2011-01-05T15:26:00 Instantaneous value + 1 Energy (kWh) 33361 Instantaneous value + 1 Volume (1e-2 m^3) 50098 Maximum value + 1 Power (100 W) 550 Maximum value + 1 Volume flow (m m^3/h) 1027 Instantaneous value + 1 + 1 + 0 Energy (kWh) 0 Instantaneous value + 1 + 2 + 0 Energy (kWh) 0 Instantaneous value + 1 + 0 + 1 Volume (1e-2 m^3) 0 Instantaneous value + 1 + 0 + 2 Volume (1e-2 m^3) 0 Instantaneous value + 1 + 0 + 3 Energy (kWh) 0 Instantaneous value + 1 Time Point (date) 2010-12-31 diff --git a/test/test-frames/manual_frame3.xml b/test/test-frames/manual_frame3.xml index 2b1211e..34a51b5 100644 --- a/test/test-frames/manual_frame3.xml +++ b/test/test-frames/manual_frame3.xml @@ -13,18 +13,25 @@ Instantaneous value + 0 Volume (m m^3) 12565 Maximum value + 5 + 0 + 0 Volume flow (m m^3/h) 113 Instantaneous value + 0 + 2 + 1 Energy (10 Wh) 21837 diff --git a/test/test-frames/manual_frame7.xml b/test/test-frames/manual_frame7.xml index dc166e3..a3c2dad 100644 --- a/test/test-frames/manual_frame7.xml +++ b/test/test-frames/manual_frame7.xml @@ -13,6 +13,7 @@ Instantaneous value + 0 Fabrication number 1020304 diff --git a/test/test-frames/nzr_dhz_5_63.xml b/test/test-frames/nzr_dhz_5_63.xml index f7120a3..40b91b2 100644 --- a/test/test-frames/nzr_dhz_5_63.xml +++ b/test/test-frames/nzr_dhz_5_63.xml @@ -13,36 +13,42 @@ Instantaneous value + 0 Energy (Wh) 1274 Instantaneous value + 0 Energy (Wh) 1274 Instantaneous value + 0 1e-1 V 2372 Instantaneous value + 0 1e-1 A 0 Instantaneous value + 0 Power (W) 0 Instantaneous value + 0 Fabrication number 30100608 diff --git a/test/test-frames/wmbus-converted.xml b/test/test-frames/wmbus-converted.xml index aefeabd..e7f0686 100644 --- a/test/test-frames/wmbus-converted.xml +++ b/test/test-frames/wmbus-converted.xml @@ -13,6 +13,7 @@ Instantaneous value + 0 Energy (Wh) 5000