Home > Enterprise >  Why Qt serial read data never arrives? (Qt 5.15.2, C , Win64, MSVC2019_64)
Why Qt serial read data never arrives? (Qt 5.15.2, C , Win64, MSVC2019_64)

Time:10-29

To develop my program first without connecting two physical machines on serial port, I downloaded and used this program to simulate COM ports: https://sourceforge.net/projects/com0com/ I connected virtual COM4 to virtual COM5. It works fine.

Using Br@y's Terminal program, I tested if I connect to COM4 in one Terminal instance, and to COM5 in another instance on the same computer, the data that I send on one terminal arrives in the other terminal, and vice versa. Terminal program: https://sites.google.com/site/terminalbpp/

Now let's see the problem: I used SerialPortReader class from this official Qt sample code for async serial read: https://code.qt.io/cgit/qt/qtserialport.git/tree/examples/serialport/creaderasync It connects to COM5 and sets baud rate to 9600 successfully, but no data arrives if I send something via Terminal to COM4, so: SerialPortReader runs through with no error, but after then, no matter what message I send on my Terminal instance, handleReadyRead, handleError, and handleTimeout never get called.

(If I have already a terminal emulator connected to the virtual COM5 port, then connection in my C program fails, so indeed the open() check works fine. Also, if I try to send more than one messages to my program via the virtual COM4 port, Terminal freezes, which is a clear sign of that the previous message has not yet been read on the other side(COM5).)

I have googled a lot, but have not yet found any solutions. Someone here said that it is/was a bug Qt Serial Port Errors - Data not getting read and that the problem is in qserialport_win.cpp, but even if I change that and compile my program again, nothing happens. I use the following code to create the class, but the class' content is unchanged, I use it as I found in the sample program:

    // Serial comm init
    QSerialPort serialPort;
    QString serialPortName = "COM5";
    serialPort.setPortName(serialPortName);

    int serialPortBaudRate = 9600;
    

    if (serialPort.open(QIODevice::ReadOnly)) {
        if(serialPort.setBaudRate(serialPortBaudRate) &&
            serialPort.setDataBits(QSerialPort::Data8) &&
            serialPort.setParity(QSerialPort::NoParity) &&
            serialPort.setStopBits(QSerialPort::OneStop) &&
            serialPort.setFlowControl(QSerialPort::NoFlowControl)) {
            //SerialPortReader serialPortReader(&serialPort);
            SerialPortReader serialPortReader(&serialPort, this);
        } else {
            std::cout << "Failed to set COM connection properties " << serialPortName.toStdString() << serialPort.errorString().toStdString() << std::endl;
        }
    } else {
        std::cout << "Failed to open port " << serialPortName.toStdString() << serialPort.errorString().toStdString() << std::endl;
    }

I would appreciate any help. Thanks!

CodePudding user response:

Today I figured out a sketchy but working version:

SerialPortReader.h

#pragma once
#include <QtCore/QObject>
#include <QByteArray>
#include <QSerialPort>
#include <QTextStream>
#include <QTimer>

class SerialPortReader : public QObject {
    Q_OBJECT

public:
    explicit SerialPortReader(QObject *parent = 0);
    ~SerialPortReader() override;
    void close();

private:
    QSerialPort *serialPort = nullptr;
    QByteArray m_readData;
    QTimer m_timer;

public slots:
    void handleReadyRead();
    //void handleTimeout();
    //void handleError(QSerialPort::SerialPortError error);

};

SerialPortReader.cpp

#include <iostream>
#include "SerialPortReader.h"

SerialPortReader::SerialPortReader(QObject *parent) : QObject(parent)
{

    serialPort = new QSerialPort(this);
    const QString serialPortName = "COM4"; //argumentList.at(1);
    serialPort->setPortName(serialPortName);

    const int serialPortBaudRate = QSerialPort::Baud9600;
    serialPort->setBaudRate(serialPortBaudRate);

    if (!serialPort->open(QIODevice::ReadOnly)) {
        std::cout << "Failed to open port" << std::endl;
        //return 1;
    }


    std::cout << "SerialPortReader(QSerialPort *serialPort, QObject *parent)" << std::endl;

    connect(serialPort, SIGNAL(readyRead()), this, SLOT(handleReadyRead()), Qt::QueuedConnection);

   // connect(serialPort, &QSerialPort::readyRead, this, &SerialPortReader::handleReadyRead);
    //connect(serialPort, &QSerialPort::errorOccurred, this, &SerialPortReader::handleError);
    //connect(&m_timer, &QTimer::timeout, this, &SerialPortReader::handleTimeout);

    //m_timer.start(5000);
}

void SerialPortReader::handleReadyRead()
{
    std::cout << "handleReadyRead()" << std::endl;

    m_readData.append(serialPort->readAll());

    if (!m_timer.isActive())
        m_timer.start(5000);
}

/*
void SerialPortReader::handleTimeout()
{
    std::cout << "handleTimeout()" << std::endl;

    if (m_readData.isEmpty()) {
        std::cout << "No data was currently available for reading" << std::endl;
    } else {
        std::cout << "Data successfully received" << std::endl;
        //m_standardOutput << m_readData << Qt::endl;
    }

    //QCoreApplication::quit();
}

void SerialPortReader::handleError(QSerialPort::SerialPortError serialPortError)
{
    std::cout << "handleError()" << std::endl;

    if (serialPortError == QSerialPort::ReadError) {
        std::cout << "An I/O error occurred while reading" << std::endl;
        //QCoreApplication::exit(1);
    }
}
*/

SerialPortReader::~SerialPortReader() {
    close();
}

// Close the files, filestreams, etc
void SerialPortReader::close() {
    // ...
}

... and in my QApplication code you just need to include the .h and write this to instantiate the serial listener:

SerialPortReader *serialPortReader = new SerialPortReader(this);
  • Related