How to properly handle shared hardware resources? #103
-
We are currently experimenting with qcoro for use in our hardware control software. Typically, our software communicates with hardware via commands where a command or query is sent, and then a response is received and processed. Previously, we were doing this via a "heartbeat" where we repeatedly call a slot at a given interval (using a At time, we also need to send explicit commands to the device (to turn something on or off for example). How can we reliably use coroutines sharing the same communication port and maintain the periodic checks while also being able to send arbitrary commands? Is there a better strategy we should be using? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 8 replies
-
I think the coroutines are a good solution for this - consider that whenever a QCoro coroutine is suspended, the execution returns to caller (so, usually the Qt event loop). Thus you can have as many "service" coroutines as you want and always only one is executing at a time, the others are suspended (as long as everything is single-threaded, of course) - same as Qt slots. If I understand your description correctly, a fictional // Heartbeat coroutine
QCoro::Task<> Comm::heartbeat() {
QTimer sleep;
sleep.start(1s);
while (mSocket->open()) {
co_await sleep;
const auto stats = co_await command("default");
}
}
// Sends a command and waits for response
QCoro::Task<QByteArray> Comm::command(const QByteArray &command) {
mSocket->write(command);
co_await mSocket->waitForReadyRead();
// Don't use readAll() in real code as that might eat up multiple pending responses
// Real implementation depends on your protocol design.
co_return mSocket->readAll();
}
void Comm::start() {
// Start the coroutine from the event loop
QMetaObject::invokeMethod(this, &Comm::heartbeat, Qt::QueuedConnection);
}
void Comm::stop() {
// Causes the heartbeat coroutine to terminate at latest in 1 second (next time the timer wakes up the
// coroutine) - tthis might need som extra "synchronization"
// as you definitely want to make sure the coroutine ends before destroying the Comm object.
mSocket->close();
} Regarding sending commands, it's safe to do so (as long as you are on the same thread as the other coroutines), since either the Hope this helps. |
Beta Was this translation helpful? Give feedback.
I think the coroutines are a good solution for this - consider that whenever a QCoro coroutine is suspended, the execution returns to caller (so, usually the Qt event loop). Thus you can have as many "service" coroutines as you want and always only one is executing at a time, the others are suspended (as long as everything is single-threaded, of course) - same as Qt slots.
If I understand your description correctly, a fictional
Comm
class might look something like this: