From 33658a57a46abd5f8b0829d2aa95476e709fd74a Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Thu, 23 Nov 2023 17:04:54 +0300 Subject: [PATCH] add modbus input mode --- CMakeLists.txt | 2 +- ncurses_and_readline.c | 46 ++++++++++++++++++++++++++++++++---------- ncurses_and_readline.h | 5 ++++- popup_msg.c | 2 +- string_functions.c | 36 ++++++++++++++++++++++++++++++--- 5 files changed, 74 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 601a454..fba365d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.0) set(PROJ tty_term) -set(MINOR_VERSION "1") +set(MINOR_VERSION "2") set(MID_VERSION "1") set(MAJOR_VERSION "0") set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}") diff --git a/ncurses_and_readline.c b/ncurses_and_readline.c index 9b3e2de..e992edf 100644 --- a/ncurses_and_readline.c +++ b/ncurses_and_readline.c @@ -39,10 +39,11 @@ #include "string_functions.h" enum { // using colors - BKG_NO = 1, - BKGMARKED_NO = 2, - NORMAL_NO = 3, - MARKED_NO = 4 + BKG_NO = 1, // normal status string + BKGMARKED_NO, // marked status string + NORMAL_NO, // normal output + MARKED_NO, // marked output + ERROR_NO // error displayed }; #define COLOR(x) COLOR_PAIR(x ## _NO) @@ -55,7 +56,7 @@ static bool should_exit = false; static disptype disp_type = DISP_TEXT; // type of displaying data static disptype input_type = DISP_TEXT; // parsing type of input data -const char *dispnames[] = {"TEXT", "RAW", "HEX"}; +const char *dispnames[DISP_SIZE] = {"TEXT", "RAW", "HEX", "RTU (RAW)", "RTU (HEX)", "Error"}; static chardevice *dtty = NULL; @@ -121,6 +122,18 @@ static void forward_to_readline(char c){ rl_callback_read_char(); } +/** + * @brief show_err - show error on status string + * @param text - text to display + */ +static void show_err(const char *text){ + wclear(sep_win); + wattron(sep_win, COLOR(ERROR)); + wprintw(sep_win, "%s", text); + wattroff(sep_win, COLOR(ERROR)); + wrefresh(sep_win); +} + /** * @brief ptrtobuf - get n'th string of `formatted_buffer` * @param lineno - line number @@ -128,7 +141,7 @@ static void forward_to_readline(char c){ */ static char *ptrtobuf(size_t lineno){ if(!linebuffer->line_array_idx){ - WARNX("line_array_idx not inited"); + show_err("line_array_idx not inited"); return NULL; } if(lineno > linebuffer->lnarr_curr) return NULL; @@ -523,11 +536,12 @@ void init_ncurses(){ } if(!msg_win || !sep_win || !cmd_win) fail_exit("Failed to allocate windows"); - wtimeout(cmd_win, 4); + wtimeout(cmd_win, 5); keypad(cmd_win, TRUE); if(has_colors()){ init_pair(BKG_NO, COLOR_WHITE, COLOR_BLUE); init_pair(BKGMARKED_NO, 1, COLOR_BLUE); // COLOR_RED used in my usefull_macros + init_pair(ERROR_NO, COLOR_BLACK, 1); init_pair(NORMAL_NO, COLOR_WHITE, COLOR_BLACK); init_pair(MARKED_NO, COLOR_CYAN, COLOR_BLACK); wbkgd(sep_win, COLOR(BKG)); @@ -560,9 +574,9 @@ static void got_command(char *line){ if(!*line) return; // zero length if(!previous_line || strcmp(previous_line, line)) add_history(line); // omit repeats FREE(previous_line); - if(convert_and_send(input_type, line) == -1){ - ERRX("Device disconnected"); - } + int res = convert_and_send(input_type, line); + if(res == 0) show_err("Wrong data format"); + else if(res == -1) ERRX("Device disconnected"); previous_line = line; } } @@ -588,7 +602,7 @@ static void change_disp(disptype in, disptype out){ input_type = in; DBG("input -> %s", dispnames[in]); } - if(out >= DISP_TEXT && out < DISP_UNCHANGED && out != disp_type){ + if(out >= DISP_TEXT && out <= DISP_HEX && out != disp_type){ disp_type = out; DBG("output -> %s", dispnames[out]); resize(); // reformat everything @@ -636,6 +650,8 @@ static const char *help[] = { " F2 - text mode", " F3 - raw mode (all symbols in hex codes)", " F4 - hexdump mode (like hexdump output)", + " F5 - modbus RTU mode (only for sending), input like RAW: ID data", + " F6 - modbus RTU mode (only for sending), input like HEX: ID data", " mouse scroll - scroll text output", " q,^c,^d - quit", " TAB - switch between scroll and edit modes", @@ -690,6 +706,14 @@ void *cmdline(void* arg){ DBG("\n\nIN HEX mode\n\n"); dt = DISP_HEX; break; + case KEY_F(5): // RTU mode + DBG("\n\nIN RTU RAW mode\n\n"); + dt = DISP_RTURAW; + break; + case KEY_F(6): // RTU mode + DBG("\n\nIN RTU HEX mode\n\n"); + dt = DISP_RTUHEX; + break; case KEY_MOUSE: if(getmouse(&event) == OK){ if(event.bstate & (BUTTON4_PRESSED)) rolldown(1); // wheel up diff --git a/ncurses_and_readline.h b/ncurses_and_readline.h index ad1a40d..54f4706 100644 --- a/ncurses_and_readline.h +++ b/ncurses_and_readline.h @@ -26,7 +26,10 @@ typedef enum{ // display/input data as DISP_TEXT, // text (non-ASCII input and output as \xxx) DISP_RAW, // hex output as xx xx xx, input in as numbers in bin (0bxx), oct(0xx), hex (0xxx||0Xxx) or dec and letters DISP_HEX, // hexdump output, input in hex only (with or without spaces) - DISP_UNCHANGED // old + DISP_RTURAW, // modbus RTU (only to send): first number is node address, all other - data; CRC calculated + DISP_RTUHEX, // RTU, input in hex (in raw - like RAW) + DISP_UNCHANGED, // old + DISP_SIZE // sizeof } disptype; void init_readline(); diff --git a/popup_msg.c b/popup_msg.c index a112c8f..7e82d39 100644 --- a/popup_msg.c +++ b/popup_msg.c @@ -79,7 +79,7 @@ void popup_msg(WINDOW *parent, const char *const *msg){ getmaxyx(parent, maxy, maxx); // borders //x0 = (maxx > 12) ? 2 : ((maxx > 9) ? 1 : 0); - x0 = (maxx > 80) ? maxx/2-40 : maxx / 32; + x0 = (maxx > 80) ? maxx/2-60 : maxx / 32; y0 = (maxy > 20) ? 2 : ((maxy > 16) ? 1 : 0); int wide = maxx - 2*x0; int high = maxy - 2*y0; diff --git a/string_functions.c b/string_functions.c index 70b7aed..62a9f20 100644 --- a/string_functions.c +++ b/string_functions.c @@ -27,7 +27,7 @@ static int eollen = 1; // read text string and throw out all < 31 and > 126 static inline const char *omit_nonletters(disptype input_type, const char *line){ - int start = (input_type == DISP_TEXT) ? 31 : 32; // remove spaces for RAW and HEX modes + int start = (input_type == DISP_TEXT) ? 31 : 32; // remove spaces for non-TEXT modes while(*line){ char c = *line; if(c > start && c < 127) break; @@ -159,6 +159,17 @@ static inline const char *getspec(const char *line, int *ch){ *ch = got; return line; } +/* +static inline const char* getu32(const char *str, uint32_t *val){ + char *eptr; + if(!str) return NULL; + long ll = strtol(str, &eptr, 0); + if(ll < 0 || ll > UINT32_MAX){ // wrong number + return NULL; + } + if(val) *val = (uint32_t)ll; + return omit_nonletters(DISP_RTU, eptr); +}*/ /** * @brief convert_and_send - convert input line and send it (in text mode add `eol`) @@ -171,11 +182,14 @@ int convert_and_send(disptype input_type, const char *line){ size_t curpos = 0; // position in `buf` line = omit_nonletters(input_type, line); DBG("got: '%s' to send", line); - while(*line){ - if(curpos >= bufsiz){ // out ouptut buffer can't be larger than input + void CHKbufsiz(size_t sz){ + if(curpos + sz >= bufsiz){ // out ouptut buffer can't be larger than input bufsiz += BUFSIZ; buf = realloc(buf, bufsiz); } + } + while(*line){ + CHKbufsiz(1); int ch = -1; switch(input_type){ case DISP_TEXT: // only check for '\' @@ -183,6 +197,7 @@ int convert_and_send(disptype input_type, const char *line){ if(ch == '\\') line = getspec(line, &ch); break; case DISP_RAW: // read next uint8_t and put into buffer + case DISP_RTURAW: // the same (but calculate CRC at the end) ch = *line++; if(ch == '0'){ // number: 0, 0xHH, 0OOO, 0bBBBBBBBB ch = *line; @@ -205,6 +220,7 @@ int convert_and_send(disptype input_type, const char *line){ } // else - letter (without escape-symbols!) break; case DISP_HEX: // read next 2 hex bytes and put into buffer + case DISP_RTUHEX: // the same (but calculate CRC at the end) line = gethex(line, &ch); break; default: @@ -222,6 +238,20 @@ int convert_and_send(disptype input_type, const char *line){ memcpy(buf+curpos, eol, eollen); curpos += eollen; DBG("Add EOL"); + }else if(input_type == DISP_RTURAW || input_type == DISP_RTUHEX){ // calculate CRC + CHKbufsiz(2); + uint16_t crc = 0xFFFF; + for(size_t pos = 0; pos < curpos; ++pos){ + crc ^= (uint16_t)buf[pos]; + for(int i = 8; i; --i){ + if((crc & 1)){ + crc >>= 1; + crc ^= 0xA001; + }else crc >>= 1; + } + } + buf[curpos++] = crc & 0xff; // Lo + buf[curpos++] = crc >> 8; // Hi } return SendData(buf, curpos); }