size_t SerialPort::Write(const void *data, size_t length) { DWORD NumberOfBytesWritten; if (hPort == INVALID_HANDLE_VALUE) return 0; OverlappedEvent osWriter; // Start reading data if (::WriteFile(hPort, data, length, &NumberOfBytesWritten, osWriter.GetPointer())) return NumberOfBytesWritten; if (::GetLastError() != ERROR_IO_PENDING) return 0; // Let's wait for ReadFile() to finish unsigned timeout_ms = 1000 + length * 10; switch (osWriter.Wait(timeout_ms)) { case OverlappedEvent::FINISHED: // Get results ::GetOverlappedResult(hPort, osWriter.GetPointer(), &NumberOfBytesWritten, FALSE); return NumberOfBytesWritten; default: ::CancelIo(hPort); ::SetCommMask(hPort, 0); osWriter.Wait(); return 0; } }
size_t SerialPort::Write(const void *data, size_t length) { DWORD NumberOfBytesWritten; if (hPort == INVALID_HANDLE_VALUE) return 0; #ifdef _WIN32_WCE #if 0 /* this workaround is currently disabled because it causes major problems with some of our device drivers, causing timeouts; this may be a regression on the bugged HP31x, but I prefer to support sane platforms any day */ if (IsWindowsCE() && !IsAltair()) /* this is needed to work around a driver bug on the HP31x - without it, the second consecutive write without a task switch will hang the whole PNA; this Sleep() call enforces a task switch */ Sleep(100); #endif // lpNumberOfBytesWritten : This parameter can be NULL only when the lpOverlapped parameter is not NULL. if (!::WriteFile(hPort, data, length, &NumberOfBytesWritten, NULL)) return 0; return NumberOfBytesWritten; #else OverlappedEvent osWriter; // Start reading data if (::WriteFile(hPort, data, length, &NumberOfBytesWritten, osWriter.GetPointer())) return NumberOfBytesWritten; if (::GetLastError() != ERROR_IO_PENDING) return 0; // Let's wait for ReadFile() to finish unsigned timeout_ms = 1000 + length * 10; switch (osWriter.Wait(timeout_ms)) { case OverlappedEvent::FINISHED: // Get results ::GetOverlappedResult(hPort, osWriter.GetPointer(), &NumberOfBytesWritten, FALSE); return NumberOfBytesWritten; default: ::CancelIo(hPort); ::SetCommMask(hPort, 0); osWriter.Wait(); return 0; } #endif }
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; }