QSerialPort wait for response
-
Hi,
I am working on an application which communicates with a tool via the serial port. I have a GUI and need to be able to send a command via the serial port and wait for reply with a given length until timeout, but the GUI needs to stay responsive. Can you point me to a suitable example?
Thanks
-
@Spiel Use https://doc.qt.io/qt-5/qiodevice.html#readyRead and a QTimer
-
@Spiel said in QSerialPort wait for response:
Can you point me to a suitable example?
you may want to look at the terminal example as well.
-
@jsulm Can you please expand a bit on that suggestion? Currently I am using a method called
send(data, responseLength, timeout)
, which simulates a synchronous operation without blocking the main event loop, by having a separateQEventLoop
. I'd like to rework the code and get rid of theQEventLoop
.If I connect a slot to the
readyRead
signal, which buffers the data, and start aQTimer
each time I send data, I will be able to check if data of certain length has been received in a slot connected to the timer's timeout. However thesend
method will return immediately, and that will break my application logic. -
@Spiel There is absolutely no need for separate event loops! Qt is an asynchronous framework and QSerialPort also has asynchronous API. Please read documentation and take a look at examples (for example the one pointed out by @Pablo-J-Rogina).
Back to my suggestion: it should be clear how to implement a slot and connect it to a signal? So, implement a slot and connect it to https://doc.qt.io/qt-5/qiodevice.html#readyRead If you don't know how to do this please read https://doc.qt.io/qt-5/signalsandslots.html
Then, after sending the command you start QTimer with your timeout. If you get a response your slot connected to readyRead signal will be called. If the slot is called before timeout from QTimer then everything is fine if it is called after timeout you can ignore it (or do what ever you want to do in this case). -
@Spiel said in QSerialPort wait for response:
send a command via the serial port and wait for reply with a given length until timeout, but the GUI needs to stay responsive.
...
make an asynchronous operation look like a synchronous operation for the caller, without using a nested event loop.
You have listed 3 requirements:
- Responsive GUI
- Synchronous function
- No separate event loop
It is not possible to have all 3; you must choose 2. Which two are most important to you?
-
@JKSH said in QSerialPort wait for response:
No separate event loop
This was my requirement :-)
@Spiel Do you really really need a synchronous operation?
-
I believe I do need synchronous operation. Please bear in mind that I only have less than two months of desktop programming, so I am probably getting a lot of concepts wrong at this point.
The application I am working on communicates with an embedded device using a number of different commands, in no particular order, and the responses vary in length. Each step depends on the outcome of the previous - hence I need to somehow wait until I get a response for a command, before deciding what should I do next. I've built my application using the nested
QEventLoop
, which allowed me to have pseudo-synchronous operation. However, after conversing with colleagues and doing some research, I found that my approach will lead to subtle bugs. Now I face a situation where I need to redesign my code logic in order to avoid that.I am open to suggestions how to do that.
-
@Spiel said in QSerialPort wait for response:
hence I need to somehow wait until I get a response for a command
No, you don't have to wait. The basic idea is: send command and as soon as you get response (via readyRead signal) you know that the command is processed and you can send next one. This way of programming can be confusing at the beginning, but this is how asynchronous APIs/frameworks (like Qt) work. It is better to do it this way instead of working against the framework/API.
-
@jsulm said in QSerialPort wait for response:
@JKSH said in QSerialPort wait for response:
No separate event loop
This was my requirement :-)
OP did say "I'd like to rework the code and get rid of the
QEventLoop
"@Spiel said in QSerialPort wait for response:
The application I am working on communicates with an embedded device using a number of different commands, in no particular order, and the responses vary in length. Each step depends on the outcome of the previous - hence I need to somehow wait until I get a response for a command, before deciding what should I do next.
I agree with @jsulm -- synchronous operations are not needed for this.
Depending on how many possible paths/branches your logic can take, you might benefit from a State Machine architecture (see https://www.mathworks.com/videos/understanding-state-machines-what-are-they-1-of-4-90488.html for an intro).
Each "step" could be represented as a state on the state machine diagram. Each time you receive the
readyRead()
signal from the serial port, you would process the response and then decide which state transition to take.