summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demo/Main.qml6
-rw-r--r--src/BobinkClient.cpp38
-rw-r--r--src/BobinkClient.h2
-rw-r--r--src/BobinkNode.cpp147
-rw-r--r--src/BobinkNode.h6
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;