Multiple serialport write in one call.
-
I'm writing strings to device through serial port. My function sends the same command twice with an interval of 3 seconds as following code.
QSerialPort m_curSerial; //initializing process hidden m_curSerial.write(command); qDebug()<<"flush"<<m_curSerial.flush(); qDebug()<<QDateTime::currentDateTime(); QThread::sleep(3); m_curSerial.write(command); qDebug()<<"flush"<<m_curSerial.flush(); qDebug()<<QDateTime::currentDateTime();
Then I handle the byteWritten signal, only print a timestamp
void SerialDevice::handleBytesWritten(){ qDebug()<<"bytes written"; qDebug()<<QDateTime::currentDateTime(); }
the output is somehow beyond expectation:
flush true QDateTime(2018-11-26 16:52:55.051 flush true QDateTime(2018-11-26 16:52:58.052 bytes written QDateTime(2018-11-26 16:52:58.057 bytes written QDateTime(2018-11-26 16:52:58.057 read ready "@00FA00400000000102000040*\r" read ready "@00FA00400000000102000040*\r"
Two commands are flushed at 52:55 and 52:58. But the bytesWritten signal are only emitted together after the second write finished, so are the readReay signals.
I also tried sending more commands with longer interval , but the signals are still emitted after the last command flushes. There is a flash light on my R232 cable, it shows the commands are actually written to device at 3 second interval, It is the signals which are delayed.
Is it just how the signals work or am I getting anything wrong? How can I catch the byteWritten and readReady signal after each succesful write?
Any hint appreciated, Thanks
-
1st If you need something like this you should really think about your design.
The solution is replacing
QThread::sleep(3);
withQEventLoop waiter; QTimer::singleShot(3000,&waiter,&QEventLoop::quit); waiter.exec();
The signals will be sent as soon as the control goes back to an event loop.
QThread::sleep(3);
blocks that loop -
QSerialPort can only send when the Qt event loop is reached, which does not happen until after both write() calls are done. You will not receive bytesWritten() signals until that time.
In general Qt QIODevice interfaces are intended to be driven in asynchronous fashion. To get the synchronous behaviour you were expecting you probably need a waitForBytesWritten() call after each write(). Even then, it does not guarantee that the entire command has been written, just at least one byte.
-
@mondo said in Mutiple serialport write in one call.:
QSerialPort m_curSerial;
//initializing process hidden
m_curSerial.write(command);
qDebug()<<"flush"<<m_curSerial.flush();
qDebug()<<QDateTime::currentDateTime();QThread::sleep(3);
m_curSerial.write(command);
qDebug()<<"flush"<<m_curSerial.flush();
qDebug()<<QDateTime::currentDateTime();For the love if ..
Do NOT use QThread::sleep if you can avoid it! -
Thanks for replying.
So the key issue is the event loop. This code piece is a simplifed piece for finding the problem. The real stuff I needed was an independent thread which send the same command to my device all the time.void Scheduler::targetReadyCheck(){ std::thread initThread(&Scheduler::targetReadyCycle, this); initThread.detach(); } void Scheduler::targetReadyCycle(){ bool isReady; while(true){ isReady = plc->checkTargetReady(); } } }
The checkTargetReady() function contains the code I posted above which write to the serial port. I found the commands are written but no signal emitted. Then I came to the simplied code to locate the issue.
Now I'm changing Qthread:sleep to QTimer, and trying methods to trigger the event loop.
Will post the results later and close the question.
Thanks again. -
You should probably have a look at the http://doc.qt.io/qt-5/qtserialport-cwriterasync-serialportwriter-cpp.html example
-
Alright.
Here is my conclusion:First, "you should never ever block the event loop"
Second, use timer to call functions repeatively to replace an infinite loop
concluded from replies above and this post [https://stackoverflow.com/questions/17514890/qthread-event-loop-and-infinite-work-loop](link url)
For now Qtimer solves my problem.
Thanks all for replying