'QSerialPort do not open correctly virtual port COM

I'm developing a driver for a device with Qt. I have already done that many times and I have a code that I use every time. But, this time, when I open the QserialPort, it seems to work correctly, but it is not : I can write, the device receives commands, but I cannot receive on the soft : the signal QSerialPort::ReadyRead is never triggered. When I open the serial port with Putty (just open it without sending anything) and close it just after, my Qt soft work perfectly when I reconnect it : I can now receive correctly...

Do you have an idea of what putty do of different/more than my soft when opening the port ? (I have the same parameters and I'm on windows and Qt 5.15.2).

My code for opening :

_serial->setPortName(com);
_serial->setBaudRate(QSerialPort::Baud115200);
_serial->setDataBits(QSerialPort::Data8);
_serial->setParity(QSerialPort::NoParity);
_serial->setStopBits(QSerialPort::OneStop);
_serial->setFlowControl(QSerialPort::NoFlowControl);

if(!_serial->open(QIODevice::ReadWrite))
{
    emit error(tr("Unable to open port"));
    return;
}

_serial->clear();

My code for write (simple string like "hello") :

_serial->write("Hello");

My code for connect the signal :

connect(_serial, &QSerialPort::readyRead, this, &device::processCommand);

My code for read serial (processCommand()):

 QString bufferData;

if (_serial->isOpen())
{
    _datas.append(_serial->readAll());
    bufferData = _datas.constData();
}

EDIT : The Qt exemple 'Terminal' do not works on windows with my device but works on ubuntu...

EDIT 2 : SOLUTION : I have finally find the solution, just add _serial->setDataTerminalReady(true); after opening the QSerialPort.

Thanks.



Solution 1:[1]

I ran into the same problem where the read signal was not detected in the virtual USB port. In the end I came to the conclusion that the QSerialPort class shouldn't.
I solved it using QThread and Win32 API.

#pragma once

#include <windows.h>
#include <QMutex>
#include <QThread>
#include <QWaitCondition>

#define SERIAL_RX_BUF_SIZE 2047

class SerialThread : public QThread
{
    Q_OBJECT

public:
    explicit SerialThread(QObject *parent = nullptr);
    ~SerialThread();

    bool startThread(const QString& portName);
    void stopThread();
    void request(const QString& command);

signals:
    void response(char* text);
    void timeout();

private:
    void run() override;
    bool writeCommand(const QString& command);

    QString m_portName;
    QString m_command;
    QMutex m_mutex;
    QWaitCondition  m_wait;
    volatile bool m_quit = false;
    HANDLE m_hComm;
    char m_buf[SERIAL_RX_BUF_SIZE + 1];
};
#include "serial_thread.h"
#include <QDebug>

SerialThread::SerialThread(QObject *parent) :
    QThread(parent)
{
    memset(m_buf, 0, sizeof(m_buf));
}

SerialThread::~SerialThread()
{
}

bool SerialThread::startThread(const QString &portName)
{
    const QMutexLocker locker(&m_mutex);

    m_hComm = CreateFileA(portName.toStdString().c_str(),           // PORT NAME
        GENERIC_READ | GENERIC_WRITE,   // READ/WRITE
        0,                              // NO SHARING
        NULL,                           // NO SECURITY
        OPEN_EXISTING,                  // OPEN EXISTING PORT ONLY
        0,                              // NON OVERLAPPED I/O
        NULL);                          // NULL FOR COMM DEVICES

    if (m_hComm == INVALID_HANDLE_VALUE)
    {
        return false;
    }

    m_portName = portName;

    if (!SetCommMask(m_hComm, EV_RXCHAR | EV_ERR))
    {
        qCritical() << "SetCommMask failed";
        CloseHandle(m_hComm);
        return false;
    }

    COMMTIMEOUTS comm_timeouts;

    if (!GetCommTimeouts(m_hComm, &comm_timeouts))
    {
        qCritical() << "GetCommTimeouts failed";
        CloseHandle(m_hComm);
        return false;
    }

    comm_timeouts.ReadIntervalTimeout = 1;
    comm_timeouts.ReadTotalTimeoutMultiplier = 0;
    comm_timeouts.ReadTotalTimeoutConstant = 500;
    comm_timeouts.WriteTotalTimeoutMultiplier = 0;
    comm_timeouts.WriteTotalTimeoutConstant = 0;

    if (!SetCommTimeouts(m_hComm, &comm_timeouts))
    {
        qCritical() << "SetCommTimeouts failed";
        CloseHandle(m_hComm);
        return false;
    }
    start();

    return true;
}

void SerialThread::stopThread()
{
    m_mutex.lock();
    m_quit = true;
    m_mutex.unlock();
    m_wait.wakeAll();
    wait();
}

void SerialThread::request(const QString& command)
{
    m_mutex.lock();
    m_command = command;
    m_mutex.unlock();
    m_wait.wakeAll();
}

void SerialThread::run()
{
    DWORD dwEvtMask, nRead;
    
    while (!m_quit)
    {
        m_mutex.lock();
        m_wait.wait(&m_mutex);
        m_mutex.unlock();

        {
            const QMutexLocker locker(&m_mutex);

            if (m_command.isEmpty())
            {
                continue;
            }

            if (!writeCommand(m_command))
            {
                continue;
            }

            if (WaitCommEvent(m_hComm, &dwEvtMask, NULL))
            {
                if (dwEvtMask & EV_ERR)
                {
                    qCritical() << "Wait failed with error: " << GetLastError();
                    break;
                }

                if (dwEvtMask & EV_RXCHAR)
                {
                    if (!ReadFile(m_hComm, &m_buf, SERIAL_RX_BUF_SIZE, &nRead, NULL))
                    {
                        qCritical() << "ReadFile error: " << GetLastError();
                    }
                    else
                    {
                        m_buf[nRead] = 0;
                        qDebug() << "Read: " << nRead;
                        emit response(m_buf);
                    }
                }
            }
            else
            {
                DWORD dwRet = GetLastError();
                if (ERROR_IO_PENDING == dwRet)
                {
                    qDebug() << "RX timeout";
                    emit timeout();
                }
                else
                {
                    qCritical() << "WaitCommEvent failed: " << dwRet;
                }
            }
            m_command.clear();
        }
    }

    CloseHandle(m_hComm);
    m_quit = false;
}

bool SerialThread::writeCommand(const QString& command)
{
    std::string s = command.toStdString();
    DWORD n;
    if (!WriteFile(m_hComm, s.data(), s.length(), &n, NULL))
    {
        qCritical() << "WriteFile error";
        return false;
    }

    return true;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1