Как организовать работу N com-портов одновременно?

Здравствуйте! Работаю с com-port, и хочу сделать отправку и прием для нескольких портов.

В случае работы с одним портом предельно понятно, на каком-то уровне. Работаю с ним так:

#include "mainwindow.h"
#include "ui_mainwindow.h"

//----------------------------------------------------------------------------------------------------------------------------------------------------
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    m_ui(new Ui::MainWindow), m_timerWaitAnswer(new QTimer)
{
    m_ui->setupUi(this);

    //Получение списка портов и запись их в выпадающий список
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
        m_ui->serialPortComboBox->addItem(info.portName());

    // Отправка в сом-порт по нажатию на кнопку
    connect(m_ui->sendComPortPushButton, SIGNAL(clicked(bool)), this, SLOT(writeComPort()));

    // Подключаем чтение с порта по таймеру
    connect(m_timerWaitAnswer, SIGNAL(timeout()), this, SLOT(readComPort()));
    connect(m_ui->serialPortComboBox, SIGNAL(activated(QString)), this, SLOT(reopenComPort(QString)));

    m_comPort = new QSerialPort;
}

//----------------------------------------------------------------------------------------------------------------------------------------------------
MainWindow::~MainWindow()
{
    if(m_comPort->isOpen())
        m_comPort->close();

    delete m_ui;
}

//----------------------------------------------------------------------------------------------------------------------------------------------------
void MainWindow::openComPort(QString comName, QSerialPort::BaudRate baud, QSerialPort::DataBits dataBits, QSerialPort::Parity parity,
                                     QSerialPort::StopBits stopBits, QSerialPort::FlowControl flowControl)
{
    m_comPort->setPortName(comName);

    // Настройка параметров com-порта
    m_comPort->setBaudRate(baud);
    m_comPort->setDataBits(dataBits);
    m_comPort->setParity(parity);
    m_comPort->setStopBits(stopBits);
    m_comPort->setFlowControl(flowControl);

    // Открываем com-порт. В случае неудачи, выводим ошибку в лог
    if (!m_comPort->open(QIODevice::ReadWrite))
        qDebug() << "failed";
    else
        qDebug() << "connected";
}

//----------------------------------------------------------------------------------------------------------------------------------------------------
void MainWindow::readComPort()
{
    m_waitAnswer = false;

    QString data;

    // Чтение данных и вывод
    m_bufferRead.append(m_comPort->readAll());
    qDebug() << m_comPort->readAll();

    m_ui->textEdit->setText(m_bufferRead.data());

    m_bufferRead.clear();
    m_timerWaitAnswer->stop();
}

//----------------------------------------------------------------------------------------------------------------------------------------------------
void MainWindow::writeComPort()
{
    QByteArray toSend;

    QString value = m_ui->sendComPortLineEdit->text();

    if(value.isEmpty()) return;

    toSend.append(value);

    // Отправка в сом-порт
    m_comPort->write(toSend);
    m_ui->textEdit->setText(toSend);

    // Запуск таймера ожидания ответа
    m_timerWaitAnswer->start(m_ui->timeSpinBox->text().toInt());

    m_waitAnswer = true;
}

//----------------------------------------------------------------------------------------------------------------------------------------------------
void MainWindow::reopenComPort(QString namePort)
{
    m_comPort->close();

    // Открываем новый com-порт
    openComPort(namePort, QSerialPort::Baud9600, QSerialPort::Data8, QSerialPort::EvenParity,
                                         QSerialPort::OneStop, QSerialPort::NoFlowControl); 
}

Заголовочный файл:

<code lang="cpp">
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QTimer>
#include <QDebug>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    // Конструктор
    explicit MainWindow(QWidget *parent = 0);

    // Деструктор
    ~MainWindow();

public slots:
    // Читает из com-порта
    void readComPort();

    // Записывает данные в com-порт
    void writeComPort();

    // Переоткрывает com-порт
    void reopenComPort(QString namePort);

private:
    // Форма окна
    Ui::MainWindow *m_ui;

    // Флаг ожидания ответа
    bool m_waitAnswer;

    // Открываемый com-порт
    QSerialPort *m_comPort;

    // Приемный буфер
    QByteArray m_bufferRead;

    // Таймер
    QTimer *m_timerWaitAnswer;

    // Открывает com-порт
    void openComPort(QString comName, QSerialPort::BaudRate baud, QSerialPort::DataBits dataBits, QSerialPort::Parity parity,
                     QSerialPort::StopBits stopBits, QSerialPort::FlowControl flowControl);
};

#endif // MAINWINDOW_H
</code>


Так выглядит взаимодействие с одним портом:
<img src="https://habrastorage.org/webt/65/eb/f8/65ebf8a872479371143502.jpeg" alt="image"/>

