mirror of
https://github.com/eddyem/small_tel.git
synced 2025-12-06 02:35:14 +03:00
seems like it works
This commit is contained in:
parent
61acba7e17
commit
a7c53df2e7
@ -4,7 +4,7 @@ LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-a
|
|||||||
LDFLAGS += -flto `pkg-config --libs usefull_macros` -lm
|
LDFLAGS += -flto `pkg-config --libs usefull_macros` -lm
|
||||||
SRCS := $(wildcard *.c)
|
SRCS := $(wildcard *.c)
|
||||||
DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111
|
DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111
|
||||||
#DEFINES += -DEBUG
|
DEFINES += -DEBUG
|
||||||
OBJDIR := mk
|
OBJDIR := mk
|
||||||
CFLAGS += `pkg-config --cflags usefull_macros` -O3 -Wall -Werror -Wextra -Wno-trampolines -flto
|
CFLAGS += `pkg-config --cflags usefull_macros` -O3 -Wall -Werror -Wextra -Wno-trampolines -flto
|
||||||
OBJS := $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o))
|
OBJS := $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o))
|
||||||
|
|||||||
@ -42,23 +42,34 @@ extern glob_pars *GP;
|
|||||||
|
|
||||||
static weather_t lastweather = {0};
|
static weather_t lastweather = {0};
|
||||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
static weatherstat_t wstat;
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
FORMAT_ERROR, // send user an error message
|
||||||
|
FORMAT_CURDFULL, // param=value for current data
|
||||||
|
FORMAT_CURDSHORT, // comma-separated current data
|
||||||
|
FORMAT_STATFULL, // param=value for stat
|
||||||
|
FORMAT_STATSHORT // comma-separated stat
|
||||||
|
} format_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**************** SERVER FUNCTIONS ****************/
|
/**************** SERVER FUNCTIONS ****************/
|
||||||
/**
|
/**
|
||||||
* Send data over socket
|
* Send data over socket
|
||||||
* @param sock - socket fd
|
* @param sock - socket fd
|
||||||
* @param webquery - ==1 if this is web query
|
* @param webquery - ==1 if this is web query
|
||||||
* @param format - 1 - full (param=value), 0 - simple (comma-separated)
|
* @param format - data format
|
||||||
* @return 1 if all OK
|
* @return 1 if all OK
|
||||||
*/
|
*/
|
||||||
static int send_data(int sock, int webquery, int format){
|
static int send_data(int sock, int webquery, format_t format){
|
||||||
char tbuf[BUFSIZ]; // buffer to send
|
char tbuf[BUFSIZ]; // buffer to send
|
||||||
char databuf[BUFSIZ]; // buffer with data
|
char databuf[BUFSIZ]; // buffer with data
|
||||||
ssize_t Len = 0;
|
ssize_t Len = 0;
|
||||||
const char *eol = webquery ? "\r\n" : "\n";
|
const char *eol = webquery ? "\r\n" : "\n";
|
||||||
// fill buffer with data
|
// fill buffer with data
|
||||||
pthread_mutex_lock(&mutex);
|
pthread_mutex_lock(&mutex);
|
||||||
if(format){ // full format
|
if(format == FORMAT_CURDFULL){ // full format
|
||||||
Len = snprintf(databuf, BUFSIZ,
|
Len = snprintf(databuf, BUFSIZ,
|
||||||
"Wind=%.1f%sDir=%.1f%sPressure=%.1f%sTemperature=%.1f%sHumidity=%.1f%s"
|
"Wind=%.1f%sDir=%.1f%sPressure=%.1f%sTemperature=%.1f%sHumidity=%.1f%s"
|
||||||
"Rain=%.1f%sTime=%.3f%s",
|
"Rain=%.1f%sTime=%.3f%s",
|
||||||
@ -66,13 +77,48 @@ static int send_data(int sock, int webquery, int format){
|
|||||||
lastweather.temperature, eol, lastweather.humidity, eol, lastweather.rainfall, eol,
|
lastweather.temperature, eol, lastweather.humidity, eol, lastweather.rainfall, eol,
|
||||||
lastweather.tmeasure, eol
|
lastweather.tmeasure, eol
|
||||||
);
|
);
|
||||||
}else{ // short format
|
}else if(format == FORMAT_CURDSHORT){ // short format
|
||||||
Len = snprintf(databuf, BUFSIZ,
|
Len = snprintf(databuf, BUFSIZ,
|
||||||
"%.3f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f%s",
|
"%.3f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f%s",
|
||||||
lastweather.tmeasure, lastweather.windspeed, lastweather.winddir,
|
lastweather.tmeasure, lastweather.windspeed, lastweather.winddir,
|
||||||
lastweather.pressure, lastweather.temperature, lastweather.humidity,
|
lastweather.pressure, lastweather.temperature, lastweather.humidity,
|
||||||
lastweather.rainfall, eol
|
lastweather.rainfall, eol
|
||||||
);
|
);
|
||||||
|
}else if(format == FORMAT_STATFULL){
|
||||||
|
char *ptr = databuf;
|
||||||
|
int l = BUFSIZ;
|
||||||
|
#define PRSTAT(field, nm) do{register int lc = snprintf(ptr, l, \
|
||||||
|
nm "max=%.1f%s" nm "min=%.1f%s" nm "mean=%.1f%s" nm "rms=%.1f%s", \
|
||||||
|
wstat.field.max, eol, wstat.field.min, eol, wstat.field.mean, eol, wstat.field.rms, eol); \
|
||||||
|
Len += lc; l -= lc; ptr += lc;}while(0)
|
||||||
|
PRSTAT(windspeed, "Wind");
|
||||||
|
PRSTAT(winddir, "Dir");
|
||||||
|
PRSTAT(pressure, "Pressure");
|
||||||
|
PRSTAT(temperature, "Temperature");
|
||||||
|
PRSTAT(humidity, "Humidity");
|
||||||
|
PRSTAT(rainfall, "Rain");
|
||||||
|
PRSTAT(tmeasure, "Time");
|
||||||
|
#undef PRSTAT
|
||||||
|
}else if(format == FORMAT_STATSHORT){
|
||||||
|
char *ptr = databuf;
|
||||||
|
int l = BUFSIZ;
|
||||||
|
register int lc;
|
||||||
|
#define PRSTAT(field, nm) do{lc = snprintf(ptr, l, \
|
||||||
|
"%.1f,%.1f,%.1f,%.1f", \
|
||||||
|
wstat.field.max, wstat.field.min, wstat.field.mean, wstat.field.rms); \
|
||||||
|
Len += lc; l -= lc; ptr += lc;}while(0)
|
||||||
|
#define COMMA() do{lc = snprintf(ptr, l, ","); Len += lc; l -= lc; ptr += lc;}while(0)
|
||||||
|
PRSTAT(windspeed, "Wind"); COMMA();
|
||||||
|
PRSTAT(winddir, "Dir"); COMMA();
|
||||||
|
PRSTAT(pressure, "Pressure"); COMMA();
|
||||||
|
PRSTAT(temperature, "Temperature"); COMMA();
|
||||||
|
PRSTAT(humidity, "Humidity"); COMMA();
|
||||||
|
PRSTAT(rainfall, "Rain"); COMMA();
|
||||||
|
PRSTAT(tmeasure, "Time");
|
||||||
|
Len += snprintf(ptr, l, "%s", eol);
|
||||||
|
#undef PRSTAT
|
||||||
|
}else{
|
||||||
|
Len = snprintf(databuf, BUFSIZ, "Error!");
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&mutex);
|
pthread_mutex_unlock(&mutex);
|
||||||
// OK buffer ready, prepare to send it
|
// OK buffer ready, prepare to send it
|
||||||
@ -86,21 +132,21 @@ static int send_data(int sock, int webquery, int format){
|
|||||||
if(L < 0){
|
if(L < 0){
|
||||||
WARN("sprintf()");
|
WARN("sprintf()");
|
||||||
LOGWARN("sprintf()");
|
LOGWARN("sprintf()");
|
||||||
return 0;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if(L != write(sock, tbuf, L)){
|
if(L != write(sock, tbuf, L)){
|
||||||
LOGWARN("Can't write header");
|
LOGWARN("Can't write header");
|
||||||
WARN("write");
|
WARN("write");
|
||||||
return 0;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(Len != write(sock, databuf, Len)){
|
if(Len != write(sock, databuf, Len)){
|
||||||
WARN("write()");
|
WARN("write()");
|
||||||
LOGERR("send_data(): write() failed");
|
LOGERR("send_data(): write() failed");
|
||||||
return 0;
|
return FALSE;
|
||||||
}
|
}
|
||||||
//LOGDBG("fd %d, write %s", sock, textbuf);
|
//LOGDBG("fd %d, write %s", sock, textbuf);
|
||||||
return 1;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// search a first word after needle without spaces
|
// search a first word after needle without spaces
|
||||||
@ -115,6 +161,15 @@ static char* stringscan(char *str, char *needle){
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double getpar(const char *s){
|
||||||
|
double x = -1.;
|
||||||
|
char *eptr = NULL;
|
||||||
|
while(*s && *s <= ' ') ++s;
|
||||||
|
x = strtod(s, &eptr);
|
||||||
|
if(eptr == s) x = -1.;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief handle_socket - read information from socket
|
* @brief handle_socket - read information from socket
|
||||||
* @param sock - socket fd
|
* @param sock - socket fd
|
||||||
@ -142,7 +197,7 @@ static int handle_socket(int sock){
|
|||||||
// now we should check what do user want
|
// now we should check what do user want
|
||||||
char *found = buff;
|
char *found = buff;
|
||||||
DBG("user send: %s", buff);
|
DBG("user send: %s", buff);
|
||||||
int format = 1; // text format - default for web-queries
|
format_t format = FORMAT_CURDFULL; // text format - default for web-queries
|
||||||
|
|
||||||
if(0 == strncmp(buff, "GET", 3)){
|
if(0 == strncmp(buff, "GET", 3)){
|
||||||
DBG("GET");
|
DBG("GET");
|
||||||
@ -164,10 +219,15 @@ static int handle_socket(int sock){
|
|||||||
int l = strlen(buff);
|
int l = strlen(buff);
|
||||||
if(contlen && l > contlen) found = &buff[l - contlen];
|
if(contlen && l > contlen) found = &buff[l - contlen];
|
||||||
}
|
}
|
||||||
}else if(0 == strncmp(buff, "simple", 6)) format = 0; // simple format
|
}else if(0 == strncmp(buff, "simple", 6)) format = FORMAT_CURDSHORT; // simple format
|
||||||
else if(0 == strncmp(buff, "stat", 4)){ // show stat
|
else if(0 == strncmp(buff, "stat", 4)){ // show stat
|
||||||
stat_for(90.);
|
double dt = -1.; int l = 4;
|
||||||
return 0;
|
if(0 == strncmp(buff, "statsimple", 10)){
|
||||||
|
l = 10; format = FORMAT_STATSHORT;
|
||||||
|
}else format = FORMAT_STATFULL;
|
||||||
|
dt = getpar(buff + l);
|
||||||
|
if(dt < 1.) dt = 900.; // 15 minutes - default
|
||||||
|
if(stat_for(dt, &wstat) < 1.) format = FORMAT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// here we can process user data
|
// here we can process user data
|
||||||
|
|||||||
@ -69,8 +69,11 @@ void addtobuf(weather_t *record){
|
|||||||
pthread_mutex_unlock(&mutex);
|
pthread_mutex_unlock(&mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// get statistics for last `Tsec` seconds; @return real dT for given interval
|
// get statistics for last `Tsec` seconds; @return real dT for given interval
|
||||||
double stat_for(double Tsec/*, weather_t *w*/){
|
double stat_for(double Tsec, weatherstat_t *wstat){
|
||||||
|
if(!wstat || Tsec < 1.) return 0.;
|
||||||
double dt = 0., tlast = buf[lastidx].tmeasure;
|
double dt = 0., tlast = buf[lastidx].tmeasure;
|
||||||
size_t startfrom = lastidx;
|
size_t startfrom = lastidx;
|
||||||
pthread_mutex_lock(&mutex);
|
pthread_mutex_lock(&mutex);
|
||||||
@ -80,26 +83,64 @@ double stat_for(double Tsec/*, weather_t *w*/){
|
|||||||
else --startfrom;
|
else --startfrom;
|
||||||
}
|
}
|
||||||
dt = tlast - buf[startfrom].tmeasure;
|
dt = tlast - buf[startfrom].tmeasure;
|
||||||
DBG("got indexes: start=%zd, end=%zd, dt=%.2f", startfrom, lastidx, dt);
|
// DBG("got indexes: start=%zd, end=%zd, dt=%.2f", startfrom, lastidx, dt);
|
||||||
weather_t min = {0}, max = {0}, sum = {0}, sum2 = {0};
|
weather_t min = {0}, max = {0}, sum = {0}, sum2 = {0};
|
||||||
size_t amount = 0;
|
size_t amount = 0;
|
||||||
memcpy(&min, &buf[lastidx], sizeof(weather_t));
|
memcpy(&min, &buf[lastidx], sizeof(weather_t));
|
||||||
|
min.tmeasure = buf[startfrom].tmeasure;
|
||||||
|
max.tmeasure = buf[lastidx].tmeasure;
|
||||||
|
double tmean = (max.tmeasure+min.tmeasure)/2.;
|
||||||
|
// DBG("tmean=%.1f, min=%.1f, max=%.1f", tmean, min.tmeasure, max.tmeasure);
|
||||||
|
size_t st = startfrom;
|
||||||
|
// calculate amount of north and south winds
|
||||||
|
size_t north = 0, south = 0;
|
||||||
|
while(st != lastidx){
|
||||||
|
double w = buf[st].winddir;
|
||||||
|
if(w < 90. || w > 300.) ++north;
|
||||||
|
else ++south;
|
||||||
|
if(++st == buflen) st = 0;
|
||||||
|
}
|
||||||
|
double wminus = 0.;
|
||||||
|
if(north > 2*south) wminus = 360.;
|
||||||
while(startfrom != lastidx){
|
while(startfrom != lastidx){
|
||||||
weather_t *curw = &buf[startfrom];
|
weather_t *curw = &buf[startfrom];
|
||||||
#define CHK(field) do{register double d = curw->field; if(d > max.field) max.field = d; else if(d < min.field) min.field = d; \
|
#define CHK(field) do{register double d = curw->field; if(d > max.field) max.field = d; if(d < min.field) min.field = d; \
|
||||||
sum.field += d; sum2.field += d*d;}while(0)
|
sum.field += d; sum2.field += d*d;}while(0)
|
||||||
CHK(windspeed);
|
CHK(windspeed);
|
||||||
|
register double s = curw->windspeed, sd = (curw->winddir - wminus) * s;
|
||||||
|
if(s > max.winddir) max.winddir = s;
|
||||||
|
if(s < min.winddir) min.winddir = s;
|
||||||
|
sum.winddir += sd;
|
||||||
|
sum2.winddir += sd * s; // v * dir^2
|
||||||
CHK(pressure);
|
CHK(pressure);
|
||||||
CHK(temperature);
|
CHK(temperature);
|
||||||
CHK(humidity);
|
CHK(humidity);
|
||||||
CHK(rainfall);
|
CHK(rainfall);
|
||||||
|
s = curw->tmeasure;
|
||||||
|
sum.tmeasure += s; s -= tmean;
|
||||||
|
sum2.tmeasure += s * s; // correct tmeasure by mean time to exclude cumulative error of double
|
||||||
|
#undef CHK
|
||||||
++amount;
|
++amount;
|
||||||
if(++startfrom == buflen) startfrom = 0;
|
if(++startfrom == buflen) startfrom = 0;
|
||||||
}
|
}
|
||||||
DBG("Got %zd records", amount);
|
// DBG("Got %zd records; tsum/sum2: %g/%g", amount, sum.tmeasure, sum2.tmeasure);
|
||||||
double wmean = sum.windspeed/amount;
|
wstat->winddir.max = max.winddir;
|
||||||
DBG("wind min/max/mean/rms=%.1f/%.1f/%.1f/%.1f", min.windspeed, max.windspeed,
|
wstat->winddir.min = min.winddir;
|
||||||
wmean, sqrt(sum2.windspeed/amount - wmean*wmean));
|
register double s2 = sum2.winddir / sum.windspeed, s = sum.winddir / sum.windspeed;
|
||||||
|
wstat->winddir.mean = s;
|
||||||
|
wstat->winddir.rms = sqrt(s2 - s*s);
|
||||||
|
#define STAT(field) do{ register double ms = sum.field/amount, ms2 = sum2.field/amount; \
|
||||||
|
wstat->field.min = min.field; wstat->field.max = max.field; wstat->field.mean = ms; wstat->field.rms = sqrt(ms2 - ms*ms); }while(0)
|
||||||
|
STAT(windspeed);
|
||||||
|
STAT(pressure);
|
||||||
|
STAT(temperature);
|
||||||
|
STAT(humidity);
|
||||||
|
STAT(rainfall);
|
||||||
|
wstat->tmeasure.max = max.tmeasure;
|
||||||
|
wstat->tmeasure.min = min.tmeasure;
|
||||||
|
wstat->tmeasure.mean = sum.tmeasure/amount;
|
||||||
|
wstat->tmeasure.rms = sqrt(sum2.tmeasure/amount);
|
||||||
|
// DBG("tmean=%.1f, min=%.1f, max=%.1f", wstat->tmeasure.mean, wstat->tmeasure.min, wstat->tmeasure.max);
|
||||||
pthread_mutex_unlock(&mutex);
|
pthread_mutex_unlock(&mutex);
|
||||||
return dt;
|
return dt;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,24 @@
|
|||||||
// maximal time difference for records in statbuf - one hour
|
// maximal time difference for records in statbuf - one hour
|
||||||
#define STATMAXT (3600.)
|
#define STATMAXT (3600.)
|
||||||
|
|
||||||
double stat_for(double Tsec/*, weather_t *w*/);
|
// main statistical data
|
||||||
|
typedef struct{
|
||||||
|
double min;
|
||||||
|
double max;
|
||||||
|
double mean;
|
||||||
|
double rms;
|
||||||
|
} stat_t;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
stat_t windspeed;
|
||||||
|
stat_t winddir;
|
||||||
|
stat_t pressure;
|
||||||
|
stat_t temperature;
|
||||||
|
stat_t humidity;
|
||||||
|
stat_t rainfall;
|
||||||
|
stat_t tmeasure;
|
||||||
|
} weatherstat_t;
|
||||||
|
|
||||||
|
double stat_for(double Tsec, weatherstat_t *wstat);
|
||||||
void addtobuf(weather_t *record);
|
void addtobuf(weather_t *record);
|
||||||
double get_tmax();
|
double get_tmax();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user