add pre-pre-pre-alpha of Sidereal Servo II management

This commit is contained in:
Edward Emelianov 2022-06-15 00:10:54 +03:00
parent 0efee1f520
commit 73bdcfb119
7 changed files with 493 additions and 0 deletions

View File

@ -0,0 +1,56 @@
# run `make DEF=...` to add extra defines
PROGRAM := runscope
LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all
LDFLAGS += -lusefull_macros
SRCS := $(wildcard *.c)
DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111
OBJDIR := mk
CFLAGS += -O2 -Wall -Wextra -Wno-trampolines -std=gnu99
OBJS := $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o))
DEPS := $(OBJS:.o=.d)
TARGFILE := $(OBJDIR)/TARGET
CC = gcc
#TARGET := RELEASE
ifeq ($(shell test -e $(TARGFILE) && echo -n yes),yes)
TARGET := $(file < $(TARGFILE))
else
TARGET := release
endif
all:
@make $(TARGET)
release: $(PROGRAM)
debug: CFLAGS += -DEBUG -Werror
debug: TARGET := debug
debug: $(PROGRAM)
$(TARGFILE): $(OBJDIR)
@echo -e "\t\tTARGET: $(TARGET)"
@echo "$(TARGET)" > $(TARGFILE)
$(PROGRAM) : $(TARGFILE) $(OBJS)
@echo -e "\t\tLD $(PROGRAM)"
$(CC) $(LDFLAGS) $(OBJS) -o $(PROGRAM)
$(OBJDIR):
@mkdir $(OBJDIR)
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif
$(OBJDIR)/%.o: %.c
@echo -e "\t\tCC $<"
$(CC) -MD -c $(LDFLAGS) $(CFLAGS) $(DEFINES) -o $@ $<
clean:
@echo -e "\t\tCLEAN"
@rm -rf $(OBJDIR) 2>/dev/null || true
xclean: clean
@rm -f $(PROGRAM)
.PHONY: clean xclean

View File

@ -0,0 +1,87 @@
/*
* This file is part of the SSII project.
* Copyright 2022 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 <assert.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <math.h>
#include "cmdlnopts.h"
#include "usefull_macros.h"
/*
* here are global parameters initialisation
*/
static int help;
static glob_pars G;
// default PID filename:
#define DEFAULT_PIDFILE "/tmp/runscope.pid"
#define DEFAULT_SERDEV "/dev/ttyUSB0"
// DEFAULTS
// default global parameters
static glob_pars const Gdefault = {
.device = DEFAULT_SERDEV,
.pidfile = DEFAULT_PIDFILE,
.speed = 19200,
.logfile = NULL // don't save logs
};
/*
* Define command line options by filling structure:
* name has_arg flag val type argptr help
*/
static myoption cmdlnopts[] = {
// common options
{"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 (default:" DEFAULT_SERDEV ")")},
{"speed", NEED_ARG, NULL, 's', arg_int, APTR(&G.speed), _("serial device speed (default: 115200)")},
{"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&G.logfile), _("file to save logs")},
{"pidfile", NEED_ARG, NULL, 'P', arg_string, APTR(&G.pidfile), _("pidfile (default: " DEFAULT_PIDFILE ")")},
end_option
};
/**
* Parse command line options and return dynamically allocated structure
* to global parameters
* @param argc - copy of argc from main
* @param argv - copy of argv from main
* @return allocated structure with global parameters
*/
glob_pars *parse_args(int argc, char **argv){
int i;
void *ptr;
ptr = memcpy(&G, &Gdefault, sizeof(G)); assert(ptr);
size_t hlen = 1024;
char helpstring[1024], *hptr = helpstring;
snprintf(hptr, hlen, "Usage: %%s [args]\n\n\tWhere args are:\n");
// format of help: "Usage: progname [args]\n"
change_helpstring(helpstring);
// parse arguments
parseargs(&argc, &argv, cmdlnopts);
if(help) showhelp(-1, cmdlnopts);
if(argc > 0){
G.rest_pars_num = argc;
G.rest_pars = MALLOC(char *, argc);
for (i = 0; i < argc; i++)
G.rest_pars[i] = strdup(argv[i]);
}
return &G;
}

View File

@ -0,0 +1,38 @@
/*
* This file is part of the SSII project.
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef CMDLNOPTS_H__
#define CMDLNOPTS_H__
/*
* here are some typedef's for global data
*/
typedef struct{
char *device; // serial device name
char *pidfile; // name of PID file
char *logfile; // logging to this file
int speed; // connection speed
int rest_pars_num; // number of rest parameters
char** rest_pars; // the rest parameters: array of char*
} glob_pars;
glob_pars *parse_args(int argc, char **argv);
#endif // CMDLNOPTS_H__

