From 53ec829cb770bd5a71952a90b99114b5fbf9e530 Mon Sep 17 00:00:00 2001 From: eddyem Date: Tue, 12 Mar 2019 10:06:31 +0300 Subject: [PATCH] fixed bug with termio/termios --- Snippets.config | 3 + Snippets.creator | 1 + Snippets.creator.user | 170 ++++++++++++++++++++++++ Snippets.files | 14 ++ Snippets.includes | 2 + examples/cmdlnopts.c | 9 +- examples/cmdlnopts.h | 8 +- examples/fifo.c | 4 + examples/options.c | 38 ++++-- locale/ru/LC_MESSAGES/usefull_macros.mo | Bin 1730 -> 1730 bytes locale/ru/ru.po | 78 +++++------ term.c | 86 ++++++++---- usefull_macros.h | 12 +- 13 files changed, 331 insertions(+), 94 deletions(-) create mode 100644 Snippets.config create mode 100644 Snippets.creator create mode 100644 Snippets.creator.user create mode 100644 Snippets.files create mode 100644 Snippets.includes diff --git a/Snippets.config b/Snippets.config new file mode 100644 index 0000000..e3e2368 --- /dev/null +++ b/Snippets.config @@ -0,0 +1,3 @@ +// Add predefined macros for your project here. For example: +// #define THE_ANSWER 42 +#define EBUG 1 diff --git a/Snippets.creator b/Snippets.creator new file mode 100644 index 0000000..e94cbbd --- /dev/null +++ b/Snippets.creator @@ -0,0 +1 @@ +[General] diff --git a/Snippets.creator.user b/Snippets.creator.user new file mode 100644 index 0000000..d9b768e --- /dev/null +++ b/Snippets.creator.user @@ -0,0 +1,170 @@ + + + + + + EnvironmentId + {cf63021e-ef53-49b0-b03b-2f2570cdf3b6} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + KOI8-R + false + 4 + false + 80 + true + true + 1 + true + false + 1 + true + true + 0 + 8 + true + 2 + true + false + true + false + + + + ProjectExplorer.Project.PluginSettings + + + true + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {91347f2c-5221-46a7-80b1-0a054ca02f79} + 0 + 0 + 0 + + /home/eddy/Docs/SAO/C_diff/snippets_library + + + + all + + false + + + false + true + Сборка + + GenericProjectManager.GenericMakeStep + + 1 + Сборка + + ProjectExplorer.BuildSteps.Build + + + + + clean + + false + + + false + true + Сборка + + GenericProjectManager.GenericMakeStep + + 1 + Очистка + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + По умолчанию + По умолчанию + GenericProjectManager.GenericBuildConfiguration + + 1 + + + 0 + Установка + + ProjectExplorer.BuildSteps.Deploy + + 1 + Конфигурация установки + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + false + false + 1000 + + true + 2 + + + Особая программа + + ProjectExplorer.CustomExecutableRunConfiguration + + 3768 + false + true + false + false + true + + + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 20 + + + Version + 20 + + diff --git a/Snippets.files b/Snippets.files new file mode 100644 index 0000000..1595196 --- /dev/null +++ b/Snippets.files @@ -0,0 +1,14 @@ +CMakeLists.txt +daemon.c +examples/CMakeLists.txt +examples/cmdlnopts.c +examples/cmdlnopts.h +examples/fifo.c +examples/helloworld.c +examples/options.c +fifo_lifo.c +parseargs.c +term.c +term.h +usefull_macros.c +usefull_macros.h diff --git a/Snippets.includes b/Snippets.includes new file mode 100644 index 0000000..63f6562 --- /dev/null +++ b/Snippets.includes @@ -0,0 +1,2 @@ +. +examples diff --git a/examples/cmdlnopts.c b/examples/cmdlnopts.c index 7321625..e4db8cc 100644 --- a/examples/cmdlnopts.c +++ b/examples/cmdlnopts.c @@ -29,15 +29,15 @@ /* * here are global parameters initialisation */ -int help; -glob_pars G; +static int help; +static glob_pars G; // default PID filename: #define DEFAULT_PIDFILE "/tmp/testcmdlnopts.pid" // DEFAULTS // default global parameters -glob_pars const Gdefault = { +static glob_pars const Gdefault = { .device = NULL, .pidfile = DEFAULT_PIDFILE, .speed = 9600, @@ -48,13 +48,14 @@ glob_pars const Gdefault = { * Define command line options by filling structure: * name has_arg flag val type argptr help */ -myoption cmdlnopts[] = { +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")}, {"speed", NEED_ARG, NULL, 's', arg_int, APTR(&G.speed), _("serial device speed (default: 9600)")}, {"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 ")")}, + {"exclusive",NO_ARGS, NULL, 'e', arg_int, APTR(&G.exclusive), _("open serial device exclusively")}, end_option }; diff --git a/examples/cmdlnopts.h b/examples/cmdlnopts.h index 4e4fbff..e35e77f 100644 --- a/examples/cmdlnopts.h +++ b/examples/cmdlnopts.h @@ -20,8 +20,8 @@ */ #pragma once -#ifndef __CMDLNOPTS_H__ -#define __CMDLNOPTS_H__ +#ifndef CMDLNOPTS_H__ +#define CMDLNOPTS_H__ /* * here are some typedef's for global data @@ -32,9 +32,11 @@ typedef struct{ char *logfile; // logging to this file int speed; // connection speed int rest_pars_num; // number of rest parameters + int exclusive; // exclusive open port char** rest_pars; // the rest parameters: array of char* } glob_pars; glob_pars *parse_args(int argc, char **argv); -#endif // __CMDLNOPTS_H__ + +#endif // CMDLNOPTS_H__ diff --git a/examples/fifo.c b/examples/fifo.c index 037f800..62cff5e 100644 --- a/examples/fifo.c +++ b/examples/fifo.c @@ -18,6 +18,10 @@ #include #include +/* + * Example of FIFO/LIFO usage + */ + int main(int argc, char *argv[argc]) { List *f = NULL; printf("Available memory: %luMB\n", get_available_mem()/1024/1024); diff --git a/examples/options.c b/examples/options.c index 5772f15..35cf8c5 100644 --- a/examples/options.c +++ b/examples/options.c @@ -16,13 +16,27 @@ * along with this program. If not, see . */ +#include "cmdlnopts.h" #include // signal -#include // exit, free #include // printf +#include // exit, free #include // strdup #include // sleep #include -#include "cmdlnopts.h" + + +#include // tcsetattr +#include // tcsetattr, close, read, write +#include // ioctl +#include // printf, getchar, fopen, perror +#include // exit +#include // read +#include // read +#include // signal +#include // time +#include // memcpy +#include // int types +#include // gettimeofday /** * This is an example of usage: @@ -34,8 +48,8 @@ * The `cmdlnopts.[hc]` are intrinsic files of this demo. */ -TTY_descr *dev = NULL; // shoul be global to restore if die -glob_pars *GP = NULL; // for GP->pidfile need in `signals` +static TTY_descr *dev = NULL; // shoul be global to restore if die +static glob_pars *GP = NULL; // for GP->pidfile need in `signals` /** * We REDEFINE the default WEAK function of signal processing @@ -82,23 +96,31 @@ int main(int argc, char *argv[]){ } if(GP->device){ putlog("Try to open serial %s", GP->device); - dev = tty_open(GP->device, GP->speed, 256); + dev = new_tty(GP->device, GP->speed, 256); + if(dev) dev = tty_open(dev, GP->exclusive); if(!dev){ putlog("Can't open %s with speed %d. Exit.", GP->device, GP->speed); signals(0); } } + // main stuff goes here long seed = throw_random_seed(); green("Now I will sleep for 10 seconds. Do whatever you want. Random seed: %ld\n", seed); double t0 = dtime(); + char b[2] = {0}; while(dtime() - t0 < 10.){ // read data from port and print in into terminal if(dev){ if(read_tty(dev)){ - printf("Data from port: %s\n", dev->buf); + printf("Got %zd bytes from port: %s\n", dev->buflen, dev->buf); + t0 = dtime(); } - char ch = read_console(); - if(ch) write_tty(dev->comfd, &ch, 1); + int r = read_console(); + if(r < 1) continue; + t0 = dtime(); + b[0] = (char) r; + printf("send to tty: %d (%c)\n", r, b[0]); + write_tty(dev->comfd, b, 1); } } // clean everything diff --git a/locale/ru/LC_MESSAGES/usefull_macros.mo b/locale/ru/LC_MESSAGES/usefull_macros.mo index fc3cb046a20739a559e765cce9ca98187e6317a1..2ad2e5d3c619f7010a339f3f91017b44a4a9dec7 100644 GIT binary patch delta 26 icmX@adx&?#US?iPT?1oXLn8$PODj|3&8L`uFaZE=;RqT4 delta 26 icmX@adx&?#US?hkT|*;X14{)1Ln{-@&8L`uFaZE=>\n" "Language-Team: LANGUAGE \n" @@ -17,7 +17,7 @@ msgstr "Project-Id-Version: PACKAGE VERSION\n" "Content-Transfer-Encoding: 8bit\n" #. / \n (pid=%d), .\n -#: /Big/Data/C_sources/snippets_library/daemon.c:70 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:70 #, c-format msgid "\n" "Found running process (pid=%d), exit.\n" @@ -25,132 +25,118 @@ msgstr "\n" " (pid=%d), .\n" #. / %s: ! -#: /Big/Data/C_sources/snippets_library/parseargs.c:483 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:483 #, c-format msgid "%s: argument needed!" msgstr "%s: !" -#. / -#: /Big/Data/C_sources/snippets_library/term.c:123 -#, fuzzy -msgid "Can't apply new TTY settings" -msgstr " " - #. / mmap' -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:254 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:262 msgid "Can't close mmap'ed file" msgstr " mmap' " #. / -#: /Big/Data/C_sources/snippets_library/term.c:129 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/term.c:129 msgid "Can't do exclusive open" msgstr " " -#. Get settings -#. / -#: /Big/Data/C_sources/snippets_library/term.c:111 -#, fuzzy -msgid "Can't get old TTY settings" -msgstr " " - #. / munmap -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:268 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:276 msgid "Can't munmap" msgstr " munmap" #. / %s -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:237 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:245 #, c-format msgid "Can't open %s for reading" msgstr " %s " #. / /dev/random -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:184 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:184 msgid "Can't open /dev/random" -msgstr "" +msgstr " /dev/random" #. / PID -#: /Big/Data/C_sources/snippets_library/daemon.c:143 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:143 msgid "Can't open PID file" msgstr " PID " #. / -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:382 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:390 msgid "Can't open log file" msgstr " " #. / /dev/random -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:189 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:189 msgid "Can't read /dev/random" -msgstr "" +msgstr " /dev/random" #. / -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:299 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:307 msgid "Can't setup console" msgstr " " #. / stat %s -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:242 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:250 #, c-format msgid "Can't stat %s" msgstr " stat %s" -#. / %s -#: /Big/Data/C_sources/snippets_library/term.c:105 -#, fuzzy, c-format -msgid "Can't use port %s" -msgstr " %s" - #. / -#: /Big/Data/C_sources/snippets_library/parseargs.c:84 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:84 msgid "Integer out of range" msgstr " " #. / mmap -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:249 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:257 msgid "Mmap error for input" msgstr " mmap" #. / -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:374 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:382 msgid "Need filename for log file" msgstr " " +#: /home/eddy/Docs/SAO/C_diff/snippets_library/term.c:176 +msgid "Need non-zero buffer for TTY device" + +msgstr " " + #. / ! -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:232 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:240 msgid "No filename given!" msgstr " !" #. / -#: /Big/Data/C_sources/snippets_library/term.c:168 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/term.c:169 msgid "Port name is missing" -msgstr "" +msgstr " " #. / %s \n -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:378 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:386 #, c-format msgid "Try to open log file %s in append mode\n" msgstr " %s \n" #. / \"%s\" \"%s\" -#: /Big/Data/C_sources/snippets_library/parseargs.c:488 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:488 #, c-format msgid "Wrong argument \"%s\" of parameter \"%s\"" msgstr " \"%s\" \"%s\"" #. amount of pcount and/or scount wrong #. / -#: /Big/Data/C_sources/snippets_library/parseargs.c:54 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:54 msgid "Wrong helpstring!" msgstr " " #. / : %s -#: /Big/Data/C_sources/snippets_library/parseargs.c:478 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:478 #, c-format msgid "Wrong parameter: %s" msgstr " : %s" -#: /Big/Data/C_sources/snippets_library/term.c:92 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/term.c:92 #, c-format msgid "Wrong speed value: %d!" -msgstr "" +msgstr " : %d!" diff --git a/term.c b/term.c index b8f0b8a..4a045ba 100644 --- a/term.c +++ b/term.c @@ -35,8 +35,8 @@ #define LOGBUFSZ (1024) typedef struct { - int speed; // communication speed in bauds/s - int bspeed; // baudrate from termios.h + int speed; // communication speed in bauds/s + tcflag_t bspeed; // baudrate from termios.h } spdtbl; static int tty_init(TTY_descr *descr); @@ -80,7 +80,7 @@ static spdtbl speeds[] = { * @param speed - integer speed (bps) * @return 0 if error, Bxxx if all OK */ -int conv_spd(int speed){ +tcflag_t conv_spd(int speed){ spdtbl *spd = speeds; int curspeed = 0; do{ @@ -99,35 +99,35 @@ int conv_spd(int speed){ * @return 0 if all OK or error code */ static int tty_init(TTY_descr *descr){ - DBG("\nOpen port..."); - if ((descr->comfd = open(descr->portname, O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0){ + DBG("\nOpen port..."); // |O_NONBLOCK + if ((descr->comfd = open(descr->portname, O_RDWR|O_NOCTTY)) < 0){ /// %s WARN(_("Can't use port %s"), descr->portname); return globErr ? globErr : 1; } DBG("OK\nGet current settings..."); - if(ioctl(descr->comfd, TCGETA, &descr->oldtty) < 0){ // Get settings + if(tcgetattr(descr->comfd, &descr->oldtty) < 0){ // Get settings /// WARN(_("Can't get old TTY settings")); return globErr ? globErr : 1; } descr->tty = descr->oldtty; - struct termios *tty = &descr->tty; - tty->c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG) - tty->c_oflag = 0; - tty->c_cflag = descr->baudrate|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(descr->comfd, TCSETA, &descr->tty) < 0){ + descr->tty.c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG) + descr->tty.c_oflag = 0; + descr->tty.c_cflag = descr->baudrate|CS8|CREAD|CLOCAL; // 9.6k, 8N1, RW, ignore line ctrl + descr->tty.c_cc[VMIN] = 0; // non-canonical mode + descr->tty.c_cc[VTIME] = 5; + if(tcsetattr(descr->comfd, TCSANOW, &descr->tty) < 0){ /// WARN(_("Can't apply new TTY settings")); return globErr ? globErr : 1; } // make exclusive open + if(descr->exclusive){ if(ioctl(descr->comfd, TIOCEXCL)){ /// WARN(_("Can't do exclusive open")); - } + }} DBG("OK"); return 0; } @@ -138,47 +138,62 @@ static int tty_init(TTY_descr *descr){ void close_tty(TTY_descr **descr){ if(descr == NULL || *descr == NULL) return; TTY_descr *d = *descr; - FREE(d->portname); - FREE(d->buf); if(d->comfd){ DBG("close file.."); ioctl(d->comfd, TCSANOW, &d->oldtty); // return TTY to previous state close(d->comfd); } + FREE(d->portname); + FREE(d->buf); FREE(*descr); DBG("done!\n"); } /** - * @brief tty_open - init & open tty device - * @param port - TTY device filename + * @brief new_tty - create new TTY structure with partially filled fields + * @param comdev - TTY device filename * @param speed - speed (number) * @param bufsz - size of buffer for input data (or 0 if opened only to write) * @return pointer to TTY structure if all OK */ -TTY_descr *tty_open(char *port, int speed, size_t bufsz){ - int spd = conv_spd(speed); +TTY_descr *new_tty(char *comdev, int speed, size_t bufsz){ + tcflag_t spd = conv_spd(speed); if(!spd) return NULL; - DBG("open %s with speed %d)", port, speed); + DBG("create %s with speed %d and buffer size %zd", comdev, speed, bufsz); TTY_descr *descr = MALLOC(TTY_descr, 1); - descr->portname = strdup(port); + descr->portname = strdup(comdev); descr->baudrate = spd; + descr->speed = speed; if(!descr->portname){ /// WARNX(_("Port name is missing")); - }else if(!tty_init(descr)){ + }else{ if(bufsz){ descr->buf = MALLOC(char, bufsz+1); descr->bufsz = bufsz; DBG("allocate buffer with size %zd", bufsz); - } - return descr; + return descr; + }else WARNX(_("Need non-zero buffer for TTY device")); } FREE(descr->portname); FREE(descr); return NULL; } +/** + * @brief tty_open - init & open tty device + * @param d - already filled structure (with new_tty or by hands) + * @param exclusive - == 1 to make exclusive open + * @return pointer to TTY structure if all OK + */ +TTY_descr *tty_open(TTY_descr *d, int exclusive){ + DBG("open %s with speed %d%s", d->portname, d->speed, exclusive ? "" : " (exclusive)"); + if(!d || !d->portname || !d->baudrate) return NULL; + if(exclusive) d->exclusive = TRUE; + else d->exclusive = FALSE; + if(tty_init(d)) return NULL; + return d; +} /** * @brief read_tty - read data from TTY with 10ms timeout @@ -188,7 +203,8 @@ TTY_descr *tty_open(char *port, int speed, size_t bufsz){ */ size_t read_tty(TTY_descr *d){ if(d->comfd < 0) return 0; - ssize_t L = 0, l; + size_t L = 0; + ssize_t l; size_t length = d->bufsz; char *ptr = d->buf; fd_set rfds; @@ -199,19 +215,30 @@ size_t read_tty(TTY_descr *d){ FD_ZERO(&rfds); FD_SET(d->comfd, &rfds); // wait for 10ms - tv.tv_sec = 0; tv.tv_usec = 10000; + tv.tv_sec = 0; tv.tv_usec = 50000; retval = select(d->comfd + 1, &rfds, NULL, NULL, &tv); if (!retval) break; if(FD_ISSET(d->comfd, &rfds)){ if((l = read(d->comfd, ptr, length)) < 1){ - return 0; + break; } +#ifdef EBUG + char *s = ptr; +#endif ptr += l; L += l; +#ifdef EBUG + *ptr = 0; +#endif + //DBG("got %zd bytes: %s\nBUF[%zd](%d): %s", l, s, L, d->bufsz, d->buf); + DBG("FD %d got %zd bytes: %s\nsym: %d, BUF[%zd](%zd): %s", d->comfd, l, s, (int)s[0], L, d->bufsz, d->buf); length -= l; } - }while(l); + }while(l && length); d->buflen = L; d->buf[L] = 0; +#ifdef EBUG + if(L) DBG("Got %zd bytes total: %s", d->buflen, d->buf); +#endif return (size_t)L; } @@ -222,6 +249,7 @@ size_t read_tty(TTY_descr *d){ * @return 0 if all OK */ int write_tty(int comfd, const char *buff, size_t length){ + DBG("comfd: %d, buff: \"%s\", len: %zd", comfd, buff, length); ssize_t L = write(comfd, buff, length); if((size_t)L != length){ /// " !" diff --git a/usefull_macros.h b/usefull_macros.h index daa4a79..c4e3c4d 100644 --- a/usefull_macros.h +++ b/usefull_macros.h @@ -146,19 +146,23 @@ uint64_t get_available_mem(); \******************************************************************************/ typedef struct { char *portname; // device filename (should be freed before structure freeing) - int baudrate; // baudrate (B...) + int speed; // baudrate in human-readable format + tcflag_t baudrate; // baudrate (B...) struct termios oldtty; // TTY flags for previous port settings struct termios tty; // TTY flags for current settings int comfd; // TTY file descriptor char *buf; // buffer for data read - int bufsz; // size of buf - int buflen; // length of data read into buf + size_t bufsz; // size of buf + size_t buflen; // length of data read into buf + bool exclusive; // should device be exclusive opened } TTY_descr; void close_tty(TTY_descr **descr); -TTY_descr *tty_open(char *comdev, int speed, size_t bufsz); +TTY_descr *new_tty(char *comdev, int speed, size_t bufsz); +TTY_descr *tty_open(TTY_descr *d, int exclusive); size_t read_tty(TTY_descr *descr); int write_tty(int comfd, const char *buff, size_t length); +tcflag_t conv_spd(int speed); // convert string to double with checking int str2double(double *num, const char *str);