Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make QSerialPort from Qt5.13.1 work?

Tags:

c++

windows

qt

qt5

Problem

QSerialPort from version 5.13.1 of the Qt library does not physically output data under Windows 7 and 10.

Example

In order to demonstrate the described problem I have prepared the following setup:

  1. Hardware

I have tested the connection between a PC with a physical serial port (COM1) and a real serial device, but for demonstration purposes I have created a simple loopback by connecting together pins 2 and 3 of the DSub connector of the PC, i.e. Tx and Rx.

  1. Software

The problem occurs in my own GUI applications, as well as in the official examples shipped with Qt. However, for the sake of the demonstration I wrote a very basic console app:

SerialBug.pro

QT -= gui
QT += serialport

CONFIG += console

SOURCES += \
        main.cpp

main.cpp

#include <QCoreApplication>
#include <QSerialPort>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QSerialPort port("COM1");

    port.setBaudRate(QSerialPort::Baud4800);
    port.setDataBits(QSerialPort::Data8);
    port.setStopBits(QSerialPort::OneStop);
    port.setParity(QSerialPort::NoParity);
    port.setFlowControl(QSerialPort::NoFlowControl);

    QObject::connect(&port, &QSerialPort::readyRead,
                     [&port](){
        qDebug() << port.readAll();
    });

    QObject::connect(&port, &QSerialPort::bytesWritten,
                     [](qint64 bytes){
        qDebug() << bytes;
    });

    QObject::connect(&port, &QSerialPort::errorOccurred,
                     [](QSerialPort::SerialPortError error){
        qDebug() << error;
    });

    if (port.open(QSerialPort::ReadWrite)) {
        qDebug() << port.write("Test");
    }

    return a.exec();
}

Result

Compiling and running the example code with MSVC2017 and Qt 5.13.0 in release mode, the following output is produced:

QSerialPort::NoError
4
4
"Test"

The exact same code compiled in release mode with MSVC2017, but this time with Qt 5.13.1, produces the following output:

QSerialPort::NoError
4

port.write returns 4, meaning 4 bytes are send to the serial port, but that is not actually done. bytesWritten is not emitted and the data is not read back.

Note: A serial monitor program is showing the written data, but the data does not reach the pins.

Is it possible to fix the code in any way in order to make it work with Qt5.13.1?

like image 563
scopchanov Avatar asked Sep 20 '19 01:09

scopchanov


People also ask

How do I install Qserialport?

download and unpack the QtSerialPort sources. run QtCreator and open the root "qtserialport/qtserialport.pro" project file. get to "Projects->(Your Kit)->Build->Build Steps" add a new make "Build Step" and write to the "Make arguments" the install target.

How do you read serial data in Qt?

We can do it with below code block. void MainWindow::readData() { bool _ok; //This code is to read all data on serial port QByteArray data = serial->readAll(); if (ui->chkGetHexadecimalValue->isChecked() == true) qDebug() << data.


1 Answers

Cause

Searching Qt bug tracker there seem to be multiple bugs about QSerialPort not working on Qt 5.13.1 on Windows. All of them are duplicated with QTBUG-78086 which also contains a link to Gerrit review of the fix.

From the bug description:

The signal readyRead is never emitted, even if data is sent to the serial port from a connected device. The member bytesAvailable returns 0 even if data has been sent to the serial port from a connected device.

Basically, they have tried to emit _q_notify in qwinoverlappedionotifier.cpp only if there's no notification pending. Unfortunatelly

That commit completely breaks the I/O on Windows.

Solution

For now you have the options to downgrade to 5.13.0, wait for Qt 5.13.2 or

Fix the Qt 5.13.1 qserialport yourself:

  • open QTDIR\5.13.1\Src\qtserialport\qtserialport.pro with QtCreator
  • (optional) you might need to select a kit, e.g. Projects -> Manage kits -> Desktop Qt 5.13.1 MSVC2017 64bit
  • in the project tree open src/serialport/serialport-lib/sources/qwinoverlappedionotifier.cpp
  • delete QAtomicInt pendingNotifications;
  • change

    if (!waiting && pendingNotifications-- == 0)
        emit q->_q_notify();
    

    to

    if (!waiting)
        emit q->_q_notify();
    
  • change

    int n = pendingNotifications.fetchAndStoreAcquire(0);
    while (--n >= 0) {
        if (WaitForSingleObject(hSemaphore, 0) == WAIT_OBJECT_0)
            dispatchNextIoResult();
    }
    

    to

    if (WaitForSingleObject(hSemaphore, 0) == WAIT_OBJECT_0)
        dispatchNextIoResult();
    
  • In QtCreator go to build -> clean all, then run qmake, then rebuild all

  • locate the build folder, then copy and replace Qt5SerialPort.dll and Qt5SerialPortd.dll from build\bin to QTDIR\5.13.1\msvc2017_64\bin

Your code should work now.

like image 94
talamaki Avatar answered Nov 03 '22 01:11

talamaki