From 7ca1d440fa7304ebb855e5b3d204e962f34252b0 Mon Sep 17 00:00:00 2001 From: "X.F.Zhou" Date: Mon, 18 Jul 2022 21:53:55 +0800 Subject: [PATCH 1/3] implement SerialImpl::waitByteTimes on windows --- src/impl/win.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/impl/win.cc b/src/impl/win.cc index 889e06f..a1d7ce4 100644 --- a/src/impl/win.cc +++ b/src/impl/win.cc @@ -322,9 +322,13 @@ Serial::SerialImpl::waitReadable (uint32_t /*timeout*/) } void -Serial::SerialImpl::waitByteTimes (size_t /*count*/) +Serial::SerialImpl::waitByteTimes (size_t count) { - THROW (IOException, "waitByteTimes is not implemented on Windows."); + DWORD wait_time = timeout_.inter_byte_timeout * count; + HANDLE wait_event = CreateEvent(NULL, FALSE, FALSE, NULL); + ResetEvent(wait_event); + WaitForSingleObject(wait_event, wait_time); + CloseHandle(wait_event); } size_t From 21c6e32255fa0905a3b7e355e399612e2bdd2526 Mon Sep 17 00:00:00 2001 From: "X.F.Zhou" Date: Mon, 18 Jul 2022 21:56:15 +0800 Subject: [PATCH 2/3] implement SerialImpl::waitReadable on windows Add a FILE_FLAG_OVERLAPPED flag when open the port Revise the Read and Write method to support Asynchronous I/O --- include/serial/impl/win.h | 1 + src/impl/win.cc | 71 +++++++++++++++++++++++++++++++++------ 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/include/serial/impl/win.h b/include/serial/impl/win.h index 2c0c6cd..4661a6d 100644 --- a/include/serial/impl/win.h +++ b/include/serial/impl/win.h @@ -198,6 +198,7 @@ private: HANDLE read_mutex; // Mutex used to lock the write functions HANDLE write_mutex; + OVERLAPPED overlapped_; }; } diff --git a/src/impl/win.cc b/src/impl/win.cc index a1d7ce4..e9fd21c 100644 --- a/src/impl/win.cc +++ b/src/impl/win.cc @@ -43,6 +43,8 @@ Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate, open (); read_mutex = CreateMutex(NULL, false, NULL); write_mutex = CreateMutex(NULL, false, NULL); + memset(&overlapped_, 0x00, sizeof(overlapped_)); + overlapped_.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); } Serial::SerialImpl::~SerialImpl () @@ -50,6 +52,7 @@ Serial::SerialImpl::~SerialImpl () this->close(); CloseHandle(read_mutex); CloseHandle(write_mutex); + CloseHandle(overlapped_.hEvent); } void @@ -70,7 +73,7 @@ Serial::SerialImpl::open () 0, 0, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0); if (fd_ == INVALID_HANDLE_VALUE) { @@ -279,6 +282,8 @@ Serial::SerialImpl::close () { if (is_open_ == true) { if (fd_ != INVALID_HANDLE_VALUE) { + SetCommMask(fd_, 0); + ResetEvent(overlapped_.hEvent); int ret; ret = CloseHandle(fd_); if (ret == 0) { @@ -315,9 +320,49 @@ Serial::SerialImpl::available () } bool -Serial::SerialImpl::waitReadable (uint32_t /*timeout*/) +Serial::SerialImpl::waitReadable (uint32_t timeout) { - THROW (IOException, "waitReadable is not implemented on Windows."); + COMSTAT cs; + DWORD error; + DWORD old_msk, msk, length; + + if (!isOpen()) { + return false; + } + + if (!GetCommMask(fd_, &old_msk)) { + stringstream ss; + ss << "Error while get mask of the serial port: " << GetLastError(); + THROW(IOException, ss.str().c_str()); + } + + msk = 0; + SetCommMask(fd_, EV_RXCHAR | EV_ERR); + if (!WaitCommEvent(fd_, &msk, &overlapped_)) { + if (GetLastError() == ERROR_IO_PENDING) { + if (WaitForSingleObject(overlapped_.hEvent, (DWORD)timeout) == WAIT_TIMEOUT) { + SetCommMask(fd_, old_msk); + return false; + } + + GetOverlappedResult(fd_, &overlapped_, &length, TRUE); + ::ResetEvent(overlapped_.hEvent); + } else { + ClearCommError(fd_, &error, &cs); + SetCommMask(fd_, old_msk); + return cs.cbInQue > 0; + } + } + + SetCommMask(fd_, old_msk); + if (msk & EV_ERR) { + ClearCommError(fd_, &error, &cs); + return cs.cbInQue > 0; + } + if (msk & EV_RXCHAR) { + return true; + } + return false; } @@ -338,11 +383,13 @@ Serial::SerialImpl::read (uint8_t *buf, size_t size) throw PortNotOpenedException ("Serial::read"); } DWORD bytes_read; - if (!ReadFile(fd_, buf, static_cast(size), &bytes_read, NULL)) { - stringstream ss; - ss << "Error while reading from the serial port: " << GetLastError(); - THROW (IOException, ss.str().c_str()); + overlapped_.Offset = 0; + overlapped_.OffsetHigh = 0; + if (!ReadFile(fd_, buf, static_cast(size), NULL, &overlapped_)) { + WaitForSingleObject(overlapped_.hEvent, timeout_.read_timeout_constant); } + GetOverlappedResult(fd_, &overlapped_, &bytes_read, TRUE); + ::ResetEvent(overlapped_.hEvent); return (size_t) (bytes_read); } @@ -353,11 +400,13 @@ Serial::SerialImpl::write (const uint8_t *data, size_t length) throw PortNotOpenedException ("Serial::write"); } DWORD bytes_written; - if (!WriteFile(fd_, data, static_cast(length), &bytes_written, NULL)) { - stringstream ss; - ss << "Error while writing to the serial port: " << GetLastError(); - THROW (IOException, ss.str().c_str()); + overlapped_.Offset = 0; + overlapped_.OffsetHigh = 0; + if (!WriteFile(fd_, data, static_cast(length), NULL, &overlapped_)) { + WaitForSingleObject(overlapped_.hEvent, timeout_.write_timeout_constant); } + GetOverlappedResult(fd_, &overlapped_, &bytes_written, TRUE); + ::ResetEvent(overlapped_.hEvent); return (size_t) (bytes_written); } From 02654f03eb1a2342d3fdd513bd2c95108434be42 Mon Sep 17 00:00:00 2001 From: "Mr.Chip" Date: Wed, 21 Aug 2024 13:20:06 +0800 Subject: [PATCH 3/3] Fix: only set timeout for handle instead of reconfiguring the com port --- src/impl/win.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/impl/win.cc b/src/impl/win.cc index e9fd21c..17b0ca6 100644 --- a/src/impl/win.cc +++ b/src/impl/win.cc @@ -427,7 +427,17 @@ Serial::SerialImpl::setTimeout (serial::Timeout &timeout) { timeout_ = timeout; if (is_open_) { - reconfigurePort (); + //reconfigurePort (); + // Setup timeouts + COMMTIMEOUTS timeouts = { 0 }; + timeouts.ReadIntervalTimeout = timeout_.inter_byte_timeout; + timeouts.ReadTotalTimeoutConstant = timeout_.read_timeout_constant; + timeouts.ReadTotalTimeoutMultiplier = timeout_.read_timeout_multiplier; + timeouts.WriteTotalTimeoutConstant = timeout_.write_timeout_constant; + timeouts.WriteTotalTimeoutMultiplier = timeout_.write_timeout_multiplier; + if (!SetCommTimeouts(fd_, &timeouts)) { + THROW(IOException, "Error setting timeouts."); + } } }