From d1978d6ad902b05a6f3a0d92201887637b77822b Mon Sep 17 00:00:00 2001 From: Tim Pattinson Date: Sun, 15 Mar 2026 21:00:41 +1100 Subject: [PATCH 1/3] Add a configurable timeout for UART transmit and recieve Currently only implemented for WIN32 --- UART.cpp | 10 +++++++--- UART.h | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/UART.cpp b/UART.cpp index 4dce394..8ecca10 100644 --- a/UART.cpp +++ b/UART.cpp @@ -106,8 +106,12 @@ UART::~UART() { @param devfile The device file @param baud Baud rate to use (in bits per second) @param dtrEnable True if DTR line should be enabled (needed by some devices like the NanoVNA to communicate) + @param txUs Transmit timeout in microseconds (default 50,000 = 50 milliseconds) + @param rxUs Recieve timeout in microseconds (default 500,000 = 500 milliseconds) + + //TODO timeouts only implemented for WIN32 */ -bool UART::Connect(const std::string& devfile, int baud, [[maybe_unused]] bool dtrEnable) +bool UART::Connect(const std::string& devfile, int baud, [[maybe_unused]] bool dtrEnable, [[maybe_unused]]unsigned int txUs,[[maybe_unused]]unsigned int rxUs) { if(devfile.find(":") != string::npos) { @@ -166,9 +170,9 @@ bool UART::Connect(const std::string& devfile, int baud, [[maybe_unused]] bool d COMMTIMEOUTS timeouts; SecureZeroMemory(&timeouts, sizeof(COMMTIMEOUTS)); timeouts.ReadIntervalTimeout = 50; // Timeout between each byte (in milliseconds) - timeouts.ReadTotalTimeoutConstant = 500;// Total timeout for a read operation (in milliseconds) + timeouts.ReadTotalTimeoutConstant = rxUs/1000;// Total timeout for a read operation (in milliseconds) timeouts.ReadTotalTimeoutMultiplier = 1; // Multiplier for each byte - timeouts.WriteTotalTimeoutConstant = 50; // in milliseconds + timeouts.WriteTotalTimeoutConstant = txUs/1000; // in milliseconds timeouts.WriteTotalTimeoutMultiplier = 10;// in milliseconds result = SetCommTimeouts(m_fd, &timeouts); if(!result) diff --git a/UART.h b/UART.h index 7287679..76d9876 100644 --- a/UART.h +++ b/UART.h @@ -67,7 +67,7 @@ class UART UART(); UART(const std::string& devfile, int baud); - bool Connect(const std::string& devfile, int baud, bool dtrEnable = false); + bool Connect(const std::string& devfile, int baud, bool dtrEnable = false,unsigned int txUs = 1000*50,unsigned int rxUs = 1000*500); void Close(); virtual ~UART(); From ec05f97fd42d81f12527749740d1467d634a58c6 Mon Sep 17 00:00:00 2001 From: Tim Pattinson Date: Sun, 15 Mar 2026 21:35:20 +1100 Subject: [PATCH 2/3] win32: append \\.\ to COM port name (needed for COM10 and above) --- UART.cpp | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/UART.cpp b/UART.cpp index 8ecca10..37b6f8f 100644 --- a/UART.cpp +++ b/UART.cpp @@ -128,7 +128,25 @@ bool UART::Connect(const std::string& devfile, int baud, [[maybe_unused]] bool d else { #ifdef _WIN32 - m_fd = CreateFileA(devfile.c_str(), // port name + string win32_portname; + + // Specify the COM port name using \\.\COM10 + // this is needed for COM10 and above on windows + // note the escape character is also backslash + if(devfile.find("COM")==0){ + // pre-append "\\.\" + win32_portname = R"(\\.\)" + devfile; + }else if(devfile.find(R"(\\.\COM)")==0){ + // the "\\.\"" is already there + win32_portname = devfile; + }else{ + // the name of the COM port is not valid + LogError("COM port name %s invalid, expected COM1 or \\\\.\\COM1\n",devfile.c_str()); + return false; + } + + + m_fd = CreateFileA(win32_portname.c_str(), // port name GENERIC_READ | GENERIC_WRITE, // Read/Write 0, // No Sharing NULL, // No Security @@ -138,7 +156,7 @@ bool UART::Connect(const std::string& devfile, int baud, [[maybe_unused]] bool d if (m_fd == INVALID_HANDLE_VALUE) { - LogError("Could not open COM port %s\n", devfile.c_str()); + LogError("Could not open COM port %s\n", win32_portname.c_str()); return false; } // Configure port @@ -149,7 +167,7 @@ bool UART::Connect(const std::string& devfile, int baud, [[maybe_unused]] bool d bool result = GetCommState(m_fd, &dcbSerialParams); if(!result) { - LogError("Could not get state for COM port %s\n", devfile.c_str()); + LogError("Could not get state for COM port %s\n", win32_portname.c_str()); return false; } // Set values @@ -163,7 +181,7 @@ bool UART::Connect(const std::string& devfile, int baud, [[maybe_unused]] bool d result = SetCommState(m_fd, &dcbSerialParams); if(!result) { - LogError("Could not set state for COM port %s\n", devfile.c_str()); + LogError("Could not set state for COM port %s\n", win32_portname.c_str()); return false; } // Set timeouts @@ -177,7 +195,7 @@ bool UART::Connect(const std::string& devfile, int baud, [[maybe_unused]] bool d result = SetCommTimeouts(m_fd, &timeouts); if(!result) { - LogError("Could not set timeouts for COM port %s\n", devfile.c_str()); + LogError("Could not set timeouts for COM port %s\n", win32_portname.c_str()); return false; } From 5d5368929846c9b7b28c71e57e200386969be7de Mon Sep 17 00:00:00 2001 From: Tim Pattinson Date: Sun, 22 Mar 2026 19:57:44 +1100 Subject: [PATCH 3/3] Refactor setting timeouts for UART into its own function --- UART.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++------------ UART.h | 1 + 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/UART.cpp b/UART.cpp index 37b6f8f..8102690 100644 --- a/UART.cpp +++ b/UART.cpp @@ -185,19 +185,9 @@ bool UART::Connect(const std::string& devfile, int baud, [[maybe_unused]] bool d return false; } // Set timeouts - COMMTIMEOUTS timeouts; - SecureZeroMemory(&timeouts, sizeof(COMMTIMEOUTS)); - timeouts.ReadIntervalTimeout = 50; // Timeout between each byte (in milliseconds) - timeouts.ReadTotalTimeoutConstant = rxUs/1000;// Total timeout for a read operation (in milliseconds) - timeouts.ReadTotalTimeoutMultiplier = 1; // Multiplier for each byte - timeouts.WriteTotalTimeoutConstant = txUs/1000; // in milliseconds - timeouts.WriteTotalTimeoutMultiplier = 10;// in milliseconds - result = SetCommTimeouts(m_fd, &timeouts); - if(!result) - { - LogError("Could not set timeouts for COM port %s\n", win32_portname.c_str()); + + if(!SetTimeouts(txUs,rxUs)) return false; - } return true; #else @@ -275,6 +265,46 @@ bool UART::Connect(const std::string& devfile, int baud, [[maybe_unused]] bool d return true; } +/** + @brief Sets timeouts on a UART that is open + + @param txUs Transmit timeout in microseconds (default 50,000 = 50 milliseconds) + @param rxUs Recieve timeout in microseconds (default 500,000 = 500 milliseconds) + + //TODO timeouts only implemented for WIN32 + */ +bool UART::SetTimeouts(unsigned int txUs,unsigned int rxUs) +{ + #ifdef WIN32 + // check if the file handle is open before attempting to use it + if(IsValid()){ + COMMTIMEOUTS timeouts; + SecureZeroMemory(&timeouts, sizeof(COMMTIMEOUTS)); + timeouts.ReadIntervalTimeout = 50; // Timeout between each byte (in milliseconds) + timeouts.ReadTotalTimeoutConstant = rxUs/1000;// Total timeout for a read operation (in milliseconds) + timeouts.ReadTotalTimeoutMultiplier = 1; // Multiplier for each byte + timeouts.WriteTotalTimeoutConstant = txUs/1000; // in milliseconds + timeouts.WriteTotalTimeoutMultiplier = 10;// in milliseconds + bool result = SetCommTimeouts(m_fd, &timeouts); + if(!result) + { + LogError("Could not set timeouts for COM port\n"); + return false; + } + }else{ + LogError("Did not set timeouts on UART that is not open\n"); + } + + #else + LogError("UART::SetTimeouts is unimplemented on non-Windows platforms\n"); + return true; + #endif + + return true; + +} + + /** @brief Disconnects from the serial port */ diff --git a/UART.h b/UART.h index 76d9876..43c4052 100644 --- a/UART.h +++ b/UART.h @@ -68,6 +68,7 @@ class UART UART(); UART(const std::string& devfile, int baud); bool Connect(const std::string& devfile, int baud, bool dtrEnable = false,unsigned int txUs = 1000*50,unsigned int rxUs = 1000*500); + bool SetTimeouts(unsigned int txUs = 1000*50,unsigned int rxUs = 1000*500); void Close(); virtual ~UART();