summaryrefslogtreecommitdiffstats
path: root/src/plugins/opcua/freeopcua
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/opcua/freeopcua')
-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
8 files changed, 339 insertions, 150 deletions
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