almost works as I need

This commit is contained in:
2026-09-25 15:00:34 +03:00
parent 8e796ce419
commit 30b7c9bc9e
11 changed files with 475 additions and 93 deletions

View File

@@ -25,6 +25,8 @@
#define CMD_GOTOAZ ":MA#" #define CMD_GOTOAZ ":MA#"
#define CMD_SLEWRADEC ":MS#" #define CMD_SLEWRADEC ":MS#"
#define CMD_BAUDRATE ":SB0#" #define CMD_BAUDRATE ":SB0#"
#define CMD_DUALTRK ":Sdat1#"
#define CMD_REFCORR_ON ":SREF1#"
#define CMD_STOP ":STOP#" #define CMD_STOP ":STOP#"
#define CMD_HIGHPREC ":U2#" #define CMD_HIGHPREC ":U2#"
@@ -34,10 +36,14 @@
#define CMD_GETDEC ":GD#" #define CMD_GETDEC ":GD#"
#define CMD_GETSTAT ":Gstat#" #define CMD_GETSTAT ":Gstat#"
#define CMD_GETRA ":GR#" #define CMD_GETRA ":GR#"
#define CMD_GETPS ":pS#"
// setters // setters
#define CMD_SETALT ":Sa%s#" #define CMD_SETALT ":Sa%s#"
#define CMD_SETDEC ":Sd%s#" #define CMD_SETDEC ":Sd%s#"
#define CMD_SETRA ":Sr%s#" #define CMD_SETTIME ":SLDT%04d-%02d-%02d,%02d:%02d:%02d.%02ld#"
#define CMD_SETMINALT ":So%d#" #define CMD_SETMINALT ":So%d#"
#define CMD_SETRA ":Sr%s#"
#define CMD_SETPRESSURE ":SRPRS%.1f#"
#define CMD_SETTEMPER ":SRTMP%.1f#"
#define CMD_SETZD ":Sz%s#" #define CMD_SETZD ":Sz%s#"

View File

