add heater commands and fits-header creation

This commit is contained in:
2026-03-31 17:54:09 +03:00
parent cae7a6e213
commit 0f0c87ee2f
12 changed files with 402 additions and 46 deletions

View File

@@ -0,0 +1,23 @@
PROGRAM = stellariumdaemon
LDFLAGS = -lerfa -pthread -lusefull_macros
SRCS = $(wildcard *.c)
CC = gcc
DEFINES = -D_GNU_SOURCE -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=1111
DEFINES += -DEBUG
CXX = gcc
CFLAGS = -Wall -Werror -Wextra -Wno-trampolines $(DEFINES)
OBJS = $(SRCS:.c=.o)
all : $(PROGRAM)
$(PROGRAM) : $(OBJS)
$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $(PROGRAM)
# some addition dependencies
# %.o: %.c
# $(CC) $(LDFLAGS) $(CFLAGS) $< -o $@
#$(SRCS) : %.c : %.h $(INDEPENDENT_HEADERS)
# @touch $@
clean:
/bin/rm -f *.o *~
depend:
$(CXX) -MM $(CXX.SRCS)

View File

@@ -0,0 +1,6 @@
Stellarium control of 10-micron mount
Special commands in terminal mode:
PAUSE - pause output to port from everywhere except terminal thread
CONTINUE - allow to write to port for everyone

View File

@@ -5,7 +5,7 @@ LDFLAGS += -lusefull_macros
SRCS := $(wildcard *.c) SRCS := $(wildcard *.c)
DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111 DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111
OBJDIR := mk OBJDIR := mk
CFLAGS += -O2 -Wall -Wextra -Wno-trampolines -std=gnu23 CFLAGS += -O2 -Wall -Wextra -Wno-trampolines -Wno-format-truncation -std=gnu23
OBJS := $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o)) OBJS := $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o))
DEPS := $(OBJS:.o=.d) DEPS := $(OBJS:.o=.d)
TARGFILE := $(OBJDIR)/TARGET TARGFILE := $(OBJDIR)/TARGET

View File

@@ -31,8 +31,12 @@
#define TXT_COOLEROFF "COOLEROFF?\r" #define TXT_COOLEROFF "COOLEROFF?\r"
#define TXT_COOLERT "COOLERT?\r" #define TXT_COOLERT "COOLERT?\r"
#define TXT_COOLERSTAT "COOLERSTATUS?\r" #define TXT_COOLERSTAT "COOLERSTATUS?\r"
#define TXT_HEATON "HEATON?100\r"
#define TXT_HEATOFF "HEATOFF?\r"
#define TXT_HEATSTAT "HEATSTATUS?\r"
#define TXT_PING "PING?\r" #define TXT_PING "PING?\r"
#define TXT_ANS_OK "OK" #define TXT_ANS_OK "OK"
#define TXT_ANS_HEATSTAT "OK\rHEATERSTATUS?"
#define TXT_ANS_COOLERSTAT "OK\rCOOLERPWM?" #define TXT_ANS_COOLERSTAT "OK\rCOOLERPWM?"
#define TXT_ANS_COOLERT "OK\rCOOLERT?" #define TXT_ANS_COOLERT "OK\rCOOLERT?"
#define TXT_ANS_STATUS "OK\rSHUTTERS?" #define TXT_ANS_STATUS "OK\rSHUTTERS?"

View File

