diff --git a/include/exec.h b/include/exec.h index e037b22..71494af 100644 --- a/include/exec.h +++ b/include/exec.h @@ -30,7 +30,7 @@ typedef struct { char *command; - char *regex; + char *format; } meter_handle_exec_t; /* forward declarations */ diff --git a/include/s0.h b/include/s0.h index 43d42e2..27e7b73 100644 --- a/include/s0.h +++ b/include/s0.h @@ -27,13 +27,13 @@ #define _S0_H_ #include -#include typedef struct { char *device; + int resolution; - int fd; /* file descriptor of port */ - struct termios oldtio; /* required to reset port */ + int fd; /* file descriptor of port */ + struct termios old_tio; /* required to reset port */ } meter_handle_s0_t; /* forward declarations */ diff --git a/include/sml.h b/include/sml.h index 90e67b7..9169a5e 100644 --- a/include/sml.h +++ b/include/sml.h @@ -35,29 +35,23 @@ #include #include +#include + #include "obis.h" typedef struct { char *host; char *device; - int baudrate; + speed_t baudrate; - int fd; - //termios old_tio; + int fd; /* file descriptor of port */ + struct termios old_tio; /* required to reset port */ } meter_handle_sml_t; /* forward declarations */ struct meter; struct reading; -/** - * Cast arbitrary sized sml_value to double - * - * @param value the sml_value which should be casted - * @return double value representation of sml_value, NAN if an error occured - */ -double sml_value_todouble(sml_value *value); - /** * Initialize meter structure with a list of options * @@ -107,9 +101,11 @@ void meter_sml_parse(sml_list *list, struct reading *rd); * Open serial port by device * * @param device the device path, usually /dev/ttyS* + * @param old_config pointer to termios structure, will be filled with old port configuration + * @param baudrate the baudrate * @return file descriptor, <0 on error */ -int meter_sml_open_port(const char *device); +int meter_sml_open_device(const char *device, struct termios *old_config, speed_t baudrate); /** * Open socket diff --git a/src/d0.c b/src/d0.c index fecd4a2..1f4ee8a 100644 --- a/src/d0.c +++ b/src/d0.c @@ -11,7 +11,6 @@ * @license http://www.gnu.org/licenses/gpl.txt GNU Public License * @author Steffen Vogel * @author Mathias Dalheimer - * based heavily on libehz (https://github.com/gonium/libehz.git) */ /* * This file is part of volkzaehler.org @@ -34,11 +33,11 @@ #include #include #include +#include #include #include /* socket */ -#include #include #include @@ -47,47 +46,33 @@ #include "obis.h" #include "options.h" -int meter_d0_open_socket(const char *node, const char *service) { - struct sockaddr_in sin; - struct addrinfo *ais; - int fd; // file descriptor - int res; - - fd = socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - print(log_error, "socket(): %s", NULL, strerror(errno)); - return ERR; - } - - getaddrinfo(node, service, NULL, &ais); - memcpy(&sin, ais->ai_addr, ais->ai_addrlen); - freeaddrinfo(ais); - - res = connect(fd, (struct sockaddr *) &sin, sizeof(sin)); - if (res < 0) { - print(log_error, "connect(%s, %s): %s", NULL, node, service, strerror(errno)); - return ERR; - } - - return fd; -} - int meter_init_d0(meter_t *mtr, list_t options) { meter_handle_d0_t *handle = &mtr->handle.d0; /* connection */ - handle->host = NULL; - handle->device = NULL; - if (options_lookup_string(options, "host", &handle->host) != SUCCESS && options_lookup_string(options, "device", &handle->device) != SUCCESS) { - print(log_error, "Missing host or port", mtr); + char *host, *device; + if (options_lookup_string(options, "host", &host) == SUCCESS) { + handle->host = strdup(host); + handle->device = NULL; + } + else if (options_lookup_string(options, "device", &device) == SUCCESS) { + handle->device = strdup(device); + handle->host = NULL; + } + else { + print(log_error, "Missing host and port", mtr); return ERR; } /* baudrate */ - handle->baudrate = 9600; - if (options_lookup_int(options, "baudrate", &handle->baudrate) == ERR_INVALID_TYPE) { - print(log_error, "Invalid type for baudrate", mtr); - return ERR; + switch (options_lookup_int(options, "baudrate", &handle->baudrate)) { + case ERR_NOT_FOUND: /* using default value if not specified */ + handle->baudrate = 9600; + break; + + default: + print(log_error, "Failed to parse the baudrate", mtr); + return ERR; } return SUCCESS; @@ -236,8 +221,9 @@ size_t meter_read_d0(meter_t *mtr, reading_t rds[], size_t max_readings) { case END_LINE: if (byte == '\r' || byte == '\n') { - 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); + /* free slots available and sain content? */ + if ((number_of_tuples < max_readings) && (strlen(obis_code) > 0) && (strlen(value) > 0)) { + print(log_debug, "Parsed reading (OBIS code=%s, value=%s, unit=%s)", mtr, 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); @@ -251,7 +237,8 @@ size_t meter_read_d0(meter_t *mtr, reading_t rds[], size_t max_readings) { break; case END: - print(log_debug, "Read package with %i tuples (vendor=%s, baudrate=%c, identification=%s)", mtr, number_of_tuples, vendor, baudrate, identification); + 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; } } @@ -261,3 +248,27 @@ error: return 0; } +int meter_d0_open_socket(const char *node, const char *service) { + struct sockaddr_in sin; + struct addrinfo *ais; + int fd; /* file descriptor */ + int res; + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + print(log_error, "socket(): %s", NULL, strerror(errno)); + return ERR; + } + + getaddrinfo(node, service, NULL, &ais); + memcpy(&sin, ais->ai_addr, ais->ai_addrlen); + freeaddrinfo(ais); + + res = connect(fd, (struct sockaddr *) &sin, sizeof(sin)); + if (res < 0) { + print(log_error, "connect(%s, %s): %s", NULL, node, service, strerror(errno)); + return ERR; + } + + return fd; +} diff --git a/src/exec.c b/src/exec.c index 820b8d7..d4ae8c8 100644 --- a/src/exec.c +++ b/src/exec.c @@ -1,5 +1,5 @@ /** - * Get data by calling programs + * Get data by calling a program * * @package vzlogger * @copyright Copyright (c) 2011, The volkszaehler.org project @@ -33,17 +33,32 @@ int meter_init_exec(meter_t *mtr, list_t options) { meter_handle_exec_t *handle = &mtr->handle.exec; - if (options_lookup_string(options, "command", &handle->command) != SUCCESS) { + char *command; + if (options_lookup_string(options, "command", &command) == SUCCESS) { + handle->command = strdup(command); + } + else { print(log_error, "Missing command or invalid type", mtr); return ERR; } - handle->regex = NULL; - if (options_lookup_string(options, "regex", &handle->regex) == ERR_INVALID_TYPE) { - print(log_error, "Regex has to be a string", mtr); - return ERR; + char *format; + switch (options_lookup_string(options, "format", &format)) { + case SUCCESS: + handle->format = strdup(format); + // TODO parse format (see file.c) + break; + + case ERR_NOT_FOUND: + handle->format = NULL; /* use default format */ + break; + + default: + print(log_error, "Failed to parse format", mtr); + return ERR; } + return SUCCESS; } diff --git a/src/s0.c b/src/s0.c index 6f853ca..9a191fb 100644 --- a/src/s0.c +++ b/src/s0.c @@ -37,17 +37,28 @@ int meter_init_s0(meter_t *mtr, list_t options) { meter_handle_s0_t *handle = &mtr->handle.s0; - if (options_lookup_string(options, "device", &handle->device) != SUCCESS) { + char *device; + if (options_lookup_string(options, "device", &device) == SUCCESS) { + handle->device = strdup(device); + } + else { print(log_error, "Missing device or invalid type", mtr); return ERR; } + switch (options_lookup_int(options, "resolution", &handle->resolution)) { + case ERR_NOT_FOUND: + handle->resolution = 1; /* 1 Wh per impulse */ + break; + + case ERR_INVALID_TYPE: + print(log_error, "Failed to parse resolution", mtr); + return ERR; + } + return SUCCESS; } -/** - * Setup serial port - */ int meter_open_s0(meter_t *mtr) { meter_handle_s0_t *handle = &mtr->handle.s0; @@ -60,7 +71,7 @@ int meter_open_s0(meter_t *mtr) { } /* save current port settings */ - tcgetattr(fd, &handle->oldtio); + tcgetattr(fd, &handle->old_tio); /* configure port */ struct termios tio; @@ -85,11 +96,9 @@ int meter_open_s0(meter_t *mtr) { int meter_close_s0(meter_t *mtr) { meter_handle_s0_t *handle = &mtr->handle.s0; - /* reset serial port */ - tcsetattr(handle->fd, TCSANOW, &handle->oldtio); + tcsetattr(handle->fd, TCSANOW, &handle->old_tio); /* reset serial port */ - /* close serial port */ - return close(handle->fd); + return close(handle->fd); /* close serial port */ } size_t meter_read_s0(meter_t *mtr, reading_t rds[], size_t n) { diff --git a/src/sml.c b/src/sml.c index f39096d..f62e5de 100644 --- a/src/sml.c +++ b/src/sml.c @@ -38,7 +38,6 @@ /* serial port */ #include #include -#include /* socket */ #include @@ -57,18 +56,49 @@ int meter_init_sml(meter_t *mtr, list_t options) { meter_handle_sml_t *handle = &mtr->handle.sml; /* connection */ - handle->host = NULL; - handle->device = NULL; - if (options_lookup_string(options, "host", &handle->host) != SUCCESS && options_lookup_string(options, "device", &handle->device) != SUCCESS) { - print(log_error, "Missing host or port", mtr); + char *host, *device; + if (options_lookup_string(options, "host", &host) == SUCCESS) { + handle->host = strdup(host); + handle->device = NULL; + } + else if (options_lookup_string(options, "device", &device) == SUCCESS) { + handle->device = strdup(device); + handle->host = NULL; + } + else { + print(log_error, "Missing host and port", mtr); return ERR; } /* baudrate */ - handle->baudrate = 9600; - if (options_lookup_int(options, "baudrate", &handle->baudrate) == ERR_INVALID_TYPE) { - print(log_error, "Invalid type for baudrate", mtr); - return ERR; + int baudrate; + switch (options_lookup_int(options, "baudrate", &baudrate)) { + case SUCCESS: + /* find constant for termios structure */ + switch (baudrate) { + case 1200: handle->baudrate = B1200; break; + case 1800: handle->baudrate = B1800; break; + case 2400: handle->baudrate = B2400; break; + case 4800: handle->baudrate = B4800; break; + case 9600: handle->baudrate = B9600; break; + case 19200: handle->baudrate = B19200; break; + case 38400: handle->baudrate = B38400; break; + case 57600: handle->baudrate = B57600; break; + case 115200: handle->baudrate = B115200; break; + case 230400: handle->baudrate = B230400; break; + default: + print(log_error, "Invalid baudrate: %i", mtr, baudrate); + return ERR; + } + break; + + case ERR_NOT_FOUND: /* using default value if not specified */ + handle->baudrate = B9600; + break; + + default: + print(log_error, "Failed to parse the baudrate", mtr); + return ERR; } return SUCCESS; @@ -77,16 +107,17 @@ int meter_init_sml(meter_t *mtr, list_t options) { int meter_open_sml(meter_t *mtr) { meter_handle_sml_t *handle = &mtr->handle.sml; - if (handle->device != NULL) { - print(log_error, "TODO: implement serial interface", mtr); - return ERR; + if (handle->device != NULL) { /* local connection */ + handle->fd = meter_sml_open_device(handle->device, &handle->old_tio, handle->baudrate); } - else if (handle->host != NULL) { + else if (handle->host != NULL) { /* remote connection */ char *addr = strdup(handle->host); - char *node = strsep(&addr, ":"); + char *node = strsep(&addr, ":"); /* split port/service from hostname */ char *service = strsep(&addr, ":"); handle->fd = meter_sml_open_socket(node, service); + + free(addr); } return (handle->fd < 0) ? ERR : SUCCESS; @@ -95,7 +126,11 @@ int meter_open_sml(meter_t *mtr) { int meter_close_sml(meter_t *meter) { meter_handle_sml_t *handle = &meter->handle.sml; - // TODO reset serial port + if (handle->device != NULL) { + /* reset serial port */ + tcsetattr(handle->fd, TCSANOW, &handle->old_tio); + } + return close(handle->fd); } @@ -109,7 +144,7 @@ size_t meter_read_sml(meter_t *meter, reading_t rds[], size_t n) { sml_get_list_response *body; sml_list *entry; - /* blocking read from fd */ + /* wait until a we receive a new datagram from the meter (blocking read) */ bytes = sml_transport_read(handle->fd, buffer, SML_BUFFER_LEN); /* parse SML file & stripping escape sequences */ @@ -145,14 +180,13 @@ void meter_sml_parse(sml_list *entry, reading_t *rd) { obis_init(&rd->identifier.obis, entry->obj_name->str); - /* get time */ // TODO handle SML_TIME_SEC_INDEX or time by SML File/Message - if (entry->val_time) { + if (entry->val_time) { /* use time from meter */ rd->time.tv_sec = *entry->val_time->data.timestamp; rd->time.tv_usec = 0; } else { - gettimeofday(&rd->time, NULL); + gettimeofday(&rd->time, NULL); /* use local time */ } } @@ -180,10 +214,10 @@ int meter_sml_open_socket(const char *node, const char *service) { return fd; } -int meter_sml_open_port(const char *device) { +int meter_sml_open_device(const char *device, struct termios *old_tio, speed_t baudrate) { int bits; - struct termios config; - memset(&config, 0, sizeof(config)); + struct termios tio; + memset(&tio, 0, sizeof(struct termios)); int fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); if (fd < 0) { @@ -191,24 +225,30 @@ int meter_sml_open_port(const char *device) { return ERR; } - // set RTS + /* enable RTS as supply for infrared adapters */ ioctl(fd, TIOCMGET, &bits); bits |= TIOCM_RTS; ioctl(fd, TIOCMSET, &bits); - tcgetattr(fd, &config) ; + /* get old configuration */ + tcgetattr(fd, &tio) ; - // set 8-N-1 - config.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); - config.c_oflag &= ~OPOST; - config.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - config.c_cflag &= ~(CSIZE | PARENB | PARODD | CSTOPB); - config.c_cflag |= CS8; + /* backup old configuration to restore it when closing the meter connection */ + memcpy(old_tio, &tio, sizeof(struct termios)); - // set speed to 9600 baud - cfsetispeed( &config, B9600); - cfsetospeed( &config, B9600); + /* set 8-N-1 */ + tio.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + tio.c_oflag &= ~OPOST; + tio.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + tio.c_cflag &= ~(CSIZE | PARENB | PARODD | CSTOPB); + tio.c_cflag |= CS8; + + /* set baudrate */ + cfsetispeed(&tio, baudrate); + cfsetospeed(&tio, baudrate); + + /* apply new configuration */ + tcsetattr(fd, TCSANOW, &tio); - tcsetattr(fd, TCSANOW, &config); return fd; }