added support for raw S0-Hutschienenzähler on RS232 port

This commit is contained in:
Steffen Vogel 2011-06-09 18:29:30 +02:00
parent f688d1ff09
commit fad473e9bb
9 changed files with 130 additions and 126 deletions

View file

@ -83,26 +83,31 @@ size_t curl_custom_write_callback(void *ptr, size_t size, size_t nmemb, void *da
return realsize;
}
json_object * api_build_json(channel_t *ch) {
json_object * api_json_tuples(channel_t *ch, bool_t all) {
reading_t rd;
json_object *json_obj = json_object_new_object();
json_object *json_tuples = json_object_new_array();
for (int j = 0; j < ch->queue.size; j++) {
queue_deque(&ch->queue, &rd);
int index = ch->queue.read_p;
do {
pthread_mutex_lock(&ch->mutex);
rd = ch->queue.buf[index];
pthread_mutex_unlock(&ch->mutex);
if (rd.tv.tv_sec) { /* skip empty readings */
json_object *json_tuple = json_object_new_array();
json_object_array_add(json_tuple, json_object_new_int(rd.tv.tv_sec * 1000 + rd.tv.tv_usec / 1000));
json_object_array_add(json_tuple, json_object_new_double(rd.value));
json_object_array_add(json_tuples, json_tuple);
}
}
struct json_object *json_tuple = json_object_new_array();
int timestamp = rd.tv.tv_sec * 1000 + rd.tv.tv_usec / 1000;
json_object_array_add(json_tuple, json_object_new_int(timestamp));
json_object_array_add(json_tuple, json_object_new_double(rd.value));
json_object_array_add(json_tuples, json_tuple);
index++;
index %= ch->queue.size;
} while (index != (all) ? ch->queue.read_p : ch->queue.write_p);
json_object_object_add(json_obj, "tuples", json_tuples);
return json_obj;
return json_tuples;
}
CURL * api_curl_init(channel_t *ch) {
@ -133,8 +138,8 @@ CURL * api_curl_init(channel_t *ch) {
}
void api_parse_exception(CURLresponse response, char *err) {
struct json_tokener * json_tok;
struct json_object * json_obj;
struct json_tokener *json_tok;
struct json_object *json_obj;
json_tok = json_tokener_new();
json_obj = json_tokener_parse_ex(json_tok, response.data, response.size);
@ -188,9 +193,7 @@ void *api_thread(void *arg) {
}
pthread_mutex_unlock(&ch->mutex);
pthread_mutex_lock(&ch->mutex);
json_str = json_object_to_json_string(api_build_json(ch));
pthread_mutex_unlock(&ch->mutex);
json_str = json_object_to_json_string(api_json_tuples(ch, FALSE));
print(1, "JSON request body: %s", ch, json_str);
@ -205,7 +208,7 @@ void *api_thread(void *arg) {
if (curl_code == CURLE_OK && http_code == 200) { /* everything is ok */
print(1, "Request succeeded with code: %i", ch, http_code);
// TODO clear queue
queue_clear(&ch->queue);
}
else { /* error */
if (curl_code != CURLE_OK) {
@ -213,7 +216,7 @@ void *api_thread(void *arg) {
}
else if (http_code != 200) {
char err[255];
api_parse_exception(response, &err);
api_parse_exception(response, err);
print(-1, "Invalid middlware response: %s", ch, err);
}
@ -224,8 +227,7 @@ void *api_thread(void *arg) {
/* householding */
free(json_str);
// TODO free json objects
if (response.data) free(response.data);
free(response.data);
pthread_testcancel(); /* test for cancelation request */
} while (opts.daemon);

View file

@ -43,8 +43,8 @@ int handle_request(void *cls, struct MHD_Connection *connection, const char *url
struct MHD_Response *response;
struct json_object * json_obj = json_object_new_object();
struct json_object * json_data = json_object_new_object();
struct json_object *json_obj = json_object_new_object();
struct json_object *json_data = json_object_new_object();
for (int i = 0; i < num_chans; i++) {
channel_t *ch = &chans[i];
@ -56,25 +56,8 @@ int handle_request(void *cls, struct MHD_Connection *connection, const char *url
pthread_cond_wait(&ch->condition, &ch->mutex); // TODO use pthread_cond_timedwait()
pthread_mutex_unlock(&ch->mutex);
struct json_object * json_tuples = json_object_new_array();
for (int j = 0; j < ch->queue.size; j++) {
pthread_mutex_lock(&ch->mutex);
queue_deque(&ch->queue, &rd);
pthread_mutex_unlock(&ch->mutex);
if (rd.value != 0) { /* skip invalid / empty readings */
struct json_object * json_tuple = json_object_new_array();
int timestamp = rd.tv.tv_sec * 1000 + rd.tv.tv_usec / 1000;
json_object_array_add(json_tuple, json_object_new_int(timestamp));
json_object_array_add(json_tuple, json_object_new_double(rd.value));
json_object_array_add(json_tuples, json_tuple);
}
}
struct json_object *json_tuples = api_json_tuples(ch, TRUE);
json_object_object_add(json_data, "uuid", json_object_new_string(ch->uuid));
json_object_object_add(json_data, "interval", json_object_new_int(ch->interval));
json_object_object_add(json_data, "tuples", json_tuples);

View file

@ -40,15 +40,17 @@
#include "protocols/obis.h"
#include "protocols/1wire.h"
#include "protocols/rawS0.h"
/**
* List of available protocols
* incl. function pointers
*/
static protocol_t protocols[] = {
{"obis", "Plaintext OBIS", obis_get, obis_init, obis_close},
// {"fluksousb", "FluksoUSB board", flukso_get, flukso_init, flukso_close},
{"1wire", "Dallas 1-Wire sensors (via OWFS)", onewire_get, onewire_init, onewire_close},
{"obis", "Plaintext OBIS", obis_get, obis_init, obis_close, MODE_SENSOR},
// {"fluksousb", "FluksoUSB board", flukso_get, flukso_init, flukso_close, MODE_SENSOR},
{"rawS0", "S0 on RS232", rawS0_get, rawS0_init, rawS0_close, MODE_METER},
{"1wire", "Dallas 1-Wire sensors (via OWFS)", onewire_get, onewire_init, onewire_close, MODE_SENSOR},
{NULL} /* stop condition for iterator */
};
@ -179,7 +181,6 @@ void parse_options(int argc, char * argv[], options_t * opts) {
case 'l':
opts->local = TRUE;
opts->daemon = TRUE; /* implicates daemon mode */
break;
case 'd':
@ -310,16 +311,20 @@ void *read_thread(void *arg) {
reading_t rd = ch->prot->read_func(ch->handle); /* aquire reading */
pthread_mutex_lock(&ch->mutex);
queue_enque(&ch->queue, rd);
pthread_cond_broadcast(&ch->condition);
queue_push(&ch->queue, rd);
pthread_cond_broadcast(&ch->condition); /* notify webserver and logging thread */
pthread_mutex_unlock(&ch->mutex);
print(1, "Value read: %.3f (next reading in %i secs)", ch, rd.value, ch->interval);
//if (opts.verbose > 5) queue_print(&ch->queue); /* Debugging */
print(1, "Value read: %.1f", ch, rd.value);
if (opts.verbose > 5) queue_print(&ch->queue); /* Debugging */
if (ch->prot->mode != MODE_METER) { /* for meters, the read_func call is blocking */
print(5, "Next reading in %i seconds", ch, ch->interval);
sleep(ch->interval); /* else sleep and restart aquisition */
}
pthread_testcancel(); /* test for cancelation request */
sleep(ch->interval); /* else sleep and restart aquisition */
} while (opts.daemon);
} while (opts.daemon || opts.local);
/* close channel */
ch->prot->close_func(ch->handle);
@ -374,11 +379,11 @@ int main(int argc, char * argv[]) {
pthread_join(ch->reading_thread, NULL);
pthread_join(ch->logging_thread, NULL);
/*free(ch->middleware);
free(ch->middleware);
free(ch->uuid);
free(ch->options);
queue_free(&ch->queue);*/
queue_free(&ch->queue);
pthread_cond_destroy(&ch->condition);
pthread_mutex_destroy(&ch->mutex);

View file

@ -12,12 +12,19 @@ typedef void *(*ifp_t)(char *options);
typedef void (*cfp_t)(void *handle);
typedef reading_t (*rfp_t)(void *handle);
typedef enum {
MODE_METER,
MODE_SENSOR
} mode_t;
typedef struct {
char * name; /* short identifier for protocol */
char * desc; /* more detailed description */
rfp_t read_func; /* function pointer to read data */
ifp_t init_func; /* function pointer to init a channel */
cfp_t close_func; /* function pointer to close a channel */
mode_t mode; /* should we wait for next pulse? */
} protocol_t;
#endif /* _PROTOCOL_H_ */

View file

@ -1,7 +1,5 @@
/**
* OBIS protocol parser
*
*
* S0 Hutschienenzähler directly connected to an rs232 port
*
* @package vzlogger
* @copyright Copyright (c) 2011, The volkszaehler.org project
@ -27,7 +25,9 @@
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "../main.h"
#include "../protocol.h"
@ -35,42 +35,71 @@
typedef struct {
int fd; /* file descriptor of port */
struct termios old_tio;
struct termios tio;
struct termios oldtio; /* required to reset port */
} rawS0_state_t;
/**
* Setup serial port
*/
void * rawS0_init(char * port) {
struct termios tio;
int *fd = malloc(sizeof(int));
rawS0_state_t *state;
struct termios newtio;
memset(&tio, 0, sizeof(tio));
/* initialize handle */
state = malloc(sizeof(rawS0_state_t));
tio.c_iflag = 0;
tio.c_oflag = 0;
tio.c_cflag = CS7|CREAD|CLOCAL; // 7n1, see termios.h for more information
tio.c_lflag = 0;
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 5;
state->fd = open(port, O_RDWR | O_NOCTTY);
if (state->fd < 0) {
char err[255];
strerror_r(errno, err, 255);
print(-1, "%s: %s", NULL, port, err);
exit(EXIT_FAILURE);
}
tcgetattr(state->fd, &state->oldtio); /* save current port settings */
*fd = open(port, O_RDWR | O_NONBLOCK);
cfsetospeed(&tio, B9600); // 9600 baud
cfsetispeed(&tio, B9600); // 9600 baud
/* configure port */
memset(&newtio, 0, sizeof(struct termios));
return (void *) fd;
newtio.c_cflag = B300 | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
newtio.c_lflag = 0; /* set input mode (non-canonical, no echo,...) */
newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
newtio.c_cc[VMIN] = 1; /* blocking read until data is received */
/* apply configuration */
tcsetattr(state->fd, TCSANOW, &newtio);
return (void *) state;
}
void obis_close(void *handle) {
// TODO close serial port
void rawS0_close(void *handle) {
rawS0_state_t *state = (rawS0_state_t *) handle;
tcsetattr(state->fd, TCSANOW, &state->oldtio);
close(state->fd);
free(handle);
}
reading_t obis_get(void *handle) {
reading_t rawS0_get(void *handle) {
char buf[255];
rawS0_state_t *state = (rawS0_state_t *) handle;
reading_t rd;
read();
rd.value = 1;
tcflush(state->fd, TCIOFLUSH);
read(state->fd, buf, 255); /* blocking until one character/pulse is read */
gettimeofday(&rd.tv, NULL);
/* wait some ms for debouncing */
usleep(30000);
return rd;
}

View file

@ -1,8 +1,5 @@
/**
* OBIS protocol parser
*
* This is our example protocol. Use this skeleton to add your own
* protocols and meters.
* S0 Hutschienenzähler directly connected to an rs232 port
*
* @package vzlogger
* @copyright Copyright (c) 2011, The volkszaehler.org project

View file

@ -3,62 +3,43 @@
#include "queue.h"
bool_t queue_init(queue_t *q, size_t size) {
queue_t * queue_init(queue_t *q, size_t size) {
q->buf = malloc(sizeof(reading_t) * size); /* keep one slot open */
if (q->buf) {
q->size = size;
q->read_p = q->write_p = 0; /* queue is empty */
return TRUE;
return q;
}
else {
return FALSE; /* cannot allocate memory */
else { /* cannot allocat memory */
return NULL;
}
}
bool_t queue_is_full(queue_t *q) {
return (((q->write_p + 1) % q->size) == q->read_p);
}
bool_t queue_is_empty(queue_t *q) {
return (q->read_p == q->write_p);
}
bool_t queue_enque(queue_t *q, reading_t rd) {
void queue_free(queue_t *q) {
queue_clear(q);
free(q->buf);
}
void queue_clear(queue_t *q) {
q->read_p = q->write_p;
}
void queue_push(queue_t *q, reading_t rd) {
q->buf[q->write_p] = rd;
q->write_p++;
q->write_p %= q->size;
return !queue_is_full(q);
}
bool_t queue_deque(queue_t *q, reading_t *rd) {
*rd = q->buf[q->read_p];
q->read_p++;
q->read_p %= q->size;
return !queue_is_empty(q);
}
size_t queue_size(queue_t *q) {
return q->write_p - q->read_p + (q->read_p > q->write_p) * q->size;
}
bool_t queue_first(queue_t *q, reading_t *rd) {
*rd = q->buf[q->read_p];
return !queue_is_empty(q);
}
void queue_print(queue_t *q) {
printf("Queue dump: [%.1f", q->buf[0].value);
for (int i = 1; i < q->size; i++) {
printf("|%.2f", q->buf[i].value);
}
printf("]\n");
}
void queue_free(queue_t *q) {
free(q->buf);
printf("] write_p = %i\t read_p = %i\n", q->write_p, q->read_p);
}

View file

@ -43,19 +43,18 @@ typedef struct {
int read_p;
int write_p;
int fill_count;
reading_t *buf;
} queue_t;
bool_t queue_init(queue_t *q, size_t size);
bool_t queue_is_full(queue_t *q);
queue_t * queue_init(queue_t *q, size_t size);
bool_t queue_is_empty(queue_t *q);
bool_t queue_enque(queue_t *q, reading_t rd);
bool_t queue_deque(queue_t *q, reading_t *rd);
bool_t queue_first(queue_t *q, reading_t *rd);
size_t queue_size(queue_t *q);
void queue_print(queue_t *q);
void queue_push(queue_t *q, reading_t rd);
void queue_clear(queue_t *q);
void queue_free(queue_t *q);
void queue_print(queue_t *q);
#endif /* _QUEUE_H_ */

View file

@ -5,4 +5,5 @@
;prot intval uuid middleware options
;1wire 3 52960fe0-8882-11e0-b356-85eba28c1922 http://localhost/workspace/volkszaehler.org/htdocs/middleware /mnt/1wire/10.12E6D3000800/temperature
;obis 10 ef0e9adf-cd9e-4d9a-92c5-b4fb4c89ff98 http://volkszaehler.org/demo/middleware.php /dev/ttyS0
obis 10 ef0e9adf-cd9e-4d9a-92c5-b4fb4c89ff98 http://volksxzaehler.org/demo/middleware.php /dev/ttyS1
rawS0 10 27a1b4c0-8f8a-11e0-ad82-db6efbc4ba2e http://volkszaehler.org/demo/middleware.php /dev/ttyUSB2