Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to setup QSerialPort on a separate thread?

Following the official documentation I'm trying to do this:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    QThread *thread = new QThread;    
    Worker *worker= new Worker();

    worker->moveToThread(thread);

    //init connections

    thread->start();
}

Worker constructor:

Worker::Worker(QObject *parent) :
    QObject(parent)
{
    serial = new QSerialPort(this);  //passing the parent, which should be the current thread      
}

No compiling errors but when I execute it throws me this:

QObject: Cannot create children for a parent that is in a different thread. 
(Parent is QSerialPort(0x11bd1148), parent's thread is QThread(0x11bd2ef8), current thread is QThread(0x3e47b8)

Namely, it's telling me that serial has as a parent the main thread and not the thread that I have created.

The same result if I don't instantiate serial in the constructor but in the main process, which is triggered after we've called thread->start():

Worker::Worker(QObject *parent) :
    QObject(parent)
{             
}

Worker::doWork()
{
    if(!serial)
        serial= new QSerialPort(this); 

    //...
}

What am I missing?


Send function as an example (a slot):

void Worker::send(const QByteArray &data)
{
    serial->write(data);
    if( serial->waitForBytesWritten(TIMEOUT) )
        qDebug() << "sent: " << data;
}
like image 780
anat0lius Avatar asked May 09 '14 08:05

anat0lius


1 Answers

In short, it is a bad idea to use the QtSerialPort module like this.

We designed this module based on QIODevice which already provides you non-blocking mechanism for your GUI application to use the QSerialPort class.

You should look into the following signals:

void QIODevice::bytesWritten(qint64 bytes) [signal]

This signal is emitted every time a payload of data has been written to the device. The bytes argument is set to the number of bytes that were written in this payload. bytesWritten() is not emitted recursively; if you reenter the event loop or call waitForBytesWritten() inside a slot connected to the bytesWritten() signal, the signal will not be reemitted (although waitForBytesWritten() may still return true).

and...

void QIODevice::readyRead() [signal]

This signal is emitted once every time new data is available for reading from the device. It will only be emitted again once new data is available, such as when a new payload of network data has arrived on your network socket, or when a new block of data has been appended to your device.

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 (although waitForReadyRead() may still return true).

Note for developers implementing classes derived from QIODevice: you should always emit readyRead() when new data has arrived (do not emit it only because there's data still to be read in your buffers). Do not emit readyRead() in other conditions.

I wrote two examples for doing this through the command line which you can find in here:

Command Line Writer Async Example

Command Line Reader Sync Example

like image 106
lpapp Avatar answered Nov 04 '22 11:11

lpapp