View File

@ -0,0 +1,104 @@
/*
* This file is part of the SSII project.
* Copyright 2022 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 <signal.h> // signal
#include <stdio.h> // printf
#include <stdlib.h> // exit, free
#include <string.h> // strdup
#include <unistd.h> // sleep
#include <usefull_macros.h>
#include "cmdlnopts.h"
#include "sidservo.h"
/*
#include <termios.h> // tcsetattr
#include <unistd.h> // tcsetattr, close, read, write
#include <sys/ioctl.h> // ioctl
#include <stdio.h> // printf, getchar, fopen, perror
#include <stdlib.h> // exit
#include <sys/stat.h> // read
#include <fcntl.h> // read
#include <signal.h> // signal
#include <time.h> // time
#include <string.h> // memcpy
#include <stdint.h> // int types
#include <sys/time.h> // gettimeofday
*/
/**
* This is an example of usage:
* - command line arguments,
* - log file,
* - check of another file version running,
* - signals management,
* - serial port reading/writing.
* The `cmdlnopts.[hc]` are intrinsic files of this demo.
*/
static glob_pars *GP = NULL; // for GP->pidfile need in `signals`
/**
* We REDEFINE the default WEAK function of signal processing
*/
void signals(int sig){
if(sig > 0){
signal(sig, SIG_IGN);
DBG("Get signal %d, quit.\n", sig);
}
LOGERR("Exit with status %d", sig);
if(GP && GP->pidfile) // remove unnesessary PID file
unlink(GP->pidfile);
SSclose();
exit(sig);
}
void iffound_default(pid_t pid){
ERRX("Another copy of this process found, pid=%d. Exit.", pid);
}
int main(int argc, char *argv[]){
initial_setup();
char *self = strdup(argv[0]);
GP = parse_args(argc, argv);
/* if(GP->rest_pars_num){
printf("%d extra options:\n", GP->rest_pars_num);
for(int i = 0; i < GP->rest_pars_num; ++i)
printf("%s\n", GP->rest_pars[i]);
}*/
check4running(self, GP->pidfile);
red("%s started, snippets library version is %s\n", self, sl_libversion());
free(self);
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
if(GP->logfile) OPENLOG(GP->logfile, LOGLEVEL_ANY, 1);
LOGMSG("Start application...");
if(!SSinit(GP->device, GP->speed)) signals(-2);
/*
double t0 = dtime();
while(1){ // read data from port and print in into terminal
;
}*/
// clean everything
signals(0);
// never reached
return 0;
}

View File

