From ef2c86675e9f55d84a59f9cbf1556cd826a7523b Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Thu, 29 May 2025 17:32:00 +0300 Subject: [PATCH] pre-alpha version of new dome daemon --- .../Makefile | 0 .../domedaemon-astrosib.deprecated/Readme.md | 12 + .../cmdlnopts.c | 0 .../cmdlnopts.h | 0 .../domeasib.cflags | 0 .../domeasib.config | 0 .../domeasib.creator | 0 .../domeasib.creator.user | 0 .../domeasib.cxxflags | 0 .../domeasib.files | 0 .../domeasib.includes | 0 Daemons/domedaemon-astrosib.deprecated/main.c | 89 ++++++ .../parseargs.c | 0 .../parseargs.h | 0 .../socket.c | 0 .../socket.h | 0 .../term.c | 0 .../term.h | 0 .../usefull_macros.c | 0 .../usefull_macros.h | 0 Daemons/domedaemon-astrosib/CMakeLists.txt | 64 +++++ Daemons/domedaemon-astrosib/Readme.md | 13 +- Daemons/domedaemon-astrosib/astrosib_proto.h | 27 ++ Daemons/domedaemon-astrosib/dome.c | 257 ++++++++++++++++++ Daemons/domedaemon-astrosib/dome.h | 65 +++++ .../domedaemon-astrosib.cflags | 1 + .../domedaemon-astrosib.config | 2 + .../domedaemon-astrosib.creator | 1 + .../domedaemon-astrosib.cxxflags | 1 + .../domedaemon-astrosib.files | 6 + .../domedaemon-astrosib.includes | 0 Daemons/domedaemon-astrosib/main.c | 129 +++++---- Daemons/domedaemon-astrosib/server.c | 166 +++++++++++ Daemons/domedaemon-astrosib/server.h | 23 ++ 34 files changed, 794 insertions(+), 62 deletions(-) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/Makefile (100%) create mode 100644 Daemons/domedaemon-astrosib.deprecated/Readme.md rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/cmdlnopts.c (100%) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/cmdlnopts.h (100%) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/domeasib.cflags (100%) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/domeasib.config (100%) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/domeasib.creator (100%) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/domeasib.creator.user (100%) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/domeasib.cxxflags (100%) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/domeasib.files (100%) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/domeasib.includes (100%) create mode 100644 Daemons/domedaemon-astrosib.deprecated/main.c rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/parseargs.c (100%) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/parseargs.h (100%) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/socket.c (100%) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/socket.h (100%) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/term.c (100%) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/term.h (100%) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/usefull_macros.c (100%) rename Daemons/{domedaemon-astrosib => domedaemon-astrosib.deprecated}/usefull_macros.h (100%) create mode 100644 Daemons/domedaemon-astrosib/CMakeLists.txt create mode 100644 Daemons/domedaemon-astrosib/astrosib_proto.h create mode 100644 Daemons/domedaemon-astrosib/dome.c create mode 100644 Daemons/domedaemon-astrosib/dome.h create mode 100644 Daemons/domedaemon-astrosib/domedaemon-astrosib.cflags create mode 100644 Daemons/domedaemon-astrosib/domedaemon-astrosib.config create mode 100644 Daemons/domedaemon-astrosib/domedaemon-astrosib.creator create mode 100644 Daemons/domedaemon-astrosib/domedaemon-astrosib.cxxflags create mode 100644 Daemons/domedaemon-astrosib/domedaemon-astrosib.files create mode 100644 Daemons/domedaemon-astrosib/domedaemon-astrosib.includes create mode 100644 Daemons/domedaemon-astrosib/server.c create mode 100644 Daemons/domedaemon-astrosib/server.h diff --git a/Daemons/domedaemon-astrosib/Makefile b/Daemons/domedaemon-astrosib.deprecated/Makefile similarity index 100% rename from Daemons/domedaemon-astrosib/Makefile rename to Daemons/domedaemon-astrosib.deprecated/Makefile diff --git a/Daemons/domedaemon-astrosib.deprecated/Readme.md b/Daemons/domedaemon-astrosib.deprecated/Readme.md new file mode 100644 index 0000000..2cad6a2 --- /dev/null +++ b/Daemons/domedaemon-astrosib.deprecated/Readme.md @@ -0,0 +1,12 @@ +Astrosib all-sky dome control network daemon +================== + +Open a socket at given port (default: 55555), works with http & direct requests. + +**Protocol** + +Send requests over socket (by curl or something else) or http requests (in browser). + +* *open* - open dome; +* *close* - close dome; +* *status* - dome state (return "opened", "closed" or "intermediate"); diff --git a/Daemons/domedaemon-astrosib/cmdlnopts.c b/Daemons/domedaemon-astrosib.deprecated/cmdlnopts.c similarity index 100% rename from Daemons/domedaemon-astrosib/cmdlnopts.c rename to Daemons/domedaemon-astrosib.deprecated/cmdlnopts.c diff --git a/Daemons/domedaemon-astrosib/cmdlnopts.h b/Daemons/domedaemon-astrosib.deprecated/cmdlnopts.h similarity index 100% rename from Daemons/domedaemon-astrosib/cmdlnopts.h rename to Daemons/domedaemon-astrosib.deprecated/cmdlnopts.h diff --git a/Daemons/domedaemon-astrosib/domeasib.cflags b/Daemons/domedaemon-astrosib.deprecated/domeasib.cflags similarity index 100% rename from Daemons/domedaemon-astrosib/domeasib.cflags rename to Daemons/domedaemon-astrosib.deprecated/domeasib.cflags diff --git a/Daemons/domedaemon-astrosib/domeasib.config b/Daemons/domedaemon-astrosib.deprecated/domeasib.config similarity index 100% rename from Daemons/domedaemon-astrosib/domeasib.config rename to Daemons/domedaemon-astrosib.deprecated/domeasib.config diff --git a/Daemons/domedaemon-astrosib/domeasib.creator b/Daemons/domedaemon-astrosib.deprecated/domeasib.creator similarity index 100% rename from Daemons/domedaemon-astrosib/domeasib.creator rename to Daemons/domedaemon-astrosib.deprecated/domeasib.creator diff --git a/Daemons/domedaemon-astrosib/domeasib.creator.user b/Daemons/domedaemon-astrosib.deprecated/domeasib.creator.user similarity index 100% rename from Daemons/domedaemon-astrosib/domeasib.creator.user rename to Daemons/domedaemon-astrosib.deprecated/domeasib.creator.user diff --git a/Daemons/domedaemon-astrosib/domeasib.cxxflags b/Daemons/domedaemon-astrosib.deprecated/domeasib.cxxflags similarity index 100% rename from Daemons/domedaemon-astrosib/domeasib.cxxflags rename to Daemons/domedaemon-astrosib.deprecated/domeasib.cxxflags diff --git a/Daemons/domedaemon-astrosib/domeasib.files b/Daemons/domedaemon-astrosib.deprecated/domeasib.files similarity index 100% rename from Daemons/domedaemon-astrosib/domeasib.files rename to Daemons/domedaemon-astrosib.deprecated/domeasib.files diff --git a/Daemons/domedaemon-astrosib/domeasib.includes b/Daemons/domedaemon-astrosib.deprecated/domeasib.includes similarity index 100% rename from Daemons/domedaemon-astrosib/domeasib.includes rename to Daemons/domedaemon-astrosib.deprecated/domeasib.includes diff --git a/Daemons/domedaemon-astrosib.deprecated/main.c b/Daemons/domedaemon-astrosib.deprecated/main.c new file mode 100644 index 0000000..80755f7 --- /dev/null +++ b/Daemons/domedaemon-astrosib.deprecated/main.c @@ -0,0 +1,89 @@ +/* geany_encoding=koi8-r + * main.c + * + * Copyright 2018 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#include "usefull_macros.h" +#include +#include // wait +#include //prctl +#include +#include "cmdlnopts.h" +#include "socket.h" + +// dome @ /dev/ttyS2 + +glob_pars *GP; +static pid_t childpid = 0; + +void signals(int signo){ + if(childpid){ // parent process + restore_tty(); + putlog("exit with status %d", signo); + } + exit(signo); +} + +int main(int argc, char **argv){ + initial_setup(); + signal(SIGTERM, signals); // kill (-15) - quit + signal(SIGHUP, SIG_IGN); // hup - ignore + signal(SIGINT, signals); // ctrl+C - quit + signal(SIGQUIT, signals); // ctrl+\ - quit + signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z + GP = parse_args(argc, argv); + if(GP->terminal){ + if(!GP->device) ERRX(_("Point serial device name")); + try_connect(GP->device); + run_terminal(); + signals(0); // never reached! + } + if(GP->logfile) + openlogfile(GP->logfile); + #ifndef EBUG + if(daemon(1, 0)){ + ERR("daemon()"); + } + time_t lastd = 0; + while(1){ // guard for dead processes + childpid = fork(); + if(childpid){ + DBG("Created child with PID %d\n", childpid); + wait(NULL); + time_t t = time(NULL); + if(t - lastd > 600) // at least 10 minutes of work + putlog("child %d died\n", childpid); + lastd = t; + WARNX("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 + } + } + #endif + + if(GP->device) try_connect(GP->device); + if(!poll_device()){ + ERRX(_("No answer from device")); + } + putlog("Child %d connected to %s", getpid(), GP->device); + daemonize(GP->port); + signals(0); // newer reached + return 0; +} diff --git a/Daemons/domedaemon-astrosib/parseargs.c b/Daemons/domedaemon-astrosib.deprecated/parseargs.c similarity index 100% rename from Daemons/domedaemon-astrosib/parseargs.c rename to Daemons/domedaemon-astrosib.deprecated/parseargs.c diff --git a/Daemons/domedaemon-astrosib/parseargs.h b/Daemons/domedaemon-astrosib.deprecated/parseargs.h similarity index 100% rename from Daemons/domedaemon-astrosib/parseargs.h rename to Daemons/domedaemon-astrosib.deprecated/parseargs.h diff --git a/Daemons/domedaemon-astrosib/socket.c b/Daemons/domedaemon-astrosib.deprecated/socket.c similarity index 100% rename from Daemons/domedaemon-astrosib/socket.c rename to Daemons/domedaemon-astrosib.deprecated/socket.c diff --git a/Daemons/domedaemon-astrosib/socket.h b/Daemons/domedaemon-astrosib.deprecated/socket.h similarity index 100% rename from Daemons/domedaemon-astrosib/socket.h rename to Daemons/domedaemon-astrosib.deprecated/socket.h diff --git a/Daemons/domedaemon-astrosib/term.c b/Daemons/domedaemon-astrosib.deprecated/term.c similarity index 100% rename from Daemons/domedaemon-astrosib/term.c rename to Daemons/domedaemon-astrosib.deprecated/term.c diff --git a/Daemons/domedaemon-astrosib/term.h b/Daemons/domedaemon-astrosib.deprecated/term.h similarity index 100% rename from Daemons/domedaemon-astrosib/term.h rename to Daemons/domedaemon-astrosib.deprecated/term.h diff --git a/Daemons/domedaemon-astrosib/usefull_macros.c b/Daemons/domedaemon-astrosib.deprecated/usefull_macros.c similarity index 100% rename from Daemons/domedaemon-astrosib/usefull_macros.c rename to Daemons/domedaemon-astrosib.deprecated/usefull_macros.c diff --git a/Daemons/domedaemon-astrosib/usefull_macros.h b/Daemons/domedaemon-astrosib.deprecated/usefull_macros.h similarity index 100% rename from Daemons/domedaemon-astrosib/usefull_macros.h rename to Daemons/domedaemon-astrosib.deprecated/usefull_macros.h diff --git a/Daemons/domedaemon-astrosib/CMakeLists.txt b/Daemons/domedaemon-astrosib/CMakeLists.txt new file mode 100644 index 0000000..6393040 --- /dev/null +++ b/Daemons/domedaemon-astrosib/CMakeLists.txt @@ -0,0 +1,64 @@ +cmake_minimum_required(VERSION 3.30) + +set(PROJ domedaemon) +project(${PROJ}) + +set(MINOR_VERSION "0") +set(MID_VERSION "1") +set(MAJOR_VERSION "0") +set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}") + +enable_language(C) +message("VER: ${VERSION}") + +# options +option(DEBUG "Compile in debug mode" OFF) + +# default flags +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W -Wextra -std=gnu99") +if(DEBUG) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Og -g3 -ggdb -fno-builtin-strlen -Werror") + add_definitions(-DEBUG) + set(CMAKE_BUILD_TYPE DEBUG) + set(CMAKE_VERBOSE_MAKEFILE "ON") +else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -march=native -fdata-sections -ffunction-sections") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + set(CMAKE_BUILD_TYPE RELEASE) +endif() + +message("Build type: ${CMAKE_BUILD_TYPE}") + +set(CMAKE_COLOR_MAKEFILE ON) + +# here is one of two variants: all .c in directory or .c files in list +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SOURCES) + +###### pkgconfig ###### +find_package(PkgConfig REQUIRED) +pkg_check_modules(MODULES REQUIRED usefull_macros>=0.3.2) + +# change wrong behaviour with install prefix +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND CMAKE_INSTALL_PREFIX MATCHES "/usr/local") +else() + message("Change default install path to /usr/local") + set(CMAKE_INSTALL_PREFIX "/usr/local") +endif() +message("Install dir prefix: ${CMAKE_INSTALL_PREFIX}") + +# executable file +add_executable(${PROJ} ${SOURCES}) +# -I +target_include_directories(${PROJ} PUBLIC ${MODULES_INCLUDE_DIRS}) +# -L +target_link_directories(${PROJ} PUBLIC ${MODULES_LIBRARY_DIRS}) +# -l +target_link_libraries(${PROJ} ${MODULES_LIBRARIES}) +# -D +add_definitions( + -DPACKAGE_VERSION=\"${VERSION}\" -DMINOR_VERSION=\"${MINOR_VERSION}\" + -DMID_VERSION=\"${MID_VERSION}\" -DMAJOR_VERSION=\"${MAJOR_VESION}\" + ) + +# Installation of the program +INSTALL(TARGETS ${PROJ} DESTINATION "bin") diff --git a/Daemons/domedaemon-astrosib/Readme.md b/Daemons/domedaemon-astrosib/Readme.md index 2cad6a2..dac9836 100644 --- a/Daemons/domedaemon-astrosib/Readme.md +++ b/Daemons/domedaemon-astrosib/Readme.md @@ -1,12 +1,5 @@ -Astrosib all-sky dome control network daemon -================== +New version of "Astrosib" dome daemon. -Open a socket at given port (default: 55555), works with http & direct requests. +Based on snippets_library ver. >= 0.3.2 +Allow more functionality than old one. -**Protocol** - -Send requests over socket (by curl or something else) or http requests (in browser). - -* *open* - open dome; -* *close* - close dome; -* *status* - dome state (return "opened", "closed" or "intermediate"); diff --git a/Daemons/domedaemon-astrosib/astrosib_proto.h b/Daemons/domedaemon-astrosib/astrosib_proto.h new file mode 100644 index 0000000..d5d70e1 --- /dev/null +++ b/Daemons/domedaemon-astrosib/astrosib_proto.h @@ -0,0 +1,27 @@ +/* + * This file is part of the domedaemon-astrosib project. + * Copyright 2025 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 + +#define ASIB_CMD_STATUS "STATUS" +#define ASIB_CMD_RELAY "SWITCHTOGGILE" +#define ASIB_CMD_STOP "STOPDOME" +#define ASIB_CMD_OPEN "OPENDOME" +#define ASIB_CMD_CLOSE "CLOSEDOME" +#define ASIB_CMD_MOVEONE "SHUTTERMOVEDEG" +#define ASIB_CMD_RELAY "SWITCHTOGGILE" diff --git a/Daemons/domedaemon-astrosib/dome.c b/Daemons/domedaemon-astrosib/dome.c new file mode 100644 index 0000000..74dd609 --- /dev/null +++ b/Daemons/domedaemon-astrosib/dome.c @@ -0,0 +1,257 @@ +/* + * This file is part of the domedaemon-astrosib project. + * Copyright 2025 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 . + */ + +#include +#include + +#include "astrosib_proto.h" +#include "dome.h" + +// number of relay turning on/off motors power +#define MOTRELAY_NO 1 +// state of relay to turn power on/off +#define MOTRELAY_ON 1 +#define MOTRELAY_OFF 0 + +// time interval for requiring current dome status in idle state (e.g. trigger watchdog) +#define STATUSREQ_IDLE 10. +// update interval in moving state +#define STATUSREQ_MOVE 0.5 + +// dome status by polling (each STATUSREQ_IDLE seconds) +static dome_status_t dome_status = {0}; +// finite state machine state +static dome_state_t state = DOME_S_IDLE; +// last time dome_status was updated +static double last_status_time = 0.; +// current update interval +static double status_req_interval = STATUSREQ_MOVE; +// serial device +static sl_tty_t *serialdev = NULL; +static pthread_mutex_t serialmutex = PTHREAD_MUTEX_INITIALIZER; + +void dome_serialdev(sl_tty_t *serial){ + serialdev = serial; +} +/** + * @brief serial_write - write buffer without "\r" on end to port + * @param cmd - data to send + * @param answer - buffer for answer (or NULL if not need) + * @param anslen - length of `answer` + * @return error code + */ +static int serial_write(const char *cmd, char *answer, int anslen){ + if(!serialdev || !cmd || !answer || anslen < 2) return FALSE; + static char *buf = NULL; + static size_t buflen = 0; + DBG("Write %s", cmd); + size_t cmdlen = strlen(cmd); + if(buflen < cmdlen + 2){ + buflen = (cmdlen + 4096) / 4096; + buflen *= 4096; + if(!(buf = realloc(buf, buflen))){ + LOGERR("serial_write(): realloc() failed!"); + ERRX("serial_write(): realloc() failed!"); + } + } + size_t _2write = snprintf(buf, buflen-1, "%s\r", cmd); + DBG("try to send %zd bytes", _2write); + if(sl_tty_write(serialdev->comfd, buf, _2write)) return FALSE; + int got = 0, totlen = 0; + --anslen; // for /0 + do{ + got = sl_tty_read(serialdev); + if(got > 0){ + if(got > anslen) return FALSE; // buffer overflow + memcpy(answer, serialdev->buf, got); + totlen += got; + answer += got; + anslen -= got; + answer[0] = 0; + } + DBG("got = %d", got); + }while(got > 0 && anslen); + if(got < 0){ + LOGERR("serial_write(): serial device disconnected!"); + ERRX("serial_write(): serial device disconnected!"); + } + if(totlen < 1) return FALSE; // no answer received + if(answer[-1] == '\r') answer[-1] = 0; // remove trailing trash + return TRUE; +} + +// return TRUE if can parse status +static int parsestatus(const char *buf){ + if(!buf) return FALSE; + DBG("buf=%s", buf); + int n = sscanf(buf, ASIB_CMD_STATUS "%d,%d,%d,%d,%f,%f,%f,%f,%f,%f,%d,%d,%d,%d,%d", + &dome_status.coverstate[0], &dome_status.coverstate[1], + &dome_status.encoder[0], &dome_status.encoder[1], + &dome_status.Tin, &dome_status.Tout, + &dome_status.Imot[0], &dome_status.Imot[1], &dome_status.Imot[2], &dome_status.Imot[3], + &dome_status.relay[0], &dome_status.relay[1], &dome_status.relay[2], + &dome_status.rainArmed, &dome_status.israin); + DBG("n=%d", n); + if(n != 15){ + WARNX("Something wrong with STATUS answer"); + LOGWARN("Something wrong with STATUS answer"); + LOGWARNADD("%s", buf); + return FALSE; + } + return TRUE; +} + +// check status; return FALSE if failed +static int check_status(){ + char buf[BUFSIZ]; + // clear input buffers + int got = sl_tty_read(serialdev); + if(got > 0) printf("Got from serial %zd bytes of trash: `%s`\n", serialdev->buflen, serialdev->buf); + else if(got < 0){ + LOGERR("Serial device disconnected?"); + ERRX("Serial device disconnected?"); + } + DBG("Require status"); + if(!serial_write(ASIB_CMD_STATUS, buf, BUFSIZ)) return FALSE; + int ret = FALSE; + if(parsestatus(buf)){ + last_status_time = sl_dtime(); + ret = TRUE; + } + return ret; +} + +// run naked command or command with parameters +static int runcmd(const char *cmd, const char *par){ + char buf[128]; + if(!cmd) return FALSE; + DBG("Send command %s with par %s", cmd, par); + if(!par) snprintf(buf, 127, "%s", cmd); + else snprintf(buf, 127, "%s%s", cmd, par); + if(!serial_write(buf, buf, 128)) return FALSE; + if(strncmp(buf, "OK", 2)) return FALSE; + return TRUE; +} + +// check current state and turn on/off relay if need +static void chkrelay(){ + if(state != DOME_S_MOVING) return; + if(dome_status.coverstate[0] == COVER_INTERMEDIATE || + dome_status.coverstate[1] == COVER_INTERMEDIATE) return; // still moving + // OK, we are on place - turn off motors' power + char buf[128]; + snprintf(buf, 127, "%s%d,%d", ASIB_CMD_RELAY, MOTRELAY_NO, MOTRELAY_OFF); + if(serial_write(buf, buf, 128) && check_status()){ + DBG("Check are motors really off"); + if(dome_status.relay[MOTRELAY_NO-1] == MOTRELAY_OFF){ + DBG("OK state->IDLE"); + state = DOME_S_IDLE; + } + } +} + +// turn ON motors' relay +static int motors_on(){ + char buf[128]; + snprintf(buf, 127, "%s%d,%d", ASIB_CMD_RELAY, MOTRELAY_NO, MOTRELAY_ON); + if(serial_write(buf, buf, 128) && check_status()){ + DBG("Check are motors really on"); + if(dome_status.relay[MOTRELAY_NO-1] == MOTRELAY_ON){ + DBG("OK state->MOVING"); + state = DOME_S_MOVING; + return TRUE; + } + } + return FALSE; +} + +// just get current status +double get_dome_status(dome_status_t *s){ + if(s){ + pthread_mutex_lock(&serialmutex); + *s = dome_status; + pthread_mutex_unlock(&serialmutex); + } + return last_status_time; +} + +dome_state_t get_dome_state(){return state;} + +dome_state_t dome_poll(dome_cmd_t cmd, int par){ + char buf[128]; + int st = DOME_S_ERROR; + double curtime = sl_dtime(); + //DBG("curtime-lasttime=%g", curtime - last_status_time); + // simple polling and there's a lot of time until next serial device poll + if(cmd == DOME_POLL && curtime - last_status_time < status_req_interval) + return state; + pthread_mutex_lock(&serialmutex); + // check if we need to turn ON motors' relay + switch(cmd){ + case DOME_OPEN: + case DOME_CLOSE: + case DOME_OPEN_ONE: + case DOME_CLOSE_ONE: + if(!motors_on()) goto ret; + break; + default: + break; + } + switch(cmd){ + case DOME_STOP: + if(!runcmd(ASIB_CMD_STOP, NULL)) goto ret; + break; + case DOME_OPEN: + if(!runcmd(ASIB_CMD_OPEN, NULL)) goto ret; + break; + case DOME_CLOSE: + if(!runcmd(ASIB_CMD_CLOSE, NULL)) goto ret; + break; + case DOME_OPEN_ONE: + if(par < 1 || par > 2) goto ret; + snprintf(buf, 127, "%d 90", par); + if(!runcmd(ASIB_CMD_MOVEONE, buf)) goto ret; + break; + case DOME_CLOSE_ONE: + if(par < 1 || par > 2) goto ret; + snprintf(buf, 127, "%d 0", par); + if(!runcmd(ASIB_CMD_MOVEONE, buf)) goto ret; + break; + case DOME_RELAY_ON: + if(par < 1 || par > 3) goto ret; + snprintf(buf, 127, "%d,1", par); + if(!runcmd(ASIB_CMD_RELAY, buf)) goto ret; + break; + case DOME_RELAY_OFF: + if(par < 1 || par > 3) goto ret; + snprintf(buf, 127, "%d,0", par); + if(!runcmd(ASIB_CMD_RELAY, buf)) goto ret; + break; + default: + break; + } +ret: + if(check_status()){ + chkrelay(); + st = state; + } + if(state == DOME_S_IDLE) status_req_interval = STATUSREQ_IDLE; + else status_req_interval = STATUSREQ_MOVE; + pthread_mutex_unlock(&serialmutex); + return st; +} diff --git a/Daemons/domedaemon-astrosib/dome.h b/Daemons/domedaemon-astrosib/dome.h new file mode 100644 index 0000000..50bf17b --- /dev/null +++ b/Daemons/domedaemon-astrosib/dome.h @@ -0,0 +1,65 @@ +/* + * This file is part of the domedaemon-astrosib project. + * Copyright 2025 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 + +#include + +#define NRELAY_MIN 1 +#define NRELAY_MAX 3 + +// dome finite state machine state +typedef enum{ + DOME_S_IDLE, // idle, motors disabled + DOME_S_MOVING, // moving, motors enabled + DOME_S_ERROR // some kind of error +} dome_state_t; + +// commands through dome_poll interface +typedef enum{ + DOME_POLL, // just poll state maching + DOME_STOP, // stop any moving + DOME_OPEN, // fully open dome + DOME_CLOSE, // fully close dome + DOME_OPEN_ONE, // open only one part # `par` (1-2) + DOME_CLOSE_ONE, // close only one part # `par` + DOME_RELAY_ON, // turn on relay # `par` (1-3) + DOME_RELAY_OFF, // turn off relay # `par` +} dome_cmd_t; + +// cover states +enum{ + COVER_INTERMEDIATE = 1, + COVER_OPENED = 2, + COVER_CLOSED = 3 +}; + +typedef struct{ + int coverstate[2]; // north/south covers state (3 - closed, 2 - opened, 1 - intermediate) + int encoder[2]; // encoders values + float Tin; // temperatures (unavailable) + float Tout; + float Imot[4]; // motors' currents + int relay[3]; // relays' state + int rainArmed; // rain sensor closes the dome + int israin; // arm sensor signal +} dome_status_t; + +double get_dome_status(dome_status_t *s); +dome_state_t get_dome_state(); +dome_state_t dome_poll(dome_cmd_t cmd, int par); +void dome_serialdev(sl_tty_t *serial); diff --git a/Daemons/domedaemon-astrosib/domedaemon-astrosib.cflags b/Daemons/domedaemon-astrosib/domedaemon-astrosib.cflags new file mode 100644 index 0000000..68d5165 --- /dev/null +++ b/Daemons/domedaemon-astrosib/domedaemon-astrosib.cflags @@ -0,0 +1 @@ +-std=c17 \ No newline at end of file diff --git a/Daemons/domedaemon-astrosib/domedaemon-astrosib.config b/Daemons/domedaemon-astrosib/domedaemon-astrosib.config new file mode 100644 index 0000000..e0284f4 --- /dev/null +++ b/Daemons/domedaemon-astrosib/domedaemon-astrosib.config @@ -0,0 +1,2 @@ +// Add predefined macros for your project here. For example: +// #define THE_ANSWER 42 diff --git a/Daemons/domedaemon-astrosib/domedaemon-astrosib.creator b/Daemons/domedaemon-astrosib/domedaemon-astrosib.creator new file mode 100644 index 0000000..e94cbbd --- /dev/null +++ b/Daemons/domedaemon-astrosib/domedaemon-astrosib.creator @@ -0,0 +1 @@ +[General] diff --git a/Daemons/domedaemon-astrosib/domedaemon-astrosib.cxxflags b/Daemons/domedaemon-astrosib/domedaemon-astrosib.cxxflags new file mode 100644 index 0000000..6435dfc --- /dev/null +++ b/Daemons/domedaemon-astrosib/domedaemon-astrosib.cxxflags @@ -0,0 +1 @@ +-std=c++17 \ No newline at end of file diff --git a/Daemons/domedaemon-astrosib/domedaemon-astrosib.files b/Daemons/domedaemon-astrosib/domedaemon-astrosib.files new file mode 100644 index 0000000..0050f0e --- /dev/null +++ b/Daemons/domedaemon-astrosib/domedaemon-astrosib.files @@ -0,0 +1,6 @@ +astrosib_proto.h +dome.c +dome.h +main.c +server.c +server.h diff --git a/Daemons/domedaemon-astrosib/domedaemon-astrosib.includes b/Daemons/domedaemon-astrosib/domedaemon-astrosib.includes new file mode 100644 index 0000000..e69de29 diff --git a/Daemons/domedaemon-astrosib/main.c b/Daemons/domedaemon-astrosib/main.c index 80755f7..530cdf3 100644 --- a/Daemons/domedaemon-astrosib/main.c +++ b/Daemons/domedaemon-astrosib/main.c @@ -1,11 +1,10 @@ -/* geany_encoding=koi8-r - * main.c +/* + * This file is part of the Snippets project. + * Copyright 2024 Edward V. Emelianov . * - * Copyright 2018 Edward V. Emelianov - * - * This program is free software; you can redistribute it and/or modify + * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * 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, @@ -14,60 +13,84 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * along with this program. If not, see . */ -#include "usefull_macros.h" + #include +#include +#include #include // wait #include //prctl -#include -#include "cmdlnopts.h" -#include "socket.h" +#include -// dome @ /dev/ttyS2 +#include "server.h" -glob_pars *GP; -static pid_t childpid = 0; +// TCP socket port +#define DEFAULT_PORT "55555" +// baudrate - 9600 +#define DEFAULT_SERSPEED 9600 +// serial polling timeout - 100ms +#define DEFAULT_SERTMOUT 100000 -void signals(int signo){ - if(childpid){ // parent process - restore_tty(); - putlog("exit with status %d", signo); - } - exit(signo); +typedef struct{ + char *device; // serial device name + char *node; // port to connect or UNIX socket name + char *logfile; // logfile name + int isunix; // open UNIX-socket instead of TCP + int verbose; // verbose level +} parameters; + +static parameters G = { + .node = DEFAULT_PORT, +}; +static int help; + +static sl_option_t cmdlnopts[] = { + {"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), "show this help"}, + {"device", NEED_ARG, NULL, 'd', arg_string, APTR(&G.device), "serial device name"}, + {"node", NEED_ARG, NULL, 'n', arg_string, APTR(&G.node), "UNIX socket name or network port to connect (default: " DEFAULT_PORT ")"}, + {"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&G.logfile), "save logs to file"}, + {"unix", NO_ARGS, NULL, 'u', arg_int, APTR(&G.isunix), "open UNIX-socket instead of TCP"}, + {"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verbose), "logging verbose level (each -v adds one)"}, + end_option +}; + +void signals(int sig){ + if(sig){ + signal(sig, SIG_IGN); + DBG("Get signal %d, quit.\n", sig); + LOGERR("Exit with status %d", sig); + }else LOGERR("Exit"); + exit(sig); } int main(int argc, char **argv){ - initial_setup(); - signal(SIGTERM, signals); // kill (-15) - quit - signal(SIGHUP, SIG_IGN); // hup - ignore - signal(SIGINT, signals); // ctrl+C - quit - signal(SIGQUIT, signals); // ctrl+\ - quit - signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z - GP = parse_args(argc, argv); - if(GP->terminal){ - if(!GP->device) ERRX(_("Point serial device name")); - try_connect(GP->device); - run_terminal(); - signals(0); // never reached! - } - if(GP->logfile) - openlogfile(GP->logfile); - #ifndef EBUG - if(daemon(1, 0)){ - ERR("daemon()"); - } + sl_init(); + sl_parseargs(&argc, &argv, cmdlnopts); + if(help) sl_showhelp(-1, cmdlnopts); + if(!G.node) ERRX("Point node"); + if(!G.device) ERRX("Point path to serial device"); + sl_loglevel_e lvl = G.verbose + LOGLEVEL_ERR; + if(lvl >= LOGLEVEL_AMOUNT) lvl = LOGLEVEL_AMOUNT - 1; + if(G.logfile) OPENLOG(G.logfile, lvl, 1); + LOGMSG("Started"); + signal(SIGTERM, signals); + signal(SIGINT, signals); + signal(SIGQUIT, signals); + signal(SIGTSTP, SIG_IGN); + signal(SIGHUP, signals); +#ifndef EBUG time_t lastd = 0; while(1){ // guard for dead processes - childpid = fork(); + pid_t childpid = fork(); if(childpid){ DBG("Created child with PID %d\n", childpid); + LOGMSG("Created child with PID %d\n", childpid); wait(NULL); time_t t = time(NULL); - if(t - lastd > 600) // at least 10 minutes of work - putlog("child %d died\n", childpid); + if(t - lastd > 600){ // at least 10 minutes of work + LOGERR("Child %d died\n", childpid); + } lastd = t; WARNX("Child %d died\n", childpid); sleep(1); @@ -76,14 +99,16 @@ int main(int argc, char **argv){ break; // go out to normal functional } } - #endif - - if(GP->device) try_connect(GP->device); - if(!poll_device()){ - ERRX(_("No answer from device")); +#endif + sl_socktype_e type = (G.isunix) ? SOCKT_UNIX : SOCKT_NETLOCAL; + sl_tty_t *serial = sl_tty_new(G.device, DEFAULT_SERSPEED, 4096); + if(serial) serial = sl_tty_open(serial, 1); + if(!serial){ + LOGERR("Can't open serial device %s", G.device); + ERRX("Can't open serial device %s", G.device); } - putlog("Child %d connected to %s", getpid(), GP->device); - daemonize(GP->port); - signals(0); // newer reached + sl_tty_tmout(DEFAULT_SERTMOUT); + server_run(type, G.node, serial); + LOGERR("Unreacheable code reached!"); return 0; } diff --git a/Daemons/domedaemon-astrosib/server.c b/Daemons/domedaemon-astrosib/server.c new file mode 100644 index 0000000..31d2b8e --- /dev/null +++ b/Daemons/domedaemon-astrosib/server.c @@ -0,0 +1,166 @@ +/* + * This file is part of the Snippets project. + * Copyright 2024 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 . + */ + +#include +#include +#include +#include +#include +#include + +#include "dome.h" + +// max age time of last status - 30s +#define STATUS_MAX_AGE (30.) + +// commands +#define CMD_UNIXT "unixt" +#define CMD_STATUS "status" +#define CMD_STATUST "statust" +#define CMD_RELAY "relay" + +// main socket +static sl_sock_t *s = NULL; + +/////// handlers +// unixt - send to ALL clients +static sl_sock_hresult_e dtimeh(sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ const char *req){ + char buf[32]; + snprintf(buf, 31, "%s=%.2f\n", item->key, sl_dtime()); + sl_sock_sendstrmessage(c, buf); + return RESULT_SILENCE; +} +// status - get current dome status in old format (first four numbers) +static sl_sock_hresult_e statush(sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ const char *req){ + char buf[128]; + dome_status_t dome_status; + double lastt = get_dome_status(&dome_status); + if(sl_dtime() - lastt > STATUS_MAX_AGE) return RESULT_FAIL; + snprintf(buf, 127, "%s=%d,%d,%d,%d\n", item->key, dome_status.coverstate[0], + dome_status.coverstate[1], dome_status.encoder[0], dome_status.encoder[1]); + sl_sock_sendstrmessage(c, buf); + return RESULT_SILENCE; +} +static const char *textst(int coverstate){ + switch(coverstate){ + case COVER_INTERMEDIATE: return "intermediate"; + case COVER_OPENED: return "opened"; + case COVER_CLOSED: return "closed"; + default: return "undefined"; + } + return NULL; +} +// statust - text format status +static sl_sock_hresult_e statusth(sl_sock_t *c, _U_ sl_sock_hitem_t *item, _U_ const char *req){ + char buf[BUFSIZ]; + dome_status_t dome_status; + double lastt = get_dome_status(&dome_status); + if(sl_dtime() - lastt > STATUS_MAX_AGE) return RESULT_FAIL; + snprintf(buf, 127, "cover1=%s\ncover2=%s\nangle1=%d\nangle2=%d\nrelay1=%d\nrelay2=%d\nrelay3=%d\nreqtime=%.9f\n", + textst(dome_status.coverstate[0]), textst(dome_status.coverstate[1]), + dome_status.encoder[0], dome_status.encoder[1], + dome_status.relay[0], dome_status.relay[1], dome_status.relay[2], + lastt); + sl_sock_sendstrmessage(c, buf); + return RESULT_SILENCE; +} +// relay on/off +static sl_sock_hresult_e relays(int Nrelay, int Stat){ + if(Nrelay < NRELAY_MIN|| Nrelay > NRELAY_MAX) return RESULT_BADKEY; + dome_cmd_t cmd = Stat ? DOME_RELAY_ON : DOME_RELAY_OFF; + if(DOME_S_ERROR == dome_poll(cmd, Nrelay)) return RESULT_FAIL; + return RESULT_OK; +} +static sl_sock_hresult_e relay(sl_sock_t *c, sl_sock_hitem_t *item, const char *req){ + char buf[128]; + int N = item->key[sizeof(CMD_RELAY) - 1] - '0'; + if(!req || !*req){ // getter + dome_status_t dome_status; + double lastt = get_dome_status(&dome_status); + if(sl_dtime() - lastt > STATUS_MAX_AGE) return RESULT_FAIL; + snprintf(buf, 127, "%s=%d\n", item->key, dome_status.relay[N-1]); + sl_sock_sendstrmessage(c, buf); + return RESULT_SILENCE; + } + int Stat = *req - '0'; + return relays(N, Stat); +} + +// and all handlers collection +static sl_sock_hitem_t handlers[] = { + {dtimeh, CMD_UNIXT, "get server's UNIX time", NULL}, + {statush, CMD_STATUS, "get dome's status in old format", NULL}, + {statusth, CMD_STATUST, "get dome's status in full text format", NULL}, + {relay, CMD_RELAY "1", "turn on/off (=1/0) relay 1", NULL}, + {relay, CMD_RELAY "2", "turn on/off (=1/0) relay 2", NULL}, + {relay, CMD_RELAY "3", "turn on/off (=1/0) relay 3", NULL}, + {NULL, NULL, NULL, NULL} +}; + +// Too much clients handler +static void toomuch(int fd){ + const char m[] = "Try later: too much clients connected\n"; + send(fd, m, sizeof(m)-1, MSG_NOSIGNAL); + shutdown(fd, SHUT_WR); + DBG("shutdown, wait"); + double t0 = sl_dtime(); + uint8_t buf[8]; + while(sl_dtime() - t0 < 11.){ + if(sl_canread(fd)){ + ssize_t got = read(fd, buf, 8); + DBG("Got=%zd", got); + if(got < 1) break; + } + } + DBG("Disc after %gs", sl_dtime() - t0); + LOGWARN("Client fd=%d tried to connect after MAX reached", fd); +} +// new connections handler +static void connected(sl_sock_t *c){ + if(c->type == SOCKT_UNIX) LOGMSG("New client fd=%d connected", c->fd); + else LOGMSG("New client fd=%d, IP=%s connected", c->fd, c->IP); +} +// disconnected handler +static void disconnected(sl_sock_t *c){ + if(c->type == SOCKT_UNIX) LOGMSG("Disconnected client fd=%d", c->fd); + else LOGMSG("Disconnected client fd=%d, IP=%s", c->fd, c->IP); +} + +void server_run(sl_socktype_e type, const char *node, sl_tty_t *serial){ + if(!node || !serial){ + LOGERR("server_run(): wrong parameters"); + ERRX("server_run(): wrong parameters"); + } + dome_serialdev(serial); + sl_sock_changemaxclients(5); + sl_sock_maxclhandler(toomuch); + sl_sock_connhandler(connected); + sl_sock_dischandler(disconnected); + s = sl_sock_run_server(type, node, -1, handlers); + if(!s) ERRX("Can't create socket and/or run threads"); + while(s && s->connected){ + if(!s->rthread){ + LOGERR("Server handlers thread is dead"); + break; + } + // finite state machine polling + dome_poll(DOME_POLL, 0); + } + sl_sock_delete(&s); + ERRX("Server handlers thread is dead"); +} diff --git a/Daemons/domedaemon-astrosib/server.h b/Daemons/domedaemon-astrosib/server.h new file mode 100644 index 0000000..1d4d78c --- /dev/null +++ b/Daemons/domedaemon-astrosib/server.h @@ -0,0 +1,23 @@ +/* + * This file is part of the domedaemon-astrosib project. + * Copyright 2025 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 + +#include + +void server_run(sl_socktype_e type, const char *node, sl_tty_t *serial);