From 50c62c35463b62a3a7acebf9ebe22d44f1c6dca2 Mon Sep 17 00:00:00 2001 From: Thomas Vanbesien Date: Thu, 19 Feb 2026 12:29:05 +0100 Subject: Log attribute reads to debug console and replace raw C++ types with Qt equivalents Connect QOpcUaNode::attributeRead signal to new handler that logs read results (value or error code) to the debug console via BobinkClient::statusMessage. Add nameFromAttribute() helper. Replace const char* arrays with QLatin1StringView, bare string literals with QStringLiteral, uint with quint32, int with qint32. Rename statusLog to debugLog in Main.qml for consistency. --- src/BobinkNode.cpp | 147 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 132 insertions(+), 15 deletions(-) (limited to 'src/BobinkNode.cpp') diff --git a/src/BobinkNode.cpp b/src/BobinkNode.cpp index 241b9c5..a39c195 100644 --- a/src/BobinkNode.cpp +++ b/src/BobinkNode.cpp @@ -8,6 +8,8 @@ #include #include +using namespace Qt::Literals::StringLiterals; + static constexpr double DEFAULT_PUBLISHING_INTERVAL = 250.0; // ms /* ------------------------------------------------------------------ */ @@ -153,6 +155,12 @@ BobinkNode::startMonitoring () &BobinkNode::handleAttributeUpdated); connect (m_opcuaNode, &QOpcUaNode::attributeWritten, this, &BobinkNode::handleAttributeWritten); + connect (m_opcuaNode, &QOpcUaNode::attributeRead, this, + &BobinkNode::handleAttributeReadFinished); + connect (m_opcuaNode, &QOpcUaNode::enableMonitoringFinished, this, + &BobinkNode::handleEnableMonitoringFinished); + connect (m_opcuaNode, &QOpcUaNode::disableMonitoringFinished, this, + &BobinkNode::handleDisableMonitoringFinished); QOpcUaMonitoringParameters params (DEFAULT_PUBLISHING_INTERVAL); m_opcuaNode->enableMonitoring (QOpcUa::NodeAttribute::Value, params); @@ -252,6 +260,72 @@ BobinkNode::handleClientConnectedChanged () } } +void +BobinkNode::handleAttributeReadFinished (QOpcUa::NodeAttributes attrs) +{ + auto *client = BobinkClient::instance (); + if (!client || !m_opcuaNode) + return; + + for (int bit = 0; bit < 27; ++bit) + { + auto attr = static_cast (1 << bit); + if (!attrs.testFlag (attr)) + continue; + + auto sc = m_opcuaNode->attributeError (attr); + QLatin1StringView name = nameFromAttribute (attr); + if (sc == QOpcUa::UaStatusCode::Good) + emit client->statusMessage ( + QStringLiteral ("Read %1.%2 = %3") + .arg (m_nodeId, name, + m_opcuaNode->attribute (attr).toString ())); + else + emit client->statusMessage ( + QStringLiteral ("Read %1.%2 failed: 0x%3") + .arg (m_nodeId, name) + .arg (static_cast (sc), 8, 16, QLatin1Char ('0'))); + } +} + +void +BobinkNode::handleEnableMonitoringFinished (QOpcUa::NodeAttribute, + QOpcUa::UaStatusCode statusCode) +{ + auto *client = BobinkClient::instance (); + if (!client) + return; + + if (statusCode == QOpcUa::Good) + emit client->statusMessage ( + QStringLiteral ("Monitoring started: %1").arg (m_nodeId)); + else + emit client->statusMessage ( + QStringLiteral ("Monitoring failed for %1: 0x%2") + .arg (m_nodeId) + .arg (static_cast (statusCode), 8, 16, + QLatin1Char ('0'))); +} + +void +BobinkNode::handleDisableMonitoringFinished (QOpcUa::NodeAttribute, + QOpcUa::UaStatusCode statusCode) +{ + auto *client = BobinkClient::instance (); + if (!client) + return; + + if (statusCode == QOpcUa::Good) + emit client->statusMessage ( + QStringLiteral ("Monitoring stopped: %1").arg (m_nodeId)); + else + emit client->statusMessage ( + QStringLiteral ("Stop monitoring failed for %1: 0x%2") + .arg (m_nodeId) + .arg (static_cast (statusCode), 8, 16, + QLatin1Char ('0'))); +} + /* ------------------------------------------------------------------ */ /* Helpers */ /* ------------------------------------------------------------------ */ @@ -275,23 +349,66 @@ QOpcUa::NodeAttribute BobinkNode::attributeFromName (const QString &name) { static const QHash map = { - { "NodeId", QOpcUa::NodeAttribute::NodeId }, - { "NodeClass", QOpcUa::NodeAttribute::NodeClass }, - { "BrowseName", QOpcUa::NodeAttribute::BrowseName }, - { "DisplayName", QOpcUa::NodeAttribute::DisplayName }, - { "Description", QOpcUa::NodeAttribute::Description }, - { "Value", QOpcUa::NodeAttribute::Value }, - { "DataType", QOpcUa::NodeAttribute::DataType }, - { "ValueRank", QOpcUa::NodeAttribute::ValueRank }, - { "ArrayDimensions", QOpcUa::NodeAttribute::ArrayDimensions }, - { "AccessLevel", QOpcUa::NodeAttribute::AccessLevel }, - { "UserAccessLevel", QOpcUa::NodeAttribute::UserAccessLevel }, - { "MinimumSamplingInterval", + { QStringLiteral ("NodeId"), QOpcUa::NodeAttribute::NodeId }, + { QStringLiteral ("NodeClass"), QOpcUa::NodeAttribute::NodeClass }, + { QStringLiteral ("BrowseName"), QOpcUa::NodeAttribute::BrowseName }, + { QStringLiteral ("DisplayName"), QOpcUa::NodeAttribute::DisplayName }, + { QStringLiteral ("Description"), QOpcUa::NodeAttribute::Description }, + { QStringLiteral ("Value"), QOpcUa::NodeAttribute::Value }, + { QStringLiteral ("DataType"), QOpcUa::NodeAttribute::DataType }, + { QStringLiteral ("ValueRank"), QOpcUa::NodeAttribute::ValueRank }, + { QStringLiteral ("ArrayDimensions"), + QOpcUa::NodeAttribute::ArrayDimensions }, + { QStringLiteral ("AccessLevel"), QOpcUa::NodeAttribute::AccessLevel }, + { QStringLiteral ("UserAccessLevel"), + QOpcUa::NodeAttribute::UserAccessLevel }, + { QStringLiteral ("MinimumSamplingInterval"), QOpcUa::NodeAttribute::MinimumSamplingInterval }, - { "Historizing", QOpcUa::NodeAttribute::Historizing }, - { "Executable", QOpcUa::NodeAttribute::Executable }, - { "UserExecutable", QOpcUa::NodeAttribute::UserExecutable }, + { QStringLiteral ("Historizing"), QOpcUa::NodeAttribute::Historizing }, + { QStringLiteral ("Executable"), QOpcUa::NodeAttribute::Executable }, + { QStringLiteral ("UserExecutable"), + QOpcUa::NodeAttribute::UserExecutable }, }; return map.value (name, QOpcUa::NodeAttribute::None); } + +QLatin1StringView +BobinkNode::nameFromAttribute (QOpcUa::NodeAttribute attr) +{ + switch (attr) + { + case QOpcUa::NodeAttribute::NodeId: + return "NodeId"_L1; + case QOpcUa::NodeAttribute::NodeClass: + return "NodeClass"_L1; + case QOpcUa::NodeAttribute::BrowseName: + return "BrowseName"_L1; + case QOpcUa::NodeAttribute::DisplayName: + return "DisplayName"_L1; + case QOpcUa::NodeAttribute::Description: + return "Description"_L1; + case QOpcUa::NodeAttribute::Value: + return "Value"_L1; + case QOpcUa::NodeAttribute::DataType: + return "DataType"_L1; + case QOpcUa::NodeAttribute::ValueRank: + return "ValueRank"_L1; + case QOpcUa::NodeAttribute::ArrayDimensions: + return "ArrayDimensions"_L1; + case QOpcUa::NodeAttribute::AccessLevel: + return "AccessLevel"_L1; + case QOpcUa::NodeAttribute::UserAccessLevel: + return "UserAccessLevel"_L1; + case QOpcUa::NodeAttribute::MinimumSamplingInterval: + return "MinimumSamplingInterval"_L1; + case QOpcUa::NodeAttribute::Historizing: + return "Historizing"_L1; + case QOpcUa::NodeAttribute::Executable: + return "Executable"_L1; + case QOpcUa::NodeAttribute::UserExecutable: + return "UserExecutable"_L1; + default: + return "Unknown"_L1; + } +} -- cgit v1.2.3