moved protocol dependent configuration to protocol sources
This commit is contained in:
parent
7cafc0f450
commit
eb09fd5a62
7 changed files with 174 additions and 103 deletions
|
@ -30,7 +30,7 @@
|
|||
|
||||
typedef struct {
|
||||
char *command;
|
||||
char *regex;
|
||||
char *format;
|
||||
} meter_handle_exec_t;
|
||||
|
||||
/* forward declarations */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
87
src/d0.c
87
src/d0.c
|
@ -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;
|
||||
}
|
||||
|
|
27
src/exec.c
27
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;
|
||||
}
|
||||
|
||||
|
|
27
src/s0.c
27
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) {
|
||||
|
|
108
src/sml.c
108
src/sml.c
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue