add weather processing to 10micron stellarium

This commit is contained in:
Edward Emelianov 2021-06-10 00:53:24 +03:00
parent 6bfcc8730c
commit b25c15cbfc
15 changed files with 681 additions and 169 deletions

View File

@ -9,7 +9,9 @@ main.c
main.h
parseargs.c
parseargs.h
socket.c
socket.h
telescope.c
telescope.h
usefull_macros.c
usefull_macros.h
usefull_macro.c
usefull_macro.h

View File

@ -24,20 +24,23 @@
#include <strings.h>
#include <math.h>
#include "cmdlnopts.h"
#include "usefull_macros.h"
#include "parseargs.h"
#include "usefull_macro.h"
/*
* here are global parameters initialisation
*/
int help;
glob_pars G;
glob_pars *GP = NULL;
#define DEFAULT_COMDEV "/dev/ttyUSB0"
// port for connections
#define DEFAULT_PORT "10000"
#define DEFAULT_DBGPORT "10001"
// accept only local connections
//#define ACCEPT_IP "192.168.3.225"
// weather server port and name
#define DEFAULT_WSPORT (12345)
#define DEFAULT_WSNAME "robotel1.sao.ru"
// default PID filename:
#define DEFAULT_PIDFILE "/tmp/stellariumdaemon.pid"
// default file with headers
@ -52,6 +55,8 @@ glob_pars const Gdefault = {
.pidfile = DEFAULT_PIDFILE,
.crdsfile = DEFAULT_FITSHDR,
.emulation = 0,
.weathserver = DEFAULT_WSNAME,
.weathport = DEFAULT_WSPORT,
.logfile = NULL // don't save logs
};
@ -70,6 +75,8 @@ myoption cmdlnopts[] = {
{"pidfile", NEED_ARG, NULL, 'P', arg_string, APTR(&G.pidfile), _("pidfile (default: " DEFAULT_PIDFILE ")")},
{"port", NEED_ARG, NULL, 'p', arg_string, APTR(&G.port), _("port to connect (default: " DEFAULT_PORT ")")},
{"dbgport", NEED_ARG, NULL, 'D', arg_string, APTR(&G.dbgport), _("port to connect for debug console (default: " DEFAULT_DBGPORT ")")},
{"wport", NEED_ARG, NULL, 'w', arg_int, APTR(&G.weathport), _("weather server port")},
{"wname", NEED_ARG, NULL, 'W', arg_string, APTR(&G.weathserver),_("weather server address")},
end_option
};

View File

@ -23,8 +23,6 @@
#ifndef __CMDLNOPTS_H__
#define __CMDLNOPTS_H__
#include "parseargs.h"
/*
* here are some typedef's for global data
*/
@ -35,11 +33,15 @@ typedef struct{
char *pidfile; // name of PID file
char *logfile; // logging to this file
char *crdsfile; // file where FITS-header should be written
char *weathserver; // weather server name
int emulation; // run in emulation mode
int rest_pars_num; // number of rest parameters
int weathport; // weather server port
char** rest_pars; // the rest parameters: array of char*
} glob_pars;
// global parameters
extern glob_pars *GP;
glob_pars *parse_args(int argc, char **argv);
#endif // __CMDLNOPTS_H__

View File

@ -22,7 +22,7 @@
*/
#include "math.h"
#include "emulation.h"
#include "usefull_macros.h"
#include "usefull_macro.h"
// emulation speed over RA & DEC (0.5 degr per sec)
#define RA_SPEED (0.033)

View File

