Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QSerialPort stops receiving with latest QT > 5.7



  • I have to add some features to an existing application that was created with QT5.7. The application reads data from an embedded camera using our own serial protocol by USB. The camera is sending it data continuously. With the original application I recorded data over several hours.
    For the new features I updated QT to the latest version 5.12 and run into the problem that the communication stops after receiving some data. Disconnecting and reconnecting, receives again just some data, that means the camera can be excluded as the problem. During analyzing I found the problem is the QSerialport class with another behaviour in newer QT versions. For analyzing I reduced the application to the serial communication class see below and found the following behavior (output of SerialConnection::readRxData()):
    [data package counter] Data received: [received data size]

    Compiling with QT5.7 MinGw5.3.0 32bit
    Runs forever. The data packet are 512 bytes
    Output:
    1743063 Data received: 512
    1743064 Data received: 512
    1743065 Data received: 512
    1743066 Data received: 512
    1743067 Data received: 512
    1743068 Data received: 512

    Compiling with QT5.11.3 MinGW5.3.0 32bit
    Stops after a some bytes. The data packets are mostly 4096 bytes, but flucuating
    Output:
    8313 Data received: 4096
    8314 Data received: 1614
    8315 Data received: 4096
    8316 Data received: 4096
    8317 Data received: 4096
    8318 Data received: 4096
    8319 Data received: 4096
    8320 Data received: 4096
    8321 Data received: 13902
    [receivement stopped]

    Compiling with QT5.12.1 MinGW7.3.0 64bit
    Stops quite fast. The data packets are mostly 4096 bytes, flucuating, I can force the stop when producing mouse events
    Output:
    221 Data received: 4096
    222 Data received: 4096
    223 Data received: 4096
    224 Data received: 1614
    225 Data received: 4096
    226 Data received: 4096
    227 Data received: 16384
    receivement stopped

    Before the class stops I always see the last received data is quite large, mostly around 1638x bytes.

    Does somebody know why this happens?
    Thank you for every help

    This is my code to reproduce the problem:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QThread>
    #include "SerialConnection.h"
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui;
        SerialConnection serial;
    };
    
    #endif // MAINWINDOW_H
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        serial.open();
        serial.sendCommand(7,0);
    }
    
    
    
    
    #ifndef SERIAL_CONNECTION_H
    #define SERIAL_CONNECTION_H
    
    #include <QObject>
    #include <QSerialPort>
    #include "ConnectionStatus.h"
    
    class SerialConnection: public QObject
    {    
        Q_OBJECT
    
    public:
        SerialConnection(QObject *parent = nullptr);
        ~SerialConnection();
        void open();
        void close();
        bool isOpen() const;
        void waitForCommunication();
        void sendCommand(const unsigned char selector, const int value);
        void sendHandShake(const bool connected);
    
    
    Q_SIGNALS:
        void newConnectionStatus(const ConnectionStatus status);
    
    private Q_SLOTS:
        void readRxData();
        void timeout();
        void portDestroyed();
        void handleError(QSerialPort::SerialPortError error);
    
    private:    
        QSerialPort *m_pport;
        bool m_txIsBusy;
    };
    
    #endif // SERIAL_CONNECTION_H
    
    
    
    #include "SerialConnection.h"
    #include <QSerialPortInfo>
    #include <QtCore>
    #include <QTimer>
    #include <QDebug>
    #include <cassert>
    
    //The device with this pid/vid is opened
    #define TARGET_VID 0x483
    #define TARGET_PID 0x5740
    
    #define COMMAND_SIZE 10
    #define COMMAND_START_MARKING 0xAA
    #define COMMAND_END_MARKING   0x55
    
    
    #define HS_START_MARKING 0xBB
    
    
    SerialConnection::SerialConnection(QObject *parent) : QObject(parent)
    {
        m_pport = new QSerialPort(parent);
        m_txIsBusy = false;
        connect(m_pport, &QSerialPort::readyRead, this, &SerialConnection::readRxData);
        //connect(m_pport, &QSerialPort::error, this, &SerialConnection::handleError);
        // QT 5.12 connect(m_pport, &QSerialPort::errorOccurred, this, &SerialConnection::handleError);
        connect(m_pport, &QSerialPort::destroyed, this, &SerialConnection::portDestroyed);
    }
    
    SerialConnection::~SerialConnection()
    {
        delete m_pport;
    }
    
    void SerialConnection::open()
    {
      bool foundDevice = false;
      const auto infos = QSerialPortInfo::availablePorts();
    
      //Search for the virtual com port device that matches vid and pid
      for (const QSerialPortInfo &info : infos)
      {
        int vid = info.vendorIdentifier();
        int pid = info.productIdentifier();
        if ((vid == TARGET_VID) && (pid == TARGET_PID))
        {
            m_pport->setPortName(info.portName());
            foundDevice = true;
            break;
        }
      }
    
      if (foundDevice == false)
      {
          Q_EMIT newConnectionStatus(ConnectionStatus::ERROR_DEVICE_NOT_FOUND);
      }
      else
      {
          m_txIsBusy = false;
    
          bool ok = m_pport->open(QIODevice::ReadWrite);
          if (ok)
          {
              sendHandShake(true);
              Q_EMIT newConnectionStatus(ConnectionStatus::CONNECTED);
          }
      }
    }
    
    void SerialConnection::close()
    {
      waitForCommunication();
      sendHandShake(false);
      Q_EMIT newConnectionStatus(ConnectionStatus::DISCONNECTED);
      if (m_pport->isOpen())
      {
          m_pport->close();
      }
    }
    
    
    void SerialConnection::handleError(QSerialPort::SerialPortError error)
    {
        if (error == QSerialPort::NoError)
        {
            return;
        }
    
        if ((error == QSerialPort::ResourceError) || (error == QSerialPort::TimeoutError))
        {
            Q_EMIT newConnectionStatus(ConnectionStatus::ERROR_UNKNOWN);
            close();
        }
    }
    
    
    void SerialConnection::portDestroyed()
    {
    
    }
    
    
    bool SerialConnection::isOpen() const
    {
        if (m_pport != nullptr)
        {
            return m_pport->isOpen();
        }
        return false;
    }
    
    void SerialConnection::sendCommand(const unsigned char selector, const int value)
    {
      if ((m_pport == nullptr) || (m_pport->isOpen() == false))
      {
        return;
      }  
    
    
      qDebug() << "Write: " << selector << ", " << value << endl;
      while(m_txIsBusy)
      {
        QCoreApplication::processEvents();
      }
    
      //byte 0: start of command, byte 1: selector (which value), byte 2..8: data, byte 9: end of command
      char data[COMMAND_SIZE];
      data[0] = COMMAND_START_MARKING;
      data[1] = selector;
      data[2] = (value >> 24) & 0xFF;
      data[3] = (value >> 16) & 0xFF;
      data[4] = (value >> 8) & 0xFF;
      data[5] = value & 0xFF;
      data[9] = COMMAND_END_MARKING;
      if (m_pport->write(data, sizeof(data)) == -1)
      {
          assert(false);
      }
      m_txIsBusy = true;
      QTimer::singleShot(100, this, SLOT(timeout()));
    }
    
    void SerialConnection::sendHandShake(const bool connected)
    {
      if ((m_pport == nullptr) || (m_pport->isOpen() == false))
      {
        return;
      }
    
      while(m_txIsBusy)
      {
        QCoreApplication::processEvents();
      }
    
      //byte 0: start of command, byte 1: selector (which value), byte 2..8: data, byte 9: end of command
      char data[COMMAND_SIZE];
      data[0] = HS_START_MARKING;
      data[1] = connected;
      data[2] = 0;
      data[3] = 0;
      data[4] = 0;
      data[5] = 0;
      data[9] = COMMAND_END_MARKING;
      if (m_pport->write(data, sizeof(data)) == -1)
      {
          assert(false);
      }
    
      QTimer timer;
      timer.setSingleShot(true);
      timer.start(1000);
    
      while(timer.isActive())
      {
        QCoreApplication::processEvents();
      }
    }
    
    void SerialConnection::waitForCommunication()
    {
      while(m_txIsBusy)
      {
        QCoreApplication::processEvents();
      }
    }
    
    void SerialConnection::readRxData()
    {
        static int cnt = 0;
    
        QByteArray array = m_pport->readAll();
        //qDebug() << "Data received: " << array.size() << "BufferSize=" << m_pport->readBufferSize() << endl;
        qDebug() << "#" << ++cnt << " Data received: " << array.size() << endl;
    
        return;
    }
    
    
    
    void SerialConnection::timeout()
    {
      m_txIsBusy = false;
    }
    
    
    

  • Qt Champions 2020

    Most likelly, a problem is in your code or a HW.

    To check out the QSP, you can:

    1. Install com0com virtual port drivers (or any other).
    2. Create the COM port pair there.
    3. Write a simple console 'sender' app which will periodically send the data.
    4. Write a simple console 'receiver' app which will receive the data.
    5. Launch both apps to see what happens.
    6. If the stream will be stopped - this means that a problem is in QSP.

    PS: Also you need to handle the QSP::errorOccurred() signal!
    PS: Also, using while() it is a bad idea.



  • @kuzulis I installed com0com and have written a sender, but the behaviour is completely different and I can't reproduce the problem. The sent datablocks are received in the same size (up to 4096bytes) and the same time independent of the blocksize and speed I use to send the data. I don't think this approach helps...
    PS: The errorOccurred is handled and I doen't get an error. I commented it out for using QT5.7


Log in to reply