From 2a238e68ed9e0412d3fcbb0d512f1a16c2b37f84 Mon Sep 17 00:00:00 2001 From: 0xFEEDC0DE64 Date: Mon, 7 Apr 2025 17:33:46 +0200 Subject: [PATCH] Preperations for modbus rtu --- changevaluesdialog.cpp | 4 +- changevaluesdialog.h | 6 +- main.cpp | 4 +- mainwindow.cpp | 145 ++++++++++++++++++++++++------- mainwindow.h | 16 +++- mainwindow.ui | 191 +++++++++++++++++++++++++++++++++-------- 6 files changed, 289 insertions(+), 77 deletions(-) diff --git a/changevaluesdialog.cpp b/changevaluesdialog.cpp index 72fcb96..993bc29 100644 --- a/changevaluesdialog.cpp +++ b/changevaluesdialog.cpp @@ -6,10 +6,10 @@ // Qt includes #include -#include +#include #include -ChangeValuesDialog::ChangeValuesDialog(QModbusTcpClient &modbus, int serverAddress, QModbusDataUnit::RegisterType registerType, QWidget *parent) : +ChangeValuesDialog::ChangeValuesDialog(QModbusClient &modbus, int serverAddress, QModbusDataUnit::RegisterType registerType, QWidget *parent) : QDialog{parent}, m_ui{std::make_unique()}, m_modbus{modbus} diff --git a/changevaluesdialog.h b/changevaluesdialog.h index 9e9fbaa..1b6dd1a 100644 --- a/changevaluesdialog.h +++ b/changevaluesdialog.h @@ -11,7 +11,7 @@ #include "changevaluesmodel.h" // forward declares -class QModbusTcpClient; +class QModbusClient; class QModbusReply; namespace Ui {class ChangeValuesDialog; } @@ -20,7 +20,7 @@ class ChangeValuesDialog : public QDialog Q_OBJECT public: - explicit ChangeValuesDialog(QModbusTcpClient &modbus, int serverAddress, QModbusDataUnit::RegisterType registerType, QWidget *parent = nullptr); + explicit ChangeValuesDialog(QModbusClient &modbus, int serverAddress, QModbusDataUnit::RegisterType registerType, QWidget *parent = nullptr); ~ChangeValuesDialog() override; private slots: @@ -29,7 +29,7 @@ private slots: private: const std::unique_ptr m_ui; - QModbusTcpClient &m_modbus; + QModbusClient &m_modbus; ChangeValuesModel m_model; std::unique_ptr m_reply; }; diff --git a/main.cpp b/main.cpp index f3110e0..698f5e1 100644 --- a/main.cpp +++ b/main.cpp @@ -7,8 +7,6 @@ int main(int argc, char *argv[]) { - QApplication app{argc, argv}; - qSetMessagePattern(QStringLiteral("%{time dd.MM.yyyy HH:mm:ss.zzz} " "[" "%{if-debug}D%{endif}" @@ -25,6 +23,8 @@ int main(int argc, char *argv[]) QCoreApplication::setApplicationName(QStringLiteral("qmodbustester")); QCoreApplication::setApplicationVersion(QStringLiteral("1.0")); + QApplication app{argc, argv}; + MainWindow mainWindow; mainWindow.show(); diff --git a/mainwindow.cpp b/mainwindow.cpp index 4b9c59b..12ab8cf 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -3,7 +3,10 @@ // Qt includes #include +#include +#include #include +#include #include #include #include @@ -23,26 +26,13 @@ QString toString(QModbusDataUnit::RegisterType registerType); MainWindow::MainWindow(QWidget *parent) : QMainWindow{parent}, m_ui{std::make_unique()}, - m_modbus{std::make_unique(this)}, - m_model{std::make_unique(this)} + m_model{std::make_unique(this)}, + m_completerModel{this}, + m_completer{&m_completerModel, this} { m_ui->setupUi(this); - m_ui->spinBoxTimeout->setValue(m_modbus->timeout()); - connect(m_modbus.get(), &QModbusClient::timeoutChanged, m_ui->spinBoxTimeout, &QSpinBox::setValue); - connect(m_ui->spinBoxTimeout, &QSpinBox::valueChanged, m_modbus.get(), &QModbusClient::setTimeout); - - m_ui->spinBoxRetries->setValue(m_modbus->numberOfRetries()); - //connect(m_modbus.get(), &QModbusClient::numberOfRetriesChanged, m_ui->spinBoxRetries, &QSpinBox::setValue); - connect(m_ui->spinBoxRetries, &QSpinBox::valueChanged, m_modbus.get(), &QModbusClient::setNumberOfRetries); - - modbusStateChanged(m_modbus->state()); - - connect(m_modbus.get(), &QModbusClient::errorOccurred, - this, &MainWindow::modbusErrorOccured); - - connect(m_modbus.get(), &QModbusClient::stateChanged, - this, &MainWindow::modbusStateChanged); + qDebug() << m_settings.fileName(); { const auto addItem = [&](const auto &text, const auto &value){ @@ -63,11 +53,44 @@ MainWindow::MainWindow(QWidget *parent) : connect(m_ui->pushButtonRequest, &QAbstractButton::pressed, this, &MainWindow::requestPressed); connect(m_ui->pushButtonWrite, &QAbstractButton::pressed, this, &MainWindow::writePressed); + auto completions = m_settings.value("lastHosts").toStringList(); + m_completerModel.setStringList(completions); + + m_completer.setModel(&m_completerModel); + m_completer.setCaseSensitivity(Qt::CaseInsensitive); + m_ui->lineEditServer->setCompleter(&m_completer); + + if (!completions.isEmpty()) + m_ui->lineEditServer->setText(completions.first()); + m_ui->tableView->setModel(m_model.get()); + + refreshSerialPorts(); + + connect(m_ui->toolButtonRefreshSerialports, &QToolButton::pressed, this, &MainWindow::refreshSerialPorts); + + { + QMetaEnum e = QMetaEnum::fromType(); + for (int i = 0; i < e.keyCount(); i++) + m_ui->comboBoxParity->addItem(e.key(i), QSerialPort::Parity(e.value(i))); + } + + { + QMetaEnum e = QMetaEnum::fromType(); + for (int i = 0; i < e.keyCount(); i++) + m_ui->comboBoxStopBits->addItem(e.key(i), QSerialPort::StopBits(e.value(i))); + } } MainWindow::~MainWindow() = default; +void MainWindow::refreshSerialPorts() +{ + m_ui->comboBoxSerialPort->clear(); + for (const auto &port : QSerialPortInfo::availablePorts()) + m_ui->comboBoxSerialPort->addItem(port.portName() + " [" + port.manufacturer() + "; " + port.serialNumber() + "]", port.portName()); +} + void MainWindow::connectPressed() { if (m_reply) @@ -78,30 +101,70 @@ void MainWindow::connectPressed() return; } - switch (const auto state = m_modbus->state()) + switch (!m_modbus || m_modbus->state() != QModbusDevice::ConnectedState) { - case QModbusDevice::ConnectedState: + case false: m_modbus->disconnectDevice(); + m_modbus.release()->deleteLater(); break; - case QModbusDevice::UnconnectedState: - m_modbus->setConnectionParameter(QModbusDevice::NetworkAddressParameter, m_ui->lineEditServer->text()); - m_modbus->setConnectionParameter(QModbusDevice::NetworkPortParameter, m_ui->spinBoxPort->value()); + + case true : + switch (m_ui->comboBoxConnectionType->currentIndex()) + { + case 0: // tcp + m_modbus = std::make_unique(this); + m_modbus->setConnectionParameter(QModbusDevice::NetworkAddressParameter, m_ui->lineEditServer->text()); + m_modbus->setConnectionParameter(QModbusDevice::NetworkPortParameter, m_ui->spinBoxPort->value()); + break; + case 1: // rtu + m_modbus = std::make_unique(this); + m_modbus->setConnectionParameter(QModbusDevice::SerialPortNameParameter, m_ui->comboBoxSerialPort->currentData().toString()); + m_modbus->setConnectionParameter(QModbusDevice::SerialParityParameter, m_ui->comboBoxParity->currentData().value()); + m_modbus->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, QSerialPort::Baud9600); + m_modbus->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, m_ui->comboBoxStopBits->currentData().value()); + break; + default: + QMessageBox::warning(this, tr("Invalid connection type"), tr("Invalid connection type")); + return; + } + + m_modbus->setTimeout(m_ui->spinBoxTimeout->value()); + connect(m_modbus.get(), &QModbusClient::timeoutChanged, m_ui->spinBoxTimeout, &QSpinBox::setValue); + connect(m_ui->spinBoxTimeout, &QSpinBox::valueChanged, m_modbus.get(), &QModbusClient::setTimeout); + + m_modbus->setNumberOfRetries(m_ui->spinBoxRetries->value()); + //connect(m_modbus.get(), &QModbusClient::numberOfRetriesChanged, m_ui->spinBoxRetries, &QSpinBox::setValue); + connect(m_ui->spinBoxRetries, &QSpinBox::valueChanged, m_modbus.get(), &QModbusClient::setNumberOfRetries); + + modbusStateChanged(m_modbus->state()); + + connect(m_modbus.get(), &QModbusClient::errorOccurred, + this, &MainWindow::modbusErrorOccured); + + connect(m_modbus.get(), &QModbusClient::stateChanged, + this, &MainWindow::modbusStateChanged); + + if (!m_modbus->connectDevice()) { - + QMessageBox::warning(this, + tr("Modbus client could not connect"), + tr("Modbus client could not connect:\n\n%0") + .arg(m_modbus->errorString()) + ); } break; - default: - QMessageBox::warning(this, - tr("Modbus client is in wrong state"), - tr("Modbus client is in wrong state:\n\n%0") - .arg(QMetaEnum::fromType().valueToKey(state)) - ); } } void MainWindow::requestPressed() { + if (!m_modbus) + { + QMessageBox::warning(this, tr("No valid serial port openend"), tr("No valid serial port openend")); + return; + } + if (const auto state = m_modbus->state(); state != QModbusDevice::ConnectedState) { QMessageBox::warning(this, @@ -134,7 +197,7 @@ void MainWindow::requestPressed() QModbusDataUnit dataUnit(registerType.value(), m_ui->spinBoxRegister->value(), m_ui->spinBoxCount->value()); qDebug() << m_ui->spinBoxSlave->value() << dataUnit.registerType() << dataUnit.startAddress() << dataUnit.valueCount(); - if (m_reply = std::unique_ptr(m_modbus->sendReadRequest(std::move(dataUnit), m_ui->spinBoxSlave->value()))) + if (m_reply = std::unique_ptr{m_modbus->sendReadRequest(std::move(dataUnit), m_ui->spinBoxSlave->value())}) { updateRequestFields(); @@ -146,6 +209,8 @@ void MainWindow::requestPressed() if (!m_ui->checkBoxAutorefresh->isChecked()) m_model->setResult({}); connect(m_reply.get(), &QModbusReply::finished, this, &MainWindow::replyFinished); + connect(m_reply.get(), &QModbusReply::errorOccurred, this, &MainWindow::replyErrorOccurred); + connect(m_reply.get(), &QModbusReply::intermediateErrorOccurred, this, &MainWindow::replyIntermediateErrorOccurred); } } else @@ -189,7 +254,15 @@ void MainWindow::modbusStateChanged(int state) m_ui->labelConnectionStatus->setText(QMetaEnum::fromType().valueToKey(state)); if (state == QModbusDevice::ConnectedState) + { + auto completions = m_settings.value("lastHosts").toStringList(); + completions.removeAll(m_ui->lineEditServer->text()); + completions.prepend(m_ui->lineEditServer->text()); + m_settings.setValue("lastHosts", completions); + m_completerModel.setStringList(completions); + m_ui->pushButtonConnect->setText(tr("Disconnect")); + } else if (state == QModbusDevice::UnconnectedState) { m_ui->pushButtonConnect->setText(tr("Connect")); @@ -238,7 +311,7 @@ void MainWindow::replyFinished() } else { - qWarning() << "result is invalid!"; + qWarning() << "result is invalid!" << m_reply->error() << m_reply->errorString(); m_model->setResult({}); @@ -290,6 +363,16 @@ void MainWindow::replyFinished() updateRequestFields(); } +void MainWindow::replyErrorOccurred(QModbusDevice::Error error) +{ + qDebug() << error; +} + +void MainWindow::replyIntermediateErrorOccurred(QModbusDevice::IntermediateError error) +{ + qDebug() << error; +} + void MainWindow::updateRequestFields() { m_ui->spinBoxSlave->setEnabled(!m_reply); diff --git a/mainwindow.h b/mainwindow.h index 8e21be2..75e9663 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -6,9 +6,14 @@ // Qt includes #include #include +#include +#include +#include +#include +#include // forward declares -class QModbusTcpClient; +class QModbusClient; class QModbusReply; namespace Ui { class MainWindow; } class ModbusTableModel; @@ -22,6 +27,8 @@ public: ~MainWindow() override; private slots: + void refreshSerialPorts(); + void connectPressed(); void requestPressed(); void writePressed(); @@ -30,13 +37,18 @@ private slots: void modbusStateChanged(int state); void replyFinished(); + void replyErrorOccurred(QModbusDevice::Error error); + void replyIntermediateErrorOccurred(QModbusDevice::IntermediateError error); private: void updateRequestFields(); const std::unique_ptr m_ui; - const std::unique_ptr m_modbus; + QSettings m_settings; + std::unique_ptr m_modbus; const std::unique_ptr m_model; std::unique_ptr m_reply; QElapsedTimer m_timer; + QStringListModel m_completerModel; + QCompleter m_completer; }; diff --git a/mainwindow.ui b/mainwindow.ui index 8252d76..0c6bc99 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -6,7 +6,7 @@ 0 0 - 947 + 1108 736 @@ -25,40 +25,135 @@ - - - Server: - - - lineEditServer - + + + + TCP + + + + + Serial + + - - - 192.168.8.116 - - - - - - - Port: - - - spinBoxPort - - - - - - - 65535 - - - 502 + + + 0 + + + + + + Server: + + + lineEditServer + + + + + + + + + + + + + + Port: + + + spinBoxPort + + + + + + + 65535 + + + 502 + + + + + + + + + + + SerialPort: + + + comboBoxSerialPort + + + + + + + + + + 🗘 + + + + + + + Baudrate: + + + spinBoxBaudrate + + + + + + + 4000000 + + + 9600 + + + + + + + Parity: + + + comboBoxParity + + + + + + + + + + StopBits: + + + comboBoxStopBits + + + + + + + + @@ -91,7 +186,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -134,6 +229,9 @@ 65535 + + 1000 + @@ -151,6 +249,9 @@ 65535 + + 3 + @@ -166,7 +267,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -277,7 +378,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -297,7 +398,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -326,8 +427,8 @@ 0 0 - 947 - 20 + 1108 + 22 @@ -351,5 +452,21 @@ + + comboBoxConnectionType + currentIndexChanged(int) + stackedWidget + setCurrentIndex(int) + + + 123 + 44 + + + 225 + 44 + + +