summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/opcua/client/client.pri23
-rw-r--r--src/opcua/client/qopcuabackend_p.h6
-rw-r--r--src/opcua/client/qopcuaclient.cpp17
-rw-r--r--src/opcua/client/qopcuaclient.h3
-rw-r--r--src/opcua/client/qopcuaclient_p.h1
-rw-r--r--src/opcua/client/qopcuaclientimpl.cpp25
-rw-r--r--src/opcua/client/qopcuaclientimpl_p.h8
-rw-r--r--src/opcua/client/qopcuamonitoredevent.cpp91
-rw-r--r--src/opcua/client/qopcuamonitoredevent.h72
-rw-r--r--src/opcua/client/qopcuamonitoredevent_p.h78
-rw-r--r--src/opcua/client/qopcuamonitoredeventprivate.cpp62
-rw-r--r--src/opcua/client/qopcuamonitoredvalue.cpp86
-rw-r--r--src/opcua/client/qopcuamonitoredvalue.h70
-rw-r--r--src/opcua/client/qopcuamonitoredvalue_p.h78
-rw-r--r--src/opcua/client/qopcuamonitoredvalueprivate.cpp64
-rw-r--r--src/opcua/client/qopcuamonitoringparameters.cpp390
-rw-r--r--src/opcua/client/qopcuamonitoringparameters.h165
-rw-r--r--src/opcua/client/qopcuamonitoringparameters_p.h (renamed from src/opcua/client/qopcuasubscription_p.h)56
-rw-r--r--src/opcua/client/qopcuanode.cpp115
-rw-r--r--src/opcua/client/qopcuanode.h14
-rw-r--r--src/opcua/client/qopcuanode_p.h59
-rw-r--r--src/opcua/client/qopcuanodeimpl_p.h12
-rw-r--r--src/opcua/client/qopcuasubscription.cpp107
-rw-r--r--src/opcua/client/qopcuasubscription.h71
-rw-r--r--src/opcua/client/qopcuasubscriptionimpl.cpp49
-rw-r--r--src/opcua/client/qopcuasubscriptionimpl_p.h73
-rw-r--r--src/opcua/client/qopcuasubscriptionprivate.cpp53
-rw-r--r--src/opcua/client/qopcuavaluesubscription.cpp77
-rw-r--r--src/opcua/client/qopcuavaluesubscription.h67
-rw-r--r--src/opcua/core/qopcuaprovider.cpp4
-rw-r--r--src/opcua/doc/src/qtopcua.qdoc6
-rw-r--r--src/plugins/opcua/freeopcua/qfreeopcuaclient.cpp11
-rw-r--r--src/plugins/opcua/freeopcua/qfreeopcuaclient.h2
-rw-r--r--src/plugins/opcua/freeopcua/qfreeopcuanode.cpp30
-rw-r--r--src/plugins/opcua/freeopcua/qfreeopcuanode.h5
-rw-r--r--src/plugins/opcua/freeopcua/qfreeopcuasubscription.cpp247
-rw-r--r--src/plugins/opcua/freeopcua/qfreeopcuasubscription.h59
-rw-r--r--src/plugins/opcua/freeopcua/qfreeopcuaworker.cpp117
-rw-r--r--src/plugins/opcua/freeopcua/qfreeopcuaworker.h18
-rw-r--r--src/plugins/opcua/open62541/qopen62541backend.cpp203
-rw-r--r--src/plugins/opcua/open62541/qopen62541backend.h31
-rw-r--r--src/plugins/opcua/open62541/qopen62541client.cpp8
-rw-r--r--src/plugins/opcua/open62541/qopen62541client.h1
-rw-r--r--src/plugins/opcua/open62541/qopen62541node.cpp28
-rw-r--r--src/plugins/opcua/open62541/qopen62541node.h3
-rw-r--r--src/plugins/opcua/open62541/qopen62541subscription.cpp295
-rw-r--r--src/plugins/opcua/open62541/qopen62541subscription.h56
-rw-r--r--tests/auto/qopcuaclient/tst_client.cpp204
48 files changed, 1776 insertions, 1544 deletions
diff --git a/src/opcua/client/client.pri b/src/opcua/client/client.pri
index c91ffdf..9be8a86 100644
--- a/src/opcua/client/client.pri
+++ b/src/opcua/client/client.pri
@@ -2,35 +2,24 @@
PUBLIC_HEADERS += \
client/qopcuaclient.h \
- client/qopcuasubscription.h \
client/qopcuanode.h \
- client/qopcuatype.h \
- client/qopcuamonitoredevent.h \
- client/qopcuamonitoredvalue.h
+ client/qopcuatype.h
SOURCES += \
client/qopcuaclient.cpp \
- client/qopcuasubscription.cpp \
client/qopcuanode.cpp \
client/qopcuatype.cpp \
- client/qopcuamonitoredevent.cpp \
- client/qopcuamonitoredvalue.cpp \
client/qopcuaclientimpl.cpp \
client/qopcuanodeimpl.cpp \
client/qopcuaclientprivate.cpp \
- client/qopcuamonitoredeventprivate.cpp \
- client/qopcuasubscriptionprivate.cpp \
- client/qopcuamonitoredvalueprivate.cpp \
- client/qopcuasubscriptionimpl.cpp \
- client/qopcuabackend.cpp
+ client/qopcuabackend.cpp \
+ client/qopcuamonitoringparameters.cpp
HEADERS += \
client/qopcuaclient_p.h \
client/qopcuaclientimpl_p.h \
client/qopcuanode_p.h \
client/qopcuanodeimpl_p.h \
- client/qopcuamonitoredevent_p.h \
- client/qopcuamonitoredvalue_p.h \
- client/qopcuasubscription_p.h \
- client/qopcuasubscriptionimpl_p.h \
- client/qopcuabackend_p.h
+ client/qopcuabackend_p.h \
+ client/qopcuamonitoringparameters.h \
+ client/qopcuamonitoringparameters_p.h
diff --git a/src/opcua/client/qopcuabackend_p.h b/src/opcua/client/qopcuabackend_p.h
index da4cf9c..28cbd28 100644
--- a/src/opcua/client/qopcuabackend_p.h
+++ b/src/opcua/client/qopcuabackend_p.h
@@ -58,6 +58,7 @@
QT_BEGIN_NAMESPACE
class QOpcUaNodeImpl;
+class QOpcUaMonitoringParameters;
class Q_OPCUA_EXPORT QOpcUaBackend : public QObject
{
@@ -80,6 +81,11 @@ Q_SIGNALS:
void attributesRead(uintptr_t handle, QVector<QOpcUaReadResult> attributes, QOpcUa::UaStatusCode serviceResult);
void attributeWritten(uintptr_t hande, QOpcUaNode::NodeAttribute attribute, QVariant value, QOpcUa::UaStatusCode statusCode);
+ void attributeUpdated(uintptr_t handle, QOpcUaNode::NodeAttribute attr, QVariant value);
+ void monitoringEnableDisable(uintptr_t handle, QOpcUaNode::NodeAttribute attr, bool subscribe, QOpcUaMonitoringParameters status);
+ void monitoringStatusChanged(uintptr_t handle, QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameters items,
+ QOpcUaMonitoringParameters param);
+
private:
Q_DISABLE_COPY(QOpcUaBackend)
};
diff --git a/src/opcua/client/qopcuaclient.cpp b/src/opcua/client/qopcuaclient.cpp
index 86fd7f9..4306af7 100644
--- a/src/opcua/client/qopcuaclient.cpp
+++ b/src/opcua/client/qopcuaclient.cpp
@@ -241,21 +241,4 @@ QString QOpcUaClient::backend() const
return d_func()->m_impl->backend();
}
-/*!
- Creates a subscription with \a interval milliseconds publishing period
- on the server and returns a QOpcUaSubscription object for it. The
- subscription may be used to monitor nodes for events or value changes.
- The caller becomes the owner of the newly created subscription object.
-
- For this method to work the client needs to be connected to the server.
- A null pointer is returned on error.
-*/
-QOpcUaSubscription *QOpcUaClient::createSubscription(quint32 interval)
-{
- if (state() != QOpcUaClient::Connected)
- return nullptr;
-
- return d_func()->m_impl->createSubscription(interval);
-}
-
QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaclient.h b/src/opcua/client/qopcuaclient.h
index 604c5f4..15c9ee2 100644
--- a/src/opcua/client/qopcuaclient.h
+++ b/src/opcua/client/qopcuaclient.h
@@ -39,7 +39,6 @@
#include <QtOpcUa/qopcuaglobal.h>
#include <QtOpcUa/qopcuanode.h>
-#include <QtOpcUa/qopcuasubscription.h>
#include <QtCore/qobject.h>
#include <QtCore/qurl.h>
@@ -82,8 +81,6 @@ public:
Q_INVOKABLE void disconnectFromEndpoint();
QOpcUaNode *node(const QString &nodeId);
- QOpcUaSubscription *createSubscription(quint32 interval);
-
QUrl url() const;
ClientState state() const;
diff --git a/src/opcua/client/qopcuaclient_p.h b/src/opcua/client/qopcuaclient_p.h
index a5511fd..8e9d447 100644
--- a/src/opcua/client/qopcuaclient_p.h
+++ b/src/opcua/client/qopcuaclient_p.h
@@ -50,7 +50,6 @@
#include <QtOpcUa/qopcuaclient.h>
#include <QtOpcUa/qopcuaglobal.h>
-#include <QtOpcUa/qopcuavaluesubscription.h>
#include <private/qopcuaclientimpl_p.h>
#include <QtCore/qobject.h>
diff --git a/src/opcua/client/qopcuaclientimpl.cpp b/src/opcua/client/qopcuaclientimpl.cpp
index f44a928..e3e414d 100644
--- a/src/opcua/client/qopcuaclientimpl.cpp
+++ b/src/opcua/client/qopcuaclientimpl.cpp
@@ -36,6 +36,7 @@
#include <private/qopcuabackend_p.h>
#include <private/qopcuaclientimpl_p.h>
+#include <QtOpcUa/qopcuamonitoringparameters.h>
QT_BEGIN_NAMESPACE
@@ -61,6 +62,9 @@ void QOpcUaClientImpl::connectBackendWithClient(QOpcUaBackend *backend)
connect(backend, &QOpcUaBackend::attributesRead, this, &QOpcUaClientImpl::handleAttributesRead);
connect(backend, &QOpcUaBackend::stateAndOrErrorChanged, this, &QOpcUaClientImpl::stateAndOrErrorChanged);
connect(backend, &QOpcUaBackend::attributeWritten, this, &QOpcUaClientImpl::handleAttributeWritten);
+ connect(backend, &QOpcUaBackend::attributeUpdated, this, &QOpcUaClientImpl::handleAttributeUpdated);
+ connect(backend, &QOpcUaBackend::monitoringEnableDisable, this, &QOpcUaClientImpl::handleMonitoringEnableDisable);
+ connect(backend, &QOpcUaBackend::monitoringStatusChanged, this, &QOpcUaClientImpl::handleMonitoringStatusChanged);
}
void QOpcUaClientImpl::handleAttributesRead(uintptr_t handle, QVector<QOpcUaReadResult> attr, QOpcUa::UaStatusCode serviceResult)
@@ -77,4 +81,25 @@ void QOpcUaClientImpl::handleAttributeWritten(uintptr_t handle, QOpcUaNode::Node
emit (*it)->attributeWritten(attr, value, statusCode);
}
+void QOpcUaClientImpl::handleAttributeUpdated(uintptr_t handle, QOpcUaNode::NodeAttribute attr, const QVariant &value)
+{
+ auto it = m_handles.constFind(handle);
+ if (it != m_handles.constEnd() && !it->isNull())
+ emit (*it)->attributeUpdated(attr, value);
+}
+
+void QOpcUaClientImpl::handleMonitoringEnableDisable(uintptr_t handle, QOpcUaNode::NodeAttribute attr, bool subscribe, QOpcUaMonitoringParameters status)
+{
+ auto it = m_handles.constFind(handle);
+ if (it != m_handles.constEnd() && !it->isNull())
+ emit (*it)->monitoringEnableDisable(attr, subscribe, status);
+}
+
+void QOpcUaClientImpl::handleMonitoringStatusChanged(uintptr_t handle, QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameters items, QOpcUaMonitoringParameters param)
+{
+ auto it = m_handles.constFind(handle);
+ if (it != m_handles.constEnd() && !it->isNull())
+ emit (*it)->monitoringStatusChanged(attr, items, param);
+}
+
QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaclientimpl_p.h b/src/opcua/client/qopcuaclientimpl_p.h
index 7ddbf95..07d3f9c 100644
--- a/src/opcua/client/qopcuaclientimpl_p.h
+++ b/src/opcua/client/qopcuaclientimpl_p.h
@@ -60,8 +60,8 @@ QT_BEGIN_NAMESPACE
class QOpcUaNode;
class QOpcUaClient;
-class QOpcUaSubscription;
class QOpcUaBackend;
+class QOpcUaMonitoringParameters;
class Q_OPCUA_EXPORT QOpcUaClientImpl : public QObject
{
@@ -83,13 +83,15 @@ public:
void connectBackendWithClient(QOpcUaBackend *backend);
- virtual QOpcUaSubscription *createSubscription(quint32 interval) = 0;
-
QOpcUaClient *m_client;
private Q_SLOTS:
void handleAttributesRead(uintptr_t handle, QVector<QOpcUaReadResult> attr, QOpcUa::UaStatusCode serviceResult);
void handleAttributeWritten(uintptr_t handle, QOpcUaNode::NodeAttribute attr, const QVariant &value, QOpcUa::UaStatusCode statusCode);
+ void handleAttributeUpdated(uintptr_t handle, QOpcUaNode::NodeAttribute attr, const QVariant &value);
+ void handleMonitoringEnableDisable(uintptr_t handle, QOpcUaNode::NodeAttribute attr, bool subscribe, QOpcUaMonitoringParameters status);
+ void handleMonitoringStatusChanged(uintptr_t handle, QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameters items,
+ QOpcUaMonitoringParameters param);
signals:
void connected();
diff --git a/src/opcua/client/qopcuamonitoredevent.cpp b/src/opcua/client/qopcuamonitoredevent.cpp
deleted file mode 100644
index 40a7399..0000000
--- a/src/opcua/client/qopcuamonitoredevent.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtOpcUa module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qopcuamonitoredevent.h"
-#include "qopcuasubscription.h"
-#include <private/qopcuamonitoredevent_p.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- * \internal
- */
-QOpcUaMonitoredEvent::QOpcUaMonitoredEvent(QOpcUaNode *node, QOpcUaSubscription *subscription, QObject *parent)
- : QObject(*new QOpcUaMonitoredEventPrivate(node, subscription), parent)
-{}
-
-/*!
- Destroys this event monitor instance. This will automatically
- remove it from its subscription.
- */
-QOpcUaMonitoredEvent::~QOpcUaMonitoredEvent()
-{
- d_func()->m_subscription->removeEvent(this);
-}
-
-/*!
- Returns the node which belongs to this event monitor instance.
-*/
-QOpcUaNode &QOpcUaMonitoredEvent::node()
-{
- return *d_func()->m_node;
-}
-
-/*!
- \class QOpcUaMonitoredEvent
- \inmodule QtOpcUa
-
- \brief Represents a source for events corresponding to a node on a OPC UA server.
-
- \chapter QOpcUaMonitoredEvent
- Every QOpcUaMonitoredEvent emits signals when the corresponding event on
- the server is triggered. They are backed by QOpcUaSubscriptions.
-
- The objects are owned by the user and must be deleted when they are no longer needed.
- Deletion causes the monitored items to be unsubscribed from the server.
-*/
-
-/*!
- \fn void QOpcUaMonitoredEvent::newEvent(QVector<QVariant> val) const
- This signal is emitted when a new event is received by a data change
- subscription.
- The QVector \a val currently contains three QVariants holding the values of the
- first three event fields.
- \warning When using the FreeOPCUA backend, no signal is emitted as the
- internal implementation of events does not call the callback method.
-*/
-
-QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuamonitoredevent.h b/src/opcua/client/qopcuamonitoredevent.h
deleted file mode 100644
index 6bc345b..0000000
--- a/src/opcua/client/qopcuamonitoredevent.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtOpcUa module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QOPCUAMONITOREDEVENT_H
-#define QOPCUAMONITOREDEVENT_H
-
-#include <QtOpcUa/qopcuaglobal.h>
-#include <QtOpcUa/qopcuanode.h>
-
-#include <QtCore/qobject.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qvector.h>
-
-QT_BEGIN_NAMESPACE
-
-class QOpcUaMonitoredEventPrivate;
-class QOpcUaMonitoredEventImpl;
-class QOpcUaSubscription;
-
-class Q_OPCUA_EXPORT QOpcUaMonitoredEvent : public QObject
-{
- Q_OBJECT
-
-public:
- Q_DECLARE_PRIVATE(QOpcUaMonitoredEvent)
-
- QOpcUaMonitoredEvent(QOpcUaNode *node, QOpcUaSubscription *subscription, QObject *parent = nullptr);
- ~QOpcUaMonitoredEvent() override;
- QOpcUaNode &node();
-
-Q_SIGNALS:
- void newEvent(QVector<QVariant> value) const;
-private:
- Q_DISABLE_COPY(QOpcUaMonitoredEvent)
-};
-
-QT_END_NAMESPACE
-
-#endif // QOPCUAMONITOREDEVENT_H
diff --git a/src/opcua/client/qopcuamonitoredevent_p.h b/src/opcua/client/qopcuamonitoredevent_p.h
deleted file mode 100644
index 1f300ac..0000000
--- a/src/opcua/client/qopcuamonitoredevent_p.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 basysKom GmbH, opensource@basyskom.com
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtOpcUa module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QOPCUAMONITOREDEVENT_P_H
-#define QOPCUAMONITOREDEVENT_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtOpcUa/qopcuaglobal.h>
-#include <QtOpcUa/qopcuamonitoredevent.h>
-#include <QtOpcUa/qopcuanode.h>
-
-#include <private/qobject_p.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qvector.h>
-
-QT_BEGIN_NAMESPACE
-
-class QOpcUaSubscriptionImpl;
-class QOpcUaSubscription;
-
-class Q_OPCUA_EXPORT QOpcUaMonitoredEventPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QOpcUaMonitoredEvent)
-public:
- QOpcUaMonitoredEventPrivate(QOpcUaNode *node, QOpcUaSubscription *subscription);
- ~QOpcUaMonitoredEventPrivate() override;
-
- bool triggerNewEvent(const QVector<QVariant> &val);
- QOpcUaNode *m_node;
- QOpcUaSubscription *m_subscription;
-};
-
-QT_END_NAMESPACE
-
-#endif // QOPCUAMONITOREDEVENT_P_H
diff --git a/src/opcua/client/qopcuamonitoredeventprivate.cpp b/src/opcua/client/qopcuamonitoredeventprivate.cpp
deleted file mode 100644
index d9c59a1..0000000
--- a/src/opcua/client/qopcuamonitoredeventprivate.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 basysKom GmbH, opensource@basyskom.com
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtOpcUa module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <private/qopcuamonitoredevent_p.h>
-#include <private/qopcuasubscriptionimpl_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QOpcUaMonitoredEventPrivate::QOpcUaMonitoredEventPrivate(QOpcUaNode *node, QOpcUaSubscription *subscription)
- : m_node(node)
- , m_subscription(subscription)
-{
-}
-
-QOpcUaMonitoredEventPrivate::~QOpcUaMonitoredEventPrivate()
-{
-}
-
-bool QOpcUaMonitoredEventPrivate::triggerNewEvent(const QVector<QVariant> &val)
-{
- static const int meta = qRegisterMetaType<QVector<QVariant>>();
- Q_UNUSED(meta);
-
- // explicitly use invoke to force the signal to be emitted on the main thread
- // even if the plugin triggered this from a worker thread
- return QMetaObject::invokeMethod(q_func(), "newEvent", Qt::AutoConnection, Q_ARG(QVector<QVariant>, val));
-}
-
-QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuamonitoredvalue.cpp b/src/opcua/client/qopcuamonitoredvalue.cpp
deleted file mode 100644
index 802ad24..0000000
--- a/src/opcua/client/qopcuamonitoredvalue.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtOpcUa module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qopcuamonitoredvalue.h"
-#include "qopcuasubscription.h"
-#include <private/qopcuamonitoredvalue_p.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QOpcUaMonitoredValue
- \inmodule QtOpcUa
-
- \brief Represents a source for values corresponding to a node on a OPC UA server.
-
- \chapter QOpcUaMonitoredValue
- Every QOpcUaMonitoredValue emits signals when the corresponding value in
- nodes on the server change. They are backed by QOpcUaSubscriptions.
-
- The objects are owned by the user and must be deleted when they are no longer needed.
- Deletion causes the monitored items to be unsubscribed from the server.
-*/
-
-/*!
- \fn void QOpcUaMonitoredValue::valueChanged(QVariant val) const
-
- This signal is emitted when a new update for a data change subscription
- arrives. \a val contains the new value.
- */
-
-QOpcUaMonitoredValue::QOpcUaMonitoredValue(QOpcUaNode *node, QOpcUaSubscription *subscription, QObject *parent)
- : QObject(*new QOpcUaMonitoredValuePrivate(node, subscription), parent)
-{
-}
-
-QOpcUaMonitoredValue::~QOpcUaMonitoredValue()
-{
- Q_D(QOpcUaMonitoredValue);
- if (d->m_subscription)
- d->m_subscription->removeValue(this);
-}
-
-/*!
- \fn QOpcUaNode &QOpcUaMonitoredValue::node()
-
- Returns the node which belongs to this value monitor instance.
-*/
-QOpcUaNode &QOpcUaMonitoredValue::node()
-{
- return *d_func()->m_node;
-}
-
-QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuamonitoredvalue.h b/src/opcua/client/qopcuamonitoredvalue.h
deleted file mode 100644
index 1761a79..0000000
--- a/src/opcua/client/qopcuamonitoredvalue.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtOpcUa module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QOPCUAMONITOREDVALUE_H
-#define QOPCUAMONITOREDVALUE_H
-
-#include <QtOpcUa/qopcuaglobal.h>
-#include <QtOpcUa/qopcuanode.h>
-
-#include <QtCore/qvariant.h>
-
-QT_BEGIN_NAMESPACE
-
-class QOpcUaMonitoredValuePrivate;
-class QOpcUaMonitoredValueImpl;
-class QOpcUaSubscription;
-
-class Q_OPCUA_EXPORT QOpcUaMonitoredValue : public QObject
-{
- Q_OBJECT
-
-public:
- Q_DECLARE_PRIVATE(QOpcUaMonitoredValue)
-
- QOpcUaMonitoredValue(QOpcUaNode *node, QOpcUaSubscription *subscription, QObject *parent = nullptr);
- ~QOpcUaMonitoredValue() override;
- QOpcUaNode &node();
-
-Q_SIGNALS:
- void valueChanged(QVariant val) const;
-private:
- Q_DISABLE_COPY(QOpcUaMonitoredValue)
-};
-
-QT_END_NAMESPACE
-
-#endif // QOPCUAMONITOREDVALUE_H
diff --git a/src/opcua/client/qopcuamonitoredvalue_p.h b/src/opcua/client/qopcuamonitoredvalue_p.h
deleted file mode 100644
index 49bf31b..0000000
--- a/src/opcua/client/qopcuamonitoredvalue_p.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 basysKom GmbH, opensource@basyskom.com
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtOpcUa module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QOPCUAMONITOREDVALUE_P_H
-#define QOPCUAMONITOREDVALUE_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtOpcUa/qopcuaglobal.h>
-#include <QtOpcUa/qopcuamonitoredvalue.h>
-#include <QtOpcUa/qopcuanode.h>
-
-#include <private/qobject_p.h>
-#include <QtCore/qvariant.h>
-
-QT_BEGIN_NAMESPACE
-
-class QOpcUaSubscriptionImpl;
-class QOpcUaSubscription;
-
-class Q_OPCUA_EXPORT QOpcUaMonitoredValuePrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QOpcUaMonitoredValue)
-public:
- QOpcUaMonitoredValuePrivate(QOpcUaNode *node, QOpcUaSubscription *subscription);
- ~QOpcUaMonitoredValuePrivate() override;
-
- void triggerValueChanged(const QVariant &val);
- QOpcUaNode *m_node;
- QOpcUaSubscription *m_subscription;
- QVariant m_currentValue;
-};
-
-QT_END_NAMESPACE
-
-#endif // QOPCUAMONITOREDVALUE_P_H
diff --git a/src/opcua/client/qopcuamonitoredvalueprivate.cpp b/src/opcua/client/qopcuamonitoredvalueprivate.cpp
deleted file mode 100644
index 8cd2297..0000000
--- a/src/opcua/client/qopcuamonitoredvalueprivate.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 basysKom GmbH, opensource@basyskom.com
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtOpcUa module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <private/qopcuamonitoredvalue_p.h>
-#include <private/qopcuasubscriptionimpl_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QOpcUaMonitoredValuePrivate::QOpcUaMonitoredValuePrivate(QOpcUaNode *node, QOpcUaSubscription *subscription)
- : m_node(node)
- , m_subscription(subscription)
- // TODO: is it useful to initialize a monitored item with a potentially uninitialized value?
- , m_currentValue(node->attribute(QOpcUaNode::NodeAttribute::Value))
-{
-}
-
-QOpcUaMonitoredValuePrivate::~QOpcUaMonitoredValuePrivate()
-{
-}
-
-void QOpcUaMonitoredValuePrivate::triggerValueChanged(const QVariant &val)
-{
- // explicitly use invoke to force the signal to be emitted on the main thread
- // even if the plugin triggered this from a worker thread
- if (val != m_currentValue) {
- m_currentValue = val;
- QMetaObject::invokeMethod(q_func(), "valueChanged", Qt::AutoConnection, Q_ARG(QVariant, val));
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuamonitoringparameters.cpp b/src/opcua/client/qopcuamonitoringparameters.cpp
new file mode 100644
index 0000000..c20d2b8
--- /dev/null
+++ b/src/opcua/client/qopcuamonitoringparameters.cpp
@@ -0,0 +1,390 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuamonitoringparameters.h"
+#include "private/qopcuamonitoringparameters_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \enum QOpcUaMonitoringParameters::MonitoringMode
+
+ This enum is used to set the monitoring mode for a monitored item.
+
+ \value Disabled Sampling is disabled and no notifications are being generated.
+ \value Sampling Sampling is enabled and notifications are generated and queued, but reporting is disabled.
+ \value Reporting Sampling is enabled, notifications are generated and queued, reporting is enabled.
+*/
+
+/*!
+ \enum QOpcUaMonitoringParameters::SubscriptionType
+
+ \value Shared Share subscription with other monitored items with the same interval
+ \value Exclusive Request a new subscription for this attribute
+*/
+
+/*!
+ \class QOpcUaMonitoringParameters
+
+ This struct contains parameters for the creation of the subscription and monitored items for
+ a enableMonitoring request.
+
+ The same struct is used as return value for monitoringStatus and contains
+ the revised values from the server.
+*/
+
+/*!
+ \enum QOpcUaMonitoringParameters::Parameter
+
+ Enumerates parameters that can be modified at runtime using \l modifyMonitoring().
+ Not all values are guaranteed to be supported by all plugins. Lack of support will be reported
+ in the \l monitoringStatusChanged signal.
+
+ \value PublishingEnabled
+ \value PublishingInterval
+ \value LifetimeCount
+ \value MaxKeepAliveCount
+ \value MaxNotificationsPerPublish
+ \value Priority
+ \value SamplingInterval
+ \value Filter
+ \value QueueSize
+ \value DiscardOldest
+ \value MonitoringMode
+*/
+
+/*!
+ \class QOpcUaMonitoringParameters::DataChangeFilter
+
+ This struct is used to set up filtering for a DataChange monitored item.
+ It is defined in OPC-UA part 4, 7.12.2.
+*/
+
+/*!
+ \variable QOpcUaMonitoringParameters::DataChangeFilter::trigger
+
+ The trigger for this filter.
+*/
+
+/*!
+ \variable QOpcUaMonitoringParameters::DataChangeFilter::deadbandType
+
+ The deadband type for this filter.
+*/
+
+/*!
+ \variable QOpcUaMonitoringParameters::DataChangeFilter::deadbandValue
+
+ The deadband value for this filter.
+*/
+
+/*!
+ \enum QOpcUaMonitoringParameters::DataChangeFilter::DataChangeTrigger
+
+ Enumerates the possible triggers for a \l DataChangeFilter.
+
+ \value Status Triggers if the status code for the value changes.
+ \value StatusValue Triggers if the status code or the value changes.
+ \value StatusValueTimestamp Triggers if the status code, the value or the source timestamp changes.
+*/
+
+/*!
+ \enum QOpcUaMonitoringParameters::DataChangeFilter::DeadbandType
+
+ Enumerates the possible deadband types for a \l DataChangeFilter.
+
+ \value None No deadband filtering.
+ \value Absolute A notification is generated if the absolute value of the difference between the last cached value
+ and the current value is greater than the deadband value.
+ \value Percent Only valid for AnalogItems with an EURange property. A notification is generated if the absolute value
+ of the difference between the last cached value and the current value is greater than value percent of the EURange.
+*/
+
+QOpcUaMonitoringParameters::QOpcUaMonitoringParameters()
+ : d_ptr(new QOpcUaMonitoringParametersPrivate())
+{}
+
+QOpcUaMonitoringParameters::~QOpcUaMonitoringParameters()
+{}
+
+/*!
+ This is the constructor which covers most use cases for the QtOpcUa user.
+ \a publishingInterval must be supplied, \a shared and \a subscriptionId are optional.
+*/
+QOpcUaMonitoringParameters::QOpcUaMonitoringParameters(double publishingInterval, QOpcUaMonitoringParameters::SubscriptionType shared, quint32 subscriptionId)
+ : d_ptr(new QOpcUaMonitoringParametersPrivate)
+{
+ d_ptr->publishingInterval = publishingInterval;
+ d_ptr->shared = shared;
+ d_ptr->subscriptionId = subscriptionId;
+
+}
+
+QOpcUaMonitoringParameters::QOpcUaMonitoringParameters(const QOpcUaMonitoringParameters &other)
+ : d_ptr(other.d_ptr)
+{}
+
+QOpcUaMonitoringParameters &QOpcUaMonitoringParameters::operator=(const QOpcUaMonitoringParameters &other)
+{
+ d_ptr = other.d_ptr;
+ return *this;
+}
+
+/*!
+ Returns the subscription type.
+*/
+QOpcUaMonitoringParameters::SubscriptionType QOpcUaMonitoringParameters::shared() const
+{
+ return d_ptr->shared;
+}
+
+/*!
+ Request \a shared as subscription type for the subscription.
+*/
+void QOpcUaMonitoringParameters::setShared(SubscriptionType shared)
+{
+ d_ptr->shared = shared;
+}
+
+/*!
+ Returns the status code of the monitored item creation.
+*/
+QOpcUa::UaStatusCode QOpcUaMonitoringParameters::statusCode() const
+{
+ return d_ptr->statusCode;
+}
+
+/*!
+ Set the status code to \a statusCode.
+*/
+void QOpcUaMonitoringParameters::setStatusCode(QOpcUa::UaStatusCode statusCode)
+{
+ d_ptr->statusCode = statusCode;
+}
+
+/*!
+ Returns the publishing mode for the subscription.
+*/
+bool QOpcUaMonitoringParameters::publishingEnabled() const
+{
+ return d_ptr->publishingEnabled;
+}
+
+/*!
+ Set \a publishingEnabled as publishing mode for the subscription.
+*/
+void QOpcUaMonitoringParameters::setPublishingEnabled(bool publishingEnabled)
+{
+ d_ptr->publishingEnabled = publishingEnabled;
+}
+
+/*!
+ Returns the priority of the subscription used for the monitored item.
+*/
+quint8 QOpcUaMonitoringParameters::priority() const
+{
+ return d_ptr->priority;
+}
+
+/*!
+ Set \a priority as priority for the subscription.
+*/
+void QOpcUaMonitoringParameters::setPriority(quint8 priority)
+{
+ d_ptr->priority = priority;
+}
+
+/*!
+ Returns the maximum notifications per publish value of the subscription.
+*/
+quint32 QOpcUaMonitoringParameters::maxNotificationsPerPublish() const
+{
+ return d_ptr->maxNotificationsPerPublish;
+}
+
+/*!
+ Request \a maxNotificationsPerPublish as maximum notifications per publish value for the subscription.
+*/
+void QOpcUaMonitoringParameters::setMaxNotificationsPerPublish(quint32 maxNotificationsPerPublish)
+{
+ d_ptr->maxNotificationsPerPublish = maxNotificationsPerPublish;
+}
+
+/*!
+ Returns the maximum keepalive count of the subscription.
+*/
+quint32 QOpcUaMonitoringParameters::maxKeepAliveCount() const
+{
+ return d_ptr->maxKeepAliveCount;
+}
+
+/*!
+ Request \a maxKeepAliveCount as maximum keepalive count for the subscription.
+*/
+void QOpcUaMonitoringParameters::setMaxKeepAliveCount(quint32 maxKeepAliveCount)
+{
+ d_ptr->maxKeepAliveCount = maxKeepAliveCount;
+}
+
+/*!
+ Returns the lifetime count of the subscription.
+*/
+quint32 QOpcUaMonitoringParameters::lifetimeCount() const
+{
+ return d_ptr->lifetimeCount;
+}
+
+/*!
+ Request \a lifetimeCount as lifetime count for the subscription.
+*/
+void QOpcUaMonitoringParameters::setLifetimeCount(quint32 lifetimeCount)
+{
+ d_ptr->lifetimeCount = lifetimeCount;
+}
+
+/*!
+ Returns the publishing interval of the subscription.
+*/
+double QOpcUaMonitoringParameters::publishingInterval() const
+{
+ return d_ptr->publishingInterval;
+}
+
+/*!
+ Request \a publishingInterval as publishing interval for the subscription.
+*/
+void QOpcUaMonitoringParameters::setPublishingInterval(double publishingInterval)
+{
+ d_ptr->publishingInterval = publishingInterval;
+}
+
+/*!
+ Returns the assigned subscription id.
+*/
+quint32 QOpcUaMonitoringParameters::subscriptionId() const
+{
+ return d_ptr->subscriptionId;
+}
+
+/*!
+ Request the monitored items to be created on a known subscription with subscriptionId \a value.
+*/
+void QOpcUaMonitoringParameters::setSubscriptionId(quint32 subscriptionId)
+{
+ d_ptr->subscriptionId = subscriptionId;
+}
+
+/*!
+ Returns the monitoring mode for the monitored item.
+*/
+QOpcUaMonitoringParameters::MonitoringMode QOpcUaMonitoringParameters::monitoringMode() const
+{
+ return d_ptr->monitoringMode;
+}
+
+/*!
+ Request \a monitoringMode as monitoring mode for the monitored item.
+*/
+void QOpcUaMonitoringParameters::setMonitoringMode(MonitoringMode monitoringMode)
+{
+ d_ptr->monitoringMode = monitoringMode;
+}
+
+/*!
+ Returns the discardOldest setting of the monitored item.
+*/
+bool QOpcUaMonitoringParameters::discardOldest() const
+{
+ return d_ptr->discardOldest;
+}
+
+/*!
+ Request \a discardOldest as discardOldest setting for the monitored item.
+*/
+void QOpcUaMonitoringParameters::setDiscardOldest(bool discardOldest)
+{
+ d_ptr->discardOldest = discardOldest;
+}
+
+/*!
+ Returns the queue size of the monitored item.
+*/
+quint32 QOpcUaMonitoringParameters::queueSize() const
+{
+ return d_ptr->queueSize;
+}
+
+/*!
+ Request \a queueSize as queue size for the monitored item.
+*/
+void QOpcUaMonitoringParameters::setQueueSize(quint32 queueSize)
+{
+ d_ptr->queueSize = queueSize;
+}
+
+/*!
+ Returns the filter result. Empty for DataChangeFilter.
+*/
+QVariant QOpcUaMonitoringParameters::filter() const
+{
+ return d_ptr->filter;
+}
+
+/*!
+ Request \a filter as filter for for the monitored item.
+*/
+void QOpcUaMonitoringParameters::setFilter(const QVariant &filter)
+{
+ d_ptr->filter = filter;
+}
+
+/*!
+ Returns the revised sampling interval of the monitored item.
+*/
+double QOpcUaMonitoringParameters::samplingInterval() const
+{
+ return d_ptr->samplingInterval;
+}
+
+/*!
+ Request \a samplingInterval as sampling interval for the monitored item.
+*/
+void QOpcUaMonitoringParameters::setSamplingInterval(double samplingInterval)
+{
+ d_ptr->samplingInterval = samplingInterval;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuamonitoringparameters.h b/src/opcua/client/qopcuamonitoringparameters.h
new file mode 100644
index 0000000..422726a
--- /dev/null
+++ b/src/opcua/client/qopcuamonitoringparameters.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAMONITORINGPARAMETERS_H
+#define QOPCUAMONITORINGPARAMETERS_H
+
+#include <QtOpcUa/qopcuatype.h>
+
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaMonitoringParametersPrivate;
+
+class Q_OPCUA_EXPORT QOpcUaMonitoringParameters
+{
+ Q_GADGET
+
+public:
+
+ enum class MonitoringMode {
+ Disabled = 0,
+ Sampling = 1,
+ Reporting = 2
+ };
+
+ enum class SubscriptionType {
+ Shared,
+ Exclusive
+ };
+
+ enum class Parameter {
+ PublishingEnabled = (1 << 0),
+ PublishingInterval = (1 << 1),
+ LifetimeCount = (1 << 2),
+ MaxKeepAliveCount = (1 << 3),
+ MaxNotificationsPerPublish = (1 << 4),
+ Priority = (1 << 5),
+ SamplingInterval = (1 << 6),
+ Filter = (1 << 7),
+ QueueSize = (1 << 8),
+ DiscardOldest = (1 << 9),
+ MonitoringMode = (1 << 10)
+ };
+ Q_ENUM(Parameter)
+ Q_DECLARE_FLAGS(Parameters, Parameter)
+
+ // This type and the enums are defined in OPC-UA part 4, 7.12.2
+ struct DataChangeFilter {
+ enum class DataChangeTrigger {
+ Status = 0,
+ StatusValue = 1,
+ StatusValueTimestamp = 3
+ };
+
+ enum class DeadbandType {
+ None = 0,
+ Absolute = 1,
+ Percent = 2
+ };
+
+ DataChangeTrigger trigger;
+ DeadbandType deadbandType;
+ double deadbandValue;
+
+ DataChangeFilter()
+ : trigger(DataChangeTrigger::Status)
+ , deadbandType(DeadbandType::None)
+ , deadbandValue(0)
+ {}
+ DataChangeFilter(DataChangeTrigger p_trigger, DeadbandType p_deadbandType, double p_deadbandValue)
+ : trigger(p_trigger)
+ , deadbandType(p_deadbandType)
+ , deadbandValue(p_deadbandValue)
+ {}
+ };
+
+ QOpcUaMonitoringParameters();
+ ~QOpcUaMonitoringParameters();
+ QOpcUaMonitoringParameters(double publishingInterval, SubscriptionType shared = SubscriptionType::Shared, quint32 subscriptionId = 0);
+ QOpcUaMonitoringParameters(const QOpcUaMonitoringParameters &other);
+ QOpcUaMonitoringParameters &operator=(const QOpcUaMonitoringParameters &other);
+
+ double samplingInterval() const;
+ void setSamplingInterval(double samplingInterval);
+ QVariant filter() const;
+ void setFilter(const QVariant &filter);
+ quint32 queueSize() const;
+ void setQueueSize(quint32 queueSize);
+ bool discardOldest() const;
+ void setDiscardOldest(bool discardOldest);
+ QOpcUaMonitoringParameters::MonitoringMode monitoringMode() const;
+ void setMonitoringMode(MonitoringMode monitoringMode);
+ quint32 subscriptionId() const;
+ void setSubscriptionId(quint32 subscriptionId);
+ double publishingInterval() const;
+ void setPublishingInterval(double publishingInterval);
+ quint32 lifetimeCount() const;
+ void setLifetimeCount(quint32 lifetimeCount);
+ quint32 maxKeepAliveCount() const;
+ void setMaxKeepAliveCount(quint32 maxKeepAliveCount);
+ quint32 maxNotificationsPerPublish() const;
+ void setMaxNotificationsPerPublish(quint32 maxNotificationsPerPublish);
+ quint8 priority() const;
+ void setPriority(quint8 priority);
+ bool publishingEnabled() const;
+ void setPublishingEnabled(bool publishingEnabled);
+ QOpcUa::UaStatusCode statusCode() const;
+ void setStatusCode(QOpcUa::UaStatusCode statusCode);
+ QOpcUaMonitoringParameters::SubscriptionType shared() const;
+ void setShared(SubscriptionType subscriptionType);
+
+private:
+ QSharedDataPointer<QOpcUaMonitoringParametersPrivate> d_ptr;
+};
+
+Q_DECLARE_TYPEINFO(QOpcUaMonitoringParameters::SubscriptionType, Q_PRIMITIVE_TYPE);
+Q_DECLARE_TYPEINFO(QOpcUaMonitoringParameters::DataChangeFilter::DataChangeTrigger, Q_PRIMITIVE_TYPE);
+Q_DECLARE_TYPEINFO(QOpcUaMonitoringParameters::DataChangeFilter::DeadbandType, Q_PRIMITIVE_TYPE);
+Q_DECLARE_OPERATORS_FOR_FLAGS(QOpcUaMonitoringParameters::Parameters)
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaMonitoringParameters)
+Q_DECLARE_METATYPE(QOpcUaMonitoringParameters::SubscriptionType)
+Q_DECLARE_METATYPE(QOpcUaMonitoringParameters::DataChangeFilter)
+Q_DECLARE_METATYPE(QOpcUaMonitoringParameters::DataChangeFilter::DataChangeTrigger)
+Q_DECLARE_METATYPE(QOpcUaMonitoringParameters::DataChangeFilter::DeadbandType)
+Q_DECLARE_METATYPE(QOpcUaMonitoringParameters::Parameter)
+Q_DECLARE_METATYPE(QOpcUaMonitoringParameters::Parameters)
+
+#endif // QOPCUAMONITORINGPARAMETERS_H
diff --git a/src/opcua/client/qopcuasubscription_p.h b/src/opcua/client/qopcuamonitoringparameters_p.h
index f509c10..5b6e824 100644
--- a/src/opcua/client/qopcuasubscription_p.h
+++ b/src/opcua/client/qopcuamonitoringparameters_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 basysKom GmbH, opensource@basyskom.com
+** Copyright (C) 2017 basysKom GmbH, opensource@basyskom.com
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
@@ -34,8 +34,8 @@
**
****************************************************************************/
-#ifndef QOPCUASUBSCRIPTION_P_H
-#define QOPCUASUBSCRIPTION_P_H
+#ifndef QOPCUAMONITORINGPARAMETERS_P_H
+#define QOPCUAMONITORINGPARAMETERS_P_H
//
// W A R N I N G
@@ -48,27 +48,53 @@
// We mean it.
//
-#include <QtOpcUa/qopcuaglobal.h>
-#include <QtOpcUa/qopcuasubscription.h>
-#include <private/qopcuasubscriptionimpl_p.h>
+#include <QtOpcUa/qopcuamonitoringparameters.h>
-#include <private/qobject_p.h>
-#include <QtCore/qscopedpointer.h>
+#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
-class Q_OPCUA_EXPORT QOpcUaSubscriptionPrivate : public QObjectPrivate
+class Q_OPCUA_EXPORT QOpcUaMonitoringParametersPrivate : public QSharedData
{
public:
- Q_DECLARE_PUBLIC(QOpcUaSubscription)
- QOpcUaSubscriptionPrivate(QOpcUaSubscriptionImpl *impl, quint32 interval);
- ~QOpcUaSubscriptionPrivate();
+ QOpcUaMonitoringParametersPrivate()
+ : samplingInterval(0)
+ , queueSize(0)
+ , discardOldest(true)
+ , monitoringMode(QOpcUaMonitoringParameters::MonitoringMode::Reporting)
+ , subscriptionId(0)
+ , publishingInterval(0)
+ , lifetimeCount(0)
+ , maxKeepAliveCount(0)
+ , maxNotificationsPerPublish(0)
+ , priority(0)
+ , publishingEnabled(true)
+ , statusCode(QOpcUa::UaStatusCode::BadAttributeIdInvalid)
+ , shared(QOpcUaMonitoringParameters::SubscriptionType::Shared)
+ {}
- QScopedPointer<QOpcUaSubscriptionImpl> m_impl;
- quint32 m_interval;
+ // MonitoredItem
+ double samplingInterval;
+ QVariant filter;
+ quint32 queueSize;
+ bool discardOldest;
+ QOpcUaMonitoringParameters::MonitoringMode monitoringMode;
+
+ // Subscription
+ quint32 subscriptionId;
+ double publishingInterval;
+ quint32 lifetimeCount;
+ quint32 maxKeepAliveCount;
+ quint32 maxNotificationsPerPublish;
+ quint8 priority;
+ bool publishingEnabled;
+
+ // QtOpcUa specific
+ QOpcUa::UaStatusCode statusCode;
+ QOpcUaMonitoringParameters::SubscriptionType shared;
};
QT_END_NAMESPACE
-#endif // QOPCUASUBSCRIPTION_P_H
+#endif // QOPCUAMONITORINGPARAMETERS_P_H
diff --git a/src/opcua/client/qopcuanode.cpp b/src/opcua/client/qopcuanode.cpp
index d948365..e02d0aa 100644
--- a/src/opcua/client/qopcuanode.cpp
+++ b/src/opcua/client/qopcuanode.cpp
@@ -35,12 +35,9 @@
****************************************************************************/
#include "qopcuaclient.h"
-#include "qopcuamonitoredvalue.h"
#include "qopcuanode.h"
#include <private/qopcuaclient_p.h>
#include <private/qopcuaclientimpl_p.h>
-#include <private/qopcuamonitoredevent_p.h>
-#include <private/qopcuamonitoredvalue_p.h>
#include <private/qopcuanode_p.h>
#include <private/qopcuanodeimpl_p.h>
@@ -80,11 +77,6 @@ QT_BEGIN_NAMESPACE
event we want to keep up with to the subscription.
\image subscriptions.png
-
- After calling valueMonitor() or eventMonitor(), a QOpcUaMonitoredValue or
- QOpcUaMonitoredEvent is returned.
- These objects emit a signal on a data change or event,
- depending on which type of subscription has been requested from the server.
*/
/*!
@@ -121,7 +113,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn QOpcUaNode::attributeWritten(QOpcUaNode::NodeAttribute attribute, quint32 statusCode)
+ \fn QOpcUaNode::attributeWritten(QOpcUaNode::NodeAttribute attribute, QOpcUa::UaStatusCode statusCode)
This signal is emitted after a \l writeAttribute() or \l writeAttributes() operation has finished.
@@ -130,6 +122,29 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \fn void enableMonitoringFinished(QOpcUaNode::NodeAttribute attr, QOpcUa::UaStatusCode statusCode)
+
+ This signal is emitted after an asynchronous call to \l enableMonitoring() has finished.
+ After this signal has been emitted, \l monitoringStatus() returns valid information for \a attr.
+*/
+
+/*!
+ \fn void disableMonitoringFinished(QOpcUaNode::NodeAttribute attr, QOpcUa::UaStatusCode statusCode)
+
+ This signal is emitted after an asynchronous call to \l disableMonitoring() has finished.
+ After this signal has been emitted, monitoringStatus returns a default constructed value with
+ status code BadMonitoredItemIdIinvalid for \a attr.
+*/
+
+/*!
+ \fn void QOpcUaNode::monitoringStatusChanged(QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, QVariant value, QOpcUa::UaStatusCode statusCode);
+
+ This signal is emitted after an asynchronous call to \l modifyMonitoring() has finished.
+ The node attribute for which the operation was requested is returned in \a attr. \a item contains the parameters that have been modified.
+ \a statusCode contains the result of the modify operation on the server.
+*/
+
+/*!
\internal QOpcUaNodeImpl is an opaque type (as seen from the public API).
This prevents users of the public API to use this constructor (eventhough
it is public).
@@ -244,6 +259,72 @@ QOpcUa::UaStatusCode QOpcUaNode::attributeError(QOpcUaNode::NodeAttribute attrib
\li Guid
\endtable
*/
+
+/*!
+ This method creates a monitored item for each of the attributes given in \a attr.
+ The settings from \a settings are used in the creation of the monitored items and the subscription.
+
+ The \a shared field of \a settings controls how the monitored items are assigned to a subscription. If shared in \a settings is set to Shared,
+ the monitored item will be added to a subscription with a matching \a interval. If shared in \a settings is set to Exclusive,
+ either a new subscription is created, or if a subscription is provided via the subscriptionId field in \a settings, an existing subscription is used.
+ This can be used to group monitored items on a subscription manually by creating the first monitored item with \a shared=false and
+ using the subscriptionId returned in \a subscriptionId of monitoringStatus(\a attr) in the following requests.
+
+ Returns true if the asynchronous call has been successfully dispatched.
+
+ On the completion of the call, the \l enableMonitoringFinished signal is emitted.
+ There are multiple error cases in which a Bad status code is generated: A subscription with \a subscriptionId does not exist,
+ the node does not exist on the server, the node does not have the requested attribute or the maximum number of monitored items for
+ the server is reached.
+ */
+bool QOpcUaNode::enableMonitoring(QOpcUaNode::NodeAttributes attr, const QOpcUaMonitoringParameters &settings)
+{
+ if (d_func()->m_client.isNull() || d_func()->m_client->state() != QOpcUaClient::Connected)
+ return false;
+
+ return d_func()->m_impl->enableMonitoring(attr, settings);
+}
+
+/*!
+ This method modifies settings of the monitored item or the subscription.
+ The parameter \a item of the monitored item or subscription associated with \a attr is attempted to set to \a value.
+
+ Returns true if the asynchronous call has been successfully dispatched.
+
+ After the call has finished, the monitoringStatusChanged signal is emitted. This signal contains the modified parameters and the status code.
+ A Bad status code is generated if there is no monitored item associated with the requested attribute, revising the requested
+ parameter is not implemented or if the server has rejected the requested value.
+*/
+bool QOpcUaNode::modifyMonitoring(QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, const QVariant &value)
+{
+ if (d_func()->m_client.isNull() || d_func()->m_client->state() != QOpcUaClient::Connected)
+ return false;
+
+ return d_func()->m_impl->modifyMonitoring(attr, item, value);
+}
+
+/*!
+ Returns the monitoring parameters associated with the attribute \a attr. This can be used to check the success of \l enableMonitoring()
+ or if parameters have been revised.
+ The returned values are only valid after \l enableMonitoringFinished or \l monitoringStatusChanged have been emitted for \a attr.
+*/
+QOpcUaMonitoringParameters QOpcUaNode::monitoringStatus(QOpcUaNode::NodeAttribute attr)
+{
+ auto it = d_func()->m_monitoringStatus.constFind(attr);
+ if (it == d_func()->m_monitoringStatus.constEnd()) {
+ QOpcUaMonitoringParameters p;
+ p.setStatusCode(QOpcUa::UaStatusCode::BadAttributeIdInvalid);
+ return p;
+ }
+
+ return *it;
+}
+
+/*!
+ Writes \value to the attribute given in \a attribute using the type information from \a type.
+
+ Returns true if the write operation has been dispatched successfully.
+ */
bool QOpcUaNode::writeAttribute(QOpcUaNode::NodeAttribute attribute, const QVariant &value, QOpcUa::Types type)
{
if (d_func()->m_client.isNull() || d_func()->m_client->state() != QOpcUaClient::Connected)
@@ -269,6 +350,22 @@ bool QOpcUaNode::writeAttributes(const AttributeMap &toWrite, QOpcUa::Types valu
}
/*!
+ This method disables monitoring for the attributes given in \a attr.
+
+ Returns true if the asynchronous call has been successfully dispatched.
+
+ After the call is finished, the \l disableMonitoringFinished signal is emitted and monitoringStatus returns a default constructed value with
+ status code BadMonitoredItemIdIinvalid for \a attr.
+*/
+bool QOpcUaNode::disableMonitoring(QOpcUaNode::NodeAttributes attr)
+{
+ if (d_func()->m_client.isNull() || d_func()->m_client->state() != QOpcUaClient::Connected)
+ return false;
+
+ return d_func()->m_impl->disableMonitoring(attr);
+}
+
+/*!
QStringList filled with the node IDs of all child nodes of the OPC UA node.
*/
QStringList QOpcUaNode::childrenIds() const
diff --git a/src/opcua/client/qopcuanode.h b/src/opcua/client/qopcuanode.h
index b2e3d13..cc0f889 100644
--- a/src/opcua/client/qopcuanode.h
+++ b/src/opcua/client/qopcuanode.h
@@ -38,6 +38,7 @@
#define QOPCUANODE_H
#include <QtOpcUa/qopcuaglobal.h>
+#include <QtOpcUa/qopcuamonitoringparameters.h>
#include <QtOpcUa/qopcuatype.h>
#include <QtCore/qdatetime.h>
@@ -50,8 +51,6 @@ QT_BEGIN_NAMESPACE
class QOpcUaNodePrivate;
class QOpcUaNodeImpl;
class QOpcUaClient;
-class QOpcUaMonitoredEvent;
-class QOpcUaMonitoredValue;
class Q_OPCUA_EXPORT QOpcUaNode : public QObject
{
@@ -119,6 +118,11 @@ public:
bool writeAttribute(QOpcUaNode::NodeAttribute attribute, const QVariant &value, QOpcUa::Types type = QOpcUa::Types::Undefined);
bool writeAttributes(const AttributeMap &toWrite, QOpcUa::Types valueAttributeType = QOpcUa::Types::Undefined);
+ bool enableMonitoring(QOpcUaNode::NodeAttributes attr, const QOpcUaMonitoringParameters &settings);
+ bool disableMonitoring(QOpcUaNode::NodeAttributes attr);
+ bool modifyMonitoring(QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, const QVariant &value);
+ QOpcUaMonitoringParameters monitoringStatus(QOpcUaNode::NodeAttribute attr);
+
QStringList childrenIds() const;
QString nodeId() const;
@@ -131,6 +135,12 @@ public:
Q_SIGNALS:
void readFinished(QOpcUaNode::NodeAttributes attributes);
void attributeWritten(QOpcUaNode::NodeAttribute attribute, QOpcUa::UaStatusCode statusCode);
+ void attributeUpdated(QOpcUaNode::NodeAttribute attr, QVariant value);
+
+ void monitoringStatusChanged(QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameters items,
+ QOpcUa::UaStatusCode statusCode);
+ void enableMonitoringFinished(QOpcUaNode::NodeAttribute attr, QOpcUa::UaStatusCode statusCode);
+ void disableMonitoringFinished(QOpcUaNode::NodeAttribute attr, QOpcUa::UaStatusCode statusCode);
private:
Q_DISABLE_COPY(QOpcUaNode)
diff --git a/src/opcua/client/qopcuanode_p.h b/src/opcua/client/qopcuanode_p.h
index bd57fb5..53f2996 100644
--- a/src/opcua/client/qopcuanode_p.h
+++ b/src/opcua/client/qopcuanode_p.h
@@ -94,12 +94,67 @@ public:
emit q_func()->attributeWritten(attr, statusCode);
});
+
+ m_attributeUpdatedConnection = QObject::connect(impl, &QOpcUaNodeImpl::attributeUpdated,
+ [this](QOpcUaNode::NodeAttribute attr, QVariant value)
+ {
+ this->m_nodeAttributes[attr] = {value, QOpcUa::UaStatusCode::Good};
+ emit q_func()->attributeUpdated(attr, value);
+ });
+
+ m_monitoringEnableDisableConnection = QObject::connect(impl, &QOpcUaNodeImpl::monitoringEnableDisable,
+ [this](QOpcUaNode::NodeAttribute attr, bool subscribe, QOpcUaMonitoringParameters status)
+ {
+ if (subscribe == true) {
+ m_monitoringStatus[attr] = status;
+ emit q_func()->enableMonitoringFinished(attr, status.statusCode());
+ }
+ else {
+ m_monitoringStatus.remove(attr);
+ emit q_func()->disableMonitoringFinished(attr, status.statusCode());
+ }
+ });
+
+ m_monitoringStatusChangedConnection = QObject::connect(impl, &QOpcUaNodeImpl::monitoringStatusChanged,
+ [this](QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameters items, QOpcUaMonitoringParameters param)
+ {
+ auto it = m_monitoringStatus.find(attr);
+ if (param.statusCode() == QOpcUa::UaStatusCode::Good && it != m_monitoringStatus.end()) {
+ if (items & QOpcUaMonitoringParameters::Parameter::PublishingEnabled)
+ it->setPublishingEnabled(param.publishingEnabled());
+ if (items & QOpcUaMonitoringParameters::Parameter::PublishingInterval)
+ it->setPublishingInterval(param.publishingInterval());
+ if (items & QOpcUaMonitoringParameters::Parameter::LifetimeCount)
+ it->setLifetimeCount(param.lifetimeCount());
+ if (items & QOpcUaMonitoringParameters::Parameter::MaxKeepAliveCount)
+ it->setMaxKeepAliveCount(param.maxKeepAliveCount());
+ if (items & QOpcUaMonitoringParameters::Parameter::MaxNotificationsPerPublish)
+ it->setMaxNotificationsPerPublish(param.maxNotificationsPerPublish());
+ if (items & QOpcUaMonitoringParameters::Parameter::Priority)
+ it->setPriority(param.priority());
+ if (items & QOpcUaMonitoringParameters::Parameter::SamplingInterval)
+ it->setSamplingInterval(param.samplingInterval());
+ if (items & QOpcUaMonitoringParameters::Parameter::Filter)
+ it->setFilter(param.filter());
+ if (items & QOpcUaMonitoringParameters::Parameter::QueueSize)
+ it->setQueueSize(param.queueSize());
+ if (items & QOpcUaMonitoringParameters::Parameter::DiscardOldest)
+ it->setDiscardOldest(param.discardOldest());
+ if (items & QOpcUaMonitoringParameters::Parameter::MonitoringMode)
+ it->setMonitoringMode(param.monitoringMode());
+ }
+
+ emit q_func()->monitoringStatusChanged(attr, items, param.statusCode());
+ });
}
~QOpcUaNodePrivate()
{
QObject::disconnect(m_attributesReadConnection);
QObject::disconnect(m_attributeWrittenConnection);
+ QObject::disconnect(m_attributeUpdatedConnection);
+ QObject::disconnect(m_monitoringEnableDisableConnection);
+ QObject::disconnect(m_monitoringStatusChangedConnection);
}
QScopedPointer<QOpcUaNodeImpl> m_impl;
@@ -110,9 +165,13 @@ public:
QOpcUa::UaStatusCode statusCode;
};
QHash<QOpcUaNode::NodeAttribute, AttributeWithStatus> m_nodeAttributes;
+ QHash<QOpcUaNode::NodeAttribute, QOpcUaMonitoringParameters> m_monitoringStatus;
QMetaObject::Connection m_attributesReadConnection;
QMetaObject::Connection m_attributeWrittenConnection;
+ QMetaObject::Connection m_attributeUpdatedConnection;
+ QMetaObject::Connection m_monitoringEnableDisableConnection;
+ QMetaObject::Connection m_monitoringStatusChangedConnection;
};
QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuanodeimpl_p.h b/src/opcua/client/qopcuanodeimpl_p.h
index 585a025..ff49dc3 100644
--- a/src/opcua/client/qopcuanodeimpl_p.h
+++ b/src/opcua/client/qopcuanodeimpl_p.h
@@ -49,6 +49,7 @@
//
#include <QtOpcUa/qopcuaglobal.h>
+#include <QtOpcUa/qopcuamonitoringparameters.h>
#include <QtOpcUa/qopcuanode.h>
#include <QtOpcUa/qopcuatype.h>
@@ -56,9 +57,6 @@
QT_BEGIN_NAMESPACE
-class QOpcUaMonitoredEvent;
-class QOpcUaMonitoredValue;
-
struct QOpcUaReadResult {
QOpcUaNode::NodeAttribute attributeId;
QOpcUa::UaStatusCode statusCode;
@@ -73,11 +71,15 @@ public:
virtual ~QOpcUaNodeImpl();
virtual bool readAttributes(QOpcUaNode::NodeAttributes attr) = 0;
+ virtual bool enableMonitoring(QOpcUaNode::NodeAttributes attr, const QOpcUaMonitoringParameters &settings) = 0;
+ virtual bool disableMonitoring(QOpcUaNode::NodeAttributes attr) = 0;
virtual QStringList childrenIds() const = 0;
virtual QString nodeId() const = 0;
virtual bool writeAttribute(QOpcUaNode::NodeAttribute attribute, const QVariant &value, QOpcUa::Types type) = 0;
virtual bool writeAttributes(const QOpcUaNode::AttributeMap &toWrite, QOpcUa::Types valueAttributeType) = 0;
+ virtual bool modifyMonitoring(QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item,
+ const QVariant &value) = 0;
virtual QPair<double, double> readEuRange() const = 0;
virtual QPair<QString, QString> readEui() const = 0;
@@ -89,6 +91,10 @@ Q_SIGNALS:
void attributesRead(QVector<QOpcUaReadResult> attr, QOpcUa::UaStatusCode serviceResult);
void attributeWritten(QOpcUaNode::NodeAttribute attr, QVariant value, QOpcUa::UaStatusCode statusCode);
+ void attributeUpdated(QOpcUaNode::NodeAttribute attr, QVariant value);
+ void monitoringEnableDisable(QOpcUaNode::NodeAttribute attr, bool subscribe, QOpcUaMonitoringParameters status);
+ void monitoringStatusChanged(QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameters items,
+ QOpcUaMonitoringParameters param);
};
QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuasubscription.cpp b/src/opcua/client/qopcuasubscription.cpp
deleted file mode 100644
index f09a4a2..0000000
--- a/src/opcua/client/qopcuasubscription.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtOpcUa module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qopcuasubscription.h"
-#include <private/qopcuasubscription_p.h>
-#include <private/qopcuasubscriptionimpl_p.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QOpcUaSubscription
- \inmodule QtOpcUa
-
- \brief Enables the user to utilize the
- subscription mechanism in OPC UA for event subscriptions.
-*/
-
-/*!
- \internal
- */
-QOpcUaSubscription::QOpcUaSubscription(QOpcUaSubscriptionImpl *impl, quint32 interval, QObject *parent)
- : QObject(*new QOpcUaSubscriptionPrivate(impl, interval), parent)
-{
-}
-
-/*!
- \fn QOpcUaSubscription::~QOpcUaSubscription()
-
- Destroys this subscription instance. It will also destroy the subscrption on
- the server.
- */
-QOpcUaSubscription::~QOpcUaSubscription()
-{
-}
-
-/*!
- Create an event monitor for \a node by adding it to this subscription object.
-
- Returns a QOpcUaMonitoredEvent which can be used to receive a signal when an
- event occcurs.
-*/
-QOpcUaMonitoredEvent *QOpcUaSubscription::addEvent(QOpcUaNode *node)
-{
- return d_func()->m_impl->addEvent(node);
-}
-
-/*!
- Create a value monitor for \a node by adding it to this subscription object.
-
- Return a QOpcUaMonitoredEvent which can be used to receive a signal when
- the value changes.
- */
-QOpcUaMonitoredValue *QOpcUaSubscription::addValue(QOpcUaNode *node)
-{
- return d_func()->m_impl->addValue(node);
-}
-
-/*!
- Remove the monitored event represented by \a event from this subscription.
- */
-void QOpcUaSubscription::removeEvent(QOpcUaMonitoredEvent *e)
-{
- d_func()->m_impl->removeEvent(e);
-}
-
-/*!
- Remove the monitored value represented by \a value from this subscription.
- */
-void QOpcUaSubscription::removeValue(QOpcUaMonitoredValue *value)
-{
- d_func()->m_impl->removeValue(value);
-}
-
-QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuasubscription.h b/src/opcua/client/qopcuasubscription.h
deleted file mode 100644
index 2559a74..0000000
--- a/src/opcua/client/qopcuasubscription.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtOpcUa module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QOPCUASUBSCRIPTION_H
-#define QOPCUASUBSCRIPTION_H
-
-#include <QtOpcUa/qopcuaglobal.h>
-
-#include <QtCore/qobject.h>
-
-QT_BEGIN_NAMESPACE
-
-class QOpcUaMonitoredEvent;
-class QOpcUaMonitoredValue;
-class QOpcUaNode;
-class QOpcUaSubscriptionImpl;
-class QOpcUaSubscriptionPrivate;
-
-class Q_OPCUA_EXPORT QOpcUaSubscription : public QObject
-{
- Q_OBJECT
- Q_DECLARE_PRIVATE(QOpcUaSubscription)
-public:
- QOpcUaSubscription(QOpcUaSubscriptionImpl *impl, quint32 interval, QObject *parent = nullptr);
- ~QOpcUaSubscription() override;
-
- QOpcUaMonitoredEvent *addEvent(QOpcUaNode *node);
- void removeEvent(QOpcUaMonitoredEvent *e);
-
- QOpcUaMonitoredValue *addValue(QOpcUaNode *node);
- void removeValue(QOpcUaMonitoredValue *value);
-private:
- Q_DISABLE_COPY(QOpcUaSubscription)
-};
-
-QT_END_NAMESPACE
-
-#endif // QOPCUASUBSCRIPTION_H
diff --git a/src/opcua/client/qopcuasubscriptionimpl.cpp b/src/opcua/client/qopcuasubscriptionimpl.cpp
deleted file mode 100644
index 08b7eab..0000000
--- a/src/opcua/client/qopcuasubscriptionimpl.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 basysKom GmbH, opensource@basyskom.com
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtOpcUa module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <private/qopcuasubscriptionimpl_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QOpcUaSubscriptionImpl::QOpcUaSubscriptionImpl()
-{
-}
-
-QOpcUaSubscriptionImpl::~QOpcUaSubscriptionImpl()
-{
-}
-
-QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuasubscriptionimpl_p.h b/src/opcua/client/qopcuasubscriptionimpl_p.h
deleted file mode 100644
index 8c0a138..0000000
--- a/src/opcua/client/qopcuasubscriptionimpl_p.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 basysKom GmbH, opensource@basyskom.com
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtOpcUa module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QOPCUASUBSCRIPTIONIMPL_P_H
-#define QOPCUASUBSCRIPTIONIMPL_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtOpcUa/qopcuaglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-class QOpcUaMonitoredEvent;
-class QOpcUaMonitoredValue;
-class QOpcUaNode;
-
-class Q_OPCUA_EXPORT QOpcUaSubscriptionImpl
-{
-public:
- QOpcUaSubscriptionImpl();
- virtual ~QOpcUaSubscriptionImpl();
-
- virtual QOpcUaMonitoredEvent *addEvent(QOpcUaNode *node) = 0;
- virtual void removeEvent(QOpcUaMonitoredEvent *event) = 0;
- virtual QOpcUaMonitoredValue *addValue(QOpcUaNode *node) = 0;
- virtual void removeValue(QOpcUaMonitoredValue *value) = 0;
-};
-
-QT_END_NAMESPACE
-
-#endif // QOPCUASUBSCRIPTIONIMPL_P_H
diff --git a/src/opcua/client/qopcuasubscriptionprivate.cpp b/src/opcua/client/qopcuasubscriptionprivate.cpp
deleted file mode 100644
index 762d413..0000000
--- a/src/opcua/client/qopcuasubscriptionprivate.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 basysKom GmbH, opensource@basyskom.com
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtOpcUa module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <private/qopcuasubscription_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QOpcUaSubscriptionPrivate::QOpcUaSubscriptionPrivate(QOpcUaSubscriptionImpl *impl, quint32 interval)
- : m_impl(impl)
- , m_interval(interval)
-{
-
-}
-
-QOpcUaSubscriptionPrivate::~QOpcUaSubscriptionPrivate()
-{
-
-}
-
-QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuavaluesubscription.cpp b/src/opcua/client/qopcuavaluesubscription.cpp
deleted file mode 100644
index d48f772..0000000
--- a/src/opcua/client/qopcuavaluesubscription.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtOpcUa module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qopcuavaluesubscription.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QOpcUaValueSubscription
- \inmodule QtOpcUa
-
- \brief Enables the user to utilize the
- subscription mechanism in OPC UA for data change subscriptions.
-
- \note This class is not exposed to application developers.
-*/
-
-/*!
- Creates an empty QOpcUaValueSubscription object with interval \a interval
- */
-QOpcUaValueSubscription::QOpcUaValueSubscription(uint interval)
- : QOpcUaSubscription()
- , d_ptr(0) // new QOpcUaValueSubscriptionPrivate(this))
-{
- m_interval = interval;
-}
-
-/*!
- Return the interval of the subscription.
- */
-uint QOpcUaValueSubscription::interval() const
-{
- return m_interval;
-}
-
-/*!
- \fn QOpcUaMonitoredValue QOpcUaValueSubscription::addValue(const QString &nodeId)
-
- Adds the node with \a nodeId to this subscription.
-
- Must be reimplemented in the concrete plugin implementation.
-*/
-
-QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuavaluesubscription.h b/src/opcua/client/qopcuavaluesubscription.h
deleted file mode 100644
index 95d2873..0000000
--- a/src/opcua/client/qopcuavaluesubscription.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtOpcUa module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QOPCUAVALUESUBSCRIPTION_H
-#define QOPCUAVALUESUBSCRIPTION_H
-
-#include <QtOpcUa/qopcuasubscription.h>
-
-QT_BEGIN_NAMESPACE
-
-class QOpcUaMonitoredValue;
-class QOpcUaValueSubscriptionPrivate;
-
-class Q_OPCUA_EXPORT QOpcUaValueSubscription : public QOpcUaSubscription
-{
-public:
- ~QOpcUaValueSubscription() override = default;
-
- virtual QOpcUaMonitoredValue *addValue(const QString &nodeId) = 0;
-
- uint interval() const;
-
-protected:
- explicit QOpcUaValueSubscription(uint interval);
-
- uint m_interval;
-
-private:
- Q_DECLARE_PRIVATE(QOpcUaValueSubscription)
-};
-
-QT_END_NAMESPACE
-
-#endif // QOPCUAVALUESUBSCRIPTION_H
diff --git a/src/opcua/core/qopcuaprovider.cpp b/src/opcua/core/qopcuaprovider.cpp
index da33774..c0c95fc 100644
--- a/src/opcua/core/qopcuaprovider.cpp
+++ b/src/opcua/core/qopcuaprovider.cpp
@@ -116,6 +116,10 @@ QOpcUaProvider::QOpcUaProvider(QObject *parent)
qRegisterMetaType<QOpcUaClient::ClientState>();
qRegisterMetaType<QOpcUaClient::ClientError>();
qRegisterMetaType<uintptr_t>("uintptr_t");
+ qRegisterMetaType<QOpcUaMonitoringParameters::SubscriptionType>();
+ qRegisterMetaType<QOpcUaMonitoringParameters::Parameter>();
+ qRegisterMetaType<QOpcUaMonitoringParameters::Parameters>();
+ qRegisterMetaType<QOpcUaMonitoringParameters>();
}
QOpcUaProvider::~QOpcUaProvider()
diff --git a/src/opcua/doc/src/qtopcua.qdoc b/src/opcua/doc/src/qtopcua.qdoc
index 171b1e7..7f53361 100644
--- a/src/opcua/doc/src/qtopcua.qdoc
+++ b/src/opcua/doc/src/qtopcua.qdoc
@@ -187,11 +187,9 @@
\endtable
\section1 Classes and ownership
- Four important classes are exposed to the user: QOpcUaClient, QOpcUaNode,
- QOpcUaMonitoredEvent and QOpcUaMonitoredValue.
+ Two important classes are exposed to the user: QOpcUaClient and QOpcUaNode.
- Objects of the types QOpcUaNode, QOpcUaMonitoredEvent and QOpcUaMonitoredValue
- are owned by the user and must be deleted when they are no longer needed.
+ Objects of the type QOpcUaNode are owned by the user and must be deleted when they are no longer needed.
\section1 Related Information
diff --git a/src/plugins/opcua/freeopcua/qfreeopcuaclient.cpp b/src/plugins/opcua/freeopcua/qfreeopcuaclient.cpp
index c0cc2ff..31b9134 100644
--- a/src/plugins/opcua/freeopcua/qfreeopcuaclient.cpp
+++ b/src/plugins/opcua/freeopcua/qfreeopcuaclient.cpp
@@ -37,7 +37,6 @@
#include "qfreeopcuaclient.h"
#include "qfreeopcuanode.h"
#include "qfreeopcuaworker.h"
-#include <QtOpcUa/qopcuasubscription.h>
#include <private/qopcuaclient_p.h>
#include <QtCore/qloggingcategory.h>
@@ -95,14 +94,4 @@ QOpcUaNode *QFreeOpcUaClientImpl::node(const QString &nodeId)
}
}
-QOpcUaSubscription *QFreeOpcUaClientImpl::createSubscription(quint32 interval)
-{
- QOpcUaSubscription *result;
- QMetaObject::invokeMethod(m_opcuaWorker, "createSubscription",
- Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(QOpcUaSubscription *, result),
- Q_ARG(quint32, interval));
- return result;
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/freeopcua/qfreeopcuaclient.h b/src/plugins/opcua/freeopcua/qfreeopcuaclient.h
index f477dde..47423f1 100644
--- a/src/plugins/opcua/freeopcua/qfreeopcuaclient.h
+++ b/src/plugins/opcua/freeopcua/qfreeopcuaclient.h
@@ -63,8 +63,6 @@ public:
bool isSecureConnectionSupported() const override { return false; }
QString backend() const override { return QStringLiteral("freeopcua"); }
- QOpcUaSubscription *createSubscription(quint32 interval) override;
-
QFreeOpcUaWorker *m_opcuaWorker{};
private:
diff --git a/src/plugins/opcua/freeopcua/qfreeopcuanode.cpp b/src/plugins/opcua/freeopcua/qfreeopcuanode.cpp
index 82046fc..f4a07cf 100644
--- a/src/plugins/opcua/freeopcua/qfreeopcuanode.cpp
+++ b/src/plugins/opcua/freeopcua/qfreeopcuanode.cpp
@@ -39,8 +39,6 @@
#include "qfreeopcuasubscription.h"
#include "qfreeopcuavalueconverter.h"
#include "qfreeopcuaworker.h"
-#include <QtOpcUa/qopcuamonitoredevent.h>
-#include <QtOpcUa/qopcuamonitoredvalue.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qloggingcategory.h>
@@ -73,6 +71,34 @@ bool QFreeOpcUaNode::readAttributes(QOpcUaNode::NodeAttributes attr)
Q_ARG(QOpcUaNode::NodeAttributes, attr));
}
+bool QFreeOpcUaNode::enableMonitoring(QOpcUaNode::NodeAttributes attr, const QOpcUaMonitoringParameters &settings)
+{
+ return QMetaObject::invokeMethod(m_client->m_opcuaWorker, "enableMonitoring",
+ Qt::QueuedConnection,
+ Q_ARG(uintptr_t, reinterpret_cast<uintptr_t>(this)),
+ Q_ARG(OpcUa::Node, m_node),
+ Q_ARG(QOpcUaNode::NodeAttributes, attr),
+ Q_ARG(QOpcUaMonitoringParameters, settings));
+}
+
+bool QFreeOpcUaNode::disableMonitoring(QOpcUaNode::NodeAttributes attr)
+{
+ return QMetaObject::invokeMethod(m_client->m_opcuaWorker, "disableMonitoring",
+ Qt::QueuedConnection,
+ Q_ARG(uintptr_t, reinterpret_cast<uintptr_t>(this)),
+ Q_ARG(QOpcUaNode::NodeAttributes, attr));
+}
+
+bool QFreeOpcUaNode::modifyMonitoring(QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, const QVariant &value)
+{
+ return QMetaObject::invokeMethod(m_client->m_opcuaWorker, "modifyMonitoring",
+ Qt::QueuedConnection,
+ Q_ARG(uintptr_t, reinterpret_cast<uintptr_t>(this)),
+ Q_ARG(QOpcUaNode::NodeAttribute, attr),
+ Q_ARG(QOpcUaMonitoringParameters::Parameter, item),
+ Q_ARG(QVariant, value));
+}
+
QStringList QFreeOpcUaNode::childrenIds() const
{
QStringList result;
diff --git a/src/plugins/opcua/freeopcua/qfreeopcuanode.h b/src/plugins/opcua/freeopcua/qfreeopcuanode.h
index 52fef68..46f2ebd 100644
--- a/src/plugins/opcua/freeopcua/qfreeopcuanode.h
+++ b/src/plugins/opcua/freeopcua/qfreeopcuanode.h
@@ -43,8 +43,6 @@
#include <opc/ua/node.h>
-class QFreeOpcUaWorker;
-
namespace OpcUa
{
class UaClient;
@@ -61,6 +59,9 @@ public:
~QFreeOpcUaNode() override;
bool readAttributes(QOpcUaNode::NodeAttributes attr) override;
+ bool enableMonitoring(QOpcUaNode::NodeAttributes attr, const QOpcUaMonitoringParameters &settings);
+ bool disableMonitoring(QOpcUaNode::NodeAttributes attr);
+ bool modifyMonitoring(QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, const QVariant &value);
QStringList childrenIds() const override;
QString nodeId() const override;
diff --git a/src/plugins/opcua/freeopcua/qfreeopcuasubscription.cpp b/src/plugins/opcua/freeopcua/qfreeopcuasubscription.cpp
index 487b3ed..f89ae57 100644
--- a/src/plugins/opcua/freeopcua/qfreeopcuasubscription.cpp
+++ b/src/plugins/opcua/freeopcua/qfreeopcuasubscription.cpp
@@ -35,13 +35,9 @@
****************************************************************************/
#include "qfreeopcuaclient.h"
-#include "qfreeopcuanode.h"
#include "qfreeopcuasubscription.h"
#include "qfreeopcuavalueconverter.h"
-#include <QtOpcUa/qopcuamonitoredvalue.h>
-#include <QtOpcUa/qopcuasubscription.h>
-#include <private/qopcuamonitoredevent_p.h>
-#include <private/qopcuamonitoredvalue_p.h>
+#include "qfreeopcuaworker.h"
#include <private/qopcuanode_p.h>
#include <QtCore/qloggingcategory.h>
@@ -50,157 +46,194 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_FREEOPCUA)
-QFreeOpcUaSubscription::QFreeOpcUaSubscription(OpcUa::UaClient *client, quint32 interval)
- : m_client(client)
+QFreeOpcUaSubscription::QFreeOpcUaSubscription(QFreeOpcUaWorker *backend, const QOpcUaMonitoringParameters &settings)
+ : m_interval(settings.publishingInterval())
+ , m_shared(settings.shared())
+ , m_backend(backend)
{
- Q_ASSERT(m_client);
+ Q_ASSERT(m_backend);
+}
+
+QFreeOpcUaSubscription::~QFreeOpcUaSubscription()
+{
+ removeOnServer();
+}
+
+quint32 QFreeOpcUaSubscription::createOnServer()
+{
+ if (m_subscription)
+ return 0;
try {
- m_subscription = m_client->CreateSubscription(interval, *this);
+ m_subscription = m_backend->CreateSubscription(m_interval, *this);
+ m_interval = m_subscription->GetData().RevisedPublishingInterval;
} catch (const std::exception &ex) {
- qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "Caught: %s", ex.what());
+ qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "CreateOnServer caught: %s", ex.what());
+ return 0;
}
+ return m_subscription->GetId();
}
-QFreeOpcUaSubscription::~QFreeOpcUaSubscription()
+bool QFreeOpcUaSubscription::removeOnServer()
{
+ bool success = false;
try {
if (m_subscription) {
- for (int32_t handle : m_dataChangeHandles.keys())
- m_subscription->UnSubscribe(handle);
-
- for (int32_t handle : m_eventHandles.keys())
- m_subscription->UnSubscribe(handle);
-
m_subscription->Delete();
+ m_subscription.reset();
+ success = true;
}
} catch (const std::exception &ex) {
- qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "Caught: %s", ex.what());
+ qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "RemoveOnServer caught: %s", ex.what());
}
+
+ qDeleteAll(m_itemIdToItemMapping);
+
+ m_itemIdToItemMapping.clear();
+ m_handleToItemMapping.clear();
+
+ return success;
}
-void QFreeOpcUaSubscription::DataChange(quint32 handle, const OpcUa::Node &node,
- const OpcUa::Variant &val,
- OpcUa::AttributeId attr)
+void QFreeOpcUaSubscription::modifyMonitoring(uintptr_t handle, QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, QVariant value)
{
- OPCUA_UNUSED(node);
- OPCUA_UNUSED(attr);
-
- auto it = m_dataChangeHandles.find(handle);
- if (it == m_dataChangeHandles.end()) {
- qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "Received event for unknown handle: %ul", handle);
+ Q_UNUSED(item);
+ Q_UNUSED(value);
+
+ if (!getItemForAttribute(handle, attr)) {
+ qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "Could not modify parameter for %lu, there are no monitored items", handle);
+ QOpcUaMonitoringParameters p;
+ p.setStatusCode(QOpcUa::UaStatusCode::BadAttributeIdInvalid);
+ emit m_backend->monitoringStatusChanged(handle, attr, item, p);
return;
}
- try {
- (*it)->d_func()->triggerValueChanged(QFreeOpcUaValueConverter::toQVariant(val));
- } catch (const std::exception &ex) {
- qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "Caught: %s", ex.what());
- }
+ QOpcUaMonitoringParameters s;
+ s.setStatusCode(QOpcUa::UaStatusCode::BadNotImplemented);
+ emit m_backend->monitoringEnableDisable(handle, attr, true, s);
}
-QOpcUaMonitoredValue *QFreeOpcUaSubscription::addValue(QOpcUaNode *node)
+bool QFreeOpcUaSubscription::addAttributeMonitoredItem(uintptr_t handle, QOpcUaNode::NodeAttribute attr, const OpcUa::Node &node, QOpcUaMonitoringParameters settings)
{
- if (!m_subscription)
- return nullptr;
+ Q_UNUSED(settings); // Setting these options is not yet supported
- try {
- // Only add a monitored item if the node has a value attribute
- QFreeOpcUaNode *nnode = static_cast<QFreeOpcUaNode *>(node->d_func()->m_impl.data());
- if (nnode->m_node.GetAttribute(OpcUa::AttributeId::Value).Status != OpcUa::StatusCode::Good)
- return nullptr;
+ quint32 monitoredItemId;
+ try {
if (m_subscription) {
- uint32_t handle = m_subscription->SubscribeDataChange(m_client->GetNode(node->nodeId().toStdString()));
- QOpcUaMonitoredValue *monitoredValue = new QOpcUaMonitoredValue(node, m_qsubscription);
- m_dataChangeHandles[handle] = monitoredValue;
- return monitoredValue;
+ monitoredItemId = m_subscription->SubscribeDataChange(node, QFreeOpcUaValueConverter::toUaAttributeId(attr));
+ }
+ else {
+ QOpcUaMonitoringParameters s;
+ s.setStatusCode(QOpcUa::UaStatusCode::BadSubscriptionIdInvalid);
+ emit m_backend->monitoringEnableDisable(handle, attr, true, s);
+ return false;
}
} catch (const std::exception &ex) {
- qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "Caught: %s", ex.what());
+ qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "addAttributeMonitoredItem caught: %s", ex.what());
+ QOpcUaMonitoringParameters s;
+ s.setStatusCode(QFreeOpcUaValueConverter::exceptionToStatusCode(ex));
+ emit m_backend->monitoringEnableDisable(handle, attr, true, s);
+ return false;
}
- return nullptr;
+
+ MonitoredItem *temp = new MonitoredItem(handle, attr, monitoredItemId);
+ m_handleToItemMapping[handle][attr] = temp;
+ m_itemIdToItemMapping[monitoredItemId] = temp;
+
+ QOpcUaMonitoringParameters s;
+ s.setSubscriptionId(m_subscription->GetId());
+ s.setPublishingInterval(m_interval);
+ s.setMaxKeepAliveCount(m_subscription->GetData().RevisedMaxKeepAliveCount);
+ s.setLifetimeCount(m_subscription->GetData().RevisedLifetimeCount);
+ s.setStatusCode(QOpcUa::UaStatusCode::Good);
+ s.setSamplingInterval(m_interval);
+ emit m_backend->monitoringEnableDisable(handle, attr, true, s);
+
+ return true;
}
-void QFreeOpcUaSubscription::Event(quint32 handle, const OpcUa::Event &event)
+bool QFreeOpcUaSubscription::removeAttributeMonitoredItem(uintptr_t handle, QOpcUaNode::NodeAttribute attr)
{
- auto it = m_eventHandles.find(handle);
- if (it == m_eventHandles.end()) {
- qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA) << "Received event for unknown handle:" << handle;
- return;
+ QScopedPointer<MonitoredItem> item(getItemForAttribute(handle, attr));
+
+ if (!item) {
+ qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "There is no monitored item for this attribute");
+ QOpcUaMonitoringParameters s;
+ s.setStatusCode(QOpcUa::UaStatusCode::BadMonitoredItemIdInvalid);
+ emit m_backend->monitoringEnableDisable(handle, attr, false, s);
+ return false;
}
- try {
- QVector<QVariant> val;
- val.reserve(3);
-
- val.push_back(QVariant(QString::fromStdString(event.Message.Text)));
- val.push_back(QVariant(QString::fromStdString(event.SourceName)));
- val.push_back(QVariant(event.Severity));
+ QOpcUaMonitoringParameters s;
- QOpcUaMonitoredEvent *me = *it;
- me->d_func()->triggerNewEvent(val);
+ try {
+ m_subscription->UnSubscribe(item->monitoredItemId);
+ s.setStatusCode(QOpcUa::UaStatusCode::Good);
} catch (const std::exception &ex) {
- qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "Caught: %s", ex.what());
+ qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "removeAttributeMonitoredItem caught: %s", ex.what());
+ s.setStatusCode(QFreeOpcUaValueConverter::exceptionToStatusCode(ex));
}
+
+ m_itemIdToItemMapping.remove(item->monitoredItemId);
+ auto it = m_handleToItemMapping.find(handle);
+ it->remove(attr);
+ if (it->empty())
+ m_handleToItemMapping.erase(it);
+
+ emit m_backend->monitoringEnableDisable(handle, attr, false, s);
+
+ return true;
}
-QOpcUaMonitoredEvent *QFreeOpcUaSubscription::addEvent(QOpcUaNode *node)
+double QFreeOpcUaSubscription::interval() const
{
- // Note: Callback is not called due to some error in the event implementation in freeopcua
- if (!m_subscription)
- return nullptr;
+ return m_interval;
+}
- try {
- QFreeOpcUaNode *nnode = static_cast<QFreeOpcUaNode *>(node->d_func()->m_impl.data());
- if (nnode->m_node.GetAttribute(OpcUa::AttributeId::EventNotifier).Status != OpcUa::StatusCode::Good)
- return nullptr;
+QOpcUaMonitoringParameters::SubscriptionType QFreeOpcUaSubscription::shared() const
+{
+ return m_shared;
+}
- OpcUa::Node serverNode = m_client->GetNode(OpcUa::ObjectId::Server);
- OpcUa::Node typeNode = m_client->GetNode(node->nodeId().toStdString());
+quint32 QFreeOpcUaSubscription::subscriptionId() const
+{
+ if (m_subscription)
+ return m_subscription->GetId();
+ else
+ return 0;
+}
- uint32_t handle = m_subscription->SubscribeEvents(serverNode, typeNode);
- QOpcUaMonitoredEvent *monitoredEvent = new QOpcUaMonitoredEvent(node, m_qsubscription);
- m_eventHandles[handle] = monitoredEvent;
- return monitoredEvent;
- } catch (const std::exception &ex) {
- qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "Caught: %s", ex.what());
- }
- return nullptr;
+int QFreeOpcUaSubscription::monitoredItemsCount() const
+{
+ return m_itemIdToItemMapping.size();
}
-void QFreeOpcUaSubscription::removeEvent(QOpcUaMonitoredEvent *event)
+QFreeOpcUaSubscription::MonitoredItem *QFreeOpcUaSubscription::getItemForAttribute(uintptr_t handle, QOpcUaNode::NodeAttribute attr)
{
- try {
- auto it = m_eventHandles.begin();
- while (it != m_eventHandles.end()) {
- if (it.value() == event) {
- m_subscription->UnSubscribe(it.key());
- m_eventHandles.erase(it);
- break;
- }
- ++it;
- }
- } catch (const std::exception &ex) {
- qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "Caught: %s", ex.what());
- }
+ auto nodeEntry = m_handleToItemMapping.find(handle);
+
+ if (nodeEntry == m_handleToItemMapping.end())
+ return nullptr;
+
+ auto item = nodeEntry->find(attr);
+ if (item == nodeEntry->end())
+ return nullptr;
+
+ return item.value();
}
-void QFreeOpcUaSubscription::removeValue(QOpcUaMonitoredValue *value)
+void QFreeOpcUaSubscription::DataChange(quint32 handle, const OpcUa::Node &node,
+ const OpcUa::Variant &val,
+ OpcUa::AttributeId attr)
{
- try {
- auto it = m_dataChangeHandles.begin();
- while (it != m_dataChangeHandles.end()) {
- if (it.value() == value) {
- m_subscription->UnSubscribe(it.key());
- m_dataChangeHandles.erase(it);
- break;
- }
- ++it;
- }
- } catch (const std::exception &ex) {
- qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "Caught: %s", ex.what());
- }
+ OPCUA_UNUSED(node);
+ OPCUA_UNUSED(attr);
+
+ auto item = m_itemIdToItemMapping.find(handle);
+ if (item == m_itemIdToItemMapping.end())
+ return;
+ emit m_backend->attributeUpdated(item.value()->handle, item.value()->attr, QFreeOpcUaValueConverter::toQVariant(val));
}
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/freeopcua/qfreeopcuasubscription.h b/src/plugins/opcua/freeopcua/qfreeopcuasubscription.h
index bcc4d1e..8d36bfe 100644
--- a/src/plugins/opcua/freeopcua/qfreeopcuasubscription.h
+++ b/src/plugins/opcua/freeopcua/qfreeopcuasubscription.h
@@ -37,9 +37,9 @@
#ifndef QFREEOPCUASUBSCRIPTION_H
#define QFREEOPCUASUBSCRIPTION_H
-#include <QtOpcUa/qopcuamonitoredevent.h>
-#include <QtOpcUa/qopcuamonitoredvalue.h>
-#include <private/qopcuasubscriptionimpl_p.h>
+#include "qfreeopcuanode.h"
+
+#include <QtCore/qhash.h>
#include <opc/ua/subscription.h>
@@ -51,30 +51,57 @@ namespace OpcUa {
QT_BEGIN_NAMESPACE
class QOpcUaNode;
-class QFreeOpcUaMonitoredValue;
-class QOpcUaSubscription;
+class QFreeOpcUaWorker;
-class QFreeOpcUaSubscription : public QOpcUaSubscriptionImpl, public OpcUa::SubscriptionHandler
+class QFreeOpcUaSubscription : public OpcUa::SubscriptionHandler
{
public:
- explicit QFreeOpcUaSubscription(OpcUa::UaClient *client, quint32 interval);
+ QFreeOpcUaSubscription(QFreeOpcUaWorker *backend, const QOpcUaMonitoringParameters &settings);
~QFreeOpcUaSubscription() override;
// FreeOPC-UA callbacks
void DataChange(uint32_t handle, const OpcUa::Node &node, const OpcUa::Variant &val,
OpcUa::AttributeId attr) override;
- void Event(quint32 handle, const OpcUa::Event &event) override;
- QOpcUaMonitoredEvent *addEvent(QOpcUaNode *node) override;
- void removeEvent(QOpcUaMonitoredEvent *event) override;
- QOpcUaMonitoredValue *addValue(QOpcUaNode *node) override;
- void removeValue(QOpcUaMonitoredValue *value) override;
+ quint32 createOnServer();
+ bool removeOnServer();
+
+ void modifyMonitoring(uintptr_t handle, QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, QVariant value);
+
+ bool addAttributeMonitoredItem(uintptr_t handle, QOpcUaNode::NodeAttribute attr, const OpcUa::Node &node, QOpcUaMonitoringParameters settings);
+ bool removeAttributeMonitoredItem(uintptr_t handle, QOpcUaNode::NodeAttribute attr);
+
+ double interval() const;
+ QOpcUaMonitoringParameters::SubscriptionType shared() const;
+ quint32 subscriptionId() const;
+ int monitoredItemsCount() const;
+
+ struct MonitoredItem {
+ uintptr_t handle;
+ QOpcUaNode::NodeAttribute attr;
+ quint32 monitoredItemId;
+ MonitoredItem(uintptr_t h, QOpcUaNode::NodeAttribute a, quint32 id)
+ : handle(h)
+ , attr(a)
+ , monitoredItemId(id)
+ {}
+ MonitoredItem()
+ : handle(0)
+ , monitoredItemId(0)
+ {}
+ };
+
+private:
+ MonitoredItem *getItemForAttribute(uintptr_t handle, QOpcUaNode::NodeAttribute attr);
+
+ double m_interval;
+ QOpcUaMonitoringParameters::SubscriptionType m_shared;
- OpcUa::UaClient *m_client;
- QOpcUaSubscription *m_qsubscription;
OpcUa::Subscription::SharedPtr m_subscription;
- QMap<int32_t, QOpcUaMonitoredValue *> m_dataChangeHandles;
- QMap<int32_t, QOpcUaMonitoredEvent *> m_eventHandles;
+ QFreeOpcUaWorker *m_backend;
+
+ QHash<quint32, MonitoredItem *> m_itemIdToItemMapping;
+ QHash<uintptr_t, QHash<QOpcUaNode::NodeAttribute, MonitoredItem *>> m_handleToItemMapping;
};
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/freeopcua/qfreeopcuaworker.cpp b/src/plugins/opcua/freeopcua/qfreeopcuaworker.cpp
index 6e3f95e..8656987 100644
--- a/src/plugins/opcua/freeopcua/qfreeopcuaworker.cpp
+++ b/src/plugins/opcua/freeopcua/qfreeopcuaworker.cpp
@@ -39,7 +39,6 @@
#include "qfreeopcuasubscription.h"
#include "qfreeopcuavalueconverter.h"
#include "qfreeopcuaworker.h"
-#include <QtOpcUa/qopcuasubscription.h>
#include <QtNetwork/qhostinfo.h>
#include <QtCore/qloggingcategory.h>
@@ -55,6 +54,11 @@ QFreeOpcUaWorker::QFreeOpcUaWorker(QFreeOpcUaClientImpl *client)
, m_client(client)
{}
+QFreeOpcUaWorker::~QFreeOpcUaWorker()
+{
+ qDeleteAll(m_subscriptions);
+}
+
void QFreeOpcUaWorker::asyncConnectToEndpoint(const QUrl &url)
{
try {
@@ -197,12 +201,113 @@ void QFreeOpcUaWorker::writeAttributes(uintptr_t handle, OpcUa::Node node, QOpcU
}
}
-QOpcUaSubscription *QFreeOpcUaWorker::createSubscription(quint32 interval)
+QFreeOpcUaSubscription *QFreeOpcUaWorker::getSubscription(const QOpcUaMonitoringParameters &settings)
+{
+ if (settings.shared() == QOpcUaMonitoringParameters::SubscriptionType::Shared) {
+ for (auto entry : m_subscriptions)
+ if (entry->interval() == settings.publishingInterval() && entry->shared() == QOpcUaMonitoringParameters::SubscriptionType::Shared)
+ return entry;
+ }
+
+ QFreeOpcUaSubscription *sub = new QFreeOpcUaSubscription(this, settings);
+ quint32 id = sub->createOnServer();
+ if (!id) {
+ delete sub;
+ return nullptr;
+ }
+ m_subscriptions[id] = sub;
+ return sub;
+}
+
+bool QFreeOpcUaWorker::removeSubscription(quint32 subscriptionId)
{
- QFreeOpcUaSubscription *backendSubscription = new QFreeOpcUaSubscription(this, interval);
- QOpcUaSubscription *subscription = new QOpcUaSubscription(backendSubscription, interval);
- backendSubscription->m_qsubscription = subscription;
- return subscription;
+ auto sub = m_subscriptions.find(subscriptionId);
+ if (sub != m_subscriptions.end()) {
+ sub.value()->removeOnServer();
+ delete sub.value();
+ m_subscriptions.remove(subscriptionId);
+ return true;
+ }
+ return false;
+}
+
+void QFreeOpcUaWorker::enableMonitoring(uintptr_t handle, OpcUa::Node node, QOpcUaNode::NodeAttributes attr, const QOpcUaMonitoringParameters &settings)
+{
+ QFreeOpcUaSubscription *usedSubscription = nullptr;
+
+ // Create a new subscription if necessary
+ if (settings.subscriptionId()) {
+ if (!m_subscriptions.contains(settings.subscriptionId())) {
+ qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "There is no subscription with id %u", settings.subscriptionId());
+ qt_forEachAttribute(attr, [&](QOpcUaNode::NodeAttribute attr) {
+ QOpcUaMonitoringParameters s;
+ s.setStatusCode(QOpcUa::UaStatusCode::BadSubscriptionIdInvalid);
+ emit monitoringEnableDisable(handle, attr, true, s);
+ });
+ return;
+ }
+ usedSubscription = m_subscriptions[settings.subscriptionId()]; // Ignore interval != subscription.interval
+ } else {
+ usedSubscription = getSubscription(settings);
+ }
+
+ if (!usedSubscription) {
+ qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "Could not create subscription with interval %f", settings.publishingInterval());
+ qt_forEachAttribute(attr, [&](QOpcUaNode::NodeAttribute attr) {
+ QOpcUaMonitoringParameters s;
+ s.setStatusCode(QOpcUa::UaStatusCode::BadSubscriptionIdInvalid);
+ emit monitoringEnableDisable(handle, attr, true, s);
+ });
+ return;
+ }
+
+ qt_forEachAttribute(attr, [&](QOpcUaNode::NodeAttribute attr) {
+ bool success = usedSubscription->addAttributeMonitoredItem(handle, attr, node, settings);
+ if (success)
+ m_attributeMapping[handle][attr] = usedSubscription;
+ });
+
+ if (usedSubscription->monitoredItemsCount() == 0)
+ removeSubscription(usedSubscription->subscriptionId()); // No items were added
+}
+
+void QFreeOpcUaWorker::disableMonitoring(uintptr_t handle, QOpcUaNode::NodeAttributes attr)
+{
+ qt_forEachAttribute(attr, [&](QOpcUaNode::NodeAttribute attr) {
+ QFreeOpcUaSubscription *sub = getSubscriptionForItem(handle, attr);
+ if (sub) {
+ sub->removeAttributeMonitoredItem(handle, attr);
+ if (sub->monitoredItemsCount() == 0)
+ removeSubscription(sub->subscriptionId());
+ }
+ });
+}
+
+void QFreeOpcUaWorker::modifyMonitoring(uintptr_t handle, QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, QVariant value)
+{
+ QFreeOpcUaSubscription *subscription = getSubscriptionForItem(handle, attr);
+ if (!subscription) {
+ qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA, "Could not modify parameter for %lu, the monitored item does not exist", handle);
+ QOpcUaMonitoringParameters p;
+ p.setStatusCode(QOpcUa::UaStatusCode::BadSubscriptionIdInvalid);
+ emit monitoringStatusChanged(handle, attr, item, p);
+ return;
+ }
+
+ subscription->modifyMonitoring(handle, attr, item, value);
+}
+
+QFreeOpcUaSubscription *QFreeOpcUaWorker::getSubscriptionForItem(uintptr_t handle, QOpcUaNode::NodeAttribute attr)
+{
+ auto nodeEntry = m_attributeMapping.find(handle);
+ if (nodeEntry == m_attributeMapping.end())
+ return nullptr;
+
+ auto subscription = nodeEntry->find(attr);
+ if (subscription == nodeEntry->end())
+ return nullptr;
+
+ return subscription.value();
}
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/freeopcua/qfreeopcuaworker.h b/src/plugins/opcua/freeopcua/qfreeopcuaworker.h
index d4ede6b..65d2c23 100644
--- a/src/plugins/opcua/freeopcua/qfreeopcuaworker.h
+++ b/src/plugins/opcua/freeopcua/qfreeopcuaworker.h
@@ -37,8 +37,8 @@
#ifndef QFREEOPCUAWORKER_H
#define QFREEOPCUAWORKER_H
+#include "qfreeopcuasubscription.h"
#include <QtOpcUa/qopcuanode.h>
-#include <QtOpcUa/qopcuasubscription.h>
#include <private/qopcuabackend_p.h>
#include <QtCore/qobject.h>
@@ -49,7 +49,6 @@
QT_BEGIN_NAMESPACE
class QFreeOpcUaNode;
-class QOpcUaSubscription;
class QOpcUaNode;
class QFreeOpcUaClientImpl;
@@ -58,8 +57,7 @@ class QFreeOpcUaWorker : public QOpcUaBackend, public OpcUa::UaClient
Q_OBJECT
public:
QFreeOpcUaWorker(QFreeOpcUaClientImpl *client);
-
- Q_INVOKABLE QOpcUaSubscription *createSubscription(quint32 interval);
+ ~QFreeOpcUaWorker();
public slots:
void asyncConnectToEndpoint(const QUrl &url);
@@ -69,8 +67,20 @@ public slots:
void writeAttribute(uintptr_t handle, OpcUa::Node node, QOpcUaNode::NodeAttribute attr, QVariant value, QOpcUa::Types type);
void writeAttributes(uintptr_t handle, OpcUa::Node node, QOpcUaNode::AttributeMap toWrite, QOpcUa::Types valueAttributeType);
+ QFreeOpcUaSubscription *getSubscription(const QOpcUaMonitoringParameters &settings);
+ bool removeSubscription(quint32 subscriptionId);
+
+ void enableMonitoring(uintptr_t handle, OpcUa::Node node, QOpcUaNode::NodeAttributes attr, const QOpcUaMonitoringParameters &settings);
+ void disableMonitoring(uintptr_t handle, QOpcUaNode::NodeAttributes attr);
+ void modifyMonitoring(uintptr_t handle, QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, QVariant value);
+
private:
+ QFreeOpcUaSubscription *getSubscriptionForItem(uintptr_t handle, QOpcUaNode::NodeAttribute attr);
+
QFreeOpcUaClientImpl *m_client;
+
+ QHash<quint32, QFreeOpcUaSubscription *> m_subscriptions;
+ QHash<uintptr_t, QHash<QOpcUaNode::NodeAttribute, QFreeOpcUaSubscription *>> m_attributeMapping; // Handle -> Attribute -> Subscription
};
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/open62541/qopen62541backend.cpp b/src/plugins/opcua/open62541/qopen62541backend.cpp
index 4411a04..7c5226f 100644
--- a/src/plugins/opcua/open62541/qopen62541backend.cpp
+++ b/src/plugins/opcua/open62541/qopen62541backend.cpp
@@ -60,10 +60,20 @@ struct UaLocalizedTextMemberDeleter
Open62541AsyncBackend::Open62541AsyncBackend(QOpen62541Client *parent)
: QOpcUaBackend()
- , m_clientImpl(parent)
, m_uaclient(nullptr)
- , m_subscriptionTimer(nullptr)
+ , m_clientImpl(parent)
+ , m_subscriptionTimer(this)
+ , m_sendPublishRequests(false)
+ , m_shortestInterval(std::numeric_limits<qint32>::max())
+{
+ m_subscriptionTimer.setSingleShot(true);
+ QObject::connect(&m_subscriptionTimer, &QTimer::timeout,
+ this, &Open62541AsyncBackend::sendPublishRequest);
+}
+
+Open62541AsyncBackend::~Open62541AsyncBackend()
{
+ qDeleteAll(m_subscriptions);
}
void Open62541AsyncBackend::readAttributes(uintptr_t handle, UA_NodeId id, QOpcUaNode::NodeAttributes attr)
@@ -155,6 +165,109 @@ void Open62541AsyncBackend::writeAttributes(uintptr_t handle, UA_NodeId id, QOpc
UA_NodeId_deleteMembers(&id);
}
+void Open62541AsyncBackend::enableMonitoring(uintptr_t handle, UA_NodeId id, QOpcUaNode::NodeAttributes attr, const QOpcUaMonitoringParameters &settings)
+{
+ QOpen62541Subscription *usedSubscription = nullptr;
+
+ // Create a new subscription if necessary
+ if (settings.subscriptionId()) {
+ auto sub = m_subscriptions.find(settings.subscriptionId());
+ if (sub == m_subscriptions.end()) {
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541, "There is no subscription with id %u", settings.subscriptionId());
+
+ qt_forEachAttribute(attr, [&](QOpcUaNode::NodeAttribute attribute){
+ QOpcUaMonitoringParameters s;
+ s.setStatusCode(QOpcUa::UaStatusCode::BadSubscriptionIdInvalid);
+ emit monitoringEnableDisable(handle, attribute, true, s);
+ });
+ return;
+ }
+ usedSubscription = sub.value(); // Ignore interval != subscription.interval
+ } else {
+ usedSubscription = getSubscription(settings);
+ }
+
+ if (!usedSubscription) {
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541, "Could not create subscription with interval %f", settings.publishingInterval());
+ qt_forEachAttribute(attr, [&](QOpcUaNode::NodeAttribute attribute){
+ QOpcUaMonitoringParameters s;
+ s.setStatusCode(QOpcUa::UaStatusCode::BadSubscriptionIdInvalid);
+ emit monitoringEnableDisable(handle, attribute, true, s);
+ });
+ return;
+ }
+
+ qt_forEachAttribute(attr, [&](QOpcUaNode::NodeAttribute attribute){
+ bool success = usedSubscription->addAttributeMonitoredItem(handle, attribute, id, settings);
+ if (success)
+ m_attributeMapping[handle][attribute] = usedSubscription;
+ });
+
+ if (usedSubscription->monitoredItemsCount() == 0)
+ removeSubscription(usedSubscription->subscriptionId()); // No items were added
+
+ modifyPublishRequests();
+}
+
+void Open62541AsyncBackend::disableMonitoring(uintptr_t handle, QOpcUaNode::NodeAttributes attr)
+{
+ qt_forEachAttribute(attr, [&](QOpcUaNode::NodeAttribute attribute){
+ QOpen62541Subscription *sub = getSubscriptionForItem(handle, attribute);
+ if (sub) {
+ sub->removeAttributeMonitoredItem(handle, attribute);
+ if (sub->monitoredItemsCount() == 0)
+ removeSubscription(sub->subscriptionId());
+ }
+ });
+ modifyPublishRequests();
+}
+
+void Open62541AsyncBackend::modifyMonitoring(uintptr_t handle, QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, QVariant value)
+{
+ QOpen62541Subscription *subscription = getSubscriptionForItem(handle, attr);
+ if (!subscription) {
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541, "Could not modify parameter for %lu, the monitored item does not exist", handle);
+ QOpcUaMonitoringParameters p;
+ p.setStatusCode(QOpcUa::UaStatusCode::BadMonitoredItemIdInvalid);
+ emit monitoringStatusChanged(handle, attr, item, p);
+ return;
+ }
+
+ subscription->modifyMonitoring(handle, attr, item, value);
+ modifyPublishRequests();
+}
+
+QOpen62541Subscription *Open62541AsyncBackend::getSubscription(const QOpcUaMonitoringParameters &settings)
+{
+ if (settings.shared() == QOpcUaMonitoringParameters::SubscriptionType::Shared) {
+ for (auto entry : qAsConst(m_subscriptions)) {
+ if (qFuzzyCompare(entry->interval(), settings.publishingInterval()) && entry->shared() == QOpcUaMonitoringParameters::SubscriptionType::Shared)
+ return entry;
+ }
+ }
+
+ QOpen62541Subscription *sub = new QOpen62541Subscription(this, settings);
+ UA_UInt32 id = sub->createOnServer();
+ if (!id) {
+ delete sub;
+ return nullptr;
+ }
+ m_subscriptions[id] = sub;
+ return sub;
+}
+
+bool Open62541AsyncBackend::removeSubscription(UA_UInt32 subscriptionId)
+{
+ auto sub = m_subscriptions.find(subscriptionId);
+ if (sub != m_subscriptions.end()) {
+ sub.value()->removeOnServer();
+ delete sub.value();
+ m_subscriptions.remove(subscriptionId);
+ return true;
+ }
+ return false;
+}
+
static UA_StatusCode nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, void *pass)
{
Q_UNUSED(referenceTypeId);
@@ -208,24 +321,6 @@ QStringList Open62541AsyncBackend::childrenIds(const UA_NodeId *parentNode)
return result;
}
-UA_UInt32 Open62541AsyncBackend::createSubscription(int interval)
-{
- UA_UInt32 result;
- UA_SubscriptionSettings settings = UA_SubscriptionSettings_default;
- settings.requestedPublishingInterval = interval;
- UA_StatusCode ret = UA_Client_Subscriptions_new(m_uaclient, settings, &result);
- if (ret != UA_STATUSCODE_GOOD)
- return 0;
- return result;
-}
-
-void Open62541AsyncBackend::deleteSubscription(UA_UInt32 id)
-{
- UA_StatusCode ret = UA_Client_Subscriptions_remove(m_uaclient, id);
- if (ret != UA_STATUSCODE_GOOD)
- qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "QOpcUa::Open62541: Could not remove subscription";
-}
-
void Open62541AsyncBackend::connectToEndpoint(const QUrl &url)
{
m_uaclient = UA_Client_new(UA_ClientConfig_default);
@@ -251,12 +346,6 @@ void Open62541AsyncBackend::connectToEndpoint(const QUrl &url)
return;
}
- if (!m_subscriptionTimer) {
- m_subscriptionTimer = new QTimer(this);
- m_subscriptionTimer->setInterval(5000);
- QObject::connect(m_subscriptionTimer, &QTimer::timeout,
- this, &Open62541AsyncBackend::updatePublishSubscriptionRequests);
- }
emit stateAndOrErrorChanged(QOpcUaClient::Connected, QOpcUaClient::NoError);
}
@@ -270,42 +359,58 @@ void Open62541AsyncBackend::disconnectFromEndpoint()
UA_Client_delete(m_uaclient);
m_uaclient = nullptr;
- m_subscriptionTimer->stop();
+ m_subscriptionTimer.stop();
emit stateAndOrErrorChanged(QOpcUaClient::Disconnected, QOpcUaClient::NoError);
}
-void Open62541AsyncBackend::updatePublishSubscriptionRequests() const
+void Open62541AsyncBackend::sendPublishRequest()
{
- if (m_uaclient)
- UA_Client_Subscriptions_manuallySendPublishRequest(m_uaclient);
+ if (!m_uaclient)
+ return;
+
+ if (!m_sendPublishRequests) {
+ return;
+ }
+
+ if (UA_Client_Subscriptions_manuallySendPublishRequest(m_uaclient) == UA_STATUSCODE_BADSERVERNOTCONNECTED) {
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541, "Unable to send publish request");
+ m_sendPublishRequests = false;
+ return;
+ }
+
+ m_subscriptionTimer.start(m_shortestInterval);
}
-void Open62541AsyncBackend::activateSubscriptionTimer(int timeout)
+void Open62541AsyncBackend::modifyPublishRequests()
{
- // ### TODO: Check all available subscriptions and their timeout value
- // Get minimum value
- if (timeout <= 0)
+ if (m_subscriptions.count() == 0) {
+ m_subscriptionTimer.stop();
+ m_sendPublishRequests = false;
+ m_shortestInterval = std::numeric_limits<qint32>::max();
return;
+ }
- m_subscriptionIntervals.insert(timeout);
+ for (auto it : qAsConst(m_subscriptions))
+ if (it->interval() < m_shortestInterval)
+ m_shortestInterval = it->interval();
- int minInterval = timeout;
- for (auto it : m_subscriptionIntervals) {
- if (it < minInterval)
- minInterval = it;
- }
- // Update subscriptionTimer timeout
- m_subscriptionTimer->setInterval(minInterval);
- // Start / Stop timer
- m_subscriptionTimer->start();
+ m_subscriptionTimer.stop();
+ m_sendPublishRequests = true;
+ sendPublishRequest();
}
-void Open62541AsyncBackend::removeSubscriptionTimer(int timeout)
+QOpen62541Subscription *Open62541AsyncBackend::getSubscriptionForItem(uintptr_t handle, QOpcUaNode::NodeAttribute attr)
{
- if (!m_subscriptionIntervals.remove(timeout))
- qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Trying to remove non-existent interval.";
- if (m_subscriptionIntervals.isEmpty())
- m_subscriptionTimer->stop();
+ auto nodeEntry = m_attributeMapping.find(handle);
+ if (nodeEntry == m_attributeMapping.end())
+ return nullptr;
+
+ auto subscription = nodeEntry->find(attr);
+ if (subscription == nodeEntry->end()) {
+ return nullptr;
+ }
+
+ return subscription.value();
}
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/open62541/qopen62541backend.h b/src/plugins/opcua/open62541/qopen62541backend.h
index 4445f90..d6e2a80 100644
--- a/src/plugins/opcua/open62541/qopen62541backend.h
+++ b/src/plugins/opcua/open62541/qopen62541backend.h
@@ -35,6 +35,7 @@
****************************************************************************/
#include "qopen62541client.h"
+#include "qopen62541subscription.h"
#include <private/qopcuabackend_p.h>
#include <QtCore/qset.h>
@@ -50,6 +51,7 @@ class Open62541AsyncBackend : public QOpcUaBackend
Q_OBJECT
public:
Open62541AsyncBackend(QOpen62541Client *parent);
+ ~Open62541AsyncBackend();
public Q_SLOTS:
void connectToEndpoint(const QUrl &url);
@@ -61,18 +63,31 @@ public Q_SLOTS:
void writeAttribute(uintptr_t handle, UA_NodeId id, QOpcUaNode::NodeAttribute attrId, QVariant value, QOpcUa::Types type);
void writeAttributes(uintptr_t handle, UA_NodeId id, QOpcUaNode::AttributeMap toWrite, QOpcUa::Types valueAttributeType);
+ void enableMonitoring(uintptr_t handle, UA_NodeId id, QOpcUaNode::NodeAttributes attr, const QOpcUaMonitoringParameters &settings);
+ void disableMonitoring(uintptr_t handle, QOpcUaNode::NodeAttributes attr);
+ void modifyMonitoring(uintptr_t handle, QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, QVariant value);
// Subscription
- UA_UInt32 createSubscription(int interval);
- void deleteSubscription(UA_UInt32 id);
- void updatePublishSubscriptionRequests() const;
- void activateSubscriptionTimer(int timeout);
- void removeSubscriptionTimer(int timeout);
+ QOpen62541Subscription *getSubscription(const QOpcUaMonitoringParameters &settings);
+ bool removeSubscription(UA_UInt32 subscriptionId);
+ void sendPublishRequest();
+ void modifyPublishRequests();
+
public:
- QOpen62541Client *m_clientImpl;
UA_Client *m_uaclient;
- QTimer *m_subscriptionTimer;
- QSet<int> m_subscriptionIntervals;
+
+private:
+ QOpen62541Subscription *getSubscriptionForItem(uintptr_t handle, QOpcUaNode::NodeAttribute attr);
+
+ QOpen62541Client *m_clientImpl;
+ QTimer m_subscriptionTimer;
+
+ QHash<quint32, QOpen62541Subscription *> m_subscriptions;
+
+ QHash<uintptr_t, QHash<QOpcUaNode::NodeAttribute, QOpen62541Subscription *>> m_attributeMapping; // Handle -> Attribute -> Subscription
+
+ bool m_sendPublishRequests;
+ qint32 m_shortestInterval;
};
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/open62541/qopen62541client.cpp b/src/plugins/opcua/open62541/qopen62541client.cpp
index bbf6467..63867e2 100644
--- a/src/plugins/opcua/open62541/qopen62541client.cpp
+++ b/src/plugins/opcua/open62541/qopen62541client.cpp
@@ -91,14 +91,6 @@ QOpcUaNode *QOpen62541Client::node(const QString &nodeId)
return new QOpcUaNode(new QOpen62541Node(uaNodeId, this, nodeId), m_client);
}
-QOpcUaSubscription *QOpen62541Client::createSubscription(quint32 interval)
-{
- QOpen62541Subscription *backendSubscription = new QOpen62541Subscription(m_backend, interval);
- QOpcUaSubscription *subscription = new QOpcUaSubscription(backendSubscription, interval);
- backendSubscription->m_qsubscription = subscription;
- return subscription;
-}
-
QString QOpen62541Client::backend() const
{
return QStringLiteral("open62541");
diff --git a/src/plugins/opcua/open62541/qopen62541client.h b/src/plugins/opcua/open62541/qopen62541client.h
index 7b605f3..3721d98 100644
--- a/src/plugins/opcua/open62541/qopen62541client.h
+++ b/src/plugins/opcua/open62541/qopen62541client.h
@@ -59,7 +59,6 @@ public:
void disconnectFromEndpoint() override;
QOpcUaNode *node(const QString &nodeId) override;
- QOpcUaSubscription *createSubscription(quint32 interval) override;
QString backend() const override;
diff --git a/src/plugins/opcua/open62541/qopen62541node.cpp b/src/plugins/opcua/open62541/qopen62541node.cpp
index 8634f65..d765784 100644
--- a/src/plugins/opcua/open62541/qopen62541node.cpp
+++ b/src/plugins/opcua/open62541/qopen62541node.cpp
@@ -72,6 +72,34 @@ bool QOpen62541Node::readAttributes(QOpcUaNode::NodeAttributes attr)
Q_ARG(QOpcUaNode::NodeAttributes, attr));
}
+bool QOpen62541Node::enableMonitoring(QOpcUaNode::NodeAttributes attr, const QOpcUaMonitoringParameters &settings)
+{
+ return QMetaObject::invokeMethod(m_client->m_backend, "enableMonitoring",
+ Qt::QueuedConnection,
+ Q_ARG(uintptr_t, reinterpret_cast<uintptr_t>(this)),
+ Q_ARG(UA_NodeId, m_nodeId),
+ Q_ARG(QOpcUaNode::NodeAttributes, attr),
+ Q_ARG(QOpcUaMonitoringParameters, settings));
+}
+
+bool QOpen62541Node::disableMonitoring(QOpcUaNode::NodeAttributes attr)
+{
+ return QMetaObject::invokeMethod(m_client->m_backend, "disableMonitoring",
+ Qt::QueuedConnection,
+ Q_ARG(uintptr_t, reinterpret_cast<uintptr_t>(this)),
+ Q_ARG(QOpcUaNode::NodeAttributes, attr));
+}
+
+bool QOpen62541Node::modifyMonitoring(QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, const QVariant &value)
+{
+ return QMetaObject::invokeMethod(m_client->m_backend, "modifyMonitoring",
+ Qt::QueuedConnection,
+ Q_ARG(uintptr_t, reinterpret_cast<uintptr_t>(this)),
+ Q_ARG(QOpcUaNode::NodeAttribute, attr),
+ Q_ARG(QOpcUaMonitoringParameters::Parameter, item),
+ Q_ARG(QVariant, value));
+}
+
QStringList QOpen62541Node::childrenIds() const
{
QStringList result = m_client->m_backend->childrenIds(&m_nodeId);
diff --git a/src/plugins/opcua/open62541/qopen62541node.h b/src/plugins/opcua/open62541/qopen62541node.h
index ef54618..95e794c 100644
--- a/src/plugins/opcua/open62541/qopen62541node.h
+++ b/src/plugins/opcua/open62541/qopen62541node.h
@@ -51,6 +51,9 @@ public:
~QOpen62541Node() override;
bool readAttributes(QOpcUaNode::NodeAttributes attr) override;
+ bool enableMonitoring(QOpcUaNode::NodeAttributes attr, const QOpcUaMonitoringParameters &settings);
+ bool disableMonitoring(QOpcUaNode::NodeAttributes attr);
+ bool modifyMonitoring(QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, const QVariant &value);
QStringList childrenIds() const override;
QString nodeId() const override;
diff --git a/src/plugins/opcua/open62541/qopen62541subscription.cpp b/src/plugins/opcua/open62541/qopen62541subscription.cpp
index 4f40d3c..8acc41d 100644
--- a/src/plugins/opcua/open62541/qopen62541subscription.cpp
+++ b/src/plugins/opcua/open62541/qopen62541subscription.cpp
@@ -39,7 +39,6 @@
#include "qopen62541node.h"
#include "qopen62541subscription.h"
#include "qopen62541valueconverter.h"
-#include <private/qopcuamonitoredvalue_p.h>
#include <private/qopcuanode_p.h>
#include <QtCore/qloggingcategory.h>
@@ -54,115 +53,273 @@ static void monitoredValueHandler(UA_UInt32 monId, UA_DataValue *value, void *co
subscription->monitoredValueUpdated(monId, value);
}
-QOpen62541Subscription::QOpen62541Subscription(Open62541AsyncBackend *backend, quint32 interval)
+QOpen62541Subscription::QOpen62541Subscription(Open62541AsyncBackend *backend, const QOpcUaMonitoringParameters &settings)
: m_backend(backend)
- , m_interval(interval)
+ , m_interval(settings.publishingInterval())
, m_subscriptionId(0)
+ , m_lifetimeCount(settings.lifetimeCount() ? settings.lifetimeCount() : UA_SubscriptionSettings_default.requestedLifetimeCount)
+ , m_maxKeepaliveCount(settings.maxKeepAliveCount() ? settings.maxKeepAliveCount() : UA_SubscriptionSettings_default.requestedMaxKeepAliveCount)
+ , m_shared(settings.shared())
+ , m_priority(settings.priority())
{
}
QOpen62541Subscription::~QOpen62541Subscription()
{
- removeNativeSubscription();
+ removeOnServer();
+ qDeleteAll(m_itemIdToItemMapping);
}
-QOpcUaMonitoredEvent *QOpen62541Subscription::addEvent(QOpcUaNode *node)
+UA_UInt32 QOpen62541Subscription::createOnServer()
{
- Q_UNUSED(node);
- Q_UNIMPLEMENTED();
- return nullptr;
+ UA_UInt32 subscriptionId = 0;
+ UA_SubscriptionSettings settings = UA_SubscriptionSettings_default;
+ settings.requestedPublishingInterval = m_interval;
+ settings.requestedLifetimeCount = m_lifetimeCount;
+ settings.requestedMaxKeepAliveCount = m_maxKeepaliveCount;
+ settings.priority = m_priority;
+ UA_StatusCode res = UA_Client_Subscriptions_new(m_backend->m_uaclient, settings, &subscriptionId);
+
+ if (res != UA_STATUSCODE_GOOD) {
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541, "Could not create subscription with interval %f: 0x%X", m_interval, res);
+ return 0;
+ }
+
+ m_subscriptionId = subscriptionId;
+ return subscriptionId;
}
-void QOpen62541Subscription::removeEvent(QOpcUaMonitoredEvent *event)
+bool QOpen62541Subscription::removeOnServer()
{
- Q_UNUSED(event);
- Q_UNIMPLEMENTED();
+ if (m_subscriptionId == 0)
+ return false;
+
+ UA_StatusCode res = UA_Client_Subscriptions_remove(m_backend->m_uaclient, m_subscriptionId);
+ m_subscriptionId = 0;
+
+ return (res == UA_STATUSCODE_GOOD) ? true : false;
}
-QOpcUaMonitoredValue *QOpen62541Subscription::addValue(QOpcUaNode *node)
+void QOpen62541Subscription::modifyMonitoring(uintptr_t handle, QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, QVariant value)
{
- if (!ensureNativeSubscription())
- return nullptr;
+ QOpcUaMonitoringParameters p;
+ p.setStatusCode(QOpcUa::UaStatusCode::BadNotImplemented);
+
+ if (!getItemForAttribute(handle, attr)) {
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541, "Could not modify parameter for %lu, there are no monitored items", handle);
+ p.setStatusCode(QOpcUa::UaStatusCode::BadAttributeIdInvalid);
+ emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ return;
+ }
- QOpen62541Node *open62541node = static_cast<QOpen62541Node *>(node->d_func()->m_impl.data());
+ // SetPublishingMode service
+ if (item == QOpcUaMonitoringParameters::Parameter::PublishingEnabled) {
+ emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ return;
+ }
+
+ // SetMonitoringMode service
+ if (item == QOpcUaMonitoringParameters::Parameter::MonitoringMode) {
+ emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ return;
+ }
+
+ // ModifySubscription service
+ {
+ UA_ModifySubscriptionRequest req;
+ UA_ModifySubscriptionRequest_init(&req);
+ req.subscriptionId = m_subscriptionId;
+ req.requestedPublishingInterval = m_interval;
+ req.requestedLifetimeCount = m_lifetimeCount;
+ req.requestedMaxKeepAliveCount = m_maxKeepaliveCount;
+
+ bool match = false;
+
+ switch (item) {
+ case QOpcUaMonitoringParameters::Parameter::PublishingInterval: {
+ bool ok;
+ req.requestedPublishingInterval = value.toDouble(&ok);
+ if (!ok) {
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541, "Could not modify PublishingInterval for %lu, value is not a double", handle);
+ p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
+ emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ return;
+ }
+ match = true;
+ break;
+ }
+ case QOpcUaMonitoringParameters::Parameter::LifetimeCount: {
+ bool ok;
+ req.requestedLifetimeCount = value.toUInt(&ok);
+ if (!ok) {
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541, "Could not modify LifetimeCount for %lu, value is not an integer", handle);
+ p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
+ emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ return;
+ }
+ match = true;
+ break;
+ }
+ case QOpcUaMonitoringParameters::Parameter::MaxKeepAliveCount: {
+ bool ok;
+ req.requestedMaxKeepAliveCount = value.toUInt(&ok);
+ if (!ok) {
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541, "Could not modify MaxKeepAliveCount for %lu, value is not an integer", handle);
+ p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
+ emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ return;
+ }
+ match = true;
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (match) {
+ UA_ModifySubscriptionResponse res = UA_Client_Service_modifySubscription(m_backend->m_uaclient, req);
+
+ if (res.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
+ p.setStatusCode(static_cast<QOpcUa::UaStatusCode>(res.responseHeader.serviceResult));
+ emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ } else {
+ p.setStatusCode(QOpcUa::UaStatusCode::Good);
+ p.setPublishingInterval(res.revisedPublishingInterval);
+ p.setLifetimeCount(res.revisedLifetimeCount);
+ p.setMaxKeepAliveCount(res.revisedMaxKeepAliveCount);
+
+ QOpcUaMonitoringParameters::Parameters changed = item;
+ if (!qFuzzyCompare(p.publishingInterval(), m_interval))
+ changed |= QOpcUaMonitoringParameters::Parameter::PublishingInterval;
+ if (p.lifetimeCount() != m_lifetimeCount)
+ changed |= QOpcUaMonitoringParameters::Parameter::LifetimeCount;
+ if (p.maxKeepAliveCount() != m_maxKeepaliveCount)
+ changed |= QOpcUaMonitoringParameters::Parameter::MaxKeepAliveCount;
+
+ for (auto it : qAsConst(m_itemIdToItemMapping))
+ emit m_backend->monitoringStatusChanged(it->handle, it->attr, changed, p);
+
+ m_lifetimeCount = res.revisedLifetimeCount;
+ m_maxKeepaliveCount = res.revisedMaxKeepAliveCount;
+ m_interval = res.revisedPublishingInterval;
+ }
+ return;
+ }
+ }
+
+ // ModifyMonitoredItems service
+ {
+ // TODO: Add support as soon as Open62541 supports this.
+ }
+
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Revising attribute is not implemented:" << item;
+ p.setStatusCode(QOpcUa::UaStatusCode::BadNotImplemented);
+ emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+}
+
+bool QOpen62541Subscription::addAttributeMonitoredItem(uintptr_t handle, QOpcUaNode::NodeAttribute attr, const UA_NodeId &id, QOpcUaMonitoringParameters settings)
+{
+ Q_UNUSED(settings); // This is for later applications like including parameters for the monitored item into settings
UA_UInt32 monitoredItemId = 0;
- UA_StatusCode ret = UA_Client_Subscriptions_addMonitoredItem(m_backend->m_uaclient, m_subscriptionId,
- open62541node->nativeNodeId(), UA_ATTRIBUTEID_VALUE,
+ UA_StatusCode ret = UA_Client_Subscriptions_addMonitoredItem(m_backend->m_uaclient, m_subscriptionId, id,
+ QOpen62541ValueConverter::toUaAttributeId(attr),
monitoredValueHandler, this, &monitoredItemId);
+
if (ret != UA_STATUSCODE_GOOD) {
- qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not add monitored item:" << ret;
- return nullptr;
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541, "Could not add monitored item to subscription %u: 0x%X", m_subscriptionId, ret);
+ QOpcUaMonitoringParameters s;
+ s.setStatusCode(static_cast<QOpcUa::UaStatusCode>(ret));
+ emit m_backend->monitoringEnableDisable(handle, attr, true, s);
+ return false;
}
- QOpcUaMonitoredValue *monitoredValue = new QOpcUaMonitoredValue(node, m_qsubscription);
- if (m_dataChangeHandles.contains(monitoredItemId)) {
- qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "monitoredItemId already handled:" << monitoredItemId;
- } else {
- m_dataChangeHandles[monitoredItemId] = monitoredValue;
- }
+ MonitoredItem *temp = new MonitoredItem(handle, attr, monitoredItemId);
+ m_handleToItemMapping[handle][attr] = temp;
+ m_itemIdToItemMapping[monitoredItemId] = temp;
- // Open62541 does not support automated subscriptions, hence we need to poll for the initial
- // value.
- UA_Client_Subscriptions_manuallySendPublishRequest(m_backend->m_uaclient);
- QMetaObject::invokeMethod(m_backend, "activateSubscriptionTimer", Qt::QueuedConnection, Q_ARG(int, m_interval));
+ QOpcUaMonitoringParameters s;
+ s.setSubscriptionId(m_subscriptionId);
+ s.setPublishingInterval(m_interval);
+ s.setMaxKeepAliveCount(m_maxKeepaliveCount);
+ s.setLifetimeCount(m_lifetimeCount);
+ s.setStatusCode(static_cast<QOpcUa::UaStatusCode>(ret));
+ s.setSamplingInterval(m_interval);
+ emit m_backend->monitoringEnableDisable(handle, attr, true, s);
- return monitoredValue;
+ return true;
}
-void QOpen62541Subscription::removeValue(QOpcUaMonitoredValue *monitoredValue)
+bool QOpen62541Subscription::removeAttributeMonitoredItem(uintptr_t handle, QOpcUaNode::NodeAttribute attr)
{
- auto it = m_dataChangeHandles.begin();
- while (it != m_dataChangeHandles.end()) {
- if (it.value() == monitoredValue) {
- UA_StatusCode ret = UA_Client_Subscriptions_removeMonitoredItem(m_backend->m_uaclient, m_subscriptionId, it.key());
- if (ret != UA_STATUSCODE_GOOD) {
- qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not remove monitored value from subscription:" << it.key();
- }
- m_dataChangeHandles.erase(it);
- QMetaObject::invokeMethod(m_backend, "removeSubscriptionTimer", Qt::QueuedConnection, Q_ARG(int, m_interval));
- break;
- }
- ++it;
+ MonitoredItem *item = getItemForAttribute(handle, attr);
+ if (!item) {
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541, "There is no monitored item for this attribute");
+ QOpcUaMonitoringParameters s;
+ s.setStatusCode(QOpcUa::UaStatusCode::BadMonitoredItemIdInvalid);
+ emit m_backend->monitoringEnableDisable(handle, attr, false, s);
+ return false;
}
+
+ UA_StatusCode res = UA_Client_Subscriptions_removeMonitoredItem(m_backend->m_uaclient, m_subscriptionId, item->monitoredItemId);
+ if (res != UA_STATUSCODE_GOOD)
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541, "Could not remove monitored item %u from subscription %u: 0x%X",
+ item->monitoredItemId, m_subscriptionId, res);
+
+ m_itemIdToItemMapping.remove(item->monitoredItemId);
+ auto it = m_handleToItemMapping.find(handle);
+ it->remove(attr);
+ if (it->empty())
+ m_handleToItemMapping.erase(it);
+
+ delete item;
+
+ QOpcUaMonitoringParameters s;
+ s.setStatusCode(static_cast<QOpcUa::UaStatusCode>(res));
+ emit m_backend->monitoringEnableDisable(handle, attr, false, s);
+
+ return true;
}
void QOpen62541Subscription::monitoredValueUpdated(UA_UInt32 monId, UA_DataValue *value)
{
- auto monitoredValue = m_dataChangeHandles.find(monId);
- if (monitoredValue == m_dataChangeHandles.end()) {
- qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not find object for monitoredItemId:" << monId;
+ auto item = m_itemIdToItemMapping.constFind(monId);
+ if (item == m_itemIdToItemMapping.constEnd())
return;
- }
+ emit m_backend->attributeUpdated(item.value()->handle, item.value()->attr, QOpen62541ValueConverter::toQVariant(value->value));
+}
- if (!value || !value->hasValue)
- return;
+double QOpen62541Subscription::interval() const
+{
+ return m_interval;
+}
- QVariant var = QOpen62541ValueConverter::toQVariant(value->value);
- if (var.isValid())
- (*monitoredValue)->d_func()->triggerValueChanged(var);
- else
- qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not convert value for node:" << (*monitoredValue)->node().nodeId();
+UA_UInt32 QOpen62541Subscription::subscriptionId() const
+{
+ return m_subscriptionId;
}
-bool QOpen62541Subscription::ensureNativeSubscription()
+int QOpen62541Subscription::monitoredItemsCount() const
{
- if (m_subscriptionId == 0) {
- QMetaObject::invokeMethod(m_backend, "createSubscription",
- Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(UA_UInt32, m_subscriptionId),
- Q_ARG(int, m_interval));
- }
- return m_subscriptionId != 0;
+ return m_itemIdToItemMapping.size();
}
-void QOpen62541Subscription::removeNativeSubscription()
+QOpcUaMonitoringParameters::SubscriptionType QOpen62541Subscription::shared() const
{
- if (m_subscriptionId != 0) {
- QMetaObject::invokeMethod(m_backend, "deleteSubscription",
- Qt::BlockingQueuedConnection,
- Q_ARG(UA_UInt32, m_subscriptionId));
- m_subscriptionId = 0;
- }
+ return m_shared;
+}
+
+QOpen62541Subscription::MonitoredItem *QOpen62541Subscription::getItemForAttribute(uintptr_t handle, QOpcUaNode::NodeAttribute attr)
+{
+ auto nodeEntry = m_handleToItemMapping.constFind(handle);
+
+ if (nodeEntry == m_handleToItemMapping.constEnd())
+ return nullptr;
+
+ auto item = nodeEntry->constFind(attr);
+ if (item == nodeEntry->constEnd())
+ return nullptr;
+
+ return item.value();
}
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/open62541/qopen62541subscription.h b/src/plugins/opcua/open62541/qopen62541subscription.h
index e527c7b..a75aa90 100644
--- a/src/plugins/opcua/open62541/qopen62541subscription.h
+++ b/src/plugins/opcua/open62541/qopen62541subscription.h
@@ -38,39 +38,63 @@
#define QOPEN62541SUBSCRIPTION_H
#include "qopen62541.h"
-#include <QtOpcUa/qopcuamonitoredevent.h>
-#include <QtOpcUa/qopcuamonitoredvalue.h>
-#include <private/qopcuasubscriptionimpl_p.h>
+#include <QtOpcUa/qopcuanode.h>
QT_BEGIN_NAMESPACE
class QOpen62541Client;
class Open62541AsyncBackend;
-class QOpen62541Subscription : public QOpcUaSubscriptionImpl
+class QOpen62541Subscription
{
public:
- explicit QOpen62541Subscription(Open62541AsyncBackend *backend, quint32 interval);
- ~QOpen62541Subscription() override;
+ QOpen62541Subscription(Open62541AsyncBackend *backend, const QOpcUaMonitoringParameters &settings);
+ ~QOpen62541Subscription();
- QOpcUaMonitoredEvent *addEvent(QOpcUaNode *node) override;
- void removeEvent(QOpcUaMonitoredEvent *event) override;
+ UA_UInt32 createOnServer();
+ bool removeOnServer();
- QOpcUaMonitoredValue *addValue(QOpcUaNode *node) override;
- void removeValue(QOpcUaMonitoredValue *v) override;
+ void modifyMonitoring(uintptr_t handle, QOpcUaNode::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, QVariant value);
+
+ bool addAttributeMonitoredItem(uintptr_t handle, QOpcUaNode::NodeAttribute attr, const UA_NodeId &id, QOpcUaMonitoringParameters settings);
+ bool removeAttributeMonitoredItem(uintptr_t handle, QOpcUaNode::NodeAttribute attr);
void monitoredValueUpdated(UA_UInt32 monId, UA_DataValue *value);
- QOpcUaSubscription *m_qsubscription;
+ struct MonitoredItem {
+ uintptr_t handle;
+ QOpcUaNode::NodeAttribute attr;
+ UA_UInt32 monitoredItemId;
+ MonitoredItem(uintptr_t h, QOpcUaNode::NodeAttribute a, UA_UInt32 id)
+ : handle(h)
+ , attr(a)
+ , monitoredItemId(id)
+ {}
+ MonitoredItem()
+ : handle(0)
+ , monitoredItemId(0)
+ {}
+ };
+
+ double interval() const;
+ UA_UInt32 subscriptionId() const;
+ int monitoredItemsCount() const;
+
+ QOpcUaMonitoringParameters::SubscriptionType shared() const;
private:
- bool ensureNativeSubscription();
- void removeNativeSubscription();
+ MonitoredItem *getItemForAttribute(uintptr_t handle, QOpcUaNode::NodeAttribute attr);
+
Open62541AsyncBackend *m_backend;
- quint32 m_interval;
+ double m_interval;
UA_UInt32 m_subscriptionId;
- QMap<UA_UInt32, QOpcUaMonitoredValue *> m_dataChangeHandles;
- QMap<UA_UInt32, QOpcUaMonitoredEvent *> m_eventHandles;
+ UA_UInt32 m_lifetimeCount;
+ UA_UInt32 m_maxKeepaliveCount;
+ QOpcUaMonitoringParameters::SubscriptionType m_shared;
+ quint8 m_priority;
+
+ QHash<uintptr_t, QHash<QOpcUaNode::NodeAttribute, MonitoredItem *>> m_handleToItemMapping; // Handle -> Attribute -> MonitoredItem
+ QHash<UA_UInt32, MonitoredItem *> m_itemIdToItemMapping; // ItemId -> Item for fast lookup on data change
};
QT_END_NAMESPACE
diff --git a/tests/auto/qopcuaclient/tst_client.cpp b/tests/auto/qopcuaclient/tst_client.cpp
index bd01c55..ad5e7eb 100644
--- a/tests/auto/qopcuaclient/tst_client.cpp
+++ b/tests/auto/qopcuaclient/tst_client.cpp
@@ -35,8 +35,6 @@
****************************************************************************/
#include <QtOpcUa/QOpcUaClient>
-#include <QtOpcUa/QOpcUaMonitoredEvent>
-#include <QtOpcUa/QOpcUaMonitoredValue>
#include <QtOpcUa/QOpcUaNode>
#include <QtOpcUa/QOpcUaProvider>
@@ -177,10 +175,6 @@ private slots:
void dataChangeSubscriptionInvalidNode();
defineDataMethod(methodCall_data)
void methodCall();
- defineDataMethod(eventSubscription_data)
- void eventSubscription();
- defineDataMethod(eventSubscribeInvalidNode_data)
- void eventSubscribeInvalidNode();
defineDataMethod(readRange_data)
void readRange();
defineDataMethod(readEui_data)
@@ -568,19 +562,132 @@ void Tst_QOpcUaClient::dataChangeSubscription()
READ_MANDATORY_VARIABLE_NODE(node);
QTRY_COMPARE(node->attribute(QOpcUaNode::NodeAttribute::Value), 0);
- QScopedPointer<QOpcUaSubscription> subscription(opcuaClient->createSubscription(100));
- QScopedPointer<QOpcUaMonitoredValue> monitoredValue(subscription->addValue(node.data()));
- QVERIFY(monitoredValue != nullptr);
- if (!monitoredValue)
- QFAIL("can not monitor value");
+ WRITE_VALUE_ATTRIBUTE(node, QVariant(double(0)), QOpcUa::Types::Double);
+
+ QSignalSpy dataChangeSpy(node.data(), &QOpcUaNode::attributeUpdated);
+ QSignalSpy monitoringEnabledSpy(node.data(), &QOpcUaNode::enableMonitoringFinished);
+
+ node->enableMonitoring(QOpcUaNode::NodeAttribute::Value, QOpcUaMonitoringParameters(100, QOpcUaMonitoringParameters::SubscriptionType::Exclusive));
+ monitoringEnabledSpy.wait();
- QSignalSpy valueSpy(monitoredValue.data(), &QOpcUaMonitoredValue::valueChanged);
+ QVERIFY(monitoringEnabledSpy.size() == 1);
+ QVERIFY(monitoringEnabledSpy.at(0).at(0).value<QOpcUaNode::NodeAttribute>() == QOpcUaNode::NodeAttribute::Value);
+ QVERIFY(node->monitoringStatus(QOpcUaNode::NodeAttribute::Value).statusCode() == 0);
+
+ QOpcUaMonitoringParameters valueStatus = node->monitoringStatus(QOpcUaNode::NodeAttribute::Value);
+ QVERIFY(valueStatus.subscriptionId() != 0);
+ QVERIFY(valueStatus.statusCode() == 0);
WRITE_VALUE_ATTRIBUTE(node, QVariant(double(42)), QOpcUa::Types::Double);
+ dataChangeSpy.wait();
+ if (dataChangeSpy.size() < 2)
+ dataChangeSpy.wait();
+
+ QVERIFY(dataChangeSpy.size() >= 1);
+
+ int index = dataChangeSpy.size() == 1 ? 0 : 1;
+ QVERIFY(dataChangeSpy.at(index).at(0).value<QOpcUaNode::NodeAttribute>() == QOpcUaNode::NodeAttribute::Value);
+ QVERIFY(dataChangeSpy.at(index).at(1) == double(42));
+
+ monitoringEnabledSpy.clear();
+ dataChangeSpy.clear();
+
+ node->enableMonitoring(QOpcUaNode::NodeAttribute::DisplayName, QOpcUaMonitoringParameters(100,QOpcUaMonitoringParameters::SubscriptionType::Exclusive,
+ valueStatus.subscriptionId()));
+ monitoringEnabledSpy.wait();
+
+ QVERIFY(monitoringEnabledSpy.size() == 1);
+ QVERIFY(monitoringEnabledSpy.at(0).at(0).value<QOpcUaNode::NodeAttribute>() == QOpcUaNode::NodeAttribute::DisplayName);
+ QVERIFY(node->monitoringStatus(QOpcUaNode::NodeAttribute::DisplayName).statusCode() == 0);
+
+ QOpcUaMonitoringParameters displayNameStatus = node->monitoringStatus(QOpcUaNode::NodeAttribute::DisplayName);
+ QVERIFY(displayNameStatus.subscriptionId() == valueStatus.subscriptionId());
+ QVERIFY(displayNameStatus.statusCode() == 0);
+
+ dataChangeSpy.wait();
+ QVERIFY(dataChangeSpy.size() == 1);
+ QVERIFY(dataChangeSpy.at(0).at(0).value<QOpcUaNode::NodeAttribute>() == QOpcUaNode::NodeAttribute::DisplayName);
+ QVERIFY(dataChangeSpy.at(0).at(1).value<QOpcUa::QLocalizedText>().text == QLatin1String("ns=3;s=TestNode.ReadWrite"));
+
+ monitoringEnabledSpy.clear();
+ dataChangeSpy.clear();
+ node->enableMonitoring(QOpcUaNode::NodeAttribute::NodeId, QOpcUaMonitoringParameters(100));
+ monitoringEnabledSpy.wait();
+ QVERIFY(monitoringEnabledSpy.size() == 1);
+ QVERIFY(monitoringEnabledSpy.at(0).at(0).value<QOpcUaNode::NodeAttribute>() == QOpcUaNode::NodeAttribute::NodeId);
+ QVERIFY(node->monitoringStatus(QOpcUaNode::NodeAttribute::NodeId).subscriptionId() != valueStatus.subscriptionId());
+ QVERIFY(node->monitoringStatus(QOpcUaNode::NodeAttribute::NodeId).statusCode() == 0);
- valueSpy.wait();
- QCOMPARE(valueSpy.count(), 1);
- QCOMPARE(valueSpy.at(0).at(0).toDouble(), double(42));
+ QOpcUaMonitoringParameters nodeIdStatus = node->monitoringStatus(QOpcUaNode::NodeAttribute::NodeId);
+ QVERIFY(nodeIdStatus.subscriptionId() != valueStatus.subscriptionId());
+ QVERIFY(nodeIdStatus.statusCode() == 0);
+
+ dataChangeSpy.wait();
+ QVERIFY(dataChangeSpy.size() == 1);
+ QVERIFY(dataChangeSpy.at(0).at(0).value<QOpcUaNode::NodeAttribute>() == QOpcUaNode::NodeAttribute::NodeId);
+ QVERIFY(dataChangeSpy.at(0).at(1) == QLatin1String("ns=3;s=TestNode.ReadWrite"));
+
+ QVector<QOpcUaNode::NodeAttribute> attrs;
+
+ if (opcuaClient->backend() == QLatin1String("open62541")) {
+ QSignalSpy monitoringModifiedSpy(node.data(), &QOpcUaNode::monitoringStatusChanged);
+ node->modifyMonitoring(QOpcUaNode::NodeAttribute::Value, QOpcUaMonitoringParameters::Parameter::PublishingInterval, 200);
+
+ monitoringModifiedSpy.wait();
+ if (monitoringModifiedSpy.size() < 2)
+ monitoringModifiedSpy.wait();
+
+ attrs = {QOpcUaNode::NodeAttribute::Value, QOpcUaNode::NodeAttribute::DisplayName};
+ for (auto it : qAsConst(monitoringModifiedSpy)) {
+ QOpcUaNode::NodeAttribute temp = it.at(0).value<QOpcUaNode::NodeAttribute>();
+ QVERIFY(attrs.contains(temp));
+ QVERIFY(it.at(1).value<QOpcUaMonitoringParameters::Parameters>() & QOpcUaMonitoringParameters::Parameter::PublishingInterval);
+ QVERIFY(it.at(2) == QOpcUa::UaStatusCode::Good);
+ QVERIFY(node->monitoringStatus(temp).publishingInterval() == double(200));
+ attrs.remove(attrs.indexOf(temp));
+ }
+ QVERIFY(attrs.size() == 0);
+
+ QVERIFY(node->monitoringStatus(QOpcUaNode::NodeAttribute::Value).publishingInterval() == 200);
+ QVERIFY(node->monitoringStatus(QOpcUaNode::NodeAttribute::DisplayName).publishingInterval() == 200);
+
+ monitoringModifiedSpy.clear();
+ QOpcUaMonitoringParameters::DataChangeFilter filter;
+ filter.deadbandType = QOpcUaMonitoringParameters::DataChangeFilter::DeadbandType::Absolute;
+ filter.trigger = QOpcUaMonitoringParameters::DataChangeFilter::DataChangeTrigger::StatusValue;
+ filter.deadbandValue = 10;
+ node->modifyMonitoring(QOpcUaNode::NodeAttribute::Value, QOpcUaMonitoringParameters::Parameter::Filter, QVariant::fromValue(filter));
+ monitoringModifiedSpy.wait();
+ QVERIFY(monitoringModifiedSpy.size() == 1);
+ QVERIFY(monitoringModifiedSpy.at(0).at(0).value<QOpcUaNode::NodeAttribute>() == QOpcUaNode::NodeAttribute::Value);
+ QVERIFY(monitoringModifiedSpy.at(0).at(1).value<QOpcUaMonitoringParameters::Parameters>() & QOpcUaMonitoringParameters::Parameter::Filter);
+ QEXPECT_FAIL("", "Modifying monitored items is not yet supported by open62541", Continue);
+ QVERIFY(monitoringModifiedSpy.at(0).at(2).value<QOpcUa::UaStatusCode>() == QOpcUa::UaStatusCode::Good);
+
+ } else {
+ qDebug() << "Modifying monitoring settings is not supported by the freeopcua backend";
+ }
+
+ QSignalSpy monitoringDisabledSpy(node.data(), &QOpcUaNode::disableMonitoringFinished);
+
+ node->disableMonitoring(QOpcUaNode::NodeAttribute::Value | QOpcUaNode::NodeAttribute::DisplayName | QOpcUaNode::NodeAttribute::NodeId);
+ monitoringDisabledSpy.wait();
+ if (monitoringDisabledSpy.size() < 2)
+ monitoringDisabledSpy.wait();
+ if (monitoringDisabledSpy.size() < 3)
+ monitoringDisabledSpy.wait();
+
+ QVERIFY(monitoringDisabledSpy.size() == 3);
+
+ attrs = {QOpcUaNode::NodeAttribute::Value, QOpcUaNode::NodeAttribute::DisplayName, QOpcUaNode::NodeAttribute::NodeId};
+ for (auto it : qAsConst(monitoringDisabledSpy)) {
+ QOpcUaNode::NodeAttribute temp = it.at(0).value<QOpcUaNode::NodeAttribute>();
+ QVERIFY(attrs.contains(temp));
+ QVERIFY(node->monitoringStatus(temp).subscriptionId() == 0);
+ QVERIFY(node->monitoringStatus(temp).statusCode() == QOpcUa::UaStatusCode::BadAttributeIdInvalid);
+ attrs.remove(attrs.indexOf(temp));
+ }
+ QVERIFY(attrs.size() == 0);
}
void Tst_QOpcUaClient::dataChangeSubscriptionInvalidNode()
@@ -589,10 +696,17 @@ void Tst_QOpcUaClient::dataChangeSubscriptionInvalidNode()
OpcuaConnector connector(opcuaClient, m_endpoint);
QScopedPointer<QOpcUaNode> noDataNode(opcuaClient->node("ns=0;i=84"));
- QVERIFY(noDataNode != 0);
- QScopedPointer<QOpcUaSubscription> subscription(opcuaClient->createSubscription(100));
- QOpcUaMonitoredValue *result = subscription->addValue(noDataNode.data());
- QVERIFY(result == 0);
+ QSignalSpy monitoringEnabledSpy(noDataNode.data(), &QOpcUaNode::enableMonitoringFinished);
+
+ QOpcUaMonitoringParameters settings;
+ settings.setPublishingInterval(100);
+ noDataNode->enableMonitoring(QOpcUaNode::NodeAttribute::Value, settings);
+ monitoringEnabledSpy.wait();
+
+ QVERIFY(monitoringEnabledSpy.size() == 1);
+ QVERIFY(monitoringEnabledSpy.at(0).at(0).value<QOpcUaNode::NodeAttribute>() == QOpcUaNode::NodeAttribute::Value);
+ QVERIFY(noDataNode->monitoringStatus(QOpcUaNode::NodeAttribute::Value).statusCode() == QOpcUa::UaStatusCode::BadAttributeIdInvalid);
+ QVERIFY(noDataNode->monitoringStatus(QOpcUaNode::NodeAttribute::Value).subscriptionId() == 0);
}
void Tst_QOpcUaClient::methodCall()
@@ -618,58 +732,6 @@ void Tst_QOpcUaClient::methodCall()
QVERIFY(ret[0].type() == QVariant::Double && ret[0].value<double>() == 16);
}
-void Tst_QOpcUaClient::eventSubscription()
-{
- QFETCH(QOpcUaClient *, opcuaClient);
- OpcuaConnector connector(opcuaClient, m_endpoint);
-
- QSKIP("Events are not implemented in the open62541-based testserver");
- if (opcuaClient->backend() == QLatin1String("freeopcua")) {
- QSKIP("Event subscriptions do not yet work with the freeopcua backend");
- }
- if (opcuaClient->backend() == QLatin1String("open62541")) {
- QSKIP("Event subscriptions do not yet work with the open62541 backend");
- }
-
- QScopedPointer<QOpcUaNode> triggerNode(opcuaClient->node("ns=3;s=TriggerNode"));
- QVERIFY(triggerNode != 0);
-
- QScopedPointer<QOpcUaSubscription> subscription(opcuaClient->createSubscription(100));
- QOpcUaMonitoredEvent *monitoredEvent = subscription->addEvent(triggerNode.data());
- QVERIFY(monitoredEvent != 0);
-
- if (!monitoredEvent)
- QFAIL("can not monitor event");
-
- QSignalSpy monitorSpy(monitoredEvent, &QOpcUaMonitoredEvent::newEvent);
-
- QScopedPointer<QOpcUaNode> triggerVariable(opcuaClient->node("ns=3;s=TriggerVariable"));
- QVERIFY(triggerVariable != 0);
- WRITE_VALUE_ATTRIBUTE(triggerVariable, QVariant(double(0)), QOpcUa::Types::Double);
- WRITE_VALUE_ATTRIBUTE(triggerVariable, QVariant(double(1)), QOpcUa::Types::Double);
-
- QVERIFY(monitorSpy.wait());
- QVector<QVariant> val = monitorSpy.at(0).at(0).toList().toVector();
- QCOMPARE(val.size(), 3);
- QCOMPARE(val.at(0).type(), QVariant::String);
- QCOMPARE(val.at(1).type(), QVariant::String);
- QCOMPARE(val.at(2).type(), QVariant::Int);
-
- delete monitoredEvent;
-}
-
-void Tst_QOpcUaClient::eventSubscribeInvalidNode()
-{
- QFETCH(QOpcUaClient *, opcuaClient);
- OpcuaConnector connector(opcuaClient, m_endpoint);
-
- QScopedPointer<QOpcUaNode> noEventNode(opcuaClient->node(readWriteNode));
- QVERIFY(noEventNode != 0);
- QScopedPointer<QOpcUaSubscription> subscription(opcuaClient->createSubscription(100));
- QOpcUaMonitoredEvent *monitoredEvent = subscription->addEvent(noEventNode.data());
- QVERIFY(monitoredEvent == 0);
-}
-
void Tst_QOpcUaClient::readRange()
{
QFETCH(QOpcUaClient *, opcuaClient);