Port::WaitResult SerialPort::WaitDataPending(OverlappedEvent &overlapped, unsigned timeout_ms) const { int nbytes = GetDataPending(); if (nbytes > 0) return WaitResult::READY; else if (nbytes < 0) return WaitResult::FAILED; ::SetCommMask(hPort, EV_RXCHAR); DWORD dwCommModemStatus; if (!::WaitCommEvent(hPort, &dwCommModemStatus, overlapped.GetPointer())) { if (::GetLastError() != ERROR_IO_PENDING) return WaitResult::FAILED; switch (overlapped.Wait(timeout_ms)) { case OverlappedEvent::FINISHED: break; case OverlappedEvent::TIMEOUT: /* the operation may still be running, we have to cancel it */ ::CancelIo(hPort); ::SetCommMask(hPort, 0); overlapped.Wait(); return WaitResult::TIMEOUT; case OverlappedEvent::CANCELED: /* the operation may still be running, we have to cancel it */ ::CancelIo(hPort); ::SetCommMask(hPort, 0); overlapped.Wait(); return WaitResult::CANCELLED; } DWORD result; if (!::GetOverlappedResult(hPort, overlapped.GetPointer(), &result, FALSE)) return WaitResult::FAILED; } if ((dwCommModemStatus & EV_RXCHAR) == 0) return WaitResult::FAILED; return GetDataPending() > 0 ? WaitResult::READY : WaitResult::FAILED; }
void SerialPort::Run() { assert(Thread::IsInside()); DWORD dwBytesTransferred; BYTE inbuf[1024]; // JMW added purging of port on open to prevent overflow Flush(); #ifndef _WIN32_WCE OverlappedEvent osStatus, osReader; if (!osStatus.Defined() || !osReader.Defined()) // error creating event; abort return; #endif // Specify a set of events to be monitored for the port. if (is_widcomm) SetRxTimeout(180); else { ::SetCommMask(hPort, EV_RXCHAR); SetRxTimeout(0); } while (!CheckStopped()) { #ifndef _WIN32_WCE WaitResult result = WaitDataPending(osStatus, INFINITE); switch (result) { case WaitResult::READY: break; case WaitResult::TIMEOUT: continue; case WaitResult::FAILED: case WaitResult::CANCELLED: ::Sleep(100); continue; } int nbytes = GetDataPending(); if (nbytes <= 0) { ::Sleep(100); continue; } // Start reading data if ((size_t)nbytes > sizeof(inbuf)) nbytes = sizeof(inbuf); if (!::ReadFile(hPort, inbuf, nbytes, &dwBytesTransferred, osReader.GetPointer())) { if (::GetLastError() != ERROR_IO_PENDING) { // Error in ReadFile() occured ::Sleep(100); continue; } if (osReader.Wait() != OverlappedEvent::FINISHED) { ::CancelIo(hPort); ::SetCommMask(hPort, 0); osReader.Wait(); continue; } if (!::GetOverlappedResult(hPort, osReader.GetPointer(), &dwBytesTransferred, FALSE)) continue; } #else if (is_widcomm) { /* WaitCommEvent() doesn't work with the Widcomm Bluetooth driver, it blocks for 11 seconds, regardless whether data is received. This workaround polls for input manually. Observed on an iPaq hx4700 with WM6. */ } else { // Wait for an event to occur for the port. DWORD dwCommModemStatus; if (!::WaitCommEvent(hPort, &dwCommModemStatus, 0)) { // error reading from port Sleep(100); continue; } if ((dwCommModemStatus & EV_RXCHAR) == 0) /* no data available */ continue; } // Read the data from the serial port. if (!ReadFile(hPort, inbuf, 1024, &dwBytesTransferred, NULL) || dwBytesTransferred == 0) { Sleep(100); continue; } #endif DataReceived(inbuf, dwBytesTransferred); } Flush(); }
void SerialPort::Run() { assert(Thread::IsInside()); DWORD dwBytesTransferred; BYTE inbuf[1024]; // JMW added purging of port on open to prevent overflow Flush(); OverlappedEvent osStatus, osReader; if (!osStatus.Defined() || !osReader.Defined()) // error creating event; abort return; // Specify a set of events to be monitored for the port. ::SetCommMask(hPort, EV_RXCHAR); SetRxTimeout(0); while (!CheckStopped()) { WaitResult result = WaitDataPending(osStatus, INFINITE); switch (result) { case WaitResult::READY: break; case WaitResult::TIMEOUT: continue; case WaitResult::FAILED: case WaitResult::CANCELLED: ::Sleep(100); continue; } int nbytes = GetDataPending(); if (nbytes <= 0) { ::Sleep(100); continue; } // Start reading data if ((size_t)nbytes > sizeof(inbuf)) nbytes = sizeof(inbuf); if (!::ReadFile(hPort, inbuf, nbytes, &dwBytesTransferred, osReader.GetPointer())) { if (::GetLastError() != ERROR_IO_PENDING) { // Error in ReadFile() occured ::Sleep(100); continue; } if (osReader.Wait() != OverlappedEvent::FINISHED) { ::CancelIo(hPort); ::SetCommMask(hPort, 0); osReader.Wait(); continue; } if (!::GetOverlappedResult(hPort, osReader.GetPointer(), &dwBytesTransferred, FALSE)) continue; } DataReceived(inbuf, dwBytesTransferred); } Flush(); }