Проблемы обмена в QSerialPort при аппаратном управлении потоком

Сейчас пишу программу обмена данными в QT Creator 5.12 через, скажем так, специфичную сеть передачи данных. "Модемы" этой сети работают по UART RS-232, причём только в режиме аппаратного управления потоком.

Суть проблемы.

При выдаче данных в порт проблем нет я могу установить или сбросить сигналы DTR и RTS QSerialPort::dataTerminalReady(bool), and QSerialPort::requestToSend(bool) и проконтролировать наличие ответов CTS и DSR с помощью QSerialPort::pinoutSignals(). И, разумеется после этого, передаються данные успешно.

Проблемы при приёме данных из устройства: предполагаю, что причина в отсутствии в классе QSerialPort методов QSerialPort::setClearToSend(bool) и QSerialPort::setDataSetReady(bool) поскольку на запрос от аппаратуры канала данных RTS я не могу ответить CTS и на DTR ответить DSR, чтобы принять данные при аппаратном управлении потоком, хотя увидеть эти запросы я, конечно, могу с помощью QSerialPort::pinoutSignals(). Таким образом просто передача данных из модема в мою программу не начинается. Наблюдали сигналы с помощью осциллографа.

Конечно, теоретически, возможно сделать специальный кабель, где будут закольцованы сигналы RTS на CTS и DTR на DSR внутри каждого разъёма, но аппаратура с кабелями уже давно у получателя и переписать код контроллера порта в "модеме" на неуправляемую передачу потока данных не представляется возможным.

Может я чего-то не понимаю? Кто знает - подскажите выход из этого затруднения.

Собственно код класса для обмена данными: Заголовочный файл

#ifndef PORTUART_H
#define PORTUART_H

#include <QObject>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QTimer>

class PortUART : public QObject
{
    Q_OBJECT
public:
    explicit PortUART(QObject *parent = nullptr);
    ~PortUART();

signals:
    void signalReadedPortIO(QByteArray Str); //Resived data
    void signalErrComPort(QSerialPort::SerialPortError err); //Retranslate Error

public slots:
    bool setComData(QString name, QSerialPort::BaudRate baud, QSerialPort::DataBits databits, QSerialPort::Parity parbits, QSerialPort::StopBits stopbits, QSerialPort::FlowControl qflow_control);
    bool open(void);
    bool close(void);
    QString getName();
    qint64 WriteToPort(QByteArray message);

    bool isOpen(void);
    bool isWritable(void);
    bool isReadable(void);

    void read();
    void errorSerail(QSerialPort::SerialPortError err);
    void timerOverflow(void);
private:
    QTimer *pTimer;
    int timeInterval = 1000;
    QByteArray rcBuffer;

    QSerialPort *serial = nullptr;
    QString port_name;
    QSerialPort::BaudRate baud_rate;
    QSerialPort::DataBits data_bits;
    QSerialPort::Parity parity;
    QSerialPort::StopBits stop_bits;
    QSerialPort::FlowControl flow_control;
};

#endif // PORTUART_H

Файл реализации

#include "portuart.h"
#include <QDebug>

PortUART::PortUART(QObject *parent) : QObject(parent)
{
    baud_rate = QSerialPort::Baud115200;
    data_bits = QSerialPort::Data8;
    parity = QSerialPort::NoParity;
    stop_bits = QSerialPort::OneStop;
    flow_control = QSerialPort::HardwareControl;
    serial = new QSerialPort(this);
    connect(serial, SIGNAL(readyRead()), this, SLOT(read()));
    connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(errorSerail(QSerialPort::SerialPortError)));
    pTimer = new QTimer;
    connect(pTimer, SIGNAL(timeout()), this, SLOT(timerOverflow()));
}

PortUART::~PortUART()
{
    if (serial != nullptr)
    {
        if(serial->isOpen())
            serial->close();
        delete serial;
    }
    if (pTimer != nullptr)
        delete pTimer;
}

