diff --git a/Daemons/weatherdaemon_multimeteo/CMakeLists.txt b/Daemons/weatherdaemon_multimeteo/CMakeLists.txt index 50d2245..45f159a 100644 --- a/Daemons/weatherdaemon_multimeteo/CMakeLists.txt +++ b/Daemons/weatherdaemon_multimeteo/CMakeLists.txt @@ -1,11 +1,11 @@ -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 4.0) set(PROJ weatherdaemon) +set(PROJLIB senslib) set(MAJOR_VERSION "0") set(MID_VERSION "0") set(MINOR_VERSION "1") aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SOURCES) -#set(SOURCES main.c cmdlnopts.c sensors.c) set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}") project(${PROJ} VERSION ${VERSION} LANGUAGES C) @@ -16,9 +16,8 @@ option(DEBUG "Compile in debug mode" OFF) option(DUMMY "Dummy device plugin" ON) option(FDEXAMPLE "Example of file descriptor plugin" ON) - # default flags -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W -Wextra -fno-builtin-strlen") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W -Wextra -pedantic-errors -fPIC") message("Install dir prefix: ${CMAKE_INSTALL_PREFIX}") @@ -42,7 +41,7 @@ endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") find_package(PkgConfig REQUIRED) -pkg_check_modules(${PROJ} REQUIRED usefull_macros>=0.3.2) +pkg_check_modules(${PROJ} REQUIRED usefull_macros>=0.3.5) #include(FindOpenMP) #if(OPENMP_FOUND) @@ -51,12 +50,17 @@ pkg_check_modules(${PROJ} REQUIRED usefull_macros>=0.3.2) # add_definitions(-DOMP_FOUND) #endif() -# exe & lib files +# static lib for sensors +set(LIBSRC "weathlib.c") +set(LIBHEADER "weathlib.h") +add_library(${PROJLIB} STATIC ${LIBSRC}) +set_target_properties(${PROJLIB} PROPERTIES VERSION ${VERSION}) + +# exe & deps files add_executable(${PROJ} ${SOURCES}) -target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} -lm ${CMAKE_DL_LIBS}) +target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} ${PROJLIB} -lm ${CMAKE_DL_LIBS}) target_include_directories(${PROJ} PUBLIC ${${PROJ}_INCLUDE_DIRS} .) target_link_directories(${PROJ} PUBLIC ${${PROJ}_LIBRARY_DIRS} ) -set_target_properties(${PROJLIB} PROPERTIES VERSION ${VERSION}) include(GNUInstallDirs) # Installation of the program diff --git a/Daemons/weatherdaemon_multimeteo/fd.c b/Daemons/weatherdaemon_multimeteo/fd.c index 5a821ba..0a27b34 100644 --- a/Daemons/weatherdaemon_multimeteo/fd.c +++ b/Daemons/weatherdaemon_multimeteo/fd.c @@ -83,7 +83,7 @@ static int opensocket(char *path, sl_socktype_e type){ struct addrinfo ai = {0}, *res = &ai; struct sockaddr_un unaddr = {0}; char *node = path, *service = NULL; - ai.ai_socktype = SOCK_STREAM; + ai.ai_socktype = 0; // try to get socket type from `getaddrinfo` switch(type){ case SOCKT_UNIX: { @@ -95,12 +95,10 @@ static int opensocket(char *path, sl_socktype_e type){ 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){ diff --git a/Daemons/weatherdaemon_multimeteo/plugins/CMakeLists.txt b/Daemons/weatherdaemon_multimeteo/plugins/CMakeLists.txt index 5444b5e..cb69d97 100644 --- a/Daemons/weatherdaemon_multimeteo/plugins/CMakeLists.txt +++ b/Daemons/weatherdaemon_multimeteo/plugins/CMakeLists.txt @@ -6,8 +6,8 @@ find_package(PkgConfig REQUIRED) pkg_check_modules(PLUGINS REQUIRED usefull_macros) include_directories(${PLUGINS_INCLUDE_DIRS} ..) -link_directories(${PLUGINS_LIBRARY_DIRS}) -link_libraries(${$PLUGINS_LIBRARIES} -fPIC) +link_directories(${PLUGINS_LIBRARY_DIRS} ..) +link_libraries(${$PLUGINS_LIBRARIES} ${PROJLIB} -fPIC) set(LIBS "") diff --git a/Daemons/weatherdaemon_multimeteo/plugins/dummy.c b/Daemons/weatherdaemon_multimeteo/plugins/dummy.c index 2186787..1b50ef9 100644 --- a/Daemons/weatherdaemon_multimeteo/plugins/dummy.c +++ b/Daemons/weatherdaemon_multimeteo/plugins/dummy.c @@ -16,94 +16,72 @@ * along with this program. If not, see . */ -// dummy meteostation sending data each `dt` seconds - -#include -#include -#include +// dummy meteostation sending data each `tpoll` seconds #include "weathlib.h" #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; - -static val_t values[NS] = { // fields `name` and `comment` have no sense until value meaning is `IS_OTHER` - {.name = "WIND", .comment = "wind speed, m/s", .sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_WIND}, - {.name = "WINDDIR", .comment = "wind direction azimuth (from south over west), deg", .sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_WINDDIR}, - {.name = "EXTTEMP", .comment = "external temperature, degC", .sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_AMB_TEMP}, - {.name = "PRESSURE", .comment = "atmospheric pressure, hPa", .sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_PRESSURE}, - {.name = "HUMIDITY", .comment = "air relative humidity, %%", .sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_HUMIDITY}, - {.name = "PRECIP", .comment = "precipitations flag (0 - no, 1 - yes)", .sense = VAL_OBLIGATORY, .type = VALT_UINT, .meaning = IS_PRECIP}, +static const val_t values[NS] = { // fields `name` and `comment` have no sense until value meaning is `IS_OTHER` + {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_WIND}, + {.sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_WINDDIR}, + {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_AMB_TEMP}, + {.sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_PRESSURE}, + {.sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_HUMIDITY}, + {.sense = VAL_OBLIGATORY, .type = VALT_UINT, .meaning = IS_PRECIP}, }; static void *mainthread(void _U_ *U){ FNAME(); double t0 = sl_dtime(); while(1){ - float f = values[0].value.f + (drand48() - 0.5) / 2.; - if(f >= 0.) values[0].value.f = f; - f = values[1].value.f + (drand48() - 0.5) * 4.; - if(f > 160. && f < 200.) values[1].value.f = f; - f = values[2].value.f + (drand48() - 0.5) / 20.; - if(f > 13. && f < 21.) values[2].value.f = f; - f = values[3].value.f + (drand48() - 0.5) / 100.; - if(f > 585. && f < 615.) values[3].value.f = f; - f = values[4].value.f + (drand48() - 0.5) / 10.; - if(f > 60. && f <= 100.) values[4].value.f = f; - values[5].value.u = (f > 98.) ? 1 : 0; + float f = sensor.values[0].value.f + (drand48() - 0.5) / 2.; + if(f >= 0.) sensor.values[0].value.f = f; + f = sensor.values[1].value.f + (drand48() - 0.5) * 4.; + if(f > 160. && f < 200.) sensor.values[1].value.f = f; + f = sensor.values[2].value.f + (drand48() - 0.5) / 20.; + if(f > 13. && f < 21.) sensor.values[2].value.f = f; + f = sensor.values[3].value.f + (drand48() - 0.5) / 100.; + if(f > 585. && f < 615.) sensor.values[3].value.f = f; + f = sensor.values[4].value.f + (drand48() - 0.5) / 10.; + if(f > 60. && f <= 100.) sensor.values[4].value.f = f; + sensor.values[5].value.u = (f > 98.) ? 1 : 0; time_t cur = time(NULL); - for(int i = 0; i < NS; ++i) values[i].time = cur; - if(freshdatahandler) freshdatahandler(&sensor); - while(sl_dtime() - t0 < dt) usleep(500); + for(int i = 0; i < NS; ++i) sensor.values[i].time = cur; + if(sensor.freshdatahandler) sensor.freshdatahandler(&sensor); + while(sl_dtime() - t0 < sensor.tpoll) usleep(500); t0 = sl_dtime(); } return NULL; } -static int init(int N, time_t pollt, int _U_ fd){ +static int init(struct sensordata_t* s, int N, time_t pollt, int _U_ fd){ FNAME(); - values[0].value.f = 1.; - values[1].value.f = 180.; - values[2].value.f = 17.; - values[3].value.f = 600.; - values[4].value.f = 80.; - values[5].value.u = 0; - if(pthread_create(&thread, NULL, mainthread, NULL)) return 0; + if(pthread_create(&s->thread, NULL, mainthread, NULL)) return 0; + if(pollt) s->tpoll = pollt; + s->values = MALLOC(val_t, NS); + for(int i = 0; i < NS; ++i) s->values[i] = values[i]; + sensor.values[0].value.f = 1.; + sensor.values[1].value.f = 180.; + sensor.values[2].value.f = 17.; + sensor.values[3].value.f = 600.; + sensor.values[4].value.f = 80.; + sensor.values[5].value.u = 0; sensor.PluginNo = N; - if(pollt) dt = (double) pollt; // refresh each `pollt` seconds return NS; } -static int onrefresh(void (*handler)(const struct sensordata_t* const)){ - FNAME(); - if(!handler) return FALSE; - freshdatahandler = handler; - return TRUE; -} - -static void die(){ - FNAME(); - if(0 == pthread_kill(thread, 9)){ - DBG("Killed, join"); - pthread_join(thread, NULL); - DBG("Done"); - } -} - /** * @brief getval - value's getter * @param o (o) - value * @param N - it's index * @return FALSE if failed */ -static int getval(val_t *o, int N){ +static int getval(struct sensordata_t* s, val_t *o, int N){ if(N < 0 || N >= NS) return FALSE; - if(o) *o = values[N]; + if(o) *o = s->values[N]; return TRUE; } @@ -111,7 +89,7 @@ sensordata_t sensor = { .name = "Dummy weatherstation", .Nvalues = NS, .init = init, - .onrefresh = onrefresh, + .onrefresh = common_onrefresh, .get_value = getval, - .die = die, + .kill = common_kill, }; diff --git a/Daemons/weatherdaemon_multimeteo/plugins/fdexample.c b/Daemons/weatherdaemon_multimeteo/plugins/fdexample.c index 19f34de..726a4f5 100644 --- a/Daemons/weatherdaemon_multimeteo/plugins/fdexample.c +++ b/Daemons/weatherdaemon_multimeteo/plugins/fdexample.c @@ -16,11 +16,8 @@ * along with this program. If not, see . */ -#include -#include // pthread_kill #include #include -#include #include "weathlib.h" @@ -28,19 +25,13 @@ #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 const val_t values[NS] = { // fields `name` and `comment` have no sense until value meaning is `IS_OTHER` + {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_WIND}, + {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_AMB_TEMP}, + {.sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_PRESSURE}, + {.sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_HUMIDITY}, }; static int format_values(char *buf){ @@ -52,8 +43,8 @@ static int format_values(char *buf){ DBG("TOKEN: %s", token); if(sl_str2d(&v, token)){ DBG("next value: %g", v); - values[gotvals].value.f = (float) v; - values[gotvals].time = tnow; + sensor.values[gotvals].value.f = (float) v; + sensor.values[gotvals].time = tnow; ++gotvals; } token = strtok(NULL, ","); @@ -91,32 +82,34 @@ static void *mainthread(void _U_ *U){ time_t task = 0; const char begging[] = "Enter comma-separated data: wind, exttemp, pressure, humidity\n"; char buf[128]; - while(fdes > -1){ + while(sensor.fdes > -1){ time_t tnow = time(NULL); - int canread = sl_canread(fdes); + int canread = sl_canread(sensor.fdes); if(canread < 0){ - WARNX("Disconnected fd %d", fdes); + WARNX("Disconnected fd %d", sensor.fdes); break; }else if(canread == 1){ - ssize_t got = read(fdes, buf, 128); + ssize_t got = read(sensor.fdes, buf, 128); if(got > 0){ - sl_RB_write(rb, (uint8_t*)buf, got); + sl_RB_write(sensor.ringbuffer, (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(sl_RB_readline(sensor.ringbuffer, buf, 127) > 0){ + if(NS == format_values(buf) && sensor.freshdatahandler) + sensor.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; + if(sensor.tpoll){ + if(tnow >= task){ + DBG("write %s", begging); + ssize_t got = writedata(sensor.fdes, begging, sizeof(begging)-1); + if(got > 0) task = tnow + sensor.tpoll; + else if(got < 0){ + close(sensor.fdes); + sensor.fdes = -1; + } } } } @@ -124,55 +117,35 @@ static void *mainthread(void _U_ *U){ return NULL; } -static int init(int N, time_t pollt, int fd){ +static int init(struct sensordata_t *s, 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; + if(!s) return -1; + s->fdes = fd; + if(s->fdes < 0) return -1; sensor.PluginNo = N; - if(pollt) Tpoll = pollt; - fdes = fd; - if(fdes < 0) return -1; + if(pollt) s->tpoll = pollt; + if(pthread_create(&s->thread, NULL, mainthread, NULL)) return -1; + s->values = MALLOC(val_t, NS); + // don't use memcpy, as `values` could be aligned + for(int i = 0; i < NS; ++i) s->values[i] = values[i]; + if(!(s->ringbuffer = sl_RB_new(BUFSIZ))){ + WARNX("Can't init ringbuffer!"); + return -1; + } return NS; } -static int onrefresh(void (*handler)(const struct sensordata_t* const)){ - FNAME(); - if(!handler) return FALSE; - freshdatahandler = handler; +static int getval(struct sensordata_t *s, val_t *o, int N){ + if(!s || N < 0 || N >= NS) return FALSE; + if(o) *o = s->values[N]; 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, + .onrefresh = common_onrefresh, .get_value = getval, - .die = die, + .kill = common_kill, }; diff --git a/Daemons/weatherdaemon_multimeteo/sensors.c b/Daemons/weatherdaemon_multimeteo/sensors.c index 9fc1e07..c5d851c 100644 --- a/Daemons/weatherdaemon_multimeteo/sensors.c +++ b/Daemons/weatherdaemon_multimeteo/sensors.c @@ -46,15 +46,14 @@ int set_pollT(time_t t){ } /** - * @brief get_plugin - get copy of opened plugin + * @brief get_plugin - get link to opened plugin * @param o (o) - plugin with given index * @param N - index in `allplugins` - * @return TRUE if OK + * @return NULL if failed or pointer */ -int get_plugin(sensordata_t *o, int N){ - if(!o || N < 0 || N >= nplugins) return FALSE; - *o = *allplugins[N]; - return TRUE; +sensordata_t *get_plugin(int N){ + if(N < 0 || N >= nplugins) return NULL; + return allplugins[N]; } void *open_plugin(const char *name){ @@ -74,7 +73,7 @@ void *open_plugin(const char *name){ #ifdef EBUG // in release this function can be used for meteo logging -static void dumpsensors(const struct sensordata_t* const station){ +static void dumpsensors(struct sensordata_t* station){ FNAME(); if(!station || !station->get_value || station->Nvalues < 1) return; char buf[FULL_LEN+1]; @@ -82,7 +81,7 @@ static void dumpsensors(const struct sensordata_t* const station){ 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(!station->get_value(station, &v, i)) continue; if(0 < format_sensval(&v, buf, FULL_LEN+1, N)){ printf("%s\n", buf); ++nsum; Tsum += v.time; @@ -128,11 +127,11 @@ int openplugins(char **paths, int N){ } int fd = -1; if(colon) fd = getFD(colon); - int ns = S->init(nplugins, poll_interval, fd); // here nplugins is index in array + int ns = S->init(S, nplugins, poll_interval, fd); // here nplugins is index in array if(ns < 1) WARNXL("Can't init plugin %s", paths[i]); else{ #ifdef EBUG - if(!S->onrefresh(dumpsensors)) WARNXL("Can't init refresh funtion"); + if(!S->onrefresh(S, dumpsensors)) WARNXL("Can't init refresh funtion"); #endif LOGMSG("Plugin %s nave %d sensors", paths[i], ns); allplugins[nplugins++] = S; @@ -149,7 +148,7 @@ int openplugins(char **paths, int N){ void closeplugins(){ if(!allplugins || nplugins < 1) return; for(int i = 0; i < nplugins; ++i){ - if(allplugins[i]->die) allplugins[i]->die(); + if(allplugins[i]->kill) allplugins[i]->kill(allplugins[i]); } FREE(allplugins); nplugins = 0; diff --git a/Daemons/weatherdaemon_multimeteo/sensors.h b/Daemons/weatherdaemon_multimeteo/sensors.h index 9ec6d59..2b77da7 100644 --- a/Daemons/weatherdaemon_multimeteo/sensors.h +++ b/Daemons/weatherdaemon_multimeteo/sensors.h @@ -25,7 +25,7 @@ int openplugins(char **paths, int N); void closeplugins(); -int get_plugin(sensordata_t *o, int N); +sensordata_t *get_plugin(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); diff --git a/Daemons/weatherdaemon_multimeteo/server.c b/Daemons/weatherdaemon_multimeteo/server.c index 8d1b38d..98e5d0d 100644 --- a/Daemons/weatherdaemon_multimeteo/server.c +++ b/Daemons/weatherdaemon_multimeteo/server.c @@ -45,10 +45,10 @@ static sl_sock_hresult_e listhandler(sl_sock_t *client, _U_ sl_sock_hitem_t *ite char buf[256]; int N = get_nplugins(); if(N < 1) return RESULT_FAIL; - sensordata_t d; + sensordata_t *d = NULL; for(int i = 0; i < N; ++i){ - if(!get_plugin(&d, i)) continue; - snprintf(buf, 255, "PLUGIN[%d]=%s\nNVALUES[%d]=%d\n", i, d.name, i, d.Nvalues); + if(!(d = get_plugin(i))) continue; + snprintf(buf, 255, "PLUGIN[%d]=%s\nNVALUES[%d]=%d\n", i, d->name, i, d->Nvalues); sl_sock_sendstrmessage(client, buf); } return RESULT_SILENCE; @@ -63,8 +63,8 @@ static sl_sock_hresult_e listhandler(sl_sock_t *client, _U_ sl_sock_hitem_t *ite static void showdata(sl_sock_t *client, int N, int showidx){ char buf[FULL_LEN+1]; val_t v; - sensordata_t s; - if(!get_plugin(&s, N) || (s.Nvalues < 1)){ + sensordata_t *s = NULL; + if(!(s = get_plugin(N)) || (s->Nvalues < 1)){ snprintf(buf, FULL_LEN, "Can't get plugin[%d]\n", N); sl_sock_sendstrmessage(client, buf); return; @@ -72,8 +72,8 @@ static void showdata(sl_sock_t *client, int N, int showidx){ if(!showidx || get_nplugins() == 1) N = -1; // only one -> don't show indexes time_t oldest = time(NULL) - oldest_interval; uint64_t Tsum = 0; int nsum = 0; - for(int i = 0; i < s.Nvalues; ++i){ - if(!s.get_value(&v, i)) continue; + for(int i = 0; i < s->Nvalues; ++i){ + if(!s->get_value(s, &v, i)) continue; if(v.time < oldest) continue; if(1 > format_sensval(&v, buf, FULL_LEN+1, N)) continue; DBG("formatted: '%s'", buf); diff --git a/Daemons/weatherdaemon_multimeteo/weatherdaemon.files b/Daemons/weatherdaemon_multimeteo/weatherdaemon.files index fce6b66..35c7497 100644 --- a/Daemons/weatherdaemon_multimeteo/weatherdaemon.files +++ b/Daemons/weatherdaemon_multimeteo/weatherdaemon.files @@ -1,9 +1,14 @@ +CMakeLists.txt cmdlnopts.c cmdlnopts.h +fd.c +fd.h main.c plugins/dummy.c +plugins/fdexample.c sensors.c sensors.h server.c server.h +weathlib.c weathlib.h diff --git a/Daemons/weatherdaemon_multimeteo/weathlib.c b/Daemons/weatherdaemon_multimeteo/weathlib.c new file mode 100644 index 0000000..6393c8c --- /dev/null +++ b/Daemons/weatherdaemon_multimeteo/weathlib.c @@ -0,0 +1,66 @@ +/* + * 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 . + */ + +// Some common functions and handlers for sensors + +#include "weathlib.h" + +/** + * @brief sensor_alive - test if sensor's thread isn't dead + * @param s - sensor + * @return FALSE if thread is dead + */ +int sensor_alive(sensordata_t *s){ + if(!s) return FALSE; + if(pthread_kill(s->thread, 0)) return FALSE; + return TRUE; +} + +/** + * @brief common_onrefresh - common `change onrefresh handler` + * @param s - sensor + * @return FALSE if failed + */ +int common_onrefresh(sensordata_t *s, void (*handler)(sensordata_t *)){ + FNAME(); + if(!s || !handler) return FALSE; + s->freshdatahandler = handler; + return TRUE; +} + +/** + * @brief common_kill - common `die` function + * @param s - sensor + */ +void common_kill(sensordata_t *s){ + FNAME(); + if(!s) return; + if(0 == pthread_kill(s->thread, -9)){ + DBG("%s main thread killed, join", s->name); + pthread_join(s->thread, NULL); + DBG("Done"); + } + DBG("Delete RB"); + sl_RB_delete(&s->ringbuffer); + if(s->fdes > -1){ + close(s->fdes); + DBG("FD closed"); + } + FREE(s->values); + DBG("Sensor %s killed", s->name); +} diff --git a/Daemons/weatherdaemon_multimeteo/weathlib.h b/Daemons/weatherdaemon_multimeteo/weathlib.h index 8e07aca..1ed3f1c 100644 --- a/Daemons/weatherdaemon_multimeteo/weathlib.h +++ b/Daemons/weatherdaemon_multimeteo/weathlib.h @@ -18,8 +18,11 @@ #pragma once +#include +#include // pthread_kill #include #include +#include // length (in symbols) of key, value and comment #define KEY_LEN (8) @@ -81,12 +84,25 @@ typedef struct{ } val_t; // all sensor's data +// all functions have `this` as first arg 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, 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 + int (*init)(struct sensordata_t*, int, time_t, int); // init meteostation with given PluginNo, poll_interval and fd; return amount of parameters found or -1 if error + int (*onrefresh)(struct sensordata_t*, void (*handler)(struct sensordata_t*)); // handler of new data; return TRUE if OK + int (*get_value)(struct sensordata_t*, val_t*, int); // getter of Nth value + void (*kill)(struct sensordata_t*); // close everything and remove sensor + // private members: + val_t *values; // array of values + pthread_t thread; // main thread + void (*freshdatahandler)(struct sensordata_t*); // handler of fresh data + int fdes; // file descriptor of device/socket + sl_ringbuffer_t *ringbuffer; // ringbuffer for device reading + time_t tpoll; // forced polling time for sensor } sensordata_t; + +// library functions and other +int common_onrefresh(sensordata_t*, void (*handler)(sensordata_t*)); +void common_kill(sensordata_t *s); +int sensor_alive(sensordata_t *s);