Cannot read QSerialPort without event loop
-
wrote on 12 Jan 2018, 09:03 last edited by
Hi all,
i am writing a library which uses QSerialPort and has no event loop. Sending data works fine, but i cannot receive any. QSerialPort does not report any errors.
According to the documentation all QIODevices should work without an event loop, so i am missing something. But what am i missing?
Using QT 5.9.3 on Win7 x64 with MinGW. My code:... if(!port.open(QIODevice::ReadOnly)) { switch (port.error()) { case QSerialPort::DeviceNotFoundError: { qCritical("Port with name \"%s\" not found", port.portName().toLocal8Bit().constData()); return PORT_NOT_EXIST; } case QSerialPort::PermissionError: { qCritical("No permission to open serial port"); return PORT_NO_ACCESS; } case QSerialPort::OpenError: { qCritical("Port is already in use"); return PORT_BUSY; } default: { qCritical("Unknown error while opening the port"); return PORT_OPEN_UNKNOWN; } } } std::thread thread(readPort, &port); thread.join(); port.close(); } void readPort(QSerialPort* port) { for(qint64 startTime = QDateTime::currentSecsSinceEpoch()+10;QDateTime::currentSecsSinceEpoch() < startTime;std::this_thread::sleep_for(std::chrono::milliseconds(100))) { QByteArray data = port->read(100); if(!data.isEmpty()) { qInfo("Read data %s", data.constData()); } } }
-
wrote on 12 Jan 2018, 14:35 last edited by
The documentation for QSerialPort says:
QSerialPort provides a set of functions that suspend the calling thread until certain signals are emitted. These functions can be used to implement blocking serial ports:
waitForReadyRead() blocks calls until new data is available for reading.
waitForBytesWritten() blocks calls until one payload of data has been written to the serial port.I think you should try waitForReadyRead() instead of implementing your own pooling.
-
The documentation for QSerialPort says:
QSerialPort provides a set of functions that suspend the calling thread until certain signals are emitted. These functions can be used to implement blocking serial ports:
waitForReadyRead() blocks calls until new data is available for reading.
waitForBytesWritten() blocks calls until one payload of data has been written to the serial port.I think you should try waitForReadyRead() instead of implementing your own pooling.
I think you should try waitForReadyRead() instead of implementing your own pooling.
he can try, but I think the problem stays the same: you need an event loop.
that said, I have written a DLL (closed source, sorry) for serial communication. if that was called from a Qt program, all was fine.
for non Qt programs, I changed it in a way to let QtSerialPort run in a QThread (a bit difficult), und created an event loop in the DLL if
QCoreApplication::instance
wasNULL
.maybe @kuzulis has some more comments?
-
wrote on 12 Jan 2018, 16:54 last edited by
The same documentation page for QSerialPort states that:
A blocking serial port does not require an event loop and typically leads to simpler code.
So I assumed that waitForReadyRead() might somehow handle this internally. If there's a QCoreApplication instance, maybe he could also call processEvents() inside his "for" to emulate a event loop.
-
Oh ?!
So even
bool QIODevice::waitForReadyRead(int msecs)
says
"This function can operate without an event loop."Its not in a way we except ?
-
Oh ?!
So even
bool QIODevice::waitForReadyRead(int msecs)
says
"This function can operate without an event loop."Its not in a way we except ?
-
wrote on 13 Jan 2018, 16:11 last edited by
Thank you all for your input. Using waitForReadyRead did unfortunately not change anything. I think instantiating QCoreApplication as long as it does not exist will be the best short term solution for this.
Should this be reported as bug? -
Thank you all for your input. Using waitForReadyRead did unfortunately not change anything. I think instantiating QCoreApplication as long as it does not exist will be the best short term solution for this.
Should this be reported as bug?@Hetsh said in Cannot read QSerialPort without event loop:
Should this be reported as bug?
Yes, please do (and add a link here). That way we dig deeper into the issue.
Thanks.
-
There are no any bug. You need in QCoreApplication instance anyway. This even not an QtSerialPort issue.
-
There are no any bug. You need in QCoreApplication instance anyway. This even not an QtSerialPort issue.
@kuzulis @mrjj @Leonardo @Hetsh
I prepared a documentation update to clarify the status quo: https://codereview.qt-project.org/216669
-
Hi @Hetsh,
As @kuzulis correctly said (in the doc review), there are two examples that work without event loop:
http://doc.qt.io/qt-5/qtserialport-creadersync-example.html
http://doc.qt.io/qt-5/qtserialport-cwritersync-example.htmlSo you will need a QCoreApplication, but not an event loop.
-
wrote on 15 Jan 2018, 13:56 last edited by
@aha_1980 The example works, but it is using the waitFor methods in the "main" thread, which i cannot do.
@kuzulis I instantiated QCoreApplication both in the main thread and in the polling thread without any success.I did a quick test on linux and it works without a QCoreApplication instance or event loop.
Back on windows I implemented the workaround from @aha_1980 by instantiating QCoreApplication in another thread and starting an event loop there. An important step is to move the port to the QCoreApplications thread. It won't work otherwise: https://pastebin.com/3sDcq3Hv
I filed a bug report.
Thank you all for your help :-)
-
Did creadersync example works for you?
-
Did creadersync example works for you?
-
I have answered in your BR, and closed it as invalid, because you use QSP wrong.
PS: It works even w/o of QCoreApplication instrance and w/o of event loop. But needs to use the QCoreApplication instance to avoid some future/others problems (it suggested everywhere in Qt, AFAIK).
-
I have answered in your BR, and closed it as invalid, because you use QSP wrong.
PS: It works even w/o of QCoreApplication instrance and w/o of event loop. But needs to use the QCoreApplication instance to avoid some future/others problems (it suggested everywhere in Qt, AFAIK).
-
I have answered in your BR, and closed it as invalid, because you use QSP wrong.
PS: It works even w/o of QCoreApplication instrance and w/o of event loop. But needs to use the QCoreApplication instance to avoid some future/others problems (it suggested everywhere in Qt, AFAIK).
wrote on 5 Jul 2022, 09:28 last edited by@kuzulis I am coding a Qt non-GUI DLL plugin that exports functions to do several things, including reading serial ports. These functions are called by an external .exe program (not using Qt, not coded by me) using a standardized API.
I have all sorts of bugs when using
QSerialPort
, as described in https://forum.qt.io/topic/137566/qserialport-with-no-gui-qobject-starttimer-timers-can-only-be-used-with-threads-started-with-qthread/12.How to use QSerialPort without threads, without QCoreApplication, without event-loop, but just blocking IO calls?
-
Qt Champions 2020wrote on 5 Jul 2022, 13:56 last edited by kuzulis 7 May 2022, 13:57
As an option, you can create a separate thread in your DLL, e.g. QThread. Then, create the QSerialPort and then move it to that thread... Maybe it will help... An idea is that QSerialPort should get a QThread as a parent.
AFAIK, it is not simple to use the Qt classes in the separate DLL's. It belongs not only to QSerialPort, it belongs also to other QIODevice and other classes. e.g. that classess can use the QTimer internally, which does not work without of an event loop... So, it is hard... I have not ideas.