moved protocol dependent configuration to protocol sources

This commit is contained in:
Steffen Vogel 2011-12-05 21:42:57 +01:00
parent 7cafc0f450
commit eb09fd5a62
7 changed files with 174 additions and 103 deletions

View file

@ -30,7 +30,7 @@
typedef struct {
char *command;
char *regex;
char *format;
} meter_handle_exec_t;
/* forward declarations */

View file

@ -27,13 +27,13 @@
#define _S0_H_
#include <termios.h>
#include <signal.h>
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 */

View file

@ -35,29 +35,23 @@
#include <sml/sml_file.h>
#include <sml/sml_value.h>
#include <termios.h>
#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

View file

@ -11,7 +11,6 @@
* @license http://www.gnu.org/licenses/gpl.txt GNU Public License
* @author Steffen Vogel <info@steffenvogel.de>
* @author Mathias Dalheimer <md@gonium.net>
* based heavily on libehz (https://github.com/gonium/libehz.git)
*/
/*
* This file is part of volkzaehler.org
@ -34,11 +33,11 @@
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <sys/time.h>
/* socket */
#include <errno.h>
#include <netdb.h>
#include <sys/socket.h>
@ -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;
}

View file

@ -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;
}

View file

@ -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) {

108
src/sml.c
View file

@ -38,7 +38,6 @@
/* serial port */
#include <fcntl.h>
#include <sys/ioctl.h>
#include <termios.h>
/* socket */
#include <netdb.h>
@ -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;
}