Implement reachable state for modbus tcp connections
parent
5bff288ec6
commit
f32b62ff77
|
|
@ -88,7 +88,7 @@ public slots:
|
|||
void disconnectDevice();
|
||||
bool reconnectDevice();
|
||||
|
||||
private:
|
||||
protected:
|
||||
QTimer *m_reconnectTimer = nullptr;
|
||||
QModbusTcpClient *m_modbusTcpClient = nullptr;
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ def writePropertyUpdateMethodImplementationsTcp(fileDescriptor, className, regis
|
|||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);')
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){')
|
||||
writeLine(fileDescriptor, ' handleModbusError(reply->error());')
|
||||
writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {')
|
||||
writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();')
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
|
|
@ -144,7 +145,9 @@ def writeBlockUpdateMethodImplementationsTcp(fileDescriptor, className, blockDef
|
|||
writeLine(fileDescriptor, ' return;')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);')
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){')
|
||||
writeLine(fileDescriptor, ' handleModbusError(reply->error());')
|
||||
writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {')
|
||||
writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();')
|
||||
writeLine(fileDescriptor, ' const QVector<quint16> blockValues = unit.values();')
|
||||
|
|
@ -266,6 +269,39 @@ def writeInternalBlockReadMethodImplementationsTcp(fileDescriptor, className, bl
|
|||
|
||||
##############################################################
|
||||
|
||||
def writeVerifyReachabilityImplementationsTcp(fileDescriptor, className, registerDefinitions, checkReachableRegister):
|
||||
|
||||
propertyName = checkReachableRegister['id']
|
||||
propertyTyp = getCppDataType(checkReachableRegister)
|
||||
|
||||
writeLine(fileDescriptor, 'void %s::verifyReachability()' % (className))
|
||||
writeLine(fileDescriptor, '{')
|
||||
writeLine(fileDescriptor, ' // Try to read the check reachability register %s in order to verify if the communication is working or not.' % checkReachableRegister['id'])
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Verify reachability by reading \\"%s\\" register:" << %s << "size:" << %s;' % (className, checkReachableRegister['description'], checkReachableRegister['address'], checkReachableRegister['size']))
|
||||
writeLine(fileDescriptor, ' QModbusReply *reply = read%s();' % (propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, ' if (!reply) {')
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "Error occurred verifying reachability by reading \\"%s\\" register";' % (className, checkReachableRegister['description']))
|
||||
writeLine(fileDescriptor, ' return;')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' if (reply->isFinished()) {')
|
||||
writeLine(fileDescriptor, ' reply->deleteLater(); // Broadcast reply returns immediatly')
|
||||
writeLine(fileDescriptor, ' return;')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){')
|
||||
writeLine(fileDescriptor, ' // Note: we don\'t care about the result here, only the error')
|
||||
writeLine(fileDescriptor, ' handleModbusError(reply->error());')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){')
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "ModbusRtu reply error occurred while verifying reachability by reading \\"%s\\" register" << error << reply->errorString();' % (className, checkReachableRegister['description']))
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
##############################################################
|
||||
|
||||
def writeInitMethodImplementationTcp(fileDescriptor, className, registerDefinitions, blockDefinitions):
|
||||
writeLine(fileDescriptor, 'bool %s::initialize()' % (className))
|
||||
writeLine(fileDescriptor, '{')
|
||||
|
|
@ -317,6 +353,7 @@ def writeInitMethodImplementationTcp(fileDescriptor, className, registerDefiniti
|
|||
writeLine(fileDescriptor, ' m_pendingInitReplies.append(reply);')
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);')
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, m_initObject, [this, reply](){')
|
||||
writeLine(fileDescriptor, ' handleModbusError(reply->error());')
|
||||
writeLine(fileDescriptor, ' m_pendingInitReplies.removeAll(reply);')
|
||||
writeLine(fileDescriptor, ' if (reply->error() != QModbusDevice::NoError) {')
|
||||
writeLine(fileDescriptor, ' finishInitialization(false);')
|
||||
|
|
@ -371,11 +408,12 @@ def writeInitMethodImplementationTcp(fileDescriptor, className, registerDefiniti
|
|||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);')
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, m_initObject, [this, reply](){')
|
||||
writeLine(fileDescriptor, ' m_pendingInitReplies.removeAll(reply);')
|
||||
writeLine(fileDescriptor, ' handleModbusError(reply->error());')
|
||||
writeLine(fileDescriptor, ' if (reply->error() != QModbusDevice::NoError) {')
|
||||
writeLine(fileDescriptor, ' finishInitialization(false);')
|
||||
writeLine(fileDescriptor, ' return;')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();')
|
||||
writeLine(fileDescriptor, ' const QVector<quint16> blockValues = unit.values();')
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading init block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize))
|
||||
|
|
@ -456,6 +494,7 @@ def writeUpdateMethodTcp(fileDescriptor, className, registerDefinitions, blockDe
|
|||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);')
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){')
|
||||
writeLine(fileDescriptor, ' m_pendingUpdateReplies.removeAll(reply);')
|
||||
writeLine(fileDescriptor, ' handleModbusError(reply->error());')
|
||||
writeLine(fileDescriptor, ' if (reply->error() != QModbusDevice::NoError) {')
|
||||
writeLine(fileDescriptor, ' verifyUpdateFinished();')
|
||||
writeLine(fileDescriptor, ' return;')
|
||||
|
|
@ -508,6 +547,7 @@ def writeUpdateMethodTcp(fileDescriptor, className, registerDefinitions, blockDe
|
|||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);')
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){')
|
||||
writeLine(fileDescriptor, ' m_pendingUpdateReplies.removeAll(reply);')
|
||||
writeLine(fileDescriptor, ' handleModbusError(reply->error());')
|
||||
writeLine(fileDescriptor, ' if (reply->error() != QModbusDevice::NoError) {')
|
||||
writeLine(fileDescriptor, ' verifyUpdateFinished();')
|
||||
writeLine(fileDescriptor, ' return;')
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ def writeTcpHeaderFile():
|
|||
writeLine(headerFile, ' explicit %s(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent = nullptr);' % className)
|
||||
writeLine(headerFile, ' ~%s() = default;' % className)
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, ' bool reachable() const;')
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, ' ModbusDataUtils::ByteOrder endianness() const;')
|
||||
writeLine(headerFile, ' void setEndianness(ModbusDataUtils::ByteOrder endianness);')
|
||||
writeLine(headerFile)
|
||||
|
|
@ -104,6 +106,8 @@ def writeTcpHeaderFile():
|
|||
|
||||
# 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)
|
||||
|
|
@ -135,6 +139,10 @@ def writeTcpHeaderFile():
|
|||
writeLine(headerFile, 'private:')
|
||||
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 = %s;' % (errorLimitUntilNotReachable))
|
||||
writeLine(headerFile, ' quint8 m_communicationFailedCounter = 0;')
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, ' QVector<QModbusReply *> m_pendingInitReplies;')
|
||||
writeLine(headerFile, ' QVector<QModbusReply *> m_pendingUpdateReplies;')
|
||||
|
|
@ -144,6 +152,10 @@ def writeTcpHeaderFile():
|
|||
writeLine(headerFile, ' void finishInitialization(bool success);')
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, ' void verifyUpdateFinished();')
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, ' void handleModbusError(QModbusDevice::Error error);')
|
||||
writeLine(headerFile, ' void evaluateReachableState();')
|
||||
writeLine(headerFile, ' void verifyReachability();')
|
||||
|
||||
# End of class
|
||||
writeLine(headerFile)
|
||||
|
|
@ -174,14 +186,30 @@ def writeTcpSourceFile():
|
|||
writeLine(sourceFile, '{')
|
||||
writeLine(sourceFile, ' connect(this, &ModbusTCPMaster::connectionStateChanged, this, [this](bool status){')
|
||||
writeLine(sourceFile, ' if (status) {')
|
||||
writeLine(sourceFile, ' qCDebug(dc%s()) << "Modbus TCP connection" << m_hostAddress.toString() << "connected. Start testing if the connection is reachable...";' % (className))
|
||||
writeLine(sourceFile, ' // Cleanup before starting to initialize')
|
||||
writeLine(sourceFile, ' m_pendingInitReplies.clear();')
|
||||
writeLine(sourceFile, ' m_pendingUpdateReplies.clear();')
|
||||
writeLine(sourceFile, ' m_communicationWorking = false;')
|
||||
writeLine(sourceFile, ' m_communicationFailedCounter = 0;')
|
||||
writeLine(sourceFile, ' verifyReachability();')
|
||||
writeLine(sourceFile, ' } else {')
|
||||
writeLine(sourceFile, ' qCWarning(dc%s()) << "Modbus TCP connection diconnected from" << m_hostAddress.toString() << ". 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)
|
||||
|
||||
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;')
|
||||
|
|
@ -268,6 +296,41 @@ def writeTcpSourceFile():
|
|||
writeLine(sourceFile, '}')
|
||||
writeLine(sourceFile)
|
||||
|
||||
writeLine(sourceFile, 'void %s::handleModbusError(QModbusDevice::Error error)' % (className))
|
||||
writeLine(sourceFile, '{')
|
||||
writeLine(sourceFile, ' if (error == QModbusDevice::NoError) {')
|
||||
writeLine(sourceFile, ' // Reset the communication 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 && 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)
|
||||
|
||||
writeVerifyReachabilityImplementationsTcp(sourceFile, className, registerJson['registers'], checkReachableRegister)
|
||||
|
||||
|
||||
# Write the debug print
|
||||
debugObjectParamName = className[0].lower() + className[1:]
|
||||
writeLine(sourceFile, 'QDebug operator<<(QDebug debug, %s *%s)' % (className, debugObjectParamName))
|
||||
|
|
@ -570,7 +633,7 @@ def writeRtuSourceFile():
|
|||
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, ' // Reset the communication 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))
|
||||
|
|
@ -590,7 +653,7 @@ def writeRtuSourceFile():
|
|||
|
||||
writeLine(sourceFile, 'void %s::evaluateReachableState()' % (className))
|
||||
writeLine(sourceFile, '{')
|
||||
writeLine(sourceFile, ' bool reachable = m_communicationWorking & m_modbusRtuMaster->connected();')
|
||||
writeLine(sourceFile, ' bool reachable = m_communicationWorking && m_modbusRtuMaster->connected();')
|
||||
writeLine(sourceFile, ' if (m_reachable == reachable)')
|
||||
writeLine(sourceFile, ' return;')
|
||||
writeLine(sourceFile)
|
||||
|
|
|
|||
|
|
@ -128,10 +128,7 @@ void IntegrationPluginPhoenixConnect::setupThing(ThingSetupInfo *info)
|
|||
}
|
||||
});
|
||||
|
||||
connect(connection, &PhoenixModbusTcpConnection::updateFinished, thing, [connection, thing](){
|
||||
qCDebug(dcPhoenixContact()) << "Update finished:" << thing->name() << connection;
|
||||
});
|
||||
|
||||
// Only during setup
|
||||
connect(connection, &PhoenixModbusTcpConnection::initializationFinished, info, [this, thing, connection, monitor, info](bool success){
|
||||
if (success) {
|
||||
qCDebug(dcPhoenixContact()) << "Phoenix wallbox initialized. Firmware version:" << connection->firmwareVersion();
|
||||
|
|
@ -145,6 +142,10 @@ void IntegrationPluginPhoenixConnect::setupThing(ThingSetupInfo *info)
|
|||
}
|
||||
});
|
||||
|
||||
connect(connection, &PhoenixModbusTcpConnection::updateFinished, thing, [connection, thing](){
|
||||
qCDebug(dcPhoenixContact()) << "Update finished:" << thing->name() << connection;
|
||||
});
|
||||
|
||||
connect(connection, &PhoenixModbusTcpConnection::initializationFinished, thing, [thing, connection](bool success){
|
||||
if (success) {
|
||||
thing->setStateValue("connected", true);
|
||||
|
|
@ -152,7 +153,6 @@ void IntegrationPluginPhoenixConnect::setupThing(ThingSetupInfo *info)
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
// Handle property changed signals
|
||||
connect(connection, &PhoenixModbusTcpConnection::cpStatusChanged, thing, [thing, connection](quint16 cpStatus){
|
||||
qCDebug(dcPhoenixContact()) << "CP Signal state changed:" << (char)cpStatus;
|
||||
|
|
|
|||
Loading…
Reference in New Issue