PDA

View Full Version : Hints to design threaded serial-reader/writer interface ?



oldFox64
24th April 2014, 07:58
Already created a GUI-program that reads & writes (mostly writes) through serial port with an event loop. I managed more or less that the GUI be responsive but logically the right way is to use threads. So my intention is to move the reading & writing of serial port on a separate thread.

What I have until now:



class SerialIO : public QThread
{
Q_OBJECT

public:
SerialIO(QObject *parent = 0);
~SerialIO();
void run();
void addData(const QByteArray); //to out_buffer
const QByteArray getData(); //from in_buffer

signals:
//not sure...
void readyToSend();
void readyToRecv();

public slots:
void send();
void recv();

private:
QSerialPort *serial;
QBuffer out_buffer;
QBuffer in_buffer;


};


As the main task is to write a file through the serial port, my idea is to inject the file line by line, filling the buffer and the thread class will send it at his own pace. What I receive are ACK's basically.

anda_skoa
24th April 2014, 09:40
I am not sure what you mean with "logically right way".

Usually taking something that works and making it harder to debug and maintain is more likely the opposite of logical :)

Cheers,
_

oldFox64
24th April 2014, 09:52
it """works""", I mean, I made something very dirty.

I know that the proper way to do this is with threads. I did another very similar project but in Java, which was easier for me thanks to a more complete API.

stampede
24th April 2014, 11:24
My hint is - don't mix the logic and implementation. Application "logic" requires that there should be an object that handles communication with the serial port, but the fact that it should/shouldn't use threads is specific to implementation (another "logic" requirement could be that it shouldn't block the ui, but that can be achieved without threads). So my suggestion is to wrap the serial communication mechanism into a class interface, and use some threading mechanism as another layer - through QThread, thread pools, QtConcurrent or whatever suits your needs.
So don't do this:

class SerialIO : public QThread
{
...
}
// what does it even mean that "Every SerialIO object is a kind of Thread object" ?

but rather:


class SerialIO : public QObject
{
...
}
...

SerialIO * io = new SerialIO(...);
QThread * thread = new QThread(...);
io->moveToThread(thread);

this way you have a possibility to enable / disable threading support for the serial io without changing the core communication code.

anda_skoa
24th April 2014, 13:06
I know that the proper way to do this is with threads. I did another very similar project but in Java, which was easier for me thanks to a more complete API.

Java is a bad example in this context, because it lacked asynchronous I/O for a long time and a lot if its APIs are still blocking by default.

Qt, on the other hand, is primarily designed to be non-blocking, I/O being handled asynchronously (operation returning immediately, results being signalled).

If you really must increase the complexity of your program then the approach suggested by stampede is usually the way to go.
It allows everything to be tested with a single thread, etc.

Cheers,
_

oldFox64
5th May 2014, 16:03
Now I discover that QBuffer's aren't usable for my case, as they only "grow" and don't remove data when they are been read.

Which data structure should I use as a buffer if I want the buffer removes the data that has been read ?

Something like this:
http://tutorials.jenkov.com/images/java-nio/buffers-modes.png

anda_skoa
5th May 2014, 16:27
Doesn't the internal buffer of the QIODevice already do that?

Cheers,
_