I am trying to get a simple Modbus running and I am getting trouble with the sequense of commands.
I have figured first, that I can't run multiple functions in a function. If I do this, then it looks like a connection was made, but it fails. If I create 2 buttons ("Connect", "Read") and click first connect and then read, then the connection was succesfully and i am able to read the response.
So how can I change the code, so that it will connect to a TCP Modbus, read some data and then close the connection with one function/button?
This is an example of my code:
In file modbusmaster.hpp:
#ifndef MODBUSMASTER_HPP
#define MODBUSMASTER_HPP
#include <QMainWindow>
#include <QModbusTcpClient>
#include <QModbusDevice>
#include <QModbusDataUnit>
#include <QDebug>
#include <QUrl>
class QModbusClient;
class ModbusMaster : public QMainWindow
{
Q_OBJECT
public:
explicit ModbusMaster(QWidget *parent = nullptr);
QModbusClient *_modbus = nullptr;
QModbusClient *modbusDevice = nullptr;
bool open(QString host, int port);
bool read(QModbusDataUnit::RegisterType type, int startAddress, quint16 count);
void readReady();
signals:
};
#endif // MODBUSMASTER_HPP
In file modbusmaster.cpp:
#include "modbusmaster.hpp"
ModbusMaster::ModbusMaster(QWidget *parent) : QMainWindow(parent)
{
}
bool ModbusMaster::open(QString host, int port)
{
if (_modbus) {
_modbus->disconnectDevice();
delete _modbus;
_modbus = nullptr;
}
_modbus = new QModbusTcpClient(this);
connect(_modbus, &QModbusClient::errorOccurred, [this](QModbusDevice::Error) {
qDebug() << _modbus->errorString();
});
if(!_modbus) {
qDebug() << "Could not create Modbus Client.";
} else {
qDebug() << "Modbus Client is created.";
}
if (_modbus->state() != QModbusDevice::ConnectedState) {
_modbus->setConnectionParameter(QModbusDevice::NetworkPortParameter, port);
_modbus->setConnectionParameter(QModbusDevice::NetworkAddressParameter, host);
_modbus->setTimeout(1000);
_modbus->setNumberOfRetries(3);
if (!_modbus->connectDevice()) {
qDebug() << "Connect failed: " << _modbus->errorString();
} else {
qDebug() << "Modbus Client is Connected";
return true;
}
}
return false;
}
bool ModbusMaster::read(QModbusDataUnit::RegisterType type, int startAddress, quint16 count)
{
if (!_modbus) {
qDebug() << "!_modbus";
return false;
}
if (_modbus->state() != QModbusDevice::ConnectedState){
qDebug() << "Modbus Client is not Connected in read section";
return false;
}
QModbusDataUnit req(type, startAddress, count);
if (auto *reply = _modbus->sendReadRequest(req, 1))
{
qDebug() << "auto *reply = _modbus->sendReadRequest(req, 1)";
if (!reply->isFinished())
connect(reply, &QModbusReply::finished, this, &ModbusMaster::readReady);
else
delete reply;
return true;
}
return false;
}
void ModbusMaster::readReady()
{
auto reply = qobject_cast<QModbusReply *>(sender());
if (!reply) return;
reply->deleteLater();
if (reply->error() == QModbusDevice::NoError)
{
qDebug() << reply;
}
else if (reply->error() == QModbusDevice::ProtocolError)
{
qDebug() << QString("Read response error: %1 (Mobus exception: 0x%2)").
arg(reply->errorString()).
arg(reply->rawResult().exceptionCode(), -1, 16);
} else {
qDebug() << QString("Read response error: %1 (code: 0x%2)").
arg(reply->errorString()).
arg(reply->error(), -1, 16);
}
}
In file mainwindow.cpp:
#include "modbusmaster.hpp"
.......
void mainwindow::on_button_clicked()
{
ModbusMaster test;
test.open("172.19.1.54", 54);
test.read(QModbusDataUnit::HoldingRegisters, 0, 10);
}
.......
the "on_button_clicked" doesn't work. It shows only the qDebug() Results:
Modbus Client is created.
Modbus Client is Connected
Modbus Client is not Connected in read section
If I use 2 buttons, one for the test.open and the other with test.read, then it's ok.
So what am I missing here?