Extend modbus tcp class

This commit is contained in:
Simon Stürz 2021-05-27 10:32:04 +02:00 committed by Michael Zanetti
parent 8f281ed304
commit f8bc078437
2 changed files with 157 additions and 90 deletions

View File

@ -34,13 +34,15 @@
NYMEA_LOGGING_CATEGORY(dcModbusTCP, "ModbusTCP")
ModbusTCPMaster::ModbusTCPMaster(const QHostAddress &hostAddress, uint port, QObject *parent) :
QObject(parent)
QObject(parent),
m_hostAddress(hostAddress),
m_port(port)
{
m_modbusTcpClient = new QModbusTcpClient(this);
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, port);
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, hostAddress.toString());
m_modbusTcpClient->setTimeout(1000);
m_modbusTcpClient->setNumberOfRetries(3);
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, m_port);
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, m_hostAddress.toString());
m_modbusTcpClient->setTimeout(m_timeout);
m_modbusTcpClient->setNumberOfRetries(m_numberOfRetries);
connect(m_modbusTcpClient, &QModbusTcpClient::stateChanged, this, &ModbusTCPMaster::onModbusStateChanged);
connect(m_modbusTcpClient, &QModbusRtuSerialMaster::errorOccurred, this, &ModbusTCPMaster::onModbusErrorOccurred);
@ -52,38 +54,87 @@ ModbusTCPMaster::ModbusTCPMaster(const QHostAddress &hostAddress, uint port, QOb
ModbusTCPMaster::~ModbusTCPMaster()
{
if (!m_modbusTcpClient) {
m_modbusTcpClient->disconnectDevice();
m_modbusTcpClient->deleteLater();
}
if (!m_reconnectTimer) {
if (m_reconnectTimer) {
m_reconnectTimer->stop();
m_reconnectTimer->deleteLater();
delete m_reconnectTimer;
m_reconnectTimer = nullptr;
}
if (m_modbusTcpClient) {
m_modbusTcpClient->disconnectDevice();
delete m_modbusTcpClient;
m_modbusTcpClient = nullptr;
}
}
QHostAddress ModbusTCPMaster::hostAddress() const
{
return m_hostAddress;
}
uint ModbusTCPMaster::port() const
{
return m_port;
}
bool ModbusTCPMaster::setPort(uint port)
{
m_port = port;
return connectDevice();
}
bool ModbusTCPMaster::setHostAddress(const QHostAddress &hostAddress)
{
m_hostAddress = hostAddress;
return connectDevice();
}
bool ModbusTCPMaster::connectDevice() {
// TCP connection to target device
qCDebug(dcModbusTCP()) << "Setting up TCP connecion";
qCDebug(dcModbusTCP()) << "Setting up TCP connecion" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port);
if (!m_modbusTcpClient)
return false;
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, m_port);
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, m_hostAddress.toString());
m_modbusTcpClient->setTimeout(m_timeout);
m_modbusTcpClient->setNumberOfRetries(m_numberOfRetries);
return m_modbusTcpClient->connectDevice();
}
bool ModbusTCPMaster::connected()
void ModbusTCPMaster::disconnectDevice()
{
if (!m_modbusTcpClient)
return;
m_modbusTcpClient->disconnectDevice();
}
bool ModbusTCPMaster::connected() const
{
return (m_modbusTcpClient->state() == QModbusDevice::State::ConnectedState);
}
int ModbusTCPMaster::numberOfRetries() const
{
return m_modbusTcpClient->numberOfRetries();
}
void ModbusTCPMaster::setNumberOfRetries(int number)
{
m_numberOfRetries = number;
m_modbusTcpClient->setNumberOfRetries(number);
}
int ModbusTCPMaster::timeout() const
{
return m_modbusTcpClient->timeout();
}
void ModbusTCPMaster::setTimeout(int timeout)
{
m_timeout = timeout;
m_modbusTcpClient->setTimeout(timeout);
}
@ -97,74 +148,51 @@ QModbusDevice::Error ModbusTCPMaster::error() const
return m_modbusTcpClient->error();
}
uint ModbusTCPMaster::port()
{
return m_modbusTcpClient->connectionParameter(QModbusDevice::NetworkPortParameter).toUInt();
}
bool ModbusTCPMaster::setHostAddress(const QHostAddress &hostAddress)
{
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, hostAddress.toString());
return connectDevice();
}
bool ModbusTCPMaster::setPort(uint port)
{
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, port);
return connectDevice();
}
void ModbusTCPMaster::onReconnectTimer()
{
if(!m_modbusTcpClient->connectDevice()) {
if (!m_modbusTcpClient->connectDevice()) {
m_reconnectTimer->start(10000);
}
}
QHostAddress ModbusTCPMaster::hostAddress()
{
return QHostAddress(m_modbusTcpClient->connectionParameter(QModbusDevice::NetworkAddressParameter).toString());
}
QUuid ModbusTCPMaster::readCoil(uint slaveAddress, uint registerAddress, uint size)
{
if (!m_modbusTcpClient) {
return "";
return QUuid();
}
QUuid requestId = QUuid::createUuid();
QUuid requestId = QUuid::createUuid();
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, registerAddress, size);
if (QModbusReply *reply = m_modbusTcpClient->sendReadRequest(request, slaveAddress)) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [reply, requestId, this] {
if (reply->error() == QModbusDevice::NoError) {
emit readRequestExecuted(requestId, true);
const QModbusDataUnit unit = reply->result();
uint modbusAddress = unit.startAddress();
emit receivedCoil(reply->serverAddress(), modbusAddress, unit.values());
} else {
emit readRequestExecuted(requestId, false);
qCWarning(dcModbusTCP()) << "Read response error:" << reply->error();
}
});
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
qCWarning(dcModbusTCP()) << "Modbus reply error:" << error;
emit readRequestError(requestId, reply->errorString());
reply->finished(); // To make sure it will be deleted
emit reply->finished(); // To make sure it will be deleted
});
QTimer::singleShot(200, reply, &QModbusReply::deleteLater);
} else {
delete reply; // broadcast replies return immediately
return "";
return QUuid();
}
} else {
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
return "";
return QUuid();
}
return requestId;
}
@ -172,51 +200,70 @@ QUuid ModbusTCPMaster::readCoil(uint slaveAddress, uint registerAddress, uint si
QUuid ModbusTCPMaster::writeHoldingRegisters(uint slaveAddress, uint registerAddress, const QVector<quint16> &values)
{
if (!m_modbusTcpClient) {
return "";
return QUuid();
}
QUuid requestId = QUuid::createUuid();
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, registerAddress, values.length());
request.setValues(values);
if (QModbusReply *reply = m_modbusTcpClient->sendWriteRequest(request, slaveAddress)) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [reply, requestId, this] {
if (reply->error() == QModbusDevice::NoError) {
writeRequestExecuted(requestId, true);
emit writeRequestExecuted(requestId, true);
const QModbusDataUnit unit = reply->result();
uint modbusAddress = unit.startAddress();
emit receivedHoldingRegister(reply->serverAddress(), modbusAddress, unit.values());
} else {
writeRequestExecuted(requestId, false);
emit writeRequestExecuted(requestId, false);
qCWarning(dcModbusTCP()) << "Read response error:" << reply->error();
}
reply->deleteLater();
});
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
qCWarning(dcModbusTCP()) << "Modbus replay error:" << error;
emit writeRequestError(requestId, reply->errorString());
reply->finished(); // To make sure it will be deleted
emit reply->finished(); // To make sure it will be deleted
});
QTimer::singleShot(2000, reply, &QModbusReply::deleteLater);
} else {
delete reply; // broadcast replies return immediately
return "";
return QUuid();
}
} else {
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
return "";
return QUuid();
}
return requestId;
}
QModbusReply *ModbusTCPMaster::sendRawRequest(const QModbusRequest &request, int serverAddress)
{
return m_modbusTcpClient->sendRawRequest(request, serverAddress);
}
QModbusReply *ModbusTCPMaster::sendReadRequest(const QModbusDataUnit &read, int serverAddress)
{
return m_modbusTcpClient->sendReadRequest(read, serverAddress);
}
QModbusReply *ModbusTCPMaster::sendReadWriteRequest(const QModbusDataUnit &read, const QModbusDataUnit &write, int serverAddress)
{
return m_modbusTcpClient->sendReadWriteRequest(read, write, serverAddress);
}
QModbusReply *ModbusTCPMaster::sendWriteRequest(const QModbusDataUnit &write, int serverAddress)
{
return m_modbusTcpClient->sendWriteRequest(write, serverAddress);
}
QUuid ModbusTCPMaster::readDiscreteInput(uint slaveAddress, uint registerAddress, uint size)
{
if (!m_modbusTcpClient) {
return "";
return QUuid();
}
QUuid requestId = QUuid::createUuid();
@ -226,33 +273,32 @@ QUuid ModbusTCPMaster::readDiscreteInput(uint slaveAddress, uint registerAddress
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [reply, requestId, this] {
if (reply->error() == QModbusDevice::NoError) {
emit readRequestExecuted(requestId, true);
const QModbusDataUnit unit = reply->result();
uint modbusAddress = unit.startAddress();
emit receivedDiscreteInput(reply->serverAddress(), modbusAddress, unit.values());
} else {
emit readRequestExecuted(requestId, false);
qCWarning(dcModbusTCP()) << "Read response error:" << reply->error();
}
});
connect(reply, &QModbusReply::errorOccurred, this, [requestId, this] (QModbusDevice::Error error){
connect(reply, &QModbusReply::errorOccurred, this, [requestId, this] (QModbusDevice::Error error){
qCWarning(dcModbusTCP()) << "Modbus replay error:" << error;
QModbusReply *reply = qobject_cast<QModbusReply *>(sender());
emit readRequestError(requestId, reply->errorString());
reply->finished(); // To make sure it will be deleted
emit reply->finished(); // To make sure it will be deleted
});
QTimer::singleShot(2000, reply, &QModbusReply::deleteLater);
} else {
delete reply; // broadcast replies return immediately
return "";
return QUuid();
}
} else {
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
return "";
return QUuid();
}
return requestId;
}
@ -260,10 +306,10 @@ QUuid ModbusTCPMaster::readDiscreteInput(uint slaveAddress, uint registerAddress
QUuid ModbusTCPMaster::readInputRegister(uint slaveAddress, uint registerAddress, uint size)
{
if (!m_modbusTcpClient) {
return "";
return QUuid();
}
QUuid requestId = QUuid::createUuid();
QUuid requestId = QUuid::createUuid();
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, registerAddress, size);
if (QModbusReply *reply = m_modbusTcpClient->sendReadRequest(request, slaveAddress)) {
@ -276,26 +322,27 @@ QUuid ModbusTCPMaster::readInputRegister(uint slaveAddress, uint registerAddress
const QModbusDataUnit unit = reply->result();
uint modbusAddress = unit.startAddress();
emit receivedInputRegister(reply->serverAddress(), modbusAddress, unit.values());
} else {
emit readRequestExecuted(requestId, false);
qCWarning(dcModbusTCP()) << "Read response error:" << reply->error();
}
});
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
qCWarning(dcModbusTCP()) << "Modbus reply error:" << error;
emit readRequestError(requestId, reply->errorString());
reply->finished(); // To make sure it will be deleted
emit reply->finished(); // To make sure it will be deleted
});
QTimer::singleShot(2000, reply, &QModbusReply::deleteLater);
} else {
delete reply; // broadcast replies return immediately
return "";
return QUuid();
}
} else {
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
return "";
return QUuid();
}
return requestId;
}
@ -303,10 +350,10 @@ QUuid ModbusTCPMaster::readInputRegister(uint slaveAddress, uint registerAddress
QUuid ModbusTCPMaster::readHoldingRegister(uint slaveAddress, uint registerAddress, uint size)
{
if (!m_modbusTcpClient) {
return "";
return QUuid();
}
QUuid requestId = QUuid::createUuid();
QUuid requestId = QUuid::createUuid();
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, registerAddress, size);
if (QModbusReply *reply = m_modbusTcpClient->sendReadRequest(request, slaveAddress)) {
@ -327,20 +374,22 @@ QUuid ModbusTCPMaster::readHoldingRegister(uint slaveAddress, uint registerAddre
}
reply->deleteLater();
});
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
qCWarning(dcModbusTCP()) << "Modbus reply error:" << error;
emit readRequestError(requestId, reply->errorString());
reply->finished(); // To make sure it will be deleted
emit reply->finished(); // To make sure it will be deleted
});
QTimer::singleShot(2000, reply, &QModbusReply::deleteLater);
} else {
delete reply; // broadcast replies return immediately
return "";
return QUuid();
}
} else {
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
return "";
return QUuid();
}
return requestId;
}
@ -353,10 +402,10 @@ QUuid ModbusTCPMaster::writeCoil(uint slaveAddress, uint registerAddress, bool v
QUuid ModbusTCPMaster::writeCoils(uint slaveAddress, uint registerAddress, const QVector<quint16> &values)
{
if (!m_modbusTcpClient) {
return "";
return QUuid();
}
QUuid requestId = QUuid::createUuid();
QUuid requestId = QUuid::createUuid();
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, registerAddress, values.length());
request.setValues(values);
@ -377,20 +426,21 @@ QUuid ModbusTCPMaster::writeCoils(uint slaveAddress, uint registerAddress, const
}
reply->deleteLater();
});
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
qCWarning(dcModbusTCP()) << "Modbus reply error:" << error;
emit writeRequestError(requestId, reply->errorString());
reply->finished(); // To make sure it will be deleted
emit reply->finished(); // To make sure it will be deleted
});
QTimer::singleShot(2000, reply, &QModbusReply::deleteLater);
} else {
delete reply; // broadcast replies return immediately
return "";
return QUuid();
}
} else {
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
return "";
return QUuid();
}
return requestId;
}
@ -400,19 +450,20 @@ QUuid ModbusTCPMaster::writeHoldingRegister(uint slaveAddress, uint registerAddr
return writeHoldingRegisters(slaveAddress, registerAddress, QVector<quint16>() << value);
}
void ModbusTCPMaster::onModbusErrorOccurred(QModbusDevice::Error error)
{
qCWarning(dcModbusTCP()) << "An error occured" << error;
}
void ModbusTCPMaster::onModbusStateChanged(QModbusDevice::State state)
{
qCDebug(dcModbusTCP()) << "Connection state changed for" << m_hostAddress << state;
bool connected = (state == QModbusDevice::ConnectedState);
if (!connected) {
//try to reconnect in 10 seconds
m_reconnectTimer->start(10000);
}
emit connectionStateChanged(connected);
}

