diff --git a/CMakeLists.txt b/CMakeLists.txt index 128d481..c5e4ca1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.0) set(PROJ tty_term) -set(MINOR_VERSION "0") +set(MINOR_VERSION "1") set(MID_VERSION "1") set(MAJOR_VERSION "0") set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}") @@ -67,7 +67,7 @@ include_directories(${${PROJ}_INCLUDE_DIRS}) # -L link_directories(${${PROJ}_LIBRARY_DIRS}) # -D -add_definitions(${CFLAGS} -DLOCALEDIR=\"${LOCALEDIR}\" +add_definitions(${CFLAGS} -DLOCALEDIR=\"${LOCALEDIR}\" -DPROJECT=\"${PROJ}\" -DPACKAGE_VERSION=\"${VERSION}\" -DGETTEXT_PACKAGE=\"${PROJ}\" -DMINOR_VERSION=\"${MINOR_VERSION}\" -DMID_VERSION=\"${MID_VERSION}\" -DMAJOR_VERSION=\"${MAJOR_VESION}\") diff --git a/cmdlnopts.c b/cmdlnopts.c index 770dbbd..1664965 100644 --- a/cmdlnopts.c +++ b/cmdlnopts.c @@ -46,12 +46,13 @@ static myoption cmdlnopts[] = { // set 1 to param despite of its repeating number: {"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), _("show this help")}, {"speed", NEED_ARG, NULL, 's', arg_int, APTR(&G.speed), _("baudrate (default: 9600)")}, - {"name", NEED_ARG, NULL, 'n', arg_string, APTR(&G.ttyname), _("serial device path or server name/IP")}, + {"name", NEED_ARG, NULL, 'n', arg_string, APTR(&G.ttyname), _("serial device path or server name/IP or socket path")}, {"eol", NEED_ARG, NULL, 'e', arg_string, APTR(&G.eol), _("end of line: n (default), r, nr or rn")}, {"timeout", NEED_ARG, NULL, 't', arg_int, APTR(&G.tmoutms), _("timeout for select() in ms (default: 100)")}, {"port", NEED_ARG, NULL, 'p', arg_string, APTR(&G.port), _("socket port (none for UNIX)")}, {"socket", NO_ARGS, NULL, 'S', arg_int, APTR(&G.socket), _("open socket")}, {"dumpfile",NEED_ARG, NULL, 'd', arg_string, APTR(&G.dumpfile), _("dump data to this file")}, + {"format", NEED_ARG, NULL, 'f', arg_string, APTR(&G.port), _("tty format (default: 8N1)")}, end_option }; @@ -65,7 +66,7 @@ static myoption cmdlnopts[] = { glob_pars *parse_args(int argc, char **argv){ void *ptr = memcpy(&G, &Gdefault, sizeof(G)); assert(ptr); // format of help: "Usage: progname [args]\n" - change_helpstring(_("Usage: %s [args]\n\n\tWhere args are:\n")); + change_helpstring(_(PROJECT " version " PACKAGE_VERSION "\nUsage: %s [args]\n\n\tWhere args are:\n")); // parse arguments parseargs(&argc, &argv, cmdlnopts); if(help) showhelp(-1, cmdlnopts); diff --git a/dbg.h b/dbg.h index 5df7693..a9af66c 100644 --- a/dbg.h +++ b/dbg.h @@ -20,7 +20,10 @@ #ifndef DBG_H__ #define DBG_H__ +// dirty trick +#define termios xxtermios #include +#undef termios #ifdef EBUG #undef DBG @@ -32,10 +35,10 @@ #define FNAME() do{LOGDBG("%s (%s, line %d)", __func__, __FILE__, __LINE__);}while(0) #define DBG(...) do{LOGDBG("%s (%s, line %d):", __func__, __FILE__, __LINE__); \ LOGDBGADD(__VA_ARGS__);} while(0) -#define ERR(...) do{LOGERR(__VA_ARGS__); signals(9);}while(0) -#define ERRX(...) do{LOGERR(__VA_ARGS__); signals(9);}while(0) +#define ERR(...) do{red(__VA_ARGS__); printf("\n"); LOGERR(__VA_ARGS__); signals(9);}while(0) +#define ERRX(...) do{red(__VA_ARGS__); printf("\n"); LOGERR(__VA_ARGS__); signals(9);}while(0) //#define WARN(...) do{LOGWARN(__VA_ARGS__);}while(0) -#define WARNX(...) do{LOGWARN(__VA_ARGS__);}while(0) +#define WARNX(...) do{red(__VA_ARGS__); printf("\n"); LOGWARN(__VA_ARGS__);}while(0) #endif #endif // DBG_H__ diff --git a/main.c b/main.c index e0c2575..b9f8861 100644 --- a/main.c +++ b/main.c @@ -61,13 +61,12 @@ int main(int argc, char **argv){ signals(0); } conndev.name = strdup(G->ttyname); - conndev.speed = G->speed; + conndev.port = strdup(G->port); if(G->socket){ if(!G->port) conndev.type = DEV_UNIXSOCKET; - else{ - conndev.type = DEV_NETSOCKET; - conndev.port = strdup(G->port); - } + else conndev.type = DEV_NETSOCKET; + }else{ + conndev.speed = G->speed; } if(!opendev(&conndev, G->dumpfile)){ signals(0); diff --git a/ncurses_and_readline.c b/ncurses_and_readline.c index 293a09c..5f27eb5 100644 --- a/ncurses_and_readline.c +++ b/ncurses_and_readline.c @@ -155,8 +155,8 @@ static void show_mode(bool for_resize){ dtty->name+1, dtty->seol); break; case DEV_TTY: - snprintf(buf, 127, "INSERT (TAB to switch, ctrl+D to quit) DEV: %s, ENDLINE: %s, SPEED: %d", - dtty->name, dtty->seol, dtty->speed); + snprintf(buf, 127, "INSERT (TAB to switch, ctrl+D to quit) DEV: %s, ENDLINE: %s, SPEED: %d, FORMAT: %s", + dtty->name, dtty->seol, dtty->speed, dtty->port); break; default: break; diff --git a/ttysocket.c b/ttysocket.c index 8334552..9461ca5 100644 --- a/ttysocket.c +++ b/ttysocket.c @@ -17,11 +17,14 @@ */ #include +#include #include -#include // getchar +#include #include +#include #include #include +#include #include #include // unix socket @@ -78,7 +81,7 @@ static size_t rmeols(chardevice *d){ DBG("d is NULL"); return 0; } - TTY_descr *D = d->dev; + TTY_descr2 *D = d->dev; if(!D || D->comfd < 0){ DBG("D bad"); return 0; @@ -108,7 +111,7 @@ static size_t rmeols(chardevice *d){ // get data drom TTY static char *getttydata(chardevice *d, int *len){ if(!d || !d->dev) return NULL; - TTY_descr *D = d->dev; + TTY_descr2 *D = d->dev; if(D->comfd < 0) return NULL; int L = 0; int length = D->bufsz; @@ -136,12 +139,13 @@ static char *getttydata(chardevice *d, int *len){ if(len) *len = L; if(!L) return NULL; rmeols(d); + DBG("buffer len: %zd, content: =%s=", D->buflen, D->buf); return D->buf; } static char *getsockdata(chardevice *d, int *len){ if(!d || !d->dev) return NULL; - TTY_descr *D = d->dev; + TTY_descr2 *D = d->dev; if(D->comfd < 0) return NULL; char *ptr = NULL; int n = waittoread(D->comfd); @@ -233,9 +237,9 @@ int SendData(chardevice *d, char *str){ static const int socktypes[] = {SOCK_STREAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET, SOCK_DCCP, SOCK_PACKET, SOCK_DGRAM, 0}; -static TTY_descr* opensocket(chardevice *d){ +static TTY_descr2* opensocket(chardevice *d){ if(!d) return FALSE; - TTY_descr *descr = MALLOC(TTY_descr, 1); // only for `buf` and bufsz/buflen + TTY_descr2 *descr = MALLOC(TTY_descr2, 1); // only for `buf` and bufsz/buflen descr->buf = MALLOC(char, BUFSIZ); descr->bufsz = BUFSIZ; // now try to open a socket @@ -302,6 +306,109 @@ static TTY_descr* opensocket(chardevice *d){ return descr; } +static char *parse_format(const char *iformat, tcflag_t *flags){ + tcflag_t f = 0; + if(!iformat){ // default + *flags = CS8; + return strdup("8N1"); + } + if(strlen(iformat) != 3) goto someerr; + switch(iformat[0]){ + case '5': + f |= CS5; + break; + case '6': + f |= CS6; + break; + case '7': + f |= CS7; + break; + case '8': + f |= CS8; + break; + default: + goto someerr; + } + switch(iformat[1]){ + case '0': // always 0 + f |= PARENB | CMSPAR; + break; + case '1': // always 1 + f |= PARENB | CMSPAR | PARODD; + break; + case 'E': // even + f |= PARENB; + break; + case 'N': // none + f |= PARENB | PARODD; + break; + case 'O': // odd + break; + default: + goto someerr; + } + switch(iformat[2]){ + case '1': + break; + case '2': + f |= CSTOPB; + break; + default: + goto someerr; + } + *flags = f; + return strdup(iformat); +someerr: + WARNX(_("Wrong USART format \"%s\"; use NPS, where N: 5..8; P: N/E/O/1/0, S: 1/2"), iformat); + return NULL; +} + +static TTY_descr2* opentty(chardevice *d){ + if(!d->name){ + /// Отсутствует имя порта + WARNX(_("Port name is missing")); + return NULL; + } + TTY_descr2 *descr = MALLOC(TTY_descr2, 1); + descr->portname = strdup(d->name); + descr->speed = d->speed; + tcflag_t flags; + descr->format = parse_format(d->port, &flags); + if(!descr->format) goto someerr; + descr->buf = MALLOC(char, BUFSIZ); + descr->bufsz = BUFSIZ-1; + if((descr->comfd = open(descr->portname, O_RDWR|O_NOCTTY)) < 0){ + WARN(_("Can't use port %s"), descr->portname); + goto someerr; + } + if(ioctl(descr->comfd, TCGETS2, &descr->oldtty)){ + WARN(_("Can't get port config")); + goto someerr; + } + descr->tty = descr->oldtty; + descr->tty.c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG) + descr->tty.c_iflag = 0; + descr->tty.c_cflag = BOTHER | flags |CREAD|CLOCAL; + descr->tty.c_ispeed = d->speed; + descr->tty.c_ospeed = d->speed; + if(ioctl(descr->comfd, TCSETS2, &descr->tty)){ + WARN(_("Can't set new port config")); + goto someerr; + } + ioctl(descr->comfd, TCGETS2, &descr->tty); + d->speed = descr->tty.c_ispeed; +#ifdef EBUG + printf("ispeed: %d, ospeed: %d, cflag=%d (BOTHER=%d)\n", descr->tty.c_ispeed, descr->tty.c_ospeed, descr->tty.c_cflag&CBAUD, BOTHER); + if(system("stty -F /dev/ttyUSB0")) WARN("system()"); +#endif + return descr; +someerr: + FREE(descr->format); + FREE(descr->buf); + FREE(descr); + return NULL; +} + /** * @brief opendev - open TTY or socket output device * @param d - device type @@ -313,8 +420,8 @@ int opendev(chardevice *d, char *path){ switch(d->type){ case DEV_TTY: DBG("Serial"); - d->dev = new_tty(d->name, d->speed, BUFSIZ); - if(!d->dev || !(d->dev = tty_open(d->dev, 1))){ + d->dev = opentty(d); + if(!d->dev){ WARN("Can't open device %s", d->name); DBG("CANT OPEN"); return FALSE; @@ -354,7 +461,9 @@ void closedev(chardevice *d){ switch(d->type){ case DEV_TTY: if(d->dev){ - close_tty(&d->dev); + TTY_descr2 *t = d->dev; + ioctl(t->comfd, TCSETS2, &t->oldtty); // return TTY to previous state + close(t->comfd); } break; case DEV_NETSOCKET: @@ -366,5 +475,12 @@ void closedev(chardevice *d){ default: return; } + if(d->dev){ + FREE(d->dev->format); + FREE(d->dev->portname); + FREE(d->dev->buf); + FREE(d->dev); + } FREE(d->name); + DBG("Device closed"); } diff --git a/ttysocket.h b/ttysocket.h index 317759f..3841649 100644 --- a/ttysocket.h +++ b/ttysocket.h @@ -21,7 +21,9 @@ #define TTY_H__ #include -#include "dbg.h" +#include +#include +//#include "dbg.h" typedef enum{ DEV_TTY, @@ -29,10 +31,22 @@ typedef enum{ DEV_UNIXSOCKET, } devtype; +typedef struct { + char *portname; // device filename (should be freed before structure freeing) + int speed; // baudrate in human-readable format + char *format; // format like 8N1 + struct termios2 oldtty; // TTY flags for previous port settings + struct termios2 tty; // TTY flags for current settings + int comfd; // TTY file descriptor + char *buf; // buffer for data read + size_t bufsz; // size of buf + size_t buflen; // length of data read into buf +} TTY_descr2; + typedef struct{ devtype type; // type char *name; // filename (dev or UNIX socket) or server name/IP - TTY_descr *dev; // tty serial device + TTY_descr2 *dev; // tty serial device char *port; // port to connect int speed; // tty speed pthread_mutex_t mutex; // reading/writing mutex