vzlogger/src/meter.c

118 lines
3.8 KiB
C

/**
* Protocol interface
*
* @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 <string.h>
#include <stdio.h>
#include "meter.h"
#include "options.h"
#define METER_DETAIL(NAME, DESC, MAX_RDS, PERIODIC) { meter_protocol_##NAME, #NAME, DESC, MAX_RDS, PERIODIC, meter_init_##NAME, meter_open_##NAME, meter_close_##NAME, meter_read_##NAME }
static const meter_details_t protocols[] = {
/* alias description max_rds periodic
===============================================================================================*/
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
METER_DETAIL(sml, "Smart Meter Language", 32, FALSE),
#endif /* SML_SUPPORT */
{} /* stop condition for iterator */
};
int meter_init(meter_t *mtr, list_t options) {
static int instances; /* static to generate unique channel ids */
snprintf(mtr->id, 5, "mtr%i", instances++); /* set/increment id */
/* protocol */
char *protocol_str;
if (options_lookup_string(options, "protocol", &protocol_str) != SUCCESS) {
print(log_error, "Missing protocol or invalid type", mtr);
return ERR;
}
if (meter_lookup_protocol(protocol_str, &mtr->protocol) != SUCCESS) {
print(log_error, "Invalid protocol: %s", mtr, protocol_str);
return ERR; /* skipping this meter */
}
/* interval */
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);
}
int meter_close(meter_t *mtr) {
const meter_details_t *details = meter_get_details(mtr->protocol);
return details->close_func(mtr);
}
size_t meter_read(meter_t *mtr, reading_t rds[], size_t n) {
const meter_details_t *details = meter_get_details(mtr->protocol);
return details->read_func(mtr, rds, n);
}
const meter_details_t * meter_get_protocols() {
return protocols;
}
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) {
return it;
}
}
return NULL;
}