diff options
author | Jannis Voelker <jannis.voelker@basyskom.com> | 2018-02-06 14:48:23 +0100 |
---|---|---|
committer | Jannis Völker <jannis.voelker@basyskom.com> | 2018-02-28 07:19:38 +0000 |
commit | 600ba0dcc3cd731fb55491f81ed533de9f7fb106 (patch) | |
tree | 4e3ad9c5c2debaa1fa3152c0e96dba14b38e0c50 | |
parent | f6ecf08115f6615b058cc7800246d5dc6dd54704 (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.cpp | 5 | ||||
-rw-r--r-- | src/plugins/opcua/open62541/qopen62541subscription.cpp | 40 | ||||
-rw-r--r-- | tests/auto/qopcuaclient/tst_client.cpp | 54 |
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); |