From 1a01995e4854368066a3e26887dff6854dba6493 Mon Sep 17 00:00:00 2001 From: Wolfgang Hottgenroth Date: Tue, 3 Nov 2020 09:37:12 +0100 Subject: [PATCH] drop libmbus files --- cube/libmbus/mbus/mbus-protocol.c | 3861 ----------------------------- cube/libmbus/mbus/mbus-protocol.h | 624 ----- 2 files changed, 4485 deletions(-) delete mode 100644 cube/libmbus/mbus/mbus-protocol.c delete mode 100644 cube/libmbus/mbus/mbus-protocol.h diff --git a/cube/libmbus/mbus/mbus-protocol.c b/cube/libmbus/mbus/mbus-protocol.c deleted file mode 100644 index 45df1be..0000000 --- a/cube/libmbus/mbus/mbus-protocol.c +++ /dev/null @@ -1,3861 +0,0 @@ -//------------------------------------------------------------------------------ -// Copyright (C) 2010-2011, Robert Johansson, Raditex AB -// All rights reserved. -// -// rSCADA -// http://www.rSCADA.se -// info@rscada.se -// -//------------------------------------------------------------------------------ - -#include -#include -#include -#include - -#include - -static int parse_debug = 0, debug = 0; -static char error_str[512]; - -#define NITEMS(x) (sizeof(x)/sizeof(x[0])) - -//------------------------------------------------------------------------------ -// internal data -//------------------------------------------------------------------------------ -static mbus_slave_data slave_data[MBUS_MAX_PRIMARY_SLAVES]; - -// -// init event callback -// -void (*_mbus_recv_event)(u_char src_type, const char *buff, size_t len) = NULL; -void (*_mbus_send_event)(u_char src_type, const char *buff, size_t len) = NULL; - -// -// trace callbacks -// -void -mbus_dump_recv_event(u_char src_type, const char *buff, size_t len) -{ - mbus_hex_dump("RECV", buff, len); -} - -void -mbus_dump_send_event(u_char src_type, const char *buff, size_t len) -{ - mbus_hex_dump("SEND", buff, len); -} - -//------------------------------------------------------------------------------ -/// Register a function for receive events. -//------------------------------------------------------------------------------ -void -mbus_register_recv_event(void (*event)(u_char src_type, const char *buff, size_t len)) -{ - _mbus_recv_event = event; -} - -//------------------------------------------------------------------------------ -/// Register a function for send events. -//------------------------------------------------------------------------------ -void -mbus_register_send_event(void (*event)(u_char src_type, const char *buff, size_t len)) -{ - _mbus_send_event = event; -} - -//------------------------------------------------------------------------------ -/// Return a string that contains an the latest error message. -//------------------------------------------------------------------------------ -char * -mbus_error_str() -{ - return error_str; -} - -void -mbus_error_str_set(char *message) -{ - if (message) - { - snprintf(error_str, sizeof(error_str), "%s", message); - } -} - -void -mbus_error_reset() -{ - snprintf(error_str, sizeof(error_str), "no errors"); -} - -//------------------------------------------------------------------------------ -/// Return a pointer to the slave_data register. This register can be used for -/// storing current slave status. -//------------------------------------------------------------------------------ -mbus_slave_data * -mbus_slave_data_get(size_t i) -{ - if (i < MBUS_MAX_PRIMARY_SLAVES) - { - return &slave_data[i]; - } - - return NULL; -} - -//------------------------------------------------------------------------------ -// -// M-Bus FRAME RELATED FUNCTIONS -// -//------------------------------------------------------------------------------ - -//------------------------------------------------------------------------------ -/// Allocate an M-bus frame data structure and initialize it according to which -/// frame type is requested. -//------------------------------------------------------------------------------ -mbus_frame * -mbus_frame_new(int frame_type) -{ - mbus_frame *frame = NULL; - - if ((frame = malloc(sizeof(mbus_frame))) != NULL) - { - memset((void *)frame, 0, sizeof(mbus_frame)); - - frame->type = frame_type; - switch (frame->type) - { - case MBUS_FRAME_TYPE_ACK: - - frame->start1 = MBUS_FRAME_ACK_START; - - break; - - case MBUS_FRAME_TYPE_SHORT: - - frame->start1 = MBUS_FRAME_SHORT_START; - frame->stop = MBUS_FRAME_STOP; - - break; - - case MBUS_FRAME_TYPE_CONTROL: - - frame->start1 = MBUS_FRAME_CONTROL_START; - frame->start2 = MBUS_FRAME_CONTROL_START; - frame->length1 = 3; - frame->length2 = 3; - frame->stop = MBUS_FRAME_STOP; - - break; - - case MBUS_FRAME_TYPE_LONG: - - frame->start1 = MBUS_FRAME_LONG_START; - frame->start2 = MBUS_FRAME_LONG_START; - frame->stop = MBUS_FRAME_STOP; - - break; - } - } - - return frame; -} - -//------------------------------------------------------------------------------ -/// Free the memory resources allocated for the M-Bus frame data structure. -//------------------------------------------------------------------------------ -int -mbus_frame_free(mbus_frame *frame) -{ - if (frame) - { - if (frame->next != NULL) - mbus_frame_free(frame->next); - - free(frame); - return 0; - } - return -1; -} - -//------------------------------------------------------------------------------ -/// Caclulate the checksum of the M-Bus frame. Internal. -//------------------------------------------------------------------------------ -u_char -calc_checksum(mbus_frame *frame) -{ - size_t i; - u_char cksum; - - assert(frame != NULL); - switch(frame->type) - { - case MBUS_FRAME_TYPE_SHORT: - - cksum = frame->control; - cksum += frame->address; - - break; - - case MBUS_FRAME_TYPE_CONTROL: - - cksum = frame->control; - cksum += frame->address; - cksum += frame->control_information; - - break; - - case MBUS_FRAME_TYPE_LONG: - - cksum = frame->control; - cksum += frame->address; - cksum += frame->control_information; - - for (i = 0; i < frame->data_size; i++) - { - cksum += frame->data[i]; - } - - break; - - case MBUS_FRAME_TYPE_ACK: - default: - cksum = 0; - } - - return cksum; -} - -//------------------------------------------------------------------------------ -/// Caclulate the checksum of the M-Bus frame. The checksum algorithm is the -/// arithmetic sum of the frame content, without using carry. Which content -/// that is included in the checksum calculation depends on the frame type. -//------------------------------------------------------------------------------ -int -mbus_frame_calc_checksum(mbus_frame *frame) -{ - if (frame) - { - switch (frame->type) - { - case MBUS_FRAME_TYPE_ACK: - case MBUS_FRAME_TYPE_SHORT: - case MBUS_FRAME_TYPE_CONTROL: - case MBUS_FRAME_TYPE_LONG: - frame->checksum = calc_checksum(frame); - - break; - - default: - return -1; - } - } - - return 0; -} - -/// -/// Calculate the values of the lengths fields in the M-Bus frame. Internal. -/// -u_char -calc_length(const mbus_frame *frame) -{ - assert(frame != NULL); - switch(frame->type) - { - case MBUS_FRAME_TYPE_CONTROL: - return 3; - case MBUS_FRAME_TYPE_LONG: - return frame->data_size + 3; - default: - return 0; - } -} - -//------------------------------------------------------------------------------ -/// Calculate the values of the lengths fields in the M-Bus frame. -//------------------------------------------------------------------------------ -int -mbus_frame_calc_length(mbus_frame *frame) -{ - if (frame) - { - frame->length1 = frame->length2 = calc_length(frame); - } - - return 0; -} - -//------------------------------------------------------------------------------ -/// Return the M-Bus frame type -//------------------------------------------------------------------------------ -int -mbus_frame_type(mbus_frame *frame) -{ - if (frame) - { - return frame->type; - } - return -1; -} - -//------------------------------------------------------------------------------ -/// Verify that parsed frame is a valid M-bus frame. -// -// Possible checks: -// -// 1) frame type -// 2) Start/stop bytes -// 3) control field -// 4) length field and actual data size -// 5) checksum -// -//------------------------------------------------------------------------------ -int -mbus_frame_verify(mbus_frame *frame) -{ - u_char checksum; - - if (frame) - { - switch (frame->type) - { - case MBUS_FRAME_TYPE_ACK: - return frame->start1 == MBUS_FRAME_ACK_START; - - case MBUS_FRAME_TYPE_SHORT: - if(frame->start1 != MBUS_FRAME_SHORT_START) - { - snprintf(error_str, sizeof(error_str), "No frame start"); - - return -1; - } - - if ((frame->control != MBUS_CONTROL_MASK_SND_NKE) && - (frame->control != MBUS_CONTROL_MASK_REQ_UD1) && - (frame->control != (MBUS_CONTROL_MASK_REQ_UD1 | MBUS_CONTROL_MASK_FCB)) && - (frame->control != MBUS_CONTROL_MASK_REQ_UD2) && - (frame->control != (MBUS_CONTROL_MASK_REQ_UD2 | MBUS_CONTROL_MASK_FCB))) - { - snprintf(error_str, sizeof(error_str), "Unknown Control Code 0x%.2x", frame->control); - - return -1; - } - - break; - - case MBUS_FRAME_TYPE_CONTROL: - case MBUS_FRAME_TYPE_LONG: - if(frame->start1 != MBUS_FRAME_CONTROL_START || - frame->start2 != MBUS_FRAME_CONTROL_START) - { - snprintf(error_str, sizeof(error_str), "No frame start"); - - return -1; - } - - if ((frame->control != MBUS_CONTROL_MASK_SND_UD) && - (frame->control != (MBUS_CONTROL_MASK_SND_UD | MBUS_CONTROL_MASK_FCB)) && - (frame->control != MBUS_CONTROL_MASK_RSP_UD) && - (frame->control != (MBUS_CONTROL_MASK_RSP_UD | MBUS_CONTROL_MASK_DFC)) && - (frame->control != (MBUS_CONTROL_MASK_RSP_UD | MBUS_CONTROL_MASK_ACD)) && - (frame->control != (MBUS_CONTROL_MASK_RSP_UD | MBUS_CONTROL_MASK_DFC | MBUS_CONTROL_MASK_ACD))) - { - snprintf(error_str, sizeof(error_str), "Unknown Control Code 0x%.2x", frame->control); - - return -1; - } - - if (frame->length1 != frame->length2) - { - snprintf(error_str, sizeof(error_str), "Frame length 1 != 2"); - - return -1; - } - - if (frame->length1 != calc_length(frame)) - { - snprintf(error_str, sizeof(error_str), "Frame length 1 != calc length"); - - return -1; - } - - break; - - default: - snprintf(error_str, sizeof(error_str), "Unknown frame type 0x%.2x", frame->type); - - return -1; - } - - if(frame->stop != MBUS_FRAME_STOP) - { - snprintf(error_str, sizeof(error_str), "No frame stop"); - - return -1; - } - - checksum = calc_checksum(frame); - - if(frame->checksum != checksum) - { - snprintf(error_str, sizeof(error_str), "Invalid checksum (0x%.2x != 0x%.2x)", frame->checksum, checksum); - - return -1; - } - - return 0; - } - - snprintf(error_str, sizeof(error_str), "Got null pointer to frame."); - - return -1; -} - - -//------------------------------------------------------------------------------ -// -// DATA ENCODING, DECODING, AND CONVERSION FUNCTIONS -// -//------------------------------------------------------------------------------ - -//------------------------------------------------------------------------------ -/// -/// Encode BCD data -/// -//------------------------------------------------------------------------------ -int -mbus_data_bcd_encode(u_char *bcd_data, size_t bcd_data_size, int value) -{ - int v0, v1, v2, x1, x2; - size_t i; - - v2 = value; - - if (bcd_data) - { - for (i = 0; i < bcd_data_size; i++) - { - v0 = v2; - v1 = (int)(v0 / 10.0); - v2 = (int)(v1 / 10.0); - - x1 = v0 - v1 * 10; - x2 = v1 - v2 * 10; - - bcd_data[bcd_data_size-1-i] = (x2 << 4) | x1; - } - - return 0; - } - - return -1; -} - -//------------------------------------------------------------------------------ -/// -/// Decode BCD data -/// -//------------------------------------------------------------------------------ -long long -mbus_data_bcd_decode(u_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 * 10) + ((bcd_data[i-1]>>4) & 0xF); - val = (val * 10) + ( bcd_data[i-1] & 0xF); - } - - return val; - } - - return -1; -} - -//------------------------------------------------------------------------------ -/// -/// Decode INTEGER data -/// -//------------------------------------------------------------------------------ -int -mbus_data_int_decode(u_char *int_data, size_t int_data_size) -{ - int val = 0; - size_t i; - - if (int_data) - { - for (i = int_data_size; i > 0; i--) - { - val = (val << 8) + int_data[i-1]; - } - - return val; - } - - return -1; -} - -long -mbus_data_long_decode(u_char *int_data, size_t int_data_size) -{ - long val = 0; - size_t i; - - if (int_data) - { - for (i = int_data_size; i > 0; i--) - { - val = (val << 8) + int_data[i-1]; - } - - return val; - } - - return -1; -} - -long long -mbus_data_long_long_decode(u_char *int_data, size_t int_data_size) -{ - long long val = 0; - size_t i; - - if (int_data) - { - for (i = int_data_size; i > 0; i--) - { - val = (val << 8) + int_data[i-1]; - } - - return val; - } - - return -1; -} - -//------------------------------------------------------------------------------ -/// -/// Encode INTEGER data (into 'int_data_size' bytes) -/// -//------------------------------------------------------------------------------ -int -mbus_data_int_encode(u_char *int_data, size_t int_data_size, int value) -{ - int i; - - if (int_data) - { - for (i = 0; i < int_data_size; i++) - { - int_data[i] = (value>>(i*8)) & 0xFF; - } - - return 0; - } - - return -1; -} - -//------------------------------------------------------------------------------ -/// -/// Decode float data -/// -/// see also http://en.wikipedia.org/wiki/Single-precision_floating-point_format -/// -//------------------------------------------------------------------------------ -float -mbus_data_float_decode(u_char *float_data) -{ - float val = 0.0f; - long temp = 0, fraction; - int sign,exponent; - size_t i; - - if (float_data) - { - for (i = 4; i > 0; i--) - { - temp = (temp << 8) + float_data[i-1]; - } - - // first bit = sign bit - sign = (temp >> 31) ? -1 : 1; - - // decode 8 bit exponent - exponent = ((temp & 0x7F800000) >> 23) - 127; - - // decode explicit 23 bit fraction - fraction = temp & 0x007FFFFF; - - if ((exponent != -127) && - (exponent != 128)) - { - // normalized value, add bit 24 - fraction |= 0x800000; - } - - // calculate float value - val = (float) sign * fraction * pow(2.0f, -23.0f) * (1 << exponent); - - return val; - } - - return -1.0; -} - -//------------------------------------------------------------------------------ -/// -/// Decode string data. -/// -//------------------------------------------------------------------------------ -void -mbus_data_str_decode(u_char *dst, const u_char *src, size_t len) -{ - size_t i; - - i = 0; - - if (src && dst) - { - dst[len] = '\0'; - while(len > 0) { - dst[i++] = src[--len]; - } - } -} - -//------------------------------------------------------------------------------ -/// -/// Decode binary data. -/// -//------------------------------------------------------------------------------ -void -mbus_data_bin_decode(u_char *dst, const u_char *src, size_t len, size_t max_len) -{ - size_t i, pos; - - i = 0; - pos = 0; - - if (src && dst) - { - while((i < len) && ((pos+3) < max_len)) { - pos += snprintf(&dst[pos], max_len - pos, "%.2X ", src[i]); - i++; - } - - if (pos > 0) - { - // remove last space - pos--; - } - - dst[pos] = '\0'; - } -} - -//------------------------------------------------------------------------------ -/// -/// Decode time data (usable for type f = 4 bytes or type g = 2 bytes) -/// -//------------------------------------------------------------------------------ -void -mbus_data_tm_decode(struct tm *t, u_char *t_data, size_t t_data_size) -{ - if (t && t_data) - { - t->tm_sec = 0; - t->tm_min = 0; - t->tm_hour = 0; - t->tm_mday = 0; - t->tm_mon = 0; - t->tm_year = 0; - t->tm_isdst = 0; - - if (t_data_size == 4) // Type F = Compound CP32: Date and Time - { - if ((t_data[0] & 0x80) == 0) // Time valid ? - { - t->tm_min = t_data[0] & 0x3F; - t->tm_hour = t_data[1] & 0x1F; - t->tm_mday = t_data[2] & 0x1F; - t->tm_mon = (t_data[3] & 0x0F) - 1; - t->tm_year = ((t_data[2] & 0xE0) >> 5) | - ((t_data[3] & 0xF0) >> 1); - t->tm_isdst = (t_data[1] & 0x80) ? 1 : 0; // day saving time - } - } - else if (t_data_size == 2) // Type G: Compound CP16: Date - { - t->tm_mday = t_data[0] & 0x1F; - t->tm_mon = (t_data[1] & 0x0F) - 1; - t->tm_year = ((t_data[0] & 0xE0) >> 5) | - ((t_data[1] & 0xF0) >> 1); - } - } -} - -//------------------------------------------------------------------------------ -/// -/// Generate manufacturer code from 2-byte encoded data -/// -//------------------------------------------------------------------------------ -int -mbus_data_manufacturer_encode(u_char *m_data, u_char *m_code) -{ - int m_val; - - if (m_data == NULL || m_code == NULL) - return -1; - - m_val = ((((int)m_code[0] - 64) & 0x001F) << 10) + - ((((int)m_code[1] - 64) & 0x001F) << 5) + - ((((int)m_code[2] - 64) & 0x001F)); - - mbus_data_int_encode(m_data, 2, m_val); - - return 0; -} - -//------------------------------------------------------------------------------ -/// -/// Generate manufacturer code from 2-byte encoded data -/// -//------------------------------------------------------------------------------ -const char * -mbus_decode_manufacturer(u_char byte1, u_char byte2) -{ - static char m_str[4]; - - int m_id; - - m_str[0] = byte1; - m_str[1] = byte2; - - m_id = mbus_data_int_decode(m_str, 2); - - m_str[0] = (char)(((m_id>>10) & 0x001F) + 64); - m_str[1] = (char)(((m_id>>5) & 0x001F) + 64); - m_str[2] = (char)(((m_id) & 0x001F) + 64); - m_str[3] = 0; - - return m_str; -} - -const char * -mbus_data_product_name(mbus_data_variable_header *header) -{ - static char buff[128]; - unsigned int manufacturer; - - memset(buff, 0, sizeof(buff)); - - if (header) - { - manufacturer = (header->manufacturer[1] << 8) + header->manufacturer[0]; - - if (manufacturer == MBUS_VARIABLE_DATA_MAN_ACW) - { - switch (header->version) - { - case 0x09: - strcpy(buff,"Itron CF Echo 2"); - break; - case 0x0A: - strcpy(buff,"Itron CF 51"); - break; - case 0x0B: - strcpy(buff,"Itron CF 55"); - break; - case 0x0E: - strcpy(buff,"Itron BM +m"); - break; - case 0x0F: - strcpy(buff,"Itron CF 800"); - break; - case 0x14: - strcpy(buff,"Itron CYBLE M-Bus 1.4"); - break; - } - } - else if (manufacturer == MBUS_VARIABLE_DATA_MAN_EFE) - { - switch (header->version) - { - case 0x00: - strcpy(buff, ((header->medium == 0x06) ? "Engelmann WaterStar" : "Engelmann SensoStar 2")); - break; - case 0x01: - strcpy(buff,"Engelmann SensoStar 2C"); - break; - } - } - else if (manufacturer == MBUS_VARIABLE_DATA_MAN_SLB) - { - switch (header->version) - { - case 0x02: - strcpy(buff,"Allmess Megacontrol CF-50"); - break; - case 0x06: - strcpy(buff,"CF Compact / Integral MK MaXX"); - break; - } - } - else if (manufacturer == MBUS_VARIABLE_DATA_MAN_HYD) - { - switch (header->version) - { - case 0x28: - strcpy(buff,"ABB F95 Typ US770"); - break; - } - } - else if (manufacturer == MBUS_VARIABLE_DATA_MAN_LUG) - { - switch (header->version) - { - case 0x02: - strcpy(buff,"Landis & Gyr Ultraheat 2WR5"); - break; - case 0x03: - strcpy(buff,"Landis & Gyr Ultraheat 2WR6"); - break; - case 0x04: - strcpy(buff,"Landis & Gyr Ultraheat UH50"); - break; - case 0x07: - strcpy(buff,"Landis & Gyr Ultraheat T230"); - break; - } - } - else if (manufacturer == MBUS_VARIABLE_DATA_MAN_SVM) - { - switch (header->version) - { - case 0x08: - strcpy(buff,"Elster F2"); - break; - case 0x09: - strcpy(buff,"Kamstrup SVM F22"); - break; - } - } - else if (manufacturer == MBUS_VARIABLE_DATA_MAN_SON) - { - switch (header->version) - { - case 0x0D: - strcpy(buff,"Sontex Supercal 531"); - break; - } - } - else if (manufacturer == MBUS_VARIABLE_DATA_MAN_LSE) - { - switch (header->version) - { - case 0x99: - strcpy(buff,"Siemens WFH21"); - break; - } - } - else if (manufacturer == MBUS_VARIABLE_DATA_MAN_SPX) - { - switch (header->version) - { - case 0x31: - case 0x34: - strcpy(buff,"Sensus PolluTherm"); - break; - } - } - else if (manufacturer == MBUS_VARIABLE_DATA_MAN_ELS) - { - switch (header->version) - { - case 0x02: - strcpy(buff,"Elster TMP-A"); - break; - } - } - else if (manufacturer == MBUS_VARIABLE_DATA_MAN_NZR) - { - switch (header->version) - { - case 0x01: - strcpy(buff,"NZR DHZ 5/63"); - break; - } - } - else if (manufacturer == MBUS_VARIABLE_DATA_MAN_KAM) - { - switch (header->version) - { - case 0x08: - strcpy(buff,"Kamstrup Multical 601"); - break; - } - } - else if (manufacturer == MBUS_VARIABLE_DATA_MAN_EMH) - { - switch (header->version) - { - case 0x00: - strcpy(buff,"EMH DIZ"); - break; - } - } - else if (manufacturer == MBUS_VARIABLE_DATA_MAN_TCH) - { - switch (header->version) - { - case 0x26: - strcpy(buff,"Techem m-bus S"); - break; - } - } - else if (manufacturer == MBUS_VARIABLE_DATA_MAN_ZRM) - { - switch (header->version) - { - case 0x81: - strcpy(buff,"Minol Minocal C2"); - break; - case 0x82: - strcpy(buff,"Minol Minocal WR3"); - break; - } - } - } - - return buff; -} - -//------------------------------------------------------------------------------ -// -// FIXED-LENGTH DATA RECORD FUNCTIONS -// -//------------------------------------------------------------------------------ - - -// -// Value Field Medium/Unit Medium -// hexadecimal Bit 16 Bit 15 Bit 8 Bit 7 -// 0 0 0 0 0 Other -// 1 0 0 0 1 Oil -// 2 0 0 1 0 Electricity -// 3 0 0 1 1 Gas -// 4 0 1 0 0 Heat -// 5 0 1 0 1 Steam -// 6 0 1 1 0 Hot Water -// 7 0 1 1 1 Water -// 8 1 0 0 0 H.C.A. -// 9 1 0 0 1 Reserved -// A 1 0 1 0 Gas Mode 2 -// B 1 0 1 1 Heat Mode 2 -// C 1 1 0 0 Hot Water Mode 2 -// D 1 1 0 1 Water Mode 2 -// E 1 1 1 0 H.C.A. Mode 2 -// F 1 1 1 1 Reserved -// - -/// -/// For fixed-length frames, get a string describing the medium. -/// -const char * -mbus_data_fixed_medium(mbus_data_fixed *data) -{ - static char buff[256]; - - if (data) - { - switch ( (data->cnt1_type&0xC0)>>6 | (data->cnt2_type&0xC0)>>4 ) - { - case 0x00: - snprintf(buff, sizeof(buff), "Other"); - break; - case 0x01: - snprintf(buff, sizeof(buff), "Oil"); - break; - case 0x02: - snprintf(buff, sizeof(buff), "Electricity"); - break; - case 0x03: - snprintf(buff, sizeof(buff), "Gas"); - break; - case 0x04: - snprintf(buff, sizeof(buff), "Heat"); - break; - case 0x05: - snprintf(buff, sizeof(buff), "Steam"); - break; - case 0x06: - snprintf(buff, sizeof(buff), "Hot Water"); - break; - case 0x07: - snprintf(buff, sizeof(buff), "Water"); - break; - case 0x08: - snprintf(buff, sizeof(buff), "H.C.A."); - break; - case 0x09: - snprintf(buff, sizeof(buff), "Reserved"); - break; - case 0x0A: - snprintf(buff, sizeof(buff), "Gas Mode 2"); - break; - case 0x0B: - snprintf(buff, sizeof(buff), "Heat Mode 2"); - break; - case 0x0C: - snprintf(buff, sizeof(buff), "Hot Water Mode 2"); - break; - case 0x0D: - snprintf(buff, sizeof(buff), "Water Mode 2"); - break; - case 0x0E: - snprintf(buff, sizeof(buff), "H.C.A. Mode 2"); - break; - case 0x0F: - snprintf(buff, sizeof(buff), "Reserved"); - break; - default: - snprintf(buff, sizeof(buff), "unknown"); - break; - } - - return buff; - } - - return NULL; -} - - -//------------------------------------------------------------------------------ -// Hex code Hex code -//Unit share Unit share -// MSB..LSB MSB..LSB -// Byte 7/8 Byte 7/8 -// h,m,s 000000 00 MJ/h 100000 20 -// D,M,Y 000001 01 MJ/h * 10 100001 21 -// Wh 000010 02 MJ/h * 100 100010 22 -// Wh * 10 000011 03 GJ/h 100011 23 -// Wh * 100 000100 04 GJ/h * 10 100100 24 -// kWh 000101 05 GJ/h * 100 100101 25 -// kWh * 10 000110 06 ml 100110 26 -// kWh * 100 000111 07 ml * 10 100111 27 -// MWh 001000 08 ml * 100 101000 28 -// MWh * 10 001001 09 l 101001 29 -// MWh * 100 001010 0A l * 10 101010 2A -// kJ 001011 0B l * 100 101011 2B -// kJ * 10 001100 0C m3 101100 2C -// kJ * 100 001101 0D m3 * 10 101101 2D -// MJ 001110 0E m3 * 100 101110 2E -// MJ * 10 001111 0F ml/h 101111 2F -// MJ * 100 010000 10 ml/h * 10 110000 30 -// GJ 010001 11 ml/h * 100 110001 31 -// GJ * 10 010010 12 l/h 110010 32 -// GJ * 100 010011 13 l/h * 10 110011 33 -// W 010100 14 l/h * 100 110100 34 -// W * 10 010101 15 m3/h 110101 35 -// W * 100 010110 16 m3/h * 10 110110 36 -// kW 010111 17 m3/h * 100 110111 37 -// kW * 10 011000 18 °C* 10-3 111000 38 -// kW * 100 011001 19 units for HCA 111001 39 -// MW 011010 1A reserved 111010 3A -// MW * 10 011011 1B reserved 111011 3B -// MW * 100 011100 1C reserved 111100 3C -// kJ/h 011101 1D reserved 111101 3D -// kJ/h * 10 011110 1E same but historic 111110 3E -// kJ/h * 100 011111 1F without units 111111 3F -// -//------------------------------------------------------------------------------ -/// -/// For fixed-length frames, get a string describing the unit of the data. -/// -const char * -mbus_data_fixed_unit(int medium_unit_byte) -{ - static char buff[256]; - - switch (medium_unit_byte & 0x3F) - { - case 0x00: - snprintf(buff, sizeof(buff), "h,m,s"); - break; - case 0x01: - snprintf(buff, sizeof(buff), "D,M,Y"); - break; - - case 0x02: - snprintf(buff, sizeof(buff), "Wh"); - break; - case 0x03: - snprintf(buff, sizeof(buff), "10 Wh"); - break; - case 0x04: - snprintf(buff, sizeof(buff), "100 Wh"); - break; - case 0x05: - snprintf(buff, sizeof(buff), "kWh"); - break; - case 0x06: - snprintf(buff, sizeof(buff), "10 kWh"); - break; - case 0x07: - snprintf(buff, sizeof(buff), "100 kWh"); - break; - case 0x08: - snprintf(buff, sizeof(buff), "MWh"); - break; - case 0x09: - snprintf(buff, sizeof(buff), "10 MWh"); - break; - case 0x0A: - snprintf(buff, sizeof(buff), "100 MWh"); - break; - - case 0x0B: - snprintf(buff, sizeof(buff), "kJ"); - break; - case 0x0C: - snprintf(buff, sizeof(buff), "10 kJ"); - break; - case 0x0E: - snprintf(buff, sizeof(buff), "100 kJ"); - break; - case 0x0D: - snprintf(buff, sizeof(buff), "MJ"); - break; - case 0x0F: - snprintf(buff, sizeof(buff), "10 MJ"); - break; - case 0x10: - snprintf(buff, sizeof(buff), "100 MJ"); - break; - case 0x11: - snprintf(buff, sizeof(buff), "GJ"); - break; - case 0x12: - snprintf(buff, sizeof(buff), "10 GJ"); - break; - case 0x13: - snprintf(buff, sizeof(buff), "100 GJ"); - break; - - case 0x14: - snprintf(buff, sizeof(buff), "W"); - break; - case 0x15: - snprintf(buff, sizeof(buff), "10 W"); - break; - case 0x16: - snprintf(buff, sizeof(buff), "100 W"); - break; - case 0x17: - snprintf(buff, sizeof(buff), "kW"); - break; - case 0x18: - snprintf(buff, sizeof(buff), "10 kW"); - break; - case 0x19: - snprintf(buff, sizeof(buff), "100 kW"); - break; - case 0x1A: - snprintf(buff, sizeof(buff), "MW"); - break; - case 0x1B: - snprintf(buff, sizeof(buff), "10 MW"); - break; - case 0x1C: - snprintf(buff, sizeof(buff), "100 MW"); - break; - - case 0x1D: - snprintf(buff, sizeof(buff), "kJ/h"); - break; - case 0x1E: - snprintf(buff, sizeof(buff), "10 kJ/h"); - break; - case 0x1F: - snprintf(buff, sizeof(buff), "100 kJ/h"); - break; - case 0x20: - snprintf(buff, sizeof(buff), "MJ/h"); - break; - case 0x21: - snprintf(buff, sizeof(buff), "10 MJ/h"); - break; - case 0x22: - snprintf(buff, sizeof(buff), "100 MJ/h"); - break; - case 0x23: - snprintf(buff, sizeof(buff), "GJ/h"); - break; - case 0x24: - snprintf(buff, sizeof(buff), "10 GJ/h"); - break; - case 0x25: - snprintf(buff, sizeof(buff), "100 GJ/h"); - break; - - case 0x26: - snprintf(buff, sizeof(buff), "ml"); - break; - case 0x27: - snprintf(buff, sizeof(buff), "10 ml"); - break; - case 0x28: - snprintf(buff, sizeof(buff), "100 ml"); - break; - case 0x29: - snprintf(buff, sizeof(buff), "l"); - break; - case 0x2A: - snprintf(buff, sizeof(buff), "10 l"); - break; - case 0x2B: - snprintf(buff, sizeof(buff), "100 l"); - break; - case 0x2C: - snprintf(buff, sizeof(buff), "m^3"); - break; - case 0x2D: - snprintf(buff, sizeof(buff), "10 m^3"); - break; - case 0x2E: - snprintf(buff, sizeof(buff), "m^3"); - break; - - case 0x2F: - snprintf(buff, sizeof(buff), "ml/h"); - break; - case 0x30: - snprintf(buff, sizeof(buff), "10 ml/h"); - break; - case 0x31: - snprintf(buff, sizeof(buff), "100 ml/h"); - break; - case 0x32: - snprintf(buff, sizeof(buff), "l/h"); - break; - case 0x33: - snprintf(buff, sizeof(buff), "10 l/h"); - break; - case 0x34: - snprintf(buff, sizeof(buff), "100 l/h"); - break; - case 0x35: - snprintf(buff, sizeof(buff), "m^3/h"); - break; - case 0x36: - snprintf(buff, sizeof(buff), "10 m^3/h"); - break; - case 0x37: - snprintf(buff, sizeof(buff), "100 m^3/h"); - break; - - case 0x38: - snprintf(buff, sizeof(buff), "1e-3 °C"); - break; - case 0x39: - snprintf(buff, sizeof(buff), "units for HCA"); - break; - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - snprintf(buff, sizeof(buff), "reserved"); - break; - case 0x3E: - snprintf(buff, sizeof(buff), "reserved but historic"); - break; - case 0x3F: - snprintf(buff, sizeof(buff), "without units"); - break; - default: - snprintf(buff, sizeof(buff), "unknown"); - break; - } - - return buff; -} - -//------------------------------------------------------------------------------ -// -// VARIABLE-LENGTH DATA RECORD FUNCTIONS -// -//------------------------------------------------------------------------------ - -//------------------------------------------------------------------------------ -// -// Medium Code bin Code hex -// Other 0000 0000 00 -// Oil 0000 0001 01 -// Electricity 0000 0010 02 -// Gas 0000 0011 03 -// Heat (Volume measured at return temperature: outlet) 0000 0100 04 -// Steam 0000 0101 05 -// Hot Water 0000 0110 06 -// Water 0000 0111 07 -// Heat Cost Allocator. 0000 1000 08 -// Compressed Air 0000 1001 09 -// Cooling load meter (Volume measured at return temperature: outlet) 0000 1010 0A -// Cooling load meter (Volume measured at flow temperature: inlet) ♣ 0000 1011 0B -// Heat (Volume measured at flow temperature: inlet) 0000 1100 0C -// Heat / Cooling load meter ♣ 0000 1101 OD -// Bus / System 0000 1110 0E -// Unknown Medium 0000 1111 0F -// Reserved .......... 10 to 15 -// Cold Water 0001 0110 16 -// Dual Water 0001 0111 17 -// Pressure 0001 1000 18 -// A/D Converter 0001 1001 19 -// Reserved .......... 20 to FF -//------------------------------------------------------------------------------ - -/// -/// For variable-length frames, returns a string describing the medium. -/// -const char * -mbus_data_variable_medium_lookup(u_char medium) -{ - static char buff[256]; - - switch (medium) - { - case MBUS_VARIABLE_DATA_MEDIUM_OTHER: - snprintf(buff, sizeof(buff), "Other"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_OIL: - snprintf(buff, sizeof(buff), "Oil"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_ELECTRICITY: - snprintf(buff, sizeof(buff), "Electricity"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_GAS: - snprintf(buff, sizeof(buff), "Gas"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_HEAT_OUT: - snprintf(buff, sizeof(buff), "Heat: Outlet"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_STEAM: - snprintf(buff, sizeof(buff), "Steam"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_HOT_WATER: - snprintf(buff, sizeof(buff), "Hot water"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_WATER: - snprintf(buff, sizeof(buff), "Water"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_HEAT_COST: - snprintf(buff, sizeof(buff), "Heat Cost Allocator"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_COMPR_AIR: - snprintf(buff, sizeof(buff), "Compressed Air"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_COOL_OUT: - snprintf(buff, sizeof(buff), "Cooling load meter: Outlet"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_COOL_IN: - snprintf(buff, sizeof(buff), "Cooling load meter: Inlet"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_HEAT_IN: - snprintf(buff, sizeof(buff), "Heat: Inlet"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_HEAT_COOL: - snprintf(buff, sizeof(buff), "Heat / Cooling load meter"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_BUS: - snprintf(buff, sizeof(buff), "Bus/System"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_UNKNOWN: - snprintf(buff, sizeof(buff), "Unknown Medium"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_COLD_WATER: - snprintf(buff, sizeof(buff), "Cold water"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_DUAL_WATER: - snprintf(buff, sizeof(buff), "Dual water"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_PRESSURE: - snprintf(buff, sizeof(buff), "Pressure"); - break; - - case MBUS_VARIABLE_DATA_MEDIUM_ADC: - snprintf(buff, sizeof(buff), "A/D Converter"); - break; - - case 0x10: // - 0x15 - case 0x20: // - 0xFF - snprintf(buff, sizeof(buff), "Reserved"); - break; - - - // add more ... - default: - snprintf(buff, sizeof(buff), "Unknown medium (0x%.2x)", medium); - break; - } - - return buff; -} - -//------------------------------------------------------------------------------ -/// -/// Lookup the unit description from a VIF field in a data record -/// -//------------------------------------------------------------------------------ -const char * -mbus_unit_prefix(int exp) -{ - static char buff[256]; - - switch (exp) - { - case 0: - buff[0] = 0; - break; - - case -3: - snprintf(buff, sizeof(buff), "m"); - break; - - case -6: - snprintf(buff, sizeof(buff), "my"); - break; - - case 1: - snprintf(buff, sizeof(buff), "10 "); - break; - - case 2: - snprintf(buff, sizeof(buff), "100 "); - break; - - case 3: - snprintf(buff, sizeof(buff), "k"); - break; - - case 4: - snprintf(buff, sizeof(buff), "10 k"); - break; - - case 5: - snprintf(buff, sizeof(buff), "100 k"); - break; - - case 6: - snprintf(buff, sizeof(buff), "M"); - break; - - case 9: - snprintf(buff, sizeof(buff), "T"); - break; - - default: - snprintf(buff, sizeof(buff), "1e%d ", exp); - } - - return buff; -} - -//------------------------------------------------------------------------------ -/// Look up the data lenght from a VIF field in the data record. -/// -/// See the table on page 41 the M-BUS specification. -//------------------------------------------------------------------------------ -u_char -mbus_dif_datalength_lookup(u_char dif) -{ - switch (dif&0x0F) - { - case 0x0: - return 0; - case 0x1: - return 1; - case 0x2: - return 2; - case 0x3: - return 3; - case 0x4: - return 4; - case 0x5: - return 4; - case 0x6: - return 6; - case 0x7: - return 8; - - case 0x8: - return 0; - case 0x9: - return 1; - case 0xA: - return 2; - case 0xB: - return 3; - case 0xC: - return 4; - case 0xD: - // variable data length, - // data length stored in data field - return 0; - case 0xE: - return 6; - case 0xF: - return 8; - - default: // never reached - return 0x00; - - } -} - -//------------------------------------------------------------------------------ -/// Look up the unit from a VIF field in the data record. -/// -/// See section 8.4.3 Codes for Value Information Field (VIF) in the M-BUS spec -//------------------------------------------------------------------------------ -const char * -mbus_vif_unit_lookup(u_char vif) -{ - static char buff[256]; - int n; - - switch (vif & 0x7F) // ignore the extension bit in this selection - { - // E000 0nnn Energy 10(nnn-3) W - case 0x00: - case 0x00+1: - case 0x00+2: - case 0x00+3: - case 0x00+4: - case 0x00+5: - case 0x00+6: - case 0x00+7: - n = (vif & 0x07) - 3; - snprintf(buff, sizeof(buff), "Energy (%sWh)", mbus_unit_prefix(n)); - break; - - // 0000 1nnn Energy 10(nnn)J (0.001kJ to 10000kJ) - case 0x08: - case 0x08+1: - case 0x08+2: - case 0x08+3: - case 0x08+4: - case 0x08+5: - case 0x08+6: - case 0x08+7: - - n = (vif & 0x07); - snprintf(buff, sizeof(buff), "Energy (%sJ)", mbus_unit_prefix(n)); - - break; - - // E001 1nnn Mass 10(nnn-3) kg 0.001kg to 10000kg - case 0x18: - case 0x18+1: - case 0x18+2: - case 0x18+3: - case 0x18+4: - case 0x18+5: - case 0x18+6: - case 0x18+7: - - n = (vif & 0x07); - snprintf(buff, sizeof(buff), "Mass (%skg)", mbus_unit_prefix(n-3)); - - break; - - // E010 1nnn Power 10(nnn-3) W 0.001W to 10000W - case 0x28: - case 0x28+1: - case 0x28+2: - case 0x28+3: - case 0x28+4: - case 0x28+5: - case 0x28+6: - case 0x28+7: - - n = (vif & 0x07); - snprintf(buff, sizeof(buff), "Power (%sW)", mbus_unit_prefix(n-3)); - //snprintf(buff, sizeof(buff), "Power (10^%d W)", n-3); - - break; - - // E011 0nnn Power 10(nnn) J/h 0.001kJ/h to 10000kJ/h - case 0x30: - case 0x30+1: - case 0x30+2: - case 0x30+3: - case 0x30+4: - case 0x30+5: - case 0x30+6: - case 0x30+7: - - n = (vif & 0x07); - snprintf(buff, sizeof(buff), "Power (%sJ/h)", mbus_unit_prefix(n)); - - break; - - // E001 0nnn Volume 10(nnn-6) m3 0.001l to 10000l - case 0x10: - case 0x10+1: - case 0x10+2: - case 0x10+3: - case 0x10+4: - case 0x10+5: - case 0x10+6: - case 0x10+7: - - n = (vif & 0x07); - snprintf(buff, sizeof(buff), "Volume (%s m^3)", mbus_unit_prefix(n-6)); - - break; - - // E011 1nnn Volume Flow 10(nnn-6) m3/h 0.001l/h to 10000l/ - case 0x38: - case 0x38+1: - case 0x38+2: - case 0x38+3: - case 0x38+4: - case 0x38+5: - case 0x38+6: - case 0x38+7: - - n = (vif & 0x07); - snprintf(buff, sizeof(buff), "Volume flow (%s m^3/h)", mbus_unit_prefix(n-6)); - - break; - - // E100 0nnn Volume Flow ext. 10(nnn-7) m3/min 0.0001l/min to 1000l/min - case 0x40: - case 0x40+1: - case 0x40+2: - case 0x40+3: - case 0x40+4: - case 0x40+5: - case 0x40+6: - case 0x40+7: - - n = (vif & 0x07); - snprintf(buff, sizeof(buff), "Volume flow (%s m^3/min)", mbus_unit_prefix(n-7)); - - break; - - // E100 1nnn Volume Flow ext. 10(nnn-9) m3/s 0.001ml/s to 10000ml/ - case 0x48: - case 0x48+1: - case 0x48+2: - case 0x48+3: - case 0x48+4: - case 0x48+5: - case 0x48+6: - case 0x48+7: - - n = (vif & 0x07); - snprintf(buff, sizeof(buff), "Volume flow (%s m^3/s)", mbus_unit_prefix(n-9)); - - break; - - // E101 0nnn Mass flow 10(nnn-3) kg/h 0.001kg/h to 10000kg/ - case 0x50: - case 0x50+1: - case 0x50+2: - case 0x50+3: - case 0x50+4: - case 0x50+5: - case 0x50+6: - case 0x50+7: - - n = (vif & 0x07); - snprintf(buff, sizeof(buff), "Mass flow (%s kg/h)", mbus_unit_prefix(n-3)); - - break; - - // E101 10nn Flow Temperature 10(nn-3) °C 0.001°C to 1°C - case 0x58: - case 0x58+1: - case 0x58+2: - case 0x58+3: - - n = (vif & 0x03); - snprintf(buff, sizeof(buff), "Flow temperature (%sdeg C)", mbus_unit_prefix(n-3)); - - break; - - // E101 11nn Return Temperature 10(nn-3) °C 0.001°C to 1°C - case 0x5C: - case 0x5C+1: - case 0x5C+2: - case 0x5C+3: - - n = (vif & 0x03); - snprintf(buff, sizeof(buff), "Return temperature (%sdeg C)", mbus_unit_prefix(n-3)); - - break; - - // E110 10nn Pressure 10(nn-3) bar 1mbar to 1000mbar - case 0x68: - case 0x68+1: - case 0x68+2: - case 0x68+3: - - n = (vif & 0x03); - snprintf(buff, sizeof(buff), "Pressure (%s bar)", mbus_unit_prefix(n-3)); - - break; - - // E010 00nn On Time - // nn = 00 seconds - // nn = 01 minutes - // nn = 10 hours - // nn = 11 days - // E010 01nn Operating Time coded like OnTime - // E111 00nn Averaging Duration coded like OnTime - // E111 01nn Actuality Duration coded like OnTime - case 0x20: - case 0x20+1: - case 0x20+2: - case 0x20+3: - case 0x24: - case 0x24+1: - case 0x24+2: - case 0x24+3: - case 0x70: - case 0x70+1: - case 0x70+2: - case 0x70+3: - case 0x74: - case 0x74+1: - case 0x74+2: - case 0x74+3: - { - int offset; - - if ((vif & 0x7C) == 0x20) - offset = snprintf(buff, sizeof(buff), "On time "); - else if ((vif & 0x7C) == 0x24) - offset = snprintf(buff, sizeof(buff), "Operating time "); - else if ((vif & 0x7C) == 0x70) - offset = snprintf(buff, sizeof(buff), "Averaging Duration "); - else - offset = snprintf(buff, sizeof(buff), "Actuality Duration "); - - switch (vif & 0x03) - { - case 0x00: - snprintf(&buff[offset], sizeof(buff)-offset, "(seconds)"); - break; - case 0x01: - snprintf(&buff[offset], sizeof(buff)-offset, "(minutes)"); - break; - case 0x02: - snprintf(&buff[offset], sizeof(buff)-offset, "(hours)"); - break; - case 0x03: - snprintf(&buff[offset], sizeof(buff)-offset, "(days)"); - break; - } - } - break; - - // E110 110n Time Point - // n = 0 date - // n = 1 time & date - // data type G - // data type F - case 0x6C: - case 0x6C+1: - - if (vif & 0x1) - snprintf(buff, sizeof(buff), "Time Point (time & date)"); - else - snprintf(buff, sizeof(buff), "Time Point (date)"); - - break; - - // E110 00nn Temperature Difference 10(nn-3)K (mK to K) - case 0x60: - case 0x60+1: - case 0x60+2: - case 0x60+3: - - n = (vif & 0x03); - - snprintf(buff, sizeof(buff), "Temperature Difference (%s deg C)", mbus_unit_prefix(n-3)); - - break; - - // E110 01nn External Temperature 10(nn-3) °C 0.001°C to 1°C - case 0x64: - case 0x64+1: - case 0x64+2: - case 0x64+3: - - n = (vif & 0x03); - snprintf(buff, sizeof(buff), "External temperature (%s deg C)", mbus_unit_prefix(n-3)); - - break; - - // E110 1110 Units for H.C.A. dimensionless - case 0x6E: - snprintf(buff, sizeof(buff), "Units for H.C.A."); - break; - - // E110 1111 Reserved - case 0x6F: - snprintf(buff, sizeof(buff), "Reserved"); - break; - - // Custom VIF in the following string: never reached... - case 0x7C: - snprintf(buff, sizeof(buff), "Custom VIF"); - break; - - // Fabrication No - case 0x78: - snprintf(buff, sizeof(buff), "Fabrication number"); - break; - - // Bus Address - case 0x7A: - snprintf(buff, sizeof(buff), "Bus Address"); - break; - - // Manufacturer specific: 7Fh / FF - case 0x7F: - case 0xFF: - snprintf(buff, sizeof(buff), "Manufacturer specific"); - break; - - default: - snprintf(buff, sizeof(buff), "Unknown (VIF=0x%.2X)", vif); - break; - } - - - return buff; -} - - -//------------------------------------------------------------------------------ -// Lookup the error message -// -// See section 6.6 Codes for general application errors in the M-BUS spec -//------------------------------------------------------------------------------ -const char * -mbus_data_error_lookup(int error) -{ - static char buff[256]; - - switch (error) - { - case MBUS_ERROR_DATA_UNSPECIFIED: - snprintf(buff, sizeof(buff), "Unspecified error"); - break; - - case MBUS_ERROR_DATA_UNIMPLEMENTED_CI: - snprintf(buff, sizeof(buff), "Unimplemented CI-Field"); - break; - - case MBUS_ERROR_DATA_BUFFER_TOO_LONG: - snprintf(buff, sizeof(buff), "Buffer too long, truncated"); - break; - - case MBUS_ERROR_DATA_TOO_MANY_RECORDS: - snprintf(buff, sizeof(buff), "Too many records"); - break; - - case MBUS_ERROR_DATA_PREMATURE_END: - snprintf(buff, sizeof(buff), "Premature end of record"); - break; - - case MBUS_ERROR_DATA_TOO_MANY_DIFES: - snprintf(buff, sizeof(buff), "More than 10 DIFE´s"); - break; - - case MBUS_ERROR_DATA_TOO_MANY_VIFES: - snprintf(buff, sizeof(buff), "More than 10 VIFE´s"); - break; - - case MBUS_ERROR_DATA_RESERVED: - snprintf(buff, sizeof(buff), "Reserved"); - break; - - case MBUS_ERROR_DATA_APPLICATION_BUSY: - snprintf(buff, sizeof(buff), "Application busy"); - break; - - case MBUS_ERROR_DATA_TOO_MANY_READOUTS: - snprintf(buff, sizeof(buff), "Too many readouts"); - break; - - default: - snprintf(buff, sizeof(buff), "Unknown error (0x%.2X)", error); - break; - } - - return buff; -} - - -//------------------------------------------------------------------------------ -/// Lookup the unit from the VIB (VIF or VIFE) -// -// Enhanced Identification -// E000 1000 Access Number (transmission count) -// E000 1001 Medium (as in fixed header) -// E000 1010 Manufacturer (as in fixed header) -// E000 1011 Parameter set identification -// E000 1100 Model / Version -// E000 1101 Hardware version # -// E000 1110 Firmware version # -// E000 1111 Software version # -//------------------------------------------------------------------------------ -const char * -mbus_vib_unit_lookup(mbus_value_information_block *vib) -{ - static char buff[256]; - int n; - - if (vib == NULL) - return ""; - - if (vib->vif == 0xFD || vib->vif == 0xFB) // first type of VIF extention: see table 8.4.4 - { - if (vib->nvife == 0) - { - snprintf(buff, sizeof(buff), "Missing VIF extension"); - } - else if (vib->vife[0] == 0x08 || vib->vife[0] == 0x88) - { - // E000 1000 - snprintf(buff, sizeof(buff), "Access Number (transmission count)"); - } - else if (vib->vife[0] == 0x09|| vib->vife[0] == 0x89) - { - // E000 1001 - snprintf(buff, sizeof(buff), "Medium (as in fixed header)"); - } - else if (vib->vife[0] == 0x0A || vib->vife[0] == 0x8A) - { - // E000 1010 - snprintf(buff, sizeof(buff), "Manufacturer (as in fixed header)"); - } - else if (vib->vife[0] == 0x0B || vib->vife[0] == 0x8B) - { - // E000 1010 - snprintf(buff, sizeof(buff), "Parameter set identification"); - } - else if (vib->vife[0] == 0x0C || vib->vife[0] == 0x8C) - { - // E000 1100 - snprintf(buff, sizeof(buff), "Model / Version"); - } - else if (vib->vife[0] == 0x0D || vib->vife[0] == 0x8D) - { - // E000 1100 - snprintf(buff, sizeof(buff), "Hardware version"); - } - else if (vib->vife[0] == 0x0E || vib->vife[0] == 0x8E) - { - // E000 1101 - snprintf(buff, sizeof(buff), "Firmware version"); - } - else if (vib->vife[0] == 0x0F || vib->vife[0] == 0x8F) - { - // E000 1101 - snprintf(buff, sizeof(buff), "Software version"); - } - else if (vib->vife[0] == 0x17 || vib->vife[0] == 0x97) - { - // VIFE = E001 0111 Error flags - snprintf(buff, sizeof(buff), "Error flags"); - } - else if (vib->vife[0] == 0x10) - { - // VIFE = E001 0000 Customer location - snprintf(buff, sizeof(buff), "Customer location"); - } - else if (vib->vife[0] == 0x0C) - { - // E000 1100 Model / Version - snprintf(buff, sizeof(buff), "Model / Version"); - } - else if (vib->vife[0] == 0x11) - { - // VIFE = E001 0001 Customer - snprintf(buff, sizeof(buff), "Customer"); - } - else if (vib->vife[0] == 0x9) - { - // VIFE = E001 0110 Password - snprintf(buff, sizeof(buff), "Password"); - } - else if (vib->vife[0] == 0x0b) - { - // VIFE = E000 1011 Parameter set identification - snprintf(buff, sizeof(buff), "Parameter set identification"); - } - else if ((vib->vife[0] & 0x70) == 0x40) - { - // VIFE = E100 nnnn 10^(nnnn-9) V - n = (vib->vife[0] & 0x0F); - snprintf(buff, sizeof(buff), "%s V", mbus_unit_prefix(n-9)); - } - else if ((vib->vife[0] & 0x70) == 0x50) - { - // VIFE = E101 nnnn 10nnnn-12 A - n = (vib->vife[0] & 0x0F); - snprintf(buff, sizeof(buff), "%s A", mbus_unit_prefix(n-12)); - } - else if ((vib->vife[0] & 0xF0) == 0x70) - { - // VIFE = E111 nnn Reserved - snprintf(buff, sizeof(buff), "Reserved VIF extension"); - } - else - { - snprintf(buff, sizeof(buff), "Unrecongized VIF extension: 0x%.2x", vib->vife[0]); - } - return buff; - } - else if (vib->vif == 0x7C) - { - // custom VIF - snprintf(buff, sizeof(buff), "%s", vib->custom_vif); - return buff; - } - - return mbus_vif_unit_lookup(vib->vif); // no extention, use VIF -} - -//------------------------------------------------------------------------------ -// Decode data and write to string -// -// Data format (for record->data data array) -// -// Length in Bit Code Meaning Code Meaning -// 0 0000 No data 1000 Selection for Readout -// 8 0001 8 Bit Integer 1001 2 digit BCD -// 16 0010 16 Bit Integer 1010 4 digit BCD -// 24 0011 24 Bit Integer 1011 6 digit BCD -// 32 0100 32 Bit Integer 1100 8 digit BCD -// 32 / N 0101 32 Bit Real 1101 variable length -// 48 0110 48 Bit Integer 1110 12 digit BCD -// 64 0111 64 Bit Integer 1111 Special Functions -// -// The Code is stored in record->drh.dib.dif -// -/// -/// Return a string containing the data -/// -// Source: MBDOC48.PDF -// -//------------------------------------------------------------------------------ -const char * -mbus_data_record_decode(mbus_data_record *record) -{ - static char buff[768]; - u_char vif, vife; - - // ignore extension bit - vif = (record->drh.vib.vif & 0x7F); - vife = (record->drh.vib.vife[0] & 0x7F); - - if (record) - { - int val; - float val3; - long long val4; - struct tm time; - - switch (record->drh.dib.dif & 0x0F) - { - case 0x00: // no data - - buff[0] = 0; - - break; - - case 0x01: // 1 byte integer (8 bit) - - val = mbus_data_int_decode(record->data, 1); - - snprintf(buff, sizeof(buff), "%d", val); - - if (debug) - printf("%s: DIF 0x%.2x was decoded using 1 byte integer\n", __PRETTY_FUNCTION__, record->drh.dib.dif); - - break; - - - case 0x02: // 2 byte (16 bit) - - // E110 1100 Time Point (date) - if (vif == 0x6C) - { - mbus_data_tm_decode(&time, record->data, 2); - snprintf(buff, sizeof(buff), "%04d-%02d-%02d", - (time.tm_year + 2000), - (time.tm_mon + 1), - time.tm_mday); - } - else // 2 byte integer - { - val = mbus_data_int_decode(record->data, 2); - snprintf(buff, sizeof(buff), "%d", val); - if (debug) - printf("%s: DIF 0x%.2x was decoded using 2 byte integer\n", __PRETTY_FUNCTION__, record->drh.dib.dif); - - } - - break; - - case 0x03: // 3 byte integer (24 bit) - - val = mbus_data_int_decode(record->data, 3); - - snprintf(buff, sizeof(buff), "%d", val); - - if (debug) - printf("%s: DIF 0x%.2x was decoded using 3 byte integer\n", __PRETTY_FUNCTION__, record->drh.dib.dif); - - break; - - case 0x04: // 4 byte (32 bit) - - // E110 1101 Time Point (date/time) - // E011 0000 Start (date/time) of tariff - // E111 0000 Date and time of battery change - if ( (vif == 0x6D) || - ((record->drh.vib.vif == 0xFD) && (vife == 0x30)) || - ((record->drh.vib.vif == 0xFD) && (vife == 0x70))) - { - mbus_data_tm_decode(&time, record->data, 4); - snprintf(buff, sizeof(buff), "%04d-%02d-%02dT%02d:%02d:%02d", - (time.tm_year + 2000), - (time.tm_mon + 1), - time.tm_mday, - time.tm_hour, - time.tm_min, - time.tm_sec); - } - else // 4 byte integer - { - val = mbus_data_int_decode(record->data, 4); - snprintf(buff, sizeof(buff), "%d", val); - } - - if (debug) - printf("%s: DIF 0x%.2x was decoded using 4 byte integer\n", __PRETTY_FUNCTION__, record->drh.dib.dif); - - break; - - case 0x05: // 4 Byte Real (32 bit) - - val3 = mbus_data_float_decode(record->data); - - snprintf(buff, sizeof(buff), "%f", val3); - - if (debug) - printf("%s: DIF 0x%.2x was decoded using 4 byte Real\n", __PRETTY_FUNCTION__, record->drh.dib.dif); - - break; - - case 0x06: // 6 byte integer (48 bit) - - val4 = mbus_data_long_long_decode(record->data, 6); - - snprintf(buff, sizeof(buff), "%lld", val4); - - if (debug) - printf("%s: DIF 0x%.2x was decoded using 6 byte integer\n", __PRETTY_FUNCTION__, record->drh.dib.dif); - - break; - - case 0x07: // 8 byte integer (64 bit) - - val4 = mbus_data_long_long_decode(record->data, 8); - - snprintf(buff, sizeof(buff), "%lld", val4); - - if (debug) - printf("%s: DIF 0x%.2x was decoded using 8 byte integer\n", __PRETTY_FUNCTION__, record->drh.dib.dif); - - break; - - //case 0x08: - - case 0x09: // 2 digit BCD (8 bit) - - val = (int)mbus_data_bcd_decode(record->data, 1); - snprintf(buff, sizeof(buff), "%d", val); - - if (debug) - printf("%s: DIF 0x%.2x was decoded using 2 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif); - - break; - - case 0x0A: // 4 digit BCD (16 bit) - - val = (int)mbus_data_bcd_decode(record->data, 2); - snprintf(buff, sizeof(buff), "%d", val); - - if (debug) - printf("%s: DIF 0x%.2x was decoded using 4 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif); - - break; - - case 0x0B: // 6 digit BCD (24 bit) - - val = (int)mbus_data_bcd_decode(record->data, 3); - snprintf(buff, sizeof(buff), "%d", val); - - if (debug) - printf("%s: DIF 0x%.2x was decoded using 6 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif); - - break; - - case 0x0C: // 8 digit BCD (32 bit) - - val = (int)mbus_data_bcd_decode(record->data, 4); - snprintf(buff, sizeof(buff), "%d", val); - - if (debug) - printf("%s: DIF 0x%.2x was decoded using 8 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif); - - break; - - case 0x0E: // 12 digit BCD (48 bit) - - val4 = mbus_data_bcd_decode(record->data, 6); - snprintf(buff, sizeof(buff), "%lld", val4); - - if (debug) - printf("%s: DIF 0x%.2x was decoded using 12 digit BCD\n", __PRETTY_FUNCTION__, record->drh.dib.dif); - - break; - - case 0x0F: // special functions - - mbus_data_bin_decode(buff, record->data, record->data_len, sizeof(buff)); - break; - - case 0x0D: // variable length - if (record->data_len <= 0xBF) - { - mbus_data_str_decode(buff, record->data, record->data_len); - break; - } - /* FALLTHROUGH */ - - default: - - snprintf(buff, sizeof(buff), "Unknown DIF (0x%.2x)", record->drh.dib.dif); - break; - } - - return buff; - } - - return NULL; -} -//------------------------------------------------------------------------------ -/// Return the unit description for a variable-length data record -//------------------------------------------------------------------------------ -const char * -mbus_data_record_unit(mbus_data_record *record) -{ - static char buff[128]; - - if (record) - { - snprintf(buff, sizeof(buff), "%s", mbus_vib_unit_lookup(&(record->drh.vib))); - - return buff; - } - - return NULL; -} - -//------------------------------------------------------------------------------ -/// Return the value for a variable-length data record -//------------------------------------------------------------------------------ -const char * -mbus_data_record_value(mbus_data_record *record) -{ - static char buff[768]; - - if (record) - { - snprintf(buff, sizeof(buff), "%s", mbus_data_record_decode(record)); - - return buff; - } - - return NULL; -} - -//------------------------------------------------------------------------------ -/// Return a string containing the function description -//------------------------------------------------------------------------------ -const char * -mbus_data_record_function(mbus_data_record *record) -{ - static char buff[128]; - - if (record) - { - switch (record->drh.dib.dif & MBUS_DATA_RECORD_DIF_MASK_FUNCTION) - { - case 0x00: - snprintf(buff, sizeof(buff), "Instantaneous value"); - break; - - case 0x10: - snprintf(buff, sizeof(buff), "Maximum value"); - break; - - case 0x20: - snprintf(buff, sizeof(buff), "Minimum value"); - break; - - case 0x30: - snprintf(buff, sizeof(buff), "Value during error state"); - break; - - default: - snprintf(buff, sizeof(buff), "unknown"); - } - - return buff; - } - - return NULL; -} - - -/// -/// For fixed-length frames, return a string describing the type of value (stored or actual) -/// -const char * -mbus_data_fixed_function(int status) -{ - static char buff[128]; - - snprintf(buff, sizeof(buff), "%s", - (status & MBUS_DATA_FIXED_STATUS_DATE_MASK) == MBUS_DATA_FIXED_STATUS_DATE_STORED ? - "Stored value" : "Actual value" ); - - return buff; -} - -//------------------------------------------------------------------------------ -// -// PARSER FUNCTIONS -// -//------------------------------------------------------------------------------ - -//------------------------------------------------------------------------------ -/// PARSE M-BUS frame data structures from binary data. -//------------------------------------------------------------------------------ -int -mbus_parse(mbus_frame *frame, u_char *data, size_t data_size) -{ - size_t i, len; - - if (frame && data && data_size > 0) - { - if (parse_debug) - printf("%s: Attempting to parse binary data [size = %zu]\n", __PRETTY_FUNCTION__, data_size); - - if (parse_debug) - printf("%s: ", __PRETTY_FUNCTION__); - - for (i = 0; i < data_size && parse_debug; i++) - { - printf("%.2X ", data[i] & 0xFF); - } - - if (parse_debug) - printf("\n%s: done.\n", __PRETTY_FUNCTION__); - - switch (data[0]) - { - case MBUS_FRAME_ACK_START: - - // OK, got a valid ack frame, require no more data - frame->start1 = data[0]; - frame->type = MBUS_FRAME_TYPE_ACK; - return 0; - //return MBUS_FRAME_BASE_SIZE_ACK - 1; // == 0 - - case MBUS_FRAME_SHORT_START: - - if (data_size < MBUS_FRAME_BASE_SIZE_SHORT) - { - // OK, got a valid short packet start, but we need more data - return MBUS_FRAME_BASE_SIZE_SHORT - data_size; - } - - if (data_size != MBUS_FRAME_BASE_SIZE_SHORT) - { - snprintf(error_str, sizeof(error_str), "Too much data in frame."); - - // too much data... ? - return -2; - } - - // init frame data structure - frame->start1 = data[0]; - frame->control = data[1]; - frame->address = data[2]; - frame->checksum = data[3]; - frame->stop = data[4]; - - frame->type = MBUS_FRAME_TYPE_SHORT; - - // verify the frame - if (mbus_frame_verify(frame) != 0) - { - return -3; - } - - // successfully parsed data - return 0; - - case MBUS_FRAME_LONG_START: // (also CONTROL) - - if (data_size < 3) - { - // OK, got a valid long/control packet start, but we need - // more data to determine the length - return 3 - data_size; - } - - // init frame data structure - frame->start1 = data[0]; - frame->length1 = data[1]; - frame->length2 = data[2]; - - if (frame->length1 != frame->length2) - { - snprintf(error_str, sizeof(error_str), "Invalid M-Bus frame length."); - - // not a valid M-bus frame - return -2; - } - - // check length of packet: - len = frame->length1; - - if (data_size < (size_t)(MBUS_FRAME_FIXED_SIZE_LONG + len)) - { - // OK, but we need more data - return MBUS_FRAME_FIXED_SIZE_LONG + len - data_size; - } - - if (data_size > (size_t)(MBUS_FRAME_FIXED_SIZE_LONG + len)) - { - snprintf(error_str, sizeof(error_str), "Too much data in frame."); - - // too much data... ? - return -2; - } - - // we got the whole packet, continue parsing - frame->start2 = data[3]; - frame->control = data[4]; - frame->address = data[5]; - frame->control_information = data[6]; - - frame->data_size = len - 3; - for (i = 0; i < frame->data_size; i++) - { - frame->data[i] = data[7 + i]; - } - - frame->checksum = data[data_size-2]; // data[6 + frame->data_size + 1] - frame->stop = data[data_size-1]; // data[6 + frame->data_size + 2] - - if (frame->data_size == 0) - { - frame->type = MBUS_FRAME_TYPE_CONTROL; - } - else - { - frame->type = MBUS_FRAME_TYPE_LONG; - } - - // verify the frame - if (mbus_frame_verify(frame) != 0) - { - return -3; - } - - // successfully parsed data - return 0; - default: - snprintf(error_str, sizeof(error_str), "Invalid M-Bus frame start."); - - // not a valid M-Bus frame header (start byte) - return -4; - } - - } - - snprintf(error_str, sizeof(error_str), "Got null pointer to frame, data or zero data_size."); - - return -1; -} - - -//------------------------------------------------------------------------------ -/// Parse the fixed-length data of a M-Bus frame -//------------------------------------------------------------------------------ -int -mbus_data_fixed_parse(mbus_frame *frame, mbus_data_fixed *data) -{ - if (frame && data) - { - // copy the fixed-length data structure - memcpy((void *)data, (void *)(frame->data), sizeof(mbus_data_fixed)); - - return 0; - } - - return -1; -} - - -//------------------------------------------------------------------------------ -/// Parse the variable-length data of a M-Bus frame -//------------------------------------------------------------------------------ -int -mbus_data_variable_parse(mbus_frame *frame, mbus_data_variable *data) -{ - mbus_data_record *record; - size_t i, j; - - if (frame && data) - { - // parse header - data->nrecords = 0; - data->more_records_follow = 0; - i = sizeof(mbus_data_variable_header); - if(frame->data_size < i) - return -1; - - // first copy the variable data fixed header - memcpy((void *)&(data->header), (void *)(frame->data), i); - - data->record = NULL; - - while (i < frame->data_size) - { - if ((record = mbus_data_record_new()) == NULL) - { - // clean up... - return (-2); - } - - // copy timestamp - memcpy((void *)&(record->timestamp), (void *)&(frame->timestamp), sizeof(time_t)); - - // read and parse DIB (= DIF + DIFE) - - // DIF - record->drh.dib.dif = frame->data[i]; - - if (record->drh.dib.dif == 0x0F || record->drh.dib.dif == 0x1F) - { - if ((record->drh.dib.dif & 0xFF) == 0x1F) - { - data->more_records_follow = 1; - } - - i++; - // just copy the remaining data as it is vendor specific - record->data_len = frame->data_size - i; - for (j = 0; j < record->data_len; j++) - { - record->data[j] = frame->data[i++]; - } - - // append the record and move on to next one - mbus_data_record_append(data, record); - data->nrecords++; - continue; - } - - // calculate length of data record - record->data_len = mbus_dif_datalength_lookup(record->drh.dib.dif); - - // read DIF extensions - record->drh.dib.ndife = 0; - while (frame->data[i] & MBUS_DIB_DIF_EXTENSION_BIT && - record->drh.dib.ndife < NITEMS(record->drh.dib.dife)) - { - u_char dife = frame->data[i+1]; - record->drh.dib.dife[record->drh.dib.ndife] = dife; - - record->drh.dib.ndife++; - i++; - } - i++; - - // read and parse VIB (= VIF + VIFE) - - // VIF - record->drh.vib.vif = frame->data[i]; - - if (record->drh.vib.vif == 0x7C) - { - // variable length VIF in ASCII format - int var_vif_len; - i++; - var_vif_len = frame->data[i++]; - mbus_data_str_decode(record->drh.vib.custom_vif, &(frame->data[i]), var_vif_len); - i += var_vif_len; - } - else - { - // VIFE - record->drh.vib.nvife = 0; - while (frame->data[i] & MBUS_DIB_VIF_EXTENSION_BIT && - record->drh.vib.nvife < NITEMS(record->drh.vib.vife)) - { - u_char vife = frame->data[i+1]; - record->drh.vib.vife[record->drh.vib.nvife] = vife; - - record->drh.vib.nvife++; - i++; - } - i++; - } - - // re-calculate data length, if of variable length type - if ((record->drh.dib.dif & 0x0F) == 0x0D) // flag for variable length data - { - if(frame->data[i] <= 0xBF) - record->data_len = frame->data[i++]; - else if(frame->data[i] >= 0xC0 && frame->data[i] <= 0xCF) - record->data_len = (frame->data[i++] - 0xC0) * 2; - else if(frame->data[i] >= 0xD0 && frame->data[i] <= 0xDF) - record->data_len = (frame->data[i++] - 0xD0) * 2; - else if(frame->data[i] >= 0xE0 && frame->data[i] <= 0xEF) - record->data_len = frame->data[i++] - 0xE0; - else if(frame->data[i] >= 0xF0 && frame->data[i] <= 0xFA) - record->data_len = frame->data[i++] - 0xF0; - } - - // copy data - for (j = 0; j < record->data_len; j++) - { - record->data[j] = frame->data[i++]; - } - - // append the record and move on to next one - mbus_data_record_append(data, record); - data->nrecords++; - } - - return 0; - } - - return -1; -} - -//------------------------------------------------------------------------------ -/// Check the stype of the frame data (error, fixed or variable) and dispatch to the -/// corresponding parser function. -//------------------------------------------------------------------------------ -int -mbus_frame_data_parse(mbus_frame *frame, mbus_frame_data *data) -{ - if (frame && data) - { - if (frame->control_information == MBUS_CONTROL_INFO_ERROR_GENERAL) - { - data->type = MBUS_DATA_TYPE_ERROR; - - if (frame->data_size > 0) - { - data->error = (int) frame->data[0]; - } - else - { - data->error = 0; - } - - return 0; - } - else if (frame->control_information == MBUS_CONTROL_INFO_RESP_FIXED) - { - if (frame->data_size == 0) - { - snprintf(error_str, sizeof(error_str), "Got zero data_size."); - - return -1; - } - - data->type = MBUS_DATA_TYPE_FIXED; - return mbus_data_fixed_parse(frame, &(data->data_fix)); - } - else if (frame->control_information == MBUS_CONTROL_INFO_RESP_VARIABLE) - { - if (frame->data_size == 0) - { - snprintf(error_str, sizeof(error_str), "Got zero data_size."); - - return -1; - } - - data->type = MBUS_DATA_TYPE_VARIABLE; - return mbus_data_variable_parse(frame, &(data->data_var)); - } - else - { - snprintf(error_str, sizeof(error_str), "Unknown control information 0x%.2x", frame->control_information); - - return -1; - } - } - - snprintf(error_str, sizeof(error_str), "Got null pointer to frame or data."); - - return -1; -} - -//------------------------------------------------------------------------------ -/// Pack the M-bus frame into a binary string representation that can be sent -/// on the bus. The binary packet format is different for the different types -/// of M-bus frames. -//------------------------------------------------------------------------------ -int -mbus_frame_pack(mbus_frame *frame, u_char *data, size_t data_size) -{ - size_t i, offset = 0; - - if (frame && data) - { - if (mbus_frame_calc_length(frame) == -1) - { - return -2; - } - - if (mbus_frame_calc_checksum(frame) == -1) - { - return -3; - } - - switch (frame->type) - { - case MBUS_FRAME_TYPE_ACK: - - if (data_size < MBUS_FRAME_ACK_BASE_SIZE) - { - return -4; - } - - data[offset++] = frame->start1; - - return offset; - - case MBUS_FRAME_TYPE_SHORT: - - if (data_size < MBUS_FRAME_SHORT_BASE_SIZE) - { - return -4; - } - - data[offset++] = frame->start1; - data[offset++] = frame->control; - data[offset++] = frame->address; - data[offset++] = frame->checksum; - data[offset++] = frame->stop; - - return offset; - - case MBUS_FRAME_TYPE_CONTROL: - - if (data_size < MBUS_FRAME_CONTROL_BASE_SIZE) - { - return -4; - } - - data[offset++] = frame->start1; - data[offset++] = frame->length1; - data[offset++] = frame->length2; - data[offset++] = frame->start2; - - data[offset++] = frame->control; - data[offset++] = frame->address; - data[offset++] = frame->control_information; - - data[offset++] = frame->checksum; - data[offset++] = frame->stop; - - return offset; - - case MBUS_FRAME_TYPE_LONG: - - if (data_size < frame->data_size + MBUS_FRAME_LONG_BASE_SIZE) - { - return -4; - } - - data[offset++] = frame->start1; - data[offset++] = frame->length1; - data[offset++] = frame->length2; - data[offset++] = frame->start2; - - data[offset++] = frame->control; - data[offset++] = frame->address; - data[offset++] = frame->control_information; - - for (i = 0; i < frame->data_size; i++) - { - data[offset++] = frame->data[i]; - } - - data[offset++] = frame->checksum; - data[offset++] = frame->stop; - - return offset; - - default: - return -5; - } - } - - return -1; -} - - -//------------------------------------------------------------------------------ -/// pack the data stuctures into frame->data -//------------------------------------------------------------------------------ -int -mbus_frame_internal_pack(mbus_frame *frame, mbus_frame_data *frame_data) -{ - mbus_data_record *record; - int j; - - if (frame == NULL || frame_data == NULL) - return -1; - - frame->data_size = 0; - - switch (frame_data->type) - { - case MBUS_DATA_TYPE_ERROR: - - frame->data[frame->data_size++] = (char) frame_data->error; - - break; - - case MBUS_DATA_TYPE_FIXED: - - // - // pack fixed data structure - // - frame->data[frame->data_size++] = frame_data->data_fix.id_bcd[0]; - frame->data[frame->data_size++] = frame_data->data_fix.id_bcd[1]; - frame->data[frame->data_size++] = frame_data->data_fix.id_bcd[2]; - frame->data[frame->data_size++] = frame_data->data_fix.id_bcd[3]; - frame->data[frame->data_size++] = frame_data->data_fix.tx_cnt; - frame->data[frame->data_size++] = frame_data->data_fix.status; - frame->data[frame->data_size++] = frame_data->data_fix.cnt1_type; - frame->data[frame->data_size++] = frame_data->data_fix.cnt2_type; - frame->data[frame->data_size++] = frame_data->data_fix.cnt1_val[0]; - frame->data[frame->data_size++] = frame_data->data_fix.cnt1_val[1]; - frame->data[frame->data_size++] = frame_data->data_fix.cnt1_val[2]; - frame->data[frame->data_size++] = frame_data->data_fix.cnt1_val[3]; - frame->data[frame->data_size++] = frame_data->data_fix.cnt2_val[0]; - frame->data[frame->data_size++] = frame_data->data_fix.cnt2_val[1]; - frame->data[frame->data_size++] = frame_data->data_fix.cnt2_val[2]; - frame->data[frame->data_size++] = frame_data->data_fix.cnt2_val[3]; - - break; - - case MBUS_DATA_TYPE_VARIABLE: - - // - // first pack variable data structure header - // - frame->data[frame->data_size++] = frame_data->data_var.header.id_bcd[0]; - frame->data[frame->data_size++] = frame_data->data_var.header.id_bcd[1]; - frame->data[frame->data_size++] = frame_data->data_var.header.id_bcd[2]; - frame->data[frame->data_size++] = frame_data->data_var.header.id_bcd[3]; - frame->data[frame->data_size++] = frame_data->data_var.header.manufacturer[0]; - frame->data[frame->data_size++] = frame_data->data_var.header.manufacturer[1]; - frame->data[frame->data_size++] = frame_data->data_var.header.version; - frame->data[frame->data_size++] = frame_data->data_var.header.medium; - frame->data[frame->data_size++] = frame_data->data_var.header.access_no; - frame->data[frame->data_size++] = frame_data->data_var.header.status; - frame->data[frame->data_size++] = frame_data->data_var.header.signature[0]; - frame->data[frame->data_size++] = frame_data->data_var.header.signature[1]; - - // - // pack all data records - // - for (record = frame_data->data_var.record; record; record = record->next) - { - // pack DIF - if (parse_debug) - printf("%s: packing DIF [%zu]", __PRETTY_FUNCTION__, frame->data_size); - frame->data[frame->data_size++] = record->drh.dib.dif; - for (j = 0; j < record->drh.dib.ndife; j++) - { - frame->data[frame->data_size++] = record->drh.dib.dife[j]; - } - - // pack VIF - if (parse_debug) - printf("%s: packing VIF [%zu]", __PRETTY_FUNCTION__, frame->data_size); - frame->data[frame->data_size++] = record->drh.vib.vif; - for (j = 0; j < record->drh.vib.nvife; j++) - { - frame->data[frame->data_size++] = record->drh.vib.vife[j]; - } - - // pack data - if (parse_debug) - printf("%s: packing data [%zu : %zu]", __PRETTY_FUNCTION__, frame->data_size, record->data_len); - for (j = 0; j < record->data_len; j++) - { - frame->data[frame->data_size++] = record->data[j]; - } - } - - break; - - default: - return -2; - } - - return 0; -} - -//------------------------------------------------------------------------------ -// -// Print/Dump functions -// -//------------------------------------------------------------------------------ - -//------------------------------------------------------------------------------ -/// Switch parse debugging -//------------------------------------------------------------------------------ -void -mbus_parse_set_debug(int debug) -{ - parse_debug = debug; -} - -//------------------------------------------------------------------------------ -/// Dump frame in HEX on standard output -//------------------------------------------------------------------------------ -int -mbus_frame_print(mbus_frame *frame) -{ - mbus_frame *iter; - u_char data_buff[256]; - int len, i; - - if (frame == NULL) - return -1; - - for (iter = frame; iter; iter = iter->next) - { - if ((len = mbus_frame_pack(iter, data_buff, sizeof(data_buff))) == -1) - { - return -2; - } - - printf("%s: Dumping M-Bus frame [type %d, %d bytes]: ", __PRETTY_FUNCTION__, iter->type, len); - for (i = 0; i < len; i++) - { - printf("%.2X ", data_buff[i]); - } - printf("\n"); - } - - return 0; -} - -//------------------------------------------------------------------------------ -/// -/// Print the data part of a frame. -/// -//------------------------------------------------------------------------------ -int -mbus_frame_data_print(mbus_frame_data *data) -{ - if (data) - { - if (data->type == MBUS_DATA_TYPE_ERROR) - { - return mbus_data_error_print(data->error); - } - - if (data->type == MBUS_DATA_TYPE_FIXED) - { - return mbus_data_fixed_print(&(data->data_fix)); - } - - if (data->type == MBUS_DATA_TYPE_VARIABLE) - { - return mbus_data_variable_print(&(data->data_var)); - } - } - - return -1; -} - -//------------------------------------------------------------------------------ -/// Print M-bus frame info to stdout -//------------------------------------------------------------------------------ -int -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: Manufacturer = 0x%.2X%.2X\n", __PRETTY_FUNCTION__, - header->manufacturer[1], header->manufacturer[0]); - - printf("%s: Manufacturer = %s\n", __PRETTY_FUNCTION__, - mbus_decode_manufacturer(header->manufacturer[0], header->manufacturer[1])); - - printf("%s: Version = 0x%.2X\n", __PRETTY_FUNCTION__, header->version); - printf("%s: Medium = %s (0x%.2X)\n", __PRETTY_FUNCTION__, mbus_data_variable_medium_lookup(header->medium), header->medium); - printf("%s: Access # = 0x%.2X\n", __PRETTY_FUNCTION__, header->access_no); - printf("%s: Status = 0x%.2X\n", __PRETTY_FUNCTION__, header->status); - printf("%s: Signature = 0x%.2X%.2X\n", __PRETTY_FUNCTION__, - header->signature[1], header->signature[0]); - - } - - return -1; -} - -int -mbus_data_variable_print(mbus_data_variable *data) -{ - mbus_data_record *record; - size_t j; - - if (data) - { - mbus_data_variable_header_print(&(data->header)); - - 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); - - // VENDOR SPECIFIC - if (record->drh.dib.dif == 0x0F || record->drh.dib.dif == 0x1F) //MBUS_DIB_DIF_VENDOR_SPECIFIC) - { - printf("%s: VENDOR DATA [size=%zd] = ", __PRETTY_FUNCTION__, record->data_len); - for (j = 0; j < record->data_len; j++) - { - printf("%.2X ", record->data[j]); - } - printf("\n"); - - if (record->drh.dib.dif == 0x1F) - { - printf("%s: More records follow in next telegram\n", __PRETTY_FUNCTION__); - } - continue; - } - - // calculate length of data record - printf("DATA LENGTH = %zd\n", record->data_len); - - // DIFE - for (j = 0; j < record->drh.dib.ndife; j++) - { - u_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); - } - - } - } - - return -1; -} - -int -mbus_data_fixed_print(mbus_data_fixed *data) -{ - if (data) - { - printf("%s: ID = %d\n", __PRETTY_FUNCTION__, (int)mbus_data_bcd_decode(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)); - - printf("%s: Medium1 = %s\n", __PRETTY_FUNCTION__, mbus_data_fixed_medium(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)); - } - else - { - printf("%s: Counter1 = %d\n", __PRETTY_FUNCTION__, mbus_data_int_decode(data->cnt1_val, 4)); - } - - 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)); - } - else - { - printf("%s: Counter2 = %d\n", __PRETTY_FUNCTION__, mbus_data_int_decode(data->cnt2_val, 4)); - } - } - - return -1; -} - -void -mbus_hex_dump(const char *label, const char *buff, size_t len) -{ - time_t rawtime; - struct tm * timeinfo; - char timestamp[21]; - size_t i; - - if (label == NULL || buff == NULL) - return; - - time ( &rawtime ); - timeinfo = gmtime ( &rawtime ); - - strftime(timestamp,20,"%Y-%m-%d %H:%M:%S",timeinfo); - fprintf(stderr, "[%s] %s (%03d):", timestamp, label, len); - - for (i = 0; i < len; i++) - { - fprintf(stderr, " %02X", (u_char) buff[i]); - } - - fprintf(stderr, "\n"); -} - -int -mbus_data_error_print(int error) -{ - printf("%s: Error = %d\n", __PRETTY_FUNCTION__, error); - - return -1; -} - -//------------------------------------------------------------------------------ -// -// XML RELATED FUNCTIONS -// -//------------------------------------------------------------------------------ - -//------------------------------------------------------------------------------ -/// -/// Encode string to XML -/// -//------------------------------------------------------------------------------ -void -mbus_str_xml_encode(u_char *dst, const u_char *src, size_t max_len) -{ - size_t i, len; - - i = 0; - len = 0; - - if (dst == NULL) - return; - - if (src != NULL) - { - while((len+6) < max_len) - { - if (src[i] == '\0') - { - break; - } - - switch (src[i]) - { - case '&': - len += snprintf(&dst[len], max_len - len, "&"); - break; - case '<': - len += snprintf(&dst[len], max_len - len, "<"); - break; - case '>': - len += snprintf(&dst[len], max_len - len, ">"); - break; - case '"': - len += snprintf(&dst[len], max_len - len, """); - break; - default: - dst[len++] = src[i]; - break; - } - - i++; - } - } - - dst[len] = '\0'; -} - -//------------------------------------------------------------------------------ -/// Generate XML for the variable-length data header -//------------------------------------------------------------------------------ -char * -mbus_data_variable_header_xml(mbus_data_variable_header *header) -{ - static char buff[8192]; - char str_encoded[768]; - size_t len = 0; - int val; - - if (header) - { - len += snprintf(&buff[len], sizeof(buff) - len, " \n"); - - val = (int)mbus_data_bcd_decode(header->id_bcd, 4); - - len += snprintf(&buff[len], sizeof(buff) - len, " %d\n", val); - 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); - - mbus_str_xml_encode(str_encoded, mbus_data_product_name(header), sizeof(str_encoded)); - - len += snprintf(&buff[len], sizeof(buff) - len, " %s\n", str_encoded); - - mbus_str_xml_encode(str_encoded, mbus_data_variable_medium_lookup(header->medium), sizeof(str_encoded)); - - len += snprintf(&buff[len], sizeof(buff) - len, " %s\n", str_encoded); - len += snprintf(&buff[len], sizeof(buff) - len, " %d\n", header->access_no); - len += snprintf(&buff[len], sizeof(buff) - len, " %.2X\n", header->status); - len += snprintf(&buff[len], sizeof(buff) - len, " %.2X%.2X\n", header->signature[1], header->signature[0]); - - len += snprintf(&buff[len], sizeof(buff) - len, " \n\n"); - - return buff; - } - - return ""; -} - -//------------------------------------------------------------------------------ -/// Generate XML for a single variable-length data record -//------------------------------------------------------------------------------ -char * -mbus_data_variable_record_xml(mbus_data_record *record, int record_cnt, int frame_cnt, mbus_data_variable_header *header) -{ - static char buff[8192]; - char str_encoded[768]; - size_t len = 0; - struct tm * timeinfo; - char timestamp[21]; - int val; - - if (record) - { - if (frame_cnt >= 0) - { - len += snprintf(&buff[len], sizeof(buff) - len, - " \n", - record_cnt, frame_cnt); - } - else - { - len += snprintf(&buff[len], sizeof(buff) - len, - " \n", record_cnt); - } - - if (record->drh.dib.dif == 0x0F) // MBUS_DIB_DIF_VENDOR_SPECIFIC - { - len += snprintf(&buff[len], sizeof(buff) - len, - " Manufacturer specific\n"); - } - else if (record->drh.dib.dif == 0x1F) - { - len += snprintf(&buff[len], sizeof(buff) - len, - " More records follow\n"); - } - else - { - 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); - - mbus_str_xml_encode(str_encoded, mbus_data_record_unit(record), sizeof(str_encoded)); - len += snprintf(&buff[len], sizeof(buff) - len, - " %s\n", str_encoded); - } - - mbus_str_xml_encode(str_encoded, mbus_data_record_value(record), sizeof(str_encoded)); - len += snprintf(&buff[len], sizeof(buff) - len, " %s\n", str_encoded); - - timeinfo = gmtime ( &(record->timestamp) ); - strftime(timestamp,20,"%Y-%m-%dT%H:%M:%S",timeinfo); - len += snprintf(&buff[len], sizeof(buff) - len, " %s\n", timestamp); - - len += snprintf(&buff[len], sizeof(buff) - len, " \n\n"); - - return buff; - } - - return ""; -} - -//------------------------------------------------------------------------------ -/// Generate XML for variable-length data -//------------------------------------------------------------------------------ -char * -mbus_data_variable_xml(mbus_data_variable *data) -{ - mbus_data_record *record; - char *buff = NULL; - size_t len = 0, buff_size = 8192; - int i; - - if (data) - { - buff = (char*) malloc(buff_size); - - if (buff == NULL) - return NULL; - - len += snprintf(&buff[len], buff_size - len, "\n\n"); - - len += snprintf(&buff[len], buff_size - len, "%s", - mbus_data_variable_header_xml(&(data->header))); - - for (record = data->record, i = 0; record; record = record->next, i++) - { - if ((buff_size - len) < 1024) - { - buff_size *= 2; - buff = (char*) realloc(buff,buff_size); - - if (buff == NULL) - return NULL; - } - - len += snprintf(&buff[len], buff_size - len, "%s", - mbus_data_variable_record_xml(record, i, -1, &(data->header))); - } - len += snprintf(&buff[len], buff_size - len, "\n"); - - return buff; - } - - return NULL; -} - -//------------------------------------------------------------------------------ -/// Generate XML representation of fixed-length frame. -//------------------------------------------------------------------------------ -char * -mbus_data_fixed_xml(mbus_data_fixed *data) -{ - char *buff = NULL; - char str_encoded[256]; - size_t len = 0, buff_size = 8192; - - if (data) - { - buff = (char*) malloc(buff_size); - - if (buff == NULL) - return NULL; - - len += snprintf(&buff[len], buff_size - len, "\n\n"); - - len += snprintf(&buff[len], buff_size - len, " \n"); - len += snprintf(&buff[len], buff_size - len, " %d\n", (int)mbus_data_bcd_decode(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); - - len += snprintf(&buff[len], buff_size - len, " %d\n", data->tx_cnt); - len += snprintf(&buff[len], buff_size - len, " %.2X\n", data->status); - len += snprintf(&buff[len], buff_size - len, " \n\n"); - - len += snprintf(&buff[len], buff_size - len, " \n"); - - mbus_str_xml_encode(str_encoded, mbus_data_fixed_function(data->status), sizeof(str_encoded)); - len += snprintf(&buff[len], buff_size - len, " %s\n", str_encoded); - - mbus_str_xml_encode(str_encoded, mbus_data_fixed_unit(data->cnt1_type), sizeof(str_encoded)); - 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)); - } - else - { - len += snprintf(&buff[len], buff_size - len, " %d\n", mbus_data_int_decode(data->cnt1_val, 4)); - } - len += snprintf(&buff[len], buff_size - len, " \n\n"); - - len += snprintf(&buff[len], buff_size - len, " \n"); - - mbus_str_xml_encode(str_encoded, mbus_data_fixed_function(data->status), sizeof(str_encoded)); - len += snprintf(&buff[len], buff_size - len, " %s\n", str_encoded); - - mbus_str_xml_encode(str_encoded, mbus_data_fixed_unit(data->cnt2_type), sizeof(str_encoded)); - 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)); - } - else - { - len += snprintf(&buff[len], buff_size - len, " %d\n", mbus_data_int_decode(data->cnt2_val, 4)); - } - len += snprintf(&buff[len], buff_size - len, " \n\n"); - - len += snprintf(&buff[len], buff_size - len, "\n"); - - return buff; - } - - return NULL; -} - -//------------------------------------------------------------------------------ -/// Generate XML representation of a general application error. -//------------------------------------------------------------------------------ -char * -mbus_data_error_xml(int error) -{ - char *buff = NULL; - char str_encoded[256]; - size_t len = 0, buff_size = 8192; - - buff = (char*) malloc(buff_size); - - if (buff == NULL) - return NULL; - - len += snprintf(&buff[len], buff_size - len, "\n\n"); - - len += snprintf(&buff[len], buff_size - len, " \n"); - - mbus_str_xml_encode(str_encoded, mbus_data_error_lookup(error), sizeof(str_encoded)); - len += snprintf(&buff[len], buff_size - len, " %s\n", str_encoded); - - len += snprintf(&buff[len], buff_size - len, " \n\n"); - - len += snprintf(&buff[len], buff_size - len, "\n"); - - return buff; -} - -//------------------------------------------------------------------------------ -/// Return a string containing an XML representation of the M-BUS frame data. -//------------------------------------------------------------------------------ -char * -mbus_frame_data_xml(mbus_frame_data *data) -{ - if (data) - { - if (data->type == MBUS_DATA_TYPE_ERROR) - { - return mbus_data_error_xml(data->error); - } - - if (data->type == MBUS_DATA_TYPE_FIXED) - { - return mbus_data_fixed_xml(&(data->data_fix)); - } - - if (data->type == MBUS_DATA_TYPE_VARIABLE) - { - return mbus_data_variable_xml(&(data->data_var)); - } - } - - return NULL; -} - - -//------------------------------------------------------------------------------ -/// Return an XML representation of the M-BUS frame. -//------------------------------------------------------------------------------ -char * -mbus_frame_xml(mbus_frame *frame) -{ - mbus_frame_data frame_data; - mbus_frame *iter; - - mbus_data_record *record; - char *buff = NULL; - - size_t len = 0, buff_size = 8192; - int record_cnt = 0, frame_cnt; - - if (frame) - { - if (mbus_frame_data_parse(frame, &frame_data) == -1) - { - mbus_error_str_set("M-bus data parse error."); - return NULL; - } - - if (frame_data.type == MBUS_DATA_TYPE_ERROR) - { - // - // generate XML for error - // - return mbus_data_error_xml(frame_data.error); - } - - if (frame_data.type == MBUS_DATA_TYPE_FIXED) - { - // - // generate XML for fixed data - // - return mbus_data_fixed_xml(&(frame_data.data_fix)); - } - - if (frame_data.type == MBUS_DATA_TYPE_VARIABLE) - { - // - // generate XML for a sequence of variable data frames - // - - buff = (char*) malloc(buff_size); - - if (buff == NULL) - return NULL; - - // include frame counter in XML output if more than one frame - // is available (frame_cnt = -1 => not included in output) - frame_cnt = (frame->next == NULL) ? -1 : 0; - - len += snprintf(&buff[len], buff_size - len, "\n\n"); - - // only print the header info for the first frame (should be - // the same for each frame in a sequence of a multi-telegram - // transfer. - len += snprintf(&buff[len], buff_size - len, "%s", - mbus_data_variable_header_xml(&(frame_data.data_var.header))); - - // loop through all records in the current frame, using a global - // record count as record ID in the XML output - for (record = frame_data.data_var.record; record; record = record->next, record_cnt++) - { - if ((buff_size - len) < 1024) - { - buff_size *= 2; - buff = (char*) realloc(buff,buff_size); - - if (buff == NULL) - return NULL; - } - - len += snprintf(&buff[len], buff_size - len, "%s", - mbus_data_variable_record_xml(record, record_cnt, frame_cnt, &(frame_data.data_var.header))); - } - - // free all records in the list - if (frame_data.data_var.record) - { - mbus_data_record_free(frame_data.data_var.record); - } - - frame_cnt++; - - for (iter = frame->next; iter; iter = iter->next, frame_cnt++) - { - if (mbus_frame_data_parse(iter, &frame_data) == -1) - { - mbus_error_str_set("M-bus variable data parse error."); - return NULL; - } - - // loop through all records in the current frame, using a global - // record count as record ID in the XML output - for (record = frame_data.data_var.record; record; record = record->next, record_cnt++) - { - if ((buff_size - len) < 1024) - { - buff_size *= 2; - buff = (char*) realloc(buff,buff_size); - - if (buff == NULL) - return NULL; - } - - len += snprintf(&buff[len], buff_size - len, "%s", - mbus_data_variable_record_xml(record, record_cnt, frame_cnt, &(frame_data.data_var.header))); - } - - // free all records in the list - if (frame_data.data_var.record) - { - mbus_data_record_free(frame_data.data_var.record); - } - } - - len += snprintf(&buff[len], buff_size - len, "\n"); - - return buff; - } - } - - return NULL; -} - - -//------------------------------------------------------------------------------ -/// Allocate and initialize a new frame data structure -//------------------------------------------------------------------------------ -mbus_frame_data * -mbus_frame_data_new() -{ - mbus_frame_data *data; - - if ((data = (mbus_frame_data *)malloc(sizeof(mbus_frame_data))) == NULL) - { - return NULL; - } - data->data_var.record = NULL; - - return data; -} - - -//----------------------------------------------------------------------------- -/// Free up data associated with a frame data structure -//------------------------------------------------------------------------------ -void -mbus_frame_data_free(mbus_frame_data *data) -{ - if (data) - { - if (data->data_var.record) - { - mbus_data_record_free(data->data_var.record); // free's up the whole list - } - - free(data); - } -} - - - -//------------------------------------------------------------------------------ -/// Allocate and initialize a new variable data record -//------------------------------------------------------------------------------ -mbus_data_record * -mbus_data_record_new() -{ - mbus_data_record *record; - - if ((record = (mbus_data_record *)malloc(sizeof(mbus_data_record))) == NULL) - { - return NULL; - } - - record->next = NULL; - return record; -} - -//------------------------------------------------------------------------------ -/// free up memory associated with a data record and all the subsequent records -/// in its list (apply recursively) -//------------------------------------------------------------------------------ -void -mbus_data_record_free(mbus_data_record *record) -{ - if (record) - { - mbus_data_record *next = record->next; - - free(record); - - if (next) - mbus_data_record_free(next); - } -} - -//------------------------------------------------------------------------------ -/// Return a string containing an XML representation of the M-BUS frame. -//------------------------------------------------------------------------------ -void -mbus_data_record_append(mbus_data_variable *data, mbus_data_record *record) -{ - mbus_data_record *iter; - - if (data && record) - { - if (data->record == NULL) - { - data->record = record; - } - else - { - // find the end of the list - for (iter = data->record; iter->next; iter = iter->next); - - iter->next = record; - } - } -} - -//------------------------------------------------------------------------------ -// Extract the secondary address from an M-Bus frame. The secondary address -// should be a 16 character string comprised of the device ID (4 bytes), -// manufacturer ID (2 bytes), version (1 byte) and medium (1 byte). -//------------------------------------------------------------------------------ -char * -mbus_frame_get_secondary_address(mbus_frame *frame) -{ - static char addr[32]; - mbus_frame_data *data; - long id; - - if (frame == NULL || (data = mbus_frame_data_new()) == NULL) - { - printf("%s: Failed to allocate data structure [%p, %p].\n", __PRETTY_FUNCTION__, (void*)frame, (void*)data); - return NULL; - } - - if (frame->control_information != MBUS_CONTROL_INFO_RESP_VARIABLE) - { - snprintf(error_str, sizeof(error_str), "Non-variable data response (can't get secondary address from response)."); - return NULL; - } - - if (mbus_frame_data_parse(frame, data) == -1) - { - return NULL; - } - - id = (long) mbus_data_bcd_decode(data->data_var.header.id_bcd, 4); - - snprintf(addr, sizeof(addr), "%08lu%02X%02X%02X%02X", - id, - data->data_var.header.manufacturer[0], - data->data_var.header.manufacturer[1], - data->data_var.header.version, - data->data_var.header.medium); - - // free data - mbus_frame_data_free(data); - - return addr; -} - -//------------------------------------------------------------------------------ -// Pack a secondary address string into an mbus frame -//------------------------------------------------------------------------------ -int -mbus_frame_select_secondary_pack(mbus_frame *frame, char *address) -{ - int val, i, j, k; - char tmp[16]; - - if (frame == NULL || address == NULL || strlen(address) != 16) - { - snprintf(error_str, sizeof(error_str), "%s: frame or address arguments are NULL or invalid.", __PRETTY_FUNCTION__); - return -1; - } - - frame->control = MBUS_CONTROL_MASK_SND_UD | MBUS_CONTROL_MASK_DIR_M2S | MBUS_CONTROL_MASK_FCB; - frame->address = 253; // for addressing secondary slaves - frame->control_information = 0x52; // mode 1 - - frame->data_size = 8; - - // parse secondary_addr_str and populate frame->data[0-7] - // ex: secondary_addr_str = "14491001 1057 01 06" - // (excluding the blank spaces) - - strncpy(tmp, &address[14], 2); tmp[2] = 0; - val = strtol(tmp, NULL, 16); - frame->data[7] = val & 0xFF; - - strncpy(tmp, &address[12], 2); tmp[2] = 0; - val = strtol(tmp, NULL, 16); - frame->data[6] = val & 0xFF; - - strncpy(tmp, &address[8], 4); tmp[4] = 0; - val = strtol(tmp, NULL, 16); - frame->data[4] = (val>>8) & 0xFF; - frame->data[5] = val & 0xFF; - - // parse the ID string, allowing for F wildcard characters. - frame->data[0] = 0; - frame->data[1] = 0; - frame->data[2] = 0; - frame->data[3] = 0; - j = 3; k = 1; - for (i = 0; i < 8; i++) - { - if (address[i] == 'F' || address[i] == 'f') - { - frame->data[j] |= 0x0F << (4 * k--); - } - else - { - frame->data[j] |= (0x0F & (address[i] - '0')) << (4 * k--); - } - - if (k < 0) - { - k = 1; j--; - } - } - - return 0; -} diff --git a/cube/libmbus/mbus/mbus-protocol.h b/cube/libmbus/mbus/mbus-protocol.h deleted file mode 100644 index 5fa5298..0000000 --- a/cube/libmbus/mbus/mbus-protocol.h +++ /dev/null @@ -1,624 +0,0 @@ -//------------------------------------------------------------------------------ -// Copyright (C) 2010-2011, Robert Johansson, Raditex AB -// All rights reserved. -// -// rSCADA -// http://www.rSCADA.se -// info@rscada.se -// -//------------------------------------------------------------------------------ - -/** - * @file mbus-protocol.h - * - * @brief Functions and data structures for M-Bus protocol parsing. - * - */ - -#ifndef _MBUS_PROTOCOL_H_ -#define _MBUS_PROTOCOL_H_ - -#include -#include -#include - -// -// Packet formats: -// -// ACK: size = 1 byte -// -// byte1: ack = 0xE5 -// -// SHORT: size = 5 byte -// -// byte1: start = 0x10 -// byte2: control = ... -// byte3: address = ... -// byte4: chksum = ... -// byte5: stop = 0x16 -// -// CONTROL: size = 9 byte -// -// byte1: start1 = 0x68 -// byte2: length1 = ... -// byte3: length2 = ... -// byte4: start2 = 0x68 -// byte5: control = ... -// byte6: address = ... -// byte7: ctl.info= ... -// byte8: chksum = ... -// byte9: stop = 0x16 -// -// LONG: size = N >= 9 byte -// -// byte1: start1 = 0x68 -// byte2: length1 = ... -// byte3: length2 = ... -// byte4: start2 = 0x68 -// byte5: control = ... -// byte6: address = ... -// byte7: ctl.info= ... -// byte8: data = ... -// ... = ... -// byteN-1: chksum = ... -// byteN: stop = 0x16 -// -// -// - -typedef struct _mbus_frame { - - u_char start1; - u_char length1; - u_char length2; - u_char start2; - u_char control; - u_char address; - u_char control_information; - // variable data field - u_char checksum; - u_char stop; - - u_char data[252]; - size_t data_size; - - int type; - time_t timestamp; - - //mbus_frame_data frame_data; - - void *next; // pointer to next mbus_frame for multi-telegram replies - -} mbus_frame; - -typedef struct _mbus_slave_data { - - int state_fcb; - int state_acd; - -} mbus_slave_data; - -#define NITEMS(x) (sizeof(x)/sizeof(x[0])) - -// -// Supported handle types -// -#define MBUS_HANDLE_TYPE_TCP 0 -#define MBUS_HANDLE_TYPE_SERIAL 1 - -//------------------------------------------------------------------------------ -// MBUS FRAME DATA FORMATS -// - -// DATA RECORDS -#define MBUS_DIB_DIF_EXTENSION_BIT 0x80 -#define MBUS_DIB_VIF_EXTENSION_BIT 0x80 - -typedef struct _mbus_data_information_block { - - u_char dif; - u_char dife[10]; - size_t ndife; - -} mbus_data_information_block; - -typedef struct _mbus_value_information_block { - - u_char vif; - u_char vife[10]; - size_t nvife; - - u_char custom_vif[128]; - -} mbus_value_information_block; - -typedef struct _mbus_data_record_header { - - mbus_data_information_block dib; - mbus_value_information_block vib; - -} mbus_data_record_header; - -typedef struct _mbus_data_record { - - mbus_data_record_header drh; - - u_char data[234]; - size_t data_len; - - time_t timestamp; - - void *next; - -} mbus_data_record; - -// -// HEADER FOR VARIABLE LENGTH DATA FORMAT -// -typedef struct _mbus_data_variable_header { - - //Ident.Nr. Manufr. Version Medium Access No. Status Signature - //4 Byte 2 Byte 1 Byte 1 Byte 1 Byte 1 Byte 2 Byte - - // ex - // 88 63 80 09 82 4D 02 04 15 00 00 00 - - u_char id_bcd[4]; // 88 63 80 09 - u_char manufacturer[2]; // 82 4D - u_char version; // 02 - u_char medium; // 04 - u_char access_no; // 15 - u_char status; // 00 - u_char signature[2]; // 00 00 - -} mbus_data_variable_header; - -// -// VARIABLE LENGTH DATA FORMAT -// -typedef struct _mbus_data_variable { - - mbus_data_variable_header header; - - mbus_data_record *record; - size_t nrecords; - - u_char *data; - size_t data_len; - - u_char more_records_follow; - - // are these needed/used? - u_char mdh; - u_char *mfg_data; - size_t mfg_data_len; - -} mbus_data_variable; - -// -// FIXED LENGTH DATA FORMAT -// -typedef struct _mbus_data_fixed { - - // ex - // 35 01 00 00 counter 2 = 135 l (historic value) - // - // e.g. - // - // 78 56 34 12 identification number = 12345678 - // 0A transmission counter = 0Ah = 10d - // 00 status 00h: counters coded BCD, actual values, no errors - // E9 7E Type&Unit: medium water, unit1 = 1l, unit2 = 1l (same, but historic) - // 01 00 00 00 counter 1 = 1l (actual value) - // 35 01 00 00 counter 2 = 135 l (historic value) - - u_char id_bcd[4]; - u_char tx_cnt; - u_char status; - u_char cnt1_type; - u_char cnt2_type; - u_char cnt1_val[4]; - u_char cnt2_val[4]; - -} mbus_data_fixed; - -// -// ABSTRACT DATA FORMAT (error, fixed or variable length) -// -#define MBUS_DATA_TYPE_FIXED 1 -#define MBUS_DATA_TYPE_VARIABLE 2 -#define MBUS_DATA_TYPE_ERROR 3 - -typedef struct _mbus_frame_data { - - mbus_data_variable data_var; - mbus_data_fixed data_fix; - - int type; - int error; - -} mbus_frame_data; - -// -// HEADER FOR SECONDARY ADDRESSING -// -typedef struct _mbus_data_secondary_address { - - //Ident.Nr. Manufr. Version Medium - //4 Byte 2 Byte 1 Byte 1 Byte - - // ex - // 14 49 10 01 10 57 01 06 - - u_char id_bcd[4]; // 14 49 10 01 - u_char manufacturer[2]; // 10 57 - u_char version; // 01 - u_char medium; // 06 - -} mbus_data_secondary_address; - - -// -// for compatibility with non-gcc compilers: -// -//#ifndef __PRETTY_FUNCTION__ -//#define __PRETTY_FUNCTION__ "libmbus" -//#endif - -//------------------------------------------------------------------------------ -// FRAME types -// -#define MBUS_FRAME_TYPE_ANY 0x00 -#define MBUS_FRAME_TYPE_ACK 0x01 -#define MBUS_FRAME_TYPE_SHORT 0x02 -#define MBUS_FRAME_TYPE_CONTROL 0x03 -#define MBUS_FRAME_TYPE_LONG 0x04 - -#define MBUS_FRAME_ACK_BASE_SIZE 1 -#define MBUS_FRAME_SHORT_BASE_SIZE 5 -#define MBUS_FRAME_CONTROL_BASE_SIZE 9 -#define MBUS_FRAME_LONG_BASE_SIZE 9 - -#define MBUS_FRAME_BASE_SIZE_ACK 1 -#define MBUS_FRAME_BASE_SIZE_SHORT 5 -#define MBUS_FRAME_BASE_SIZE_CONTROL 9 -#define MBUS_FRAME_BASE_SIZE_LONG 9 - -#define MBUS_FRAME_FIXED_SIZE_ACK 1 -#define MBUS_FRAME_FIXED_SIZE_SHORT 5 -#define MBUS_FRAME_FIXED_SIZE_CONTROL 6 -#define MBUS_FRAME_FIXED_SIZE_LONG 6 - -// -// Frame start/stop bits -// -#define MBUS_FRAME_ACK_START 0xE5 -#define MBUS_FRAME_SHORT_START 0x10 -#define MBUS_FRAME_CONTROL_START 0x68 -#define MBUS_FRAME_LONG_START 0x68 -#define MBUS_FRAME_STOP 0x16 - -// -// -// -#define MBUS_MAX_PRIMARY_SLAVES 256 - -// -// Control field -// -#define MBUS_CONTROL_FIELD_DIRECTION 0x07 -#define MBUS_CONTROL_FIELD_FCB 0x06 -#define MBUS_CONTROL_FIELD_ACD 0x06 -#define MBUS_CONTROL_FIELD_FCV 0x05 -#define MBUS_CONTROL_FIELD_DFC 0x05 -#define MBUS_CONTROL_FIELD_F3 0x04 -#define MBUS_CONTROL_FIELD_F2 0x03 -#define MBUS_CONTROL_FIELD_F1 0x02 -#define MBUS_CONTROL_FIELD_F0 0x01 - -#define MBUS_CONTROL_MASK_SND_NKE 0x40 -#define MBUS_CONTROL_MASK_SND_UD 0x53 -#define MBUS_CONTROL_MASK_REQ_UD2 0x5B -#define MBUS_CONTROL_MASK_REQ_UD1 0x5A -#define MBUS_CONTROL_MASK_RSP_UD 0x08 - -#define MBUS_CONTROL_MASK_FCB 0x20 -#define MBUS_CONTROL_MASK_FCV 0x10 - -#define MBUS_CONTROL_MASK_ACD 0x20 -#define MBUS_CONTROL_MASK_DFC 0x10 - -#define MBUS_CONTROL_MASK_DIR 0x40 -#define MBUS_CONTROL_MASK_DIR_M2S 0x40 -#define MBUS_CONTROL_MASK_DIR_S2M 0x00 - -// -// Address field -// -#define MBUS_ADDRESS_BROADCAST_REPLY 0xFE -#define MBUS_ADDRESS_BROADCAST_NOREPLY 0xFF -#define MBUS_ADDRESS_NETWORK_LAYER 0xFD - -// -// Control Information field -// -//Mode 1 Mode 2 Application Definition in -// 51h 55h data send EN1434-3 -// 52h 56h selection of slaves Usergroup July ́93 -// 50h application reset Usergroup March ́94 -// 54h synronize action suggestion -// B8h set baudrate to 300 baud Usergroup July ́93 -// B9h set baudrate to 600 baud Usergroup July ́93 -// BAh set baudrate to 1200 baud Usergroup July ́93 -// BBh set baudrate to 2400 baud Usergroup July ́93 -// BCh set baudrate to 4800 baud Usergroup July ́93 -// BDh set baudrate to 9600 baud Usergroup July ́93 -// BEh set baudrate to 19200 baud suggestion -// BFh set baudrate to 38400 baud suggestion -// B1h request readout of complete RAM content Techem suggestion -// B2h send user data (not standardized RAM write) Techem suggestion -// B3h initialize test calibration mode Usergroup July ́93 -// B4h EEPROM read Techem suggestion -// B6h start software test Techem suggestion -// 90h to 97h codes used for hashing longer recommended - -#define MBUS_CONTROL_INFO_DATA_SEND 0x51 -#define MBUS_CONTROL_INFO_DATA_SEND_MSB 0x55 -#define MBUS_CONTROL_INFO_SELECT_SLAVE 0x52 -#define MBUS_CONTROL_INFO_SELECT_SLAVE_MSB 0x56 -#define MBUS_CONTROL_INFO_APPLICATION_RESET 0x50 -#define MBUS_CONTROL_INFO_SYNC_ACTION 0x54 -#define MBUS_CONTROL_INFO_SET_BAUDRATE_300 0xB8 -#define MBUS_CONTROL_INFO_SET_BAUDRATE_600 0xB9 -#define MBUS_CONTROL_INFO_SET_BAUDRATE_1200 0xBA -#define MBUS_CONTROL_INFO_SET_BAUDRATE_2400 0xBB -#define MBUS_CONTROL_INFO_SET_BAUDRATE_4800 0xBC -#define MBUS_CONTROL_INFO_SET_BAUDRATE_9600 0xBD -#define MBUS_CONTROL_INFO_SET_BAUDRATE_19200 0xBE -#define MBUS_CONTROL_INFO_SET_BAUDRATE_38400 0xBF -#define MBUS_CONTROL_INFO_REQUEST_RAM_READ 0xB1 -#define MBUS_CONTROL_INFO_SEND_USER_DATA 0xB2 -#define MBUS_CONTROL_INFO_INIT_TEST_CALIB 0xB3 -#define MBUS_CONTROL_INFO_EEPROM_READ 0xB4 -#define MBUS_CONTROL_INFO_SW_TEST_START 0xB6 - -//Mode 1 Mode 2 Application Definition in -// 70h report of general application errors Usergroup March 94 -// 71h report of alarm status Usergroup March 94 -// 72h 76h variable data respond EN1434-3 -// 73h 77h fixed data respond EN1434-3 -#define MBUS_CONTROL_INFO_ERROR_GENERAL 0x70 -#define MBUS_CONTROL_INFO_STATUS_ALARM 0x71 - -#define MBUS_CONTROL_INFO_RESP_FIXED 0x73 -#define MBUS_CONTROL_INFO_RESP_FIXED_MSB 0x77 - -#define MBUS_CONTROL_INFO_RESP_VARIABLE 0x72 -#define MBUS_CONTROL_INFO_RESP_VARIABLE_MSB 0x76 - -// -// DATA BITS -// -#define MBUS_DATA_FIXED_STATUS_FORMAT_MASK 0x80 -#define MBUS_DATA_FIXED_STATUS_FORMAT_BCD 0x00 -#define MBUS_DATA_FIXED_STATUS_FORMAT_INT 0x80 -#define MBUS_DATA_FIXED_STATUS_DATE_MASK 0x40 -#define MBUS_DATA_FIXED_STATUS_DATE_STORED 0x40 -#define MBUS_DATA_FIXED_STATUS_DATE_CURRENT 0x00 - - -// -// data record fields -// -#define MBUS_DATA_RECORD_DIF_MASK_INST 0x00 -#define MBUS_DATA_RECORD_DIF_MASK_MIN 0x10 - -#define MBUS_DATA_RECORD_DIF_MASK_TYPE_INT32 0x04 -#define MBUS_DATA_RECORD_DIF_MASK_DATA 0x0F -#define MBUS_DATA_RECORD_DIF_MASK_FUNCTION 0x30 -#define MBUS_DATA_RECORD_DIF_MASK_STORAGE_NO 0x40 -#define MBUS_DATA_RECORD_DIF_MASK_EXTENTION 0x80 -#define MBUS_DATA_RECORD_DIF_MASK_NON_DATA 0xF0 - -// -// GENERAL APPLICATION ERRORS -// -#define MBUS_ERROR_DATA_UNSPECIFIED 0x00 -#define MBUS_ERROR_DATA_UNIMPLEMENTED_CI 0x01 -#define MBUS_ERROR_DATA_BUFFER_TOO_LONG 0x02 -#define MBUS_ERROR_DATA_TOO_MANY_RECORDS 0x03 -#define MBUS_ERROR_DATA_PREMATURE_END 0x04 -#define MBUS_ERROR_DATA_TOO_MANY_DIFES 0x05 -#define MBUS_ERROR_DATA_TOO_MANY_VIFES 0x06 -#define MBUS_ERROR_DATA_RESERVED 0x07 -#define MBUS_ERROR_DATA_APPLICATION_BUSY 0x08 -#define MBUS_ERROR_DATA_TOO_MANY_READOUTS 0x09 - -// -// FIXED DATA FLAGS -// - -// -// VARIABLE DATA FLAGS -// -#define MBUS_VARIABLE_DATA_MEDIUM_OTHER 0x00 -#define MBUS_VARIABLE_DATA_MEDIUM_OIL 0x01 -#define MBUS_VARIABLE_DATA_MEDIUM_ELECTRICITY 0x02 -#define MBUS_VARIABLE_DATA_MEDIUM_GAS 0x03 -#define MBUS_VARIABLE_DATA_MEDIUM_HEAT_OUT 0x04 -#define MBUS_VARIABLE_DATA_MEDIUM_STEAM 0x05 -#define MBUS_VARIABLE_DATA_MEDIUM_HOT_WATER 0x06 -#define MBUS_VARIABLE_DATA_MEDIUM_WATER 0x07 -#define MBUS_VARIABLE_DATA_MEDIUM_HEAT_COST 0x08 -#define MBUS_VARIABLE_DATA_MEDIUM_COMPR_AIR 0x09 -#define MBUS_VARIABLE_DATA_MEDIUM_COOL_OUT 0x0A -#define MBUS_VARIABLE_DATA_MEDIUM_COOL_IN 0x0B -#define MBUS_VARIABLE_DATA_MEDIUM_HEAT_IN 0x0C -#define MBUS_VARIABLE_DATA_MEDIUM_HEAT_COOL 0x0D -#define MBUS_VARIABLE_DATA_MEDIUM_BUS 0x0E -#define MBUS_VARIABLE_DATA_MEDIUM_UNKNOWN 0x0F -#define MBUS_VARIABLE_DATA_MEDIUM_COLD_WATER 0x16 -#define MBUS_VARIABLE_DATA_MEDIUM_DUAL_WATER 0x17 -#define MBUS_VARIABLE_DATA_MEDIUM_PRESSURE 0x18 -#define MBUS_VARIABLE_DATA_MEDIUM_ADC 0x19 - -#define MBUS_VARIABLE_DATA_MAN_ACW 0x0477 -#define MBUS_VARIABLE_DATA_MAN_ABB 0x0442 -#define MBUS_VARIABLE_DATA_MAN_AMT 0x05B4 -#define MBUS_VARIABLE_DATA_MAN_EFE 0x14C5 -#define MBUS_VARIABLE_DATA_MAN_ELS 0x1593 -#define MBUS_VARIABLE_DATA_MAN_EMH 0x15A8 -#define MBUS_VARIABLE_DATA_MAN_HYD 0x2324 -#define MBUS_VARIABLE_DATA_MAN_KAM 0x2C2D -#define MBUS_VARIABLE_DATA_MAN_LSE 0x3265 -#define MBUS_VARIABLE_DATA_MAN_LUG 0x32A7 -#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_SLB 0x4D82 -#define MBUS_VARIABLE_DATA_MAN_SON 0x4DEE -#define MBUS_VARIABLE_DATA_MAN_SPX 0x4E18 -#define MBUS_VARIABLE_DATA_MAN_SVM 0x4ECD -#define MBUS_VARIABLE_DATA_MAN_TCH 0x5068 -#define MBUS_VARIABLE_DATA_MAN_ZRM 0x6A4D - -// -// Event callback functions -// -extern void (*_mbus_recv_event)(u_char src_type, const char *buff, size_t len); -extern void (*_mbus_send_event)(u_char src_type, const char *buff, size_t len); - -void mbus_dump_recv_event(u_char src_type, const char *buff, size_t len); -void mbus_dump_send_event(u_char src_type, const char *buff, size_t len); - -// -// Event register functions -// -void mbus_register_recv_event(void (*event)(u_char src_type, const char *buff, size_t len)); -void mbus_register_send_event(void (*event)(u_char src_type, const char *buff, size_t len)); - -// -// variable length records -// -mbus_data_record *mbus_data_record_new(); -void mbus_data_record_free(mbus_data_record *record); -void mbus_data_record_append(mbus_data_variable *data, mbus_data_record *record); - - -// XXX: Add application reset subcodes - -mbus_frame *mbus_frame_new(int frame_type); -int mbus_frame_free(mbus_frame *frame); - -mbus_frame_data *mbus_frame_data_new(); -void mbus_frame_data_free(mbus_frame_data *data); - -// -// -// -int mbus_frame_calc_checksum(mbus_frame *frame); -int mbus_frame_calc_length (mbus_frame *frame); - -// -// Parse/Pack to bin -// -int mbus_parse(mbus_frame *frame, u_char *data, size_t data_size); - -int mbus_data_fixed_parse (mbus_frame *frame, mbus_data_fixed *data); -int mbus_data_variable_parse(mbus_frame *frame, mbus_data_variable *data); - -int mbus_frame_data_parse (mbus_frame *frame, mbus_frame_data *data); - -int mbus_frame_pack(mbus_frame *frame, u_char *data, size_t data_size); - -int mbus_frame_verify(mbus_frame *frame); - -int mbus_frame_internal_pack(mbus_frame *frame, mbus_frame_data *frame_data); - -// -// data parsing -// -const char *mbus_data_record_function(mbus_data_record *record); -const char *mbus_data_fixed_function(int status); - -// -// M-Bus frame data struct access/write functions -// -int mbus_frame_type(mbus_frame *frame); - -// -// Slave status data register. -// -mbus_slave_data *mbus_slave_data_get(size_t i); - -// -// XML generating functions -// -void mbus_str_xml_encode(u_char *dst, const u_char *src, size_t max_len); -char *mbus_data_xml(mbus_frame_data *data); -char *mbus_data_variable_xml(mbus_data_variable *data); -char *mbus_data_fixed_xml(mbus_data_fixed *data); -char *mbus_data_error_xml(int error); -char *mbus_frame_data_xml(mbus_frame_data *data); - -char *mbus_data_variable_header_xml(mbus_data_variable_header *header); - -char *mbus_frame_xml(mbus_frame *frame); - -// -// Debug/dump -// -int mbus_frame_print(mbus_frame *frame); -int mbus_frame_data_print(mbus_frame_data *data); -int mbus_data_fixed_print(mbus_data_fixed *data); -int mbus_data_error_print(int error); -int mbus_data_variable_header_print(mbus_data_variable_header *header); -int mbus_data_variable_print(mbus_data_variable *data); - -char *mbus_error_str(); -void mbus_error_str_set(char *message); -void mbus_error_reset(); - -void mbus_parse_set_debug(int debug); -void mbus_hex_dump(const char *label, const char *buff, size_t len); - -// -// data encode/decode functions -// -int mbus_data_manufacturer_encode(u_char *m_data, u_char *m_code); -const char *mbus_decode_manufacturer(u_char byte1, u_char byte2); -const char *mbus_data_product_name(mbus_data_variable_header *header); - -int mbus_data_bcd_encode(u_char *bcd_data, size_t bcd_data_size, int value); -int mbus_data_int_encode(u_char *int_data, size_t int_data_size, int value); - -long long mbus_data_bcd_decode(u_char *bcd_data, size_t bcd_data_size); -int mbus_data_int_decode(u_char *int_data, size_t int_data_size); -long mbus_data_long_decode(u_char *int_data, size_t int_data_size); -long long mbus_data_long_long_decode(u_char *int_data, size_t int_data_size); - -float mbus_data_float_decode(u_char *float_data); - -void mbus_data_tm_decode(struct tm *t, u_char *t_data, size_t t_data_size); - -void mbus_data_str_decode(u_char *dst, const u_char *src, size_t len); - -void mbus_data_bin_decode(u_char *dst, const u_char *src, size_t len, size_t max_len); - -const char *mbus_data_fixed_medium(mbus_data_fixed *data); -const char *mbus_data_fixed_unit(int medium_unit_byte); -const char *mbus_data_variable_medium_lookup(u_char medium); -const char *mbus_unit_prefix(int exp); - -const char *mbus_data_error_lookup(int error); - -const char *mbus_vib_unit_lookup(mbus_value_information_block *vib); -const char *mbus_vif_unit_lookup(u_char vif); - -u_char mbus_dif_datalength_lookup(u_char dif); - -char *mbus_frame_get_secondary_address(mbus_frame *frame); -int mbus_frame_select_secondary_pack(mbus_frame *frame, char *address); - -#endif /* _MBUS_PROTOCOL_H_ */ -