mirror of
https://github.com/eddyem/BTA_utils.git
synced 2025-12-06 18:55:18 +03:00
338 lines
8.6 KiB
C
338 lines
8.6 KiB
C
/*
|
|
* 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;
|
|
}
|