bool PortUART::setComData(QString name, QSerialPort::BaudRate baud, QSerialPort::DataBits databits, QSerialPort::Parity parbits, QSerialPort::StopBits stopbits, QSerialPort::FlowControl qflow_control)
{
    port_name = name;
    baud_rate = baud;
    data_bits = databits;
    parity = parbits;
    stop_bits = stopbits;
    flow_control = qflow_control;
    timeInterval = static_cast<int>((1000.0 / static_cast<int>(baud_rate)) * 500);
    timeInterval < 50 ? timeInterval = 50 : timeInterval += 0; // пауза не меньше 50 мс
    timeInterval > 250 ? timeInterval = 1000 : timeInterval += 0; // пауза не больше 1000 мс
    return true;
}

bool PortUART::open(void)
{
    try
    {
        //setup COM port
        serial->setPortName(port_name);
        serial->setBaudRate(baud_rate);
        serial->setDataBits(data_bits);
        serial->setParity(parity);
        serial->setStopBits(stop_bits);
        serial->setFlowControl(flow_control);

        serial->open(QIODevice::ReadWrite);

        if(serial->isWritable())
        {
            qDebug() << "Yes, i can write to port!";
        }

        serial->clear();
        if (flow_control == QSerialPort::HardwareControl)
        {
            serial->setDataTerminalReady(true);
            serial->setRequestToSend(true);
            serial->pinoutSignals( );
        }
    }
    catch(...)
    {
        return false;
    }
    return true;
}

bool PortUART::close(void)
{
    if (serial->isOpen())
    {
        serial->close();
        return true;
    }
    else
    {
        return false;
    }
}

void PortUART::read()
{
    if (pTimer->isActive())
        pTimer->stop();
    else
        rcBuffer.clear();
    QByteArray bytes = serial->readAll();
    qDebug() << QString(bytes.toHex().toUpper());
    //qDebug() << QString(bytes);
    rcBuffer.append(bytes);
    //emit signalReadedPortIO(bytes);
    pTimer->start(timeInterval);
}

void PortUART::timerOverflow(void)
{
    if (rcBuffer.size() > 0)
    {
        emit signalReadedPortIO(rcBuffer);
    }
    pTimer->stop();
}

void PortUART::errorSerail(QSerialPort::SerialPortError err)
{
    if (err != 0)
    {
        qDebug() << "Error: " << err;
        emit signalErrComPort(err);
    }
}

QString PortUART::getName(void)
{
    return port_name;
}

bool PortUART::isOpen()
{
    return serial->isOpen();
}

bool PortUART::isWritable()
{
    return serial->isOpen();
}

bool PortUART::isReadable()
{
    return serial->isOpen();
}

qint64 PortUART::WriteToPort(QByteArray message)
{
    if (serial->isWritable() == false)
    {
        return 0;
    }
    return serial->write(message);
}

Ответы (1 шт):

Автор решения: Виктор

По рекомендации из поддержки QT я сделал изменения в файле C:\Qt\Qt5.12.7\5.12.7\Src\qtserialport\src\serialport\qserialport_win.cpp и перекомпилировал эту библиотеку в режиме "релиз".

static inline void qt_set_flowcontrol(DCB *dcb, QSerialPort::FlowControl flowcontrol)
{
    dcb->fInX = FALSE;
    dcb->fOutX = FALSE;
    dcb->fOutxCtsFlow = FALSE;
    if (dcb->fRtsControl == RTS_CONTROL_HANDSHAKE) //Думаю, что эта строка лишняя, но я не стал её менять
        dcb->fRtsControl = RTS_CONTROL_DISABLE;
    switch (flowcontrol) {
    case QSerialPort::NoFlowControl:
        break;
    case QSerialPort::SoftwareControl:
        dcb->fInX = TRUE;
        dcb->fOutX = TRUE;
        break;
    case QSerialPort::HardwareControl:
        dcb->fOutxCtsFlow = TRUE;
        dcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
        dcb->fOutxDsrFlow = TRUE; // Это я добавил
        dcb->fDtrControl = DTR_CONTROL_HANDSHAKE; // Это я добавил
        break;
    default:
        break;
    }
}

После этого, как вы наверное догадались, включилась дополнительно реакция DTR->DSR и успешно заработала RTS->CTS.

→ Ссылка