modbus-tool: Improve reachability check error handling

master
Simon Stürz 2023-06-02 16:56:46 +02:00
parent 28f280b15c
commit 586f50a2dc
5 changed files with 95 additions and 10 deletions

View File

@ -270,3 +270,45 @@ QVector<quint16> ModbusDataUtils::convertFromFloat64(double value, ByteOrder byt
memcpy(&rawValue, &value, sizeof(double));
return ModbusDataUtils::convertFromUInt64(rawValue, byteOrder);
}
QString ModbusDataUtils::exceptionCodeToString(QModbusPdu::ExceptionCode exception)
{
QString exceptionString;
switch (exception) {
case QModbusPdu::IllegalFunction:
exceptionString = "Illegal function";
break;
case QModbusPdu::IllegalDataAddress:
exceptionString = "Illegal data address";
break;
case QModbusPdu::IllegalDataValue:
exceptionString = "Illegal data value";
break;
case QModbusPdu::ServerDeviceFailure:
exceptionString = "Server device failure";
break;
case QModbusPdu::Acknowledge:
exceptionString = "Acknowledge";
break;
case QModbusPdu::ServerDeviceBusy:
exceptionString = "Server device busy";
break;
case QModbusPdu::NegativeAcknowledge:
exceptionString = "Negative acknowledge";
break;
case QModbusPdu::MemoryParityError:
exceptionString = "Memory parity error";
break;
case QModbusPdu::GatewayPathUnavailable:
exceptionString = "Gateway path unavailable";
break;
case QModbusPdu::GatewayTargetDeviceFailedToRespond:
exceptionString = "Gateway target device failed to respond";
break;
case QModbusPdu::ExtendedException:
exceptionString = "Extended exception";
break;
}
return exceptionString;
}

View File

@ -33,6 +33,7 @@
#include <QVector>
#include <QObject>
#include <QModbusPdu>
class ModbusDataUtils
{
@ -102,6 +103,8 @@ public:
static QVector<quint16> convertFromString(const QString &value, quint16 stringLength, ByteOrder characterByteOrder = ByteOrderLittleEndian);
static QVector<quint16> convertFromFloat32(float value, ByteOrder byteOrder = ByteOrderLittleEndian);
static QVector<quint16> convertFromFloat64(double value, ByteOrder byteOrder = ByteOrderLittleEndian);
static QString exceptionCodeToString(QModbusPdu::ExceptionCode exception);
};
#endif // MODBUSDATAUTILS_H

View File