@ -0,0 +1,138 @@
/*
* This file is part of the SSII project.
* Copyright 2022 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 <stdio.h>
#include <string.h>
#include "sidservo.h"
static TTY_descr *dev = NULL; // shoul be global to restore if die
static uint8_t buff[BUFLEN];
static int buflen = 0;
static uint16_t calcChecksum(uint8_t *buf, int len){
uint16_t checksum = 0x11; // I don't know from where does this "magick"
for(int i = 0; i < len; i++)
checksum += *buf++;
checksum ^= 0xFF00; // invert high byte
DBG("Checksum: 0x%04x", checksum);
return checksum;
}
/**
* @brief SSinit - open serial device and get initial info
* @return TRUE if all OK
*/
int SSinit(char *devpath, int speed){
LOGDBG("Try to open serial %s @%d", devpath, speed);
dev = new_tty(devpath, speed, BUFLEN);
if(dev) dev = tty_open(dev, 1); // open exclusively
if(!dev){
LOGERR("Can't open %s with speed %d. Exit.", devpath, speed);
signals(-1);
}
for(int ntries = 0; ntries < 5; ++ntries){ // try at most 5 times
if(!SSgetstat(NULL)) continue;
SSstat *s = (SSstat*) buff;
#ifdef EBUG
green("\nGet data:\n");
printf("DECmot=%d (0x%08x)\n", s->DECmot, (uint32_t)s->DECmot);
printf("DECenc=%d (0x%08x)\n", s->DECenc, (uint32_t)s->DECenc);
printf("RAmot=%d (0x%08x)\n", s->RAmot, (uint32_t)s->RAmot);
printf("RAenc=%d (0x%08x)\n", s->RAenc, (uint32_t)s->RAenc);
printf("keypad=0x%02x\n", s->keypad);
printf("XBits=0x%02x\n", s->XBits);
printf("YBits=0x%02x\n", s->YBits);
printf("EBits=0x%02x\n", s->ExtraBits);
printf("ain0=%u\n", s->ain0);
printf("ain1=%u\n", s->ain1);
printf("millis=%u\n", s->millis);
printf("tF=%d\n", s->tF);
printf("V=%f\n", ((float)s->voltage)/10.f);
printf("checksum=0x%04x\n\n", s->checksum);
#endif
if(calcChecksum(buff, sizeof(SSstat)-2) == s->checksum) return TRUE;
}
return FALSE;
}
/**
* @brief SSclose - stop telescope and close serial device
*/
void SSclose(){
if(dev) close_tty(&dev);
}
/**
* @brief SSwrite - write & return answer
* @param buf - buffer with text or binary data
* @param buflen - its length
* @return amount of bytes read, if got answer; 0 without answer, -1 if device disconnected, -2 if can't write
*/
int SSwrite(const uint8_t *buf, int len){
DBG("try to write %d bytes", len);
if(write_tty(dev->comfd, (const char*)buf, len)){
LOGERR("Can't write data to port");
return -2;
}
write_tty(dev->comfd, "\r", 1); // add EOL
buflen = 0;
double t0 = dtime();
while(dtime() - t0 < READTIMEOUT && buflen < BUFLEN){
int r = read_tty(dev);
if(r == -1){
LOGERR("Seems like tty device disconnected");
return -1;
}
if(r == 0) continue;
int rest = BUFLEN - buflen;
if((int)dev->buflen > rest) dev->buflen = rest; // TODO: what to do with possible buffer overrun?
memcpy(&buff[buflen], dev->buf, dev->buflen);
buflen += dev->buflen;
}
DBG("got buflen=%d", buflen);
#ifdef EBUG
for(int i = 0; i < buflen; ++i){
printf("%02x (%c) ", buff[i], (buff[i] > 31) ? buff[i] : ' ');
}
printf("\n");
#endif
return buflen;
}
/**
* @brief SSread - return buff and buflen
* @param l (o) - length of data
* @return buff or NULL if buflen == 0
*/
uint8_t *SSread(int *l){
if(l) *l = buflen;
if(!buflen) return NULL;
return buff;
}
/**
* @brief SSgetstat - get struct with status & check its crc
* @param s - pointer to allocated struct (or NULL just to check)
* @return 1 if OK
*/
int SSgetstat(SSstat *s){
if(SSwrite(CMD_GETSTAT, sizeof(CMD_GETSTAT)) != sizeof(SSstat)) return FALSE;
if(s) memcpy(s, buff, sizeof(SSstat));
return TRUE;
}

View File

@ -0,0 +1,61 @@
/*
* This file is part of the SSII project.
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef SIDSERVO_H__
#define SIDSERVO_H__
#include <usefull_macros.h>
// ASCII commands
#define U8P(x) ((uint8_t*)x)
// get binary data of all statistics
#define CMD_GETSTAT U8P("XXS")
#define BUFLEN (256)
// timeout (seconds) of reading answer
#define READTIMEOUT (0.1)
// all need data in one
typedef struct{
int32_t DECmot; // Dec/RA motor position
int32_t RAmot;
int32_t DECenc; // Dec/RA encoder position
int32_t RAenc;
uint8_t keypad; // keypad status
uint8_t XBits;
uint8_t YBits;
uint8_t ExtraBits;
uint16_t ain0; // analog inputs
uint16_t ain1;
uint32_t millis; // milliseconds clock
int8_t tF; // temperature (degF)
uint8_t voltage; // input voltage *10
uint32_t reserved0;
uint32_t reserved1;
uint16_t checksum; // checksum, H inverted
}__attribute__((packed)) SSstat;
int SSinit(char *devpath, int speed);
void SSclose();
int SSwrite(const uint8_t *buf, int len);
uint8_t *SSread(int *l);
int SSgetstat(SSstat *s);
#endif // SIDSERVO_H__

View File

@ -0,0 +1,9 @@
Calculates times of sunrise, sunset and noon, gives @ stdout just UNIX time of event
Sunrise/sunset - for particular angle below horizon (default: -18degr).
Usage:
- just `noon`, `sunrise` or `sunset` for default angles;
- `sunrise/sunset angle` for `angle` in degrees below horizon;
- `sunrise/sunset "standard"|"civil"|"nautic"|"astro" - calculates event for -0.833degr, -6degr, -12degr and -18degr.