Matteo Balugani
Matteo Balugani

Reputation: 11

QT: problems with the continuous reading of data from the serial port

I'm reading data from serial port with QT, in mainwindow I've write this code:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QTextStream>
#include<QSerialPort>
#include<QSerialPortInfo>
#include<QtDebug>
#include<QThread>
QSerialPort *serial;
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent),
     ui(new Ui::MainWindow),
      m_standardOutput(stdout)
{
     ui->setupUi(this);
    serial= new QSerialPort(this);
    serial->setPortName("COM3");
    serial->setBaudRate(QSerialPort::Baud115200);
    serial->setDataBits(QSerialPort::Data8);
    serial->setParity(QSerialPort::NoParity);
    serial->setStopBits(QSerialPort::OneStop);
    serial->setFlowControl(QSerialPort::NoFlowControl);
    serial->open(QIODevice::ReadOnly);



    connect(serial, &QSerialPort::readyRead, this, &MainWindow::ReaderH);

    float HUM;
     HUM=H;

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::ReaderH()
{

        quint64 X=20;
    serial->waitForReadyRead();
    m_readData=serial->QSerialPort::read(X);
    //if (!m_timer.isActive())
      //     m_timer.start(5000);
     inter2=QString(m_readData);
    QStringList firstlist2= inter2.split(";");
    m_readData3=firstlist2.takeFirst();
    H=m_readData3.toFloat();
     qDebug() <<"Data:"<<m_readData<< " \r\n";
    //QThread::sleep(11);


}

the program reads the data correctly for a few seconds, after a while the reading starts to be out of phase, like this:

Data: "60.904655;25.779804$"

Data: "60.970406;25.816269$"

Data: "60.988335;25.798037$"

Data: "60."

Data: "883736;25.7"

Data: "61570$"

Data: "60."

Data: "91063"

Data: "7;25.779804$"

Data: "60."

Data: "934544;25."

Data: "798037$"

Data: "60"

Data: ".871784;25.798037$"

I can't understand how to solve the problem. Thank you for your time.

Upvotes: 1

Views: 863

Answers (1)

Alexandre
Alexandre

Reputation: 506

When reading from a serial port, you need to cut the "stream" into "messages" yourself. You should not make any assumption about the timing of your data in order to be robust.

When data are received, you should input them to a "decoder", i.e. typically a class that reads byte per byte and finds the "delimiters" of the packets.

The decoder class usually have an internal buffer and may look like that:

class Decoder : public QObject
{
    Q_OBJECT

signals: 
    void messsageReceived(QByteArray message);

public:    
    void decode(const QByteArray& bytes)
    {
        for (char c : bytes)
        {
            if (c == '$')
            {
                emit messsageReceived(m_buffer);
                m_buffer.clear();
            }
            else
            {
                 m_buffer.append(c);
            }
        }
    }

private:
    QByteArray m_buffer;
};

Also there is usually no guarantee that you will start reading at the beginning of a packet. The first read might occur at the middle of a packet, that's why most protocol use a "Start" and a "Stop" sequence, or you should drop the first packet if you are not able to validate its consistency. In the snippet above, the first packet is not handled.

Also, serial ports do not guarantee to transmit bytes error free over the line, so it is mandatory to have a validation mechanism if the data are sensible, such as a checksum (i.e. CRC). If some data is corrupted, the packet should be dropped, and maybe a mechanism has to be put in place at a higher level so that the packet is re-transmitted (if needed).

Upvotes: 1

Related Questions