Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QSerialPort readLine() extremely slow compared to readAll()

The data I'm reading from a serialport (in Qt, using QtSerialPort/QSerialPort) is separated by the newline '\n' and return '\r' characters, which is the way I intend to look at it for parsing. The line length may very, but it is very easy to extract the data from the format of each line.

//signal/slot connection on readyRead() is as follows:
connect(serial, SIGNAL(readyRead()), this, SLOT(readData()));

where readData() is defined as:

void MainWindow::readData()
{
   //As mentioned below, which I will reiterate, I have already tried the addition of 
   // canReadLine():
   if (serial->canReadLine()){
     QByteArray data = serial->readLine();
     //QByteArray allData = serial->readAll();
     parseSerialBytes(data);
     //console->putData(data);
     //console->putData(alldata);
   }
}

However, the QIODevice::readLine() function is extremely slow, and clearly blocking data from being received at full frequency compared to QIODevice::readAll()

Can someone please explain how to properly use the readLine() function so I don't have to loop through readAll() into the QByteArray to parse each line? I used the "terminal" Qt Widgets example to create this asynchronous serialport read functionality.

Thanks in advance - this seems to be a common problem I have not yet seen answered here.

like image 495
Rachael Avatar asked Jul 15 '14 22:07

Rachael


Video Answer


1 Answers

This is a common error. The readData is called only once per a chunk of data, not necessarily once per line.

You need to keep reading lines as long as data is available. It is also a bad design to have serial line reading in a widget class. Move it to a separate object.

class Receiver : public QObject {
  Q_OBJECT
  QSerialPort m_port;
  QByteArray m_buffer;
  void processLine(const QByteArray & line) {
    ...
  }
  Q_SLOT void readData() {
    // IMPORTANT: That's a *while*, not an *if*!
    while (m_port.canReadLine()) processLine(m_port.readLine());
  }
public:
  Receiver(QObject * receiver = 0) : QObject(parent) {
    connect(&m_port, &QIODevice::readyRead, this, &Receiver::readData);
    ...
  }
}

Your error was to implement readData as shown below. Such code reads only one line no matter how many lines are available to be read. It'll appear "slow" since on each invocation there's more and more accumulated data that's left behind unread. Eventually it'll run out of heap.

void readData() {
  // WRONG!
  if (m_port.canReadLine()) processLine(m_port.readLine());
}
like image 88
Kuba hasn't forgotten Monica Avatar answered Sep 19 '22 22:09

Kuba hasn't forgotten Monica