summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/opcua/freeopcua/qfreeopcuaworker.cpp22
-rw-r--r--src/plugins/opcua/freeopcua/qfreeopcuaworker.h3
-rw-r--r--src/plugins/opcua/open62541/qopen62541backend.cpp28
-rw-r--r--src/plugins/opcua/open62541/qopen62541backend.h3
-rw-r--r--src/plugins/opcua/uacpp/quacppbackend.cpp8
-rw-r--r--src/plugins/opcua/uacpp/quacppbackend.h1
6 files changed, 52 insertions, 13 deletions
diff --git a/src/plugins/opcua/freeopcua/qfreeopcuaworker.cpp b/src/plugins/opcua/freeopcua/qfreeopcuaworker.cpp
index 3acdf8b..75a4692 100644
--- a/src/plugins/opcua/freeopcua/qfreeopcuaworker.cpp
+++ b/src/plugins/opcua/freeopcua/qfreeopcuaworker.cpp
@@ -52,15 +52,18 @@ Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_FREEOPCUA)
QFreeOpcUaWorker::QFreeOpcUaWorker(QFreeOpcUaClientImpl *client)
: QOpcUaBackend()
, m_client(client)
+ , m_minPublishingInterval(0)
{}
QFreeOpcUaWorker::~QFreeOpcUaWorker()
{
- qDeleteAll(m_subscriptions);
+ cleanupSubscriptions();
}
void QFreeOpcUaWorker::asyncConnectToEndpoint(const QUrl &url)
{
+ cleanupSubscriptions();
+
try {
QString sNodeName = QHostInfo::localHostName();
SetApplicationURI(QString("urn:%1:%2:%3").arg(
@@ -102,8 +105,7 @@ void QFreeOpcUaWorker::asyncDisconnectFromEndpoint()
qCWarning(QT_OPCUA_PLUGINS_FREEOPCUA) << "Could not disconnect from endpoint:" << ex.what();
}
- qDeleteAll(m_subscriptions);
- m_subscriptions.clear();
+ cleanupSubscriptions();
emit stateAndOrErrorChanged(QOpcUaClient::Disconnected, QOpcUaClient::UnknownError);
}
@@ -258,8 +260,10 @@ void QFreeOpcUaWorker::writeAttributes(uintptr_t handle, OpcUa::Node node, QOpcU
QFreeOpcUaSubscription *QFreeOpcUaWorker::getSubscription(const QOpcUaMonitoringParameters &settings)
{
if (settings.shared() == QOpcUaMonitoringParameters::SubscriptionType::Shared) {
+ // Requesting multiple subscriptions with publishing interval < minimum publishing interval breaks subscription sharing
+ double interval = revisePublishingInterval(settings.publishingInterval(), m_minPublishingInterval);
for (auto entry : qAsConst(m_subscriptions))
- if (entry->interval() == settings.publishingInterval() && entry->shared() == QOpcUaMonitoringParameters::SubscriptionType::Shared)
+ if (qFuzzyCompare(entry->interval(), interval) && entry->shared() == QOpcUaMonitoringParameters::SubscriptionType::Shared)
return entry;
}
@@ -269,6 +273,8 @@ QFreeOpcUaSubscription *QFreeOpcUaWorker::getSubscription(const QOpcUaMonitoring
delete sub;
return nullptr;
}
+ if (sub->interval() > settings.samplingInterval()) // The publishing interval has been revised by the server.
+ m_minPublishingInterval = sub->interval();
QObject::connect(sub, &QFreeOpcUaSubscription::timeout, this, &QFreeOpcUaWorker::handleSubscriptionTimeout, Qt::QueuedConnection);
m_subscriptions[id] = sub;
return sub;
@@ -373,6 +379,14 @@ QFreeOpcUaSubscription *QFreeOpcUaWorker::getSubscriptionForItem(uintptr_t handl
return subscription.value();
}
+void QFreeOpcUaWorker::cleanupSubscriptions()
+{
+ qDeleteAll(m_subscriptions);
+ m_subscriptions.clear();
+ m_attributeMapping.clear();
+ m_minPublishingInterval = 0;
+}
+
void QFreeOpcUaWorker::callMethod(uintptr_t handle, OpcUa::NodeId objectId, OpcUa::NodeId methodId, QVector<QOpcUa::TypedVariant> args)
{
try {
diff --git a/src/plugins/opcua/freeopcua/qfreeopcuaworker.h b/src/plugins/opcua/freeopcua/qfreeopcuaworker.h
index c3edb7d..e65ca81 100644
--- a/src/plugins/opcua/freeopcua/qfreeopcuaworker.h
+++ b/src/plugins/opcua/freeopcua/qfreeopcuaworker.h
@@ -77,11 +77,14 @@ public slots:
void handleSubscriptionTimeout(QFreeOpcUaSubscription *sub, QVector<QPair<uintptr_t, QOpcUa::NodeAttribute>> items);
private:
QFreeOpcUaSubscription *getSubscriptionForItem(uintptr_t handle, QOpcUa::NodeAttribute attr);
+ void cleanupSubscriptions();
QFreeOpcUaClientImpl *m_client;
QHash<quint32, QFreeOpcUaSubscription *> m_subscriptions;
QHash<uintptr_t, QHash<QOpcUa::NodeAttribute, QFreeOpcUaSubscription *>> m_attributeMapping; // Handle -> Attribute -> Subscription
+
+ double m_minPublishingInterval;
};
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/open62541/qopen62541backend.cpp b/src/plugins/opcua/open62541/qopen62541backend.cpp
index 15d1166..93a568a 100644
--- a/src/plugins/opcua/open62541/qopen62541backend.cpp
+++ b/src/plugins/opcua/open62541/qopen62541backend.cpp
@@ -66,6 +66,7 @@ Open62541AsyncBackend::Open62541AsyncBackend(QOpen62541Client *parent)
, m_useStateCallback(false)
, m_subscriptionTimer(this)
, m_sendPublishRequests(false)
+ , m_minPublishingInterval(0)
{
m_subscriptionTimer.setSingleShot(true);
QObject::connect(&m_subscriptionTimer, &QTimer::timeout,
@@ -74,7 +75,7 @@ Open62541AsyncBackend::Open62541AsyncBackend(QOpen62541Client *parent)
Open62541AsyncBackend::~Open62541AsyncBackend()
{
- qDeleteAll(m_subscriptions);
+ cleanupSubscriptions();
if (m_uaclient)
UA_Client_delete(m_uaclient);
}
@@ -280,8 +281,10 @@ void Open62541AsyncBackend::modifyMonitoring(uintptr_t handle, QOpcUa::NodeAttri
QOpen62541Subscription *Open62541AsyncBackend::getSubscription(const QOpcUaMonitoringParameters &settings)
{
if (settings.shared() == QOpcUaMonitoringParameters::SubscriptionType::Shared) {
+ // Requesting multiple subscriptions with publishing interval < minimum publishing interval breaks subscription sharing
+ double interval = revisePublishingInterval(settings.publishingInterval(), m_minPublishingInterval);
for (auto entry : qAsConst(m_subscriptions)) {
- if (qFuzzyCompare(entry->interval(), settings.publishingInterval()) && entry->shared() == QOpcUaMonitoringParameters::SubscriptionType::Shared)
+ if (qFuzzyCompare(entry->interval(), interval) && entry->shared() == QOpcUaMonitoringParameters::SubscriptionType::Shared)
return entry;
}
}
@@ -293,6 +296,8 @@ QOpen62541Subscription *Open62541AsyncBackend::getSubscription(const QOpcUaMonit
return nullptr;
}
m_subscriptions[id] = sub;
+ if (sub->interval() > settings.samplingInterval()) // The publishing interval has been revised by the server.
+ m_minPublishingInterval = sub->interval();
// This must be a queued connection to prevent the slot from being called while the client is inside UA_Client_runAsync().
QObject::connect(sub, &QOpen62541Subscription::timeout, this, &Open62541AsyncBackend::handleSubscriptionTimeout, Qt::QueuedConnection);
return sub;
@@ -429,11 +434,14 @@ static void clientStateCallback(UA_Client *client, UA_ClientState state)
if (state == UA_CLIENTSTATE_DISCONNECTED) {
emit backend->stateAndOrErrorChanged(QOpcUaClient::Disconnected, QOpcUaClient::ConnectionError);
backend->m_useStateCallback = false;
+ backend->cleanupSubscriptions();
}
}
void Open62541AsyncBackend::connectToEndpoint(const QUrl &url)
{
+ cleanupSubscriptions();
+
if (m_uaclient)
UA_Client_delete(m_uaclient);
@@ -468,9 +476,7 @@ void Open62541AsyncBackend::connectToEndpoint(const QUrl &url)
void Open62541AsyncBackend::disconnectFromEndpoint()
{
m_subscriptionTimer.stop();
- qDeleteAll(m_subscriptions);
- m_subscriptions.clear();
- m_attributeMapping.clear();
+ cleanupSubscriptions();
m_useStateCallback = false;
@@ -500,9 +506,7 @@ void Open62541AsyncBackend::sendPublishRequest()
if (UA_Client_runAsync(m_uaclient, 1) == UA_STATUSCODE_BADSERVERNOTCONNECTED) {
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Unable to send publish request";
m_sendPublishRequests = false;
- qDeleteAll(m_subscriptions);
- m_subscriptions.clear();
- m_attributeMapping.clear();
+ cleanupSubscriptions();
return;
}
@@ -549,4 +553,12 @@ QOpen62541Subscription *Open62541AsyncBackend::getSubscriptionForItem(uintptr_t
return subscription.value();
}
+void Open62541AsyncBackend::cleanupSubscriptions()
+{
+ qDeleteAll(m_subscriptions);
+ m_subscriptions.clear();
+ m_attributeMapping.clear();
+ m_minPublishingInterval = 0;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/open62541/qopen62541backend.h b/src/plugins/opcua/open62541/qopen62541backend.h
index d5d6743..3a4c1fa 100644
--- a/src/plugins/opcua/open62541/qopen62541backend.h
+++ b/src/plugins/opcua/open62541/qopen62541backend.h
@@ -72,6 +72,7 @@ public Q_SLOTS:
void sendPublishRequest();
void modifyPublishRequests();
void handleSubscriptionTimeout(QOpen62541Subscription *sub, QVector<QPair<uintptr_t, QOpcUa::NodeAttribute>> items);
+ void cleanupSubscriptions();
public:
UA_Client *m_uaclient;
@@ -88,6 +89,8 @@ private:
QHash<uintptr_t, QHash<QOpcUa::NodeAttribute, QOpen62541Subscription *>> m_attributeMapping; // Handle -> Attribute -> Subscription
bool m_sendPublishRequests;
+
+ double m_minPublishingInterval;
};
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/uacpp/quacppbackend.cpp b/src/plugins/opcua/uacpp/quacppbackend.cpp
index e85150d..52ad6a5 100644
--- a/src/plugins/opcua/uacpp/quacppbackend.cpp
+++ b/src/plugins/opcua/uacpp/quacppbackend.cpp
@@ -57,6 +57,7 @@ Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_UACPP)
UACppAsyncBackend::UACppAsyncBackend(QUACppClient *parent)
: QOpcUaBackend()
, m_clientImpl(parent)
+ , m_minPublishingInterval(0)
{
QMutexLocker locker(&m_lifecycleMutex);
if (!m_platformLayerInitialized) {
@@ -456,8 +457,10 @@ void UACppAsyncBackend::callMethod(uintptr_t handle, const UaNodeId &objectId, c
QUACppSubscription *UACppAsyncBackend::getSubscription(const QOpcUaMonitoringParameters &settings)
{
if (settings.shared() == QOpcUaMonitoringParameters::SubscriptionType::Shared) {
+ // Requesting multiple subscriptions with publishing interval < minimum publishing interval breaks subscription sharing
+ double interval = revisePublishingInterval(settings.publishingInterval(), m_minPublishingInterval);
for (auto entry : qAsConst(m_subscriptions)) {
- if (qFuzzyCompare(entry->interval(), settings.publishingInterval()) && entry->shared() == QOpcUaMonitoringParameters::SubscriptionType::Shared)
+ if (qFuzzyCompare(entry->interval(), interval) && entry->shared() == QOpcUaMonitoringParameters::SubscriptionType::Shared)
return entry;
}
}
@@ -468,6 +471,8 @@ QUACppSubscription *UACppAsyncBackend::getSubscription(const QOpcUaMonitoringPar
delete sub;
return nullptr;
}
+ if (sub->interval() > settings.samplingInterval()) // The publishing interval has been revised by the server.
+ m_minPublishingInterval = sub->interval();
m_subscriptions[id] = sub;
return sub;
}
@@ -489,6 +494,7 @@ void UACppAsyncBackend::cleanupSubscriptions()
qDeleteAll(m_subscriptions);
m_subscriptions.clear();
m_attributeMapping.clear();
+ m_minPublishingInterval = 0;
}
bool UACppAsyncBackend::removeSubscription(quint32 subscriptionId)
diff --git a/src/plugins/opcua/uacpp/quacppbackend.h b/src/plugins/opcua/uacpp/quacppbackend.h
index 07ac784..a96db60 100644
--- a/src/plugins/opcua/uacpp/quacppbackend.h
+++ b/src/plugins/opcua/uacpp/quacppbackend.h
@@ -75,6 +75,7 @@ public:
static quint32 m_numClients;
static bool m_platformLayerInitialized;
QMutex m_lifecycleMutex;
+ double m_minPublishingInterval;
};
QT_END_NAMESPACE