简体   繁体   中英

set low_latency flag on a serial port on windows in c++

I have a program that opens a serial port using boost asio.

The serial port, by default, has a delay that keeps the line idle. On windows platforms I saw a delay of 30ms and on Linux platforms the delay was 20ms.

For the Linux environment I found that the class 'ioctl' of "linux.h" has a way to set the serial settings with some flags (and what I needed: low_latency).

the code is as follows:

boost::asio::basic_serial_port<boost::asio::serial_port_service>::native_type native = serial_port_.native(); // serial_port_ is the boost's serial port class.
struct serial_struct serial;
ioctl(native, TIOCGSERIAL, &serial);
serial.flags |= ASYNC_LOW_LATENCY; // (0x2000)
ioctl(native, TIOCSSERIAL, &serial);

I want to reduce the delay on my windows platform as well. Is there an equivalent way that does the same for windows with C++?

BTW, I saw that there are some solutions that suggests to change the properties of the serial port at the Windows Device Manager, but I don't have those properties as these solutions showed and I need a code solution.

Take the native handle you get in from boost asio in windows and pass it to SetCommTimeouts: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363437(v=vs.85).aspx

In particular, look at the ReadIntervalTimeout of the COMMTIMEOUT structure: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363190(v=vs.85).aspx

ReadIntervalTimeout The maximum time allowed to elapse between the arrival of two bytes on the communications line, in milliseconds. During a ReadFile operation, the time period begins when the first byte is received. If the interval between the arrival of any two bytes exceeds this amount, the ReadFile operation is completed and any buffered data is returned. A value of zero indicates that interval time-outs are not used. A value of MAXDWORD, combined with zero values for both the ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members, specifies that the read operation is to return immediately with the bytes that have already been received, even if no bytes have been received.

You can also query the current values with GetCommTimeouts: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363261(v=vs.85).aspx

I recall having this problem in the NT4/Win2k/WinXP era, I assume the problem you are having is similar.

Using the COMMTIMEOUT structure always added a timeslice delay after each timeout, which meant that for variable length packets you always added 10ms or 16ms of latency, depending on whether the machine was an SMP machine or not. You could not, for example, really get a 1ms timeout. This was true even when using COMMTIMEOUT on async operations on the serial port with completion ports.

To eliminate the problem I used IO Completion Ports and had a pipeline of single character read operations outstanding. The reads completed as bytes arrived on the port, and could be dequeued in the main IOCP event loop. This gave very high performance at the cost of some code complexity.

This approach will not work as readily with boost::asio because only one outstanding read is permitted. You could try to implement a Windows IOCP based serial port back end for Windows for asio, or you could have a separate IOCP and thread for serial comms.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM