summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJannis Voelker <jannis.voelker@basyskom.com>2018-02-09 11:10:00 +0100
committerFrank Meerkoetter <frank.meerkoetter@basyskom.com>2018-03-14 20:34:22 +0000
commitc62c6d518d14a0bc4d0ff1964253d7d7af9715e9 (patch)
treee122a5d25ae408254a768dd80e4d92ff0970e222
parent868a04b17c7d14e9339102b69128db4798d30898 (diff)
Add DataChangeFilter support to the open62541 backend
This patch enables the usage of deadband filters for data changes with the open62541 backend. The open62541 test server does not support data change filters, the test case is skipped. This patch has been tested using the Prosys simulation server. There is currently no filter support in freeopcua. Change-Id: I4f47780901fd75c97a858999fcc05b89e5cfda45 Reviewed-by: Frank Meerkoetter <frank.meerkoetter@basyskom.com>
-rw-r--r--src/opcua/client/qopcuamonitoringparameters.cpp13
-rw-r--r--src/opcua/client/qopcuamonitoringparameters.h1
-rw-r--r--src/plugins/opcua/open62541/qopen62541subscription.cpp26
-rw-r--r--src/plugins/opcua/open62541/qopen62541subscription.h1
-rw-r--r--tests/auto/qopcuaclient/tst_client.cpp61
5 files changed, 102 insertions, 0 deletions
diff --git a/src/opcua/client/qopcuamonitoringparameters.cpp b/src/opcua/client/qopcuamonitoringparameters.cpp
index cb0d17d..18e5433 100644
--- a/src/opcua/client/qopcuamonitoringparameters.cpp
+++ b/src/opcua/client/qopcuamonitoringparameters.cpp
@@ -485,7 +485,20 @@ QVariant QOpcUaMonitoringParameters::filter() const
}
/*!
+ Request \l DataChangeFilter \a filter as filter for the monitored item.
+ \sa setFilter()
+*/
+void QOpcUaMonitoringParameters::setDataChangeFilter(const QOpcUaMonitoringParameters::DataChangeFilter &filter)
+{
+ d_ptr->filter = QVariant::fromValue(filter);
+}
+
+/*!
Request \a filter as filter for for the monitored item.
+
+ For general use, the type-safe versions that are listed below are preferred.
+
+ \sa setDataChangeFilter()
*/
void QOpcUaMonitoringParameters::setFilter(const QVariant &filter)
{
diff --git a/src/opcua/client/qopcuamonitoringparameters.h b/src/opcua/client/qopcuamonitoringparameters.h
index 3a5f0e8..8a730de 100644
--- a/src/opcua/client/qopcuamonitoringparameters.h
+++ b/src/opcua/client/qopcuamonitoringparameters.h
@@ -117,6 +117,7 @@ public:
double samplingInterval() const;
void setSamplingInterval(double samplingInterval);
QVariant filter() const;
+ void setDataChangeFilter(const DataChangeFilter &filter);
void setFilter(const QVariant &filter);
quint32 queueSize() const;
void setQueueSize(quint32 queueSize);
diff --git a/src/plugins/opcua/open62541/qopen62541subscription.cpp b/src/plugins/opcua/open62541/qopen62541subscription.cpp
index 32ea564..8100610 100644
--- a/src/plugins/opcua/open62541/qopen62541subscription.cpp
+++ b/src/plugins/opcua/open62541/qopen62541subscription.cpp
@@ -242,6 +242,9 @@ bool QOpen62541Subscription::addAttributeMonitoredItem(uintptr_t handle, QOpcUa:
req.requestedParameters.queueSize = settings.queueSize() == 0 ? 1 : settings.queueSize();
req.requestedParameters.discardOldest = settings.discardOldest();
+ if (settings.filter().type() == QVariant::Type::UserType && settings.filter().userType() == QMetaType::type("QOpcUaMonitoringParameters::DataChangeFilter"))
+ req.requestedParameters.filter = createFilter(settings.filter());
+
UA_MonitoredItemCreateResult res = UA_Client_MonitoredItems_createDataChange(m_backend->m_uaclient, m_subscriptionId, UA_TIMESTAMPSTORETURN_BOTH, req, this, monitoredValueHandler, nullptr);
UA_MonitoredItemCreateRequest_deleteMembers(&req);
@@ -350,4 +353,27 @@ QOpen62541Subscription::MonitoredItem *QOpen62541Subscription::getItemForAttribu
return item.value();
}
+UA_ExtensionObject QOpen62541Subscription::createFilter(const QVariant &filterData)
+{
+ UA_ExtensionObject obj;
+ UA_ExtensionObject_init(&obj);
+
+ if (filterData.type() == QVariant::UserType && filterData.userType() == QMetaType::type("QOpcUaMonitoringParameters::DataChangeFilter")) {
+ QOpcUaMonitoringParameters::DataChangeFilter temp = filterData.value<QOpcUaMonitoringParameters::DataChangeFilter>();
+ UA_DataChangeFilter *filter = UA_DataChangeFilter_new();
+ filter->deadbandType = static_cast<UA_UInt32>(temp.deadbandType);
+ filter->deadbandValue = temp.deadbandValue;
+ filter->trigger = static_cast<UA_DataChangeTrigger>(temp.trigger);
+ obj.encoding = UA_EXTENSIONOBJECT_DECODED;
+ obj.content.decoded.type = &UA_TYPES[UA_TYPES_DATACHANGEFILTER];
+ obj.content.decoded.data = filter;
+ return obj;
+ }
+
+ if (filterData.isValid())
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not create filter, invalid input.";
+
+ return obj;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/open62541/qopen62541subscription.h b/src/plugins/opcua/open62541/qopen62541subscription.h
index b400cd5..2f03a66 100644
--- a/src/plugins/opcua/open62541/qopen62541subscription.h
+++ b/src/plugins/opcua/open62541/qopen62541subscription.h
@@ -83,6 +83,7 @@ public:
private:
MonitoredItem *getItemForAttribute(uintptr_t handle, QOpcUa::NodeAttribute attr);
+ UA_ExtensionObject createFilter(const QVariant &filterData);
Open62541AsyncBackend *m_backend;
double m_interval;
diff --git a/tests/auto/qopcuaclient/tst_client.cpp b/tests/auto/qopcuaclient/tst_client.cpp
index ae736e8..3026f28 100644
--- a/tests/auto/qopcuaclient/tst_client.cpp
+++ b/tests/auto/qopcuaclient/tst_client.cpp
@@ -229,6 +229,8 @@ private slots:
void invalidIndexRange();
defineDataMethod(subscriptionIndexRange_data)
void subscriptionIndexRange();
+ defineDataMethod(subscriptionDataChangeFilter_data)
+ void subscriptionDataChangeFilter();
defineDataMethod(stringCharset_data)
void stringCharset();
@@ -1848,6 +1850,65 @@ void Tst_QOpcUaClient::subscriptionIndexRange()
QCOMPARE(monitoringDisabledSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
}
+void Tst_QOpcUaClient::subscriptionDataChangeFilter()
+{
+ QFETCH(QOpcUaClient *, opcuaClient);
+ OpcuaConnector connector(opcuaClient, m_endpoint);
+
+ QSKIP("DataChangeFilter is not supported by the open62541 test server");
+ // To run this test case, change the url for connector to the URL of a Prosys simulation server
+ // and use ns=3;s=Double as node id for doubleNode.
+
+ if (opcuaClient->backend() == QLatin1String("freeopcua"))
+ QSKIP("DataChangeFilter support is not implemented in the freeopcua plugin");
+ if (opcuaClient->backend() == QLatin1String("uacpp"))
+ QSKIP("DataChangeFilter support is not implemented in the unified automation plugin");
+
+
+ QScopedPointer<QOpcUaNode> doubleNode(opcuaClient->node("ns=2;s=Demo.Static.Scalar.Double"));
+ QVERIFY(doubleNode != 0);
+
+ QOpcUaMonitoringParameters p(100);
+ QOpcUaMonitoringParameters::DataChangeFilter filter;
+ filter.deadbandType = QOpcUaMonitoringParameters::DataChangeFilter::DeadbandType::Absolute;
+ filter.trigger = QOpcUaMonitoringParameters::DataChangeFilter::DataChangeTrigger::StatusValue;
+ filter.deadbandValue = 1.0;
+ p.setDataChangeFilter(filter);
+
+ QSignalSpy monitoringEnabledSpy(doubleNode.data(), &QOpcUaNode::enableMonitoringFinished);
+ QSignalSpy monitoringDisabledSpy(doubleNode.data(), &QOpcUaNode::disableMonitoringFinished);
+ QSignalSpy dataChangeSpy(doubleNode.data(), &QOpcUaNode::attributeUpdated);
+
+ WRITE_VALUE_ATTRIBUTE(doubleNode, 1.0, QOpcUa::Types::Double);
+
+ doubleNode->enableMonitoring(QOpcUa::NodeAttribute::Value, p);
+ monitoringEnabledSpy.wait();
+ QCOMPARE(monitoringEnabledSpy.size(), 1);
+ QCOMPARE(monitoringEnabledSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value);
+ QCOMPARE(monitoringEnabledSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+
+ dataChangeSpy.wait(); // Wait for the initial data change
+ QCOMPARE(dataChangeSpy.size(), 1);
+ dataChangeSpy.clear();
+
+ WRITE_VALUE_ATTRIBUTE(doubleNode, 1.5, QOpcUa::Types::Double);
+
+ dataChangeSpy.wait();
+ QCOMPARE(dataChangeSpy.size(), 0);
+
+ WRITE_VALUE_ATTRIBUTE(doubleNode, 3.0, QOpcUa::Types::Double);
+
+ dataChangeSpy.wait();
+ QCOMPARE(dataChangeSpy.size(), 1);
+ QCOMPARE(doubleNode->attribute(QOpcUa::NodeAttribute::Value), 3.0);
+
+ doubleNode->disableMonitoring(QOpcUa::NodeAttribute::Value);
+ monitoringDisabledSpy.wait();
+ QCOMPARE(monitoringDisabledSpy.size(), 1);
+ QCOMPARE(monitoringDisabledSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value);
+ QCOMPARE(monitoringDisabledSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+}
+
void Tst_QOpcUaClient::stringCharset()
{
QFETCH(QOpcUaClient *, opcuaClient);