@ -19,7 +19,8 @@
#include <time.h>
#include "libsofa.h"
#include "usefull_macros.h"
#include "socket.h"
#include "usefull_macro.h"
#ifdef EBUG
void reprd(char* s, double ra, double dc){
@ -45,31 +46,73 @@ void radtodeg(double r){
#define REP(a,b,c)
#endif
// temporal stubs for weather/place/DUT1 data; return 0 if all OK
int getPlace(placeData *p){
if(!p) return 0;
/* Site longitude, latitude (radians) and height above the geoid (m). */
p->slong = 0.7232763200;
p->slat = 0.7618977414;
/*
iauAf2a('+', 41, 26, 26.45, &p->slong); // longitude
iauAf2a('+', 43, 39, 12.69, &p->slat); // latitude
*/
p->salt = 2070.0; // altitude
//DBG("long: %.10f, lat: %.10f", p->slong, p->slat);
return 0;
// temporal stubs for weather/place/DUT1 data; user can change values of these variables
static placeData place = {.slong = 0.7232763200, .slat = 0.7618977414, .salt = 2070.};
placeData *getPlace(){
return &place;
}
int getWeath(placeWeather *w){
if(!w) return 0;
w->relhum = 0.7;
w->tc = 1.;
w->php = 780.;
return 0;
static localWeather weather = {0};
typedef struct{
const char *name;
double *valptr;
} weathpars;
#define WPCOUNT (7)
static weathpars WPars[WPCOUNT] = {
{"BTAHumid", &weather.relhum},
{"BTAPres", &weather.pres},
{"Exttemp", &weather.tc},
{"Rain", &weather.rain},
{"Clouds", &weather.clouds},
{"Wind", &weather.wind},
{"Time", &weather.time}
};
localWeather *getWeath(){
//DBG("DT=%zd", time(NULL) - (time_t)weather.time);
char *w = getweathbuffer();
//DBG("w=%s", w);
if(w){ // get new data - check it
int ctr = 0;
for(int i = 0; i < WPCOUNT; ++i){
if(getparval(WPars[i].name, w, WPars[i].valptr)) ++ctr;
}
if(ctr != WPCOUNT) WARN("Not full set of parameters in %s", w);
FREE(w);
}
if((time_t)weather.time == 0 || time(NULL) - (time_t)weather.time > 3600) return NULL;
return &weather;
}
int getDUT(almDut *a){
if(!a) return 0;
a->px = a->py = a->DUT1 = 0.;
return 0;
static almDut dut1 = {0};
almDut *getDUT(){
// check DUT1 data HERE once per some time
return &dut1;
}
/**
* @brief r2sHMS - convert angle in radians into string "'HH:MM:SS.SS'"
* @param radians - angle
* @param hms (o) - string
* @param len - length of hms
*/
void r2sHMS(double radians, char *hms, int len){
char pm;
int i[4];
iauA2tf(2, radians, &pm, i);
snprintf(hms, len, "'%c%02d:%02d:%02d.%02d'", pm, i[0],i[1],i[2],i[3]);
}
/**
* @brief r2sDMS - convert angle in radians into string "'DD:MM:SS.S'"
* @param radians - angle
* @param dms (o) - string
* @param len - length of hms
*/
void r2sDMS(double radians, char *dms, int len){
char pm;
int i[4];
iauA2af(1, radians, &pm, i);
snprintf(dms, len, "'%c%02d:%02d:%02d.%d'", pm, i[0],i[1],i[2],i[3]);
}
/**
@ -110,15 +153,89 @@ int get_MJDt(struct timeval *tval, sMJD *MJD){
return 0;
}
/**
* @brief get_LST - calculate local siderial time
* @param mjd (i) - date/time for LST (utc1 & tt used)
* @param dUT1 - (UT1-UTC)
* @param slong - site longitude (radians)
* @param LST (o) - local sidereal time (radians)
* @return 0 if all OK
*/
int get_LST(sMJD *mjd, double dUT1, double slong, double *LST){
double ut11, ut12;
sMJD Mjd;
if(!mjd){
if(get_MJDt(NULL, &Mjd)) return 1;
}else memcpy(&Mjd, mjd, sizeof(sMJD));
if(iauUtcut1(Mjd.utc1, Mjd.utc2, dUT1, &ut11, &ut12)) return 2;
/*double era = iauEra00(ut11, ut12) + slong;
double eo = iauEe06a(mjd->tt1, mjd->tt2);
printf("ERA = %s; ", radtohrs(era));
printf("ERA-eo = %s\n", radtohrs(era-eo));*/
if(!LST) return 0;
double ST = iauGst06a(ut11, ut12, Mjd.tt1, Mjd.tt2);
ST += slong;
if(ST > D2PI) ST -= D2PI;
else if(ST < 0.) ST += D2PI;
*LST = ST;
return 0;
}
/**
* @brief hor2eq - convert horizontal coordinates to polar
* @param h (i) - horizontal coordinates
* @param pc (o) - polar coordinates
* @param sidTime - sidereal time
*/
void hor2eq(horizCrds *h, polarCrds *pc, double sidTime){
if(!h || !pc) return;
placeData *p = getPlace();
iauAe2hd(h->az, DPI/2. - h->zd, p->slat, &pc->ha, &pc->dec); // A,H -> HA,DEC; phi - site latitude
pc->ra = sidTime - pc->ha;
pc->eo = 0.;
}
/**
* @brief eq2horH - convert polar coordinates to horizontal
* @param pc (i) - polar coordinates (only HA used)
* @param h (o) - horizontal coordinates
* @param sidTime - sidereal time
*/
void eq2horH(polarCrds *pc, horizCrds *h){
if(!h || !pc) return;
placeData *p = getPlace();
double alt;
iauHd2ae(pc->ha, pc->dec, p->slat, &h->az, &alt);
h->zd = DPI/2. - alt;
}
/**
* @brief eq2hor - convert polar coordinates to horizontal
* @param pc (i) - polar coordinates (only RA used)
* @param h (o) - horizontal coordinates
* @param sidTime - sidereal time
*/
void eq2hor(polarCrds *pc, horizCrds *h, double sidTime){
if(!h || !pc) return;
double ha = sidTime - pc->ra + pc->eo;
placeData *p = getPlace();
double alt;
iauHd2ae(ha, pc->dec, p->slat, &h->az, &alt);
h->zd = DPI/2. - alt;
}
/**
* @brief get_ObsPlace - calculate observed place (without PM etc) for given date @550nm
* @param tval (i) - time
* @param p2000 (i) - polar coordinates for J2000 (only ra/dec used), ICRS (catalog)
* @param weath (i) - weather data (relhum, temp, press) or NULL if none
* @param pnow (o) - polar coordinates for given epoch (or NULL)
* @param hnow (o) - horizontal coordinates for given epoch (or NULL)
* @return 0 if all OK
*/
int get_ObsPlace(struct timeval *tval, polarCrds *p2000, polarCrds *pnow, horizCrds *hnow){
int get_ObsPlace(struct timeval *tval, polarCrds *p2000, localWeather *weath, polarCrds *pnow, horizCrds *hnow){
double pr = 0.0; // RA proper motion (radians/year; Note 2)
double pd = 0.0; // Dec proper motion (radians/year)
double px = 0.0; // parallax (arcsec)
@ -126,28 +243,26 @@ int get_ObsPlace(struct timeval *tval, polarCrds *p2000, polarCrds *pnow, horizC
sMJD MJD;
if(get_MJDt(tval, &MJD)) return -1;
if(!p2000) return -1;
placeData p;
placeWeather w;
almDut d;
if(getPlace(&p)) return -1;
if(getWeath(&w)) return -1;
if(getDUT(&d)) return -1;
/* Effective wavelength (microns) */
double wl = 0.55;
/* ICRS to observed. */
double aob, zob, hob, dob, rob, eo;
/*
DBG("iauAtco13(%g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g)",
p2000->ra, p2000->dec, pr, pd, px, rv, MJD.utc1, MJD.utc2, d.DUT1, p.slong, p.slat, p.salt,
d.px, d.py, w.php, w.tc, w.relhum, wl);
*/
double p = 0., t = 0., h = 0.;
if(weath){
p = weath->pres; t = weath->tc; h = weath->relhum;
}
/*
DBG("iauAtco13(%g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g)",
p2000->ra, p2000->dec, pr, pd, px, rv, MJD.utc1, MJD.utc2, d.DUT1, p.slong, p.slat, p.salt,
d.px, d.py, p, t, h, wl);
*/
if(iauAtco13(p2000->ra, p2000->dec,
pr, pd, px, rv,
MJD.utc1, MJD.utc2,
d.DUT1,
p.slong, p.slat, p.salt,
d.px, d.py,
w.php, w.tc, w.relhum,
dut1.DUT1,
place.slong, place.slat, place.salt,
dut1.px, dut1.py,
p, t, h,
wl,
&aob, &zob,
&hob, &dob, &rob, &eo)) return -1;

View File

@ -56,10 +56,14 @@ typedef struct{
// place weather data
typedef struct{
double relhum; // rel. humidity, 0..1
double php; // atm. pressure (hectopascales)
double relhum; // rel. humidity, 0..100%
double pres; // atm. pressure (mmHg)
double tc; // temperature, degrC
} placeWeather;
double rain; // rain value (0..1)
double clouds; // clouds (0 - bad, >2500 - good)
double wind; // wind speed, m/s
double time; // measurements time
} localWeather;
// DUT/polar almanach data
typedef struct{
@ -68,9 +72,15 @@ typedef struct{
double py;
} almDut;
void r2sHMS(double radians, char *hms, int len);
void r2sDMS(double radians, char *hms, int len);
void hor2eq(horizCrds *h, polarCrds *pc, double sidTime);
void eq2horH(polarCrds *pc, horizCrds *h);
void eq2hor(polarCrds *pc, horizCrds *h, double sidTime);
int get_MJDt(struct timeval *tval, sMJD *MJD);
int get_ObsPlace(struct timeval *tval, polarCrds *p2000, polarCrds *pnow, horizCrds *hnow);
int getDUT(almDut *a);
int getWeath(placeWeather *w);
int getPlace(placeData *p);
int get_LST(sMJD *mjd, double dUT1, double slong, double *LST);
int get_ObsPlace(struct timeval *tval, polarCrds *p2000, localWeather *weath, polarCrds *pnow, horizCrds *hnow);
almDut *getDUT();
localWeather *getWeath();
placeData *getPlace();
#endif // LIBSOFA_H__

View File

@ -34,6 +34,7 @@
#include "emulation.h"
#include "libsofa.h"
#include "main.h"
#include "socket.h"
#include "telescope.h"
// daemon.c
@ -45,9 +46,6 @@ extern void check4running(char *self, char *pidfilename, void (*iffound)(pid_t p
// pause for incoming message waiting (out coordinates sent after that timeout)
#define SOCK_TMOUT (1)
// global parameters
static glob_pars *GP = NULL;
static pid_t childpid = 1; // PID of child process
volatile int global_quit = 0;
// quit by signal
@ -56,12 +54,13 @@ void signals(int sig){
if(childpid){ // parent process
restore_tty(); // restore all parameters
unlink(GP->pidfile); // and remove pidfile
}
weatherserver_disconnect();
}
DBG("Get signal %d, quit.\n", sig);
global_quit = 1;
sleep(1);
if(childpid) putlog("PID %d exit with status %d after child's %d death", getpid(), sig, childpid);
else WARNX("Child %d died with %d", getpid(), sig);
sleep(1);
exit(sig);
}
@ -228,30 +227,33 @@ int proc_data(uint8_t *data, ssize_t len){
double tagRA = RA2HRS(ra), tagDec = DEC2DEG(dec);
DBG("RA: %u (%g), DEC: %d (%g)", ra, tagRA, dec, tagDec);
// check RA/DEC
horizCrds h;
polarCrds p;
p.ra = tagRA/12. * M_PI;
p.dec = tagDec * DD2R;
if(get_ObsPlace(NULL, &p, NULL, &h)){
WARNX("Can't convert coordinates to horiz");
horizCrds hnow; // without refraction
polarCrds p2000, pnow;
p2000.ra = tagRA/12. * M_PI;
p2000.dec = tagDec * DD2R;
// now J2000 obs Jnow
if(get_ObsPlace(NULL, &p2000, NULL, &pnow, &hnow)){
WARNX("Can't convert coordinates to Jnow");
return 0;
}
#ifdef EBUG
int i[4], j[4]; char pm, pm1;
iauA2af(2, h.az, &pm, i);
iauA2af(2, h.zd, &pm1, j);
iauA2af(2, hnow.az, &pm, i);
iauA2af(2, hnow.zd, &pm1, j);
DBG("az: %c%02d %02d %02d.%2.d, zd: %c%02d %02d %02d.%2.d",
pm, i[0],i[1],i[2],i[3],
pm1,j[0],j[1],j[2],j[3]);
iauA2af(2, M_PI_2 - h.zd, &pm, i);
iauA2af(2, M_PI_2 - hnow.zd, &pm, i);
DBG("h: %c%02d %02d %02d.%2.d", pm, i[0],i[1],i[2],i[3]);
#endif
if(h.zd > 80.*DD2R){
if(hnow.zd > 80.*DD2R){
WARNX("Z > 80degr, stop telescope");
putlog("Z>80 - stop!");
stop_telescope();
return 0;
}
tagRA = (pnow.ra - pnow.eo) / M_PI * 12.;
tagDec = pnow.dec / DD2R;
if(!setCoords(tagRA, tagDec)) return 0;
return 1;
}
@ -318,7 +320,7 @@ static void *hdrthread(_U_ void *buf){
// write FITS-header at most once per second
while(!global_quit){
wrhdr();
usleep(1000); // give a chance to write/read for others
usleep(100000); // give a chance to write/read for others
}
return NULL;
}
@ -446,6 +448,10 @@ static inline void main_proc(){
if(pthread_create(&termthrd, NULL, termthread, NULL))
ERR(_("Can't create terminal thread"));
}
// connect to weather daemon
if(!weatherserver_connect()){
DBG("Can't connect to weather server, will try later");
}
// open socket
int sock = opensocket(GP->port);
if(sock < 0){
@ -488,6 +494,7 @@ int main(int argc, char **argv){
if(GP->logfile) openlogfile(GP->logfile);
putlog("Starting, master PID=%d", getpid());
#ifndef EBUG
while(1){
childpid = fork();
if(childpid < 0){
@ -506,6 +513,9 @@ int main(int argc, char **argv){
return 0;
}
}
#else
main_proc();
#endif
return 0;
}

View File

@ -34,7 +34,7 @@
#include <unistd.h>
#include "cmdlnopts.h"
#include "usefull_macros.h"
#include "usefull_macro.h"
// global parameters
extern glob_pars *Global_parameters;

View File

@ -29,7 +29,7 @@
#include <libintl.h>// gettext
#include <ctype.h> // isalpha
#include "parseargs.h"
#include "usefull_macros.h"
#include "usefull_macro.h"
char *helpstring = "%s\n";

View File

@ -0,0 +1,208 @@
/*
* This file is part of the StelD project.
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "cmdlnopts.h"
#include "socket.h"
#include "usefull_macro.h"
// max time to wait answer from server
#define WAITANSTIME (1.0)
static int sockfd = -1; // server file descriptor
static pthread_t sock_thread;
static char buf[BUFSIZ]; // buffer for messages
static int Nread; // amount of bytes in buf
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static void *getmessages(_U_ void *par);
/**
* @brief weatherserver_connect - connect to a weather server
* @return FALSE if failed
*/
int weatherserver_connect(){
if(sockfd > 0) return TRUE;
DBG("connect to %s:%d", GP->weathserver, GP->weathport);
char port[10];
snprintf(port, 10, "%d", GP->weathport);
struct addrinfo hints = {0}, *res, *p;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if(getaddrinfo(GP->weathserver, port, &hints, &res) != 0){
WARN("getaddrinfo()");
return FALSE;
}
// loop through all the results and connect to the first we can
for(p = res; p; p = p->ai_next){
if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
WARN("socket");
continue;
}
if(connect(sockfd, p->ai_addr, p->ai_addrlen) == -1){
WARN("connect()");
close(sockfd);
continue;
}
break; // if we get here, we have a successfull connection
}
if(!p){
WARNX("Can't connect to socket");
sockfd = -1;
return FALSE;
}
freeaddrinfo(res);
if(pthread_create(&sock_thread, NULL, getmessages, NULL)){
WARN("pthread_create()");
weatherserver_disconnect();
return FALSE;
}
DBG("connected, fd=%d", sockfd);
return TRUE;
}
void weatherserver_disconnect(){
if(sockfd > -1){
pthread_kill(sock_thread, 9);
pthread_join(sock_thread, NULL);
close(sockfd);
}
sockfd = -1;
}
/**
* @brief getparval - return value of parameter
* @param par (i) - parameter value
* @param ansbuf (i) - buffer with server answer
* @param val (o) - value of parameter
* @return TRUE if parameter found and set `val` to its value
*/
int getparval(const char *par, const char *ansbuf, double *val){
if(!par || !ansbuf) return FALSE;
int ret = FALSE;
char *b = strdup(ansbuf);
char *parval = NULL, *token = strtok(b, "\n");
int l = strlen(par);
if(!token) goto rtn;
while(token){
if(strncmp(token, par, l) == 0){ // found
//DBG("token: '%s'", token);
parval = strchr(token, '=');
if(!parval) goto rtn;
++parval; while(*parval == ' ' || *parval == '\t') ++parval;
//DBG("parval: '%s'", parval);
ret = TRUE;
break;
}
token = strtok(NULL, "\n");
}
if(parval && val){
*val = atof(parval);
//DBG("Set %s to %g", par, *val);
}
rtn:
FREE(b);
return ret;
}
/**
* wait for answer from socket
* @return FALSE in case of error or timeout, TRUE if socket is ready
*/
static int canread(){
if(sockfd < 0) return FALSE;
fd_set fds;
struct timeval timeout;
int rc;
// wait not more than 10ms
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
FD_ZERO(&fds);
FD_SET(sockfd, &fds);
do{
rc = select(sockfd+1, &fds, NULL, NULL, &timeout);
if(rc < 0){
if(errno != EINTR){
WARN("select()");
return FALSE;
}
continue;
}
break;
}while(1);
if(FD_ISSET(sockfd, &fds)) return TRUE;
return FALSE;
}
/**
* @brief getmessages - continuosly read data from server and fill buffer
*/
static void *getmessages(_U_ void *par){
write(sockfd, "get\n", 4);
while(sockfd > 0){
pthread_mutex_lock(&mutex);
if(Nread == 0){
double t0 = dtime();
while(dtime() - t0 < WAITANSTIME && Nread < BUFSIZ){
if(!canread()) continue;
int n = read(sockfd, buf+Nread, BUFSIZ-Nread);
if(n == 0) break;
if(n < 0){
close(sockfd);
sockfd = -1;
return NULL;
}
Nread += n;
}
if(Nread){
buf[Nread] = 0;
//DBG("got %d: %s", Nread, buf);
}
}
pthread_mutex_unlock(&mutex);
if(Nread == 0){
sleep(1);
}
}
return NULL;
}
/**
* @brief getweathbuffer - read whole buffer with data and set Nread to zero
* @return NULL if no data or buffer (allocated here)
*/
char *getweathbuffer(){
if(!weatherserver_connect()) return NULL; // not connected & can't connect
char *ret = NULL;
pthread_mutex_lock(&mutex);
if(Nread){
ret = strdup(buf);
Nread = 0;
}
pthread_mutex_unlock(&mutex);
return ret;
}

View File

@ -0,0 +1,28 @@
/*
* This file is part of the StelD project.
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef SOCKET_H__
#define SOCKET_H__
void weatherserver_disconnect();
int weatherserver_connect();
int getparval(const char *par, const char *ansbuf, double *val);
char *getweathbuffer();
#endif // SOCKET_H__

View File

@ -28,7 +28,7 @@
#include "libsofa.h"
#include "main.h" // global_quit
#include "telescope.h"
#include "usefull_macros.h"
#include "usefull_macro.h"
// polling timeout for answer from mount
#ifndef T_POLLING_TMOUT
@ -45,6 +45,12 @@ static char *hdname = NULL;
static double ptRAdeg, ptDECdeg; // target RA/DEC J2000
static int Target = 0; // target coordinates entered
static double r = 0., d = 0.; // RA/DEC from wrhdr
static int mountstatus = 0; // return of :Gstat#
static time_t tlast = 0; // last time coordinates were refreshed
static int pause_communication = 0; // ==1 to prevent writing to port outside of terminal thread
/**
* read strings from terminal (ending with '\n') with timeout
* @return NULL if nothing was read or pointer to static buffer
@ -96,7 +102,7 @@ static char *write_cmd(const char *cmd, char *buff){
char *ans;
while(dtime() - t0 < T_POLLING_TMOUT){ // read answer
if((ans = read_string())){ // parse new data
// DBG("got answer: %s", ans);
//DBG("got answer: %s", ans);
pthread_mutex_unlock(&mutex);
if(!buff) return NULL;
strncpy(buff, ans, BUFLEN-1);
@ -108,22 +114,24 @@ static char *write_cmd(const char *cmd, char *buff){
}
// write to telescope mount corrections: datetime, pressure and temperature
// @return 1 if time was corrected
// @return 1 if time and weather was corrected
static int makecorr(){
int ret = 0;
if(pause_communication) return 0;
int ret = 1;
// write current date&time
char buf[64], ibuff[BUFLEN], *ans;
DBG("curtime: %s", write_cmd(":GUDT#", ibuff));
ans = write_cmd(":Gstat#", ibuff);
if(ans){
mountstatus = atoi(ans);
// if system is in tracking or unknown state - don't update data!
if(mountstatus == TEL_SLEWING || mountstatus == TEL_TRACKING) return 0;
}
/*
* there's no GPS on this mount and there's no need for it!
write_cmd(":gT#", NULL); // correct time by GPS
ans = write_cmd(":gtg#", ibuff);
*/
if(!ans || *ans == '0'){ // system is in tracking or unknown state - don't update data!
return 0;
}
WARNX("Refresh datetime");
time_t t = time(NULL);
struct tm *stm = localtime(&t);
@ -136,27 +144,33 @@ static int makecorr(){
if(!ans || *ans != '1'){
WARNX("Can't write current date/time");
putlog("Can't set system time");
ret = 0;
}else{
putlog("Set system time by command %s", buf);
ret = 1;
}
DBG("curtime: %s", write_cmd(":GUDT#", ibuff));
sprintf(buf, ":SREF0#"); // turn off 2-coord guiding & refraction
write_cmd(buf, ibuff);
sprintf(buf, ":Sdat0#"); // turn off dual-axis tracking
write_cmd(buf, ibuff);
/*placeWeather w;
if(getWeath(&w)) putlog("Can't determine weather data");
else{ // set refraction model data
snprintf(buf, 64, ":SRPRS%.1f#", w.php);
localWeather *w = getWeath();
if(!w){
ret = 0;
putlog("Can't determine weather data");
}else{ // set refraction model data
snprintf(buf, 64, ":SRPRS%.1f#", w->pres*1013./760.);
ans = write_cmd(buf, ibuff);
if(!ans || *ans != '1') putlog("Can't set pressure data of refraction model");
else putlog("Correct pressure to %g", w.php);
snprintf(buf, 64, ":SRTMP%.1f#", w.tc);
if(!ans || *ans != '1'){
ret = 0;
putlog("Can't set pressure data of refraction model");
}else putlog("Correct pressure to %gmmHg", w->pres);
snprintf(buf, 64, ":SRTMP%.1f#", w->tc);
ans = write_cmd(buf, ibuff);
if(!ans || *ans != '1') putlog("Can't set temperature data of refraction model");
else putlog("Correct temperature to %g", w.tc);
}*/
if(!ans || *ans != '1'){
ret = 0;
putlog("Can't set temperature data of refraction model");
}else putlog("Correct temperature to %g", w->tc);
}
sprintf(buf, ":SREF1#"); // turn on refraction correction
write_cmd(buf, ibuff);
sprintf(buf, ":Sdat1#"); // turn on dual-axis tracking
write_cmd(buf, ibuff);
return ret;
}
@ -201,7 +215,8 @@ int connect_telescope(char *dev, char *hdrname){
hdname = strdup(hdrname);
DBG("connected");
Target = 0;
write_cmd(":gT#", NULL); // correct time by GPS
getWeath(); getPlace(); getDUT(); // determine starting values
//write_cmd(":gT#", NULL); // correct time by GPS
return 1;
}
@ -212,11 +227,15 @@ int connect_telescope(char *dev, char *hdrname){
*/
/**
* send coordinates to telescope
* @param ra - right ascention (hours)
* @param dec - declination (degrees)
* @param ra - right ascention (hours), Jnow without refraction
* @param dec - declination (degrees), Jnow without refraction
* @return 1 if all OK
*/
int point_telescope(double ra, double dec){
if(pause_communication){
putlog("Can't point telescope in paused mode");
return 0;
}
DBG("try to send ra=%g, decl=%g", ra, dec);
ptRAdeg = ra * 15.;
ptDECdeg = dec;
@ -322,10 +341,6 @@ static int printhdr(int fd, const char *key, const char *val, const char *cmnt){
return 0;
}
static double r = 0., d = 0.; // RA/DEC from wrhdr
static int mountstatus = 0; // return of :Gstat#
static time_t tlast = 0; // last time coordinates were refreshed
/**
* get coordinates
* @param ra (o) - right ascension (hours)
@ -340,11 +355,15 @@ int get_telescope_coords(double *ra, double *decl){
return mountstatus;
}
void stop_telescope(){
void stop_telescope(){ // work even in paused mode if moving!
Target = 0;
if(pause_communication){
if(mountstatus == TEL_PARKED || mountstatus == TEL_STOPPED || mountstatus == TEL_INHIBITED
|| mountstatus == TEL_OUTLIMIT) return;
}
write_cmd(":RT9#", NULL); // stop tracking
write_cmd(":AL#", NULL); // stop tracking
write_cmd(":STOP#", NULL); // halt moving
Target = 0;
}
// site characteristics
@ -391,18 +410,18 @@ static void getplace(){
}
static const char *statuses[12] = {
[0] = "'Tracking'",
[1] = "'Stopped or homing'",
[2] = "'Slewing to park'",
[3] = "'Unparking'",
[4] = "'Slewing to home'",
[5] = "'Parked'",
[6] = "'Slewing or going to stop'",
[7] = "'Stopped'",
[8] = "'Motors inhibited, T too low'",
[9] = "'Outside tracking limit'",
[10]= "'Following satellite'",
[11]= "'Data inconsistency'"
[TEL_TRACKING] = "'Tracking'",
[TEL_STOPHOM] = "'Stopped or homing'",
[TEL_PARKING] = "'Slewing to park'",
[TEL_UNPARKING] = "'Unparking'",
[TEL_HOMING] = "'Slewing to home'",
[TEL_PARKED] = "'Parked'",
[TEL_SLEWING] = "'Slewing or going to stop'",
[TEL_STOPPED] = "'Stopped'",
[TEL_INHIBITED] = "'Motors inhibited, T too low'",
[TEL_OUTLIMIT] = "'Outside tracking limit'",
[TEL_FOLSAT]= "'Following satellite'",
[TEL_DATINCOSIST]= "'Data inconsistency'"
};
/**
@ -412,7 +431,7 @@ static const char *statuses[12] = {
*/
static const char* strstatus(int status){
if(status < 0) return "'Signal lost'";
if(status < (int)(sizeof(statuses)/sizeof(char*)-1)) return statuses[status];
if(status < TEL_MAXSTATUS) return statuses[status];
if(status == 99) return "'Error'";
return "'Unknown status'";
}
@ -421,9 +440,21 @@ static const char* strstatus(int status){
* @brief wrhdr - try to write into header file
*/
void wrhdr(){
static time_t commWasPaused = 0;
if(pause_communication){ // don't allow pauses more for 15 minutes!
if(commWasPaused == 0){
commWasPaused = time(NULL);
return;
}else{
if(time(NULL) - commWasPaused > 15*60){
putlog("Clear communication pause after 15 minutes");
pause_communication = 0;
}else return;
}
}
static int failcounter = 0;
static time_t lastcorr = 0; // last time of corrections made
if(time(NULL) - lastcorr > CORRECTIONS_TIMEDIFF){
if(time(NULL) - lastcorr > CORRECTIONS_TIMEDIFF){ // make correction once per hour
if(makecorr()) lastcorr = time(NULL);
else lastcorr += 30; // failed -> check 30s later
}
@ -437,6 +468,7 @@ void wrhdr(){
DBG("Can't get RA!");
signals(9);
}
DBG("Failed");
return;
}
ans = write_cmd(":GD#", ibuff);
@ -446,8 +478,43 @@ void wrhdr(){
DBG("Can't get DEC!");
signals(9);
}
DBG("Failed");
return;
}
almDut *dut = getDUT();
localWeather *weather = getWeath();
double LST = 0; // local sidereal time IN RADIANS!
placeData *place = getPlace();
if(get_LST(NULL, dut->DUT1, place->slong, &LST)){
DBG("Can't calculate coordinates, get from mount");
ans = write_cmd(":GS#", ibuff);
lst = dups(ans, 1);
if(!str2coord(ans, &LST)){
if(++failcounter == 10){
putlog("Lost connection with mount");
DBG("Can't get LST!");
signals(9);
}
DBG("Failed");
return;
}
LST *= 15.*DD2R; // convert hours to radians
}else{
lst = MALLOC(char, 32);
r2sHMS(LST, lst, 32);
}
sMJD mjd;
if(get_MJDt(NULL, &mjd)){
ans = write_cmd(":GJD1#", ibuff);
jd = dups(ans, 0);
}else{
jd = MALLOC(char, 32);
snprintf(jd, 32, "%.10f", mjd.MJD);
}
polarCrds pNow = {.ra = r*15.*DD2R, .dec = d*DD2R}; // coordinates now
horizCrds hNow;
eq2hor(&pNow, &hNow, LST);
failcounter = 0;
tlast = time(NULL);
// check it here, not in the beginning of function - to check connection with mount first
@ -456,8 +523,6 @@ void wrhdr(){
return;
}
if(!elevation || !longitude || !latitude) getplace();
ans = write_cmd(":GJD1#", ibuff); jd = dups(ans, 0);
ans = write_cmd(":GS#", ibuff); lst = dups(ans, 1);
ans = write_cmd(":GUDT#", ibuff);
if(ans){
char *comma = strchr(ans, ',');
@ -487,7 +552,13 @@ void wrhdr(){
#define WRHDR(k, v, c) do{if(printhdr(fd, k, v, c)){goto returning;}}while(0)
WRHDR("TIMESYS", "'UTC'", "Time system");
WRHDR("ORIGIN", "'SAO RAS'", "Organization responsible for the data");
WRHDR("TELESCOP", "'Astrosib-500'", "Telescope name");
WRHDR("TELESCOP", TELESCOPE_NAME, "Telescope name");
snprintf(val, 22, "%.10f", dut->px);
WRHDR("POLARX", val, "IERS pole X coordinate, arcsec");
snprintf(val, 22, "%.10f", dut->py);
WRHDR("POLARY", val, "IERS pole Y coordinate, arcsec");
snprintf(val, 22, "%.10f", dut->py);
WRHDR("DUT1", val, "IERS `UT1-UTC`, sec");
if(Target){ // target coordinates entered - store them @header
snprintf(val, 22, "%.10f", ptRAdeg);
WRHDR("TAGRA", val, "Target RA (J2000), degrees");
@ -495,24 +566,47 @@ void wrhdr(){
WRHDR("TAGDEC", val, "Target DEC (J2000), degrees");
}
snprintf(val, 22, "%.10f", r*15.); // convert RA to degrees
WRHDR("RA", val, "Telescope right ascension, current epoch");
WRHDR("RA", val, "Telescope right ascension, current epoch, deg");
snprintf(val, 22, "%.10f", d);
WRHDR("DEC", val, "Telescope declination, current epoch");
WRHDR("DEC", val, "Telescope declination, current epoch, deg");
snprintf(val, 22, "%.10f", hNow.az * DR2D);
WRHDR("AZ", val, "Telescope azimuth, current epoch, deg");
snprintf(val, 22, "%.10f", hNow.zd * DR2D);
WRHDR("ZD", val, "Telescope zenith distance, current epoch, deg");
WRHDR("TELSTAT", strstatus(mountstatus), "Telescope mount status");
sMJD mjd;
if(!get_MJDt(NULL, &mjd)){
snprintf(val, 22, "%.10f", 2000.+(mjd.MJD-MJD2000)/365.25); // calculate EPOCH/EQUINOX
WRHDR("EQUINOX", val, "Equinox of celestial coordinate system");
snprintf(val, 22, "%.10f", mjd.MJD);
WRHDR("MJD-END", val, "Modified julian date of observations end");
snprintf(val, 22, "%.10f", 2000.+(mjd.MJD-MJD2000)/365.25); // calculate EPOCH/EQUINOX
WRHDR("EQUINOX", val, "Equinox of celestial coordinate system");
if(!jd){
snprintf(val, 22, "%.10f", mjd.MJD);
WRHDR("MJD-END", val, "Modified julian date of observations end");
}
}
if(jd){
WRHDR("MJD-END", jd, "Modified julian date of observations end");
}
if(jd) WRHDR("JD-END", jd, "Julian date of observations end");
if(pS) WRHDR("PIERSIDE", pS, "Pier side of telescope mount");
if(elevation) WRHDR("ELEVAT", elevation, "Elevation of site over the sea level");
if(longitude) WRHDR("LONGITUD", longitude, "Geo longitude of site (east negative)");
if(latitude) WRHDR("LATITUDE", latitude, "Geo latitude of site (south negative)");
if(lst) WRHDR("LSTEND", lst, "Local sidereal time of observations end");
if(date) WRHDR("DATE-END", date, "Date (UTC) of observations end");
if(weather){
snprintf(val, 22, "%.1f", weather->relhum);
WRHDR("HUMIDITY", val, "Relative humidity, %%");
snprintf(val, 22, "%.1f", weather->pres);
WRHDR("PRESSURE", val, "Atmospheric pressure, mmHg");
snprintf(val, 22, "%.1f", weather->tc);
WRHDR("EXTTEMP", val, "External temperature, degrC");
snprintf(val, 22, "%.0f", weather->rain);
WRHDR("RAIN", val, "Rain conditions");
snprintf(val, 22, "%.1f", weather->clouds);
WRHDR("SKYQUAL", val, "Sky quality (0 - wery bad, >2500 - good)");
snprintf(val, 22, "%.1f", weather->wind);
WRHDR("WINDSPD", val, "Wind speed (m/s)");
snprintf(val, 22, "%.0f", weather->time);
WRHDR("WEATTIME", val, "Unix time of weather measurements");
}
// WRHDR("", , "");
#undef WRHDR
returning:
@ -543,9 +637,22 @@ void *term_thread(void *sockd){
char *ch = strchr(buff, '\n');
if(ch) *ch = 0;
if(!buff[0]) continue; // empty string
DBG("%s COMMAND: %s", peerIP, buff);
if(strcasecmp(buff, "pause") == 0){
DBG("PAUSED");
putlog("Port writing outside terminal thread is paused");
pause_communication = 1;
continue;
}
if(strcasecmp(buff, "continue") == 0){
DBG("CONTINUED");
putlog("Port writing outside terminal thread is restored by user");
pause_communication = 0;
continue;
}
char *ans = write_cmd(buff, ibuff);
putlog("%s COMMAND %s ANSWER %s", peerIP, buff, ibuff);
DBG("%s COMMAND: %s ANSWER: %s", peerIP, buff, ibuff);
DBG("ANSWER: %s", ibuff);
if(ans){
ssize_t l = (ssize_t)strlen(ans);
if(l++){

View File

@ -29,6 +29,25 @@
// make datetime/pressure/temperature corrections each CORRECTIONS_TIMEDIFF seconds
#define CORRECTIONS_TIMEDIFF (3600)
#define TELESCOPE_NAME "'Astrosib-500 (1)'"
// telescope statuses
typedef enum{
TEL_TRACKING = 0,
TEL_STOPHOM = 1,
TEL_PARKING = 2,
TEL_UNPARKING = 3,
TEL_HOMING = 4,
TEL_PARKED = 5,
TEL_SLEWING = 6,
TEL_STOPPED = 7,
TEL_INHIBITED = 8,
TEL_OUTLIMIT = 9,
TEL_FOLSAT = 10,
TEL_DATINCOSIST = 11,
TEL_MAXSTATUS = 12 // number of statuses
} tel_status;
int connect_telescope(char *dev, char *hdrname);
int point_telescope(double ra, double decl);
int get_telescope_coords(double *ra, double *decl);

View File

@ -19,8 +19,9 @@
* MA 02110-1301, USA.
*/
#include "usefull_macros.h"
#include "usefull_macro.h"
#include <linux/limits.h> // PATH_MAX
#include <pthread.h>
/**
* function for different purposes that need to know time intervals
@ -393,49 +394,52 @@ int str2double(double *num, const char *str){
return TRUE;
}
static FILE *Flog = NULL; // log file descriptor
static char *logname = NULL;
// static time_t log_open_time = 0;
/**
* Try to open log file
* if failed show warning message
*/
void openlogfile(char *name){
if(!name){
WARNX(_("Need filename for log file"));
return;
}
green(_("Try to open log file %s in append mode\n"), name);
fflush(stdout);
if(!(Flog = fopen(name, "a"))){
WARN(_("Can't open log file"));
return;
}
// log_open_time = time(NULL);
logname = name;
}
static pthread_mutex_t logmutex;
/**
* Save message to log file, rotate logs every 24 hours
* @brief openlogfile - create log file: init mutex, test file open ability
* @param log - log structure
* @return 0 if all OK
*/
int openlogfile(char *name){
FREE(logname);
pthread_mutex_destroy(&logmutex);
FILE *logfd = fopen(name, "a");
if(!logfd){
WARN("Can't open log file");
return 2;
}
fclose(logfd);
if(pthread_mutex_init(&logmutex, NULL)){
WARN("Can't init log mutes");
return 3;
}
logname = strdup(name);
return 0;
}
int putlog(const char *fmt, ...){
if(!Flog) return 0;
time_t t_now = time(NULL);
/*if(t_now - log_open_time > 86400){ // rotate log
fprintf(Flog, "\n\t\t%sRotate log\n", ctime(&t_now));
fclose(Flog);
char newname[PATH_MAX];
snprintf(newname, PATH_MAX, "%s.old", logname);
if(rename(logname, newname)) WARN("rename()");
openlogfile(logname);
if(!Flog) return 0;
}*/
int i = fprintf(Flog, "\n\t\t%s", ctime(&t_now));
if(!logname) return 0;
if(pthread_mutex_lock(&logmutex)){
WARN("Can't lock log mutex");
return 0;
}
int i = 0;
FILE *logfd = fopen(logname, "a");
if(!logfd) goto rtn;
char strtm[128];
time_t t = time(NULL);
struct tm *curtm = localtime(&t);
strftime(strtm, 128, "%Y/%m/%d-%H:%M:%S", curtm);
i = fprintf(logfd, "%s\t", strtm);
va_list ar;
va_start(ar, fmt);
i = vfprintf(Flog, fmt, ar);
i += vfprintf(logfd, fmt, ar);
va_end(ar);
fprintf(Flog, "\n");
fflush(Flog);
i += fprintf(logfd, "\n");
fclose(logfd);
rtn:
pthread_mutex_unlock(&logmutex);
return i;
}

View File

@ -138,7 +138,7 @@ int write_tty(const char *buff, size_t length);
int str2double(double *num, const char *str);
void openlogfile(char *name);
int openlogfile(char *name);
int putlog(const char *fmt, ...);
#endif // __USEFULL_MACROS_H__