From 5be6876f9e42a43b591db0714ea685e79faa3aec Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Thu, 9 Apr 2026 18:35:06 +0300 Subject: [PATCH] seems like it works --- .../weatherdaemon_multimeteo/CMakeLists.txt | 4 +- Daemons/weatherdaemon_multimeteo/cmdlnopts.c | 31 ++- .../weatherdaemon_multimeteo/mainweather.c | 26 ++- .../plugins/CMakeLists.txt | 5 + .../plugins/btameteo.c | 71 +++--- .../weatherdaemon_multimeteo/plugins/dummy.c | 77 +++---- .../plugins/fdexample.c | 75 +++--- .../plugins/hydreon.c | 75 +++--- .../plugins/reinhardt.c | 114 +++++---- .../weatherdaemon_multimeteo/plugins/wxa100.c | 216 ++++++++++++++++++ Daemons/weatherdaemon_multimeteo/sensors.c | 28 ++- .../weatherdaemon.files | 1 + Daemons/weatherdaemon_multimeteo/weathlib.c | 48 +++- Daemons/weatherdaemon_multimeteo/weathlib.h | 21 +- 14 files changed, 527 insertions(+), 265 deletions(-) create mode 100644 Daemons/weatherdaemon_multimeteo/plugins/wxa100.c diff --git a/Daemons/weatherdaemon_multimeteo/CMakeLists.txt b/Daemons/weatherdaemon_multimeteo/CMakeLists.txt index 0224c4f..333a1d7 100644 --- a/Daemons/weatherdaemon_multimeteo/CMakeLists.txt +++ b/Daemons/weatherdaemon_multimeteo/CMakeLists.txt @@ -18,10 +18,10 @@ option(FDEXAMPLE "Example of file descriptor plugin" ON) option(HYDREON "Hydreon rain sensor plugin" ON) option(BTAMETEO "BTA main meteostation plugin" ON) option(REINHARDT "Old Reinhardt meteostation plugin" ON) - +option(WXA100 "WXA100-06 meteostation plugin" ON) # default flags -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W -Wextra -pedantic-errors -fPIC") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W -Wextra -fPIC") message("Install dir prefix: ${CMAKE_INSTALL_PREFIX}") diff --git a/Daemons/weatherdaemon_multimeteo/cmdlnopts.c b/Daemons/weatherdaemon_multimeteo/cmdlnopts.c index 28c7b34..bff2445 100644 --- a/Daemons/weatherdaemon_multimeteo/cmdlnopts.c +++ b/Daemons/weatherdaemon_multimeteo/cmdlnopts.c @@ -107,13 +107,15 @@ sl_option_t confopts[] = { COMMON_OPTS end_option }; - +#if 0 static int sortstrings(const void *v1, const void *v2){ const char **s1 = (const char **)v1, **s2 = (const char **)v2; return strcmp(*s1, *s2); } +#endif // compare plugins from configuration and command line; add to command line plugins all new +// to use similar stations several times you should point for them different settings static void compplugins(glob_pars *cmdline, glob_pars *conf){ if(!cmdline) return; char **p; @@ -136,10 +138,28 @@ static void compplugins(glob_pars *cmdline, glob_pars *conf){ for(int i = 0; i < nconf; ++i){ newarray[i+ncmd] = conf->plugins[i]; } FREE(conf->plugins); } - qsort(newarray, newsize, sizeof(char*), sortstrings); + // don't sort: we need leave priority as user pointed + //qsort(newarray, newsize, sizeof(char*), sortstrings); DBG("NOW together:"); p = newarray; while(*p) printf("\t%s\n", *p++); - p = newarray; - int nondobuleidx = 0; + for(int i = 0; i < newsize-1; ++i){ + if(NULL == newarray[i]) continue; + for(int j = i+1; j < newsize; ++j){ + if(NULL == newarray[j]) continue; + if(0 == strcmp(newarray[i], newarray[j])) FREE(newarray[j]); + } + } + // now collect them in order + int nondoubleidx = 0; + for(int i = 0; i < newsize; ++i){ + if(newarray[i]){ + if(i != nondoubleidx){ + newarray[nondoubleidx] = newarray[i]; + newarray[i] = NULL; + } + ++nondoubleidx; + } + } +#if 0 for(int i = 0; i < newsize;){ int j = i + 1; for(; j < newsize; ++j){ @@ -153,9 +173,10 @@ static void compplugins(glob_pars *cmdline, glob_pars *conf){ ++nondobuleidx; i = j; } +#endif DBG("Result:"); p = newarray; while(*p) printf("\t%s\n", *p++); cmdline->plugins = newarray; - cmdline->nplugins = nondobuleidx; + cmdline->nplugins = nondoubleidx; } /** diff --git a/Daemons/weatherdaemon_multimeteo/mainweather.c b/Daemons/weatherdaemon_multimeteo/mainweather.c index 0c088da..1128b7f 100644 --- a/Daemons/weatherdaemon_multimeteo/mainweather.c +++ b/Daemons/weatherdaemon_multimeteo/mainweather.c @@ -66,7 +66,7 @@ static val_t collected_data[NAMOUNT_OF_DATA] = { [NAMB_TEMP] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_AMB_TEMP}, [NPRESSURE] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_PRESSURE}, [NPRECIP] = {.sense = VAL_OBLIGATORY, .type = VALT_UINT, .meaning = IS_PRECIP}, - [NPRECIP_LEVEL] = {.sense = VAL_OBLIGATORY, .type = VALT_INT, .meaning = IS_PRECIP_LEVEL}, + [NPRECIP_LEVEL] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_PRECIP_LEVEL}, [NMIST] = {.sense = VAL_OBLIGATORY, .type = VALT_UINT, .meaning = IS_MIST}, [NCLOUDS] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_CLOUDS}, [NSKYTEMP] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_SKYTEMP}, @@ -182,10 +182,10 @@ int get_collected(val_t *val, int N){ } static void fix_new_data(val_t *collected, val_t *fresh){ - FNAME(); if(!collected || !fresh) return; collected->time = fresh->time; if(collected->type == fresh->type){ // good case + DBG("Types are the same"); collected->value = fresh->value; return; } @@ -194,30 +194,36 @@ static void fix_new_data(val_t *collected, val_t *fresh){ case VALT_UINT: switch(fresh->type){ case VALT_INT: - collected->value.u = (uint32_t) collected->value.i; + collected->value.u = (uint32_t) fresh->value.i; + DBG("i->u"); break; case VALT_FLOAT: - collected->value.u = (uint32_t) collected->value.f; + collected->value.u = (uint32_t) fresh->value.f; + DBG("f->u"); default: break; } break; case VALT_INT: switch(fresh->type){ case VALT_UINT: - collected->value.i = (int32_t) collected->value.u; + collected->value.i = (int32_t) fresh->value.u; + DBG("u->i"); break; case VALT_FLOAT: - collected->value.i = (int32_t) collected->value.f; + collected->value.i = (int32_t) fresh->value.f; + DBG("f->i"); default: break; } break; case VALT_FLOAT: switch(fresh->type){ case VALT_UINT: - collected->value.f = (float) collected->value.u; + collected->value.f = (float) fresh->value.u; + DBG("u->f"); break; case VALT_INT: - collected->value.f = (float) collected->value.i; + collected->value.f = (float) fresh->value.i; + DBG("i->f"); default: break; } break; @@ -262,7 +268,7 @@ void refresh_sensval(sensordata_t *s){ double dir = -100., dir2 = -100.; // mean wind directions DBG("%d meteo values", s->Nvalues); for(int i = 0; i < s->Nvalues; ++i){ - DBG("Try to get %dth value", i); + DBG("\nTry to get %dth value", i); if(!s->get_value(s, &value, i)) continue; DBG("got value"); int idx = -1; @@ -321,7 +327,7 @@ void refresh_sensval(sensordata_t *s){ } if(idx < 0 || idx >= NAMOUNT_OF_DATA) continue; DBG("IDX=%d", idx); - time_t freshdelay = (s->PluginNo == 0) ? 0 : poll_time; // use data of less imrortant plugins only if our data is too old + time_t freshdelay = (s->PluginNo == 0) ? 0 : 90; // use data of less imrortant plugins only if our data is too old time_t curmt = collected_data[idx].time + freshdelay; if(value.time < curmt){ DBG("Data too old (value: %zd, curr: %zd", value.time, curmt); diff --git a/Daemons/weatherdaemon_multimeteo/plugins/CMakeLists.txt b/Daemons/weatherdaemon_multimeteo/plugins/CMakeLists.txt index 80fda8a..52dad20 100644 --- a/Daemons/weatherdaemon_multimeteo/plugins/CMakeLists.txt +++ b/Daemons/weatherdaemon_multimeteo/plugins/CMakeLists.txt @@ -37,4 +37,9 @@ if(REINHARDT) list(APPEND LIBS reinhardt) endif() +if(WXA100) + add_library(wxa100 SHARED wxa100.c) + list(APPEND LIBS wxa100) +endif() + install(TARGETS ${LIBS} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/Daemons/weatherdaemon_multimeteo/plugins/btameteo.c b/Daemons/weatherdaemon_multimeteo/plugins/btameteo.c index 3d7712a..b3813a9 100644 --- a/Daemons/weatherdaemon_multimeteo/plugins/btameteo.c +++ b/Daemons/weatherdaemon_multimeteo/plugins/btameteo.c @@ -19,6 +19,8 @@ #include "bta_shdata.h" #include "weathlib.h" +#define SENSOR_NAME "BTA 6-m telescope main meteostation" + enum{ NWIND, NHUMIDITY, @@ -28,67 +30,66 @@ enum{ NAMOUNT }; -extern sensordata_t sensor; - static const val_t values[NAMOUNT] = { - [NWIND] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_WIND}, - [NHUMIDITY] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_HUMIDITY}, - [NAMB_TEMP] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_AMB_TEMP}, - [NPRESSURE] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_PRESSURE}, - [NPRECIP] = {.sense = VAL_OBLIGATORY, .type = VALT_UINT, .meaning = IS_PRECIP}, + [NWIND] = {.sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_WIND}, + [NHUMIDITY] = {.sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_HUMIDITY}, + [NAMB_TEMP] = {.sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_AMB_TEMP}, + [NPRESSURE] = {.sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_PRESSURE}, + [NPRECIP] = {.sense = VAL_RECOMMENDED, .type = VALT_UINT, .meaning = IS_PRECIP}, }; -static void *mainthread(void _U_ *U){ +static void *mainthread(void *s){ FNAME(); + sensordata_t *sensor = (sensordata_t *)s; while(1){ if(check_shm_block(&sdat)){ DBG("Got next"); time_t tnow = time(NULL); - pthread_mutex_lock(&sensor.valmutex); + pthread_mutex_lock(&sensor->valmutex); for(int i = 0; i < NAMOUNT; ++i) - sensor.values[i].time = tnow; - sensor.values[NWIND].value.f = val_Wnd; - sensor.values[NPRESSURE].value.f = val_B; - sensor.values[NAMB_TEMP].value.f = val_T1; - sensor.values[NHUMIDITY].value.f = val_Hmd; + sensor->values[i].time = tnow; + sensor->values[NWIND].value.f = val_Wnd; + sensor->values[NPRESSURE].value.f = val_B; + sensor->values[NAMB_TEMP].value.f = val_T1; + sensor->values[NHUMIDITY].value.f = val_Hmd; DBG("Tprecip=%.1f, tnow=%.1f", Precip_time, sl_dtime()); - sensor.values[NPRECIP].value.u = (tnow - (time_t)Precip_time < 60) ? 1 : 0; - pthread_mutex_unlock(&sensor.valmutex); - if(sensor.freshdatahandler) sensor.freshdatahandler(&sensor); + sensor->values[NPRECIP].value.u = (tnow - (time_t)Precip_time < 60) ? 1 : 0; + pthread_mutex_unlock(&sensor->valmutex); + if(sensor->freshdatahandler) sensor->freshdatahandler(sensor); }else break; // no connection? sleep(1); } DBG("Lost connection -> suicide"); - common_kill(&sensor); + sensor->kill(sensor); return NULL; } -static int init(struct sensordata_t *s, int N, time_t pollt, int _U_ fd){ +sensordata_t *sensor_new(int N, time_t pollt, int _U_ fd){ FNAME(); - if(!s) return -1; - sensor.PluginNo = N; + sensordata_t *s = common_new(); + if(!s) return NULL; + s->PluginNo = N; if(pollt) s->tpoll = pollt; if(!get_shm_block(&sdat, ClientSide)){ - WARNX("Can't get BTA shared memory block"); - return -1; + WARNX("Can't get BTA shared memory block or create main thread"); + s->kill(s); + return NULL; } - if(pthread_create(&s->thread, NULL, mainthread, NULL)) return -1; s->values = MALLOC(val_t, NAMOUNT); for(int i = 0; i < NAMOUNT; ++i) s->values[i] = values[i]; - if(!(s->ringbuffer = sl_RB_new(BUFSIZ))){ + s->Nvalues = NAMOUNT; + strncpy(s->name, SENSOR_NAME, NAME_LEN); + /*if(!(s->ringbuffer = sl_RB_new(BUFSIZ))){ WARNX("Can't init ringbuffer!"); common_kill(s); return -1; + }*/ + if(pthread_create(&s->thread, NULL, mainthread, (void*)s)){ + WARN("Can't create main thread"); + s->kill(s); + return NULL; } - return NAMOUNT; + s->fdes = 0; + return s; } -sensordata_t sensor = { - .name = "BTA 6-m telescope main meteostation", - .Nvalues = NAMOUNT, - .init = init, - .onrefresh = common_onrefresh, - .valmutex = PTHREAD_MUTEX_INITIALIZER, - .get_value = common_getval, - .kill = common_kill, -}; diff --git a/Daemons/weatherdaemon_multimeteo/plugins/dummy.c b/Daemons/weatherdaemon_multimeteo/plugins/dummy.c index 62a7be2..eece63c 100644 --- a/Daemons/weatherdaemon_multimeteo/plugins/dummy.c +++ b/Daemons/weatherdaemon_multimeteo/plugins/dummy.c @@ -20,9 +20,9 @@ #include "weathlib.h" -#define NS (6) +#define SENSOR_NAME "Dummy weatherstation" -extern sensordata_t sensor; +#define NS (6) 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}, @@ -33,56 +33,55 @@ static const val_t values[NS] = { // fields `name` and `comment` have no sense u {.sense = VAL_OBLIGATORY, .type = VALT_UINT, .meaning = IS_PRECIP}, }; -static void *mainthread(void _U_ *U){ +static void *mainthread(void *s){ FNAME(); double t0 = sl_dtime(); + sensordata_t *sensor = (sensordata_t *)s; while(1){ DBG("locked"); - pthread_mutex_lock(&sensor.valmutex); - 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) / 2.; - 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; + pthread_mutex_lock(&sensor->valmutex); + 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) / 2.; + 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) sensor.values[i].time = cur; - pthread_mutex_unlock(&sensor.valmutex); + for(int i = 0; i < NS; ++i) sensor->values[i].time = cur; + pthread_mutex_unlock(&sensor->valmutex); DBG("unlocked"); - if(sensor.freshdatahandler) sensor.freshdatahandler(&sensor); - while(sl_dtime() - t0 < sensor.tpoll) usleep(500); + if(sensor->freshdatahandler) sensor->freshdatahandler(sensor); + while(sl_dtime() - t0 < sensor->tpoll) usleep(500); t0 = sl_dtime(); } return NULL; } -static int init(struct sensordata_t* s, int N, time_t pollt, int _U_ fd){ +sensordata_t *sensor_new(int N, time_t pollt, int _U_ fd){ FNAME(); - if(pthread_create(&s->thread, NULL, mainthread, NULL)) return 0; + sensordata_t *s = common_new(); + if(!s) return NULL; + s->Nvalues = NS; + strncpy(s->name, SENSOR_NAME, NAME_LEN); 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; - return NS; + s->values[0].value.f = 1.; + s->values[1].value.f = 180.; + s->values[2].value.f = 17.; + s->values[3].value.f = 600.; + s->values[4].value.f = 80.; + s->values[5].value.u = 0; + s->PluginNo = N; + if(pthread_create(&s->thread, NULL, mainthread, (void*)s)){ + s->kill(s); + return NULL; + } + s->fdes = 0; + return s; } - -sensordata_t sensor = { - .name = "Dummy weatherstation", - .Nvalues = NS, - .init = init, - .onrefresh = common_onrefresh, - .valmutex = PTHREAD_MUTEX_INITIALIZER, - .get_value = common_getval, - .kill = common_kill, -}; diff --git a/Daemons/weatherdaemon_multimeteo/plugins/fdexample.c b/Daemons/weatherdaemon_multimeteo/plugins/fdexample.c index c31f6be..7136804 100644 --- a/Daemons/weatherdaemon_multimeteo/plugins/fdexample.c +++ b/Daemons/weatherdaemon_multimeteo/plugins/fdexample.c @@ -23,10 +23,9 @@ // dummy example of file descriptors usage +#define SENSOR_NAME "Dummy socket or serial device weatherstation" #define NS (4) -extern sensordata_t sensor; - 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}, @@ -34,23 +33,23 @@ static const val_t values[NS] = { // fields `name` and `comment` have no sense u {.sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_HUMIDITY}, }; -static int format_values(char *buf){ +static int format_values(sensordata_t *sensor, char *buf){ int gotvals = 0; char *token = strtok(buf, ","); time_t tnow = time(NULL); + pthread_mutex_lock(&sensor->valmutex); while(token && gotvals < NS){ double v; DBG("TOKEN: %s", token); if(sl_str2d(&v, token)){ DBG("next value: %g", v); - pthread_mutex_lock(&sensor.valmutex); - sensor.values[gotvals].value.f = (float) v; - sensor.values[gotvals].time = tnow; - pthread_mutex_unlock(&sensor.valmutex); + sensor->values[gotvals].value.f = (float) v; + sensor->values[gotvals].time = tnow; ++gotvals; } token = strtok(NULL, ","); } + pthread_mutex_unlock(&sensor->valmutex); DBG("GOT: %d", gotvals); return gotvals; } @@ -79,72 +78,68 @@ static ssize_t writedata(int fd, const char *str, size_t size){ return sent; } -static void *mainthread(void _U_ *U){ +static void *mainthread(void *s){ FNAME(); time_t task = 0; const char begging[] = "Enter comma-separated data: wind, exttemp, pressure, humidity\n"; char buf[128]; - while(sensor.fdes > -1){ + sensordata_t *sensor = (sensordata_t *)s; + while(sensor->fdes > -1){ time_t tnow = time(NULL); - int canread = sl_canread(sensor.fdes); + int canread = sl_canread(sensor->fdes); if(canread < 0){ - WARNX("Disconnected fd %d", sensor.fdes); + WARNX("Disconnected fd %d", sensor->fdes); break; }else if(canread == 1){ - ssize_t got = read(sensor.fdes, buf, 128); + ssize_t got = read(sensor->fdes, buf, 128); if(got > 0){ - sl_RB_write(sensor.ringbuffer, (uint8_t*)buf, got); + sl_RB_write(sensor->ringbuffer, (uint8_t*)buf, got); }else if(got < 0){ DBG("Disconnected?"); break; } } - if(sl_RB_readline(sensor.ringbuffer, buf, 127) > 0){ - if(NS == format_values(buf) && sensor.freshdatahandler) - sensor.freshdatahandler(&sensor); + if(sl_RB_readline(sensor->ringbuffer, buf, 127) > 0){ + if(NS == format_values(sensor, buf) && sensor->freshdatahandler) + sensor->freshdatahandler(sensor); } - if(sensor.tpoll){ + 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; + 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; + close(sensor->fdes); + sensor->fdes = -1; } } } } DBG("OOOOps!"); - common_kill(&sensor); + sensor->kill(sensor); return NULL; } -static int init(struct sensordata_t *s, int N, time_t pollt, int fd){ +sensordata_t *sensor_new(int N, time_t pollt, int fd){ FNAME(); - if(!s) return -1; + if(fd < 0) return NULL; + sensordata_t *s = common_new(); + if(!s) return NULL; s->fdes = fd; - if(s->fdes < 0) return -1; - sensor.PluginNo = N; + s->PluginNo = N; if(pollt) s->tpoll = pollt; - if(pthread_create(&s->thread, NULL, mainthread, NULL)) return -1; + strncpy(s->name, SENSOR_NAME, NAME_LEN); 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!"); - common_kill(s); - return -1; + s->kill(s); + return NULL; } - return NS; + if(pthread_create(&s->thread, NULL, mainthread, (void*)s)){ + s->kill(s); + return NULL; + } + return s; } - -sensordata_t sensor = { - .name = "Dummy socket or serial device weatherstation", - .Nvalues = NS, - .init = init, - .onrefresh = common_onrefresh, - .valmutex = PTHREAD_MUTEX_INITIALIZER, - .get_value = common_getval, - .kill = common_kill, -}; diff --git a/Daemons/weatherdaemon_multimeteo/plugins/hydreon.c b/Daemons/weatherdaemon_multimeteo/plugins/hydreon.c index 80e3f32..e104661 100644 --- a/Daemons/weatherdaemon_multimeteo/plugins/hydreon.c +++ b/Daemons/weatherdaemon_multimeteo/plugins/hydreon.c @@ -23,6 +23,8 @@ // HYDREON rain sensor +#define SENSOR_NAME "Hydreon RG-11 rain sensor" + // amount of datafields #define RREGNUM 6 #define RGBITNUM 8 @@ -83,8 +85,6 @@ typedef struct{ uint8_t RainThr; // (??? == 12) } slowregs; -extern sensordata_t sensor; - enum{ NPRECIP = 0, NPRECIP_LEVEL, @@ -146,78 +146,71 @@ static int encodepacket(const char *buf, int len, rg11 *Rregs, slowregs *Sregs){ return TRUE; } -static void *mainthread(void _U_ *U){ +static void *mainthread(void *s){ FNAME(); char buf[128]; rg11 Rregs; slowregs Sregs; - while(sensor.fdes > -1){ + sensordata_t *sensor = (sensordata_t *)s; + while(sensor->fdes > -1){ time_t tnow = time(NULL); - int canread = sl_canread(sensor.fdes); + int canread = sl_canread(sensor->fdes); if(canread < 0){ - WARNX("Disconnected fd %d", sensor.fdes); + WARNX("Disconnected fd %d", sensor->fdes); break; }else if(canread == 1){ - ssize_t got = read(sensor.fdes, buf, 128); + ssize_t got = read(sensor->fdes, buf, 128); if(got > 0){ //DBG("write into buffer: %s[%zd]", buf, got); - sl_RB_write(sensor.ringbuffer, (uint8_t*)buf, got); + sl_RB_write(sensor->ringbuffer, (uint8_t*)buf, got); }else if(got < 0){ DBG("Disconnected?"); break; } } - int got = sl_RB_readto(sensor.ringbuffer, 's', (uint8_t*)buf, 127); + int got = sl_RB_readto(sensor->ringbuffer, 's', (uint8_t*)buf, 127); if(got > 0){ buf[--got] = 0; if(encodepacket(buf, got, &Rregs, &Sregs)){ DBG("refresh..."); - pthread_mutex_lock(&sensor.valmutex); + pthread_mutex_lock(&sensor->valmutex); for(int i = 0; i < NAMOUNT; ++i) - sensor.values[i].time = tnow; - sensor.values[NPRECIP].value.u = (Rregs.RGBits & (Raining | Storm)) ? 1 : 0; + sensor->values[i].time = tnow; + sensor->values[NPRECIP].value.u = (Rregs.RGBits & (Raining | Storm)) ? 1 : 0; float f = Sregs.Barrel * 256.f + Sregs.Bucket - 14.f; - sensor.values[NPRECIP_LEVEL].value.f = (f > 0.f) ? f : 0.f; - sensor.values[NSINCERN].value.u = Sregs.SinceRn; - sensor.values[NPOW].value.u = Rregs.PeakRS; - sensor.values[NAVG].value.u = Rregs.LRA; - sensor.values[NAMBL].value.u = Sregs.AmbLight; - sensor.values[NFREEZ].value.u = (Rregs.RGBits & Freeze) ? 1 : 0; - pthread_mutex_unlock(&sensor.valmutex); - if(sensor.freshdatahandler) sensor.freshdatahandler(&sensor); + sensor->values[NPRECIP_LEVEL].value.f = (f > 0.f) ? f : 0.f; + sensor->values[NSINCERN].value.u = Sregs.SinceRn; + sensor->values[NPOW].value.u = Rregs.PeakRS; + sensor->values[NAVG].value.u = Rregs.LRA; + sensor->values[NAMBL].value.u = Sregs.AmbLight; + sensor->values[NFREEZ].value.u = (Rregs.RGBits & Freeze) ? 1 : 0; + pthread_mutex_unlock(&sensor->valmutex); + if(sensor->freshdatahandler) sensor->freshdatahandler(sensor); } } } DBG("OOOOps!"); - common_kill(&sensor); + sensor->kill(sensor); return NULL; } -static int init(struct sensordata_t *s, int N, time_t pollt, int fd){ +sensordata_t *sensor_new(int N, time_t pollt, int fd){ FNAME(); - if(!s) return -1; + if(fd < 0) return NULL; + sensordata_t *s = common_new(); + if(!s) return NULL; + strncpy(s->name, SENSOR_NAME, NAME_LEN); s->fdes = fd; - if(s->fdes < 0) return -1; - sensor.PluginNo = N; + s->PluginNo = N; + s->Nvalues = NAMOUNT; if(pollt) s->tpoll = pollt; - if(pthread_create(&s->thread, NULL, mainthread, NULL)) return -1; s->values = MALLOC(val_t, NAMOUNT); // don't use memcpy, as `values` could be aligned for(int i = 0; i < NAMOUNT; ++i) s->values[i] = values[i]; - if(!(s->ringbuffer = sl_RB_new(BUFSIZ))){ - WARNX("Can't init ringbuffer!"); - common_kill(s); - return -1; + if(!(s->ringbuffer = sl_RB_new(BUFSIZ)) || + pthread_create(&s->thread, NULL, mainthread, (void*)s)){ + s->kill(s); + return NULL; } - return NAMOUNT; + return s; } - -sensordata_t sensor = { - .name = "Hydreon RG-11 rain sensor", - .Nvalues = NAMOUNT, - .init = init, - .onrefresh = common_onrefresh, - .valmutex = PTHREAD_MUTEX_INITIALIZER, - .get_value = common_getval, - .kill = common_kill, -}; diff --git a/Daemons/weatherdaemon_multimeteo/plugins/reinhardt.c b/Daemons/weatherdaemon_multimeteo/plugins/reinhardt.c index e05a262..afbc0db 100644 --- a/Daemons/weatherdaemon_multimeteo/plugins/reinhardt.c +++ b/Daemons/weatherdaemon_multimeteo/plugins/reinhardt.c @@ -20,6 +20,8 @@ #include "weathlib.h" +#define SENSOR_NAME "Old Reinhard meteostation" + //static const char *emultemplate = " 06:50:36, 20.01.00, TE-2.20, DR1405.50, WU2057.68, RT0.00, WK1.00, WR177.80, WT-2.20, FE0.69, RE0.00, WG7.36, WV260.03, TI0.00, FI0.00,"; enum{ @@ -34,17 +36,15 @@ enum{ NAMOUNT }; -extern sensordata_t sensor; - static const val_t values[NAMOUNT] = { - [NWIND] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_WIND}, + [NWIND] = {.sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_WIND}, [NWINDDIR] = {.sense = VAL_RECOMMENDED,.type = VALT_FLOAT, .meaning = IS_WINDDIR}, - [NHUMIDITY] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_HUMIDITY}, - [NAMB_TEMP] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_AMB_TEMP}, - [NPRESSURE] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_PRESSURE}, + [NHUMIDITY] = {.sense = VAL_BROKEN, .type = VALT_FLOAT, .meaning = IS_HUMIDITY}, + [NAMB_TEMP] = {.sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_AMB_TEMP}, + [NPRESSURE] = {.sense = VAL_BROKEN, .type = VALT_FLOAT, .meaning = IS_PRESSURE}, [NCLOUDS] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_CLOUDS}, - [NPRECIP] = {.sense = VAL_OBLIGATORY, .type = VALT_UINT, .meaning = IS_PRECIP}, - [NPRECIPLVL]= {.sense = VAL_RECOMMENDED,.type = VALT_FLOAT, .meaning = IS_PRECIP_LEVEL}, + [NPRECIP] = {.sense = VAL_RECOMMENDED, .type = VALT_UINT, .meaning = IS_PRECIP}, + [NPRECIPLVL]= {.sense = VAL_UNNECESSARY,.type = VALT_FLOAT, .meaning = IS_PRECIP_LEVEL}, }; /** @@ -70,124 +70,118 @@ static int getpar(char *string, double *Val, char *Name){ return TRUE; } -static void *mainthread(void _U_ *U){ +static void *mainthread(void *s){ FNAME(); char buf[BUFSIZ]; time_t tpoll = 0; - while(sensor.fdes > -1){ + sensordata_t *sensor = (sensordata_t *)s; + while(sensor->fdes > -1){ time_t tnow = time(NULL); - if(tnow - tpoll > sensor.tpoll){ - if(sl_tty_write(sensor.fdes, "?U\r\n", 4)){ + if(tnow - tpoll > sensor->tpoll){ + if(sl_tty_write(sensor->fdes, "?U\r\n", 4)){ WARN("Can't ask new data"); break; } - DBG("poll @%zd, pollt=%zd", tnow, sensor.tpoll); + DBG("poll @%zd, pollt=%zd", tnow, sensor->tpoll); tpoll = tnow; } - int canread = sl_canread(sensor.fdes); + int canread = sl_canread(sensor->fdes); if(canread < 0){ - WARNX("Disconnected fd %d", sensor.fdes); + WARNX("Disconnected fd %d", sensor->fdes); break; }else if(canread == 1){ - ssize_t got = read(sensor.fdes, buf, BUFSIZ); + ssize_t got = read(sensor->fdes, buf, BUFSIZ); if(got > 0){ - sl_RB_write(sensor.ringbuffer, (uint8_t*)buf, got); + sl_RB_write(sensor->ringbuffer, (uint8_t*)buf, got); }else if(got < 0){ DBG("Disconnected?"); break; } } - if(sl_RB_datalen(sensor.ringbuffer) > BUFSIZ-1){ + if(sl_RB_datalen(sensor->ringbuffer) > BUFSIZ-1){ WARNX("Overfull? Clear data from ring buffer"); - sl_RB_clearbuf(sensor.ringbuffer); + sl_RB_clearbuf(sensor->ringbuffer); } - if(sl_RB_readto(sensor.ringbuffer, '\n', (uint8_t*)buf, BUFSIZ-1) > 0){ + if(sl_RB_readto(sensor->ringbuffer, '\n', (uint8_t*)buf, BUFSIZ-1) > 0){ tnow = time(NULL); DBG("Got next: %s", buf); - pthread_mutex_lock(&sensor.valmutex); + pthread_mutex_lock(&sensor->valmutex); double d; //int Ngot = 0; if(getpar(buf, &d, "RE")){ //++Ngot; - sensor.values[NPRECIPLVL].value.f = (float) d; - sensor.values[NPRECIPLVL].time = tnow; + sensor->values[NPRECIPLVL].value.f = (float) d; + sensor->values[NPRECIPLVL].time = tnow; DBG("Got precip. lvl: %g", d); } if(getpar(buf, &d, "RT")){ //++Ngot; - sensor.values[NPRECIP].value.u = (d > 0.) ? 1 : 0; - sensor.values[NPRECIP].time = tnow; + sensor->values[NPRECIP].value.u = (d > 0.) ? 1 : 0; + sensor->values[NPRECIP].time = tnow; DBG("Got precip.: %g", d); } if(getpar(buf, &d, "WU")){ //++Ngot; - sensor.values[NCLOUDS].value.f = (float) d; - sensor.values[NCLOUDS].time = tnow; + sensor->values[NCLOUDS].value.f = (float) d; + sensor->values[NCLOUDS].time = tnow; DBG("Got clouds.: %g", d); } if(getpar(buf, &d, "TE")){ //++Ngot; - sensor.values[NAMB_TEMP].value.f = (float) d; - sensor.values[NAMB_TEMP].time = tnow; + sensor->values[NAMB_TEMP].value.f = (float) d; + sensor->values[NAMB_TEMP].time = tnow; DBG("Got ext. T: %g", d); } if(getpar(buf, &d, "WG")){ //++Ngot; d /= 3.6; DBG("Wind: %g", d); - sensor.values[NWIND].value.f = (float) d; - sensor.values[NWIND].time = tnow; + sensor->values[NWIND].value.f = (float) d; + sensor->values[NWIND].time = tnow; } if(getpar(buf, &d, "WR")){ //++Ngot; - sensor.values[NWINDDIR].value.f = (float) d; - sensor.values[NWINDDIR].time = tnow; + sensor->values[NWINDDIR].value.f = (float) d; + sensor->values[NWINDDIR].time = tnow; DBG("Winddir: %g", d); } if(getpar(buf, &d, "DR")){ //++Ngot; - sensor.values[NPRESSURE].value.f = (float) (d * 0.7500616); - sensor.values[NPRESSURE].time = tnow; + sensor->values[NPRESSURE].value.f = (float) (d * 0.7500616); + sensor->values[NPRESSURE].time = tnow; DBG("Pressure: %g", d); } if(getpar(buf, &d, "FE")){ //++Ngot; - sensor.values[NHUMIDITY].value.f = (float) d; - sensor.values[NHUMIDITY].time = tnow; + sensor->values[NHUMIDITY].value.f = (float) d; + sensor->values[NHUMIDITY].time = tnow; DBG("Humidity: %g", d); } - pthread_mutex_unlock(&sensor.valmutex); - if(sensor.freshdatahandler) sensor.freshdatahandler(&sensor); + pthread_mutex_unlock(&sensor->valmutex); + if(sensor->freshdatahandler) sensor->freshdatahandler(sensor); } } - common_kill(&sensor); + sensor->kill(sensor); return NULL; } -static int init(struct sensordata_t *s, int N, time_t pollt, int fd){ +sensordata_t *sensor_new(int N, time_t pollt, int fd){ FNAME(); - if(!s || fd < 0) return -1; - sensor.PluginNo = N; - sensor.fdes = fd; + if(fd < 0) return NULL; + sensordata_t *s = common_new(); + if(!s) return NULL; + s->Nvalues = NAMOUNT; + s->PluginNo = N; + s->fdes = fd; + strncpy(s->name, SENSOR_NAME, NAME_LEN); if(pollt) s->tpoll = pollt; - if(pthread_create(&s->thread, NULL, mainthread, NULL)) return -1; s->values = MALLOC(val_t, NAMOUNT); for(int i = 0; i < NAMOUNT; ++i) s->values[i] = values[i]; - if(!(s->ringbuffer = sl_RB_new(BUFSIZ))){ - WARNX("Can't init ringbuffer!"); - common_kill(s); - return -1; + if(!(s->ringbuffer = sl_RB_new(BUFSIZ)) || + pthread_create(&s->thread, NULL, mainthread, (void*)s)){ + s->kill(s); + return NULL; } - return NAMOUNT; + return s; } - -sensordata_t sensor = { - .name = "Old Reinhard meteostation", - .Nvalues = NAMOUNT, - .init = init, - .onrefresh = common_onrefresh, - .valmutex = PTHREAD_MUTEX_INITIALIZER, - .get_value = common_getval, - .kill = common_kill, -}; diff --git a/Daemons/weatherdaemon_multimeteo/plugins/wxa100.c b/Daemons/weatherdaemon_multimeteo/plugins/wxa100.c new file mode 100644 index 0000000..68a6fa4 --- /dev/null +++ b/Daemons/weatherdaemon_multimeteo/plugins/wxa100.c @@ -0,0 +1,216 @@ +/* + * 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 + +#include "weathlib.h" + +#define SENSOR_NAME "WXA100-06 ultrasonic meteostation" + +// static const char *emultemplate = "0R0,S=1.9,D=217.2,P=787.7,T=10.8,H=69.0,R=31.0,Ri=0.0,Rs=Y"; + +enum{ + NWIND, + NWINDDIR, + NHUMIDITY, + NAMB_TEMP, + NPRESSURE, + NPRECIP, + NPRECIPLVL, + NPRECIPINT, + NAMOUNT +}; + +static const val_t values[NAMOUNT] = { + [NWIND] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_WIND}, + [NWINDDIR] = {.sense = VAL_RECOMMENDED,.type = VALT_FLOAT, .meaning = IS_WINDDIR}, + [NHUMIDITY] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_HUMIDITY}, + [NAMB_TEMP] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_AMB_TEMP}, + [NPRESSURE] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_PRESSURE}, + [NPRECIP] = {.sense = VAL_OBLIGATORY, .type = VALT_UINT, .meaning = IS_PRECIP}, + [NPRECIPLVL]= {.sense = VAL_RECOMMENDED,.type = VALT_FLOAT, .meaning = IS_PRECIP_LEVEL}, + [NPRECIPINT]= {.sense = VAL_RECOMMENDED,.type = VALT_FLOAT, .meaning = IS_OTHER, .name = "PRECRATE", .comment = "Precipitation rate, mm/h"}, +}; + +typedef struct{ + double windspeed; // speed in m/s + double winddir; // direction from north + double pressure; // pressure in hPa + double temperature; // outern temperature in degC + double humidity; // humidity in percents + double rainfall; // cumulative rain level (mm) + double rainrate; // rain rate, mm/h + double israin; // ==1 if it's raining +} weather_t; + +typedef struct{ + const char *parname; // parameter started value + int isboolean; // ==1 if answer Y/N + int parlen; // parameter length in bytes + double *weatherpar; // data target +} wpair_t; + +static weather_t lastweather; + +static const wpair_t wpairs[] = { + {"S=", 0, 2, &lastweather.windspeed}, + {"D=", 0, 2, &lastweather.winddir}, + {"P=", 0, 2, &lastweather.pressure}, + {"T=", 0, 2, &lastweather.temperature}, + {"H=", 0, 2, &lastweather.humidity}, + {"R=", 0, 2, &lastweather.rainfall}, + {"Ri=",0, 3, &lastweather.rainrate}, + {"Rs=",1, 3, &lastweather.israin}, + {NULL, 0, 0, NULL} +}; + +static int parseans(char *str){ + int ncollected = 0; + if(strncmp(str, "0R0,", 4)){ + WARNX("Wrong answer"); + LOGWARN("poll_device() get wrong answer: %s", str); + return 0; + } + // init with NaNs + const wpair_t *el = wpairs; + while(el->parname){ + *el->weatherpar = NAN; + ++el; + } + char *token = strtok(str, ","); + while(token){ + el = wpairs; + while(el->parname){ + if(strncmp(token, el->parname, el->parlen) == 0){ // found next parameter + token += el->parlen; + char *endptr; + if(el->isboolean){ + *el->weatherpar = (*token == 'Y') ? 1. : 0.; + ++ncollected; + }else{ + *el->weatherpar = strtod(token, &endptr); + if(endptr == token){ + DBG("Wrong double value %s", token); + }else ++ncollected; + } + break; + } + ++el; + } + token = strtok(NULL, ","); + } + DBG("Got %d values", ncollected); + return ncollected; +} + +static void *mainthread(void *s){ + FNAME(); + char buf[BUFSIZ]; + time_t tpoll = 0; + sensordata_t *sensor = (sensordata_t *)s; + while(sensor->fdes > -1){ + time_t tnow = time(NULL); + if(tnow - tpoll > sensor->tpoll){ + if(sl_tty_write(sensor->fdes, "!0R0\r\n", 6)){ + WARN("Can't ask new data"); + break; + } + DBG("poll @%zd, pollt=%zd", tnow, sensor->tpoll); + tpoll = tnow; + } + int canread = sl_canread(sensor->fdes); + if(canread < 0){ + WARNX("Disconnected fd %d", sensor->fdes); + break; + }else if(canread == 1){ + ssize_t got = read(sensor->fdes, buf, BUFSIZ); + if(got > 0){ + sl_RB_write(sensor->ringbuffer, (uint8_t*)buf, got); + }else if(got < 0){ + DBG("Disconnected?"); + break; + } + } + if(sl_RB_datalen(sensor->ringbuffer) > BUFSIZ-1){ + WARNX("Overfull? Clear data from ring buffer"); + sl_RB_clearbuf(sensor->ringbuffer); + } + if(sl_RB_readline(sensor->ringbuffer, buf, BUFSIZ-1) > 0 && parseans(buf) > 0){ + tnow = time(NULL); + pthread_mutex_lock(&sensor->valmutex); + if(!isnan(lastweather.rainfall)){ + sensor->values[NPRECIPLVL].value.f = (float) lastweather.rainfall; + sensor->values[NPRECIPLVL].time = tnow; + } + if(!isnan(lastweather.rainrate)){ + sensor->values[NPRECIPINT].value.f = (float) lastweather.rainrate; + sensor->values[NPRECIPINT].time = tnow; + } + if(!isnan(lastweather.israin)){ + sensor->values[NPRECIP].value.u = (lastweather.israin > 0.) ? 1 : 0; + sensor->values[NPRECIP].time = tnow; + } + if(!isnan(lastweather.temperature)){ + sensor->values[NAMB_TEMP].value.f = (float) lastweather.temperature; + sensor->values[NAMB_TEMP].time = tnow; + } + if(!isnan(lastweather.windspeed)){ + sensor->values[NWIND].value.f = (float) lastweather.windspeed; + sensor->values[NWIND].time = tnow; + } + if(!isnan(lastweather.winddir)){ + sensor->values[NWINDDIR].value.f = (float) lastweather.winddir; + sensor->values[NWINDDIR].time = tnow; + } + if(!isnan(lastweather.pressure)){ + sensor->values[NPRESSURE].value.f = (float) (lastweather.pressure * 0.7500616); // mmHg instead of hPa! + sensor->values[NPRESSURE].time = tnow; + } + if(!isnan(lastweather.humidity)){ + sensor->values[NHUMIDITY].value.f = (float) lastweather.humidity; + sensor->values[NHUMIDITY].time = tnow; + } + pthread_mutex_unlock(&sensor->valmutex); + if(sensor->freshdatahandler) sensor->freshdatahandler(sensor); + } + } + sensor->kill(sensor); + return NULL; +} + +sensordata_t *sensor_new(int N, time_t pollt, int fd){ + FNAME(); + if(fd < 0) return NULL; + sensordata_t *s = common_new(); + if(!s) return NULL; + strncpy(s->name, SENSOR_NAME, NAME_LEN); + s->PluginNo = N; + s->fdes = fd; + s->Nvalues = NAMOUNT; + if(pollt) s->tpoll = pollt; + s->values = MALLOC(val_t, NAMOUNT); + for(int i = 0; i < NAMOUNT; ++i) s->values[i] = values[i]; + if(!(s->ringbuffer = sl_RB_new(BUFSIZ)) || + pthread_create(&s->thread, NULL, mainthread, (void*)s)){ + s->kill(s); + return NULL; + } + return s; +} + diff --git a/Daemons/weatherdaemon_multimeteo/sensors.c b/Daemons/weatherdaemon_multimeteo/sensors.c index 6539c1d..9ede2d3 100644 --- a/Daemons/weatherdaemon_multimeteo/sensors.c +++ b/Daemons/weatherdaemon_multimeteo/sensors.c @@ -60,12 +60,16 @@ sensordata_t *get_plugin(int N){ return allplugins[N]; } +// TODO: fix for usage with several identical meteostations void *open_plugin(const char *name){ DBG("try to open lib %s", name); - void* dlh = dlopen(name, RTLD_NOLOAD); // library may be already opened + void* dlh = dlopen(name, RTLD_NOW | RTLD_NOLOAD); // library may be already opened if(!dlh){ DBG("Not loaded - load"); dlh = dlopen(name, RTLD_NOW); + }else{ + WARNX("Library %s already opened", name); + //return NULL; } if(!dlh){ char *e = dlerror(); @@ -131,24 +135,18 @@ int openplugins(char **paths, int N){ void* dlh = open_plugin(buf); if(!dlh) continue; DBG("OPENED"); - void *s = dlsym(dlh, "sensor"); - if(s){ - sensordata_t *S = (sensordata_t*) s; - if(!S->get_value) WARNXL("Sensor library %s have no values' getter!", paths[i]); - if(!S->init){ - WARNXL("Sensor library %s have no init funtion"); - continue; - } + sensor_new_t sensnew = (sensor_new_t) dlsym(dlh, "sensor_new"); + if(sensnew){ int fd = -1; if(colon) fd = getFD(colon); - 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]); + sensordata_t *S = sensnew(nplugins, poll_interval, fd); // here nplugins is index in array + if(!S) WARNXL("Can't init plugin %s", paths[i]); else{ if(!S->onrefresh || !S->onrefresh(S, dumpsensors)) WARNXL("Can't init refresh funtion"); - LOGMSG("Plugin %s nave %d sensors", paths[i], ns); + LOGMSG("Plugin %s nave %d sensors", paths[i], S->Nvalues); allplugins[nplugins++] = S; } - }else WARNXL("Can't find field `sensor` in plugin %s: %s", paths[i], dlerror()); + }else WARNXL("Can't find initing function in plugin %s: %s", paths[i], dlerror()); } return nplugins; } @@ -207,9 +205,9 @@ int format_sensval(const val_t *v, char *buf, int buflen, int Np){ [IS_HW_TEMP] = "Hardware (mirror?) termperature, degC", [IS_PRESSURE] = "Atmospheric pressure, mmHg", [IS_PRECIP] = "Precipitation (1 - yes, 0 - no)", - [IS_PRECIP_LEVEL]="Precipitation level (mm)", + [IS_PRECIP_LEVEL]="Cumulative precipitation level (mm)", [IS_MIST] = "Mist (1 - yes, 0 - no)", - [IS_CLOUDS] = "Integral clouds value (bigger - better)", + [IS_CLOUDS] = "Integral sky quality value (bigger - better)", [IS_SKYTEMP] = "Mean sky temperatyre" }; const char *name = NULL, *comment = NULL; diff --git a/Daemons/weatherdaemon_multimeteo/weatherdaemon.files b/Daemons/weatherdaemon_multimeteo/weatherdaemon.files index 8d51059..0c25e69 100644 --- a/Daemons/weatherdaemon_multimeteo/weatherdaemon.files +++ b/Daemons/weatherdaemon_multimeteo/weatherdaemon.files @@ -13,6 +13,7 @@ plugins/dummy.c plugins/fdexample.c plugins/hydreon.c plugins/reinhardt.c +plugins/wxa100.c sensors.c sensors.h server.c diff --git a/Daemons/weatherdaemon_multimeteo/weathlib.c b/Daemons/weatherdaemon_multimeteo/weathlib.c index 4c35d7a..af45d63 100644 --- a/Daemons/weatherdaemon_multimeteo/weathlib.c +++ b/Daemons/weatherdaemon_multimeteo/weathlib.c @@ -18,15 +18,37 @@ // Some common functions and handlers for sensors +#include + #include "weathlib.h" +// private functions (for plugins usage only) +static int common_onrefresh(sensordata_t*, void (*handler)(sensordata_t*)); +static void common_kill(sensordata_t *); +static int common_getval(sensordata_t*, val_t*, int); +//static int common_init(sensordata_t*, int, time_t, int); + +/** + * @brief common_new - call this function from your plugin's `sensor_new` + * @return + */ +sensordata_t *common_new(){ + sensordata_t *s = MALLOC(sensordata_t, 1); + s->fdes = -1; // not inited + s->onrefresh = common_onrefresh; + s->get_value = common_getval; + s->kill = common_kill; + pthread_mutex_init(&s->valmutex, NULL); + return s; +} + /** * @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(!s || s->fdes < 0) return FALSE; if(pthread_kill(s->thread, 0)) return FALSE; return TRUE; } @@ -50,19 +72,23 @@ int common_onrefresh(sensordata_t *s, void (*handler)(sensordata_t *)){ void common_kill(sensordata_t *s){ FNAME(); if(!s) return; - if(0 == pthread_cancel(s->thread)){ - DBG("%s main thread canceled, join", s->name); - pthread_join(s->thread, NULL); - DBG("Done"); + if(s->fdes > -1){ // inited and maybe have opened file/socket + if(0 == pthread_cancel(s->thread)){ + DBG("%s main thread canceled, join", s->name); + pthread_join(s->thread, NULL); + DBG("Done"); + } + close(s->fdes); } DBG("Delete RB"); - sl_RB_delete(&s->ringbuffer); - if(s->fdes > -1){ - close(s->fdes); - DBG("FD closed"); - } + if(s->ringbuffer) sl_RB_delete(&s->ringbuffer); FREE(s->values); - DBG("Sensor %s killed", s->name); + if(s->privdatafree) s->privdatafree(s->privdata); + else FREE(s->privdata); + DBG("Sensor '%s' killed", s->name); + LOGERR("Sensor '%s' killed", s->name); + FREE(s); + DBG("There's no more this sensor"); } /** diff --git a/Daemons/weatherdaemon_multimeteo/weathlib.h b/Daemons/weatherdaemon_multimeteo/weathlib.h index 47f9e9b..e518c18 100644 --- a/Daemons/weatherdaemon_multimeteo/weathlib.h +++ b/Daemons/weatherdaemon_multimeteo/weathlib.h @@ -21,6 +21,7 @@ #include #include // pthread_kill #include +#include #include #include @@ -89,7 +90,6 @@ 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)(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 @@ -97,14 +97,21 @@ typedef struct sensordata_t{ val_t *values; // array of values pthread_t thread; // main thread pthread_mutex_t valmutex;// value getter/setter mutex - void (*freshdatahandler)(struct sensordata_t*); // handler of fresh data - int fdes; // file descriptor of device/socket + // !!! if your plugin don't use file descriptor, you should set fdes to any non-negative value after running main thread + int fdes; // file descriptor of device/socket or "init" flag (should be > -1) sl_ringbuffer_t *ringbuffer; // ringbuffer for device reading time_t tpoll; // forced polling time for sensor + void (*freshdatahandler)(struct sensordata_t*); // handler of fresh data + void (*privdatafree)(void*); // free private data (if don't wanna write own `kill` instead of `common kill` + void *privdata; // some private data like struct } sensordata_t; -// library functions and other -int common_onrefresh(sensordata_t*, void (*handler)(sensordata_t*)); -void common_kill(sensordata_t *s); +// type for function extraction +typedef sensordata_t* (*sensor_new_t)(int, time_t, int); + +// init meteostation with given PluginNo, poll_interval and fd +sensordata_t *sensor_new(int PluginNo, time_t poll_interval, int fd); // external initial function for any plugin int sensor_alive(sensordata_t *s); -int common_getval(struct sensordata_t *s, val_t *o, int N); + +// private function (for plugins usage only) +sensordata_t *common_new();