diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 5c79772..32d95dd 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,3 +8,4 @@ link_libraries(usefull_macros) # exe list add_executable(helloworld helloworld.c) add_executable(options options.c cmdlnopts.c) +add_executable(fifo fifo.c) diff --git a/examples/cmdlnopts.c b/examples/cmdlnopts.c index 73851d2..7321625 100644 --- a/examples/cmdlnopts.c +++ b/examples/cmdlnopts.c @@ -32,15 +32,15 @@ int help; glob_pars G; -#define DEFAULT_COMDEV "/dev/ttyUSB0" // default PID filename: #define DEFAULT_PIDFILE "/tmp/testcmdlnopts.pid" // DEFAULTS // default global parameters glob_pars const Gdefault = { - .device = DEFAULT_COMDEV, + .device = NULL, .pidfile = DEFAULT_PIDFILE, + .speed = 9600, .logfile = NULL // don't save logs }; @@ -51,7 +51,8 @@ glob_pars const Gdefault = { 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_COMDEV ")")}, + {"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 ")")}, end_option diff --git a/examples/cmdlnopts.h b/examples/cmdlnopts.h index c337f3d..4e4fbff 100644 --- a/examples/cmdlnopts.h +++ b/examples/cmdlnopts.h @@ -30,6 +30,7 @@ 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; diff --git a/examples/fifo.c b/examples/fifo.c new file mode 100644 index 0000000..037f800 --- /dev/null +++ b/examples/fifo.c @@ -0,0 +1,57 @@ +/* + * This file is part of the usefull_macros project. + * Copyright 2018 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 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 . + */ +#include +#include + +int main(int argc, char *argv[argc]) { + List *f = NULL; + printf("Available memory: %luMB\n", get_available_mem()/1024/1024); + //initial_setup(); - there's no need for this function if you don't use locale & don't want to have + // specific output in non-tty + if(argc == 1){ + green("Usage:\n\t%s args - fill fifo with arguments\n", __progname); + return 1; + } + red("\n\nLIFO example\n"); + for(int i = 1; i < argc; ++i){ + if(!list_push(&f, argv[i])) ERR("Allocation error!"); + green("push to list "); + printf("%s\n", argv[i]); + } + char *d; + printf("\n"); + while(f){ + d = list_pop(&f); + green("pull: "); + printf("%s\n", d); + } + red("\n\nFIFO example\n"); + for(int i = 1; i < argc; ++i){ + if(!list_push_tail(&f, argv[i])) ERR("Allocation error!"); + green("push to list "); + printf("%s\n", argv[i]); + } + printf("\n"); + while(f){ + d = list_pop(&f); + green("pull: "); + printf("%s\n", d); + // after last usage we should FREE data, but here it is parameter of main() + } + return 0; +} diff --git a/examples/options.c b/examples/options.c index b3cddc3..5772f15 100644 --- a/examples/options.c +++ b/examples/options.c @@ -16,12 +16,12 @@ * along with this program. If not, see . */ -#include #include // signal #include // exit, free #include // printf #include // strdup #include // sleep +#include #include "cmdlnopts.h" /** @@ -34,15 +34,22 @@ * 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` + /** * We REDEFINE the default WEAK function of signal processing */ void signals(int sig){ - signal(sig, SIG_IGN); - restore_console(); - restore_tty(); - DBG("Get signal %d, quit.\n", sig); + if(sig){ + signal(sig, SIG_IGN); + DBG("Get signal %d, quit.\n", sig); + } putlog("Exit with status %d", sig); + if(GP->pidfile) // remove unnesessary PID file + unlink(GP->pidfile); + restore_console(); + close_tty(&dev); exit(sig); } @@ -53,7 +60,7 @@ void iffound_default(pid_t pid){ int main(int argc, char *argv[]){ initial_setup(); char *self = strdup(argv[0]); - glob_pars *GP = parse_args(argc, argv); + 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) @@ -69,13 +76,32 @@ int main(int argc, char *argv[]){ if(GP->logfile) openlogfile(GP->logfile); setup_con(); putlog(("Start application...")); - ; // main stuff goes here - green("Now I will sleep for 10 seconds. Do whatever you want.\n"); - sleep(10); - ; // clean everything - if(GP->pidfile) // remove unnesessary PID file - unlink(GP->pidfile); - restore_console(); - restore_tty(); + if(GP->rest_pars_num){ + for(int i = 0; i < GP->rest_pars_num; ++i) + printf("Extra argument: %s\n", GP->rest_pars[i]); + } + if(GP->device){ + putlog("Try to open serial %s", GP->device); + dev = tty_open(GP->device, GP->speed, 256); + 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(); + 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); + } + char ch = read_console(); + if(ch) write_tty(dev->comfd, &ch, 1); + } + } + // clean everything + signals(0); return 0; } diff --git a/fifo_lifo.c b/fifo_lifo.c new file mode 100644 index 0000000..bfa3e58 --- /dev/null +++ b/fifo_lifo.c @@ -0,0 +1,81 @@ +/* + * fifo_lifo.c - simple FIFO/LIFO + * + * 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" + +/** + * @brief list_push_tail - push data into the tail of a stack (like FIFO) + * @param lst (io) - list + * @param v (i) - data to push + * @return pointer to just pused node or NULL in case of error + */ +List *list_push_tail(List **lst, void *v){ + List *node; + if(!lst) return NULL; + if((node = MALLOC(List, 1)) == NULL) + return NULL; // allocation error + node->data = v; // insert data + if(!*lst){ + *lst = node; + }else{ + (*lst)->last->next = node; + } + (*lst)->last = node; + return node; +} + +/** + * @brief list_push - push data into the head of a stack (like LIFO) + * @param lst (io) - list + * @param v (i) - data to push + * @return pointer to just pused node + */ +List *list_push(List **lst, void *v){ + List *node; + if(!lst) return NULL; + if((node = MALLOC(List, 1)) == NULL) + return NULL; // allocation error + node->data = v; // insert data + if(!*lst){ + *lst = node; + (*lst)->last = node; + return node; + } + node->next = *lst; + node->last = (*lst)->last; + *lst = node; + return node; +} + +/** + * @brief list_pop - get data from head of list. Don't forget to FREE list data after `pop` + * @param lst (io) - list + * @return data from lst head + */ +void *list_pop(List **lst){ + void *ret; + List *node = *lst; + if(!lst || !*lst) return NULL; + ret = (*lst)->data; + *lst = (*lst)->next; + FREE(node); + return ret; +} diff --git a/locale/ru/LC_MESSAGES/usefull_macros.mo b/locale/ru/LC_MESSAGES/usefull_macros.mo index c2ccd6f..fc3cb04 100644 Binary files a/locale/ru/LC_MESSAGES/usefull_macros.mo and b/locale/ru/LC_MESSAGES/usefull_macros.mo differ diff --git a/locale/ru/messages.po b/locale/ru/messages.po new file mode 100644 index 0000000..7e0efd7 --- /dev/null +++ b/locale/ru/messages.po @@ -0,0 +1,155 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-12-09 01:49+0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=koi8-r\n" +"Content-Transfer-Encoding: 8bit\n" + +#. / \nОбнаружен одноименный процесс (pid=%d), выход.\n +#: /Big/Data/C_sources/snippets_library/daemon.c:70 +#, c-format +msgid "" +"\n" +"Found running process (pid=%d), exit.\n" +msgstr "" + +#. / Не могу открыть PID файл +#: /Big/Data/C_sources/snippets_library/daemon.c:143 +msgid "Can't open PID file" +msgstr "" + +#. amount of pcount and/or scount wrong +#. / Неправильный формат строки помощи +#: /Big/Data/C_sources/snippets_library/parseargs.c:54 +msgid "Wrong helpstring!" +msgstr "" + +#. / Целое вне допустимого диапазона +#: /Big/Data/C_sources/snippets_library/parseargs.c:84 +msgid "Integer out of range" +msgstr "" + +#. / Неправильный параметр: %s +#: /Big/Data/C_sources/snippets_library/parseargs.c:478 +#, c-format +msgid "Wrong parameter: %s" +msgstr "" + +#. / %s: необходим аргумент! +#: /Big/Data/C_sources/snippets_library/parseargs.c:483 +#, c-format +msgid "%s: argument needed!" +msgstr "" + +#. / Неправильный аргумент \"%s\" параметра \"%s\" +#: /Big/Data/C_sources/snippets_library/parseargs.c:488 +#, c-format +msgid "Wrong argument \"%s\" of parameter \"%s\"" +msgstr "" + +#: /Big/Data/C_sources/snippets_library/term.c:92 +#, c-format +msgid "Wrong speed value: %d!" +msgstr "" + +#. / Не могу использовать порт %s +#: /Big/Data/C_sources/snippets_library/term.c:105 +#, c-format +msgid "Can't use port %s" +msgstr "" + +#. Get settings +#. / Не могу получить действующие настройки порта +#: /Big/Data/C_sources/snippets_library/term.c:111 +msgid "Can't get old TTY settings" +msgstr "" + +#. / Не могу сменить настройки порта +#: /Big/Data/C_sources/snippets_library/term.c:123 +msgid "Can't apply new TTY settings" +msgstr "" + +#. / Не могу сделать порт эксклюзивным +#: /Big/Data/C_sources/snippets_library/term.c:129 +msgid "Can't do exclusive open" +msgstr "" + +#. / Отсутствует имя порта +#: /Big/Data/C_sources/snippets_library/term.c:168 +msgid "Port name is missing" +msgstr "" + +#. / Не могу открыть /dev/random +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:184 +msgid "Can't open /dev/random" +msgstr "" + +#. / Не могу прочесть /dev/random +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:189 +msgid "Can't read /dev/random" +msgstr "" + +#. / Не задано имя файла! +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:232 +msgid "No filename given!" +msgstr "" + +#. / Не могу открыть %s для чтения +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:237 +#, c-format +msgid "Can't open %s for reading" +msgstr "" + +#. / Не могу выполнить stat %s +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:242 +#, c-format +msgid "Can't stat %s" +msgstr "" + +#. / Ошибка mmap +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:249 +msgid "Mmap error for input" +msgstr "" + +#. / Не могу закрыть mmap'нутый файл +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:254 +msgid "Can't close mmap'ed file" +msgstr "" + +#. / Не могу munmap +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:268 +msgid "Can't munmap" +msgstr "" + +#. / Не могу настроить консоль +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:299 +msgid "Can't setup console" +msgstr "" + +#. / Не задано имя логфайла +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:374 +msgid "Need filename for log file" +msgstr "" + +#. / Пробую открыть логфайл %s в режиме дополнения\n +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:378 +#, c-format +msgid "Try to open log file %s in append mode\n" +msgstr "" + +#. / Не могу открыть логфайл +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:382 +msgid "Can't open log file" +msgstr "" diff --git a/locale/ru/ru.po b/locale/ru/ru.po index 0766f5e..ca2d500 100644 --- a/locale/ru/ru.po +++ b/locale/ru/ru.po @@ -7,7 +7,7 @@ msgid "" msgstr "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" - "POT-Creation-Date: 2018-12-07 02:52+0300\n" + "POT-Creation-Date: 2018-12-09 01:49+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -30,87 +30,104 @@ msgstr "\n" 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:218 +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:254 msgid "Can't close mmap'ed file" msgstr "Не могу закрыть mmap'нутый файл" -#. / Не могу перевести порт в эксклюзивный режим -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:352 +#. / Не могу сделать порт эксклюзивным +#: /Big/Data/C_sources/snippets_library/term.c:129 msgid "Can't do exclusive open" msgstr "Не могу перевести порт в эксклюзивный режим" #. Get settings -#. / Не могу получить настройки порта -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:345 -msgid "Can't get port 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:232 +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:268 msgid "Can't munmap" msgstr "Не могу munmap" #. / Не могу открыть %s для чтения -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:201 +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:237 #, c-format msgid "Can't open %s for reading" msgstr "Не могу открыть %s для чтения" +#. / Не могу открыть /dev/random +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:184 +msgid "Can't open /dev/random" +msgstr "" + #. / Не могу открыть PID файл #: /Big/Data/C_sources/snippets_library/daemon.c:143 msgid "Can't open PID file" msgstr "Не могу открыть PID файл" #. / Не могу открыть логфайл -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:462 +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:382 msgid "Can't open log file" msgstr "Не могу открыть логфайл" -#. / Не могу открыть порт %s -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:340 -#, c-format -msgid "Can't open port %s" -msgstr "Не могу открыть порт %s" - -#. / Не могу установить настройки -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:365 -msgid "Can't set settings" -msgstr "Не могу установить настройки" +#. / Не могу прочесть /dev/random +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:189 +msgid "Can't read /dev/random" +msgstr "" #. / Не могу настроить консоль -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:263 +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:299 msgid "Can't setup console" msgstr "Не могу настроить консоль" #. / Не могу выполнить stat %s -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:206 +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:242 #, 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 msgid "Integer out of range" msgstr "Целое вне допустимого диапазона" #. / Ошибка mmap -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:213 +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:249 msgid "Mmap error for input" msgstr "Ошибка mmap" #. / Не задано имя логфайла -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:454 +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:374 msgid "Need filename for log file" msgstr "Не задано имя логфайла" #. / Не задано имя файла! -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:196 +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:232 msgid "No filename given!" msgstr "Не задано имя файла!" +#. / Отсутствует имя порта +#: /Big/Data/C_sources/snippets_library/term.c:168 +msgid "Port name is missing" +msgstr "" + #. / Пробую открыть логфайл %s в режиме дополнения\n -#: /Big/Data/C_sources/snippets_library/usefull_macros.c:458 +#: /Big/Data/C_sources/snippets_library/usefull_macros.c:378 #, c-format msgid "Try to open log file %s in append mode\n" msgstr "Пробую открыть логфайл %s в режиме дополнения\n" @@ -132,3 +149,8 @@ msgstr " #, c-format msgid "Wrong parameter: %s" msgstr "Неправильный параметр: %s" + +#: /Big/Data/C_sources/snippets_library/term.c:92 +#, c-format +msgid "Wrong speed value: %d!" +msgstr "" diff --git a/term.c b/term.c new file mode 100644 index 0000000..b8f0b8a --- /dev/null +++ b/term.c @@ -0,0 +1,232 @@ +/* + * client.c - simple terminal client + * + * 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 // tcsetattr, close, read, write +#include // ioctl +#include // printf, getchar, fopen, perror +#include // exit, realloc +#include // read +#include // read +#include // signal +#include // time +#include // memcpy +#include // int types +#include // gettimeofday +#include // usleep +#include "usefull_macros.h" + +#define LOGBUFSZ (1024) + +typedef struct { + int speed; // communication speed in bauds/s + int bspeed; // baudrate from termios.h +} spdtbl; + +static int tty_init(TTY_descr *descr); + +static spdtbl speeds[] = { + {50, B50}, + {75, B75}, + {110, B110}, + {134, B134}, + {150, B150}, + {200, B200}, + {300, B300}, + {600, B600}, + {1200, B1200}, + {1800, B1800}, + {2400, B2400}, + {4800, B4800}, + {9600, B9600}, + {19200, B19200}, + {38400, B38400}, + {57600, B57600}, + {115200, B115200}, + {230400, B230400}, + {460800, B460800}, + {500000, B500000}, + {576000, B576000}, + {921600, B921600}, + {1000000, B1000000}, + {1152000, B1152000}, + {1500000, B1500000}, + {2000000, B2000000}, + {2500000, B2500000}, + {3000000, B3000000}, + {3500000, B3500000}, + {4000000, B4000000}, + {0,0} +}; + +/** + * @brief conv_spd - test if `speed` is in .speed of `speeds` array + * @param speed - integer speed (bps) + * @return 0 if error, Bxxx if all OK + */ +int conv_spd(int speed){ + spdtbl *spd = speeds; + int curspeed = 0; + do{ + curspeed = spd->speed; + if(curspeed == speed) + return spd->bspeed; + ++spd; + }while(curspeed); + WARNX(_("Wrong speed value: %d!"), speed); + return 0; +} + +/** + * @brief tty_init - open & setup terminal + * @param descr (io) - port descriptor + * @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){ + /// Не могу использовать порт %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 + /// Не могу получить действующие настройки порта + 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){ + /// Не могу сменить настройки порта + WARN(_("Can't apply new TTY settings")); + return globErr ? globErr : 1; + } + // make exclusive open + if(ioctl(descr->comfd, TIOCEXCL)){ + /// Не могу сделать порт эксклюзивным + WARN(_("Can't do exclusive open")); + } + DBG("OK"); + return 0; +} + +/** + * @brief restore_tty - restore opened TTY to previous state and close it + */ +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(*descr); + DBG("done!\n"); +} + +/** + * @brief tty_open - init & open tty device + * @param port - 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); + if(!spd) return NULL; + DBG("open %s with speed %d)", port, speed); + TTY_descr *descr = MALLOC(TTY_descr, 1); + descr->portname = strdup(port); + descr->baudrate = spd; + if(!descr->portname){ + /// Отсутствует имя порта + WARNX(_("Port name is missing")); + }else if(!tty_init(descr)){ + if(bufsz){ + descr->buf = MALLOC(char, bufsz+1); + descr->bufsz = bufsz; + DBG("allocate buffer with size %zd", bufsz); + } + return descr; + } + FREE(descr->portname); + FREE(descr); + return NULL; +} + + +/** + * @brief read_tty - read data from TTY with 10ms timeout + * @param buff (o) - buffer for data read + * @param length - buffer len + * @return amount of bytes read + */ +size_t read_tty(TTY_descr *d){ + if(d->comfd < 0) return 0; + ssize_t L = 0, l; + size_t length = d->bufsz; + char *ptr = d->buf; + fd_set rfds; + struct timeval tv; + int retval; + do{ + l = 0; + FD_ZERO(&rfds); + FD_SET(d->comfd, &rfds); + // wait for 10ms + tv.tv_sec = 0; tv.tv_usec = 10000; + 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; + } + ptr += l; L += l; + length -= l; + } + }while(l); + d->buflen = L; + d->buf[L] = 0; + return (size_t)L; +} + +/** + * @brief write_tty - write data to serial port + * @param buff (i) - data to write + * @param length - its length + * @return 0 if all OK + */ +int write_tty(int comfd, const char *buff, size_t length){ + ssize_t L = write(comfd, buff, length); + if((size_t)L != length){ + /// "Ошибка записи!" + WARN("Write error"); + return 1; + } + return 0; +} diff --git a/term.h b/term.h new file mode 100644 index 0000000..153236e --- /dev/null +++ b/term.h @@ -0,0 +1,34 @@ +/* + * term.h + * + * Copyright 2016 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 __TERM_H__ +#define __TERM_H__ + +#include // tcsetattr, baudrates + +void term_quit(int ex_stat); +int conv_spd(int speed); +void ttys_open(char **ports, int **speeds, int globspeed); + +void set_comlogname(char* nm); +void set_charmode(); + +#endif // __TERM_H__ diff --git a/usefull_macros.c b/usefull_macros.c index ad29770..f764901 100644 --- a/usefull_macros.c +++ b/usefull_macros.c @@ -33,6 +33,7 @@ #include #include #include // PATH_MAX +#include // floor #include "usefull_macros.h" @@ -62,11 +63,6 @@ double dtime(){ \******************************************************************************/ 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, ...); - /** * @brief r_pr_, g_pr_ - format red / green messages * @param fmt ... - printf-like format @@ -112,6 +108,11 @@ int r_WARN(const char *fmt, ...){ return i; } +// pointers to coloured output printf +int (*red)(const char *fmt, ...) = r_pr_; +int (*green)(const char *fmt, ...) = g_pr_; +int (*_WARN)(const char *fmt, ...) = r_WARN; + static const char stars[] = "****************************************"; /** * @brief s_WARN, r_pr_notty - notty variants of coloured printf @@ -165,6 +166,49 @@ void initial_setup(){ #endif } +/******************************************************************************\ + * Different things +\******************************************************************************/ + +/** +* @brief throw_random_seed - Generate a quasy-random number to initialize PRNG +* @return value for srand48 +*/ +long throw_random_seed(){ + long r_ini; + int fail = 0; + int fd = open("/dev/random", O_RDONLY); + do{ + if(-1 == fd){ + /// Не могу открыть /dev/random + WARN(_("Can't open /dev/random")); + fail = 1; break; + } + if(sizeof(long) != read(fd, &r_ini, sizeof(long))){ + /// Не могу прочесть /dev/random + WARN(_("Can't read /dev/random")); + fail = 1; + } + close(fd); + }while(0); + if(fail){ + double tt = dtime() * 1e6; + double mx = (double)LONG_MAX; + r_ini = (long)(tt - mx * floor(tt/mx)); + } + return (r_ini); +} + +/** + * @brief get_available_mem + * @return system available physical memory + */ +uint64_t get_available_mem(){ + return sysconf(_SC_AVPHYS_PAGES) * (uint64_t) sysconf(_SC_PAGE_SIZE); +} + + + /******************************************************************************\ * Memory \******************************************************************************/ @@ -300,122 +344,6 @@ int mygetchar(){ return ret; } - -/******************************************************************************\ - * TTY with select() - * BE CAREFULL! These functions aren't thread-safe! - * BE CAREFULL! These functions are for one serial port only! -\******************************************************************************/ -static struct termios oldtty, tty; // TTY flags -static int comfd = -1; // TTY fd - -/** - * @brief restore_tty - restore port settings to previous - */ -void restore_tty(){ - if(comfd == -1) return; - if(oldtty.c_cflag) - tcsetattr(comfd, TCSANOW, &oldtty); // return TTY to previous state - close(comfd); - comfd = -1; -} - -/** - * @brief tty_init - init port with 8N1 in non-blocking RW mode - * @param comdev (i) - port device - * @param speed - communication speed - */ -void tty_init(char *comdev, tcflag_t speed){ - if(comfd == -1){ // not opened - if(!comdev){ - WARNX("comdev == NULL"); - signals(11); - } - DBG("Open port..."); - do{ - comfd = open(comdev, O_RDWR|O_NOCTTY|O_NONBLOCK); - }while (comfd == -1 && errno == EINTR); - if(comfd < 0){ - /// Не могу открыть порт %s - WARN(_("Can't open port %s"),comdev); - signals(2); - } - if(tcgetattr(comfd, &oldtty)){ // Get settings - /// Не могу получить настройки порта - WARN(_("Can't get port settings")); - oldtty.c_cflag = 0; - } - DBG("Make exclusive"); - // make exclusive open - if(ioctl(comfd, TIOCEXCL)){ - /// Не могу перевести порт в эксклюзивный режим - WARN(_("Can't do exclusive open")); - close(comfd); - signals(2); - } - } - tty = oldtty; - tty.c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG) - tty.c_oflag = 0; - 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){ - /// Не могу установить настройки - WARN(_("Can't set settings")); - signals(0); - } - DBG("OK"); -} - -/** - * @brief read_tty - read data from TTY with 10ms timeout - * @param buff (o) - buffer for data read - * @param length - buffer len - * @return amount of bytes read - */ -size_t read_tty(char *buff, size_t length){ - if(comfd < 0) return 0; - ssize_t L = 0, l; - char *ptr = buff; - fd_set rfds; - struct timeval tv; - int retval; - do{ - l = 0; - FD_ZERO(&rfds); - FD_SET(comfd, &rfds); - // wait for 10ms - tv.tv_sec = 0; tv.tv_usec = 10000; - retval = select(comfd + 1, &rfds, NULL, NULL, &tv); - if (!retval) break; - if(FD_ISSET(comfd, &rfds)){ - if((l = read(comfd, ptr, length)) < 1){ - return 0; - } - ptr += l; L += l; - length -= l; - } - }while(l); - return (size_t)L; -} - -/** - * @brief write_tty - write data to serial port - * @param buff (i) - data to write - * @param length - its length - * @return 0 if all OK - */ -int write_tty(const char *buff, size_t length){ - ssize_t L = write(comfd, buff, length); - if((size_t)L != length){ - /// "Ошибка записи!" - WARN("Write error"); - return 1; - } - return 0; -} - /** * @brief str2double - safely convert data from string to double * @param num (o) - double number read from string @@ -481,7 +409,10 @@ int putlog(const char *fmt, ...){ openlogfile(logname); if(!Flog) return 0; } - int i = fprintf(Flog, "\n\t\t%s", ctime(&t_now)); + //int i = fprintf(Flog, "%s\t\t", ctime(&t_now)); + char buf[256]; + strftime(buf, 255, "%Y/%m/%d %H:%M:%S", localtime(&t_now)); + int i = fprintf(Flog, "%s\t\t", buf); va_list ar; va_start(ar, fmt); i = vfprintf(Flog, fmt, ar); @@ -490,3 +421,4 @@ int putlog(const char *fmt, ...){ fflush(Flog); return i; } + diff --git a/usefull_macros.h b/usefull_macros.h index 0716b36..daa4a79 100644 --- a/usefull_macros.h +++ b/usefull_macros.h @@ -23,10 +23,14 @@ #ifndef __USEFULL_MACROS_H__ #define __USEFULL_MACROS_H__ -#include // tcflag_t -#include // bool -#include // pid_t -#include // errno +#include // bool +#include // pid_t +#include // errno +#include // termios +#include // alloc, free +// just for different purposes +#include +#include #if defined GETTEXT /* @@ -111,9 +115,9 @@ void WEAK signals(int sig); double dtime(); // functions for color output in tty & no-color in pipes -int (*red)(const char *fmt, ...); -int (*_WARN)(const char *fmt, ...); -int (*green)(const char *fmt, ...); +extern int (*red)(const char *fmt, ...); +extern int (*_WARN)(const char *fmt, ...); +extern int (*green)(const char *fmt, ...); // safe allocation void * my_alloc(size_t N, size_t S); // setup locales & other @@ -133,11 +137,28 @@ void setup_con(); int read_console(); int mygetchar(); -// serial port -void restore_tty(); -void tty_init(char *comdev, tcflag_t speed); -size_t read_tty(char *buff, size_t length); -int write_tty(const char *buff, size_t length); +long throw_random_seed(); + +uint64_t get_available_mem(); + +/******************************************************************************\ + The original term.h +\******************************************************************************/ +typedef struct { + char *portname; // device filename (should be freed before structure freeing) + int 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 +} TTY_descr; + +void close_tty(TTY_descr **descr); +TTY_descr *tty_open(char *comdev, int speed, size_t bufsz); +size_t read_tty(TTY_descr *descr); +int write_tty(int comfd, const char *buff, size_t length); // convert string to double with checking int str2double(double *num, const char *str); @@ -252,3 +273,15 @@ void check4running(char *selfname, char *pidfilename); // read name of process by its PID char *readPSname(pid_t pid); #endif // __USEFULL_MACROS_H__ + +/******************************************************************************\ + The original fifo_lifo.h +\******************************************************************************/ +typedef struct buff_node{ + void *data; + struct buff_node *next, *last; +} List; + +List *list_push_tail(List **lst, void *v); +List *list_push(List **lst, void *v); +void *list_pop(List **lst);