splittet reading related stuff into extra file

This commit is contained in:
Steffen Vogel 2012-01-19 18:03:09 +01:00
parent e140190402
commit a04c73764e
5 changed files with 429 additions and 29 deletions

44
include/fluksov2.h Normal file
View file

@ -0,0 +1,44 @@
/**
* Replacement for fluksod by directly parsing the fluksometers SPI output
*
* @package vzlogger
* @copyright Copyright (c) 2011, The volkszaehler.org project
* @license http://www.gnu.org/licenses/gpl.txt GNU Public License
* @author Steffen Vogel <info@steffenvogel.de>
*/
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _FLUKSOV2_H_
#define _FLUKSOV2_H_
typedef struct {
char *fifo;
int fd; /* file descriptor of fifo */
} meter_handle_fluksov2_t;
/* forward declarations */
struct meter;
struct reading;
int meter_init_fluksov2(struct meter *mtr, list_t options);
int meter_open_fluksov2(struct meter *mtr);
int meter_close_fluksov2(struct meter *mtr);
size_t meter_read_fluksov2(struct meter *mtr, struct reading *rds, size_t n);
#endif /* _FLUKSOV2_H_ */

91
include/reading.h Normal file
View file

@ -0,0 +1,91 @@
/**
* Reading related functions
*
* @package vzlogger
* @copyright Copyright (c) 2011, The volkszaehler.org project
* @license http://www.gnu.org/licenses/gpl.txt GNU Public License
* @author Steffen Vogel <info@steffenvogel.de>
*/
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _READING_H_
#define _READING_H_
#include "obis.h"
#define MAX_IDENTIFIER_LEN 255
typedef union reading_id {
obis_id_t obis;
char *string;
char *uuid;
int channel;
} reading_id_t;
typedef struct reading {
double value;
struct timeval time;
reading_id_t identifier;
struct reading *next; /* pointer for linked list */
} reading_t;
/* prototypes */
enum meter_procotol; /* forward declaration */
/**
* Parse two reading identifiers in a given protocol context
*
* @return result like in strcmp()
*/
int meter_id_compare(enum meter_procotol, reading_id_t a, reading_id_t b);
/**
* Parse identifier by a given string and protocol
*
* @param protocol the given protocol context in which the string should be parsed
* @param string the string-encoded identifier
* @return 0 on success, < 0 on error
*/
int reading_id_parse(enum meter_procotol protocol, reading_id_t *id, const char *string);
/**
* Print identifier to buffer for debugging/dump
*
* @return the amount of bytes used in buffer
*/
size_t reading_id_unparse(enum meter_procotol protocol, reading_id_t identifier, char *buffer, size_t n);
/**
* Converts timeval structure to double
*
* @param tv the timeval structure
* @return the double value
*/
double tvtod(struct timeval tv);
/**
* Converts double to timeval structure
*
* @param ts the double value
* @return the timeval strucure
*/
struct timeval dtotv(double ts);
#endif /* _READING_H_ */

145
src/fluksov2.c Normal file
View file

