From 8e796ce419c9c15fc0eb47f3ffb1be1ed5df5afe Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Thu, 24 Sep 2026 17:51:41 +0300 Subject: [PATCH] telescope is moving; need to add some more commands & write FITS-header --- .../10micron_stellarium/10micron_commands.h | 43 +++ Daemons/10micron_stellarium/angles.c | 74 +++- Daemons/10micron_stellarium/angles.h | 7 +- Daemons/10micron_stellarium/args.c | 40 ++- Daemons/10micron_stellarium/args.h | 2 +- Daemons/10micron_stellarium/emulation.c | 56 +-- Daemons/10micron_stellarium/main.c | 44 ++- Daemons/10micron_stellarium/mount.c | 331 ++++++++++++++---- Daemons/10micron_stellarium/mount.h | 11 +- .../mountdaemon_10micron.creator.user | 34 +- .../mountdaemon_10micron.files | 1 + Daemons/10micron_stellarium/server.c | 88 +++-- Daemons/10micron_stellarium/server.h | 5 + 13 files changed, 553 insertions(+), 183 deletions(-) create mode 100644 Daemons/10micron_stellarium/10micron_commands.h diff --git a/Daemons/10micron_stellarium/10micron_commands.h b/Daemons/10micron_stellarium/10micron_commands.h new file mode 100644 index 0000000..1d00641 --- /dev/null +++ b/Daemons/10micron_stellarium/10micron_commands.h @@ -0,0 +1,43 @@ +/* + * This file is part of the mountdaemon_10micron project. + * Copyright 2026 Edward V. Emelianov . + * + * 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 . + */ + +#pragma once + +// commands +#define CMD_SHUTDOWN ":shutdown#" // TODO! +#define CMD_TRKSTART ":AP#" +#define CMD_TRKSTOP ":AL#" +#define CMD_GOTOAZ ":MA#" +#define CMD_SLEWRADEC ":MS#" +#define CMD_BAUDRATE ":SB0#" +#define CMD_STOP ":STOP#" +#define CMD_HIGHPREC ":U2#" + +// getters +#define CMD_GETALT ":GA#" +#define CMD_GETAZIM ":GZ#" +#define CMD_GETDEC ":GD#" +#define CMD_GETSTAT ":Gstat#" +#define CMD_GETRA ":GR#" + +// setters +#define CMD_SETALT ":Sa%s#" +#define CMD_SETDEC ":Sd%s#" +#define CMD_SETRA ":Sr%s#" +#define CMD_SETMINALT ":So%d#" +#define CMD_SETZD ":Sz%s#" diff --git a/Daemons/10micron_stellarium/angles.c b/Daemons/10micron_stellarium/angles.c index 145f321..44dc720 100644 --- a/Daemons/10micron_stellarium/angles.c +++ b/Daemons/10micron_stellarium/angles.c @@ -84,25 +84,37 @@ void getPlaceData(placeData_t *pd){ } /** - * convert RA/DEC to string in forman RA: HH:MM:SS.SS, DEC: DD:MM:SS.S + * @brief ra2str - convert RA to string form "HH:MM:SS.SS" + * @param ra - RA (hours) + * @param buf - output buffer + * @return pointer to buffer */ -char *radec2str(double ra, double dec, char buf[RADEC_STR_MAXLEN]){ +char *ra2str(double ra, char buf[RADEC_STR_MAXLEN]){ + int h = (int)ra; + ra -= h; ra *= 60.; + int m = (int)ra; + ra -= m; ra *= 60.; + snprintf(buf, RADEC_STR_MAXLEN, "%d:%d:%.2f", h,m,ra); + buf[RADEC_STR_MAXLEN-1] = 0; + return buf; +} +/** + * @brief dec2str - convert Dec to string form "DD:MM:SS.S" + * @param dec - Dec (degrees) + * @param buf - output buffer + * @return pointer to buffer + */ +char *dec2str(double dec, char buf[RADEC_STR_MAXLEN]){ char sign = '+'; if(dec < 0){ sign = '-'; dec = -dec; } - - int h = (int)ra; - ra -= h; ra *= 60.; - int m = (int)ra; - ra -= m; ra *= 60.; - int d = (int) dec; dec -= d; dec *= 60.; int dm = (int)dec; dec -= dm; dec *= 60.; - snprintf(buf, RADEC_STR_MAXLEN, "%d:%d:%.2f %c%d:%d:%.1f", h,m,ra, sign,d,dm,dec); + snprintf(buf, RADEC_STR_MAXLEN, "%c%d:%d:%.1f",sign,d,dm,dec); buf[RADEC_STR_MAXLEN-1] = 0; return buf; } @@ -156,8 +168,10 @@ void norm_RADEC(double *ra, double *dec){ void norm_RADECr(double *ra, double *dec){ if(!ra || !dec) return; + DBG("Ra: %g, Dec: %g", RAD2DEG(*ra), RAD2DEG(*dec)); if(*dec >= -ERFA_DPI/2. && *dec <= ERFA_DPI/2.){ // need only check RA *ra = eraAnp(*ra); + DBG("Ra become %g", RAD2DEG(*ra)); return; } // 1: convert to (-pi..+pi) @@ -170,6 +184,7 @@ void norm_RADECr(double *ra, double *dec){ *dec = -ERFA_DPI - *dec; *ra = eraAnp(*ra + ERFA_DPI); } + DBG("Ra become %g, dec become %g", RAD2DEG(*ra), RAD2DEG(*dec)); } // normalize angle to (-180, 180] @@ -249,6 +264,39 @@ void r2sDMS(double radians, char *dms, int len){ eraA2af(1, radians, &pm, i); snprintf(dms, len, "'%c%02d:%02d:%02d.%d'", pm, i[0],i[1],i[2],i[3]); } +// the same, but argument in degrees +void d2sDMS(double degrees, char *dms, int len){ + double radians = DEG2RAD(degrees); + return r2sDMS(radians, dms, len); +} + +/** + * convert str into coordinate (degrees/hours) + * @param str (i) - string with angle + * @param val (o) - output angle value + * @return true if all OK + */ +bool str2coord(const char *str, double *val){ + if(!str || !val) return false; + int d, m; + float s; + int sign = 1; + if(*str == '+') ++str; + else if(*str == '-'){ + sign = -1; + ++str; + } + int n = sscanf(str, "%d:%d:%f#", &d, &m, &s); + if(n != 3){ + DBG("sscanf('%s')=%d", str, 3); + return false; + } + double ang = d + ((double)m)/60. + s/3600.; + if(sign == -1) *val = -ang; + else *val = ang; + return true; +} + /** * @brief get_MJDt - calculate MJD of date from argument @@ -287,11 +335,11 @@ bool get_MJDt(struct timeval *tval, sMJD_t *MJD){ WARNX("get_MJDt(): eraDtf2d() error"); return false; } - DBG("y=%d, m=%d, d=%d, H=%d, M=%d, seconds=%g, UTC=%g", y, m, d, tms.tm_hour, tms.tm_min, tSeconds, utc1+utc2); + //DBG("y=%d, m=%d, d=%d, H=%d, M=%d, seconds=%g, UTC=%g", y, m, d, tms.tm_hour, tms.tm_min, tSeconds, utc1+utc2); MJD->MJD = (utc1 - ERFA_DJM0) + utc2; MJD->utc1 = utc1; MJD->utc2 = utc2; - DBG("MJD: %g, %.8f", utc1 - ERFA_DJM0, utc2); + //DBG("MJD: %g, %.8f", utc1 - ERFA_DJM0, utc2); if(eraUtctai(utc1, utc2, &MJD->tai1, &MJD->tai2)){ WARNX("get_MJDt(): eraUtctai() error"); return false; @@ -322,8 +370,8 @@ bool get_LST(sMJD_t *mjd, double *LST){ }else Mjd = *mjd; if(eraUtcut1(Mjd.utc1, Mjd.utc2, AlmDut.DUT1, &ut11, &ut12)) return false; double ST = eraGst06a(ut11, ut12, Mjd.tt1, Mjd.tt2); - DBG("ST0=%gh; longitude=%gh (%gdeg) STl=%gh", RAD2HRS(ST), - RAD2HRS(place.slong), RAD2DEG(place.slong), RAD2HRS(ST+place.slong)); + //DBG("ST0=%gh; longitude=%gh (%gdeg) STl=%gh", RAD2HRS(ST), + // RAD2HRS(place.slong), RAD2DEG(place.slong), RAD2HRS(ST+place.slong)); ST += place.slong; if(ST > ERFA_D2PI) ST -= ERFA_D2PI; else if(ST < 0.) ST += ERFA_D2PI; diff --git a/Daemons/10micron_stellarium/angles.h b/Daemons/10micron_stellarium/angles.h index e03cefb..3f33954 100644 --- a/Daemons/10micron_stellarium/angles.h +++ b/Daemons/10micron_stellarium/angles.h @@ -21,7 +21,7 @@ #include #include -#define RADEC_STR_MAXLEN 72 +#define RADEC_STR_MAXLEN 64 #define RAD2DEG(angle) ((angle) * ERFA_DR2D) #define DEG2RAD(angle) ((angle) * ERFA_DD2R) @@ -64,7 +64,9 @@ typedef struct{ double py; } almDut_t; -char *radec2str(double ra, double dec, char buf[RADEC_STR_MAXLEN]); +char *ra2str(double ra, char buf[RADEC_STR_MAXLEN]); +char *dec2str(double dec, char buf[RADEC_STR_MAXLEN]); +bool str2coord(const char *str, double *val); bool normAZ(double *a, double *z); void norm_RA(double *ra); void norm_RADEC(double *ra, double *dec); @@ -77,6 +79,7 @@ void eq2hor(polarCrds_t *pc, horizCrds_t *h, double sidTime); void r2sHMS(double radians, char *hms, int len); void r2sDMS(double radians, char *hms, int len); +void d2sDMS(double degrees, char *dms, int len); void hor2eq(horizCrds_t *h, polarCrds_t *pc, double sidTime); void eq2horH(polarCrds_t *pc, horizCrds_t *h); void eq2hor(polarCrds_t *pc, horizCrds_t *h, double sidTime); diff --git a/Daemons/10micron_stellarium/args.c b/Daemons/10micron_stellarium/args.c index 4e5529a..c5cb666 100644 --- a/Daemons/10micron_stellarium/args.c +++ b/Daemons/10micron_stellarium/args.c @@ -32,8 +32,8 @@ #define DEFAULT_FITSHDR "/tmp/10micron.fitsheader" // baudrate - 115200 #define DEFAULT_SERSPEED 115200 -// serial polling timeout - 100ms -#define DEFAULT_SERTMOUT 100000 +// serial answer polling timeout - 1s +#define DEFAULT_SERTMOUT 1.0 // mount name #define DEFAULT_MOUNT_NAME "10Micron GM4000HPS" @@ -59,10 +59,10 @@ static parameters_t Conf = {0}; {"cmdport", NEED_ARG, NULL, 'P', arg_string, APTR(&Stor.cmdnode), "port or UNIX-socket path to connect for command console (default: " DEFAULT_CMDNODE ")"}, \ {"sleept", NEED_ARG, NULL, 't', arg_int, APTR(&Stor.sleept), "time of servers' sleeping in main cycle, us (default: " STR(DEFAULT_SLEEP_T) " us)"}, \ {"isunix", NO_ARGS, NULL, 'U', arg_int, APTR(&Stor.isunix), "use UNIX-socket for cmdport"}, \ - {"sertmout",NEED_ARG, NULL, 'T', arg_int, APTR(&Stor.sertmout), "serial timeout, us (default: " STR(DEFAULT_SERTMOUT) " us)"}, \ + {"sertmout",NEED_ARG, NULL, 'T', arg_double, APTR(&Stor.sertmout), "serial timeout, seconds (default: " STR(DEFAULT_SERTMOUT) " s)"}, \ {"serspeed",NEED_ARG, NULL, 'S', arg_int, APTR(&Stor.serspeed), "serial speed (default: " STR(DEFAULT_SERSPEED) ")"}, \ - {"maxclients",NEED_ARG, NULL, 0, arg_int, APTR(&Stor.maxclients),"max amount of clients connected to one socket (default: " STR(DEFAULT_MAXCLIENTS) ")"}, \ - {"mountname",NEED_ARG, NULL, 0, arg_string, APTR(&Stor.mountname), "mount name (default: " DEFAULT_MOUNT_NAME ")"}, \ + {"maxclients",NEED_ARG, NULL, 0, arg_int, APTR(&Stor.maxclients),"max amount of clients connected to one socket (default: " STR(DEFAULT_MAXCLIENTS) ")"}, \ + {"mountname",NEED_ARG, NULL, 0, arg_string, APTR(&Stor.mountname), "mount name (default: " DEFAULT_MOUNT_NAME ")"}, \ {"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&Stor.verbose), "verbose level (each -v increases it)"}, \ @@ -105,20 +105,34 @@ static void chkint(int *conf, int *cmd, int dflt){ } } +static void chkdbl(double *conf, double *cmd, double dflt){ + if(!*conf){ + if(!*cmd) *cmd = dflt; + return; + } + if(!*cmd){ + DBG("Conf-only parameter %g", *conf); + *cmd = *conf; + } +} -#define STRCHK(field) chkstr(&Conf.field, &G.field, NULL) +#define STRCHK(field) chkstr(&Conf.field, &G.field, NULL) #define STRCHKD(field, def) chkstr(&Conf.field, &G.field, def) -#define INTCHK(field) chkint(&Conf.field, &G.field, 0) -#define INTCHKD(field, def) chkint(&Conf.field, &G.field, def) +#define INTCHK(field) chkint(&Conf.field, &G.field, 0) +#define INTCHKD(field, def) chkint(&Conf.field, &G.field, def) +#define DBLCHK(field) chkdbl(&Conf.field, &G.field, 0.) +#define DBLCHKD(field, def) chkdbl(&Conf.field, &G.field, def) parameters_t *parse_cmdline(int *argc, char ***argv){ sl_parseargs(argc, argv, cmdlnopts); if(help) sl_showhelp(-1, cmdlnopts); - if(!conffile) return &G; + //if(!conffile) return &G; // fix for conffile - if(!sl_conf_readopts(conffile, confopts)){ // show conf help - sl_conf_showhelp(-1, confopts); - return NULL; + if(conffile){ + if(!sl_conf_readopts(conffile, confopts)){ // show conf help + sl_conf_showhelp(-1, confopts); + return NULL; + } } // now fix for command line and check all: DBG("Check all args"); @@ -133,7 +147,7 @@ parameters_t *parse_cmdline(int *argc, char ***argv){ INTCHK(verbose); INTCHKD(sleept, DEFAULT_SLEEP_T); INTCHK(isunix); - INTCHKD(sertmout, DEFAULT_SERTMOUT); + DBLCHKD(sertmout, DEFAULT_SERTMOUT); INTCHKD(serspeed, DEFAULT_SERSPEED); INTCHKD(maxclients, DEFAULT_MAXCLIENTS); return &G; diff --git a/Daemons/10micron_stellarium/args.h b/Daemons/10micron_stellarium/args.h index 2f59a05..f52c9d7 100644 --- a/Daemons/10micron_stellarium/args.h +++ b/Daemons/10micron_stellarium/args.h @@ -30,9 +30,9 @@ typedef struct{ int verbose; // verbose level int sleept; // server's sleeping in main cycle time int isunix; // use UNIX-socket for command port - int sertmout; // serial timeout, us int serspeed; // serial speed, baud int maxclients; // max amount of clients connected to one socket + double sertmout; // serial timeout, s } parameters_t; parameters_t *parse_cmdline(int *argc, char ***argv); diff --git a/Daemons/10micron_stellarium/emulation.c b/Daemons/10micron_stellarium/emulation.c index c743374..af5934f 100644 --- a/Daemons/10micron_stellarium/emulation.c +++ b/Daemons/10micron_stellarium/emulation.c @@ -25,8 +25,9 @@ #include "angles.h" #include "emulation.h" -// emulation speed over any trajectory -#define SPEED (DEG2RAD(5.)) +// emulation speed over axis +#define RASPEED (DEG2RAD(5.)) +#define DECSPEED (DEG2RAD(8.)) // limiting Zen.d. #define ZD_LIMIT (DEG2RAD(80.)) // pointing tolerance: ~1'' @@ -108,11 +109,12 @@ static double angular_distance(const polarCrds_t *a, const polarCrds_t *b){ return acos(cd); } #endif -// distance by axis moving -static double axdist(const polarCrds_t *a, const polarCrds_t *b){ +// time to reach position b from position a +static double reacht(const polarCrds_t *a, const polarCrds_t *b){ // convert to [-pi, pi) - double dra = eraAnpm(b->ra - a->ra), ddec = eraAnpm(b->dec - a->dec); - return sqrt(dra*dra + ddec*ddec); + double tra = fabs(eraAnpm(b->ra - a->ra)) / RASPEED, tdec = fabs(eraAnpm(b->dec - a->dec)) / DECSPEED; + if(tra > tdec) return tra; + return tdec; } // calculate flip target (dec>90deg) @@ -142,47 +144,49 @@ void get_emul_coords(double *ra, double *decl){ } if(!flip_in_progress){ // check if we need to flip // distance for direct moving - double dist_direct = axdist(&CurRD, &TagRD); + double time_direct = reacht(&CurRD, &TagRD); // new point after flipping polarCrds_t flip_candidate; get_flip_target(&TagRD, &flip_candidate); // distance for moving with flip - double dist_flip = axdist(&CurRD, &flip_candidate); + double time_flip = reacht(&CurRD, &flip_candidate); - if(dist_flip < dist_direct){ + if(time_flip < time_direct){ // need to make flip: it's shorter flip_target = flip_candidate; flip_in_progress = true; - DBG("Flip chosen: direct=%.3fdeg, flip=%.3fdeg\n\n\n", RAD2DEG(dist_direct), RAD2DEG(dist_flip)); + DBG("Target: ra=%gdeg, dec=%gdeg; flip target: ra=%gdeg, dec=%gdec", RAD2DEG(TagRD.ra), RAD2DEG(TagRD.dec), RAD2DEG(flip_candidate.ra), RAD2DEG(flip_candidate.dec)); + DBG("Flip chosen: direct=%.3fsec, flip=%.3fsec\n\n\n", RAD2DEG(time_direct), RAD2DEG(time_flip)); }else{ flip_in_progress = false; - DBG("Move directly: direct=%.3fdeg, flip=%.3fdeg\n\n\n", RAD2DEG(dist_direct), RAD2DEG(dist_flip)); + DBG("Move directly: direct=%.3fsec, flip=%.3fsec\n\n\n", RAD2DEG(time_direct), RAD2DEG(time_flip)); } } // flip target is the same as TagRD, but with RA+=12h and dec > 90deg polarCrds_t *target = flip_in_progress ? &flip_target : &TagRD; // RA difference over target and last position: [-pi, pi) double dRA = eraAnpm(target->ra - CurRD.ra); - DBG("RA difference: %gdegr", RAD2DEG(dRA)); + DBG("RA difference: %gdegr (tag: %g, cur: %g)", RAD2DEG(dRA), RAD2DEG(target->ra), RAD2DEG(CurRD.ra)); double dDec = eraAnpm(target->dec - CurRD.dec); - DBG("DEC difference: %gdegr", RAD2DEG(dDec)); + DBG("DEC difference: %gdegr (tag: %g, cur: %g)", RAD2DEG(dDec), RAD2DEG(target->dec), RAD2DEG(CurRD.dec)); double dist = sqrt(dRA*dRA + dDec*dDec); - if(dist < POINTING_TOL){ // on position + double tra = fabs(dRA) / RASPEED, tdec = fabs(dDec) / DECSPEED; + double time_to_reach = (tra > tdec) ? tra : tdec; + double dt = tcur - tlast; + if(dist < POINTING_TOL || time_to_reach < dt){ // on position + DBG("ON Position, time to reach=%gs, dt=%gs\n\n\n", time_to_reach, dt); if(pointAZ) emulation_stop(); // got A/Z position, stop else atomic_store(&emul_status, MNT_S_TRACKING); - if(flip_in_progress){ - flip_in_progress = false; - CurRD = TagRD; // fix to dec <=90 - } + if(flip_in_progress) flip_in_progress = false; + CurRD = TagRD; // fix to dec <=90 }else{ - double dt = tcur - tlast; - double step = SPEED * dt; - if(step > dist) step = dist; - double factor = step / dist; - CurRD.ra += dRA * factor; - CurRD.dec += dDec * factor; - //if(CurRD.dec > ERFA_DPI/2.0) CurRD.dec = ERFA_DPI/2.0; - //else if(CurRD.dec < -ERFA_DPI/2.0) CurRD.dec = -ERFA_DPI/2.0; + DBG("dRA=%gdeg, dDEC=%gdegh\n\n\n", RAD2DEG(dRA), RAD2DEG(dDec)); + double sign = (dRA > 0.) ? 1. : -1.; + if(tra < dt) CurRD.ra = target->ra; + else CurRD.ra += dt * RASPEED * sign; + sign = (dDec > 0.) ? 1. : -1.; + if(tdec < dt) CurRD.dec = target->dec; + else CurRD.dec += dt * DECSPEED * sign; if(CurRD.ra < 0.) CurRD.ra += ERFA_D2PI; else if(CurRD.ra >= ERFA_D2PI) CurRD.ra -= ERFA_D2PI; } diff --git a/Daemons/10micron_stellarium/main.c b/Daemons/10micron_stellarium/main.c index 25e7764..271dd1b 100644 --- a/Daemons/10micron_stellarium/main.c +++ b/Daemons/10micron_stellarium/main.c @@ -29,11 +29,14 @@ #include "mount.h" static pid_t childpid = -1; // PID of child process -static const char *pidfile = NULL; +static parameters_t *G = NULL; +#ifndef EBUG +static bool isrunning = false; +#endif void signals(int sig){ if(childpid){ // single or parent process - if(pidfile) unlink(pidfile); // remove pidfile + if(G->pidfile) unlink(G->pidfile); // remove pidfile if(childpid > 0) kill(childpid, SIGTERM); } if(sig){ @@ -46,27 +49,42 @@ void signals(int sig){ LOGWARN("Child %d died with %d", getpid(), sig); server_stop(); } +#ifndef EBUG + isrunning = true; +#endif DBG("EXIT"); } int main(int argc, char **argv){ sl_init(); - parameters_t *G = parse_cmdline(&argc, &argv); + G = parse_cmdline(&argc, &argv); if(!G) return 1; sl_loglevel_e lvl = G->verbose + LOGLEVEL_ERR; if(lvl >= LOGLEVEL_AMOUNT) lvl = LOGLEVEL_AMOUNT - 1; DBG("verb: %d, level: %d", G->verbose, lvl); int fd; - if((fd = open(G->crdsfile, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) // test FITS-header file for writing - ERR(_("Can't open %s for writing"), G->crdsfile); + if((fd = open(G->crdsfile, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0){ // test FITS-header file for writing + WARN(_("Can't open %s for writing"), G->crdsfile); + return 1; + } close(fd); - if(G->sleept < 1) ERRX("Sleeping time sould be positive value"); - if(!server_setsleept(G->sleept)) ERRX("Can't set sleep time to %d", G->sleept); + if(G->sleept < 1){ + WARNX("Sleeping time sould be positive value (%d)", G->sleept); + return 2; + } + if(!server_setsleept(G->sleept)){ + WARNX("Can't set sleep time to %d", G->sleept); + return 3; + } if(G->emulation) set_emulation_mode(); - else if(!mount_set_dev(G->device, G->serspeed, G->sertmout)) - ERRX("Can't open device %s @ %d", G->device, G->serspeed); - if(!mount_set_name(G->mountname)) - ERRX("Can't set mount name to %s", G->mountname); + else if(!mount_set_dev(G->device, G->serspeed, G->sertmout)){ + WARNX("Can't open device %s @ %d", G->device, G->serspeed); + return 4; + } + if(!mount_set_name(G->mountname)){ + WARNX("Can't set mount name to %s", G->mountname); + return 5; + } signal(SIGTERM, signals); signal(SIGINT, signals); signal(SIGQUIT, signals); @@ -78,7 +96,7 @@ int main(int argc, char **argv){ LOGMSG("Started, master PID=%d", getpid()); #ifndef EBUG time_t lastd = 0; - while(1){ // guard for dead processes + while(isrunning){ // guard for dead processes childpid = fork(); if(childpid < 0){ LOGERR("fork() returns error"); @@ -114,5 +132,5 @@ int main(int argc, char **argv){ DBG("Run server"); server_run(); DBG("Server died"); - return 1; + return 0; } diff --git a/Daemons/10micron_stellarium/mount.c b/Daemons/10micron_stellarium/mount.c index dfcc48b..e89c339 100644 --- a/Daemons/10micron_stellarium/mount.c +++ b/Daemons/10micron_stellarium/mount.c @@ -22,6 +22,7 @@ #include #include +#include "10micron_commands.h" #include "emulation.h" #include "mount.h" @@ -30,12 +31,13 @@ static bool isemulated = false; // ==true for emulation mode +// default serial timeout, seconds +static double sertmout = 1.; + static char mount_name[MNAME_LEN+3] = "'noname'"; static sl_tty_t *mount_dev = NULL; // device mutex, blocking only in non-local functions static pthread_mutex_t mntdev_mutex = PTHREAD_MUTEX_INITIALIZER; -// ring buffer for data incoming from serial port -static sl_ringbuffer_t *RBin = NULL; // status static atomic_int mountstatus = MNT_S_ERROR; @@ -148,20 +150,25 @@ bool mount_set_name(const char *name){ * @brief mount_set_dev - open mount device without checking that mount is alive * @param dev - path to device * @param speed - baudrate + * @param timeout - timeout (seconds) for answer's waiting * @return false if failed to open device `dev` */ -bool mount_set_dev(char *dev, int speed, int timeout){ +bool mount_set_dev(char *dev, int speed, double timeout){ pthread_mutex_lock(&mntdev_mutex); if(mount_dev) sl_tty_close(&mount_dev); mount_dev = sl_tty_new(dev, speed, 4096); if(mount_dev) mount_dev = sl_tty_open(mount_dev, 1); if(!mount_dev){ pthread_mutex_unlock(&mntdev_mutex); + DBG("Can't init serial device"); return false; } - sl_tty_tmout(timeout); - if(!RBin) RBin = sl_RB_new(BUFSIZ); - else sl_RB_clearbuf(RBin); + DBG("Mount device inited and opened"); + // set terminal timeout to `timeout / 10` or 100ms + int usecs = (timeout < 1.) ? (int)(timeout * 1e5) : 100000; + sl_tty_tmout(usecs); + sertmout = timeout; + DBG("set timeout of answer waiting to %gs", sertmout); pthread_mutex_unlock(&mntdev_mutex); return true; } @@ -179,7 +186,8 @@ static const char *statuses[MNT_S_STATAMOUNT] = { [MNT_S_OUTLIMIT] = "'Outside tracking limit'", [MNT_S_FOLSAT]= "'Following satellite'", [MNT_S_DATINCOSIST]= "'Data inconsistency'", - [MNT_S_ERROR] = "'Error (disconnected?)'" + [MNT_S_ERROR] = "'Error'", + [MNT_S_OFF] = "'Off'" }; /** @@ -187,53 +195,138 @@ static const char *statuses[MNT_S_STATAMOUNT] = { * @param status - integer status code * @return statically allocated string with explanation */ -const char* mount_status_str(){ - int curst = (isemulated) ? emulation_status() : atomic_load(&mountstatus); - if(curst > -1 && curst < MNT_S_STATAMOUNT) return statuses[curst]; +const char* mount_status_str(mount_status_t st){ + if(st < MNT_S_STATAMOUNT) return statuses[st]; return "'Unknown status'"; } -// return current mount status -mount_status_t mount_status(){ - return (mount_status_t)atomic_load(&mountstatus); -} /** - * @brief write_cmd - try to write command to mount - * @param cmd - string with command or NULL just to clear all incoming data - * @return false on write/read error; all read information is in RBin (even if `false` returned, you SHOULD read all available strings from it) + * @brief send_cmd_resp - send command and wait for '#'-terminated response + * @param cmd - command (e.g. ":Sr12.345#") + * @param resp - buffer for response (may be NULL) + * @param resplen - its size + * @return true if '#'-terminated response received before timeout */ -static bool write_cmd(const char *cmd){ - bool ret = true; - if(cmd){ - size_t l = strlen(cmd); - if(sl_tty_write(mount_dev->comfd, cmd, l)) ret = false; +static bool send_cmd_resp(const char *cmd, char *resp, size_t resplen){ + if(!mount_dev) return false; + while(sl_tty_read(mount_dev) > 0); // clear tty buffer + if(!cmd) return false; // just clear buffer when cmd==NULL + DBG("Command '%s', fd: %d", cmd, mount_dev->comfd); + if(sl_tty_write(mount_dev->comfd, cmd, strlen(cmd))){ + WARN("sl_tty_write()"); + return false; } - int got = 0; - while((got = sl_tty_read(mount_dev)) > 0){ - if(sl_RB_write(RBin, (uint8_t*) mount_dev->buf, got)){ - got = -1; - break; + if(resp && resplen) resp[0] = 0; + size_t pos = 0; + double t0 = sl_dtime(); + bool gotEOM = false; + while(sl_dtime() - t0 < sertmout){ + int got = sl_tty_read(mount_dev); + if(got < 0){ + WARN("sl_tty_read()"); + if(resp && resplen) resp[pos < resplen ? pos : resplen-1] = 0; + DBG("pos: %zd, resp: '%s'", pos, resp); + return false; + } else if(pos && got == 0) break; // break if we already receive the message + for(int i = 0; i < got; ++i){ + char c = mount_dev->buf[i]; + if(c == '\r' || c == '\n') continue; // WTF? + if(c == '#'){ // end of message + gotEOM = true; + //if(resp && resplen) resp[pos < resplen ? pos : resplen-1] = 0; + //DBG("Got end of message: '%s' (waited for %gs)", resp, ); + //return true; + break; + } + if(resp && pos + 1 < resplen) resp[pos++] = c; } } - if(got < 0) return false; - return ret; + DBG("Waited for %gs", sl_dtime() - t0); + if(resp && resplen){ + resp[pos < resplen ? pos : resplen-1] = 0; + DBG("pos: %zd, resp: '%s'", pos, resp); + // 10Micron/LX200-like: '0' or 'E'/'e' -> error; '1' - OK + if(gotEOM || (pos == 1 && resp[0] == '1')) return true; + } + return false; +} + +/** + * @brief write_cmd - try to write command to mount and check answer for not false/error + * @param cmd - string with command or NULL just to clear all incoming data + * @param haveanswer - true if mount have to answer to `cmd` + * @return false on write/read error or error in answer + */ +static bool write_cmd(const char *cmd, bool haveanswer){ + char buf[128]; + if(!haveanswer){ + DBG("Command '%s'", cmd); + if(!mount_dev || !cmd){ + DBG("no mount device?"); + return false; + } + if(sl_tty_write(mount_dev->comfd, cmd, strlen(cmd))){ + DBG("Error writing request '%s'", cmd); + return false; + } + while(sl_tty_read(mount_dev) > 0); + }else if(!send_cmd_resp(cmd, buf, 128)){ + DBG("Error writing command '%s'", cmd); + return false; + } + return true; +} + +// return current mount status +mount_status_t mount_status(){ + mount_status_t curst = (mount_status_t)atomic_load(&mountstatus); + if(curst == MNT_S_OFF) return curst; // do nothing when mount if off + if(!mount_dev){ + atomic_store(&mountstatus, MNT_S_OFF); + return MNT_S_OFF; + } + char resp[64]; + pthread_mutex_lock(&mntdev_mutex); + int ntry = 0; + for(; ntry < 3; ++ntry) + if(send_cmd_resp(CMD_GETSTAT, resp, 64)) break; + if(ntry == 3){ // mount not responded -> set status OFF + curst = MNT_S_OFF; + }else{ // parsing of status + char *nxt = NULL; + long statN = strtol(resp, &nxt, 10); + //DBG("resp=%s, nxt=%s, stat=%ld", resp, nxt, statN); + if(!nxt || *nxt || statN >= MNT_S_ERROR || statN < 0) curst = MNT_S_ERROR; // wrong answer + else curst = (mount_status_t) statN; + DBG("STATUS: %s (%d)", statuses[curst], curst); + } + pthread_mutex_unlock(&mntdev_mutex); + atomic_store(&mountstatus, curst); + return curst; } // check if mount connected static bool chkconn(){ + FNAME(); int r = 0; do{ // clear incoming buffer @ start r = sl_tty_read(mount_dev); }while(r > 0); - if(r < 0) return false; - write_cmd("#"); // clear cmd buffer - sl_RB_clearbuf(RBin); - bool w = write_cmd(":SB0#"); - sl_RB_clearbuf(RBin); - return w; + if(r < 0){ + WARN("Error reading"); + DBG("error reading: got %d", r); + return false; + } + write_cmd("#", false); // clear cmd buffer + bool ret = false; + for(int i = 0; i < 5; ++i){ + DBG("Try %d", i+1); + ret = write_cmd(CMD_BAUDRATE, true); + if(ret) break; + } + return ret; } - // try to guess serial speed & set 115200 static bool guess_speed(){ if(!mount_dev) return false; @@ -242,6 +335,7 @@ static bool guess_speed(){ const int speeds[SPDBUFSZ] = {57600, 38400, 19200, 9600, 4800, 2400, 1200}; int idx = 0; for(; idx < SPDBUFSZ; ++idx){ + DBG("try speed %d", speeds[idx]); mount_dev->speed = speeds[idx]; sl_tty_t *trydev = sl_tty_open(mount_dev, 1); if(!trydev) continue; @@ -252,6 +346,7 @@ static bool guess_speed(){ close(mount_dev->comfd); mount_dev->speed = 115200; if(!sl_tty_open(mount_dev, 1)) return false; + DBG("OK, opened @ 115200"); #undef SPDBUFSZ return true; } @@ -261,14 +356,16 @@ bool mount_connect(){ if(isemulated) return true; if(!mount_dev) return false; pthread_mutex_lock(&mntdev_mutex); - if(!chkconn() && !guess_speed()) return false; + if(!chkconn() && !guess_speed()){ + pthread_mutex_unlock(&mntdev_mutex); + return false; + } bool ret = true; - if(!write_cmd(":STOP#")) ret = false; // stop tracking after poweron - sl_RB_clearbuf(RBin); - if(!write_cmd(":U2#")) ret = false; // set high precision - sl_RB_clearbuf(RBin); - if(!write_cmd(":So10#")) ret = false; // set minimum altitude to 10 degrees - sl_RB_clearbuf(RBin); + if(!write_cmd(CMD_STOP, false)) ret = false; // stop tracking after poweron + if(!write_cmd(CMD_HIGHPREC, false)) ret = false; // set high precision + char buf[64]; + snprintf(buf, 63, CMD_SETMINALT, 10); + if(!write_cmd(buf, true)) ret = false; // set minimum altitude to 10 degrees pthread_mutex_unlock(&mntdev_mutex); if(ret) LOGMSG("Connected to %s@115200", mount_dev->portname); else LOGERR("Can't write commands to mount"); @@ -292,23 +389,71 @@ void mount_disconnect(){ * @return true if all OK */ bool mount_point(double ra, double dec){ - char buf[RADEC_STR_MAXLEN]; - radec2str(ra, dec, buf); - DBG("Set RA/Decl to %s", buf); - LOGMSG("Try to set RA/Decl to %s", buf); + char rastr[RADEC_STR_MAXLEN], decstr[RADEC_STR_MAXLEN]; norm_RADEC(&ra, &dec); + ra2str(ra, rastr); + dec2str(dec, decstr); + DBG("Set RA/Decl to %s/%s", rastr, decstr); + LOGMSG("Try to set RA/Decl to %s/%s", rastr, decstr); if(isemulated) return point_emulation(ra, dec); - // run real pointing to ra(hrs) & dec (deg) - return false; + if(!mount_dev) return false; + pthread_mutex_lock(&mntdev_mutex); + char cmd[128]; + bool ret = false; + snprintf(cmd, 127, CMD_SETRA, rastr); // send RA + if(!write_cmd(cmd, true)) goto retn; + snprintf(cmd, 127, CMD_SETDEC, decstr); // send Dec + if(!write_cmd(cmd, true)) goto retn; + if(send_cmd_resp(CMD_SLEWRADEC, cmd, 127)){ // check error + if(*cmd != '0'){ + WARNX("Slew error, answer: %s", cmd); + LOGWARN("Slew error, answer: %s", cmd); + goto retn; + } + } + ret = true; +retn: + pthread_mutex_unlock(&mntdev_mutex); + return ret; } +/** + * @brief mount_pointAZ - point to stationary coordinates + * @param A - azumuth (degrees): CLOCKWISE FROM NORTH!!! + * @param Z - zenith (degrees) + * @return false if failed + */ bool mount_pointAZ(double A, double Z){ - DBG("Point to stationary object, A=%g, Z=%g", A, Z); + char altstr[RADEC_STR_MAXLEN], azstr[RADEC_STR_MAXLEN]; + if(!normAZ(&A, &Z)){ + DBG("Wrong Z?"); + return false; + } + d2sDMS(A, azstr, RADEC_STR_MAXLEN); + d2sDMS(90. - Z, altstr, RADEC_STR_MAXLEN); + DBG("Point to stationary object, Az=%s, Alt=%s", azstr, altstr); if(isemulated){ return pointAZ_emulation(A, Z); } - ; // run real pointing - return false; + if(!mount_dev) return false; + pthread_mutex_lock(&mntdev_mutex); + bool ret = false; + char cmd[128]; + snprintf(cmd, 127, CMD_SETALT, altstr); + if(!write_cmd(cmd, true)) goto retn; + snprintf(cmd, 127, CMD_SETZD, azstr); + if(!write_cmd(cmd, true)) goto retn; + if(send_cmd_resp(CMD_GOTOAZ, cmd, 127)){ // returned not '0' + if(*cmd != '0'){ + WARNX("Goto error, answer: %s", cmd); + LOGWARN("Goto error, answer: %s", cmd); + goto retn; + } + } + ret = true; +retn: + pthread_mutex_unlock(&mntdev_mutex); + return ret; } void set_emulation_mode(){ @@ -322,8 +467,49 @@ mount_status_t mount_getcoords(double *ra, double *dec){ DBG("Emulated coordinates: %gh, %gdeg", RAD2HRS(*ra), RAD2DEG(*dec)); return emulation_status(); } - ; // get real coordinates - return mount_status(); + if(!mount_dev) return MNT_S_ERROR; + char resp[64]; + mount_status_t st = MNT_S_ERROR; + pthread_mutex_lock(&mntdev_mutex); + if(!send_cmd_resp(CMD_GETRA, resp, 64)) goto retn; + if(!str2coord(resp, ra)) goto retn; + if(!send_cmd_resp(CMD_GETDEC, resp, 64)) goto retn; + if(!str2coord(resp, dec)) goto retn; + st = MNT_S_STATAMOUNT; +retn: + pthread_mutex_unlock(&mntdev_mutex); + if(st == MNT_S_STATAMOUNT) st = mount_status(); + return st; +} + +mount_status_t mount_getaz(double *a, double *z){ + if(!a || !z) return MNT_S_ERROR; + if(isemulated){ + double ra, dec; + get_emul_coords(&ra, &dec); + polarCrds_t P = {.dec = dec, .ra = ra}; + horizCrds_t H; + double LST; + get_LST(NULL, &LST); + eq2hor(&P, &H, LST); + *a = H.az; *z = H.zd; + return emulation_status(); + } + if(!mount_dev) return MNT_S_ERROR; + char resp[64]; + mount_status_t st = MNT_S_ERROR; + pthread_mutex_lock(&mntdev_mutex); + if(!send_cmd_resp(CMD_GETAZIM, resp, 64)) goto retn; + if(!str2coord(resp, a)) goto retn; + if(!send_cmd_resp(CMD_GETALT, resp, 64)) goto retn; + double alt; + if(!str2coord(resp, &alt)) goto retn; + *z = 90. - alt; + st = MNT_S_STATAMOUNT; +retn: + pthread_mutex_unlock(&mntdev_mutex); + if(st == MNT_S_STATAMOUNT) st = mount_status(); + return st; } /** @@ -333,10 +519,27 @@ mount_status_t mount_getcoords(double *ra, double *dec){ bool mount_stop(){ if(isemulated){ emulation_stop(); - }else{ - return mount_stop(); + return true; } - return true; + if(!mount_dev) return false; + bool ret = false; + pthread_mutex_lock(&mntdev_mutex); + if(write_cmd(CMD_STOP, false)) ret = true; + pthread_mutex_unlock(&mntdev_mutex); + return ret; +} + +bool mount_tracking_stop(){ + if(isemulated){ + emulation_stop(); + return true; + } + if(!mount_dev) return false; + bool ret = false; + pthread_mutex_lock(&mntdev_mutex); + if(write_cmd(CMD_TRKSTOP, false)) ret = true; + pthread_mutex_unlock(&mntdev_mutex); + return ret; } /** @@ -346,10 +549,15 @@ bool mount_stop(){ bool mount_tracking_start(){ if(isemulated){ emul_start_tracking(); - }else{ - return false; + return true; } - return true; + if(!mount_dev) return false; + bool ret = false; + pthread_mutex_lock(&mntdev_mutex); + write_cmd(CMD_TRKSTOP, false); // workaround from command protocol if mount was stopped with :STOP# + if(write_cmd(CMD_TRKSTART, false)) ret = true; + pthread_mutex_unlock(&mntdev_mutex); + return ret; } /** @@ -358,7 +566,8 @@ bool mount_tracking_start(){ */ bool mount_park(){ if(isemulated) return pointAZ_emulation(ParkCoords.az, ParkCoords.zd); - return mount_pointAZ(ParkCoords.az, ParkCoords.zd); + // TODO: set lower limit to 0deg + return mount_pointAZ(RAD2DEG(ParkCoords.az), RAD2DEG(ParkCoords.zd)); } /** diff --git a/Daemons/10micron_stellarium/mount.h b/Daemons/10micron_stellarium/mount.h index d27feb9..bb0e29c 100644 --- a/Daemons/10micron_stellarium/mount.h +++ b/Daemons/10micron_stellarium/mount.h @@ -34,8 +34,9 @@ typedef enum{ MNT_S_OUTLIMIT = 9, MNT_S_FOLSAT = 10, MNT_S_DATINCOSIST = 11, - MNT_S_ERROR = 12, // my status - MNT_S_STATAMOUNT = 13 // number of statuses + MNT_S_ERROR = 12, // status 98/99 (>11) + MNT_S_OFF, // not responding -> off + MNT_S_STATAMOUNT // number of statuses } mount_status_t; void set_emulation_mode(); @@ -54,16 +55,18 @@ double mount_getInpHor(horizCrds_t *c); bool mount_set_name(const char *name); -bool mount_set_dev(char *dev, int speed, int timeout); -const char* mount_status_str(); +bool mount_set_dev(char *dev, int speed, double timeout); +const char* mount_status_str(mount_status_t st); mount_status_t mount_status(); bool mount_connect(); void mount_disconnect(); mount_status_t mount_getcoords(double *ra, double *dec); +mount_status_t mount_getaz(double *a, double *z); bool mount_point(double ra, double dec); bool mount_pointAZ(double A, double Z); bool mount_stop(); +bool mount_tracking_stop(); bool mount_tracking_start(); bool mount_park(); diff --git a/Daemons/10micron_stellarium/mountdaemon_10micron.creator.user b/Daemons/10micron_stellarium/mountdaemon_10micron.creator.user index 0cf5bde..f10b7c7 100644 --- a/Daemons/10micron_stellarium/mountdaemon_10micron.creator.user +++ b/Daemons/10micron_stellarium/mountdaemon_10micron.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -14,8 +14,6 @@ ProjectExplorer.Project.EditorSettings true - true - true Cpp @@ -30,33 +28,15 @@ 2 KOI8-R - false 4 - false - 0 - 80 - true - true 1 - 0 - false false - false 1 - true true - 0 8 true - false - 1 true - true - true - *.md, *.MD, Makefile true - true - true @@ -76,11 +56,7 @@ 0 true - true - true - Builtin.DefaultTidyAndClazy - 4 - true + @@ -132,7 +108,7 @@ false false - + По умолчанию GenericProjectManager.GenericBuildConfiguration 0 @@ -159,7 +135,7 @@ 2 - + false -e cpu-cycles --call-graph dwarf,4096 -F 250 @@ -195,7 +171,7 @@ 2 - + false -e cpu-cycles --call-graph dwarf,4096 -F 250 diff --git a/Daemons/10micron_stellarium/mountdaemon_10micron.files b/Daemons/10micron_stellarium/mountdaemon_10micron.files index 2eccabf..a30736b 100644 --- a/Daemons/10micron_stellarium/mountdaemon_10micron.files +++ b/Daemons/10micron_stellarium/mountdaemon_10micron.files @@ -1,3 +1,4 @@ +10micron_commands.h angles.c angles.h args.c diff --git a/Daemons/10micron_stellarium/server.c b/Daemons/10micron_stellarium/server.c index 29800ac..60d4d4d 100644 --- a/Daemons/10micron_stellarium/server.c +++ b/Daemons/10micron_stellarium/server.c @@ -45,10 +45,12 @@ #define CMD_TAGZD "tagzd" #define CMD_TELRA "telra" #define CMD_TELDEC "teldec" +#define CMD_TELAZ "telaz" +#define CMD_TELZD "telzd" #define CMD_GOTORD "gotord" #define CMD_GOTORH "gotorh" #define CMD_GOTOAZ "gotoaz" -#define CMD_STOP "stop" +#define CMD_STOPTRK "stoptrk" #define CMD_TRACK "track" #define CMD_PARK "park" #define CMD_PARKAZ "parkaz" @@ -84,7 +86,8 @@ static sl_sock_hresult_e dtimeh(sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ con // statust - text format status static sl_sock_hresult_e status(sl_sock_t *c, sl_sock_hitem_t *item, _U_ const char *req){ char buf[BUFSIZ]; - snprintf(buf, BUFSIZ-1, "%s=%s\n", item->key, mount_status_str()); + mount_status_t st = mount_status(); + snprintf(buf, BUFSIZ-1, "%s=%s\n", item->key, mount_status_str(st)); LOGDBG("Client %d asks status: %s", c->fd, buf); sl_sock_sendstrmessage(c, buf); return RESULT_SILENCE; @@ -94,7 +97,9 @@ static int parse_key_value(const char *req, double *val){ if(!req) return 0; // is getter DBG("parsing of %s", req); double d; - if(sscanf(req, "%lf", &d) != 1) return -1; // error + if(strchr(req, ':')){ // DD:MM:SS or HH:MM:SS + if(!str2coord(req, &d)) return -1; + }else if(sscanf(req, "%lf", &d) != 1) return -1; // error if(val) *val = d; return 1; // is setter } @@ -112,7 +117,7 @@ static sl_sock_hresult_e cmd_tagra(sl_sock_t *c, sl_sock_hitem_t *item, const ch mount_getInpCoords(&p); double ra_h = RAD2HRS(p.ra); char buf[64]; - snprintf(buf, sizeof(buf), "%s=%.6f\n", item->key, ra_h); + snprintf(buf, 63, "%s=%.6f\n", item->key, ra_h); sl_sock_sendstrmessage(c, buf); } return RESULT_SILENCE; @@ -130,7 +135,7 @@ static sl_sock_hresult_e cmd_tagdec(sl_sock_t *c, sl_sock_hitem_t *item, const c mount_getInpCoords(&p); double dec_d = RAD2DEG(p.dec); char buf[64]; - snprintf(buf, sizeof(buf), "%s=%.6f\n", item->key, dec_d); + snprintf(buf, 63, "%s=%.6f\n", item->key, dec_d); sl_sock_sendstrmessage(c, buf); } return RESULT_SILENCE; @@ -148,7 +153,7 @@ static sl_sock_hresult_e cmd_tagha(sl_sock_t *c, sl_sock_hitem_t *item, const ch mount_getInpCoords(&p); double ha_h = RAD2HRS(p.ha); char buf[64]; - snprintf(buf, sizeof(buf), "%s=%.6f\n", item->key, ha_h); + snprintf(buf, 63, "%s=%.6f\n", item->key, ha_h); sl_sock_sendstrmessage(c, buf); } return RESULT_SILENCE; @@ -166,7 +171,7 @@ static sl_sock_hresult_e cmd_tagaz(sl_sock_t *c, sl_sock_hitem_t *item, const ch mount_getInpHor(&h); double az_d = RAD2DEG(h.az); char buf[64]; - snprintf(buf, sizeof(buf), "%s=%.6f\n", item->key, az_d); + snprintf(buf, 63, "%s=%.6f\n", item->key, az_d); sl_sock_sendstrmessage(c, buf); } return RESULT_SILENCE; @@ -184,7 +189,7 @@ static sl_sock_hresult_e cmd_tagzd(sl_sock_t *c, sl_sock_hitem_t *item, const ch mount_getInpHor(&h); double zd_d = RAD2DEG(h.zd); char buf[64]; - snprintf(buf, sizeof(buf), "%s=%.6f\n", item->key, zd_d); + snprintf(buf, 63, "%s=%.6f\n", item->key, zd_d); sl_sock_sendstrmessage(c, buf); } return RESULT_SILENCE; @@ -194,8 +199,7 @@ static sl_sock_hresult_e cmd_telra(sl_sock_t *c, sl_sock_hitem_t *item, _U_ cons double ra, dec; if(mount_getcoords(&ra, &dec) == MNT_S_ERROR) return RESULT_FAIL; char buf[64]; - double ra_h = RAD2HRS(ra); - snprintf(buf, sizeof(buf), "%s=%.6f\n", item->key, ra_h); + snprintf(buf, 63, "%s=%.6f\n", item->key, ra); sl_sock_sendstrmessage(c, buf); return RESULT_SILENCE; } @@ -204,8 +208,25 @@ static sl_sock_hresult_e cmd_teldec(sl_sock_t *c, sl_sock_hitem_t *item, _U_ con double ra, dec; if(mount_getcoords(&ra, &dec) == MNT_S_ERROR) return RESULT_FAIL; char buf[64]; - double dec_d = RAD2DEG(dec); - snprintf(buf, sizeof(buf), "%s=%.6f\n", item->key, dec_d); + snprintf(buf, 63, "%s=%.6f\n", item->key, dec); + sl_sock_sendstrmessage(c, buf); + return RESULT_SILENCE; +} + +static sl_sock_hresult_e cmd_telaz(sl_sock_t *c, sl_sock_hitem_t *item, _U_ const char *req) { + double a, z; + if(mount_getaz(&a, &z) == MNT_S_ERROR) return RESULT_FAIL; + char buf[64]; + snprintf(buf, 63, "%s=%.6f\n", item->key, a); + sl_sock_sendstrmessage(c, buf); + return RESULT_SILENCE; +} + +static sl_sock_hresult_e cmd_telzd(sl_sock_t *c, sl_sock_hitem_t *item, _U_ const char *req) { + double a, z; + if(mount_getaz(&a, &z) == MNT_S_ERROR) return RESULT_FAIL; + char buf[64]; + snprintf(buf, 63, "%s=%.6f\n", item->key, z); sl_sock_sendstrmessage(c, buf); return RESULT_SILENCE; } @@ -241,8 +262,13 @@ static sl_sock_hresult_e cmd_gotoaz(_U_ sl_sock_t *c, _U_ sl_sock_hitem_t *item, } static sl_sock_hresult_e cmd_stop(_U_ sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ const char *req) { - mount_stop(); - return RESULT_OK; + if(mount_stop()) return RESULT_OK; + return RESULT_FAIL; +} + +static sl_sock_hresult_e cmd_stoptrk(_U_ sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ const char *req) { + if(mount_tracking_stop()) return RESULT_OK; + return RESULT_FAIL; } // run tracking from current position @@ -268,7 +294,7 @@ static sl_sock_hresult_e cmd_parkaz(sl_sock_t *c, sl_sock_hitem_t *item, const c horizCrds_t h; mount_getPark(&h); char buf[64]; - snprintf(buf, sizeof(buf), "%s=%.6f\n", item->key, RAD2DEG(h.az)); + snprintf(buf, 63, "%s=%.6f\n", item->key, RAD2DEG(h.az)); sl_sock_sendstrmessage(c, buf); } return RESULT_SILENCE; @@ -284,7 +310,7 @@ static sl_sock_hresult_e cmd_parkzd(sl_sock_t *c, sl_sock_hitem_t *item, const c horizCrds_t h; mount_getPark(&h); char buf[64]; - snprintf(buf, sizeof(buf), "%s=%.6f\n", item->key, RAD2DEG(h.zd)); + snprintf(buf, 63, "%s=%.6f\n", item->key, RAD2DEG(h.zd)); sl_sock_sendstrmessage(c, buf); } return RESULT_SILENCE; @@ -309,6 +335,9 @@ static sl_sock_hitem_t handlers[] = { {cmd_tagzd, CMD_TAGZD, "get/set target zenith distance (Deg)", NULL}, {cmd_teldec, CMD_TELDEC, "get current telescope declination (Deg)", NULL}, {cmd_telra, CMD_TELRA, "get current telescope right acsention (Hrs)", NULL}, + {cmd_telaz, CMD_TELAZ, "get current telescope azimuth (Deg)", NULL}, + {cmd_telzd, CMD_TELZD, "get current telescope zenith distance (Deg)", NULL}, + {cmd_stoptrk, CMD_STOPTRK, "stop tracking", NULL}, {cmd_track, CMD_TRACK, "start tracking from current position", NULL}, {dtimeh, CMD_UNIXT, "get server's UNIX time", NULL}, {NULL, NULL, NULL, NULL} @@ -395,20 +424,37 @@ void server_run(){ return; } if(!mount_connect()){ - LOGERR("Can't connect to mount"); - sl_sock_delete(&cmd_socket); - return; + LOGWARN("Can't connect to mount, will try to reconnect later"); } isrunning = true; DBG("While"); + double tcheck = 0.; + bool notlogged = true; while(isrunning && cmd_socket && cmd_socket->connected){ usleep(sleept); if(!cmd_socket->rthread){ LOGERR("Server handlers thread is dead"); break; } - // finite state machine polling - //dome_poll(DOME_POLL, 0); + // check mount state + double tnow = sl_dtime(); + if(tnow - tcheck >= MOUNT_CHECK_T){ + tcheck = tnow; + mount_status_t curst = mount_status(); + if(curst == MNT_S_OFF){ // mount is off -> try to reconnect + if(notlogged){ + WARNX("Mount is OFF"); + LOGWARN("Mount is OFF"); + notlogged = false; + } + DBG("Try to [re]connect"); + if(mount_connect()){ + notlogged = true; + WARNX("Mount is ON"); + } + } + DBG("Current status: %s", mount_status_str(curst)); + } } DBG("Stop command socket"); sl_sock_delete(&cmd_socket); diff --git a/Daemons/10micron_stellarium/server.h b/Daemons/10micron_stellarium/server.h index 0daae2a..5cf4e3c 100644 --- a/Daemons/10micron_stellarium/server.h +++ b/Daemons/10micron_stellarium/server.h @@ -23,8 +23,13 @@ // default and max available time for "usleep" #define DEFAULT_SLEEP_T 100 #define MAX_SLEEP_T 10000 + +// maximal amount of connected clients #define DEFAULT_MAXCLIENTS 5 +// status checking interval, seconds +#define MOUNT_CHECK_T 10. + typedef struct{ int cmd_isunix; // UNIX-socket instead of INET for `cmdnode` const char *stellport; // port of stellarium server; could be "localhost:port" for local-only work