From 726137547bfd444b432818c9e8a14cadc71491b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 27 Jul 2022 14:51:08 +0200 Subject: [PATCH] Implement reachable property for modbus RTU --- .../tools/connectiontool/modbusrtu.py | 6 ++ libnymea-modbus/tools/generate-connection.py | 62 ++++++++++++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/libnymea-modbus/tools/connectiontool/modbusrtu.py b/libnymea-modbus/tools/connectiontool/modbusrtu.py index f272b2c..f8ceb41 100644 --- a/libnymea-modbus/tools/connectiontool/modbusrtu.py +++ b/libnymea-modbus/tools/connectiontool/modbusrtu.py @@ -93,6 +93,7 @@ def writePropertyUpdateMethodImplementationsRtu(fileDescriptor, className, regis writeLine(fileDescriptor) writeLine(fileDescriptor, ' if (!reply->isFinished()) {') writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, this, [this, reply](){') + writeLine(fileDescriptor, ' handleModbusError(reply->error());') writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {') writeLine(fileDescriptor, ' QVector values = reply->result();') writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) @@ -150,6 +151,7 @@ def writeBlockUpdateMethodImplementationsRtu(fileDescriptor, className, blockDef writeLine(fileDescriptor) writeLine(fileDescriptor, ' if (!reply->isFinished()) {') writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, this, [this, reply](){') + writeLine(fileDescriptor, ' handleModbusError(reply->error());') writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {') writeLine(fileDescriptor, ' QVector blockValues = reply->result();') writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize)) @@ -311,7 +313,9 @@ def writeInitMethodImplementationRtu(fileDescriptor, className, registerDefiniti writeLine(fileDescriptor, ' if (!reply->isFinished()) {') writeLine(fileDescriptor, ' m_pendingInitReplies.append(reply);') writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, m_initObject, [this, reply](){') + writeLine(fileDescriptor, ' handleModbusError(reply->error());') writeLine(fileDescriptor, ' m_pendingInitReplies.removeAll(reply);') + writeLine(fileDescriptor) writeLine(fileDescriptor, ' if (reply->error() != ModbusRtuReply::NoError) {') writeLine(fileDescriptor, ' finishInitialization(false);') writeLine(fileDescriptor, ' return;') @@ -359,7 +363,9 @@ def writeInitMethodImplementationRtu(fileDescriptor, className, registerDefiniti writeLine(fileDescriptor, ' if (!reply->isFinished()) {') writeLine(fileDescriptor, ' m_pendingInitReplies.append(reply);') writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, m_initObject, [this, reply](){') + writeLine(fileDescriptor, ' handleModbusError(reply->error());') writeLine(fileDescriptor, ' m_pendingInitReplies.removeAll(reply);') + writeLine(fileDescriptor) writeLine(fileDescriptor, ' if (reply->error() != ModbusRtuReply::NoError) {') writeLine(fileDescriptor, ' finishInitialization(false);') writeLine(fileDescriptor, ' return;') diff --git a/libnymea-modbus/tools/generate-connection.py b/libnymea-modbus/tools/generate-connection.py index f7f66c9..72f8a95 100644 --- a/libnymea-modbus/tools/generate-connection.py +++ b/libnymea-modbus/tools/generate-connection.py @@ -315,6 +315,8 @@ def writeRtuHeaderFile(): writeLine(headerFile, ' ModbusRtuMaster *modbusRtuMaster() const;') writeLine(headerFile, ' quint16 slaveId() const;') writeLine(headerFile) + writeLine(headerFile, ' bool reachable() const;') + writeLine(headerFile) writeLine(headerFile, ' ModbusDataUtils::ByteOrder endianness() const;') writeLine(headerFile, ' void setEndianness(ModbusDataUtils::ByteOrder endianness);') writeLine(headerFile) @@ -351,6 +353,8 @@ def writeRtuHeaderFile(): # Write registers value changed signals writeLine(headerFile, 'signals:') + writeLine(headerFile, ' void reachableChanged(bool reachable);') + writeLine(headerFile) writeLine(headerFile, ' void initializationFinished(bool success);') writeLine(headerFile, ' void updateFinished();') writeLine(headerFile) @@ -384,6 +388,10 @@ def writeRtuHeaderFile(): writeLine(headerFile, ' ModbusRtuMaster *m_modbusRtuMaster = nullptr;') writeLine(headerFile, ' ModbusDataUtils::ByteOrder m_endianness = ModbusDataUtils::ByteOrder%s;' % endianness) writeLine(headerFile, ' quint16 m_slaveId = 1;') + writeLine(headerFile, ' bool m_reachable = false;') + writeLine(headerFile, ' bool m_communicationWorking = false;') + writeLine(headerFile, ' quint8 m_communicationFailedMax = 10;') + writeLine(headerFile, ' quint8 m_communicationFailedCounter = 0;') writeLine(headerFile) writeLine(headerFile, ' QVector m_pendingInitReplies;') writeLine(headerFile, ' QVector m_pendingUpdateReplies;') @@ -393,6 +401,10 @@ def writeRtuHeaderFile(): writeLine(headerFile, ' void finishInitialization(bool success);') writeLine(headerFile) writeLine(headerFile, ' void verifyUpdateFinished();') + writeLine(headerFile) + writeLine(headerFile, ' void handleModbusError(ModbusRtuReply::Error error);') + writeLine(headerFile, ' void evaluateReachableState();') + # End of class writeLine(headerFile) @@ -423,7 +435,17 @@ def writeRtuSourceFile(): writeLine(sourceFile, ' m_modbusRtuMaster(modbusRtuMaster),') writeLine(sourceFile, ' m_slaveId(slaveId)') writeLine(sourceFile, '{') - writeLine(sourceFile, '') + writeLine(sourceFile, ' connect(m_modbusRtuMaster, &ModbusRtuMaster::connectedChanged, this, [=](bool connected){') + writeLine(sourceFile, ' if (connected) {') + writeLine(sourceFile, ' qCDebug(dc%s()) << "Modbus RTU resource" << m_modbusRtuMaster->serialPort() << "connected again. Test if the connection is reachable...";' % (className)) + writeLine(sourceFile, ' } else {') + writeLine(sourceFile, ' qCWarning(dc%s()) << "Modbus RTU resource" << m_modbusRtuMaster->serialPort() << "disconnected. The connection is not reachable any more.";' % (className)) + writeLine(sourceFile, ' m_communicationWorking = false;') + writeLine(sourceFile, ' m_communicationFailedCounter = 0;') + writeLine(sourceFile, ' }') + writeLine(sourceFile) + writeLine(sourceFile, ' evaluateReachableState();') + writeLine(sourceFile, ' });') writeLine(sourceFile, '}') writeLine(sourceFile) @@ -438,6 +460,12 @@ def writeRtuSourceFile(): writeLine(sourceFile, '}') writeLine(sourceFile) + writeLine(sourceFile, 'bool %s::reachable() const' % (className)) + writeLine(sourceFile, '{') + writeLine(sourceFile, ' return m_reachable;') + writeLine(sourceFile, '}') + writeLine(sourceFile) + writeLine(sourceFile, 'ModbusDataUtils::ByteOrder %s::endianness() const' % (className)) writeLine(sourceFile, '{') writeLine(sourceFile, ' return m_endianness;') @@ -521,6 +549,38 @@ def writeRtuSourceFile(): writeLine(sourceFile, '}') writeLine(sourceFile) + writeLine(sourceFile, 'void %s::handleModbusError(ModbusRtuReply::Error error)' % (className)) + writeLine(sourceFile, '{') + writeLine(sourceFile, ' if (error == ModbusRtuReply::NoError) {') + writeLine(sourceFile, ' // Reset the com counter and we know we can reach the device') + writeLine(sourceFile, ' m_communicationFailedCounter = 0;') + writeLine(sourceFile, ' if (!m_communicationWorking)') + writeLine(sourceFile, ' qCDebug(dc%s()) << "Received a reply without any errors. The communication with the device seems to work now.";' % (className)) + writeLine(sourceFile) + writeLine(sourceFile, ' m_communicationWorking = true;') + writeLine(sourceFile, ' evaluateReachableState();') + writeLine(sourceFile, ' } else {') + writeLine(sourceFile, ' m_communicationFailedCounter++;') + writeLine(sourceFile, ' if (m_communicationWorking && m_communicationFailedCounter >= m_communicationFailedMax) {') + writeLine(sourceFile, ' m_communicationWorking = false;') + writeLine(sourceFile, ' qCWarning(dc%s()) << "Received" << m_communicationFailedCounter << "errors while communicating with the RTU master. Mark as not reachable until the communication works again.";' % (className)) + writeLine(sourceFile, ' evaluateReachableState();') + writeLine(sourceFile, ' }') + writeLine(sourceFile, ' }') + writeLine(sourceFile, '}') + writeLine(sourceFile) + + writeLine(sourceFile, 'void %s::evaluateReachableState()' % (className)) + writeLine(sourceFile, '{') + writeLine(sourceFile, ' bool reachable = m_communicationWorking & m_modbusRtuMaster->connected();') + writeLine(sourceFile, ' if (m_reachable == reachable)') + writeLine(sourceFile, ' return;') + writeLine(sourceFile) + writeLine(sourceFile, ' m_reachable = reachable;') + writeLine(sourceFile, ' emit reachableChanged(m_reachable);') + writeLine(sourceFile, '}') + writeLine(sourceFile) + # Write the debug print debugObjectParamName = className[0].lower() + className[1:] writeLine(sourceFile, 'QDebug operator<<(QDebug debug, %s *%s)' % (className, debugObjectParamName))