View File

@ -37,8 +37,6 @@
#include <QTimer>
#include <QUuid>
Q_DECLARE_LOGGING_CATEGORY(dcModbusTcp)
class ModbusTCPMaster : public QObject
{
Q_OBJECT
@ -46,9 +44,21 @@ public:
explicit ModbusTCPMaster(const QHostAddress &hostAddress, uint port, QObject *parent = nullptr);
~ModbusTCPMaster();
QHostAddress hostAddress() const;
bool setHostAddress(const QHostAddress &hostAddress);
uint port() const;
bool setPort(uint port);
bool connectDevice();
bool connected();
void disconnectDevice();
bool connected() const;
int numberOfRetries() const;
void setNumberOfRetries(int number);
int timeout() const;
void setTimeout(int timeout);
QString errorString() const;
@ -65,14 +75,20 @@ public:
QUuid writeHoldingRegister(uint slaveAddress, uint registerAddress, quint16 value);
QUuid writeHoldingRegisters(uint slaveAddress, uint registerAddress, const QVector<quint16> &values);
QHostAddress hostAddress();
uint port();
bool setHostAddress(const QHostAddress &hostAddress);
bool setPort(uint port);
// Generic requests
QModbusReply *sendRawRequest(const QModbusRequest &request, int serverAddress);
QModbusReply *sendReadRequest(const QModbusDataUnit &read, int serverAddress);
QModbusReply *sendReadWriteRequest(const QModbusDataUnit &read, const QModbusDataUnit &write, int serverAddress);
QModbusReply *sendWriteRequest(const QModbusDataUnit &write, int serverAddress);
private:
QTimer *m_reconnectTimer = nullptr;
QModbusTcpClient *m_modbusTcpClient;
QModbusTcpClient *m_modbusTcpClient = nullptr;
QHostAddress m_hostAddress;
uint m_port;
int m_timeout = 1000;
int m_numberOfRetries = 3;
private slots:
void onReconnectTimer();