From 4a686bb4c364e73e25bd6054724c2e4fa204cefb Mon Sep 17 00:00:00 2001 From: uvos Date: Wed, 21 Dec 2022 23:34:48 +0100 Subject: [PATCH 1/4] inital verison --- CMakeLists.txt | 14 ++++ main.cpp | 179 +++++++++++++++++++++++++++++++++++++++++++++++++ serial_io.cpp | 105 +++++++++++++++++++++++++++++ serial_io.h | 26 +++++++ 4 files changed, 324 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 main.cpp create mode 100644 serial_io.cpp create mode 100644 serial_io.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b859ce7 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.0) + +project(serialterminal) + +set(SRC_FILES main.cpp serial_io.cpp ) +set(LIBS -pthread -lreadline) + +add_executable(${PROJECT_NAME} ${SRC_FILES}) + +target_link_libraries( ${PROJECT_NAME} ${LIBS}) +set_target_properties( ${PROJECT_NAME} PROPERTIES COMPILE_FLAGS -m64 LINK_FLAGS -m64) +add_definitions(" -std=c++11 -Wall ") + +install(TARGETS serialterminal RUNTIME DESTINATION bin) diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..6cd85b3 --- /dev/null +++ b/main.cpp @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "serial_io.h" + +sig_atomic_t stop = false; +constexpr int HISTORY_SIZE = 100; + +void intHandler(int dummy) +{ + stop = true; +} + +static void printUsage() +{ + std::cout<<"usage mulitplexer [option]\n\ + Available options:\n\ + -h, --help print this help\n\ + -p, --serialport serial port device to use\n\ + -P, --port tcp port to use\n\ + -b, --baud set baud rate with termios id\n\ + -r, --rates list Available baud rates\n\ + -s, --sinkless run without serial port\n"; +} + + +struct Config +{ + std::string portFileName = "/dev/ttyUSB0"; + unsigned short port = 6856; + int baud = B9600; + bool noSerial = false; +}; + +static int parseCmdArgs(int argc, char** argv, Config *config) +{ + for (int i = 1; i < argc; i++) + { + if (std::string(argv[i]) == "--help" || std::string(argv[i]) == "-h") + { + printUsage(); + return -1; + } + else if (std::string(argv[i]) == "--serialport" || std::string(argv[i]) == "-p") + { + if(argc > i) config->portFileName = argv[i+1]; + else return -1; + } + else if (std::string(argv[i]) == "--baud" || std::string(argv[i]) == "-b") + { + if(argc > i) config->baud = atoi(argv[i+1]); + else return -1; + } + else if (std::string(argv[i]) == "-r" || std::string(argv[i]) == "--rates") + { + printRates(); + return -1; + } + } + return 0; +} + +void recvThreadFunction(int serial, int signal) +{ + int pollQue = epoll_create1(0); + struct epoll_event ev = {}; + + ev.events = EPOLLIN; + ev.data.fd = serial; + epoll_ctl(pollQue, EPOLL_CTL_ADD, serial, &ev); + ev.events = EPOLLIN; + ev.data.fd = signal; + epoll_ctl(pollQue, EPOLL_CTL_ADD, signal, &ev); + + struct epoll_event event; + int ret; + while((ret = epoll_wait(pollQue, &event, 1, -1)) > 0) + { + if(event.data.fd == signal) + break; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + char buffer[4096]; + int readlen = sRead(serial, buffer, 4096); + if(readlen > 0) + { + rl_clear_visible_line(); + std::cout< ", cb_linehandler); + + int pollQue = epoll_create1(0); + struct epoll_event ev = {}; + ev.events = EPOLLIN; + ev.data.fd = fileno(rl_instream); + epoll_ctl(pollQue, EPOLL_CTL_ADD, fileno(rl_instream), &ev); + ev.events = EPOLLIN; + ev.data.fd = sigfd; + epoll_ctl(pollQue, EPOLL_CTL_ADD, sigfd, &ev); + + struct epoll_event event; + int ret; + while((ret = epoll_wait(pollQue, &event, 1, -1)) > 0) + { + if(event.data.fd == sigfd) + break; + else + rl_callback_read_char(); + } + + readThread.join(); + close(pollQue); + close(sigfd); + std::cout< +#include +#include + +#ifdef __cplusplus +#include +#endif + +#define BAUDRATE B38400 + +void sWrite(int port, char string[], size_t length); + +void sWrite(int port, const char string[], size_t length); + +ssize_t sRead(int port, void *buf, size_t count); + +#ifdef __cplusplus +void printRates(); +#endif + +int serialport_init(const char* device, int baud = BAUDRATE); + + +#endif // SERIAL_H From 8d5e1ea537e3c29367a17ac80a60f42c10756316 Mon Sep 17 00:00:00 2001 From: uvos Date: Wed, 21 Dec 2022 23:37:03 +0100 Subject: [PATCH 2/4] add rl_callback_handler_remove so that readline cleans up --- main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/main.cpp b/main.cpp index 6cd85b3..b99fd58 100644 --- a/main.cpp +++ b/main.cpp @@ -173,6 +173,7 @@ int main(int argc, char* argv[]) readThread.join(); close(pollQue); close(sigfd); + rl_callback_handler_remove(); std::cout< Date: Mon, 3 Apr 2023 21:17:53 +0200 Subject: [PATCH 3/4] Insure that a newline is sent --- CMakeLists.txt | 3 ++- main.cpp | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b859ce7..5ece9d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ add_executable(${PROJECT_NAME} ${SRC_FILES}) target_link_libraries( ${PROJECT_NAME} ${LIBS}) set_target_properties( ${PROJECT_NAME} PROPERTIES COMPILE_FLAGS -m64 LINK_FLAGS -m64) -add_definitions(" -std=c++11 -Wall ") +add_definitions("-std=c++11 -Wall") +set(CMAKE_INSTALL_PREFIX /usr) install(TARGETS serialterminal RUNTIME DESTINATION bin) diff --git a/main.cpp b/main.cpp index b99fd58..1a6ccec 100644 --- a/main.cpp +++ b/main.cpp @@ -89,9 +89,10 @@ void recvThreadFunction(int serial, int signal) break; std::this_thread::sleep_for(std::chrono::milliseconds(100)); char buffer[4096]; - int readlen = sRead(serial, buffer, 4096); + int readlen = sRead(serial, buffer, 4095); if(readlen > 0) { + buffer[readlen] = '\0'; rl_clear_visible_line(); std::cout< Date: Mon, 3 Apr 2023 21:34:00 +0200 Subject: [PATCH 4/4] Make exit not racey --- main.cpp | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/main.cpp b/main.cpp index 1a6ccec..7964879 100644 --- a/main.cpp +++ b/main.cpp @@ -22,14 +22,14 @@ void intHandler(int dummy) static void printUsage() { - std::cout<<"usage mulitplexer [option]\n\ - Available options:\n\ - -h, --help print this help\n\ - -p, --serialport serial port device to use\n\ - -P, --port tcp port to use\n\ - -b, --baud set baud rate with termios id\n\ - -r, --rates list Available baud rates\n\ - -s, --sinkless run without serial port\n"; + std::cout<<"usage mulitplexer [option]\n" + <<"Available options:\n" + <<"-h, --help print this help\n" + <<"-p, --serialport serial port device to use\n" + <<"-P, --port tcp port to use\n" + <<"-b, --baud set baud rate with termios id\n" + <<"-r, --rates list Available baud rates\n" + <<"-s, --sinkless run without serial port\n"; } @@ -69,7 +69,7 @@ static int parseCmdArgs(int argc, char** argv, Config *config) return 0; } -void recvThreadFunction(int serial, int signal) +void recvThreadFunction(int serial, int exitfd) { int pollQue = epoll_create1(0); struct epoll_event ev = {}; @@ -78,14 +78,14 @@ void recvThreadFunction(int serial, int signal) ev.data.fd = serial; epoll_ctl(pollQue, EPOLL_CTL_ADD, serial, &ev); ev.events = EPOLLIN; - ev.data.fd = signal; - epoll_ctl(pollQue, EPOLL_CTL_ADD, signal, &ev); + ev.data.fd = exitfd; + epoll_ctl(pollQue, EPOLL_CTL_ADD, exitfd, &ev); struct epoll_event event; int ret; while((ret = epoll_wait(pollQue, &event, 1, -1)) > 0) { - if(event.data.fd == signal) + if(event.data.fd == exitfd) break; std::this_thread::sleep_for(std::chrono::milliseconds(100)); char buffer[4096]; @@ -148,7 +148,15 @@ int main(int argc, char* argv[]) signal(SIGTERM, intHandler); signal(SIGPIPE, SIG_IGN); - std::thread readThread(recvThreadFunction, serial, sigfd); + int exitPipe[2]; + int ret = pipe(exitPipe); + if(ret) + { + std::cout<<"Could not create pipe\n"; + return 3; + } + + std::thread readThread(recvThreadFunction, serial, exitPipe[0]); rl_catch_signals = 0; rl_callback_handler_install ("> ", cb_linehandler); @@ -163,13 +171,17 @@ int main(int argc, char* argv[]) epoll_ctl(pollQue, EPOLL_CTL_ADD, sigfd, &ev); struct epoll_event event; - int ret; while((ret = epoll_wait(pollQue, &event, 1, -1)) > 0) { if(event.data.fd == sigfd) + { + write(exitPipe[1], "\n", 1); break; + } else + { rl_callback_read_char(); + } } readThread.join();