wjwwood / serial

Cross-platform, Serial Port library written in C++
http://wjwwood.github.com/serial/
MIT License
2.11k stars 1.03k forks source link

Windows serial Timeout using max() or simpleTimeout fails (fix included) #236

Open GordonLElliott opened 3 years ago

GordonLElliott commented 3 years ago

The timeout setup fails to work in Windows 10 when the Timeout::max() function is used for the first Timeout parameter, as this causes an immediate return without waiting.

The usage example is clearly intending to wait on reads, because different wait times are entered and tested. That makes no sense if the read function was not intended to wait -- as a non-blocking (zero time) wait occurs in the failure.

Using Timeout::max() (a.k.a. MAXDWORD in Microsoft documentation on the subject) for the inter_byte_timeout_ parameter causes the read function to return without waiting. The documentation says that the other two read time parameters need to be zero, but this appears not to be the case now in Windows 10 (whatever the historical result).

Also I believe that the "simple" Timeout (simpleTimeout) should wait forever on write, and only timeout on the read function. One might use a long low baud rate string for example, and don't expect early write function return before the output is queued. (Note in Windows still queues 16 bytes before returning in typical ports, probably in a hardware queue on many devices, so the first write will take less time to return by 16 character times.)

I don't know how the equivalent function works in Linux, and a proper fix may need conditional compiling!

With fixes suggested applied below, I have example working with VS2019:

  static Timeout simpleTimeout(uint32_t timeout) {
    //return Timeout(max(), timeout, 0, timeout, 0);
    // [GLE] For "Simple" I assume wait forever on write!
    // [GLE] First parameter inter_byte_timeout_ must be 0 to 
    // disable. Using MAXDWORD (the max() function) causes the
    // immediate return on read, and seems to ignore the other
    // parameters now in Windows 10. Using 0 to disable in "Simple".
    return Timeout(0, timeout, 0, max(), 0);
  }

In addition, any programming (as in the example) should use 0 for first Timeout parameter in Windows to disable the character-character time delay. The Serial::Timeout::max() value is used to cause non-blocking read.

Probably should be a couple of constants defined, or more, depending upon the position in the parameters.

Once again on Windows 10: Timeout(Serial::Timeout::max(),xxx,xxx,xxx,xxx) causes read to return non-blocking with no wait, just characters received to this point. Appears to ignore 2nd and 3rd parameters if set that way, contrary to Microsoft documentation. Timeout(0,a,b,xxx,xxx) causes read to ignore inter-character delays and use a+n*b time where n is number of characters and a,b in milliseconds, b here is the position for multiplying the number of characters times the time (typically related to baud rate).