From 6e831620f974248a193b903220d24878760ec77c Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Thu, 2 May 2024 00:17:22 +0200 Subject: [PATCH 01/31] Drop boost logger, simplify cmake targets --- CMakeLists.txt | 34 ++++------------------------------ include/Logger.h | 37 +++++++++++++++++++++++++++++++++++++ include/Logger.inl | 11 +++++++++++ include/RealSerialPort.h | 15 +++++++-------- include/common.hpp | 2 +- include/logging.h | 23 ----------------------- src/Logger.cpp | 27 +++++++++++++++++++++++++++ src/SerialClient.cpp | 14 +++++++------- src/SerialServer.cpp | 17 ++++++++--------- src/VirtualSerialPort.cpp | 30 +++++++++++++++--------------- src/logging.cpp | 34 ---------------------------------- src/main.cpp | 4 +--- 12 files changed, 118 insertions(+), 130 deletions(-) create mode 100644 include/Logger.h create mode 100644 include/Logger.inl delete mode 100644 include/logging.h create mode 100644 src/Logger.cpp delete mode 100644 src/logging.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4dd8fb4..a64393b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,48 +23,22 @@ endif() include_directories(${CMAKE_SOURCE_DIR}/include) -add_library(logging src/logging.cpp) -target_include_directories(logging PUBLIC ${CMAKE_SOURCE_DIR}/include) -target_link_libraries(logging PUBLIC - Boost::log - Boost::log_setup - Boost::date_time -) - -add_library(core_lib src/logging.cpp src/SerialServer.cpp src/SerialClient.cpp src/VirtualSerialPort.cpp) +# Create core library without Logger.cpp, which is now in the logging library +add_library(core_lib src/Logger.cpp src/SerialServer.cpp src/SerialClient.cpp src/VirtualSerialPort.cpp) target_include_directories(core_lib PUBLIC ${CMAKE_SOURCE_DIR}/include) -target_link_libraries(core_lib PRIVATE +target_link_libraries(core_lib PUBLIC Boost::system Boost::program_options Boost::log Boost::log_setup Boost::date_time - logging pthread ) +# Create the executable add_executable(ser2net2ser src/main.cpp) target_link_libraries(ser2net2ser PRIVATE core_lib - logging Boost::system Boost::program_options - Boost::log - Boost::log_setup - Boost::date_time ) - -# # TODO: REENABLE TESTS -# enable_testing() -# add_executable(test_app tests/test_server.cpp) -# target_compile_definitions(test_app PRIVATE UNIT_TEST) -# target_link_libraries(test_app PRIVATE -# serial_server_lib # this includes server.cpp -# Boost::system -# GTest::gtest_main -# GTest::gtest -# GTest::gmock -# ) - -# include(GoogleTest) -# gtest_discover_tests(test_app EXTRA_ARGS --gtest_color=yes) diff --git a/include/Logger.h b/include/Logger.h new file mode 100644 index 0000000..a217781 --- /dev/null +++ b/include/Logger.h @@ -0,0 +1,37 @@ +#ifndef LOGGER_H +#define LOGGER_H + +#include +#include +#include + +class Logger { +public: + enum class Level { + Info, + Warning, + Error + }; + +private: + std::ostringstream stream; + Level logLevel; + static std::mutex mtx; + +public: + Logger(Level level = Level::Info); + ~Logger(); + + // Delete copy constructor and assignment operator + Logger(const Logger&) = delete; + Logger& operator=(const Logger&) = delete; + Logger& operator<<(std::ostream& (*pf)(std::ostream&)); + static std::string levelToString(Level level); + + template + Logger& operator<<(const T& msg); +}; + +#include "Logger.inl" // Include template implementation + +#endif // LOGGER_H diff --git a/include/Logger.inl b/include/Logger.inl new file mode 100644 index 0000000..bd55e53 --- /dev/null +++ b/include/Logger.inl @@ -0,0 +1,11 @@ +template +inline Logger& Logger::operator<<(const T& msg) { + stream << msg; + return *this; +} + +// Handle ostream manipulators like std::endl +inline Logger& Logger::operator<<(std::ostream& (*pf)(std::ostream&)) { + stream << pf; + return *this; +} diff --git a/include/RealSerialPort.h b/include/RealSerialPort.h index 38806fb..5e30673 100644 --- a/include/RealSerialPort.h +++ b/include/RealSerialPort.h @@ -2,8 +2,8 @@ #define REALSERIALPORT_H #include "ISerialPort.h" +#include "Logger.h" #include -#include using boost::asio::serial_port_base; @@ -12,17 +12,17 @@ class RealSerialPort : public ISerialPort { explicit RealSerialPort(boost::asio::io_service& io) : port(io) {} void open(const std::string& device, serial_port_base::baud_rate baudRate) override { - BOOST_LOG_TRIVIAL(info) << "Setting up connection to serial port " << device; + Logger(Logger::Level::Info) << "Setting up connection to serial port " << device; try { port.open(device); setSerialOptions(baudRate); } catch (const boost::system::system_error& e) { - BOOST_LOG_TRIVIAL(error) << "Failed to open serial port: " << e.what(); + Logger(Logger::Level::Error) << "Failed to open serial port: " << e.what(); } } void setSerialOptions(serial_port_base::baud_rate baudRate) { - BOOST_LOG_TRIVIAL(info) << "Setting connection options."; + Logger(Logger::Level::Info) << "Setting connection options."; port.set_option(baudRate); port.set_option(serial_port_base::character_size(8)); port.set_option(serial_port_base::parity(serial_port_base::parity::none)); @@ -31,18 +31,17 @@ class RealSerialPort : public ISerialPort { } void async_read_some(const boost::asio::mutable_buffer& buffer, std::function handler) override { - // BOOST_LOG_TRIVIAL(info) << "Read some."; if (!port.is_open()) { - BOOST_LOG_TRIVIAL(error) << "Attempt to read from a closed serial port."; + Logger(Logger::Level::Error) << "Attempt to read from a closed serial port."; return; } port.async_read_some(buffer, handler); } void async_write(const boost::asio::const_buffer& buffer, std::function handler) override { - BOOST_LOG_TRIVIAL(info) << "write some some."; + Logger(Logger::Level::Info) << "write some some."; if (!port.is_open()) { - BOOST_LOG_TRIVIAL(error) << "Attempt to write to a closed serial port."; + Logger(Logger::Level::Error) << "Attempt to write to a closed serial port."; return; } boost::asio::async_write(port, buffer, handler); diff --git a/include/common.hpp b/include/common.hpp index ca65d32..71485a9 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -12,6 +12,6 @@ #include #include -#include "logging.h" +#include "Logger.h" #endif // COMMON_HPP diff --git a/include/logging.h b/include/logging.h deleted file mode 100644 index 59e8f88..0000000 --- a/include/logging.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef LOGGING_H -#define LOGGING_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace logging = boost::log; -namespace src = boost::log::sources; -namespace expr = boost::log::expressions; -namespace keywords = boost::log::keywords; - -extern src::severity_logger lg; - -void init_logging(); - -#endif // LOGGING_H diff --git a/src/Logger.cpp b/src/Logger.cpp new file mode 100644 index 0000000..ef9166d --- /dev/null +++ b/src/Logger.cpp @@ -0,0 +1,27 @@ +#include "Logger.h" +#include +#include +#include + +std::mutex Logger::mtx; + +Logger::Logger(Level level) : logLevel(level) {} + +Logger::~Logger() { + mtx.lock(); + auto now = std::chrono::system_clock::now(); + auto now_c = std::chrono::system_clock::to_time_t(now); + std::tm now_tm = *std::localtime(&now_c); + + std::cout << std::put_time(&now_tm, "%Y-%m-%d %H:%M:%S") << " " << levelToString(logLevel) << " " << stream.str() << std::endl; + mtx.unlock(); +} + +std::string Logger::levelToString(Level level) { + switch (level) { + case Level::Info: return "[info]"; + case Level::Warning: return "[warning]"; + case Level::Error: return "[error]"; + } + return "[info]"; +} diff --git a/src/SerialClient.cpp b/src/SerialClient.cpp index 93d0c74..f1d6552 100644 --- a/src/SerialClient.cpp +++ b/src/SerialClient.cpp @@ -10,11 +10,11 @@ using std::endl; SerialClient::SerialClient(boost::asio::io_service& io_service, const std::string& server_ip, unsigned short server_port, const std::string& vsp_name) : vsp_(io_service, vsp_name) { - std::cout << "Initializing client..."; - std::cout << "Connecting to server at " << server_ip << ":" << server_port; + Logger(Logger::Level::Info) << "Initializing client..."; + Logger(Logger::Level::Info) << "Connecting to server at " << server_ip << ":" << server_port; socketClient_.connectToServer(server_ip.c_str(), server_port); - std::cout << "Connected to server."; - std::cout << "Opening virtual serial port: " << vsp_name; + Logger(Logger::Level::Info) << "Connected to server."; + Logger(Logger::Level::Info) << "Opening virtual serial port: " << vsp_name; } void SerialClient::run() { @@ -36,10 +36,10 @@ void SerialClient::run() { ssize_t bytes_read = vsp_.async_read(buffer, sizeof(buffer) - 1); if (bytes_read > 0) { buffer[bytes_read] = '\0'; - std::cout << "From PTY: " << buffer; + Logger(Logger::Level::Info) << "From PTY: " << buffer; socketClient_.sendToServer(buffer, bytes_read); } else if (bytes_read == 0) { - std::cout << "PTY closed." << std::endl; + Logger(Logger::Level::Info) << "PTY closed." << std::endl; break; } else { std::cerr << "Error reading from PTY: " << strerror(errno) << std::endl; @@ -53,7 +53,7 @@ void SerialClient::run() { std::cout << "From Server: " << buffer; vsp_.async_write(buffer, bytes_read); } else if (bytes_read == 0) { - std::cout << "Server closed connection." << std::endl; + Logger(Logger::Level::Info) << "Server closed connection." << std::endl; break; } else { std::cerr << "Error reading from socket: " << strerror(errno) << std::endl; diff --git a/src/SerialServer.cpp b/src/SerialServer.cpp index 952b46a..dabf8c8 100644 --- a/src/SerialServer.cpp +++ b/src/SerialServer.cpp @@ -1,5 +1,4 @@ #include "SerialServer.h" -#include SerialServer::SerialServer(boost::asio::io_service& io_service, const std::string& device, unsigned int baud_rate) : io_service_(io_service), @@ -10,9 +9,9 @@ SerialServer::SerialServer(boost::asio::io_service& io_service, const std::strin } void SerialServer::run() { - BOOST_LOG_TRIVIAL(info) << "SerialServer::run"; + Logger(Logger::Level::Info) << "SerialServer::run"; start_accept(); - BOOST_LOG_TRIVIAL(info) << "ioservice::run"; + Logger(Logger::Level::Info) << "ioservice::run"; io_service_.run(); } @@ -26,14 +25,14 @@ void SerialServer::start_accept() { } void SerialServer::handle_session() { - BOOST_LOG_TRIVIAL(info) << "SerialServer::handle_session"; + Logger(Logger::Level::Info) << "SerialServer::handle_session"; async_read_socket(); async_read_serial(); } void SerialServer::async_read_socket() { - BOOST_LOG_TRIVIAL(info) << "SerialServer::async_read_socket"; + Logger(Logger::Level::Info) << "SerialServer::async_read_socket"; socket_.async_read_some(boost::asio::buffer(buffer_), [this](boost::system::error_code ec, std::size_t length) { if (!ec) { @@ -41,11 +40,11 @@ void SerialServer::async_read_socket() { if (!ec) { async_read_socket(); } else { - BOOST_LOG_TRIVIAL(error) << "Error writing to client: " << ec.message(); + Logger(Logger::Level::Error) << "Error writing to client: " << ec.message(); } }); } else { - BOOST_LOG_TRIVIAL(error) << "Read error on socket: " << ec.message(); + Logger(Logger::Level::Error) << "Read error on socket: " << ec.message(); socket_.close(); } }); @@ -61,11 +60,11 @@ void SerialServer::async_read_serial() { if (!ec) { async_read_serial(); } else { - BOOST_LOG_TRIVIAL(error) << "Error sending to socket: " << ec.message(); + Logger(Logger::Level::Error) << "Error sending to socket: " << ec.message(); } }); } else { - BOOST_LOG_TRIVIAL(error) << "Read error on serial port: " << ec.message(); + Logger(Logger::Level::Error) << "Read error on serial port: " << ec.message(); socket_.close(); } }); diff --git a/src/VirtualSerialPort.cpp b/src/VirtualSerialPort.cpp index 01d3cd5..5843584 100644 --- a/src/VirtualSerialPort.cpp +++ b/src/VirtualSerialPort.cpp @@ -7,29 +7,29 @@ VirtualSerialPort::VirtualSerialPort(boost::asio::io_context& io_context, const char* slave_name; master_fd = posix_openpt(O_RDWR | O_NOCTTY); if (master_fd == -1) { - BOOST_LOG_TRIVIAL(error) << "Failed to open PTY master: " << strerror(errno); + Logger(Logger::Level::Error) << "Failed to open PTY master: " << strerror(errno); throw std::runtime_error("Failed to open PTY master"); } - BOOST_LOG_TRIVIAL(info) << "PTY master opened successfully"; + Logger(Logger::Level::Info) << "PTY master opened successfully"; if (grantpt(master_fd) == -1 || unlockpt(master_fd) == -1 || (slave_name = ptsname(master_fd)) == nullptr) { - BOOST_LOG_TRIVIAL(error) << "Failed to grant or unlock PTY: " << strerror(errno); + Logger(Logger::Level::Error) << "Failed to grant or unlock PTY: " << strerror(errno); throw std::runtime_error("Failed to grant or unlock PTY"); } - BOOST_LOG_TRIVIAL(info) << "PTY grant and unlock successful"; - BOOST_LOG_TRIVIAL(info) << "Slave PTY name: " << slave_name << std::endl; + Logger(Logger::Level::Info) << "PTY grant and unlock successful"; + Logger(Logger::Level::Info) << "Slave PTY name: " << slave_name << std::endl; // Attempt to create a symbolic link from slave_name to "/dev/ttyUSB0" if (symlink(slave_name, device_name_.c_str()) == -1) { - BOOST_LOG_TRIVIAL(error) << "Failed to create symlink for PTY slave: " << strerror(errno); + Logger(Logger::Level::Error) << "Failed to create symlink for PTY slave: " << strerror(errno); throw std::runtime_error("Failed to create symlink for PTY slave"); } - BOOST_LOG_TRIVIAL(info) << "Symlink for PTY slave created successfully"; + Logger(Logger::Level::Info) << "Symlink for PTY slave created successfully"; // Open the slave pseudoterminal slave_fd = open(slave_name, O_RDWR); if (slave_fd == -1) { - BOOST_LOG_TRIVIAL(error) << "Failed to create symlink for PTY slave: " << strerror(errno); + Logger(Logger::Level::Error) << "Failed to create symlink for PTY slave: " << strerror(errno); throw std::runtime_error("Failed to open the slave pseudoterminal"); } @@ -38,10 +38,10 @@ VirtualSerialPort::VirtualSerialPort(boost::asio::io_context& io_context, const chmod(device_name_.c_str(), 0660); struct group* tty_grp = getgrnam("tty"); if (tty_grp && chown(device_name_.c_str(), -1, tty_grp->gr_gid) == -1) { - BOOST_LOG_TRIVIAL(error) << "Failed to change group of device: " << strerror(errno); + Logger(Logger::Level::Error) << "Failed to change group of device: " << strerror(errno); throw std::runtime_error("Failed to change group of device"); } - BOOST_LOG_TRIVIAL(info) << "Group changed successfully for the device"; + Logger(Logger::Level::Info) << "Group changed successfully for the device"; master_fd_.assign(master_fd); slave_fd_.assign(slave_fd); @@ -52,7 +52,7 @@ VirtualSerialPort::VirtualSerialPort(boost::asio::io_context& io_context, const void VirtualSerialPort::setup_pty(int fd) { struct termios tty; if (tcgetattr(fd, &tty) != 0) { - BOOST_LOG_TRIVIAL(error) << "Error from tcgetattr: " << strerror(errno); + Logger(Logger::Level::Error) << "Error from tcgetattr: " << strerror(errno); return; } @@ -70,9 +70,9 @@ void VirtualSerialPort::setup_pty(int fd) { tty.c_oflag &= ~OPOST; if (tcsetattr(fd, TCSANOW, &tty) != 0) { - BOOST_LOG_TRIVIAL(error) << "Error from tcsetattr: " << strerror(errno); + Logger(Logger::Level::Error) << "Error from tcsetattr: " << strerror(errno); } else { - BOOST_LOG_TRIVIAL(info) << "PTY attributes set successfully"; + Logger(Logger::Level::Info) << "PTY attributes set successfully"; } } @@ -87,9 +87,9 @@ VirtualSerialPort::~VirtualSerialPort() { } ssize_t VirtualSerialPort::async_read(char* buffer, unsigned int length) { - BOOST_LOG_TRIVIAL(info) << "VSP::async_read"; + Logger(Logger::Level::Info) << "VSP::async_read"; ssize_t bytes_read = read(master_fd_.native_handle(), buffer, length); - BOOST_LOG_TRIVIAL(info) << "READ FROM SERIAL!!!! -> "; + Logger(Logger::Level::Info) << "READ FROM SERIAL!!!! -> "; return bytes_read; } diff --git a/src/logging.cpp b/src/logging.cpp deleted file mode 100644 index bffd618..0000000 --- a/src/logging.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "logging.h" - -// Define the global logger -src::severity_logger lg; - -void init_logging() { - logging::add_common_attributes(); - - logging::add_console_log( - std::cout, - keywords::format = ( - expr::stream - << expr::format_date_time("TimeStamp", "%Y-%m-%d %H:%M:%S") - << " [" << logging::trivial::severity << "] " - << expr::smessage - ) - ); - - logging::add_file_log( - keywords::file_name = "serial_application_%N.log", - keywords::rotation_size = 10 * 1024 * 1024, // Rotate files every 10 MiB - keywords::time_based_rotation = logging::sinks::file::rotation_at_time_point(0, 0, 0), - keywords::format = ( - expr::stream - << expr::format_date_time("TimeStamp", "%Y-%m-%d %H:%M:%S") - << " [" << logging::trivial::severity << "] " - << expr::smessage - ) - ); - - logging::core::get()->set_filter( - logging::trivial::severity >= logging::trivial::info - ); -} diff --git a/src/main.cpp b/src/main.cpp index 89732e2..46e1b0e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ #include #include #include -#include "logging.h" +#include "Logger.h" #include "SerialClient.h" #include "SerialServer.h" #include "RealSerialPort.h" @@ -25,8 +25,6 @@ void setup_and_run_client(io_service& io, const variables_map& vm) { } int main(int argc, char* argv[]) { - init_logging(); - if (argc < 2) { cerr << "Usage: ser2net2ser [options]\n"; return 1; From 544aba95d929ac57be1a80372305e769f6a50ce5 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Thu, 2 May 2024 00:19:51 +0200 Subject: [PATCH 02/31] Client works, remove readme dislaimer --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index a518df8..f9ed2c2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # ser2net2ser -> WIP: server seems to work fine, client still has some issues - ## Requirements - Linux or macOS operating system From a681974c7ec315abbc8db447d0c2a148e2462d2f Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Thu, 2 May 2024 00:25:03 +0200 Subject: [PATCH 03/31] Cleanup logs in serial client --- src/SerialClient.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SerialClient.cpp b/src/SerialClient.cpp index f1d6552..b725282 100644 --- a/src/SerialClient.cpp +++ b/src/SerialClient.cpp @@ -28,7 +28,7 @@ void SerialClient::run() { FD_SET(socketClient_.sock_fd, &read_fds); if (select(max_fd, &read_fds, NULL, NULL, NULL) < 0 && errno != EINTR) { - std::cerr << "Select error: " << strerror(errno) << std::endl; + Logger(Logger::Level::Error) << "Select error: " << strerror(errno) << std::endl; break; } @@ -42,7 +42,7 @@ void SerialClient::run() { Logger(Logger::Level::Info) << "PTY closed." << std::endl; break; } else { - std::cerr << "Error reading from PTY: " << strerror(errno) << std::endl; + Logger(Logger::Level::Error) << "Error reading from PTY: " << strerror(errno) << std::endl; } } @@ -50,13 +50,13 @@ void SerialClient::run() { ssize_t bytes_read = socketClient_.receiveFromServer(buffer, sizeof(buffer) - 1); if (bytes_read > 0) { buffer[bytes_read] = '\0'; - std::cout << "From Server: " << buffer; + Logger(Logger::Level::Info) << "From Server: " << buffer; vsp_.async_write(buffer, bytes_read); } else if (bytes_read == 0) { Logger(Logger::Level::Info) << "Server closed connection." << std::endl; break; } else { - std::cerr << "Error reading from socket: " << strerror(errno) << std::endl; + Logger(Logger::Level::Error) << "Error reading from socket: " << strerror(errno) << std::endl; } } } From ad337938cf0242574cd95895a6134e8c4184b0e4 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Thu, 2 May 2024 00:26:06 +0200 Subject: [PATCH 04/31] Cleanup devel debuug minimal clients --- src/another-client.cpp | 129 ------------------------------ src/separate_main.cpp | 54 ------------- src/yet-another-client.cpp | 155 ------------------------------------- 3 files changed, 338 deletions(-) delete mode 100644 src/another-client.cpp delete mode 100644 src/separate_main.cpp delete mode 100644 src/yet-another-client.cpp diff --git a/src/another-client.cpp b/src/another-client.cpp deleted file mode 100644 index ded4a54..0000000 --- a/src/another-client.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int main() { - int master_fd, slave_fd; - int sock_fd; - struct sockaddr_in server_addr; - char *slave_name; - char server_ip[] = "192.168.1.29"; // Example IP address - int server_port = 3333; // Example port - - // Create a pseudoterminal - master_fd = posix_openpt(O_RDWR | O_NOCTTY); - if (master_fd == -1) { - std::cerr << "Error opening PTY: " << strerror(errno) << std::endl; - return 1; - } - - if (grantpt(master_fd) == -1 || unlockpt(master_fd) == -1 || (slave_name = ptsname(master_fd)) == nullptr) { - std::cerr << "Failed to initialize PTY: " << strerror(errno) << std::endl; - close(master_fd); - return 1; - } - - std::cout << "Slave PTY name: " << slave_name << std::endl; - - // Attempt to create a symbolic link from slave_name to "/dev/ttyUSB0" - if (symlink(slave_name, "/dev/ttyUSB0") == -1) { - std::cerr << "Failed to create symlink for PTY slave: " << strerror(errno) << std::endl; - close(master_fd); - return 1; - } - std::cout << "Symlink for PTY slave created successfully" << std::endl; - - // Open the slave pseudoterminal - slave_fd = open(slave_name, O_RDWR); - if (slave_fd == -1) { - std::cerr << "Error opening slave PTY: " << strerror(errno) << std::endl; - close(master_fd); - return 1; - } - - // Set up the socket - sock_fd = socket(AF_INET, SOCK_STREAM, 0); - if (sock_fd == -1) { - std::cerr << "Error creating socket: " << strerror(errno) << std::endl; - close(slave_fd); - close(master_fd); - return 1; - } - - memset(&server_addr, 0, sizeof(server_addr)); - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(server_port); - if (inet_pton(AF_INET, server_ip, &server_addr.sin_addr) <= 0) { - std::cerr << "Invalid address/ Address not supported" << std::endl; - close(sock_fd); - close(slave_fd); - close(master_fd); - return 1; - } - - if (connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { - std::cerr << "Connection Failed: " << strerror(errno) << std::endl; - close(sock_fd); - close(slave_fd); - close(master_fd); - return 1; - } - - std::cout << "Connected to server at " << server_ip << ":" << server_port << std::endl; - - // Communication loop - fd_set read_fds; - char buffer[256]; - int max_fd = std::max(master_fd, sock_fd) + 1; - while (true) { - FD_ZERO(&read_fds); - FD_SET(master_fd, &read_fds); - FD_SET(sock_fd, &read_fds); - - int activity = select(max_fd, &read_fds, NULL, NULL, NULL); - - if ((activity < 0) && (errno != EINTR)) { - std::cerr << "Select error: " << strerror(errno) << std::endl; - break; - } - - if (FD_ISSET(master_fd, &read_fds)) { - ssize_t bytes_read = read(master_fd, buffer, sizeof(buffer) - 1); - if (bytes_read > 0) { - buffer[bytes_read] = '\0'; - std::cout << "From PTY: " << buffer; - send(sock_fd, buffer, bytes_read, 0); // Send to network - } else if (bytes_read == 0) { - std::cout << "PTY closed." << std::endl; - break; - } else { - std::cerr << "Error reading from PTY: " << strerror(errno) << std::endl; - } - } - - if (FD_ISSET(sock_fd, &read_fds)) { - ssize_t bytes_read = recv(sock_fd, buffer, sizeof(buffer) - 1, 0); - if (bytes_read > 0) { - buffer[bytes_read] = '\0'; - std::cout << "From Server: " << buffer; - write(master_fd, buffer, bytes_read); // Send back to PTY - } else if (bytes_read == 0) { - std::cout << "Server closed connection." << std::endl; - break; - } else { - std::cerr << "Error reading from socket: " << strerror(errno) << std::endl; - } - } - } - - close(sock_fd); - close(slave_fd); - close(master_fd); - return 0; -} \ No newline at end of file diff --git a/src/separate_main.cpp b/src/separate_main.cpp deleted file mode 100644 index ab28c60..0000000 --- a/src/separate_main.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include "VirtualSerialPort.h" -#include - -int main() { - try { - boost::asio::io_context io_context; - std::string device = "ttyUSB9"; // Adjust the device name as needed - - // Instantiate your VirtualSerialPort - VirtualSerialPort vsp(io_context, device); - - // Prepare a message to send - std::string test_message = "Hello, Virtual Serial Port!"; - boost::asio::const_buffer write_buffer = boost::asio::buffer(test_message); - - // Function to handle write completion - auto write_handler = [](const boost::system::error_code& ec, std::size_t bytes_transferred) { - std::cout << "Write completed. Bytes transferred: " << bytes_transferred << std::endl; - if (ec) { - std::cerr << "Error on write: " << ec.message() << std::endl; - } - }; - - // Write to the virtual serial port - vsp.async_write(write_buffer, write_handler); - - // Prepare a buffer for reading - std::array read_buffer; - boost::asio::mutable_buffer mutable_buffer = boost::asio::buffer(read_buffer); - - // Function to handle read completion - auto read_handler = [&read_buffer](const boost::system::error_code& ec, std::size_t bytes_transferred) { - std::cout << "Read completed. Bytes transferred: " << bytes_transferred << std::endl; - if (!ec) { - std::cout << "Received: " << std::string(read_buffer.begin(), read_buffer.begin() + bytes_transferred) << std::endl; - } else { - std::cerr << "Error on read: " << ec.message() << std::endl; - } - }; - - // Read from the virtual serial port - vsp.async_read(mutable_buffer, read_handler); - - // Run the io_context to perform asynchronous operations - io_context.run(); - - } catch (const std::exception& e) { - std::cerr << "Exception: " << e.what() << std::endl; - return 1; - } - - return 0; -} diff --git a/src/yet-another-client.cpp b/src/yet-another-client.cpp deleted file mode 100644 index 114da9b..0000000 --- a/src/yet-another-client.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class PTYSimulator { -public: - int master_fd, slave_fd; - char* slave_name; - - PTYSimulator() : master_fd(-1), slave_fd(-1), slave_name(nullptr) {} - - ~PTYSimulator() { - close(slave_fd); - close(master_fd); - } - - bool setup() { - master_fd = posix_openpt(O_RDWR | O_NOCTTY); - if (master_fd == -1 || grantpt(master_fd) == -1 || unlockpt(master_fd) == -1 || (slave_name = ptsname(master_fd)) == nullptr) { - std::cerr << "Failed to initialize PTY: " << strerror(errno) << std::endl; - return false; - } - - std::cout << "Slave PTY name: " << slave_name << std::endl; - - // Attempt to create a symbolic link from slave_name to "/dev/ttyUSB0" - if (symlink(slave_name, "/dev/ttyUSB0") == -1) { - std::cerr << "Failed to create symlink for PTY slave: " << strerror(errno) << std::endl; - return false; - } - - std::cout << "Symlink for PTY slave created successfully" << std::endl; - - slave_fd = open(slave_name, O_RDWR); - if (slave_fd == -1) { - std::cerr << "Error opening slave PTY: " << strerror(errno) << std::endl; - return false; - } - - return true; - } - - ssize_t readFromPTY(char* buffer, size_t bufferSize) { - return read(master_fd, buffer, bufferSize); - } - - void writeToPTY(const char* buffer, size_t bufferSize) { - write(master_fd, buffer, bufferSize); - } -}; - -class SocketClient { - struct sockaddr_in server_addr; - -public: - int sock_fd; - SocketClient() : sock_fd(-1) { - memset(&server_addr, 0, sizeof(server_addr)); - } - - ~SocketClient() { - close(sock_fd); - } - - bool connectToServer(const char* server_ip, int server_port) { - sock_fd = socket(AF_INET, SOCK_STREAM, 0); - if (sock_fd == -1) { - std::cerr << "Error creating socket: " << strerror(errno) << std::endl; - return false; - } - - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(server_port); - if (inet_pton(AF_INET, server_ip, &server_addr.sin_addr) <= 0) { - std::cerr << "Invalid address/ Address not supported" << std::endl; - return false; - } - - if (::connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { - std::cerr << "Connection Failed: " << strerror(errno) << std::endl; - return false; - } - - std::cout << "Connected to server at " << server_ip << ":" << server_port << std::endl; - return true; - } - - ssize_t sendToServer(const char* buffer, size_t bufferSize) { - return send(sock_fd, buffer, bufferSize, 0); - } - - ssize_t receiveFromServer(char* buffer, size_t bufferSize) { - return recv(sock_fd, buffer, bufferSize, 0); - } -}; - -int main() { - PTYSimulator pty; - SocketClient socketClient; - - if (!pty.setup() || !socketClient.connectToServer("192.168.1.29", 3333)) { - return 1; - } - - fd_set read_fds; - char buffer[256]; - int max_fd = std::max(pty.master_fd, socketClient.sock_fd) + 1; - - while (true) { - FD_ZERO(&read_fds); - FD_SET(pty.master_fd, &read_fds); - FD_SET(socketClient.sock_fd, &read_fds); - - if (select(max_fd, &read_fds, NULL, NULL, NULL) < 0 && errno != EINTR) { - std::cerr << "Select error: " << strerror(errno) << std::endl; - break; - } - - if (FD_ISSET(pty.master_fd, &read_fds)) { - ssize_t bytes_read = pty.readFromPTY(buffer, sizeof(buffer) - 1); - if (bytes_read > 0) { - buffer[bytes_read] = '\0'; - std::cout << "From PTY: " << buffer; - socketClient.sendToServer(buffer, bytes_read); - } else if (bytes_read == 0) { - std::cout << "PTY closed." << std::endl; - break; - } else { - std::cerr << "Error reading from PTY: " << strerror(errno) << std::endl; - } - } - - if (FD_ISSET(socketClient.sock_fd, &read_fds)) { - ssize_t bytes_read = socketClient.receiveFromServer(buffer, sizeof(buffer) - 1); - if (bytes_read > 0) { - buffer[bytes_read] = '\0'; - std::cout << "From Server: " << buffer; - pty.writeToPTY(buffer, bytes_read); - } else if (bytes_read == 0) { - std::cout << "Server closed connection." << std::endl; - break; - } else { - std::cerr << "Error reading from socket: " << strerror(errno) << std::endl; - } - } - } - - return 0; -} From aea675cdebd5f56fe876ae839c37b23be0b0eb02 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Thu, 2 May 2024 00:35:16 +0200 Subject: [PATCH 05/31] Remove one streamDescriptor usage --- include/VirtualSerialPort.h | 3 +-- src/SerialClient.cpp | 6 +++--- src/VirtualSerialPort.cpp | 24 ++++++++++-------------- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/include/VirtualSerialPort.h b/include/VirtualSerialPort.h index a094e8d..92b47ef 100644 --- a/include/VirtualSerialPort.h +++ b/include/VirtualSerialPort.h @@ -6,14 +6,13 @@ class VirtualSerialPort { public: - boost::asio::posix::stream_descriptor master_fd_; + int master_fd_raw_; VirtualSerialPort(boost::asio::io_context& io_context, const std::string& device); ~VirtualSerialPort(); ssize_t async_read(char* buffer, unsigned int length); ssize_t async_write(const char* buffer, unsigned int length); - void close(); private: boost::asio::posix::stream_descriptor slave_fd_; diff --git a/src/SerialClient.cpp b/src/SerialClient.cpp index b725282..b5bb73c 100644 --- a/src/SerialClient.cpp +++ b/src/SerialClient.cpp @@ -20,11 +20,11 @@ SerialClient::SerialClient(boost::asio::io_service& io_service, const std::strin void SerialClient::run() { fd_set read_fds; char buffer[256]; - int max_fd = std::max(vsp_.master_fd_.native_handle(), socketClient_.sock_fd) + 1; + int max_fd = std::max(vsp_.master_fd_raw_, socketClient_.sock_fd) + 1; while (true) { FD_ZERO(&read_fds); - FD_SET(vsp_.master_fd_.native_handle(), &read_fds); + FD_SET(vsp_.master_fd_raw_, &read_fds); FD_SET(socketClient_.sock_fd, &read_fds); if (select(max_fd, &read_fds, NULL, NULL, NULL) < 0 && errno != EINTR) { @@ -32,7 +32,7 @@ void SerialClient::run() { break; } - if (FD_ISSET(vsp_.master_fd_.native_handle(), &read_fds)) { + if (FD_ISSET(vsp_.master_fd_raw_, &read_fds)) { ssize_t bytes_read = vsp_.async_read(buffer, sizeof(buffer) - 1); if (bytes_read > 0) { buffer[bytes_read] = '\0'; diff --git a/src/VirtualSerialPort.cpp b/src/VirtualSerialPort.cpp index 5843584..5068c77 100644 --- a/src/VirtualSerialPort.cpp +++ b/src/VirtualSerialPort.cpp @@ -1,18 +1,18 @@ #include "VirtualSerialPort.h" VirtualSerialPort::VirtualSerialPort(boost::asio::io_context& io_context, const std::string& device) - : master_fd_(io_context), slave_fd_(io_context), device_name_("/dev/" + device) { + : slave_fd_(io_context), device_name_("/dev/" + device) { std::lock_guard lock(mutex_); - int master_fd, slave_fd; + int slave_fd; char* slave_name; - master_fd = posix_openpt(O_RDWR | O_NOCTTY); - if (master_fd == -1) { + master_fd_raw_ = posix_openpt(O_RDWR | O_NOCTTY); + if (master_fd_raw_ == -1) { Logger(Logger::Level::Error) << "Failed to open PTY master: " << strerror(errno); throw std::runtime_error("Failed to open PTY master"); } Logger(Logger::Level::Info) << "PTY master opened successfully"; - if (grantpt(master_fd) == -1 || unlockpt(master_fd) == -1 || (slave_name = ptsname(master_fd)) == nullptr) { + if (grantpt(master_fd_raw_) == -1 || unlockpt(master_fd_raw_) == -1 || (slave_name = ptsname(master_fd_raw_)) == nullptr) { Logger(Logger::Level::Error) << "Failed to grant or unlock PTY: " << strerror(errno); throw std::runtime_error("Failed to grant or unlock PTY"); } @@ -43,9 +43,8 @@ VirtualSerialPort::VirtualSerialPort(boost::asio::io_context& io_context, const } Logger(Logger::Level::Info) << "Group changed successfully for the device"; - master_fd_.assign(master_fd); slave_fd_.assign(slave_fd); - setup_pty(master_fd); + setup_pty(master_fd_raw_); setup_pty(slave_fd); } @@ -76,25 +75,22 @@ void VirtualSerialPort::setup_pty(int fd) { } } -void VirtualSerialPort::close() { - master_fd_.close(); +VirtualSerialPort::~VirtualSerialPort() { + close(master_fd_raw_); slave_fd_.close(); unlink(device_name_.c_str()); -} -VirtualSerialPort::~VirtualSerialPort() { - close(); } ssize_t VirtualSerialPort::async_read(char* buffer, unsigned int length) { Logger(Logger::Level::Info) << "VSP::async_read"; - ssize_t bytes_read = read(master_fd_.native_handle(), buffer, length); + ssize_t bytes_read = read(master_fd_raw_, buffer, length); Logger(Logger::Level::Info) << "READ FROM SERIAL!!!! -> "; return bytes_read; } ssize_t VirtualSerialPort::async_write(const char* buffer, unsigned int length) { - return write(master_fd_.native_handle(), buffer, length); + return write(master_fd_raw_, buffer, length); } From 28c1c9095439bc3a3bebd72d2e466b6303474850 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Thu, 2 May 2024 00:37:45 +0200 Subject: [PATCH 06/31] Change another descriptor to plain integer --- include/VirtualSerialPort.h | 2 +- src/VirtualSerialPort.cpp | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/include/VirtualSerialPort.h b/include/VirtualSerialPort.h index 92b47ef..cd6331e 100644 --- a/include/VirtualSerialPort.h +++ b/include/VirtualSerialPort.h @@ -15,7 +15,7 @@ class VirtualSerialPort { ssize_t async_write(const char* buffer, unsigned int length); private: - boost::asio::posix::stream_descriptor slave_fd_; + int slave_fd_raw_; // boost::array buffer_; // std::array read_buffer_; std::string device_name_; diff --git a/src/VirtualSerialPort.cpp b/src/VirtualSerialPort.cpp index 5068c77..6bce434 100644 --- a/src/VirtualSerialPort.cpp +++ b/src/VirtualSerialPort.cpp @@ -1,9 +1,8 @@ #include "VirtualSerialPort.h" VirtualSerialPort::VirtualSerialPort(boost::asio::io_context& io_context, const std::string& device) - : slave_fd_(io_context), device_name_("/dev/" + device) { + : device_name_("/dev/" + device) { std::lock_guard lock(mutex_); - int slave_fd; char* slave_name; master_fd_raw_ = posix_openpt(O_RDWR | O_NOCTTY); if (master_fd_raw_ == -1) { @@ -27,14 +26,12 @@ VirtualSerialPort::VirtualSerialPort(boost::asio::io_context& io_context, const Logger(Logger::Level::Info) << "Symlink for PTY slave created successfully"; // Open the slave pseudoterminal - slave_fd = open(slave_name, O_RDWR); - if (slave_fd == -1) { + slave_fd_raw_ = open(slave_name, O_RDWR); + if (slave_fd_raw_ == -1) { Logger(Logger::Level::Error) << "Failed to create symlink for PTY slave: " << strerror(errno); throw std::runtime_error("Failed to open the slave pseudoterminal"); } - - chmod(device_name_.c_str(), 0660); struct group* tty_grp = getgrnam("tty"); if (tty_grp && chown(device_name_.c_str(), -1, tty_grp->gr_gid) == -1) { @@ -43,9 +40,8 @@ VirtualSerialPort::VirtualSerialPort(boost::asio::io_context& io_context, const } Logger(Logger::Level::Info) << "Group changed successfully for the device"; - slave_fd_.assign(slave_fd); setup_pty(master_fd_raw_); - setup_pty(slave_fd); + setup_pty(slave_fd_raw_); } void VirtualSerialPort::setup_pty(int fd) { @@ -77,7 +73,7 @@ void VirtualSerialPort::setup_pty(int fd) { VirtualSerialPort::~VirtualSerialPort() { close(master_fd_raw_); - slave_fd_.close(); + close(slave_fd_raw_); unlink(device_name_.c_str()); } From e545affeac23b12f80068a5eaad7c703a94f87f5 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Thu, 2 May 2024 00:42:20 +0200 Subject: [PATCH 07/31] Cleanup boost lib usage from client --- include/SerialClient.h | 4 +--- include/VirtualSerialPort.h | 4 +--- src/SerialClient.cpp | 7 ++----- src/VirtualSerialPort.cpp | 2 +- src/main.cpp | 2 +- 5 files changed, 6 insertions(+), 13 deletions(-) diff --git a/include/SerialClient.h b/include/SerialClient.h index f8e5933..2f6cb4c 100644 --- a/include/SerialClient.h +++ b/include/SerialClient.h @@ -5,8 +5,6 @@ #include "VirtualSerialPort.h" #include "SocketClient.h" -using namespace boost::asio; -using ip::tcp; using std::string; class SerialClient { @@ -15,7 +13,7 @@ class SerialClient { VirtualSerialPort vsp_; public: - SerialClient(boost::asio::io_service& io_service, const std::string& server_ip, unsigned short server_port, const std::string& vsp_name); + SerialClient(const std::string& server_ip, unsigned short server_port, const std::string& vsp_name); SocketClient socketClient_; void run(); }; diff --git a/include/VirtualSerialPort.h b/include/VirtualSerialPort.h index cd6331e..03d1cdb 100644 --- a/include/VirtualSerialPort.h +++ b/include/VirtualSerialPort.h @@ -8,7 +8,7 @@ class VirtualSerialPort { public: int master_fd_raw_; - VirtualSerialPort(boost::asio::io_context& io_context, const std::string& device); + VirtualSerialPort(const std::string& device); ~VirtualSerialPort(); ssize_t async_read(char* buffer, unsigned int length); @@ -16,8 +16,6 @@ class VirtualSerialPort { private: int slave_fd_raw_; - // boost::array buffer_; - // std::array read_buffer_; std::string device_name_; std::mutex mutex_; diff --git a/src/SerialClient.cpp b/src/SerialClient.cpp index b5bb73c..73f1f8f 100644 --- a/src/SerialClient.cpp +++ b/src/SerialClient.cpp @@ -1,15 +1,12 @@ #include "SerialClient.h" -using namespace boost::asio; -using namespace boost::program_options; -using ip::tcp; using std::string; using std::cout; using std::cerr; using std::endl; -SerialClient::SerialClient(boost::asio::io_service& io_service, const std::string& server_ip, unsigned short server_port, const std::string& vsp_name) - : vsp_(io_service, vsp_name) { +SerialClient::SerialClient(const std::string& server_ip, unsigned short server_port, const std::string& vsp_name) + : vsp_(vsp_name) { Logger(Logger::Level::Info) << "Initializing client..."; Logger(Logger::Level::Info) << "Connecting to server at " << server_ip << ":" << server_port; socketClient_.connectToServer(server_ip.c_str(), server_port); diff --git a/src/VirtualSerialPort.cpp b/src/VirtualSerialPort.cpp index 6bce434..94a0239 100644 --- a/src/VirtualSerialPort.cpp +++ b/src/VirtualSerialPort.cpp @@ -1,6 +1,6 @@ #include "VirtualSerialPort.h" -VirtualSerialPort::VirtualSerialPort(boost::asio::io_context& io_context, const std::string& device) +VirtualSerialPort::VirtualSerialPort(const std::string& device) : device_name_("/dev/" + device) { std::lock_guard lock(mutex_); char* slave_name; diff --git a/src/main.cpp b/src/main.cpp index 46e1b0e..e469474 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,7 +20,7 @@ void setup_and_run_server(io_service& io, const variables_map& vm) { } void setup_and_run_client(io_service& io, const variables_map& vm) { - SerialClient client(io, vm["server"].as(), vm["port"].as(), vm["vsp"].as()); + SerialClient client(vm["server"].as(), vm["port"].as(), vm["vsp"].as()); client.run(); } From 4980cb5dd406fb42a213adc845ff93448249ef9f Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Thu, 2 May 2024 00:48:53 +0200 Subject: [PATCH 08/31] Cleanup vsp implementation --- src/VirtualSerialPort.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/VirtualSerialPort.cpp b/src/VirtualSerialPort.cpp index 94a0239..2410a8c 100644 --- a/src/VirtualSerialPort.cpp +++ b/src/VirtualSerialPort.cpp @@ -79,14 +79,13 @@ VirtualSerialPort::~VirtualSerialPort() { } ssize_t VirtualSerialPort::async_read(char* buffer, unsigned int length) { - Logger(Logger::Level::Info) << "VSP::async_read"; - ssize_t bytes_read = read(master_fd_raw_, buffer, length); - Logger(Logger::Level::Info) << "READ FROM SERIAL!!!! -> "; - return bytes_read; + // Logger(Logger::Level::Info) << "VSP::async_read"; + return read(master_fd_raw_, buffer, length); } ssize_t VirtualSerialPort::async_write(const char* buffer, unsigned int length) { + // Logger(Logger::Level::Info) << "VSP::async_write"; return write(master_fd_raw_, buffer, length); } From a8eaa1a6254f9bea9c8053e91bb5b5577a0e63d9 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Thu, 2 May 2024 01:34:22 +0200 Subject: [PATCH 09/31] Drop dependency on boost --- .github/workflows/release.yml | 20 +++--- .github/workflows/test.yml | 26 ++++---- CMakeLists.txt | 18 +++--- Dockerfile | 14 +---- README.md | 1 - include/ISerialPort.h | 10 ++- include/RealSerialPort.h | 55 +++++----------- include/SerialServer.h | 24 +++---- include/VirtualSerialPort.h | 1 + include/common.hpp | 4 -- src/RealSerialPort.cpp | 69 ++++++++++++++++++++ src/SerialServer.cpp | 114 ++++++++++++++++++---------------- src/main.cpp | 78 ++++++++++++----------- 13 files changed, 236 insertions(+), 198 deletions(-) create mode 100644 src/RealSerialPort.cpp diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 65e6d5b..abdca54 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,16 +31,16 @@ jobs: with: python-version: '3.x' - - name: Install dependencies (Ubuntu) - if: startsWith(matrix.config.os, 'ubuntu') - run: | - sudo apt-get update - sudo apt-get install -y libboost-all-dev - - - name: Install dependencies (macOS) - if: startsWith(matrix.config.os, 'macos') - run: | - brew install boost + # - name: Install dependencies (Ubuntu) + # if: startsWith(matrix.config.os, 'ubuntu') + # run: | + # sudo apt-get update + # sudo apt-get install -y libboost-all-dev + + # - name: Install dependencies (macOS) + # if: startsWith(matrix.config.os, 'macos') + # run: | + # brew install boost - name: Install dependencies (Windows) if: startsWith(matrix.config.os, 'windows') diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fa58b5f..f7a01ea 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,21 +29,21 @@ jobs: with: python-version: '3.x' - - name: Install dependencies (Ubuntu) - if: startsWith(matrix.config.os, 'ubuntu') - run: | - sudo apt-get update - sudo apt-get install -y libboost-all-dev + # - name: Install dependencies (Ubuntu) + # if: startsWith(matrix.config.os, 'ubuntu') + # run: | + # sudo apt-get update + # sudo apt-get install -y libboost-all-dev - - name: Install dependencies (macOS) - if: startsWith(matrix.config.os, 'macos') - run: | - brew install boost + # - name: Install dependencies (macOS) + # if: startsWith(matrix.config.os, 'macos') + # run: | + # brew install boost - - name: Install dependencies (Windows) - if: startsWith(matrix.config.os, 'windows') - run: | - choco install boost-msvc-14.2 + # - name: Install dependencies (Windows) + # if: startsWith(matrix.config.os, 'windows') + # run: | + # choco install boost-msvc-14.2 - name: Set up CMake (All platforms) uses: lukka/get-cmake@latest diff --git a/CMakeLists.txt b/CMakeLists.txt index a64393b..26d60c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,9 +4,6 @@ project(SerialNetworkBridge LANGUAGES CXX) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) -# Find Boost libraries -find_package(Boost 1.65 REQUIRED COMPONENTS system program_options log_setup log date_time) - include(FetchContent) FetchContent_Declare( googletest @@ -24,14 +21,15 @@ endif() include_directories(${CMAKE_SOURCE_DIR}/include) # Create core library without Logger.cpp, which is now in the logging library -add_library(core_lib src/Logger.cpp src/SerialServer.cpp src/SerialClient.cpp src/VirtualSerialPort.cpp) +add_library(core_lib + src/Logger.cpp + src/RealSerialPort.cpp + src/SerialServer.cpp + src/SerialClient.cpp + src/VirtualSerialPort.cpp +) target_include_directories(core_lib PUBLIC ${CMAKE_SOURCE_DIR}/include) target_link_libraries(core_lib PUBLIC - Boost::system - Boost::program_options - Boost::log - Boost::log_setup - Boost::date_time pthread ) @@ -39,6 +37,4 @@ target_link_libraries(core_lib PUBLIC add_executable(ser2net2ser src/main.cpp) target_link_libraries(ser2net2ser PRIVATE core_lib - Boost::system - Boost::program_options ) diff --git a/Dockerfile b/Dockerfile index de100ca..f2946b6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,11 +6,7 @@ WORKDIR /app # Install build dependencies RUN apt-get update && apt-get install -y \ g++ \ - cmake \ - libboost-system-dev \ - libboost-program-options-dev \ - libboost-log-dev \ - libboost-date-time-dev + cmake # Copy source code COPY . /app @@ -23,14 +19,6 @@ FROM ubuntu:20.04 WORKDIR /app -# Install runtime dependencies only -RUN apt-get update && apt-get install -y \ - libboost-system1.71.0 \ - libboost-program-options1.71.0 \ - libboost-log1.71.0 \ - libboost-date-time1.71.0 && \ - rm -rf /var/lib/apt/lists/* - # Copy binaries from the builder stage COPY --from=builder /app/ser2net2ser /usr/local/bin/ser2net2ser diff --git a/README.md b/README.md index f9ed2c2..f32be8a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ ## Requirements - Linux or macOS operating system -- Boost libraries (system, program_options, log_setup, log, date_time) - CMake for building the project - Docker (optional) for containerization diff --git a/include/ISerialPort.h b/include/ISerialPort.h index 1777a15..5c1534e 100644 --- a/include/ISerialPort.h +++ b/include/ISerialPort.h @@ -2,17 +2,15 @@ #define ISERIALPORT_H #include -#include +#include -using namespace boost::asio; using std::string; class ISerialPort { public: - virtual void open(const string& device, boost::asio::serial_port_base::baud_rate baudRate) = 0; - // virtual void set_option(const serial_port_base::baud_rate& option) = 0; - virtual void async_read_some(const boost::asio::mutable_buffer& buffer, std::function handler) = 0; - virtual void async_write(const boost::asio::const_buffer& buffer, std::function handler) = 0; + virtual void open(const string& device, unsigned int baudRate) = 0; + virtual ssize_t async_read_some(char* buffer, size_t size) = 0; + virtual ssize_t async_write(const char* buffer, size_t size) = 0; virtual ~ISerialPort() = default; }; diff --git a/include/RealSerialPort.h b/include/RealSerialPort.h index 5e30673..1725f7a 100644 --- a/include/RealSerialPort.h +++ b/include/RealSerialPort.h @@ -3,52 +3,27 @@ #include "ISerialPort.h" #include "Logger.h" -#include - -using boost::asio::serial_port_base; +#include +#include +#include +#include +#include +#include +#include +#include class RealSerialPort : public ISerialPort { public: - explicit RealSerialPort(boost::asio::io_service& io) : port(io) {} - - void open(const std::string& device, serial_port_base::baud_rate baudRate) override { - Logger(Logger::Level::Info) << "Setting up connection to serial port " << device; - try { - port.open(device); - setSerialOptions(baudRate); - } catch (const boost::system::system_error& e) { - Logger(Logger::Level::Error) << "Failed to open serial port: " << e.what(); - } - } - - void setSerialOptions(serial_port_base::baud_rate baudRate) { - Logger(Logger::Level::Info) << "Setting connection options."; - port.set_option(baudRate); - port.set_option(serial_port_base::character_size(8)); - port.set_option(serial_port_base::parity(serial_port_base::parity::none)); - port.set_option(serial_port_base::stop_bits(serial_port_base::stop_bits::one)); - port.set_option(serial_port_base::flow_control(serial_port_base::flow_control::none)); - } - - void async_read_some(const boost::asio::mutable_buffer& buffer, std::function handler) override { - if (!port.is_open()) { - Logger(Logger::Level::Error) << "Attempt to read from a closed serial port."; - return; - } - port.async_read_some(buffer, handler); - } + explicit RealSerialPort(const std::string& device, unsigned int baudRate); + ~RealSerialPort(); - void async_write(const boost::asio::const_buffer& buffer, std::function handler) override { - Logger(Logger::Level::Info) << "write some some."; - if (!port.is_open()) { - Logger(Logger::Level::Error) << "Attempt to write to a closed serial port."; - return; - } - boost::asio::async_write(port, buffer, handler); - } + void open(const std::string& device, unsigned int baudRate) override; + ssize_t async_read_some(char* buffer, size_t size) override; + ssize_t async_write(const char* buffer, size_t size) override; private: - boost::asio::serial_port port; + int fd; // File descriptor for the serial port + void configurePort(unsigned int baudRate); }; #endif // REALSERIALPORT_H diff --git a/include/SerialServer.h b/include/SerialServer.h index e640f49..b4efc10 100644 --- a/include/SerialServer.h +++ b/include/SerialServer.h @@ -2,26 +2,28 @@ #define SERIALSERVER_H #include "RealSerialPort.h" -#include -#include +#include +#include +#include +#include class SerialServer { public: - SerialServer(boost::asio::io_service& io_service, const std::string& device, unsigned int baud_rate); + SerialServer(const std::string& device, unsigned int baudRate, unsigned int port); + ~SerialServer(); void run(); private: - void start_accept(); - void handle_session(); - void async_read_socket(); - void async_read_serial(); - - boost::asio::io_service& io_service_; - boost::asio::ip::tcp::acceptor acceptor_; - boost::asio::ip::tcp::socket socket_; + int server_sock; + int client_sock; RealSerialPort serial_port_; std::array buffer_; + + void start_accept(); + void handle_session(int client_sock); + void async_read_socket(int client_sock); + void async_read_serial(int client_sock); }; #endif // SERIALSERVER_H diff --git a/include/VirtualSerialPort.h b/include/VirtualSerialPort.h index 03d1cdb..69979c9 100644 --- a/include/VirtualSerialPort.h +++ b/include/VirtualSerialPort.h @@ -3,6 +3,7 @@ #include "common.hpp" #include +#include class VirtualSerialPort { public: diff --git a/include/common.hpp b/include/common.hpp index 71485a9..1f98fc3 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -8,10 +8,6 @@ #include #include -#include -#include -#include - #include "Logger.h" #endif // COMMON_HPP diff --git a/src/RealSerialPort.cpp b/src/RealSerialPort.cpp new file mode 100644 index 0000000..c54a83c --- /dev/null +++ b/src/RealSerialPort.cpp @@ -0,0 +1,69 @@ +#include "RealSerialPort.h" + +RealSerialPort::RealSerialPort(const std::string& device, unsigned int baudRate) : fd(-1) { + open(device, baudRate); +} + +RealSerialPort::~RealSerialPort() { + if (fd != -1) { + close(fd); + } +} + +void RealSerialPort::open(const std::string& device, unsigned int baudRate) { + fd = ::open(device.c_str(), O_RDWR | O_NOCTTY | O_SYNC); + if (fd == -1) { + Logger(Logger::Level::Error) << "Failed to open serial port: " << device << " with error: " << strerror(errno); + throw std::runtime_error("Failed to open serial port"); + } + + configurePort(baudRate); + Logger(Logger::Level::Info) << "Serial port opened and configured on " << device; +} + +void RealSerialPort::configurePort(unsigned int baudRate) { + struct termios tty; + if (tcgetattr(fd, &tty) != 0) { + Logger(Logger::Level::Error) << "Error from tcgetattr: " << strerror(errno); + throw std::runtime_error("Error configuring serial port"); + } + + cfsetospeed(&tty, baudRate); + cfsetispeed(&tty, baudRate); + + tty.c_cflag |= (CLOCAL | CREAD); // Ignore modem controls, enable reading + tty.c_cflag &= ~CSIZE; + tty.c_cflag |= CS8; // 8-bit characters + tty.c_cflag &= ~PARENB; // No parity bit + tty.c_cflag &= ~CSTOPB; // Only need 1 stop bit + tty.c_cflag &= ~CRTSCTS; // No hardware flow control + + // Setup for non-canonical mode + tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + tty.c_oflag &= ~OPOST; + + tty.c_cc[VMIN] = 1; // Minimum number of characters to read + tty.c_cc[VTIME] = 1; // Time to wait for data (tenths of seconds) + + if (tcsetattr(fd, TCSANOW, &tty) != 0) { + Logger(Logger::Level::Error) << "Error from tcsetattr: " << strerror(errno); + throw std::runtime_error("Error applying serial port settings"); + } +} + +ssize_t RealSerialPort::async_read_some(char* buffer, size_t size) { + ssize_t n = read(fd, buffer, size); + if (n < 0) { + Logger(Logger::Level::Error) << "Read error on serial port: " << strerror(errno); + } + return n; +} + +ssize_t RealSerialPort::async_write(const char* buffer, size_t size) { + ssize_t n = write(fd, buffer, size); + if (n < 0) { + Logger(Logger::Level::Error) << "Write error on serial port: " << strerror(errno); + } + return n; +} diff --git a/src/SerialServer.cpp b/src/SerialServer.cpp index dabf8c8..bb3a5e7 100644 --- a/src/SerialServer.cpp +++ b/src/SerialServer.cpp @@ -1,71 +1,79 @@ #include "SerialServer.h" +#include +#include +#include +#include -SerialServer::SerialServer(boost::asio::io_service& io_service, const std::string& device, unsigned int baud_rate) - : io_service_(io_service), - acceptor_(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 3333)), - socket_(io_service), - serial_port_(io_service) { - serial_port_.open(device, boost::asio::serial_port_base::baud_rate(baud_rate)); +SerialServer::SerialServer(const std::string& device, unsigned int baud_rate, unsigned int port) + : serial_port_(device, baud_rate) { + struct sockaddr_in serv_addr; + + server_sock = socket(AF_INET, SOCK_STREAM, 0); + if (server_sock < 0) { + std::cerr << "ERROR opening socket"; + exit(1); + } + + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(port); + + if (bind(server_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + std::cerr << "ERROR on binding: " << strerror(errno); + exit(1); } + listen(server_sock, 5); +} + +SerialServer::~SerialServer() { + close(server_sock); +} + void SerialServer::run() { - Logger(Logger::Level::Info) << "SerialServer::run"; + std::cout << "SerialServer::run"; start_accept(); - Logger(Logger::Level::Info) << "ioservice::run"; - io_service_.run(); } void SerialServer::start_accept() { - acceptor_.async_accept(socket_, [this](boost::system::error_code ec) { - if (!ec) { - handle_session(); - } - start_accept(); - }); -} + struct sockaddr_in cli_addr; + socklen_t clilen = sizeof(cli_addr); -void SerialServer::handle_session() { - Logger(Logger::Level::Info) << "SerialServer::handle_session"; + client_sock = accept(server_sock, (struct sockaddr *)&cli_addr, &clilen); + if (client_sock < 0) { + std::cerr << "ERROR on accept: " << strerror(errno); + return; + } + handle_session(client_sock); +} - async_read_socket(); - async_read_serial(); +void SerialServer::handle_session(int client_sock) { + std::cout << "SerialServer::handle_session"; + async_read_socket(client_sock); + async_read_serial(client_sock); } -void SerialServer::async_read_socket() { - Logger(Logger::Level::Info) << "SerialServer::async_read_socket"; +void SerialServer::async_read_socket(int client_sock) { + std::cout << "SerialServer::async_read_socket"; + ssize_t length = read(client_sock, buffer_.data(), buffer_.size()); - socket_.async_read_some(boost::asio::buffer(buffer_), [this](boost::system::error_code ec, std::size_t length) { - if (!ec) { - serial_port_.async_write(boost::asio::buffer(buffer_, length), [this](boost::system::error_code ec, std::size_t) { - if (!ec) { - async_read_socket(); - } else { - Logger(Logger::Level::Error) << "Error writing to client: " << ec.message(); - } - }); - } else { - Logger(Logger::Level::Error) << "Read error on socket: " << ec.message(); - socket_.close(); - } - }); + if (length > 0) { + serial_port_.async_write(buffer_.data(), length); + } else if (length < 0) { + std::cerr << "Read error on socket: " << strerror(errno); + close(client_sock); + } } -void SerialServer::async_read_serial() { - // WIP: this works fine - // BOOST_LOG_TRIVIAL(info) << "SerialServer::async_read_serial"; +void SerialServer::async_read_serial(int client_sock) { + std::cout << "SerialServer::async_read_serial"; + ssize_t length = serial_port_.async_read_some(buffer_.data(), buffer_.size()); - serial_port_.async_read_some(boost::asio::buffer(buffer_), [this](boost::system::error_code ec, std::size_t length) { - if (!ec) { - boost::asio::async_write(socket_, boost::asio::buffer(buffer_, length), [this](boost::system::error_code ec, std::size_t) { - if (!ec) { - async_read_serial(); - } else { - Logger(Logger::Level::Error) << "Error sending to socket: " << ec.message(); - } - }); - } else { - Logger(Logger::Level::Error) << "Read error on serial port: " << ec.message(); - socket_.close(); - } - }); + if (length > 0) { + write(client_sock, buffer_.data(), length); + } else if (length < 0) { + std::cerr << "Read error on serial port: " << strerror(errno); + close(client_sock); + } } diff --git a/src/main.cpp b/src/main.cpp index e469474..43ad5a2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,26 +1,23 @@ #include -#include -#include +#include +#include #include "Logger.h" #include "SerialClient.h" #include "SerialServer.h" #include "RealSerialPort.h" -using namespace boost::asio; -using namespace boost::program_options; using std::string; using std::cout; using std::cerr; using std::endl; -void setup_and_run_server(io_service& io, const variables_map& vm) { - unsigned int baud_rate = vm["baud"].as(); // Get baud rate as unsigned int - SerialServer server(io, vm["device"].as(), baud_rate); +void setup_and_run_server(const string& device, unsigned int baud_rate, unsigned int port) { + SerialServer server(device, baud_rate, port); server.run(); } -void setup_and_run_client(io_service& io, const variables_map& vm) { - SerialClient client(vm["server"].as(), vm["port"].as(), vm["vsp"].as()); +void setup_and_run_client(const string& server_ip, unsigned short port, const string& vsp) { + SerialClient client(server_ip, port, vsp); client.run(); } @@ -31,44 +28,53 @@ int main(int argc, char* argv[]) { } string command = argv[1]; - io_service io; try { if (command == "serve") { - options_description serve_desc("Server options"); - serve_desc.add_options() - ("help,h", "produce help message") - ("device,d", value()->default_value("/dev/ttyUSB0"), "Device name") - ("baud,b", value()->default_value(9600), "Baud rate") - ("port,p", value()->default_value(12345), "Port number"); - variables_map vm; - store(parse_command_line(argc, argv, serve_desc), vm); + string device = "/dev/ttyUSB0"; + unsigned int baud = 9600; + unsigned int port = 12345; - if (vm.count("help")) { - cout << serve_desc << endl; - return 0; + for (int i = 2; i < argc; i += 2) { + string arg = argv[i]; + if (arg == "--device" || arg == "-d") { + if (i + 1 < argc) device = argv[i + 1]; + } else if (arg == "--baud" || arg == "-b") { + if (i + 1 < argc) baud = std::stoi(argv[i + 1]); + } else if (arg == "--port" || arg == "-p") { + if (i + 1 < argc) port = std::stoi(argv[i + 1]); + } else if (arg == "--help" || arg == "-h") { + cout << "Usage: ser2net2ser serve [--device ] [--baud ] [--port ]\n"; + return 0; + } } - notify(vm); - setup_and_run_server(io, vm); + setup_and_run_server(device, baud, port); } else if (command == "connect") { - options_description connect_desc("Client options"); - connect_desc.add_options() - ("help,h", "produce help message") - ("server,s", value()->default_value("127.0.0.1"), "Server IP address") - ("port,p", value()->default_value(12345), "Server port") - ("vsp,v", value()->required(), "Virtual serial port name"); - variables_map vm; - store(parse_command_line(argc, argv, connect_desc), vm); + string server_ip = "127.0.0.1"; + unsigned short port = 12345; + string vsp; - if (vm.count("help")) { - cout << connect_desc << endl; - return 0; + for (int i = 2; i < argc; i += 2) { + string arg = argv[i]; + if (arg == "--server" || arg == "-s") { + if (i + 1 < argc) server_ip = argv[i + 1]; + } else if (arg == "--port" || arg == "-p") { + if (i + 1 < argc) port = static_cast(std::stoi(argv[i + 1])); + } else if (arg == "--vsp" || arg == "-v") { + if (i + 1 < argc) vsp = argv[i + 1]; + } else if (arg == "--help" || arg == "-h") { + cout << "Usage: ser2net2ser connect [--server ] [--port ] --vsp \n"; + return 0; + } } + if (vsp.empty()) { + cerr << "Virtual serial port name must be specified with --vsp.\n"; + return 1; + } - notify(vm); - setup_and_run_client(io, vm); + setup_and_run_client(server_ip, port, vsp); } else { throw std::invalid_argument("Invalid command provided. Use 'serve' or 'connect'."); } From bbaf28dc23deaeb1a5a2ef7318c8d213e330854a Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Thu, 2 May 2024 01:42:59 +0200 Subject: [PATCH 10/31] Add missing import --- include/SerialServer.h | 1 + include/VirtualSerialPort.h | 1 + 2 files changed, 2 insertions(+) diff --git a/include/SerialServer.h b/include/SerialServer.h index b4efc10..38bf8ec 100644 --- a/include/SerialServer.h +++ b/include/SerialServer.h @@ -6,6 +6,7 @@ #include #include #include +#include class SerialServer { public: diff --git a/include/VirtualSerialPort.h b/include/VirtualSerialPort.h index 69979c9..86b5ac2 100644 --- a/include/VirtualSerialPort.h +++ b/include/VirtualSerialPort.h @@ -2,6 +2,7 @@ #define VIRTUALSERIALPORT_H #include "common.hpp" +#include #include #include From 2190ed0ff67503e59f1da7437501d7d5b807bbdd Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Thu, 2 May 2024 01:54:36 +0200 Subject: [PATCH 11/31] Update logs --- src/SerialServer.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/SerialServer.cpp b/src/SerialServer.cpp index bb3a5e7..81566c4 100644 --- a/src/SerialServer.cpp +++ b/src/SerialServer.cpp @@ -32,11 +32,12 @@ SerialServer::~SerialServer() { } void SerialServer::run() { - std::cout << "SerialServer::run"; + Logger(Logger::Level::Info) << "SerialServer::run"; start_accept(); } void SerialServer::start_accept() { + Logger(Logger::Level::Info) << "SerialServer::start_accept"; struct sockaddr_in cli_addr; socklen_t clilen = sizeof(cli_addr); @@ -49,13 +50,13 @@ void SerialServer::start_accept() { } void SerialServer::handle_session(int client_sock) { - std::cout << "SerialServer::handle_session"; + Logger(Logger::Level::Info) << "SerialServer::handle_session"; async_read_socket(client_sock); async_read_serial(client_sock); } void SerialServer::async_read_socket(int client_sock) { - std::cout << "SerialServer::async_read_socket"; + Logger(Logger::Level::Info) << "SerialServer::async_read_socket"; ssize_t length = read(client_sock, buffer_.data(), buffer_.size()); if (length > 0) { @@ -67,7 +68,7 @@ void SerialServer::async_read_socket(int client_sock) { } void SerialServer::async_read_serial(int client_sock) { - std::cout << "SerialServer::async_read_serial"; + Logger(Logger::Level::Info) << "SerialServer::async_read_serial"; ssize_t length = serial_port_.async_read_some(buffer_.data(), buffer_.size()); if (length > 0) { From 26c6c55d987c7fdbc66659ae8afadf5c2dfc4104 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Thu, 2 May 2024 02:05:17 +0200 Subject: [PATCH 12/31] Update logos --- include/SocketClient.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/SocketClient.h b/include/SocketClient.h index 5c2422d..39b631d 100644 --- a/include/SocketClient.h +++ b/include/SocketClient.h @@ -21,25 +21,26 @@ class SocketClient { } bool connectToServer(const char* server_ip, int server_port) { + Logger(Logger::Level::Info) << "Start connecting to socet server:" << server_ip << server_port; sock_fd = socket(AF_INET, SOCK_STREAM, 0); if (sock_fd == -1) { - std::cerr << "Error creating socket: " << strerror(errno) << std::endl; + Logger(Logger::Level::Error) << "Error creating socket: " << strerror(errno) << std::endl; return false; } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(server_port); if (inet_pton(AF_INET, server_ip, &server_addr.sin_addr) <= 0) { - std::cerr << "Invalid address/ Address not supported" << std::endl; + Logger(Logger::Level::Error) << "Invalid address/ Address not supported" << std::endl; return false; } if (::connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { - std::cerr << "Connection Failed: " << strerror(errno) << std::endl; + Logger(Logger::Level::Error) << "Connection Failed: " << strerror(errno) << std::endl; return false; } - std::cout << "Connected to server at " << server_ip << ":" << server_port << std::endl; + Logger(Logger::Level::Info) << "Connected to server at " << server_ip << ":" << server_port << std::endl; return true; } From b4e55d0f1b945b757f02dd8905de45f9c4842ff1 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Thu, 2 May 2024 02:07:19 +0200 Subject: [PATCH 13/31] Exit 1 --- include/SocketClient.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/SocketClient.h b/include/SocketClient.h index 39b631d..87c1b25 100644 --- a/include/SocketClient.h +++ b/include/SocketClient.h @@ -35,8 +35,9 @@ class SocketClient { return false; } - if (::connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + if (connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { Logger(Logger::Level::Error) << "Connection Failed: " << strerror(errno) << std::endl; + exit(1); return false; } From ced8509f85e8b70cca7fcd28acf46a53f84b83e0 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sat, 4 May 2024 11:19:15 +0200 Subject: [PATCH 14/31] Update readme a bit - check if TOC works on gh --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index f32be8a..9c798de 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,12 @@ # ser2net2ser +# Table of Contents +[[_TOC_]] + +## Motivation + +I've been using `socat` + `ser2net` for sharing serial devices over network for some time, mostly in my other project -> [kubeserial]. + ## Requirements - Linux or macOS operating system @@ -63,3 +70,7 @@ Dockerfiles for both the server and client are included. Build and run the conta ```bash make build-images ``` + + + +[kubeserial]: https://github.com/janekbaraniewski/kubeserial "KubeSerial" From f7f8dc1b434b5d7545dfdd9bccd54803249253bb Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sat, 4 May 2024 11:34:09 +0200 Subject: [PATCH 15/31] Update readme --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9c798de..e38bc9c 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,17 @@ # ser2net2ser -# Table of Contents -[[_TOC_]] +## Table of Contents + +1. [Motivation](#motivation) +2. [Requirements](#requirements) +3. [Building the project](#building-the-project) +4. [Running the server](#running-the-server) +5. [Running the client](#running-the-client) + ## Motivation -I've been using `socat` + `ser2net` for sharing serial devices over network for some time, mostly in my other project -> [kubeserial]. +I've been using `socat` + `ser2net` for sharing serial devices over network for some time, mainly in my other project -> [kubeserial]. I've run into few limitations so I created this project to recreate the behaviour of `socat` + `ser2net` and then solve connection issues I've been having. ## Requirements From b0cb2309888cbc803cfa9f754925fbecba4caa8c Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sat, 4 May 2024 11:34:23 +0200 Subject: [PATCH 16/31] Update readme --- README.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/README.md b/README.md index e38bc9c..a1b5811 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,5 @@ # ser2net2ser -## Table of Contents - -1. [Motivation](#motivation) -2. [Requirements](#requirements) -3. [Building the project](#building-the-project) -4. [Running the server](#running-the-server) -5. [Running the client](#running-the-client) - - ## Motivation I've been using `socat` + `ser2net` for sharing serial devices over network for some time, mainly in my other project -> [kubeserial]. I've run into few limitations so I created this project to recreate the behaviour of `socat` + `ser2net` and then solve connection issues I've been having. From f96944f0ab67ae65fa1468d9f5c3f0df064d85d6 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sun, 5 May 2024 14:40:46 +0200 Subject: [PATCH 17/31] Alternative implementation of server --- CMakeLists.txt | 2 ++ include/SerialPort.h | 17 ++++++++++ include/SerialServer.h | 16 ++++----- include/TCPServer.h | 24 ++++++++++++++ src/SerialPort.cpp | 54 ++++++++++++++++++++++++++++++ src/SerialServer.cpp | 74 +++++------------------------------------- src/TCPServer.cpp | 73 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 184 insertions(+), 76 deletions(-) create mode 100644 include/SerialPort.h create mode 100644 include/TCPServer.h create mode 100644 src/SerialPort.cpp create mode 100644 src/TCPServer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 26d60c0..8a4b2d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,8 @@ add_library(core_lib src/SerialServer.cpp src/SerialClient.cpp src/VirtualSerialPort.cpp + src/SerialPort.cpp + src/TCPServer.cpp ) target_include_directories(core_lib PUBLIC ${CMAKE_SOURCE_DIR}/include) target_link_libraries(core_lib PUBLIC diff --git a/include/SerialPort.h b/include/SerialPort.h new file mode 100644 index 0000000..c875f6e --- /dev/null +++ b/include/SerialPort.h @@ -0,0 +1,17 @@ +#ifndef SERIALPORT_H +#define SERIALPORT_H + +#include + +class SerialPort { +private: + int serial_fd; + +public: + SerialPort(const std::string& device, int baud_rate); + ~SerialPort(); + void writeData(const std::string& data); + std::string readData(); +}; + +#endif // SERIALPORT_H diff --git a/include/SerialServer.h b/include/SerialServer.h index 38bf8ec..9387655 100644 --- a/include/SerialServer.h +++ b/include/SerialServer.h @@ -1,13 +1,16 @@ #ifndef SERIALSERVER_H #define SERIALSERVER_H -#include "RealSerialPort.h" #include #include #include #include #include +#include "RealSerialPort.h" +#include "SerialPort.h" +#include "TCPServer.h" + class SerialServer { public: SerialServer(const std::string& device, unsigned int baudRate, unsigned int port); @@ -16,15 +19,8 @@ class SerialServer { void run(); private: - int server_sock; - int client_sock; - RealSerialPort serial_port_; - std::array buffer_; - - void start_accept(); - void handle_session(int client_sock); - void async_read_socket(int client_sock); - void async_read_serial(int client_sock); + SerialPort serial_port_; + TcpServer server_; }; #endif // SERIALSERVER_H diff --git a/include/TCPServer.h b/include/TCPServer.h new file mode 100644 index 0000000..0fc4494 --- /dev/null +++ b/include/TCPServer.h @@ -0,0 +1,24 @@ +#ifndef TCPSERVER_H +#define TCPSERVER_H + +#include "SerialPort.h" +#include + +class TcpServer { +private: + int server_fd_; + struct sockaddr_in address_; + int port_; + bool is_running_; + SerialPort& serial_; + + static void handleClient(int client_socket, SerialPort& serial); + +public: + TcpServer(int port, SerialPort& serial); + ~TcpServer(); + void run(); + void stop(); +}; + +#endif // TCPSERVER_H diff --git a/src/SerialPort.cpp b/src/SerialPort.cpp new file mode 100644 index 0000000..73bd063 --- /dev/null +++ b/src/SerialPort.cpp @@ -0,0 +1,54 @@ +#include "SerialPort.h" +#include +#include +#include +#include +#include + +SerialPort::SerialPort(const std::string& device, int baud_rate) { + serial_fd = open(device.c_str(), O_RDWR | O_NOCTTY | O_SYNC); + if (serial_fd < 0) { + throw std::runtime_error("Error opening serial port"); + } + + struct termios tty; + memset(&tty, 0, sizeof tty); + if (tcgetattr(serial_fd, &tty) != 0) { + throw std::runtime_error("Error from tcgetattr"); + } + + cfsetospeed(&tty, baud_rate); + cfsetispeed(&tty, baud_rate); + + tty.c_cflag |= (CLOCAL | CREAD); + tty.c_cflag &= ~CSIZE; + tty.c_cflag |= CS8; + tty.c_cflag &= ~PARENB; + tty.c_cflag &= ~CSTOPB; + tty.c_cflag &= ~CRTSCTS; + + tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + tty.c_oflag &= ~OPOST; + + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 1; + + if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) { + throw std::runtime_error("Error from tcsetattr"); + } +} + +SerialPort::~SerialPort() { + close(serial_fd); +} + +void SerialPort::writeData(const std::string& data) { + write(serial_fd, data.c_str(), data.size()); +} + +std::string SerialPort::readData() { + char buf[256]; + int n = read(serial_fd, buf, sizeof(buf)); + return std::string(buf, n); +} diff --git a/src/SerialServer.cpp b/src/SerialServer.cpp index 81566c4..cee3644 100644 --- a/src/SerialServer.cpp +++ b/src/SerialServer.cpp @@ -1,80 +1,22 @@ -#include "SerialServer.h" #include #include #include #include -SerialServer::SerialServer(const std::string& device, unsigned int baud_rate, unsigned int port) - : serial_port_(device, baud_rate) { - struct sockaddr_in serv_addr; - - server_sock = socket(AF_INET, SOCK_STREAM, 0); - if (server_sock < 0) { - std::cerr << "ERROR opening socket"; - exit(1); - } - - memset(&serv_addr, 0, sizeof(serv_addr)); - serv_addr.sin_family = AF_INET; - serv_addr.sin_addr.s_addr = INADDR_ANY; - serv_addr.sin_port = htons(port); - - if (bind(server_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { - std::cerr << "ERROR on binding: " << strerror(errno); - exit(1); - } +#include "SerialServer.h" - listen(server_sock, 5); -} +SerialServer::SerialServer(const std::string& device, unsigned int baud_rate, unsigned int port) + : serial_port_(device, baud_rate), server_(port, serial_port_) {} SerialServer::~SerialServer() { - close(server_sock); + server_.stop(); } void SerialServer::run() { Logger(Logger::Level::Info) << "SerialServer::run"; - start_accept(); -} - -void SerialServer::start_accept() { - Logger(Logger::Level::Info) << "SerialServer::start_accept"; - struct sockaddr_in cli_addr; - socklen_t clilen = sizeof(cli_addr); - - client_sock = accept(server_sock, (struct sockaddr *)&cli_addr, &clilen); - if (client_sock < 0) { - std::cerr << "ERROR on accept: " << strerror(errno); - return; - } - handle_session(client_sock); -} - -void SerialServer::handle_session(int client_sock) { - Logger(Logger::Level::Info) << "SerialServer::handle_session"; - async_read_socket(client_sock); - async_read_serial(client_sock); -} - -void SerialServer::async_read_socket(int client_sock) { - Logger(Logger::Level::Info) << "SerialServer::async_read_socket"; - ssize_t length = read(client_sock, buffer_.data(), buffer_.size()); - - if (length > 0) { - serial_port_.async_write(buffer_.data(), length); - } else if (length < 0) { - std::cerr << "Read error on socket: " << strerror(errno); - close(client_sock); - } -} - -void SerialServer::async_read_serial(int client_sock) { - Logger(Logger::Level::Info) << "SerialServer::async_read_serial"; - ssize_t length = serial_port_.async_read_some(buffer_.data(), buffer_.size()); - - if (length > 0) { - write(client_sock, buffer_.data(), length); - } else if (length < 0) { - std::cerr << "Read error on serial port: " << strerror(errno); - close(client_sock); + try { + server_.run(); + } catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; } } diff --git a/src/TCPServer.cpp b/src/TCPServer.cpp new file mode 100644 index 0000000..0d65407 --- /dev/null +++ b/src/TCPServer.cpp @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include + +#include "TCPServer.h" + +TcpServer::TcpServer(int port, SerialPort& serial) : port_(port), is_running_(false), serial_(serial) { + if ((server_fd_ = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + throw std::runtime_error("Socket creation failed"); + } + + int opt = 1; + if (setsockopt(server_fd_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { + throw std::runtime_error("Setsockopt failed"); + } + + address_.sin_family = AF_INET; + address_.sin_addr.s_addr = INADDR_ANY; + address_.sin_port = htons(port); + + if (bind(server_fd_, (struct sockaddr*)&address_, sizeof(address_)) < 0) { + throw std::runtime_error("Bind failed"); + } + + if (listen(server_fd_, 3) < 0) { + throw std::runtime_error("Listen failed"); + } +} + +TcpServer::~TcpServer() { + if (is_running_) { + stop(); + } +} + +void TcpServer::run() { + is_running_ = true; + while (is_running_) { + int addrlen = sizeof(address_); + int new_socket = accept(server_fd_, (struct sockaddr *)&address_, (socklen_t*)&addrlen); + if (new_socket < 0) { + throw std::runtime_error("Accept failed"); + } + std::thread clientThread(handleClient, new_socket, std::ref(serial_)); + clientThread.detach(); + } +} + +void TcpServer::stop() { + close(server_fd_); + is_running_ = false; +} + +void TcpServer::handleClient(int client_socket, SerialPort& serial) { + const int bufferSize = 1024; + char buffer[bufferSize]; + + while (true) { + memset(buffer, 0, bufferSize); + int read_size = read(client_socket, buffer, bufferSize - 1); + if (read_size <= 0) { + break; // Client disconnected or error + } + + serial.writeData(std::string(buffer, read_size)); + std::string response = serial.readData(); + write(client_socket, response.c_str(), response.size()); + } + + close(client_socket); +} From 54bb4424bfe3750a9c1d727dfd61942b9861772d Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sun, 5 May 2024 14:45:27 +0200 Subject: [PATCH 18/31] Fix log message --- include/SocketClient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/SocketClient.h b/include/SocketClient.h index 87c1b25..15eec3a 100644 --- a/include/SocketClient.h +++ b/include/SocketClient.h @@ -21,7 +21,7 @@ class SocketClient { } bool connectToServer(const char* server_ip, int server_port) { - Logger(Logger::Level::Info) << "Start connecting to socet server:" << server_ip << server_port; + Logger(Logger::Level::Info) << "Start connecting to socet server:" << server_ip << ":" << server_port; sock_fd = socket(AF_INET, SOCK_STREAM, 0); if (sock_fd == -1) { Logger(Logger::Level::Error) << "Error creating socket: " << strerror(errno) << std::endl; From a67b3ce487037e20f4371624b5f2ef7d8e54a09d Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sun, 5 May 2024 14:53:23 +0200 Subject: [PATCH 19/31] Update logging --- include/TCPServer.h | 1 + src/TCPServer.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/TCPServer.h b/include/TCPServer.h index 0fc4494..2c24e94 100644 --- a/include/TCPServer.h +++ b/include/TCPServer.h @@ -1,6 +1,7 @@ #ifndef TCPSERVER_H #define TCPSERVER_H +#include "Logger.h" #include "SerialPort.h" #include diff --git a/src/TCPServer.cpp b/src/TCPServer.cpp index 0d65407..482c6e1 100644 --- a/src/TCPServer.cpp +++ b/src/TCPServer.cpp @@ -7,6 +7,7 @@ #include "TCPServer.h" TcpServer::TcpServer(int port, SerialPort& serial) : port_(port), is_running_(false), serial_(serial) { + Logger(Logger::Level::Info) << "Init tcp server"; if ((server_fd_ = socket(AF_INET, SOCK_STREAM, 0)) == 0) { throw std::runtime_error("Socket creation failed"); } @@ -27,6 +28,7 @@ TcpServer::TcpServer(int port, SerialPort& serial) : port_(port), is_running_(fa if (listen(server_fd_, 3) < 0) { throw std::runtime_error("Listen failed"); } + Logger(Logger::Level::Info) << "Init tcp server finished"; } TcpServer::~TcpServer() { @@ -36,6 +38,7 @@ TcpServer::~TcpServer() { } void TcpServer::run() { + Logger(Logger::Level::Info) << "Start tcp server"; is_running_ = true; while (is_running_) { int addrlen = sizeof(address_); @@ -59,8 +62,10 @@ void TcpServer::handleClient(int client_socket, SerialPort& serial) { while (true) { memset(buffer, 0, bufferSize); + Logger(Logger::Level::Info) << "Reading client connection"; int read_size = read(client_socket, buffer, bufferSize - 1); if (read_size <= 0) { + Logger(Logger::Level::Info) << "Client disconnected or error"; break; // Client disconnected or error } From 9f1b7cc79bdba87fc5dd29b4376e28db239dd133 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sun, 5 May 2024 14:56:14 +0200 Subject: [PATCH 20/31] Update logging --- src/TCPServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TCPServer.cpp b/src/TCPServer.cpp index 482c6e1..045538f 100644 --- a/src/TCPServer.cpp +++ b/src/TCPServer.cpp @@ -7,7 +7,7 @@ #include "TCPServer.h" TcpServer::TcpServer(int port, SerialPort& serial) : port_(port), is_running_(false), serial_(serial) { - Logger(Logger::Level::Info) << "Init tcp server"; + Logger(Logger::Level::Info) << "Init tcp server on port " << port_; if ((server_fd_ = socket(AF_INET, SOCK_STREAM, 0)) == 0) { throw std::runtime_error("Socket creation failed"); } From e35e76592be63af20bba11f249b4a39810f3e696 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sun, 5 May 2024 15:06:39 +0200 Subject: [PATCH 21/31] Update logging --- src/TCPServer.cpp | 32 ++++++++-------- src/alternative_server_main.cpp | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 15 deletions(-) create mode 100644 src/alternative_server_main.cpp diff --git a/src/TCPServer.cpp b/src/TCPServer.cpp index 045538f..897e9f0 100644 --- a/src/TCPServer.cpp +++ b/src/TCPServer.cpp @@ -41,14 +41,18 @@ void TcpServer::run() { Logger(Logger::Level::Info) << "Start tcp server"; is_running_ = true; while (is_running_) { - int addrlen = sizeof(address_); - int new_socket = accept(server_fd_, (struct sockaddr *)&address_, (socklen_t*)&addrlen); - if (new_socket < 0) { - throw std::runtime_error("Accept failed"); + struct sockaddr_in clientAddr; + socklen_t clientLen = sizeof(clientAddr); + int clientSocket = accept(server_fd_, (struct sockaddr *) &clientAddr, &clientLen); + if (clientSocket < 0) { + Logger(Logger::Level::Info) << "Cannot accept connection"; + continue; } - std::thread clientThread(handleClient, new_socket, std::ref(serial_)); - clientThread.detach(); + + std::thread clientThread(handleClient, clientSocket); + clientThread.detach(); // Detach the thread to handle multiple clients } + } void TcpServer::stop() { @@ -57,19 +61,17 @@ void TcpServer::stop() { } void TcpServer::handleClient(int client_socket, SerialPort& serial) { - const int bufferSize = 1024; - char buffer[bufferSize]; - + char buffer[1024]; while (true) { - memset(buffer, 0, bufferSize); - Logger(Logger::Level::Info) << "Reading client connection"; - int read_size = read(client_socket, buffer, bufferSize - 1); - if (read_size <= 0) { + memset(buffer, 0, sizeof(buffer)); + Logger(Logger::Level::Info) << "Reading from client connection"; + ssize_t bytesReceived = read(client_socket, buffer, sizeof(buffer)); + if (bytesReceived <= 0) { Logger(Logger::Level::Info) << "Client disconnected or error"; - break; // Client disconnected or error + break; } - serial.writeData(std::string(buffer, read_size)); + serial.writeData(std::string(buffer, bytesReceived)); std::string response = serial.readData(); write(client_socket, response.c_str(), response.size()); } diff --git a/src/alternative_server_main.cpp b/src/alternative_server_main.cpp new file mode 100644 index 0000000..09f3666 --- /dev/null +++ b/src/alternative_server_main.cpp @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include + +void handleClient(int clientSocket) { + char buffer[1024]; + while (true) { + memset(buffer, 0, sizeof(buffer)); + ssize_t bytesReceived = read(clientSocket, buffer, sizeof(buffer)); + if (bytesReceived <= 0) { + std::cerr << "Read error or connection closed by client" << std::endl; + break; + } + + std::cout << "Received: " << buffer << std::endl; + write(clientSocket, buffer, bytesReceived); + } + + close(clientSocket); +} + +int main() { + const int port = 3333; + int serverFd = socket(AF_INET, SOCK_STREAM, 0); + if (serverFd < 0) { + std::cerr << "Cannot open socket" << std::endl; + return 1; + } + + struct sockaddr_in serverAddr; + memset(&serverAddr, 0, sizeof(serverAddr)); + serverAddr.sin_family = AF_INET; + serverAddr.sin_addr.s_addr = INADDR_ANY; // Listen on all network interfaces + serverAddr.sin_port = htons(port); + + if (bind(serverFd, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0) { + std::cerr << "Cannot bind to port " << port << std::endl; + return 1; + } + + if (listen(serverFd, 10) < 0) { // Listen for up to 10 connections + std::cerr << "Listen failed" << std::endl; + return 1; + } + + std::cout << "Server is listening on port " << port << std::endl; + + while (true) { + struct sockaddr_in clientAddr; + socklen_t clientLen = sizeof(clientAddr); + int clientSocket = accept(serverFd, (struct sockaddr *) &clientAddr, &clientLen); + if (clientSocket < 0) { + std::cerr << "Cannot accept connection" << std::endl; + continue; + } + + std::thread clientThread(handleClient, clientSocket); + clientThread.detach(); // Detach the thread to handle multiple clients + } + + close(serverFd); + return 0; +} From f9fbe937294a0a3cd2c7f8a65e2de5b3660399f8 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sun, 5 May 2024 15:15:02 +0200 Subject: [PATCH 22/31] Update server implementation --- include/TCPServer.h | 26 +++++++++++++++----------- src/TCPServer.cpp | 26 ++++++++------------------ 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/include/TCPServer.h b/include/TCPServer.h index 2c24e94..8495a99 100644 --- a/include/TCPServer.h +++ b/include/TCPServer.h @@ -1,25 +1,29 @@ #ifndef TCPSERVER_H #define TCPSERVER_H -#include "Logger.h" -#include "SerialPort.h" +#include #include +#include +#include +#include "SerialPort.h" +#include "Logger.h" class TcpServer { -private: - int server_fd_; - struct sockaddr_in address_; - int port_; - bool is_running_; - SerialPort& serial_; - - static void handleClient(int client_socket, SerialPort& serial); - public: TcpServer(int port, SerialPort& serial); ~TcpServer(); + void run(); void stop(); + +private: + void handleClient(int client_socket); + + int server_fd_; + int port_; + bool is_running_; + struct sockaddr_in address_; + SerialPort& serial_; }; #endif // TCPSERVER_H diff --git a/src/TCPServer.cpp b/src/TCPServer.cpp index 897e9f0..e1075ed 100644 --- a/src/TCPServer.cpp +++ b/src/TCPServer.cpp @@ -1,13 +1,9 @@ -#include -#include +#include "TCPServer.h" #include #include -#include - -#include "TCPServer.h" +#include -TcpServer::TcpServer(int port, SerialPort& serial) : port_(port), is_running_(false), serial_(serial) { - Logger(Logger::Level::Info) << "Init tcp server on port " << port_; +TcpServer::TcpServer(int port, SerialPort& serial) : port_(port), serial_(serial), is_running_(false) { if ((server_fd_ = socket(AF_INET, SOCK_STREAM, 0)) == 0) { throw std::runtime_error("Socket creation failed"); } @@ -28,7 +24,6 @@ TcpServer::TcpServer(int port, SerialPort& serial) : port_(port), is_running_(fa if (listen(server_fd_, 3) < 0) { throw std::runtime_error("Listen failed"); } - Logger(Logger::Level::Info) << "Init tcp server finished"; } TcpServer::~TcpServer() { @@ -38,21 +33,18 @@ TcpServer::~TcpServer() { } void TcpServer::run() { - Logger(Logger::Level::Info) << "Start tcp server"; is_running_ = true; while (is_running_) { struct sockaddr_in clientAddr; socklen_t clientLen = sizeof(clientAddr); - int clientSocket = accept(server_fd_, (struct sockaddr *) &clientAddr, &clientLen); + int clientSocket = accept(server_fd_, (struct sockaddr *)&clientAddr, &clientLen); if (clientSocket < 0) { - Logger(Logger::Level::Info) << "Cannot accept connection"; continue; } - std::thread clientThread(handleClient, clientSocket); + std::thread clientThread(&TcpServer::handleClient, this, clientSocket); clientThread.detach(); // Detach the thread to handle multiple clients } - } void TcpServer::stop() { @@ -60,19 +52,17 @@ void TcpServer::stop() { is_running_ = false; } -void TcpServer::handleClient(int client_socket, SerialPort& serial) { +void TcpServer::handleClient(int client_socket) { char buffer[1024]; while (true) { memset(buffer, 0, sizeof(buffer)); - Logger(Logger::Level::Info) << "Reading from client connection"; ssize_t bytesReceived = read(client_socket, buffer, sizeof(buffer)); if (bytesReceived <= 0) { - Logger(Logger::Level::Info) << "Client disconnected or error"; break; } - serial.writeData(std::string(buffer, bytesReceived)); - std::string response = serial.readData(); + serial_.writeData(std::string(buffer, bytesReceived)); + std::string response = serial_.readData(); write(client_socket, response.c_str(), response.size()); } From 03bc5fa45e52cc3d57edc0784230ec72d369fc19 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sun, 5 May 2024 15:37:41 +0200 Subject: [PATCH 23/31] Add more logging --- src/TCPServer.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/TCPServer.cpp b/src/TCPServer.cpp index e1075ed..01385a3 100644 --- a/src/TCPServer.cpp +++ b/src/TCPServer.cpp @@ -4,6 +4,7 @@ #include TcpServer::TcpServer(int port, SerialPort& serial) : port_(port), serial_(serial), is_running_(false) { + Logger(Logger::Level::Info) << "TCPServer init start"; if ((server_fd_ = socket(AF_INET, SOCK_STREAM, 0)) == 0) { throw std::runtime_error("Socket creation failed"); } @@ -24,6 +25,7 @@ TcpServer::TcpServer(int port, SerialPort& serial) : port_(port), serial_(serial if (listen(server_fd_, 3) < 0) { throw std::runtime_error("Listen failed"); } + Logger(Logger::Level::Info) << "TCPServer init finish"; } TcpServer::~TcpServer() { @@ -34,6 +36,7 @@ TcpServer::~TcpServer() { void TcpServer::run() { is_running_ = true; + Logger(Logger::Level::Info) << "TCPServer start listening"; while (is_running_) { struct sockaddr_in clientAddr; socklen_t clientLen = sizeof(clientAddr); @@ -54,15 +57,21 @@ void TcpServer::stop() { void TcpServer::handleClient(int client_socket) { char buffer[1024]; + Logger(Logger::Level::Info) << "HandleClient start"; while (true) { memset(buffer, 0, sizeof(buffer)); ssize_t bytesReceived = read(client_socket, buffer, sizeof(buffer)); if (bytesReceived <= 0) { + Logger(Logger::Level::Error) << "HandleClient - failed reading from client"; break; } + Logger(Logger::Level::Info) << "HandleClient - read data from client " << buffer; + + Logger(Logger::Level::Info) << "HandleClient - writing data to serial port"; serial_.writeData(std::string(buffer, bytesReceived)); std::string response = serial_.readData(); + Logger(Logger::Level::Info) << "HandleClient - got response from serial port " << response; write(client_socket, response.c_str(), response.size()); } From 6172e95128e58c4747cfdf3fa19aa42daf16d7c5 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sun, 5 May 2024 16:01:53 +0200 Subject: [PATCH 24/31] Add reader thread, add more logging --- include/SerialPort.h | 15 ++++++++++++++- src/SerialPort.cpp | 33 ++++++++++++++++++++++++++++++--- src/TCPServer.cpp | 24 +++++++++++++++--------- 3 files changed, 59 insertions(+), 13 deletions(-) diff --git a/include/SerialPort.h b/include/SerialPort.h index c875f6e..cfb4baa 100644 --- a/include/SerialPort.h +++ b/include/SerialPort.h @@ -1,15 +1,28 @@ #ifndef SERIALPORT_H #define SERIALPORT_H -#include +#include +#include +#include +#include +#include class SerialPort { private: int serial_fd; + std::thread read_thread; + std::atomic keep_reading; + std::queue read_buffer; + std::mutex mtx; + std::condition_variable cv; + + void readLoop(); public: SerialPort(const std::string& device, int baud_rate); ~SerialPort(); + void startReading(); + void stopReading(); void writeData(const std::string& data); std::string readData(); }; diff --git a/src/SerialPort.cpp b/src/SerialPort.cpp index 73bd063..c997ce9 100644 --- a/src/SerialPort.cpp +++ b/src/SerialPort.cpp @@ -47,8 +47,35 @@ void SerialPort::writeData(const std::string& data) { write(serial_fd, data.c_str(), data.size()); } + +void SerialPort::readLoop() { + while (keep_reading) { + char buf[256]; + int n = read(serial_fd, buf, sizeof(buf) - 1); + if (n > 0) { + buf[n] = '\0'; // Ensure null-termination + std::lock_guard lock(mtx); + read_buffer.push(std::string(buf)); + cv.notify_one(); + } + } +} + +void SerialPort::startReading() { + keep_reading = true; + read_thread = std::thread(&SerialPort::readLoop, this); +} + +void SerialPort::stopReading() { + keep_reading = false; + if (read_thread.joinable()) + read_thread.join(); +} + std::string SerialPort::readData() { - char buf[256]; - int n = read(serial_fd, buf, sizeof(buf)); - return std::string(buf, n); + std::unique_lock lock(mtx); + cv.wait(lock, [this]{ return !read_buffer.empty(); }); + std::string data = read_buffer.front(); + read_buffer.pop(); + return data; } diff --git a/src/TCPServer.cpp b/src/TCPServer.cpp index 01385a3..7ba0e6a 100644 --- a/src/TCPServer.cpp +++ b/src/TCPServer.cpp @@ -57,23 +57,29 @@ void TcpServer::stop() { void TcpServer::handleClient(int client_socket) { char buffer[1024]; - Logger(Logger::Level::Info) << "HandleClient start"; + Logger(Logger::Level::Info) << "HandleClient start - read thread from serial"; + std::thread readThread([&]() { + while (true) { + std::string response = serial_.readData(); // This will block until data is available + if (!response.empty()) { + Logger(Logger::Level::Info) << "HandleClient start - write to client " << response.c_str(); + write(client_socket, response.c_str(), response.size()); + } + } + }); + + Logger(Logger::Level::Info) << "HandleClient start - read data from client"; while (true) { memset(buffer, 0, sizeof(buffer)); ssize_t bytesReceived = read(client_socket, buffer, sizeof(buffer)); if (bytesReceived <= 0) { - Logger(Logger::Level::Error) << "HandleClient - failed reading from client"; break; } - - Logger(Logger::Level::Info) << "HandleClient - read data from client " << buffer; - - Logger(Logger::Level::Info) << "HandleClient - writing data to serial port"; + Logger(Logger::Level::Info) << "HandleClient start - write to serial " << buffer; serial_.writeData(std::string(buffer, bytesReceived)); - std::string response = serial_.readData(); - Logger(Logger::Level::Info) << "HandleClient - got response from serial port " << response; - write(client_socket, response.c_str(), response.size()); } + serial_.stopReading(); + readThread.join(); close(client_socket); } From df4ac21bd08811c62f4d574671f189e18368de5e Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sun, 5 May 2024 16:10:50 +0200 Subject: [PATCH 25/31] More logging --- include/SerialPort.h | 2 ++ src/SerialPort.cpp | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/include/SerialPort.h b/include/SerialPort.h index cfb4baa..d55650b 100644 --- a/include/SerialPort.h +++ b/include/SerialPort.h @@ -7,6 +7,8 @@ #include #include +#include "Logger.h" + class SerialPort { private: int serial_fd; diff --git a/src/SerialPort.cpp b/src/SerialPort.cpp index c997ce9..eca4909 100644 --- a/src/SerialPort.cpp +++ b/src/SerialPort.cpp @@ -6,6 +6,7 @@ #include SerialPort::SerialPort(const std::string& device, int baud_rate) { + Logger(Logger::Level::Info) << "SerialPort init start"; serial_fd = open(device.c_str(), O_RDWR | O_NOCTTY | O_SYNC); if (serial_fd < 0) { throw std::runtime_error("Error opening serial port"); @@ -37,6 +38,7 @@ SerialPort::SerialPort(const std::string& device, int baud_rate) { if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) { throw std::runtime_error("Error from tcsetattr"); } + Logger(Logger::Level::Info) << "SerialPort init finish"; } SerialPort::~SerialPort() { @@ -44,16 +46,19 @@ SerialPort::~SerialPort() { } void SerialPort::writeData(const std::string& data) { + Logger(Logger::Level::Info) << "SerialPort write data - " << data; write(serial_fd, data.c_str(), data.size()); } void SerialPort::readLoop() { + Logger(Logger::Level::Info) << "SerialPort start reading loop"; while (keep_reading) { char buf[256]; int n = read(serial_fd, buf, sizeof(buf) - 1); if (n > 0) { buf[n] = '\0'; // Ensure null-termination + Logger(Logger::Level::Info) << "SerialPort read - " << buf; std::lock_guard lock(mtx); read_buffer.push(std::string(buf)); cv.notify_one(); @@ -73,9 +78,11 @@ void SerialPort::stopReading() { } std::string SerialPort::readData() { + Logger(Logger::Level::Info) << "SerialPort read data"; std::unique_lock lock(mtx); cv.wait(lock, [this]{ return !read_buffer.empty(); }); std::string data = read_buffer.front(); read_buffer.pop(); + Logger(Logger::Level::Info) << "SerialPort read data - got data - " << data; return data; } From 6014a87b790ea29c6c8275b8d9e6a8348faa04e3 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sun, 5 May 2024 16:16:02 +0200 Subject: [PATCH 26/31] Add missing startReading when client connects --- src/TCPServer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/TCPServer.cpp b/src/TCPServer.cpp index 7ba0e6a..7d0ac5e 100644 --- a/src/TCPServer.cpp +++ b/src/TCPServer.cpp @@ -58,6 +58,7 @@ void TcpServer::stop() { void TcpServer::handleClient(int client_socket) { char buffer[1024]; Logger(Logger::Level::Info) << "HandleClient start - read thread from serial"; + serial_.startReading(); std::thread readThread([&]() { while (true) { std::string response = serial_.readData(); // This will block until data is available From ea7fb0469c494c710d78415fe6b8b4f36e5ea7c7 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sun, 5 May 2024 16:19:54 +0200 Subject: [PATCH 27/31] Add more logs --- src/SerialPort.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SerialPort.cpp b/src/SerialPort.cpp index eca4909..870b60f 100644 --- a/src/SerialPort.cpp +++ b/src/SerialPort.cpp @@ -6,7 +6,7 @@ #include SerialPort::SerialPort(const std::string& device, int baud_rate) { - Logger(Logger::Level::Info) << "SerialPort init start"; + Logger(Logger::Level::Info) << "SerialPort init start - device " << device << " - baudRate - " << baud_rate; serial_fd = open(device.c_str(), O_RDWR | O_NOCTTY | O_SYNC); if (serial_fd < 0) { throw std::runtime_error("Error opening serial port"); From b6b937dc96fde9786dc0ea3f4a8b4f9716168c81 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sun, 5 May 2024 16:27:38 +0200 Subject: [PATCH 28/31] Update serial device flags --- src/SerialPort.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/SerialPort.cpp b/src/SerialPort.cpp index 870b60f..a087fcd 100644 --- a/src/SerialPort.cpp +++ b/src/SerialPort.cpp @@ -27,7 +27,9 @@ SerialPort::SerialPort(const std::string& device, int baud_rate) { tty.c_cflag &= ~PARENB; tty.c_cflag &= ~CSTOPB; tty.c_cflag &= ~CRTSCTS; + tty.c_cflag |= CRTSCTS; + // tty.c_iflag |= (IXON | IXOFF | IXANY); tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); tty.c_oflag &= ~OPOST; From 797ac155fd674eec8354cf057e66731d46679474 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sun, 5 May 2024 16:34:42 +0200 Subject: [PATCH 29/31] Update serial device flags --- include/SerialPort.h | 1 + src/SerialPort.cpp | 36 ++++++++++++++++++++++-------------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/include/SerialPort.h b/include/SerialPort.h index d55650b..e7fd541 100644 --- a/include/SerialPort.h +++ b/include/SerialPort.h @@ -19,6 +19,7 @@ class SerialPort { std::condition_variable cv; void readLoop(); + void configurePort(int baud_rate); public: SerialPort(const std::string& device, int baud_rate); diff --git a/src/SerialPort.cpp b/src/SerialPort.cpp index a087fcd..8b74aaf 100644 --- a/src/SerialPort.cpp +++ b/src/SerialPort.cpp @@ -6,15 +6,27 @@ #include SerialPort::SerialPort(const std::string& device, int baud_rate) { - Logger(Logger::Level::Info) << "SerialPort init start - device " << device << " - baudRate - " << baud_rate; + Logger(Logger::Level::Info) << "SerialPort init start - device " << device << " - baudRate - " << baud_rate << std::endl; serial_fd = open(device.c_str(), O_RDWR | O_NOCTTY | O_SYNC); if (serial_fd < 0) { + Logger(Logger::Level::Error) << "Error opening serial port: " << strerror(errno) << std::endl; throw std::runtime_error("Error opening serial port"); } + configurePort(baud_rate); + Logger(Logger::Level::Info) << "SerialPort init finish" << std::endl; +} + +SerialPort::~SerialPort() { + close(serial_fd); +} + + +void SerialPort::configurePort(int baud_rate) { struct termios tty; memset(&tty, 0, sizeof tty); if (tcgetattr(serial_fd, &tty) != 0) { + Logger(Logger::Level::Error) << "Error from tcgetattr: " << strerror(errno) << std::endl; throw std::runtime_error("Error from tcgetattr"); } @@ -23,28 +35,24 @@ SerialPort::SerialPort(const std::string& device, int baud_rate) { tty.c_cflag |= (CLOCAL | CREAD); tty.c_cflag &= ~CSIZE; - tty.c_cflag |= CS8; - tty.c_cflag &= ~PARENB; - tty.c_cflag &= ~CSTOPB; - tty.c_cflag &= ~CRTSCTS; - tty.c_cflag |= CRTSCTS; + tty.c_cflag |= CS8; // 8-bit chars + tty.c_cflag &= ~PARENB; // no parity bit + tty.c_cflag &= ~CSTOPB; // only need 1 stop bit + tty.c_cflag &= ~CRTSCTS; // no hardware flowcontrol - // tty.c_iflag |= (IXON | IXOFF | IXANY); + // setup for raw input tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); tty.c_oflag &= ~OPOST; - tty.c_cc[VMIN] = 1; - tty.c_cc[VTIME] = 1; + // special characters + tty.c_cc[VMIN] = 1; // minimum number of characters to read + tty.c_cc[VTIME] = 1; // timeout in deciseconds for noncanonical read if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) { + Logger(Logger::Level::Error) << "Error from tcsetattr: " << strerror(errno) << std::endl; throw std::runtime_error("Error from tcsetattr"); } - Logger(Logger::Level::Info) << "SerialPort init finish"; -} - -SerialPort::~SerialPort() { - close(serial_fd); } void SerialPort::writeData(const std::string& data) { From 10593d17036b6ed49d9292c3b6edd4035bb4fa64 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sun, 5 May 2024 16:42:19 +0200 Subject: [PATCH 30/31] Update serial device flags --- src/SerialPort.cpp | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/SerialPort.cpp b/src/SerialPort.cpp index 8b74aaf..b52f4e4 100644 --- a/src/SerialPort.cpp +++ b/src/SerialPort.cpp @@ -7,7 +7,7 @@ SerialPort::SerialPort(const std::string& device, int baud_rate) { Logger(Logger::Level::Info) << "SerialPort init start - device " << device << " - baudRate - " << baud_rate << std::endl; - serial_fd = open(device.c_str(), O_RDWR | O_NOCTTY | O_SYNC); + serial_fd = open(device.c_str(), O_RDWR | O_NOCTTY); if (serial_fd < 0) { Logger(Logger::Level::Error) << "Error opening serial port: " << strerror(errno) << std::endl; throw std::runtime_error("Error opening serial port"); @@ -26,32 +26,31 @@ void SerialPort::configurePort(int baud_rate) { struct termios tty; memset(&tty, 0, sizeof tty); if (tcgetattr(serial_fd, &tty) != 0) { - Logger(Logger::Level::Error) << "Error from tcgetattr: " << strerror(errno) << std::endl; - throw std::runtime_error("Error from tcgetattr"); + Logger(Logger::Level::Error) << "tcgetattr failed: " << strerror(errno) << std::endl; + throw std::runtime_error("tcgetattr failed"); } - cfsetospeed(&tty, baud_rate); - cfsetispeed(&tty, baud_rate); + cfsetospeed(&tty, B115200); + cfsetispeed(&tty, B115200); - tty.c_cflag |= (CLOCAL | CREAD); - tty.c_cflag &= ~CSIZE; - tty.c_cflag |= CS8; // 8-bit chars - tty.c_cflag &= ~PARENB; // no parity bit - tty.c_cflag &= ~CSTOPB; // only need 1 stop bit - tty.c_cflag &= ~CRTSCTS; // no hardware flowcontrol + tty.c_cflag |= (CLOCAL | CREAD); // Ignore modem controls, enable reading + tty.c_cflag &= ~CSIZE; // Clear the mask + tty.c_cflag |= CS8; // 8 data bits + tty.c_cflag &= ~PARENB; // No parity bit + tty.c_cflag &= ~CSTOPB; // 1 stop bit + tty.c_cflag &= ~CRTSCTS; // No hardware flow control - // setup for raw input - tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); - tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - tty.c_oflag &= ~OPOST; + tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off software flow control + tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Disable canonical mode, echo, and signal chars + tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (raw output) - // special characters - tty.c_cc[VMIN] = 1; // minimum number of characters to read - tty.c_cc[VTIME] = 1; // timeout in deciseconds for noncanonical read + // Set read conditions: minimal character and timing + tty.c_cc[VMIN] = 0; + tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) { - Logger(Logger::Level::Error) << "Error from tcsetattr: " << strerror(errno) << std::endl; - throw std::runtime_error("Error from tcsetattr"); + Logger(Logger::Level::Error) << "tcsetattr failed: " << strerror(errno) << std::endl; + throw std::runtime_error("tcsetattr failed"); } } @@ -64,7 +63,7 @@ void SerialPort::writeData(const std::string& data) { void SerialPort::readLoop() { Logger(Logger::Level::Info) << "SerialPort start reading loop"; while (keep_reading) { - char buf[256]; + char buf[1024]; int n = read(serial_fd, buf, sizeof(buf) - 1); if (n > 0) { buf[n] = '\0'; // Ensure null-termination From 9b17bb2e8a15d724712984515656dc15997fb8b5 Mon Sep 17 00:00:00 2001 From: Jan Baraniewski Date: Sun, 5 May 2024 16:48:26 +0200 Subject: [PATCH 31/31] Cleanup --- CMakeLists.txt | 1 - include/RealSerialPort.h | 29 ----------------- include/SerialServer.h | 1 - src/RealSerialPort.cpp | 69 ---------------------------------------- src/main.cpp | 1 - 5 files changed, 101 deletions(-) delete mode 100644 include/RealSerialPort.h delete mode 100644 src/RealSerialPort.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a4b2d6..1a8a735 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,6 @@ include_directories(${CMAKE_SOURCE_DIR}/include) # Create core library without Logger.cpp, which is now in the logging library add_library(core_lib src/Logger.cpp - src/RealSerialPort.cpp src/SerialServer.cpp src/SerialClient.cpp src/VirtualSerialPort.cpp diff --git a/include/RealSerialPort.h b/include/RealSerialPort.h deleted file mode 100644 index 1725f7a..0000000 --- a/include/RealSerialPort.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef REALSERIALPORT_H -#define REALSERIALPORT_H - -#include "ISerialPort.h" -#include "Logger.h" -#include -#include -#include -#include -#include -#include -#include -#include - -class RealSerialPort : public ISerialPort { -public: - explicit RealSerialPort(const std::string& device, unsigned int baudRate); - ~RealSerialPort(); - - void open(const std::string& device, unsigned int baudRate) override; - ssize_t async_read_some(char* buffer, size_t size) override; - ssize_t async_write(const char* buffer, size_t size) override; - -private: - int fd; // File descriptor for the serial port - void configurePort(unsigned int baudRate); -}; - -#endif // REALSERIALPORT_H diff --git a/include/SerialServer.h b/include/SerialServer.h index 9387655..4827c38 100644 --- a/include/SerialServer.h +++ b/include/SerialServer.h @@ -7,7 +7,6 @@ #include #include -#include "RealSerialPort.h" #include "SerialPort.h" #include "TCPServer.h" diff --git a/src/RealSerialPort.cpp b/src/RealSerialPort.cpp deleted file mode 100644 index c54a83c..0000000 --- a/src/RealSerialPort.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "RealSerialPort.h" - -RealSerialPort::RealSerialPort(const std::string& device, unsigned int baudRate) : fd(-1) { - open(device, baudRate); -} - -RealSerialPort::~RealSerialPort() { - if (fd != -1) { - close(fd); - } -} - -void RealSerialPort::open(const std::string& device, unsigned int baudRate) { - fd = ::open(device.c_str(), O_RDWR | O_NOCTTY | O_SYNC); - if (fd == -1) { - Logger(Logger::Level::Error) << "Failed to open serial port: " << device << " with error: " << strerror(errno); - throw std::runtime_error("Failed to open serial port"); - } - - configurePort(baudRate); - Logger(Logger::Level::Info) << "Serial port opened and configured on " << device; -} - -void RealSerialPort::configurePort(unsigned int baudRate) { - struct termios tty; - if (tcgetattr(fd, &tty) != 0) { - Logger(Logger::Level::Error) << "Error from tcgetattr: " << strerror(errno); - throw std::runtime_error("Error configuring serial port"); - } - - cfsetospeed(&tty, baudRate); - cfsetispeed(&tty, baudRate); - - tty.c_cflag |= (CLOCAL | CREAD); // Ignore modem controls, enable reading - tty.c_cflag &= ~CSIZE; - tty.c_cflag |= CS8; // 8-bit characters - tty.c_cflag &= ~PARENB; // No parity bit - tty.c_cflag &= ~CSTOPB; // Only need 1 stop bit - tty.c_cflag &= ~CRTSCTS; // No hardware flow control - - // Setup for non-canonical mode - tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); - tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - tty.c_oflag &= ~OPOST; - - tty.c_cc[VMIN] = 1; // Minimum number of characters to read - tty.c_cc[VTIME] = 1; // Time to wait for data (tenths of seconds) - - if (tcsetattr(fd, TCSANOW, &tty) != 0) { - Logger(Logger::Level::Error) << "Error from tcsetattr: " << strerror(errno); - throw std::runtime_error("Error applying serial port settings"); - } -} - -ssize_t RealSerialPort::async_read_some(char* buffer, size_t size) { - ssize_t n = read(fd, buffer, size); - if (n < 0) { - Logger(Logger::Level::Error) << "Read error on serial port: " << strerror(errno); - } - return n; -} - -ssize_t RealSerialPort::async_write(const char* buffer, size_t size) { - ssize_t n = write(fd, buffer, size); - if (n < 0) { - Logger(Logger::Level::Error) << "Write error on serial port: " << strerror(errno); - } - return n; -} diff --git a/src/main.cpp b/src/main.cpp index 43ad5a2..299a9f9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,7 +4,6 @@ #include "Logger.h" #include "SerialClient.h" #include "SerialServer.h" -#include "RealSerialPort.h" using std::string; using std::cout;