diff --git a/Stellarium_control/Makefile b/Stellarium_control/Makefile new file mode 100644 index 0000000..c115065 --- /dev/null +++ b/Stellarium_control/Makefile @@ -0,0 +1,22 @@ +PROGRAM = stellariumdaemon +LDFLAGS = +SRCS = $(wildcard *.c) +CC = gcc +DEFINES = -D_XOPEN_SOURCE=1111 -DEBUG +CXX = gcc +CFLAGS = -Wall -Werror -Wextra $(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) diff --git a/Stellarium_control/Readme b/Stellarium_control/Readme new file mode 100644 index 0000000..a8352a5 --- /dev/null +++ b/Stellarium_control/Readme @@ -0,0 +1,2 @@ +Alpha version: no real control at all, just emulation + diff --git a/Stellarium_control/daemon.c b/Stellarium_control/daemon.c new file mode 100644 index 0000000..6563648 --- /dev/null +++ b/Stellarium_control/daemon.c @@ -0,0 +1,141 @@ +/* + * daemon.c - functions for running in background like a daemon + * + * Copyright 2013 Edward V. Emelianoff + * + * 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. + */ + +#define PROC_BASE "/proc" + +#include // printf, fopen, ... +#include // getpid +#include // perror +#include // opendir +#include // opendir +#include // stat +#include // fcntl +#include // exit +#include // memset + +/** + * read process name from /proc/PID/cmdline + * @param pid - PID of interesting process + * @return filename or NULL if not found + * don't use this function twice for different names without copying + * its returning by strdup, because `name` contains in static array + */ +char *readname(pid_t pid){ + static char name[256]; + char *pp = name, byte, path[256]; + FILE *file; + int cntr = 0; + size_t sz; + snprintf (path, 255, PROC_BASE "/%d/cmdline", pid); + file = fopen(path, "r"); + if(!file) return NULL; // there's no such file + do{ // read basename + sz = fread(&byte, 1, 1, file); + if(sz != 1) break; + if(byte != '/') *pp++ = byte; + else{ + pp = name; + cntr = 0; + } + }while(byte && cntr++ < 255); + name[cntr] = 0; + fclose(file); + return name; +} + +void iffound_default(pid_t pid){ + fprintf(stderr, "\nFound running process (pid=%d), exit.\n", pid); + exit(0); +} + +/** + * check wether there is a same running process + * exit if there is a running process or error + * Checking have 3 steps: + * 1) lock executable file + * 2) check pidfile (if you run a copy?) + * 3) check /proc for executables with the same name (no/wrong pidfile) + * @param argv - argument of main() or NULL for non-locking, call this function before getopt() + * @param pidfilename - name of pidfile or NULL if none + * @param iffound - action to run if file found or NULL for exit(0) + */ +void check4running(char **argv, char *pidfilename, void (*iffound)(pid_t pid)){ + DIR *dir; + FILE *pidfile, *fself; + struct dirent *de; + struct stat s_buf; + pid_t pid = 0, self; + struct flock fl; + char *name, *myname; + if(!iffound) iffound = iffound_default; + if(argv){ // block self + fself = fopen(argv[0], "r"); // open self binary to lock + memset(&fl, 0, sizeof(struct flock)); + fl.l_type = F_WRLCK; + if(fcntl(fileno(fself), F_GETLK, &fl) == -1){ // check locking + perror("fcntl"); + exit(1); + } + if(fl.l_type != F_UNLCK){ // file is locking - exit + printf("Found locker, PID = %d!\n", fl.l_pid); + exit(1); + } + fl.l_type = F_RDLCK; + if(fcntl(fileno(fself), F_SETLKW, &fl) == -1){ + perror("fcntl"); + exit(1); + } + } + self = getpid(); // get self PID + if(!(dir = opendir(PROC_BASE))){ // open /proc directory + perror(PROC_BASE); + exit(1); + } + if(!(name = readname(self))){ // error reading self name + perror("Can't read self name"); + exit(1); + } + myname = strdup(name); + if(pidfilename && stat(pidfilename, &s_buf) == 0){ // pidfile exists + pidfile = fopen(pidfilename, "r"); + if(pidfile){ + if(fscanf(pidfile, "%d", &pid) > 0){ // read PID of (possibly) running process + if((name = readname(pid)) && strncmp(name, myname, 255) == 0) + iffound(pid); + } + fclose(pidfile); + } + } + // There is no pidfile or it consists a wrong record + while((de = readdir(dir))){ // scan /proc + if(!(pid = (pid_t)atoi(de->d_name)) || pid == self) // pass non-PID files and self + continue; + if((name = readname(pid)) && strncmp(name, myname, 255) == 0) + iffound(pid); + } + closedir(dir); + if(pidfilename){ + pidfile = fopen(pidfilename, "w"); + fprintf(pidfile, "%d\n", self); // write self PID to pidfile + fclose(pidfile); + } + free(myname); +} diff --git a/Stellarium_control/main.c b/Stellarium_control/main.c new file mode 100644 index 0000000..ec61483 --- /dev/null +++ b/Stellarium_control/main.c @@ -0,0 +1,376 @@ +/* + * main.c + * + * Copyright 2014 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. + */ +#define _BSD_SOURCE +#include + +#include +#include +#include +#include +#include +#include +#include +#include +// for pthread_kill +//#define _XOPEN_SOURCE 666 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usefull_macros.h" + +// daemon.c +extern void check4running(char **argv, char *pidfilename, void (*iffound)(pid_t pid)); + +// Max amount of connections +#define BACKLOG (1) + +#define PORT ("10000") +#define BUFLEN (1024) + +static uint8_t buff[BUFLEN+1]; + +//glob_pars *Global_parameters = NULL; + +static volatile int global_quit = 0; +// quit by signal +static void signals(int sig){ + DBG("Get signal %d, quit.\n", sig); + global_quit = 1; + sleep(1); + exit(sig); +} + +// search a first word after needle without spaces +char* stringscan(char *str, char *needle){ + char *a, *e; + char *end = str + strlen(str); + a = strstr(str, needle); + if(!a) return NULL; + a += strlen(needle); + while (a < end && (*a == ' ' || *a == '\r' || *a == '\t')) a++; + if(a >= end) return NULL; + e = strchr(a, ' '); + if(e) *e = 0; + return a; +} + +/** + * Send data to user + * @param data - data to send + * @param dlen - data length + * @param sockfd - socket fd for sending data + */ +void send_data(uint8_t *data, size_t dlen, int sockfd){ + /*char buf[1024]; + if(!strip){ + if(imtype == IMTYPE_RAW) + L = snprintf(buf, 255, "%s\n%dx%d\n", imsuffixes[imtype], w, h); + else + L = snprintf(buf, 255, "%s\n%zd\n", imsuffixes[imtype], buflen); + }else{ + L = snprintf(buf, 1023, "HTTP/2.0 200 OK\r\nContent-type: image/%s\r\n" + "Content-Length: %zd\r\n\r\n", mimetypes[imtype], buflen); + } + buff = MALLOC(uint8_t, L + buflen); + memcpy(buff, buf, L); + memcpy(buff+L, imagedata, buflen); + FREE(imagedata); + buflen += L;*/ + size_t sent = write(sockfd, data, dlen); + if(sent != dlen) WARN("write()"); + //FREE(buff); +} + +//read: 0x14 0x0 0x0 0x0 0x5b 0x5a 0x2e 0xc6 0x8c 0x23 0x5 0x0 0x23 0x9 0xe5 0xaf 0x23 0x2e 0x34 0xed +// command: goto 16h29 24.45 -26d25 55.62 +/* + LITTLE-ENDIAN!!! + from client: +LENGTH (2 bytes, integer): length of the message +TYPE (2 bytes, integer): 0 +TIME (8 bytes, integer): current time on the server computer in microseconds + since 1970.01.01 UT. Currently unused. +RA (4 bytes, unsigned integer): right ascension of the telescope (J2000) + a value of 0x100000000 = 0x0 means 24h=0h, + a value of 0x80000000 means 12h +DEC (4 bytes, signed integer): declination of the telescope (J2000) + a value of -0x40000000 means -90degrees, + a value of 0x0 means 0degrees, + a value of 0x40000000 means 90degrees + +to client: +LENGTH (2 bytes, integer): length of the message +TYPE (2 bytes, integer): 0 +TIME (8 bytes, integer): current time on the server computer in microseconds + since 1970.01.01 UT. Currently unused. +RA (4 bytes, unsigned integer): right ascension of the telescope (J2000) + a value of 0x100000000 = 0x0 means 24h=0h, + a value of 0x80000000 means 12h +DEC (4 bytes, signed integer): declination of the telescope (J2000) + a value of -0x40000000 means -90degrees, + a value of 0x0 means 0degrees, + a value of 0x40000000 means 90degrees +STATUS (4 bytes, signed integer): status of the telescope, currently unused. + status=0 means ok, status<0 means some error +*/ + +#define DEG2DEC(degr) ((int32_t)(degr / 90. * ((double)0x40000000))) +#define HRS2RA(hrs) ((uint32_t)(hrs / 12. * ((double)0x80000000))) +#define DEC2DEG(i32) (((double)i32)*90./((double)0x40000000)) +#define RA2HRS(u32) (((double)u32)*12. /((double)0x80000000)) + +typedef struct __attribute__((__packed__)){ + uint16_t len; + uint16_t type; + uint64_t time; + uint32_t ra; + int32_t dec; +} indata; + +typedef struct __attribute__((__packed__)){ + uint16_t len; + uint16_t type; + uint64_t time; + uint32_t ra; + int32_t dec; + int32_t status; +} outdata; + +static double tagRA = -1., tagDec = -100.; + +void proc_data(uint8_t *data, ssize_t len){ + FNAME(); + if(len != sizeof(indata)){ + WARN("Bad data size: got %zd instead of %zd!", len, sizeof(indata)); + return; + } + indata *dat = (indata*)data; + uint16_t L, T; + uint64_t tim; + uint32_t ra; + int32_t dec; +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ + L = le16toh(dat->len); T = le16toh(dat->type); + tim = le64toh(dat->time); + ra = le32toh(dat->ra); + dec = (int32_t)le32toh((uint32_t)dat->dec); +#else + L = dat->len; T = dat->type; + tim = dat->time; + ra = dat->ra; dec = dat->dec; +#endif + WARN("got message with len %u & type %u", L, T); + tagRA = RA2HRS(ra); tagDec = DEC2DEG(dec); + WARN("RA: %u (%g), DEC: %d (%g)", ra, tagRA, + dec, tagDec); + time_t z = time(NULL); + time_t tm = (time_t)(tim/1000000); + WARN("time: %ju (local: %ju)", (uintmax_t)tm, (uintmax_t)z); + WARN("time: %zd -- %s local: %s", tim, ctime(&tm), ctime(&z)); +/* memmove(buff, data, sizeof(indata)); + outdata *dout = (outdata*) buff; + dout->ra = 0; dout->dec = 0x40000000; + dout->status = 0; + send_data(data, sizeof(outdata), sock);*/ +} + +/** + * main socket service procedure + */ +void handle_socket(int sock){ + FNAME(); + if(global_quit) return; + ssize_t readed; + outdata dout; + uint32_t oldra; + int32_t olddec; + dout.len = sizeof(outdata); + dout.type = 0; + dout.status = 0; + dout.ra = (tagRA < -0.1) ? 0 : HRS2RA(tagRA); + dout.dec = (tagDec < -91.) ? DEG2DEC(80.) : DEG2DEC(tagDec); + oldra = dout.ra; olddec = dout.dec; + while(!global_quit){ + //dout.ra += 0xF5555555; + if(tagRA < -0.1) dout.ra += HRS2RA(0.33); + else dout.ra = HRS2RA(tagRA); + if(tagDec > -91.) dout.dec = DEG2DEC(tagDec); + if(dout.ra != oldra || dout.dec != olddec){ + send_data((uint8_t*)&dout, sizeof(outdata), sock); + DBG("sent ra = %g (%g), dec = %g (%g)", RA2HRS(dout.ra), tagRA, DEC2DEG(dout.dec), tagDec); + oldra = (dout.ra+oldra)/2; olddec = (dout.dec+olddec)/2; + } + fd_set readfds; + struct timeval timeout; + FD_ZERO(&readfds); + FD_SET(sock, &readfds); + timeout.tv_sec = 1; // wait not more than 1 second + timeout.tv_usec = 0;//100000; + int sel = select(sock + 1 , &readfds , NULL , NULL , &timeout); + if(sel < 0){ + if(errno != EINTR) + WARN("select()"); + continue; + } + if(!(FD_ISSET(sock, &readfds))) continue; + // fill incoming buffer + readed = read(sock, buff, BUFLEN); + DBG("read %zd", readed); + if(readed <= 0){ // error or disconnect + DBG("Nothing to read from fd %d (ret: %zd)", sock, readed); + break; + } + /************************************** + * DO SOMETHING WITH DATA * + **************************************/ + proc_data(buff, readed); + //send_data(...); + } + close(sock); +} + +static inline void main_proc(){ + int sock; + struct addrinfo hints, *res, *p; + int reuseaddr = 1; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + if(getaddrinfo(NULL, PORT, &hints, &res) != 0){ + ERR("getaddrinfo"); + } + struct sockaddr_in *ia = (struct sockaddr_in*)res->ai_addr; + char str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(ia->sin_addr), str, INET_ADDRSTRLEN); + DBG("port: %u, addr: %s\n", ntohs(ia->sin_port), str); + // loop through all the results and bind to the first we can + for(p = res; p != NULL; p = p->ai_next){ + if((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){ + WARN("socket"); + continue; + } + if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1){ + ERR("setsockopt"); + } + if(bind(sock, p->ai_addr, p->ai_addrlen) == -1){ + close(sock); + WARN("bind"); + continue; + } + break; // if we get here, we have a successfull connection + } + if(p == NULL){ + // looped off the end of the list with no successful bind + ERRX("failed to bind socket"); + } + // Listen + if(listen(sock, BACKLOG) == -1){ + ERR("listen"); + } + freeaddrinfo(res); + // Main loop + while(!global_quit){ +// fd_set readfds; +// struct timeval timeout; + socklen_t size = sizeof(struct sockaddr_in); + struct sockaddr_in their_addr; + int newsock; +/* FD_ZERO(&readfds); + FD_SET(sock, &readfds); + timeout.tv_sec = 0; // wait not more than 10 milliseconds + timeout.tv_usec = 10000; + int sel = select(sock + 1 , &readfds , NULL , NULL , &timeout); + if(sel < 0){ + if(errno != EINTR) + WARN("select()"); + continue; + } + if(!(FD_ISSET(sock, &readfds))) continue;*/ + // DBG("accept"); + newsock = accept(sock, (struct sockaddr*)&their_addr, &size); + // printf("got addr %ul\n", their_addr.sin_addr.s_addr); + if(newsock <= 0){ + WARN("accept()"); + continue; + } + pid_t pid = fork(); + if(pid < 0) + ERR("ERROR on fork"); + if(pid == 0){ + close(sock); + handle_socket(newsock); + exit(0); + }else + close(newsock); + } + + // wait for thread ends before closing videodev +// pthread_join(readout_thread, NULL); +// pthread_mutex_unlock(&readout_mutex); + close(sock); +} + +int main(_U_ int argc, char **argv){ + // setup coloured output + initial_setup(); + check4running(argv, NULL, NULL); +// Global_parameters = parce_args(argc, argv); +// assert(Global_parameters != NULL); + + 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 +/* +#ifndef EBUG // daemonize only in release mode + if(!Global_parameters->nodaemon){ + if(daemon(1, 0)){ + perror("daemon()"); + exit(1); + } + } +#endif // EBUG +*/ +/* + while(1){ + pid_t childpid = fork(); + if(childpid){ + DBG("Created child with PID %d\n", childpid); + wait(NULL); + printf("Child %d died\n", childpid); + }else{ + prctl(PR_SET_PDEATHSIG, SIGTERM); // send SIGTERM to child when parent dies + main_proc(); + return 0; + } + } + */ + main_proc(); + return 0; +} diff --git a/Stellarium_control/main.h b/Stellarium_control/main.h new file mode 100644 index 0000000..ec6d9c1 --- /dev/null +++ b/Stellarium_control/main.h @@ -0,0 +1,42 @@ +/* + * main.h + * + * Copyright 2014 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. + */ +#pragma once +#ifndef __MAIN_H__ +#define __MAIN_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cmdlnopts.h" +#include "usefull_macros.h" + +// global parameters +extern glob_pars *Global_parameters; + +#endif // __MAIN_H__ diff --git a/Stellarium_control/usefull_macros.c b/Stellarium_control/usefull_macros.c new file mode 100644 index 0000000..31e84d6 --- /dev/null +++ b/Stellarium_control/usefull_macros.c @@ -0,0 +1,316 @@ +/* + * usefull_macros.h - a set of usefull functions: memory, color etc + * + * Copyright 2013 Edward V. Emelianoff + * + * 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 +/** + * function for different purposes that need to know time intervals + * @return double value: time in seconds + */ +double dtime(){ + double t; + struct timeval tv; + gettimeofday(&tv, NULL); + t = tv.tv_sec + ((double)tv.tv_usec)/1e6; + return t; +} + +/******************************************************************************\ + * Coloured terminal +\******************************************************************************/ +int globErr = 0; // errno for WARN/ERR + +// pointers to coloured output printf +int (*red)(const char *fmt, ...); +int (*green)(const char *fmt, ...); +int (*_WARN)(const char *fmt, ...); + +/* + * format red / green messages + * name: r_pr_, g_pr_ + * @param fmt ... - printf-like format + * @return number of printed symbols + */ +int r_pr_(const char *fmt, ...){ + va_list ar; int i; + printf(RED); + va_start(ar, fmt); + i = vprintf(fmt, ar); + va_end(ar); + printf(OLDCOLOR); + return i; +} +int g_pr_(const char *fmt, ...){ + va_list ar; int i; + printf(GREEN); + va_start(ar, fmt); + i = vprintf(fmt, ar); + va_end(ar); + printf(OLDCOLOR); + return i; +} +/* + * print red error/warning messages (if output is a tty) + * @param fmt ... - printf-like format + * @return number of printed symbols + */ +int r_WARN(const char *fmt, ...){ + va_list ar; int i = 1; + fprintf(stderr, RED); + va_start(ar, fmt); + if(globErr){ + errno = globErr; + vwarn(fmt, ar); + errno = 0; + globErr = 0; + }else + i = vfprintf(stderr, fmt, ar); + va_end(ar); + i++; + fprintf(stderr, OLDCOLOR "\n"); + return i; +} + +const char stars[] = "****************************************"; +/* + * notty variants of coloured printf + * name: s_WARN, r_pr_notty + * @param fmt ... - printf-like format + * @return number of printed symbols + */ +int s_WARN(const char *fmt, ...){ + va_list ar; int i; + i = fprintf(stderr, "\n%s\n", stars); + va_start(ar, fmt); + if(globErr){ + errno = globErr; + vwarn(fmt, ar); + errno = 0; + globErr = 0; + }else + i = +vfprintf(stderr, fmt, ar); + va_end(ar); + i += fprintf(stderr, "\n%s\n", stars); + i += fprintf(stderr, "\n"); + return i; +} +int r_pr_notty(const char *fmt, ...){ + va_list ar; int i; + i = printf("\n%s\n", stars); + va_start(ar, fmt); + i += vprintf(fmt, ar); + va_end(ar); + i += printf("\n%s\n", stars); + return i; +} + +/** + * Run this function in the beginning of main() to setup locale & coloured output + */ +void initial_setup(){ + // setup coloured output + if(isatty(STDOUT_FILENO)){ // make color output in tty + red = r_pr_; green = g_pr_; + }else{ // no colors in case of pipe + red = r_pr_notty; green = printf; + } + if(isatty(STDERR_FILENO)) _WARN = r_WARN; + else _WARN = s_WARN; + // Setup locale + setlocale(LC_ALL, ""); + setlocale(LC_NUMERIC, "C"); +#ifdef GETTEXT_PACKAGE + bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); + textdomain(GETTEXT_PACKAGE); +#endif +} + +/******************************************************************************\ + * Memory +\******************************************************************************/ +/* + * safe memory allocation for macro ALLOC + * @param N - number of elements to allocate + * @param S - size of single element (typically sizeof) + * @return pointer to allocated memory area + */ +void *my_alloc(size_t N, size_t S){ + void *p = calloc(N, S); + if(!p) ERR("malloc"); + //assert(p); + return p; +} +/* +#include +#include +#include +#include +*/ +/** + * Mmap file to a memory area + * + * @param filename (i) - name of file to mmap + * @return stuct with mmap'ed file or die + */ +mmapbuf *My_mmap(char *filename){ + int fd; + char *ptr; + size_t Mlen; + struct stat statbuf; + if(!filename) ERRX(_("No filename given!")); + if((fd = open(filename, O_RDONLY)) < 0) + ERR(_("Can't open %s for reading"), filename); + if(fstat (fd, &statbuf) < 0) + ERR(_("Can't stat %s"), filename); + Mlen = statbuf.st_size; + if((ptr = mmap (0, Mlen, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) + ERR(_("Mmap error for input")); + if(close(fd)) ERR(_("Can't close mmap'ed file")); + mmapbuf *ret = MALLOC(mmapbuf, 1); + ret->data = ptr; + ret->len = Mlen; + return ret; +} + +void My_munmap(mmapbuf *b){ + if(munmap(b->data, b->len)) + ERR(_("Can't munmap")); + FREE(b); +} + + +/******************************************************************************\ + * Terminal in no-echo mode +\******************************************************************************/ +struct termios oldt, newt; // terminal flags +// run on exit: +/* +void quit(int sig){ + //... + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // return terminal to previous state + //... +} +*/ +// initial setup: +void setup_con(){ + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + if(tcsetattr(STDIN_FILENO, TCSANOW, &newt) < 0){ + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + exit(-2); //quit? + } +} + +/** + * Read character from console without echo + * @return char readed + */ +int read_console(){ + int rb; + struct timeval tv; + int retval; + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(STDIN_FILENO, &rfds); + tv.tv_sec = 0; tv.tv_usec = 10000; + retval = select(1, &rfds, NULL, NULL, &tv); + if(!retval) rb = 0; + else { + if(FD_ISSET(STDIN_FILENO, &rfds)) rb = getchar(); + else rb = 0; + } + return rb; +} + +/** + * getchar() without echo + * wait until at least one character pressed + * @return character readed + */ +int mygetchar(){ // аналог getchar() без необходимости жать Enter + int ret; + do ret = read_console(); + while(ret == 0); + return ret; +} + + +/******************************************************************************\ + * TTY with select() +\******************************************************************************/ +struct termio oldtty, tty; // TTY flags +char *comdev; // TTY device name +int comfd; // TTY fd +// run on exit: +/* +void quit(int ex_stat){ + ioctl(comfd, TCSANOW, &oldtty ); // return TTY to previous state + close(comfd); + //... +} +*/ +#ifndef BAUD_RATE +#define BAUD_RATE B9600 +#endif +// init: +void tty_init(){ + printf("\nOpen port...\n"); + if ((comfd = open(comdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0){ + fprintf(stderr,"Can't use port %s\n",comdev); + ioctl(comfd, TCSANOW, &oldtty); // return TTY to previous state + close(comfd); + exit(1); // quit? + } + printf(" OK\nGet current settings...\n"); + if(ioctl(comfd,TCGETA,&oldtty) < 0) exit(-1); // Get settings + tty = oldtty; + tty.c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG) + tty.c_oflag = 0; + tty.c_cflag = BAUD_RATE|CS8|CREAD|CLOCAL; // 9.6k, 8N1, RW, ignore line ctrl + tty.c_cc[VMIN] = 0; // non-canonical mode + tty.c_cc[VTIME] = 5; + if(ioctl(comfd,TCSETA,&tty) < 0) exit(-1); // set new mode + printf(" OK\n"); +} +/** + * Read data from TTY + * @param buff (o) - buffer for data read + * @param length - buffer len + * @return amount of readed bytes + */ +size_t read_tty(uint8_t *buff, size_t length){ + ssize_t L = 0; + fd_set rfds; + struct timeval tv; + int retval; + FD_ZERO(&rfds); + FD_SET(comfd, &rfds); + tv.tv_sec = 0; tv.tv_usec = 50000; // wait for 50ms + retval = select(comfd + 1, &rfds, NULL, NULL, &tv); + if (!retval) return 0; + if(FD_ISSET(comfd, &rfds)){ + if((L = read(comfd, buff, length)) < 1) return 0; + } + return (size_t)L; +} diff --git a/Stellarium_control/usefull_macros.h b/Stellarium_control/usefull_macros.h new file mode 100644 index 0000000..43a6192 --- /dev/null +++ b/Stellarium_control/usefull_macros.h @@ -0,0 +1,106 @@ +/* + * usefull_macros.h - a set of usefull macros: memory, color etc + * + * Copyright 2013 Edward V. Emelianoff + * + * 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. + */ + +#pragma once +#ifndef __USEFULL_MACROS_H__ +#define __USEFULL_MACROS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * GETTEXT + */ +#define _(String) gettext(String) +#define gettext_noop(String) String +#define N_(String) gettext_noop(String) + +// unused arguments with -Wall -Werror +#define _U_ __attribute__((__unused__)) + +/* + * Coloured messages output + */ +#define RED "\033[1;31;40m" +#define GREEN "\033[1;32;40m" +#define OLDCOLOR "\033[0;0;0m" + +/* + * ERROR/WARNING messages + */ +extern int globErr; +#define ERR(...) do{globErr=errno; _WARN(__VA_ARGS__); exit(-1);}while(0) +#define ERRX(...) do{globErr=0; _WARN(__VA_ARGS__); exit(-1);}while(0) +#define WARN(...) do{globErr=errno; _WARN(__VA_ARGS__);}while(0) +#define WARNX(...) do{globErr=0; _WARN(__VA_ARGS__);}while(0) + +/* + * print function name, debug messages + * debug mode, -DEBUG + */ +#ifdef EBUG + #define FNAME() fprintf(stderr, "\n%s (%s, line %d)\n", __func__, __FILE__, __LINE__) + #define DBG(...) do{fprintf(stderr, "%s (%s, line %d): ", __func__, __FILE__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n");} while(0) +#else + #define FNAME() do{}while(0) + #define DBG(...) do{}while(0) +#endif //EBUG + +/* + * Memory allocation + */ +#define ALLOC(type, var, size) type * var = ((type *)my_alloc(size, sizeof(type))) +#define MALLOC(type, size) ((type *)my_alloc(size, sizeof(type))) +#define FREE(ptr) do{free(ptr); ptr = NULL;}while(0) + +// functions for color output in tty & no-color in pipes +extern int (*red)(const char *fmt, ...); +extern int (*_WARN)(const char *fmt, ...); +extern int (*green)(const char *fmt, ...); +void * my_alloc(size_t N, size_t S); +void initial_setup(); + +// mmap file +typedef struct{ + char *data; + size_t len; +} mmapbuf; +mmapbuf *My_mmap(char *filename); +void My_munmap(mmapbuf *b); + +#endif // __USEFULL_MACROS_H__