@@ -0,0 +1,141 @@
/*
* This file is part of the teldaemon 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 <limits.h>
#include <string.h>
#include <sys/stat.h>
#include <usefull_macros.h>
#include "header.h"
#include "socket.h"
static char *headername = NULL;
static char *telescope_name = NULL;
static header_mask_t header_mask = {0};
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);
key = tk;
}
if(cmnt){
snprintf(tmp, 81, "%-8s= %-21s / %s", key, val, cmnt);
}else{
snprintf(tmp, 81, "%-8s= %s", key, val);
}
size_t l = strlen(tmp);
tmp[l] = '\n';
++l;
if(write(fd, tmp, l) != (ssize_t)l){
WARN("write()");
return 1;
}
return 0;
}
// return TRUE if can write to given header file
int header_create(const char *file, int flags){
if(!file || flags < 0 || flags > 0xff) return FALSE;
FILE *hf = fopen(file, "w");
if(!hf) return FALSE;
unlink(file);
if(headername) FREE(headername);
headername = strdup(file);
header_mask.flags = (uint8_t)flags;
return TRUE;
}
// set given `name` for telescope name
void telname(const char *name){
if(telescope_name) FREE(telescope_name);
if(name){
int l = strlen(name) + 3;
telescope_name = MALLOC(char, l);
snprintf(telescope_name, l-1, "'%s'", name);
}
}
// return static buffer with help
const char *getheadermaskhelp(){
return
"0 - telescope name\n"
"1 - focuser status\n"
"2 - cooler status\n"
"3 - heater status\n"
"4 - external temperature\n"
"5 - mirror temperature\n"
"6 - measured time\n"
;
}
void write_header(){
if(!headername || !header_mask.flags) return;
char aname[PATH_MAX];
char val[22];
telstatus_t st;
#define WRHDR(k, v, c) do{if(printhdr(fd, k, v, c)){goto returning;}}while(0)
snprintf(aname, PATH_MAX-1, "%sXXXXXX", headername);
int fd = mkstemp(aname);
if(fd < 0){
LOGWARN("Can't write header file: mkstemp()");
return;
}
fchmod(fd, 0644);
if(get_telescope_data(&st)) WRHDR("OPERATIO", "'FORBIDDEN'", "Observations are forbidden");
if(header_mask.telname && telescope_name) WRHDR("TELESCOP", telescope_name, "Telescope name");
if(header_mask.fosuser){
snprintf(val, 21, "%d", st.focuserpos);
WRHDR("FOCUS", val, "Current focuser position");
}
if(header_mask.cooler){
snprintf(val, 21, "%d", st.cooler);
WRHDR("COOLER", val, "Primary mirror cooler status: 0/1 (off/on)");
}
if(header_mask.heater){
snprintf(val, 21, "%d", st.heater);
WRHDR("HEATER", val, "Secondary mirror heater status: 0/1 (off/on)");
}
if(header_mask.exttemp){
snprintf(val, 21, "%.1f", st.ambienttemp);
WRHDR("TDOME", val, "In-dome temperature, degC");
}
if(header_mask.mirtemp){
snprintf(val, 21, "%.1f", st.mirrortemp);
WRHDR("TMIRROR", val, "Mirror temperature, degC");
}
if(header_mask.meastime){
snprintf(val, 21, "%.3f", st.stattime);
char timebuf[BUFSIZ];
time_t t = (time_t) st.stattime;
struct tm *tmp;
tmp = localtime(&t);
if(!tmp || 0 == strftime(timebuf, BUFSIZ, "Measurement time: %F %T", tmp)){
LOGERR("localtime() returned NULL");
goto returning;
}
WRHDR("TMEAS", val, timebuf);
}
#undef WRHDR
returning:
close(fd);
rename(aname, headername);
}

View File

@@ -0,0 +1,39 @@
/*
* This file is part of the teldaemon 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/>.
*/
#pragma once
#include <stdint.h>
typedef union{
struct{
uint8_t telname : 1; // show telescope name
uint8_t fosuser : 1; // show focuser status
uint8_t cooler : 1; // show cooler status
uint8_t heater : 1; // show heater status
uint8_t exttemp : 1; // show external temperature
uint8_t mirtemp : 1; // show mirror temperature
uint8_t meastime: 1; // show measurement time
};
uint8_t flags; // alltogether as single flags
} header_mask_t;
const char *getheadermaskhelp();
void write_header();
int header_create(const char *file, int flags);
void telname(const char *name);

View File

