diff options
Diffstat (limited to 'src/plugins/opcua/freeopcua')
-rw-r--r-- | src/plugins/opcua/freeopcua/qfreeopcuaclient.cpp | 11 | ||||
-rw-r--r-- | src/plugins/opcua/freeopcua/qfreeopcuaclient.h | 2 | ||||
-rw-r--r-- | src/plugins/opcua/freeopcua/qfreeopcuanode.cpp | 30 | ||||
-rw-r--r-- | src/plugins/opcua/freeopcua/qfreeopcuanode.h | 5 | ||||
-rw-r--r-- | src/plugins/opcua/freeopcua/qfreeopcuasubscription.cpp | 247 | ||||
-rw-r--r-- | src/plugins/opcua/freeopcua/qfreeopcuasubscription.h | 59 | ||||
-rw-r--r-- | src/plugins/opcua/freeopcua/qfreeopcuaworker.cpp | 117 | ||||
-rw-r--r-- | src/plugins/opcua/freeopcua/qfreeopcuaworker.h | 18 |
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 |