mirror of
https://github.com/eddyem/BTA_utils.git
synced 2025-12-06 02:35:13 +03:00
copy
This commit is contained in:
parent
8ed4972ce3
commit
99bc79d44e
140
daemon.c
Normal file
140
daemon.c
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* daemon.c - functions for running in background like a daemon
|
||||||
|
*
|
||||||
|
* Copyright 2013 Edward V. Emelianoff <eddy@sao.ru>
|
||||||
|
*
|
||||||
|
* 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 <stdio.h> // printf, fopen, ...
|
||||||
|
#include <unistd.h> // getpid
|
||||||
|
#include <stdio.h> // perror
|
||||||
|
#include <sys/types.h> // opendir
|
||||||
|
#include <dirent.h> // opendir
|
||||||
|
#include <sys/stat.h> // stat
|
||||||
|
#include <fcntl.h> // fcntl
|
||||||
|
#include <stdlib.h> // exit
|
||||||
|
#include <string.h> // 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);
|
||||||
|
}
|
||||||
16
jsonbta/Makefile
Normal file
16
jsonbta/Makefile
Normal file
@ -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 *~
|
||||||
|
|
||||||
211
jsonbta/bta_json.c
Normal file
211
jsonbta/bta_json.c
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* bta_json.c - create socket and reply bta data
|
||||||
|
*
|
||||||
|
* Copyright 2013 Edward V. Emelianoff <eddy@sao.ru>
|
||||||
|
*
|
||||||
|
* 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 <strings.h>
|
||||||
|
#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 "par1<del>par2<del>..."
|
||||||
|
* where "pars" are names of bta_pars fields
|
||||||
|
* <del> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ËÏÎÅÃ ÆÁÊÌÁ
|
||||||
92
jsonbta/bta_json.h
Normal file
92
jsonbta/bta_json.h
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* bta_json.h
|
||||||
|
*
|
||||||
|
* Copyright 2013 Edward V. Emelianoff <eddy@sao.ru>
|
||||||
|
*
|
||||||
|
* 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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h> // exit
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#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__
|
||||||
|
|
||||||
|
// ËÏÎÅÃ ÆÁÊÌÁ
|
||||||
380
jsonbta/bta_print.c
Normal file
380
jsonbta/bta_print.c
Normal file
@ -0,0 +1,380 @@
|
|||||||
|
/*
|
||||||
|
* bta_print.c
|
||||||
|
*
|
||||||
|
* Copyright Vladimir S. Shergin <vsher@sao.ru>
|
||||||
|
*
|
||||||
|
* some changes (2013) Edward V. Emelianoff <eddy@sao.ru>
|
||||||
|
*
|
||||||
|
* 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 <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/times.h>
|
||||||
|
#include <crypt.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#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");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ËÏÎÅÃ ÆÁÊÌÁ
|
||||||
1159
jsonbta/bta_shdata.h
Normal file
1159
jsonbta/bta_shdata.h
Normal file
File diff suppressed because it is too large
Load Diff
61
jsonbta/client.c
Normal file
61
jsonbta/client.c
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
337
jsonbta/client_streaming.c
Normal file
337
jsonbta/client_streaming.c
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
/*
|
||||||
|
* client_streaming.c - example of streaming client
|
||||||
|
*
|
||||||
|
* Copyright 2013 Edward V. Emelianoff <eddy@sao.ru>
|
||||||
|
*
|
||||||
|
* 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 <netdb.h> // addrinfo
|
||||||
|
#include <stdio.h> // printf etc
|
||||||
|
#include <string.h> // memset, strdup, strlen
|
||||||
|
#include <stdlib.h> // exit
|
||||||
|
#include <unistd.h> // close, read, sleep
|
||||||
|
#include <fcntl.h> // fcntl
|
||||||
|
#include <arpa/inet.h> // inet_ntop
|
||||||
|
#include <math.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <json/json.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
16
jsonbta/makefile_from_tb
Normal file
16
jsonbta/makefile_from_tb
Normal file
@ -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 *~
|
||||||
|
|
||||||
BIN
jsonbta/manual.pdf
Normal file
BIN
jsonbta/manual.pdf
Normal file
Binary file not shown.
268
jsonbta/manual.tex
Normal file
268
jsonbta/manual.tex
Normal file
@ -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}
|
||||||
Loading…
x
Reference in New Issue
Block a user