diff --git a/C/client_cli/client_cli.c b/C/client_cli/client_cli.c index d12f365..5cc5135 100644 --- a/C/client_cli/client_cli.c +++ b/C/client_cli/client_cli.c @@ -56,7 +56,7 @@ void send_data(unsigned char stat_mask){ char s_time[32]; monit_d data; if(!only_extr){ - printf("OT - %s\nIT - %s\nMT - %s\nWS - %s\nP - %s\nH - %s\nS - %s\n\n", + printf("OT - %s\nIT - %s\nMT - %s\nWS - %s\nP - %s\nH - %s\nS - %s (0 - off, 1 - guiding, 2 - ready, 3 - moving, 4 - opened)\n\n", _L(_s_Otemp_), _L(_s_Itemp_), _L(_s_Mtemp_), _L(_s_WSpeed_), _L(_s_Pressure_), _L(_s_Humidity_), _L(_s_State_)); diff --git a/C/daemon/client.c b/C/daemon/client.c index db99f69..71f7d9d 100644 --- a/C/daemon/client.c +++ b/C/daemon/client.c @@ -1,23 +1,3 @@ -// client.c -// -// Copyright 2012 Edward V. Emelianoff -// -// 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 2 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, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -// MA 02110-1301, USA. - - #define __CLIENT_C__ #include #include "defines.h" @@ -30,8 +10,8 @@ //#define JPG 1 -> GIF = 2 #define GIF 2 // изображение - gif (должен быть самым последним) -static char* Content_type = "Content-type: multipart/form-data; charset=koi8-r\n\n"; -static char* SCRIPT_PATH = "/cgi-bin/eddy/tempmon"; // полный путь к скрипту +static const char* Content_type = "Content-type: multipart/form-data; charset=koi8-r\n\n"; +static const char* SCRIPT_PATH = "/cgi-bin/tempmon"; // полный путь к скрипту char *qs = NULL, *buf = NULL; unsigned char Lang = 1; // английский long long starting_pos = 0LL; @@ -43,640 +23,633 @@ int out_fd; void sendSVG(const int image_type, unsigned char stat_mask, int im_height); static inline void minmax(float *min, float *max, float param){ - if(param > *max) *max = param; - else if(param < *min) *min = param; + if(param > *max) *max = param; + else if(param < *min) *min = param; } void print_curvals(unsigned char stat_mask){ // stat_mask - битовая маска для Status - int i=1, f, d_len = 0; - monit_d data; - float max_otemp, min_otemp, avr_otemp, // внешняя температура - max_itemp, min_itemp, avr_itemp, // внутренняя температура - max_mtemp, min_mtemp, avr_mtemp, // температура зеркала - max_wind, min_wind, avr_wind, // скорость ветра - max_pres, min_pres, avr_pres, // давление - max_hmd, min_hmd, avr_hmd; // влажность - printf("%s", Content_type); - while(read(out_fd, &data, sizeof(data)) == sizeof(data)){ - if(data.seconds < t_start) continue; - if(data.seconds > t_end) break; - if(!(stat_mask & (1 << data.status))) continue; - d_len++; - if(i){ - max_otemp = min_otemp = avr_otemp = data.outdoor_temp; - max_itemp = min_itemp = avr_itemp = data.indoor_temp; - max_mtemp = min_mtemp = avr_mtemp = data.mirror_temp; - max_wind = min_wind = avr_wind = data.wind_speed; - max_pres = min_pres = avr_pres = data.pressure; - max_hmd = min_hmd = avr_hmd = data.humidity; - i = 0; - }else{ - minmax(&min_otemp, &max_otemp, data.outdoor_temp); - minmax(&min_itemp, &max_itemp, data.indoor_temp); - minmax(&min_mtemp, &max_mtemp, data.mirror_temp); - minmax(&min_wind, &max_wind, data.wind_speed); - minmax(&min_pres, &max_pres, data.pressure); - minmax(&min_hmd, &max_hmd, data.humidity); - avr_otemp += data.outdoor_temp; - avr_itemp += data.indoor_temp; - avr_mtemp += data.mirror_temp; - avr_wind += data.wind_speed; - avr_pres += data.pressure; - avr_hmd += data.humidity; - } - } - if(d_len < 1){ - printf("%s", _L(_s_noData_)); - return; - } - printf("\n" + int i=1, f, d_len = 0; + monit_d data; + float max_otemp, min_otemp, avr_otemp, // внешняя температура + max_itemp, min_itemp, avr_itemp, // внутренняя температура + max_mtemp, min_mtemp, avr_mtemp, // температура зеркала + max_wind, min_wind, avr_wind, // скорость ветра + max_pres, min_pres, avr_pres, // давление + max_hmd, min_hmd, avr_hmd; // влажность + printf("%s", Content_type); + while(read(out_fd, &data, sizeof(data)) == sizeof(data)){ + if(data.seconds < t_start) continue; + if(data.seconds > t_end) break; + if(!(stat_mask & (1 << data.status))) continue; + d_len++; + if(i){ + max_otemp = min_otemp = avr_otemp = data.outdoor_temp; + max_itemp = min_itemp = avr_itemp = data.indoor_temp; + max_mtemp = min_mtemp = avr_mtemp = data.mirror_temp; + max_wind = min_wind = avr_wind = data.wind_speed; + max_pres = min_pres = avr_pres = data.pressure; + max_hmd = min_hmd = avr_hmd = data.humidity; + i = 0; + }else{ + minmax(&min_otemp, &max_otemp, data.outdoor_temp); + minmax(&min_itemp, &max_itemp, data.indoor_temp); + minmax(&min_mtemp, &max_mtemp, data.mirror_temp); + minmax(&min_wind, &max_wind, data.wind_speed); + minmax(&min_pres, &max_pres, data.pressure); + minmax(&min_hmd, &max_hmd, data.humidity); + avr_otemp += data.outdoor_temp; + avr_itemp += data.indoor_temp; + avr_mtemp += data.mirror_temp; + avr_wind += data.wind_speed; + avr_pres += data.pressure; + avr_hmd += data.humidity; + } + } + if(d_len < 1){ + printf("%s", _L(_s_noData_)); + return; + } + printf("
\n" "" "\n" "\n" "\n" "\n" "
%s%s%s%s
%s%s%s
min%.2f%.2f%.2f%.2f%.2f%.2f
max%.2f%.2f%.2f%.2f%.2f%.2f
avr%.2f%.2f%.2f%.2f%.2f%.2f
\n" - "%s: %d

\n", - _L(_s_Temp_), _L(_s_WSpeed_), _L(_s_Pressure_), _L(_s_Humidity_), - _L(_s_Ot_), _L(_s_It_), _L(_s_Mt_), - min_otemp, min_itemp, min_mtemp, min_wind, min_pres, min_hmd, - max_otemp, max_itemp, max_mtemp, max_wind, max_pres, max_hmd, - avr_otemp/d_len, avr_itemp/d_len, avr_mtemp/d_len, - avr_wind/d_len, avr_pres/d_len, avr_hmd/d_len, - _L(_s_Monlen_), d_len); - printf("%s\n", - SCRIPT_PATH, t_start, t_end, stat_mask, aver_interval, _L(_s_Save_file_)); + "%s: %d

\n", + _L(_s_Temp_), _L(_s_WSpeed_), _L(_s_Pressure_), _L(_s_Humidity_), + _L(_s_Ot_), _L(_s_It_), _L(_s_Mt_), + min_otemp, min_itemp, min_mtemp, min_wind, min_pres, min_hmd, + max_otemp, max_itemp, max_mtemp, max_wind, max_pres, max_hmd, + avr_otemp/d_len, avr_itemp/d_len, avr_mtemp/d_len, + avr_wind/d_len, avr_pres/d_len, avr_hmd/d_len, + _L(_s_Monlen_), d_len); + printf("%s\n", + SCRIPT_PATH, t_start, t_end, stat_mask, aver_interval, _L(_s_Save_file_)); } char* get_qs(char* buf, int l){ - char *m, *qs = NULL; - if((m = getenv("REQUEST_METHOD")) && strcasecmp(m, "POST") == 0) - qs = fgets(buf, l, stdin); - else if( (qs = getenv("QUERY_STRING")) ) - qs = strncpy(buf, qs, l); - if(qs && strlen(qs) < 1) qs = NULL; - return qs; + if(!buf || !*buf || l < 1) return 0; + char *m, *qs = NULL; + if((m = getenv("REQUEST_METHOD")) && strcasecmp(m, "POST") == 0) + qs = fgets(buf, l, stdin); + else if( (qs = getenv("QUERY_STRING")) ) + qs = strncpy(buf, qs, l); + if(qs && strlen(qs) < 1) qs = NULL; + return qs; } int get_qs_param(char *qs, char *param, char *meaning, int l){ - char *tok, *val, *par, *str; - int stat = 0; - str = calloc(MAX_QUERY_SIZE, 1); - strncpy(str, qs, MAX_QUERY_SIZE); - tok = strtok(str, "& \n"); - do{ - if((val = strchr(tok, '=')) == NULL) continue; - *val++ = '\0'; - par = tok; - if(strcasecmp(par, param)==0){ - if(strlen(val) > 0){ - stat = 1; - strncpy(meaning, val, l); - meaning[l-1] = 0; - } - break; - } - }while((tok = strtok(NULL, "& \n"))!=NULL); - free(str); - return stat; + char *tok, *val, *par; + if(!qs || !param) return 0; + char str[MAX_QUERY_SIZE+1]; + int stat = 0; + strncpy(str, qs, MAX_QUERY_SIZE); + tok = strtok(str, "& \n"); + do{ + if((val = strchr(tok, '=')) == NULL) continue; + *val++ = '\0'; + par = tok; + if(strcasecmp(par, param)==0){ + if(strlen(val) > 0 && l > 0){ + stat = 1; + strncpy(meaning, val, l); + meaning[l-1] = 0; + } + break; + } + }while((tok = strtok(NULL, "& \n"))!=NULL); + return stat; } void send_data(unsigned char stat_mask){ - int ii=0, j; - struct timeval tv; - struct tm ltime; - time_t t_first=0, t_last=0; - double otemp=0., itemp=0., mtemp=0., wind=0., pres=0., hum=0.; - int ctr, status, statuses[5] = {0,0,0,0,0}; - char s_time[32]; - monit_d data; - printf("Content-type: text/plain; charset=koi8-r\n\n"); - printf("OT - %s\nIT - %s\nMT - %s\nWS - %s\nP - %s\nH - %s\nS - %s\n\n", - _L(_s_Otemp_), _L(_s_Itemp_), _L(_s_Mtemp_), - _L(_s_WSpeed_), _L(_s_Pressure_), _L(_s_Humidity_), - _L(_s_State_)); - printf("%s\t\tOT\tIT\tMT\tWS\tP\tH\tS\n", _L(_s_Date_)); - while(read(out_fd, &data, sizeof(data))){ - if(data.seconds < t_start) continue; - if(data.seconds > t_end) break; - if(!(stat_mask & (1 << data.status))) continue; - if(t_first == 0) t_first = t_last = data.seconds; - else if((data.seconds - t_first) >= aver_interval){ // накопили достаточно данных - t_first = t_first/2 + t_last/2; // середина временного интервала - ltime = *localtime(&t_first);//*localtime(&t_first); - strftime(s_time, 32, "%d/%m/%Y, %H:%M:%S", <ime); - if(ii == 0) ii = 1; - ctr = 0; - for(j = 0; j<5; j++){ - if(statuses[j] > ctr){ - ctr = statuses[j]; - status = j; - } - statuses[j] = 0; - } - printf("%s\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%d\n", - s_time, - otemp/ii, - itemp/ii, - mtemp/ii, - wind/ii, - pres/ii, - hum/ii, - status); - t_first = data.seconds; - otemp=itemp=mtemp=wind=pres=hum=0.; - ii = 0; - } - t_last = data.seconds; - otemp += data.outdoor_temp; - itemp += data.indoor_temp; - mtemp += data.mirror_temp; - wind += data.wind_speed; - pres += data.pressure; - hum += data.humidity; - statuses[data.status]++; - ii++; - } + int ii=0, j; + struct tm ltime; + time_t t_first=0, t_last=0; + double otemp=0., itemp=0., mtemp=0., wind=0., pres=0., hum=0.; + int ctr, status, statuses[5] = {0,0,0,0,0}; + char s_time[32]; + monit_d data; + printf("Content-type: text/plain; charset=koi8-r\n\n"); + printf("OT - %s\nIT - %s\nMT - %s\nWS - %s\nP - %s\nH - %s\nS - %s\n\n", + _L(_s_Otemp_), _L(_s_Itemp_), _L(_s_Mtemp_), + _L(_s_WSpeed_), _L(_s_Pressure_), _L(_s_Humidity_), + _L(_s_State_)); + printf("%s\t\tOT\tIT\tMT\tWS\tP\tH\tS\n", _L(_s_Date_)); + while(read(out_fd, &data, sizeof(data))){ + if(data.seconds < t_start) continue; + if(data.seconds > t_end) break; + if(!(stat_mask & (1 << data.status))) continue; + if(t_first == 0) t_first = t_last = data.seconds; + else if((data.seconds - t_first) >= aver_interval){ // накопили достаточно данных + t_first = t_first/2 + t_last/2; // середина временного интервала + ltime = *localtime(&t_first);//*localtime(&t_first); + strftime(s_time, 32, "%d/%m/%Y, %H:%M:%S", <ime); + if(ii == 0) ii = 1; + ctr = 0; + for(j = 0; j<5; j++){ + if(statuses[j] > ctr){ + ctr = statuses[j]; + status = j; + } + statuses[j] = 0; + } + printf("%s\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%d\n", + s_time, + otemp/ii, + itemp/ii, + mtemp/ii, + wind/ii, + pres/ii, + hum/ii, + status); + t_first = data.seconds; + otemp=itemp=mtemp=wind=pres=hum=0.; + ii = 0; + } + t_last = data.seconds; + otemp += data.outdoor_temp; + itemp += data.indoor_temp; + mtemp += data.mirror_temp; + wind += data.wind_speed; + pres += data.pressure; + hum += data.humidity; + statuses[data.status]++; + ii++; + } } void fill_forms(const char* alert_message, const char S_flag){ - int shmid, i = 0; - char tmp[16]; - unsigned char mask; - int im_ht = 600; - if(S_flag == 0){ - printf("%s", Content_type); - if(alert_message) printf("

%s

\n", alert_message); - return; - } - if(get_qs_param(qs, "Stat", tmp, 16)) - mask = atoi(tmp); - else mask = 0xff; - if(get_qs_param(qs, "height", tmp, 16)){ - im_ht = atoi(tmp); - if(im_ht < 100 || im_ht > 800) im_ht = 600; - } - if(Graph){ - if(get_qs_param(qs, "Gtype", tmp, 16)){ - i = atoi(tmp); - if(iGIF) - i = GIF; - } - else i = GIF; - sendSVG(i, mask, im_ht); - } - else{ - if(S_flag == 2) send_data(mask); - else print_curvals(mask); - } + int i = 0; + char tmp[16]; + unsigned char mask; + int im_ht = 600; + if(S_flag == 0){ + printf("%s", Content_type); + if(alert_message) printf("

%s

\n", alert_message); + return; + } + if(get_qs_param(qs, "Stat", tmp, 16)) + mask = atoi(tmp); + else mask = 0xff; + if(get_qs_param(qs, "height", tmp, 16)){ + im_ht = atoi(tmp); + if(im_ht < 100 || im_ht > 800) im_ht = 600; + } + if(Graph){ + if(get_qs_param(qs, "Gtype", tmp, 16)){ + i = atoi(tmp); + if(iGIF) + i = GIF; + } + else i = GIF; + sendSVG(i, mask, im_ht); + } + else{ + if(S_flag == 2) send_data(mask); + else print_curvals(mask); + } } void sendSVG(const int image_type, unsigned char stat_mask, int im_height){ - FILE *plot = NULL; - char s_time[32]; - struct tm ltime; - struct timeval tv; - monit_d md, *data, *ptr; - time_t time_interval; - unsigned char Flag, Comma = 0; - int twographs = 0; - char *titles[] = {"T out", "T in", "T mir", "Wind", "Pres", "Hum"}; - char *command= "/Users/eddy/bin/gnuplot"; - char *types[] = {"svg", "jpeg", "gif"}; - char *contents[] = {"svg+xml", "jpeg", "gif"}; - int f, i, j, d_len, rb; - data = calloc(1002, sizeof(monit_d)); // максимум тысяча точек - ptr = data; - printf("Content-type: image/%s\n\n", contents[image_type]); - if(Graph < 1 || Graph > 63){ - fprintf(stderr, "Graph=%d, out of range\n", Graph); - goto ret; - } - d_len = 0; - //lseek(out_fd, 0, SEEK_SET); - while(read(out_fd, &md, sizeof(md))){ -//fprintf(stderr, "time=%d, t_start=%d, t_end=%d, d_len=%d, time_interval=%d\n", md.seconds, t_start, t_end, d_len, time_interval); - if(md.seconds < t_start) continue; - if(md.seconds > t_end) break; - if(d_len == 0){ - t_start = md.seconds; - time_interval = (t_end - t_start) / 300; - } - *ptr++ = md; - if(++d_len > 300) break; // лишние значения - t_start += time_interval; -//fprintf(stderr, ">>>time=%d, t_start=%d, t_end=%d, d_len=%d, time_interval=%d\n", md.seconds, t_start, t_end, d_len, time_interval); - } - close(f); - if(d_len < 3){ - fprintf(stderr, "d_len=%d, error\n", d_len); - goto ret; - } - plot = popen(command, "w"); - if(plot == NULL){ - perror("can't run gnuplot\n"); - goto ret; - } - //fprintf(plot, "set terminal %s size 800,%d font \"/usr/share/fonts/liberation/LiberationSans-Regular.ttf\"\nset xdata time\nset timefmt \"%%d/%%m-%%H:%%M\"\nset format x \"%%H:%%M\\n%%d/%%m\"\n", - fprintf(plot, "set terminal %s size 800,%d\nset xdata time\nset timefmt \"%%d/%%m-%%H:%%M\"\nset format x \"%%H:%%M\\n%%d/%%m\"\n", - types[image_type], im_height); - if((Graph & 16) && (Graph & 32)){ // присутствуют и влажность, и давление - twographs = 1; - if(Graph & 15) // есть еще данные - fprintf(plot, "set multiplot\nset origin 0,0\nset size 1,0.5\n"); - } - else if(Graph & 48){ // присутствуют только влажность, либо только давление - if(Graph & 15){ // выводим еще что-нибудь - fprintf(plot, "set ytics nomirror\nset y2tics\nset ylabel \"degr C, m/s\"\n"); - if(Graph & 16) - fprintf(plot, "set y2label \"mmHg\"\n"); // подпись для давления - else - fprintf(plot, "set y2label \"%%\"\n"); // подпись для влажности - } - } - fprintf(plot, "plot "); - for(j = 0; j < 4; j++){ - Flag = Graph & (1 << j); - if(Flag){ - if(Comma) fprintf(plot, ","); - Comma = 1; - //w l smooth csplines - fprintf(plot, " '-' using 1:2 w l lt %d title '%s'", j+1, titles[j]); - } - } - if(!twographs){ - for(j = 4; j < 6; j++){ - if(Graph & (1 << j)){ - if(Comma) fprintf(plot, ","); - Comma = 1; - fprintf(plot, " '-' using 1:2 w l axes x1y2 lt %d title '%s'", j+1, titles[j]); - } - } - } + FILE *plot = NULL; + char s_time[32]; + struct tm *ltime; + struct timeval tv; + monit_d md, *data, *ptr; + time_t time_interval, tmt; + unsigned char Flag, Comma = 0; + int twographs = 0; + char *titles[] = {"T out", "T in", "T mir", "Wind", "Pres", "Hum"}; + char *command= "/usr/bin/gnuplot"; + char *types[] = {"svg", "jpeg", "gif"}; + char *contents[] = {"svg+xml", "jpeg", "gif"}; + int f, i, j, d_len, rb; + data = calloc(1002, sizeof(monit_d)); // максимум тысяча точек + ptr = data; + printf("Content-type: image/%s\n\n", contents[image_type]); + if(Graph < 1 || Graph > 63){ + fprintf(stderr, "Graph=%d, out of range\n", Graph); + goto ret; + } + d_len = 0; + while(read(out_fd, &md, sizeof(md))){ + if(md.seconds < t_start) continue; + if(md.seconds > t_end) break; + if(d_len == 0){ + t_start = md.seconds; + time_interval = (t_end - t_start) / 300; + } + *ptr++ = md; + if(++d_len > 300) break; // лишние значения + t_start += time_interval; + } + close(f); + if(d_len < 3){ + goto ret; + } + plot = popen(command, "w"); + if(plot == NULL){ + goto ret; + } + fprintf(plot, "set terminal %s size 800,%d\nset xdata time\nset timefmt \"%%d/%%m-%%H:%%M\"\nset format x \"%%H:%%M\\n%%d/%%m\"\n", + types[image_type], im_height); + if((Graph & 16) && (Graph & 32)){ // присутствуют и влажность, и давление + twographs = 1; + if(Graph & 15) // есть еще данные + fprintf(plot, "set multiplot\nset origin 0,0\nset size 1,0.5\n"); + } + else if(Graph & 48){ // присутствуют только влажность, либо только давление + if(Graph & 15){ // выводим еще что-нибудь + fprintf(plot, "set ytics nomirror\nset y2tics\nset ylabel \"degr C, m/s\"\n"); + if(Graph & 16) + fprintf(plot, "set y2label \"mmHg\"\n"); // подпись для давления + else + fprintf(plot, "set y2label \"%%\"\n"); // подпись для влажности + } + } + fprintf(plot, "plot "); + for(j = 0; j < 4; j++){ + Flag = Graph & (1 << j); + if(Flag){ + if(Comma) fprintf(plot, ","); + Comma = 1; + //w l smooth csplines + fprintf(plot, " '-' using 1:2 w l lt %d title '%s'", j+1, titles[j]); + } + } + if(!twographs){ + for(j = 4; j < 6; j++){ + if(Graph & (1 << j)){ + if(Comma) fprintf(plot, ","); + Comma = 1; + fprintf(plot, " '-' using 1:2 w l axes x1y2 lt %d title '%s'", j+1, titles[j]); + } + } + } - fprintf(plot, "\n"); - for(j = 0; j < 6; j++){ - Flag = Graph & (1 << j); - if(twographs && j > 3) break; - if(Flag){ - for(i = 0; i < d_len; i++){ - if(!(stat_mask & (1 << data[i].status))) continue; - time_t X = (time_t)data[i].seconds; - ltime = *localtime(&X); - strftime(s_time, 32, "%d/%m-%H:%M", <ime); - fprintf(plot, "%s ", s_time); - switch(Flag){ - case 1: fprintf(plot, "%.2f\n", data[i].outdoor_temp); - break; - case 2: fprintf(plot, "%.2f\n", data[i].indoor_temp); - break; - case 4: fprintf(plot, "%.2f\n", data[i].mirror_temp); - break; - case 8: fprintf(plot, "%.2f\n", data[i].wind_speed); - break; - case 16: fprintf(plot, "%.2f\n", data[i].pressure); - break; - case 32: fprintf(plot, "%.2f\n", data[i].humidity); - break; - } - } - fprintf(plot, "e\n"); - } - } - if(twographs){ - if(Graph & 15) // строим 2 графика - fprintf(plot, "set origin 0,0.5\nset size 1,0.5\n"); - fprintf(plot, "set ylabel \"mmHg\"\nset y2label \"%%\"\n"); - fprintf(plot, "plot '-' using 1:2 w l lt 1 title 'Pres',"); - fprintf(plot, " '-' using 1:2 w l axes x1y2 lt 2 title 'Hum'\n"); - for(j = 0; j < 2; j++){ - for(i = 0; i < d_len; i++){ - if(!(stat_mask & (1 << data[i].status))) continue; - time_t X = (time_t)data[i].seconds; - ltime = *localtime(&X); - strftime(s_time, 32, "%d/%m-%H:%M", <ime); - fprintf(plot, "%s ", s_time); - switch(j){ - case 0: fprintf(plot, "%.2f\n", data[i].pressure); break; - case 1: fprintf(plot, "%.2f\n", data[i].humidity); break; - } - } - fprintf(plot, "e\n"); - } - } + fprintf(plot, "\n"); + for(j = 0; j < 6; j++){ + Flag = Graph & (1 << j); + if(twographs && j > 3) break; + if(Flag){ + for(i = 0; i < d_len; i++){ + if(!(stat_mask & (1 << data[i].status))) continue; + tmt = (time_t)data[i].seconds; + ltime = localtime(&tmt); + strftime(s_time, 32, "%d/%m-%H:%M", ltime); + fprintf(plot, "%s ", s_time); + switch(Flag){ + case 1: fprintf(plot, "%.2f\n", data[i].outdoor_temp); + break; + case 2: fprintf(plot, "%.2f\n", data[i].indoor_temp); + break; + case 4: fprintf(plot, "%.2f\n", data[i].mirror_temp); + break; + case 8: fprintf(plot, "%.2f\n", data[i].wind_speed); + break; + case 16: fprintf(plot, "%.2f\n", data[i].pressure); + break; + case 32: fprintf(plot, "%.2f\n", data[i].humidity); + break; + } + } + fprintf(plot, "e\n"); + } + } + if(twographs){ + if(Graph & 15) // строим 2 графика + fprintf(plot, "set origin 0,0.5\nset size 1,0.5\n"); + fprintf(plot, "set ylabel \"mmHg\"\nset y2label \"%%\"\n"); + fprintf(plot, "plot '-' using 1:2 w l lt 1 title 'Pres',"); + fprintf(plot, " '-' using 1:2 w l axes x1y2 lt 2 title 'Hum'\n"); + for(j = 0; j < 2; j++){ + for(i = 0; i < d_len; i++){ + if(!(stat_mask & (1 << data[i].status))) continue; + tmt = (time_t)data[i].seconds; + ltime = localtime(&tmt); + strftime(s_time, 32, "%d/%m-%H:%M", ltime); + fprintf(plot, "%s ", s_time); + switch(j){ + case 0: fprintf(plot, "%.2f\n", data[i].pressure); break; + case 1: fprintf(plot, "%.2f\n", data[i].humidity); break; + } + } + fprintf(plot, "e\n"); + } + } ret: - if(plot){ - fflush(plot); - pclose(plot); - } - free(data); + if(plot){ + fflush(plot); + pclose(plot); + } + free(data); } void find_starting_pos(){ // ищем в кэше смещение для начала поиска - int cache_fd; - Cache cache; - if((cache_fd = open(CACHE_FILE, O_RDONLY)) < 0){ - printf("%s", Content_type); - printf("

%s

", _L(_s_Cant_open_cache_)); - exit(1); - } - while(read(cache_fd, &cache, sizeof(cache))){ - if(cache.time < t_start) - starting_pos = cache.offset; - else break; - } - close(cache_fd); + int cache_fd; + Cache cache; + if((cache_fd = open(CACHE_FILE, O_RDONLY)) < 0){ + printf("%s", Content_type); + printf("

%s

", _L(_s_Cant_open_cache_)); + exit(1); + } + while(read(cache_fd, &cache, sizeof(cache))){ + if(cache.time < t_start) + starting_pos = cache.offset; + else break; + } + close(cache_fd); } void quit(int status){ - if(buf) free(buf); - if(out_fd) close(out_fd); - exit(status); + if(buf) free(buf); + if(out_fd) close(out_fd); + exit(status); } char *switch_names(int i, char* ss){ - switch(i){ - case 0: ss = _L(_s_Otemp_); break; - case 1: ss = _L(_s_Itemp_); break; - case 2: ss = _L(_s_Mtemp_); break; - case 3: ss = _L(_s_WSpeed_); break; - case 4: ss = _L(_s_Pressure_); break; - case 5: - default: ss = _L(_s_Humidity_); - } - return ss; + switch(i){ + case 0: ss = _L(_s_Otemp_); break; + case 1: ss = _L(_s_Itemp_); break; + case 2: ss = _L(_s_Mtemp_); break; + case 3: ss = _L(_s_WSpeed_); break; + case 4: ss = _L(_s_Pressure_); break; + case 5: + default: ss = _L(_s_Humidity_); + } + return ss; } char *format_time(time_t t, char *ss, int i){ - struct timeval tv; - struct tm ltime = *localtime(&t); - strftime(ss, i, "%d/%m/%Y, %H:%M", <ime); - return ss; + struct tm ltime = *localtime(&t); + strftime(ss, i, "%d/%m/%Y, %H:%M", <ime); + return ss; } void print_string(time_t t1, time_t t2, int i){ - char s_t1[32], s_t2[32], *ss; - printf("%s - %s (%s)
\n", format_time(t1, s_t1, 32), - format_time(t2, s_t2, 32), switch_names(i, ss)); + char s_t1[32], s_t2[32], *ss; + printf("%s - %s (%s)
\n", format_time(t1, s_t1, 32), + format_time(t2, s_t2, 32), switch_names(i, ss)); } void show_extremums(int ch){ - int stat_mask = 0xFF, i, AndOr = 0, memsize, counter, first; - char tmp[32], g = 0, l = 0, *ss; - monit_d data; - float Greater, Less; - float extr[6], *meds[6]={NULL, NULL, NULL, NULL, NULL, NULL}; // экстремумы, медианы - struct timeval tv; - struct tm ltime; - time_t t1[6], t2[6], t_first=0, t_last=0; + int stat_mask = 0xFF, i, AndOr = 0, memsize, counter, first; + char tmp[32], g = 0, l = 0, *ss; + monit_d data; + float Greater, Less; + float extr[6], *meds[6]={NULL, NULL, NULL, NULL, NULL, NULL}; // экстремумы, медианы + struct timeval tv; + struct tm ltime; + time_t t1[6], t2[6], t_first=0, t_last=0; - printf("%s", Content_type); - if(get_qs_param(qs, "Stat", tmp, 16)) - stat_mask = atoi(tmp); - if(stat_mask == 0) stat_mask = 0xFF; - if(get_qs_param(qs, "Graph", tmp, 16)) - Graph = atoi(tmp); - if(Graph == 0) Graph = 63; - if(ch == 3){ // получение данных и проверка их корректности - if(get_qs_param(qs, "AndOr", tmp, 16)) - AndOr = atoi(tmp); - if((AndOr & 1) != AndOr) AndOr = 0; - if(get_qs_param(qs, "Greater", tmp, 32)){ - Greater = atof(tmp); - g = 1; - } - if(get_qs_param(qs, "Less", tmp, 32)){ - Less = atof(tmp); - l = 1; - } - if(!(g | l) || // нет ни Greater, ни Less - (AndOr && !(g & l)) // указано "И", но не хватает данных - ){ - printf("

%s

\n", _L(_s_No_Data_)); - return; - } - if(AndOr){ - if(Greater >= Less){ - printf("

%s

\n", _L(_s_G_mustbe_less_L_)); - return; - } - } - else{ - if((g & l) && (Greater <= Less)){ - printf("

%s

\n", _L(_s_L_mustbe_less_G_)); - return; - } - } - } - if(aver_interval < 60) aver_interval = 60; // медианное усреднение по крайней мере за минуту - switch(ch){ - case 0: ss = _L(_s_Modes_); break; - case 1: ss = _L(_s_Max_data_); break; - case 2: ss = _L(_s_Min_data_); break; - case 3: - default: ss = _L(_s_Diapazon_); - } - printf("

%s ", ss); - if(ch == 3){ - if(g){ - printf("%s %.1f ", _L(_s_Gtr_), Greater); - if(AndOr) printf("%s ", _L(_s_And_)); - else if(l) printf("%s ", _L(_s_Or_)); - } - if(l) printf("%s %.1f", _L(_s_Less_), Less); - } - printf("

\n"); - memsize = aver_interval / TIMEINTERVAL + 3; - if(ch) for(i = 0; i < 6; i++) - if(Graph & (1<\n", format_time(t_last, tmp, 32)); - t_first = 0; - } - continue; - } - if(ch == 0){ // оценка временнЫх интервалов - if(t_first == 0) t_first = t_last = data.seconds; - continue; - } - if(t_first == 0) t_first = t_last = data.seconds; - else if((data.seconds - t_first) >= aver_interval || counter > memsize || data.seconds > t_end){ - t_first = t_first/2 + t_last/2; // середина временного интервала - for(i=0; i<6; i++) - if(Graph & (1< extr[i]){ - extr[i] = meds[i][0]; - t1[i] = t_first; - } - } - else{ // ch = 2 - ищем минимумы - if(meds[i][0] < extr[i]){ - extr[i] = meds[i][0]; - t1[i] = t_first; - } - } - } - } - else{ // ищем периоды (ch == 3) - for(i=0; i<6; i++) - if(Graph & (1< Greater && meds[i][0] < Less) - if(t1[i] == 0) t1[i] = t2[i] = t_first; - else t2[i] = t_first; - else if(t1[i] != 0){ - print_string(t1[i], t2[i], i); - t1[i] = 0; - } - } - else{ // вариант с "или" - if( (g && meds[i][0] > Greater) || (l && meds[i][0] < Less) ) - if(t1[i] == 0) t1[i] = t2[i] = t_first; - else t2[i] = t_first; - else if(t1[i] != 0){ // выводим данные - print_string(t1[i], t2[i], i); - t1[i] = 0; - } - } - } - } - t_first = data.seconds; - counter = 0; - } - if(data.seconds > t_end) break; - t_last = data.seconds; - if(Graph & 1) meds[0][counter] = data.outdoor_temp; - if(Graph & 2) meds[1][counter] = data.indoor_temp; - if(Graph & 4) meds[2][counter] = data.mirror_temp; - if(Graph & 8) meds[3][counter] = data.wind_speed; - if(Graph & 16) meds[4][counter] = data.pressure; - if(Graph & 32) meds[5][counter] = data.humidity; - counter++; - } - if(ch == 1 || ch == 2) - for(i=0; i<6; i++){ - if(Graph & (1<\n", format_time(t1[i], tmp, 32), - switch_names(i, ss), extr[i]); - } - if(ch == 0){ - printf("

%s

\n", _L(_s_Mode_Times_)); - inline void fmtprnt(char **str, time_t tm){ - printf("%s: %zd %s (%.2f %s)
\n", _L(str), tm, _L(_s_seconds_), - ((float)tm)/86400., _L(_s_days_)); - } - fmtprnt(_s_Stopped_, t1[0]); - fmtprnt(_s_Guiding_, t1[1]); - fmtprnt(_s_Ready_, t1[2]); - fmtprnt(_s_Other_, t1[3]); - fmtprnt(_s_Vopen_, t1[4]); - fmtprnt(_s_Total_, t1[5]); - } - for(i=0; i<6; i++) if(meds[i]) free(meds[i]); + printf("%s", Content_type); + if(get_qs_param(qs, "Stat", tmp, 16)) + stat_mask = atoi(tmp); + if(stat_mask == 0) stat_mask = 0xFF; + if(get_qs_param(qs, "Graph", tmp, 16)) + Graph = atoi(tmp); + if(Graph == 0) Graph = 63; + if(ch == 3){ // получение данных и проверка их корректности + if(get_qs_param(qs, "AndOr", tmp, 16)) + AndOr = atoi(tmp); + if((AndOr & 1) != AndOr) AndOr = 0; + if(get_qs_param(qs, "Greater", tmp, 32)){ + Greater = atof(tmp); + g = 1; + } + if(get_qs_param(qs, "Less", tmp, 32)){ + Less = atof(tmp); + l = 1; + } + if(!(g | l) || // нет ни Greater, ни Less + (AndOr && !(g & l)) // указано "И", но не хватает данных + ){ + printf("

%s

\n", _L(_s_No_Data_)); + return; + } + if(AndOr){ + if(Greater >= Less){ + printf("

%s

\n", _L(_s_G_mustbe_less_L_)); + return; + } + } + else{ + if((g & l) && (Greater <= Less)){ + printf("

%s

\n", _L(_s_L_mustbe_less_G_)); + return; + } + } + } + if(aver_interval < 60) aver_interval = 60; // медианное усреднение по крайней мере за минуту + switch(ch){ + case 0: ss = _L(_s_Modes_); break; + case 1: ss = _L(_s_Max_data_); break; + case 2: ss = _L(_s_Min_data_); break; + case 3: + default: ss = _L(_s_Diapazon_); + } + printf("

%s ", ss); + if(ch == 3){ + if(g){ + printf("%s %.1f ", _L(_s_Gtr_), Greater); + if(AndOr) printf("%s ", _L(_s_And_)); + else if(l) printf("%s ", _L(_s_Or_)); + } + if(l) printf("%s %.1f", _L(_s_Less_), Less); + } + printf("

\n"); + memsize = aver_interval / TIMEINTERVAL + 3; + if(ch) for(i = 0; i < 6; i++) + if(Graph & (1<\n", format_time(t_last, tmp, 32)); + t_first = 0; + } + continue; + } + if(ch == 0){ // оценка временнЫх интервалов + if(t_first == 0) t_first = t_last = data.seconds; + continue; + } + if(t_first == 0) t_first = t_last = data.seconds; + else if((data.seconds - t_first) >= aver_interval || counter > memsize || data.seconds > t_end){ + t_first = t_first/2 + t_last/2; // середина временного интервала + for(i=0; i<6; i++) + if(Graph & (1< extr[i]){ + extr[i] = meds[i][0]; + t1[i] = t_first; + } + } + else{ // ch = 2 - ищем минимумы + if(meds[i][0] < extr[i]){ + extr[i] = meds[i][0]; + t1[i] = t_first; + } + } + } + } + else{ // ищем периоды (ch == 3) + for(i=0; i<6; i++) + if(Graph & (1< Greater && meds[i][0] < Less) + if(t1[i] == 0) t1[i] = t2[i] = t_first; + else t2[i] = t_first; + else if(t1[i] != 0){ + print_string(t1[i], t2[i], i); + t1[i] = 0; + } + } + else{ // вариант с "или" + if( (g && meds[i][0] > Greater) || (l && meds[i][0] < Less) ) + if(t1[i] == 0) t1[i] = t2[i] = t_first; + else t2[i] = t_first; + else if(t1[i] != 0){ // выводим данные + print_string(t1[i], t2[i], i); + t1[i] = 0; + } + } + } + } + t_first = data.seconds; + counter = 0; + } + if(data.seconds > t_end) break; + t_last = data.seconds; + if(Graph & 1) meds[0][counter] = data.outdoor_temp; + if(Graph & 2) meds[1][counter] = data.indoor_temp; + if(Graph & 4) meds[2][counter] = data.mirror_temp; + if(Graph & 8) meds[3][counter] = data.wind_speed; + if(Graph & 16) meds[4][counter] = data.pressure; + if(Graph & 32) meds[5][counter] = data.humidity; + counter++; + } + if(ch == 1 || ch == 2) + for(i=0; i<6; i++){ + if(Graph & (1<\n", format_time(t1[i], tmp, 32), + switch_names(i, ss), extr[i]); + } + if(ch == 0){ + printf("

%s

\n", _L(_s_Mode_Times_)); + inline void fmtprnt(char **str, time_t tm){ + printf("%s: %zd %s (%.2f %s)
\n", _L(str), tm, _L(_s_seconds_), + ((float)tm)/86400., _L(_s_days_)); + } + fmtprnt(_s_Stopped_, t1[0]); + fmtprnt(_s_Guiding_, t1[1]); + fmtprnt(_s_Ready_, t1[2]); + fmtprnt(_s_Other_, t1[3]); + fmtprnt(_s_Vopen_, t1[4]); + fmtprnt(_s_Total_, t1[5]); + } + for(i=0; i<6; i++) if(meds[i]) free(meds[i]); } int main(){ - char *ptr, tmp[128]; - setbuf(stdout, NULL); - buf = (char*)calloc(MAX_QUERY_SIZE, 1); - ptr = getenv("HTTP_ACCEPT_LANGUAGE"); - if(ptr) if(strncmp(ptr, "ru", 2) == 0) Lang = 0; // используем русский - qs = get_qs(buf, MAX_QUERY_SIZE); - if(!qs){ - fill_forms(_L(_s_no_QS_), 0); - quit(0); - } - if(get_qs_param(qs, "Visor", tmp, 128)){ // открываем/закрываем забрало - int shmid, param = atoi(tmp); - shmid = shmget(SHM_KEY, sizeof(int), IPC_CREAT | 0666); - printf("%s", Content_type); - if(shmid < 0) printf("%s", _L(_s_noVisor_)); - else{ - Visor = (int*) shmat(shmid, NULL, 0); - if(Visor){ - if(param > 0) *Visor = !(*Visor); // param >0 - смена состояния - } - else printf("%s", _L(_s_noVisor_)); - } - printf("%s:
%s

%s:
", _L(_s_CurVstat_), - *Visor?"green":"red", *Visor?_L(_s_Vopen_):_L(_s_Vclose_), _L(_s_ChVstat_)); - printf("", *Visor ? _L(_s_Vclose_) : _L(_s_Vopen_) ); - quit(0); - } - if(!get_qs_param(qs, "Tstart", tmp, 128)){ - if(!get_qs_param(qs, "Graph", tmp, 16)) - fill_forms(_L(_s_no_tstart_), 0); - quit(0); - } - t_start = atoi(tmp); - if(get_qs_param(qs, "Tend", tmp, 128)) - t_end = atoi(tmp); - else - t_end = time(NULL); - if(t_end <= t_start){ - if(!get_qs_param(qs, "Graph", tmp, 16)) - fill_forms(_L(_s_Bad_date_), 0); - quit(1); - } - if(get_qs_param(qs, "Aver", tmp, 128)){ - aver_interval = atoi(tmp); - if(aver_interval < 1) aver_interval = 1; - } - find_starting_pos(); - if((out_fd = open(OUT_FILE, O_RDONLY)) < 0){ - exit(1); - } - lseek(out_fd, starting_pos, SEEK_SET); - if(get_qs_param(qs, "Select", tmp, 16)){ - int choice = atoi(tmp); - if(choice < 0 || choice > 3){ - fill_forms(NULL, 1); - quit(0); - } - show_extremums(choice); - quit(0); - } - if(get_qs_param(qs, "Graph", tmp, 16)){ - Graph = atoi(tmp); - if(Graph == 0) Graph = -1; - fill_forms(NULL, 1); - quit(0); - } - if(get_qs_param(qs, "Save", tmp, 16)){ - fill_forms(NULL, 2); // сохранить данные - quit(0); - } - else{ - fill_forms(NULL, 1); // показать экстремальные значения - quit(0); - } - quit(0); + char *ptr, tmp[128]; + setbuf(stdout, NULL); + buf = (char*)calloc(MAX_QUERY_SIZE, 1); + ptr = getenv("HTTP_ACCEPT_LANGUAGE"); + if(ptr) if(strncmp(ptr, "ru", 2) == 0) Lang = 0; // используем русский + qs = get_qs(buf, MAX_QUERY_SIZE); + if(!qs){ + fill_forms(_L(_s_no_QS_), 0); + quit(0); + } + if(get_qs_param(qs, "Visor", tmp, 128)){ // открываем/закрываем забрало + int shmid, param = atoi(tmp); + shmid = shmget(SHM_KEY, sizeof(int), IPC_CREAT | 0666); + printf("%s", Content_type); + if(shmid < 0) printf("%s", _L(_s_noVisor_)); + else{ + Visor = (int*) shmat(shmid, NULL, 0); + if(Visor){ + if(param > 0) *Visor = !(*Visor); // param >0 - смена состояния + } + else printf("%s", _L(_s_noVisor_)); + } + printf("%s:
%s

%s:
", _L(_s_CurVstat_), + *Visor?"green":"red", *Visor?_L(_s_Vopen_):_L(_s_Vclose_), _L(_s_ChVstat_)); + printf("", *Visor ? _L(_s_Vclose_) : _L(_s_Vopen_) ); + quit(0); + } + if(!get_qs_param(qs, "Tstart", tmp, 128)){ + if(!get_qs_param(qs, "Graph", tmp, 16)) + fill_forms(_L(_s_no_tstart_), 0); + quit(0); + } + t_start = atoi(tmp); + if(get_qs_param(qs, "Tend", tmp, 128)) + t_end = atoi(tmp); + else + t_end = time(NULL); + if(t_end <= t_start){ + if(!get_qs_param(qs, "Graph", tmp, 16)) + fill_forms(_L(_s_Bad_date_), 0); + quit(1); + } + if(get_qs_param(qs, "Aver", tmp, 128)){ + aver_interval = atoi(tmp); + if(aver_interval < 1) aver_interval = 1; + } + find_starting_pos(); + if((out_fd = open(OUT_FILE, O_RDONLY)) < 0){ + exit(1); + } + lseek(out_fd, starting_pos, SEEK_SET); + if(get_qs_param(qs, "Select", tmp, 16)){ + int choice = atoi(tmp); + if(choice < 0 || choice > 3){ + fill_forms(NULL, 1); + quit(0); + } + show_extremums(choice); + quit(0); + } + if(get_qs_param(qs, "Graph", tmp, 16)){ + Graph = atoi(tmp); + if(Graph == 0) Graph = -1; + fill_forms(NULL, 1); + quit(0); + } + if(get_qs_param(qs, "Save", tmp, 16)){ + fill_forms(NULL, 2); // сохранить данные + quit(0); + } + else{ + fill_forms(NULL, 1); // показать экстремальные значения + quit(0); + } + quit(0); } diff --git a/C/daemon/daemon.c b/C/daemon/daemon.c index a64f20b..17574b6 100644 --- a/C/daemon/daemon.c +++ b/C/daemon/daemon.c @@ -1,17 +1,17 @@ // daemon.c - gathering info daemon -// +// // Copyright 2012 Edward V. Emelianoff -// +// // 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 2 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, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, @@ -33,110 +33,110 @@ char STARTED[] = "Started."; char *pidfilename = PID_FILE; data_type *t_out=NULL, *t_in=NULL, *t_mir=NULL, - *pres=NULL, *hum=NULL; // будущие массивы для данных + *pres=NULL, *hum=NULL; // будущие массивы для данных int readname(char *name, pid_t pid){ // считать имя процесса из /proc/... - char *pp = name, byte, path[256]; - int cntr = 0, file; - snprintf (path, 255, PROC_BASE "/%d/cmdline", pid); - file = open(path, O_RDONLY); - if(file == -1) return 0; // нет файла или чужой процесс - do{ // считываем имя без слешей - read(file, &byte, 1); - if (byte != '/') *pp++ = byte; - else pp = name; - } - while(byte != EOF && byte != 0 && cntr++ < 255); - name[255] = 0; - close(file); - return 1; + char *pp = name, byte, path[256]; + int cntr = 0, file; + snprintf (path, 255, PROC_BASE "/%d/cmdline", pid); + file = open(path, O_RDONLY); + if(file == -1) return 0; // нет файла или чужой процесс + do{ // считываем имя без слешей + read(file, &byte, 1); + if (byte != '/') *pp++ = byte; + else pp = name; + } + while(byte != EOF && byte != 0 && cntr++ < 255); + name[255] = 0; + close(file); + return 1; } void check4running(){ - DIR *dir; - FILE* pidfile; - struct dirent *de; - struct stat s_buf; - pid_t pid, self, run = 0; - char name[256], myname[256]; - if (!(dir = opendir(PROC_BASE))){ // открываем директорию /proc - perror(PROC_BASE); - exit(1); - } - self = getpid(); // свой идентификатор - if(stat(pidfilename, &s_buf) == 0){ // есть файл с pid'ом - pidfile = fopen(pidfilename, "r"); - fscanf(pidfile, "%d", &run); // получаем pid (возможно) запущенного процесса - fclose(pidfile); - if(readname(name, run) && strncmp(name, myname, 255) == 0){ - WARN("\nFound running process (pid=%d), exit.\n", run); - exit(0); - } - } - // файла с pid'ом нет, или там неправильная запись - readname(myname, self); // свое имя процесса - while ((de = readdir (dir)) != NULL){ // пока не дойдем до конца директории - // пропустим, если директория не указывает на процесс, или указывает на self - if (!(pid = (pid_t) atoi (de->d_name)) || pid == self) - continue; - readname(name, pid); // считываем имя процесса - if(strncmp(name, myname, 255) == 0){ // если оно совпадает с myname - WARN("\nFound running process (pid=%d), exit.\n", pid); - exit(0); - } - } - closedir(dir); - unlink(pidfilename); // пробуем удалить pidfilename - WARN("my PID: %d\n", self); - pidfile = fopen(pidfilename, "w"); - fprintf(pidfile, "%d\n", self); // записываем в pidfilename свой pid - fclose(pidfile); + DIR *dir; + FILE* pidfile; + struct dirent *de; + struct stat s_buf; + pid_t pid, self, run = 0; + char name[256], myname[256]; + if (!(dir = opendir(PROC_BASE))){ // открываем директорию /proc + perror(PROC_BASE); + exit(1); + } + self = getpid(); // свой идентификатор + if(stat(pidfilename, &s_buf) == 0){ // есть файл с pid'ом + pidfile = fopen(pidfilename, "r"); + fscanf(pidfile, "%d", &run); // получаем pid (возможно) запущенного процесса + fclose(pidfile); + if(readname(name, run) && strncmp(name, myname, 255) == 0){ + WARN("\nFound running process (pid=%d), exit.\n", run); + exit(0); + } + } + // файла с pid'ом нет, или там неправильная запись + readname(myname, self); // свое имя процесса + while ((de = readdir (dir)) != NULL){ // пока не дойдем до конца директории + // пропустим, если директория не указывает на процесс, или указывает на self + if (!(pid = (pid_t) atoi (de->d_name)) || pid == self) + continue; + readname(name, pid); // считываем имя процесса + if(strncmp(name, myname, 255) == 0){ // если оно совпадает с myname + WARN("\nFound running process (pid=%d), exit.\n", pid); + exit(0); + } + } + closedir(dir); + unlink(pidfilename); // пробуем удалить pidfilename + WARN("my PID: %d\n", self); + pidfile = fopen(pidfilename, "w"); + fprintf(pidfile, "%d\n", self); // записываем в pidfilename свой pid + fclose(pidfile); } static inline void LOG(char* thetime, char* thetext){ - fprintf(stderr, "%s\t%s\n", thetime, thetext); - fprintf(F_log, "%s\t%s\n", thetime, thetext); + fprintf(stderr, "%s\t%s\n", thetime, thetext); + fprintf(F_log, "%s\t%s\n", thetime, thetext); } double dtime(){ - double ret; - struct timeval tv; - struct timezone tz; - gettimeofday(&tv, &tz); - ret = tv.tv_sec + tv.tv_usec / 1000000.; - return ret; + double ret; + struct timeval tv; + struct timezone tz; + gettimeofday(&tv, &tz); + ret = tv.tv_sec + tv.tv_usec / 1000000.; + return ret; } void printdate(char *s_time){ - time_t now = time(NULL); - struct tm ltime = *localtime(&now); - strftime(s_time, 32, "%d/%m/%Y, %H:%M:%S", <ime); + time_t now = time(NULL); + struct tm ltime = *localtime(&now); + strftime(s_time, 32, "%d/%m/%Y, %H:%M:%S", <ime); } static void signals(int sig){ - char nowatime[32]; - char *str; - int u; - printdate(nowatime); - if(sig == SIGTERM) - str = TERMINATED; - else if(sig == SIGHUP) - str = HUPPED; - else if(sig == SIGQUIT) - str = QUITTED; - else if(sig == SIGINT) - str = INTTED; - LOG(nowatime, str); - shmctl(shmid, IPC_RMID, NULL); // удаляем сегмент *Visor - close(cache_fd); - close(out_fd); - fclose(F_log); - if(t_out) free(t_out); if(t_in) free(t_in); - if(t_mir) free(t_mir); if(pres) free(pres); - if(hum) free(hum); - u = unlink(pidfilename); - if(u == -1) perror("Can't delete PIDfile"); - exit(sig); + char nowatime[32]; + char *str; + int u; + printdate(nowatime); + if(sig == SIGTERM) + str = TERMINATED; + else if(sig == SIGHUP) + str = HUPPED; + else if(sig == SIGQUIT) + str = QUITTED; + else if(sig == SIGINT) + str = INTTED; + LOG(nowatime, str); + shmctl(shmid, IPC_RMID, NULL); // удаляем сегмент *Visor + close(cache_fd); + close(out_fd); + fclose(F_log); + if(t_out) free(t_out); if(t_in) free(t_in); + if(t_mir) free(t_mir); if(pres) free(pres); + if(hum) free(hum); + u = unlink(pidfilename); + if(u == -1) perror("Can't delete PIDfile"); + exit(sig); } Status current_status(){// возвращаем текущее состояние телескопа @@ -147,166 +147,169 @@ Status current_status(){// * OTHER - наведение или прочее перемещение телескопа/купола * OPEN - идут наблюдения */ - time_t tt = time(NULL); - struct tm t_now = *localtime(&tt); - if(t_now.tm_hour > 7 && t_now.tm_hour < 18) *Visor = 0; // "закрываем" забрало днем - if(*Visor) return OPEN; // забрало открыто - if(Tel_Hardware == Hard_Off){ // варианты STOP, OTHER - if(Dome_State == D_Off) return STOP; // все выключено - return OTHER; // купол движется - } - if(Tel_State == Stopping){ // варианты READY, OTHER - if(Dome_State == D_Off) return READY; // питание есть, все остановлено - return OTHER; // купол движется - } - // варианты GUIDING, OTHER - if(Tel_Mode == Automatic) return GUIDING; // наблюдения - return OTHER; // наведение, ручная коррекция + time_t tt = time(NULL); + struct tm t_now = *localtime(&tt); + if(t_now.tm_hour > 7 && t_now.tm_hour < 18) *Visor = 0; // "закрываем" забрало днем + if(*Visor) return OPEN; // забрало открыто + if(Tel_Hardware == Hard_Off){ // варианты STOP, OTHER + if(Dome_State == D_Off) return STOP; // все выключено + return OTHER; // купол движется + } + if(Tel_State == Stopping){ // варианты READY, OTHER + if(Dome_State == D_Off) return READY; // питание есть, все остановлено + return OTHER; // купол движется + } + // варианты GUIDING, OTHER + if(Tel_Mode == Automatic) return GUIDING; // наблюдения + return OTHER; // наведение, ручная коррекция } int get_data(monit_d *data){// получаем данные /* - превышение std 30% среднего значения - возвращаем 0 - по ошибке возвращаем -1 - все нормально - возвращаем 1 + превышение std 30% среднего значения - возвращаем 0 + по ошибке возвращаем -1 + все нормально - возвращаем 1 */ - int nn = 0; - double tt; - data_type *to = t_out, *ti = t_in, *tm = t_mir, max_wnd = 0., - *p = pres, *h = hum; + int nn = 0; + double tt; + data_type *to = t_out, *ti = t_in, *tm = t_mir, max_wnd = 0., + *p = pres, *h = hum; // Состоянием телескопа считать последнее - tt = dtime(); - while(check_shm_block(&sdat) && (dtime() - tt < TIMEINTERVAL)){ - *to++ = val_T1; - *ti++ = val_T2; - *tm++ = val_T3; - if(val_Wnd > max_wnd) max_wnd = val_Wnd; - *p++ = Pressure; - *h++ = val_Hmd; - if(++nn == MAX_DATA_LEN) break; - usleep(1000000); // опрашиваем 1 раз в секунду + tt = dtime(); + while(check_shm_block(&sdat) && (dtime() - tt < TIMEINTERVAL)){ + *to++ = val_T1; + *ti++ = val_T2; + *tm++ = val_T3; + if(val_Wnd > max_wnd) max_wnd = val_Wnd; + *p++ = Pressure; + *h++ = val_Hmd; + if(++nn == MAX_DATA_LEN) break; + usleep(1000000); // опрашиваем 1 раз в секунду // !!! на цифре 10 завязано вычисление объема памяти для calloc, если надо будет // изменить величину паузы, необходимо и скорректировать MAX_DATA_LEN в main - } - if(!check_shm_block(&sdat)) return -1; // ошибка получения данных - data->seconds = time(NULL) - TIMEINTERVAL/2; - // вычисляем медианные показания - data->outdoor_temp = quick_select(t_out, nn); - data->indoor_temp = quick_select(t_in, nn); - data->mirror_temp = quick_select(t_mir, nn); - data->wind_speed = max_wnd; - data->pressure = quick_select(pres, nn); - data->humidity = quick_select(hum, nn); - data->status = current_status(); - return 1; + } + if(!check_shm_block(&sdat)) return -1; // ошибка получения данных + data->seconds = time(NULL) - TIMEINTERVAL/2; + // вычисляем медианные показания + data->outdoor_temp = quick_select(t_out, nn); + data->indoor_temp = quick_select(t_in, nn); + data->mirror_temp = quick_select(t_mir, nn); + data->wind_speed = max_wnd; + data->pressure = quick_select(pres, nn); + data->humidity = quick_select(hum, nn); + data->status = current_status(); + return 1; } void mkcache(uint *remain){ - char nowatime[32]; - off_t offset = 0; // в данном случае - off64_t, т.е. long long - Cache s_cache; - struct stat filestat; - unsigned long long cntr = 1ULL; - uint cc = 1; - monit_d data; - printdate(nowatime); - LOG(nowatime, "Making cache"); - if(read(out_fd, &data, sizeof(data)) < sizeof(data)){ - LOG(nowatime, "Corrupted out file"); - exit(1); - } - s_cache.offset = 0; - s_cache.time = data.seconds; - write(cache_fd, &s_cache, sizeof(s_cache)); - do{ - if(cc >= Nth){ - s_cache.time = data.seconds; - write(cache_fd, &s_cache, sizeof(s_cache)); - cc = 0; - } - cc++; cntr++; - s_cache.offset = tell(out_fd); - }while(read(out_fd, &data, sizeof(data)) == sizeof(data)); - *remain = cntr && (Nth - 1); - printdate(nowatime); - LOG(nowatime, "Cache is ready"); + char nowatime[32]; + off_t offset = 0; // в данном случае - off64_t, т.е. long long + Cache s_cache; + struct stat filestat; + unsigned long long cntr = 1ULL; + uint cc = 1; + monit_d data; + printdate(nowatime); + LOG(nowatime, "Making cache"); + if(read(out_fd, &data, sizeof(data)) < sizeof(data)){ + LOG(nowatime, "Corrupted out file"); + exit(1); + } + s_cache.offset = 0; + s_cache.time = data.seconds; + write(cache_fd, &s_cache, sizeof(s_cache)); + do{ + if(cc >= Nth){ + s_cache.time = data.seconds; + write(cache_fd, &s_cache, sizeof(s_cache)); + cc = 0; + } + cc++; cntr++; + s_cache.offset = tell(out_fd); + }while(read(out_fd, &data, sizeof(data)) == sizeof(data)); + *remain = cntr && (Nth - 1); + printdate(nowatime); + LOG(nowatime, "Cache is ready"); } int main(int argc, char** argv){ - char nowatime[32]; - struct stat s_stat; - uint cc = Nth + 1; - int tmp; - FILE *pidfile; - monit_d data; - Cache s_cache; - check4running(); - if(!(F_log = fopen(LOG_FILE, "a"))){ - fprintf(stderr, "Can't open log file, quit\n"); - exit(1); - } - setbuf(F_log, NULL); - printdate(nowatime); - LOG(nowatime, STARTED); - if((cache_fd = open(CACHE_FILE, O_RDWR|O_CREAT, 00644)) < 0){ - LOG(nowatime, "Can't open cache file, quit"); - exit(1); - } - if((out_fd = open(OUT_FILE, O_WRONLY|O_CREAT, 00644)) < 0){ - LOG(nowatime, "Can't open out file, quit"); - exit(1); - } - if(stat(OUT_FILE, &s_stat) < 0){ - LOG(nowatime, "Can't stat out file, quit"); - exit(1); - } - if(s_stat.st_size > 0){ // если файл с данными есть, проверяем наличие записей в кэше - if(stat(CACHE_FILE, &s_stat) < 0){ - LOG(nowatime, "Can't stat cache file, quit"); - exit(1); - } - if(s_stat.st_size == 0) - mkcache(&cc); - lseek(cache_fd, 0, SEEK_END); - lseek(out_fd, 0, SEEK_END); - } - close(0); close(1); close(2); - if(fork() != 0) exit(0); - signal(SIGTERM, signals); // kill (-15) - signal(SIGHUP, SIG_IGN); // на него можно что-нибудь повесить - signal(SIGINT, signals); // ctrl+C - signal(SIGQUIT, signals); // ctrl+\ - signal(SIGTSTP, SIG_IGN); // игнорируем ctrl+Z - get_shm_block( &sdat, ClientSide); - shmid = shmget(SHM_KEY, sizeof(int), IPC_CREAT | 0666); - Visor = (int*) shmat(shmid, NULL, 0); - MAX_DATA_LEN = ((int)(TIMEINTERVAL)) + 2; - t_out = (data_type*)calloc(MAX_DATA_LEN, sizeof(data_type)); - t_in = (data_type*)calloc(MAX_DATA_LEN, sizeof(data_type)); - t_mir = (data_type*)calloc(MAX_DATA_LEN, sizeof(data_type)); - pres = (data_type*)calloc(MAX_DATA_LEN, sizeof(data_type)); - hum = (data_type*)calloc(MAX_DATA_LEN, sizeof(data_type)); - while(1){ - tmp = get_data(&data); - if(tmp == 0){ - sleep(10); - continue; - } - if(tmp == -1){ - printdate(nowatime); - LOG(nowatime, "Error getting data"); - sleep(300); - continue; - } - s_cache.offset = tell(out_fd); - write(out_fd, &data, sizeof(data)); - if(++cc >= Nth){ - s_cache.time = data.seconds; - write(cache_fd, &s_cache, sizeof(s_cache)); - cc = 0; - printdate(nowatime); - LOG(nowatime, "Add cache data"); - } - } + char nowatime[32]; + struct stat s_stat; + uint cc = Nth + 1; + int tmp; + FILE *pidfile; + monit_d data; + Cache s_cache; + check4running(); + if(!(F_log = fopen(LOG_FILE, "a"))){ + fprintf(stderr, "Can't open log file, quit\n"); + exit(1); + } + setbuf(F_log, NULL); + printdate(nowatime); + LOG(nowatime, STARTED); + if((cache_fd = open(CACHE_FILE, O_RDWR|O_CREAT, 00644)) < 0){ + LOG(nowatime, "Can't open cache file, quit"); + exit(1); + } + if((out_fd = open(OUT_FILE, O_WRONLY|O_CREAT, 00644)) < 0){ + LOG(nowatime, "Can't open out file, quit"); + exit(1); + } + if(stat(OUT_FILE, &s_stat) < 0){ + LOG(nowatime, "Can't stat out file, quit"); + exit(1); + } + if(s_stat.st_size > 0){ // если файл с данными есть, проверяем наличие записей в кэше + if(stat(CACHE_FILE, &s_stat) < 0){ + LOG(nowatime, "Can't stat cache file, quit"); + exit(1); + } + if(s_stat.st_size == 0) + mkcache(&cc); + lseek(cache_fd, 0, SEEK_END); + lseek(out_fd, 0, SEEK_END); + } + close(0); close(1); close(2); + if(fork() != 0) exit(0); + signal(SIGTERM, signals); // kill (-15) + signal(SIGHUP, SIG_IGN); // на него можно что-нибудь повесить + signal(SIGINT, signals); // ctrl+C + signal(SIGQUIT, signals); // ctrl+\ + signal(SIGTSTP, SIG_IGN); // игнорируем ctrl+Z + if(!get_shm_block( &sdat, ClientSide)){ + fprintf(stderr, "Can't open SHM block!"); + exit(1); + } + shmid = shmget(SHM_KEY, sizeof(int), IPC_CREAT | 0666); + Visor = (int*) shmat(shmid, NULL, 0); + MAX_DATA_LEN = ((int)(TIMEINTERVAL)) + 2; + t_out = (data_type*)calloc(MAX_DATA_LEN, sizeof(data_type)); + t_in = (data_type*)calloc(MAX_DATA_LEN, sizeof(data_type)); + t_mir = (data_type*)calloc(MAX_DATA_LEN, sizeof(data_type)); + pres = (data_type*)calloc(MAX_DATA_LEN, sizeof(data_type)); + hum = (data_type*)calloc(MAX_DATA_LEN, sizeof(data_type)); + while(1){ + tmp = get_data(&data); + if(tmp == 0){ + sleep(10); + continue; + } + if(tmp == -1){ + printdate(nowatime); + LOG(nowatime, "Error getting data"); + sleep(300); + continue; + } + s_cache.offset = tell(out_fd); + write(out_fd, &data, sizeof(data)); + if(++cc >= Nth){ + s_cache.time = data.seconds; + write(cache_fd, &s_cache, sizeof(s_cache)); + cc = 0; + printdate(nowatime); + LOG(nowatime, "Add cache data"); + } + } } diff --git a/C/daemon/html/cal.jpg b/C/daemon/html/cal.jpg new file mode 100644 index 0000000..2df6fe7 Binary files /dev/null and b/C/daemon/html/cal.jpg differ diff --git a/C/daemon/html/contexthelp.js b/C/daemon/html/contexthelp.js new file mode 100644 index 0000000..8a7257c --- /dev/null +++ b/C/daemon/html/contexthelp.js @@ -0,0 +1,134 @@ +var tipobj=null; + +function startHelp(evt){ + evt.stopPropagation(); + evt.preventDefault(); + document.body.style.cursor = "help"; + document.body.onclick = Help; + document.body.onmouseover = stoponclick; +} + +function Help(evt){ + evt.stopPropagation(); + evt.preventDefault(); + if(!helptip(evt)) return; + document.body.onclick = ''; + document.body.style.cursor = "default"; + document.body.onmouseover = ''; +} + +var oldclc, oldmout; +function stoponclick(evt){ + var obj = evt.target; + if(obj == document.body) return; + oldclc = obj.onclick; + oldmout = obj.onmouseout; + obj.onclick = Help; + obj.onmouseout = releaseonclick; + obj.style.cursor = "help"; +} +function releaseonclick(evt){ + var obj = evt.target; + obj.onmouseout = oldmout; + obj.onclick = oldclc; + obj.style.cursor = "default"; +} +function helptip(evt){ + var ss = helpgen(evt), helper; + if(ss.length > 0){ + tipobj = document.createElement("DIV"); + tipobj.id = 'helptip'; + tipobj.setAttribute("name", "helptip"); + tipobj.onclick = rmtip; + tipobj.innerHTML = ss; + helper = document.createElement("DIV"); + helper.className = 'redtxt'; + helper.innerHTML = "Чтобы закрыть это окно, щелкните по нему левой кнопкой мыши или нажмите клавишу ESCAPE"; + helper.onclick = function(evt){evt.stopPropagation(); + document.body.removeChild(evt.target.parentNode);}; + tipobj.appendChild(helper); + document.body.appendChild(tipobj); + positiontip(evt); + } + releaseonclick(evt); + return (ss.length); +} + +function helpgen(evt){ + var obj = evt.target; + var objid, objname, ss="", nm; + onkey(27); + objid = obj.id; objname = obj.name; + if(objid == "" && objname == null){ + objid = obj.parentNode.id; + objname = obj.parentNode.name; + } + if(objid == "" && objname == null) return (ss); + if(objid == "" && objname != null) nm = objname; + else nm = objid; + ss = HelpText[nm]; + if(ss == null) ss = HelpText[obj.parentNode.id]; + return (ss); +} + +function positiontip(e){ + var wd = tipobj.offsetWidth, ht = tipobj.offsetHeight; + var curX = e.clientX + 25; + var curY = e.clientY - ht/2; + var btmedge = document.body.clientHeight - curY - 15; + var rightedge = document.body.clientWidth - curX - 15; + if(rightedge < wd) curX -= wd+50; + if(btmedge < ht) curY -= ht-btmedge+15; + if(curY < 15) curY = 15; + tipobj.style.left = curX+"px"; + tipobj.style.top = curY+"px"; +} + +function onkey(code){ + if(code != 27) return; + var helps = document.getElementsByName('helptip'); + var l = helps.length-1; + for(var i=l; i>-1; i--) document.body.removeChild(helps[i]); +} +function rmtip(evt){ + document.body.removeChild(evt.target); +} + +const HelpText = { + dtheader: "Ниже расположены поля, в которые необходимо ввести начальное и (опционально) конечное значения интервала времени, по которому будет производиться выбор данных.

Вы можете воспользоваться простым календарем (щелкнув на иконке справа от формы ввода даты и времени) или же ввести данные вручную.

При вводе данных вручную обратите внимание на формат даты и времени: дата вводится в формате МЕСЯЦ/ЧИСЛО/ГОД, затем через пробел вводится время в формате ЧАСЫ:МИНУТЫ. ГОД необходимо писать полным (т.е. 2010, а не просто 10).

Например, время \"7 часов 35 минут 10 марта 2010 года\" необходимо вводить так:

\"03/10/2010 7:35\".", + t_beg: "Введите в это поле время, начиная с которого вы хотите получить статистические данные.", + t_end: "Ввведите в это поле время окончания интервала.

Если вы оставите поле пустым, конечным будет считаться текущее время.", + cal: "Нажмите сюда, если вы хотите выбрать время и дату при помощи простого календаря.

В форму календаря сначала введите нужное время, затем выберите нужный год и месяц и щелкните по нужной дате.", + reqbtn: "После ввода начального и (опционально) конечного значения интересующего Вас интервала времени, нажмите на эту кнопку для построения графиков и получения статистической информации.", + avertime: "Это поле позволяет выбрать интервал времени, по которому будет производиться медианное усреднение данных, получаемых Вами при нажатии на ссылку \"Сохранить файл\".", + averinterval: "Введите в это поле промежуток времени, по которому будет производиться медианное усреднение.", + averval: "Выберите единицу измерения времени: минуты, часы или сутки.", + modes: "Выберите интересующие режимы работы телескопа.

При щелчке по этой надписи выбор всех режимов инвертируется.", + Mstp: "Питание телескопа и купола отключено.", + Mgd: "Режим сопровождения объекта (скорее всего, в это время проводились наблюдения).", + Mrd: "Основной режим простоя: телескоп готов к работе.", + Moth: "Режим, не попадающий в предыдущие (например, наведение на объект).", + Mopn: "На телескопе проводятся наблюдения.

Внимание! Этот режим не устанавливается автоматически и зависит от того, не забудет ли оператор при начале наблюдений нажать кнопку \"Забрало открыто\", а после их окончаний - кнопку \"Забрало закрыто\".", + Statbtn: "При нажатии этой кнопки отображается/скрывается форма для запроса дополнительной статистики: экстремальные значения метеопараметров, интересующий диапазон метеопараметров.", + Visorbtn: "При нажатии на эту кнопку активируется режим \"Забрало открыто/закрыто\".

Текущий статус отображается текстовой строкой.", + StMax: "Нажмите на эту кнопку для отображения максимальных значений всех метеопараметров за выбранный промежуток времени.", + StMin: "Нажмите на эту кнопку для отображения минимальных значений всех метеопараметров за выбранный промежуток времени.", + StMode: "Нажмите на эту кнопку, если хотите узнать, сколько времени телескоп провел в каждом из режимов за выбранный промежуток времени.", + morethan: "Введите в это поле нижнюю границу значения интересующего метеопараметра.

Параметр должен быть отмечен \"галочкой\" на форме \"Отобразить\".", + and_or: "Выбор логики, возможные значения: \"И\" и \"ИЛИ\". Примеры:
  • для поиска значений больше заданного заполните поле \"больше\", оставьте пустым поле \"меньше\", выберите логику \"ИЛИ\";
  • для поиска значений меньше заданного оставьте незаполненным поле \"больше\", заполните поле \"меньше\", логика - \"ИЛИ\";
  • если Вы выберете логику \"ИЛИ\" и заполните оба поля, будут найдены значения вне диапазона между \"меньше\" и \"больше\", число в поле \"меньше\" должно быть меньше числа в поле \"больше\";
  • при выборе логики \"И\" оба поля должны быть обязательно заполнены, отображаются данные внутри диапазона между \"больше\" и \"меньше\", число в поле \"меньше\" должно быть больше числа в поле \"больше\".
Если в результате запроса никакие результаты не отобразились, значит, выбранные метеопараметры имели значения внутри заданного диапазона в течение всего выбранного времени.", + lessthan: "Введите в это поле верхнюю границу значения интересующего метеопараметра.

Параметр должен быть отмечен \"галочкой\" на форме \"Отобразить\".", + MkStat: "После заполнения полей слева, нажмите эту кнопку для получения статистики.", + Sall: "Отметьте те метеопараметры, которые вы хотите видеть на графике, или по которым вы хотите запросить диапазоны времени с интересующими значениями.

При щелчке по этой надписи инвертируется выбор всех метеопараметров.", + Stemp: "Щелкните по этой надписи для инвертирования выбора температур.", + Sout: "Отобразить данные по внешней температуре.", + Sin: "Отобразить данные по внутренней температуре.", + Smr: "Отобразить данные по температуре зеркала.", + Swnd: "Отобразить данные по скорости ветра.", + Sprs: "Отобразить данные по атмосферному давлению.", + Shmd: "Отобразить данные по относительной влажности.", + imcontrols: "Выберите формат изображения для отображения графиков.", + SVG: "Векторный формат SVG лучше всего подходит для отображения графиков, может быть вставлен в любую презентацию или отчет (во втором случае конвертируйте его в eps при помощи утилиты convert пакета ImageMagic).

Внимание! Старые браузеры не способны отобразить этот формат. Если ваш браузер не будет отображать графики, либо обновите его, либо выберите другой формат изображения.", + JPEG: "Наиболее популярный формат для хранения растровых изображения. Имеет наихудшее качество, в чем вы можете убедиться.", + GIF: "Растровый формат, немногим лучше JPEG.

JPEG и GIF неудобны для помещения в презентации или отчеты, т.к. плохо масштабируются (из-за своей растровой природы)." +} + diff --git a/C/daemon/html/datetime.css b/C/daemon/html/datetime.css new file mode 100644 index 0000000..723a6b4 --- /dev/null +++ b/C/daemon/html/datetime.css @@ -0,0 +1,145 @@ +/* form with data & time */ +.datetime { + width: 150px;} + +/* button showdate */ +.dpBtn { + width: 22px;} + +/* input for time value */ +.dpTime { + width: 80px;} + +/* the div that holds the date picker calendar */ +.dpDiv { + } + + +/* the table (within the div) that holds the date picker calendar */ +.dpTable { + font-family: Tahoma, Arial, Helvetica, sans-serif; + font-size: 12px; + text-align: center; + color: #505050; + background: #ECF5F8; + border: 0px; + width: 180px; + } + + +/* a table row that holds date numbers (either blank or 1-31) */ +.dpTR { + } + + +/* the top table row that holds the month, year, and forward/backward buttons */ +.dpTitleTR { + } + + +/* the second table row, that holds the names of days of the week (Mo, Tu, We, etc.) */ +.dpDayTR { + } + + +/* the bottom table row, that has the "This Month" and "Close" buttons */ +.dpTodayButtonTR { + } + + +/* a table cell that holds a date number (either blank or 1-31) */ +.dpTD { + border: 0px; + width: 25px; + } + + +/* a table cell that holds a highlighted day (usually either today's date or the current date field value) */ +.dpDayHighlightTD { + border: 0px; + background-color: #CCCCCC; + } + + +/* the date number table cell that the mouse pointer is currently over (you can use contrasting colors to make it apparent which cell is being hovered over) */ +.dpTDHover { + border: 0px; + font-style: oblique; + background-color: #aca998; + cursor: pointer; + color: red; + } + + +/* the table cell that holds the name of the month and the year */ +.dpTitleTD { + border: 0px; + } + +/* the table cell that holds the time */ +.dpFullTitleTD { + border: 0px; + } + +/* a table cell that holds one of the forward/backward buttons */ +.dpButtonTD { + border: 0px; + } + + +/* the table cell that holds the "This Month" or "Close" button at the bottom */ +.dpTodayButtonTD { + border: 0px; + } + + +/* a table cell that holds the names of days of the week (Mo, Tu, We, etc.) */ +.dpDayTD { + background-color: #CCCCCC; + border: 0px; + color: white; + } + + +/* additional style information for the text that indicates the month and year */ +.dpTitleText { + font-size: 12px; + color: gray; + text-align: center; + font-weight: bold; + } + + +/* additional style information for the cell that holds a highlighted day (usually either today's date or the current date field value) */ +.dpDayHighlight { + color: 4060ff; + font-weight: bold; + } + + +/* the forward/backward buttons at the top */ +.dpButton { + font-family: Verdana, Tahoma, Arial, Helvetica, sans-serif; + font-size: 6pt; + background: #8FCADB; + padding: 2px; + width: 20pt; + border: 0px solid #64A6B9; + color: white; + font-weight: bold; + margin-bottom: 1px; + } + + +/* the "This Month" and "Close" buttons at the bottom */ +.dpTodayButton { + font-family: Arial, Verdana, Tahoma, Helvetica, sans-serif; + font-size: 10px; + color: white; + background: #8FCADB; + font-weight: bold; + border: 0px solid #64A6B9; + padding: 1px 3px 1px 3px; + margin-right: 3px; + } + diff --git a/C/daemon/html/datetime.js b/C/daemon/html/datetime.js new file mode 100644 index 0000000..ce6a95d --- /dev/null +++ b/C/daemon/html/datetime.js @@ -0,0 +1,376 @@ +var datePickerDivID = "datepicker"; +var iFrameDivID = "datepickeriframe"; + +var dayArray = new Array('Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'); +var monthArray = new Array('January', 'February', 'March', 'April', 'May', 'June', 'July', + 'August', 'September', 'October', 'November', 'December'); + +var timefieldValue = null; // Содержимого поля "время" + +var defaultDateSeparator = "/"; // common values would be "/" or "." +var defaultDateFormat = "mdy" // valid values are "mdy", "dmy", and "ymd" +var dateSeparator = defaultDateSeparator; +var dateFormat = defaultDateFormat; + +function displayDatePicker(dateFieldName, displayBelowThisObject, dtFormat, dtSep) +{ + var targetDateField = document.getElementsByName(dateFieldName).item(0); + + // if we weren't told what node to display the datepicker beneath, just display it + // beneath the date field we're updating + if (!displayBelowThisObject) + displayBelowThisObject = targetDateField; + + // if a date separator character was given, update the dateSeparator variable + if (dtSep) + dateSeparator = dtSep; + else + dateSeparator = defaultDateSeparator; + + // if a date format was given, update the dateFormat variable + if (dtFormat) + dateFormat = dtFormat; + else + dateFormat = defaultDateFormat; + + var x = displayBelowThisObject.offsetLeft; + var y = displayBelowThisObject.offsetTop + displayBelowThisObject.offsetHeight ; + + // deal with elements inside tables and such + var parent = displayBelowThisObject; + while (parent.offsetParent) { + parent = parent.offsetParent; + x += parent.offsetLeft; + y += parent.offsetTop ; + } + + drawDatePicker(targetDateField, x, y); +} + + +function drawDatePicker(targetDateField, x, y) +{ + var dt = getFieldDate(targetDateField.value ); + + // the datepicker table will be drawn inside of a
with an ID defined by the + // global datePickerDivID variable. If such a div doesn't yet exist on the HTML + // document we're working with, add one. + if (!document.getElementById(datePickerDivID)) { + // don't use innerHTML to update the body, because it can cause global variables + // that are currently pointing to objects on the page to have bad references + //document.body.innerHTML += "
"; + var newNode = document.createElement("div"); + newNode.setAttribute("id", datePickerDivID); + newNode.setAttribute("class", "dpDiv"); + newNode.setAttribute("style", "visibility: hidden;"); + document.body.appendChild(newNode); + } + + // move the datepicker div to the proper x,y coordinate and toggle the visiblity + var pickerDiv = document.getElementById(datePickerDivID); + pickerDiv.style.position = "absolute"; + pickerDiv.style.left = x + "px"; + pickerDiv.style.top = y + "px"; + pickerDiv.style.visibility = (pickerDiv.style.visibility == "visible" ? "hidden" : "visible"); + pickerDiv.style.display = (pickerDiv.style.display == "block" ? "none" : "block"); + pickerDiv.style.zIndex = 10000; + + // draw the datepicker table + refreshDatePicker(targetDateField.name, dt.getFullYear(), dt.getMonth(), dt.getDate()); +} + +function getTimeString(time){ + var hourString = "00" + time.getHours(); + var minuteString = "00" + time.getMinutes(); + hourString = hourString.substring(hourString.length - 2); + minuteString = minuteString.substring(minuteString.length - 2); + var timeString = ' ' + hourString + ':' + minuteString; + return timeString; +} + +// Fill time field with current time +function getTimeInput(){ + var str = "time: " + return str; +} + +/** +This is the function that actually draws the datepicker calendar. +*/ +function refreshDatePicker(dateFieldName, year, month, day) +{ + // if no arguments are passed, use today's date; otherwise, month and year + // are required (if a day is passed, it will be highlighted later) + var thisDay = new Date(); + + if ((month >= 0) && (year > 0)) { + thisDay = new Date(year, month, 1); + } else { + day = thisDay.getDate(); + thisDay.setDate(1); + } + + // the calendar will be drawn as a table + // you can customize the table elements with a global CSS style sheet, + // or by hardcoding style and formatting elements below + var crlf = "\r\n"; + var TABLE = "" + crlf; + var xTABLE = "
" + crlf; + var TR = ""; + var TR_title = ""; + var TR_days = ""; + var TR_todaybutton = ""; + var xTR = "" + crlf; + var TD = "' + getButtonCode(dateFieldName, thisDay, -1, "<","Previous month") + xTD; + html += TD_title + DIV_title + monthArray[ thisDay.getMonth()] + " " + thisDay.getFullYear() + xDIV + xTD; + html += TD_buttons + getButtonCode(dateFieldName, thisDay, 12, ">>", "Next year") + '
' + getButtonCode(dateFieldName, thisDay, 1, ">","next month") + xTD; + html += xTR; + + // this is the row that indicates which day of the week we're on + html += TR_days; + for(i = 0; i < dayArray.length; i++) + html += TD_days + dayArray[i] + xTD; + html += xTR; + + // now we'll start populating the table with days of the month + html += TR; + + // first, the leading blanks + for (i = 0; i < thisDay.getDay(); i++) + html += TD + " " + xTD; + + // now, the days of the month + do { + dayNum = thisDay.getDate(); + TD_onclick = " onclick=\"updateDateField('" + dateFieldName + "', '" + getDateString(thisDay) + "');\">"; + + if (dayNum == day) + html += TD_selected + TD_onclick + DIV_selected + dayNum + xDIV + xTD; + else + html += TD + TD_onclick + dayNum + xTD; + + // if this is a Saturday, start a new row + if (thisDay.getDay() == 6) + html += xTR + TR; + + // increment the day + thisDay.setDate(thisDay.getDate() + 1); + } while (thisDay.getDate() > 1) + + // fill in any trailing blanks + if (thisDay.getDay() > 0) { + for (i = 6; i > thisDay.getDay(); i--) + html += TD + " " + xTD; + } + html += xTR; + + // add a button to allow the user to easily return to today, or close the calendar + var today = new Date(); + html += TR_todaybutton + TD_todaybutton; + html += " "; + html += xTD + TD_buttons + xTD + TD_todaybutton; + html += ""; + html += xTD + xTR; + + // and finally, close the table + html += xTABLE; + + document.getElementById(datePickerDivID).innerHTML = html; + // add an "iFrame shim" to allow the datepicker to display above selection lists + adjustiFrame(); +} + + +/** +Convenience function for writing the code for the buttons that bring us back or forward +a month. +*/ +function getButtonCode(dateFieldName, dateVal, adjust, label, title) +{ + var newMonth = (dateVal.getMonth () + adjust) % 12; + var newYear = dateVal.getFullYear() + parseInt((dateVal.getMonth() + adjust) / 12); + if (newMonth < 0) { + newMonth += 12; + newYear += -1; + } + + return ""; +} + + +/** +Convert a JavaScript Date object to a string, based on the dateFormat and dateSeparator +variables at the beginning of this script library. +*/ +function getDateString(dateVal) +{ + var dayString = "00" + dateVal.getDate(); + var monthString = "00" + (dateVal.getMonth()+1); + + dayString = dayString.substring(dayString.length - 2); + monthString = monthString.substring(monthString.length - 2); + + switch (dateFormat) { + case "dmy" : + return dayString + dateSeparator + monthString + dateSeparator + dateVal.getFullYear(); + case "ymd" : + return dateVal.getFullYear() + dateSeparator + monthString + dateSeparator + dayString; + case "mdy" : + default : + return monthString + dateSeparator + dayString + dateSeparator + dateVal.getFullYear(); + } +} + + +/** +Convert a string to a JavaScript Date object. +*/ +function getFieldDate(dateString) +{ + var dateVal; + var dArray; + var d, m, y; + + try { + dArray = splitDateString(dateString); + if (dArray) { + switch (dateFormat) { + case "dmy" : + d = parseInt(dArray[0], 10); + m = parseInt(dArray[1], 10) - 1; + y = parseInt(dArray[2], 10); + break; + case "ymd" : + d = parseInt(dArray[2], 10); + m = parseInt(dArray[1], 10) - 1; + y = parseInt(dArray[0], 10); + break; + case "mdy" : + default : + d = parseInt(dArray[1], 10); + m = parseInt(dArray[0], 10) - 1; + y = parseInt(dArray[2], 10); + break; + } + dateVal = new Date(y, m, d); + } else if (dateString) { + dateVal = new Date(dateString); + } else { + dateVal = new Date(); + } + } catch(e) { + dateVal = new Date(); + } + return dateVal; +} + + +/** +Try to split a date string into an array of elements, using common date separators. +If the date is split, an array is returned; otherwise, we just return false. +*/ +function splitDateString(dateString) +{ + var dArray; + if (dateString.indexOf("/") >= 0) + dArray = dateString.split("/"); + else if (dateString.indexOf(".") >= 0) + dArray = dateString.split("."); + else if (dateString.indexOf("-") >= 0) + dArray = dateString.split("-"); + else if (dateString.indexOf("\\") >= 0) + dArray = dateString.split("\\"); + else + dArray = false; + + return dArray; +} + +function updateDateField(dateFieldName, dateString) +{ + var timeString = ""; + if(timefieldValue && dateString){ + var time = new Date; + time.setTime(Date.parse(dateString +' ' + timefieldValue)); + timeString = getTimeString(time); + } + + var targetDateField = document.getElementsByName(dateFieldName).item(0); + if (dateString) + targetDateField.value = dateString + timeString; + + var pickerDiv = document.getElementById(datePickerDivID); + pickerDiv.style.visibility = "hidden"; + pickerDiv.style.display = "none"; + + adjustiFrame(); + targetDateField.focus(); + + if ((dateString) && (typeof(datePickerClosed) == "function")) + datePickerClosed(targetDateField); +} + +function adjustiFrame(pickerDiv, iFrameDiv) +{ + // put a try/catch block around the whole thing, just in case + try { + if (!document.getElementById(iFrameDivID)) { + // don't use innerHTML to update the body, because it can cause global variables + // that are currently pointing to objects on the page to have bad references + //document.body.innerHTML += "