@ -100,9 +100,9 @@ bool ModbusTcpMaster::connectDevice()
m_modbusTcpClient->setTimeout(m_timeout);
m_modbusTcpClient->setNumberOfRetries(m_numberOfRetries);
return m_modbusTcpClient->connectDevice();
} else if (m_modbusTcpClient->state() != QModbusDevice::ConnectedState) {
} else if (m_modbusTcpClient->state() != QModbusDevice::ConnectedState && m_modbusTcpClient->state() != QModbusDevice::ConnectingState) {
// Restart the timer in case of connecting not finished yet or closing
qCDebug(dcModbusTcpMaster()) << "Starting the reconnect mechanism timer";
qCDebug(dcModbusTcpMaster()) << "Starting the re-connect mechanism timer";
m_reconnectTimer->start();
} else {
qCWarning(dcModbusTcpMaster()) << "Connect modbus TCP device" << connectionUrl() << "called, but the socket is currently in the" << m_modbusTcpClient->state();

View File

@ -114,7 +114,12 @@ def writePropertyUpdateMethodImplementationsTcp(fileDescriptor, className, regis
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating \\"%s\\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();' % (className, registerDefinition['description']))
writeLine(fileDescriptor, ' QModbusResponse response = reply->rawResult();')
writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating \\"%s\\" registers from" << m_modbusTcpMaster->hostAddress().toString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());' % (className, registerDefinition['description']))
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating \\"%s\\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();' % (className, registerDefinition['description']))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor, '}')
writeLine(fileDescriptor)
@ -177,7 +182,12 @@ def writeBlockUpdateMethodImplementationsTcp(fileDescriptor, className, blockDef
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName))
writeLine(fileDescriptor, ' QModbusResponse response = reply->rawResult();')
writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());' % (className, blockName))
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor, '}')
writeLine(fileDescriptor)
@ -317,7 +327,15 @@ def writeTestReachabilityImplementationsTcp(fileDescriptor, className, registerD
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' connect(m_checkRechableReply, &QModbusReply::errorOccurred, this, [this] (QModbusDevice::Error error){')
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "Modbus reply error occurred while verifying reachability by reading \\"%s\\" register" << error << m_checkRechableReply->errorString();' % (className, checkReachableRegister['description']))
writeLine(fileDescriptor, ' QModbusResponse response = m_checkRechableReply->rawResult();')
writeLine(fileDescriptor, ' if (m_checkRechableReply->error() == QModbusDevice::ProtocolError && response.isException()) {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while verifying reachability by reading \\"%s\\" register" << error << m_checkRechableReply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());' % (className, checkReachableRegister['description']))
writeLine(fileDescriptor, ' // Note: if we get an exception on the reachability register, the modbus server is probably not ready')
writeLine(fileDescriptor, ' // For some reasons on some devices the reply will never be finished on exception response. A reconnect might fix it.')
writeLine(fileDescriptor, ' QTimer::singleShot(2000, m_modbusTcpMaster, &ModbusTcpMaster::reconnectDevice);')
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "Modbus reply error occurred while verifying reachability by reading \\"%s\\" register" << error << m_checkRechableReply->errorString();' % (className, checkReachableRegister['description']))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor, '}')
writeLine(fileDescriptor)
@ -398,7 +416,12 @@ def writeInitMethodImplementationTcp(fileDescriptor, className, registerDefiniti
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, m_initObject, [this, reply] (QModbusDevice::Error error){')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while reading \\"%s\\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();' % (className, registerDefinition['description']))
writeLine(fileDescriptor, ' QModbusResponse response = reply->rawResult();')
writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while reading \\"%s\\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());' % (className, registerDefinition['description']))
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while reading \\"%s\\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();' % (className, registerDefinition['description']))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' });')
# Read init blocks
@ -465,7 +488,12 @@ def writeInitMethodImplementationTcp(fileDescriptor, className, registerDefiniti
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, m_initObject, [reply] (QModbusDevice::Error error){')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName))
writeLine(fileDescriptor, ' QModbusResponse response = reply->rawResult();')
writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());' % (className, blockName))
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)
@ -546,7 +574,12 @@ def writeUpdateMethodTcp(fileDescriptor, className, registerDefinitions, blockDe
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while reading \\"%s\\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();' % (className, registerDefinition['description']))
writeLine(fileDescriptor, ' QModbusResponse response = reply->rawResult();')
writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while reading \\"%s\\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());' % (className, registerDefinition['description']))
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while reading \\"%s\\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();' % (className, registerDefinition['description']))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' });')
# Read init blocks
@ -613,7 +646,12 @@ def writeUpdateMethodTcp(fileDescriptor, className, registerDefinitions, blockDe
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName))
writeLine(fileDescriptor, ' QModbusResponse response = reply->rawResult();')
writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());' % (className, blockName))
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)

View File

@ -208,6 +208,8 @@ def writeTcpSourceFile():
writeLine(sourceFile, '#include <loggingcategories.h>')
writeLine(sourceFile, '#include <math.h>')
writeLine(sourceFile, '#include <QTimer>')
writeLine(sourceFile, '#include <QModbusDevice>')
writeLine(sourceFile, '#include <QModbusResponse>')
writeLine(sourceFile)
writeLine(sourceFile, 'NYMEA_LOGGING_CATEGORY(dc%s, "%s")' % (className, className))
writeLine(sourceFile)
@ -366,7 +368,7 @@ def writeTcpSourceFile():
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, ' qCWarning(dc%s()) << "Received" << m_communicationFailedCounter << "errors while communicating with the TCP master. Mark as not reachable until the communication works again.";' % (className))
writeLine(sourceFile, ' evaluateReachableState();')
writeLine(sourceFile, ' }')
writeLine(sourceFile, ' }')