Improve reconnect behaviour

This commit is contained in:
Simon Stürz 2021-05-27 11:27:41 +02:00 committed by Michael Zanetti
parent f8bc078437
commit a62032ae45
2 changed files with 53 additions and 36 deletions

View File

@ -49,21 +49,18 @@ ModbusTCPMaster::ModbusTCPMaster(const QHostAddress &hostAddress, uint port, QOb
m_reconnectTimer = new QTimer(this); m_reconnectTimer = new QTimer(this);
m_reconnectTimer->setSingleShot(true); m_reconnectTimer->setSingleShot(true);
connect(m_reconnectTimer, &QTimer::timeout, this, &ModbusTCPMaster::onReconnectTimer); m_reconnectTimer->setInterval(4000);
connect(m_reconnectTimer, &QTimer::timeout, this, &ModbusTCPMaster::connectDevice);
} }
ModbusTCPMaster::~ModbusTCPMaster() ModbusTCPMaster::~ModbusTCPMaster()
{ {
if (m_reconnectTimer) { if (m_reconnectTimer) {
m_reconnectTimer->stop(); m_reconnectTimer->stop();
delete m_reconnectTimer;
m_reconnectTimer = nullptr;
} }
if (m_modbusTcpClient) { if (m_modbusTcpClient) {
m_modbusTcpClient->disconnectDevice(); disconnectDevice();
delete m_modbusTcpClient;
m_modbusTcpClient = nullptr;
} }
} }
@ -77,30 +74,37 @@ uint ModbusTCPMaster::port() const
return m_port; return m_port;
} }
bool ModbusTCPMaster::setPort(uint port) void ModbusTCPMaster::setPort(uint port)
{ {
m_port = port; m_port = port;
return connectDevice();
} }
bool ModbusTCPMaster::setHostAddress(const QHostAddress &hostAddress) void ModbusTCPMaster::setHostAddress(const QHostAddress &hostAddress)
{ {
m_hostAddress = hostAddress; m_hostAddress = hostAddress;
return connectDevice();
} }
bool ModbusTCPMaster::connectDevice() { bool ModbusTCPMaster::connectDevice() {
// TCP connection to target device // TCP connection to target device
qCDebug(dcModbusTCP()) << "Setting up TCP connecion" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port);
if (!m_modbusTcpClient) if (!m_modbusTcpClient)
return false; return false;
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, m_port); // Only connect if we are in the unconnected state
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, m_hostAddress.toString()); if (m_modbusTcpClient->state() == QModbusDevice::UnconnectedState) {
m_modbusTcpClient->setTimeout(m_timeout); qCDebug(dcModbusTCP()) << "Connecting modbus TCP client to" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port);
m_modbusTcpClient->setNumberOfRetries(m_numberOfRetries); 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();
} else if (m_modbusTcpClient->state() != QModbusDevice::ConnectedState) {
// Restart the timer in case of connecting not finished yet or closing
m_reconnectTimer->start();
} else {
qCWarning(dcModbusTCP()) << "Connect modbus TCP device" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port) << "called, but the socket is currently in the" << m_modbusTcpClient->state();
}
return m_modbusTcpClient->connectDevice(); return false;
} }
void ModbusTCPMaster::disconnectDevice() void ModbusTCPMaster::disconnectDevice()
@ -108,12 +112,24 @@ void ModbusTCPMaster::disconnectDevice()
if (!m_modbusTcpClient) if (!m_modbusTcpClient)
return; return;
// Stop the reconnect timer since disconnect was explicitly called
m_reconnectTimer->stop();
m_modbusTcpClient->disconnectDevice(); m_modbusTcpClient->disconnectDevice();
} }
bool ModbusTCPMaster::reconnectDevice()
{
qCWarning(dcModbusTCP()) << "Reconnecting modbus TCP device" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port);
if (!m_modbusTcpClient)
return false;
disconnectDevice();
return connectDevice();
}
bool ModbusTCPMaster::connected() const bool ModbusTCPMaster::connected() const
{ {
return (m_modbusTcpClient->state() == QModbusDevice::State::ConnectedState); return m_connected;
} }
int ModbusTCPMaster::numberOfRetries() const int ModbusTCPMaster::numberOfRetries() const
@ -148,13 +164,6 @@ QModbusDevice::Error ModbusTCPMaster::error() const
return m_modbusTcpClient->error(); return m_modbusTcpClient->error();
} }
void ModbusTCPMaster::onReconnectTimer()
{
if (!m_modbusTcpClient->connectDevice()) {
m_reconnectTimer->start(10000);
}
}
QUuid ModbusTCPMaster::readCoil(uint slaveAddress, uint registerAddress, uint size) QUuid ModbusTCPMaster::readCoil(uint slaveAddress, uint registerAddress, uint size)
{ {
if (!m_modbusTcpClient) { if (!m_modbusTcpClient) {
@ -458,12 +467,17 @@ void ModbusTCPMaster::onModbusErrorOccurred(QModbusDevice::Error error)
void ModbusTCPMaster::onModbusStateChanged(QModbusDevice::State state) void ModbusTCPMaster::onModbusStateChanged(QModbusDevice::State state)
{ {
qCDebug(dcModbusTCP()) << "Connection state changed for" << m_hostAddress << state; qCDebug(dcModbusTCP()) << "Connection state changed for" << m_hostAddress << state;
bool connected = (state == QModbusDevice::ConnectedState); bool connected = (state == QModbusDevice::ConnectedState);
if (!connected) { if (m_connected != connected) {
//try to reconnect in 10 seconds m_connected = connected;
m_reconnectTimer->start(10000); emit connectionStateChanged(m_connected);
} }
emit connectionStateChanged(connected); // If the socket is connected, stop the reconnect timer...
// If the socket is unconnected (not connecting and not closing), start the reconnect timer
if (m_connected) {
m_reconnectTimer->stop();
} else if (state == QModbusDevice::UnconnectedState) {
m_reconnectTimer->start();
}
} }

View File

@ -44,14 +44,13 @@ public:
explicit ModbusTCPMaster(const QHostAddress &hostAddress, uint port, QObject *parent = nullptr); explicit ModbusTCPMaster(const QHostAddress &hostAddress, uint port, QObject *parent = nullptr);
~ModbusTCPMaster(); ~ModbusTCPMaster();
// If you change the hostaddress, make sure to reconnectDevice afterwards
QHostAddress hostAddress() const; QHostAddress hostAddress() const;
bool setHostAddress(const QHostAddress &hostAddress); void setHostAddress(const QHostAddress &hostAddress);
// If you change the port, make sure to reconnectDevice afterwards
uint port() const; uint port() const;
bool setPort(uint port); void setPort(uint port);
bool connectDevice();
void disconnectDevice();
bool connected() const; bool connected() const;
@ -81,6 +80,11 @@ public:
QModbusReply *sendReadWriteRequest(const QModbusDataUnit &read, const QModbusDataUnit &write, int serverAddress); QModbusReply *sendReadWriteRequest(const QModbusDataUnit &read, const QModbusDataUnit &write, int serverAddress);
QModbusReply *sendWriteRequest(const QModbusDataUnit &write, int serverAddress); QModbusReply *sendWriteRequest(const QModbusDataUnit &write, int serverAddress);
public slots:
bool connectDevice();
void disconnectDevice();
bool reconnectDevice();
private: private:
QTimer *m_reconnectTimer = nullptr; QTimer *m_reconnectTimer = nullptr;
QModbusTcpClient *m_modbusTcpClient = nullptr; QModbusTcpClient *m_modbusTcpClient = nullptr;
@ -89,10 +93,9 @@ private:
uint m_port; uint m_port;
int m_timeout = 1000; int m_timeout = 1000;
int m_numberOfRetries = 3; int m_numberOfRetries = 3;
bool m_connected = false;
private slots: private slots:
void onReconnectTimer();
void onModbusErrorOccurred(QModbusDevice::Error error); void onModbusErrorOccurred(QModbusDevice::Error error);
void onModbusStateChanged(QModbusDevice::State state); void onModbusStateChanged(QModbusDevice::State state);