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 ofSerialConnection::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 stoppedBefore 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; }
-
Most likelly, a problem is in your code or a HW.
To check out the QSP, you can:
- Install com0com virtual port drivers (or any other).
- Create the COM port pair there.
- Write a simple console 'sender' app which will periodically send the data.
- Write a simple console 'receiver' app which will receive the data.
- Launch both apps to see what happens.
- 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