В случае, когда работаем не с одним, а с двумя и более портами, как нужно организовать работу, чтобы все работало корректно?
Вопрос как в подходе, так как есть свои идеи, так и в некой реализации. Создавать несколько экземпляров com-портов - не гибко, если вдруг их количество увеличится.. Информация в интернетах, разумеется, есть, но не помогает прийти к какому-то решению для меня. Пробовал решить проблему следующим образом (пока без чтения и прочего):
<code lang="cpp">
#include "mainwindow.h"
#include "ui_mainwindow.h"


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();

    connect(ui->sendButton, SIGNAL(clicked()), this, SLOT(sendToAllPorts()));

    connectToAllPorts();

    connect(this, SIGNAL(messageSentSuccessfully(QString)), this, SLOT(msgSentSuccessfully(QString)));
}

//------------------------------------------------------------------------------
MainWindow::~MainWindow()
{
    delete ui;
}

//------------------------------------------------------------------------------
void MainWindow::msgSentSuccessfully(QString message)
{
    qDebug() << "Сообщение успешно отправлено: " << message;
}

//------------------------------------------------------------------------------
void MainWindow::msgFailedToSend(QString message)
{
    qDebug() << "Сообщение не удалось отправить: " << message;
}

//------------------------------------------------------------------------------
void MainWindow::sendMessage(QString message)
{
    // Отправка сообщения на все порты
    qDebug() << "Отправка сообщения: " << message;

    // Проверка успешной отправки сообщения
    bool messageSent = true; // Предположим, что сообщение успешно отправлено

    if (messageSent) {
        emit messageSentSuccessfully(message);
    } else {
        emit messageFailedToSend(message);
    }
}

//------------------------------------------------------------------------------
void MainWindow::sendToAllPorts()
{
    QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();
    message = "Hello, World!";

    foreach (const QSerialPortInfo &portInfo, ports)
    {
        QSerialPort port;
        port.setPort(portInfo);
        if (port.open(QIODevice::WriteOnly))
        {
            qDebug() << "Sending message" << message << "to port" << portInfo.portName();
            qint64 bytesWritten = port.write(message);
            if (bytesWritten == -1)
            {
                qDebug() << "Failed to write to port" << portInfo.portName();
            }
            else
            {
                qDebug() << "Message sent to port" << portInfo.portName();
            }
            port.close();
        }
        else
        {
            qDebug() << "Failed to open port" << portInfo.portName();
        }
    }
}

//------------------------------------------------------------------------------
void MainWindow::connectToAllPorts()
{

    QVector<QSerialPort*> ports; //availablePorts;
    foreach (const QSerialPortInfo &portInfo, QSerialPortInfo::availablePorts())
    {
        QSerialPort *port = new QSerialPort(portInfo);

        // Настройка параметров com-порта
        m_comPort->setBaudRate(QSerialPort::Baud9600);
        m_comPort->setDataBits(QSerialPort::Data8);
        m_comPort->setParity(QSerialPort::EvenParity);
        m_comPort->setStopBits(QSerialPort::OneStop);
        m_comPort->setFlowControl(QSerialPort::NoFlowControl);

        if (port->open(QIODevice::ReadWrite)) 
        {
            ports.append(port);
            qDebug() << "Port " << portInfo.portName() << " opened successfully";
        }
        else
        {
            qDebug() << "Failed to open port " << portInfo.portName();
        }
    }

    qDebug() << ports;
}
</code>

Заголовочный файл:
<code lang="cpp">
#ifndef MAINWINDOW_H
#define MAINWINDOW_H


#include <QMainWindow>
#include <QSerialPortInfo>
#include <QSerialPort>
#include <QDebug>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

public slots:
    void sendMessage(QString message);
    void msgSentSuccessfully(QString message);
    void msgFailedToSend(QString message);
    void ReadData();

signals:
    void messageSentSuccessfully(const QString &message);
    void messageFailedToSend(const QString &message);

private slots:
    void sendToAllPorts();

private:
    Ui::MainWindow *ui;

    QList<QSerialPortInfo> ports;
    QByteArray message;
    QSerialPort *m_comPort;
    void connectToAllPorts();
};

#endif // MAINWINDOW_H
</code>

При включении считываются доступные порты, записываются в QVector, через qDebug отображаю их и делаю автоматическое, на данный момент, подключение ко всем портам. Как впоследствии обращаться к ним для работы для отправки и приема?
  • Вопрос задан
  • 206 просмотров
Пригласить эксперта
Ответы на вопрос 1
@alexalexes
// Форма окна
    Ui::MainWindow *m_ui;

    // Флаг ожидания ответа
    bool m_waitAnswer;

    // Открываемый com-порт
    QSerialPort *m_comPort;

    // Приемный буфер
    QByteArray m_bufferRead;

    // Таймер
    QTimer *m_timerWaitAnswer;

Эти свойства у вас отвечают за контекст одного конкретного порта.
1. Нужно описать элемент-структуру по этим свойствам - тем самым опишите контекст порта.
2. Сделать массив из этих элементов - массив контекстов портов.
3. В каждом методе работы с портом обеспечить передачу входного параметра, чтобы указывать, какой i-ый элемент структуры использовать (какой контекст порта - конкретный порт), чтобы что-то делать с параметрами конкретного порта.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы