diff --git a/bin/logger/include/configuration.h b/bin/logger/include/configuration.h deleted file mode 100644 index cd4c205..0000000 --- a/bin/logger/include/configuration.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Parsing commandline options and channel list - * - * @author Steffen Vogel - * @copyright Copyright (c) 2011, The volkszaehler.org project - * @package vzlogger - * @license http://opensource.org/licenses/gpl-license.php GNU Public License - */ -/* - * This file is part of volkzaehler.org - * - * volkzaehler.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * volkzaehler.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with volkszaehler.org. If not, see . - */ - -#ifndef _CONFIGURATION_H_ -#define _CONFIGURATION_H_ - -#include - -#include "channel.h" -#include "list.h" -#include "vzlogger.h" - -void parse_configuration(char *filename, list_t *assocs, options_t *opts); -channel_t * parse_channel(struct json_object *jso); -assoc_t * parse_meter(struct json_object *jso); - -int check_type(char *key, struct json_object *jso, enum json_type type); - -#endif /* _CONFIGURATION_H_ */ diff --git a/bin/logger/include/list.h b/bin/logger/include/list.h deleted file mode 100644 index 2b7e79f..0000000 --- a/bin/logger/include/list.h +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Generic linked list - * - * @package vzlogger - * @copyright Copyright (c) 2011, The volkszaehler.org project - * @license http://www.gnu.org/licenses/gpl.txt GNU Public License - * @author Steffen Vogel - */ -/* - * This file is part of volkzaehler.org - * - * volkzaehler.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * volkzaehler.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with volkszaehler.org. If not, see . - */ - -#ifndef _LIST_H_ -#define _LIST_H_ - -#include - -#define foreach(list, it) \ - for( \ - __list_item_t *(it) = (list).head; \ - (it) != NULL; \ - (it) = (it)->next \ - ) \ - -typedef struct __list_item { - void *data; - struct __list_item *prev; - struct __list_item *next; -} __list_item_t; - -typedef struct { - int size; - __list_item_t *head; - __list_item_t *tail; -} list_t; - -inline void list_init(list_t *list) { - list->size = 0; - list->head = list->tail = NULL; -} - -inline int list_push(list_t *list, void *data) { - __list_item_t *new = malloc(sizeof(__list_item_t)); - - if (new == NULL) return -1; /* cannot allocate memory */ - - new->data = data; - new->prev = list->tail; - new->next = NULL; - - if (list->tail == NULL) { - list->head = new; - } - else { - list->tail->next = new; - } - - list->tail = new; - list->size = list->size + 1; - - return list->size; -} - -inline void * list_pop(list_t *list) { - __list_item_t *old = list->tail; - - if (old == NULL) { - return NULL; - } - - void *data = old->data; - - list->tail = old->prev; - list->size--; - - free(old); - - return data; -} - -inline void list_free(list_t *list) { - while (list->head != NULL) { - __list_item_t *old = list->head; - list->head = old->next; - - free(old->data); - free(old); - } - - list->size = 0; - list->tail = NULL; -} - -#endif /* _LIST_H_ */ 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/include/onewire.h b/include/onewire.h deleted file mode 100644 index 1d0006d..0000000 --- a/include/onewire.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Wrapper to read Dallas 1-wire Sensors via the 1-wire Filesystem (owfs) - * - * @package vzlogger - * @copyright Copyright (c) 2011, The volkszaehler.org project - * @license http://www.gnu.org/licenses/gpl.txt GNU Public License - * @author Steffen Vogel - */ -/* - * This file is part of volkzaehler.org - * - * volkzaehler.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * volkzaehler.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with volkszaehler.org. If not, see . - */ - -#ifndef _ONEWIRE_H_ -#define _ONEWIRE_H_ - -#include - -typedef struct { - FILE *file; -} meter_handle_onewire_t; - -struct meter; /* forward declaration */ -struct reading; /* forward declaration */ - -int meter_open_onewire(struct meter *mtr); -void meter_close_onewire(struct meter *mtr); -size_t meter_read_onewire(struct meter *mtr, struct reading *rds, size_t n); - -#endif /* _ONEWIRE_H_ */ diff --git a/src/d0.c b/src/d0.c index afdff39..fecd4a2 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. @@ -50,7 +50,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) { @@ -116,86 +117,101 @@ int meter_close_d0(meter_t *mtr) { return 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; - } + 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'; @@ -205,41 +221,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(id, &rds[m].identifier.obis); - 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(obis_code, &rds[number_of_tuples].identifier.obis); + 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: - print(log_info, "Read package with %i tuples (vendor=%s, baudrate=%c, ident=%s)", mtr, m, vendor, baudrate, identification); - return m; + print(log_debug, "Read package with %i tuples (vendor=%s, baudrate=%c, identification=%s)", mtr, number_of_tuples, vendor, baudrate, identification); + return number_of_tuples; } } diff --git a/src/obis.c b/src/obis.c index 6bcf46c..b0df1f4 100644 --- a/src/obis.c +++ b/src/obis.c @@ -105,33 +105,35 @@ obis_id_t * obis_init(obis_id_t *id, unsigned char *raw) { int obis_parse(const char *str, obis_id_t *id) { enum { A = 0, B, C, D, E, F }; - char b = 0; - int num = 0; - int field = -1; - size_t n = strlen(str); + char byte; /* currently processed byte */ + int num; + int field; + int len = strlen(str); - memset(&id->raw, DC, 6); /* initialize as wildcard */ + num = byte = 0; + field = -1; + memset(&id->raw, 0xff, 6); /* initialize as wildcard */ /* format: "A-B:C.D.E[*&]F" */ /* fields A, B, E, F are optional */ /* fields C & D are mandatory */ - for (int i = 0; i < n; i++) { - b = str[i]; + for (int i = 0; i < len; 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 { diff --git a/src/onewire.c b/src/onewire.c deleted file mode 100644 index 346e8d3..0000000 --- a/src/onewire.c +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Wrapper to read Dallas 1-wire Sensors via the 1-wire Filesystem (owfs) - * - * @package vzlogger - * @copyright Copyright (c) 2011, The volkszaehler.org project - * @license http://www.gnu.org/licenses/gpl.txt GNU Public License - * @author Steffen Vogel - */ -/* - * This file is part of volkzaehler.org - * - * volkzaehler.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * volkzaehler.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with volkszaehler.org. If not, see . - */ - -#include - -#include "meter.h" -#include "onewire.h" - -/** - * Initialize sensor - * - * @param address path to the sensor in the owfs - * @return pointer to file descriptor - */ -int meter_open_onewire(meter_t *mtr) { - meter_handle_onewire_t *handle = &mtr->handle.onewire; - - handle->file = fopen(mtr->connection, "r"); - - return (handle->file == NULL) ? -1 : 0; -} - -void meter_close_onewire(meter_t *mtr) { - meter_handle_onewire_t *handle = &mtr->handle.onewire; - - fclose(handle->file); -} - -size_t meter_read_onewire(meter_t *mtr, reading_t rds[], size_t n) { - meter_handle_onewire_t *handle = &mtr->handle.onewire; - - char buffer[16]; - int bytes; - - do { - rewind(handle->file); - bytes = fread(buffer, 1, 16, handle->file); - buffer[bytes] = '\0'; /* zero terminated, required? */ - - if (bytes) { - rds->value = strtof(buffer, NULL); - gettimeofday(&rds->time, NULL); - } - } while (rds->value == 85); /* skip invalid readings */ - - return 1; -}