From 88b2cfcdbeff60e4308aca5b6ec4183e64efbbfb Mon Sep 17 00:00:00 2001 From: eddyem Date: Fri, 27 Jan 2017 17:35:00 +0300 Subject: [PATCH] shit! I should always write "git commit -a", WTF!!! --- Makefile | 33 +++++------- cmdlnopts.c | 9 +++- cmdlnopts.h | 6 ++- main.c | 15 +++++- parseargs.c | 2 +- parseargs.h | 2 +- sbig340.c.tags | 13 ++++- term.c | 137 +++++++++++++++++++++++++++++++++++++++++++---- term.h | 20 ++++++- usefull_macros.c | 36 +++++++------ usefull_macros.h | 4 +- 11 files changed, 222 insertions(+), 55 deletions(-) diff --git a/Makefile b/Makefile index f159e29..9aeb8d2 100644 --- a/Makefile +++ b/Makefile @@ -1,40 +1,34 @@ -PROGRAM = sbig340 -LDFLAGS = -#-fdata-sections -ffunction-sections -Wl,--gc-sections -SRCS = $(wildcard *.c) -DEFINES = $(DEF) -D_XOPEN_SOURCE=1111 -DEBUG -OBJDIR = mk -CFLAGS = -Wall -Werror -Wextra -Wno-trampolines -std=gnu99 -OBJS = $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o)) -DEPS = $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.d)) +# run `make DEF=...` to add extra defines +PROGRAM := sbig340 +LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all +SRCS := $(wildcard *.c) +DEFINES := $(DEF) -D_XOPEN_SOURCE=1111 -DEBUG +OBJDIR := mk +CFLAGS += -O2 -Wall -Werror -Wextra -Wno-trampolines -std=gnu99 +OBJS := $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o)) +DEPS := $(OBJS:.o=.d) CC = gcc -all : $(PROGRAM) +all : $(OBJDIR) $(PROGRAM) $(PROGRAM) : $(OBJS) @echo -e "\t\tLD $(PROGRAM)" - $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $(PROGRAM) + $(CC) $(LDFLAGS) $(OBJS) -o $(PROGRAM) $(OBJDIR): mkdir $(OBJDIR) -$(OBJS): $(OBJDIR) $(DEPS) - -$(OBJDIR)/%.d: %.c $(OBJDIR) - $(CC) -MM -MG $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(@D)/\1.o $(@D)/\1.d:,' >$@ - ifneq ($(MAKECMDGOALS),clean) -include $(DEPS) endif $(OBJDIR)/%.o: %.c @echo -e "\t\tCC $<" - $(CC) -c $(CFLAGS) $(DEFINES) -o $@ $< + $(CC) -MD -c $(LDFLAGS) $(CFLAGS) $(DEFINES) -o $@ $< clean: @echo -e "\t\tCLEAN" - @rm -f $(OBJS) - @rm -f $(DEPS) + @rm -f $(OBJS) $(DEPS) @rmdir $(OBJDIR) 2>/dev/null || true xclean: clean @@ -44,4 +38,3 @@ gentags: CFLAGS="$(CFLAGS) $(DEFINES)" geany -g $(PROGRAM).c.tags *[hc] 2>/dev/null .PHONY: gentags clean xclean - diff --git a/cmdlnopts.c b/cmdlnopts.c index e019c28..656a385 100644 --- a/cmdlnopts.c +++ b/cmdlnopts.c @@ -1,4 +1,4 @@ -/* +/* geany_encoding=koi8-r * cmdlnopts.c - the only function that parse cmdln args and returns glob parameters * * Copyright 2013 Edward V. Emelianoff @@ -40,8 +40,11 @@ int rewrite_ifexists = 0, // rewrite existing files == 0 or 1 glob_pars const Gdefault = { .daemon = 0, .terminal = 0, + .heater = HEATER_LEAVE, .device = DEFAULT_COMDEV, .rest_pars_num = 0, + .splist = 0, + .newspeed = 0, .rest_pars = NULL }; @@ -55,6 +58,10 @@ myoption cmdlnopts[] = { {"daemon", NO_ARGS, NULL, 'd', arg_int, APTR(&G.daemon), _("run as daemon")}, {"terminal",NO_ARGS, NULL, 't', arg_int, APTR(&G.terminal), _("run as terminal")}, {"device", NEED_ARG, NULL, 'i', arg_string, APTR(&G.device), _("serial device name (default: " DEFAULT_COMDEV ")")}, + {"heater-on",NO_ARGS, APTR(&G.heater),HEATER_ON, arg_none, NULL, _("turn heater on")}, + {"heater-off",NO_ARGS, APTR(&G.heater),HEATER_OFF, arg_none, NULL, _("turn heater off")}, + {"spd-list",NO_ARGS, NULL, 'l', arg_int, APTR(&G.splist), _("list speeds available")}, + {"spd-set", NEED_ARG, NULL, 's', arg_int, APTR(&G.newspeed), _("set terminal speed")}, // simple integer parameter with obligatory arg: end_option }; diff --git a/cmdlnopts.h b/cmdlnopts.h index 2fde25b..b8fcffd 100644 --- a/cmdlnopts.h +++ b/cmdlnopts.h @@ -1,4 +1,4 @@ -/* +/* geany_encoding=koi8-r * cmdlnopts.h - comand line options for parceargs * * Copyright 2013 Edward V. Emelianoff @@ -24,6 +24,7 @@ #define __CMDLNOPTS_H__ #include "parseargs.h" +#include "term.h" /* * here are some typedef's for global data @@ -33,6 +34,9 @@ typedef struct{ int terminal; // run as terminal (send/receive) char *device; // serial device name int rest_pars_num; // number of rest parameters + heater_cmd heater; // turn heater on/off/leave unchanged + int splist; // list speeds available + int newspeed; // change speed char** rest_pars; // the rest parameters: array of char* } glob_pars; diff --git a/main.c b/main.c index 2337452..0ca5042 100644 --- a/main.c +++ b/main.c @@ -1,4 +1,4 @@ -/* +/* geany_encoding=koi8-r * main.c * * Copyright 2017 Edward V. Emelianov @@ -19,6 +19,7 @@ * MA 02110-1301, USA. */ #include "usefull_macros.h" +#include #include "term.h" #include "cmdlnopts.h" @@ -30,7 +31,13 @@ void signals(int signo){ int main(int argc, char **argv){ initial_setup(); + for(int i = 0; i < 255; ++i) signal(i, signals); + signal(SIGTSTP, SIG_IGN); // ctrl+Z - ignore + signal(SIGQUIT, SIG_IGN); // ctrl+\ - ignore + glob_pars *G = parse_args(argc, argv); + printf("sp: %d\n", G->splist); + if(G->splist) list_speeds(); if(G->daemon && G->terminal){ WARNX(_("Options --daemon and --terminal can't be together!")); return 1; @@ -39,6 +46,12 @@ int main(int argc, char **argv){ WARNX(_("Check power and connection: device not answer!")); return 1; } + char *fw = get_firmvare_version(); + if(fw) printf(_("Firmware version: %s\n"), fw); + if(G->newspeed && term_setspeed(G->newspeed)) + ERRX(_("Can't change speed to %d"), G->newspeed); + if(G->heater != HEATER_LEAVE) + heater(G->heater); // turn on/off heater if(G->daemon || G->terminal){ red(_("All other commandline options rejected!\n")); if(G->terminal) run_terminal(); // non-echo terminal mode diff --git a/parseargs.c b/parseargs.c index 62c3808..03fd825 100644 --- a/parseargs.c +++ b/parseargs.c @@ -1,4 +1,4 @@ -/* +/* geany_encoding=koi8-r * parseargs.c - parsing command line arguments & print help * * Copyright 2013 Edward V. Emelianoff diff --git a/parseargs.h b/parseargs.h index a0ac099..537fc5b 100644 --- a/parseargs.h +++ b/parseargs.h @@ -1,4 +1,4 @@ -/* +/* geany_encoding=koi8-r * parseargs.h - headers for parsing command line arguments * * Copyright 2013 Edward V. Emelianoff diff --git a/sbig340.c.tags b/sbig340.c.tags index cc9dc30..93876ee 100644 --- a/sbig340.c.tags +++ b/sbig340.c.tags @@ -1743,6 +1743,7 @@ __END_NAMESPACE_STD __EXCEPTIONSÌ65536Ö0 __FDS_BITSÌ131072Í(set)Ö0 __FD_CLRÌ131072Í(d,set)Ö0 +__FD_ELTÌ65536Ö0 __FD_ELTÌ131072Í(d)Ö0 __FD_ISSETÌ131072Í(d,set)Ö0 __FD_MASKÌ131072Í(d)Ö0 @@ -1917,6 +1918,7 @@ __MATHDECL_1 __MATHDECL_VECÌ131072Í(type,function,suffix,args)Ö0 __MATH_DECLARE_LDOUBLEÌ65536Ö0 __MATH_DECLARING_DOUBLEÌ65536Ö0 +__MATH_INLINEÌ65536Ö0 __MATH_PRECNAMEÌ65536Ö0 __MATH_PRECNAMEÌ131072Í(name,r)Ö0 __MAX_BAUDÌ65536Ö0 @@ -1924,12 +1926,12 @@ __MMX__ __MODE_T_TYPEÌ65536Ö0 __NFDBITSÌ65536Ö0 __NLINK_T_TYPEÌ65536Ö0 -__NO_INLINE__Ì65536Ö0 __NTHÌ131072Í(fct)Ö0 __OFF64_T_TYPEÌ65536Ö0 __OFF_T_MATCHES_OFF64_TÌ65536Ö0 __OFF_T_TYPEÌ65536Ö0 __OPEN_NEEDS_MODEÌ131072Í(oflag)Ö0 +__OPTIMIZE__Ì65536Ö0 __ORDER_BIG_ENDIAN__Ì65536Ö0 __ORDER_LITTLE_ENDIAN__Ì65536Ö0 __ORDER_PDP_ENDIAN__Ì65536Ö0 @@ -2019,6 +2021,8 @@ __STDC_IEC_559__ __STDC_ISO_10646__Ì65536Ö0 __STDC_NO_THREADS__Ì65536Ö0 __STDC__Ì65536Ö0 +__STDIO_INLINEÌ65536Ö0 +__STDLIB_MB_LEN_MAXÌ65536Ö0 __STD_TYPEÌ65536Ö0 __STRINGÌ131072Í(x)Ö0 __SUSECONDS_T_TYPEÌ65536Ö0 @@ -2093,6 +2097,7 @@ __USECONDS_T_TYPE __USEFULL_MACROS_H__Ì65536Ö0 __USER_LABEL_PREFIX__Ì65536Ö0 __USE_ATFILEÌ65536Ö0 +__USE_EXTERN_INLINESÌ65536Ö0 __USE_FILE_OFFSET64Ì65536Ö0 __USE_FORTIFY_LEVELÌ65536Ö0 __USE_GNUÌ65536Ö0 @@ -2217,6 +2222,7 @@ __isascii __isascii_lÌ131072Í(c,l)Ö0 __isblank_lÌ131072Í(c,l)Ö0 __iscntrl_lÌ131072Í(c,l)Ö0 +__isctype_fÌ131072Í(type)Ö0 __isctype_lÌ131072Í(c,type,locale)Ö0 __isdigit_lÌ131072Í(c,l)Ö0 __isgraph_lÌ131072Í(c,l)Ö0 @@ -2235,6 +2241,8 @@ __linux__ __lldiv_t_definedÌ65536Ö0 __long_double_tÌ65536Ö0 __malloc_and_calloc_definedÌ65536Ö0 +__mempcpyÌ65536Ö0 +__mempcpyÌ131072Í(dest,src,n)Ö0 __mode_t_definedÌ65536Ö0 __need_EmathÌ65536Ö0 __need_FILEÌ65536Ö0 @@ -2361,6 +2369,7 @@ error_t falseÌ65536Ö0 flagÌ64Îanon_struct_2Ö0Ïint * fpclassifyÌ131072Í(x)Ö0 +fread_unlockedÌ65536Ö0 g_pr_Ì16Í(const char *fmt, ...)Ö0Ïint get_aptrÌ16Í(void *paptr, argtype type)Ö0Ïvoid * get_curspeedÌ16Í()Ö0Ïint @@ -2431,6 +2440,8 @@ main majorÌ131072Í(dev)Ö0 makedevÌ131072Í(maj,min)Ö0 math_errhandlingÌ65536Ö0 +mempcpyÌ65536Ö0 +mempcpyÌ131072Í(dest,src,n)Ö0 minorÌ131072Í(dev)Ö0 mmapbufÌ4096Ö0Ïanon_struct_4 my_allocÌ16Í(size_t N, size_t S)Ö0Ïvoid * diff --git a/term.c b/term.c index 856f9a5..92d6ea0 100644 --- a/term.c +++ b/term.c @@ -1,4 +1,4 @@ -/* +/* geany_encoding=koi8-r * client.c - simple terminal client * * Copyright 2013 Edward V. Emelianoff @@ -47,7 +47,7 @@ tcflag_t Bspeeds[] = { }; static const int speedssize = (int)sizeof(Bspeeds)/sizeof(Bspeeds[0]); static int curspd = -1; -int speeds[] = { +static int speeds[] = { 9600, 19200, 38400, @@ -57,6 +57,12 @@ int speeds[] = { 460800 }; +void list_speeds(){ + green(_("Speeds available:\n")); + for(int i = 0; i < speedssize; ++i) + printf("\t%d\n", speeds[i]); +} + /** * Return -1 if not connected or value of current speed in bps */ @@ -77,7 +83,9 @@ int send_data(uint8_t *buf){ chksum ^= ~(*ptr++) & 0x7f; DBG("send: %s%c", buf, (char)chksum); if(write_tty(buf, l)) return 1; + DBG("cmd done"); if(write_tty(&chksum, 1)) return 1; + DBG("checksum done"); last_chksum = chksum; return 0; } @@ -98,15 +106,35 @@ trans_status wait_checksum(){ uint8_t chr; do{ if(read_tty(&chr, 1)) break; - }while(dtime() - d0 < 0.1); - if(dtime() - d0 >= 0.1) return TRANS_TIMEOUT; + DBG("wait.."); + }while(dtime() - d0 < WAIT_TMOUT); + if(dtime() - d0 >= WAIT_TMOUT) return TRANS_TIMEOUT; + DBG("chksum: got 0x%x, need 0x%x", chr, last_chksum); if(chr != last_chksum) return TRANS_BADCHSUM; return TRANS_SUCCEED; } +/** + * read string from terminal (with timeout) + * @param str (o) - buffer for string + * @param L - its length + * @return number of characters read + */ +size_t read_string(uint8_t *str, int L){ + size_t r = 0, l; + uint8_t *ptr = str; + double d0 = dtime(); + do{ + if((l = read_tty(ptr, L))){ + r += l; L -= l; ptr += l; + d0 = dtime(); + } + }while(dtime() - d0 < WAIT_TMOUT); + return r; +} /** - * wait for answer (not more than 0.1s) + * wait for answer (not more than WAIT_TMOUT seconds) * @param rdata (o) - readed data * @param rdlen (o) - its length (static array - THREAD UNSAFE) * @return transaction status @@ -120,7 +148,7 @@ trans_status wait4answer(uint8_t **rdata, int *rdlen){ double d0 = dtime(); do{ if((L = read_tty(buf, sizeof(buf)))) break; - }while(dtime() - d0 < 0.1); + }while(dtime() - d0 < WAIT_TMOUT); if(!L) return TRANS_TIMEOUT; *rdata = buf; *rdlen = L; @@ -155,6 +183,67 @@ int try_connect(char *device){ return 0; } +/** + * Change terminal speed to `speed` + * @return 0 if all OK + */ +int term_setspeed(int speed){ + int spdidx = 0; + size_t L; + for(; spdidx < speedssize; ++spdidx) + if(speeds[spdidx] == speed) break; + if(spdidx == speedssize){ + WARNX(_("Wrong speed: %d!"), speed); + list_speeds(); + return 1; + } + if(spdidx == curspd){ + printf(_("Already connected at %d\n"), speeds[spdidx]); + return 0; + } + green(_("Try to change speed to %d\n"), speed); + uint8_t msg[7] = {CMD_CHANGE_BAUDRATE, spdidx + '0', 0}; + if(send_data(msg)){ + WARNX(_("Error during message send")); + return 1; + } + if(TRANS_SUCCEED != wait_checksum()){ + WARNX(_("Bad checksum")); + return 1; + } + tty_init(NULL, Bspeeds[spdidx]); // change speed & wait 'S' as answer + double d0 = dtime(); + do{ + if((L = read_tty(msg, 1))){ + DBG("READ %c", msg[0]); + if(ANS_CHANGE_BAUDRATE == msg[0]) + break; + } + }while(dtime() - d0 < WAIT_TMOUT); + if(L != 1 || msg[0] != ANS_CHANGE_BAUDRATE){ + WARNX(_("Didn't receive the answer")); + return 1; + } + // now send "Test" and wait for "TestOk": + if(write_tty((const uint8_t*)"Test", 4)){ + WARNX(_("Error in communications")); + return 1; + } + d0 = dtime(); + if((L = read_string(msg, 6))) msg[L] = 0; + DBG("got %zd: %s", L, msg); + if(L != 6 || strcmp((char*)msg, "TestOk")){ + WARNX(_("Received wrong answer!")); + return 1; + } + if(write_tty((const uint8_t*)"k", 1)){ + WARNX(_("Error in communications")); + return 1; + } + green(_("Speed changed!\n")); + return 0; +} + /** * run terminal emulation: send user's commands with checksum and show answers */ @@ -177,10 +266,12 @@ void run_terminal(){ printf("\n"); } if((rb = read_console())){ - printf("Send command: %c ... ", (char)rb); - send_cmd((uint8_t)rb); - if(TRANS_SUCCEED != wait_checksum()) printf(_("Error.\n")); - else printf(_("Done.\n")); + if(rb > 31){ + printf("Send command: %c ... ", (char)rb); + send_cmd((uint8_t)rb); + if(TRANS_SUCCEED != wait_checksum()) printf(_("Error.\n")); + else printf(_("Done.\n")); + } } } } @@ -190,3 +281,29 @@ void run_terminal(){ */ void daemonize(){ } + +void heater(heater_cmd cmd){ + if(cmd == HEATER_LEAVE) return; + uint8_t buf[3] = {CMD_HEATER, 0, 0}; + if(cmd == HEATER_ON) buf[1] = 1; + int i; + for(i = 0; i < 10 && send_data(buf); ++i); + trans_status st = TRANS_TIMEOUT; + if(i < 10) st = wait_checksum(); + if(i == 10 || st != TRANS_SUCCEED){ + WARNX(_("Can't send heater command: %s"), (st==TRANS_TIMEOUT) ? _("no answer") : _("bad checksum")); + } +} + +/** + * @return static buffer with version string, for example, "V1.10" or "T2.15" ('T' means testing) or NULL + */ +char *get_firmvare_version(){ + static char buf[256]; + if(TRANS_SUCCEED != send_cmd(CMD_FIRMWARE_WERSION)) return NULL; + if(TRANS_SUCCEED != wait_checksum()) return NULL; + uint8_t V[2]; + if(2 != read_string(V, 2)) return NULL; + snprintf(buf, 256, "%c%d.%d", (V[0] &0x80)?'T':'V', V[0]&0x7f, V[1]); + return buf; +} diff --git a/term.h b/term.h index 17ad829..b1e3403 100644 --- a/term.h +++ b/term.h @@ -1,4 +1,4 @@ -/* +/* geany_encoding=koi8-r * term.h - functions to work with serial terminal * * Copyright 2017 Edward V. Emelianov @@ -23,24 +23,40 @@ #define __TERM_H__ // communication errors - typedef enum{ TRANS_SUCCEED = 0, // no errors TRANS_BADCHSUM, // wrong checksum TRANS_TIMEOUT // no data for 0.1s } trans_status; +// change heater +typedef enum{ + HEATER_LEAVE = 0, // leave unchanged + HEATER_ON, // turn on + HEATER_OFF // turn off +} heater_cmd; + +// terminal timeout (seconds) +#define WAIT_TMOUT (0.1) /******************************** Commands definition ********************************/ // communications test #define CMD_COMM_TEST 'E' +#define CMD_HEATER 'g' +#define CMD_CHANGE_BAUDRATE 'B' +#define CMD_FIRMWARE_WERSION 'V' /******************************** Answers definition ********************************/ #define ANS_COMM_TEST 'O' +#define ANS_CHANGE_BAUDRATE 'S' void run_terminal(); void daemonize(); int open_serial(char *dev); int get_curspeed(); int try_connect(char *device); +void heater(heater_cmd cmd); +void list_speeds(); +int term_setspeed(int speed); +char *get_firmvare_version(); #endif // __TERM_H__ diff --git a/usefull_macros.c b/usefull_macros.c index f93a183..fbac349 100644 --- a/usefull_macros.c +++ b/usefull_macros.c @@ -1,4 +1,4 @@ -/* +/* geany_encoding=koi8-r * usefull_macros.h - a set of usefull functions: memory, color etc * * Copyright 2013 Edward V. Emelianoff @@ -288,18 +288,24 @@ void restore_tty(){ #endif // init: (speed = B9600 etc) void tty_init(char *comdev, tcflag_t speed){ - DBG("Open port..."); - if ((comfd = open(comdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0){ - WARN("Can't use port %s\n",comdev); - ioctl(comfd, TCSANOW, &oldtty); // return TTY to previous state - close(comfd); - signals(0); // quit? - } - DBG("OK\nGet current settings..."); - if(ioctl(comfd,TCGETA,&oldtty) < 0){ // Get settings - /// "îÅ ÍÏÇÕ ÐÏÌÕÞÉÔØ ÎÁÓÔÒÏÊËÉ" - WARN(_("Can't get settings")); - signals(0); + if(comfd == -1){ // not opened + if(!comdev){ + WARNX("comdev == NULL"); + signals(11); + } + DBG("Open port..."); + if ((comfd = open(comdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0){ + WARN("Can't use port %s\n",comdev); + ioctl(comfd, TCSANOW, &oldtty); // return TTY to previous state + close(comfd); + signals(2); // quit? + } + DBG("OK\nGet current settings..."); + if(ioctl(comfd,TCGETA,&oldtty) < 0){ // Get settings + /// "îÅ ÍÏÇÕ ÐÏÌÕÞÉÔØ ÎÁÓÔÒÏÊËÉ" + WARN(_("Can't get settings")); + signals(2); + } } tty = oldtty; tty.c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG) @@ -307,7 +313,7 @@ void tty_init(char *comdev, tcflag_t speed){ tty.c_cflag = speed|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){ + if(ioctl(comfd, TCSETA, &tty) < 0){ /// "îÅ ÍÏÇÕ ÕÓÔÁÎÏ×ÉÔØ ÎÁÓÔÒÏÊËÉ" WARN(_("Can't set settings")); signals(0); @@ -336,7 +342,7 @@ size_t read_tty(uint8_t *buff, size_t length){ return (size_t)L; } -int write_tty(uint8_t *buff, size_t length){ +int write_tty(const uint8_t *buff, size_t length){ ssize_t L = write(comfd, buff, length); if((size_t)L != length){ /// "ïÛÉÂËÁ ÚÁÐÉÓÉ!" diff --git a/usefull_macros.h b/usefull_macros.h index c9c47e2..1e2f325 100644 --- a/usefull_macros.h +++ b/usefull_macros.h @@ -1,4 +1,4 @@ -/* +/* geany_encoding=koi8-r * usefull_macros.h - a set of usefull macros: memory, color etc * * Copyright 2013 Edward V. Emelianoff @@ -133,7 +133,7 @@ int mygetchar(); void restore_tty(); void tty_init(char *comdev, tcflag_t speed); size_t read_tty(uint8_t *buff, size_t length); -int write_tty(uint8_t *buff, size_t length); +int write_tty(const uint8_t *buff, size_t length); int str2double(double *num, const char *str);