From 7c2aaf1cb06c2231f44e25a1b13bbd2f47b12651 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Fri, 27 Feb 2026 18:31:22 +0300 Subject: [PATCH] add serial/socket plugin example --- .../weatherdaemon_multimeteo/CMakeLists.txt | 1 + Daemons/weatherdaemon_multimeteo/cmdlnopts.c | 5 +- Daemons/weatherdaemon_multimeteo/cmdlnopts.h | 1 + Daemons/weatherdaemon_multimeteo/fd.c | 154 +++++++++++++++ Daemons/weatherdaemon_multimeteo/fd.h | 21 +++ Daemons/weatherdaemon_multimeteo/main.c | 10 + .../plugins/CMakeLists.txt | 9 +- .../weatherdaemon_multimeteo/plugins/dummy.c | 10 +- .../plugins/fdexample.c | 178 ++++++++++++++++++ Daemons/weatherdaemon_multimeteo/sensors.c | 28 ++- Daemons/weatherdaemon_multimeteo/sensors.h | 4 + Daemons/weatherdaemon_multimeteo/server.c | 4 +- Daemons/weatherdaemon_multimeteo/weathlib.h | 4 +- 13 files changed, 416 insertions(+), 13 deletions(-) create mode 100644 Daemons/weatherdaemon_multimeteo/fd.c create mode 100644 Daemons/weatherdaemon_multimeteo/fd.h create mode 100644 Daemons/weatherdaemon_multimeteo/plugins/fdexample.c diff --git a/Daemons/weatherdaemon_multimeteo/CMakeLists.txt b/Daemons/weatherdaemon_multimeteo/CMakeLists.txt index 2b1211c..50d2245 100644 --- a/Daemons/weatherdaemon_multimeteo/CMakeLists.txt +++ b/Daemons/weatherdaemon_multimeteo/CMakeLists.txt @@ -14,6 +14,7 @@ message("VER: ${VERSION}") # list of options option(DEBUG "Compile in debug mode" OFF) option(DUMMY "Dummy device plugin" ON) +option(FDEXAMPLE "Example of file descriptor plugin" ON) # default flags diff --git a/Daemons/weatherdaemon_multimeteo/cmdlnopts.c b/Daemons/weatherdaemon_multimeteo/cmdlnopts.c index 6173662..5dea00f 100644 --- a/Daemons/weatherdaemon_multimeteo/cmdlnopts.c +++ b/Daemons/weatherdaemon_multimeteo/cmdlnopts.c @@ -56,11 +56,12 @@ static glob_pars G; {"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&G.logfile), "save logs to file (default: none)"}, \ {"pidfile", NEED_ARG, NULL, 'P', arg_string, APTR(&G.pidfile), "pidfile name (default: " DEFAULT_PID ")"}, \ {"sockpath",NEED_ARG, NULL, 0, arg_string, APTR(&G.sockname), "UNIX socket path (starting from '\\0' for anonimous) of command socket"}, \ - {"plugin", MULT_PAR, NULL, 'p', arg_string, APTR(&G.plugins), "add this weather plugin (may be a lot of)"}, + {"plugin", MULT_PAR, NULL, 'p', arg_string, APTR(&G.plugins), "add this weather plugin (may be a lot of); FORMAT: \"dlpath:l:dev\", where `dlpath` - path of plugin library; `l` - 'D' for device, 'U' for UNIX-socket or 'N' for INET socket; dev - path to device and speed (like /dev/ttyS0:9600), UNIX socket name or host:port for INET"}, \ + {"pollt", NEED_ARG, NULL, 'T', arg_int, APTR(&G.pollt), "set maximal polling interval (seconds, integer)"}, sl_option_t cmdlnopts[] = { {"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), "show this help"}, - {"conffile",NEED_ARG, NULL, 'c', arg_string, APTR(&G.conffile), "configuration file name (consists all or a part of long-named parameters and their values (e.g. plugin=liboldweather.so)"}, + {"conffile",NEED_ARG, NULL, 'c', arg_string, APTR(&G.conffile), "configuration file name (consists all or a part of long-named parameters and their values (e.g. plugin=liboldweather.so:D:/dev/ttyS0:115200)"}, {"verb", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verb), "logfile verbocity level (each -v increased)"}, \ COMMON_OPTS end_option diff --git a/Daemons/weatherdaemon_multimeteo/cmdlnopts.h b/Daemons/weatherdaemon_multimeteo/cmdlnopts.h index 3fcdca8..5651382 100644 --- a/Daemons/weatherdaemon_multimeteo/cmdlnopts.h +++ b/Daemons/weatherdaemon_multimeteo/cmdlnopts.h @@ -30,6 +30,7 @@ typedef struct{ char **plugins; // all plugins connected int nplugins; // amount of plugins char *conffile; // configuration file used instead of long command line + int pollt; // sensors maximal polling interval } glob_pars; diff --git a/Daemons/weatherdaemon_multimeteo/fd.c b/Daemons/weatherdaemon_multimeteo/fd.c new file mode 100644 index 0000000..5a821ba --- /dev/null +++ b/Daemons/weatherdaemon_multimeteo/fd.c @@ -0,0 +1,154 @@ +/* + * This file is part of the weatherdaemon project. + * Copyright 2026 Edward V. Emelianov . + * + * This program 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 + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +// try to open device or socket that user pointed for plugin +// WARNING!!! The `getFD` function intended for single use for each plugin! +// WARNING!!! If you will try to close some plugins in running mode and open others, it +// WARNING!!! would cause to a memory leak! + +#include +#include +#include +#include +#include +#include // unix socket +#include + +#include "fd.h" + +/** + * @brief openserial - try to open serial device + * @param path - path to device and speed, colon-separated (without given speed assume 9600) + * @return -1 if failed or opened FD + * WARNING!!! Memory leakage danger. Don't call this function too much times! + */ +static int openserial(char *path){ + FNAME(); + int speed = 9600; // default speed + char *colon = strchr(path, ':'); + if(colon){ + *colon++ = 0; + if(!sl_str2i(&speed, colon)){ + WARNX("Wrong speed settings: '%s'", colon); + return -1; + } + } + sl_tty_t *serial = sl_tty_new(path, speed, BUFSIZ); + if(!serial || !sl_tty_open(serial, TRUE)){ + WARN("Can't open %s @ speed %d", path, speed); + return -1; + } + return serial->comfd; +} + +static char *convunsname(const char *path){ + char *apath = MALLOC(char, 106); + if(*path == 0 || *path == '@'){ + DBG("convert name starting from 0 or @"); + apath[0] = 0; + strncpy(apath+1, path+1, 104); + }else if(strncmp("\\0", path, 2) == 0){ + DBG("convert name starting from \\0"); + apath[0] = 0; + strncpy(apath+1, path+2, 104); + }else strncpy(apath, path, 105); + return apath; +} + +/** + * @brief opensocket - try to open socket + * @param sock - UNIX socket path or hostname:port for INET socket + * @param type - UNIX or INET + * @return -1 if failed or opened FD + */ +static int opensocket(char *path, sl_socktype_e type){ + FNAME(); + DBG("path: '%s'", path); + int sock = -1; + struct addrinfo ai = {0}, *res = &ai; + struct sockaddr_un unaddr = {0}; + char *node = path, *service = NULL; + ai.ai_socktype = SOCK_STREAM; + switch(type){ + case SOCKT_UNIX: + { + char *str = convunsname(path); + if(!str) return -1; + unaddr.sun_family = AF_UNIX; + ai.ai_addr = (struct sockaddr*) &unaddr; + ai.ai_addrlen = sizeof(unaddr); + memcpy(unaddr.sun_path, str, 106); + FREE(str); + ai.ai_family = AF_UNIX; + //ai.ai_socktype = SOCK_SEQPACKET; + } + break; + case SOCKT_NET: + case SOCKT_NETLOCAL: + //ai.ai_socktype = SOCK_DGRAM; + ai.ai_family = AF_INET; + char *delim = strchr(path, ':'); + if(delim){ + *delim = 0; + service = delim+1; + if(delim == path) node = NULL; // only port + } + DBG("node: '%s', service: '%s'", node, service); + int e = getaddrinfo(node, service, &ai, &res); + if(e){ + WARNX("getaddrinfo(): %s", gai_strerror(e)); + return -1; + } + for(struct addrinfo *p = res; p; p = p->ai_next){ + if((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) continue; + DBG("Try proto %d, type %d", p->ai_protocol, p->ai_socktype); + if(connect(sock, p->ai_addr, p->ai_addrlen) == -1){ + WARN("connect()"); + close(sock); sock = -1; + } else break; + } + break; + default: // never reached + WARNX("Unsupported socket type %d", type); + return -1; + } + DBG("FD: %d", sock); + return sock; +} + +/** + * @brief getFD - try to open given device/socket + * @param path - rest of string for --plugin= (e.g. "N:host.com:12345") + * WARNING!!! Contents of `path` would be modified in this function! + * @return opened file descriptor or -1 in case of error + */ +int getFD(char *path){ + if(!path || !*path) return -1; + char type = *path; + path += 2; + switch(type){ + case 'D': // serial device + return openserial(path); + case 'N': // INET socket + return opensocket(path, SOCKT_NET); + case 'U': // UNIX socket + return opensocket(path, SOCKT_UNIX); + } + WARNX("Wrong plugin format: '%c', should be 'D', 'N' or 'U'", type); + return -1; +} diff --git a/Daemons/weatherdaemon_multimeteo/fd.h b/Daemons/weatherdaemon_multimeteo/fd.h new file mode 100644 index 0000000..8737879 --- /dev/null +++ b/Daemons/weatherdaemon_multimeteo/fd.h @@ -0,0 +1,21 @@ +/* + * This file is part of the weatherdaemon project. + * Copyright 2026 Edward V. Emelianov . + * + * This program 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 + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +#pragma once + +int getFD(char *path); diff --git a/Daemons/weatherdaemon_multimeteo/main.c b/Daemons/weatherdaemon_multimeteo/main.c index 023e524..94ccf5d 100644 --- a/Daemons/weatherdaemon_multimeteo/main.c +++ b/Daemons/weatherdaemon_multimeteo/main.c @@ -41,6 +41,12 @@ void signals(int signo){ exit(signo); } +static void getpipe(int _U_ signo){ + WARNX("Get sigpipe!"); + // TODO: check all sensors for disconnected one + signal(SIGPIPE, getpipe); +} + extern const char *__progname; int main(int argc, char **argv){ @@ -51,6 +57,7 @@ int main(int argc, char **argv){ signal(SIGINT, signals); // ctrl+C - quit signal(SIGQUIT, signals); // ctrl+\ - quit signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z + signal(SIGPIPE, getpipe); // socket disconnected GP = parse_args(argc, argv); if(!GP) ERRX("Error parsing args"); if(!GP->sockname) ERRX("Point command socket name"); @@ -61,6 +68,9 @@ int main(int argc, char **argv){ if(!OPENLOG(GP->logfile, lvl, 1)) ERRX("Can't open log file"); LOGMSG("Started"); } + if(GP->pollt > 0){ + if(!set_pollT((time_t)GP->pollt)) ERRX("Can't set polling time to %d seconds", GP->pollt); + } int nopened = openplugins(GP->plugins, GP->nplugins); if(nopened < 1){ LOGERR("No plugins found; exit!"); diff --git a/Daemons/weatherdaemon_multimeteo/plugins/CMakeLists.txt b/Daemons/weatherdaemon_multimeteo/plugins/CMakeLists.txt index 72e2e24..5444b5e 100644 --- a/Daemons/weatherdaemon_multimeteo/plugins/CMakeLists.txt +++ b/Daemons/weatherdaemon_multimeteo/plugins/CMakeLists.txt @@ -6,7 +6,7 @@ find_package(PkgConfig REQUIRED) pkg_check_modules(PLUGINS REQUIRED usefull_macros) include_directories(${PLUGINS_INCLUDE_DIRS} ..) -link_directories(${PLUGINSLIBRARY_DIRS}) +link_directories(${PLUGINS_LIBRARY_DIRS}) link_libraries(${$PLUGINS_LIBRARIES} -fPIC) set(LIBS "") @@ -14,6 +14,11 @@ set(LIBS "") if(DUMMY) add_library(wsdummy SHARED dummy.c) list(APPEND LIBS wsdummy) -endif(DUMMY) +endif() + +if(FDEXAMPLE) + add_library(fdex SHARED fdexample.c) + list(APPEND LIBS fdex) +endif() install(TARGETS ${LIBS} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/Daemons/weatherdaemon_multimeteo/plugins/dummy.c b/Daemons/weatherdaemon_multimeteo/plugins/dummy.c index c819294..2186787 100644 --- a/Daemons/weatherdaemon_multimeteo/plugins/dummy.c +++ b/Daemons/weatherdaemon_multimeteo/plugins/dummy.c @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +// dummy meteostation sending data each `dt` seconds + #include #include #include @@ -25,6 +27,7 @@ #define NS (6) extern sensordata_t sensor; +static double dt = 1.; static void (*freshdatahandler)(const struct sensordata_t* const) = NULL; // do nothing with fresh data static pthread_t thread; @@ -38,7 +41,7 @@ static val_t values[NS] = { // fields `name` and `comment` have no sense until v {.name = "PRECIP", .comment = "precipitations flag (0 - no, 1 - yes)", .sense = VAL_OBLIGATORY, .type = VALT_UINT, .meaning = IS_PRECIP}, }; -void *mainthread(void _U_ *U){ +static void *mainthread(void _U_ *U){ FNAME(); double t0 = sl_dtime(); while(1){ @@ -56,13 +59,13 @@ void *mainthread(void _U_ *U){ time_t cur = time(NULL); for(int i = 0; i < NS; ++i) values[i].time = cur; if(freshdatahandler) freshdatahandler(&sensor); - while(sl_dtime() - t0 < 1.) usleep(500); + while(sl_dtime() - t0 < dt) usleep(500); t0 = sl_dtime(); } return NULL; } -static int init(int N){ +static int init(int N, time_t pollt, int _U_ fd){ FNAME(); values[0].value.f = 1.; values[1].value.f = 180.; @@ -72,6 +75,7 @@ static int init(int N){ values[5].value.u = 0; if(pthread_create(&thread, NULL, mainthread, NULL)) return 0; sensor.PluginNo = N; + if(pollt) dt = (double) pollt; // refresh each `pollt` seconds return NS; } diff --git a/Daemons/weatherdaemon_multimeteo/plugins/fdexample.c b/Daemons/weatherdaemon_multimeteo/plugins/fdexample.c new file mode 100644 index 0000000..19f34de --- /dev/null +++ b/Daemons/weatherdaemon_multimeteo/plugins/fdexample.c @@ -0,0 +1,178 @@ +/* + * This file is part of the weatherdaemon project. + * Copyright 2026 Edward V. Emelianov . + * + * This program 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 + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +#include +#include // pthread_kill +#include +#include +#include + +#include "weathlib.h" + +// dummy example of file descriptors usage + +#define NS (4) + +static time_t Tpoll = 10; +extern sensordata_t sensor; +static int fdes = -1; +static sl_ringbuffer_t *rb; +static pthread_t thread; +static void (*freshdatahandler)(const struct sensordata_t* const) = NULL; +static void die(); + +static val_t values[NS] = { // fields `name` and `comment` have no sense until value meaning is `IS_OTHER` + {.name = "WIND", .sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_WIND}, + {.name = "EXTTEMP", .sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_AMB_TEMP}, + {.name = "PRESSURE", .sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_PRESSURE}, + {.name = "HUMIDITY", .sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_HUMIDITY}, +}; + +static int format_values(char *buf){ + int gotvals = 0; + char *token = strtok(buf, ","); + time_t tnow = time(NULL); + while(token && gotvals < NS){ + double v; + DBG("TOKEN: %s", token); + if(sl_str2d(&v, token)){ + DBG("next value: %g", v); + values[gotvals].value.f = (float) v; + values[gotvals].time = tnow; + ++gotvals; + } + token = strtok(NULL, ","); + } + DBG("GOT: %d", gotvals); + return gotvals; +} + +static ssize_t writedata(int fd, const char *str, size_t size){ + ssize_t sent = 0; + do{ + DBG("try to write %zd bytes", size); + int canwrite = sl_canwrite(fd); + if(canwrite < 0){ + WARNX("Disconnected?!"); + return -1; + }else if(canwrite){ + ssize_t r = write(fd, str+sent, size); + if(r < 0){ + sent = -1; + WARNX("Disconnected??"); + break; + }else{ + sent += r; + size -= r; + } + DBG("sent %zd bytes; total send %zd, leave %zd", r, sent, size); + } + }while(size); + return sent; +} + +static void *mainthread(void _U_ *U){ + FNAME(); + time_t task = 0; + const char begging[] = "Enter comma-separated data: wind, exttemp, pressure, humidity\n"; + char buf[128]; + while(fdes > -1){ + time_t tnow = time(NULL); + int canread = sl_canread(fdes); + if(canread < 0){ + WARNX("Disconnected fd %d", fdes); + break; + }else if(canread == 1){ + ssize_t got = read(fdes, buf, 128); + if(got > 0){ + sl_RB_write(rb, (uint8_t*)buf, got); + }else if(got < 0){ + DBG("Disconnected?"); + break; + } + } + if(sl_RB_readline(rb, buf, 127) > 0){ + if(NS == format_values(buf) && freshdatahandler) + freshdatahandler(&sensor); + } + if(tnow >= task){ + DBG("write %s", begging); + ssize_t got = writedata(fdes, begging, sizeof(begging)-1); + if(got > 0) task = tnow + Tpoll; + else if(got < 0){ + close(fdes); + fdes = -1; + } + } + } + DBG("OOOOps!"); + return NULL; +} + +static int init(int N, time_t pollt, int fd){ + FNAME(); + if(!(rb = sl_RB_new(BUFSIZ))){ + WARNX("Can't init ringbuffer!"); + return 0; + } + if(pthread_create(&thread, NULL, mainthread, NULL)) return 0; + sensor.PluginNo = N; + if(pollt) Tpoll = pollt; + fdes = fd; + if(fdes < 0) return -1; + return NS; +} + +static int onrefresh(void (*handler)(const struct sensordata_t* const)){ + FNAME(); + if(!handler) return FALSE; + freshdatahandler = handler; + return TRUE; +} + + +static int getval(val_t *o, int N){ + if(N < 0 || N >= NS) return FALSE; + if(o) *o = values[N]; + return TRUE; +} + +static void die(){ + FNAME(); + if(0 == pthread_kill(thread, -9)){ + DBG("Killed, join"); + pthread_join(thread, NULL); + DBG("Done"); + } + DBG("Delete RB"); + sl_RB_delete(&rb); + if(fdes > -1){ + close(fdes); + DBG("FD closed"); + } + DBG("FDEXAMPLE: died"); +} + +sensordata_t sensor = { + .name = "Dummy socket or serial device weatherstation", + .Nvalues = NS, + .init = init, + .onrefresh = onrefresh, + .get_value = getval, + .die = die, +}; diff --git a/Daemons/weatherdaemon_multimeteo/sensors.c b/Daemons/weatherdaemon_multimeteo/sensors.c index 3d264dd..9fc1e07 100644 --- a/Daemons/weatherdaemon_multimeteo/sensors.c +++ b/Daemons/weatherdaemon_multimeteo/sensors.c @@ -17,8 +17,10 @@ */ #include +#include #include +#include "fd.h" #include "sensors.h" #define WARNXL(...) do{ LOGWARN(__VA_ARGS__); WARNX(__VA_ARGS__); } while(0) @@ -26,6 +28,9 @@ #define ERRXL(...) do{ LOGERR(__VA_ARGS__); ERRX(__VA_ARGS__); } while(0) #define ERRL(...) do{ LOGERR(__VA_ARGS__); ERR(__VA_ARGS__); } while(0) +// poll each `poll_interval` seconds +static time_t poll_interval = 15; + static int nplugins = 0; static sensordata_t **allplugins = NULL; @@ -33,6 +38,13 @@ int get_nplugins(){ return nplugins; } +// set polling interval +int set_pollT(time_t t){ + if(t == 0 || t > MAX_POLLT) return FALSE; + poll_interval = t; + return TRUE; +} + /** * @brief get_plugin - get copy of opened plugin * @param o (o) - plugin with given index @@ -66,14 +78,20 @@ static void dumpsensors(const struct sensordata_t* const station){ FNAME(); if(!station || !station->get_value || station->Nvalues < 1) return; char buf[FULL_LEN+1]; + uint64_t Tsum = 0; int nsum = 0; int N = (nplugins > 1) ? station->PluginNo : -1; for(int i = 0; i < station->Nvalues; ++i){ val_t v; if(!station->get_value(&v, i)) continue; if(0 < format_sensval(&v, buf, FULL_LEN+1, N)){ printf("%s\n", buf); + ++nsum; Tsum += v.time; } } + time_t last = (time_t)(Tsum / nsum); + if(0 < format_msrmttm(last, buf, FULL_LEN+1)){ + printf("%s\n\n", buf); + } } #endif @@ -85,6 +103,7 @@ static void dumpsensors(const struct sensordata_t* const station){ * This function should be runned only once at start */ int openplugins(char **paths, int N){ + char buf[PATH_MAX+1]; if(!paths || !*paths || N < 1) return 0; if(allplugins || nplugins){ WARNXL("Plugins already opened"); return 0; @@ -93,7 +112,10 @@ int openplugins(char **paths, int N){ green("Try to open plugins:\n"); for(int i = 0; i < N; ++i){ printf("\tplugin[%d]=%s\n", i, paths[i]); - void* dlh = open_plugin(paths[i]); + snprintf(buf, PATH_MAX, "%s", paths[i]); + char *colon = strchr(buf, ':'); + if(colon) *colon++ = 0; + void* dlh = open_plugin(buf); if(!dlh) continue; DBG("OPENED"); void *s = dlsym(dlh, "sensor"); @@ -104,7 +126,9 @@ int openplugins(char **paths, int N){ WARNXL("Sensor library %s have no init funtion"); continue; } - int ns = S->init(nplugins); + int fd = -1; + if(colon) fd = getFD(colon); + int ns = S->init(nplugins, poll_interval, fd); // here nplugins is index in array if(ns < 1) WARNXL("Can't init plugin %s", paths[i]); else{ #ifdef EBUG diff --git a/Daemons/weatherdaemon_multimeteo/sensors.h b/Daemons/weatherdaemon_multimeteo/sensors.h index 20894c2..9ec6d59 100644 --- a/Daemons/weatherdaemon_multimeteo/sensors.h +++ b/Daemons/weatherdaemon_multimeteo/sensors.h @@ -20,9 +20,13 @@ #include "weathlib.h" +// don't allow to set polling time more than 10 minutes +#define MAX_POLLT (600) + int openplugins(char **paths, int N); void closeplugins(); int get_plugin(sensordata_t *o, int N); int get_nplugins(); int format_sensval(const val_t *v, char *buf, int buflen, int Np); int format_msrmttm(time_t t, char *buf, int buflen); +int set_pollT(time_t t); diff --git a/Daemons/weatherdaemon_multimeteo/server.c b/Daemons/weatherdaemon_multimeteo/server.c index 05a01ad..8d1b38d 100644 --- a/Daemons/weatherdaemon_multimeteo/server.c +++ b/Daemons/weatherdaemon_multimeteo/server.c @@ -42,13 +42,13 @@ static sl_sock_hresult_e timehandler(sl_sock_t *client, _U_ sl_sock_hitem_t *ite // show all connected libraries static sl_sock_hresult_e listhandler(sl_sock_t *client, _U_ sl_sock_hitem_t *item, _U_ const char *req){ if(!client) return RESULT_FAIL; - char buf[128]; + char buf[256]; int N = get_nplugins(); if(N < 1) return RESULT_FAIL; sensordata_t d; for(int i = 0; i < N; ++i){ if(!get_plugin(&d, i)) continue; - snprintf(buf, 127, "PLUGIN[%d]=%s\nNVALUES[%d]=%d\n", i, d.name, i, d.Nvalues); + snprintf(buf, 255, "PLUGIN[%d]=%s\nNVALUES[%d]=%d\n", i, d.name, i, d.Nvalues); sl_sock_sendstrmessage(client, buf); } return RESULT_SILENCE; diff --git a/Daemons/weatherdaemon_multimeteo/weathlib.h b/Daemons/weatherdaemon_multimeteo/weathlib.h index 0d76b57..8e07aca 100644 --- a/Daemons/weatherdaemon_multimeteo/weathlib.h +++ b/Daemons/weatherdaemon_multimeteo/weathlib.h @@ -28,7 +28,7 @@ // maximal full length of "KEY=val / comment" (as for sfitsio) #define FULL_LEN (81) // name of meteo-plugin -#define NAME_LEN (31) +#define NAME_LEN (127) // importance of values typedef enum{ @@ -85,7 +85,7 @@ typedef struct sensordata_t{ char name[NAME_LEN+1]; // max 31 symbol of sensor's name (e.g. "rain sensor") int Nvalues; // amount of values int PluginNo; // plugin number in array (if several) - int (*init)(int); // init meteostation with given PluginNo; return amount of parameters found + int (*init)(int, time_t, int); // init meteostation with given PluginNo, poll_interval and fd; return amount of parameters found int (*onrefresh)(void (*handler)(const struct sensordata_t* const)); // handler of new data; return TRUE if OK int (*get_value)(val_t *, int); // getter of Nth value void (*die)(); // close everything and die