diff options
| -rw-r--r-- | demo/Main.qml | 6 | ||||
| -rw-r--r-- | src/BobinkClient.cpp | 38 | ||||
| -rw-r--r-- | src/BobinkClient.h | 2 | ||||
| -rw-r--r-- | src/BobinkNode.cpp | 147 | ||||
| -rw-r--r-- | src/BobinkNode.h | 6 |
5 files changed, 163 insertions, 36 deletions
diff --git a/demo/Main.qml b/demo/Main.qml index ca22bb8..7b76fee 100644 --- a/demo/Main.qml +++ b/demo/Main.qml @@ -336,15 +336,15 @@ ApplicationWindow { function appendLog(msg) { let ts = new Date().toLocaleTimeString(Qt.locale(), "HH:mm:ss"); - statusLog.text += "[" + ts + "] " + msg + "\n"; - statusLog.cursorPosition = statusLog.text.length; + debugLog.text += "[" + ts + "] " + msg + "\n"; + debugLog.cursorPosition = debugLog.text.length; } ScrollView { anchors.fill: parent anchors.margins: 4 TextArea { - id: statusLog + id: debugLog readOnly: true color: "#cccccc" font.family: "monospace" diff --git a/src/BobinkClient.cpp b/src/BobinkClient.cpp index e7f6d0d..f8303a3 100644 --- a/src/BobinkClient.cpp +++ b/src/BobinkClient.cpp @@ -9,6 +9,8 @@ #include <QOpcUaUserTokenPolicy> #include <QStandardPaths> +using namespace Qt::Literals::StringLiterals; + BobinkClient *BobinkClient::s_instance = nullptr; static QString @@ -22,10 +24,11 @@ defaultPkiDir () static void ensurePkiDirs (const QString &base) { - for (const auto *sub : { "own/certs", "own/private", "trusted/certs", - "trusted/crl", "issuers/certs", "issuers/crl" }) + for (const auto sub : + { u"own/certs"_s, u"own/private"_s, u"trusted/certs"_s, + u"trusted/crl"_s, u"issuers/certs"_s, u"issuers/crl"_s }) { - QDir ().mkpath (base + QLatin1Char ('/') + QLatin1String (sub)); + QDir ().mkpath (base + QLatin1Char ('/') + sub); } } @@ -85,19 +88,20 @@ BobinkClient::setupClient () connect (m_client, &QOpcUaClient::errorChanged, this, [this] (QOpcUaClient::ClientError error) { - static const char *names[] - = { "NoError", - "InvalidUrl", - "AccessDenied", - "ConnectionError", - "UnknownError", - "UnsupportedAuthenticationInformation", - "InvalidAuthenticationInformation", - "InvalidEndpointDescription", - "NoMatchingUserIdentityTokenFound", - "UnsupportedSecurityPolicy", - "InvalidPki" }; - int idx = static_cast<int> (error); + static const QLatin1StringView names[] = { + "NoError"_L1, + "InvalidUrl"_L1, + "AccessDenied"_L1, + "ConnectionError"_L1, + "UnknownError"_L1, + "UnsupportedAuthenticationInformation"_L1, + "InvalidAuthenticationInformation"_L1, + "InvalidEndpointDescription"_L1, + "NoMatchingUserIdentityTokenFound"_L1, + "UnsupportedSecurityPolicy"_L1, + "InvalidPki"_L1, + }; + qint32 idx = static_cast<qint32> (error); if (idx > 0 && idx <= 10) emit connectionError ( QStringLiteral ("Client error: %1").arg (names[idx])); @@ -564,7 +568,7 @@ BobinkClient::handleConnectError (QOpcUaErrorState *errorState) emit connectionError ( QStringLiteral ("Connection error at step %1, code 0x%2") .arg (static_cast<int> (errorState->connectionStep ())) - .arg (static_cast<uint> (errorState->errorCode ()), 8, 16, + .arg (static_cast<quint32> (errorState->errorCode ()), 8, 16, QLatin1Char ('0'))); } } diff --git a/src/BobinkClient.h b/src/BobinkClient.h index c86cfaa..5b7b284 100644 --- a/src/BobinkClient.h +++ b/src/BobinkClient.h @@ -167,7 +167,7 @@ private: bool m_certAccepted = false; QString m_discoveryUrl; - int m_discoveryInterval = 30000; // ms + qint32 m_discoveryInterval = 30000; // ms QTimer m_discoveryTimer; bool m_discovering = false; QList<QOpcUaApplicationDescription> m_discoveredServers; 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 <QOpcUaClient> #include <QOpcUaMonitoringParameters> +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<QOpcUa::NodeAttribute> (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<quint32> (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<quint32> (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<quint32> (statusCode), 8, 16, + QLatin1Char ('0'))); +} + /* ------------------------------------------------------------------ */ /* Helpers */ /* ------------------------------------------------------------------ */ @@ -275,23 +349,66 @@ QOpcUa::NodeAttribute BobinkNode::attributeFromName (const QString &name) { static const QHash<QString, QOpcUa::NodeAttribute> 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; + } +} diff --git a/src/BobinkNode.h b/src/BobinkNode.h index 0fa1678..c37a883 100644 --- a/src/BobinkNode.h +++ b/src/BobinkNode.h @@ -85,9 +85,15 @@ private: void handleAttributeWritten (QOpcUa::NodeAttribute attr, QOpcUa::UaStatusCode statusCode); void handleClientConnectedChanged (); + void handleAttributeReadFinished (QOpcUa::NodeAttributes attrs); + void handleEnableMonitoringFinished (QOpcUa::NodeAttribute attr, + QOpcUa::UaStatusCode statusCode); + void handleDisableMonitoringFinished (QOpcUa::NodeAttribute attr, + QOpcUa::UaStatusCode statusCode); static NodeStatus statusFromCode (QOpcUa::UaStatusCode code); static QOpcUa::NodeAttribute attributeFromName (const QString &name); + static QLatin1StringView nameFromAttribute (QOpcUa::NodeAttribute attr); QString m_nodeId; QVariant m_value; |
