QSerialPort::waitForReadyRead() unusable for quick responses
-
Re: [QSerialPort::waitForReadyRead() delays at least 5-10ms](how to make it respond faster?)
Why at all does it delay reading? I don't even need time criticality. I just want to be able to read my sensors response... How come waitForReadyRead discards the response, but readyRead is able to capture it in parallel?
I'm using a dedicated SerialPort thread to be able to write synchronized communication, which is much easier to read. You transmit something and block until you get the desired response in a single function instead of splitting it up across multiple signal/slots and trying to decipher which response belongs to which request. -
Re: [QSerialPort::waitForReadyRead() delays at least 5-10ms](how to make it respond faster?)
Why at all does it delay reading? I don't even need time criticality. I just want to be able to read my sensors response... How come waitForReadyRead discards the response, but readyRead is able to capture it in parallel?
I'm using a dedicated SerialPort thread to be able to write synchronized communication, which is much easier to read. You transmit something and block until you get the desired response in a single function instead of splitting it up across multiple signal/slots and trying to decipher which response belongs to which request.@InTheBeninging said in QSerialPort::waitForReadyRead() unusable for quick responses:
How come waitForReadyRead discards the response
What do you mean? It should not discard any data.
Can you show your code?From the documentation: "This function blocks until new data is available for reading and the readyRead() signal has been emitted". So, it will unblock after readyRead was emitted, but that should not cause any bigger slow down (unless you connect a slot to that signal and do something there).
-
@InTheBeninging said in QSerialPort::waitForReadyRead() unusable for quick responses:
How come waitForReadyRead discards the response
What do you mean? It should not discard any data.
Can you show your code?From the documentation: "This function blocks until new data is available for reading and the readyRead() signal has been emitted". So, it will unblock after readyRead was emitted, but that should not cause any bigger slow down (unless you connect a slot to that signal and do something there).
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); m_serialPort = new QSerialPort(this); m_serialPort->setPortName("COM5"); m_serialPort->setBaudRate(QSerialPort::Baud38400); m_serialPort->setDataBits(QSerialPort::Data8); m_serialPort->setParity(QSerialPort::NoParity); m_serialPort->setStopBits(QSerialPort::OneStop); m_serialPort->setFlowControl(QSerialPort::NoFlowControl); if (!m_serialPort->open(QIODevice::ReadWrite)) { qDebug() << "FAIL openSerialPort() can't open QSerialPort. Is the Device powered on?" << m_serialPort->errorString(); return; } qDebug() << "OK openSerialPort()"; QObject::connect(m_serialPort, &QSerialPort::readyRead, this, [&]{ QByteArray requestData = m_serialPort->readAll(); while (m_serialPort->waitForReadyRead(10)) requestData += m_serialPort->readAll(); qDebug() << QString::fromStdString(requestData.toStdString()) << requestData; }); QObject::connect(ui->pushButton_laserOff, &QPushButton::clicked, this, [&]{ char command[] = "%01#WLR+0000055\r"; int bytesWritten = m_serialPort->write(command, 16); bool portStatus = m_serialPort->waitForReadyRead(1000); if(!portStatus) { qDebug() << "FAIL serialWriteRead() TIMEOUT device unresponsive. SerialPort Error:" << m_serialPort->errorString() << "Bytes Written: " << bytesWritten << "Command:" << QString::fromStdString(std::string(command)) << m_serialPort->error(); return; } QByteArray requestData = m_serialPort->readAll(); while (m_serialPort->waitForReadyRead(10)) requestData += m_serialPort->readAll(); qDebug() << requestData; }); QObject::connect(ui->pushButton_laserOn, &QPushButton::clicked, this, [&]{ // char command[] = "%01#WLR+0000154\r"; char command[] = {'\x25','\x30','\x31','\x23','\x57','\x4C','\x52','\x2B','\x30','\x30','\x30','\x30','\x31','\x35','\x34','\x0D'}; int bytesWritten = m_serialPort->write(command, 16); bool portStatus = m_serialPort->waitForReadyRead(1000); if(!portStatus) { qDebug() << "FAIL serialWriteRead() TIMEOUT device unresponsive. SerialPort Error:" << m_serialPort->errorString() << "Bytes Written: " << bytesWritten << "Command:" << QString::fromStdString(std::string(command)) << m_serialPort->error(); return; } QByteArray requestData = m_serialPort->readAll(); while (m_serialPort->waitForReadyRead(10)) requestData += m_serialPort->readAll(); qDebug() << requestData; }); }
It always outputs whats written in the !portStatus, in other words waitForReadyRead always returns false, but the readyRead lambda is being run anyway...
-
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); m_serialPort = new QSerialPort(this); m_serialPort->setPortName("COM5"); m_serialPort->setBaudRate(QSerialPort::Baud38400); m_serialPort->setDataBits(QSerialPort::Data8); m_serialPort->setParity(QSerialPort::NoParity); m_serialPort->setStopBits(QSerialPort::OneStop); m_serialPort->setFlowControl(QSerialPort::NoFlowControl); if (!m_serialPort->open(QIODevice::ReadWrite)) { qDebug() << "FAIL openSerialPort() can't open QSerialPort. Is the Device powered on?" << m_serialPort->errorString(); return; } qDebug() << "OK openSerialPort()"; QObject::connect(m_serialPort, &QSerialPort::readyRead, this, [&]{ QByteArray requestData = m_serialPort->readAll(); while (m_serialPort->waitForReadyRead(10)) requestData += m_serialPort->readAll(); qDebug() << QString::fromStdString(requestData.toStdString()) << requestData; }); QObject::connect(ui->pushButton_laserOff, &QPushButton::clicked, this, [&]{ char command[] = "%01#WLR+0000055\r"; int bytesWritten = m_serialPort->write(command, 16); bool portStatus = m_serialPort->waitForReadyRead(1000); if(!portStatus) { qDebug() << "FAIL serialWriteRead() TIMEOUT device unresponsive. SerialPort Error:" << m_serialPort->errorString() << "Bytes Written: " << bytesWritten << "Command:" << QString::fromStdString(std::string(command)) << m_serialPort->error(); return; } QByteArray requestData = m_serialPort->readAll(); while (m_serialPort->waitForReadyRead(10)) requestData += m_serialPort->readAll(); qDebug() << requestData; }); QObject::connect(ui->pushButton_laserOn, &QPushButton::clicked, this, [&]{ // char command[] = "%01#WLR+0000154\r"; char command[] = {'\x25','\x30','\x31','\x23','\x57','\x4C','\x52','\x2B','\x30','\x30','\x30','\x30','\x31','\x35','\x34','\x0D'}; int bytesWritten = m_serialPort->write(command, 16); bool portStatus = m_serialPort->waitForReadyRead(1000); if(!portStatus) { qDebug() << "FAIL serialWriteRead() TIMEOUT device unresponsive. SerialPort Error:" << m_serialPort->errorString() << "Bytes Written: " << bytesWritten << "Command:" << QString::fromStdString(std::string(command)) << m_serialPort->error(); return; } QByteArray requestData = m_serialPort->readAll(); while (m_serialPort->waitForReadyRead(10)) requestData += m_serialPort->readAll(); qDebug() << requestData; }); }
It always outputs whats written in the !portStatus, in other words waitForReadyRead always returns false, but the readyRead lambda is being run anyway...
@InTheBeninging according to your code you don't even need these lines
while (m_serialPort->waitForReadyRead(10))
requestData += m_serialPort->readAll();You cannot connect ready read signal and directly after that call waitForReadyRead.It is bad coding
-
@InTheBeninging according to your code you don't even need these lines
while (m_serialPort->waitForReadyRead(10))
requestData += m_serialPort->readAll();You cannot connect ready read signal and directly after that call waitForReadyRead.It is bad coding
@Ronel_qtmaster Could you elaborate why?
-
@Ronel_qtmaster Could you elaborate why?
@InTheBeninging said in QSerialPort::waitForReadyRead() unusable for quick responses:
Could you elaborate why?
Already written: "This function blocks until new data is available for reading and the readyRead() signal has been emitted"
So you basically program a loop for no reason. Don't block, only use signals and slots.
-
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); m_serialPort = new QSerialPort(this); m_serialPort->setPortName("COM5"); m_serialPort->setBaudRate(QSerialPort::Baud38400); m_serialPort->setDataBits(QSerialPort::Data8); m_serialPort->setParity(QSerialPort::NoParity); m_serialPort->setStopBits(QSerialPort::OneStop); m_serialPort->setFlowControl(QSerialPort::NoFlowControl); if (!m_serialPort->open(QIODevice::ReadWrite)) { qDebug() << "FAIL openSerialPort() can't open QSerialPort. Is the Device powered on?" << m_serialPort->errorString(); return; } qDebug() << "OK openSerialPort()"; QObject::connect(m_serialPort, &QSerialPort::readyRead, this, [&]{ QByteArray requestData = m_serialPort->readAll(); while (m_serialPort->waitForReadyRead(10)) requestData += m_serialPort->readAll(); qDebug() << QString::fromStdString(requestData.toStdString()) << requestData; }); QObject::connect(ui->pushButton_laserOff, &QPushButton::clicked, this, [&]{ char command[] = "%01#WLR+0000055\r"; int bytesWritten = m_serialPort->write(command, 16); bool portStatus = m_serialPort->waitForReadyRead(1000); if(!portStatus) { qDebug() << "FAIL serialWriteRead() TIMEOUT device unresponsive. SerialPort Error:" << m_serialPort->errorString() << "Bytes Written: " << bytesWritten << "Command:" << QString::fromStdString(std::string(command)) << m_serialPort->error(); return; } QByteArray requestData = m_serialPort->readAll(); while (m_serialPort->waitForReadyRead(10)) requestData += m_serialPort->readAll(); qDebug() << requestData; }); QObject::connect(ui->pushButton_laserOn, &QPushButton::clicked, this, [&]{ // char command[] = "%01#WLR+0000154\r"; char command[] = {'\x25','\x30','\x31','\x23','\x57','\x4C','\x52','\x2B','\x30','\x30','\x30','\x30','\x31','\x35','\x34','\x0D'}; int bytesWritten = m_serialPort->write(command, 16); bool portStatus = m_serialPort->waitForReadyRead(1000); if(!portStatus) { qDebug() << "FAIL serialWriteRead() TIMEOUT device unresponsive. SerialPort Error:" << m_serialPort->errorString() << "Bytes Written: " << bytesWritten << "Command:" << QString::fromStdString(std::string(command)) << m_serialPort->error(); return; } QByteArray requestData = m_serialPort->readAll(); while (m_serialPort->waitForReadyRead(10)) requestData += m_serialPort->readAll(); qDebug() << requestData; }); }
It always outputs whats written in the !portStatus, in other words waitForReadyRead always returns false, but the readyRead lambda is being run anyway...
@InTheBeninging I'm really confused by this code. I don't see any threads here ("I'm using a dedicated SerialPort thread" - where?). You're doing the serial communication inside GUI thread. So, what you wrote in your first post here and the code do not match.
You're mixing readyRead with waitForReadyRead which you should not. And it is bad to wait for serial port in slots connected to buttons - this will block the UI until something arrives or timeout. -
@InTheBeninging I'm really confused by this code. I don't see any threads here ("I'm using a dedicated SerialPort thread" - where?). You're doing the serial communication inside GUI thread. So, what you wrote in your first post here and the code do not match.
You're mixing readyRead with waitForReadyRead which you should not. And it is bad to wait for serial port in slots connected to buttons - this will block the UI until something arrives or timeout.@jsulm said in QSerialPort::waitForReadyRead() unusable for quick responses:
this will block the UI until something arrives
nothing will arrive:
readyRead() is not emitted recursively; if you reenter the event loop or call waitForReadyRead() inside a slot connected to the readyRead() signal, the signal will not be reemitted
-
@Christian-Ehrlicher @J-Hilk @jsulm
I'm sorry I didn't clear this up, the given code is just a demo stripped off of my codebase. These lambdas are actual slots in my Worker object living in another thread. I'm sending Command Objects to said Worker, whose execution functions contain the functionality of the demod lambdas.It doesn't work either when i remove the use of the readyRead signal.
So you mean I can't use waitForReadyRead within a slot?
I have a couple other Serial Devices handled in the same manner and it works like intended. It's just that this particular sensor is responding too quick. -
@Christian-Ehrlicher @J-Hilk @jsulm
I'm sorry I didn't clear this up, the given code is just a demo stripped off of my codebase. These lambdas are actual slots in my Worker object living in another thread. I'm sending Command Objects to said Worker, whose execution functions contain the functionality of the demod lambdas.It doesn't work either when i remove the use of the readyRead signal.
So you mean I can't use waitForReadyRead within a slot?
I have a couple other Serial Devices handled in the same manner and it works like intended. It's just that this particular sensor is responding too quick.@InTheBeninging said in QSerialPort::waitForReadyRead() unusable for quick responses:
So you mean I can't use waitForReadyRead within a slot?
Yes. Don't use
waitForReadyRead
at all. I have not ideas why the Qt (which declares as an asynch framework) provides that blocking API at all.PS: You are mixing a hedgehog and a snake - the result is known. )))
-
Nevermind, it does work now. It was not even being too fast, as i found out my sensor has a delay parameter which i've set to 1 second and it still didn't work.
Turns out it was the hardware adapter I was using, that converted the RS485 Connection to a USB COM Port. It didn't work with the cheap one (ch340), but after switching to a more expensive one (ftdi) it magically worked. Seems to be depending on their drivers.
-
I InTheBeninging has marked this topic as solved on
-
@InTheBeninging said in QSerialPort::waitForReadyRead() unusable for quick responses:
So you mean I can't use waitForReadyRead within a slot?
Yes. Don't use
waitForReadyRead
at all. I have not ideas why the Qt (which declares as an asynch framework) provides that blocking API at all.PS: You are mixing a hedgehog and a snake - the result is known. )))
@kuzulis
Because that's exactly what this virtual function is for. In QIODevice it says "This function can operate without an event loop. It is useful when writing non-GUI applications and when performing I/O operations in a non-GUI thread."
So the latter part sounds exactly like what i did... I don't see why that would be bad design? Telling one not to use a function which is clearly meant to be used in a thread and completely ignoring the constraint to have a synchronous snippet/ a single function is just misleading at best.