diff --git a/src/windows/com.rs b/src/windows/com.rs index 20e243fb..1126ca0c 100644 --- a/src/windows/com.rs +++ b/src/windows/com.rs @@ -249,13 +249,21 @@ impl SerialPort for COMPort { fn set_timeout(&mut self, timeout: Duration) -> Result<()> { let milliseconds = timeout.as_millis(); + // In the way we are setting up timeouts here, a timeout_constant of MAXDWORD gets + // rejected. Let's clamp the timeout constant for values of MAXDWORD and above. See remarks + // at https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-commtimeouts. + // + // This effectively throws away accuracy for really long timeouts but at least preserves a + // long-ish timeout. But just casting to DWORD would result in presumably unexpected short + // and non-monotonic timeouts from cutting off the higher bits. + let timeout_constant = u128::min(milliseconds, MAXDWORD as u128 - 1) as DWORD; let mut timeouts = COMMTIMEOUTS { ReadIntervalTimeout: MAXDWORD, ReadTotalTimeoutMultiplier: MAXDWORD, - ReadTotalTimeoutConstant: milliseconds as DWORD, + ReadTotalTimeoutConstant: timeout_constant, WriteTotalTimeoutMultiplier: 0, - WriteTotalTimeoutConstant: milliseconds as DWORD, + WriteTotalTimeoutConstant: timeout_constant, }; if unsafe { SetCommTimeouts(self.handle, &mut timeouts) } == 0 {