@ -0,0 +1,145 @@
/**
* Parsing SPI output of the new fluksometer
*
* @package vzlogger
* @copyright Copyright (c) 2011, The volkszaehler.org project
* @license http://www.gnu.org/licenses/gpl.txt GNU Public License
* @author Steffen Vogel <info@steffenvogel.de>
*/
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "meter.h"
#include "fluksov2.h"
#include "options.h"
int meter_init_fluksov2(meter_t *mtr, list_t options) {
meter_handle_fluksov2_t *handle = &mtr->handle.fluksov2;
char *fifo;
if (options_lookup_string(options, "fifo", &fifo) == SUCCESS) {
handle->fifo = strdup(fifo);
}
else {
handle->fifo = "/var/run/spid/delta/out";
}
return SUCCESS;
}
int meter_open_fluksov2(meter_t *mtr) {
meter_handle_fluksov2_t *handle = &mtr->handle.fluksov2;
/* open port */
handle->fd = open(handle->fifo, O_RDONLY);
if (handle->fd < 0) {
print(log_error, "open(%s): %s", mtr, handle->fifo, strerror(errno));
return ERR;
}
return SUCCESS;
}
int meter_close_fluksov2(meter_t *mtr) {
meter_handle_fluksov2_t *handle = &mtr->handle.fluksov2;
return close(handle->fd); /* close fifo */
}
size_t read_line(int fd, char *buffer, size_t n) {
int r; /* return code of read() */
int e = 0; /* end of line? */
int i = 0; /* iterator for buffer */
char c; /* character read */
while (i < n) {
r = read(fd, &c, 1); /* read byte-per-byte, to identify a line break */
if (r < 0) { /* an error occured, pass through to caller */
return r;
}
else if (r == 1) { /* successful read */
switch (c) {
case '\n': /* line delimiter */
case '\r':
end++;
if (end == 2) {
return i; /* line end after "\n\r" */
}
else {
break; /* wait for second delimiter */
}
default: /* normal character */
buffer[i] = c;
i++;
}
}
}
return i;
}
size_t meter_read_fluksov2(meter_t *mtr, reading_t rds[], size_t n) {
meter_handle_fluksov2_t *handle = &mtr->handle.fluksov2;
char line[64];
size_t i = 0; /* number of readings */
size_t h = 0; /* sensor numer */
int r = read_line(handle->fd, line, 64); /* blocking read of a complete line */
if (r <= 0) {
print(log_error, "read(%s): %s", mtr, handle->fifo, strerror(errno));
return 0;
}
char *time_str = strtok(line, " \t"); /* first token is the timestamp */
struct timeval time = {
.tv_sec = strtoq(time_str, NULL, 10)
.tv_usec = 0 /* no millisecond resolution available */
};
for (int j = 0; j < 3 && i < n; j++) {
char *tok = strtok(NULL, " \t");
if (tok == NULL) {
return i;
}
switch (j) {
case 0: /* id (integer) */
break; /* just ignore */
case 1: /* consumption (Wh) */
rds[i].identifier.channel = i;
rds[i].time = time;
rds[i].value = strtod(tok, NULL);
i++;
case 2: /* power (W) */
j = 0;
i++;
}
}
return 0;
}

View file

