diff --git a/bin/logger/src/configuration.c b/bin/logger/src/configuration.c index d92ee67..5651328 100644 --- a/bin/logger/src/configuration.c +++ b/bin/logger/src/configuration.c @@ -239,7 +239,7 @@ channel_t * parse_channel(struct json_object *jso) { else if (enabled == TRUE) { // TODO other identifiers are not supported at the moment reading_id_t id; - + // TODO: at present (2011-11-05) aliases for identifiers don't work because "lookup aliases" is not (re-)implemented yet in src/obis.c; for now, only the obis identifiers (like "1.8.0") are allowed, so if (obis_parse(&id.obis, identifier, strlen(identifier)) != 0) { print(-1, "Invalid identifier: %s", NULL, identifier); exit(EXIT_FAILURE); diff --git a/src/d0.c b/src/d0.c index a930a88..8db36a9 100644 --- a/src/d0.c +++ b/src/d0.c @@ -1,7 +1,7 @@ /** * Plaintext protocol according to DIN EN 62056-21 * - * This protocol uses OBIS to identify the readout data + * This protocol uses OBIS codes to identify the readout data * * This is our example protocol. Use this skeleton to add your own * protocols and meters. @@ -48,7 +48,8 @@ int meter_d0_open_socket(const char *node, const char *service) { struct sockaddr_in sin; struct addrinfo *ais; - int fd, res; + int fd; // file descriptor + int res; fd = socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { @@ -94,87 +95,101 @@ void meter_close_d0(meter_t *mtr) { close(handle->fd); } -size_t meter_read_d0(meter_t *mtr, reading_t rds[], size_t n) { +size_t meter_read_d0(meter_t *mtr, reading_t rds[], size_t max_readings) { meter_handle_d0_t *handle = &mtr->handle.d0; - enum { START, VENDOR, BAUD, IDENT, START_LINE, OBIS, VALUE, UNIT, END_LINE, END } context; + enum { START, VENDOR, BAUDRATE, IDENTIFICATION, START_LINE, OBIS_CODE, VALUE, UNIT, END_LINE, END } context; char vendor[3+1]; /* 3 upper case vendor + '\0' termination */ char identification[16+1]; /* 16 meter specific + '\0' termination */ - char id[16+1]; - char value[32+1]; - char unit[16+1]; + char obis_code[16+1]; /* A-B:C.D.E*F + fields A, B, E, F are optional + fields C & D are mandatory + A: energy type; 1: energy + B: channel number; 0: no channel specified + C: data items; 0-89 in COSEM context: IEC 62056-62, Clause D.1; 96: General service entries + 1: Totel Active power+ + 21: L1 Active power+ + 31: L1 Current + 32: L1 Voltage + 41: L2 Active power+ + 51: L2 Current + 52: L2 Voltage + 61: L3 Active power+ + 71: L3 Current + 72: L3 Voltage + 96.1.255: Metering point ID 256 (electricity related) + 96.5.5: Meter started status flag + D: types + E: further processing or classification of quantities + F: storage of data + see DIN-EN-62056-61 */ + char value[32+1]; /* value, i.e. the actual reading */ + char unit[16+1]; /* the unit of the value, e.g. kWh, V, ... */ - char baudrate; /* 1 byte */ - char byte; - int j, k, m; + char baudrate; /* 1 byte for */ + char byte; /* we parse our input byte wise */ + int byte_iterator; + int number_of_tuples; - j = k = m = baudrate = 0; + byte_iterator = number_of_tuples = baudrate = 0; - context = START; + context = START; /* start with context START */ while (read(handle->fd, &byte, 1)) { - if (byte == '/') context = START; - else if (byte == '!') context = END; - + if (byte == '/') context = START; /* reset to START if "/" reoccurs */ + else if (byte == '!') context = END; /* "!" is the identifier for the END */ switch (context) { - case START: - if (byte == '/') { - j = k = m = 0; - context = VENDOR; - printf("reset!!!\n"); - } + case START: /* strip the initial "/" */ + byte_iterator = number_of_tuples = 0; /* start */ + context = VENDOR; /* set new context: START -> VENDOR */ break; - case VENDOR: - if (!isalpha(byte)) goto error; - else vendor[j++] = byte; + case VENDOR: /* VENDOR has 3 Bytes */ + if (!isalpha(byte)) goto error; /* Vendor ID needs to be alpha */ + vendor[byte_iterator++] = byte; /* read next byte */ + if (byte_iterator >= 3) { /* stop after 3rd byte */ + vendor[byte_iterator] = '\0'; /* termination */ + byte_iterator = 0; /* reset byte counter */ - if (j >= 3) { - vendor[j] = '\0'; /* termination */ - j = k = 0; - - context = BAUD; - } + context = BAUDRATE; /* set new context: VENDOR -> BAUDRATE */ + } break; - case BAUD: - baudrate = byte; - context = IDENT; - j = k = 0; + case BAUDRATE: /* BAUDRATE consists of 1 char only */ + baudrate = byte; + context = IDENTIFICATION; /* set new context: BAUDRATE -> IDENTIFICATION */ + byte_iterator = 0; break; - case IDENT: - /* Data block starts after twice a '\r\n' sequence */ - /* b= CR LF CR LF */ - /* k= 1 2 3 4 */ - if (byte == '\r' || byte == '\n') { - k++; - if (k >= 4) { - identification[j] = '\0'; /* termination */ - j = k = 0; - - context = START_LINE; - } + case IDENTIFICATION: /* IDENTIFICATION has 16 bytes */ + if (byte == '\r' || byte == '\n') { /* detect line end */ + identification[byte_iterator] = '\0'; /* termination */ + context = OBIS_CODE; /* set new context: IDENTIFICATION -> OBIS_CODE */ + byte_iterator = 0; } - else identification[j++] = byte; + else identification[byte_iterator++] = byte; break; case START_LINE: - case OBIS: - if (byte == '(') { - id[j] = '\0'; - j = k = 0; + break; + case OBIS_CODE: + if ((byte != '\n') && (byte != '\r')) + { + if (byte == '(') { + obis_code[byte_iterator] = '\0'; + byte_iterator = 0; - context = VALUE; + context = VALUE; + } + else obis_code[byte_iterator++] = byte; } - else id[j++] = byte; break; case VALUE: if (byte == '*' || byte == ')') { - value[j] = '\0'; - j = k = 0; + value[byte_iterator] = '\0'; + byte_iterator = 0; if (byte == ')') { unit[0] = '\0'; @@ -184,41 +199,38 @@ size_t meter_read_d0(meter_t *mtr, reading_t rds[], size_t n) { context = UNIT; } } - else value[j++] = byte; + else value[byte_iterator++] = byte; break; case UNIT: if (byte == ')') { - unit[j] = '\0'; - j = k = 0; + unit[byte_iterator] = '\0'; + byte_iterator = 0; context = END_LINE; } - else unit[j++] = byte; + else unit[byte_iterator++] = byte; break; case END_LINE: if (byte == '\r' || byte == '\n') { - k++; - if (k >= 2) { - if (m < n) { /* free slots available? */ - printf("parsed reading (id=%s, value=%s, unit=%s)\n", id, value, unit); - rds[m].value = strtof(value, NULL); - obis_parse(&rds[m].identifier.obis, id, strlen(id)); - gettimeofday(&rds[m].time, NULL); + if ((number_of_tuples < max_readings) && (strlen(obis_code) > 0) && (strlen(value) > 0)) { /* free slots available and sain content? */ + printf("parsed reading (OBIS code=%s, value=%s, unit=%s)\n", obis_code, value, unit); + rds[number_of_tuples].value = strtof(value, NULL); + obis_parse(&rds[number_of_tuples].identifier.obis, obis_code, strlen(obis_code)); + gettimeofday(&rds[number_of_tuples].time, NULL); - j = k = 0; - m++; - } + byte_iterator = 0; + number_of_tuples++; - context = START_LINE; + context = OBIS_CODE; } } break; case END: - printf("read package with %i tuples (vendor=%s, baudrate=%c, ident=%s)\n", m, vendor, baudrate, identification); - return m; + printf("read package with %i tuples (vendor=%s, baudrate=%c, identification=%s)\n", number_of_tuples, vendor, baudrate, identification); + return number_of_tuples; } } diff --git a/src/obis.c b/src/obis.c index 26ec8d7..94d657b 100644 --- a/src/obis.c +++ b/src/obis.c @@ -103,11 +103,11 @@ obis_id_t * obis_init(obis_id_t *id, const unsigned char *raw) { int obis_parse(obis_id_t *id, const char *str, size_t n) { enum { A = 0, B, C, D, E, F }; - char b; + char byte; //currently processed Byte int num; int field; - num = b = 0; + num = byte = 0; field = -1; memset(&id->raw, 0xff, 6); /* initialize as wildcard */ @@ -115,22 +115,22 @@ int obis_parse(obis_id_t *id, const char *str, size_t n) { /* fields A, B, E, F are optional */ /* fields C & D are mandatory */ for (int i = 0; i < n; i++) { - b = str[i]; + byte = str[i]; - if (isdigit(b)) { - num = (num * 10) + (b - '0'); /* parse digits */ + if (isdigit(byte)) { + num = (num * 10) + (byte - '0'); /* parse digits */ } else { - if (b == '-' && field < A) { /* end of field A */ + if (byte == '-' && field < A) { /* end of field A */ field = A; } - else if (b == ':' && field < B) { /* end of field B */ + else if (byte == ':' && field < B) { /* end of field B */ field = B; } - else if (b == '.' && field < D) { /* end of field C & D*/ + else if (byte == '.' && field < D) { /* end of field C & D*/ field = (field < C) ? C : D; } - else if ((b == '*' || b == '&') && field == D) { /* end of field E, start of field F */ + else if ((byte == '*' || byte == '&') && field == D) { /* end of field E, start of field F */ field = E; } else goto error; // TODO lookup aliases @@ -149,7 +149,7 @@ int obis_parse(obis_id_t *id, const char *str, size_t n) { return 0; error: - printf("something unexpected happened (field=%i, b=%c, num=%i): %s:%i!\n", field, b, num, __FUNCTION__, __LINE__); + printf("something unexpected happened (field=%i, byte=%c, num=%i): %s:%i!\n", field, byte, num, __FUNCTION__, __LINE__); return -1; }