diff --git a/daemon.c b/daemon.c new file mode 100644 index 0000000..d21209e --- /dev/null +++ b/daemon.c @@ -0,0 +1,140 @@ +/* + * daemon.c - functions for running in background like a daemon + * + * Copyright 2013 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 PROC_BASE "/proc" + +#include // printf, fopen, ... +#include // getpid +#include // perror +#include // opendir +#include // opendir +#include // stat +#include // fcntl +#include // exit +#include // memset + +/** + * read process name from /proc/PID/cmdline + * @param pid - PID of interesting process + * @return filename or NULL if not found + * don't use this function twice for different names without copying + * its returning by strdup, because `name` contains in static array + */ +char *readname(pid_t pid){ + static char name[256]; + char *pp = name, byte, path[256]; + FILE *file; + int cntr = 0; + size_t sz; + snprintf (path, 255, PROC_BASE "/%d/cmdline", pid); + file = fopen(path, "r"); + if(!file) return NULL; // there's no such file + do{ // read basename + sz = fread(&byte, 1, 1, file); + if(sz != 1) break; + if(byte != '/') *pp++ = byte; + else{ + pp = name; + cntr = 0; + } + }while(byte && cntr++ < 255); + name[cntr] = 0; + fclose(file); + return name; +} + +void iffound_default(pid_t pid){ + fprintf(stderr, "\nFound running process (pid=%d), exit.\n", pid); + exit(0); +} + +/** + * check wether there is a same running process + * exit if there is a running process or error + * Checking have 3 steps: + * 1) lock executable file + * 2) check pidfile (if you run a copy?) + * 3) check /proc for executables with the same name (no/wrong pidfile) + * @param argv - argument of main() or NULL for non-locking, call this function before getopt() + * @param pidfilename - name of pidfile or NULL if none + * @param iffound - action to run if file found or NULL for exit(0) + */ +void check4running(char **argv, char *pidfilename, void (*iffound)(pid_t pid)){ + DIR *dir; + FILE *pidfile, *fself; + struct dirent *de; + struct stat s_buf; + pid_t pid = 0, self; + struct flock fl; + char *name, *myname; + if(!iffound) iffound = iffound_default; + if(argv){ // block self + fself = fopen(argv[0], "r"); // open self binary to lock + memset(&fl, 0, sizeof(struct flock)); + fl.l_type = F_WRLCK; + if(fcntl(fileno(fself), F_GETLK, &fl) == -1){ // check locking + perror("fcntl"); + exit(1); + } + if(fl.l_type != F_UNLCK){ // file is locking - exit + printf("Found locker, PID = %d!\n", fl.l_pid); + exit(1); + } + fl.l_type = F_RDLCK; + if(fcntl(fileno(fself), F_SETLKW, &fl) == -1){ + perror("fcntl"); + exit(1); + } + } + self = getpid(); // get self PID + if(!(dir = opendir(PROC_BASE))){ // open /proc directory + perror(PROC_BASE); + exit(1); + } + if(!(name = readname(self))){ // error reading self name + perror("Can't read self name"); + exit(1); + } + myname = strdup(name); + if(pidfilename && stat(pidfilename, &s_buf) == 0){ // pidfile exists + pidfile = fopen(pidfilename, "r"); + if(pidfile){ + fscanf(pidfile, "%d", &pid); // read PID of (possibly) running process + fclose(pidfile); + if((name = readname(pid)) && strncmp(name, myname, 255) == 0) + iffound(pid); + } + } + // There is no pidfile or it consists a wrong record + while((de = readdir(dir))){ // scan /proc + if(!(pid = (pid_t)atoi(de->d_name)) || pid == self) // pass non-PID files and self + continue; + if((name = readname(pid)) && strncmp(name, myname, 255) == 0) + iffound(pid); + } + closedir(dir); + if(pidfilename){ + pidfile = fopen(pidfilename, "w"); + fprintf(pidfile, "%d\n", self); // write self PID to pidfile + fclose(pidfile); + } + free(myname); +} diff --git a/jsonbta/Makefile b/jsonbta/Makefile new file mode 100644 index 0000000..2fb1875 --- /dev/null +++ b/jsonbta/Makefile @@ -0,0 +1,16 @@ +LOADLIBES = -lm -lcrypt +SRCS = bta_json.c bta_print.c ../daemon.c +CC = gcc +DEFINES = +CXX = gcc +CPPFLAGS = -Wall -Werror $(DEFINES) +OBJS = $(SRCS:.c=.o) +all : bta_json client_streaming +$(OBJS): bta_json.h bta_shdata.h +bta_json : $(OBJS) + $(CC) $(CPPFLAGS) $(OBJS) $(LOADLIBES) -o bta_json +client_streaming: client_streaming.o + $(CC) $(CPPFLAGS) -lm -ljson client_streaming.o -o client_streaming +clean: + /bin/rm -f *.o *~ + diff --git a/jsonbta/bta_json.c b/jsonbta/bta_json.c new file mode 100644 index 0000000..4cb1482 --- /dev/null +++ b/jsonbta/bta_json.c @@ -0,0 +1,211 @@ +/* + * bta_json.c - create socket and reply bta data + * + * Copyright 2013 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. + */ + +#include +#include "bta_json.h" + +// wait for child to avoid zombies +static void wait_for_child(int sig){ + pid_t child; + while((child = waitpid(-1, NULL, WNOHANG)) > 0); +} + +// search a first word after needle without spaces +char* stringscan(char *str, char *needle){ + char *a, *e; + char *end = str + strlen(str); + a = strstr(str, needle); + if(!a) return NULL; + a += strlen(needle); + while (a < end && (*a == ' ' || *a == '\r' || *a == '\t' || *a == '\r')) a++; + if(a >= end) return NULL; + e = strchr(a, ' '); + if(e) *e = 0; + return a; +} + +/** + * Parce data received from client + * In case of http request we send all avaiable data + * In case of request from client socket, parce it + * Socket's request have structure like "par1par2..." + * where "pars" are names of bta_pars fields + * is delimeter: one of symbols " &\t\n" + * @param buf - incoming data + * @param L - length of buf + * @param par - returned parameters structure + */ +void parce_incoming_buf(char *buf, size_t L, bta_pars *par){ + char *tok, *got; + memset(par, 0, sizeof(bta_pars)); + DBG("got data: %s", buf); + // http request - send all if get == "bta_par" + // if get == "bta_par?a&b&c...", change buf to pars + if((got = stringscan(buf, "GET"))){ + size_t LR = strlen(RESOURCE); + if(strcmp(got, RESOURCE) == 0){ + par->ALL = true; + return; + }else if(strncmp(got, RESOURCE, LR) == 0) buf = &got[LR+1]; + else exit(-1); // wrong request + } + // request from socket -> check all parameters + tok = strtok(buf, " &\t\n"); + if(!tok) return; + do{ + #define checkpar(val) if(strcasecmp(tok, val) == 0){par->val = true; continue;} + checkpar(vel); + checkpar(diff); + checkpar(corr); + checkpar(mtime); + checkpar(meteo); + checkpar(target); + checkpar(p2mode); + checkpar(eqcoor); + checkpar(telmode); + checkpar(sidtime); + checkpar(horcoor); + checkpar(valsens); + checkpar(telfocus); + #undef checkpar + }while((tok = strtok(NULL, " &\t\n"))); +} + +void handle(int newsock){ + size_t buflen = 4095; + char buffer[buflen + 1]; + bta_pars par; + do{ + ssize_t readed = recv(newsock, buffer, buflen, 0); + if(readed < 1) break; // client closed or error + parce_incoming_buf(buffer, readed, &par); + #ifdef EBUG + #define checkpar(val) if(par.val){ fprintf(stderr, "par: %s\n", val); } + if(par.ALL){ fprintf(stderr, "par: ALL\n"); } + checkpar(vel); + checkpar(diff); + checkpar(corr); + checkpar(mtime); + checkpar(sidtime); + checkpar(meteo); + checkpar(target); + checkpar(p2mode); + checkpar(eqcoor); + checkpar(telmode); + checkpar(horcoor); + checkpar(valsens); + checkpar(telfocus); + #undef checkpar + #endif // EBUG + make_JSON(newsock, &par); + }while(!par.ALL); + close(newsock); +} + +int main(int argc, char **argv){ + int sock; + struct sigaction sa; + struct addrinfo hints, *res, *p; + int reuseaddr = 1; + check4running(argv, PIDFILE, NULL); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + if(getaddrinfo(NULL, PORT, &hints, &res) != 0){ + perror("getaddrinfo"); + return 1; + } + struct sockaddr_in *ia = (struct sockaddr_in*)res->ai_addr; + char str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(ia->sin_addr), str, INET_ADDRSTRLEN); + printf("port: %u, addr: %s\n", ntohs(ia->sin_port), str); + // loop through all the results and bind to the first we can + for(p = res; p != NULL; p = p->ai_next){ + if((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){ + perror("socket"); + continue; + } + if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1){ + perror("setsockopt"); + return -1; + } + if(bind(sock, p->ai_addr, p->ai_addrlen) == -1){ + close(sock); + perror("bind"); + continue; + } + break; // if we get here, we must have connected successfully + } + if(p == NULL){ + // looped off the end of the list with no successful bind + fprintf(stderr, "failed to bind socket\n"); + exit(2); + } + // Listen + if(listen(sock, BACKLOG) == -1) { + perror("listen"); + return 1; + } + freeaddrinfo(res); + // Set up the signal handler + sa.sa_handler = wait_for_child; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + if (sigaction(SIGCHLD, &sa, NULL) == -1) { + perror("sigaction"); + return 1; + } + // OK, all done, now we can daemonize + #ifndef EBUG // daemonize only in release mode + if(daemon(1, 0)){ + perror("daemon()"); + exit(1); + } + #endif // EBUG + // Main loop + while(1){ + struct sockaddr_in their_addr; + socklen_t size = sizeof(struct sockaddr_in); + int newsock = accept(sock, (struct sockaddr*)&their_addr, &size); + int pid; + if(newsock == -1) return 0; + pid = fork(); + if(pid == 0){ + // Child process + close(sock); + handle(newsock); + return 0; + }else{ + // Parent process + if(pid == -1) return 1; + else{ + close(newsock); + DBG("Create child: %d", pid); + } + } + } + close(sock); + return 0; +} + + +// конец файла diff --git a/jsonbta/bta_json.h b/jsonbta/bta_json.h new file mode 100644 index 0000000..99b34f4 --- /dev/null +++ b/jsonbta/bta_json.h @@ -0,0 +1,92 @@ +/* + * bta_json.h + * + * Copyright 2013 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. + */ + +#pragma once +#ifndef __BTA_JSON_H__ +#define __BTA_JSON_H__ + +#include +#include +#include // exit +#include +#include +#include +#include +#include +#include +#include +#include + +#define RESOURCE "/bta_par" // resource to request in http +#define PORT "12345" // Port to listen on +#define BACKLOG 10 // Passed to listen() +#define PIDFILE "/tmp/btajson.pid" // PID file + +#ifdef EBUG // debug mode + #define DBG(...) do{fprintf(stderr, __VA_ARGS__); fprintf(stderr,"\n");}while(0) +#else + #define DBG(...) +#endif + +typedef struct{ + bool ALL; + bool corr; + bool diff; + bool eqcoor; + bool horcoor; + bool meteo; + bool mtime; + bool p2mode; + bool sidtime; + bool target; + bool telfocus; + bool telmode; + bool valsens; + bool vel; +} bta_pars; + +// named parameters +#ifndef BTA_PRINT_C + #define defpar(val) const char* val = #val +#else + #define defpar(val) extern const char* val +#endif +defpar(mtime); +defpar(sidtime); +defpar(telmode); +defpar(telfocus); +defpar(target); +defpar(p2mode); +defpar(eqcoor); +defpar(horcoor); +defpar(valsens); +defpar(diff); +defpar(vel); +defpar(corr); +defpar(meteo); +#undef defpar + +void make_JSON(int sock, bta_pars *par); // bta_print.c +void check4running(char **argv, char *pidfilename, void (*iffound)(pid_t pid)); // daemon.h + +#endif // __BTA_JSON_H__ + +// конец файла diff --git a/jsonbta/bta_print.c b/jsonbta/bta_print.c new file mode 100644 index 0000000..5920b16 --- /dev/null +++ b/jsonbta/bta_print.c @@ -0,0 +1,380 @@ +/* + * bta_print.c + * + * Copyright Vladimir S. Shergin + * + * some changes (2013) 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bta_shdata.h" +#define BTA_PRINT_C +#include "bta_json.h" + +#define BUFSZ 255 +static char buf[BUFSZ+1]; + +char *double_asc(double d, char *fmt){ + if(!fmt) snprintf(buf, BUFSZ, "%.6f", d); + else snprintf(buf, BUFSZ, fmt, d); + return buf; +} + +char *time_asc(double t){ + int h, min; + double sec; + h = (int)(t/3600.); + min = (int)((t - (double)h*3600.)/60.); + sec = t - (double)h*3600. - (double)min*60.; + h %= 24; + if(sec>59.99) sec=59.99; + snprintf(buf, BUFSZ, "\"%02d:%02d:%05.2f\"", h,min,sec); + return buf; +} + +char *angle_asc(double a){ + char s; + int d, min; + double sec; + if (a >= 0.) + s = '+'; + else { + s = '-'; a = -a; + } + d = (int)(a/3600.); + min = (int)((a - (double)d*3600.)/60.); + sec = a - (double)d*3600. - (double)min*60.; + d %= 360; + if(sec>59.9) sec=59.9; + snprintf (buf, BUFSZ, "\"%c%02d:%02d:%04.1f\"", s,d,min,sec); + return buf; +} + +char *angle_fmt(double a, char *format){ + char s, *p; + int d, min, n; + double sec, msec; + char *newformat = calloc(strlen(format) + 3, 1); + assert(newformat); + sprintf(newformat, "\"%s\"", format); + if (a >= 0.) + s = '+'; + else { + s = '-'; a = -a; + } + d = (int)(a/3600.); + min = (int)((a - (double)d*3600.)/60.); + sec = a - (double)d*3600. - (double)min*60.; + d %= 360; + if ((p = strchr(format,'.')) == NULL) + msec=59.; + else if (*(p+2) == 'f' ) { + n = *(p+1) - '0'; + msec = 60. - pow(10.,(double)(-n)); + } else + msec=60.; + if(sec>msec) sec=msec; + if (strstr(format,"%c")) + snprintf(buf, BUFSZ, newformat, s,d,min,sec); + else + snprintf(buf, BUFSZ, newformat, d,min,sec); + free(newformat); + return buf; +} + +#ifndef PI +#define PI 3.14159265358979323846 /* pi */ +#endif + +#define R2D 180./PI /* rad. to degr. */ +#define D2R PI/180. /* degr. to rad. */ +#define R2S 648000./PI /* rad. to sec */ +#define S2R PI/648000. /* sec. to rad. */ +#define S360 1296000. /* sec in 360degr */ + +const double longitude=149189.175; /* SAO longitude 41 26 29.175 (-2:45:45.945)*/ +const double Fi=157152.7; /* SAO latitude 43 39 12.7 */ +const double cos_fi=0.7235272793; /* Cos of SAO latitude */ +const double sin_fi=0.6902957888; /* Sin --- "" ----- */ + +static void calc_AZ(double alpha, double delta, double stime, double *az, double *zd){ + double sin_t,cos_t, sin_d,cos_d, cos_z; + double t, d, z, a, x, y; + + t = (stime - alpha) * 15.; + if (t < 0.) + t += S360; // +360degr + t *= S2R; // -> rad + d = delta * S2R; + sin_t = sin(t); + cos_t = cos(t); + sin_d = sin(d); + cos_d = cos(d); + + cos_z = cos_fi * cos_d * cos_t + sin_fi * sin_d; + z = acos(cos_z); + + y = cos_d * sin_t; + x = cos_d * sin_fi * cos_t - cos_fi * sin_d; + a = atan2(y, x); + + *zd = z * R2S; + *az = a * R2S; +} + +static double calc_PA(double alpha, double delta, double stime){ + double sin_t,cos_t, sin_d,cos_d; + double t, d, p, sp, cp; + + t = (stime - alpha) * 15.; + if (t < 0.) + t += S360; // +360degr + t *= S2R; // -> rad + d = delta * S2R; + sin_t = sin(t); + cos_t = cos(t); + sin_d = sin(d); + cos_d = cos(d); + + sp = sin_t * cos_fi; + cp = sin_fi * cos_d - sin_d * cos_fi * cos_t; + p = atan2(sp, cp); + if (p < 0.0) + p += 2.0*PI; + + return(p * R2S); +} + +/* +static void calc_AD(double az, double zd, double stime, double *alpha, double *delta){ + double sin_d, sin_a,cos_a, sin_z,cos_z; + double t, d, z, a, p , x, y, s; + a = az * S2R; + z = zd * S2R; + sin_a = sin(a); + cos_a = cos(a); + sin_z = sin(z); + cos_z = cos(z); + + y = sin_z * sin_a; + x = cos_a * sin_fi * sin_z + cos_fi * cos_z; + t = atan2(y, x); + if (t < 0.0) + t += 2.0*PI; + + sin_d = sin_fi * cos_z - cos_fi * cos_a * sin_z; + d = asin(sin_d); + + *delta = d * R2S; + *alpha = (stime - t * R2S / 15.); + if (*alpha < 0.0) + *alpha += S360/15.; // +24h +}*/ + +void make_JSON(int sock, bta_pars *par){ + bool ALL = par->ALL; + // print next JSON pair; par, val - strings + void sendstr(char *str){ + size_t L = strlen(str); + if(send(sock, str, L, 0) != L) exit(-1); + } + int json_send(char *par, char *val){ + char buf[256]; + int L = snprintf(buf, 255, ",\n\"%s\": %s", par, val); + if(send(sock, buf, L, 0) != L) return -1; + return 0; + } + int json_send_s(char *par, char *val){ + char buf[256]; + int L = snprintf(buf, 255, ",\n\"%s\": \"%s\"", par, val); + if(send(sock, buf, L, 0) != L) return -1; + return 0; + } + #define JSON(p, val) do{if(json_send(p, val)) exit(-1);} while(0) + #define JSONSTR(p, val) do{if(json_send_s(p, val)) exit(-1);} while(0) + get_shm_block( &sdat, ClientSide); + char *str; + if(!check_shm_block(&sdat)) exit(-1); + // beginning of json object + sendstr("{\n\"ACS_BTA\": true"); + + // mean local time + if(ALL || par->mtime) + JSON("M_time", time_asc(M_time+DUT1)); + // Mean Sidereal Time + if(ALL || par->sidtime){ + #ifdef EE_time + JSON("JDate", double_asc(JDate, NULL)); + str = time_asc(S_time-EE_time); + #else + str = time_asc(S_time); + #endif + JSON("S_time", str); + } + // Telecope mode + if(ALL || par->telmode){ + if(Tel_Hardware == Hard_Off) str = "Off"; + else if(Tel_Mode != Automatic) str = "Manual"; + else{ + switch (Sys_Mode){ + default: + case SysStop : str = "Stopping"; break; + case SysWait : str = "Waiting"; break; + case SysPointAZ : + case SysPointAD : str = "Pointing"; break; + case SysTrkStop : + case SysTrkStart: + case SysTrkMove : + case SysTrkSeek : str = "Seeking"; break; + case SysTrkOk : str = "Tracking"; break; + case SysTrkCorr : str = "Correction";break; + case SysTest : str = "Testing"; break; + } + } + JSONSTR("Tel_Mode", str); + } + // Telescope focus + if(ALL || par->telfocus){ + switch (Tel_Focus){ + default: + case Prime : str = "Prime"; break; + case Nasmyth1 : str = "Nasmyth1"; break; + case Nasmyth2 : str = "Nasmyth2"; break; + } + JSONSTR("Tel_Focus", str); + JSON("ValFoc", double_asc(val_F, "%0.2f")); + } + // Telescope target + if(ALL || par->target){ + switch (Sys_Target) { + default: + case TagObject : str = "Object"; break; + case TagPosition : str = "A/Z-Pos."; break; + case TagNest : str = "Nest"; break; + case TagZenith : str = "Zenith"; break; + case TagHorizon : str = "Horizon"; break; + } + JSONSTR("Tel_Taget", str); + } + // Mode of P2 + if(ALL || par->p2mode){ + if(Tel_Hardware == Hard_On){ + switch (P2_State) { + default: + case P2_Off : str = "Stop"; break; + case P2_On : str = "Track"; break; + case P2_Plus : str = "Move+"; break; + case P2_Minus : str = "Move-"; break; + } + } else str = "Off"; + JSONSTR("P2_Mode", str); + } + // Equatorial coordinates + if(ALL || par->eqcoor){ + JSON("CurAlpha", time_asc(CurAlpha)); + JSON("CurDelta", angle_asc(CurDelta)); + JSON("SrcAlpha", time_asc(SrcAlpha)); + JSON("SrcDelta", angle_asc(SrcDelta)); + JSON("InpAlpha", time_asc(InpAlpha)); + JSON("InpDelta", angle_asc(InpDelta)); + JSON("TelAlpha", time_asc(val_Alp)); + JSON("TelDelta", angle_asc(val_Del)); + } + // Horizontal coordinates + if(ALL || par->horcoor){ + JSON("InpAzim", angle_fmt(InpAzim,"%c%03d:%02d:%04.1f")); + JSON("InpZenD", angle_fmt(InpZdist,"%02d:%02d:%04.1f")); + JSON("CurAzim", angle_fmt(tag_A,"%c%03d:%02d:%04.1f")); + JSON("CurZenD", angle_fmt(tag_Z,"%02d:%02d:%04.1f")); + JSON("CurPA", angle_fmt(tag_P,"%03d:%02d:%04.1f")); + JSON("SrcPA", angle_fmt(calc_PA(SrcAlpha,SrcDelta,S_time),"%03d:%02d:%04.1f")); + JSON("InpPA", angle_fmt(calc_PA(InpAlpha,InpDelta,S_time),"%03d:%02d:%04.1f")); + JSON("TelPA", angle_fmt(calc_PA(val_Alp, val_Del, S_time),"%03d:%02d:%04.1f")); + } + // Values from sensors + if(ALL || par->valsens){ + JSON("ValAzim", angle_fmt(val_A,"%c%03d:%02d:%04.1f")); + JSON("ValZenD", angle_fmt(val_Z,"%02d:%02d:%04.1f")); + JSON("ValP2", angle_fmt(val_P,"%03d:%02d:%04.1f")); + JSON("ValDome", angle_fmt(val_D,"%c%03d:%02d:%04.1f")); + } + // Differences + if(ALL || par->diff){ + JSON("DiffAzim", angle_fmt(Diff_A,"%c%03d:%02d:%04.1f")); + JSON("DiffZenD", angle_fmt(Diff_Z,"%c%02d:%02d:%04.1f")); + JSON("DiffP2", angle_fmt(Diff_P,"%c%03d:%02d:%04.1f")); + JSON("DiffDome", angle_fmt(val_A-val_D,"%c%03d:%02d:%04.1f")); + } + // Velocities + if(ALL || par->vel){ + JSON("VelAzim", angle_fmt(vel_A,"%c%02d:%02d:%04.1f")); + JSON("VelZenD", angle_fmt(vel_Z,"%c%02d:%02d:%04.1f")); + JSON("VelP2", angle_fmt(vel_P,"%c%02d:%02d:%04.1f")); + JSON("VelPA", angle_fmt(vel_objP,"%c%02d:%02d:%04.1f")); + JSON("VelDome", angle_fmt(vel_D,"%c%02d:%02d:%04.1f")); + } + // Correction + if(ALL || par->corr){ + double curA,curZ,srcA,srcZ; + double corAlp,corDel,corA,corZ; + if(Sys_Mode==SysTrkSeek||Sys_Mode==SysTrkOk||Sys_Mode==SysTrkCorr){ + corAlp = CurAlpha-SrcAlpha; + corDel = CurDelta-SrcDelta; + if(corAlp > 23*3600.) corAlp -= 24*3600.; + if(corAlp < -23*3600.) corAlp += 24*3600.; + calc_AZ(SrcAlpha, SrcDelta, S_time, &srcA, &srcZ); + calc_AZ(CurAlpha, CurDelta, S_time, &curA, &curZ); + corA=curA-srcA; + corZ=curZ-srcZ; + }else{ + corAlp = corDel = corA = corZ = 0.; + } + JSON("CorrAlpha", angle_fmt(corAlp,"%c%01d:%02d:%05.2f")); + JSON("CorrDelta", angle_fmt(corDel,"%c%01d:%02d:%04.1f")); + JSON("CorrAzim", angle_fmt(corA,"%c%01d:%02d:%04.1f")); + JSON("CorrZenD", angle_fmt(corZ,"%c%01d:%02d:%04.1f")); + } + // meteo + if(ALL || par->meteo){ + JSON("ValTind", double_asc(val_T2, "%05.1f")); + JSON("ValTmir", double_asc(val_T3, "%05.1f")); + JSON("ValPres", double_asc(val_B, "%05.1f")); + JSON("ValWind", double_asc(val_Wnd, "%04.1f")); + if(Wnd10_time>0.1 && Wnd10_time<=M_time) { + JSON("Blast10", double_asc((M_time-Wnd10_time)/60, "%.1f")); + JSON("Blast15", double_asc((M_time-Wnd15_time)/60, "%.1f")); + } + JSON("ValHumd", double_asc(val_Hmd, "%04.1f")); + if(Precip_time>0.1 && Precip_time<=M_time) + JSON("Precipt", double_asc((M_time-Precip_time)/60, "%.1f")); + } + // end of json onject + sendstr("\n}\n"); +} + + +// конец файла diff --git a/jsonbta/bta_shdata.h b/jsonbta/bta_shdata.h new file mode 100644 index 0000000..2aec738 --- /dev/null +++ b/jsonbta/bta_shdata.h @@ -0,0 +1,1159 @@ +#pragma once +#ifndef __BTA_SHDATA_H__ +#define __BTA_SHDATA_H__ + +#define _XOPEN_SOURCE 501 +/* Основные определения и функции поддержки межпрограммного интерфейса */ +/* Возможные внешние определения: */ +/* BTA_MODULE - при исп-и в доп. C-модулях (не в главн.программе) */ +/* SHM_OLD_SIZE - для генерации предыдущей весии структуры БТА-данных */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __GNUC_PREREQ(4,2) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-braces" +#pragma GCC diagnostic ignored "-Wsequence-point" +#pragma GCC diagnostic ignored "-Wpointer-to-int-cast" +#pragma GCC diagnostic ignored "-Wimplicit-function-declaration" +#endif + +#define uint __uint32_t + +struct SHM_Block { /* описание блока разделяемой памяти */ + union { + char name[5]; /* ключ идентефикации сегмента памяти */ + key_t code; + } key; + int size; /* размер используемой части в байтах */ + int maxsize; /* размер при создании ("с запасом" для будущих версий) */ + int mode; /* режим доступа (rwxrwxrwx) */ + int atflag; /* режим подсоединения (SHM_RDONLY или 0) */ + void (*init)(); /* процедура инициализации */ + int (*check)(); /* процедура проверки */ + void (*close)(); /* процедура отсоединения */ + int side; /* тип подсоединения: Клиент/Сервер */ + int id; /* дескриптор подсоединения */ + unsigned char *addr; /* адрес подсоединения */ +}; + +struct CMD_Queue { /* описание очереди (канала) команд */ + union { + char name[5]; /* ключ идентефикации очереди */ + key_t code; + } key; + int mode; /* режим доступа (rwxrwxrwx) */ + int side; /* тип подсоединения: Клиент/Сервер (Sender/Receiver)*/ + int id; /* дескриптор подсоединения */ + uint acckey; /* ключ доступа (для передачи Клиент->Сервер) */ +}; + +#ifndef BTA_MODULE +/* канал команд главного операторского интерфейса (Level5)*/ +struct CMD_Queue mcmd = {{'M','c','m','d',0},0200,0,-1,0}; +/* канал передачи операторских (привелегированных) команд (Level4)*/ +struct CMD_Queue ocmd = {{'O','c','m','d',0},0200,0,-1,0}; +/* канал передачи пользовательских (непривелегированных) команд (Level2/3)*/ +struct CMD_Queue ucmd = {{'U','c','m','d',0},0200,0,-1,0}; +#else +extern struct CMD_Queue mcmd; +extern struct CMD_Queue ocmd; +extern struct CMD_Queue ucmd; +#endif + +static void send_cmd_noarg(int); +static void send_cmd_str(int, char *); +static void send_cmd_i1(int, int); +static void send_cmd_i2(int, int, int); +static void send_cmd_i3(int, int, int, int); +static void send_cmd_i4(int, int, int, int, int); +static void send_cmd_d1(int, double); +static void send_cmd_d2(int, double, double); +static void send_cmd_i1d1(int, int, double); +static void send_cmd_i2d1(int, int, int, double); +static void send_cmd_i3d1(int, int, int, int, double); + +/* список команд */ +/* имя код аргументы тип */ +#define StopTel 1 /* останов телескопа */ +#define StopTeleskope() send_cmd_noarg( 1 ) /* опер. */ +#define StartHS 2 /* старт привода наведения */ +#define StartHightSpeed() send_cmd_noarg( 2 ) /* опер/тст*/ +#define StartLS 3 /* старт привода ведения */ +#define StartLowSpeed() send_cmd_noarg( 3 ) /* опер/тст*/ +#define SetTmr 4 /* уст. Ch7_15 или SysTimer */ +#define SetTimerMode(T) send_cmd_i1 ( 4, (int)(T)) /* М.опер. */ +#define SetModMod 5 /* уст. режим моделирования */ +#define SetModelMode(M) send_cmd_i1 ( 5, (int)(M)) /* М.опер. */ +#define SetCodA 6 /* код скорости по A */ +#define SetPKN_A(iA,sA) send_cmd_i2 ( 6, (int)(iA),(int)(sA)) /* опер/тст*/ +#define SetCodZ 7 /* код скорости по Z */ +#define SetPKN_Z(iZ) send_cmd_i1 ( 7, (int)(iZ)) /* опер/тст*/ +#define SetCodP 8 /* код скорости по P */ +#define SetPKN_P(iP) send_cmd_i1 ( 8, (int)(iP)) /* опер/тст*/ +#define SetVA 9 /* уст. скорость по A */ +#define SetSpeedA(vA) send_cmd_d1 ( 9, (double)(vA)) /* опер/тст*/ +#define SetVZ 10 /* уст. скорость по Z */ +#define SetSpeedZ(vZ) send_cmd_d1 (10, (double)(vZ)) /* опер/тст*/ +#define SetVP 11 /* уст. скорость по P */ +#define SetSpeedP(vP) send_cmd_d1 (11, (double)(vP)) /* опер/тст*/ +#define SetAD 12 /* зап.новые координаты R.A.и Decl */ +#define SetRADec(Alp,Del) send_cmd_d2 (12, (double)(Alp),(double)(Del))/* польз.*/ +#define SetAZ 13 /* зап.координаты азимут и зен.расст.*/ +#define SetAzimZ(A,Z) send_cmd_d2 (13, (double)(A),(double)(Z))/* польз.*/ +#define GoToAD 14 /* старт наведения на объект (по R.A.и Decl)*/ +#define GoToObject() send_cmd_noarg(14 ) /* опер. */ +#define MoveToAD 15 /* переезд на объект (по R.A.и Decl)*/ +#define MoveToObject() send_cmd_noarg(15 ) /* польз.*/ +#define GoToAZ 16 /* наведение по положению (по A Z)*/ +#define GoToAzimZ() send_cmd_noarg(16 ) /* опер. */ +#define WriteAZ 17 /* установка A и Z для FullModel*/ +#define WriteModelAZ() send_cmd_noarg(17 ) /* опер. */ +#define SetModP 18 /* уст. режим использования P2 */ +#define SetPMode(pmod) send_cmd_i1 (18, (int)(pmod)) /* польз.*/ +#define P2Move 19 /* вкл./выкл. (+-1,0) движение P2 */ +#define MoveP2(dir) send_cmd_i1 (19, (int)(dir)) /* польз.*/ +#define FocMove 20 /* вкл./выкл. (+-2,+-1,0) движение фокуса */ +#define MoveFocus(speed,time) send_cmd_i1d1(20,(int)(speed),(double)(time)) /* польз.*/ +#define UsePCorr 21 /* режим учета поправок положения (СКН) */ +#define SwitchPosCorr(pc_flag) send_cmd_i1 (21, (int)(pc_flag)) /* опер. */ +#define SetTrkFlags 22 /* уст. флагов режима слежения */ +#define SetTrkOkMode(trk_flags) send_cmd_i1 (22, (int)(trk_flags)) /* опер.*/ +#define SetTFoc 23 /* уст.фокуса: 0-ПФ, 1-Н1, 2-Н2 */ +#define SetTelFocus(N) send_cmd_i1 ( 23, (int)(N)) /* опер. */ +#define SetVAD 24 /* уст.ск.собсв.дв-я объекта по R.A.и Decl */ +#define SetVelAD(VAlp,VDel) send_cmd_d2 (24, (double)(VAlp),(double)(VDel))/* опер.*/ +#define SetRevA 25 /* уст. режим "обхода" азимута */ +#define SetAzRevers(amod) send_cmd_i1 (25, (int)(amod)) /* польз.*/ +#define SetVP2 26 /* уст.скор..дв-я P2 (для ДБУ) */ +#define SetVelP2(vP2) send_cmd_d1 (26, (double)(vP2)) /* польз.*/ +#define SetTarg 27 /* уст. цели наведения */ +#define SetSysTarg(Targ) send_cmd_i1 (27, (int)(Targ)) /* опер.*/ +#define SendMsg 28 /* размещение сообщения (всем клиентам и в протокол) */ +#define SendMessage(Mesg) send_cmd_str (28, (char *)(Mesg)) /* польз.*/ +#define CorrAD 29 /* коррекция координат R.A.и Decl */ +#define DoADcorr(dAlp,dDel) send_cmd_d2 (29, (double)(dAlp),(double)(dDel))/* польз.*/ +#define CorrAZ 30 /* коррекция координат A и Z*/ +#define DoAZcorr(dA,dZ) send_cmd_d2 (30, (double)(dA),(double)(dZ))/* польз.*/ +#define SetVCAZ 31 /* уст.скор.коррекции по A и Z*/ +#define SetVCorr(vA,vZ) send_cmd_d2 (31, (double)(vA),(double)(vZ))/* польз.*/ +#define P2MoveTo 32 /* переезд P2 по времени */ +#define MoveP2To(vP2,time) send_cmd_d2 (32, (double)(vP2),(double)(time))/* польз.*/ +#define GoToTD 33 /* старт наведения на стационар (по t и Decl)*/ +#define GoToSat() send_cmd_noarg (33 ) /* опер..*/ +#define MoveToTD 34 /* переезд на стационар (по t и Decl)*/ +#define MoveToSat() send_cmd_noarg (34 ) /* польз.*/ +#define NullCom 35 /* пустая команда (для синхронизаций?) */ +#define SyncCom() send_cmd_noarg (35 ) /* опер. */ +#define StartTel 36 /* кнопка "Пуск" телескопа */ +#define StartTeleskope() send_cmd_noarg(36 ) /* опер. */ +#define SetTMod 37 /* уст. режимы работы телескопа */ +#define SetTelMode(M) send_cmd_i1 ( 37, (int)(M)) /* М.опер. */ +#define TelOn 38 /* кнопка Вкл. Масло, ЭМУ и т.д.*/ +#define TeleskopeOn() send_cmd_noarg(38 ) /* М.опер. */ +#define SetModD 39 /* уст. режим использования купола */ +#define SetDomeMode(dmod) send_cmd_i1 (39, (int)(dmod)) /* М.опер.*/ +#define DomeMove 40 /* вкл./выкл. (+-1+-2,+-3,0) движение купола */ +#define MoveDome(speed,time) send_cmd_i1d1(40,(int)(speed),(double)(time)) /* опер.*/ +#define SetPass 41 /* уст. пароль уровня доступа */ +#define SetPasswd(LPass) send_cmd_str (41, (char *)(LPass)) /* М.опер.*/ +#define SetLevC 42 /* уст. код уровня доступа */ +#define SetLevCode(Nlev,Cod) send_cmd_i2(42, (int)(Nlev),(int)(Cod)) /* М.опер.*/ +#define SetLevK 43 /* уст. ключ уровня доступа */ +#define SetLevKey(Nlev,Key) send_cmd_i2(43, (int)(Nlev),(int)(Key)) /* М.опер.*/ +#define SetNet 44 /* уст. маску и адрес подсети */ +#define SetNetAcc(Mask,Addr) send_cmd_i2(44, (int)(Mask),(int)(Addr)) /* М.опер.*/ +#define SetMet 45 /* ввод метео данных */ +#define SetMeteo(m_id,m_val) send_cmd_i1d1(45,(int)(m_id),(double)(m_val)) /* опер.*/ +#define TurnMetOff 46 /* отмена исп. метео данных */ +#define TurnMeteoOff(m_id) send_cmd_i1 (46, (int)(m_id)) /* опер.*/ +#define SetDUT1 47 /* уст.попр.времени(IERS DUT1=UT1-UTC) */ +#define SetDtime(dT) send_cmd_d1 (47, (double)(dT)) /* М.опер.*/ +#define SetPM 48 /* уст.полож.полюса(IERS polar motion)*/ +#define SetPolMot(Xp,Yp) send_cmd_d2 (48, (double)(Xp),(double)(Yp)) /* М.опер.*/ +#define GetSEW 49 /* прочитать SEW параметр */ +#define GetSEWparam(Ndrv,Indx,Cnt) send_cmd_i3(49,(int)(Ndrv),(int)(Indx),(int)(Cnt)) /* M.опер.*/ +#define PutSEW 50 /* записать SEW параметр */ +#define PutSEWparam(Ndrv,Indx,Key,Val) send_cmd_i4(50,(int)(Ndrv),(int)(Indx),(int)(Key),(int)(Val)) /* M.опер.*/ +#define SetLocks 51 /* установка блокировок управления узлами */ +#define SetLockFlags(f) send_cmd_i1 (SetLocks, (int)(f)) /* M.опер.*/ +#define ClearLocks 52 /* отмена блокировок управления узлами */ +#define ClearLockFlags(f) send_cmd_i1 (ClearLocks, (int)(f)) /* M.опер.*/ +#define SetRKbits 53 /* Установка доп.битов PEP-RK */ +#define AddRKbits(f) send_cmd_i1 (SetRKbits, (int)(f)) /* M.опер.*/ +#define ClrRKbits 54 /* Очистка доп.битов PEP-RK */ +#define ClearRKbits(f) send_cmd_i1 (ClrRKbits, (int)(f)) /* M.опер.*/ +#define SetSEWnd 55 /* уст.номер SEW-движка купола (для индикации)*/ +#define SetDomeDrive(ND) send_cmd_i1 (SetSEWnd, (int)(ND)) /* М.опер.*/ +#define SEWsDome 56 /* Вкл./Выкл. SEW-движков купола */ +#define DomeSEW(OnOff) send_cmd_i1 (SEWsDome, (int)(OnOff)) /* М.опер.*/ + + +/* структура данных алгоритма управления (распределение "глобальной области") */ +#define BTA_Data_Ver 2 +#pragma pack(4) +//struct __attribute__((packed)) BTA_Data { +struct BTA_Data { + int magic; /* код опознания структуры */ + int version; /* номер версии структуры = BTA_Data_Ver*/ + int size; /* размер структуры = sizeof(struct BTA_Data)*/ + int pid; +#define ServPID (sdt->pid) /*номер процесса гл.упр.программы */ + + /* режимы работы */ + int model; +#define UseModel (sdt->model) /* вариант использования моделирования */ +#define NoModel 0 /* отключено */ +#define CheckModel 1 /* привода контролируются по модели */ +#define DriveModel 2 /* моделирование приводов и "слепое" управление без реальных датчиков */ +#define FullModel 3 /* полное моделирование без телескопа */ + int timer; +#define ClockType (sdt->timer) /* какие часы используются */ +#define Ch7_15 0 /* Внутр.часы упр.программы с синхронизацией по Ч7-15 */ +#define SysTimer 1 /* Таймер системы (неизвестно синхронизированный или нет) */ +#define ExtSynchro 2 /* Работает синхронизация таймера системы внешней программой (bta_time или xntpd)*/ + int system; +#define Sys_Mode (sdt->system) /* режим работы системы */ +#define SysStop 0 /* Останов */ +#define SysWait 1 /* Ожидание старта (наведения) */ +#define SysPointAZ 2 /* Наведение по положению (по A Z)*/ +#define SysPointAD 3 /* Наведение на объект (по R.A.и Decl)*/ +#define SysTrkStop 4 /* Ведение: ожидание старта */ +#define SysTrkStart 5 /* Ведение: разгон до номин.скорости (объекта)*/ +#define SysTrkMove 6 /* Ведение: переезд на объект */ +#define SysTrkSeek 7 /* Ведение: слежение за объектом */ +#define SysTrkOk 8 /* Ведение: рассогласования в допуске */ +#define SysTrkCorr 9 /* Ведение: коррекция положения */ +#define SysTest 10 /* Тестирование */ + int sys_target; +#define Sys_Target (sdt->sys_target) /* цель наведения */ +#define TagPosition 0 /* Положение A/Z */ +#define TagObject 1 /* Объект Alpha/Delta */ +#define TagNest 2 /* Положение "Гнездо" */ +#define TagZenith 3 /* Положение "Зенит" */ +#define TagHorizon 4 /* Положение "Горизонт" */ +#define TagStatObj 5 /* "Стационар" t/Delta */ + + int tel_focus; +#define Tel_Focus (sdt->tel_focus) /* тип фокуса телескопа: 0-ПФ, 1-Н1, 2-Н2 */ +#define Prime 0 +#define Nasmyth1 1 +#define Nasmyth2 2 + double pc_coeff[8]; +#define PosCor_Coeff (sdt->pc_coeff) /* коэф-ты СКН для тек.фокуса */ + + /* состояние телескопа */ +#define Stopping 0 /* Останов */ +#define Pointing 1 /* Наведение */ +#define Tracking 2 /* Ведение */ + int tel_state; +#define Tel_State (sdt->tel_state) /* реально отрабатываемое */ + int req_state; +#define Req_State (sdt->req_state) /* затребованное программой */ + int tel_hard_state; +#define Tel_Hardware (sdt->tel_hard_state) /* состояние УСО */ +#define Hard_Off 0 /* питание выключено */ +#define Hard_On 1 /* включено */ + + /* режимы работы телескопа */ + int tel_mode; +#define Tel_Mode (sdt->tel_mode) +#define Automatic 0 /* "Автомат" - нормальный режим*/ +#define Manual 1 /* "П/авт.упр." - пультовой режим и в нем:*/ +#define ZenHor 2 /* "Зенит-Горизонт" - работа при Z<5 и Z>80*/ +#define A_Move 4 /* ручное движение A */ +#define Z_Move 8 /* --- "" --- Z */ +#define Balance 0x10 /* балансировка трубы */ + + /* вкл./выкл. режим "обхода" азимута */ + int az_mode; +#define Az_Mode (sdt->az_mode) +#define Rev_Off 0 /* нормальное наведение на ближайшее положение по азимуту */ +#define Rev_On 1 /* наведение с перегоном на 360град. */ + + /* работа P2 */ + int p2_state; +#define P2_State (sdt->p2_state) /* реальное состояние привода P2 */ +#define P2_Off 0 /* Стоит */ +#define P2_On 1 /* Ведет */ +#define P2_Plus 2 /* быстро едет в + */ +#define P2_Minus -2 /* быстро едет в - */ + int p2_req_mode; +#define P2_Mode (sdt->p2_req_mode) /* режим использования P2 (пока: Вкл/Выкл)*/ + + /* состояние привода фокуса */ + int focus_state; +#define Foc_State (sdt->focus_state) +#define Foc_Off 0 /* Стоит */ +#define Foc_Lplus 1 /* медл. едет в + */ +#define Foc_Lminus -1 /* медл. едет в - */ +#define Foc_Hplus 2 /* быстро едет в + */ +#define Foc_Hminus -2 /* быстро едет в - */ + + /* состояние привода купола */ + int dome_state; +#define Dome_State (sdt->dome_state) +#define D_On 7 /* Автоматическое согласование с телескопом */ +#define D_Off 0 /* Стоит */ +#define D_Lplus 1 /* медл. едет в + */ +#define D_Lminus -1 /* медл. едет в - */ +#define D_Mplus 2 /* сред.скор. в + */ +#define D_Mminus -2 /* сред.скор. в - */ +#define D_Hplus 3 /* быстро едет в + */ +#define D_Hminus -3 /* быстро едет в - */ + +/* учет поправок положения (СКН) */ + int pcor_mode; +#define Pos_Corr (sdt->pcor_mode) /* коррекция положения объекта по A/Z: Вкл/Выкл*/ +#define PC_Off 0 /* Выкл. */ +#define PC_On 1 /* Вкл. */ + +/* флаги вкл/выкл. вариантов режима слежения */ + int trkok_mode; +#define TrkOk_Mode (sdt->trkok_mode) +#define UseDiffVel 1 /* определение&учет поправок реальной скорости приводов (~изодором)*/ +#define UseDiffAZ 2 /* слежение по рассогласованию (иначе уст.рассчетн.скоростей) */ +#define UseDFlt 4 /* вкл. цифрового фильтра рассогласований */ + + /* введенные значения */ + double i_alpha, i_delta; +#define InpAlpha (sdt->i_alpha) /* введенная координата R.A. (sec) */ +#define InpDelta (sdt->i_delta) /* -- " -- Decl. (") */ + double s_alpha, s_delta; +#define SrcAlpha (sdt->s_alpha) /* исходная координата R.A. (sec) */ +#define SrcDelta (sdt->s_delta) /* -- " -- Decl. (") */ + double v_alpha, v_delta; +#define VelAlpha (sdt->v_alpha) /* ск.собсв.дв-я объекта по R.A. (sec/сек) */ +#define VelDelta (sdt->v_delta) /* -- " -- Decl. ("/сек) */ + double i_azim, i_zdist; +#define InpAzim (sdt->i_azim) /* для наведения по азимуту (") */ +#define InpZdist (sdt->i_zdist) /* -- " -- зен.расст. (") */ + + /* рассчетные значения */ + double c_alpha, c_delta; +#define CurAlpha (sdt->c_alpha) /* текущая координата R.A. (sec) */ +#define CurDelta (sdt->c_delta) /* -- " -- Decl. (") */ + double tag_a, tag_z, tag_p; +#define tag_A (sdt->tag_a) /* текущий A (") объекта */ +#define tag_Z (sdt->tag_z) /* - " - Z (") - " - */ +#define tag_P (sdt->tag_p) /* - " - P (") - " - */ + double pcor_a, pcor_z, refr_z; +#define pos_cor_A (sdt->pcor_a) /* поправка положения объекта по A (") */ +#define pos_cor_Z (sdt->pcor_z) /* - " - - " - по Z (") */ +#define refract_Z (sdt->refr_z) /* поправка за рефракцию для объекта (") */ + double tcor_a, tcor_z, tref_z; +#define tel_cor_A (sdt->tcor_a) /* поправка обр.пересчета положения телескопа по A (") */ +#define tel_cor_Z (sdt->tcor_z) /* - " - - " - - " - по Z (") */ +#define tel_ref_Z (sdt->tref_z) /* поправка обр.пересчета за рефракцию (") */ + double diff_a, diff_z, diff_p; +#define Diff_A (sdt->diff_a) /* рассогл-е(осталось ехать) по A (") */ +#define Diff_Z (sdt->diff_z) /* - " - - " - Z (") */ +#define Diff_P (sdt->diff_p) /* - " - - " - P (") */ + double vbasea,vbasez,vbasep; +#define vel_objA (sdt->vbasea) /* базовая скорость объекта по A ("/сек) */ +#define vel_objZ (sdt->vbasez) /* - " - - " - Z - " - */ +#define vel_objP (sdt->vbasep) /* - " - - " - P - " - */ + double diffva,diffvz,diffvp; +#define diff_vA (sdt->diffva) /* поправка реальной скорости привода по азимуту */ +#define diff_vZ (sdt->diffvz) /* -- "" -- -- "" -- по Z */ +#define diff_vP (sdt->diffvp) /* -- "" -- -- "" -- по P */ + double speeda,speedz,speedp; +#define speedA (sdt->speeda) /* скорость по A ("/сек) для управления приводом */ +#define speedZ (sdt->speedz) /* - " - Z - " - */ +#define speedP (sdt->speedp) /* - " - P - " - */ + double m_time_precip; +#define Precip_time (sdt->m_time_precip)/* момент времени появления осадков (precipitations)*/ + unsigned char reserve[16]; +#define Reserve (sdt->reserve) /* свободное место */ + double rspeeda, rspeedz, rspeedp; +#define req_speedA (sdt->rspeeda) /* скорость ("/сек) выданная на привод A */ +#define req_speedZ (sdt->rspeedz) /* - " - Z */ +#define req_speedP (sdt->rspeedp) /* - " - P */ + double simvela, simvelz, simvelp, simvelf, simveld; +#define mod_vel_A (sdt->simvela) /* скорость по A ("/сек) модельная */ +#define mod_vel_Z (sdt->simvelz) /* - " - Z - " - */ +#define mod_vel_P (sdt->simvelp) /* - " - P - " - */ +#define mod_vel_F (sdt->simvelf) /* - " - F - " - */ +#define mod_vel_D (sdt->simvelf) /* - " - D - " - */ + + + /* результаты измерения датчиков и рассчитанные по ним значения */ + uint kost; +#define code_KOST (sdt->kost) /* сост. телескопа и ручной коррекции */ + /* 0x8000 - азимут положительный */ + /* 0x4000 - отработка вкл. */ + /* 0x2000 - режим ведения */ + /* 0x1000 - отработка P2 вкл.*/ + /* 0x01F0 - ск.корр. 0.2 0.4 1.0 2.0 5.0("/сек) */ + /* 0x000F - напр.корр. +Z -Z +A -A */ + double m_time, s_time, l_time; +#define M_time (sdt->m_time) /* текущее московское время (теперь UTC!)*/ +#define S_time (sdt->s_time) /* текущее звездное время */ +#define L_time (sdt->l_time) /* время работы программы */ + uint ppndd_a, ppndd_z, ppndd_p, ppndd_b; +#define ppndd_A (sdt->ppndd_a) /* код датчика ППНДД (грубого отсчета) A */ +#define ppndd_Z (sdt->ppndd_z) /* - "" - Z */ +#define ppndd_P (sdt->ppndd_p) /* - "" - P */ +#define ppndd_B (sdt->ppndd_b) /* код датчика ППНДД давления */ + uint dup_a, dup_z, dup_p, dup_f, dup_d; +#define dup_A (sdt->dup_a) /* код Грея датчика ДУП (точного отсчета) A */ +#define dup_Z (sdt->dup_z) /* - "" - Z */ +#define dup_P (sdt->dup_p) /* - "" - P */ +#define dup_F (sdt->dup_f) /* код Грея датчика ДУП фокуса телескопа */ +#define dup_D (sdt->dup_d) /* код Грея датчика ДУП положения купола */ + uint low_a, low_z, low_p, low_f, low_d; +#define low_A (sdt->low_a) /* 14р-в дв.кода точного отсчета A */ +#define low_Z (sdt->low_z) /* - "" - Z */ +#define low_P (sdt->low_p) /* - "" - P */ +#define low_F (sdt->low_f) /* код отсчета фокуса телескопа */ +#define low_D (sdt->low_d) /* код отсчета положения купола */ + uint code_a, code_z, code_p, code_b, code_f, code_d; +#define code_A (sdt->code_a) /* 23р-в дв.кода отсчета A */ +#define code_Z (sdt->code_z) /* - "" - Z */ +#define code_P (sdt->code_p) /* - "" - P */ +#define code_B (sdt->code_b) /* код давления */ +#define code_F (sdt->code_f) /* код отсчета фокуса телескопа */ +#define code_D (sdt->code_d) /* код отсчета положения купола */ + uint adc[8]; +#define ADC(N) (sdt->adc[(N)]) /* коды 8-ми каналов АЦП PCL818 */ +#define code_T1 ADC(0) /* код датчика наруж. температуры*/ +#define code_T2 ADC(1) /* код датчика температуры под куп.*/ +#define code_T3 ADC(2) /* код датчика температуры зеркала */ +#define code_Wnd ADC(3) /* код датчика ветра */ + double val_a, val_z, val_p, val_b, val_f, val_d; + double val_t1, val_t2, val_t3, val_wnd; +#define val_A (sdt->val_a) /* отсчет A (") */ +#define val_Z (sdt->val_z) /* - " - Z (") */ +#define val_P (sdt->val_p) /* - " - P (") */ +#define val_B (sdt->val_b) /* давлениe (мм.рт.ст.)*/ +#define val_F (sdt->val_f) /* фокус телескопа (мм) */ +#define val_D (sdt->val_d) /* положение купола (") */ +#define val_T1 (sdt->val_t1) /* наруж. температура (гр.)*/ +#define val_T2 (sdt->val_t2) /* температура под куп.(гр.)*/ +#define val_T3 (sdt->val_t3) /* температура зеркала (гр.)*/ +#define val_Wnd (sdt->val_wnd) /* ветер (м/сек)*/ + double val_alp, val_del; +#define val_Alp (sdt->val_alp) /* обратный пересчет R.A. (sec) */ +#define val_Del (sdt->val_del) /* -- " -- Decl. (") */ + + double vel_a, vel_z, vel_p, vel_f, vel_d; +#define vel_A (sdt->vel_a) /* скорость по A ("/сек) измеренная */ +#define vel_Z (sdt->vel_z) /* - " - Z - " - */ +#define vel_P (sdt->vel_p) /* - " - P - " - */ +#define vel_F (sdt->vel_f) /* - " - F - " - */ +#define vel_D (sdt->vel_d) /* - " - D - " - */ + + /* очередь последних системных сообщений */ +#define MesgNum 3 +#define MesgLen 39 + //struct __attribute__((packed)) SysMesg { + struct SysMesg { + int seq_num; + char type; +#define MesgEmpty 0 +#define MesgInfor 1 +#define MesgWarn 2 +#define MesgFault 3 +#define MesgLog 4 + char text[MesgLen]; + } sys_msg_buf[MesgNum]; +#define Sys_Mesg(N) (sdt->sys_msg_buf[N]) + + /* управление доступом */ + /* коды установки уровней доступа для клиентов */ + uint code_lev1,code_lev2,code_lev3,code_lev4,code_lev5; +#define code_Lev1 (sdt->code_lev1) /* "удаленный наблюдатель" - только информация */ +#define code_Lev2 (sdt->code_lev2) /* "местный наблюдатель" - + ввод координат */ +#define code_Lev3 (sdt->code_lev3) /* "главный наблюдатель" - + A/Z-корр-я, упр.P2/F */ +#define code_Lev4 (sdt->code_lev4) /* "оператор" - + пуск/стоп телеск., тестирование */ +#define code_Lev5 (sdt->code_lev5) /* "главный оператор" - все операции */ + /* ограничение сетевого доступа */ + uint netmask, netaddr, acsmask, acsaddr; +#define NetMask (sdt->netmask) /* маска подсети (обычно: 255.255.255.0) */ +#define NetWork (sdt->netaddr) /* адрес подсети (например: 192.168.3.0) */ +#define ACSMask (sdt->acsmask) /* маска АСУ-сети (например: 255.255.255.0) */ +#define ACSNet (sdt->acsaddr) /* адрес АСУ-сети (например: 192.168.13.0) */ + + /* ввод метео-данных */ + int meteo_stat; +#define MeteoMode (sdt->meteo_stat) /* флаги датчиков и ввода данных*/ +#define INPUT_B 1 /* давление *//* флаги ручного ввода метео данных */ +#define INPUT_T1 2 /* T-наружная */ +#define INPUT_T2 4 /* T-подкупольная */ +#define INPUT_T3 8 /* T-зеркала */ +#define INPUT_WND 0x10 /* ветер */ +#define INPUT_HMD 0x20 /* влажность */ +#define SENSOR_B (INPUT_B <<8) /* флаги внешних метео-датчиков (e.g.по CAN-шине)*/ +#define SENSOR_T1 (INPUT_T1 <<8) +#define SENSOR_T2 (INPUT_T2 <<8) +#define SENSOR_T3 (INPUT_T3 <<8) +#define SENSOR_WND (INPUT_WND<<8) +#define SENSOR_HMD (INPUT_HMD<<8) +#define ADC_B (INPUT_B <<16) /* флаги считывания с АЦП упр.компутера */ +#define ADC_T1 (INPUT_T1 <<16) +#define ADC_T2 (INPUT_T2 <<16) +#define ADC_T3 (INPUT_T3 <<16) +#define ADC_WND (INPUT_WND<<16) +#define ADC_HMD (INPUT_HMD<<16) +#define NET_B (INPUT_B <<24) /* флаги получения данных с метеостанции по сети */ +#define NET_T1 (INPUT_T1 <<24) +#define NET_WND (INPUT_WND<<24) +#define NET_HMD (INPUT_HMD<<24) + double inp_b, inp_t1, inp_t2, inp_t3, inp_wnd; +#define inp_B (sdt->inp_b) /* давлениe (мм.рт.ст.)*/ +#define inp_T1 (sdt->inp_t1) /* наруж. температура (гр.)*/ +#define inp_T2 (sdt->inp_t2) /* температура под куп.(гр.)*/ +#define inp_T3 (sdt->inp_t3) /* температура зеркала (гр.)*/ +#define inp_Wnd (sdt->inp_wnd) /* ветер (м/сек)*/ + + double temper, press; +#define Temper (sdt->temper) /* темрература используемая для рефракции */ +#define Pressure (sdt->press) /* давление используемое для рефракции */ + double m_time10, m_time15; +#define Wnd10_time (sdt->m_time10) /* момент времени порыва >=10м/сек*/ +#define Wnd15_time (sdt->m_time15) /* - " - - " - - " - >=15м/сек*/ + + /* IERS DUT1 (источник: ftp://maia.usno.navy.mil/ser7/ser7.dat) */ + double dut1; +#define DUT1 (sdt->dut1) /* поправка ср.солнечного времени: DUT1 = UT1-UTC */ + + double a_time, z_time, p_time; +#define A_time (sdt->a_time) /* момент считывания датчика A */ +#define Z_time (sdt->z_time) /* - " - - " - - " - Z */ +#define P_time (sdt->p_time) /* - " - - " - - " - P */ + + double speedain, speedzin, speedpin; +#define speedAin (sdt->speedain) /* постоянная скорость уст-я по A */ +#define speedZin (sdt->speedzin) /* постоянная скорость уст-я по Z */ +#define speedPin (sdt->speedpin) /* постоянная скорость уст-я по P2*/ + + double acc_a, acc_z, acc_p, acc_f, acc_d; +#define acc_A (sdt->acc_a) /* ускорение по A ("/сек^2) */ +#define acc_Z (sdt->acc_z) /* - " - Z - " - */ +#define acc_P (sdt->acc_p) /* - " - P - " - */ +#define acc_F (sdt->acc_f) /* - " - F - " - */ +#define acc_D (sdt->acc_d) /* - " - D - " - */ + + uint code_sew; +#define code_SEW (sdt->code_sew) /* код спец.доступа к SEW-контроллерам */ + +/* параметры SEW-контроллеров */ +//struct __attribute__((packed)) SEWdata { +struct SEWdata { + int status; + double set_speed; + double mes_speed; + double current; + int index; + union { + unsigned char b[4]; + __uint32_t l; + } value; +} sewdrv[3]; +#define statusSEW(Drv) (sdt->sewdrv[(Drv)-1].status) /*состояние контроллера*/ +#define statusSEW1 (sdt->sewdrv[0].status) +#define statusSEW2 (sdt->sewdrv[1].status) +#define statusSEW3 (sdt->sewdrv[2].status) +#define speedSEW(Drv) (sdt->sewdrv[(Drv)-1].set_speed) /*установленная скорость*/ +#define speedSEW1 (sdt->sewdrv[0].set_speed) /* об/мин (rpm)*/ +#define speedSEW2 (sdt->sewdrv[1].set_speed) +#define speedSEW3 (sdt->sewdrv[2].set_speed) +#define vel_SEW(Drv) (sdt->sewdrv[(Drv)-1].mes_speed) /*измеренная скорость */ +#define vel_SEW1 (sdt->sewdrv[0].mes_speed) /* об/мин (rpm)*/ +#define vel_SEW2 (sdt->sewdrv[1].mes_speed) +#define vel_SEW3 (sdt->sewdrv[2].mes_speed) +#define currentSEW(Drv) (sdt->sewdrv[(Drv)-1].current) /*ток (А)*/ +#define currentSEW1 (sdt->sewdrv[0].current) +#define currentSEW2 (sdt->sewdrv[1].current) +#define currentSEW3 (sdt->sewdrv[2].current) +#define indexSEW(Drv) (sdt->sewdrv[(Drv)-1].index) /*номер параметра*/ +#define indexSEW1 (sdt->sewdrv[0].index) +#define indexSEW2 (sdt->sewdrv[1].index) +#define indexSEW3 (sdt->sewdrv[2].index) +#define valueSEW(Drv) (sdt->sewdrv[(Drv)-1].value.l) /*код значения параметра*/ +#define valueSEW1 (sdt->sewdrv[0].value.l) +#define valueSEW2 (sdt->sewdrv[1].value.l) +#define valueSEW3 (sdt->sewdrv[2].value.l) +#define bvalSEW(Drv,Nb) (sdt->sewdrv[(Drv)-1].value.b[Nb]) /*байт кода значения параметра*/ + +/* информация от PEP-контроллеров */ + uint pep_code_a, pep_code_z, pep_code_p; +#define PEP_code_A (sdt->pep_code_a) /* 23р-в дв.кода отсчета A */ +#define PEP_code_Z (sdt->pep_code_z) /* - "" - Z */ +#define PEP_code_P (sdt->pep_code_p) /* - "" - P */ + uint pep_sw_a, pep_sw_z, pep_sw_p; +#define switch_A (sdt->pep_sw_a) /* код концевиков азимута */ +#define Sw_minus_A 1 /* азимут отрицательный (см. code_KOST&0x8000)*/ +#define Sw_plus240_A 2 /* концевик "+240град" */ +#define Sw_minus240_A 4 /* концевик "-240град" */ +#define Sw_minus45_A 8 /* положение "в горизонт" (~-46град)*/ +#define switch_Z (sdt->pep_sw_z) /* код концевиков Z */ +#define Sw_0_Z 0x01 /* концевик "0град" */ +#define Sw_5_Z 0x02 /* концевик "5град" */ +#define Sw_20_Z 0x04 /* концевик "20град" */ +#define Sw_60_Z 0x08 /* концевик "60град" */ +#define Sw_80_Z 0x10 /* концевик "80град" */ +#define Sw_90_Z 0x20 /* концевик "90град" */ +#define switch_P (sdt->pep_sw_p) /* - "" - СПФ */ +#define Sw_No_P 0x00 /* "Нет концевиков" */ +#define Sw_22_P 0x01 /* концевик "22град" */ +#define Sw_89_P 0x02 /* концевик "89град" */ +#define Sw_Sm_P 0x80 /* датчик дыма СПФ */ + uint pep_code_f, pep_code_d, pep_code_ri, pep_code_ro; +#define PEP_code_F (sdt->pep_code_f) /* код отсчета фокуса телескопа */ +#define PEP_code_D (sdt->pep_code_d) /* код отсчета положения купола */ +#define PEP_code_Rin (sdt->pep_code_ri)/* код принятый из РК */ +#define PEP_code_Rout (sdt->pep_code_ro)/* код выдаваемый в РК */ + unsigned char pep_on[10]; /* флаги работы PEP-контроллеров */ +#define PEP_A_On (sdt->pep_on[0]) +#define PEP_A_Off (PEP_A_On==0) +#define PEP_Z_On (sdt->pep_on[1]) +#define PEP_Z_Off (PEP_Z_On==0) +#define PEP_P_On (sdt->pep_on[2]) +#define PEP_P_Off (PEP_P_On==0) +#define PEP_F_On (sdt->pep_on[3]) +#define PEP_F_Off (PEP_F_On==0) +#define PEP_D_On (sdt->pep_on[4]) +#define PEP_D_Off (PEP_D_On==0) +#define PEP_R_On (sdt->pep_on[5]) +#define PEP_R_Off ((PEP_R_On&1)==0) +#define PEP_R_Inp ((PEP_R_On&2)!=0) +#define PEP_K_On (sdt->pep_on[6]) +#define PEP_K_Off ((PEP_K_On&1)==0) +#define PEP_K_Inp ((PEP_K_On&2)!=0) + + /* IERS polar motion (источник: ftp://maia.usno.navy.mil/ser7/ser7.dat) */ + double xpol, ypol; +#define polarX (sdt->xpol) /* X-поправкa полож.полюса */ +#define polarY (sdt->ypol) /* Y-поправкa полож.полюса */ + + double jdate, eetime; +#define JDate (sdt->jdate) /* текущая юлианская дата */ +#define EE_time (sdt->eetime) /* поправ.зв.вр. за "Equation of the Equinoxes" */ + + /* еще ввод метео-данных */ + double val_hmd, inp_hmd; +#define val_Hmd (sdt->val_hmd) /* значение влажности (%) */ +#define inp_Hmd (sdt->val_hmd) /* ручной ввод */ + + /* положение червяка (подвеска) */ + double worm_a, worm_z; +#define worm_A (sdt->worm_a) /* положение подвески A (мкм) */ +#define worm_Z (sdt->worm_z) /* положение подвески Z (мкм) */ + + /* флаги блокировки управления узлами */ + __uint32_t lock_flags; +#define LockFlags (sdt->lock_flags) +#define Lock_A 0x01 +#define Lock_Z 0x02 +#define Lock_P 0x04 +#define Lock_F 0x08 +#define Lock_D 0x10 +#define A_Locked (LockFlags&Lock_A) +#define Z_Locked (LockFlags&Lock_Z) +#define P_Locked (LockFlags&Lock_P) +#define F_Locked (LockFlags&Lock_F) +#define D_Locked (LockFlags&Lock_D) + + /* требуемая скорость привода купола (для упр-я SEW-приводами)*/ + int sew_dome_speed; /* пока тоже что и Dome_State */ +#define Dome_Speed (sdt->sew_dome_speed) /* т.е. D_Lplus,D_Lminus,.... */ + +/* номер SEW-движка купола (для индикации)*/ + int sew_dome_num; +#define DomeSEW_N (sdt->sew_dome_num) + +/* параметры выбранного(DomeSEW_N) SEW-контроллера купола*/ +struct SEWdata sewdomedrv; +#define statusSEWD (sdt->sewdomedrv.status) /*состояние контроллера*/ +#define speedSEWD (sdt->sewdomedrv.set_speed) /*установленная скорость об/мин (rpm)*/ +#define vel_SEWD (sdt->sewdomedrv.mes_speed) /*измеренная скорость об/мин (rpm)*/ +#define currentSEWD (sdt->sewdomedrv.current) /*ток (А)*/ +#define indexSEWD (sdt->sewdomedrv.index) /*номер параметра*/ +#define valueSEWD (sdt->sewdomedrv.value.l) /*код значения параметра*/ + +/* информация PEP-контроллера купола */ + uint pep_code_di, pep_code_do; +#define PEP_code_Din (sdt->pep_code_di) /* код принятый из PEP-купола */ +#define PEP_Dome_SEW_Ok 0x200 +#define PEP_Dome_Cable_Ok 0x100 +#define PEP_code_Dout (sdt->pep_code_do) /* код выдаваемый в PEP-купола */ +#define PEP_Dome_SEW_On 0x10 +#define PEP_Dome_SEW_Off 0x20 + +}; + +#ifndef BTA_MODULE +struct BTA_Data *sdt; +#else +extern struct BTA_Data *sdt; +#endif + +struct BTA_Local { /* структура локальных данных */ + unsigned char reserve[120]; /* свободное место для расширения глобальной области */ + /* (на глобальную область резервируем 1500 байт) */ + double pr_oil_a,pr_oil_z,pr_oil_t; +#define PressOilA (sdtl->pr_oil_a) /* Давление в маслопроводе A (МПа) */ +#define PressOilZ (sdtl->pr_oil_z) /* Давление в маслопроводе Z (МПа) */ +#define PressOilTank (sdtl->pr_oil_t) /* Датчик уровня масла в баке(КПа) */ + double t_oil_1,t_oil_2; +#define OilTemper1 (sdtl->t_oil_1) /* Температура масла */ +#define OilTemper2 (sdtl->t_oil_2) /* Температура охлаждающей воды */ +}; + +#ifndef BTA_MODULE +struct BTA_Local *sdtl; /* конец глобальных, начало локальных данных */ +#else +extern struct BTA_Local *sdtl; +#endif + +#define ClientSide 0 +#define ServerSide 1 + +#ifndef BTA_MODULE +static void bta_data_init(); +static int bta_data_check(); +static void bta_data_close(); + +/* описание блока данных алгоритма управления ("глобальная область") */ +struct SHM_Block sdat = { +{'S','d','a','t',0},sizeof(struct BTA_Data),2048,0444,SHM_RDONLY,bta_data_init,bta_data_check,bta_data_close,0,-1,NULL +}; +#else +extern struct SHM_Block sdat; +#endif + +#ifndef BTA_MODULE +/* инициализация данных алгоритма управления (обнуление "глобальной области") */ +static void bta_data_init() { + int i; + sdt = (struct BTA_Data *)sdat.addr; + sdtl = (struct BTA_Local *)(sdat.addr+sizeof(struct BTA_Data)); + if(sdat.side == ClientSide) { + if(sdt->magic != sdat.key.code) { + fprintf(stderr,"Wrong shared data (maybe server turned off)\n"); + /*exit(1);*/ + } + if(sdt->version == 0) { + fprintf(stderr,"Null shared data version (maybe server turned off)\n"); + /*exit(1);*/ + } + else if(sdt->version != BTA_Data_Ver) { + fprintf(stderr,"Wrong shared data version: I'am - %d, but server - %d ...\n", + BTA_Data_Ver, sdt->version ); + /*exit(1);*/ + } + if(sdt->size != sdat.size) { + if(sdt->size > sdat.size) { + /* но клиент имеет право использовать начальную часть данных */ + fprintf(stderr,"Wrong shared area size: I needs - %d, but server - %d ...\n", + sdat.size, sdt->size ); + } else { + /* "залезание" в пустую резервную часть теперь тоже */ + /* будем оставлять на совести автора клиента! */ + fprintf(stderr,"Attention! Too little shared data structure!\n"); + sleep(1); + fprintf(stderr,"I needs - %d, but server gives only %d ...\n", + sdat.size, sdt->size ); + sleep(1); + fprintf(stderr,"May be server's version too old!?\n"); + /* exit(1); */ + + } + } + return; + } + /* ServerSide */ + if(sdt->magic != sdat.key.code || + sdt->version != BTA_Data_Ver || + sdt->size != sdat.size) { + + for(i=0; imagic = sdat.key.code; + sdt->version = BTA_Data_Ver; + sdt->size = sdat.size; + ServPID = 0; + UseModel = NoModel; + ClockType = Ch7_15; + Sys_Mode = SysStop; + Sys_Target = TagPosition; + Tel_Focus = Prime; + Tel_Hardware = Hard_On; + Tel_Mode = Automatic; + Az_Mode = Rev_Off; + P2_State = P2_Mode = P2_Off; + Foc_State = Foc_Off; + Dome_State = D_Off; + Pos_Corr = PC_On; + TrkOk_Mode = UseDiffVel | UseDiffAZ ; + InpAlpha=InpDelta= 0.; + SrcAlpha=SrcDelta= 0.; + VelAlpha=VelDelta= 0.; + CurAlpha=CurDelta= 0.; + InpAzim=InpZdist = 0.; + Diff_A=Diff_Z=Diff_P=0.0; + pos_cor_A=pos_cor_Z=refract_Z = 0.; + tel_cor_A=tel_cor_Z=tel_ref_Z = 0.; + vel_objA=vel_objZ=vel_objP = 0.; + diff_vA=diff_vZ=diff_vP=0.; + speedA = speedZ = speedP = 0.; + req_speedA = req_speedZ = req_speedP = 0.; + mod_vel_A=mod_vel_Z=mod_vel_P=mod_vel_F=mod_vel_D=0.; + code_KOST = 0; + M_time = S_time = L_time = 0.; + ppndd_A=ppndd_Z=ppndd_P=ppndd_B=0; + dup_A=dup_Z=dup_P=dup_F=dup_D=0; + low_A=low_Z=low_P=low_F=low_D=0; + code_A=code_Z=code_P=code_B=code_F=code_D=code_T1=code_T2=code_T3=code_Wnd=0; + val_A=val_Z=val_P=val_B=val_F=val_D=val_T1=val_T2=val_T3=val_Wnd=val_Alp=val_Del=0.; + vel_A=vel_Z=vel_P=vel_F=vel_D=0.; + for(i=0; imagic == sdat.key.code) && (sdt->version == BTA_Data_Ver) ); +} +static void bta_data_close() { + if(sdat.side == ServerSide) { + sdt->magic = 0; + sdt->version = 0; + } +} + +/* блок информационных сообщений ??? */ +/*struct SHM_Block info = {{'I','n','f','o',0},1024,1024,0444,SHM_RDONLY,NULL,NULL,NULL,0,-1,NULL};*/ + +/* Allocate shared memory segment */ +static void get_shm_block( struct SHM_Block *sb, int server) { + int getsize = (server)? sb->maxsize : sb->size; + + /* first try to find existing one */ + sb->id = shmget(sb->key.code, getsize, sb->mode); + + if (sb->id<0 && errno==ENOENT && server) { + /* if no - try to create a new one */ + int cresize = sb->maxsize; + if(sb->size > cresize) { + fprintf(stderr,"Wrong shm maxsize(%d) < realsize(%d)\n",sb->maxsize,sb->size); + cresize = sb->size; + } + sb->id = shmget(sb->key.code, cresize, IPC_CREAT|IPC_EXCL|sb->mode); + } + if (sb->id<0) { + char msg[80]; + if(server) + sprintf(msg,"Can't create shared memory segment '%s'",sb->key.name); + else + sprintf(msg,"Can't find shared segment '%s' (maybe no server process) ",sb->key.name); + perror(msg); + exit(errno); + } + /* attach it to our memory space */ + sb->addr = (unsigned char *)shmat ( sb->id, NULL, sb->atflag ); + + if ((int)(sb->addr) == -1) { + char msg[80]; + sprintf(msg,"Can't attach shared memory segment '%s'",sb->key.name); + perror(msg); + exit(errno); + } + if(server) { + if((shmctl(sb->id, SHM_LOCK, NULL) < 0) < 0) { + char msg[80]; + sprintf(msg,"Can't prevents swapping of shared memory segment '%s'",sb->key.name); + perror(msg); + exit(errno); + } + } + fprintf(stderr,"Create&attach shared memory segment '%s' %dbytes at %x \n", + sb->key.name, sb->size, (uint)sb->addr); + + sb->side = server; + + if(sb->init!=NULL) + sb->init(); +} +static int close_shm_block( struct SHM_Block *sb) { + int ret; + if(sb->close != NULL) + sb->close(); + if(sb->side == ServerSide) { +// ret = shmctl(sb->id, SHM_UNLOCK, NULL); + ret = shmctl(sb->id, IPC_RMID, NULL); + } + ret = shmdt (sb->addr); + return(ret); +} +#endif + +static int check_shm_block( struct SHM_Block *sb) { + if(sb->check != NULL) + return(sb->check()); + else return(1); +} + +#ifndef BTA_MODULE +int snd_id=-1; /* текущий (и единственный?) канал отсылки команд клиента */ +int cmd_src_pid=0; /* номер процесса источника для ОДНОЙ след.команды */ +__uint32_t cmd_src_ip=0; /* IP-адр. источника для ОДНОЙ след.команды */ +#else +extern int snd_id; +extern int cmd_src_pid; +extern __uint32_t cmd_src_ip; +#endif + +#ifndef BTA_MODULE +/* Create|Find command queue */ +static void get_cmd_queue( struct CMD_Queue *cq, int server) { + if (!server && cq->id>=0) { /* if already in use */ + snd_id = cq->id; /* set current... */ + return; + } + /* first try to find existing one */ + cq->id = msgget(cq->key.code, cq->mode); + if (cq->id<0 && errno==ENOENT && server) + /* if no - try to create a new one */ + cq->id = msgget(cq->key.code, IPC_CREAT|IPC_EXCL|cq->mode); + if (cq->id<0) { + char msg[80]; + if(server) + sprintf(msg,"Can't create comand queue '%s'",cq->key.name); + else + sprintf(msg,"Can't find comand queue '%s' (maybe no server process) ",cq->key.name); + perror(msg); + exit(errno); + } + cq->side = server; + if (server) { + char buf[120]; /* выбросить все команды из очереди */ + while(msgrcv(cq->id, (struct msgbuf *)buf, 112, 0, IPC_NOWAIT)>0); + } else + snd_id = cq->id; + cq->acckey = 0; +} +#endif + +/* установка ключа доступа в тек. канале */ +static void set_acckey(uint newkey) { + if (snd_id<0) return; + if(ucmd.id==snd_id) ucmd.acckey=newkey; + else if(ocmd.id==snd_id) ocmd.acckey=newkey; + else if(mcmd.id==snd_id) mcmd.acckey=newkey; +} + +/* установка данных источника для ОДНОЙ след.команды */ +/* если не подходят умолчания: IP=0(локальная команда) и PID текущ.процесса */ +static void set_cmd_src(__uint32_t ip, int pid) { + cmd_src_pid = pid; + cmd_src_ip = ip; +} + +/* структура сообщения */ +struct my_msgbuf { + __int32_t mtype; /* type of message */ + __uint32_t acckey; /* ключ доступа клиента */ + __uint32_t src_pid; /* номер процесса источника */ + __uint32_t src_ip; /* IP-адр. источника, =0 - локальная команда */ + char mtext[100]; /* message text */ +}; +/* отсылка команд клиента к серверу */ +static void send_cmd(int cmd_code, char *buf, int size) { + struct my_msgbuf mbuf; + + if (snd_id<0) return; + if (size>100) size=100; + if (cmd_code>0) + mbuf.mtype = cmd_code; + else + return; + if(ucmd.id==snd_id) mbuf.acckey=ucmd.acckey; + else if(ocmd.id==snd_id) mbuf.acckey=ocmd.acckey; + else if(mcmd.id==snd_id) mbuf.acckey=mcmd.acckey; + + mbuf.src_pid = cmd_src_pid? cmd_src_pid : getpid(); + mbuf.src_ip = cmd_src_ip; + cmd_src_pid = cmd_src_ip = 0; + + if(size>0) + memcpy( mbuf.mtext, buf, size); + else { + mbuf.mtext[0] = 0; + size = 1; + } + msgsnd( snd_id, (struct msgbuf *)&mbuf, size+12, IPC_NOWAIT); +} +static void send_cmd_noarg(int cmd_code) { + send_cmd(cmd_code, NULL, 0); +} +static void send_cmd_str(int cmd_code, char *arg) { + send_cmd(cmd_code, arg, strlen(arg)+1); +} +static void send_cmd_i1(int cmd_code, int arg1) { + send_cmd(cmd_code, (char *)&arg1, sizeof(int)); +} +static void send_cmd_i2(int cmd_code, int arg1, int arg2) { + int ibuf[2]; + ibuf[0] = arg1; + ibuf[1] = arg2; + send_cmd(cmd_code, (char *)ibuf, 2*sizeof(int)); +} +static void send_cmd_i3(int cmd_code, int arg1, int arg2, int arg3) { + int ibuf[3]; + ibuf[0] = arg1; + ibuf[1] = arg2; + ibuf[2] = arg3; + send_cmd(cmd_code, (char *)ibuf, 3*sizeof(int)); +} +static void send_cmd_i4(int cmd_code, int arg1, int arg2, int arg3, int arg4) { + int ibuf[4]; + ibuf[0] = arg1; + ibuf[1] = arg2; + ibuf[2] = arg3; + ibuf[3] = arg4; + send_cmd(cmd_code, (char *)ibuf, 4*sizeof(int)); +} +static void send_cmd_d1(int cmd_code, double arg1) { + send_cmd(cmd_code, (char *)&arg1, sizeof(double)); +} +static void send_cmd_d2(int cmd_code, double arg1, double arg2) { + double dbuf[2]; + dbuf[0] = arg1; + dbuf[1] = arg2; + send_cmd(cmd_code, (char *)dbuf, 2*sizeof(double)); +} +static void send_cmd_i1d1(int cmd_code, int arg1, double arg2) { + struct { + int ival; + double dval; + } buf; + buf.ival = arg1; + buf.dval = arg2; + send_cmd(cmd_code, (char *)&buf, sizeof(buf)); +} +static void send_cmd_i2d1(int cmd_code, int arg1, int arg2, double arg3) { + struct { + int ival[2]; + double dval; + } buf; + buf.ival[0] = arg1; + buf.ival[1] = arg2; + buf.dval = arg3; + send_cmd(cmd_code, (char *)&buf, sizeof(buf)); +} +static void send_cmd_i3d1(int cmd_code, int arg1, int arg2, int arg3, double arg4) { + struct { + int ival[3]; + double dval; + } buf; + buf.ival[0] = arg1; + buf.ival[1] = arg2; + buf.ival[2] = arg3; + buf.dval = arg4; + send_cmd(cmd_code, (char *)&buf, sizeof(buf)); +} + +static void encode_lev_passwd(char *passwd, int nlev, uint *keylev, uint *codlev) { + char salt[4]; + char *encr; + union { + uint ui; + char c[4]; + } key,cod; + sprintf(salt,"L%1d",nlev); + encr = (char *)crypt(passwd, salt); + cod.c[0] = encr[2]; + key.c[0] = encr[3]; + cod.c[1] = encr[4]; + key.c[1] = encr[5]; + cod.c[2] = encr[6]; + key.c[2] = encr[7]; + cod.c[3] = encr[8]; + key.c[3] = encr[9]; + *keylev = key.ui; + *codlev = cod.ui; +} + +static int find_lev_passwd(char *passwd, uint *keylev, uint *codlev) { + int nlev; + for(nlev=5; nlev>0; nlev--) { + encode_lev_passwd(passwd, nlev, keylev, codlev); + if(nlev == 1 && code_Lev1 == *codlev) break; + if(nlev == 2 && code_Lev2 == *codlev) break; + if(nlev == 3 && code_Lev3 == *codlev) break; + if(nlev == 4 && code_Lev4 == *codlev) break; + if(nlev == 5 && code_Lev5 == *codlev) break; + } + return(nlev); +} + +static int check_lev_passwd(char *passwd) { + uint keylev,codlev; + int nlev; + nlev = find_lev_passwd(passwd, &keylev, &codlev); + if(nlev>0) set_acckey(keylev); + return(nlev); +} + +#pragma GCC diagnostic pop + +#endif // __BTA_SHDATA_H__ diff --git a/jsonbta/client.c b/jsonbta/client.c new file mode 100644 index 0000000..a787509 --- /dev/null +++ b/jsonbta/client.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bta_json.h" + +int main(int argc, char *argv[]){ + int sockfd = 0, n = 0; + char recvBuff[1024]; + memset(recvBuff, '0',sizeof(recvBuff)); + struct addrinfo h, *r, *p; + memset(&h, 0, sizeof(h)); + h.ai_family = AF_INET; + h.ai_socktype = SOCK_STREAM; + h.ai_flags = AI_CANONNAME; + char *host = "localhost"; + if(argc > 1) host = argv[1]; + char *port = PORT; + if(argc > 2) port = argv[2]; + if(getaddrinfo(host, port, &h, &r)){perror("getaddrinfo"); return -1;} + struct sockaddr_in *ia = (struct sockaddr_in*)r->ai_addr; + char str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(ia->sin_addr), str, INET_ADDRSTRLEN); + printf("canonname: %s, port: %u, addr: %s\n", r->ai_canonname, ntohs(ia->sin_port), str); + for(p = r; p; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { + perror("socket"); + continue; + } + if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { + close(sockfd); + perror("connect"); + continue; + } + break; // if we get here, we must have connected successfully + } + if (p == NULL) { + // looped off the end of the list with no connection + fprintf(stderr, "failed to connect\n"); + return -1; + } + freeaddrinfo(r); + char *msg = malloc(2048); + char *res = RESOURCE; + if(argc == 4) res = argv[3]; + snprintf(msg, 2047, "GET %s HTTP/1.1\r\n", res); + if(send(sockfd, msg, strlen(msg), 0) != strlen(msg)){perror("send");} + while((n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0){ + recvBuff[n] = 0; + if(fputs(recvBuff, stdout) == EOF) printf("\n Error : Fputs error\n"); + } + if(n < 0) printf("\n Read error \n"); + return 0; +} diff --git a/jsonbta/client_streaming.c b/jsonbta/client_streaming.c new file mode 100644 index 0000000..77c839a --- /dev/null +++ b/jsonbta/client_streaming.c @@ -0,0 +1,337 @@ +/* + * client_streaming.c - example of streaming client + * + * Copyright 2013 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. + */ +#include // addrinfo +#include // printf etc +#include // memset, strdup, strlen +#include // exit +#include // close, read, sleep +#include // fcntl +#include // inet_ntop +#include +#include +#include + +#define PORT "12345" +#define RESOURSE "GET /bta_par HTTP/1.1\r\n" + +typedef enum{ + T_STRING, // string + T_DMS, // degrees:minutes:seconds + T_HMS, // hours:minutes:seconds + T_DOUBLE // double +} otype; + +/* +#define defpar(val) const char* val = #val +defpar(mtime); +defpar(sidtime); +defpar(telmode); +defpar(telfocus); +defpar(target); +defpar(p2mode); +defpar(eqcoor); +defpar(horcoor); +defpar(valsens); +defpar(diff); +defpar(vel); +defpar(corr); +defpar(meteo); +#undef defpar +*/ +/* +{ +"M_time": "22:49:13.61", +"JDate": 2456367.284184, +"S_time": "09:09:07.34", +"Tel_Mode": "Stopping", +"Tel_Focus": "Prime", +"ValFoc": 43.54, +"Tel_Taget": "Nest", +"P2_Mode": "Stop", +"CurAlpha": "00:26:06.78", +"CurDelta": "+25:34:34.0", +"SrcAlpha": "06:03:08.53", +"SrcDelta": "+30:00:00.0", +"InpAlpha": "06:03:08.53", +"InpDelta": "+30:00:00.0", +"TelAlpha": "04:23:09.30", +"TelDelta": "+25:34:41.3", +"InpAzim": "+085:27:36.4", +"InpZenD": "39:01:06.5", +"CurAzim": "+136:27:11.0", +"CurZenD": "97:21:25.3", +"CurPA": "033:32:49.7", +"SrcPA": "056:23:33.0", +"InpPA": "056:23:33.0", +"TelPA": "052:39:24.3", +"ValAzim": "+097:37:52.4", +"ValZenD": "59:37:00.2", +"ValP2": "310:24:30.2", +"ValDome": "+180:16:47.0", +"DiffAzim": "+000:00:00.0", +"DiffZenD": "+00:00:00.0", +"DiffP2": "+000:00:00.6", +"DiffDome": "-082:38:54.6", +"VelAzim": "+00:00:00.0", +"VelZenD": "-00:00:00.0", +"VelP2": "+00:00:00.0", +"VelPA": "+00:00:00.0", +"VelDome": "+00:00:00.0", +"CorrAlpha": "+0:00:00.00", +"CorrDelta": "+0:00:00.0", +"CorrAzim": "+0:00:00.0", +"CorrZenD": "+0:00:00.0", +"ValTind": +02.5, +"ValTmir": +01.7, +"ValPres": 590.3, +"ValWind": 06.6, +"Blast10": 1.4, +"Blast15": 3.4, +"ValHumd": 50.0 +} +*/ + +/** + * Get double parameter + * @param jobj - json record with double parameter + * @return NULL in case of error or allocated double value (MUST BE FREE LATER) + */ +double* get_jdouble(json_object *jobj){ + enum json_type type = json_object_get_type(jobj); + double val, *ret; + switch(type){ + case json_type_double: + val = json_object_get_double(jobj); + break; + case json_type_int: + val = json_object_get_int(jobj); + break; + default: + fprintf(stderr, "Wrong value! Get non-number!\n"); + return NULL; + } + ret = malloc(sizeof(double)); + assert(ret); + memcpy(ret, &val, sizeof(double)); + return ret; +} +double strtod(const char *nptr, char **endptr); + +char *atodbl(char *str, double *d){ + char *eptr; + *d = strtod(str, &eptr); + if(eptr == str) return NULL; + return eptr; +} + +/** + * get string parameter + * @param jobj - json record + * @return string or NULL in case of error + */ + +char *get_jstr(json_object *jobj){ + enum json_type type = json_object_get_type(jobj); + if(type != json_type_string) return NULL; + return (char*)json_object_get_string(jobj); +} + +double *get_jdhms(json_object *jobj){ + char *jptr = get_jstr(jobj); + char *str = jptr, *endln = str + strlen(str); + double h,m,s, sgn; + #define GetVal(x) do{if(str >= endln) return NULL; str = atodbl(str, &x); if(!str)return NULL; str++;}while(0) + GetVal(h); + GetVal(m); + GetVal(s); + #undef GetVal + sgn = (h < 0.) ? -1. : 1.; + h = fabs(h); + double *ret = malloc(sizeof(double)); + assert(ret); + *ret = sgn * (h + m / 60. + s / 3600.); + return ret; +} + +/** + * get parameter from json object + * @param jobj - json records + * @param par - parameter to find + * @param type - type of par + * @return dinamycally allocated pointer to char (if T_STRING) or double (for other types); + * if type is angle or time, its value converts from DMS/HMS to double + * in case of parameter absense or error function returns NULL + */ +void *get_json_par(json_object *jobj, char *par, otype type){ + json_object *o = json_object_object_get(jobj, par); + void *ret; + if(!o) return NULL; + switch(type){ + case T_DOUBLE: + ret = (void*)get_jdouble(o); + break; + case T_DMS: + case T_HMS: + ret = (void*)get_jdhms(o); + break; + case T_STRING: + default: + ret = (void*)strdup(get_jstr(o)); + } + json_object_put(o); // free object's memory + return ret; +} + + +/** + * set non-blocking flag to socket + * @param sock - socket fd + * +void setnonblocking(int sock){ + int opts = fcntl(sock, F_GETFL); + if(opts < 0){ + perror("fcntl(F_GETFL)"); + exit(-1); + } + opts = (opts | O_NONBLOCK); + if (fcntl(sock,F_SETFL,opts) < 0) { + perror("fcntl(F_SETFL)"); + exit(-1); + } + return; +}*/ + +/** + * wait for answer from server + * @param sock - socket fd + * @return 0 in case of error or timeout, 1 in case of socket ready + */ +int waittoread(int sock){ + fd_set fds; + struct timeval timeout; + int rc; + timeout.tv_sec = 1; // wait not more than 1 second + timeout.tv_usec = 0; + FD_ZERO(&fds); + FD_SET(sock, &fds); + rc = select(sock+1, &fds, NULL, NULL, &timeout); + if(rc < 0){ + perror("select failed"); + return 0; + } + if(rc > 0 && FD_ISSET(sock, &fds)) return 1; + return 0; +} + +int main(int argc, char *argv[]){ + size_t BUFSZ = 1024; + int sockfd = 0; + char *recvBuff = calloc(BUFSZ, 1); + assert(recvBuff); + struct addrinfo h, *r, *p; + memset(&h, 0, sizeof(h)); + h.ai_family = AF_INET; + h.ai_socktype = SOCK_STREAM; + h.ai_flags = AI_CANONNAME; + char *host = "localhost"; + if(argc > 1) host = argv[1]; + char *port = PORT; + if(argc > 2) port = argv[2]; + if(getaddrinfo(host, port, &h, &r)){perror("getaddrinfo"); return -1;} + struct sockaddr_in *ia = (struct sockaddr_in*)r->ai_addr; + char str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(ia->sin_addr), str, INET_ADDRSTRLEN); + printf("canonname: %s, port: %u, addr: %s\n", r->ai_canonname, ntohs(ia->sin_port), str); + for(p = r; p; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { + perror("socket"); + continue; + } + if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { + close(sockfd); + perror("connect"); + continue; + } + break; // if we get here, we must have connected successfully + } + if(p == NULL){ + // looped off the end of the list with no connection + fprintf(stderr, "failed to connect\n"); + return -1; + } + freeaddrinfo(r); + //setnonblocking(sockfd); + char *msg; + char *res = RESOURSE; + if(argc == 4) res = argv[3]; + msg = strdup(res); + do{ + if(send(sockfd, msg, strlen(msg), 0) != strlen(msg)){perror("send"); return -1;} + if(!waittoread(sockfd)) return -1; + int offset = 0, n = 0; + do{ + if(offset >= BUFSZ){ + BUFSZ += 1024; + recvBuff = realloc(recvBuff, BUFSZ); + assert(recvBuff); + fprintf(stderr, "Buffer reallocated, new size: %zd\n", BUFSZ); + } + n = read(sockfd, &recvBuff[offset], BUFSZ - offset); + if(!n) break; + if(n < 0){ + perror("read"); + return -1; + } + offset += n; + }while(waittoread(sockfd)); + if(!offset){ + fprintf(stderr, "Socket closed\n"); + return 0; + } + printf("read %d bytes\n", offset); + recvBuff[offset] = 0; + printf("Received data:\n-->%s<--\n", recvBuff); + fflush(stdout); + // here we do something with values we got + // for example - parce them & print + json_object *jobj = json_tokener_parse(recvBuff); + if(!jobj){ + fprintf(stderr, "Can't parse json!\n"); + return -1; + } + double *focval = (double*)get_json_par(jobj, "ValFoc", T_DOUBLE); + double *valaz = (double*)get_json_par(jobj, "ValAzim", T_DMS); + double *valzd = (double*)get_json_par(jobj, "ValZenD", T_DMS); + double *valdaz = (double*)get_json_par(jobj, "ValDome", T_DMS); + double *valP2 = (double*)get_json_par(jobj, "ValP2", T_DMS); + #define prntdbl(name, val) do{if(val) printf("%s = %g\n", name, *val); free(val);}while(0) + prntdbl("Focus value", focval); + prntdbl("Telescope azimuth", valaz); + prntdbl("Telescope zenith distance", valzd); + prntdbl("Dome azimuth", valdaz); + prntdbl("P2 angle", valP2); + #undef prntdbl + json_object_put(jobj); // destroy jobj + sleep(1); + }while(1); + return 0; +} diff --git a/jsonbta/makefile_from_tb b/jsonbta/makefile_from_tb new file mode 100644 index 0000000..5ce518c --- /dev/null +++ b/jsonbta/makefile_from_tb @@ -0,0 +1,16 @@ +LOADLIBES = -lm -lcrypt +SRCS = bta_json.c bta_print.c ../daemon.c +CC = gcc +DEFINES = +CXX = gcc +CPPFLAGS = -Wall $(DEFINES) -I/Users/eddy/include +OBJS = $(SRCS:.c=.o) +all : bta_json client_streaming +$(OBJS): bta_json.h bta_shdata.h +bta_json : $(OBJS) + $(CC) $(CPPFLAGS) $(OBJS) $(LOADLIBES) -o bta_json +client_streaming: client_streaming.o + $(CC) $(CPPFLAGS) client_streaming.o /Users/eddy/lib/libjson.a -lm -o client_streaming +clean: + /bin/rm -f *.o *~ + diff --git a/jsonbta/manual.pdf b/jsonbta/manual.pdf new file mode 100644 index 0000000..6530462 Binary files /dev/null and b/jsonbta/manual.pdf differ diff --git a/jsonbta/manual.tex b/jsonbta/manual.tex new file mode 100644 index 0000000..1f2c3de --- /dev/null +++ b/jsonbta/manual.tex @@ -0,0 +1,268 @@ +\documentclass[a4paper,12pt]{extarticle} +\usepackage{listings} +\usepackage{hyperref} +\usepackage{/home/eddy/ed} +\colorlet{punct}{red} +\definecolor{delim}{RGB}{20,105,176} +\colorlet{numb}{red!60!black} +\lstdefinelanguage{JSON}{ + basicstyle=\small\ttfamily, + numbers=left, + numberstyle=\scriptsize, + stepnumber=2, + numbersep=8pt, + showstringspaces=false, + breaklines=true, + frame=tbrL, + literate= + *{0}{{{\color{numb}0}}}{1} + {1}{{{\color{numb}1}}}{1} + {2}{{{\color{numb}2}}}{1} + {3}{{{\color{numb}3}}}{1} + {4}{{{\color{numb}4}}}{1} + {5}{{{\color{numb}5}}}{1} + {6}{{{\color{numb}6}}}{1} + {7}{{{\color{numb}7}}}{1} + {8}{{{\color{numb}8}}}{1} + {9}{{{\color{numb}9}}}{1} + {.}{{{\color{numb}.}}}{1} + {:}{{{\color{punct}{:}}}}{1} + {,}{{{\color{punct}{,}}}}{1} + {\{}{{{\color{delim}{\{}}}}{1} + {\}}{{{\color{delim}{\}}}}}{1} + {[}{{{\color{delim}{[}}}}{1} + {]}{{{\color{delim}{]}}}}{1}, + morestring=[b]", + morestring=[b]', + extendedchars=true, + escapechar=`, + stringstyle=\bfseries\color[rgb]{0.6,0,1}, + keywords={true,false}, + keywordstyle=\bfseries\color[rgb]{0,0.1,0.5}, + frameround=tttt +} +\lstset{basicstyle=\small,breaklines=true, + extendedchars=true,aboveskip=1em,belowcaptionskip=5pt, + prebreak = \hbox{% +\normalfont\small\hfill\green{\ensuremath{\hookleftarrow}}}, + postbreak = \hbox to 0pt{% +\hss\normalfont\small\green{\ensuremath{\hookrightarrow}}\hspace{1ex}}, + commentstyle=\color{blue},showspaces=false, + showstringspaces=false,stringstyle=\bfseries\color[rgb]{0.6,0,1}, + numbers=left,numberstyle=\tiny,stepnumber=2, + keywordstyle=\bfseries\color[rgb]{0,0.1,0.5}, + frameround=tttt,frame=trBL,tabsize=4,backgroundcolor=\color[rgb]{.9,.9,1}} +\lstloadlanguages{JSON,C} +\def\lstlistingname{Листинг} +\def\lstref#1{(см.~листинг~\ref{#1})} +\LTcapwidth=\textwidth + +\title{Вспомогательный сервис BTA-JSON} + +\begin{document} +\nocolon +\maketitle +\section{Введение} +Для осуществления возможности удаленного мониторинга состояния телескопа БТА (в +т.ч. для заполнения стандартного заголовка FITS-файлов) на основе разработанной +В.С.~Шергиным программы \verb'bta_print' был создан простой сетевой сервис, +выдающий по запросу пользователя всю необходимую информацию в формате JSON. + +Необходимость создания данного сервиса была обоснована тем, что прохождение +multicast-пакетов из локальной сети БТА в локальную сеть ННП зачастую +блокируется многочисленым промежуточным сетевым оборудованием. + +Данный сервис в режиме демона работает на компьютере \verb'tb.sao.ru', отвечая +на запросы, адресованные ресурсу \verb'/bta_par' на порту \verb'12345'. +Демон принимает запросы как от веб-клиентов, так и от непосредственно +подключенных клиентских сокетов. Полный адрес запроса для веб-клиента выглядит +так: +$$ +\verb'http://tb.sao.ru:12345/bta_par' +$$ + +По полному запросу сервер возвращает объект JSON с переменными, аналогичными +выводу программы \verb'bta_print'. +\begin{lstlisting}[language=JSON] +{ +"ACS_BTA": true, +"M_time": "13:58:57.74", +"JDate": 2456432.915943, +"S_time": "04:37:37.01", +"Tel_Mode": "Stopping", +"Tel_Focus": "Prime", +"ValFoc": 98.77, +"Tel_Taget": "Zenith", +"P2_Mode": "Stop", +"CurAlpha": "04:12:28.25", +"CurDelta": "+39:56:53.4", +"SrcAlpha": "06:25:53.48", +"SrcDelta": "+10:00:00.0", +"InpAlpha": "11:41:52.03", +"InpDelta": "+24:40:36.4", +"TelAlpha": "04:57:06.82", +"TelDelta": "+39:57:14.6", +"InpAzim": "-118:27:18.0", +"InpZenD": "83:52:29.3", +"CurAzim": "+053:55:21.3", +"CurZenD": "05:57:00.7", +"CurPA": "049:36:52.7", +"SrcPA": "329:54:01.0", +"InpPA": "315:37:58.0", +"TelPA": "317:08:11.1", +"ValAzim": "-045:59:40.4", +"ValZenD": "05:09:31.2", +"ValP2": "219:33:16.7", +"ValDome": "+134:55:41.6", +"DiffAzim": "+000:00:00.0", +"DiffZenD": "+00:00:00.0", +"DiffP2": "+000:00:00.0", +"DiffDome": "-180:55:22.0", +"VelAzim": "+00:00:00.0", +"VelZenD": "-00:00:00.0", +"VelP2": "+00:00:00.0", +"VelPA": "+00:00:00.0", +"VelDome": "+00:00:00.0", +"CorrAlpha": "+0:00:00.00", +"CorrDelta": "+0:00:00.0", +"CorrAzim": "+0:00:00.0", +"CorrZenD": "+0:00:00.0", +"ValTind": 010.4, +"ValTmir": 010.3, +"ValPres": 595.8, +"ValWind": 01.7, +"Blast10": 18633.4, +"Blast15": 59794.7, +"ValHumd": 86.3, +"Precipt": 1087.4 +} +\end{lstlisting} + +Момимо запуска утилиты из веб-браузеров можно использовать клиент командной +строки. Образцы клиентов находятся в директории \verb'/Users/eddy/BTA_utils' +компьютера \verb'tb.sao.ru', а также "--- в репозитории \verb'btautils' по +адресу \url{https://sourceforge.net/projects/btautils/}. Помимо однократных +запросов клиент может создать постоянное подключение к сокету демона для +регулярных запросов интересующих его данных (см.~п.~\ref{coding}). + +\section{Определение полей объекта JSON} +В таблице~\ref{json_head} приведено описание полей объекта JSON, возвращаемого +сервером клиенту. Тип данных поля имеет одно из следующих значений: +\begin{description} +\item[текст --] строковая величина (например, \verb'"Zenith"'); +\item[время --] строковая величина, характеризующая время, вида + \verb'HH:MM:SS.SS' (для времени и прямых восхождений); +\item[угол --] строковая величина вида \verb'[+]D:MM:SS.S' (для угловых + величин); +\item[число --] число с плавающей точкой. +\end{description} + + +\def\CH#1{\multicolumn{1}{|c|}{#1}} +\begin{longtable}{|>{\tt}r|p{0.46\textwidth}<{\hfil}|c|>{\tt}c|} +\caption{Поля объектов}\label{json_head}\\ +\hline\hline +\multicolumn{1}{|m{2cm}|}{\bf Название\par\hfil поля\hfil}& \CH{\bf +Описание} & \bf Тип данных &\bf Блок\\ +\hline +\CH{\bf 1}&\CH{\bf 2}& \bf 3 & \bf 4\\ +\hline\endfirsthead +\hline +\multicolumn{4}{r}{\small(продолжение см.~на следующей странице)}\\ +\endfoot +\hline\hline\endlastfoot +\caption{Продолжение}\\ +\hline +\CH{\bf 1}&\CH{\bf 2}& \bf 3& \bf 4\\ +\hline\endhead +ACS\_BTA& Унаследованное от \texttt{bta\_print} поле, всегда \texttt{true}& +--- & \bf---\\ +M\_time& Текущее московское время& время & mtime\\ +JDate& Текущая юлианская дата (сут.)& число & sidtime\\ +S\_time& Текущее звездное время& время & sidtime\\ +Tel\_Mode& Режим работы телескопа& строка & telmode\\ +Tel\_Focus& Активный фокус телескопа & строка & telfocus\\ +ValFoc& Отсчет датчика фокуса телескопа, мм& число & telfocus\\ +Tel\_Taget& Текущая цель телескопа& строка & target\\ +P2\_Mode& Режим работы поворотного стола& строка & p2mode\\ +CurAlpha& Текущие координаты предыдущей цели ($\alpha$~-- прямое восхождение) & +время & eqcoor\\ +CurDelta& Текущие координаты предыдущей цели ($\delta$~-- склонение)& угол & +eqcoor\\ +SrcAlpha& Текущие координаты цели ($\alpha$)& время & eqcoor\\ +SrcDelta& Текущие координаты цели ($\delta$)& угол & eqcoor\\ +InpAlpha& Введенные пользователем координаты ($\alpha$)& время & eqcoor\\ +InpDelta& Введенные пользователем координаты ($\delta$)& угол & eqcoor\\ +TelAlpha& Текущие координаты телескопа ($\alpha$)& время & eqcoor\\ +TelDelta& Текущие координаты телескопа ($\delta$)& угол & eqcoor\\ +InpAzim& Введенные горизонтальные координаты ($A$~-- азимут)& угол & horcoor\\ +InpZenD& Введенные горизонтальные координаты ($Z$~-- зенитное расстояние)& +угол & horcoor\\ +CurAzim& Текущие горизонтальные координаты предыдущей цели ($A$)& угол & +horcoor\\ +CurZenD& Текущие горизонтальные координаты предыдущей цели ($Z$)& угол & +horcoor\\ +CurPA& Текущий позиционный угол предыдущей цели& угол & horcoor\\ +SrcPA& Текущий позиционный угол цели& угол & horcoor\\ +InpPA& Введенный пользователем позиционный угол& угол & horcoor\\ +TelPA& Текущий позиционный угол телескопа& угол & horcoor\\ +ValAzim& Отсчет датчика азимута& угол & valsens\\ +ValZenD& Отсчет датчика зенитного расстояния& угол & valsens\\ +ValP2& Отсчет датчика положения поворотного стола& угол & valsens\\ +ValDome& Отсчет датчика азимута купола& угол & valsens\\ +DiffAzim& Рассогласование по азимуту& угол & diff\\ +DiffZenD& Рассогласование по зенитному расстоянию& угол & diff\\ +DiffP2& Рассогласование по углу вращения поворотного стола& угол & diff\\ +DiffDome& Рассогласование по азимуту купола& угол & diff\\ +VelAzim& Текущая скорость движения телескопа по азимуту& угол & vel\\ +VelZenD& Текущая скорость движения телескопа по зенитному расстоянию& угол & +vel\\ +VelP2& Текущая скорость движения поворотного стола & угол & vel\\ +VelPA& Текущая скорость <<вращения неба>>& угол & vel\\ +VelDome& Текущая скорость движения купола& угол & vel\\ +CorrAlpha& Введенная поправка по прямому восхождению& угол & corr\\ +CorrDelta& Введенная поправка по склонению& угол & corr\\ +CorrAzim& Введенная поправка по азимуту& угол & corr\\ +CorrZenD& Введенная поправка по зенитному расстоянию& угол & corr\\ +ValTind& Температура в подкупольном, $\degr$C& число & meteo\\ +ValTmir& Температура зеркала, $\degr$C& число & meteo\\ +ValPres& Атмосферное давление, мм.рт.ст.& число & meteo\\ +ValWind& Скорость ветра, м/с& число & meteo\\ +Blast10& Время от последнего порыва ветра, превышающего 10\,м/с, секунд& число & +meteo\\ +Blast15& Время от последнего порыва ветра, превышающего 15\,м/с, секунд& число & +meteo\\ +ValHumd& Влажность воздуха, \%& число & meteo\\ +Precipt& Время, прошедшее с момента последнего выпадения осадков, секунд& +число & meteo\\ +\end{longtable} + +\section{Осуществление постоянного подключения} +\label{coding} +Для осуществления постоянного удаленного подключения к демону для +периодического получения необходимых данных, необходимо создать сокет, +подключенный к хосту \verb'tb.sao.ru' по порту \verb'12345'. + +Для запроса конкретного блока данных во время постоянного подключения, в +качестве запроса необходимо отправлять текст, указанный в строке <<Блок>> +таблицы~\ref{json_head}. + +Формирование строки запроса можно сделать одним из следующих способов: +\begin{itemize} +\item посредством перечисления названий нужных блоков через разделитель +(разделителем является пробел, амперсанд, символ табуляции или символ новой +строки); +\item посредством формирования запроса вида \verb'GET /bta_par&blocks', где +\verb'blocks'~-- запрос аналогичный предыдущему пункту; +\item посредством формирования запроса вида \verb'GET /bta_par', в этом случае +демон формирует ответ с перечислением всех блоков, а затем отключается. +\end{itemize} + +Для обработки JSON--объекта можно использовать библиотеку \verb'libjson', либо +же обрабатывать его вручную (т.к. структура объекта элементарная и +однообразная). + +Учитывая то, что мультикаст-пакеты с данными по БТА распространяются не чаще +15~раз в~секунду, не стоит делать запросы чаще 10~раз в~секунду. + +\end{document}