@ -24,9 +24,7 @@
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "meter.h"
#include "options.h"
@ -39,6 +37,7 @@ static const meter_details_t protocols[] = {
METER_DETAIL(file, "Read from file (ex. 1-Wire sensors via OWFS)", 32, TRUE),
//METER_DETAIL(exec, "Read from program (ex. 1-Wire sensors via digitemp)", 32, TRUE),
METER_DETAIL(random, "Random walk", 1, TRUE),
METER_DETAIL(fluksov2, "Read from onboard SPI of a Flukso v2", 16, FALSE),
METER_DETAIL(s0, "S0 on RS232", 1, TRUE),
METER_DETAIL(d0, "Plaintext protocol (DIN EN 62056-21)", 32, FALSE),
#ifdef SML_SUPPORT
@ -64,16 +63,30 @@ int meter_init(meter_t *mtr, list_t options) {
}
/* interval */
mtr->interval = 10;
mtr->interval = -1; /* indicates unknown interval */
if (options_lookup_int(options, "interval", &mtr->interval) == ERR_INVALID_TYPE) {
print(log_error, "Invalid type for interval", mtr);
return ERR;
}
const meter_details_t *details = meter_get_details(mtr->protocol);
if (details->periodic == TRUE && mtr->interval < 0) {
print(log_error, "Interval has to be positive!", mtr);
}
return details->init_func(mtr, options);
}
int meter_lookup_protocol(const char* name, meter_protocol_t *protocol) {
for (const meter_details_t *it = meter_get_protocols(); it != NULL; it++) {
if (strcmp(it->name, name) == 0) {
*protocol = it->id;
return SUCCESS;
}
}
return ERR_NOT_FOUND;
}
int meter_open(meter_t *mtr) {
const meter_details_t *details = meter_get_details(mtr->protocol);
return details->open_func(mtr);
@ -93,16 +106,6 @@ const meter_details_t * meter_get_protocols() {
return protocols;
}
int meter_lookup_protocol(const char *name, meter_protocol_t *protocol) {
for (const meter_details_t *it = protocols; it != NULL; it++) {
if (strcmp(it->name, name) == 0) {
*protocol = it->id;
return SUCCESS;
}
}
return ERR_NOT_FOUND;
}
const meter_details_t * meter_get_details(meter_protocol_t protocol) {
for (const meter_details_t *it = protocols; it != NULL; it++) {
if (it->id == protocol) {
@ -112,19 +115,3 @@ const meter_details_t * meter_get_details(meter_protocol_t protocol) {
return NULL;
}
double tvtod(struct timeval tv) {
return tv.tv_sec + tv.tv_usec / 1e6;
}
struct timeval dtotv(double ts) {
double integral;
double fraction = modf(ts, &integral);
struct timeval tv = {
.tv_usec = (long int) (fraction * 1e6),
.tv_sec = (long int) integral
};
return tv;
}

133
src/reading.c Normal file
View file

@ -0,0 +1,133 @@
/**
* Reading related functions
*
* @package vzlogger
* @copyright Copyright (c) 2011, The volkszaehler.org project
* @license http://www.gnu.org/licenses/gpl.txt GNU Public License
* @author Steffen Vogel <info@steffenvogel.de>
*/
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <math.h>
#include "reading.h"
#include "meter.h"
int reading_id_compare(meter_protocol_t protocol, reading_id_t a, reading_id_t b) {
switch (protocol) {
case meter_protocol_d0:
case meter_protocol_sml:
return obis_compare(a.obis, b.obis);
case meter_protocol_fluksov2:
return !(a.channel == b.channel);
case meter_protocol_file:
case meter_protocol_exec:
return strcmp(a.string, b.string);
default:
/* no channel id, adding all readings to buffer */
return 0; /* equal */
}
}
int reading_id_parse(meter_protocol_t protocol, reading_id_t *id, const char *string) {
switch (protocol) {
case meter_protocol_d0:
case meter_protocol_sml:
if (obis_parse(string, &id->obis) != SUCCESS) {
if (obis_lookup_alias(string, &id->obis) != SUCCESS) {
return ERR;
}
}
break;
case meter_protocol_fluksov2: {
char type[13];
int channel;
int ret = sscanf(string, "sensor%u/%12s", &channel, type);
if (ret != 2) {
return ERR;
}
id->channel = channel + 1; /* increment by 1 to distinguish between +0 and -0 */
if (strcmp(type, "consumption") == 0) {
id->channel *= -1;
}
else if (strcmp(type, "power") != 0) {
return ERR;
}
break;
}
case meter_protocol_file:
case meter_protocol_exec:
id->string = strdup(string); // TODO free() elsewhere
break;
default: /* ignore other protocols which do not provide id's */
break;
}
return SUCCESS;
}
size_t reading_id_unparse(meter_protocol_t protocol, reading_id_t id, char *buffer, size_t n) {
switch (protocol) {
case meter_protocol_d0:
case meter_protocol_sml:
obis_unparse(id.obis, buffer, n);
break;
case meter_protocol_fluksov2:
snprintf(buffer, n, "sensor%u/%s", abs(id.channel) - 1, (id.channel > 0) ? "power" : "consumption");
break;
case meter_protocol_file:
case meter_protocol_exec:
if (id.string != NULL) {
strncpy(buffer, id.string, n);
break;
}
default:
buffer[0] = '\0';
}
return strlen(buffer);
}
double tvtod(struct timeval tv) {
return tv.tv_sec + tv.tv_usec / 1e6;
}
struct timeval dtotv(double ts) {
double integral;
double fraction = modf(ts, &integral);
struct timeval tv = {
.tv_usec = (long int) (fraction * 1e6),
.tv_sec = (long int) integral
};
return tv;
}