diff options
author | Rainer Keller <Rainer.Keller@qt.io> | 2018-08-02 10:32:47 +0200 |
---|---|---|
committer | Rainer Keller <Rainer.Keller@qt.io> | 2018-08-14 05:44:40 +0000 |
commit | 111adffce2c1766fe245e9e4bc69e23050c9b692 (patch) | |
tree | 4b2287c50edaf625f9261c0f11d2680ea921fe29 | |
parent | 7736c937ef176bcff50926fc9d6a81a0c267389e (diff) |
Namespace autoupdate
The namespace array node will be watched for changes so that
the namespaceArrayUpdated signal will be emitted without calling
updateNamespaceArray beforehand.
Change-Id: I8bd628cf6794d755065def0e4a0513dc56be6638
Reviewed-by: Jannis Völker <jannis.voelker@basyskom.com>
Reviewed-by: Rainer Keller <Rainer.Keller@qt.io>
-rw-r--r-- | src/opcua/client/qopcuaclient.cpp | 53 | ||||
-rw-r--r-- | src/opcua/client/qopcuaclient.h | 5 | ||||
-rw-r--r-- | src/opcua/client/qopcuaclient_p.h | 4 | ||||
-rw-r--r-- | src/opcua/client/qopcuaclientprivate.cpp | 47 | ||||
-rw-r--r-- | tests/auto/qopcuaclient/tst_client.cpp | 10 |
5 files changed, 114 insertions, 5 deletions
diff --git a/src/opcua/client/qopcuaclient.cpp b/src/opcua/client/qopcuaclient.cpp index 741d591..de4e863 100644 --- a/src/opcua/client/qopcuaclient.cpp +++ b/src/opcua/client/qopcuaclient.cpp @@ -569,4 +569,57 @@ QString QOpcUaClient::backend() const return d->m_impl->backend(); } +/*! + Enables automatic update of the namespace table. + + A subscription will be made to the server node and \l namespaceArrayUpdated will be emitted + when the array changed without calling \l updateNamespaceArray first. + + \a enable Determines whether to enable or disable the autoupdate functionality. + + \sa namespaceArray() namespaceArrayUpdated() +*/ +void QOpcUaClient::setEnableNamespaceAutoupdate(bool enable) +{ + Q_D(QOpcUaClient); + d->m_enableNamespaceArrayAutoupdate = enable; + d->setupNamespaceArrayMonitoring(); +} + +/*! + Returns whether autoupdate of the namespace array is activated. +*/ +bool QOpcUaClient::namespaceAutoupdateEnabled() const +{ + Q_D(const QOpcUaClient); + return d->m_enableNamespaceArrayAutoupdate; +} + +/*! + Sets the interval for the namespace table subscription. + + The subscription may be revised by the server. + + \a interval determines the interval to check for changes in milliseconds. The default is once per second. + + \sa QOpcUaClient::setEnableNamespaceAutoupdate(bool enable) +*/ +void QOpcUaClient::setNamespaceAutoupdateInterval(int interval) +{ + Q_D(QOpcUaClient); + d->m_namespaceArrayUpdateInterval = interval; + d->setupNamespaceArrayMonitoring(); +} + +/*! + Returns the current revised update inverval of the namespace array. + + \sa setNamespaceAutoupdateInterval(int interval) +*/ +int QOpcUaClient::namespaceAutoupdateInterval() const +{ + Q_D(const QOpcUaClient); + return d->m_namespaceArrayUpdateInterval; +} + QT_END_NAMESPACE diff --git a/src/opcua/client/qopcuaclient.h b/src/opcua/client/qopcuaclient.h index 3611855..7aca93b 100644 --- a/src/opcua/client/qopcuaclient.h +++ b/src/opcua/client/qopcuaclient.h @@ -105,6 +105,11 @@ public: QString backend() const; + void setEnableNamespaceAutoupdate(bool enable); + bool namespaceAutoupdateEnabled() const; + void setNamespaceAutoupdateInterval(int interval); + int namespaceAutoupdateInterval() const; + Q_SIGNALS: void connected(); void disconnected(); diff --git a/src/opcua/client/qopcuaclient_p.h b/src/opcua/client/qopcuaclient_p.h index fe2aaa2..51ce5d0 100644 --- a/src/opcua/client/qopcuaclient_p.h +++ b/src/opcua/client/qopcuaclient_p.h @@ -72,6 +72,7 @@ public: QOpcUaClient::ClientState m_state; QOpcUaClient::ClientError m_error; QUrl m_url; + bool m_enableNamespaceArrayAutoupdate; bool checkAndSetUrl(const QUrl &url); void setStateAndError(QOpcUaClient::ClientState state, @@ -80,11 +81,14 @@ public: bool updateNamespaceArray(); QStringList namespaceArray() const; void namespaceArrayUpdated(QOpcUa::NodeAttributes attr); + void setupNamespaceArrayMonitoring(); private: Q_DECLARE_PUBLIC(QOpcUaClient) QStringList m_namespaceArray; QScopedPointer<QOpcUaNode> m_namespaceArrayNode; + bool m_namespaceArrayAutoupdateEnabled; + unsigned int m_namespaceArrayUpdateInterval; }; QT_END_NAMESPACE diff --git a/src/opcua/client/qopcuaclientprivate.cpp b/src/opcua/client/qopcuaclientprivate.cpp index 18f8487..a186bf8 100644 --- a/src/opcua/client/qopcuaclientprivate.cpp +++ b/src/opcua/client/qopcuaclientprivate.cpp @@ -47,13 +47,18 @@ QOpcUaClientPrivate::QOpcUaClientPrivate(QOpcUaClientImpl *impl) , m_impl(impl) , m_state(QOpcUaClient::Disconnected) , m_error(QOpcUaClient::NoError) + , m_enableNamespaceArrayAutoupdate(false) + , m_namespaceArrayAutoupdateEnabled(false) + , m_namespaceArrayUpdateInterval(1000) { // callback from client implementation QObject::connect(m_impl.data(), &QOpcUaClientImpl::stateAndOrErrorChanged, [this](QOpcUaClient::ClientState state, QOpcUaClient::ClientError error) { setStateAndError(state, error); - if (state == QOpcUaClient::ClientState::Connected) + if (state == QOpcUaClient::ClientState::Connected) { updateNamespaceArray(); + setupNamespaceArrayMonitoring(); + } }); QObject::connect(m_impl.data(), &QOpcUaClientImpl::endpointsRequestFinished, m_impl.data(), @@ -194,4 +199,44 @@ void QOpcUaClientPrivate::namespaceArrayUpdated(QOpcUa::NodeAttributes attr) emit q->namespaceArrayUpdated(m_namespaceArray); } +void QOpcUaClientPrivate::setupNamespaceArrayMonitoring() +{ + Q_Q(QOpcUaClient); + + if (!m_namespaceArrayNode || m_state != QOpcUaClient::ClientState::Connected) + return; + + if (!m_enableNamespaceArrayAutoupdate && m_namespaceArrayAutoupdateEnabled) { + m_namespaceArrayNode->disableMonitoring(QOpcUa::NodeAttribute::Value); + m_namespaceArrayAutoupdateEnabled = false; + return; + } + + if (m_enableNamespaceArrayAutoupdate && !m_namespaceArrayAutoupdateEnabled) { + QOpcUaMonitoringParameters options; + options.setShared(QOpcUaMonitoringParameters::SubscriptionType::Exclusive); + options.setMaxKeepAliveCount(std::numeric_limits<quint32>::max() - 1); + options.setPublishingInterval(m_namespaceArrayUpdateInterval); + m_namespaceArrayAutoupdateEnabled = true; + + QObject::connect(m_namespaceArrayNode.data(), &QOpcUaNode::enableMonitoringFinished, q, + [&] (QOpcUa::NodeAttribute, QOpcUa::UaStatusCode statusCode) { + if (statusCode == QOpcUa::Good) { + // Update interval member to the revised value from the server + m_namespaceArrayUpdateInterval = m_namespaceArrayNode->monitoringStatus(QOpcUa::NodeAttribute::Value).publishingInterval(); + } else { + m_namespaceArrayAutoupdateEnabled = m_enableNamespaceArrayAutoupdate = false; + } + } + ); + QObject::connect(m_namespaceArrayNode.data(), &QOpcUaNode::attributeUpdated, q, + [&] (QOpcUa::NodeAttribute attr, QVariant /*value*/) { + namespaceArrayUpdated(attr); + } + ); + + m_namespaceArrayNode->enableMonitoring(QOpcUa::NodeAttribute::Value, options); + } +} + QT_END_NAMESPACE diff --git a/tests/auto/qopcuaclient/tst_client.cpp b/tests/auto/qopcuaclient/tst_client.cpp index 61476f4..b48eddd 100644 --- a/tests/auto/qopcuaclient/tst_client.cpp +++ b/tests/auto/qopcuaclient/tst_client.cpp @@ -3298,6 +3298,10 @@ void Tst_QOpcUaClient::addNamespace() QSignalSpy methodSpy(node.data(), &QOpcUaNode::methodCallFinished); + opcuaClient->setEnableNamespaceAutoupdate(true); + namespaceUpdatedSpy.clear(); + namespaceChangedSpy.clear(); + bool success = node->callMethod("ns=3;s=Test.Method.AddNamespace", args); QVERIFY(success == true); @@ -3308,12 +3312,10 @@ void Tst_QOpcUaClient::addNamespace() QCOMPARE(methodSpy.at(0).at(1).value<quint16>(), namespaceArray.size()); QCOMPARE(QOpcUa::isSuccessStatus(methodSpy.at(0).at(2).value<QOpcUa::UaStatusCode>()), true); - namespaceUpdatedSpy.clear(); - namespaceChangedSpy.clear(); - opcuaClient->updateNamespaceArray(); + // Do not call updateNamespaceArray() namespaceChangedSpy.wait(); - QCOMPARE(namespaceUpdatedSpy.size(), 1); + QVERIFY(namespaceUpdatedSpy.size() > 0); QCOMPARE(namespaceChangedSpy.size(), 1); auto updatedNamespaceArray = opcuaClient->namespaceArray(); QVERIFY(updatedNamespaceArray.size() == namespaceArray.size() + 1); |