@@ -227,9 +227,9 @@ void eq2horH(polarCrds_t *pc, horizCrds_t *h){
/** /**
* @brief eq2hor - convert polar coordinates to horizontal * @brief eq2hor - convert polar coordinates to horizontal
* @param pc (i) - polar coordinates (only RA used) * @param pc (i) - polar coordinates (RA, EO, DEC used) (radians)
* @param h (o) - horizontal coordinates * @param h (o) - horizontal coordinates (radians)
* @param sidTime - sidereal time * @param sidTime - sidereal time (radians)
*/ */
void eq2hor(polarCrds_t *pc, horizCrds_t *h, double sidTime){ void eq2hor(polarCrds_t *pc, horizCrds_t *h, double sidTime){
if(!h || !pc) return; if(!h || !pc) return;
@@ -262,7 +262,7 @@ void r2sDMS(double radians, char *dms, int len){
char pm; char pm;
int i[4]; int i[4];
eraA2af(1, radians, &pm, i); eraA2af(1, radians, &pm, i);
snprintf(dms, len, "'%c%02d:%02d:%02d.%d'", pm, i[0],i[1],i[2],i[3]); snprintf(dms, len, "%c%02d:%02d:%02d.%d", pm, i[0],i[1],i[2],i[3]);
} }
// the same, but argument in degrees // the same, but argument in degrees
void d2sDMS(double degrees, char *dms, int len){ void d2sDMS(double degrees, char *dms, int len){

View File

@@ -0,0 +1,203 @@
/*
* This file is part of the mountdaemon_10micron project.
* Copyright 2026 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 <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <usefull_macros.h>
#include "fitshdr.h"
#include "mount.h"
static char *hdname = NULL;
#ifndef FLT_EPSILON
#define FLT_EPSILON 1e-6
#endif
/**
* @brief set_header_name - check ability of witing into file and set given name
* @param name - header filename
* @return false if can't write into `name`
*/
bool set_header_name(const char *name){
if(!name) return false;
int fd;
if((fd = open(name, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0){ // test FITS-header file for writing
WARN("Can't open %s for writing", name);
return false;
}
close(fd);
FREE(hdname);
hdname = strdup(name);
return true;
}
/**
* @brief printhdr - write FITS record into output file
* @param fd - fd to write
* @param key - key
* @param val - value
* @param cmnt - comment
* @return 0 if all OK
*/
static int printhdr(int fd, const char *key, const char *val, const char *cmnt){
char tmp[81];
char tk[9];
if(strlen(key) > 8){
snprintf(tk, 8, "%s", key);
tk[8] = 0;
key = tk;
}
size_t L = 0;
if(cmnt){
L = snprintf(tmp, 81, "%-8s= %-21s / %s", key, val, cmnt);
}else{
L = snprintf(tmp, 81, "%-8s= %s", key, val);
}
if(L > 80){
tmp[80] = 0;
L = 80;
}
tmp[L++] = '\n';
if(write(fd, tmp, L) != (ssize_t)L){
WARN("write()");
return 1;
}
return 0;
}
/**
* @brief wrhdr - try to write into header file
*/
void wrhdr(fitsheader_t *HDR){
if(!HDR) return;
static time_t lastcorr = 0; // last time of time/weather corrections sent to mount
time_t curtime = time(NULL);
bool haveweather = false;
bool poweredON = (HDR->status == MNT_S_ERROR || HDR->status == MNT_S_OFF) ? false : true;
// weather block
if(HDR->weather.last_update < (int)(1 + MOUNT_CHECK_T * 2)){ // weather data is good
if(time(NULL) - lastcorr > CORRECTIONS_TIMEDIFF){ // make correction once per hour
if(mount_corrdata(&HDR->weather)) lastcorr = time(NULL);
}
haveweather = true;
}
if(!hdname){
DBG("hdname not given!");
return;
}
char aname[PATH_MAX];
size_t L = snprintf(aname, PATH_MAX, "%sXXXXXX", hdname);
if(L == PATH_MAX) aname[PATH_MAX-1] = 0;
int fd = mkstemp(aname);
if(fd < 0){
WARN("Can't write header file: mkstemp()");
return;
}
fchmod(fd, 0644);
char val[23];
val[22] = 0;
#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("MOUNTNAM", HDR->mountname, "Mount name");
if(fabs(HDR->dut.px) > FLT_EPSILON){
snprintf(val, 22, "%.10f", HDR->dut.px);
WRHDR("POLARX", val, "IERS pole X coordinate, arcsec");
}
if(fabs(HDR->dut.py) > FLT_EPSILON){
snprintf(val, 22, "%.10f", HDR->dut.py);
WRHDR("POLARY", val, "IERS pole Y coordinate, arcsec");
}
if(fabs(HDR->dut.DUT1) > FLT_EPSILON){
snprintf(val, 22, "%.10f", HDR->dut.DUT1);
WRHDR("DUT1", val, "IERS `UT1-UTC`, sec");
}
polarCrds_t polar;
horizCrds_t horiz;
double pt = mount_getInpCoords(&polar), ht = mount_getInpHor(&horiz);
if(pt > ht){ // horcrds is older -> show polar
if(curtime - pt < COORDS_OLD_T){
snprintf(val, 22, "%.10f", RAD2DEG(polar.ra));
WRHDR("TAGRA", val, "Target RA (J2000), degrees");
snprintf(val, 22, "%.10f", RAD2DEG(polar.dec));
WRHDR("TAGDEC", val, "Target DEC (J2000), degrees");
}
}else{ // show horiz
if(curtime - ht < COORDS_OLD_T){
snprintf(val, 22, "%.10f", RAD2DEG(horiz.az));
WRHDR("TAGAZ", val, "Target Azimuth, degrees");
snprintf(val, 22, "%.10f", RAD2DEG(horiz.zd));
WRHDR("TAGZD", val, "Target Zenith dist., degrees");
}
}
if(poweredON){
snprintf(val, 22, "%.10f", RAD2DEG(HDR->polar.ra)); // convert RA to degrees
WRHDR("RA", val, "Telescope right ascension, current epoch, deg");
snprintf(val, 22, "%.10f", RAD2DEG(HDR->polar.dec));
WRHDR("DEC", val, "Telescope declination, current epoch, deg");
snprintf(val, 22, "%.10f", RAD2DEG(HDR->altaz.az));
WRHDR("AZ", val, "Telescope azimuth, current epoch, deg");
snprintf(val, 22, "%.10f", RAD2DEG(HDR->altaz.zd));
WRHDR("ZD", val, "Telescope zenith distance, current epoch, deg");
}
WRHDR("TELSTAT", mount_status_str(HDR->status), "Telescope mount status");
double mjd;
mount_getInpMJD(&mjd);
snprintf(val, 22, "%.10f", 2000.+(mjd - ERFA_DJM00)/365.25); // calculate EPOCH/EQUINOX
WRHDR("INPEQUIN", val, "Equinox of input celestial coordinate system");
if(poweredON){
snprintf(val, 22, "%.10f", 2000.+(HDR->MJD.MJD - ERFA_DJM00)/365.25); // telescope coordinates: JNOW
WRHDR("EQUINOX", val, "Equinox of telescope celestial coordinate sys.");
snprintf(val, 22, "%.10f", HDR->MJD.MJD);
WRHDR("MJD", val, "Modified Julian date of file creation");
if(*HDR->pierside) WRHDR("PIERSIDE", HDR->pierside, "Pier side of telescope mount");
}
snprintf(val, 22, "%.1f", HDR->place.salt);
WRHDR("ELEVAT", val, "Elevation of site over the sea level");
snprintf(val, 22, "%.10f", RAD2DEG(HDR->place.slong));
WRHDR("LONGITUD", val, "Geo longitude of site (east negative)");
snprintf(val, 22, "%.10f", RAD2DEG(HDR->place.slat));
WRHDR("LATITUDE", val, "Geo latitude of site (south negative)");
snprintf(val, 22, "%.4f", RAD2HRS(HDR->sidtime));
WRHDR("LSTEND", val, "Local sidereal time of file creation");
if(haveweather){
snprintf(val, 22, "%.1f", HDR->weather.humidity);
WRHDR("HUMIDITY", val, "Relative humidity, %%");
snprintf(val, 22, "%.1f", HDR->weather.pressure);
WRHDR("PRESSURE", val, "Atmospheric pressure, mmHg");
snprintf(val, 22, "%.1f", HDR->weather.exttemp);
WRHDR("EXTTEMP", val, "External temperature, degrC");
snprintf(val, 22, "%d", HDR->weather.rain);
WRHDR("RAIN", val, "Rain conditions");
snprintf(val, 22, "%.1f", HDR->weather.clouds);
WRHDR("SKYQUAL", val, "Sky quality (0 - wery bad, >2500 - good)");
snprintf(val, 22, "%.1f", HDR->weather.wind);
WRHDR("WINDSPD", val, "Wind speed (m/s)");
snprintf(val, 22, "%.1f", HDR->weather.windmax);
WRHDR("WINDMAX", val, "Last hour maximal wind speed (m/s)");
snprintf(val, 22, "%zd", HDR->weather.last_update);
WRHDR("WEATTIME", val, "Unix time of weather measurements");
}
// WRHDR("", , "");
#undef WRHDR
returning:
close(fd);
rename(aname, hdname);
}

View File

@@ -0,0 +1,44 @@
/*
* This file is part of the mountdaemon_10micron project.
* Copyright 2026 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 <weather_data.h>
#include "angles.h"
#include "mount.h"
// maximal string length (including terminating zero)
#define MAX_HDR_STRLEN 32
// status checking interval and writing FITS-header, seconds
#define MOUNT_CHECK_T 0.5
typedef struct{
weather_data_t weather;
mount_status_t status;
almDut_t dut;
placeData_t place;
polarCrds_t polar;
horizCrds_t altaz;
sMJD_t MJD;
double sidtime;
char pierside[MAX_HDR_STRLEN];
char mountname[MAX_HDR_STRLEN];
} fitsheader_t;
bool set_header_name(const char *name);
void wrhdr(fitsheader_t *HDR);

View File

@@ -25,14 +25,12 @@
#include <usefull_macros.h> #include <usefull_macros.h>
#include "args.h" #include "args.h"
#include "fitshdr.h"
#include "server.h" #include "server.h"
#include "mount.h" #include "mount.h"
static pid_t childpid = -1; // PID of child process static pid_t childpid = -1; // PID of child process
static parameters_t *G = NULL; static parameters_t *G = NULL;
#ifndef EBUG
static bool isrunning = false;
#endif
void signals(int sig){ void signals(int sig){
if(childpid){ // single or parent process if(childpid){ // single or parent process
@@ -49,9 +47,6 @@ void signals(int sig){
LOGWARN("Child %d died with %d", getpid(), sig); LOGWARN("Child %d died with %d", getpid(), sig);
server_stop(); server_stop();
} }
#ifndef EBUG
isrunning = true;
#endif
DBG("EXIT"); DBG("EXIT");
} }
@@ -62,12 +57,7 @@ int main(int argc, char **argv){
sl_loglevel_e lvl = G->verbose + LOGLEVEL_ERR; sl_loglevel_e lvl = G->verbose + LOGLEVEL_ERR;
if(lvl >= LOGLEVEL_AMOUNT) lvl = LOGLEVEL_AMOUNT - 1; if(lvl >= LOGLEVEL_AMOUNT) lvl = LOGLEVEL_AMOUNT - 1;
DBG("verb: %d, level: %d", G->verbose, lvl); DBG("verb: %d, level: %d", G->verbose, lvl);
int fd; if(!set_header_name(G->crdsfile)) return 1;
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){ if(G->sleept < 1){
WARNX("Sleeping time sould be positive value (%d)", G->sleept); WARNX("Sleeping time sould be positive value (%d)", G->sleept);
return 2; return 2;

View File

@@ -20,21 +20,23 @@
#include <stdatomic.h> #include <stdatomic.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <sys/time.h>
#include <usefull_macros.h> #include <usefull_macros.h>
#include "10micron_commands.h" #include "10micron_commands.h"
#include "emulation.h" #include "emulation.h"
#include "mount.h" #include "mount.h"
#include "server.h" // isrunning
#define MNAME_LEN 31 #define MNAME_LEN 32
static bool isemulated = false; // ==true for emulation mode static bool isemulated = false; // ==true for emulation mode
// default serial timeout, seconds // default serial timeout, seconds
static double sertmout = 1.; static double sertmout = 1.;
static char mount_name[MNAME_LEN+3] = "'noname'"; static char mount_name[MNAME_LEN] = "noname";
static sl_tty_t *mount_dev = NULL; static sl_tty_t *mount_dev = NULL;
// device mutex, blocking only in non-local functions // device mutex, blocking only in non-local functions
static pthread_mutex_t mntdev_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t mntdev_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -47,7 +49,7 @@ static horizCrds_t ParkCoords = {.az = 0., .zd = DEG2RAD(80.)};
static polarCrds_t InpCoords = {0}, // input as user give (for epoch InpMJD) static polarCrds_t InpCoords = {0}, // input as user give (for epoch InpMJD)
TagCoords = {0}; // target for Jnow after command "point to input" TagCoords = {0}; // target for Jnow after command "point to input"
static horizCrds_t InpHoriz = {0}; static horizCrds_t InpHoriz = {0};
// input MJD (Modified Julian Date: started from ERFA_DJM0==2400000.5 // input MJD (Modified Julian Date: started from ERFA_DJM0==2400000.5)
static double InpMJD = ERFA_DJM00; // J2000 static double InpMJD = ERFA_DJM00; // J2000
// times of coords/mjd change // times of coords/mjd change
static double InpCTime = 0., TagTime = 0., InpHTime = 0., InpMTime = 0.; static double InpCTime = 0., TagTime = 0., InpHTime = 0., InpMTime = 0.;
@@ -141,11 +143,20 @@ bool mount_setInpMJD(double m){
bool mount_set_name(const char *name){ bool mount_set_name(const char *name){
if(!name || !*name) return false; if(!name || !*name) return false;
int l = strlen(name); int l = strlen(name);
if(l > MNAME_LEN) return false; if(l > MNAME_LEN-1) return false;
sprintf(mount_name, "'%s'", name); strcpy(mount_name, name);
return true; return true;
} }
void mount_get_name(char *nm, size_t l){
if(!nm) return;
size_t L = snprintf(nm, l, "'%s'", mount_name);
if(L == l){
nm[l-1] = 0;
nm[l-2] = '\'';
}
}
/** /**
* @brief mount_set_dev - open mount device without checking that mount is alive * @brief mount_set_dev - open mount device without checking that mount is alive
* @param dev - path to device * @param dev - path to device
@@ -164,9 +175,6 @@ bool mount_set_dev(char *dev, int speed, double timeout){
return false; return false;
} }
DBG("Mount device inited and opened"); 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; sertmout = timeout;
DBG("set timeout of answer waiting to %gs", sertmout); DBG("set timeout of answer waiting to %gs", sertmout);
pthread_mutex_unlock(&mntdev_mutex); pthread_mutex_unlock(&mntdev_mutex);
@@ -319,7 +327,7 @@ static bool chkconn(){
} }
write_cmd("#", false); // clear cmd buffer write_cmd("#", false); // clear cmd buffer
bool ret = false; bool ret = false;
for(int i = 0; i < 5; ++i){ for(int i = 0; i < 3 && isrunning; ++i){
DBG("Try %d", i+1); DBG("Try %d", i+1);
ret = write_cmd(CMD_BAUDRATE, true); ret = write_cmd(CMD_BAUDRATE, true);
if(ret) break; if(ret) break;
@@ -334,19 +342,24 @@ static bool guess_speed(){
#define SPDBUFSZ 7 #define SPDBUFSZ 7
const int speeds[SPDBUFSZ] = {57600, 38400, 19200, 9600, 4800, 2400, 1200}; const int speeds[SPDBUFSZ] = {57600, 38400, 19200, 9600, 4800, 2400, 1200};
int idx = 0; int idx = 0;
for(; idx < SPDBUFSZ; ++idx){ for(; idx < SPDBUFSZ && isrunning; ++idx){
DBG("try speed %d", speeds[idx]); DBG("try speed %d", speeds[idx]);
mount_dev->speed = speeds[idx]; mount_dev->speed = speeds[idx];
sl_tty_t *trydev = sl_tty_open(mount_dev, 1); sl_tty_t *trydev = sl_tty_open(mount_dev, 1);
if(!trydev) continue; if(!trydev) continue;
if(chkconn()) break; if(chkconn()){
close(mount_dev->comfd);
break;
}
close(mount_dev->comfd); close(mount_dev->comfd);
} }
if(idx == SPDBUFSZ) return false; // device not responding
close(mount_dev->comfd);
mount_dev->speed = 115200; mount_dev->speed = 115200;
if(!sl_tty_open(mount_dev, 1)) return false; if(!sl_tty_open(mount_dev, 1)){
DBG("OK, opened @ 115200"); WARN("Can't open serial @115200");
return false;
}
DBG("Opened @ 115200");
if(idx == SPDBUFSZ) return false; // device not responding
#undef SPDBUFSZ #undef SPDBUFSZ
return true; return true;
} }
@@ -362,7 +375,9 @@ bool mount_connect(){
} }
bool ret = true; bool ret = true;
if(!write_cmd(CMD_STOP, false)) ret = false; // stop tracking after poweron if(!write_cmd(CMD_STOP, false)) ret = false; // stop tracking after poweron
usleep(100000);
if(!write_cmd(CMD_HIGHPREC, false)) ret = false; // set high precision if(!write_cmd(CMD_HIGHPREC, false)) ret = false; // set high precision
usleep(100000);
char buf[64]; char buf[64];
snprintf(buf, 63, CMD_SETMINALT, 10); snprintf(buf, 63, CMD_SETMINALT, 10);
if(!write_cmd(buf, true)) ret = false; // set minimum altitude to 10 degrees if(!write_cmd(buf, true)) ret = false; // set minimum altitude to 10 degrees
@@ -412,6 +427,9 @@ bool mount_point(double ra, double dec){
} }
} }
ret = true; ret = true;
TagCoords.ra = DEG2RAD(ra);
TagCoords.dec = DEG2RAD(dec);
TagTime = sl_dtime();
retn: retn:
pthread_mutex_unlock(&mntdev_mutex); pthread_mutex_unlock(&mntdev_mutex);
return ret; return ret;
@@ -460,30 +478,29 @@ void set_emulation_mode(){
isemulated = true; isemulated = true;
} }
mount_status_t mount_getcoords(double *ra, double *dec){ bool mount_getcoords(double *ra, double *dec){
if(!ra || !dec) return MNT_S_ERROR; if(!ra || !dec) return false;
if(isemulated){ if(isemulated){
get_emul_coords(ra, dec); get_emul_coords(ra, dec);
DBG("Emulated coordinates: %gh, %gdeg", RAD2HRS(*ra), RAD2DEG(*dec)); DBG("Emulated coordinates: %gh, %gdeg", RAD2HRS(*ra), RAD2DEG(*dec));
return emulation_status(); return true;
} }
if(!mount_dev) return MNT_S_ERROR; if(!mount_dev) return false;
char resp[64]; char resp[64];
mount_status_t st = MNT_S_ERROR; bool ret = false;
pthread_mutex_lock(&mntdev_mutex); pthread_mutex_lock(&mntdev_mutex);
if(!send_cmd_resp(CMD_GETRA, resp, 64)) goto retn; if(!send_cmd_resp(CMD_GETRA, resp, 64)) goto retn;
if(!str2coord(resp, ra)) goto retn; if(!str2coord(resp, ra)) goto retn;
if(!send_cmd_resp(CMD_GETDEC, resp, 64)) goto retn; if(!send_cmd_resp(CMD_GETDEC, resp, 64)) goto retn;
if(!str2coord(resp, dec)) goto retn; if(!str2coord(resp, dec)) goto retn;
st = MNT_S_STATAMOUNT; ret = true;
retn: retn:
pthread_mutex_unlock(&mntdev_mutex); pthread_mutex_unlock(&mntdev_mutex);
if(st == MNT_S_STATAMOUNT) st = mount_status(); return ret;
return st;
} }
mount_status_t mount_getaz(double *a, double *z){ bool mount_getaz(double *a, double *z){
if(!a || !z) return MNT_S_ERROR; if(!a || !z) return false;
if(isemulated){ if(isemulated){
double ra, dec; double ra, dec;
get_emul_coords(&ra, &dec); get_emul_coords(&ra, &dec);
@@ -493,11 +510,11 @@ mount_status_t mount_getaz(double *a, double *z){
get_LST(NULL, &LST); get_LST(NULL, &LST);
eq2hor(&P, &H, LST); eq2hor(&P, &H, LST);
*a = H.az; *z = H.zd; *a = H.az; *z = H.zd;
return emulation_status(); return true;
} }
if(!mount_dev) return MNT_S_ERROR; if(!mount_dev) return false;
char resp[64]; char resp[64];
mount_status_t st = MNT_S_ERROR; bool ret = false;
pthread_mutex_lock(&mntdev_mutex); pthread_mutex_lock(&mntdev_mutex);
if(!send_cmd_resp(CMD_GETAZIM, resp, 64)) goto retn; if(!send_cmd_resp(CMD_GETAZIM, resp, 64)) goto retn;
if(!str2coord(resp, a)) goto retn; if(!str2coord(resp, a)) goto retn;
@@ -505,11 +522,10 @@ mount_status_t mount_getaz(double *a, double *z){
double alt; double alt;
if(!str2coord(resp, &alt)) goto retn; if(!str2coord(resp, &alt)) goto retn;
*z = 90. - alt; *z = 90. - alt;
st = MNT_S_STATAMOUNT; ret = true;
retn: retn:
pthread_mutex_unlock(&mntdev_mutex); pthread_mutex_unlock(&mntdev_mutex);
if(st == MNT_S_STATAMOUNT) st = mount_status(); return ret;
return st;
} }
/** /**
@@ -600,3 +616,59 @@ bool mount_setParkZD(double zd){
void mount_getPark(horizCrds_t *c){ void mount_getPark(horizCrds_t *c){
if(c) *c = ParkCoords; if(c) *c = ParkCoords;
} }
/**
* @brief mount_getpierside - get pier-side of telescope
* @param Ps (o) - side
* @param len - length of `Ps`
* @return false if failed
*/
bool mount_getpierside(char *Ps, size_t len){
pthread_mutex_lock(&mntdev_mutex);
bool ret = send_cmd_resp(CMD_GETPS, Ps, len);
pthread_mutex_unlock(&mntdev_mutex);
return ret;
}
/**
* @brief mount_corrdata - correct mount time & weather data
* @param w - new data
* @return false if failed to connect
*/
bool mount_corrdata(weather_data_t *w){
if(!w) return false;
bool ret = true; // returning value
mount_status_t curst = mount_status();
if(curst == MNT_S_SLEWING || curst == MNT_S_TRACKING) return true;
DBG("Refresh datetime");
pthread_mutex_lock(&mntdev_mutex);
char buf[128];
buf[127] = 0;
time_t t = time(NULL);
struct tm *stm = localtime(&t);
struct timeval tv;
gettimeofday(&tv, NULL);
snprintf(buf, 127, CMD_SETTIME, 1900+stm->tm_year, stm->tm_mon+1, stm->tm_mday,
stm->tm_hour, stm->tm_min, stm->tm_sec, tv.tv_usec/10000);
DBG("write: %s", buf);
if(!write_cmd(buf, true)){
WARNX("Can't write current date/time");
LOGWARN("Can't set system time");
ret = false;
}else LOGMSG("Set system time by command %s", buf);
// set refraction model data
snprintf(buf, 127, CMD_SETPRESSURE, w->pressure*1013./760.);
if(!write_cmd(buf, true)){
LOGWARN("Can't set pressure data of refraction model");
ret = false;
}else LOGMSG("Correct pressure to %gmmHg", w->pressure);
snprintf(buf, 64, CMD_SETTEMPER, w->exttemp);
if(!write_cmd(buf, true)){
LOGWARN("Can't set temperature data of refraction model");
ret = false;
}else LOGMSG("Correct temperature to %g", w->exttemp);
if(!write_cmd(CMD_REFCORR_ON, true)) ret = false;
if(!write_cmd(CMD_DUALTRK, true)) ret = false;
pthread_mutex_unlock(&mntdev_mutex);
return ret;
}

View File

@@ -18,8 +18,16 @@
#pragma once #pragma once
#include <weather_data.h>
#include "angles.h" #include "angles.h"
// input coordinates lifetime - 24hrs
#define COORDS_OLD_T (86400)
// make datetime/pressure/temperature corrections each CORRECTIONS_TIMEDIFF seconds
#define CORRECTIONS_TIMEDIFF (3600)
// mount statuses // mount statuses
typedef enum{ typedef enum{
MNT_S_TRACKING = 0, MNT_S_TRACKING = 0,
@@ -55,21 +63,28 @@ double mount_getInpHor(horizCrds_t *c);
bool mount_set_name(const char *name); bool mount_set_name(const char *name);
void mount_get_name(char *nm, size_t l);
bool mount_set_dev(char *dev, int speed, double timeout); bool mount_set_dev(char *dev, int speed, double timeout);
const char* mount_status_str(mount_status_t st); const char* mount_status_str(mount_status_t st);
mount_status_t mount_status(); mount_status_t mount_status();
bool mount_connect(); bool mount_connect();
void mount_disconnect(); void mount_disconnect();
mount_status_t mount_getcoords(double *ra, double *dec); bool mount_getcoords(double *ra, double *dec);
mount_status_t mount_getaz(double *a, double *z); bool mount_getaz(double *a, double *z);
bool mount_corrdata(weather_data_t *w);
bool mount_getpierside(char *Ps, size_t len);
bool mount_point(double ra, double dec); bool mount_point(double ra, double dec);
bool mount_pointAZ(double A, double Z); bool mount_pointAZ(double A, double Z);
bool mount_stop(); bool mount_stop();
bool mount_tracking_stop(); bool mount_tracking_stop();
bool mount_tracking_start(); bool mount_tracking_start();
bool mount_park();
bool mount_park();
bool mount_setParkAz(double az); bool mount_setParkAz(double az);
bool mount_setParkZD(double zd); bool mount_setParkZD(double zd);
void mount_getPark(horizCrds_t *c); void mount_getPark(horizCrds_t *c);

View File

@@ -8,6 +8,8 @@ dome.c
dome.h dome.h
emulation.c emulation.c
emulation.h emulation.h
fitshdr.c
fitshdr.h
main.c main.c
server.c server.c
server.h server.h

View File

@@ -27,6 +27,7 @@
#include <usefull_macros.h> #include <usefull_macros.h>
#include <weather_data.h> #include <weather_data.h>
#include "fitshdr.h"
#include "mount.h" #include "mount.h"
#include "server.h" #include "server.h"
#include "stellarium.h" #include "stellarium.h"
@@ -64,7 +65,12 @@ static int stellarium_sockfd = -1;
// sleep time (us) // sleep time (us)
static unsigned int sleept = DEFAULT_SLEEP_T; static unsigned int sleept = DEFAULT_SLEEP_T;
// running flag // running flag
static volatile bool isrunning = false; volatile bool isrunning = false;
// lost weather flag
static bool weatherlost = false;
// data for FITS-header (also to send user)
static fitsheader_t HDR = {0};
unsigned int server_getsleept(){ return sleept; } unsigned int server_getsleept(){ return sleept; }
bool server_setsleept(unsigned int t){ bool server_setsleept(unsigned int t){
@@ -86,8 +92,7 @@ static sl_sock_hresult_e dtimeh(sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ con
// statust - text format status // statust - text format status
static sl_sock_hresult_e status(sl_sock_t *c, sl_sock_hitem_t *item, _U_ const char *req){ static sl_sock_hresult_e status(sl_sock_t *c, sl_sock_hitem_t *item, _U_ const char *req){
char buf[BUFSIZ]; char buf[BUFSIZ];
mount_status_t st = mount_status(); snprintf(buf, BUFSIZ-1, "%s=%s\n", item->key, mount_status_str(HDR.status));
snprintf(buf, BUFSIZ-1, "%s=%s\n", item->key, mount_status_str(st));
LOGDBG("Client %d asks status: %s", c->fd, buf); LOGDBG("Client %d asks status: %s", c->fd, buf);
sl_sock_sendstrmessage(c, buf); sl_sock_sendstrmessage(c, buf);
return RESULT_SILENCE; return RESULT_SILENCE;
@@ -123,7 +128,7 @@ static sl_sock_hresult_e cmd_tagra(sl_sock_t *c, sl_sock_hitem_t *item, const ch
return RESULT_SILENCE; return RESULT_SILENCE;
} }
static sl_sock_hresult_e cmd_tagdec(sl_sock_t *c, sl_sock_hitem_t *item, const char *req) { static sl_sock_hresult_e cmd_tagdec(sl_sock_t *c, sl_sock_hitem_t *item, const char *req){
double val; double val;
int res = parse_key_value(req, &val); int res = parse_key_value(req, &val);
if(res < 0) return RESULT_BADVAL; if(res < 0) return RESULT_BADVAL;
@@ -141,7 +146,7 @@ static sl_sock_hresult_e cmd_tagdec(sl_sock_t *c, sl_sock_hitem_t *item, const c
return RESULT_SILENCE; return RESULT_SILENCE;
} }
static sl_sock_hresult_e cmd_tagha(sl_sock_t *c, sl_sock_hitem_t *item, const char *req) { static sl_sock_hresult_e cmd_tagha(sl_sock_t *c, sl_sock_hitem_t *item, const char *req){
double val; double val;
int res = parse_key_value(req, &val); int res = parse_key_value(req, &val);
if(res < 0) return RESULT_BADVAL; if(res < 0) return RESULT_BADVAL;
@@ -159,7 +164,7 @@ static sl_sock_hresult_e cmd_tagha(sl_sock_t *c, sl_sock_hitem_t *item, const ch
return RESULT_SILENCE; return RESULT_SILENCE;
} }
static sl_sock_hresult_e cmd_tagaz(sl_sock_t *c, sl_sock_hitem_t *item, const char *req) { static sl_sock_hresult_e cmd_tagaz(sl_sock_t *c, sl_sock_hitem_t *item, const char *req){
double val; double val;
int res = parse_key_value(req, &val); int res = parse_key_value(req, &val);
if(res < 0) return RESULT_BADVAL; if(res < 0) return RESULT_BADVAL;
@@ -177,7 +182,7 @@ static sl_sock_hresult_e cmd_tagaz(sl_sock_t *c, sl_sock_hitem_t *item, const ch
return RESULT_SILENCE; return RESULT_SILENCE;
} }
static sl_sock_hresult_e cmd_tagzd(sl_sock_t *c, sl_sock_hitem_t *item, const char *req) { static sl_sock_hresult_e cmd_tagzd(sl_sock_t *c, sl_sock_hitem_t *item, const char *req){
double val; double val;
int res = parse_key_value(req, &val); int res = parse_key_value(req, &val);
if(res < 0) return RESULT_BADVAL; if(res < 0) return RESULT_BADVAL;
@@ -195,43 +200,40 @@ static sl_sock_hresult_e cmd_tagzd(sl_sock_t *c, sl_sock_hitem_t *item, const ch
return RESULT_SILENCE; return RESULT_SILENCE;
} }
static sl_sock_hresult_e cmd_telra(sl_sock_t *c, sl_sock_hitem_t *item, _U_ const char *req) { static sl_sock_hresult_e cmd_telra(sl_sock_t *c, sl_sock_hitem_t *item, _U_ const char *req){
double ra, dec; if(weatherlost || HDR.status == MNT_S_ERROR) return RESULT_FAIL;
if(mount_getcoords(&ra, &dec) == MNT_S_ERROR) return RESULT_FAIL;
char buf[64]; char buf[64];
snprintf(buf, 63, "%s=%.6f\n", item->key, ra); snprintf(buf, 63, "%s=%.6f\n", item->key, RAD2HRS(HDR.polar.ra));
sl_sock_sendstrmessage(c, buf); sl_sock_sendstrmessage(c, buf);
return RESULT_SILENCE; return RESULT_SILENCE;
} }
static sl_sock_hresult_e cmd_teldec(sl_sock_t *c, sl_sock_hitem_t *item, _U_ const char *req) { static sl_sock_hresult_e cmd_teldec(sl_sock_t *c, sl_sock_hitem_t *item, _U_ const char *req){
double ra, dec; if(weatherlost || HDR.status == MNT_S_ERROR) return RESULT_FAIL;
if(mount_getcoords(&ra, &dec) == MNT_S_ERROR) return RESULT_FAIL;
char buf[64]; char buf[64];
snprintf(buf, 63, "%s=%.6f\n", item->key, dec); snprintf(buf, 63, "%s=%.6f\n", item->key, RAD2DEG(HDR.polar.dec));
sl_sock_sendstrmessage(c, buf); sl_sock_sendstrmessage(c, buf);
return RESULT_SILENCE; return RESULT_SILENCE;
} }
static sl_sock_hresult_e cmd_telaz(sl_sock_t *c, sl_sock_hitem_t *item, _U_ const char *req) { static sl_sock_hresult_e cmd_telaz(sl_sock_t *c, sl_sock_hitem_t *item, _U_ const char *req){
double a, z; if(weatherlost || HDR.status == MNT_S_ERROR) return RESULT_FAIL;
if(mount_getaz(&a, &z) == MNT_S_ERROR) return RESULT_FAIL;
char buf[64]; char buf[64];
snprintf(buf, 63, "%s=%.6f\n", item->key, a); snprintf(buf, 63, "%s=%.6f\n", item->key, RAD2DEG(HDR.altaz.az));
sl_sock_sendstrmessage(c, buf); sl_sock_sendstrmessage(c, buf);
return RESULT_SILENCE; return RESULT_SILENCE;
} }
static sl_sock_hresult_e cmd_telzd(sl_sock_t *c, sl_sock_hitem_t *item, _U_ const char *req) { static sl_sock_hresult_e cmd_telzd(sl_sock_t *c, sl_sock_hitem_t *item, _U_ const char *req){
double a, z; if(weatherlost || HDR.status == MNT_S_ERROR) return RESULT_FAIL;
if(mount_getaz(&a, &z) == MNT_S_ERROR) return RESULT_FAIL;
char buf[64]; char buf[64];
snprintf(buf, 63, "%s=%.6f\n", item->key, z); snprintf(buf, 63, "%s=%.6f\n", item->key, RAD2DEG(HDR.altaz.zd));
sl_sock_sendstrmessage(c, buf); sl_sock_sendstrmessage(c, buf);
return RESULT_SILENCE; return RESULT_SILENCE;
} }
static sl_sock_hresult_e cmd_gotord(_U_ sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ const char *req) { static sl_sock_hresult_e cmd_gotord(_U_ sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ const char *req){
if(weatherlost || HDR.status == MNT_S_ERROR) return RESULT_FAIL;
polarCrds_t p; polarCrds_t p;
mount_getInpCoords(&p); mount_getInpCoords(&p);
double ra_h = RAD2HRS(p.ra); double ra_h = RAD2HRS(p.ra);
@@ -240,7 +242,8 @@ static sl_sock_hresult_e cmd_gotord(_U_ sl_sock_t *c, _U_ sl_sock_hitem_t *item,
return RESULT_OK; return RESULT_OK;
} }
static sl_sock_hresult_e cmd_gotorh(_U_ sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ const char *req) { static sl_sock_hresult_e cmd_gotorh(_U_ sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ const char *req){
if(weatherlost || HDR.status == MNT_S_ERROR) return RESULT_FAIL;
polarCrds_t p; polarCrds_t p;
mount_getInpCoords(&p); mount_getInpCoords(&p);
sMJD_t mjd; sMJD_t mjd;
@@ -254,25 +257,27 @@ static sl_sock_hresult_e cmd_gotorh(_U_ sl_sock_t *c, _U_ sl_sock_hitem_t *item,
return RESULT_OK; return RESULT_OK;
} }
static sl_sock_hresult_e cmd_gotoaz(_U_ sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ const char *req) { static sl_sock_hresult_e cmd_gotoaz(_U_ sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ const char *req){
if(weatherlost || HDR.status == MNT_S_ERROR) return RESULT_FAIL;
horizCrds_t h; horizCrds_t h;
mount_getInpHor(&h); mount_getInpHor(&h);
if(mount_pointAZ(RAD2DEG(h.az), RAD2DEG(h.zd))) return RESULT_OK; if(mount_pointAZ(RAD2DEG(h.az), RAD2DEG(h.zd))) return RESULT_OK;
return RESULT_FAIL; return RESULT_FAIL;
} }
static sl_sock_hresult_e cmd_stop(_U_ sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ const char *req) { static sl_sock_hresult_e cmd_stop(_U_ sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ const char *req){
if(mount_stop()) return RESULT_OK; if(mount_stop()) return RESULT_OK;
return RESULT_FAIL; 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) { 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; if(mount_tracking_stop()) return RESULT_OK;
return RESULT_FAIL; return RESULT_FAIL;
} }
// run tracking from current position // run tracking from current position
static sl_sock_hresult_e cmd_track(_U_ sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ const char *req) { static sl_sock_hresult_e cmd_track(_U_ sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ const char *req){
if(weatherlost || HDR.status == MNT_S_ERROR) return RESULT_FAIL;
if(mount_tracking_start()) return RESULT_OK; if(mount_tracking_start()) return RESULT_OK;
return RESULT_FAIL; return RESULT_FAIL;
} }
@@ -423,12 +428,15 @@ void server_run(){
LOGERR("Can't start stellarium server"); LOGERR("Can't start stellarium server");
return; return;
} }
isrunning = true;
if(!mount_connect()){ if(!mount_connect()){
LOGWARN("Can't connect to mount, will try to reconnect later"); LOGWARN("Can't connect to mount, will try to reconnect later");
} }
isrunning = true;
DBG("While"); DBG("While");
double tcheck = 0.; double tcheck = 0., treconnect = sl_dtime();
time_t lastweathertime = 0;
getPlaceData(&HDR.place);
mount_get_name(HDR.mountname, MAX_HDR_STRLEN);
bool notlogged = true; bool notlogged = true;
while(isrunning && cmd_socket && cmd_socket->connected){ while(isrunning && cmd_socket && cmd_socket->connected){
usleep(sleept); usleep(sleept);
@@ -440,22 +448,59 @@ void server_run(){
double tnow = sl_dtime(); double tnow = sl_dtime();
if(tnow - tcheck >= MOUNT_CHECK_T){ if(tnow - tcheck >= MOUNT_CHECK_T){
tcheck = tnow; tcheck = tnow;
mount_status_t curst = mount_status(); if(get_weather_data(&HDR.weather) == 0){
if(curst == MNT_S_OFF){ // mount is off -> try to reconnect lastweathertime = HDR.weather.last_update;
}else{
WARNX("Can't get weather data");
}
// collect data for other fields
HDR.status = mount_status();
get_MJDt(NULL, &HDR.MJD);
get_LST(&HDR.MJD, &HDR.sidtime);
if(HDR.status != MNT_S_OFF){
double deg1, deg2;
if(mount_getcoords(&deg1, &deg2)){
HDR.polar.ra = DEG2RAD(deg1);
HDR.polar.dec = DEG2RAD(deg2);
}
if(mount_getaz(&deg1, &deg2)){
HDR.altaz.az = DEG2RAD(deg1);
HDR.altaz.zd = DEG2RAD(deg2);
}
}
if(tnow - lastweathertime > MOUNT_WEATHER_ALRM){
weatherlost = true;
if(HDR.status == MNT_S_TRACKING || HDR.status == MNT_S_SLEWING){
LOGERR("Lost meteo connection -> park");
if(mount_park()) lastweathertime = tnow;
}
} else weatherlost = false;
getDUT(&HDR.dut);
if(HDR.status == MNT_S_OFF || !mount_getpierside(HDR.pierside, MAX_HDR_STRLEN)) *HDR.pierside = 0;
// and write FITS-header
wrhdr(&HDR);
// check need of reconnection
if(HDR.status == MNT_S_OFF){ // mount is off -> try to reconnect
if(notlogged){ if(notlogged){
WARNX("Mount is OFF"); WARNX("Mount is OFF");
LOGWARN("Mount is OFF"); LOGWARN("Mount is OFF");
notlogged = false; notlogged = false;
} }
DBG("Try to [re]connect"); if(tnow - treconnect >= MOUNT_RECONNECT_T){
if(mount_connect()){ treconnect = tnow;
notlogged = true; DBG("Try to [re]connect");
WARNX("Mount is ON"); if(mount_connect()){
notlogged = true;
WARNX("Mount is ON");
}
} }
} }
DBG("Current status: %s", mount_status_str(curst)); DBG("Current status: %s", mount_status_str(HDR.status));
} }
} }
DBG("Stop mount");
double t0 = sl_dtime();
while(sl_dtime() - t0 < 3. && !mount_stop());
DBG("Stop command socket"); DBG("Stop command socket");
sl_sock_delete(&cmd_socket); sl_sock_delete(&cmd_socket);
WARNX("Server is dead"); WARNX("Server is dead");

View File

@@ -27,8 +27,10 @@
// maximal amount of connected clients // maximal amount of connected clients
#define DEFAULT_MAXCLIENTS 5 #define DEFAULT_MAXCLIENTS 5
// status checking interval, seconds // try to reconnect each RECONN seconds
#define MOUNT_CHECK_T 10. #define MOUNT_RECONNECT_T 60.
// max weather lost time
#define MOUNT_WEATHER_ALRM 900.
typedef struct{ typedef struct{
int cmd_isunix; // UNIX-socket instead of INET for `cmdnode` int cmd_isunix; // UNIX-socket instead of INET for `cmdnode`
@@ -37,6 +39,8 @@ typedef struct{
int maxclients; // maximal amount of clients connected int maxclients; // maximal amount of clients connected
} server_sock_t; } server_sock_t;
extern volatile bool isrunning;
bool server_check(server_sock_t *sockt); bool server_check(server_sock_t *sockt);
void server_run(); void server_run();
void server_stop(); void server_stop();

View File

@@ -162,12 +162,13 @@ static void *handle_socket(void *sockd){
dout.type = 0; dout.type = 0;
while(isrunning){ while(isrunning){
// get coordinates // get coordinates
double RA = 0., Decl = 0.; double Rhrs = 0., Ddeg = 0.;
if((dout.status = mount_getcoords(&RA, &Decl)) == MNT_S_ERROR){ if((dout.status = mount_getcoords(&Rhrs, &Ddeg)) == false){
WARNX("Error: can't get coordinates"); WARNX("Error: can't get coordinates");
sleep(1); sleep(1);
continue; continue;
} }
double RA = HRS2RAD(Rhrs), Decl = DEG2RAD(Ddeg);
//DBG("got : %g/%g", RA, Decl); //DBG("got : %g/%g", RA, Decl);
dout.ra = htole32(RAD2RA(RA)); dout.ra = htole32(RAD2RA(RA));
dout.dec = (int32_t)htole32(RAD2DEC(Decl)); dout.dec = (int32_t)htole32(RAD2DEC(Decl));