@@ -20,77 +20,125 @@
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <linux/prctl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <usefull_macros.h> #include <usefull_macros.h>
#include "header.h"
#include "socket.h" #include "socket.h"
#include "term.h" #include "term.h"
#define DEFAULT_PIDFILE "/tmp/teldaemon.pid"
#define DEFAULT_HEADERFILE "/tmp/telescope.pid"
#define DEFAULT_TELNAME "Astro-M (1)"
static pid_t childpid = 0;
typedef struct{ typedef struct{
int help; int help;
int verbose; int verbose;
int isunix; int isunix;
int maxclients; int maxclients;
int serspeed; int serspeed;
int headermask;
double sertmout; double sertmout;
char *logfile; char *logfile;
char *node; char *node;
char *termpath; char *termpath;
char *pidfile; char *pidfile;
char *headerfile;
char *telescope_name;
} parameters; } parameters;
static parameters G = { static parameters G = {
.maxclients = 2, .maxclients = 2,
.serspeed = 9600, .serspeed = 9600,
.sertmout = 1000., .sertmout = 1000.,
.pidfile = DEFAULT_PIDFILE,
.headerfile = DEFAULT_HEADERFILE,
.telescope_name = DEFAULT_TELNAME,
.headermask = 0xff,
}; };
static sl_option_t cmdlnopts[] = { static sl_option_t cmdlnopts[] = {
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&G.help), "show this help"}, {"help", NO_ARGS, NULL, 'h', arg_int, APTR(&G.help), "show this help"},
{"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verbose), "verbose level (each -v adds 1)"}, {"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verbose), "verbose level (each -v adds 1)"},
{"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&G.logfile), "log file name"}, {"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&G.logfile), "log file name (FULL path)"},
{"node", NEED_ARG, NULL, 'n', arg_string, APTR(&G.node), "node \"IP\", \"name:IP\" or path (could be \"\\0path\" for anonymous UNIX-socket)"}, {"node", NEED_ARG, NULL, 'n', arg_string, APTR(&G.node), "node \"IP\", \"name:IP\" or path (could be \"\\0path\" for anonymous UNIX-socket)"},
{"unixsock", NO_ARGS, NULL, 'u', arg_int, APTR(&G.isunix), "UNIX socket instead of INET"}, {"unixsock", NO_ARGS, NULL, 'u', arg_int, APTR(&G.isunix), "UNIX socket instead of INET"},
{"maxclients", NEED_ARG, NULL, 'm', arg_int, APTR(&G.maxclients),"max amount of clients connected to server (default: 2)"}, {"maxclients", NEED_ARG, NULL, 'm', arg_int, APTR(&G.maxclients),"max amount of clients connected to server (default: 2)"},
{"pidfile", NEED_ARG, NULL, 'p', arg_string, APTR(&G.pidfile), "PID-file"}, {"pidfile", NEED_ARG, NULL, 'p', arg_string, APTR(&G.pidfile), "PID-file (FULL path, default: " DEFAULT_PIDFILE ")"},
{"serialdev", NEED_ARG, NULL, 'd', arg_string, APTR(&G.termpath), "full path to serial device"}, {"serialdev", NEED_ARG, NULL, 'd', arg_string, APTR(&G.termpath), "full path to serial device"},
{"baudrate", NEED_ARG, NULL, 'b', arg_int, APTR(&G.serspeed), "serial device speed (baud)"}, {"baudrate", NEED_ARG, NULL, 'b', arg_int, APTR(&G.serspeed), "serial device speed (baud)"},
{"sertmout", NEED_ARG, NULL, 'T', arg_double, APTR(&G.sertmout), "serial device timeout (us)"}, {"sertmout", NEED_ARG, NULL, 't', arg_double, APTR(&G.sertmout), "serial device timeout (us)"},
{"headerfile", NEED_ARG, NULL, 'H', arg_string, APTR(&G.headerfile),"full path to output FITS-header"},
{"telname", NEED_ARG, NULL, 'N', arg_string, APTR(&G.telescope_name), "telescope name in FITS-header"},
{"headermask", NEED_ARG, NULL, 'M', arg_int, APTR(&G.headermask), "mask of header file (try -1 for help; default: show all)"},
end_option end_option
}; };
void sl_iffound_deflt(pid_t pid){
WARNX("Another copy of this process found, pid=%d. Exit.", pid);
exit(1); // don't run `signals` to protect foreign PID-file from removal
}
// SIGUSR1 - FORBID observations // SIGUSR1 - FORBID observations
// SIGUSR2 - allow // SIGUSR2 - allow
void signals(int sig){ void signals(int sig){
if(sig){ if(sig){
if(signals != signal(sig, SIG_IGN)) exit(sig); // function called "as is", before sig registration
if(childpid == 0){ // child -> test USR1/USR2
LOGDBG("Child gotta signal %d", sig);
if(sig == SIGUSR1){ if(sig == SIGUSR1){
forbid_observations(1); forbid_observations(1);
LOGMSG("Got signal `observations forbidden`");
signal(sig, signals);
return; return;
}else if(sig == SIGUSR2){ }else if(sig == SIGUSR2){
forbid_observations(0); forbid_observations(0);
LOGMSG("Got signal `observations permitted`");
signal(sig, signals);
return; return;
} }
signal(sig, SIG_IGN); }
DBG("Get signal %d, quit.\n", sig); LOGDBG("Get signal %d, quit.\n", sig);
LOGERR("Exit with status %d", sig); }
}else LOGERR("Exit"); if(childpid == 0){
DBG("Stop server"); DBG("Stop server");
LOGMSG("Stop server");
stopserver(); stopserver();
DBG("Close terminal"); DBG("Close terminal");
LOGMSG("Close terminal");
term_close(); term_close();
DBG("Exit"); }else{
if(G.pidfile){
LOGMSG("Unlink %s", G.pidfile);
usleep(10000);
unlink(G.pidfile);
}
}
LOGERR("Exit with status %d", sig);
exit(sig); exit(sig);
} }
int main(int argc, char **argv){ int main(int argc, char **argv){
sl_init(); sl_init();
sl_parseargs(&argc, &argv, cmdlnopts); sl_parseargs(&argc, &argv, cmdlnopts);
if(G.help) sl_showhelp(-1, cmdlnopts); if(G.help) sl_showhelp(-1, cmdlnopts);
if(!G.node) ERRX("Point node"); if(G.headermask < 0){
green("Header mask bits (set to show info, clear to hide):\n");
printf("%s\n", getheadermaskhelp());
return 0;
}
if(!G.node) ERRX("Point communication node");
if(!G.termpath) ERRX("Point serial device path"); if(!G.termpath) ERRX("Point serial device path");
sl_check4running((char*)__progname, G.pidfile); if(!header_create(G.headerfile, G.headermask))
ERRX("Cannot write into '%s'", G.headerfile);
telname(G.telescope_name);
sl_check4running(NULL, G.pidfile);
if(sl_daemonize()) ERR("Can't daemonize!");
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;
if(G.logfile) OPENLOG(G.logfile, lvl, 1); if(G.logfile) OPENLOG(G.logfile, lvl, 1);
@@ -103,11 +151,26 @@ int main(int argc, char **argv){
signal(SIGINT, signals); signal(SIGINT, signals);
signal(SIGQUIT, signals); signal(SIGQUIT, signals);
signal(SIGTSTP, SIG_IGN); signal(SIGTSTP, SIG_IGN);
signal(SIGHUP, signals); signal(SIGUSR1, SIG_IGN);
signal(SIGUSR2, SIG_IGN);
while(1){ // guard for dead processes
childpid = fork();
if(childpid){
LOGMSG("create child with PID %d\n", childpid);
DBG("Created child with PID %d\n", childpid);
wait(NULL);
WARNX("Child %d died\n", childpid);
LOGWARN("Child %d died\n", childpid);
sleep(1);
}else{
prctl(PR_SET_PDEATHSIG, SIGTERM); // send SIGTERM to child when parent dies
break; // go out to normal functional
}
}
// react for USRx only in child
signal(SIGUSR1, signals); signal(SIGUSR1, signals);
signal(SIGUSR2, signals); signal(SIGUSR2, signals);
runserver(G.isunix, G.node, G.maxclients); runserver(G.isunix, G.node, G.maxclients);
LOGMSG("Ended"); LOGERR("Server error -> exit");
DBG("Close");
return 0; return 0;
} }

View File

@@ -22,6 +22,7 @@
#include <string.h> #include <string.h>
#include "commands.h" #include "commands.h"
#include "header.h"
#include "socket.h" #include "socket.h"
#include "term.h" #include "term.h"
@@ -31,22 +32,21 @@ typedef enum{
CMD_FOCSTOP, CMD_FOCSTOP,
CMD_COOLERON, CMD_COOLERON,
CMD_COOLEROFF, CMD_COOLEROFF,
CMD_HEATERON,
CMD_HEATEROFF,
CMD_NONE CMD_NONE
} tel_commands_t; } tel_commands_t;
typedef struct{ typedef struct{
tel_commands_t cmd; // deferred command
tel_commands_t errcmd; // command ended with error
int focuserpos; // focuser position int focuserpos; // focuser position
char *status; // device status char status[STATBUF_SZ]; // device status
int statlen; // size of `status` buffer
double stattime; // time of last status double stattime; // time of last status
int cooler; // cooler's status int cooler; // cooler's status
int heater; // heater's status
double mirrortemp; // T mirror, degC double mirrortemp; // T mirror, degC
double ambienttemp; // T ambient, degC double ambienttemp; // T ambient, degC
double temptime; // measurement time tel_commands_t cmd; // deferred command
tel_commands_t errcmd; // command ended with error
pthread_mutex_t mutex; pthread_mutex_t mutex;
} tel_t; } tel_t;
@@ -65,6 +65,19 @@ void stopserver(){
if(locksock) sl_sock_delete(&locksock); if(locksock) sl_sock_delete(&locksock);
} }
/**
* @brief get_telescope_data - copy local `telescope` to `t`
* @param t (i) - pointer to your struct
* @return true if observations are permitted and false if forbidden
*/
bool get_telescope_data(telstatus_t *t){
if(!t) return false;
pthread_mutex_lock(&telescope.mutex);
*t = *((telstatus_t*)&telescope);
pthread_mutex_unlock(&telescope.mutex);
return ForbidObservations;
}
// send "measuret=..." // send "measuret=..."
static void sendtmeasured(sl_sock_t *client, double t){ static void sendtmeasured(sl_sock_t *client, double t){
char buf[256]; char buf[256];
@@ -160,6 +173,26 @@ static sl_sock_hresult_e coolerh(sl_sock_t *client, sl_sock_hitem_t *item, const
return RESULT_SILENCE; return RESULT_SILENCE;
} }
static sl_sock_hresult_e heaterh(sl_sock_t *client, sl_sock_hitem_t *item, const char *req){
char buf[256];
if(req){ // getter
int onoff;
if(!sl_str2i(&onoff, req)) return RESULT_BADVAL;
pthread_mutex_lock(&telescope.mutex);
if(onoff) telescope.cmd = CMD_HEATERON;
else telescope.cmd = CMD_HEATEROFF;
pthread_mutex_unlock(&telescope.mutex);
return RESULT_OK;
}
// getter
pthread_mutex_lock(&telescope.mutex);
snprintf(buf, 255, "%s=%d\n", item->key, telescope.heater);
pthread_mutex_unlock(&telescope.mutex);
sl_sock_sendstrmessage(client, buf);
return RESULT_SILENCE;
}
// focuser getter // focuser getter
static sl_sock_hresult_e foch(sl_sock_t *client, sl_sock_hitem_t *item, _U_ const char *req){ static sl_sock_hresult_e foch(sl_sock_t *client, sl_sock_hitem_t *item, _U_ const char *req){
char buf[256]; char buf[256];
@@ -217,6 +250,7 @@ static sl_sock_hitem_t handlers[] = {
{statush, "status", "get shutters' status and temperatures", NULL}, {statush, "status", "get shutters' status and temperatures", NULL},
{fstoph, "focstop", "stop focuser moving", NULL}, {fstoph, "focstop", "stop focuser moving", NULL},
{coolerh, "cooler", "get/set cooler status", NULL}, {coolerh, "cooler", "get/set cooler status", NULL},
{heaterh, "heater", "get/set heater status", NULL},
{dtimeh, "dtime", "get server's UNIX time for all clients connected", NULL}, {dtimeh, "dtime", "get server's UNIX time for all clients connected", NULL},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };
@@ -239,9 +273,9 @@ static int poll_device(){
DBG("\nGot status"); DBG("\nGot status");
pthread_mutex_lock(&telescope.mutex); pthread_mutex_lock(&telescope.mutex);
telescope.stattime = sl_dtime(); telescope.stattime = sl_dtime();
if(strncmp(data, "0,0,0,0,0", 9) == 0) snprintf(telescope.status, telescope.statlen, "closed"); if(strncmp(data, "0,0,0,0,0", 9) == 0) snprintf(telescope.status, STATBUF_SZ-1, "closed");
else if(strncmp(data, "1,1,1,1,1", 9) == 0) snprintf(telescope.status, telescope.statlen, "opened"); else if(strncmp(data, "1,1,1,1,1", 9) == 0) snprintf(telescope.status, STATBUF_SZ-1, "opened");
else snprintf(telescope.status, telescope.statlen, "intermediate"); else snprintf(telescope.status, STATBUF_SZ-1, "intermediate");
pthread_mutex_unlock(&telescope.mutex); pthread_mutex_unlock(&telescope.mutex);
if(!(data = term_cmdwans(TXT_COOLERT, TXT_ANS_COOLERT, ans))) return FALSE; if(!(data = term_cmdwans(TXT_COOLERT, TXT_ANS_COOLERT, ans))) return FALSE;
@@ -253,7 +287,6 @@ static int poll_device(){
telescope.mirrortemp = m; telescope.mirrortemp = m;
pthread_mutex_unlock(&telescope.mutex); pthread_mutex_unlock(&telescope.mutex);
} }
if(!(data = term_cmdwans(TXT_COOLERSTAT, TXT_ANS_COOLERSTAT, ans))) return FALSE; if(!(data = term_cmdwans(TXT_COOLERSTAT, TXT_ANS_COOLERSTAT, ans))) return FALSE;
DBG("\nGot cooler status"); DBG("\nGot cooler status");
if(sscanf(data, "%d", &I) == 1){ if(sscanf(data, "%d", &I) == 1){
@@ -261,6 +294,13 @@ static int poll_device(){
telescope.cooler = I; telescope.cooler = I;
pthread_mutex_unlock(&telescope.mutex); pthread_mutex_unlock(&telescope.mutex);
} }
if(!(data = term_cmdwans(TXT_HEATSTAT, TXT_ANS_HEATSTAT, ans))) return FALSE;
DBG("\nGot heater status");
if(sscanf(data, "%d", &I) == 1){
pthread_mutex_lock(&telescope.mutex);
telescope.heater = I;
pthread_mutex_unlock(&telescope.mutex);
}
return TRUE; return TRUE;
} }
@@ -269,9 +309,6 @@ void runserver(int isunix, const char *node, int maxclients){
int forbidden = 0; int forbidden = 0;
if(locksock) sl_sock_delete(&locksock); if(locksock) sl_sock_delete(&locksock);
telescope.errcmd = telescope.cmd = CMD_NONE; telescope.errcmd = telescope.cmd = CMD_NONE;
FREE(telescope.status);
telescope.statlen = STATBUF_SZ;
telescope.status = MALLOC(char, STATBUF_SZ);
pthread_mutex_init(&telescope.mutex, NULL); pthread_mutex_init(&telescope.mutex, NULL);
sl_socktype_e type = (isunix) ? SOCKT_UNIX : SOCKT_NET; sl_socktype_e type = (isunix) ? SOCKT_UNIX : SOCKT_NET;
locksock = sl_sock_run_server(type, node, -1, handlers); locksock = sl_sock_run_server(type, node, -1, handlers);
@@ -298,7 +335,10 @@ void runserver(int isunix, const char *node, int maxclients){
} }
double tnow = sl_dtime(); double tnow = sl_dtime();
if(tnow - tgot > T_INTERVAL){ if(tnow - tgot > T_INTERVAL){
if(poll_device()) tgot = tnow; if(poll_device()){
tgot = tnow;
write_header();
}
} }
if(ForbidObservations) continue; if(ForbidObservations) continue;
pthread_mutex_lock(&telescope.mutex); pthread_mutex_lock(&telescope.mutex);
@@ -308,23 +348,50 @@ void runserver(int isunix, const char *node, int maxclients){
switch(tcmd){ switch(tcmd){
case CMD_OPEN: case CMD_OPEN:
DBG("received command: open"); DBG("received command: open");
if(term_cmdwans(TXT_OPEN, TXT_ANS_OK, ans)) tcmd = CMD_NONE; if(term_cmdwans(TXT_OPEN, TXT_ANS_OK, ans)){
LOGMSG("Open dome");
tcmd = CMD_NONE;
}
break; break;
case CMD_CLOSE: case CMD_CLOSE:
DBG("received command: close"); DBG("received command: close");
if(term_cmdwans(TXT_CLOSE, TXT_ANS_OK, ans)) tcmd = CMD_NONE; if(term_cmdwans(TXT_CLOSE, TXT_ANS_OK, ans)){
LOGMSG("Close dome");
tcmd = CMD_NONE;
}
break; break;
case CMD_FOCSTOP: case CMD_FOCSTOP:
DBG("received command: stop focus"); DBG("received command: stop focus");
LOGMSG("Stop focus");
term_write(TXT_FOCSTOP, ans); tcmd = CMD_NONE; // erroreous thing: no answer for this command term_write(TXT_FOCSTOP, ans); tcmd = CMD_NONE; // erroreous thing: no answer for this command
break; break;
case CMD_COOLEROFF: case CMD_COOLEROFF:
DBG("received command: cooler off"); DBG("received command: cooler off");
if(term_cmdwans(TXT_COOLEROFF, TXT_ANS_OK, ans)) tcmd = CMD_NONE; if(term_cmdwans(TXT_COOLEROFF, TXT_ANS_OK, ans)){
LOGMSG("Cooler off");
tcmd = CMD_NONE;
}
break; break;
case CMD_COOLERON: case CMD_COOLERON:
DBG("received command: cooler on"); DBG("received command: cooler on");
if(term_cmdwans(TXT_COOLERON, TXT_ANS_OK, ans)) tcmd = CMD_NONE; if(term_cmdwans(TXT_COOLERON, TXT_ANS_OK, ans)){
LOGMSG("Cooler on");
tcmd = CMD_NONE;
}
break;
case CMD_HEATERON:
DBG("received command: heater on");
if(term_cmdwans(TXT_HEATON, TXT_ANS_OK, ans)){
LOGMSG("Heater on");
tcmd = CMD_NONE;
}
break;
case CMD_HEATEROFF:
DBG("received command: heater off");
if(term_cmdwans(TXT_HEATOFF, TXT_ANS_OK, ans)){
LOGMSG("Heater off");
tcmd = CMD_NONE;
}
break; break;
default: default:
DBG("WTF?"); DBG("WTF?");

View File

@@ -25,6 +25,17 @@
// dome polling interval (clear watchdog & get status) // dome polling interval (clear watchdog & get status)
#define T_INTERVAL (2.0) #define T_INTERVAL (2.0)
typedef struct{
int focuserpos; // focuser position
char status[STATBUF_SZ]; // device status
double stattime; // time of last status
int cooler; // cooler's status
int heater; // heater's status
double mirrortemp; // T mirror, degC
double ambienttemp; // T ambient, degC
} telstatus_t;
void runserver(int isunix, const char *node, int maxclients); void runserver(int isunix, const char *node, int maxclients);
void stopserver(); void stopserver();
void forbid_observations(int forbid); void forbid_observations(int forbid);
bool get_telescope_data(telstatus_t *t);

View File

@@ -1 +1 @@
-std=c17 -std=c23

View File

@@ -1 +1 @@
-std=c++17 -std=c++23

View File

@@ -1,4 +1,6 @@
commands.h commands.h
header.c
header.h
main.c main.c
socket.c socket.c
socket.h socket.h