QSerialPort::waitForReadyRead() delays at least 5-10ms, how to make it respond faster?
-
Hi there,
I require a very tight back-and-forth between a fast 1GHz microprocessor and host PC, using the serial port (emulated via high-speed USB 2.0). Unfortunately the transferred data packets can't be batched, but are necessarily interleaved.
Upon sending a few bytes via serialPort->write(); the processor receives the data approximately 200µs later and answers around 50µs after that. During that time, the host waits synchronously via serialPort->waitForReadyRead(1);. I intentionally avoid the event loop and the asynchronous readyRead() signal since it would yield to the OS and incur a time delay of at least one scheduler time slice (~10ms or more), if I'm not mistaken.
Unfortunately, also the supposedly synchronous waitForReadyRead() doesn't return as soon as the data has arrived in the buffer, but it seems it also yields to the OS – it takes between 5 and 10ms at minimum, which is way too much for my application. In the QSerialPort code (see here), I believe it does this with a call to SleepEx, which according to the MSDN suspends the thread. I guess that's the root of the issue.
Is there a way to receive serial data in Qt or otherwise without suspending the thread? I'd like to avoid these unnecessary waits, as I know the client will respond literally within a couple of microseconds. I've tried to just serialPort->read() in a tight loop, but it never reads any data.
//EDIT: After digging into QSerialPort code a bit more, I believe the synchronous mode (waitForBytesWritten/waitForReadyRead) is not optimal as it is just propped on top of the asynchronous mode which is clearly the more common use-case.
As such, in method QSerialPortPrivate::startAsyncRead, it uses ::readFileEx which is asynchronous and calls back to QSerialPortPrivate::ioCompletionRoutine.
Wouldn't it be better to create a startSynchRead method which is then used for the synchronous operation of QSerialPort, which then uses the appropriate synchronous winAPI method ::readFile? Any thoughts or ideas for a quick fix not involving changing QSerialPort to be properly synchronous and not only pretend to? -
You can create your own serial port module to read the data as you want, even to use it synchronously.
PS: All Qt I/O classes use the asynchronous API, and all waitForXX() methods emulates it trougth the asynchronous calls (it waits for an completion events in blocking way).
UPD: I don't know, if it is possible to implement what you want at all at using non real-time OS's. As an option, you can read your serial data using the MCU's instead of USB2.0 serial port adapter, where you can measure this short time intervals. Or, to use the native Win32 API as you want instead of Qt class, to see if it possible at all.
-
Sounds like you should not be using QSerial and instead design a custom solution outside of Qt. Qt is not for real-time processing and your description of the task seems to imply real-time constraints.