summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJannis Voelker <jannis.voelker@basyskom.com>2018-02-06 14:48:23 +0100
committerJannis Völker <jannis.voelker@basyskom.com>2018-02-28 07:19:38 +0000
commit600ba0dcc3cd731fb55491f81ed533de9f7fb106 (patch)
tree4e3ad9c5c2debaa1fa3152c0e96dba14b38e0c50
parentf6ecf08115f6615b058cc7800246d5dc6dd54704 (diff)
Unify support for indexRange in monitored items in both backends
This patch adds support for indexRange to the open62541 backend and fixes the return value for arrays with just one element in the freeopcua backend. A test case checking for correct use of the index range is added to tst_client. Change-Id: I94862e48c1fe3380ce5208738d025a9d53720354 Reviewed-by: Alex Blasche <alexander.blasche@qt.io> Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io> Reviewed-by: Frank Meerkoetter <frank.meerkoetter@basyskom.com>
-rw-r--r--src/plugins/opcua/freeopcua/qfreeopcuavalueconverter.cpp5
-rw-r--r--src/plugins/opcua/open62541/qopen62541subscription.cpp40
-rw-r--r--tests/auto/qopcuaclient/tst_client.cpp54
3 files changed, 83 insertions, 16 deletions
diff --git a/src/plugins/opcua/freeopcua/qfreeopcuavalueconverter.cpp b/src/plugins/opcua/freeopcua/qfreeopcuavalueconverter.cpp
index 0dbde36..5d488c1 100644
--- a/src/plugins/opcua/freeopcua/qfreeopcuavalueconverter.cpp
+++ b/src/plugins/opcua/freeopcua/qfreeopcuavalueconverter.cpp
@@ -335,7 +335,10 @@ QVariant arrayToQVariant(const OpcUa::Variant &var, QMetaType::Type type)
else
list.append(QVariant(type, &data));
}
- return list;
+ if (list.size() == 1)
+ return list.at(0);
+ else
+ return list;
} else if (var.IsScalar()) {
QTTYPE data = scalarUaToQt<QTTYPE, UATYPE>(var.As<UATYPE>());
diff --git a/src/plugins/opcua/open62541/qopen62541subscription.cpp b/src/plugins/opcua/open62541/qopen62541subscription.cpp
index cfe6d91..175a4ea 100644
--- a/src/plugins/opcua/open62541/qopen62541subscription.cpp
+++ b/src/plugins/opcua/open62541/qopen62541subscription.cpp
@@ -47,10 +47,12 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_OPEN62541)
-static void monitoredValueHandler(UA_Client *client, UA_UInt32 monId, UA_DataValue *value, void *context)
+static void monitoredValueHandler(UA_Client *client, UA_UInt32 subId, void *subContext, UA_UInt32 monId, void *monContext, UA_DataValue *value)
{
Q_UNUSED(client)
- QOpen62541Subscription *subscription = static_cast<QOpen62541Subscription *>(context);
+ Q_UNUSED(subId)
+ Q_UNUSED(subContext)
+ QOpen62541Subscription *subscription = static_cast<QOpen62541Subscription *>(monContext);
subscription->monitoredValueUpdated(monId, value);
}
@@ -229,31 +231,39 @@ void QOpen62541Subscription::modifyMonitoring(uintptr_t handle, QOpcUa::NodeAttr
bool QOpen62541Subscription::addAttributeMonitoredItem(uintptr_t handle, QOpcUa::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, id,
- QOpen62541ValueConverter::toUaAttributeId(attr),
- monitoredValueHandler, this, &monitoredItemId,
- qFuzzyCompare(settings.samplingInterval(), 0.0) ? m_interval : settings.samplingInterval());
-
- if (ret != UA_STATUSCODE_GOOD) {
- qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not add monitored item to subscription" << m_subscriptionId << ":" << UA_StatusCode_name(ret);
+ UA_MonitoredItemCreateRequest req;
+ UA_MonitoredItemCreateRequest_init(&req);
+ req.itemToMonitor.attributeId = QOpen62541ValueConverter::toUaAttributeId(attr);
+ UA_NodeId_copy(&id, &(req.itemToMonitor.nodeId));
+ if (settings.indexRange().size())
+ req.itemToMonitor.indexRange = UA_STRING_ALLOC(settings.indexRange().toUtf8().data());
+ req.monitoringMode = static_cast<UA_MonitoringMode>(settings.monitoringMode());
+ req.requestedParameters.samplingInterval = qFuzzyCompare(settings.samplingInterval(), 0.0) ? m_interval : settings.samplingInterval();
+ req.requestedParameters.queueSize = settings.queueSize() == 0 ? 1 : settings.queueSize();
+ req.requestedParameters.discardOldest = settings.discardOldest();
+
+ UA_MonitoredItemCreateResult res = UA_Client_MonitoredItems_createDataChange(m_backend->m_uaclient, m_subscriptionId, UA_TIMESTAMPSTORETURN_BOTH, req, this, monitoredValueHandler, nullptr);
+
+ UA_MonitoredItemCreateRequest_deleteMembers(&req);
+
+ if (res.statusCode != UA_STATUSCODE_GOOD) {
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not add monitored item to subscription" << m_subscriptionId << ":" << UA_StatusCode_name(res.statusCode);
QOpcUaMonitoringParameters s;
- s.setStatusCode(static_cast<QOpcUa::UaStatusCode>(ret));
+ s.setStatusCode(static_cast<QOpcUa::UaStatusCode>(res.statusCode));
emit m_backend->monitoringEnableDisable(handle, attr, true, s);
return false;
}
- MonitoredItem *temp = new MonitoredItem(handle, attr, monitoredItemId);
+ MonitoredItem *temp = new MonitoredItem(handle, attr, res.monitoredItemId);
m_handleToItemMapping[handle][attr] = temp;
- m_itemIdToItemMapping[monitoredItemId] = temp;
+ m_itemIdToItemMapping[res.monitoredItemId] = temp;
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.setStatusCode(QOpcUa::UaStatusCode::Good);
s.setSamplingInterval(m_interval);
emit m_backend->monitoringEnableDisable(handle, attr, true, s);
diff --git a/tests/auto/qopcuaclient/tst_client.cpp b/tests/auto/qopcuaclient/tst_client.cpp
index 732cb06..486a5dc 100644
--- a/tests/auto/qopcuaclient/tst_client.cpp
+++ b/tests/auto/qopcuaclient/tst_client.cpp
@@ -226,6 +226,8 @@ private slots:
void indexRange();
defineDataMethod(invalidIndexRange_data)
void invalidIndexRange();
+ defineDataMethod(subscriptionIndexRange_data)
+ void subscriptionIndexRange();
defineDataMethod(stringCharset_data)
void stringCharset();
@@ -1788,6 +1790,58 @@ void Tst_QOpcUaClient::invalidIndexRange()
QCOMPARE(node->attributeError(QOpcUa::NodeAttribute::Value), QOpcUa::UaStatusCode::BadIndexRangeInvalid);
}
+void Tst_QOpcUaClient::subscriptionIndexRange()
+{
+ QFETCH(QOpcUaClient *, opcuaClient);
+ OpcuaConnector connector(opcuaClient, m_endpoint);
+
+ QScopedPointer<QOpcUaNode> integerArrayNode(opcuaClient->node("ns=2;s=Demo.Static.Arrays.Int32"));
+ QVERIFY(integerArrayNode != 0);
+
+ QOpcUaMonitoringParameters p(100);
+ p.setIndexRange(QStringLiteral("1"));
+ QSignalSpy monitoringEnabledSpy(integerArrayNode.data(), &QOpcUaNode::enableMonitoringFinished);
+ QSignalSpy monitoringDisabledSpy(integerArrayNode.data(), &QOpcUaNode::disableMonitoringFinished);
+ QSignalSpy writeSpy(integerArrayNode.data(), &QOpcUaNode::attributeWritten);
+ QSignalSpy dataChangeSpy(integerArrayNode.data(), &QOpcUaNode::attributeUpdated);
+
+ QVariantList l({0, 1});
+ WRITE_VALUE_ATTRIBUTE(integerArrayNode, l, QOpcUa::Types::Int32);
+ writeSpy.clear();
+
+ integerArrayNode->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
+ dataChangeSpy.clear();
+ integerArrayNode->writeAttributeRange(QOpcUa::NodeAttribute::Value, 10, "0", QOpcUa::Types::Int32); // Write the first element of the array
+ writeSpy.wait();
+ QCOMPARE(writeSpy.size(), 1);
+ QCOMPARE(writeSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value);
+ QCOMPARE(writeSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+ dataChangeSpy.wait();
+ QCOMPARE(dataChangeSpy.size(), 0);
+
+ writeSpy.clear();
+ integerArrayNode->writeAttributeRange(QOpcUa::NodeAttribute::Value, 10, "1", QOpcUa::Types::Int32); // Write the second element of the array
+ writeSpy.wait();
+ QCOMPARE(writeSpy.size(), 1);
+ QCOMPARE(writeSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value);
+ QCOMPARE(writeSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+ dataChangeSpy.wait();
+ QCOMPARE(dataChangeSpy.size(), 1);
+ QCOMPARE(integerArrayNode->attribute(QOpcUa::NodeAttribute::Value), 10);
+
+ integerArrayNode->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);