Reading from and writing to the serial port at faster rate using serialPort->waitForReadyRead();
-
hi @Kira ,
there's multiple ways you can go here, but you should tell us more about the situation. For example why do you have to do the'processing in synchronous fashion? What is the limiting factor here?
Simplest sultion here, place your code after
waitforReadyRead
in its own slot and connect the signal to that. If you're relying on a return value, than better redesign your code :-)If you have to, there are some ways to force the event loop to process without exiting a function. (ProcessEvents() QEventLoop) But those should be used rarly, if at all.
-
I don't think you can get a response from a serial port anywhere near a nanosecond. If you send a single byte of data you may have a frame size of something like 10 bits. At a baud rate of 256k you are probably looking at something around 40 ns for every byte (assuming a 10 bit frame). This doesn't include whatever is at the other end (it must read, process, and respond).
I have noticed that the waitForReadyRead() signal can be slow depending on the type of data for some reason. I never figured out why but I suspect it may have something to do with the OS not having a way to signal when new data has arrived (which means Qt must periodically check for new data - ?).
The serial ports are buffered so writing data can seem instantaneous. In reality the data is slowly be written out the serial port long after the write() function has returned.
-
Hello,
Did you try to use QSerialPort::bytesAvailable() ?
like:while(serial.bytesAvailable() < 1){ //Data received }
I recommend to put some timeout with this way otherwise you can wait indefinitely in case no reply is received.
I had some issues with waitForReadyRead() on the past, so I reimplemented my own version
bool MySerialPort::waitForReadyRead(int msecs) { QElapsedTimer t; t.start(); while(QSerialPort::bytesAvailable() < 1 && t.elapsed() < msecs) QApplication::processEvents(); return QSerialPort::bytesAvailable() > 0; }
-
@J.Hilk : Here is part of my code:
qDebug()<<"Enter the loop"; elapsedTimer.start(); writeData(QString("X \n").toUtf8()); serialPort->waitForReadyRead(); readData = serialPort->readAll(); qDebug()<<"Print the response:"<<QString(readData).toUtf8(); elapsedTime = elapsedTimer.elapsed(); qDebug()<<"Time taken :"<<elasedTimer;
Actually my next program steps are dependent on the previous step of the serial device.
So i need to wait for the response form the device.
Can you please explain "place your code after waitforReadyRead in its own slot and connect the signal to that" & "If you have to, there are some ways to force the event loop to process without exiting a function. (ProcessEvents() QEventLoop) ":) -
@Gojir4 : Sure will try and let u know.
Can you just share the issue with waitForReadReady() if you don't mind, was it the time taken by the waitForReadReady();Hi I tried the first approach and it goes in infinite loop. I let the loop run for 10 sec. but no reply.
I can try the second approach but don't not sure will the data is available after the specified millisecs because. For the first approach the reply is not coming in seconds. Maybe it is requesting the serial port the data at such a fast rate that is not able to respond. -
@Kira said in Reading from and writing to the serial port at faster rate using serialPort->waitForReadyRead();:
Actually my next program steps are dependent on the previous step of the serial device.
So i need to wait for the response form the device.Well,
from the top of my head//this is really just the asynchronous call/react of QIODevice myClass::myClass(QObject *parent) : QObject(parent){ connect(serialPort, &QSerialPort::readyRead, this, functionPart2); } functionPart1(){ qDebug()<<"Enter the loop"; elapsedTimer.start(); writeData(QString("X \n").toUtf8()); } functionPart2(){ readData = serialPort->readAll(); qDebug()<<"Print the response:"<<QString(readData).toUtf8(); elapsedTime = elapsedTimer.elapsed(); qDebug()<<"Time taken :"<<elasedTimer; }
//If you like lambdas { qDebug()<<"Enter the loop"; elapsedTimer.start(); writeData(QString("X \n").toUtf8()); QMetaObject::Connection myConnection; myConnection = connect(serialPort, &QSerialPort::readyRead, [=]{ readData = serialPort->readAll(); qDebug()<<"Print the response:"<<QString(readData).toUtf8(); elapsedTime = elapsedTimer.elapsed(); qDebug()<<"Time taken :"<<elasedTimer; disconnect(myConnection); }); }
//Above code is untested
Can you please explain "place your code after waitforReadyRead in its own slot and connect the signal to that" & "If you have to, there are some ways to force the event loop to process without exiting a function. (ProcessEvents() QEventLoop) ":)
the idea would be to run a loop in your function, until the socket emits readyRead. To receive the signal, you event loop mustn't be blocked so you either have to periodically call ProcessEvents() or run a qevent loop.
But, again, this is bad code design, and there are better/other options here.
-
@J.Hilk : Thanks for the reply its clear enough to explain.
Regarding the first part earlier i was trying the same way as they are mentioned in example but i my case i had to search for other option.
I just wanted to ask one thing don't know whether its funny :o
Can i make my execution wait after writeData() and in the readready() slot can i emit a signal so that waiting code execution can start.
See the whole idea is to use signals and slot assuming it would take less time than the waitforReadReady(). -
Hi,
As suggested in another thread, you should consider modelling your process using a state machine.
That way you can exploit properly Qt's asynchronous mechanism while keeping your sequential logic under control.
-
@J-Hilk @Rondog @SGaist @Gojir4 :
Guys a small observation which i made would like to share:
I think i issue is not with waitForReadReady() i tried the example by implementing readready() signal but the time required is same.The problem is the request:
Please find the code belowfor (int p = 0; p < 5; p++ ){ writeData(QString("X \n").toUtf8()); serialPort->waitForReadyRead(); QByteArray readDataArray; readDataArray = serialPort->readAll(); qDebug()<<"Data Received"<<QString(readDataArray).toUtf8(); int elapsedCounter = elapsedTimer.elapsed(); qDebug()<<"Required Time:"<<elapsedCounter; QTest::qSleep(100) // Sleep After the response }
If i put a sleep in the above function all the response comes within 1 -2 millisec.
But if i remove the sleep first response comes within 1 millisec and the other responses comes after 100 millisec. approx.
Earlier i was thought that putting waitForReadReady() would nullify the execution time of the for loop and request would only be send after we receive a proper response. But it seems that next time the loop executes is giving some issue. Not able to figure out why is it happening. Does serial port requires somewait time after the request.Any one any idea why this situation is occurring and how this can be handled.
-
I never worked with the synchronous approach of IODevice, but I think, there's a reason, why theres a
waitForBytesWritten
as well.write the data, call waitForBytes written and time the response after that line. I would imagen, that the response time is continously around the 1-2 miliseconds.
-
@J.Hilk : Yes you are correcting but what i mentioned above is same for the asynchronous approach also. In example i have mentioned only the synchronous approach:
Please find the results below:
Note: Time in Millisecond:
Synchronous Approach:
Serial Port Outgoing data: "X \n"
Data Received "L"
Time: 1
Serial Port Outgoing data: "X \n"
Data Received "L"
Time: 99
Serial Port Outgoing data: "X \n"
Data Received "L"
Time: 100
Serial Port Outgoing data: "X \n"
Data Received "L"
Time: 98
Serial Port Outgoing data: "X \n"
Data Received "L"
Time: 99Asynchronous approach:
Serial Port Outgoing data: "X \n"
Serial Port Outgoing data: "X \n"
Serial Port Outgoing data: "X \n"
Serial Port Outgoing data: "X \n"
Serial Port Outgoing data: "X \n"
Serial Port Incoming data: "L"
Time: 1
Serial Port Incoming data: "L"
Time: 102
Serial Port Incoming data: "L"
Time: 202
Serial Port Incoming data: "L"
Time: 303
Serial Port Incoming data: "L"
Time: 403Here Asynchronous approach is taking more time that why i mentioned is there a issue with for loop for any other issues. :)
-
Guys figured the issue. Its basically the serial device which is talking the time to respond so the request are being queued. Code is basically fine. I tested with the other device and the output is given within 1 to 2 millisec with synchronous and asynchronous thread.
One piece of advice should i delete the thread or mark as solved because the issue does not seem to be of from QT Side.
-
@Kira said in Reading from and writing to the serial port at faster rate using serialPort->waitForReadyRead();:
One piece of advice should i delete the thread or mark as solved because the issue does not seem to be of from QT Side.
Just mark it as SOLVED, so others later that have the same problem can follow the instructions.
Thanks