summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--LICENSE-CC0110
-rw-r--r--LICENSE.GPL3674
-rw-r--r--LICENSE.GPL3-EXCEPT704
-rw-r--r--config.tests/mbedtls/main.cpp49
-rw-r--r--config.tests/mbedtls/mbedtls.pro1
-rw-r--r--examples/opcua/opcuaviewer/certificatedialog.cpp93
-rw-r--r--examples/opcua/opcuaviewer/certificatedialog.h70
-rw-r--r--examples/opcua/opcuaviewer/certificatedialog.ui131
-rw-r--r--examples/opcua/opcuaviewer/doc/images/opcuaviewer.jpgbin49281 -> 0 bytes
-rw-r--r--examples/opcua/opcuaviewer/doc/images/opcuaviewer.pngbin0 -> 122859 bytes
-rw-r--r--examples/opcua/opcuaviewer/doc/opcuaviewer.qdoc13
-rw-r--r--examples/opcua/opcuaviewer/mainwindow.cpp301
-rw-r--r--examples/opcua/opcuaviewer/mainwindow.h20
-rw-r--r--examples/opcua/opcuaviewer/opcuaviewer.pro9
-rw-r--r--examples/opcua/opcuaviewer/pki/own/certs/opcuaviewer.derbin0 -> 1121 bytes
-rw-r--r--examples/opcua/opcuaviewer/pki/own/private/opcuaviewer.pem28
-rw-r--r--examples/opcua/opcuaviewer/pki/trusted/certs/3d8ec65c47524d6ad67bed912c19a895.derbin0 -> 1344 bytes
-rw-r--r--examples/opcua/opcuaviewer/pki/trusted/certs/ca.derbin0 -> 843 bytes
-rw-r--r--examples/opcua/opcuaviewer/pki/trusted/certs/open62541-testserver.derbin0 -> 988 bytes
-rw-r--r--examples/opcua/opcuaviewer/pki/trusted/crl/ca.crl.pem12
-rw-r--r--examples/opcua/opcuaviewer/treeitem.cpp70
-rw-r--r--examples/opcua/opcuaviewer/treeitem.h8
-rw-r--r--examples/opcua/waterpump/simulationserver/simulationserver.pro21
-rw-r--r--examples/opcua/waterpump/waterpump-qml/MachineDisplay.qml2
-rw-r--r--examples/opcua/waterpump/waterpump-qml/ServerControl.qml5
-rw-r--r--examples/opcua/waterpump/waterpump-qml/doc/waterpump-qml.qdoc15
-rw-r--r--examples/opcua/waterpump/waterpump-qml/machine/Machine.qml2
-rw-r--r--examples/opcua/waterpump/waterpump-qml/machine/Tank.qml2
-rw-r--r--examples/opcua/waterpump/waterpump-qml/main.qml22
-rw-r--r--examples/opcua/waterpump/waterpump-qmlcpp/doc/waterpump-qmlcpp.qdoc54
-rw-r--r--examples/opcua/waterpump/waterpump-qmlcpp/opcuamachinebackend.cpp16
-rw-r--r--examples/opcua/waterpump/waterpump-qmlcpp/opcuamachinebackend.h1
-rw-r--r--src/imports/doc/doc.pro2
-rw-r--r--src/imports/doc/snippets/basic/basic.pro4
-rw-r--r--src/imports/doc/snippets/basic/basic.qml102
-rw-r--r--src/imports/doc/snippets/basic/main.cpp93
-rw-r--r--src/imports/doc/snippets/basic/qml.qrc5
-rw-r--r--src/imports/doc/snippets/snippets.pro5
-rw-r--r--src/imports/imports.pro1
-rw-r--r--src/imports/opcua/opcua.pro32
-rw-r--r--src/imports/opcua/opcua_plugin.cpp84
-rw-r--r--src/imports/opcua/opcuaattributeoperand.cpp250
-rw-r--r--src/imports/opcua/opcuaattributeoperand.h96
-rw-r--r--src/imports/opcua/opcuaconnection.cpp454
-rw-r--r--src/imports/opcua/opcuaconnection.h37
-rw-r--r--src/imports/opcua/opcuadatachangefilter.cpp114
-rw-r--r--src/imports/opcua/opcuadatachangefilter.h93
-rw-r--r--src/imports/opcua/opcuaelementoperand.cpp141
-rw-r--r--src/imports/opcua/opcuaelementoperand.h65
-rw-r--r--src/imports/opcua/opcuaendpointdiscovery.cpp289
-rw-r--r--src/imports/opcua/opcuaendpointdiscovery.h99
-rw-r--r--src/imports/opcua/opcuaeventfilter.cpp254
-rw-r--r--src/imports/opcua/opcuaeventfilter.h94
-rw-r--r--src/imports/opcua/opcuafilterelement.cpp175
-rw-r--r--src/imports/opcua/opcuafilterelement.h103
-rw-r--r--src/imports/opcua/opcualiteraloperand.cpp116
-rw-r--r--src/imports/opcua/opcualiteraloperand.h72
-rw-r--r--src/imports/opcua/opcuamethodargument.cpp104
-rw-r--r--src/imports/opcua/opcuamethodargument.h64
-rw-r--r--src/imports/opcua/opcuamethodnode.cpp153
-rw-r--r--src/imports/opcua/opcuamethodnode.h25
-rw-r--r--src/imports/opcua/opcuanode.cpp277
-rw-r--r--src/imports/opcua/opcuanode.h57
-rw-r--r--src/imports/opcua/opcuanodeid.cpp5
-rw-r--r--src/imports/opcua/opcuanodeidtype.cpp1
-rw-r--r--src/imports/opcua/opcuaoperandbase.cpp58
-rw-r--r--src/imports/opcua/opcuaoperandbase.h58
-rw-r--r--src/imports/opcua/opcuapathresolver.cpp19
-rw-r--r--src/imports/opcua/opcuapathresolver.h5
-rw-r--r--src/imports/opcua/opcuareaditem.cpp154
-rw-r--r--src/imports/opcua/opcuareaditem.h86
-rw-r--r--src/imports/opcua/opcuareadresult.cpp203
-rw-r--r--src/imports/opcua/opcuareadresult.h88
-rw-r--r--src/imports/opcua/opcuarelativenodeid.cpp2
-rw-r--r--src/imports/opcua/opcuarelativenodepath.cpp40
-rw-r--r--src/imports/opcua/opcuarelativenodepath.h13
-rw-r--r--src/imports/opcua/opcuaserverdiscovery.cpp298
-rw-r--r--src/imports/opcua/opcuaserverdiscovery.h92
-rw-r--r--src/imports/opcua/opcuasimpleattributeoperand.cpp247
-rw-r--r--src/imports/opcua/opcuasimpleattributeoperand.h91
-rw-r--r--src/imports/opcua/opcuastatus.cpp807
-rw-r--r--src/imports/opcua/opcuastatus.h303
-rw-r--r--src/imports/opcua/opcuavaluenode.cpp224
-rw-r--r--src/imports/opcua/opcuavaluenode.h34
-rw-r--r--src/imports/opcua/opcuawriteitem.cpp262
-rw-r--r--src/imports/opcua/opcuawriteitem.h109
-rw-r--r--src/imports/opcua/opcuawriteresult.cpp162
-rw-r--r--src/imports/opcua/opcuawriteresult.h82
-rw-r--r--src/imports/opcua/plugins.qmltypes405
-rw-r--r--src/imports/opcua/universalnode.cpp81
-rw-r--r--src/imports/opcua/universalnode.h23
-rw-r--r--src/opcua/client/client.pri106
-rw-r--r--src/opcua/client/qopcuaaddnodeitem.cpp24
-rw-r--r--src/opcua/client/qopcuaaddnodeitem.h18
-rw-r--r--src/opcua/client/qopcuaaddreferenceitem.cpp7
-rw-r--r--src/opcua/client/qopcuaaddreferenceitem.h8
-rw-r--r--src/opcua/client/qopcuaapplicationdescription.cpp337
-rw-r--r--src/opcua/client/qopcuaapplicationdescription.h104
-rw-r--r--src/opcua/client/qopcuaapplicationidentity.cpp205
-rw-r--r--src/opcua/client/qopcuaapplicationidentity.h80
-rw-r--r--src/opcua/client/qopcuaargument.cpp235
-rw-r--r--src/opcua/client/qopcuaargument.h86
-rw-r--r--src/opcua/client/qopcuaattributeoperand.cpp187
-rw-r--r--src/opcua/client/qopcuaattributeoperand.h87
-rw-r--r--src/opcua/client/qopcuaauthenticationinformation.cpp206
-rw-r--r--src/opcua/client/qopcuaauthenticationinformation.h75
-rw-r--r--src/opcua/client/qopcuaaxisinformation.cpp220
-rw-r--r--src/opcua/client/qopcuaaxisinformation.h87
-rw-r--r--src/opcua/client/qopcuabackend.cpp15
-rw-r--r--src/opcua/client/qopcuabackend_p.h22
-rw-r--r--src/opcua/client/qopcuabinarydataencoding.cpp24
-rw-r--r--src/opcua/client/qopcuabinarydataencoding.h178
-rw-r--r--src/opcua/client/qopcuabrowsepathtarget.cpp143
-rw-r--r--src/opcua/client/qopcuabrowsepathtarget.h74
-rw-r--r--src/opcua/client/qopcuaclient.cpp286
-rw-r--r--src/opcua/client/qopcuaclient.h54
-rw-r--r--src/opcua/client/qopcuaclient_p.h14
-rw-r--r--src/opcua/client/qopcuaclientimpl.cpp14
-rw-r--r--src/opcua/client/qopcuaclientimpl_p.h30
-rw-r--r--src/opcua/client/qopcuaclientprivate.cpp78
-rw-r--r--src/opcua/client/qopcuacomplexnumber.cpp141
-rw-r--r--src/opcua/client/qopcuacomplexnumber.h73
-rw-r--r--src/opcua/client/qopcuacontentfilterelement.cpp225
-rw-r--r--src/opcua/client/qopcuacontentfilterelement.h107
-rw-r--r--src/opcua/client/qopcuacontentfilterelementresult.cpp126
-rw-r--r--src/opcua/client/qopcuacontentfilterelementresult.h70
-rw-r--r--src/opcua/client/qopcuadeletereferenceitem.cpp7
-rw-r--r--src/opcua/client/qopcuadeletereferenceitem.h9
-rw-r--r--src/opcua/client/qopcuadoublecomplexnumber.cpp141
-rw-r--r--src/opcua/client/qopcuadoublecomplexnumber.h73
-rw-r--r--src/opcua/client/qopcuaelementoperand.cpp140
-rw-r--r--src/opcua/client/qopcuaelementoperand.h70
-rw-r--r--src/opcua/client/qopcuaendpointdescription.cpp349
-rw-r--r--src/opcua/client/qopcuaendpointdescription.h107
-rw-r--r--src/opcua/client/qopcuaerrorstate.cpp176
-rw-r--r--src/opcua/client/qopcuaerrorstate.h84
-rw-r--r--src/opcua/client/qopcuaeuinformation.cpp186
-rw-r--r--src/opcua/client/qopcuaeuinformation.h82
-rw-r--r--src/opcua/client/qopcuaeventfilterresult.cpp158
-rw-r--r--src/opcua/client/qopcuaeventfilterresult.h75
-rw-r--r--src/opcua/client/qopcuaexpandednodeid.cpp178
-rw-r--r--src/opcua/client/qopcuaexpandednodeid.h77
-rw-r--r--src/opcua/client/qopcuaextensionobject.cpp175
-rw-r--r--src/opcua/client/qopcuaextensionobject.h82
-rw-r--r--src/opcua/client/qopcualiteraloperand.cpp135
-rw-r--r--src/opcua/client/qopcualiteraloperand.h72
-rw-r--r--src/opcua/client/qopcualocalizedtext.cpp183
-rw-r--r--src/opcua/client/qopcualocalizedtext.h77
-rw-r--r--src/opcua/client/qopcuamonitoringparameters.cpp45
-rw-r--r--src/opcua/client/qopcuamonitoringparameters.h23
-rw-r--r--src/opcua/client/qopcuamultidimensionalarray.cpp260
-rw-r--r--src/opcua/client/qopcuamultidimensionalarray.h83
-rw-r--r--src/opcua/client/qopcuanode.cpp16
-rw-r--r--src/opcua/client/qopcuanode.h8
-rw-r--r--src/opcua/client/qopcuanode_p.h7
-rw-r--r--src/opcua/client/qopcuanodecreationattributes.cpp12
-rw-r--r--src/opcua/client/qopcuanodecreationattributes.h14
-rw-r--r--src/opcua/client/qopcuanodecreationattributes_p.h6
-rw-r--r--src/opcua/client/qopcuanodeimpl_p.h8
-rw-r--r--src/opcua/client/qopcuapkiconfiguration.cpp270
-rw-r--r--src/opcua/client/qopcuapkiconfiguration.h90
-rw-r--r--src/opcua/client/qopcuaqualifiedname.cpp144
-rw-r--r--src/opcua/client/qopcuaqualifiedname.h73
-rw-r--r--src/opcua/client/qopcuarange.cpp144
-rw-r--r--src/opcua/client/qopcuarange.h73
-rw-r--r--src/opcua/client/qopcuareaditem.cpp4
-rw-r--r--src/opcua/client/qopcuareaditem.h1
-rw-r--r--src/opcua/client/qopcuareadresult.cpp6
-rw-r--r--src/opcua/client/qopcuareferencedescription.cpp27
-rw-r--r--src/opcua/client/qopcuareferencedescription.h20
-rw-r--r--src/opcua/client/qopcuarelativepathelement.cpp195
-rw-r--r--src/opcua/client/qopcuarelativepathelement.h81
-rw-r--r--src/opcua/client/qopcuasimpleattributeoperand.cpp207
-rw-r--r--src/opcua/client/qopcuasimpleattributeoperand.h86
-rw-r--r--src/opcua/client/qopcuatype.cpp3410
-rw-r--r--src/opcua/client/qopcuatype.h727
-rw-r--r--src/opcua/client/qopcuausertokenpolicy.cpp205
-rw-r--r--src/opcua/client/qopcuausertokenpolicy.h89
-rw-r--r--src/opcua/client/qopcuawriteitem.cpp4
-rw-r--r--src/opcua/client/qopcuawriteresult.cpp6
-rw-r--r--src/opcua/client/qopcuawriteresult.h2
-rw-r--r--src/opcua/client/qopcuaxvalue.cpp143
-rw-r--r--src/opcua/client/qopcuaxvalue.h73
-rw-r--r--src/opcua/configure.json20
-rw-r--r--src/opcua/configure.pri23
-rw-r--r--src/opcua/core/qopcuaprovider.cpp52
-rw-r--r--src/opcua/doc/src/qtopcua.qdoc48
-rw-r--r--src/opcua/doc/src/security.qdoc220
-rw-r--r--src/opcua/doc/src/uacpp.qdoc234
-rw-r--r--src/opcua/opcua.pro2
-rw-r--r--src/plugins/opcua/open62541/qopen62541backend.cpp155
-rw-r--r--src/plugins/opcua/open62541/qopen62541backend.h10
-rw-r--r--src/plugins/opcua/open62541/qopen62541client.cpp28
-rw-r--r--src/plugins/opcua/open62541/qopen62541client.h9
-rw-r--r--src/plugins/opcua/open62541/qopen62541node.cpp4
-rw-r--r--src/plugins/opcua/open62541/qopen62541node.h2
-rw-r--r--src/plugins/opcua/open62541/qopen62541subscription.cpp81
-rw-r--r--src/plugins/opcua/open62541/qopen62541subscription.h10
-rw-r--r--src/plugins/opcua/open62541/qopen62541utils.h9
-rw-r--r--src/plugins/opcua/open62541/qopen62541valueconverter.cpp164
-rw-r--r--src/plugins/opcua/open62541/qopen62541valueconverter.h2
-rw-r--r--src/plugins/opcua/uacpp/quacppbackend.cpp713
-rw-r--r--src/plugins/opcua/uacpp/quacppbackend.h44
-rw-r--r--src/plugins/opcua/uacpp/quacppclient.cpp107
-rw-r--r--src/plugins/opcua/uacpp/quacppclient.h29
-rw-r--r--src/plugins/opcua/uacpp/quacppnode.cpp24
-rw-r--r--src/plugins/opcua/uacpp/quacppnode.h22
-rw-r--r--src/plugins/opcua/uacpp/quacppplugin.cpp20
-rw-r--r--src/plugins/opcua/uacpp/quacppplugin.h20
-rw-r--r--src/plugins/opcua/uacpp/quacppsubscription.cpp84
-rw-r--r--src/plugins/opcua/uacpp/quacppsubscription.h32
-rw-r--r--src/plugins/opcua/uacpp/quacpputils.cpp20
-rw-r--r--src/plugins/opcua/uacpp/quacpputils.h20
-rw-r--r--src/plugins/opcua/uacpp/quacppvalueconverter.cpp466
-rw-r--r--src/plugins/opcua/uacpp/quacppvalueconverter.h32
-rw-r--r--tests/auto/auto.pro5
-rw-r--r--tests/auto/clientSetupInCpp/clientSetupInCpp.pro11
-rw-r--r--tests/auto/clientSetupInCpp/tst_clientSetupInCpp.cpp191
-rw-r--r--tests/auto/clientSetupInCpp/tst_clientSetupInCpp.qml82
-rw-r--r--tests/auto/connection/connection.pro14
-rw-r--r--tests/auto/connection/tst_connection.cpp252
-rw-r--r--tests/auto/declarative/AbsoluteNodeTest.qml462
-rw-r--r--tests/auto/declarative/AuthorizationTest.qml126
-rw-r--r--tests/auto/declarative/BackendTestMultiplier.qml75
-rw-r--r--tests/auto/declarative/BatchReadWriteTest.qml246
-rw-r--r--tests/auto/declarative/CompletionLoggingTestCase.qml42
-rw-r--r--tests/auto/declarative/DataChangeFilterTest.qml186
-rw-r--r--tests/auto/declarative/DiscoveryTest.qml278
-rw-r--r--tests/auto/declarative/MethodnodeTest.qml253
-rw-r--r--tests/auto/declarative/MonitoringFilterTest.qml181
-rw-r--r--tests/auto/declarative/RelativenodeTest.qml385
-rw-r--r--tests/auto/declarative/SecurityTest.qml75
-rw-r--r--tests/auto/declarative/SubscriptionsTest.qml184
-rw-r--r--tests/auto/declarative/declarative.pro6
-rw-r--r--tests/auto/declarative/tst_absolutenode.qml311
-rw-r--r--tests/auto/declarative/tst_authorization.qml41
-rw-r--r--tests/auto/declarative/tst_batchReadWrite.qml41
-rw-r--r--tests/auto/declarative/tst_dataChangeFilter.qml41
-rw-r--r--tests/auto/declarative/tst_discovery.qml42
-rw-r--r--tests/auto/declarative/tst_generic.qml9
-rw-r--r--tests/auto/declarative/tst_methodnode.qml83
-rw-r--r--tests/auto/declarative/tst_monitoringFilterTest.qml41
-rw-r--r--tests/auto/declarative/tst_opcua.cpp22
-rw-r--r--tests/auto/declarative/tst_relativenode.qml262
-rw-r--r--tests/auto/declarative/tst_security.qml41
-rw-r--r--tests/auto/declarative/tst_subscriptions.qml41
-rw-r--r--tests/auto/qopcuaclient/data.qrc5
-rw-r--r--tests/auto/qopcuaclient/qopcuaclient.pro15
-rw-r--r--tests/auto/qopcuaclient/tst_client.cpp937
-rw-r--r--tests/auto/security/certs.qrc10
-rw-r--r--tests/auto/security/pki/own/certs/tst_security.derbin0 -> 1119 bytes
-rw-r--r--tests/auto/security/pki/own/private/privateKeyWithPassword:secret.pem30
-rw-r--r--tests/auto/security/pki/own/private/privateKeyWithoutPassword.pem28
-rw-r--r--tests/auto/security/pki/trusted/certs/ca.derbin0 -> 843 bytes
-rw-r--r--tests/auto/security/pki/trusted/certs/open62541-testserver.derbin0 -> 1041 bytes
-rw-r--r--tests/auto/security/pki/trusted/crl/ca.crl.pem12
-rw-r--r--tests/auto/security/security.pro9
-rw-r--r--tests/auto/security/tst_security.cpp418
-rw-r--r--tests/common/backend_environment.h65
-rw-r--r--tests/manual/eventsubscription/tst_eventsubscription.cpp46
-rw-r--r--tests/open62541-testserver/certs.qrc8
-rw-r--r--tests/open62541-testserver/main.cpp85
-rw-r--r--tests/open62541-testserver/open62541-testserver.pro21
-rw-r--r--tests/open62541-testserver/pki/own/certs/open62541-testserver.derbin0 -> 1041 bytes
-rw-r--r--tests/open62541-testserver/pki/own/private/open62541-testserver.derbin0 -> 1190 bytes
-rw-r--r--tests/open62541-testserver/pki/trusted/certs/.gitkeep0
-rw-r--r--tests/open62541-testserver/pki/trusted/certs/opcuaviewer.derbin0 -> 1121 bytes
-rw-r--r--tests/open62541-testserver/pki/trusted/certs/tst_security.derbin0 -> 1119 bytes
-rw-r--r--tests/open62541-testserver/qt_attribution.json23
-rw-r--r--tests/open62541-testserver/security_addon.cpp121
-rw-r--r--tests/open62541-testserver/security_addon.h23
-rw-r--r--tests/open62541-testserver/testserver.cpp166
-rw-r--r--tests/open62541-testserver/testserver.h5
274 files changed, 25117 insertions, 6436 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 39eb2d7..8629552 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -3,4 +3,4 @@ load(qt_build_config)
ROOT_SOURCE_DIR=$$PWD
ROOT_BUILD_DIR=$$shadowed($$PWD)
-MODULE_VERSION = 5.12.5
+MODULE_VERSION = 5.13.1
diff --git a/LICENSE-CC0 b/LICENSE-CC0
new file mode 100644
index 0000000..ad7fdad
--- /dev/null
+++ b/LICENSE-CC0
@@ -0,0 +1,110 @@
+Creative Commons CCZero 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display,
+ communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+ likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+ v. rights protecting the extraction, dissemination, use and reuse of data
+ in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation
+ thereof, including any amended or successor version of such
+ directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+ world based on applicable law or treaty, and any national
+ implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+ warranties of any kind concerning the Work, express, implied,
+ statutory or otherwise, including without limitation warranties of
+ title, merchantability, fitness for a particular purpose, non
+ infringement, or the absence of latent or other defects, accuracy, or
+ the present or absence of errors, whether or not discoverable, all to
+ the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without
+ limitation any person's Copyright and Related Rights in the Work.
+ Further, Affirmer disclaims responsibility for obtaining any necessary
+ consents, permissions or other rights required for any use of the
+ Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to
+ this CC0 or use of the Work.
diff --git a/LICENSE.GPL3 b/LICENSE.GPL3
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/LICENSE.GPL3
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/LICENSE.GPL3-EXCEPT b/LICENSE.GPL3-EXCEPT
new file mode 100644
index 0000000..b1cb1be
--- /dev/null
+++ b/LICENSE.GPL3-EXCEPT
@@ -0,0 +1,704 @@
+This is the GNU General Public License version 3, annotated with The
+Qt Company GPL Exception 1.0:
+
+-------------------------------------------------------------------------
+
+The Qt Company GPL Exception 1.0
+
+Exception 1:
+
+As a special exception you may create a larger work which contains the
+output of this application and distribute that work under terms of your
+choice, so long as the work is not otherwise derived from or based on
+this application and so long as the work does not in itself generate
+output that contains the output from this application in its original
+or modified form.
+
+Exception 2:
+
+As a special exception, you have permission to combine this application
+with Plugins licensed under the terms of your choice, to produce an
+executable, and to copy and distribute the resulting executable under
+the terms of your choice. However, the executable must be accompanied
+by a prominent notice offering all users of the executable the entire
+source code to this application, excluding the source code of the
+independent modules, but including any changes you have made to this
+application, under the terms of this license.
+
+
+-------------------------------------------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/config.tests/mbedtls/main.cpp b/config.tests/mbedtls/main.cpp
new file mode 100644
index 0000000..62cb19b
--- /dev/null
+++ b/config.tests/mbedtls/main.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <mbedtls/x509.h>
+#include <mbedtls/x509_crt.h>
+
+int main(int argc, char *argv[])
+{
+ mbedtls_pk_context pk;
+ mbedtls_pk_init( &pk );
+
+ mbedtls_x509_crt remoteCertificate;
+ mbedtls_x509_crt_init(&remoteCertificate);
+
+ return 0;
+}
diff --git a/config.tests/mbedtls/mbedtls.pro b/config.tests/mbedtls/mbedtls.pro
new file mode 100644
index 0000000..28dcadc
--- /dev/null
+++ b/config.tests/mbedtls/mbedtls.pro
@@ -0,0 +1 @@
+SOURCES += main.cpp
diff --git a/examples/opcua/opcuaviewer/certificatedialog.cpp b/examples/opcua/opcuaviewer/certificatedialog.cpp
new file mode 100644
index 0000000..dd1b61a
--- /dev/null
+++ b/examples/opcua/opcuaviewer/certificatedialog.cpp
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Unified Automation GmbH
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "certificatedialog.h"
+#include "ui_certificatedialog.h"
+#include <QPushButton>
+
+QT_BEGIN_NAMESPACE
+
+CertificateDialog::CertificateDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::CertificateDialog)
+{
+ ui->setupUi(this);
+ connect(ui->btnTrust, &QPushButton::clicked, this, &CertificateDialog::saveCertificate);
+}
+
+CertificateDialog::~CertificateDialog()
+{
+ delete ui;
+}
+
+/** Returns 0 if the connect should be aborted, 1 if it should be resumed. */
+int CertificateDialog::showCertificate(const QString &message, const QByteArray &der, const QString &trustListDirectory)
+{
+ QList<QSslCertificate> certs = QSslCertificate::fromData(der, QSsl::Der);
+
+ m_trustListDirectory = trustListDirectory;
+
+ // if it is a unstrusted self-signed certificate we can allow to trust it
+ if (certs.count() == 1 && certs[0].isSelfSigned()) {
+ m_cert = certs[0];
+ ui->btnTrust->setEnabled(true);
+ } else {
+ ui->btnTrust->setEnabled(false);
+ }
+
+ for (const QSslCertificate &cert : qAsConst(certs))
+ ui->certificate->appendPlainText(cert.toText());
+
+ ui->message->setText(message);
+ ui->certificate->moveCursor(QTextCursor::Start);
+ ui->certificate->ensureCursorVisible();
+
+ return exec();
+}
+
+void CertificateDialog::saveCertificate()
+{
+ const QByteArray digest = m_cert.digest();
+ const QString path = m_trustListDirectory + "/" + digest.toHex() + ".der";
+
+ QFile file(path);
+ if (file.open(QIODevice::WriteOnly)) {
+ file.write(m_cert.toDer());
+ file.close();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/examples/opcua/opcuaviewer/certificatedialog.h b/examples/opcua/opcuaviewer/certificatedialog.h
new file mode 100644
index 0000000..ba0fc81
--- /dev/null
+++ b/examples/opcua/opcuaviewer/certificatedialog.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Unified Automation GmbH
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CERTIFICATEDIALOG_H
+#define CERTIFICATEDIALOG_H
+
+#include <QDialog>
+#include <QSslCertificate>
+
+QT_BEGIN_NAMESPACE
+
+namespace Ui {
+class CertificateDialog;
+}
+
+class CertificateDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit CertificateDialog(QWidget *parent = nullptr);
+ ~CertificateDialog();
+
+ int showCertificate(const QString &message, const QByteArray &der, const QString &trustListDirectory);
+
+private slots:
+ void saveCertificate();
+
+private:
+ Ui::CertificateDialog *ui;
+ QSslCertificate m_cert;
+ QString m_trustListDirectory;
+};
+
+QT_END_NAMESPACE
+
+#endif // CERTIFICATEDIALOG_H
diff --git a/examples/opcua/opcuaviewer/certificatedialog.ui b/examples/opcua/opcuaviewer/certificatedialog.ui
new file mode 100644
index 0000000..0a25d2c
--- /dev/null
+++ b/examples/opcua/opcuaviewer/certificatedialog.ui
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CertificateDialog</class>
+ <widget class="QDialog" name="CertificateDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>720</width>
+ <height>423</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="message">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPlainTextEdit" name="certificate">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnIgnore">
+ <property name="text">
+ <string>Ignore Error</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnTrust">
+ <property name="text">
+ <string>Trust Certificate</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnCancel">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>btnIgnore</sender>
+ <signal>clicked()</signal>
+ <receiver>CertificateDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>475</x>
+ <y>402</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>374</x>
+ <y>397</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>btnTrust</sender>
+ <signal>clicked()</signal>
+ <receiver>CertificateDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>563</x>
+ <y>404</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>287</x>
+ <y>395</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>btnCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>CertificateDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>670</x>
+ <y>406</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>717</x>
+ <y>395</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/opcua/opcuaviewer/doc/images/opcuaviewer.jpg b/examples/opcua/opcuaviewer/doc/images/opcuaviewer.jpg
deleted file mode 100644
index 1f125d4..0000000
--- a/examples/opcua/opcuaviewer/doc/images/opcuaviewer.jpg
+++ /dev/null
Binary files differ
diff --git a/examples/opcua/opcuaviewer/doc/images/opcuaviewer.png b/examples/opcua/opcuaviewer/doc/images/opcuaviewer.png
new file mode 100644
index 0000000..67f7e24
--- /dev/null
+++ b/examples/opcua/opcuaviewer/doc/images/opcuaviewer.png
Binary files differ
diff --git a/examples/opcua/opcuaviewer/doc/opcuaviewer.qdoc b/examples/opcua/opcuaviewer/doc/opcuaviewer.qdoc
index f6502ee..493f325 100644
--- a/examples/opcua/opcuaviewer/doc/opcuaviewer.qdoc
+++ b/examples/opcua/opcuaviewer/doc/opcuaviewer.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the documentation of the QtOpcUa module.
@@ -28,13 +28,12 @@
/*!
\example opcuaviewer
\ingroup qtopcua-examples
- \title Qt OPC UA explorer
- \brief This example uses the model/view approach to display all nodes of an
- OPC UA server in a \l QTreeView.
+ \title Qt OPC UA Viewer Example
+ \brief Using the model/view approach to display all nodes of an
+ OPC UA server in a tree view.
- \section1 Introduction
- This example uses the model/view approach to display all nodes of an
+ \e {Qt OPC UA Viewer} uses the model/view approach to display all nodes of an
OPC UA server in a \l QTreeView.
- \image opcuaviewer.jpg
+ \image opcuaviewer.png
*/
diff --git a/examples/opcua/opcuaviewer/mainwindow.cpp b/examples/opcua/opcuaviewer/mainwindow.cpp
index a50dc86..23e41f0 100644
--- a/examples/opcua/opcuaviewer/mainwindow.cpp
+++ b/examples/opcua/opcuaviewer/mainwindow.cpp
@@ -50,7 +50,10 @@
#include "mainwindow.h"
#include "opcuamodel.h"
+#include "certificatedialog.h"
+#include <QCoreApplication>
+#include <QDir>
#include <QLineEdit>
#include <QComboBox>
#include <QMessageBox>
@@ -64,6 +67,8 @@
#include <QTreeView>
#include <QHeaderView>
#include <QOpcUaProvider>
+#include <QOpcUaAuthenticationInformation>
+#include <QOpcUaErrorState>
QT_BEGIN_NAMESPACE
@@ -111,24 +116,38 @@ static void messageHandler(QtMsgType type, const QMessageLogContext &context, co
}
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
- , mServerUrl(new QLineEdit(this))
, mOpcUaPlugin(new QComboBox(this))
+ , mHost(new QLineEdit(this))
+ , mServers(new QComboBox(this))
+ , mEndpoints(new QComboBox(this))
+ , mFindServersButton(new QPushButton(tr("Find Servers"), this))
+ , mGetEndpointsButton(new QPushButton(tr("Get Endpoints"), this))
, mConnectButton(new QPushButton(tr("Connect"), this))
, mLog(new QPlainTextEdit(this))
, mTreeView(new QTreeView(this))
, mOpcUaModel(new OpcUaModel(this))
, mOpcUaProvider(new QOpcUaProvider(this))
+ , mOpcUaClient(nullptr)
, mClientConnected(false)
{
+ int row = 0;
mainWindowGlobal = this;
- auto hbox = new QHBoxLayout;
- hbox->addWidget(mOpcUaPlugin);
- hbox->addWidget(mServerUrl);
- hbox->addWidget(mConnectButton);
+ auto grid = new QGridLayout;
+ grid->addWidget(new QLabel(tr("Select OPC UA Backend:")), row, 0);
+ grid->addWidget(mOpcUaPlugin, row, 1);
+ grid->addWidget(new QLabel(tr("Select host to discover:")), ++row, 0);
+ grid->addWidget(mHost, row, 1);
+ grid->addWidget(mFindServersButton, row, 2);
+ grid->addWidget(new QLabel(tr("Select OPC UA Server:")), ++row, 0);
+ grid->addWidget(mServers, row, 1);
+ grid->addWidget(mGetEndpointsButton, row, 2);
+ grid->addWidget(new QLabel(tr("Select OPC UA Endpoint:")), ++row, 0);
+ grid->addWidget(mEndpoints, row, 1);
+ grid->addWidget(mConnectButton, row, 2);
auto vbox = new QVBoxLayout;
- vbox->addLayout(hbox);
+ vbox->addLayout(grid);
vbox->addWidget(mTreeView);
vbox->addWidget(new QLabel(tr("Log:")));
vbox->addWidget(mLog);
@@ -137,13 +156,15 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
widget->setLayout(vbox);
setCentralWidget(widget);
+ mHost->setText("opc.tcp://localhost:48010");
+ mEndpoints->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
updateUiState();
- mServerUrl->setText("opc.tcp://127.0.0.1:43344");
mOpcUaPlugin->addItems(mOpcUaProvider->availableBackends());
mLog->setReadOnly(true);
mLog->setLineWrapMode(QPlainTextEdit::NoWrap);
- setMinimumWidth(500);
+ setMinimumWidth(800);
mTreeView->setModel(mOpcUaModel);
mTreeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
mTreeView->setTextElideMode(Qt::ElideRight);
@@ -156,8 +177,136 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
QMessageBox::critical(this, tr("No OPCUA plugins available"), tr("The list of available OPCUA plugins is empty. No connection possible."));
}
+ connect(mFindServersButton, &QPushButton::clicked, this, &MainWindow::findServers);
+ connect(mGetEndpointsButton, &QPushButton::clicked, this, &MainWindow::getEndpoints);
connect(mConnectButton, &QPushButton::clicked, this, &MainWindow::connectToServer);
oldMessageHandler = qInstallMessageHandler(&messageHandler);
+
+ setupPkiConfiguration();
+
+ //! [Application Identity]
+ m_identity = m_pkiConfig.applicationIdentity();
+ //! [Application Identity]
+}
+
+//! [PKI Configuration]
+void MainWindow::setupPkiConfiguration()
+{
+ const QString pkidir = QCoreApplication::applicationDirPath() + "/pki";
+ m_pkiConfig.setClientCertificateFile(pkidir + "/own/certs/opcuaviewer.der");
+ m_pkiConfig.setPrivateKeyFile(pkidir + "/own/private/opcuaviewer.pem");
+ m_pkiConfig.setTrustListDirectory(pkidir + "/trusted/certs");
+ m_pkiConfig.setRevocationListDirectory(pkidir + "/trusted/crl");
+ m_pkiConfig.setIssuerListDirectory(pkidir + "/issuers/certs");
+ m_pkiConfig.setIssuerRevocationListDirectory(pkidir + "/issuers/crl");
+
+ // create the folders if they don't exist yet
+ createPkiFolders();
+}
+//! [PKI Configuration]
+
+void MainWindow::createClient()
+{
+ if (mOpcUaClient == nullptr) {
+ mOpcUaClient = mOpcUaProvider->createClient(mOpcUaPlugin->currentText());
+ if (!mOpcUaClient) {
+ const QString message(tr("Connecting to the given sever failed. See the log for details."));
+ log(message, QString(), Qt::red);
+ QMessageBox::critical(this, tr("Failed to connect to server"), message);
+ return;
+ }
+
+ connect(mOpcUaClient, &QOpcUaClient::connectError, this, &MainWindow::showErrorDialog);
+ mOpcUaClient->setApplicationIdentity(m_identity);
+ mOpcUaClient->setPkiConfiguration(m_pkiConfig);
+
+ if (mOpcUaClient->supportedUserTokenTypes().contains(QOpcUaUserTokenPolicy::TokenType::Certificate)) {
+ QOpcUaAuthenticationInformation authInfo;
+ authInfo.setCertificateAuthentication();
+ mOpcUaClient->setAuthenticationInformation(authInfo);
+ }
+
+ connect(mOpcUaClient, &QOpcUaClient::connected, this, &MainWindow::clientConnected);
+ connect(mOpcUaClient, &QOpcUaClient::disconnected, this, &MainWindow::clientDisconnected);
+ connect(mOpcUaClient, &QOpcUaClient::errorChanged, this, &MainWindow::clientError);
+ connect(mOpcUaClient, &QOpcUaClient::stateChanged, this, &MainWindow::clientState);
+ connect(mOpcUaClient, &QOpcUaClient::endpointsRequestFinished, this, &MainWindow::getEndpointsComplete);
+ connect(mOpcUaClient, &QOpcUaClient::findServersFinished, this, &MainWindow::findServersComplete);
+ }
+}
+
+void MainWindow::findServers()
+{
+ QStringList localeIds;
+ QStringList serverUris;
+ QUrl url(mHost->text());
+
+ updateUiState();
+
+ createClient();
+ // set default port if missing
+ if (url.port() == -1) url.setPort(4840);
+
+ if (mOpcUaClient) {
+ mOpcUaClient->findServers(url, localeIds, serverUris);
+ qDebug() << "Discovering servers on " << url.toString();
+ }
+}
+
+void MainWindow::findServersComplete(const QVector<QOpcUaApplicationDescription> &servers, QOpcUa::UaStatusCode statusCode)
+{
+ QOpcUaApplicationDescription server;
+
+ if (isSuccessStatus(statusCode)) {
+ mServers->clear();
+ for (const auto &server : servers) {
+ QVector<QString> urls = server.discoveryUrls();
+ for (const auto &url : qAsConst(urls))
+ mServers->addItem(url);
+ }
+ }
+
+ updateUiState();
+}
+
+void MainWindow::getEndpoints()
+{
+ mEndpoints->clear();
+ updateUiState();
+
+ if (mServers->currentIndex() >= 0) {
+ const QString serverUrl = mServers->currentText();
+ createClient();
+ mOpcUaClient->requestEndpoints(serverUrl);
+ }
+}
+
+void MainWindow::getEndpointsComplete(const QVector<QOpcUaEndpointDescription> &endpoints, QOpcUa::UaStatusCode statusCode)
+{
+ int index = 0;
+ const char *modes[] = {
+ "Invalid",
+ "None",
+ "Sign",
+ "SignAndEncrypt"
+ };
+
+ if (isSuccessStatus(statusCode)) {
+ mEndpointList = endpoints;
+ for (const auto &endpoint : endpoints) {
+ if (endpoint.securityMode() > sizeof(modes)) {
+ qWarning() << "Invalid security mode";
+ continue;
+ }
+
+ const QString EndpointName = QString("%1 (%2)")
+ .arg(endpoint.securityPolicy())
+ .arg(modes[endpoint.securityMode()]);
+ mEndpoints->addItem(EndpointName, index++);
+ }
+ }
+
+ updateUiState();
}
void MainWindow::connectToServer()
@@ -167,38 +316,43 @@ void MainWindow::connectToServer()
return;
}
- mOpcUaClient = mOpcUaProvider->createClient(mOpcUaPlugin->currentText());
- if (!mOpcUaClient) {
- const QString message(tr("Connecting to the given sever failed. See the log for details."));
- log(message, QString(), Qt::red);
- QMessageBox::critical(this, tr("Failed to connect to server"), message);
- return;
+ if (mEndpoints->currentIndex() >= 0) {
+ m_endpoint = mEndpointList[mEndpoints->currentIndex()];
+ createClient();
+ mOpcUaClient->connectToEndpoint(m_endpoint);
}
-
- connect(mOpcUaClient, &QOpcUaClient::connected, this, &MainWindow::clientConnected);
- connect(mOpcUaClient, &QOpcUaClient::disconnected, this, &MainWindow::clientDisconnected);
- connect(mOpcUaClient, &QOpcUaClient::errorChanged, this, &MainWindow::clientError);
- connect(mOpcUaClient, &QOpcUaClient::stateChanged, this, &MainWindow::clientState);
-
- mOpcUaClient->connectToEndpoint(mServerUrl->text());
}
void MainWindow::clientConnected()
{
mClientConnected = true;
updateUiState();
- mOpcUaModel->setOpcUaClient(mOpcUaClient);
- mTreeView->header()->setSectionResizeMode(1 /* Value column*/, QHeaderView::Interactive);
+
+ connect(mOpcUaClient, &QOpcUaClient::namespaceArrayUpdated, this, &MainWindow::namespacesArrayUpdated);
+ mOpcUaClient->updateNamespaceArray();
}
void MainWindow::clientDisconnected()
{
mClientConnected = false;
mOpcUaClient->deleteLater();
+ mOpcUaClient = nullptr;
mOpcUaModel->setOpcUaClient(nullptr);
updateUiState();
}
+void MainWindow::namespacesArrayUpdated(const QStringList &namespaceArray)
+{
+ if (namespaceArray.isEmpty()) {
+ qWarning() << "Failed to retrieve the namespaces array";
+ return;
+ }
+
+ disconnect(mOpcUaClient, &QOpcUaClient::namespaceArrayUpdated, this, &MainWindow::namespacesArrayUpdated);
+ mOpcUaModel->setOpcUaClient(mOpcUaClient);
+ mTreeView->header()->setSectionResizeMode(1 /* Value column*/, QHeaderView::Interactive);
+}
+
void MainWindow::clientError(QOpcUaClient::ClientError error)
{
qDebug() << "Client error changed" << error;
@@ -211,9 +365,35 @@ void MainWindow::clientState(QOpcUaClient::ClientState state)
void MainWindow::updateUiState()
{
+ // allow changing the backend only if it was not already created
+ mOpcUaPlugin->setEnabled(mOpcUaClient == nullptr);
mConnectButton->setText(mClientConnected?tr("Disconnect"):tr("Connect"));
- mOpcUaPlugin->setDisabled(mClientConnected);
- mServerUrl->setDisabled(mClientConnected);
+
+ if (mClientConnected) {
+ mHost->setEnabled(false);
+ mServers->setEnabled(false);
+ mEndpoints->setEnabled(false);
+ mFindServersButton->setEnabled(false);
+ mGetEndpointsButton->setEnabled(false);
+ mConnectButton->setEnabled(true);
+ mConnectButton->setText(tr("Disconnect"));
+ } else {
+ mHost->setEnabled(true);
+ mServers->setEnabled(mServers->count() > 0);
+ mEndpoints->setEnabled(mEndpoints->count() > 0);
+
+ mFindServersButton->setDisabled(mHost->text().isEmpty());
+ mGetEndpointsButton->setEnabled(mServers->currentIndex() != -1);
+ mConnectButton->setEnabled(mEndpoints->currentIndex() != -1);
+ mConnectButton->setText(tr("Connect"));
+ }
+
+ if (!mOpcUaClient) {
+ mServers->setEnabled(false);
+ mEndpoints->setEnabled(false);
+ mGetEndpointsButton->setEnabled(false);
+ mConnectButton->setEnabled(false);
+ }
}
void MainWindow::log(const QString &text, const QString &context, QColor color)
@@ -234,4 +414,75 @@ void MainWindow::log(const QString &text, QColor color)
log(text, QString(), color);
}
+bool MainWindow::createPkiPath(const QString &path)
+{
+ const QString msg = tr("Creating PKI path '%1': %2");
+
+ QDir dir;
+ const bool ret = dir.mkpath(path);
+ if (ret) {
+ qDebug() << msg.arg(path).arg("SUCCESS.");
+ } else {
+ qCritical(msg.arg(path).arg("FAILED.").toLocal8Bit());
+ }
+
+ return ret;
+}
+
+bool MainWindow::createPkiFolders()
+{
+ bool result = createPkiPath(m_pkiConfig.trustListDirectory());
+ if (!result)
+ return result;
+
+ result = createPkiPath(m_pkiConfig.revocationListDirectory());
+ if (!result)
+ return result;
+
+ result = createPkiPath(m_pkiConfig.issuerListDirectory());
+ if (!result)
+ return result;
+
+ result = createPkiPath(m_pkiConfig.issuerRevocationListDirectory());
+ if (!result)
+ return result;
+
+ return result;
+}
+
+void MainWindow::showErrorDialog(QOpcUaErrorState *errorState)
+{
+ QString msg;
+ CertificateDialog dlg;
+ int result = 0;
+
+ const QString statuscode = QOpcUa::statusToString(errorState->errorCode());
+
+ if (errorState->isClientSideError())
+ msg = tr("The client reported: ");
+ else
+ msg = tr("The server reported: ");
+
+ switch (errorState->connectionStep()) {
+ case QOpcUaErrorState::ConnectionStep::CertificateValidation:
+ msg += tr("Server certificate validation failed with error 0x%1 (%2).\nClick 'Abort' to abort the connect, or 'Ignore' to continue connecting.")
+ .arg(static_cast<ulong>(errorState->errorCode()), 8, 16, QLatin1Char('0')).arg(statuscode);
+ result = dlg.showCertificate(msg, m_endpoint.serverCertificate(), m_pkiConfig.trustListDirectory());
+ errorState->setIgnoreError(result == 1);
+ break;
+ case QOpcUaErrorState::ConnectionStep::OpenSecureChannel:
+ msg += tr("OpenSecureChannel failed with error 0x%1 (%2).").arg(errorState->errorCode(), 8, 16, QLatin1Char('0')).arg(statuscode);
+ QMessageBox::warning(this, tr("Connection Error"), msg);
+ break;
+ case QOpcUaErrorState::ConnectionStep::CreateSession:
+ msg += tr("CreateSession failed with error 0x%1 (%2).").arg(errorState->errorCode(), 8, 16, QLatin1Char('0')).arg(statuscode);
+ QMessageBox::warning(this, tr("Connection Error"), msg);
+ break;
+ case QOpcUaErrorState::ConnectionStep::ActivateSession:
+ msg += tr("ActivateSession failed with error 0x%1 (%2).").arg(errorState->errorCode(), 8, 16, QLatin1Char('0')).arg(statuscode);
+ QMessageBox::warning(this, tr("Connection Error"), msg);
+ break;
+ }
+}
+
QT_END_NAMESPACE
diff --git a/examples/opcua/opcuaviewer/mainwindow.h b/examples/opcua/opcuaviewer/mainwindow.h
index 390d604..cf8b5a6 100644
--- a/examples/opcua/opcuaviewer/mainwindow.h
+++ b/examples/opcua/opcuaviewer/mainwindow.h
@@ -74,24 +74,42 @@ public:
private slots:
void connectToServer();
+ void findServers();
+ void findServersComplete(const QVector<QOpcUaApplicationDescription> &servers, QOpcUa::UaStatusCode statusCode);
+ void getEndpoints();
+ void getEndpointsComplete(const QVector<QOpcUaEndpointDescription> &endpoints, QOpcUa::UaStatusCode statusCode);
void clientConnected();
void clientDisconnected();
+ void namespacesArrayUpdated(const QStringList &namespaceArray);
void clientError(QOpcUaClient::ClientError);
void clientState(QOpcUaClient::ClientState);
+ void showErrorDialog(QOpcUaErrorState *errorState);
private:
+ void createClient();
void updateUiState();
+ void setupPkiConfiguration();
+ bool createPkiFolders();
+ bool createPkiPath(const QString &path);
private:
- QLineEdit *mServerUrl;
QComboBox *mOpcUaPlugin;
+ QLineEdit *mHost;
+ QComboBox *mServers;
+ QComboBox *mEndpoints;
+ QPushButton *mFindServersButton;
+ QPushButton *mGetEndpointsButton;
QPushButton *mConnectButton;
QPlainTextEdit *mLog;
QTreeView *mTreeView;
OpcUaModel *mOpcUaModel;
QOpcUaProvider *mOpcUaProvider;
QOpcUaClient *mOpcUaClient;
+ QVector<QOpcUaEndpointDescription> mEndpointList;
bool mClientConnected;
+ QOpcUaApplicationIdentity m_identity;
+ QOpcUaPkiConfiguration m_pkiConfig;
+ QOpcUaEndpointDescription m_endpoint; // current endpoint used to connect
};
QT_END_NAMESPACE
diff --git a/examples/opcua/opcuaviewer/opcuaviewer.pro b/examples/opcua/opcuaviewer/opcuaviewer.pro
index 644f287..bc641d0 100644
--- a/examples/opcua/opcuaviewer/opcuaviewer.pro
+++ b/examples/opcua/opcuaviewer/opcuaviewer.pro
@@ -5,7 +5,8 @@ DEPENDPATH += INCLUDEPATH
SOURCES += main.cpp \
mainwindow.cpp \
opcuamodel.cpp \
- treeitem.cpp
+ treeitem.cpp \
+ certificatedialog.cpp
#install
target.path = $$[QT_INSTALL_EXAMPLES]/opcua/opcuaviewer
@@ -14,4 +15,8 @@ INSTALLS += target
HEADERS += \
mainwindow.h \
opcuamodel.h \
- treeitem.h
+ treeitem.h \
+ certificatedialog.h
+
+FORMS += \
+ certificatedialog.ui
diff --git a/examples/opcua/opcuaviewer/pki/own/certs/opcuaviewer.der b/examples/opcua/opcuaviewer/pki/own/certs/opcuaviewer.der
new file mode 100644
index 0000000..1eeb26a
--- /dev/null
+++ b/examples/opcua/opcuaviewer/pki/own/certs/opcuaviewer.der
Binary files differ
diff --git a/examples/opcua/opcuaviewer/pki/own/private/opcuaviewer.pem b/examples/opcua/opcuaviewer/pki/own/private/opcuaviewer.pem
new file mode 100644
index 0000000..ce495ce
--- /dev/null
+++ b/examples/opcua/opcuaviewer/pki/own/private/opcuaviewer.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCb0fM15Zx3Q0Mp
+vOaoCBi908Gwv6+ZzaCf69y1B4H3lXe2jAu9D2AYO68uRqe/dzQ5TMqdKdupVeRP
+XrsLDEm7tpb+wLmzT3DyFeNjKfNZ5KlnFKadhYeK2eyh1pYQDPFgfKNBvz0VhY9f
+DNouVe+qcp38FfdM6BOQ7/n9GsuBWYdfmnOwzPZSwpNkY8tOIYUmmSATB0h5sTxq
+8L83oR7MrMx9sBs1GjdI3ghUufs9UZ0zxP6mrmqTD7ocQxDbjDBZbxgy9bn19zeV
+5l+wB+9DeIxthOGdXMIgR9g29DSFqtJGgLLOlmpgA3SVKCMUNj4neQrBiA4+kqVE
+2ncxESZPAgMBAAECggEARNmqG6CPWGtSG/kp+glJ1Wbh6NVqJA2l8cPoS907Ykib
+EwAil7FZhpuotkvmB0YGv2LdDEDYnKQlM6TqBOGzGsx9P6es5jwt7eoaBVEeBBRz
+fea0EFpWH9ZXJtOIjyMI7Ndl08FKnl3bkeY96cdzFN98S0zxbvwE2UAQN/RFA6v5
+CTIegCjDr3nLHCKVUzVWz/ns6IVTJBV11lwcU/ZedTMrPJNisobW9wVfu51Arv5g
+w+X+lb5CZWulimSrmyX23IEAiGSh7pNo5VL+H6SCYlfRIoXnS7J+RfCrsmJJs1xA
+xM6op52Wb4pQ02fu8Z68q05LsSCv1iDCOARG5GU94QKBgQDL0c48QwiNv3dgEJ45
+x9iLwWsGGrVLnrp85xxX4bgjB5oSkJg06/Ot1CRrFZPnlL786TgxbWhu3M26biNy
+b7ifsWS0kdr4neFDRmQ/v9R/eivI8iXxEnG92TxX7yNu5Ml/BuT7/Z19xhJX1i83
+kwJlZzl8gi9msItlbQFanDna2QKBgQDDtktPAzGozrk0gzG+hiNCy1C/ec/uTyyf
+RE2ZbLHHxkLU8dOIzujjeFQ1U/fNtg3GX4fGqp4My15HjVvyFpdYIHcwAbzC6DCf
+IsJdKUTVlbAZTSlr56xbNce3WMoI7LIdykQXyv5+Q2fM1NGu5iCSc6oOS/ePkoyh
+T3jL4WFBZwKBgQCtRfEhdA96ihKPXbFWB9rFfSpiJySHZCrAcq263I7xYM4QCFMN
+cqZX2ikXzGFQGDmBwzddddi5nwda/bUu3WHEiUfG5tSUVYwi6F3jgE7EDPXaQFoX
+JwoBTwQo8YlbBi9yyUa0H7jbKx9/AvxjL5xy3p2VhwuLLn1jPZdQE85viQKBgFu/
+YrCIu8f6GUKv2isJ8Q/IBnOs5DhAr5d+Sq6JERKpM/1l3Je+/9hbOYbCdWHfXbfI
+YvtUUsGGuQzsDNWBl7N9jMJZnib0+I4xmlJYHWfPQ32o+akXM2qS3KxsGFJ0u89R
+WfiZdhK1AL06a44FXfGp/We0XzrUJc8dVXCmmJQzAoGAXTq2o/0Q+at+JX0ylJCD
+v6FDxHWT1SgXK4u4M0cZl0gqnJs9uYz6fXm45vfs4rOBJA0K0Pd9M2y22m6BM3HS
+8I34Em8dFTlObkScZvtbeHUltUcXeE957l2+a32i64alTJCZ4fEoiJnzPjRzg2et
+F2ItxrH+I27dpzAG19VUgeA=
+-----END PRIVATE KEY-----
diff --git a/examples/opcua/opcuaviewer/pki/trusted/certs/3d8ec65c47524d6ad67bed912c19a895.der b/examples/opcua/opcuaviewer/pki/trusted/certs/3d8ec65c47524d6ad67bed912c19a895.der
new file mode 100644
index 0000000..8d2e9be
--- /dev/null
+++ b/examples/opcua/opcuaviewer/pki/trusted/certs/3d8ec65c47524d6ad67bed912c19a895.der
Binary files differ
diff --git a/examples/opcua/opcuaviewer/pki/trusted/certs/ca.der b/examples/opcua/opcuaviewer/pki/trusted/certs/ca.der
new file mode 100644
index 0000000..3f31274
--- /dev/null
+++ b/examples/opcua/opcuaviewer/pki/trusted/certs/ca.der
Binary files differ
diff --git a/examples/opcua/opcuaviewer/pki/trusted/certs/open62541-testserver.der b/examples/opcua/opcuaviewer/pki/trusted/certs/open62541-testserver.der
new file mode 100644
index 0000000..507aa97
--- /dev/null
+++ b/examples/opcua/opcuaviewer/pki/trusted/certs/open62541-testserver.der
Binary files differ
diff --git a/examples/opcua/opcuaviewer/pki/trusted/crl/ca.crl.pem b/examples/opcua/opcuaviewer/pki/trusted/crl/ca.crl.pem
new file mode 100644
index 0000000..5adff29
--- /dev/null
+++ b/examples/opcua/opcuaviewer/pki/trusted/crl/ca.crl.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBtDCBnQIBATANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJERTESMBAGA1UE
+CgwJb3BlbjYyNTQxMRYwFAYDVQQDDA1vcGVuNjI1NDEub3JnFw0xOTAyMDUwOTIx
+MjZaFw0xOTAzMDcwOTIxMjZaoDAwLjAfBgNVHSMEGDAWgBT2JxGCWDhuet+WnrDX
+1SXW4O8HNTALBgNVHRQEBAICEAAwDQYJKoZIhvcNAQELBQADggEBAF31DhT8Im+Z
+QkpkFtUzmM9FfjqD4vrkrCAAA6U382mwn5KDcm4LA+FjFePHgSyk+ytLD03z7hSp
+wgyxbldg4yC4GynUp7XcbB4zus6Lym/ayDgGVQEw81c/c7YAelc8u055TBJUcmuX
+/XV/JXfSO2ZWM5MZZCev79w8Oj4hmUPp9ZpAJkxt/GYictGSkDpBTMTAWRRenPUe
+F4qvkvYMkKMrURLFMfYcqa2ePszxnyjdfi6KXHllsHl0iHduSq1acAdx1G/itoDq
+ML7QLS/M/VBYYxSGghLPetanQ+6f+OYztgTuzw2nG4DXxfMhfijoi6LbfFDvy0K+
+mHqhbQW1Go8=
+-----END X509 CRL-----
diff --git a/examples/opcua/opcuaviewer/treeitem.cpp b/examples/opcua/opcuaviewer/treeitem.cpp
index 56b10a7..b069189 100644
--- a/examples/opcua/opcuaviewer/treeitem.cpp
+++ b/examples/opcua/opcuaviewer/treeitem.cpp
@@ -50,7 +50,17 @@
#include "treeitem.h"
#include "opcuamodel.h"
+#include <QOpcUaArgument>
+#include <QOpcUaAxisInformation>
#include <QOpcUaClient>
+#include <QOpcUaComplexNumber>
+#include <QOpcUaDoubleComplexNumber>
+#include <QOpcUaEUInformation>
+#include <QOpcUaExtensionObject>
+#include <QOpcUaLocalizedText>
+#include <QOpcUaQualifiedName>
+#include <QOpcUaRange>
+#include <QOpcUaXValue>
#include <QMetaEnum>
#include <QPixmap>
@@ -151,7 +161,7 @@ QVariant TreeItem::data(int column)
if (!mAttributesReady)
return tr("Loading ...");
- return mOpcNode->attribute(QOpcUa::NodeAttribute::Description).value<QOpcUa::QLocalizedText>().text();
+ return mOpcNode->attribute(QOpcUa::NodeAttribute::Description).value<QOpcUaLocalizedText>().text();
}
return QVariant();
}
@@ -228,9 +238,9 @@ void TreeItem::handleAttributes(QOpcUa::NodeAttributes attr)
if (attr & QOpcUa::NodeAttribute::NodeClass)
mNodeClass = mOpcNode->attribute(QOpcUa::NodeAttribute::NodeClass).value<QOpcUa::NodeClass>();
if (attr & QOpcUa::NodeAttribute::BrowseName)
- mNodeBrowseName = mOpcNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUa::QQualifiedName>().name();
+ mNodeBrowseName = mOpcNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>().name();
if (attr & QOpcUa::NodeAttribute::DisplayName)
- mNodeDisplayName = mOpcNode->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUa::QLocalizedText>().text();
+ mNodeDisplayName = mOpcNode->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>().text();
mAttributesReady = true;
emit mModel->dataChanged(mModel->createIndex(row(), 0, this), mModel->createIndex(row(), numberOfDisplayColumns - 1, this));
@@ -294,48 +304,48 @@ QString TreeItem::variantToString(const QVariant &value, const QString &typeNode
return QLatin1String("0x") + value.toByteArray().toHex();
else if (value.type() == QVariant::DateTime)
return value.toDateTime().toString(Qt::ISODate);
- else if (value.canConvert<QOpcUa::QQualifiedName>()) {
- const auto name = value.value<QOpcUa::QQualifiedName>();
+ else if (value.canConvert<QOpcUaQualifiedName>()) {
+ const auto name = value.value<QOpcUaQualifiedName>();
return QStringLiteral("[NamespaceIndex: %1, Name: \"%2\"]").arg(name.namespaceIndex()).arg(name.name());
- } else if (value.canConvert<QOpcUa::QLocalizedText>()) {
- const auto text = value.value<QOpcUa::QLocalizedText>();
+ } else if (value.canConvert<QOpcUaLocalizedText>()) {
+ const auto text = value.value<QOpcUaLocalizedText>();
return localizedTextToString(text);
- } else if (value.canConvert<QOpcUa::QRange>()) {
- const auto range = value.value<QOpcUa::QRange>();
+ } else if (value.canConvert<QOpcUaRange>()) {
+ const auto range = value.value<QOpcUaRange>();
return rangeToString(range);
- } else if (value.canConvert<QOpcUa::QComplexNumber>()) {
- const auto complex = value.value<QOpcUa::QComplexNumber>();
+ } else if (value.canConvert<QOpcUaComplexNumber>()) {
+ const auto complex = value.value<QOpcUaComplexNumber>();
return QStringLiteral("[Real: %1, Imaginary: %2]").arg(complex.real()).arg(complex.imaginary());
- } else if (value.canConvert<QOpcUa::QDoubleComplexNumber>()) {
- const auto complex = value.value<QOpcUa::QDoubleComplexNumber>();
+ } else if (value.canConvert<QOpcUaDoubleComplexNumber>()) {
+ const auto complex = value.value<QOpcUaDoubleComplexNumber>();
return QStringLiteral("[Real: %1, Imaginary: %2]").arg(complex.real()).arg(complex.imaginary());
- } else if (value.canConvert<QOpcUa::QXValue>()) {
- const auto xv = value.value<QOpcUa::QXValue>();
+ } else if (value.canConvert<QOpcUaXValue>()) {
+ const auto xv = value.value<QOpcUaXValue>();
return QStringLiteral("[X: %1, Value: %2]").arg(xv.x()).arg(xv.value());
- } else if (value.canConvert<QOpcUa::QEUInformation>()) {
- const auto info = value.value<QOpcUa::QEUInformation>();
+ } else if (value.canConvert<QOpcUaEUInformation>()) {
+ const auto info = value.value<QOpcUaEUInformation>();
return euInformationToString(info);
- } else if (value.canConvert<QOpcUa::QAxisInformation>()) {
- const auto info = value.value<QOpcUa::QAxisInformation>();
+ } else if (value.canConvert<QOpcUaAxisInformation>()) {
+ const auto info = value.value<QOpcUaAxisInformation>();
return QStringLiteral("[EUInformation: %1, EURange: %2, Title: %3 , AxisScaleType: %4, AxisSteps: %5]").arg(
euInformationToString(info.engineeringUnits())).arg(rangeToString(info.eURange())).arg(localizedTextToString(info.title())).arg(
info.axisScaleType() == QOpcUa::AxisScale::Linear ? "Linear" : (info.axisScaleType() == QOpcUa::AxisScale::Ln) ? "Ln" : "Log").arg(
numberArrayToString(info.axisSteps()));
- } else if (value.canConvert<QOpcUa::QExpandedNodeId>()) {
- const auto id = value.value<QOpcUa::QExpandedNodeId>();
+ } else if (value.canConvert<QOpcUaExpandedNodeId>()) {
+ const auto id = value.value<QOpcUaExpandedNodeId>();
return QStringLiteral("[NodeId: \"%1\", ServerIndex: \"%2\", NamespaceUri: \"%3\"]").arg(
id.nodeId()).arg(id.serverIndex()).arg(id.namespaceUri());
- } else if (value.canConvert<QOpcUa::QArgument>()) {
- const auto a = value.value<QOpcUa::QArgument>();
+ } else if (value.canConvert<QOpcUaArgument>()) {
+ const auto a = value.value<QOpcUaArgument>();
return QStringLiteral("[Name: \"%1\", DataType: \"%2\", ValueRank: \"%3\", ArrayDimensions: %4, Description: %5]").arg(
a.name()).arg(a.dataTypeId()).arg(a.valueRank()).arg(numberArrayToString(a.arrayDimensions())).arg(
localizedTextToString(a.description()));
- } else if (value.canConvert<QOpcUa::QExtensionObject>()) {
- const auto obj = value.value<QOpcUa::QExtensionObject>();
+ } else if (value.canConvert<QOpcUaExtensionObject>()) {
+ const auto obj = value.value<QOpcUaExtensionObject>();
return QStringLiteral("[TypeId: \"%1\", Encoding: %2, Body: 0x%3]").arg(obj.encodingTypeId()).arg(
- obj.encoding() == QOpcUa::QExtensionObject::Encoding::NoBody ?
- "NoBody" : (obj.encoding() == QOpcUa::QExtensionObject::Encoding::ByteString ?
+ obj.encoding() == QOpcUaExtensionObject::Encoding::NoBody ?
+ "NoBody" : (obj.encoding() == QOpcUaExtensionObject::Encoding::ByteString ?
"ByteString" : "XML")).arg(obj.encodedBody().isEmpty() ? "0" : QString(obj.encodedBody().toHex()));
}
@@ -345,17 +355,17 @@ QString TreeItem::variantToString(const QVariant &value, const QString &typeNode
return QString();
}
-QString TreeItem::localizedTextToString(const QOpcUa::QLocalizedText &text) const
+QString TreeItem::localizedTextToString(const QOpcUaLocalizedText &text) const
{
return QStringLiteral("[Locale: \"%1\", Text: \"%2\"]").arg(text.locale()).arg(text.text());
}
-QString TreeItem::rangeToString(const QOpcUa::QRange &range) const
+QString TreeItem::rangeToString(const QOpcUaRange &range) const
{
return QStringLiteral("[Low: %1, High: %2]").arg(range.low()).arg(range.high());
}
-QString TreeItem::euInformationToString(const QOpcUa::QEUInformation &info) const
+QString TreeItem::euInformationToString(const QOpcUaEUInformation &info) const
{
return QStringLiteral("[UnitId: %1, NamespaceUri: \"%2\", DisplayName: %3, Description: %4]").arg(info.unitId()).arg(
info.namespaceUri()).arg(localizedTextToString(info.displayName())).arg(localizedTextToString(info.description()));
diff --git a/examples/opcua/opcuaviewer/treeitem.h b/examples/opcua/opcuaviewer/treeitem.h
index bc3c8a9..eef36a7 100644
--- a/examples/opcua/opcuaviewer/treeitem.h
+++ b/examples/opcua/opcuaviewer/treeitem.h
@@ -58,6 +58,8 @@
QT_BEGIN_NAMESPACE
class OpcUaModel;
+class QOpcUaRange;
+class QOpcUaEUInformation;
class TreeItem : public QObject
{
@@ -89,9 +91,9 @@ protected:
private:
QString variantToString(const QVariant &value, const QString &typeNodeId = QString()) const;
- QString localizedTextToString(const QOpcUa::QLocalizedText &text) const;
- QString rangeToString(const QOpcUa::QRange &range) const;
- QString euInformationToString(const QOpcUa::QEUInformation &info) const;
+ QString localizedTextToString(const QOpcUaLocalizedText &text) const;
+ QString rangeToString(const QOpcUaRange &range) const;
+ QString euInformationToString(const QOpcUaEUInformation &info) const;
template <typename T>
QString numberArrayToString(const QVector<T> &vec) const;
diff --git a/examples/opcua/waterpump/simulationserver/simulationserver.pro b/examples/opcua/waterpump/simulationserver/simulationserver.pro
index f644c2d..5580daa 100644
--- a/examples/opcua/waterpump/simulationserver/simulationserver.pro
+++ b/examples/opcua/waterpump/simulationserver/simulationserver.pro
@@ -1,24 +1,27 @@
TEMPLATE = app
+CONFIG += c++11 console
+QT += opcua opcua-private
-INCLUDEPATH += \
- $$PWD/../../../../src/plugins/opcua/open62541
+# Installed example package
+MODULE_SOURCES=../../../../../../../$$QT_VERSION/Automation/sources/qtopcua/
+!exists($$MODULE_SOURCES):{
+ # Build from source tree
+ MODULE_SOURCES=$$PWD/../../../../
+}
+INCLUDEPATH += $$MODULE_SOURCES/src/plugins/opcua/open62541
DEPENDPATH += INCLUDEPATH
-CONFIG += c++11 console
-
-QT += opcua opcua-private
-
qtConfig(open62541):!qtConfig(system-open62541) {
- include($$PWD/../../../../src/3rdparty/open62541.pri)
+ include($$MODULE_SOURCES/src/3rdparty/open62541.pri)
} else {
QMAKE_USE_PRIVATE += open62541
}
SOURCES += main.cpp \
simulationserver.cpp \
- $$PWD/../../../../src/plugins/opcua/open62541/qopen62541utils.cpp \
- $$PWD/../../../../src/plugins/opcua/open62541/qopen62541valueconverter.cpp
+ $$MODULE_SOURCES/src/plugins/opcua/open62541/qopen62541utils.cpp \
+ $$MODULE_SOURCES/src/plugins/opcua/open62541/qopen62541valueconverter.cpp
HEADERS += \
simulationserver.h
diff --git a/examples/opcua/waterpump/waterpump-qml/MachineDisplay.qml b/examples/opcua/waterpump/waterpump-qml/MachineDisplay.qml
index d4b0edb..cdec1ff 100644
--- a/examples/opcua/waterpump/waterpump-qml/MachineDisplay.qml
+++ b/examples/opcua/waterpump/waterpump-qml/MachineDisplay.qml
@@ -52,7 +52,7 @@
import QtQuick 2.10
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.3
-import QtOpcUa 5.12 as QtOpcUa
+import QtOpcUa 5.13 as QtOpcUa
import "qrc:/machine"
RowLayout {
diff --git a/examples/opcua/waterpump/waterpump-qml/ServerControl.qml b/examples/opcua/waterpump/waterpump-qml/ServerControl.qml
index 867308a..2b5fe51 100644
--- a/examples/opcua/waterpump/waterpump-qml/ServerControl.qml
+++ b/examples/opcua/waterpump/waterpump-qml/ServerControl.qml
@@ -52,11 +52,12 @@
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
-import QtOpcUa 5.12 as QtOpcUa
+import QtOpcUa 5.13 as QtOpcUa
RowLayout {
readonly property alias backend: backendSelector.currentText
property QtOpcUa.Connection connection
+ property QtOpcUa.ServerDiscovery serverDiscovery
signal resetSimulation()
TextField {
@@ -76,7 +77,7 @@ RowLayout {
if (connection.connected)
connection.disconnectFromEndpoint()
else
- connection.connectToEndpoint(uaUrl.text)
+ serverDiscovery.discoveryUrl = uaUrl.text;
}
}
Button {
diff --git a/examples/opcua/waterpump/waterpump-qml/doc/waterpump-qml.qdoc b/examples/opcua/waterpump/waterpump-qml/doc/waterpump-qml.qdoc
index 982b3af..620f9d5 100644
--- a/examples/opcua/waterpump/waterpump-qml/doc/waterpump-qml.qdoc
+++ b/examples/opcua/waterpump/waterpump-qml/doc/waterpump-qml.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -28,13 +28,12 @@
/*!
\example waterpump/waterpump-qml
\ingroup qtopcua-examples
- \title Example using the QML API for Qt OPC UA
- \brief This example shows how to use Qt OPC UA QML API to interact with an OPC UA
- server to build a QML based HMI for a simple machine.
+ \title Qt Quick Waterpump Example
+ \brief Interacting with an OPC UA server to build a QML-based HMI for a
+ simple machine.
- \section1 Introduction
- This example shows how to use Qt OPC UA QML API to interact with an OPC UA
- server to build a QML based HMI for a simple machine.
+ \e{Qt Quick Waterpump} shows how to use Qt OPC UA QML API to interact with
+ an OPC UA server to build a QML based HMI for a simple machine.
\section1 The Simulation
The OPC UA server included in this example runs a simulation of a machine
@@ -108,7 +107,7 @@
For example, the button to flush the second tank is enabled
only if the backend is connected to the server, the machine is idle, and
- the tank level is above the setpoint. On click, the flushTank2() method
+ the tank level is above the setpoint. On click, the \c flushTank2() method
is called on the server.
\quotefromfile waterpump/waterpump-qml/MachineDisplay.qml
diff --git a/examples/opcua/waterpump/waterpump-qml/machine/Machine.qml b/examples/opcua/waterpump/waterpump-qml/machine/Machine.qml
index b68a52e..ebccb70 100644
--- a/examples/opcua/waterpump/waterpump-qml/machine/Machine.qml
+++ b/examples/opcua/waterpump/waterpump-qml/machine/Machine.qml
@@ -49,7 +49,7 @@
****************************************************************************/
import QtQuick 2.10
-import QtOpcUa 5.12 as QtOpcUa
+import QtOpcUa 5.13 as QtOpcUa
Item {
readonly property alias tank1: tank1
diff --git a/examples/opcua/waterpump/waterpump-qml/machine/Tank.qml b/examples/opcua/waterpump/waterpump-qml/machine/Tank.qml
index 51ab83d..41a1826 100644
--- a/examples/opcua/waterpump/waterpump-qml/machine/Tank.qml
+++ b/examples/opcua/waterpump/waterpump-qml/machine/Tank.qml
@@ -49,7 +49,7 @@
****************************************************************************/
import QtQuick 2.10
-import QtOpcUa 5.12 as QtOpcUa
+import QtOpcUa 5.13 as QtOpcUa
Item {
property QtOpcUa.Node tankNode
diff --git a/examples/opcua/waterpump/waterpump-qml/main.qml b/examples/opcua/waterpump/waterpump-qml/main.qml
index 5f04832..96d5eaa 100644
--- a/examples/opcua/waterpump/waterpump-qml/main.qml
+++ b/examples/opcua/waterpump/waterpump-qml/main.qml
@@ -53,7 +53,7 @@ import QtQuick 2.10
import QtQuick.Window 2.2
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
-import QtOpcUa 5.12 as QtOpcUa
+import QtOpcUa 5.13 as QtOpcUa
import "qrc:/machine"
Window {
@@ -68,6 +68,25 @@ Window {
id: connection
backend: serverControl.backend
defaultConnection: true
+
+ }
+
+ QtOpcUa.ServerDiscovery {
+ id: serverDiscovery
+ onServersChanged: {
+ if (!count)
+ return;
+ endpointDiscovery.serverUrl = at(0).discoveryUrls[0];
+ }
+ }
+
+ QtOpcUa.EndpointDiscovery {
+ id: endpointDiscovery
+ onEndpointsChanged: {
+ if (!count)
+ return;
+ connection.connectToEndpoint(at(0));
+ }
}
Machine {
@@ -81,6 +100,7 @@ Window {
ServerControl {
id: serverControl
connection: connection
+ serverDiscovery: serverDiscovery
}
MachineDisplay {
Layout.fillHeight: true
diff --git a/examples/opcua/waterpump/waterpump-qmlcpp/doc/waterpump-qmlcpp.qdoc b/examples/opcua/waterpump/waterpump-qmlcpp/doc/waterpump-qmlcpp.qdoc
index 51f5e89..3211991 100644
--- a/examples/opcua/waterpump/waterpump-qmlcpp/doc/waterpump-qmlcpp.qdoc
+++ b/examples/opcua/waterpump/waterpump-qmlcpp/doc/waterpump-qmlcpp.qdoc
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2018 basysKom GmbH, info@basyskom.com
** Contact: https://www.qt.io/licensing/
**
@@ -28,17 +29,16 @@
/*!
\example waterpump/waterpump-qmlcpp
\ingroup qtopcua-examples
- \title Using Qt OPC UA in a basic UI application
- \brief This example shows how to use Qt OPC UA to interact with an OPC UA
- server to build a QML based HMI for a simple machine.
+ \title Waterpump Example
+ \brief Interacting with an OPC UA server to build a QML-based HMI for a
+ simple machine.
- \section1 Introduction
- This example shows how to use Qt OPC UA to interact with an OPC UA
- server to build a QML based HMI for a simple machine.
+ \e {Waterpump} shows how to use Qt OPC UA to interact with an
+ OPC UA server to build a QML-based HMI for a simple machine.
\section1 The Simulation
The OPC UA server included in this example runs a simulation of a machine
- containing two tanks, a water pump and a valve. Water can be pumped from the
+ containing two tanks, a water pump, and a valve. Water can be pumped from the
first tank into the second tank and then be flushed from the second tank
by opening the valve. Both operations have a user-configurable setpoint
which controls how much water is pumped to or flushed from the second tank.
@@ -83,17 +83,17 @@
All methods return \l {QOpcUa::UaStatusCode} {Good} in case of success and
\l {QOpcUa::UaStatusCode} {BadUserAccessDenied} if the operation is illegal
- (e. g. trying to start the pump if the first tank is empty).
+ (for example, trying to start the pump if the first tank is empty).
- \section1 Used Features of \l QOpcUaClient
- This example uses read, write, method calls and data change subscriptions
+ \section1 Client Features
+ This example uses read, write, method calls, and data change subscriptions
and shows how to set up handlers for the asynchronous operations offered
by QOpcUaClient and QOpcUaNode.
\section1 Implementation
A backend class is used to handle the communication with the OPC UA server
- and expose the content of this server by means of properties and Q_INVOKABLE
+ and expose the content of this server by means of properties and \c Q_INVOKABLE
methods wrapping the OPC UA method calls.
\section2 Member Variables
@@ -109,7 +109,7 @@
\codeline
\dots
- For each value used in the HMI, a getter, a changed signal and a
+ For each value used in the HMI, a getter, a changed signal, and a
property are added to enable property bindings in QML
\quotefromfile waterpump/waterpump-qmlcpp/opcuamachinebackend.h
@@ -124,7 +124,7 @@
Data change subscriptions report their updates using \l QOpcUaNode::attributeUpdated.
A handler connected to this signal gets the new value as QVariant and can
- e. g. write that value to a variable or emit a signal with the new value.
+ write that value to a variable or emit a signal with the new value, for example.
\quotefromfile waterpump/waterpump-qmlcpp/opcuamachinebackend.cpp
\skipto void OpcUaMachineBackend::percentFilledTank1Updated
@@ -140,7 +140,8 @@
\section2 Interaction with the Server
- In the constructor, a QOpcUaProvider is created and the available backends are saved to provide a model for the backend selection dropdown menu.
+ In the constructor, a QOpcUaProvider is created and the available backends
+ are saved to provide a model for the backend selection dropdown menu.
\quotefromfile waterpump/waterpump-qmlcpp/opcuamachinebackend.cpp
\dots
@@ -148,15 +149,28 @@
\printuntil setBackends
\dots
- Before attempting a connection, a QOpcUaClient with the selected backend is created. Its \l QOpcUaClient::stateChanged signal must be
- connected to the backend's clientStateHandler slot.
+ Before attempting a connection, a QOpcUaClient with the selected backend is created.
+ Its \l QOpcUaClient::endpointsRequestFinished signal is connected to the
+ backend's \c requestEndpointsFinished slot.
+ The \l QOpcUaClient::stateChanged signal must be connected to the backend's
+ \c clientStateHandler slot.
\quotefromfile waterpump/waterpump-qmlcpp/opcuamachinebackend.cpp
\skipto OpcUaMachineBackend::connectToEndpoint
+ \printuntil m_client->requestEndpoints
+ \printuntil }
+
+ The \c OpcUaMachineBackend::requestEndpointsFinished slot receives the list
+ of available endpoints on the server and starts a connection to the first
+ entry in the list. If there are no available endpoints, the connection
+ establishment is aborted.
+
+ \quotefromfile waterpump/waterpump-qmlcpp/opcuamachinebackend.cpp
+ \skipto void OpcUaMachineBackend::requestEndpointsFinished
\printuntil m_client->connectToEndpoint
\printuntil }
- clientStateHandler acts on QOpcUaClient being connected or disconnected.
+ \c clientStateHandler acts on QOpcUaClient being connected or disconnected.
In case of a successful connection, the node member variables created before
are filled with node objects.
@@ -196,7 +210,7 @@
\section2 The HMI
A backend instance is created and handed to the QML part as a context property
- named uaBackend.
+ named \c uaBackend.
\dots
\quotefromfile waterpump/waterpump-qmlcpp/main.cpp
@@ -204,10 +218,10 @@
\printuntil setContextProperty
\dots
- The properties, signals and Q_INVOKABLE methods of uaBackend can now be accessed by
+ The properties, signals and \c Q_INVOKABLE methods of uaBackend can now be accessed by
the QML code. For example, the button to flush the second tank is enabled
only if the backend is connected to the server, the machine is idle and
- the tank level is above the setpoint. On click, the flushTank2() method
+ the tank level is above the setpoint. On click, the \c flushTank2() method
is called on the server.
\quotefromfile waterpump/waterpump-qmlcpp/Tank2Unit.qml
diff --git a/examples/opcua/waterpump/waterpump-qmlcpp/opcuamachinebackend.cpp b/examples/opcua/waterpump/waterpump-qmlcpp/opcuamachinebackend.cpp
index 8a7451d..e6ac84e 100644
--- a/examples/opcua/waterpump/waterpump-qmlcpp/opcuamachinebackend.cpp
+++ b/examples/opcua/waterpump/waterpump-qmlcpp/opcuamachinebackend.cpp
@@ -284,6 +284,16 @@ void OpcUaMachineBackend::resetSimulation()
m_machineNode->callMethod("ns=2;s=Machine.Reset");
}
+void OpcUaMachineBackend::requestEndpointsFinished(const QVector<QOpcUaEndpointDescription> &endpoints)
+{
+ if (endpoints.isEmpty()) {
+ qWarning() << "The server did not return any endpoints";
+ clientStateHandler(QOpcUaClient::ClientState::Disconnected);
+ return;
+ }
+ m_client->connectToEndpoint(endpoints.at(0));
+}
+
void OpcUaMachineBackend::setMessage(const QString &message)
{
if (message != m_message) {
@@ -324,8 +334,10 @@ void OpcUaMachineBackend::connectToEndpoint(const QString &url, qint32 index)
if (!m_client || (m_client && m_client->backend() != m_backends.at(index))) {
m_client.reset(provider.createClient(m_backends.at(index)));
- if (m_client)
+ if (m_client) {
+ QObject::connect(m_client.data(), &QOpcUaClient::endpointsRequestFinished, this, &OpcUaMachineBackend::requestEndpointsFinished);
QObject::connect(m_client.data(), &QOpcUaClient::stateChanged, this, &OpcUaMachineBackend::clientStateHandler);
+ }
}
if (!m_client) {
@@ -335,7 +347,7 @@ void OpcUaMachineBackend::connectToEndpoint(const QString &url, qint32 index)
}
m_successfullyCreated = true;
- m_client->connectToEndpoint(QUrl(url));
+ m_client->requestEndpoints(url);
}
void OpcUaMachineBackend::disconnectFromEndpoint()
diff --git a/examples/opcua/waterpump/waterpump-qmlcpp/opcuamachinebackend.h b/examples/opcua/waterpump/waterpump-qmlcpp/opcuamachinebackend.h
index 8d2d714..21f564e 100644
--- a/examples/opcua/waterpump/waterpump-qmlcpp/opcuamachinebackend.h
+++ b/examples/opcua/waterpump/waterpump-qmlcpp/opcuamachinebackend.h
@@ -102,6 +102,7 @@ public:
Q_INVOKABLE void resetSimulation();
public slots:
+ void requestEndpointsFinished(const QVector<QOpcUaEndpointDescription> &endpoints);
void clientStateHandler(QOpcUaClient::ClientState state);
void machineStateUpdated(QOpcUa::NodeAttribute attr, const QVariant &value);
void percentFilledTank1Updated(QOpcUa::NodeAttribute attr, const QVariant &value);
diff --git a/src/imports/doc/doc.pro b/src/imports/doc/doc.pro
new file mode 100644
index 0000000..4b60228
--- /dev/null
+++ b/src/imports/doc/doc.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = snippets
diff --git a/src/imports/doc/snippets/basic/basic.pro b/src/imports/doc/snippets/basic/basic.pro
new file mode 100644
index 0000000..20d4aa6
--- /dev/null
+++ b/src/imports/doc/snippets/basic/basic.pro
@@ -0,0 +1,4 @@
+QT += quick
+CONFIG += c++11
+SOURCES += main.cpp
+RESOURCES += qml.qrc
diff --git a/src/imports/doc/snippets/basic/basic.qml b/src/imports/doc/snippets/basic/basic.qml
new file mode 100644
index 0000000..da3c59c
--- /dev/null
+++ b/src/imports/doc/snippets/basic/basic.qml
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtOpcUa 5.13 as QtOpcUa
+
+Item {
+ //! [Basic discovery]
+ QtOpcUa.Connection {
+ id: connection
+ backend: availableBackends[0]
+ defaultConnection: true
+ }
+
+ QtOpcUa.ServerDiscovery {
+ discoveryUrl: "opc.tcp://127.0.0.1:43344"
+ onServersChanged: {
+ if (status.isGood) {
+ if (status.status == QtOpcUa.Status.GoodCompletesAsynchronusly)
+ return; // wait until finished
+ if (count > 0) {
+ // choose right server
+ endpointDiscovery.serverUrl = at(0).discoveryUrls[0];
+ console.log("Using server URL:", endpointDiscovery.serverUrl);
+ } else {
+ // no servers retrieved
+ }
+ } else {
+ // Fetching servers failed
+ console.log("Error fetching server:", servers.status.status);
+ }
+ }
+ }
+
+ QtOpcUa.EndpointDiscovery {
+ id: endpointDiscovery
+ onEndpointsChanged: {
+ if (status.isGood) {
+ if (status.status == QtOpcUa.Status.GoodCompletesAsynchronusly)
+ return; // wait until finished
+ if (count > 0) {
+ // choose right endpoint
+ console.log("Using endpoint", at(0).endpointUrl, at(0).securityPolicy);
+ connection.connectToEndpoint(at(0));
+ } else {
+ // no endpoints retrieved
+ }
+ } else {
+ // Fetching endpoints failed
+ console.log("Error fetching endpoints:", status.status);
+ }
+ }
+ }
+ //! [Basic discovery]
+}
diff --git a/src/imports/doc/snippets/basic/main.cpp b/src/imports/doc/snippets/basic/main.cpp
new file mode 100644
index 0000000..ca94f96
--- /dev/null
+++ b/src/imports/doc/snippets/basic/main.cpp
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+#include <QFile>
+#include <QDebug>
+#include <QProcess>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QString serverExePath;
+#ifdef Q_OS_WIN
+ #ifdef QT_DEBUG
+ serverExePath = app.applicationDirPath().append("/../../../../../../tests/open62541-testserver/debug/open62541-testserver.exe");
+ #else
+ serverExePath = app.applicationDirPath().append("/../../../../../../tests/open62541-testserver/release/open62541-testserver.exe");
+ #endif
+#elif defined(Q_OS_MACOS)
+ serverExePath = app.applicationDirPath().append("/../../../../../../../../tests/open62541-testserver/open62541-testserver.app/Contents/MacOS/open62541-testserver");
+#else
+ serverExePath = app.applicationDirPath().append("/../../../../../tests/open62541-testserver/open62541-testserver");
+#endif
+
+ if (!QFile::exists(serverExePath)) {
+ qWarning() << "Could not find server executable:" << serverExePath;
+ return EXIT_FAILURE;
+ }
+
+ QProcess serverProcess;
+
+ serverProcess.start(serverExePath);
+ if (!serverProcess.waitForStarted()) {
+ qWarning() << "Could not start server:" << serverProcess.errorString();
+ return EXIT_FAILURE;
+ }
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/basic.qml")));
+ if (engine.rootObjects().isEmpty())
+ return EXIT_FAILURE;
+
+ return app.exec();
+}
diff --git a/src/imports/doc/snippets/basic/qml.qrc b/src/imports/doc/snippets/basic/qml.qrc
new file mode 100644
index 0000000..8aa548d
--- /dev/null
+++ b/src/imports/doc/snippets/basic/qml.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>basic.qml</file>
+ </qresource>
+</RCC>
diff --git a/src/imports/doc/snippets/snippets.pro b/src/imports/doc/snippets/snippets.pro
new file mode 100644
index 0000000..34f621e
--- /dev/null
+++ b/src/imports/doc/snippets/snippets.pro
@@ -0,0 +1,5 @@
+TEMPLATE = subdirs
+
+linux {
+ SUBDIRS += basic
+ }
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index d7edd8e..c3c8233 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -1,3 +1,4 @@
TEMPLATE = subdirs
QT_FOR_CONFIG += opcua-private
+SUBDIRS += doc
qtHaveModule(opcua): SUBDIRS += opcua
diff --git a/src/imports/opcua/opcua.pro b/src/imports/opcua/opcua.pro
index cacf552..8326c1f 100644
--- a/src/imports/opcua/opcua.pro
+++ b/src/imports/opcua/opcua.pro
@@ -3,6 +3,7 @@ QT += quick opcua
SOURCES += \
opcua_plugin.cpp \
opcuaconnection.cpp \
+ opcuaendpointdiscovery.cpp \
opcuanode.cpp \
opcuamethodnode.cpp \
opcuavaluenode.cpp \
@@ -14,10 +15,26 @@ SOURCES += \
opcuapathresolver.cpp \
opcuaattributevalue.cpp \
opcuaattributecache.cpp \
+ opcuamethodargument.cpp \
+ opcuareaditem.cpp \
+ opcuareadresult.cpp \
+ opcuaserverdiscovery.cpp \
+ opcuastatus.cpp \
+ opcuawriteitem.cpp \
+ opcuawriteresult.cpp \
+ opcuadatachangefilter.cpp \
+ opcuaelementoperand.cpp \
+ opcualiteraloperand.cpp \
+ opcuasimpleattributeoperand.cpp \
+ opcuaattributeoperand.cpp \
+ opcuafilterelement.cpp \
+ opcuaeventfilter.cpp \
+ opcuaoperandbase.cpp \
HEADERS += \
opcua_plugin.h \
opcuaconnection.h \
+ opcuaendpointdiscovery.h \
opcuanode.h \
opcuamethodnode.h \
opcuavaluenode.h \
@@ -29,6 +46,21 @@ HEADERS += \
opcuapathresolver.h \
opcuaattributecache.h \
opcuaattributevalue.h \
+ opcuamethodargument.h \
+ opcuareaditem.h \
+ opcuareadresult.h \
+ opcuaserverdiscovery.h \
+ opcuastatus.h \
+ opcuawriteitem.h \
+ opcuawriteresult.h \
+ opcuadatachangefilter.h \
+ opcuaelementoperand.h \
+ opcualiteraloperand.h \
+ opcuasimpleattributeoperand.h \
+ opcuaattributeoperand.h \
+ opcuafilterelement.h \
+ opcuaeventfilter.h \
+ opcuaoperandbase.h \
load(qml_plugin)
diff --git a/src/imports/opcua/opcua_plugin.cpp b/src/imports/opcua/opcua_plugin.cpp
index 1f6accb..c46be14 100644
--- a/src/imports/opcua/opcua_plugin.cpp
+++ b/src/imports/opcua/opcua_plugin.cpp
@@ -35,15 +35,30 @@
****************************************************************************/
#include "opcua_plugin.h"
+#include "opcuaendpointdiscovery.h"
#include "opcuavaluenode.h"
#include "opcuamethodnode.h"
#include "opcuanodeid.h"
#include "opcuanodeidtype.h"
#include "opcuaconnection.h"
+#include "opcuadatachangefilter.h"
#include "opcuarelativenodepath.h"
#include "opcuarelativenodeid.h"
#include "qopcuatype.h"
+#include "opcuastatus.h"
+#include "opcuareaditem.h"
+#include "opcuareadresult.h"
+#include "opcuaserverdiscovery.h"
+#include "opcuawriteitem.h"
+#include "opcuawriteresult.h"
+#include "opcuaelementoperand.h"
+#include "opcualiteraloperand.h"
+#include "opcuasimpleattributeoperand.h"
+#include "opcuaattributeoperand.h"
+#include "opcuafilterelement.h"
+#include "opcuaeventfilter.h"
#include <QLoggingCategory>
+#include <QOpcUaUserTokenPolicy>
#include <qqml.h>
@@ -51,10 +66,40 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_QML, "qt.opcua.plugins.qml")
+/*!
+ \qmlproperty enumeration Constants::NodeAttribute
+
+ Attributes of a node
+
+ \value Constants.NodeAttribute.NodeId
+ \value Constants.NodeAttribute.NodeClass
+ \value Constants.NodeAttribute.BrowseName
+ \value Constants.NodeAttribute.DisplayName
+ \value Constants.NodeAttribute.Description
+ \value Constants.NodeAttribute.WriteMask
+ \value Constants.NodeAttribute.UserWriteMask
+ \value Constants.NodeAttribute.IsAbstract
+ \value Constants.NodeAttribute.Symmetric
+ \value Constants.NodeAttribute.InverseName
+ \value Constants.NodeAttribute.ContainsNoLoops
+ \value Constants.NodeAttribute.EventNotifier
+ \value Constants.NodeAttribute.Value
+ \value Constants.NodeAttribute.DataType
+ \value Constants.NodeAttribute.ValueRank
+ \value Constants.NodeAttribute.ArrayDimensions
+ \value Constants.NodeAttribute.AccessLevel
+ \value Constants.NodeAttribute.UserAccessLevel
+ \value Constants.NodeAttribute.MinimumSamplingInterval
+ \value Constants.NodeAttribute.Historizing
+ \value Constants.NodeAttribute.Executable
+ \value Constants.NodeAttribute.UserExecutable
+*/
namespace Constants {
Q_NAMESPACE
Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
Q_ENUM_NS(QOpcUa::ReferenceTypeId)
+ Q_ENUM_NS(QOpcUa::Types)
+ Q_ENUM_NS(QOpcUaUserTokenPolicy::TokenType)
// Only one type declaration is needed because all other
// types of the same meta object will be added automatically.
}
@@ -64,8 +109,8 @@ void OpcUaPlugin::registerTypes(const char *uri)
Q_ASSERT(uri == QStringLiteral("QtOpcUa"));
// @uri QtOpcUa
- const int major = 5;
- const int minor = 12;
+ int major = 5;
+ int minor = 12;
// Register the 5.12 types
@@ -80,6 +125,41 @@ void OpcUaPlugin::registerTypes(const char *uri)
qmlRegisterType<OpcUaRelativeNodeId>(uri, major, minor, "RelativeNodeId");
qmlRegisterUncreatableMetaObject(Constants::staticMetaObject, uri, major, minor, "Constants", "This type can not be created.");
+ // Register the 5.13 types
+
+ major = 5;
+ minor = 13;
+
+ qmlRegisterType<OpcUaMethodArgument>(uri, major, minor, "MethodArgument");
+ qmlRegisterUncreatableType<QOpcUaApplicationDescription>(uri, major, minor, "ApplicationDescription", "This type can not be created.");
+ qRegisterMetaType<OpcUaStatus>();
+ qmlRegisterUncreatableType<OpcUaStatus>(uri, major, minor, "Status", "This type can not be created.");
+ qmlRegisterSingletonType<OpcUaReadItemFactory>(uri, major, minor, "ReadItem", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject* {
+ Q_UNUSED(engine)
+ Q_UNUSED(scriptEngine)
+
+ return new OpcUaReadItemFactory();
+ });
+ qmlRegisterSingletonType<OpcUaWriteItemFactory>(uri, major, minor, "WriteItem", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject* {
+ Q_UNUSED(engine)
+ Q_UNUSED(scriptEngine)
+ return new OpcUaWriteItemFactory();
+ });
+ qRegisterMetaType<OpcUaReadItem>();
+ qRegisterMetaType<OpcUaReadResult>();
+ qRegisterMetaType<OpcUaWriteItem>();
+ qRegisterMetaType<OpcUaWriteResult>();
+ qmlRegisterType<OpcUaEndpointDiscovery>(uri, major, minor, "EndpointDiscovery");
+ qmlRegisterType<OpcUaServerDiscovery>(uri, major, minor, "ServerDiscovery");
+ qmlRegisterUncreatableType<QOpcUaUserTokenPolicy>(uri, major, minor, "UserTokenPolicy", "This type can not be created.");
+ qmlRegisterType<OpcUaDataChangeFilter>(uri, major, minor, "DataChangeFilter");
+ qmlRegisterType<OpcUaElementOperand>(uri, major, minor, "ElementOperand");
+ qmlRegisterType<OpcUaLiteralOperand>(uri, major, minor, "LiteralOperand");
+ qmlRegisterType<OpcUaSimpleAttributeOperand>(uri, major, minor, "SimpleAttributeOperand");
+ qmlRegisterType<OpcUaAttributeOperand>(uri, major, minor, "AttributeOperand");
+ qmlRegisterType<OpcUaFilterElement>(uri, major, minor, "FilterElement");
+ qmlRegisterType<OpcUaEventFilter>(uri, major, minor, "EventFilter");
+
// insert new versions here
// Register the latest Qt version as QML type version
diff --git a/src/imports/opcua/opcuaattributeoperand.cpp b/src/imports/opcua/opcuaattributeoperand.cpp
new file mode 100644
index 0000000..3223651
--- /dev/null
+++ b/src/imports/opcua/opcuaattributeoperand.cpp
@@ -0,0 +1,250 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcuaattributeoperand.h"
+#include "opcuanodeid.h"
+#include "universalnode.h"
+#include "opcuarelativenodepath.h"
+#include <QOpcUaRelativePathElement>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype AttributeOperand
+ \inqmlmodule QtOpcUa
+ \brief The OPC UA AttributeOperand type.
+ \since QtOpcUa 5.13
+
+ The AttributeOperand is defined in OPC-UA part 4, 7.4.4.4.
+ It has the same purpose as \l SimpleAttributeOperand but has more configurable options.
+*/
+
+/*!
+ \qmlproperty list<OpcUaNodeId> AttributeOperand::browsePath
+
+ Browse path to the node holding the attribute.
+
+ \code
+ import QtOpcUa 5.13 as QtOpcUa
+
+ QtOpcUA.AttributeOperand {
+ ...
+ browsePath: [
+ QtOpcUa.NodeId {
+ identifier: "Message"
+ ns: "http://opcfoundation.org/UA/"
+ }
+ ...
+ ]
+ }
+*/
+
+/*!
+ \qmlproperty string AttributeOperand::indexRange
+
+ Index range string used to identify a single value or subset of the attribute's value.
+
+ \code
+ import QtOpcUa 5.13 as QtOpcUa
+
+ QtOpcUa.AttributeOperand {
+ ...
+ indexRange: "0:2"
+ }
+ \endcode
+*/
+
+/*!
+ \qmlproperty Constants.NodeAttribute AttributeOperand::nodeAttribute
+
+ Attribute of the node \l browsePath is pointing to.
+ The default value is \c Constants.NodeAttribute.Value.
+
+ \code
+ import QtOpcUa 5.13 as QtOpcUa
+
+ QtOpcUa.AttributeOperand {
+ ...
+ nodeAttribute: QtOpcUa.Constants.NodeAttribute.Value
+ }
+ \endcode
+*/
+
+/*!
+ \qmlproperty string AttributeOperand::typeId
+
+ Node id of the type definition node. The operand will be of the type or one of its subtypes.
+
+ \code
+ import QtOpcUa 5.13 as QtOpcUa
+
+ QtOpcUa.AttributeOperand {
+ ...
+ typeId: "ns=0;i=2041"
+ }
+ \endcode
+*/
+
+/*!
+ \qmlproperty string AttributeOperand::alias
+
+ Alias name for the operand. This allows using this instance
+ as operand for other operations in the filter.
+*/
+
+OpcUaAttributeOperand::OpcUaAttributeOperand(QObject *parent)
+ : OpcUaOperandBase(parent)
+{
+}
+
+OpcUaAttributeOperand::~OpcUaAttributeOperand() = default;
+
+QVariant OpcUaAttributeOperand::toCppVariant(QOpcUaClient *client) const
+{
+ QOpcUaAttributeOperand value(*this);
+
+ if (m_nodeId) {
+ UniversalNode un(m_nodeId);
+ un.resolveNamespace(client);
+ value.setAlias(un.fullNodeId());
+ }
+
+ for (const auto &i : m_browsePath)
+ value.browsePathRef().append(i->toRelativePathElement(client));
+ return value;
+}
+
+QString OpcUaAttributeOperand::indexRange() const
+{
+ return QOpcUaAttributeOperand::indexRange();
+}
+
+void OpcUaAttributeOperand::setIndexRange(const QString &indexRange)
+{
+ if (indexRange != QOpcUaAttributeOperand::indexRange()) {
+ QOpcUaAttributeOperand::setIndexRange(indexRange);
+ emit dataChanged();
+ }
+}
+
+QOpcUa::NodeAttribute OpcUaAttributeOperand::nodeAttribute() const
+{
+ return QOpcUaAttributeOperand::attributeId();
+}
+
+void OpcUaAttributeOperand::setNodeAttribute(QOpcUa::NodeAttribute nodeAttribute)
+{
+ if (nodeAttribute != QOpcUaAttributeOperand::attributeId()) {
+ QOpcUaAttributeOperand::setAttributeId(nodeAttribute);
+ emit dataChanged();
+ }
+}
+
+OpcUaNodeId *OpcUaAttributeOperand::typeId() const
+{
+ return m_nodeId;
+}
+
+void OpcUaAttributeOperand::setTypeId(OpcUaNodeId *typeId)
+{
+ if (typeId != m_nodeId) {
+ m_nodeId = typeId;
+ emit dataChanged();
+ }
+}
+
+QQmlListProperty<OpcUaRelativeNodePath> OpcUaAttributeOperand::browsePath()
+{
+ return QQmlListProperty<OpcUaRelativeNodePath>(this, this,
+ &OpcUaAttributeOperand::appendBrowsePathElement,
+ &OpcUaAttributeOperand::browsePathSize,
+ &OpcUaAttributeOperand::browsePathElement,
+ &OpcUaAttributeOperand::clearBrowsePath);
+}
+
+void OpcUaAttributeOperand::appendBrowsePathElement(OpcUaRelativeNodePath *nodeId)
+{
+ m_browsePath.append(nodeId);
+ emit dataChanged();
+}
+
+int OpcUaAttributeOperand::browsePathSize() const
+{
+ return m_browsePath.size();
+}
+
+OpcUaRelativeNodePath *OpcUaAttributeOperand::browsePathElement(int index) const
+{
+ return m_browsePath.at(index);
+}
+
+void OpcUaAttributeOperand::clearBrowsePath()
+{
+ m_browsePath.clear();
+ emit dataChanged();
+}
+
+void OpcUaAttributeOperand::appendBrowsePathElement(QQmlListProperty<OpcUaRelativeNodePath> *list, OpcUaRelativeNodePath *nodeId)
+{
+ reinterpret_cast<OpcUaAttributeOperand*>(list->data)->appendBrowsePathElement(nodeId);
+}
+
+int OpcUaAttributeOperand::browsePathSize(QQmlListProperty<OpcUaRelativeNodePath> *list)
+{
+ return reinterpret_cast<OpcUaAttributeOperand*>(list->data)->browsePathSize();
+}
+
+OpcUaRelativeNodePath *OpcUaAttributeOperand::browsePathElement(QQmlListProperty<OpcUaRelativeNodePath> *list, int index)
+{
+ return reinterpret_cast<OpcUaAttributeOperand*>(list->data)->browsePathElement(index);
+}
+
+void OpcUaAttributeOperand::clearBrowsePath(QQmlListProperty<OpcUaRelativeNodePath> *list)
+{
+ reinterpret_cast<OpcUaAttributeOperand*>(list->data)->clearBrowsePath();
+}
+
+QString OpcUaAttributeOperand::alias() const
+{
+ return QOpcUaAttributeOperand::alias();
+}
+
+void OpcUaAttributeOperand::setAlias(const QString &alias)
+{
+ QOpcUaAttributeOperand::setAlias(alias);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuaattributeoperand.h b/src/imports/opcua/opcuaattributeoperand.h
new file mode 100644
index 0000000..de2f332
--- /dev/null
+++ b/src/imports/opcua/opcuaattributeoperand.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPCUAATTRIBUTEOPERAND
+#define OPCUAATTRIBUTEOPERAND
+
+#include "opcuaoperandbase.h"
+#include <QOpcUaAttributeOperand>
+#include <QQmlListProperty>
+
+QT_BEGIN_NAMESPACE
+
+class OpcUaNodeId;
+class OpcUaRelativeNodePath;
+class QOpcUaClient;
+
+class OpcUaAttributeOperand : public OpcUaOperandBase, private QOpcUaAttributeOperand {
+ Q_OBJECT
+ Q_PROPERTY(QQmlListProperty<OpcUaRelativeNodePath> browsePath READ browsePath)
+ Q_PROPERTY(QString indexRange READ indexRange WRITE setIndexRange)
+ Q_PROPERTY(QOpcUa::NodeAttribute nodeAttribute READ nodeAttribute WRITE setNodeAttribute)
+ Q_PROPERTY(OpcUaNodeId* typeId READ typeId WRITE setTypeId)
+ Q_PROPERTY(QString alias READ alias WRITE setAlias)
+
+public:
+ explicit OpcUaAttributeOperand(QObject *parent = nullptr);
+ ~OpcUaAttributeOperand();
+ virtual QVariant toCppVariant(QOpcUaClient *client) const override;
+
+ OpcUaNodeId *typeId() const;
+ void setTypeId(OpcUaNodeId *nodeId);
+
+ QString alias() const;
+ void setAlias(const QString &alias);
+
+ QString indexRange() const;
+ void setIndexRange(const QString &indexRange);
+
+ QOpcUa::NodeAttribute nodeAttribute() const;
+ void setNodeAttribute(QOpcUa::NodeAttribute nodeAttribute);
+
+ QQmlListProperty<OpcUaRelativeNodePath> browsePath();
+ void appendBrowsePathElement(OpcUaRelativeNodePath *nodeId);
+ int browsePathSize() const;
+ OpcUaRelativeNodePath *browsePathElement(int index) const;
+ void clearBrowsePath();
+
+signals:
+ void dataChanged();
+
+private:
+ static void appendBrowsePathElement(QQmlListProperty<OpcUaRelativeNodePath> *list, OpcUaRelativeNodePath *nodeId);
+ static int browsePathSize(QQmlListProperty<OpcUaRelativeNodePath> *list);
+ static OpcUaRelativeNodePath* browsePathElement(QQmlListProperty<OpcUaRelativeNodePath> *list, int index);
+ static void clearBrowsePath(QQmlListProperty<OpcUaRelativeNodePath> *list);
+
+ QVector<OpcUaRelativeNodePath*> m_browsePath;
+ OpcUaNodeId *m_nodeId = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // OPCUASIMPLEATTRIBUTEOPERAND
diff --git a/src/imports/opcua/opcuaconnection.cpp b/src/imports/opcua/opcuaconnection.cpp
index 7cbb8c5..3454520 100644
--- a/src/imports/opcua/opcuaconnection.cpp
+++ b/src/imports/opcua/opcuaconnection.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt OPC UA module.
@@ -35,8 +35,16 @@
****************************************************************************/
#include "opcuaconnection.h"
-#include <QOpcUaProvider>
+#include "opcuareadresult.h"
+#include "opcuawriteitem.h"
+#include "opcuawriteresult.h"
+#include "universalnode.h"
+#include <QJSEngine>
#include <QLoggingCategory>
+#include <QOpcUaProvider>
+#include <QOpcUaReadItem>
+#include <QOpcUaReadResult>
+#include <QOpcUaWriteItem>
QT_BEGIN_NAMESPACE
@@ -50,7 +58,7 @@ QT_BEGIN_NAMESPACE
any connection attempt.
\code
- import QtOpcUa 5.12 as QtOpcUa
+ import QtOpcUa 5.13 as QtOpcUa
QtOpcUa.Connection {
backend: "open62541"
@@ -116,6 +124,134 @@ QT_BEGIN_NAMESPACE
List of strings of all namespace URIs registered on the connected server.
*/
+/*!
+ \qmlproperty AuthenticationInformation Connection::authenticationInformation
+
+ Set the authentication information to this connection. The authentication information has
+ to be set before calling \l connectToEndpoint. If no authentication information is set,
+ the anonymous mode will be used.
+ It has no effect on the current connection. If the client is disconnected and then reconnected,
+ the new credentials are used.
+ Reading and writing this property before a \l backend is set, writes are ignored and reads return
+ and invalid \l AuthenticationInformation.
+*/
+
+/*!
+ \qmlproperty stringlist Connection::supportedSecurityPolicies
+ \since 5.13
+
+ A list of strings containing the supported security policies
+
+ This property is currently available as a Technology Preview, and therefore the API
+ and functionality provided may be subject to change at any time without
+ prior notice.
+*/
+
+/*!
+ \qmlproperty array[tokenTypes] Connection::supportedUserTokenTypes
+ \since 5.13
+
+ An array of user token policy types of all supported user token types.
+
+ This property is currently available as a Technology Preview, and therefore the API
+ and functionality provided may be subject to change at any time without
+ prior notice.
+*/
+
+/*!
+ \qmlproperty QOpcUaEndpointDescription Connection::currentEndpoint
+ \since 5.13
+
+ An endpoint description of the server to which the connection is connected to.
+ When the connection is not established, an empty endpoint description is returned.
+*/
+
+/*!
+ \qmlsignal Connection::readNodeAttributesFinished(readResults)
+ \since 5.13
+
+ Emitted when the read request, started using \l readNodeAttributes(), is finished.
+ The parameter of this signal is an array of \l ReadResult, which contains the
+ values requested from the server.
+
+ \code
+ connection.onReadNodeAttributesFinished(results) {
+ for (var i = 0; results.length; i++) {
+ if (results[i].status.isGood) {
+ console.log(results[i].value);
+ } else {
+ // handle error
+ }
+ }
+ }
+ \endcode
+
+ \sa readNodeAttributes(), ReadResult
+*/
+
+/*!
+ \qmlsignal Connection::writeNodeAttributesFinished(writeResults)
+ \since 5.13
+
+ Emitted when the write request started using \l writeNodeAttributes() is
+ finished. The parameter of this signal is an array of \l WriteResult, which
+ contains the values requested from the server.
+
+ \code
+ for (var i = 0; i < writeResults.length; i++) {
+ console.log(writeResults[i].nodeId);
+ console.log(writeResults[i].namespaceName);
+ console.log(writeResults[i].attribute);
+
+ if (writeResults[i].status.isBad) {
+ // value was not written
+ }
+ }
+ \endcode
+
+ \sa writeNodeAttributes(), WriteResult
+
+*/
+
+/*!
+ \qmlproperty QOpcUaClient Connection::connection
+ \since 5.13
+
+ This property is used only to inject a connection from C++. In case of complex setup of
+ a connection you can use C++ to handle all the details. After the connection is established
+ it can be handed to QML using this property. Ownership of the client is transferred to QML.
+
+ \code
+ class MyClass : public QObject {
+ Q_OBJECT
+ Q_PROPERTY(QOpcUaClient* connection READ connection NOTIFY connectionChanged)
+
+ public:
+ MyClass (QObject* parent = nullptr);
+ QOpcUaClient *connection() const;
+
+ signals:
+ void connectionChanged(QOpcUaClient *);
+ \endcode
+
+ Emitting the signal \c connectionChanged when the client setup is completed, the QML code below will
+ use the connection.
+
+ \code
+ import QtOpcUa 5.13 as QtOpcUa
+
+ MyClass {
+ id: myclass
+ }
+
+ QtOpcUa.Connection {
+ connection: myclass.connection
+ }
+ \endcode
+
+*/
+
+
Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_QML)
OpcUaConnection* OpcUaConnection::m_defaultConnection = nullptr;
@@ -128,10 +264,7 @@ OpcUaConnection::OpcUaConnection(QObject *parent):
OpcUaConnection::~OpcUaConnection()
{
setDefaultConnection(false);
- if (m_client) {
- m_client->deleteLater();
- m_client = nullptr;
- }
+ removeConnection();
}
QStringList OpcUaConnection::availableBackends() const
@@ -159,24 +292,14 @@ void OpcUaConnection::setBackend(const QString &name)
if (m_client->backend() == name)
return;
- m_client->disconnectFromEndpoint();
- m_client->disconnect(this);
- m_client->deleteLater();
+ removeConnection();
}
QOpcUaProvider provider;
m_client = provider.createClient(name);
if (m_client) {
qCDebug(QT_OPCUA_PLUGINS_QML) << "Created plugin" << m_client->backend();
- connect(m_client, &QOpcUaClient::stateChanged, this, &OpcUaConnection::clientStateHandler);
- connect(m_client, &QOpcUaClient::namespaceArrayUpdated, this, &OpcUaConnection::namespacesChanged);
- connect(m_client, &QOpcUaClient::namespaceArrayUpdated, this, [&]() {
- if (!m_connected) {
- m_connected = true;
- emit connectedChanged();
- }
- });
- m_client->setNamespaceAutoupdate(true);
+ setupConnection();
} else {
qCWarning(QT_OPCUA_PLUGINS_QML) << tr("Backend '%1' could not be created.").arg(name);
}
@@ -202,17 +325,19 @@ bool OpcUaConnection::isDefaultConnection() const
}
/*!
- \qmlmethod Connection::connectToEndpoint(url)
+ \qmlmethod Connection::connectToEndpoint(endpointDescription)
Connects to the given endpoint.
+
+ \sa EndpointDescription
*/
-void OpcUaConnection::connectToEndpoint(const QUrl &url)
+void OpcUaConnection::connectToEndpoint(const QOpcUaEndpointDescription &endpointDescription)
{
if (!m_client)
return;
- m_client->connectToEndpoint(url);
+ m_client->connectToEndpoint(endpointDescription);
}
/*!
@@ -258,4 +383,289 @@ QStringList OpcUaConnection::namespaces() const
return m_client->namespaceArray();
}
+QOpcUaEndpointDescription OpcUaConnection::currentEndpoint() const
+{
+ if (!m_client || !m_connected)
+ return QOpcUaEndpointDescription();
+
+ return m_client->endpoint();
+}
+
+void OpcUaConnection::setAuthenticationInformation(const QOpcUaAuthenticationInformation &authenticationInformation)
+{
+ if (!m_client)
+ return;
+ m_client->setAuthenticationInformation(authenticationInformation);
+}
+
+void OpcUaConnection::setConnection(QOpcUaClient *client)
+{
+ if (!client)
+ return;
+ removeConnection();
+ m_client = client;
+ setupConnection();
+}
+
+QOpcUaAuthenticationInformation OpcUaConnection::authenticationInformation() const
+{
+ if (!m_client)
+ return QOpcUaAuthenticationInformation();
+
+ return m_client->authenticationInformation();
+}
+
+/*!
+ \qmlmethod Connection::readNodeAttributes(valuesToBeRead)
+
+ This function is used to read multiple values from a server in one go.
+ Returns \c true if the read request was dispatched successfully.
+
+ The values to be read have to be passed as JavaScript array of \l ReadItem.
+
+ \code
+ // List of items to read
+ var readItemList = [];
+ // Item to be added to the list of items to be read
+ var readItem;
+
+ // Prepare an item to be read
+
+ // Create a new read item and fill properties
+ readItem = QtOpcUa.ReadItem.create();
+ readItem.ns = "http://qt-project.org";
+ readItem.nodeId = "s=Demo.Static.Scalar.Double";
+ readItem.attribute = QtOpcUa.Constants.NodeAttribute.DisplayName;
+
+ // Add the prepared item to the list of items to be read
+ readItemList.push(readItem);
+
+ // Add further items
+ [...]
+
+ if (!connection.readNodeAttributes(readItemList)) {
+ // handle error
+ }
+ \endcode
+
+ The result of the read request are provided by the signal
+ \l readNodeAttributesFinished().
+
+ \sa readNodeAttributesFinished(), ReadItem
+*/
+bool OpcUaConnection::readNodeAttributes(const QJSValue &value)
+{
+ if (!m_client || !m_connected) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << tr("Not connected to server.");
+ return false;
+ }
+ if (!value.isArray()) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << tr("List of ReadItems it not an array.");
+ return false;
+ }
+
+ QVector<QOpcUaReadItem> readItemList;
+
+ for (int i = 0; i < value.property("length").toInt(); ++i){
+ const auto &readItem = qjsvalue_cast<OpcUaReadItem>(value.property(i));
+ if (readItem.nodeId().isEmpty()) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << tr("Invalid ReadItem in list of items at index %1").arg(i);
+ return false;
+ }
+
+ QString finalNode;
+ bool ok;
+ int index = readItem.namespaceIdentifier().toInt(&ok);
+ if (ok) {
+ QString identifier;
+ UniversalNode::splitNodeIdAndNamespace(readItem.nodeId(), nullptr, &identifier);
+ finalNode = UniversalNode::createNodeString(index, identifier);
+ } else {
+ finalNode = UniversalNode::resolveNamespaceToNode(readItem.nodeId(), readItem.namespaceIdentifier().toString(), m_client);
+ }
+
+ if (finalNode.isEmpty()) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << tr("Failed to resolve node.");
+ return false;
+ }
+ readItemList.push_back(QOpcUaReadItem(finalNode,
+ readItem.attribute(),
+ readItem.indexRange())
+ );
+ }
+
+ return m_client->readNodeAttributes(readItemList);
+}
+
+/*!
+ \qmlmethod Connection::writeNodeAttributes(valuesToBeWritten)
+
+ This function is used to write multiple values to a server in one go.
+ Returns \c true if the write request was dispatched successfully.
+
+ The values to be written have to be passed as JavaScript array of \l WriteItem.
+
+ \code
+ // List of items to write
+ var writeItemList = [];
+ // Item to be added to the list of items to be written
+ var writeItem;
+
+ // Prepare an item to be written
+
+ // Create a new write item and fill properties
+ writeItem = QtOpcUa.WriteItem.create();
+ writeItem.ns = "http://qt-project.org";
+ writeItem.nodeId = "s=Demo.Static.Scalar.Double";
+ writeItem.attribute = QtOpcUa.Constants.NodeAttribute.Value;
+ writeItem.value = 32.1;
+ writeItem.valueType = QtOpcUa.Constants.Double;
+
+ // Add the prepared item to the list of items to be written
+ writeItemList.push(writeItem);
+
+ // Add further items
+ [...]
+
+ if (!connection.writeNodeAttributes(writeItemList)) {
+ // handle error
+ }
+ \endcode
+
+ The result of the write request are provided by the signal
+ \l Connection::writeNodeAttributesFinished().
+
+ \sa Connection::writeNodeAttributesFinished() WriteItem
+*/
+bool OpcUaConnection::writeNodeAttributes(const QJSValue &value)
+{
+ if (!m_client || !m_connected) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << tr("Not connected to server.");
+ return false;
+ }
+ if (!value.isArray()) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << tr("List of WriteItems it not an array.");
+ return false;
+ }
+
+ QVector<QOpcUaWriteItem> writeItemList;
+
+ for (int i = 0; i < value.property("length").toInt(); ++i){
+ const auto &writeItem = qjsvalue_cast<OpcUaWriteItem>(value.property(i));
+ if (writeItem.nodeId().isEmpty()) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << tr("Invalid WriteItem in list of items at index %1").arg(i);
+ return false;
+ }
+
+ QString finalNode;
+ bool ok;
+ int index = writeItem.namespaceIdentifier().toInt(&ok);
+ if (ok) {
+ QString identifier;
+ UniversalNode::splitNodeIdAndNamespace(writeItem.nodeId(), nullptr, &identifier);
+ finalNode = UniversalNode::createNodeString(index, identifier);
+ } else {
+ finalNode = UniversalNode::resolveNamespaceToNode(writeItem.nodeId(), writeItem.namespaceIdentifier().toString(), m_client);
+ }
+
+ if (finalNode.isEmpty()) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << tr("Failed to resolve node.");
+ return false;
+ }
+
+ auto tmp = QOpcUaWriteItem(finalNode,
+ writeItem.attribute(),
+ writeItem.value(),
+ writeItem.valueType(),
+ writeItem.indexRange());
+
+ tmp.setSourceTimestamp(writeItem.sourceTimestamp());
+ tmp.setServerTimestamp(writeItem.serverTimestamp());
+ if (writeItem.hasStatusCode())
+ tmp.setStatusCode(static_cast<QOpcUa::UaStatusCode>(writeItem.statusCode()));
+ writeItemList.push_back(tmp);
+ }
+
+ return m_client->writeNodeAttributes(writeItemList);
+}
+
+QStringList OpcUaConnection::supportedSecurityPolicies() const
+{
+ if (!m_client)
+ return QStringList();
+ return m_client->supportedSecurityPolicies();
+}
+
+QJSValue OpcUaConnection::supportedUserTokenTypes() const
+{
+ if (!m_client)
+ return QJSValue();
+
+ auto engine = qjsEngine(this);
+ if (!engine)
+ return QJSValue();
+
+ const auto tokenTypes = m_client->supportedUserTokenTypes();
+ auto returnValue = engine->newArray(tokenTypes.size());
+ for (int i = 0; i < tokenTypes.size(); ++i)
+ returnValue.setProperty(i, tokenTypes[i]);
+
+ return returnValue;
+}
+
+QOpcUaClient *OpcUaConnection::connection() const
+{
+ return m_client;
+}
+
+void OpcUaConnection::handleReadNodeAttributesFinished(const QVector<QOpcUaReadResult> &results)
+{
+ QVariantList returnValue;
+
+ for (const auto &result : results)
+ returnValue.append(QVariant::fromValue(OpcUaReadResult(result, m_client)));
+
+ emit readNodeAttributesFinished(QVariant::fromValue(returnValue));
+}
+
+void OpcUaConnection::handleWriteNodeAttributesFinished(const QVector<QOpcUaWriteResult> &results)
+{
+ QVariantList returnValue;
+
+ for (const auto &result : results)
+ returnValue.append(QVariant::fromValue(OpcUaWriteResult(result, m_client)));
+
+ emit writeNodeAttributesFinished(QVariant::fromValue(returnValue));
+}
+
+void OpcUaConnection::removeConnection()
+{
+ if (m_client) {
+ m_client->disconnect(this);
+ m_client->disconnectFromEndpoint();
+ if (!m_client->parent()) {
+ m_client->deleteLater();
+ }
+ m_client = nullptr;
+ }
+}
+
+void OpcUaConnection::setupConnection()
+{
+ connect(m_client, &QOpcUaClient::stateChanged, this, &OpcUaConnection::clientStateHandler);
+ connect(m_client, &QOpcUaClient::namespaceArrayUpdated, this, &OpcUaConnection::namespacesChanged);
+ connect(m_client, &QOpcUaClient::namespaceArrayUpdated, this, [&]() {
+ if (!m_connected) {
+ m_connected = true;
+ emit connectedChanged();
+ }
+ });
+ m_client->setNamespaceAutoupdate(true);
+ connect(m_client, &QOpcUaClient::readNodeAttributesFinished, this, &OpcUaConnection::handleReadNodeAttributesFinished);
+ connect(m_client, &QOpcUaClient::writeNodeAttributesFinished, this, &OpcUaConnection::handleWriteNodeAttributesFinished);
+ m_connected = (!m_client->namespaceArray().isEmpty() && m_client->state() == QOpcUaClient::Connected);
+ if (m_connected)
+ emit connectedChanged();
+}
+
QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuaconnection.h b/src/imports/opcua/opcuaconnection.h
index 3b0f46a..4fdd2ed 100644
--- a/src/imports/opcua/opcuaconnection.h
+++ b/src/imports/opcua/opcuaconnection.h
@@ -36,11 +36,18 @@
#pragma once
+#include "opcuareaditem.h"
+#include <QJSValue>
#include <QObject>
#include <QOpcUaClient>
+#include <QOpcUaAuthenticationInformation>
+#include "opcuaendpointdiscovery.h"
+#include "opcuaserverdiscovery.h"
QT_BEGIN_NAMESPACE
+class QOpcUaReadResult;
+
class OpcUaConnection : public QObject
{
Q_OBJECT
@@ -50,6 +57,11 @@ class OpcUaConnection : public QObject
Q_PROPERTY(QString backend READ backend WRITE setBackend NOTIFY backendChanged)
Q_PROPERTY(bool defaultConnection READ defaultConnection WRITE setDefaultConnection NOTIFY defaultConnectionChanged)
Q_PROPERTY(QStringList namespaces READ namespaces NOTIFY namespacesChanged)
+ Q_PROPERTY(QOpcUaAuthenticationInformation authenticationInformation READ authenticationInformation WRITE setAuthenticationInformation)
+ Q_PROPERTY(QStringList supportedSecurityPolicies READ supportedSecurityPolicies CONSTANT)
+ Q_PROPERTY(QJSValue supportedUserTokenTypes READ supportedUserTokenTypes CONSTANT)
+ Q_PROPERTY(QOpcUaEndpointDescription currentEndpoint READ currentEndpoint)
+ Q_PROPERTY(QOpcUaClient* connection READ connection WRITE setConnection NOTIFY connectionChanged)
public:
OpcUaConnection(QObject *parent = nullptr);
@@ -62,10 +74,23 @@ public:
bool isDefaultConnection() const;
QStringList namespaces() const;
+ QOpcUaEndpointDescription currentEndpoint() const;
+
+ QOpcUaAuthenticationInformation authenticationInformation() const;
+ Q_INVOKABLE bool readNodeAttributes(const QJSValue &value);
+ Q_INVOKABLE bool writeNodeAttributes(const QJSValue &value);
+
+ QStringList supportedSecurityPolicies() const;
+ QJSValue supportedUserTokenTypes() const;
+
+ QOpcUaClient *connection() const;
+
public slots:
- void connectToEndpoint(const QUrl &url);
+ void connectToEndpoint(const QOpcUaEndpointDescription &endpointDescription);
void disconnectFromEndpoint();
void setDefaultConnection(bool defaultConnection = true);
+ void setAuthenticationInformation(const QOpcUaAuthenticationInformation &authenticationInformation);
+ void setConnection(QOpcUaClient *client);
signals:
void availableBackendsChanged();
@@ -73,11 +98,19 @@ signals:
void backendChanged();
void defaultConnectionChanged();
void namespacesChanged();
+ void readNodeAttributesFinished(const QVariant &value);
+ void writeNodeAttributesFinished(const QVariant &value);
+ void connectionChanged();
private slots:
void clientStateHandler(QOpcUaClient::ClientState state);
+ void handleReadNodeAttributesFinished(const QVector<QOpcUaReadResult> &results);
+ void handleWriteNodeAttributesFinished(const QVector<QOpcUaWriteResult> &results);
private:
+ void removeConnection();
+ void setupConnection();
+
QOpcUaClient *m_client = nullptr;
bool m_connected = false;
static OpcUaConnection* m_defaultConnection;
@@ -85,6 +118,8 @@ private:
friend class OpcUaNode;
friend class OpcUaValueNode;
friend class OpcUaMethodNode;
+friend class OpcUaEndpointDiscovery;
+friend class OpcUaServerDiscovery;
};
QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuadatachangefilter.cpp b/src/imports/opcua/opcuadatachangefilter.cpp
new file mode 100644
index 0000000..fb06839
--- /dev/null
+++ b/src/imports/opcua/opcuadatachangefilter.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcuadatachangefilter.h"
+
+QT_BEGIN_NAMESPACE
+
+OpcUaDataChangeFilter::OpcUaDataChangeFilter(QObject *parent)
+ : QObject(parent)
+{
+
+}
+
+OpcUaDataChangeFilter::OpcUaDataChangeFilter(const OpcUaDataChangeFilter &other)
+ : QObject(nullptr)
+ , m_filter(other.filter())
+{
+}
+
+OpcUaDataChangeFilter::~OpcUaDataChangeFilter() = default;
+
+OpcUaDataChangeFilter &OpcUaDataChangeFilter::operator=(const OpcUaDataChangeFilter &other)
+{
+ m_filter = other.filter();
+ return *this;
+}
+
+bool OpcUaDataChangeFilter::operator==(const OpcUaDataChangeFilter &other) const
+{
+ return m_filter == other.filter();
+}
+
+OpcUaDataChangeFilter::DataChangeTrigger OpcUaDataChangeFilter::trigger() const
+{
+ return static_cast<OpcUaDataChangeFilter::DataChangeTrigger>(m_filter.trigger());
+}
+
+OpcUaDataChangeFilter::DeadbandType OpcUaDataChangeFilter::deadbandType() const
+{
+ return static_cast<OpcUaDataChangeFilter::DeadbandType>(m_filter.deadbandType());
+}
+
+double OpcUaDataChangeFilter::deadbandValue() const
+{
+ return m_filter.deadbandValue();
+}
+
+const QOpcUaMonitoringParameters::DataChangeFilter &OpcUaDataChangeFilter::filter() const
+{
+ return m_filter;
+}
+
+void OpcUaDataChangeFilter::setTrigger(DataChangeTrigger trigger)
+{
+ const auto newValue = static_cast<QOpcUaMonitoringParameters::DataChangeFilter::DataChangeTrigger>(trigger);
+
+ if (m_filter.trigger() == newValue)
+ return;
+ m_filter.setTrigger(newValue);
+ emit filterChanged();
+}
+
+void OpcUaDataChangeFilter::setDeadbandType(DeadbandType deadbandType)
+{
+ const auto newValue = static_cast<QOpcUaMonitoringParameters::DataChangeFilter::DeadbandType>(deadbandType);
+
+ if (m_filter.deadbandType() == newValue)
+ return;
+ m_filter.setDeadbandType(newValue);
+ emit filterChanged();
+}
+
+void OpcUaDataChangeFilter::setDeadbandValue(double deadbandValue)
+{
+ if (deadbandValue == m_filter.deadbandValue())
+ return;
+ m_filter.setDeadbandValue(deadbandValue);
+ emit filterChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuadatachangefilter.h b/src/imports/opcua/opcuadatachangefilter.h
new file mode 100644
index 0000000..753c0f6
--- /dev/null
+++ b/src/imports/opcua/opcuadatachangefilter.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPCUADATACHANGEFILTER
+#define OPCUADATACHANGEFILTER
+
+#include <QOpcUaMonitoringParameters>
+
+QT_BEGIN_NAMESPACE
+
+class OpcUaDataChangeFilter : public QObject {
+ Q_OBJECT
+ Q_PROPERTY(DataChangeTrigger trigger READ trigger WRITE setTrigger)
+ Q_PROPERTY(DeadbandType deadbandType READ deadbandType WRITE setDeadbandType)
+ Q_PROPERTY(double deadbandValue READ deadbandValue WRITE setDeadbandValue)
+
+public:
+ // Same as in QOpcUaMonitoringParameters::DataChangeFilter::DataChangeTrigger
+ enum class DataChangeTrigger {
+ Status = 0,
+ StatusOrValue = 1,
+ StatusOrValueOrTimestamp = 2
+ };
+ Q_ENUM(DataChangeTrigger)
+
+ // Same as in QOpcUaMonitoringParameters::DataChangeFilter::DeadbandType
+ enum class DeadbandType {
+ None = 0,
+ Absolute = 1,
+ Percent = 2
+ };
+ Q_ENUM(DeadbandType)
+
+ explicit OpcUaDataChangeFilter(QObject *parent = nullptr);
+ OpcUaDataChangeFilter(const OpcUaDataChangeFilter &);
+ OpcUaDataChangeFilter &operator=(const OpcUaDataChangeFilter &);
+ bool operator==(const OpcUaDataChangeFilter &) const;
+ ~OpcUaDataChangeFilter();
+
+ DataChangeTrigger trigger() const;
+ DeadbandType deadbandType() const;
+ double deadbandValue() const;
+
+ const QOpcUaMonitoringParameters::DataChangeFilter &filter() const;
+
+signals:
+ void filterChanged();
+
+public slots:
+ void setTrigger(DataChangeTrigger trigger);
+ void setDeadbandType(DeadbandType deadbandType);
+ void setDeadbandValue(double deadbandValue);
+
+private:
+ QOpcUaMonitoringParameters::DataChangeFilter m_filter;
+};
+
+QT_END_NAMESPACE
+
+#endif // OPCUADATACHANGEFILTER
diff --git a/src/imports/opcua/opcuaelementoperand.cpp b/src/imports/opcua/opcuaelementoperand.cpp
new file mode 100644
index 0000000..b499f62
--- /dev/null
+++ b/src/imports/opcua/opcuaelementoperand.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcuaelementoperand.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ElementOperand
+ \inqmlmodule QtOpcUa
+ \brief The OPC UA ElementOperand type.
+ \since QtOpcUa 5.13
+
+ The ElementOperand is defined in OPC-UA part 4, 7.4.4.2.
+ It is used to identify another element in the filter by its index
+ (the first element has the index 0).
+
+ This is required to create complex filters, for example to reference
+ the two operands of the AND operation in ((Severity > 500) AND (Message == "TestString")).
+ The first step is to create content filter elements for the two conditions (Severity > 500)
+ and (Message == "TestString"). A third content filter element is required to create an AND
+ combination of the two conditions. It consists of the AND operator and two element operands
+ with the indices of the two conditions created before:
+
+ \code
+ import QtOpcUa 5.13 as QtOpcUa
+
+ QtOpcUa.EventFilter {
+ select : [ ... ]
+ where: [
+ QtOpcUa.FilterElement {
+ operator: QtOpcUa.FilterElement.GreaterThan
+ firstOperand: QtOpcUA.SimpleAttributeOperand {
+ browsePath: [
+ QtOpcUa.NodeId {
+ identifier: "Severity"
+ ns: "http://opcfoundation.org/UA/"
+ }
+ ]
+ }
+ secondOperand: QtOpcUa.LiteralOperand {
+ value: 500
+ type: QtOpcUa.Constants.UInt16
+ }
+ }
+ QtOpcUa.FilterElement {
+ operator: QtOpcUa.FilterElement.Equals
+ firstOperand: QtOpcUA.SimpleAttributeOperand {
+ browsePath: [
+ QtOpcUa.NodeId {
+ identifier: "Message"
+ ns: "http://opcfoundation.org/UA/"
+ }
+ ]
+ }
+ secondOperand: QtOpcUa.LiteralOperand {
+ value: "TestString"
+ type: QtOpcUa.Constants.String
+ }
+ }
+ QtOpcUa.FilterElement {
+ operator: QtOpcUa.FilterElement.And
+ firstOperand: QtOpcUA.ElementOperand {
+ index: 0
+ }
+ secondOperand: QtOpcUa.ElementOperand {
+ index: 1
+ }
+ }
+ ]
+ }
+ \endcode
+*/
+
+/*!
+ \qmlproperty int ElementOperand::index
+
+ Index of the filter element that is going to be used as operand.
+*/
+
+OpcUaElementOperand::OpcUaElementOperand(QObject *parent)
+ : OpcUaOperandBase(parent)
+{
+}
+
+OpcUaElementOperand::~OpcUaElementOperand() = default;
+
+QVariant OpcUaElementOperand::toCppVariant(QOpcUaClient* client) const
+{
+ Q_UNUSED(client);
+ QOpcUaElementOperand value(*this);
+ return value;
+}
+
+quint32 OpcUaElementOperand::index() const
+{
+ return QOpcUaElementOperand::index();
+}
+
+void OpcUaElementOperand::setIndex(quint32 index)
+{
+ if (index != QOpcUaElementOperand::index()) {
+ QOpcUaElementOperand::setIndex(index);
+ emit dataChanged();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuaelementoperand.h b/src/imports/opcua/opcuaelementoperand.h
new file mode 100644
index 0000000..33c442c
--- /dev/null
+++ b/src/imports/opcua/opcuaelementoperand.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPCUAELEMENTOPERAND
+#define OPCUAELEMENTOPERAND
+
+#include "opcuaoperandbase.h"
+#include <QOpcUaElementOperand>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaClient;
+
+class OpcUaElementOperand : public OpcUaOperandBase, private QOpcUaElementOperand {
+ Q_OBJECT
+ Q_PROPERTY(quint32 index READ index WRITE setIndex)
+
+public:
+ explicit OpcUaElementOperand(QObject *parent = nullptr);
+ ~OpcUaElementOperand();
+ virtual QVariant toCppVariant(QOpcUaClient *client) const override;
+
+ quint32 index() const;
+ void setIndex(quint32 index);
+
+signals:
+ void dataChanged();
+};
+
+QT_END_NAMESPACE
+
+#endif // OPCUAELEMENTOPERAND
diff --git a/src/imports/opcua/opcuaendpointdiscovery.cpp b/src/imports/opcua/opcuaendpointdiscovery.cpp
new file mode 100644
index 0000000..80b0d25
--- /dev/null
+++ b/src/imports/opcua/opcuaendpointdiscovery.cpp
@@ -0,0 +1,289 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcuaendpointdiscovery.h"
+#include "opcuaconnection.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype EndpointDiscovery
+ \inqmlmodule QtOpcUa
+ \brief Provides information about available endpoints on a server.
+ \since QtOpcUa 5.13
+
+ Allows to fetch and access information about available endpoints on a server.
+
+ \snippet ../../src/imports/doc/snippets/basic/basic.qml Basic discovery
+*/
+
+/*!
+ \qmlproperty string EndpointDiscovery::serverUrl
+
+ Discovery URL of the server to fetch the endpoints from.
+ Every time the URL is changed, a request to the given server is started.
+
+ When starting the request, the list of available endpoints is cleared
+ and the status is set to \l {Status::Status}{Status.GoodCompletesAsynchronously}. Once the request is finished,
+ \l status changes.
+
+ Make sure to check \l status before acessing the list of endpoints.
+
+ \sa endpointsChanged
+*/
+
+/*!
+ \qmlproperty int EndpointDiscovery::count
+
+ Current number of endpoints in this element.
+ Before using any data from an endpoint discovery, you should check \l status if the information
+ was successfully retrieved.
+
+ \sa status Status
+*/
+
+/*!
+ \qmlproperty Status EndpointDiscovery::status
+
+ The current status of this element.
+ In case the last retrieval of endpoints was successful, the status
+ is \l {Status::Status}{Status.Good}.
+
+ \code
+ if (endpoints.status.isGood) {
+ // do something
+ } else {
+ // handle error
+ }
+ \endcode
+
+ \sa Status
+*/
+
+/*!
+ \qmlsignal EndpointDiscovery::endpointsChanged()
+
+ Emitted when a retrieval request started, finished or failed.
+ In a called function, you should first check the \l status of the object.
+ If the status is \l {Status::Status}{Status.GoodCompletesAsynchronously},
+ the request is still running.
+ If the status is \l {Status::Status}{Status.Good}, the request has finished
+ and the endpoint descriptions can be read. If the status is not good, an
+ error happended and \l status contains the returned error code.
+
+ \code
+ onEndpointsChanged: {
+ if (endpoints.status.isGood) {
+ if (endpoints.status.status == QtOpcua.Status.GoodCompletesAsynchronusly)
+ return; // wait until finished
+ if (enpoints.count > 0) {
+ var endpointUrl = enpoints.at(0).endpointUrl();
+ console.log(endpointUrl);
+ }
+ } else {
+ // handle error
+ }
+ }
+ \endcode
+
+ \sa status count at Status EndpointDescription
+*/
+
+/*!
+ \qmlproperty Connection EndpointDiscovery::connection
+
+ The connection to be used for requesting information.
+
+ If this property is not set, the default connection will be used, if any.
+
+ \sa Connection, Connection::defaultConnection
+*/
+
+OpcUaEndpointDiscovery::OpcUaEndpointDiscovery(QObject *parent)
+ : QObject(parent)
+{
+ connect(this, &OpcUaEndpointDiscovery::serverUrlChanged, this, &OpcUaEndpointDiscovery::startRequestEndpoints);
+ connect(this, &OpcUaEndpointDiscovery::connectionChanged, this, &OpcUaEndpointDiscovery::startRequestEndpoints);
+}
+
+OpcUaEndpointDiscovery::~OpcUaEndpointDiscovery() = default;
+
+const QString &OpcUaEndpointDiscovery::serverUrl() const
+{
+ return m_serverUrl;
+}
+
+void OpcUaEndpointDiscovery::setServerUrl(const QString &serverUrl)
+{
+ if (serverUrl == m_serverUrl)
+ return;
+
+ m_serverUrl = serverUrl;
+ emit serverUrlChanged(m_serverUrl);
+}
+
+int OpcUaEndpointDiscovery::count() const
+{
+ return m_endpoints.count();
+}
+
+/*!
+ \qmlmethod EndpointDescription EndpointDiscovery::at(index)
+
+ Returns the endpoint description at given \a index.
+ In case there are no endoints available or the index is invalid, an invalid
+ endpoint description is returned.
+ Before using any data from this, you should check \l status if retrieval of the
+ information was successful.
+
+ \code
+ if (endpoints.status.isGood) {
+ if (endpoints.count > 0)
+ var endpointUrl = endpoints.at(0).endpointUrl();
+ console.log(endpointUrl);
+ } else {
+ // handle error
+ }
+ \endcode
+
+ \sa count status EndpointDescription
+*/
+
+QOpcUaEndpointDescription OpcUaEndpointDiscovery::at(int row) const
+{
+ if (row >= m_endpoints.count())
+ return QOpcUaEndpointDescription();
+ return m_endpoints.at(row);
+}
+
+const OpcUaStatus &OpcUaEndpointDiscovery::status() const
+{
+ return m_status;
+}
+
+void OpcUaEndpointDiscovery::connectSignals()
+{
+ auto conn = connection();
+
+ if (!conn || !conn->m_client)
+ return;
+ connect(conn->m_client, &QOpcUaClient::endpointsRequestFinished, this, &OpcUaEndpointDiscovery::handleEndpoints, Qt::UniqueConnection);
+}
+
+void OpcUaEndpointDiscovery::handleEndpoints(const QVector<QOpcUaEndpointDescription> &endpoints, QOpcUa::UaStatusCode statusCode, const QUrl &requestUrl)
+{
+ if (requestUrl != m_serverUrl)
+ return; // response is not for last request
+
+ m_status = OpcUaStatus(statusCode);
+
+ if (m_status.isBad()) {
+ emit statusChanged();
+ return;
+ }
+
+ m_endpoints = endpoints;
+ emit endpointsChanged();
+ emit countChanged();
+ emit statusChanged();
+}
+
+void OpcUaEndpointDiscovery::startRequestEndpoints()
+{
+ if (!m_componentCompleted)
+ return;
+
+ if (m_serverUrl.isEmpty())
+ return;
+
+ m_endpoints.clear();
+
+ if (!m_connection) {
+ // If there is not connection set, try the default connection
+ // Any connection change will restart this function
+ connection();
+ return;
+ }
+
+ auto conn = connection();
+
+ if (!conn || !conn->m_client) {
+ m_status = OpcUaStatus(QOpcUa::BadNotConnected);
+ } else if (m_serverUrl.isEmpty()) {
+ m_status = OpcUaStatus(QOpcUa::BadInvalidArgument);
+ } else {
+ m_status = OpcUaStatus(QOpcUa::GoodCompletesAsynchronously);
+ conn->m_client->requestEndpoints(m_serverUrl);
+ }
+
+ emit endpointsChanged();
+ emit statusChanged();
+}
+
+void OpcUaEndpointDiscovery::setConnection(OpcUaConnection *connection)
+{
+ if (connection == m_connection || !connection)
+ return;
+
+ if (m_connection)
+ disconnect(m_connection, &OpcUaConnection::backendChanged, this, &OpcUaEndpointDiscovery::connectSignals);
+
+ m_connection = connection;
+
+ connect(m_connection, &OpcUaConnection::backendChanged, this, &OpcUaEndpointDiscovery::connectSignals, Qt::UniqueConnection);
+ connectSignals();
+ emit connectionChanged(connection);
+}
+
+OpcUaConnection *OpcUaEndpointDiscovery::connection()
+{
+ if (!m_connection)
+ setConnection(OpcUaConnection::defaultConnection());
+
+ return m_connection;
+}
+
+void OpcUaEndpointDiscovery::classBegin()
+{
+}
+
+void OpcUaEndpointDiscovery::componentComplete()
+{
+ m_componentCompleted = true;
+ startRequestEndpoints();
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuaendpointdiscovery.h b/src/imports/opcua/opcuaendpointdiscovery.h
new file mode 100644
index 0000000..4575013
--- /dev/null
+++ b/src/imports/opcua/opcuaendpointdiscovery.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPCUAENDPOINTDISCOVERY_H
+#define OPCUAENDPOINTDISCOVERY_H
+
+#include <QObject>
+#include <QVector>
+#include <QtOpcUa/qopcuatype.h>
+#include <QOpcUaEndpointDescription>
+#include <QQmlParserStatus>
+#include "opcuastatus.h"
+
+QT_BEGIN_NAMESPACE
+
+class OpcUaConnection;
+
+class OpcUaEndpointDiscovery : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_PROPERTY(QString serverUrl READ serverUrl WRITE setServerUrl NOTIFY serverUrlChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(OpcUaStatus status READ status NOTIFY statusChanged)
+ Q_PROPERTY(OpcUaConnection* connection READ connection WRITE setConnection NOTIFY connectionChanged)
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ OpcUaEndpointDiscovery(QObject *parent = nullptr);
+ ~OpcUaEndpointDiscovery();
+
+ const QString &serverUrl() const;
+ void setServerUrl(const QString &serverUrl);
+ int count() const;
+ Q_INVOKABLE QOpcUaEndpointDescription at(int row) const;
+ const OpcUaStatus &status() const;
+ void setConnection(OpcUaConnection *);
+ OpcUaConnection *connection();
+
+signals:
+ void serverUrlChanged(const QString &serverUrl);
+ void endpointsChanged();
+ void countChanged();
+ void statusChanged();
+ void connectionChanged(OpcUaConnection *);
+
+private slots:
+ void connectSignals();
+ void handleEndpoints(const QVector<QOpcUaEndpointDescription> &endpoints, QOpcUa::UaStatusCode statusCode, const QUrl &requestUrl);
+ void startRequestEndpoints();
+
+private:
+ // Callbacks from QQmlParserStatus
+ void classBegin();
+ void componentComplete();
+
+ QString m_serverUrl;
+ OpcUaConnection *m_connection = nullptr;
+ QVector<QOpcUaEndpointDescription> m_endpoints;
+ OpcUaStatus m_status;
+ bool m_componentCompleted = false;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // OPCUAENDPOINTDISCOVERY_H
diff --git a/src/imports/opcua/opcuaeventfilter.cpp b/src/imports/opcua/opcuaeventfilter.cpp
new file mode 100644
index 0000000..7002732
--- /dev/null
+++ b/src/imports/opcua/opcuaeventfilter.cpp
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcuaeventfilter.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype EventFilter
+ \inqmlmodule QtOpcUa
+ \brief Defines an EventFilter for a monitored item.
+ \since QtOpcUa 5.13
+
+ An event filter is required for monitoring events on the server.
+ It consists of \c select clauses and a \c where clause.
+
+ The \c select clauses are used to specify the data the user wants to receive when an event occurs.
+ It consists of \l {SimpleAttributeOperand} simple attribute operands which select
+ attributes of child nodes of an event type, for example the value attribute of the "Message"
+ property of BaseEventType.
+
+ The \c where clause is used to restrict the reported events by matching against certain criteria.
+ Several operators and four different operand types allow filtering based on the values of the
+ attributes of the child nodes of an event type.
+
+ The select clause consists of an array of \l SimpleAttributeOperand.
+ The where clause consists of an array of \l SimpleAttributeOperand, \l LiteralOperand, \l ElementOperand or \l AttributeOperand.
+
+ The following EventFilter tells the server to report the value of the "Message" field for events that have a "Severity" field with value >= 500:
+
+ \code
+ import QtOpcUa 5.13 as QtOpcUa
+ QtOpcUa.Node {
+ ...
+
+ eventFilter: QtOpcUa.EventFilter {
+ select: [
+ QtOpcUa.SimpleAttributeOperand {
+ browsePath: [
+ QtOpcUa.NodeId {
+ identifier: "Severity"
+ ns: "http://opcfoundation.org/UA/"
+ }
+ ]
+ },
+ QtOpcUa.SimpleAttributeOperand {
+ browsePath: [
+ QtOpcUa.NodeId {
+ identifier: "Message"
+ ns: "http://opcfoundation.org/UA/"
+ }
+ ]
+ }
+ ]
+
+ where: [
+ QtOpcUa.FilterElement {
+ operator: QtOpcUa.FilterElement.GreaterThanOrEqual
+ firstOperand: QtOpcUa.SimpleAttributeOperand {
+ browsePath: [
+ QtOpcUa.NodeId {
+ identifier: "Severity"
+ ns: "http://opcfoundation.org/UA/"
+ }
+ ]
+ }
+ secondOperand: QtOpcUa.LiteralOperand {
+ value: 700
+ type: QtOpcUa.Constants.UInt16
+ }
+ }
+ ]
+ }
+ }
+ \endcode
+
+ For a more complex example with two conditions, see \l QOpcUaElementOperand.
+
+ \sa FilterElement
+*/
+
+/*!
+ \qmlproperty list<FilterElement> EventFilter::where
+
+ Content filter used to restrict the reported events to events matching certain criteria.
+*/
+
+/*!
+ \qmlproperty list<SimpleAttributeOperand::select
+
+ Selected event fields that shall be included when a new event is reported.
+*/
+
+OpcUaEventFilter::OpcUaEventFilter(QObject *parent)
+ : QObject(parent)
+{
+}
+
+OpcUaEventFilter::~OpcUaEventFilter() = default;
+
+bool OpcUaEventFilter::operator==(const OpcUaEventFilter &other) const
+{
+ return this->m_filterElements == other.m_filterElements
+ && this->m_selectors == other.m_selectors;
+}
+
+QOpcUaMonitoringParameters::EventFilter OpcUaEventFilter::filter(QOpcUaClient *client) const
+{
+ QOpcUaMonitoringParameters::EventFilter filterValue;
+ for (const auto &i : qAsConst(m_selectors))
+ filterValue.selectClausesRef().append(i->toSimpleAttributeOperand(client));
+
+ for (const auto &i : qAsConst(m_filterElements))
+ filterValue.whereClauseRef().append(i->toFilterElement(client));
+
+ return filterValue;
+}
+
+QQmlListProperty<OpcUaFilterElement> OpcUaEventFilter::filterElements()
+{
+ return QQmlListProperty<OpcUaFilterElement>(this, this,
+ &OpcUaEventFilter::appendFilterElement,
+ &OpcUaEventFilter::filterElementCount,
+ &OpcUaEventFilter::filterElement,
+ &OpcUaEventFilter::clearFilterElements);
+}
+
+void OpcUaEventFilter::appendFilterElement(OpcUaFilterElement *nodeId)
+{
+ m_filterElements.append(nodeId);
+ emit dataChanged();
+}
+
+int OpcUaEventFilter::filterElementCount() const
+{
+ return m_filterElements.size();
+}
+
+OpcUaFilterElement *OpcUaEventFilter::filterElement(int index) const
+{
+ return m_filterElements.at(index);
+}
+
+void OpcUaEventFilter::clearFilterElements()
+{
+ m_filterElements.clear();
+ emit dataChanged();
+}
+
+void OpcUaEventFilter::appendFilterElement(QQmlListProperty<OpcUaFilterElement> *list, OpcUaFilterElement *nodeId)
+{
+ reinterpret_cast<OpcUaEventFilter*>(list->data)->appendFilterElement(nodeId);
+}
+
+int OpcUaEventFilter::filterElementCount(QQmlListProperty<OpcUaFilterElement> *list)
+{
+ return reinterpret_cast<OpcUaEventFilter*>(list->data)->filterElementCount();
+}
+
+OpcUaFilterElement *OpcUaEventFilter::filterElement(QQmlListProperty<OpcUaFilterElement> *list, int index)
+{
+ return reinterpret_cast<OpcUaEventFilter*>(list->data)->filterElement(index);
+}
+
+void OpcUaEventFilter::clearFilterElements(QQmlListProperty<OpcUaFilterElement> *list)
+{
+ reinterpret_cast<OpcUaEventFilter*>(list->data)->clearFilterElements();
+}
+
+QQmlListProperty<OpcUaSimpleAttributeOperand> OpcUaEventFilter::selectors()
+{
+ return QQmlListProperty<OpcUaSimpleAttributeOperand>(this, this,
+ &OpcUaEventFilter::appendSelector,
+ &OpcUaEventFilter::selectorCount,
+ &OpcUaEventFilter::selector,
+ &OpcUaEventFilter::clearSelectors);
+}
+
+void OpcUaEventFilter::appendSelector(OpcUaSimpleAttributeOperand *nodeId)
+{
+ m_selectors.append(nodeId);
+ emit dataChanged();
+}
+
+int OpcUaEventFilter::selectorCount() const
+{
+ return m_selectors.size();
+}
+
+OpcUaSimpleAttributeOperand *OpcUaEventFilter::selector(int index) const
+{
+ return m_selectors.at(index);
+}
+
+void OpcUaEventFilter::clearSelectors()
+{
+ m_selectors.clear();
+ emit dataChanged();
+}
+
+void OpcUaEventFilter::appendSelector(QQmlListProperty<OpcUaSimpleAttributeOperand> *list, OpcUaSimpleAttributeOperand *nodeId)
+{
+ reinterpret_cast<OpcUaEventFilter*>(list->data)->appendSelector(nodeId);
+}
+
+int OpcUaEventFilter::selectorCount(QQmlListProperty<OpcUaSimpleAttributeOperand> *list)
+{
+ return reinterpret_cast<OpcUaEventFilter*>(list->data)->selectorCount();
+}
+
+OpcUaSimpleAttributeOperand *OpcUaEventFilter::selector(QQmlListProperty<OpcUaSimpleAttributeOperand> *list, int index)
+{
+ return reinterpret_cast<OpcUaEventFilter*>(list->data)->selector(index);
+}
+
+void OpcUaEventFilter::clearSelectors(QQmlListProperty<OpcUaSimpleAttributeOperand> *list)
+{
+ reinterpret_cast<OpcUaEventFilter*>(list->data)->clearSelectors();
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuaeventfilter.h b/src/imports/opcua/opcuaeventfilter.h
new file mode 100644
index 0000000..2ef0f9f
--- /dev/null
+++ b/src/imports/opcua/opcuaeventfilter.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPCUAEVENTFILTER
+#define OPCUAEVENTFILTER
+
+#include <QQmlListProperty>
+
+#include "opcuasimpleattributeoperand.h"
+#include "opcuafilterelement.h"
+#include <QOpcUaMonitoringParameters>
+
+QT_BEGIN_NAMESPACE
+
+class OpcUaNodeId;
+class OpcUaRelativeNodePath;
+
+class OpcUaEventFilter : public QObject {
+ Q_OBJECT
+ Q_PROPERTY(QQmlListProperty<OpcUaFilterElement> where READ filterElements)
+ Q_PROPERTY(QQmlListProperty<OpcUaSimpleAttributeOperand> select READ selectors)
+
+public:
+ explicit OpcUaEventFilter(QObject *parent = nullptr);
+ ~OpcUaEventFilter();
+ bool operator==(const OpcUaEventFilter &other) const;
+ QOpcUaMonitoringParameters::EventFilter filter(QOpcUaClient *client) const;
+
+ QQmlListProperty<OpcUaSimpleAttributeOperand> selectors();
+ void appendSelector(OpcUaSimpleAttributeOperand *selector);
+ int selectorCount() const;
+ OpcUaSimpleAttributeOperand *selector(int index) const;
+ void clearSelectors();
+
+ QQmlListProperty<OpcUaFilterElement> filterElements();
+ void appendFilterElement(OpcUaFilterElement *filterElement);
+ int filterElementCount() const;
+ OpcUaFilterElement *filterElement(int index) const;
+ void clearFilterElements();
+
+signals:
+ void dataChanged();
+
+private:
+ static void appendSelector(QQmlListProperty<OpcUaSimpleAttributeOperand> *list, OpcUaSimpleAttributeOperand *);
+ static int selectorCount(QQmlListProperty<OpcUaSimpleAttributeOperand> *list);
+ static OpcUaSimpleAttributeOperand* selector(QQmlListProperty<OpcUaSimpleAttributeOperand> *list, int index);
+ static void clearSelectors(QQmlListProperty<OpcUaSimpleAttributeOperand> *list);
+
+ static void appendFilterElement(QQmlListProperty<OpcUaFilterElement> *list, OpcUaFilterElement *nodeId);
+ static int filterElementCount(QQmlListProperty<OpcUaFilterElement> *list);
+ static OpcUaFilterElement* filterElement(QQmlListProperty<OpcUaFilterElement> *list, int index);
+ static void clearFilterElements(QQmlListProperty<OpcUaFilterElement> *list);
+
+ QVector<OpcUaFilterElement*> m_filterElements;
+ QVector<OpcUaSimpleAttributeOperand*> m_selectors;
+};
+
+QT_END_NAMESPACE
+
+#endif // OPCUAEVENTFILTER
diff --git a/src/imports/opcua/opcuafilterelement.cpp b/src/imports/opcua/opcuafilterelement.cpp
new file mode 100644
index 0000000..502f59c
--- /dev/null
+++ b/src/imports/opcua/opcuafilterelement.cpp
@@ -0,0 +1,175 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcuafilterelement.h"
+
+#include "opcuaoperandbase.h"
+
+#include <QOpcUaContentFilterElement>
+#include <QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype FilterElement
+ \inqmlmodule QtOpcUa
+ \brief The OPC UA ContentFilterElement.
+ \since QtOpcUa 5.13
+
+ A content filter element contains an operator and operands.
+ There are four different operator types which contain literal values, references to
+ attributes of nodes or to other content filter elements.
+
+ A combination of one or more content filter elements makes a content filter which is used
+ by the server to filter data for the criteria defined by the content filter elements.
+ For example, the \c where clause of an event filter is a content filter which is used to decide
+ if a notification is generated for an event.
+
+ \code
+ QtOpcUa.FilterElement {
+ operator: QtOpcUa.FilterElement.GreaterThanOrEqual
+ firstOperand: QtOpcUa.SimpleAttributeOperand { ... }
+ secondOperand: QtOpcUa.LiteralOperand { ... }
+ }
+ \endcode
+
+ \sa EventFilter
+*/
+
+/*!
+ \qmlproperty FilterElement::FilterOperator
+
+ FilterOperator enumerates all possible operators for a FilterElement that are specified in
+ OPC-UA part 4, Tables 115 and 116.
+
+ \value FilterElement.Equals
+ \value FilterElement.IsNull
+ \value FilterElement.GreaterThan
+ \value FilterElement.LessThan
+ \value FilterElement.GreaterThanOrEqual
+ \value FilterElement.LessThanOrEqual
+ \value FilterElement.Like
+ \value FilterElement.Not
+ \value FilterElement.Between
+ \value FilterElement.InList
+ \value FilterElement.And
+ \value FilterElement.Or
+ \value FilterElement.Cast
+ \value FilterElement.InView
+ \value FilterElement.OfType
+ \value FilterElement.RelatedTo
+ \value FilterElement.BitwiseAnd
+ \value FilterElement.BitwiseOr
+*/
+
+/*!
+ \qmlproperty FilterElement::FilterOperator FilterElement::operatorType
+
+ The filter operator.
+*/
+
+/*!
+ \qmlproperty variant FilterElement::firstOperand
+
+ First operand to be used with the operator.
+ This can be one of \l SimplateAttributeOperand, \l AttributeOperand,
+ \l LiteralOperal or \l ElementOperand.
+*/
+
+/*!
+ \qmlproperty variant FilterElement::secondOperand
+
+ Second operand to be used with the operator.
+ This can be one of \l SimplateAttributeOperand, \l AttributeOperand,
+ \l LiteralOperal or \l ElementOperand.
+*/
+
+
+Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_QML)
+
+OpcUaFilterElement::OpcUaFilterElement(QObject *parent)
+ : QObject(parent)
+{
+}
+
+OpcUaFilterElement::~OpcUaFilterElement() = default;
+
+QOpcUaContentFilterElement OpcUaFilterElement::toFilterElement(QOpcUaClient *client)
+{
+ QOpcUaContentFilterElement value;
+ value.setFilterOperator(static_cast<QOpcUaContentFilterElement::FilterOperator>(operatorType()));
+ value.filterOperandsRef().append(m_firstOperand->toCppVariant(client));
+ value.filterOperandsRef().append(m_secondOperand->toCppVariant(client));
+ return value;
+}
+
+OpcUaFilterElement::FilterOperator OpcUaFilterElement::operatorType() const
+{
+ return m_filterOperator;
+}
+
+void OpcUaFilterElement::setOperatorType(OpcUaFilterElement::FilterOperator filterOperator)
+{
+ m_filterOperator = filterOperator;
+}
+
+OpcUaOperandBase *OpcUaFilterElement::firstOperand() const
+{
+ return m_firstOperand;
+}
+
+void OpcUaFilterElement::setFirstOperand(OpcUaOperandBase *operand)
+{
+ if (m_firstOperand != operand) {
+ m_firstOperand = operand;
+ emit dataChanged();
+ }
+}
+
+OpcUaOperandBase *OpcUaFilterElement::secondOperand() const
+{
+ return m_secondOperand;
+}
+
+void OpcUaFilterElement::setSecondOperand(OpcUaOperandBase *operand)
+{
+ if (m_secondOperand != operand) {
+ m_secondOperand = operand;
+ emit dataChanged();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuafilterelement.h b/src/imports/opcua/opcuafilterelement.h
new file mode 100644
index 0000000..5bf4eb4
--- /dev/null
+++ b/src/imports/opcua/opcuafilterelement.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPCUAFILTERELEMENT
+#define OPCUAFILTERELEMENT
+
+#include <QObject>
+#include <QOpcUaContentFilterElement>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaClient;
+class OpcUaOperandBase;
+
+class OpcUaFilterElement : public QObject {
+ Q_OBJECT
+ Q_PROPERTY(FilterOperator operator READ operatorType WRITE setOperatorType)
+ Q_PROPERTY(OpcUaOperandBase* firstOperand READ firstOperand WRITE setFirstOperand)
+ Q_PROPERTY(OpcUaOperandBase* secondOperand READ secondOperand WRITE setSecondOperand)
+
+public:
+ // Same as in qopcuacontentfilterelement.h
+ // Specified in OPC-UA part 4, Tables 115 and 116
+ enum class FilterOperator : quint32 {
+ Equals = 0,
+ IsNull = 1,
+ GreaterThan = 2,
+ LessThan = 3,
+ GreaterThanOrEqual = 4,
+ LessThanOrEqual = 5,
+ Like = 6,
+ Not = 7,
+ Between = 8,
+ InList = 9,
+ And = 10,
+ Or = 11,
+ Cast = 12,
+ InView = 13,
+ OfType = 14,
+ RelatedTo = 15,
+ BitwiseAnd = 16,
+ BitwiseOr = 17
+ };
+ Q_ENUM(FilterOperator);
+
+ explicit OpcUaFilterElement(QObject *parent = nullptr);
+ ~OpcUaFilterElement();
+ QOpcUaContentFilterElement toFilterElement(QOpcUaClient *);
+
+ FilterOperator operatorType() const;
+ void setOperatorType(FilterOperator filterOperator);
+
+ OpcUaOperandBase *firstOperand() const;
+ void setFirstOperand(OpcUaOperandBase *operand);
+
+ OpcUaOperandBase *secondOperand() const;
+ void setSecondOperand(OpcUaOperandBase *operand);
+
+signals:
+ void dataChanged();
+
+private:
+ FilterOperator m_filterOperator = FilterOperator::Equals;
+ OpcUaOperandBase *m_firstOperand = nullptr;
+ OpcUaOperandBase *m_secondOperand = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // OPCUAFILTERELEMENT
diff --git a/src/imports/opcua/opcualiteraloperand.cpp b/src/imports/opcua/opcualiteraloperand.cpp
new file mode 100644
index 0000000..eb79a53
--- /dev/null
+++ b/src/imports/opcua/opcualiteraloperand.cpp
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcualiteraloperand.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype LiteralOperand
+ \inqmlmodule QtOpcUa
+ \brief The OPC UA LiteralOperand type.
+ \since QtOpcUa 5.13
+
+ The LiteralOperand is defined in OPC-UA part 4, 7.4.4.3.
+ It contains a literal value that is to be used as operand for filters.
+
+ Setting the type should be done to match the expected types on the server.
+ Otherwise the type will be guessed and may lead to errors because it does
+ not match on the server.
+
+ \code
+ import QtOpcUa 5.13 as QtOpcUa
+
+ QtOpcUa.LiteralOperand {
+ value: 43.21
+ type: QtOpcUa.Constants.Double
+ }
+ \endcode
+*/
+
+/*!
+ \qmlproperty QOpcUa.Types LiteralOperand::type
+
+ Type of the value of the literal operand.
+*/
+
+/*!
+ \qmlproperty variant LiteralOperand::value
+
+ Value of the literal operand.
+*/
+
+OpcUaLiteralOperand::OpcUaLiteralOperand(QObject *parent)
+ : OpcUaOperandBase(parent)
+ , m_type(QOpcUa::Undefined)
+{
+}
+
+OpcUaLiteralOperand::~OpcUaLiteralOperand() = default;
+
+QVariant OpcUaLiteralOperand::toCppVariant(QOpcUaClient *client) const
+{
+ Q_UNUSED(client);
+ return QOpcUaLiteralOperand(m_value, m_type);
+}
+
+QVariant OpcUaLiteralOperand::value() const
+{
+ return m_value;
+}
+
+void OpcUaLiteralOperand::setValue(const QVariant &value)
+{
+ if (m_value != value) {
+ m_value = value;
+ emit dataChanged();
+ }
+}
+
+QOpcUa::Types OpcUaLiteralOperand::type() const
+{
+ return m_type;
+}
+
+void OpcUaLiteralOperand::setType(QOpcUa::Types type)
+{
+ if (m_type != type) {
+ m_type = type;
+ emit dataChanged();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcualiteraloperand.h b/src/imports/opcua/opcualiteraloperand.h
new file mode 100644
index 0000000..b08dfd7
--- /dev/null
+++ b/src/imports/opcua/opcualiteraloperand.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPCUALITERALOPERAND
+#define OPCUALITERALOPERAND
+
+#include "opcuaoperandbase.h"
+#include <QOpcUaLiteralOperand>
+#include <qopcuatype.h>
+
+QT_BEGIN_NAMESPACE
+
+class OpcUaLiteralOperand : public OpcUaOperandBase {
+ Q_OBJECT
+ Q_PROPERTY(QVariant value READ value WRITE setValue)
+ Q_PROPERTY(QOpcUa::Types type READ type WRITE setType)
+
+public:
+ explicit OpcUaLiteralOperand(QObject *parent = nullptr);
+ ~OpcUaLiteralOperand();
+ QVariant toCppVariant(QOpcUaClient *client) const override;
+
+ QVariant value() const;
+ void setValue(const QVariant &value);
+
+ QOpcUa::Types type() const;
+ void setType(QOpcUa::Types type);
+
+signals:
+ void dataChanged();
+
+private:
+ QVariant m_value;
+ QOpcUa::Types m_type;
+};
+
+QT_END_NAMESPACE
+
+#endif // OPCUALITERALOPERAND
diff --git a/src/imports/opcua/opcuamethodargument.cpp b/src/imports/opcua/opcuamethodargument.cpp
new file mode 100644
index 0000000..233a771
--- /dev/null
+++ b/src/imports/opcua/opcuamethodargument.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcuamethodargument.h"
+
+/*!
+ \qmltype MethodArgument
+ \inqmlmodule QtOpcUa
+ \brief Arguments for OpcUa method calls.
+ \since QtOpcUa 5.13
+
+ When calling methods which require arguments, this type is used.
+
+ This example shows how to call a method with two double arguments.
+ \code
+ QtOpcUa.MethodNode {
+ ...
+ inputArguments: [
+ QtOpcUa.MethodArgument {
+ value: 3
+ type: QtOpcUa.Constants.Double
+ },
+ QtOpcUa.MethodArgument {
+ value: 4
+ type: QtOpcUa.Constants.Double
+ }
+ ]
+ }
+ \endcode
+*/
+
+/*!
+ \qmlproperty variant MethodArgument::value
+
+ The value of the argument.
+*/
+
+/*!
+ \qmlproperty QOpcUa::Types MethodNode::type
+
+ Sets the type of the argument that is expected by the server.
+ The value variant is converted to that type when calling the method.
+ The type has to match the method on the server exactly, otherwise
+ the method call will fail.
+
+ \sa MethodNode::callMethod
+*/
+
+OpcUaMethodArgument::OpcUaMethodArgument(QObject *parent) : QObject(parent)
+{
+}
+
+QVariant OpcUaMethodArgument::value() const
+{
+ return m_value;
+}
+
+QOpcUa::Types OpcUaMethodArgument::type() const
+{
+ return m_type;
+}
+
+void OpcUaMethodArgument::setValue(QVariant value)
+{
+ m_value = value;
+}
+
+void OpcUaMethodArgument::setType(QOpcUa::Types type)
+{
+ m_type = type;
+}
diff --git a/src/imports/opcua/opcuamethodargument.h b/src/imports/opcua/opcuamethodargument.h
new file mode 100644
index 0000000..9d931bf
--- /dev/null
+++ b/src/imports/opcua/opcuamethodargument.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#pragma once
+
+#include "qopcuatype.h"
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+
+class OpcUaMethodArgument : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QVariant value READ value WRITE setValue)
+ Q_PROPERTY(QOpcUa::Types type READ type WRITE setType)
+
+public:
+ explicit OpcUaMethodArgument(QObject *parent = nullptr);
+ QVariant value() const;
+ QOpcUa::Types type() const;
+
+public slots:
+ void setValue(QVariant value);
+ void setType(QOpcUa::Types type);
+
+private:
+ QVariant m_value;
+ QOpcUa::Types m_type;
+};
+
+QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuamethodnode.cpp b/src/imports/opcua/opcuamethodnode.cpp
index bb3037e..6220242 100644
--- a/src/imports/opcua/opcuamethodnode.cpp
+++ b/src/imports/opcua/opcuamethodnode.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt OPC UA module.
@@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE
The target object node ID has to be specified by the \l objectNodeId property.
\code
- import QtOpcUa 5.12 as QtOpcUa
+ import QtOpcUa 5.13 as QtOpcUa
QtOpcUa.MethodNode {
nodeId : QtOpcUa.NodeId {
@@ -96,6 +96,61 @@ QT_BEGIN_NAMESPACE
It can be a relative or absolute node Id.
*/
+/*!
+ \qmlproperty Status MethodNode::resultStatus
+ \readonly
+
+ Status of the last method call. This property has to be checked
+ to determine if the method call was successful.
+
+ \sa Status
+*/
+
+/*!
+ \qmlproperty list<MethodArgument> MethodNode::inputArguments
+
+ Arguments to be used when calling the method on the server.
+
+ This example shows how to call a method with two double arguments.
+ \code
+ QtOpcUa.MethodNode {
+ ...
+ inputArguments: [
+ QtOpcUa.MethodArgument {
+ value: 3
+ type: QtOpcUa.Constants.Double
+ },
+ QtOpcUa.MethodArgument {
+ value: 4
+ type: QtOpcUa.Constants.Double
+ }
+ ]
+ }
+ \endcode
+
+ \sa callMethod
+*/
+
+/*!
+ \qmlproperty list<var> MethodNode::outputArguments
+ \readonly
+
+ Returns values from the method call. Depending on the output arguments,
+ this list may contain zero or more values. The \l resultStatus has to be checked
+ separately. In case the method call failed, the list will be empty.
+
+ \code
+ if (node.status.isGood) {
+ // print two arguments
+ console.log("Number of return values:", node.outputArguments.length)
+ console.log("Return value #1:", node.outputArguments[0])
+ console.log("Return value #2:", node.outputArguments[1])
+ }
+ \endcode
+
+ \sa callMethod, resultStatus
+*/
+
Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_QML)
OpcUaMethodNode::OpcUaMethodNode(QObject *parent):
@@ -108,6 +163,21 @@ OpcUaNodeIdType *OpcUaMethodNode::objectNodeId() const
return m_objectNodeId;
}
+QQmlListProperty<OpcUaMethodArgument> OpcUaMethodNode::inputArguments()
+{
+ return QQmlListProperty<OpcUaMethodArgument>(this,
+ &m_inputArguments,
+ &OpcUaMethodNode::appendArgument,
+ &OpcUaMethodNode::argumentCount,
+ &OpcUaMethodNode::argument,
+ &OpcUaMethodNode::clearArguments);
+}
+
+QVariantList OpcUaMethodNode::outputArguments()
+{
+ return m_outputArguments;
+}
+
void OpcUaMethodNode::setObjectNodeId(OpcUaNodeIdType *node)
{
if (m_objectNodeId)
@@ -120,12 +190,26 @@ void OpcUaMethodNode::setObjectNodeId(OpcUaNodeIdType *node)
void OpcUaMethodNode::callMethod()
{
- if (!m_objectNode || !m_objectNode->node() || !m_node) {
- qCWarning(QT_OPCUA_PLUGINS_QML) << "No node or no object";
+ if (!m_objectNode) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "No object node";
+ setStatus(Status::InvalidObjectNode);
+ return;
+ }
+ if (!m_objectNode->node()) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Invalid object node";
+ setStatus(Status::InvalidObjectNode);
+ return;
+ }
+ if (!m_node) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Invalid node Id";
+ setStatus(Status::InvalidNodeId);
return;
}
- m_objectNode->node()->callMethod(m_node->nodeId(), QVector<QOpcUa::TypedVariant>());
+ QVector<QOpcUa::TypedVariant> arguments;
+ for (const auto item : qAsConst(m_inputArguments))
+ arguments.push_back(QOpcUa::TypedVariant(item->value(), item->type()));
+ m_objectNode->node()->callMethod(m_node->nodeId(), arguments);
}
void OpcUaMethodNode::handleObjectNodeIdChanged()
@@ -133,12 +217,71 @@ void OpcUaMethodNode::handleObjectNodeIdChanged()
m_objectNode->deleteLater();
m_objectNode = new OpcUaNode(this);
m_objectNode->setNodeId(m_objectNodeId);
+ connect(m_objectNode, &OpcUaNode::readyToUseChanged, this, [this](){
+ connect(m_objectNode->node(), &QOpcUaNode::methodCallFinished, this, &OpcUaMethodNode::handleMethodCallFinished, Qt::UniqueConnection);
+ });
+
emit objectNodeIdChanged();
}
+void OpcUaMethodNode::handleMethodCallFinished(QString methodNodeId, QVariant result, QOpcUa::UaStatusCode statusCode)
+{
+ Q_UNUSED(methodNodeId);
+ m_resultStatus = OpcUaStatus(statusCode);
+
+ m_outputArguments.clear();
+ if (result.canConvert<QVariantList>())
+ m_outputArguments = result.value<QVariantList>();
+ else
+ m_outputArguments.append(result);
+ emit resultStatusChanged(m_resultStatus);
+ emit outputArgumentsChanged();
+}
+
void OpcUaMethodNode::setupNode(const QString &absolutePath)
{
OpcUaNode::setupNode(absolutePath);
}
+bool OpcUaMethodNode::checkValidity()
+{
+ if (m_node->attribute(QOpcUa::NodeAttribute::NodeClass).value<QOpcUa::NodeClass>() != QOpcUa::NodeClass::Method) {
+ setStatus(Status::InvalidNodeType);
+ return false;
+ }
+ if (!m_objectNode || !m_objectNode->node()) {
+ setStatus(Status::InvalidObjectNode);
+ return false;
+ }
+
+ const auto objectNodeClass = m_objectNode->node()->attribute(QOpcUa::NodeAttribute::NodeClass).value<QOpcUa::NodeClass>();
+ if (objectNodeClass != QOpcUa::NodeClass::Object && objectNodeClass != QOpcUa::NodeClass::ObjectType) {
+ setStatus(Status::InvalidObjectNode, tr("Object node is not of type `Object' or `ObjectType'"));
+ return false;
+ }
+ return true;
+}
+
+OpcUaStatus OpcUaMethodNode::resultStatus() const
+{
+ return m_resultStatus;
+}
+
+void OpcUaMethodNode::appendArgument(QQmlListProperty<OpcUaMethodArgument>* list, OpcUaMethodArgument* p) {
+ reinterpret_cast< QVector<OpcUaMethodArgument*>* >(list->data)->append(p);
+}
+
+void OpcUaMethodNode::clearArguments(QQmlListProperty<OpcUaMethodArgument>* list) {
+ reinterpret_cast< QVector<OpcUaMethodArgument*>* >(list->data)->clear();
+}
+
+OpcUaMethodArgument* OpcUaMethodNode::argument(QQmlListProperty<OpcUaMethodArgument>* list, int i) {
+ return reinterpret_cast< QVector<OpcUaMethodArgument*>* >(list->data)->at(i);
+}
+
+int OpcUaMethodNode::argumentCount(QQmlListProperty<OpcUaMethodArgument>* list) {
+ return reinterpret_cast< QVector<OpcUaMethodArgument*>* >(list->data)->count();
+}
+
+
QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuamethodnode.h b/src/imports/opcua/opcuamethodnode.h
index 255db8e..fda8fa5 100644
--- a/src/imports/opcua/opcuamethodnode.h
+++ b/src/imports/opcua/opcuamethodnode.h
@@ -37,6 +37,10 @@
#pragma once
#include "opcuanode.h"
+#include "opcuamethodargument.h"
+#include "opcuastatus.h"
+#include <QQmlListProperty>
+#include <QVector>
QT_BEGIN_NAMESPACE
@@ -46,27 +50,48 @@ class OpcUaMethodNode : public OpcUaNode
{
Q_OBJECT
Q_PROPERTY(OpcUaNodeIdType* objectNodeId READ objectNodeId WRITE setObjectNodeId NOTIFY objectNodeIdChanged)
+ Q_PROPERTY(QQmlListProperty<OpcUaMethodArgument> inputArguments READ inputArguments NOTIFY inputArgumentsChanged)
+ Q_PROPERTY(QVariantList outputArguments READ outputArguments NOTIFY outputArgumentsChanged)
+ Q_PROPERTY(OpcUaStatus resultStatus READ resultStatus NOTIFY resultStatusChanged)
public:
OpcUaMethodNode(QObject *parent = nullptr);
OpcUaNodeIdType *objectNodeId() const;
+ QQmlListProperty<OpcUaMethodArgument> inputArguments();
+ QVariantList outputArguments();
+ OpcUaStatus resultStatus() const;
+
public slots:
void setObjectNodeId(OpcUaNodeIdType *nodeId);
void callMethod();
signals:
void objectNodeIdChanged();
+ void inputArgumentsChanged();
+ void outputArgumentsChanged();
+
+ void resultStatusChanged(OpcUaStatus status);
private slots:
void handleObjectNodeIdChanged();
+ void handleMethodCallFinished(QString methodNodeId, QVariant result, QOpcUa::UaStatusCode statusCode);
private:
void setupNode(const QString &absolutePath) override;
+ bool checkValidity() override;
+
+ static void appendArgument(QQmlListProperty<OpcUaMethodArgument>*, OpcUaMethodArgument *);
+ static int argumentCount(QQmlListProperty<OpcUaMethodArgument>*);
+ static OpcUaMethodArgument* argument(QQmlListProperty<OpcUaMethodArgument>*, int);
+ static void clearArguments(QQmlListProperty<OpcUaMethodArgument>*);
private:
OpcUaNodeIdType *m_objectNodeId = nullptr;
OpcUaNode *m_objectNode = nullptr;
+ QVector<OpcUaMethodArgument*> m_inputArguments;
+ QVariantList m_outputArguments;
+ OpcUaStatus m_resultStatus;
};
QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuanode.cpp b/src/imports/opcua/opcuanode.cpp
index 28fe73c..d81f287 100644
--- a/src/imports/opcua/opcuanode.cpp
+++ b/src/imports/opcua/opcuanode.cpp
@@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE
\since QtOpcUa 5.12
\code
- import QtOpcUa 5.12 as QtOpcUa
+ import QtOpcUa 5.13 as QtOpcUa
QtOpcUa.Node {
nodeId : QtOpcUa.NodeId {
@@ -134,12 +134,59 @@ QT_BEGIN_NAMESPACE
a default constructed \l LocalizedText is returned.
*/
+/*!
+ \qmlproperty Status Node::status
+ \readonly
+
+ Current status of the node. The node is only usable when the status is \c Valid.
+ In any other case it indicates an error.
+
+ \sa errorMessage, Status
+*/
+
+/*!
+ \qmlproperty string Node::errorMessage
+ \readonly
+
+ A string representation of the current status code.
+
+ \sa status, Status
+*/
+
+/*!
+ \qmlproperty enumeration Node::Status
+
+ Status of a node.
+
+ \value Node.Status.Valid Node is ready for use
+ \value Node.Status.InvalidNodeId Node id is invalid
+ \value Node.Status.NoConnection Not connected to a server
+ \value Node.Status.InvalidNodeType Node type on the server does not match the QML type
+ \value Node.Status.InvalidClient Invalid connection client
+ \value Node.Status.FailedToResolveNode Failed to resolve node
+ \value Node.Status.InvalidObjectNode The object node is invalid or its type does not match the expected type
+ \value Node.Status.FailedToReadAttributes Failed to read attributes
+ \value Node.Status.FailedToSetupMonitoring Failed to setup monitoring
+
+ \sa status, errorMessage
+*/
+
+/*!
+ \qmlproperty EventFilter Node::eventFilter
+ \since 5.13
+
+ An event filter allows monitoring events on the server for certain conditions.
+
+ \sa EventFilter
+*/
+
Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_QML)
OpcUaNode::OpcUaNode(QObject *parent):
QObject(parent),
m_nodeId(new OpcUaNodeIdType(this)),
- m_attributesToRead(QOpcUaNode::mandatoryBaseAttributes())
+ m_attributesToRead(QOpcUaNode::mandatoryBaseAttributes()),
+ m_status(Status::InvalidNodeId)
{
m_attributesToRead |= QOpcUa::NodeAttribute::Description;
connect(&m_resolvedNode, &UniversalNode::nodeChanged, this, &OpcUaNode::nodeChanged);
@@ -179,12 +226,12 @@ void OpcUaNode::setBrowseName(const QString &value)
if (!m_resolvedNode.isNamespaceIndexValid())
return;
- m_node->writeAttribute(QOpcUa::NodeAttribute::BrowseName, QOpcUa::QQualifiedName(m_resolvedNode.namespaceIndex(), value));
+ m_node->writeAttribute(QOpcUa::NodeAttribute::BrowseName, QOpcUaQualifiedName(m_resolvedNode.namespaceIndex(), value));
}
QString OpcUaNode::browseName()
{
- return m_attributeCache.attributeValue(QOpcUa::NodeAttribute::BrowseName).value<QOpcUa::QQualifiedName>().name();
+ return m_attributeCache.attributeValue(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>().name();
}
QOpcUa::NodeClass OpcUaNode::nodeClass()
@@ -192,28 +239,62 @@ QOpcUa::NodeClass OpcUaNode::nodeClass()
return m_attributeCache.attributeValue(QOpcUa::NodeAttribute::NodeClass).value<QOpcUa::NodeClass>();
}
-void OpcUaNode::setDisplayName(const QOpcUa::QLocalizedText &value)
+void OpcUaNode::setDisplayName(const QOpcUaLocalizedText &value)
{
if (!m_connection || !m_node)
return;
m_node->writeAttribute(QOpcUa::NodeAttribute::DisplayName, value);
}
-QOpcUa::QLocalizedText OpcUaNode::displayName()
+QOpcUaLocalizedText OpcUaNode::displayName()
{
- return m_attributeCache.attributeValue(QOpcUa::NodeAttribute::DisplayName).value<QOpcUa::QLocalizedText>();
+ return m_attributeCache.attributeValue(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>();
}
-void OpcUaNode::setDescription(const QOpcUa::QLocalizedText &value)
+void OpcUaNode::setDescription(const QOpcUaLocalizedText &value)
{
if (!m_connection || !m_node)
return;
m_node->writeAttribute(QOpcUa::NodeAttribute::Description, value);
}
-QOpcUa::QLocalizedText OpcUaNode::description()
+QOpcUaLocalizedText OpcUaNode::description()
+{
+ return m_attributeCache.attributeValue(QOpcUa::NodeAttribute::Description).value<QOpcUaLocalizedText>();
+}
+
+OpcUaNode::Status OpcUaNode::status() const
+{
+ return m_status;
+}
+
+const QString &OpcUaNode::errorMessage() const
+{
+ return m_errorMessage;
+}
+
+/*!
+ \qmlmethod Date Node::getSourceTimestamp(QOpcUa::NodeAttribute attribute)
+
+ Returns the source timestamp of the given \a attribute.
+*/
+QDateTime OpcUaNode::getSourceTimestamp(QOpcUa::NodeAttribute attribute) const
+{
+ if (!m_connection || !m_node)
+ return QDateTime();
+ return m_node->sourceTimestamp(attribute);
+}
+
+/*!
+ \qmlmethod Date Node::getServerTimestamp(Constants::NodeAttribute attribute)
+
+ Returns the server timestamp of the given \a attribute.
+*/
+QDateTime OpcUaNode::getServerTimestamp(QOpcUa::NodeAttribute attribute) const
{
- return m_attributeCache.attributeValue(QOpcUa::NodeAttribute::Description).value<QOpcUa::QLocalizedText>();
+ if (!m_connection || !m_node)
+ return QDateTime();
+ return m_node->serverTimestamp(attribute);
}
void OpcUaNode::setNodeId(OpcUaNodeIdType *nodeId)
@@ -278,9 +359,52 @@ void OpcUaNode::setupNode(const QString &absoluteNodePath)
setReadyToUse(true);
});
+ connect(m_node, &QOpcUaNode::enableMonitoringFinished, this, [this](QOpcUa::NodeAttribute attr, QOpcUa::UaStatusCode statusCode){
+ if (attr != QOpcUa::NodeAttribute::EventNotifier)
+ return;
+ if (statusCode == QOpcUa::Good) {
+ m_eventFilterActive = true;
+ qCDebug(QT_OPCUA_PLUGINS_QML) << "Event filter was enabled for node" << resolvedNode().fullNodeId();
+ updateEventFilter();
+ } else {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Failed to enable event filter for node" << resolvedNode().fullNodeId();
+ setStatus(Status::FailedToSetupMonitoring);
+ }
+ });
+
+ connect(m_node, &QOpcUaNode::disableMonitoringFinished, this, [this](QOpcUa::NodeAttribute attr, QOpcUa::UaStatusCode statusCode){
+ if (attr != QOpcUa::NodeAttribute::EventNotifier)
+ return;
+ if (statusCode == QOpcUa::Good) {
+ m_eventFilterActive = false;
+ qCDebug(QT_OPCUA_PLUGINS_QML) << "Event filter was disabled for node "<< resolvedNode().fullNodeId();
+ } else {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Failed to disable event filter for node "<< resolvedNode().fullNodeId();
+ setStatus(Status::FailedToDisableMonitoring);
+ }
+ });
+
+ connect(m_node, &QOpcUaNode::monitoringStatusChanged, this, [this](QOpcUa::NodeAttribute attr, QOpcUaMonitoringParameters::Parameters items,
+ QOpcUa::UaStatusCode statusCode) {
+ Q_UNUSED(items);
+ if (attr != QOpcUa::NodeAttribute::EventNotifier)
+ return;
+ if (statusCode != QOpcUa::Good) {
+ setStatus(Status::FailedToModifyMonitoring);
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Failed to modify event filter for" << m_node->nodeId();
+ }
+ });
+
+ connect (m_node, &QOpcUaNode::eventOccurred, this, &OpcUaNode::eventOccurred);
+
+
// Read mandatory attributes
- if (!m_node->readAttributes(m_attributesToRead))
+ if (!m_node->readAttributes(m_attributesToRead)) {
qCWarning(QT_OPCUA_PLUGINS_QML) << "Reading attributes" << m_node->nodeId() << "failed";
+ setStatus(Status::FailedToReadAttributes);
+ }
+
+ updateEventFilter();
}
void OpcUaNode::updateNode()
@@ -288,6 +412,109 @@ void OpcUaNode::updateNode()
retrieveAbsoluteNodePath(m_nodeId, [this](const QString &absoluteNodePath) {setupNode(absoluteNodePath);});
}
+OpcUaEventFilter *OpcUaNode::eventFilter() const
+{
+ return m_eventFilter;
+}
+
+void OpcUaNode::setEventFilter(OpcUaEventFilter *eventFilter)
+{
+ bool changed = false;
+
+ if (m_eventFilter) {
+ disconnect(m_eventFilter, &OpcUaEventFilter::dataChanged, this, &OpcUaNode::updateEventFilter);
+ changed = !(*m_eventFilter == *eventFilter);
+ } else {
+ changed = true;
+ }
+
+ m_eventFilter = eventFilter;
+ connect(m_eventFilter, &OpcUaEventFilter::dataChanged, this, &OpcUaNode::updateEventFilter);
+
+ if (changed)
+ emit eventFilterChanged();
+}
+
+
+void OpcUaNode::updateEventFilter()
+{
+ if (!m_connection || !m_node || !m_eventFilter)
+ return;
+
+ if (m_eventFilterActive) {
+ m_node->modifyEventFilter(m_eventFilter->filter(m_connection->m_client));
+ } else {
+ QOpcUaMonitoringParameters parameters;
+ parameters.setFilter(m_eventFilter->filter(m_connection->m_client));
+ m_node->enableMonitoring(QOpcUa::NodeAttribute::EventNotifier, parameters);
+ m_eventFilterActive = true;
+ }
+}
+
+void OpcUaNode::setStatus(OpcUaNode::Status status, const QString &message)
+{
+ QString errorMessage(message);
+ bool emitStatusChanged = false;
+ bool emitErrorMessageChanged = false;
+
+ if (m_status != status) {
+ m_status = status;
+ emitStatusChanged = true;
+ }
+
+ // if error message is not given, use default error message
+ if (errorMessage.isEmpty()) {
+ switch (m_status) {
+ case Status::Valid:
+ errorMessage = tr("Node is valid");
+ break;
+ case Status::InvalidNodeId:
+ errorMessage = tr("Node Id is invalid");
+ break;
+ case Status::NoConnection:
+ errorMessage = tr("Not connected to server");
+ break;
+ case Status::InvalidNodeType:
+ errorMessage = tr("QML element does not match node type on the server");
+ break;
+ case Status::InvalidClient:
+ errorMessage = tr("Connecting client is invalid");
+ break;
+ case Status::FailedToResolveNode:
+ errorMessage = tr("Failed to resolve node");
+ break;
+ case Status::InvalidObjectNode:
+ errorMessage = tr("Invalid object node");
+ break;
+ case Status::FailedToReadAttributes:
+ errorMessage = tr("Failed to read attributes");
+ break;
+ case Status::FailedToSetupMonitoring:
+ errorMessage = tr("Failed to setup monitoring");
+ break;
+ case Status::FailedToWriteAttribute:
+ errorMessage = tr("Failed to write attribute");
+ break;
+ case Status::FailedToModifyMonitoring:
+ errorMessage = tr("Failed to modify monitoring");
+ break;
+ case Status::FailedToDisableMonitoring:
+ errorMessage = tr("Failed to disable monitoring");
+ break;
+ }
+ }
+
+ if (errorMessage != m_errorMessage) {
+ m_errorMessage = errorMessage;
+ emitErrorMessageChanged = true;
+ }
+
+ if (emitStatusChanged)
+ emit statusChanged();
+ if (emitErrorMessageChanged)
+ emit errorMessageChanged();
+}
+
const UniversalNode &OpcUaNode::resolvedNode() const
{
return m_resolvedNode;
@@ -311,8 +538,19 @@ QOpcUa::NodeAttributes OpcUaNode::attributesToRead() const
void OpcUaNode::retrieveAbsoluteNodePath(OpcUaNodeIdType *node, std::function<void (const QString &)> functor)
{
auto conn = connection();
- if (!conn || !m_nodeId || !conn->m_client) {
- qCWarning(QT_OPCUA_PLUGINS_QML) << "connection, nodeID or client is invalid";
+ if (!conn) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "No connection to server";
+ setStatus(Status::NoConnection);
+ return;
+ }
+ if (!m_nodeId) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Invalid node ID";
+ setStatus(Status::InvalidNodeId);
+ return;
+ }
+ if (!conn->m_client) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Client instance is invalid";
+ setStatus(Status::InvalidClient);
return;
}
@@ -336,6 +574,7 @@ void OpcUaNode::retrieveAbsoluteNodePath(OpcUaNodeIdType *node, std::function<vo
if (!errorMessage.isEmpty()) {
qCWarning(QT_OPCUA_PLUGINS_QML) << "Failed to resolve node:" << errorMessage;
+ setStatus(Status::FailedToResolveNode, errorMessage);
functor(QString());
return;
}
@@ -353,10 +592,22 @@ void OpcUaNode::retrieveAbsoluteNodePath(OpcUaNodeIdType *node, std::function<vo
void OpcUaNode::setReadyToUse(bool value)
{
+ if (value && !checkValidity())
+ value = false;
+
bool old = m_readyToUse;
m_readyToUse = value;
+
+ if (value)
+ setStatus(Status::Valid);
+
if (!old && value)
emit readyToUseChanged();
}
+bool OpcUaNode::checkValidity()
+{
+ return true;
+}
+
QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuanode.h b/src/imports/opcua/opcuanode.h
index c5763bd..b7501a5 100644
--- a/src/imports/opcua/opcuanode.h
+++ b/src/imports/opcua/opcuanode.h
@@ -37,9 +37,11 @@
#pragma once
#include <QObject>
-#include "qopcuatype.h"
#include "universalnode.h"
#include "opcuaattributecache.h"
+#include "qopcualocalizedtext.h"
+#include "opcuaeventfilter.h"
+#include <QDateTime>
QT_BEGIN_NAMESPACE
@@ -51,19 +53,40 @@ class OpcUaNode : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(OpcUaNode)
+ Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
+
Q_PROPERTY(OpcUaNodeIdType* nodeId READ nodeId WRITE setNodeId NOTIFY nodeIdChanged)
Q_PROPERTY(OpcUaConnection* connection READ connection WRITE setConnection NOTIFY connectionChanged)
Q_PROPERTY(bool readyToUse READ readyToUse NOTIFY readyToUseChanged)
+ Q_PROPERTY(OpcUaNode::Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged)
+ Q_PROPERTY(OpcUaEventFilter *eventFilter READ eventFilter WRITE setEventFilter NOTIFY eventFilterChanged)
// basic node properties
Q_PROPERTY(QString browseName READ browseName WRITE setBrowseName NOTIFY browseNameChanged)
Q_PROPERTY(QOpcUa::NodeClass nodeClass READ nodeClass NOTIFY nodeClassChanged)
- Q_PROPERTY(QOpcUa::QLocalizedText displayName READ displayName WRITE setDisplayName NOTIFY displayNameChanged)
- Q_PROPERTY(QOpcUa::QLocalizedText description READ description WRITE setDescription NOTIFY descriptionChanged)
+ Q_PROPERTY(QOpcUaLocalizedText displayName READ displayName WRITE setDisplayName NOTIFY displayNameChanged)
+ Q_PROPERTY(QOpcUaLocalizedText description READ description WRITE setDescription NOTIFY descriptionChanged)
Q_ENUM(QOpcUa::NodeClass);
public:
+ enum class Status {
+ Valid,
+ InvalidNodeId,
+ NoConnection,
+ InvalidNodeType,
+ InvalidClient,
+ FailedToResolveNode,
+ InvalidObjectNode,
+ FailedToReadAttributes,
+ FailedToSetupMonitoring,
+ FailedToWriteAttribute,
+ FailedToModifyMonitoring,
+ FailedToDisableMonitoring
+ };
+ Q_ENUM(Status);
+
OpcUaNode(QObject *parent = nullptr);
~OpcUaNode();
OpcUaNodeIdType *nodeId() const;
@@ -75,11 +98,20 @@ public:
QOpcUa::NodeClass nodeClass();
- void setDisplayName(const QOpcUa::QLocalizedText &value);
- QOpcUa::QLocalizedText displayName();
+ void setDisplayName(const QOpcUaLocalizedText &value);
+ QOpcUaLocalizedText displayName();
+
+ void setDescription(const QOpcUaLocalizedText &value);
+ QOpcUaLocalizedText description();
+
+ OpcUaNode::Status status() const;
+ const QString &errorMessage() const;
+
+ OpcUaEventFilter *eventFilter() const;
+ void setEventFilter(OpcUaEventFilter *eventFilter);
- void setDescription(const QOpcUa::QLocalizedText &value);
- QOpcUa::QLocalizedText description();
+ Q_INVOKABLE QDateTime getSourceTimestamp(QOpcUa::NodeAttribute) const;
+ Q_INVOKABLE QDateTime getServerTimestamp(QOpcUa::NodeAttribute) const;
// This function is not exposed to QML
const UniversalNode &resolvedNode() const;
@@ -100,16 +132,23 @@ signals:
void nodeClassChanged();
void displayNameChanged();
void descriptionChanged();
+ void statusChanged();
+ void errorMessageChanged();
+ void eventFilterChanged();
+ void eventOccurred(const QVariantList&values);
protected slots:
virtual void setupNode(const QString &absoluteNodePath);
void updateNode();
+ void updateEventFilter();
protected:
+ void setStatus(Status status, const QString &message = QString());
void setAttributesToRead(QOpcUa::NodeAttributes attributes);
QOpcUa::NodeAttributes attributesToRead() const;
void retrieveAbsoluteNodePath(OpcUaNodeIdType *, std::function<void (const QString &)>);
void setReadyToUse(bool value = true);
+ virtual bool checkValidity();
OpcUaNodeIdType *m_nodeId = nullptr;
QOpcUaNode *m_node = nullptr;
@@ -119,6 +158,10 @@ protected:
UniversalNode m_resolvedNode;
OpcUaAttributeCache m_attributeCache;
QOpcUa::NodeAttributes m_attributesToRead;
+ Status m_status;
+ QString m_errorMessage;
+ OpcUaEventFilter *m_eventFilter = nullptr;
+ bool m_eventFilterActive = false;
};
QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuanodeid.cpp b/src/imports/opcua/opcuanodeid.cpp
index 7ed6954..b34f4c8 100644
--- a/src/imports/opcua/opcuanodeid.cpp
+++ b/src/imports/opcua/opcuanodeid.cpp
@@ -35,7 +35,6 @@
****************************************************************************/
#include "opcuanodeid.h"
-#include <QDebug>
QT_BEGIN_NAMESPACE
@@ -46,7 +45,7 @@ QT_BEGIN_NAMESPACE
\since QtOpcUa 5.12
\code
- import QtOpcUa 5.12 as QtOpcUa
+ import QtOpcUa 5.13 as QtOpcUa
QtOpcUa.NodeId {
identifier: "s=Example.Node"
@@ -56,7 +55,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \qmlproperty string NodeId::namespace
+ \qmlproperty string NodeId::ns
Namespace of the node identifier.
The identifier can be the index as a number or the name as string.
diff --git a/src/imports/opcua/opcuanodeidtype.cpp b/src/imports/opcua/opcuanodeidtype.cpp
index f89f526..5511581 100644
--- a/src/imports/opcua/opcuanodeidtype.cpp
+++ b/src/imports/opcua/opcuanodeidtype.cpp
@@ -35,7 +35,6 @@
****************************************************************************/
#include "opcuanodeidtype.h"
-#include <QtDebug>
QT_BEGIN_NAMESPACE
diff --git a/src/imports/opcua/opcuaoperandbase.cpp b/src/imports/opcua/opcuaoperandbase.cpp
new file mode 100644
index 0000000..967610e
--- /dev/null
+++ b/src/imports/opcua/opcuaoperandbase.cpp
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcuaoperandbase.h"
+#include <QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_QML)
+
+OpcUaOperandBase::OpcUaOperandBase(QObject *parent)
+ : QObject(parent)
+{
+}
+
+OpcUaOperandBase::~OpcUaOperandBase() = default;
+
+QVariant OpcUaOperandBase::toCppVariant(QOpcUaClient *client) const
+{
+ Q_UNUSED(client);
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Calling invalid base function of OpcUaOperandBase";
+ return QVariant();
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuaoperandbase.h b/src/imports/opcua/opcuaoperandbase.h
new file mode 100644
index 0000000..ab9f986
--- /dev/null
+++ b/src/imports/opcua/opcuaoperandbase.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPCUAOPERANDBASE
+#define OPCUAOPERANDBASE
+
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaClient;
+
+class OpcUaOperandBase : public QObject {
+ Q_OBJECT
+
+public:
+ explicit OpcUaOperandBase(QObject *parent = nullptr);
+ ~OpcUaOperandBase();
+
+ virtual QVariant toCppVariant(QOpcUaClient *client) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // OPCUAOPERANDBASE
diff --git a/src/imports/opcua/opcuapathresolver.cpp b/src/imports/opcua/opcuapathresolver.cpp
index e5c8865..3e73e54 100644
--- a/src/imports/opcua/opcuapathresolver.cpp
+++ b/src/imports/opcua/opcuapathresolver.cpp
@@ -153,7 +153,7 @@ void OpcUaPathResolver::startNodeResolved(UniversalNode startNode, const QString
}
// construct path vector
- QVector<QOpcUa::QRelativePathElement> path;
+ QVector<QOpcUaRelativePathElement> path;
for (int i = 0; i < m_relativeNode->pathCount(); ++i)
path.append(m_relativeNode->path(i)->toRelativePathElement(m_client));
@@ -166,7 +166,7 @@ void OpcUaPathResolver::startNodeResolved(UniversalNode startNode, const QString
}
}
-void OpcUaPathResolver::browsePathFinished(QVector<QOpcUa::QBrowsePathTarget> results, QVector<QOpcUa::QRelativePathElement> path, QOpcUa::UaStatusCode status)
+void OpcUaPathResolver::browsePathFinished(QVector<QOpcUaBrowsePathTarget> results, QVector<QOpcUaRelativePathElement> path, QOpcUa::UaStatusCode status)
{
Q_UNUSED(path);
UniversalNode nodeToUse;
@@ -183,11 +183,23 @@ void OpcUaPathResolver::browsePathFinished(QVector<QOpcUa::QBrowsePathTarget> re
deleteLater();
return;
} else if (results.size() == 1) {
+ if (results.at(0).targetId().serverIndex() > 0) {
+ emit resolvedNode(UniversalNode(), QString("Relative path could not be resolved: Resulting node is located on a remote server"));
+ deleteLater();
+ return;
+ }
nodeToUse.from(results.at(0));
+
} else { // greater than one
UniversalNode tmp;
+ QString message = "No resolved node found";
+
for (const auto &result : results) {
if (result.isFullyResolved()) {
+ if (result.targetId().serverIndex() > 0) {
+ message = QString("Relative path could not be resolved: Resulting node is located on a remote server");
+ continue;
+ }
if (!tmp.nodeIdentifier().isEmpty()) {
emit resolvedNode(UniversalNode(), QLatin1String("There are multiple resolved nodes"));
deleteLater();
@@ -200,7 +212,7 @@ void OpcUaPathResolver::browsePathFinished(QVector<QOpcUa::QBrowsePathTarget> re
if (!tmp.nodeIdentifier().isEmpty()) {
nodeToUse = tmp;
} else {
- emit resolvedNode(UniversalNode(), QString("No resolved node found"));
+ emit resolvedNode(UniversalNode(), message);
deleteLater();
return;
}
@@ -209,6 +221,7 @@ void OpcUaPathResolver::browsePathFinished(QVector<QOpcUa::QBrowsePathTarget> re
nodeToUse.resolveNamespace(m_client);
qCDebug(QT_OPCUA_PLUGINS_QML) << "Relative node fully resolved to:" << nodeToUse.fullNodeId();
emit resolvedNode(nodeToUse, QString());
+ deleteLater();
}
QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuapathresolver.h b/src/imports/opcua/opcuapathresolver.h
index 7abebd7..914d1ff 100644
--- a/src/imports/opcua/opcuapathresolver.h
+++ b/src/imports/opcua/opcuapathresolver.h
@@ -40,12 +40,13 @@
#include <QPointer>
#include "qopcuatype.h"
#include "universalnode.h"
+#include "qopcuabrowsepathtarget.h"
+#include "qopcuarelativepathelement.h"
QT_BEGIN_NAMESPACE
class QOpcUaNode;
class QOpcUaClient;
-class QRelativePathElement;
class OpcUaRelativeNodeId;
class QOpcUaClient;
@@ -63,7 +64,7 @@ signals:
private slots:
void startNodeResolved(UniversalNode startNode, const QString &errorMessage);
- void browsePathFinished(QVector<QOpcUa::QBrowsePathTarget> results, QVector<QOpcUa::QRelativePathElement> path, QOpcUa::UaStatusCode status);
+ void browsePathFinished(QVector<QOpcUaBrowsePathTarget> results, QVector<QOpcUaRelativePathElement> path, QOpcUa::UaStatusCode status);
private:
OpcUaPathResolver(int level, OpcUaRelativeNodeId *relativeNode, QOpcUaClient *client, QObject *target);
diff --git a/src/imports/opcua/opcuareaditem.cpp b/src/imports/opcua/opcuareaditem.cpp
new file mode 100644
index 0000000..fc1b2b8
--- /dev/null
+++ b/src/imports/opcua/opcuareaditem.cpp
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcuareaditem.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ReadItem
+ \inqmlmodule QtOpcUa
+ \brief Specifies an item to be read from the server.
+ \since QtOpcUa 5.13
+
+ This type is used to specify items to be read from the server using the function
+ \l Connection::readNodeAttributes.
+*/
+
+/*!
+ \qmlproperty Constants.NodeAttribute ReadItem::attribute
+
+ Determines the attribute of the node to be read.
+*/
+
+/*!
+ \qmlproperty string ReadItem::indexRange
+
+ Determines the index range of the attribute to be read.
+ If not needed, leave this property empty.
+*/
+
+/*!
+ \qmlproperty string ReadItem::nodeId
+
+ Determines the node id of the node to be read.
+*/
+
+/*!
+ \qmlproperty variant ReadItem::ns
+
+ Determines the namespace of the node to be read.
+ The namespace can be given by name or index.
+ If this property is given, any namespace in the node id will be
+ ignored.
+*/
+
+class OpcUaReadItemData : public QSharedData
+{
+public:
+ QOpcUa::NodeAttribute attribute;
+ QString indexRange;
+ QString nodeId;
+ QVariant namespaceIdentifier;
+};
+
+OpcUaReadItem::OpcUaReadItem()
+ : data(new OpcUaReadItemData)
+{
+ data->attribute = QOpcUa::NodeAttribute::Value;
+}
+
+OpcUaReadItem::OpcUaReadItem(const OpcUaReadItem &other)
+ : data(other.data)
+{
+}
+
+OpcUaReadItem &OpcUaReadItem::operator=(const OpcUaReadItem &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+OpcUaReadItem::~OpcUaReadItem() = default;
+
+const QString &OpcUaReadItem::indexRange() const
+{
+ return data->indexRange;
+}
+
+void OpcUaReadItem::setIndexRange(const QString &indexRange)
+{
+ data->indexRange = indexRange;
+}
+
+const QString &OpcUaReadItem::nodeId() const
+{
+ return data->nodeId;
+}
+
+void OpcUaReadItem::setNodeId(const QString &nodeId)
+{
+ data->nodeId = nodeId;
+}
+
+QOpcUa::NodeAttribute OpcUaReadItem::attribute() const
+{
+ return data->attribute;
+}
+
+void OpcUaReadItem::setAttribute(QOpcUa::NodeAttribute attribute)
+{
+ data->attribute = attribute;
+}
+
+const QVariant &OpcUaReadItem::namespaceIdentifier() const
+{
+ return data->namespaceIdentifier;
+}
+
+void OpcUaReadItem::setNamespaceIdentifier(const QVariant &namespaceIdentifier)
+{
+ data->namespaceIdentifier = namespaceIdentifier;
+}
+
+OpcUaReadItem OpcUaReadItemFactory::create()
+{
+ return OpcUaReadItem();
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/imports/opcua/opcuareaditem.h b/src/imports/opcua/opcuareaditem.h
new file mode 100644
index 0000000..48c399b
--- /dev/null
+++ b/src/imports/opcua/opcuareaditem.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPCUAREADITEM_H
+#define OPCUAREADITEM_H
+
+#include <QObject>
+#include <QtCore/qshareddata.h>
+#include "qopcuatype.h"
+
+QT_BEGIN_NAMESPACE
+
+class OpcUaReadItemData;
+class OpcUaReadItem
+{
+ Q_GADGET
+ Q_PROPERTY(QOpcUa::NodeAttribute attribute READ attribute WRITE setAttribute)
+ Q_PROPERTY(QString indexRange READ indexRange WRITE setIndexRange)
+ Q_PROPERTY(QString nodeId READ nodeId WRITE setNodeId)
+ Q_PROPERTY(QVariant ns READ namespaceIdentifier WRITE setNamespaceIdentifier)
+
+public:
+ OpcUaReadItem();
+ OpcUaReadItem(const OpcUaReadItem &other);
+ OpcUaReadItem &operator=(const OpcUaReadItem &rhs);
+ ~OpcUaReadItem();
+
+ const QString &indexRange() const;
+ void setIndexRange(const QString &indexRange);
+
+ const QString &nodeId() const;
+ void setNodeId(const QString &nodeId);
+
+ QOpcUa::NodeAttribute attribute() const;
+ void setAttribute(QOpcUa::NodeAttribute attribute);
+
+ const QVariant &namespaceIdentifier() const;
+ void setNamespaceIdentifier(const QVariant &namespaceIdentifier);
+
+private:
+ QSharedDataPointer<OpcUaReadItemData> data;
+};
+
+class OpcUaReadItemFactory : public QObject
+{
+ Q_OBJECT
+public:
+ Q_INVOKABLE OpcUaReadItem create();
+};
+
+QT_END_NAMESPACE
+
+#endif // OPCUAREADITEM_H
diff --git a/src/imports/opcua/opcuareadresult.cpp b/src/imports/opcua/opcuareadresult.cpp
new file mode 100644
index 0000000..540be56
--- /dev/null
+++ b/src/imports/opcua/opcuareadresult.cpp
@@ -0,0 +1,203 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcuareadresult.h"
+#include "universalnode.h"
+#include <QOpcUaReadResult>
+#include <QOpcUaClient>
+#include <qopcuatype.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ReadResult
+ \inqmlmodule QtOpcUa
+ \brief Contains result data after reading from the server.
+ \since QtOpcUa 5.13
+
+ This type is used to pass the read data after reading from the server using the function
+ \l Connection::readNodeAttributes.
+*/
+
+/*!
+ \qmlproperty Constants.NodeAttribute ReadResult::attribute
+ \readonly
+
+ The node attribute of data that was read.
+*/
+
+/*!
+ \qmlproperty string ReadResult::indexRange
+ \readonly
+
+ The index range of the data that was read.
+*/
+
+/*!
+ \qmlproperty string ReadResult::nodeId
+ \readonly
+
+ The node id of the node that was read.
+*/
+
+/*!
+ \qmlproperty string ReadResult::namespaceName
+ \readonly
+
+ The namespace name of the node that was read.
+*/
+
+/*!
+ \qmlproperty datetime ReadResult::serverTimestamp
+ \readonly
+
+ The server timestamp of the data that was read.
+*/
+
+/*!
+ \qmlproperty datetime ReadResult::sourceTimestamp
+ \readonly
+
+ The source timestamp of the data that was read.
+*/
+
+/*!
+ \qmlproperty variant ReadResult::value
+ \readonly
+
+ Actual data that was requested to be read.
+*/
+
+/*!
+ \qmlproperty Status ReadResult::status
+ \readonly
+
+ Result status of this ReadResult.
+ Before using any value of this ReadResult, the status
+ should be checked for \l {Status::Status}{Status.isGood}. To make sure
+ the server has provided valid data.
+*/
+
+class OpcUaReadResultData : public QSharedData
+{
+public:
+ OpcUaStatus status;
+ QOpcUa::NodeAttribute attribute;
+ QString indexRange;
+ QString nodeId;
+ QString namespaceName;
+ QDateTime serverTimestamp;
+ QDateTime sourceTimestamp;
+ QVariant value;
+};
+
+OpcUaReadResult::OpcUaReadResult()
+ : data(new OpcUaReadResultData)
+{
+ data->attribute = QOpcUa::NodeAttribute::None;
+}
+
+OpcUaReadResult::OpcUaReadResult(const OpcUaReadResult &other)
+ : data(other.data)
+{
+}
+
+OpcUaReadResult::OpcUaReadResult(const QOpcUaReadResult &other, const QOpcUaClient *client)
+ : data(new OpcUaReadResultData)
+{
+ data->status = OpcUaStatus(other.statusCode());
+ data->attribute = other.attribute();
+ data->indexRange = other.indexRange();
+ data->serverTimestamp = other.serverTimestamp();
+ data->sourceTimestamp = other.sourceTimestamp();
+ data->value = other.value();
+
+ int namespaceIndex = -1;
+ UniversalNode::splitNodeIdAndNamespace(other.nodeId(), &namespaceIndex, &data->nodeId);
+ data->namespaceName = client->namespaceArray().at(namespaceIndex);
+}
+
+OpcUaReadResult &OpcUaReadResult::operator=(const OpcUaReadResult &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+OpcUaReadResult::~OpcUaReadResult() = default;
+
+const QString &OpcUaReadResult::indexRange() const
+{
+ return data->indexRange;
+}
+
+const QString &OpcUaReadResult::nodeId() const
+{
+ return data->nodeId;
+}
+
+QOpcUa::NodeAttribute OpcUaReadResult::attribute() const
+{
+ return data->attribute;
+}
+
+const QString &OpcUaReadResult::namespaceName() const
+{
+ return data->namespaceName;
+}
+
+const QDateTime &OpcUaReadResult::serverTimestamp() const
+{
+ return data->serverTimestamp;
+}
+
+const QDateTime &OpcUaReadResult::sourceTimestamp() const
+{
+ return data->sourceTimestamp;
+}
+
+const QVariant &OpcUaReadResult::value() const
+{
+ return data->value;
+}
+
+OpcUaStatus OpcUaReadResult::status() const
+{
+ return data->status;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/imports/opcua/opcuareadresult.h b/src/imports/opcua/opcuareadresult.h
new file mode 100644
index 0000000..d4b40c5
--- /dev/null
+++ b/src/imports/opcua/opcuareadresult.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPCUAREADRESULT_H
+#define OPCUAREADRESULT_H
+
+#include <QObject>
+#include <QDateTime>
+#include "qopcuatype.h"
+#include "opcuastatus.h"
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaReadResult;
+class QOpcUaClient;
+class OpcUaReadResultData;
+class OpcUaReadResult
+{
+ Q_GADGET
+ Q_PROPERTY(QOpcUa::NodeAttribute attribute READ attribute)
+ Q_PROPERTY(QString indexRange READ indexRange)
+ Q_PROPERTY(QString nodeId READ nodeId)
+ Q_PROPERTY(QString namespaceName READ namespaceName)
+ Q_PROPERTY(const QDateTime &serverTimestamp READ serverTimestamp)
+ Q_PROPERTY(const QDateTime &sourceTimestamp READ sourceTimestamp)
+ Q_PROPERTY(QVariant value READ value)
+ Q_PROPERTY(OpcUaStatus status READ status)
+
+public:
+ OpcUaReadResult();
+ OpcUaReadResult(const OpcUaReadResult &other);
+ OpcUaReadResult(const QOpcUaReadResult &other, const QOpcUaClient *client);
+ OpcUaReadResult &operator=(const OpcUaReadResult &rhs);
+ ~OpcUaReadResult();
+
+ const QString &indexRange() const;
+ const QString &nodeId() const;
+ QOpcUa::NodeAttribute attribute() const;
+ const QString &namespaceName() const;
+ const QDateTime &serverTimestamp() const;
+ const QDateTime &sourceTimestamp() const;
+ const QVariant &value() const;
+
+ OpcUaStatus status() const;
+
+private:
+ QSharedDataPointer<OpcUaReadResultData> data;
+};
+
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(OpcUaReadResult)
+
+#endif // OPCUAREADRESULT_H
diff --git a/src/imports/opcua/opcuarelativenodeid.cpp b/src/imports/opcua/opcuarelativenodeid.cpp
index a4afb89..f51425d 100644
--- a/src/imports/opcua/opcuarelativenodeid.cpp
+++ b/src/imports/opcua/opcuarelativenodeid.cpp
@@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE
matches can not be handled and are treated as error.
\code
- import QtOpcUa 5.12 as QtOpcUa
+ import QtOpcUa 5.13 as QtOpcUa
QtOpcUa.RelativeNodeId {
startNode: QtOpcUa.RelativeNodeId {
diff --git a/src/imports/opcua/opcuarelativenodepath.cpp b/src/imports/opcua/opcuarelativenodepath.cpp
index bcae709..8b42ed8 100644
--- a/src/imports/opcua/opcuarelativenodepath.cpp
+++ b/src/imports/opcua/opcuarelativenodepath.cpp
@@ -35,8 +35,10 @@
****************************************************************************/
#include "opcuarelativenodepath.h"
-#include "qopcuatype.h"
+#include "opcuanodeid.h"
#include "qopcuaclient.h"
+#include <QLoggingCategory>
+#include <QMetaEnum>
QT_BEGIN_NAMESPACE
@@ -47,7 +49,7 @@ QT_BEGIN_NAMESPACE
\since QtOpcUa 5.12
\code
- import QtOpcUa 5.12 as QtOpcUa
+ import QtOpcUa 5.13 as QtOpcUa
QtOpcUa.RelativeNodePath {
ns: "Test Namespace"
@@ -90,9 +92,12 @@ QT_BEGIN_NAMESPACE
\qmlproperty QOpcUa::ReferenceTypeId RelativeNodePath::referenceType
Type of reference when mathing this path element.
- The default value of this property is \c QOpcUa::ReferenceTypeId::References.
+ This can be a \l QOpcUa::ReferenceTypeId or a \l NodeId.
+ The default value of this property is \c Constants.ReferenceTypeId.References.
*/
+Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_QML)
+
OpcUaRelativeNodePath::OpcUaRelativeNodePath(QObject *parent) : QObject(parent)
{
connect(&m_browseNode, &UniversalNode::namespaceNameChanged, this, &OpcUaRelativeNodePath::nodeNamespaceChanged);
@@ -109,7 +114,7 @@ const QString &OpcUaRelativeNodePath::browseName() const
return m_browseNode.nodeIdentifier();
}
-QOpcUa::ReferenceTypeId OpcUaRelativeNodePath::referenceType() const
+QVariant OpcUaRelativeNodePath::referenceType() const
{
return m_referenceType;
}
@@ -129,13 +134,25 @@ void OpcUaRelativeNodePath::setBrowseName(QString browseName)
m_browseNode.setNodeIdentifier(browseName);
}
-void OpcUaRelativeNodePath::setReferenceType(QOpcUa::ReferenceTypeId referenceType)
+void OpcUaRelativeNodePath::setReferenceType(const QVariant &referenceType)
{
+ bool valid = false;
+
+ if (referenceType.userType() == qMetaTypeId<QObject*>() && qobject_cast<OpcUaNodeId*>(referenceType.value<QObject*>()))
+ valid = true;
+ else if (referenceType.userType() == QVariant::Int && QMetaEnum::fromType<QOpcUa::ReferenceTypeId>().valueToKey(referenceType.toInt()))
+ valid = true;
+
+ if (!valid) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Invalid reference type:" << referenceType;
+ return;
+ }
+
if (m_referenceType == referenceType)
return;
m_referenceType = referenceType;
- emit referenceTypeChanged(m_referenceType);
+ emit referenceTypeChanged();
}
void OpcUaRelativeNodePath::setIncludeSubtypes(bool includeSubtypes)
@@ -152,15 +169,20 @@ bool OpcUaRelativeNodePath::isInverse() const
return m_isInverse;
}
-QOpcUa::QRelativePathElement OpcUaRelativeNodePath::toRelativePathElement(QOpcUaClient *client) const
+QOpcUaRelativePathElement OpcUaRelativeNodePath::toRelativePathElement(QOpcUaClient *client) const
{
m_browseNode.resolveNamespaceNameToIndex(client);
- QOpcUa::QRelativePathElement x;
+ QOpcUaRelativePathElement x;
x.setIsInverse(isInverse());
x.setIncludeSubtypes(includeSubtypes());
x.setTargetName(m_browseNode.toQualifiedName());
- x.setReferenceTypeId(referenceType());
+ if (m_referenceType.userType() == QVariant::Int
+ || m_referenceType.userType() == qMetaTypeId<QOpcUa::ReferenceTypeId>())
+ x.setReferenceTypeId(m_referenceType.value<QOpcUa::ReferenceTypeId>());
+ else
+ x.setReferenceTypeId(m_referenceType.toString());
+
return x;
}
diff --git a/src/imports/opcua/opcuarelativenodepath.h b/src/imports/opcua/opcuarelativenodepath.h
index 19f7f9b..ecad1e9 100644
--- a/src/imports/opcua/opcuarelativenodepath.h
+++ b/src/imports/opcua/opcuarelativenodepath.h
@@ -43,13 +43,14 @@
QT_BEGIN_NAMESPACE
class QOpcUaClient;
+class QOpcUaRelativePathElement;
class OpcUaRelativeNodePath : public QObject
{
Q_OBJECT
Q_PROPERTY(QString ns READ nodeNamespace WRITE setNodeNamespace NOTIFY nodeNamespaceChanged)
Q_PROPERTY(QString browseName READ browseName WRITE setBrowseName NOTIFY browseNameChanged)
- Q_PROPERTY(QOpcUa::ReferenceTypeId referenceType READ referenceType WRITE setReferenceType NOTIFY referenceTypeChanged)
+ Q_PROPERTY(QVariant referenceType READ referenceType WRITE setReferenceType NOTIFY referenceTypeChanged)
Q_PROPERTY(bool includeSubtypes READ includeSubtypes WRITE setIncludeSubtypes NOTIFY includeSubtypesChanged)
Q_PROPERTY(bool isInverse READ isInverse WRITE setIsInverse NOTIFY isInverseChanged)
@@ -57,28 +58,28 @@ public:
explicit OpcUaRelativeNodePath(QObject *parent = nullptr);
const QString &nodeNamespace() const;
const QString &browseName() const;
- QOpcUa::ReferenceTypeId referenceType() const;
+ QVariant referenceType() const;
bool includeSubtypes() const;
bool isInverse() const;
- QOpcUa::QRelativePathElement toRelativePathElement(QOpcUaClient *client) const;
+ QOpcUaRelativePathElement toRelativePathElement(QOpcUaClient *client) const;
signals:
void nodeNamespaceChanged(QString ns);
void browseNameChanged(QString browseName);
- void referenceTypeChanged(QOpcUa::ReferenceTypeId referenceType);
+ void referenceTypeChanged();
void includeSubtypesChanged(bool includeSubtypes);
void isInverseChanged(bool isInverse);
public slots:
void setNodeNamespace(QString ns);
void setBrowseName(QString browseName);
- void setReferenceType(QOpcUa::ReferenceTypeId referenceType);
+ void setReferenceType(const QVariant &referenceType);
void setIncludeSubtypes(bool includeSubtypes);
void setIsInverse(bool isInverse);
private:
mutable UniversalNode m_browseNode;
- QOpcUa::ReferenceTypeId m_referenceType = QOpcUa::ReferenceTypeId::References;
+ QVariant m_referenceType = QVariant::fromValue(QOpcUa::ReferenceTypeId::References);
bool m_includeSubtypes = true;
bool m_isInverse = false;
};
diff --git a/src/imports/opcua/opcuaserverdiscovery.cpp b/src/imports/opcua/opcuaserverdiscovery.cpp
new file mode 100644
index 0000000..2cbe5f2
--- /dev/null
+++ b/src/imports/opcua/opcuaserverdiscovery.cpp
@@ -0,0 +1,298 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcuaserverdiscovery.h"
+#include "opcuaconnection.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ServerDiscovery
+ \inqmlmodule QtOpcUa
+ \brief Provides information about available servers.
+ \since QtOpcUa 5.13
+
+ Allows to fetch and access information about servers known to a server or discovery server.
+
+ \snippet ../../src/imports/doc/snippets/basic/basic.qml Basic discovery
+*/
+
+/*!
+ \qmlproperty string ServerDiscovery::discoveryUrl
+
+ URL of the server to retrieve the list of servers from.
+ Every time the URL is changed, a request to the given server is started.
+
+ When starting the request, the list of available servers is cleared
+ and the status is set to \l {Status::Status}{Status.GoodCompletesAsynchronously}.
+ Once the request is finished, \l status changes.
+ Make sure to check the \l status before acessing the list of servers.
+
+ \code
+ onServersChanged: {
+ if (status.isGood) {
+ if (status.status == QtOpcUa.Status.GoodCompletesAsynchronusly)
+ return; // wait until finished
+ if (count > 0) {
+ var serverUrl = at(0).serverUrl();
+ console.log(serverUrl);
+ }
+ } else {
+ // handle error
+ }
+ }
+ \endcode
+
+ \sa ApplicationDescription status at count Status
+*/
+
+/*!
+ \qmlproperty int ServerDiscovery::count
+
+ Current number of servers in this element.
+ Before using any data from this server discovery, you should check \l status if retrieval of the
+ information was successful.
+
+ \sa status Status
+*/
+
+/*!
+ \qmlproperty Status ServerDiscovery::status
+
+ The current status of this element.
+ In case the last retrieval of servers was successful, the status
+ should be \c Status.Good.
+
+ \code
+ if (status.isGood) {
+ // Choose endpoint to connect to
+ } else {
+ // handle error
+ }
+ \endcode
+
+ \sa Status
+*/
+
+/*!
+ \qmlsignal SeverDiscovery::serversChanged()
+
+ Emitted when a retrieval request started, finished or failed.
+ In a called function, you should first the the \l status of the object.
+ In case the status is \l Status.GoodCompletesAsynchronously, the request is still running.
+ In case the status is \l Status.Good, the request has finished and the application descriptions
+ can be read. In case the status is not good, an error happended and \l status contains the
+ returned error code.
+
+ \code
+ onServersChanged: {
+ if (status.isGood) {
+ if (status.status == QtOpcUa.Status.GoodCompletesAsynchronusly)
+ return; // wait until finished
+ if (count > 0) {
+ var serverUrl = at(0).endpointUrl();
+ console.log(serverUrl);
+ }
+ } else {
+ // handle error
+ }
+ }
+ \endcode
+
+ \sa status count at QtOpcUa.Status ApplicationDescription
+*/
+
+OpcUaServerDiscovery::OpcUaServerDiscovery(QObject *parent)
+ : QStandardItemModel(parent)
+{
+ insertColumn(0);
+}
+
+OpcUaServerDiscovery::~OpcUaServerDiscovery() = default;
+
+const QString &OpcUaServerDiscovery::discoveryUrl() const
+{
+ return m_discoveryUrl;
+}
+
+void OpcUaServerDiscovery::setDiscoveryUrl(const QString &discoveryUrl)
+{
+ if (discoveryUrl == m_discoveryUrl)
+ return;
+ m_discoveryUrl = discoveryUrl;
+
+ startFindServers();
+ emit discoveryUrlChanged();
+}
+
+int OpcUaServerDiscovery::count() const
+{
+ return rowCount();
+}
+
+/*!
+ \qmlmethod ApplicationDescription ServerDiscovery::at(index)
+
+ Returns the application description at given \a index.
+ In case there are no servers available or the index is invalid, an invalid
+ application description is returned.
+ Before using any returned data, you should check \l status if retrieval of the
+ information was successful.
+
+ \code
+ if (servers.status.isGood) {
+ if (servers.count > 0)
+ var serverUrl = at(0).serverUrl();
+ console.log(serverUrl);
+ // Choose endpoint to connect to
+ } else {
+ // handle error
+ }
+ \endcode
+
+ \sa count status ApplicationDescription
+*/
+
+/*!
+ \qmlproperty Connection ServerDiscovery::connection
+
+ The connection to be used for requesting information.
+
+ If this property is not set, the default connection will be used, if any.
+
+ \sa Connection, Connection::defaultConnection
+*/
+
+QOpcUaApplicationDescription OpcUaServerDiscovery::at(int row) const
+{
+ return index(row, 0).data(Qt::UserRole).value<QOpcUaApplicationDescription>();
+}
+
+const OpcUaStatus &OpcUaServerDiscovery::status() const
+{
+ return m_status;
+}
+
+void OpcUaServerDiscovery::connectSignals()
+{
+ auto conn = connection();
+ if (!conn || !conn->m_client)
+ return;
+ connect(conn->m_client, &QOpcUaClient::findServersFinished, this, &OpcUaServerDiscovery::handleServers, Qt::UniqueConnection);
+ startFindServers();
+}
+
+void OpcUaServerDiscovery::handleServers(const QVector<QOpcUaApplicationDescription> &servers, QOpcUa::UaStatusCode statusCode, const QUrl &requestUrl)
+{
+ if (requestUrl != m_discoveryUrl)
+ return; // response is not for last request
+
+ m_status = OpcUaStatus(statusCode);
+
+ if (m_status.isBad()) {
+ emit statusChanged();
+ return;
+ }
+
+ clearData();
+ for (const auto &i : qAsConst(servers)) {
+ const int newRow = QStandardItemModel::rowCount();
+ QStandardItemModel::insertRow(newRow);
+ QStandardItemModel::setData(index(newRow, 0), i.applicationUri() + QLatin1String("\n") + i.productUri(), Qt::DisplayRole);
+ QStandardItemModel::setData(index(newRow, 0), QVariant::fromValue(i), Qt::UserRole);
+ }
+ emit countChanged();
+ emit serversChanged();
+ emit statusChanged();
+}
+
+void OpcUaServerDiscovery::startFindServers()
+{
+ if (m_discoveryUrl.isEmpty())
+ return;
+
+ if (!m_connection) {
+ // In case no connection is set the default connection will be
+ // used, which fill trigger this function afterwards.
+ connection();
+ return;
+ }
+
+ clearData();
+
+ auto conn = connection();
+ if (!conn || !conn->m_client) {
+ m_status = OpcUaStatus(QOpcUa::BadNotConnected);
+ } else if (m_discoveryUrl.isEmpty()) {
+ m_status = OpcUaStatus(QOpcUa::BadInvalidArgument);
+ } else {
+ m_status = OpcUaStatus(QOpcUa::GoodCompletesAsynchronously);
+ conn->m_client->findServers(m_discoveryUrl);
+ }
+
+ emit serversChanged();
+ emit statusChanged();
+}
+
+void OpcUaServerDiscovery::clearData()
+{
+ QStandardItemModel::removeRows(0, QStandardItemModel::rowCount());
+}
+
+void OpcUaServerDiscovery::setConnection(OpcUaConnection *connection)
+{
+ if (connection == m_connection || !connection)
+ return;
+
+ if (m_connection)
+ disconnect(m_connection, &OpcUaConnection::backendChanged, this, &OpcUaServerDiscovery::connectSignals);
+
+ m_connection = connection;
+
+ connect(m_connection, &OpcUaConnection::backendChanged, this, &OpcUaServerDiscovery::connectSignals);
+ connectSignals();
+ emit connectionChanged(connection);
+}
+
+OpcUaConnection *OpcUaServerDiscovery::connection()
+{
+ if (!m_connection)
+ setConnection(OpcUaConnection::defaultConnection());
+
+ return m_connection;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuaserverdiscovery.h b/src/imports/opcua/opcuaserverdiscovery.h
new file mode 100644
index 0000000..c4ffc5d
--- /dev/null
+++ b/src/imports/opcua/opcuaserverdiscovery.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPCUASERVERDISCOVERY_H
+#define OPCUASERVERDISCOVERY_H
+
+#include <QStandardItemModel>
+#include <QtOpcUa/qopcuatype.h>
+#include <QOpcUaApplicationDescription>
+#include "opcuastatus.h"
+
+QT_BEGIN_NAMESPACE
+
+class OpcUaConnection;
+
+class OpcUaServerDiscovery : public QStandardItemModel
+{
+ Q_OBJECT
+ Q_PROPERTY(QString discoveryUrl READ discoveryUrl WRITE setDiscoveryUrl NOTIFY discoveryUrlChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(OpcUaStatus status READ status NOTIFY statusChanged)
+ Q_PROPERTY(OpcUaConnection* connection READ connection WRITE setConnection NOTIFY connectionChanged)
+
+public:
+ OpcUaServerDiscovery(QObject *parent = nullptr);
+ ~OpcUaServerDiscovery();
+
+ const QString &discoveryUrl() const;
+ void setDiscoveryUrl(const QString &discoverUrl);
+ int count() const;
+ Q_INVOKABLE QOpcUaApplicationDescription at(int row) const;
+ const OpcUaStatus &status() const;
+ void setConnection(OpcUaConnection *);
+ OpcUaConnection *connection();
+
+signals:
+ void discoveryUrlChanged();
+ void serversChanged();
+ void countChanged();
+ void statusChanged();
+ void connectionChanged(OpcUaConnection *);
+
+private slots:
+ void connectSignals();
+ void handleServers(const QVector<QOpcUaApplicationDescription> &servers, QOpcUa::UaStatusCode statusCode, const QUrl &requestUrl);
+ void startFindServers();
+
+private:
+ void clearData();
+
+ QString m_discoveryUrl;
+ OpcUaConnection *m_connection = nullptr;
+ OpcUaStatus m_status;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // OPCUASERVERDISCOVERY_H
diff --git a/src/imports/opcua/opcuasimpleattributeoperand.cpp b/src/imports/opcua/opcuasimpleattributeoperand.cpp
new file mode 100644
index 0000000..75dec51
--- /dev/null
+++ b/src/imports/opcua/opcuasimpleattributeoperand.cpp
@@ -0,0 +1,247 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcuasimpleattributeoperand.h"
+#include "opcuanodeid.h"
+#include "universalnode.h"
+#include <QOpcUaQualifiedName>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype SimpleAttributeOperand
+ \inqmlmodule QtOpcUa
+ \brief The OPC UA SimpleAttributeOperand type.
+ \since QtOpcUa 5.13
+
+ The SimpleAttributeOperand is specified in OPC-UA part 4, 7.4.4.5.
+ It is used when a node attribute is required as operand.
+
+ For example, the following simple attribute operand represents the value
+ of the "Severity" field of the base event type:
+
+ \code
+ import QtOpcUa 5.13 as QtOpcUa
+
+ QtOpcUa.SimpleAttributeOperand {
+ identifier: "Severity"
+ ns: "http://opcfoundation.org/UA/"
+ }
+ \endcode
+*/
+
+/*!
+ \qmlproperty list<OpcUaNodeId> SimpleAttributeOperand::browsePath
+
+ Browse path to the node holding the attribute.
+
+ \code
+ import QtOpcUa 5.13 as QtOpcUa
+
+ QtOpcUA.SimpleAttributeOperand {
+ ...
+ browsePath: [
+ QtOpcUa.NodeId {
+ identifier: "Message"
+ ns: "http://opcfoundation.org/UA/"
+ }
+ ...
+ ]
+ }
+*/
+
+/*!
+ \qmlproperty string SimpleAttributeOperand::indexRange
+
+ Index range string used to identify a single value or subset of the attribute's value.
+
+ \code
+ import QtOpcUa 5.13 as QtOpcUa
+
+ QtOpcUa.SimpleAttributeOperand {
+ ...
+ indexRange: "0:2"
+ }
+ \endcode
+*/
+
+/*!
+ \qmlproperty Constants.NodeAttribute SimpleAttributeOperand::nodeAttribute
+
+ Attribute of the node \l browsePath is pointing to.
+ The default value is \c Constants.NodeAttribute.Value.
+
+ \code
+ import QtOpcUa 5.13 as QtOpcUa
+
+ QtOpcUa.SimpleAttributeOperand {
+ ...
+ nodeAttribute: QtOpcUa.Constants.NodeAttribute.Value
+ }
+ \endcode
+*/
+
+/*!
+ \qmlproperty string SimpleAttributeOperand::typeId
+
+ Node id of the type definition node. The operand will be of the type or one of its subtypes.
+ The default value is \c "ns=0;i=2041".
+
+ \code
+ import QtOpcUa 5.13 as QtOpcUa
+
+ QtOpcUa.SimpleAttributeOperand {
+ ...
+ typeId: "ns=0;i=2041"
+ }
+ \endcode
+*/
+
+OpcUaSimpleAttributeOperand::OpcUaSimpleAttributeOperand(QObject *parent)
+ : OpcUaOperandBase(parent)
+{
+ QOpcUaSimpleAttributeOperand::setTypeId(QStringLiteral("ns=0;i=2041"));
+ QOpcUaSimpleAttributeOperand::setAttributeId(QOpcUa::NodeAttribute::Value);
+}
+
+OpcUaSimpleAttributeOperand::~OpcUaSimpleAttributeOperand() = default;
+
+QOpcUaSimpleAttributeOperand OpcUaSimpleAttributeOperand::toSimpleAttributeOperand(QOpcUaClient *client) const
+{
+ QOpcUaSimpleAttributeOperand value(*this);
+ for (UniversalNode i : m_browsePath) {
+ i.resolveNamespaceNameToIndex(client);
+ value.browsePathRef().append(i.toQualifiedName());
+ }
+ return value;
+}
+
+QVariant OpcUaSimpleAttributeOperand::toCppVariant(QOpcUaClient *client) const
+{
+ return toSimpleAttributeOperand(client);
+}
+
+QString OpcUaSimpleAttributeOperand::indexRange() const
+{
+ return QOpcUaSimpleAttributeOperand::indexRange();
+}
+
+void OpcUaSimpleAttributeOperand::setIndexRange(const QString &indexRange)
+{
+ if (indexRange != QOpcUaSimpleAttributeOperand::indexRange()) {
+ QOpcUaSimpleAttributeOperand::setIndexRange(indexRange);
+ emit dataChanged();
+ }
+}
+
+QOpcUa::NodeAttribute OpcUaSimpleAttributeOperand::nodeAttribute() const
+{
+ return QOpcUaSimpleAttributeOperand::attributeId();
+}
+
+void OpcUaSimpleAttributeOperand::setNodeAttribute(QOpcUa::NodeAttribute nodeAttribute)
+{
+ if (nodeAttribute != QOpcUaSimpleAttributeOperand::attributeId()) {
+ QOpcUaSimpleAttributeOperand::setAttributeId(nodeAttribute);
+ emit dataChanged();
+ }
+}
+
+QString OpcUaSimpleAttributeOperand::typeId() const
+{
+ return QOpcUaSimpleAttributeOperand::typeId();
+}
+
+void OpcUaSimpleAttributeOperand::setTypeId(const QString &typeId)
+{
+ if (typeId != QOpcUaSimpleAttributeOperand::typeId()) {
+ QOpcUaSimpleAttributeOperand::setTypeId(typeId);
+ emit dataChanged();
+ }
+}
+
+QQmlListProperty<OpcUaNodeId> OpcUaSimpleAttributeOperand::browsePath()
+{
+ return QQmlListProperty<OpcUaNodeId>(this, this,
+ &OpcUaSimpleAttributeOperand::appendBrowsePathElement,
+ &OpcUaSimpleAttributeOperand::browsePathSize,
+ &OpcUaSimpleAttributeOperand::browsePathElement,
+ &OpcUaSimpleAttributeOperand::clearBrowsePath);
+}
+
+void OpcUaSimpleAttributeOperand::appendBrowsePathElement(OpcUaNodeId *nodeId)
+{
+ m_browsePath.append(nodeId);
+ emit dataChanged();
+}
+
+int OpcUaSimpleAttributeOperand::browsePathSize() const
+{
+ return m_browsePath.size();
+}
+
+OpcUaNodeId *OpcUaSimpleAttributeOperand::browsePathElement(int index) const
+{
+ return m_browsePath.at(index);
+}
+
+void OpcUaSimpleAttributeOperand::clearBrowsePath()
+{
+ m_browsePath.clear();
+ emit dataChanged();
+}
+
+void OpcUaSimpleAttributeOperand::appendBrowsePathElement(QQmlListProperty<OpcUaNodeId> *list, OpcUaNodeId *nodeId)
+{
+ reinterpret_cast<OpcUaSimpleAttributeOperand*>(list->data)->appendBrowsePathElement(nodeId);
+}
+
+int OpcUaSimpleAttributeOperand::browsePathSize(QQmlListProperty<OpcUaNodeId> *list)
+{
+ return reinterpret_cast<OpcUaSimpleAttributeOperand*>(list->data)->browsePathSize();
+}
+
+OpcUaNodeId *OpcUaSimpleAttributeOperand::browsePathElement(QQmlListProperty<OpcUaNodeId> *list, int index)
+{
+ return reinterpret_cast<OpcUaSimpleAttributeOperand*>(list->data)->browsePathElement(index);
+}
+
+void OpcUaSimpleAttributeOperand::clearBrowsePath(QQmlListProperty<OpcUaNodeId> *list)
+{
+ reinterpret_cast<OpcUaSimpleAttributeOperand*>(list->data)->clearBrowsePath();
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuasimpleattributeoperand.h b/src/imports/opcua/opcuasimpleattributeoperand.h
new file mode 100644
index 0000000..06072fe
--- /dev/null
+++ b/src/imports/opcua/opcuasimpleattributeoperand.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPCUASIMPLEATTRIBUTEOPERAND
+#define OPCUASIMPLEATTRIBUTEOPERAND
+
+#include "opcuaoperandbase.h"
+#include <QOpcUaSimpleAttributeOperand>
+#include <QQmlListProperty>
+
+QT_BEGIN_NAMESPACE
+
+class OpcUaNodeId;
+class QOpcUaClient;
+
+class OpcUaSimpleAttributeOperand : public OpcUaOperandBase, private QOpcUaSimpleAttributeOperand {
+ Q_OBJECT
+ Q_PROPERTY(QQmlListProperty<OpcUaNodeId> browsePath READ browsePath)
+ Q_PROPERTY(QString indexRange READ indexRange WRITE setIndexRange)
+ Q_PROPERTY(QOpcUa::NodeAttribute nodeAttribute READ nodeAttribute WRITE setNodeAttribute)
+ Q_PROPERTY(QString typeId READ typeId WRITE setTypeId)
+
+public:
+ explicit OpcUaSimpleAttributeOperand(QObject *parent = nullptr);
+ ~OpcUaSimpleAttributeOperand();
+ QOpcUaSimpleAttributeOperand toSimpleAttributeOperand(QOpcUaClient *client) const;
+ virtual QVariant toCppVariant(QOpcUaClient *client) const override;
+
+ QString indexRange() const;
+ void setIndexRange(const QString &indexRange);
+
+ QOpcUa::NodeAttribute nodeAttribute() const;
+ void setNodeAttribute(QOpcUa::NodeAttribute nodeAttribute);
+
+ QString typeId() const;
+ void setTypeId(const QString &typeId);
+
+ QQmlListProperty<OpcUaNodeId> browsePath();
+ void appendBrowsePathElement(OpcUaNodeId*nodeId);
+ int browsePathSize() const;
+ OpcUaNodeId *browsePathElement(int index) const;
+ void clearBrowsePath();
+
+signals:
+ void dataChanged();
+
+private:
+ static void appendBrowsePathElement(QQmlListProperty<OpcUaNodeId> *list, OpcUaNodeId *nodeId);
+ static int browsePathSize(QQmlListProperty<OpcUaNodeId> *list);
+ static OpcUaNodeId* browsePathElement(QQmlListProperty<OpcUaNodeId> *list, int index);
+ static void clearBrowsePath(QQmlListProperty<OpcUaNodeId> *list);
+
+ QVector<OpcUaNodeId*> m_browsePath;
+};
+
+QT_END_NAMESPACE
+
+#endif // OPCUASIMPLEATTRIBUTEOPERAND
diff --git a/src/imports/opcua/opcuastatus.cpp b/src/imports/opcua/opcuastatus.cpp
new file mode 100644
index 0000000..9994b9b
--- /dev/null
+++ b/src/imports/opcua/opcuastatus.cpp
@@ -0,0 +1,807 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcuastatus.h"
+#include "opcuaconnection.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Status
+ \inqmlmodule QtOpcUa
+ \brief Status code of an OPC UA function.
+ \since QtOpcUa 5.13
+
+ This QML element contains information about the result status of an OPC UA action.
+ The most common use case is to check if a call was successful
+ \code
+ if (methodNode.resultCode.isGood) {
+ // do something
+ }
+ \endcode
+*/
+
+/*!
+ \qmlproperty bool Status::isGood
+
+ Returns whether the result status is a success.
+*/
+
+/*!
+ \qmlproperty bool Status::isBad
+
+ Returns whether the result status is a failure.
+*/
+
+/*!
+ \qmlproperty Status.Status Status::status
+
+ Returns the exact status code. This allows to handle the status specificly.
+
+ \code
+ if (resultStatus.status == QtOpcUa.Status.BadTimeout) {
+ // try again
+ }
+ \endcode
+*/
+
+/*!
+ \qmlproperty enumeration Status::Status
+
+ The names of this enumeration are matching the names from the standard, but
+ the values are different.
+
+ Attributes of a status
+
+ \value Status.Good Everything is fine.
+ \value Status.BadUnexpectedError An unexpected error occurred.
+ \value Status.BadInternalError An internal error occurred as a result of a programming or configuration error.
+ \value Status.BadOutOfMemory Not enough memory to complete the operation.
+ \value Status.BadResourceUnavailable An operating system resource is not available.
+ \value Status.BadCommunicationError A low level communication error occurred.
+ \value Status.BadEncodingError Encoding halted because of invalid data in the objects being serialized.
+ \value Status.BadDecodingError Decoding halted because of invalid data in the stream.
+ \value Status.BadEncodingLimitsExceeded The message encoding/decoding limits imposed by the stack have been exceeded.
+ \value Status.BadRequestTooLarge The request message size exceeds limits set by the server.
+ \value Status.BadResponseTooLarge The response message size exceeds limits set by the client.
+ \value Status.BadUnknownResponse An unrecognized response was received from the server.
+ \value Status.BadTimeout The operation timed out.
+ \value Status.BadServiceUnsupported The server does not support the requested service.
+ \value Status.BadShutdown The operation was cancelled because the application is shutting down.
+ \value Status.BadServerNotConnected The operation could not complete because the client is not connected to the server.
+ \value Status.BadServerHalted The server has stopped and cannot process any requests.
+ \value Status.BadNothingToDo There was nothing to do because the client passed a list of operations with no elements.
+ \value Status.BadTooManyOperations The request could not be processed because it specified too many operations.
+ \value Status.BadTooManyMonitoredItems The request could not be processed because there are too many monitored items in the subscription.
+ \value Status.BadDataTypeIdUnknown The extension object cannot be (de)serialized because the data type id is not recognized.
+ \value Status.BadCertificateInvalid The certificate provided as a parameter is not valid.
+ \value Status.BadSecurityChecksFailed An error occurred verifying security.
+ \value Status.BadCertificateTimeInvalid The Certificate has expired or is not yet valid.
+ \value Status.BadCertificateIssuerTimeInvalid An Issuer Certificate has expired or is not yet valid.
+ \value Status.BadCertificateHostNameInvalid The HostName used to connect to a Server does not match a HostName in the Certificate.
+ \value Status.BadCertificateUriInvalid The URI specified in the ApplicationDescription does not match the URI in the Certificate.
+ \value Status.BadCertificateUseNotAllowed The Certificate may not be used for the requested operation.
+ \value Status.BadCertificateIssuerUseNotAllowed The Issuer Certificate may not be used for the requested operation.
+ \value Status.BadCertificateUntrusted The Certificate is not trusted.
+ \value Status.BadCertificateRevocationUnknown It was not possible to determine if the Certificate has been revoked.
+ \value Status.BadCertificateIssuerRevocationUnknown It was not possible to determine if the Issuer Certificate has been revoked.
+ \value Status.BadCertificateRevoked The certificate has been revoked.
+ \value Status.BadCertificateIssuerRevoked The issuer certificate has been revoked.
+ \value Status.BadCertificateChainIncomplete The certificate chain is incomplete.
+ \value Status.BadUserAccessDenied User does not have permission to perform the requested operation.
+ \value Status.BadIdentityTokenInvalid The user identity token is not valid.
+ \value Status.BadIdentityTokenRejected The user identity token is valid but the server has rejected it.
+ \value Status.BadSecureChannelIdInvalid The specified secure channel is no longer valid.
+ \value Status.BadInvalidTimestamp The timestamp is outside the range allowed by the server.
+ \value Status.BadNonceInvalid The nonce does appear to be not a random value or it is not the correct length.
+ \value Status.BadSessionIdInvalid The session id is not valid.
+ \value Status.BadSessionClosed The session was closed by the client.
+ \value Status.BadSessionNotActivated The session cannot be used because ActivateSession has not been called.
+ \value Status.BadSubscriptionIdInvalid The subscription id is not valid.
+ \value Status.BadRequestHeaderInvalid The header for the request is missing or invalid.
+ \value Status.BadTimestampsToReturnInvalid The timestamps to return parameter is invalid.
+ \value Status.BadRequestCancelledByClient The request was cancelled by the client.
+ \value Status.BadTooManyArguments Too many arguments were provided.
+ \value Status.GoodSubscriptionTransferred The subscription was transferred to another session.
+ \value Status.GoodCompletesAsynchronously The processing will complete asynchronously.
+ \value Status.GoodOverload Sampling has slowed down due to resource limitations.
+ \value Status.GoodClamped The value written was accepted but was clamped.
+ \value Status.BadNoCommunication Communication with the data source is defined, but not established, and there is no last known value available.
+ \value Status.BadWaitingForInitialData Waiting for the server to obtain values from the underlying data source.
+ \value Status.BadNodeIdInvalid The syntax of the node id is not valid.
+ \value Status.BadNodeIdUnknown The node id refers to a node that does not exist in the server address space.
+ \value Status.BadAttributeIdInvalid The attribute is not supported for the specified Node.
+ \value Status.BadIndexRangeInvalid The syntax of the index range parameter is invalid.
+ \value Status.BadIndexRangeNoData No data exists within the range of indexes specified.
+ \value Status.BadDataEncodingInvalid The data encoding is invalid.
+ \value Status.BadDataEncodingUnsupported The server does not support the requested data encoding for the node.
+ \value Status.BadNotReadable The access level does not allow reading or subscribing to the Node.
+ \value Status.BadNotWritable The access level does not allow writing to the Node.
+ \value Status.BadOutOfRange The value was out of range.
+ \value Status.BadNotSupported The requested operation is not supported.
+ \value Status.BadNotFound A requested item was not found or a search operation ended without success.
+ \value Status.BadObjectDeleted The object cannot be used because it has been deleted.
+ \value Status.BadNotImplemented Requested operation is not implemented.
+ \value Status.BadMonitoringModeInvalid The monitoring mode is invalid.
+ \value Status.BadMonitoredItemIdInvalid The monitoring item id does not refer to a valid monitored item.
+ \value Status.BadMonitoredItemFilterInvalid The monitored item filter parameter is not valid.
+ \value Status.BadMonitoredItemFilterUnsupported The server does not support the requested monitored item filter.
+ \value Status.BadFilterNotAllowed A monitoring filter cannot be used in combination with the attribute specified.
+ \value Status.BadStructureMissing A mandatory structured parameter was missing or null.
+ \value Status.BadEventFilterInvalid The event filter is not valid.
+ \value Status.BadContentFilterInvalid The content filter is not valid.
+ \value Status.BadFilterOperatorInvalid An unregognized operator was provided in a filter.
+ \value Status.BadFilterOperatorUnsupported A valid operator was provided, but the server does not provide support for this filter operator.
+ \value Status.BadFilterOperandCountMismatch The number of operands provided for the filter operator was less then expected for the operand provided.
+ \value Status.BadFilterOperandInvalid The operand used in a content filter is not valid.
+ \value Status.BadFilterElementInvalid The referenced element is not a valid element in the content filter.
+ \value Status.BadFilterLiteralInvalid The referenced literal is not a valid value.
+ \value Status.BadContinuationPointInvalid The continuation point provide is longer valid.
+ \value Status.BadNoContinuationPoints The operation could not be processed because all continuation points have been allocated.
+ \value Status.BadReferenceTypeIdInvalid The operation could not be processed because all continuation points have been allocated.
+ \value Status.BadBrowseDirectionInvalid The browse direction is not valid.
+ \value Status.BadNodeNotInView The node is not part of the view.
+ \value Status.BadServerUriInvalid The ServerUri is not a valid URI.
+ \value Status.BadServerNameMissing No ServerName was specified.
+ \value Status.BadDiscoveryUrlMissing No DiscoveryUrl was specified.
+ \value Status.BadSempahoreFileMissing The semaphore file specified by the client is not valid.
+ \value Status.BadRequestTypeInvalid The security token request type is not valid.
+ \value Status.BadSecurityModeRejected The security mode does not meet the requirements set by the Server.
+ \value Status.BadSecurityPolicyRejected The security policy does not meet the requirements set by the Server.
+ \value Status.BadTooManySessions The server has reached its maximum number of sessions.
+ \value Status.BadUserSignatureInvalid The user token signature is missing or invalid.
+ \value Status.BadApplicationSignatureInvalid The signature generated with the client certificate is missing or invalid.
+ \value Status.BadNoValidCertificates The client did not provide at least one software certificate that is valid and meets the profile requirements for the server.
+ \value Status.BadIdentityChangeNotSupported The Server does not support changing the user identity assigned to the session.
+ \value Status.BadRequestCancelledByRequest The request was cancelled by the client with the Cancel service.
+ \value Status.BadParentNodeIdInvalid The parent node id does not to refer to a valid node.
+ \value Status.BadReferenceNotAllowed The reference could not be created because it violates constraints imposed by the data model.
+ \value Status.BadNodeIdRejected The requested node id was reject because it was either invalid or server does not allow node ids to be specified by the client.
+ \value Status.BadNodeIdExists The requested node id is already used by another node.
+ \value Status.BadNodeClassInvalid The node class is not valid.
+ \value Status.BadBrowseNameInvalid The browse name is invalid.
+ \value Status.BadBrowseNameDuplicated The browse name is not unique among nodes that share the same relationship with the parent.
+ \value Status.BadNodeAttributesInvalid The node attributes are not valid for the node class.
+ \value Status.BadTypeDefinitionInvalid The type definition node id does not reference an appropriate type node.
+ \value Status.BadSourceNodeIdInvalid The source node id does not reference a valid node.
+ \value Status.BadTargetNodeIdInvalid The target node id does not reference a valid node.
+ \value Status.BadDuplicateReferenceNotAllowed he reference type between the nodes is already defined.
+ \value Status.BadInvalidSelfReference The server does not allow this type of self reference on this node.
+ \value Status.BadReferenceLocalOnly The reference type is not valid for a reference to a remote server.
+ \value Status.BadNoDeleteRights The server will not allow the node to be deleted.
+ \value Status.UncertainReferenceNotDeleted The server was not able to delete all target references.
+ \value Status.BadServerIndexInvalid The server index is not valid.
+ \value Status.BadViewIdUnknown The view id does not refer to a valid view node.
+ \value Status.BadViewTimestampInvalid The view timestamp is not available or not supported.
+ \value Status.BadViewParameterMismatch The view parameters are not consistent with each other.
+ \value Status.BadViewVersionInvalid The view version is not available or not supported.
+ \value Status.UncertainNotAllNodesAvailable The list of references may not be complete because the underlying system is not available.
+ \value Status.GoodResultsMayBeIncomplete The server should have followed a reference to a node in a remote server but did not. The result set may be incomplete.
+ \value Status.BadNotTypeDefinition The provided Nodeid was not a type definition nodeid.
+ \value Status.UncertainReferenceOutOfServer One of the references to follow in the relative path references to a node in the address space in another server.
+ \value Status.BadTooManyMatches The requested operation has too many matches to return.
+ \value Status.BadQueryTooComplex The requested operation requires too many resources in the server.
+ \value Status.BadNoMatch The requested operation has no match to return.
+ \value Status.BadMaxAgeInvalid The max age parameter is invalid.
+ \value Status.BadSecurityModeInsufficient The operation is not permitted over the current secure channel.
+ \value Status.BadHistoryOperationInvalid The history details parameter is not valid.
+ \value Status.BadHistoryOperationUnsupported The server does not support the requested operation.
+ \value Status.BadInvalidTimestampArgument The defined timestamp to return was invalid.
+ \value Status.BadWriteNotSupported The server not does support writing the combination of value, status and timestamps provided.
+ \value Status.BadTypeMismatch The value supplied for the attribute is not of the same type as the attribute's value.
+ \value Status.BadMethodInvalid The method id does not refer to a method for the specified object.
+ \value Status.BadArgumentsMissing The client did not specify all of the input arguments for the method.
+ \value Status.BadTooManySubscriptions The server has reached its maximum number of subscriptions.
+ \value Status.BadTooManyPublishRequests The server has reached the maximum number of queued publish requests.
+ \value Status.BadNoSubscription There is no subscription available for this session.
+ \value Status.BadSequenceNumberUnknown The sequence number is unknown to the server.
+ \value Status.BadMessageNotAvailable The requested notification message is no longer available.
+ \value Status.BadInsufficientClientProfile The Client of the current Session does not support one or more Profiles that are necessary for the Subscription.
+ \value Status.BadStateNotActive The sub-state machine is not currently active.
+ \value Status.BadTcpServerTooBusy The server cannot process the request because it is too busy.
+ \value Status.BadTcpMessageTypeInvalid The type of the message specified in the header invalid.
+ \value Status.BadTcpSecureChannelUnknown The SecureChannelId and/or TokenId are not currently in use.
+ \value Status.BadTcpMessageTooLarge The size of the message specified in the header is too large.
+ \value Status.BadTcpNotEnoughResources There are not enough resources to process the request.
+ \value Status.BadTcpInternalError An internal error occurred.
+ \value Status.BadTcpEndpointUrlInvalid The Server does not recognize the QueryString specified.
+ \value Status.BadRequestInterrupted The request could not be sent because of a network interruption.
+ \value Status.BadRequestTimeout Timeout occurred while processing the request.
+ \value Status.BadSecureChannelClosed The secure channel has been closed.
+ \value Status.BadSecureChannelTokenUnknown The token has expired or is not recognized.
+ \value Status.BadSequenceNumberInvalid The sequence number is not valid.
+ \value Status.BadProtocolVersionUnsupported The applications do not have compatible protocol versions.
+ \value Status.BadConfigurationError There is a problem with the configuration that affects the usefulness of the value.
+ \value Status.BadNotConnected The variable should receive its value from another variable, but has never been configured to do so.
+ \value Status.BadDeviceFailure There has been a failure in the device/data source that generates the value that has affected the value.
+ \value Status.BadSensorFailure There has been a failure in the sensor from which the value is derived by the device/data source.
+ \value Status.BadOutOfService The source of the data is not operational.
+ \value Status.BadDeadbandFilterInvalid The deadband filter is not valid.
+ \value Status.UncertainNoCommunicationLastUsableValue Communication to the data source has failed. The variable value is the last value that had a good quality.
+ \value Status.UncertainLastUsableValue Whatever was updating this value has stopped doing so.
+ \value Status.UncertainSubstituteValue The value is an operational value that was manually overwritten.
+ \value Status.UncertainInitialValue The value is an initial value for a variable that normally receives its value from another variable.
+ \value Status.UncertainSensorNotAccurate The value is at one of the sensor limits.
+ \value Status.UncertainEngineeringUnitsExceeded The value is outside of the range of values defined for this parameter.
+ \value Status.UncertainSubNormal The value is derived from multiple sources and has less than the required number of Good sources.
+ \value Status.GoodLocalOverride The value has been overridden.
+ \value Status.BadRefreshInProgress This Condition refresh failed, a Condition refresh operation is already in progress.
+ \value Status.BadConditionAlreadyDisabled This condition has already been disabled.
+ \value Status.BadConditionAlreadyEnabled This condition has already been enabled.
+ \value Status.BadConditionDisabled Property not available, this condition is disabled.
+ \value Status.BadEventIdUnknown The specified event id is not recognized.
+ \value Status.BadEventNotAcknowledgeable The event cannot be acknowledged.
+ \value Status.BadDialogNotActive The dialog condition is not active.
+ \value Status.BadDialogResponseInvalid The response is not valid for the dialog.
+ \value Status.BadConditionBranchAlreadyAcked The condition branch has already been acknowledged.
+ \value Status.BadConditionBranchAlreadyConfirmed The condition branch has already been confirmed.
+ \value Status.BadConditionAlreadyShelved The condition has already been shelved.
+ \value Status.BadConditionNotShelved The condition is not currently shelved.
+ \value Status.BadShelvingTimeOutOfRange The shelving time not within an acceptable range.
+ \value Status.BadNoData No data exists for the requested time range or event filter.
+ \value Status.BadBoundNotFoundNo data found to provide upper or lower bound value.
+ \value Status.BadBoundNotSupported The server cannot retrieve a bound for the variable.
+ \value Status.BadDataLost Data is missing due to collection started/stopped/lost.
+ \value Status.BadDataUnavailable Expected data is unavailable for the requested time range due to an un-mounted volume, an off-line archive or tape, or similar reason for temporary unavailability.
+ \value Status.BadEntryExists The data or event was not successfully inserted because a matching entry exists.
+ \value Status.BadNoEntryExists The data or event was not successfully updated because no matching entry exists.
+ \value Status.BadTimestampNotSupported The client requested history using a timestamp format the server does not support (i.e requested ServerTimestamp when server only supports SourceTimestamp).
+ \value Status.GoodEntryInserted The data or event was successfully inserted into the historical database.
+ \value Status.GoodEntryReplaced The data or event field was successfully replaced in the historical database.
+ \value Status.UncertainDataSubNormal The value is derived from multiple values and has less than the required number of Good values.
+ \value Status.GoodNoData No data exists for the requested time range or event filter.
+ \value Status.GoodMoreData The data or event field was successfully replaced in the historical database.
+ \value Status.BadAggregateListMismatch The requested number of Aggregates does not match the requested number of NodeIds.
+ \value Status.BadAggregateNotSupported The requested Aggregate is not support by the server.
+ \value Status.BadAggregateInvalidInputs The aggregate value could not be derived due to invalid data inputs.
+ \value Status.BadAggregateConfigurationRejected The aggregate configuration is not valid for specified node.
+ \value Status.GoodDataIgnored The request pecifies fields which are not valid for the EventType or cannot be saved by the historian
+ \value Status.BadRequestNotAllowed The request was rejected by the server because it did not meet the criteria set by the server.
+ \value Status.GoodEdited The value does not come from the real source and has been edited by the server.
+ \value Status.GoodPostActionFailed There was an error in execution of these post-actions.
+ \value Status.UncertainDominantValueChanged The related EngineeringUnit has been changed but the Variable Value is still provided based on the previous unit.
+ \value Status.GoodDependentValueChanged A dependent value has been changed but the change has not been applied to the device.
+ \value Status.BadDominantValueChanged The related EngineeringUnit has been changed but this change has not been applied to the device. The Variable Value is still dependent on the previous unit but its status is currently Bad.
+ \value Status.UncertainDependentValueChanged A dependent value has been changed but the change has not been applied to the device. The quality of the dominant variable is uncertain.
+ \value Status.BadDependentValueChanged A dependent value has been changed but the change has not been applied to the device. The quality of the dominant variable is Bad.
+ \value Status.GoodCommunicationEvent The communication layer has raised an event.
+ \value Status.GoodShutdownEvent The system is shutting down.
+ \value Status.GoodCallAgain The operation is not finished and needs to be called again.
+ \value Status.GoodNonCriticalTimeout A non-critical timeout occurred.
+ \value Status.BadInvalidArgument One or more arguments are invalid.
+ \value Status.BadConnectionRejected Could not establish a network connection to remote server.
+ \value Status.BadDisconnect The server has disconnected from the client.
+ \value Status.BadConnectionClosed The network connection has been closed.
+ \value Status.BadInvalidState The operation cannot be completed because the object is closed, uninitialized or in some other invalid state.
+ \value Status.BadEndOfStream Cannot move beyond end of the stream.
+ \value Status.BadNoDataAvailable No data is currently available for reading from a non-blocking stream.
+ \value Status.BadWaitingForResponse The asynchronous operation is waiting for a response.
+ \value Status.BadOperationAbandoned The asynchronous operation was abandoned by the caller.
+ \value Status.BadExpectedStreamToBlock The stream did not return all data requested (possibly because it is a non-blocking stream).
+ \value Status.BadWouldBlock Non blocking behavior is required and the operation would block.
+ \value Status.BadSyntaxError A value had an invalid syntax.
+ \value Status.BadMaxConnectionsReached The operation could not be finished because all available connections are in use.
+*/
+
+OpcUaStatus::OpcUaStatus() = default;
+
+OpcUaStatus::OpcUaStatus(OpcUaStatus::Status status)
+{
+ m_statusCode = static_cast<quint32>(status) << 16;
+}
+
+OpcUaStatus::~OpcUaStatus() = default;
+
+bool OpcUaStatus::isBad() const
+{
+ return m_statusCode & 0x80000000;
+}
+
+bool OpcUaStatus::isGood() const
+{
+ return !isBad();
+}
+
+OpcUaStatus::OpcUaStatus(QOpcUa::UaStatusCode uaStatusCode)
+{
+ m_statusCode = static_cast<quint32>(uaStatusCode);
+}
+
+OpcUaStatus::Status OpcUaStatus::status() const
+{
+ switch (static_cast<QOpcUa::UaStatusCode>(m_statusCode)) {
+ case QOpcUa::Good:
+ return Status::Good;
+ case QOpcUa::BadUnexpectedError:
+ return Status::BadUnexpectedError;
+ case QOpcUa::BadInternalError:
+ return Status::BadInternalError;
+ case QOpcUa::BadOutOfMemory:
+ return Status::BadOutOfMemory;
+ case QOpcUa::BadResourceUnavailable:
+ return Status::BadResourceUnavailable;
+ case QOpcUa::BadCommunicationError:
+ return Status::BadCommunicationError;
+ case QOpcUa::BadEncodingError:
+ return Status::BadEncodingError;
+ case QOpcUa::BadDecodingError:
+ return Status::BadDecodingError;
+ case QOpcUa::BadEncodingLimitsExceeded:
+ return Status::BadEncodingLimitsExceeded;
+ case QOpcUa::BadRequestTooLarge:
+ return Status::BadRequestTooLarge;
+ case QOpcUa::BadResponseTooLarge:
+ return Status::BadResponseTooLarge;
+ case QOpcUa::BadUnknownResponse:
+ return Status::BadUnknownResponse;
+ case QOpcUa::BadTimeout:
+ return Status::BadTimeout;
+ case QOpcUa::BadServiceUnsupported:
+ return Status::BadServiceUnsupported;
+ case QOpcUa::BadShutdown:
+ return Status::BadShutdown;
+ case QOpcUa::BadServerNotConnected:
+ return Status::BadServerNotConnected;
+ case QOpcUa::BadServerHalted:
+ return Status::BadServerHalted;
+ case QOpcUa::BadNothingToDo:
+ return Status::BadNothingToDo;
+ case QOpcUa::BadTooManyOperations:
+ return Status::BadTooManyOperations;
+ case QOpcUa::BadTooManyMonitoredItems:
+ return Status::BadTooManyMonitoredItems;
+ case QOpcUa::BadDataTypeIdUnknown:
+ return Status::BadDataTypeIdUnknown;
+ case QOpcUa::BadCertificateInvalid:
+ return Status::BadCertificateInvalid;
+ case QOpcUa::BadSecurityChecksFailed:
+ return Status::BadSecurityChecksFailed;
+ case QOpcUa::BadCertificateTimeInvalid:
+ return Status::BadCertificateTimeInvalid;
+ case QOpcUa::BadCertificateIssuerTimeInvalid:
+ return Status::BadCertificateIssuerTimeInvalid;
+ case QOpcUa::BadCertificateHostNameInvalid:
+ return Status::BadCertificateHostNameInvalid;
+ case QOpcUa::BadCertificateUriInvalid:
+ return Status::BadCertificateUriInvalid;
+ case QOpcUa::BadCertificateUseNotAllowed:
+ return Status::BadCertificateUseNotAllowed;
+ case QOpcUa::BadCertificateIssuerUseNotAllowed:
+ return Status::BadCertificateIssuerUseNotAllowed;
+ case QOpcUa::BadCertificateUntrusted:
+ return Status::BadCertificateUntrusted;
+ case QOpcUa::BadCertificateRevocationUnknown:
+ return Status::BadCertificateRevocationUnknown;
+ case QOpcUa::BadCertificateIssuerRevocationUnknown:
+ return Status::BadCertificateIssuerRevocationUnknown;
+ case QOpcUa::BadCertificateRevoked:
+ return Status::BadCertificateRevoked;
+ case QOpcUa::BadCertificateIssuerRevoked:
+ return Status::BadCertificateIssuerRevoked;
+ case QOpcUa::BadCertificateChainIncomplete:
+ return Status::BadCertificateChainIncomplete;
+ case QOpcUa::BadUserAccessDenied:
+ return Status::BadUserAccessDenied;
+ case QOpcUa::BadIdentityTokenInvalid:
+ return Status::BadIdentityTokenInvalid;
+ case QOpcUa::BadIdentityTokenRejected:
+ return Status::BadIdentityTokenRejected;
+ case QOpcUa::BadSecureChannelIdInvalid:
+ return Status::BadSecureChannelIdInvalid;
+ case QOpcUa::BadInvalidTimestamp:
+ return Status::BadInvalidTimestamp;
+ case QOpcUa::BadNonceInvalid:
+ return Status::BadNonceInvalid;
+ case QOpcUa::BadSessionIdInvalid:
+ return Status::BadSessionIdInvalid;
+ case QOpcUa::BadSessionClosed:
+ return Status::BadSessionClosed;
+ case QOpcUa::BadSessionNotActivated:
+ return Status::BadSessionNotActivated;
+ case QOpcUa::BadSubscriptionIdInvalid:
+ return Status::BadSubscriptionIdInvalid;
+ case QOpcUa::BadRequestHeaderInvalid:
+ return Status::BadRequestHeaderInvalid;
+ case QOpcUa::BadTimestampsToReturnInvalid:
+ return Status::BadTimestampsToReturnInvalid;
+ case QOpcUa::BadRequestCancelledByClient:
+ return Status::BadRequestCancelledByClient;
+ case QOpcUa::BadTooManyArguments:
+ return Status::BadTooManyArguments;
+ case QOpcUa::GoodSubscriptionTransferred:
+ return Status::GoodSubscriptionTransferred;
+ case QOpcUa::GoodCompletesAsynchronously:
+ return Status::GoodCompletesAsynchronously;
+ case QOpcUa::GoodOverload:
+ return Status::GoodOverload;
+ case QOpcUa::GoodClamped:
+ return Status::GoodClamped;
+ case QOpcUa::BadNoCommunication:
+ return Status::BadNoCommunication;
+ case QOpcUa::BadWaitingForInitialData:
+ return Status::BadWaitingForInitialData;
+ case QOpcUa::BadNodeIdInvalid:
+ return Status::BadNodeIdInvalid;
+ case QOpcUa::BadNodeIdUnknown:
+ return Status::BadNodeIdUnknown;
+ case QOpcUa::BadAttributeIdInvalid:
+ return Status::BadAttributeIdInvalid;
+ case QOpcUa::BadIndexRangeInvalid:
+ return Status::BadIndexRangeInvalid;
+ case QOpcUa::BadIndexRangeNoData:
+ return Status::BadIndexRangeNoData;
+ case QOpcUa::BadDataEncodingInvalid:
+ return Status::BadDataEncodingInvalid;
+ case QOpcUa::BadDataEncodingUnsupported:
+ return Status::BadDataEncodingUnsupported;
+ case QOpcUa::BadNotReadable:
+ return Status::BadNotReadable;
+ case QOpcUa::BadNotWritable:
+ return Status::BadNotWritable;
+ case QOpcUa::BadOutOfRange:
+ return Status::BadOutOfRange;
+ case QOpcUa::BadNotSupported:
+ return Status::BadNotSupported;
+ case QOpcUa::BadNotFound:
+ return Status::BadNotFound;
+ case QOpcUa::BadObjectDeleted:
+ return Status::BadObjectDeleted;
+ case QOpcUa::BadNotImplemented:
+ return Status::BadNotImplemented;
+ case QOpcUa::BadMonitoringModeInvalid:
+ return Status::BadMonitoringModeInvalid;
+ case QOpcUa::BadMonitoredItemIdInvalid:
+ return Status::BadMonitoredItemIdInvalid;
+ case QOpcUa::BadMonitoredItemFilterInvalid:
+ return Status::BadMonitoredItemFilterInvalid;
+ case QOpcUa::BadMonitoredItemFilterUnsupported:
+ return Status::BadMonitoredItemFilterUnsupported;
+ case QOpcUa::BadFilterNotAllowed:
+ return Status::BadFilterNotAllowed;
+ case QOpcUa::BadStructureMissing:
+ return Status::BadStructureMissing;
+ case QOpcUa::BadEventFilterInvalid:
+ return Status::BadEventFilterInvalid;
+ case QOpcUa::BadContentFilterInvalid:
+ return Status::BadContentFilterInvalid;
+ case QOpcUa::BadFilterOperatorInvalid:
+ return Status::BadFilterOperatorInvalid;
+ case QOpcUa::BadFilterOperatorUnsupported:
+ return Status::BadFilterOperatorUnsupported;
+ case QOpcUa::BadFilterOperandCountMismatch:
+ return Status::BadFilterOperandCountMismatch;
+ case QOpcUa::BadFilterOperandInvalid:
+ return Status::BadFilterOperandInvalid;
+ case QOpcUa::BadFilterElementInvalid:
+ return Status::BadFilterElementInvalid;
+ case QOpcUa::BadFilterLiteralInvalid:
+ return Status::BadFilterLiteralInvalid;
+ case QOpcUa::BadContinuationPointInvalid:
+ return Status::BadContinuationPointInvalid;
+ case QOpcUa::BadNoContinuationPoints:
+ return Status::BadNoContinuationPoints;
+ case QOpcUa::BadReferenceTypeIdInvalid:
+ return Status::BadReferenceTypeIdInvalid;
+ case QOpcUa::BadBrowseDirectionInvalid:
+ return Status::BadBrowseDirectionInvalid;
+ case QOpcUa::BadNodeNotInView:
+ return Status::BadNodeNotInView;
+ case QOpcUa::BadServerUriInvalid:
+ return Status::BadServerUriInvalid;
+ case QOpcUa::BadServerNameMissing:
+ return Status::BadServerNameMissing;
+ case QOpcUa::BadDiscoveryUrlMissing:
+ return Status::BadDiscoveryUrlMissing;
+ case QOpcUa::BadSempahoreFileMissing:
+ return Status::BadSempahoreFileMissing;
+ case QOpcUa::BadRequestTypeInvalid:
+ return Status::BadRequestTypeInvalid;
+ case QOpcUa::BadSecurityModeRejected:
+ return Status::BadSecurityModeRejected;
+ case QOpcUa::BadSecurityPolicyRejected:
+ return Status::BadSecurityPolicyRejected;
+ case QOpcUa::BadTooManySessions:
+ return Status::BadTooManySessions;
+ case QOpcUa::BadUserSignatureInvalid:
+ return Status::BadUserSignatureInvalid;
+ case QOpcUa::BadApplicationSignatureInvalid:
+ return Status::BadApplicationSignatureInvalid;
+ case QOpcUa::BadNoValidCertificates:
+ return Status::BadNoValidCertificates;
+ case QOpcUa::BadIdentityChangeNotSupported:
+ return Status::BadIdentityChangeNotSupported;
+ case QOpcUa::BadRequestCancelledByRequest:
+ return Status::BadRequestCancelledByRequest;
+ case QOpcUa::BadParentNodeIdInvalid:
+ return Status::BadParentNodeIdInvalid;
+ case QOpcUa::BadReferenceNotAllowed:
+ return Status::BadReferenceNotAllowed;
+ case QOpcUa::BadNodeIdRejected:
+ return Status::BadNodeIdRejected;
+ case QOpcUa::BadNodeIdExists:
+ return Status::BadNodeIdExists;
+ case QOpcUa::BadNodeClassInvalid:
+ return Status::BadNodeClassInvalid;
+ case QOpcUa::BadBrowseNameInvalid:
+ return Status::BadBrowseNameInvalid;
+ case QOpcUa::BadBrowseNameDuplicated:
+ return Status::BadBrowseNameDuplicated;
+ case QOpcUa::BadNodeAttributesInvalid:
+ return Status::BadNodeAttributesInvalid;
+ case QOpcUa::BadTypeDefinitionInvalid:
+ return Status::BadTypeDefinitionInvalid;
+ case QOpcUa::BadSourceNodeIdInvalid:
+ return Status::BadSourceNodeIdInvalid;
+ case QOpcUa::BadTargetNodeIdInvalid:
+ return Status::BadTargetNodeIdInvalid;
+ case QOpcUa::BadDuplicateReferenceNotAllowed:
+ return Status::BadDuplicateReferenceNotAllowed;
+ case QOpcUa::BadInvalidSelfReference:
+ return Status::BadInvalidSelfReference;
+ case QOpcUa::BadReferenceLocalOnly:
+ return Status::BadReferenceLocalOnly;
+ case QOpcUa::BadNoDeleteRights:
+ return Status::BadNoDeleteRights;
+ case QOpcUa::UncertainReferenceNotDeleted:
+ return Status::UncertainReferenceNotDeleted;
+ case QOpcUa::BadServerIndexInvalid:
+ return Status::BadServerIndexInvalid;
+ case QOpcUa::BadViewIdUnknown:
+ return Status::BadViewIdUnknown;
+ case QOpcUa::BadViewTimestampInvalid:
+ return Status::BadViewTimestampInvalid;
+ case QOpcUa::BadViewParameterMismatch:
+ return Status::BadViewParameterMismatch;
+ case QOpcUa::BadViewVersionInvalid:
+ return Status::BadViewVersionInvalid;
+ case QOpcUa::UncertainNotAllNodesAvailable:
+ return Status::UncertainNotAllNodesAvailable;
+ case QOpcUa::GoodResultsMayBeIncomplete:
+ return Status::GoodResultsMayBeIncomplete;
+ case QOpcUa::BadNotTypeDefinition:
+ return Status::BadNotTypeDefinition;
+ case QOpcUa::UncertainReferenceOutOfServer:
+ return Status::UncertainReferenceOutOfServer;
+ case QOpcUa::BadTooManyMatches:
+ return Status::BadTooManyMatches;
+ case QOpcUa::BadQueryTooComplex:
+ return Status::BadQueryTooComplex;
+ case QOpcUa::BadNoMatch:
+ return Status::BadNoMatch;
+ case QOpcUa::BadMaxAgeInvalid:
+ return Status::BadMaxAgeInvalid;
+ case QOpcUa::BadSecurityModeInsufficient:
+ return Status::BadSecurityModeInsufficient;
+ case QOpcUa::BadHistoryOperationInvalid:
+ return Status::BadHistoryOperationInvalid;
+ case QOpcUa::BadHistoryOperationUnsupported:
+ return Status::BadHistoryOperationUnsupported;
+ case QOpcUa::BadInvalidTimestampArgument:
+ return Status::BadInvalidTimestampArgument;
+ case QOpcUa::BadWriteNotSupported:
+ return Status::BadWriteNotSupported;
+ case QOpcUa::BadTypeMismatch:
+ return Status::BadTypeMismatch;
+ case QOpcUa::BadMethodInvalid:
+ return Status::BadMethodInvalid;
+ case QOpcUa::BadArgumentsMissing:
+ return Status::BadArgumentsMissing;
+ case QOpcUa::BadTooManySubscriptions:
+ return Status::BadTooManySubscriptions;
+ case QOpcUa::BadTooManyPublishRequests:
+ return Status::BadTooManyPublishRequests;
+ case QOpcUa::BadNoSubscription:
+ return Status::BadNoSubscription;
+ case QOpcUa::BadSequenceNumberUnknown:
+ return Status::BadSequenceNumberUnknown;
+ case QOpcUa::BadMessageNotAvailable:
+ return Status::BadMessageNotAvailable;
+ case QOpcUa::BadInsufficientClientProfile:
+ return Status::BadInsufficientClientProfile;
+ case QOpcUa::BadStateNotActive:
+ return Status::BadStateNotActive;
+ case QOpcUa::BadTcpServerTooBusy:
+ return Status::BadTcpServerTooBusy;
+ case QOpcUa::BadTcpMessageTypeInvalid:
+ return Status::BadTcpMessageTypeInvalid;
+ case QOpcUa::BadTcpSecureChannelUnknown:
+ return Status::BadTcpSecureChannelUnknown;
+ case QOpcUa::BadTcpMessageTooLarge:
+ return Status::BadTcpMessageTooLarge;
+ case QOpcUa::BadTcpNotEnoughResources:
+ return Status::BadTcpNotEnoughResources;
+ case QOpcUa::BadTcpInternalError:
+ return Status::BadTcpInternalError;
+ case QOpcUa::BadTcpEndpointUrlInvalid:
+ return Status::BadTcpEndpointUrlInvalid;
+ case QOpcUa::BadRequestInterrupted:
+ return Status::BadRequestInterrupted;
+ case QOpcUa::BadRequestTimeout:
+ return Status::BadRequestTimeout;
+ case QOpcUa::BadSecureChannelClosed:
+ return Status::BadSecureChannelClosed;
+ case QOpcUa::BadSecureChannelTokenUnknown:
+ return Status::BadSecureChannelTokenUnknown;
+ case QOpcUa::BadSequenceNumberInvalid:
+ return Status::BadSequenceNumberInvalid;
+ case QOpcUa::BadProtocolVersionUnsupported:
+ return Status::BadProtocolVersionUnsupported;
+ case QOpcUa::BadConfigurationError:
+ return Status::BadConfigurationError;
+ case QOpcUa::BadNotConnected:
+ return Status::BadNotConnected;
+ case QOpcUa::BadDeviceFailure:
+ return Status::BadDeviceFailure;
+ case QOpcUa::BadSensorFailure:
+ return Status::BadSensorFailure;
+ case QOpcUa::BadOutOfService:
+ return Status::BadOutOfService;
+ case QOpcUa::BadDeadbandFilterInvalid:
+ return Status::BadDeadbandFilterInvalid;
+ case QOpcUa::UncertainNoCommunicationLastUsableValue:
+ return Status::UncertainNoCommunicationLastUsableValue;
+ case QOpcUa::UncertainLastUsableValue:
+ return Status::UncertainLastUsableValue;
+ case QOpcUa::UncertainSubstituteValue:
+ return Status::UncertainSubstituteValue;
+ case QOpcUa::UncertainInitialValue:
+ return Status::UncertainInitialValue;
+ case QOpcUa::UncertainSensorNotAccurate:
+ return Status::UncertainSensorNotAccurate;
+ case QOpcUa::UncertainEngineeringUnitsExceeded:
+ return Status::UncertainEngineeringUnitsExceeded;
+ case QOpcUa::UncertainSubNormal:
+ return Status::UncertainSubNormal;
+ case QOpcUa::GoodLocalOverride:
+ return Status::GoodLocalOverride;
+ case QOpcUa::BadRefreshInProgress:
+ return Status::BadRefreshInProgress;
+ case QOpcUa::BadConditionAlreadyDisabled:
+ return Status::BadConditionAlreadyDisabled;
+ case QOpcUa::BadConditionAlreadyEnabled:
+ return Status::BadConditionAlreadyEnabled;
+ case QOpcUa::BadConditionDisabled:
+ return Status::BadConditionDisabled;
+ case QOpcUa::BadEventIdUnknown:
+ return Status::BadEventIdUnknown;
+ case QOpcUa::BadEventNotAcknowledgeable:
+ return Status::BadEventNotAcknowledgeable;
+ case QOpcUa::BadDialogNotActive:
+ return Status::BadDialogNotActive;
+ case QOpcUa::BadDialogResponseInvalid:
+ return Status::BadDialogResponseInvalid;
+ case QOpcUa::BadConditionBranchAlreadyAcked:
+ return Status::BadConditionBranchAlreadyAcked;
+ case QOpcUa::BadConditionBranchAlreadyConfirmed:
+ return Status::BadConditionBranchAlreadyConfirmed;
+ case QOpcUa::BadConditionAlreadyShelved:
+ return Status::BadConditionAlreadyShelved;
+ case QOpcUa::BadConditionNotShelved:
+ return Status::BadConditionNotShelved;
+ case QOpcUa::BadShelvingTimeOutOfRange:
+ return Status::BadShelvingTimeOutOfRange;
+ case QOpcUa::BadNoData:
+ return Status::BadNoData;
+ case QOpcUa::BadBoundNotFound:
+ return Status::BadBoundNotFound;
+ case QOpcUa::BadBoundNotSupported:
+ return Status::BadBoundNotSupported;
+ case QOpcUa::BadDataLost:
+ return Status::BadDataLost;
+ case QOpcUa::BadDataUnavailable:
+ return Status::BadDataUnavailable;
+ case QOpcUa::BadEntryExists:
+ return Status::BadEntryExists;
+ case QOpcUa::BadNoEntryExists:
+ return Status::BadNoEntryExists;
+ case QOpcUa::BadTimestampNotSupported:
+ return Status::BadTimestampNotSupported;
+ case QOpcUa::GoodEntryInserted:
+ return Status::GoodEntryInserted;
+ case QOpcUa::GoodEntryReplaced:
+ return Status::GoodEntryReplaced;
+ case QOpcUa::UncertainDataSubNormal:
+ return Status::UncertainDataSubNormal;
+ case QOpcUa::GoodNoData:
+ return Status::GoodNoData;
+ case QOpcUa::GoodMoreData:
+ return Status::GoodMoreData;
+ case QOpcUa::BadAggregateListMismatch:
+ return Status::BadAggregateListMismatch;
+ case QOpcUa::BadAggregateNotSupported:
+ return Status::BadAggregateNotSupported;
+ case QOpcUa::BadAggregateInvalidInputs:
+ return Status::BadAggregateInvalidInputs;
+ case QOpcUa::BadAggregateConfigurationRejected:
+ return Status::BadAggregateConfigurationRejected;
+ case QOpcUa::GoodDataIgnored:
+ return Status::GoodDataIgnored;
+ case QOpcUa::BadRequestNotAllowed:
+ return Status::BadRequestNotAllowed;
+ case QOpcUa::GoodEdited:
+ return Status::GoodEdited;
+ case QOpcUa::GoodPostActionFailed:
+ return Status::GoodPostActionFailed;
+ case QOpcUa::UncertainDominantValueChanged:
+ return Status::UncertainDominantValueChanged;
+ case QOpcUa::GoodDependentValueChanged:
+ return Status::GoodDependentValueChanged;
+ case QOpcUa::BadDominantValueChanged:
+ return Status::BadDominantValueChanged;
+ case QOpcUa::UncertainDependentValueChanged:
+ return Status::UncertainDependentValueChanged;
+ case QOpcUa::BadDependentValueChanged:
+ return Status::BadDependentValueChanged;
+ case QOpcUa::GoodCommunicationEvent:
+ return Status::GoodCommunicationEvent;
+ case QOpcUa::GoodShutdownEvent:
+ return Status::GoodShutdownEvent;
+ case QOpcUa::GoodCallAgain:
+ return Status::GoodCallAgain;
+ case QOpcUa::GoodNonCriticalTimeout:
+ return Status::GoodNonCriticalTimeout;
+ case QOpcUa::BadInvalidArgument:
+ return Status::BadInvalidArgument;
+ case QOpcUa::BadConnectionRejected:
+ return Status::BadConnectionRejected;
+ case QOpcUa::BadDisconnect:
+ return Status::BadDisconnect;
+ case QOpcUa::BadConnectionClosed:
+ return Status::BadConnectionClosed;
+ case QOpcUa::BadInvalidState:
+ return Status::BadInvalidState;
+ case QOpcUa::BadEndOfStream:
+ return Status::BadEndOfStream;
+ case QOpcUa::BadNoDataAvailable:
+ return Status::BadNoDataAvailable;
+ case QOpcUa::BadWaitingForResponse:
+ return Status::BadWaitingForResponse;
+ case QOpcUa::BadOperationAbandoned:
+ return Status::BadOperationAbandoned;
+ case QOpcUa::BadExpectedStreamToBlock:
+ return Status::BadExpectedStreamToBlock;
+ case QOpcUa::BadWouldBlock:
+ return Status::BadWouldBlock;
+ case QOpcUa::BadSyntaxError:
+ return Status::BadSyntaxError;
+ case QOpcUa::BadMaxConnectionsReached:
+ return Status::BadMaxConnectionsReached;
+ }
+ return Status::BadUnexpectedError;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/imports/opcua/opcuastatus.h b/src/imports/opcua/opcuastatus.h
new file mode 100644
index 0000000..1f23292
--- /dev/null
+++ b/src/imports/opcua/opcuastatus.h
@@ -0,0 +1,303 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPCUASTATUS_H
+#define OPCUASTATUS_H
+
+#include <QStandardItemModel>
+#include <QtOpcUa/qopcuatype.h>
+#include <QOpcUaApplicationDescription>
+
+QT_BEGIN_NAMESPACE
+
+class OpcUaConnection;
+
+class OpcUaStatus
+{
+ Q_GADGET
+ Q_PROPERTY(bool isGood READ isGood)
+ Q_PROPERTY(bool isBad READ isBad)
+ Q_PROPERTY(Status status READ status)
+
+public:
+ enum class Status {
+ Good = 0x0000,
+ BadUnexpectedError = 0x8001,
+ BadInternalError = 0x8002,
+ BadOutOfMemory = 0x8003,
+ BadResourceUnavailable = 0x8004,
+ BadCommunicationError = 0x8005,
+ BadEncodingError = 0x8006,
+ BadDecodingError = 0x8007,
+ BadEncodingLimitsExceeded = 0x8008,
+ BadRequestTooLarge = 0x80B8,
+ BadResponseTooLarge = 0x80B9,
+ BadUnknownResponse = 0x8009,
+ BadTimeout = 0x800A,
+ BadServiceUnsupported = 0x800B,
+ BadShutdown = 0x800C,
+ BadServerNotConnected = 0x800D,
+ BadServerHalted = 0x800E,
+ BadNothingToDo = 0x800F,
+ BadTooManyOperations = 0x8010,
+ BadTooManyMonitoredItems = 0x80DB,
+ BadDataTypeIdUnknown = 0x8011,
+ BadCertificateInvalid = 0x8012,
+ BadSecurityChecksFailed = 0x8013,
+ BadCertificateTimeInvalid = 0x8014,
+ BadCertificateIssuerTimeInvalid = 0x8015,
+ BadCertificateHostNameInvalid = 0x8016,
+ BadCertificateUriInvalid = 0x8017,
+ BadCertificateUseNotAllowed = 0x8018,
+ BadCertificateIssuerUseNotAllowed = 0x8019,
+ BadCertificateUntrusted = 0x801A,
+ BadCertificateRevocationUnknown = 0x801B,
+ BadCertificateIssuerRevocationUnknown = 0x801C,
+ BadCertificateRevoked = 0x801D,
+ BadCertificateIssuerRevoked = 0x801E,
+ BadCertificateChainIncomplete = 0x810D,
+ BadUserAccessDenied = 0x801F,
+ BadIdentityTokenInvalid = 0x8020,
+ BadIdentityTokenRejected = 0x8021,
+ BadSecureChannelIdInvalid = 0x8022,
+ BadInvalidTimestamp = 0x8023,
+ BadNonceInvalid = 0x8024,
+ BadSessionIdInvalid = 0x8025,
+ BadSessionClosed = 0x8026,
+ BadSessionNotActivated = 0x8027,
+ BadSubscriptionIdInvalid = 0x8028,
+ BadRequestHeaderInvalid = 0x802A,
+ BadTimestampsToReturnInvalid = 0x802B,
+ BadRequestCancelledByClient = 0x802C,
+ BadTooManyArguments = 0x80E5,
+ GoodSubscriptionTransferred = 0x002D,
+ GoodCompletesAsynchronously = 0x002E,
+ GoodOverload = 0x002F,
+ GoodClamped = 0x0030,
+ BadNoCommunication = 0x8031,
+ BadWaitingForInitialData = 0x8032,
+ BadNodeIdInvalid = 0x8033,
+ BadNodeIdUnknown = 0x8034,
+ BadAttributeIdInvalid = 0x8035,
+ BadIndexRangeInvalid = 0x8036,
+ BadIndexRangeNoData = 0x8037,
+ BadDataEncodingInvalid = 0x8038,
+ BadDataEncodingUnsupported = 0x8039,
+ BadNotReadable = 0x803A,
+ BadNotWritable = 0x803B,
+ BadOutOfRange = 0x803C,
+ BadNotSupported = 0x803D,
+ BadNotFound = 0x803E,
+ BadObjectDeleted = 0x803F,
+ BadNotImplemented = 0x8040,
+ BadMonitoringModeInvalid = 0x8041,
+ BadMonitoredItemIdInvalid = 0x8042,
+ BadMonitoredItemFilterInvalid = 0x8043,
+ BadMonitoredItemFilterUnsupported = 0x8044,
+ BadFilterNotAllowed = 0x8045,
+ BadStructureMissing = 0x8046,
+ BadEventFilterInvalid = 0x8047,
+ BadContentFilterInvalid = 0x8048,
+ BadFilterOperatorInvalid = 0x80C1,
+ BadFilterOperatorUnsupported = 0x80C2,
+ BadFilterOperandCountMismatch = 0x80C3,
+ BadFilterOperandInvalid = 0x8049,
+ BadFilterElementInvalid = 0x80C4,
+ BadFilterLiteralInvalid = 0x80C5,
+ BadContinuationPointInvalid = 0x804A,
+ BadNoContinuationPoints = 0x804B,
+ BadReferenceTypeIdInvalid = 0x804C,
+ BadBrowseDirectionInvalid = 0x804D,
+ BadNodeNotInView = 0x804E,
+ BadServerUriInvalid = 0x804F,
+ BadServerNameMissing = 0x8050,
+ BadDiscoveryUrlMissing = 0x8051,
+ BadSempahoreFileMissing = 0x8052,
+ BadRequestTypeInvalid = 0x8053,
+ BadSecurityModeRejected = 0x8054,
+ BadSecurityPolicyRejected = 0x8055,
+ BadTooManySessions = 0x8056,
+ BadUserSignatureInvalid = 0x8057,
+ BadApplicationSignatureInvalid = 0x8058,
+ BadNoValidCertificates = 0x8059,
+ BadIdentityChangeNotSupported = 0x80C6,
+ BadRequestCancelledByRequest = 0x805A,
+ BadParentNodeIdInvalid = 0x805B,
+ BadReferenceNotAllowed = 0x805C,
+ BadNodeIdRejected = 0x805D,
+ BadNodeIdExists = 0x805E,
+ BadNodeClassInvalid = 0x805F,
+ BadBrowseNameInvalid = 0x8060,
+ BadBrowseNameDuplicated = 0x8061,
+ BadNodeAttributesInvalid = 0x8062,
+ BadTypeDefinitionInvalid = 0x8063,
+ BadSourceNodeIdInvalid = 0x8064,
+ BadTargetNodeIdInvalid = 0x8065,
+ BadDuplicateReferenceNotAllowed = 0x8066,
+ BadInvalidSelfReference = 0x8067,
+ BadReferenceLocalOnly = 0x8068,
+ BadNoDeleteRights = 0x8069,
+ UncertainReferenceNotDeleted = 0x40BC,
+ BadServerIndexInvalid = 0x806A,
+ BadViewIdUnknown = 0x806B,
+ BadViewTimestampInvalid = 0x80C9,
+ BadViewParameterMismatch = 0x80CA,
+ BadViewVersionInvalid = 0x80CB,
+ UncertainNotAllNodesAvailable = 0x40C0,
+ GoodResultsMayBeIncomplete = 0x00BA,
+ BadNotTypeDefinition = 0x80C8,
+ UncertainReferenceOutOfServer = 0x406C,
+ BadTooManyMatches = 0x806D,
+ BadQueryTooComplex = 0x806E,
+ BadNoMatch = 0x806F,
+ BadMaxAgeInvalid = 0x8070,
+ BadSecurityModeInsufficient = 0x80E6,
+ BadHistoryOperationInvalid = 0x8071,
+ BadHistoryOperationUnsupported = 0x8072,
+ BadInvalidTimestampArgument = 0x80BD,
+ BadWriteNotSupported = 0x8073,
+ BadTypeMismatch = 0x8074,
+ BadMethodInvalid = 0x8075,
+ BadArgumentsMissing = 0x8076,
+ BadTooManySubscriptions = 0x8077,
+ BadTooManyPublishRequests = 0x8078,
+ BadNoSubscription = 0x8079,
+ BadSequenceNumberUnknown = 0x807A,
+ BadMessageNotAvailable = 0x807B,
+ BadInsufficientClientProfile = 0x807C,
+ BadStateNotActive = 0x80BF,
+ BadTcpServerTooBusy = 0x807D,
+ BadTcpMessageTypeInvalid = 0x807E,
+ BadTcpSecureChannelUnknown = 0x807F,
+ BadTcpMessageTooLarge = 0x8080,
+ BadTcpNotEnoughResources = 0x8081,
+ BadTcpInternalError = 0x8082,
+ BadTcpEndpointUrlInvalid = 0x8083,
+ BadRequestInterrupted = 0x8084,
+ BadRequestTimeout = 0x8085,
+ BadSecureChannelClosed = 0x8086,
+ BadSecureChannelTokenUnknown = 0x8087,
+ BadSequenceNumberInvalid = 0x8088,
+ BadProtocolVersionUnsupported = 0x80BE,
+ BadConfigurationError = 0x8089,
+ BadNotConnected = 0x808A,
+ BadDeviceFailure = 0x808B,
+ BadSensorFailure = 0x808C,
+ BadOutOfService = 0x808D,
+ BadDeadbandFilterInvalid = 0x808E,
+ UncertainNoCommunicationLastUsableValue = 0x408F,
+ UncertainLastUsableValue = 0x4090,
+ UncertainSubstituteValue = 0x4091,
+ UncertainInitialValue = 0x4092,
+ UncertainSensorNotAccurate = 0x4093,
+ UncertainEngineeringUnitsExceeded = 0x4094,
+ UncertainSubNormal = 0x4095,
+ GoodLocalOverride = 0x0096,
+ BadRefreshInProgress = 0x8097,
+ BadConditionAlreadyDisabled = 0x8098,
+ BadConditionAlreadyEnabled = 0x80CC,
+ BadConditionDisabled = 0x8099,
+ BadEventIdUnknown = 0x809A,
+ BadEventNotAcknowledgeable = 0x80BB,
+ BadDialogNotActive = 0x80CD,
+ BadDialogResponseInvalid = 0x80CE,
+ BadConditionBranchAlreadyAcked = 0x80CF,
+ BadConditionBranchAlreadyConfirmed = 0x80D0,
+ BadConditionAlreadyShelved = 0x80D1,
+ BadConditionNotShelved = 0x80D2,
+ BadShelvingTimeOutOfRange = 0x80D3,
+ BadNoData = 0x809B,
+ BadBoundNotFound = 0x80D7,
+ BadBoundNotSupported = 0x80D8,
+ BadDataLost = 0x809D,
+ BadDataUnavailable = 0x809E,
+ BadEntryExists = 0x809F,
+ BadNoEntryExists = 0x80A0,
+ BadTimestampNotSupported = 0x80A1,
+ GoodEntryInserted = 0x00A2,
+ GoodEntryReplaced = 0x00A3,
+ UncertainDataSubNormal = 0x40A4,
+ GoodNoData = 0x00A5,
+ GoodMoreData = 0x00A6,
+ BadAggregateListMismatch = 0x80D4,
+ BadAggregateNotSupported = 0x80D5,
+ BadAggregateInvalidInputs = 0x80D6,
+ BadAggregateConfigurationRejected = 0x80DA,
+ GoodDataIgnored = 0x00D9,
+ BadRequestNotAllowed = 0x80E4,
+ GoodEdited = 0x00DC,
+ GoodPostActionFailed = 0x00DD,
+ UncertainDominantValueChanged = 0x40DE,
+ GoodDependentValueChanged = 0x00E0,
+ BadDominantValueChanged = 0x80E1,
+ UncertainDependentValueChanged = 0x40E2,
+ BadDependentValueChanged = 0x80E3,
+ GoodCommunicationEvent = 0x00A7,
+ GoodShutdownEvent = 0x00A8,
+ GoodCallAgain = 0x00A9,
+ GoodNonCriticalTimeout = 0x00AA,
+ BadInvalidArgument = 0x80AB,
+ BadConnectionRejected = 0x80AC,
+ BadDisconnect = 0x80AD,
+ BadConnectionClosed = 0x80AE,
+ BadInvalidState = 0x80AF,
+ BadEndOfStream = 0x80B0,
+ BadNoDataAvailable = 0x80B1,
+ BadWaitingForResponse = 0x80B2,
+ BadOperationAbandoned = 0x80B3,
+ BadExpectedStreamToBlock = 0x80B4,
+ BadWouldBlock = 0x80B5,
+ BadSyntaxError = 0x80B6,
+ BadMaxConnectionsReached = 0x80B7
+ };
+ Q_ENUM(Status)
+
+ OpcUaStatus();
+ OpcUaStatus(QOpcUa::UaStatusCode);
+ OpcUaStatus(Status);
+ ~OpcUaStatus();
+
+ bool isGood() const;
+ bool isBad() const;
+ Status status() const;
+
+private:
+ quint32 m_statusCode{QOpcUa::Good};
+};
+
+QT_END_NAMESPACE
+
+#endif // OPCUASTATUS_H
diff --git a/src/imports/opcua/opcuavaluenode.cpp b/src/imports/opcua/opcuavaluenode.cpp
index 1126719..e8ca301 100644
--- a/src/imports/opcua/opcuavaluenode.cpp
+++ b/src/imports/opcua/opcuavaluenode.cpp
@@ -39,6 +39,7 @@
#include "opcuanodeid.h"
#include "opcuaattributevalue.h"
#include <QLoggingCategory>
+#include <QMetaEnum>
QT_BEGIN_NAMESPACE
@@ -50,7 +51,7 @@ QT_BEGIN_NAMESPACE
\since QtOpcUa 5.12
\code
- import QtOpcUa 5.12 as QtOpcUa
+ import QtOpcUa 5.13 as QtOpcUa
QtOpcUa.ValueNode {
nodeId: QtOpcUa.NodeId {
@@ -73,12 +74,35 @@ QT_BEGIN_NAMESPACE
Reading and writing this property will access the node on the server.
*/
+/*!
+ \qmlproperty variant ValueNode::valueType
+
+ Type type of this node.
+ The initial value will be \l {QtOpcUa::Undefined}{QtOpcUa.Constants.Undefined} and be fetched from the server when the first connection is established.
+ Any value will be written to the server as the specified type.
+*/
+
+/*!
+ \qmlproperty Date ValueNode::sourceTimestamp
+ \readonly
+
+ Source timestamp of the value attribute.
+*/
+
+/*!
+ \qmlproperty Date ValueNode::serverTimestamp
+ \readonly
+
+ Server timestamp of the value attribute.
+*/
+
Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_QML)
OpcUaValueNode::OpcUaValueNode(QObject *parent):
OpcUaNode(parent)
{
connect(m_attributeCache.attribute(QOpcUa::NodeAttribute::Value), &OpcUaAttributeValue::changed, this, &OpcUaValueNode::valueChanged);
+ connect(this, &OpcUaValueNode::filterChanged, this, &OpcUaValueNode::updateFilters);
}
OpcUaValueNode::~OpcUaValueNode()
@@ -87,7 +111,18 @@ OpcUaValueNode::~OpcUaValueNode()
void OpcUaValueNode::setValue(const QVariant &value)
{
- m_node->writeAttribute(QOpcUa::NodeAttribute::Value, value, QOpcUa::Types::Undefined);
+ if (!m_connection || !m_node)
+ return;
+ m_node->writeAttribute(QOpcUa::NodeAttribute::Value, value, m_valueType);
+}
+
+template<typename T> QString enumToString(T value) {
+ const auto metaEnum = QMetaEnum::fromType<T>();
+ const auto key = metaEnum.valueToKey(static_cast<int>(value));
+ if (key)
+ return QString::fromLatin1(key);
+ else
+ return QString();
}
void OpcUaValueNode::setupNode(const QString &absolutePath)
@@ -101,15 +136,194 @@ void OpcUaValueNode::setupNode(const QString &absolutePath)
if (!m_node)
return;
- if (!m_node->enableMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters(100)))
- qCWarning(QT_OPCUA_PLUGINS_QML) << "Failed monitoring" << m_node->nodeId();
+ connect(m_node, &QOpcUaNode::attributeWritten, this, [this](QOpcUa::NodeAttribute attribute, QOpcUa::UaStatusCode statusCode) {
+ if (statusCode != QOpcUa::Good) {
+ QString msg = "Failed to write attribute "
+ + enumToString(attribute)
+ + ": "
+ + enumToString(statusCode);
+ setStatus(Status::FailedToWriteAttribute, msg);
+ qCWarning(QT_OPCUA_PLUGINS_QML) << msg;
+ }
+ });
+
+
+ connect(m_node, &QOpcUaNode::attributeUpdated, this, [this](QOpcUa::NodeAttribute attr, QVariant value) {
+ if (attr == QOpcUa::NodeAttribute::DataType && m_valueType == QOpcUa::Types::Undefined) {
+ const auto valueType = QOpcUa::opcUaDataTypeToQOpcUaType(value.toString());
+ m_valueType = valueType;
+ }
+ });
+
+ connect(m_node, &QOpcUaNode::enableMonitoringFinished, this, [this](QOpcUa::NodeAttribute attr, QOpcUa::UaStatusCode statusCode){
+ if (attr != QOpcUa::NodeAttribute::Value)
+ return;
+ if (statusCode == QOpcUa::Good) {
+ m_monitoredState = true;
+ emit monitoredChanged(m_monitoredState);
+ qCDebug(QT_OPCUA_PLUGINS_QML) << "Monitoring was enabled for node" << resolvedNode().fullNodeId();
+ updateFilters();
+ } else {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Failed to enable monitoring for node" << resolvedNode().fullNodeId();
+ setStatus(Status::FailedToSetupMonitoring);
+ }
+ });
+ connect(m_node, &QOpcUaNode::disableMonitoringFinished, this, [this](QOpcUa::NodeAttribute attr, QOpcUa::UaStatusCode statusCode){
+ if (attr != QOpcUa::NodeAttribute::Value)
+ return;
+ if (statusCode == QOpcUa::Good) {
+ m_monitoredState = false;
+ emit monitoredChanged(m_monitoredState);
+ qCDebug(QT_OPCUA_PLUGINS_QML) << "Monitoring was disabled for node "<< resolvedNode().fullNodeId();
+ } else {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Failed to disable monitoring for node "<< resolvedNode().fullNodeId();
+ setStatus(Status::FailedToDisableMonitoring);
+ }
+ });
+ connect(m_node, &QOpcUaNode::monitoringStatusChanged, this, [this](QOpcUa::NodeAttribute attr, QOpcUaMonitoringParameters::Parameters items,
+ QOpcUa::UaStatusCode statusCode) {
+ if (attr != QOpcUa::NodeAttribute::Value && attr != QOpcUa::NodeAttribute::EventNotifier)
+ return;
+ if (statusCode != QOpcUa::Good) {
+ setStatus(Status::FailedToModifyMonitoring);
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Failed to modify monitoring";
+ } else {
+ if (items & QOpcUaMonitoringParameters::Parameter::PublishingInterval) {
+ if (m_publishingInterval != m_node->monitoringStatus(QOpcUa::NodeAttribute::Value).publishingInterval()) {
+ m_publishingInterval = m_node->monitoringStatus(QOpcUa::NodeAttribute::Value).publishingInterval();
+ emit publishingIntervalChanged(m_publishingInterval);
+ }
+ }
+ }
+ });
+
+ updateSubscription();
+}
+
+void OpcUaValueNode::updateFilters() const
+{
+ if (!m_connection || !m_node || !m_filter || !m_monitoredState)
+ return;
+
+ m_node->modifyDataChangeFilter(QOpcUa::NodeAttribute::Value, m_filter->filter());
+}
+
+bool OpcUaValueNode::checkValidity()
+{
+ if (!m_connection || !m_node)
+ return false;
+
+ if (m_node->attribute(QOpcUa::NodeAttribute::NodeClass).value<QOpcUa::NodeClass>() != QOpcUa::NodeClass::Variable) {
+ setStatus(Status::InvalidNodeType);
+ return false;
+ } else {
+ return true;
+ }
+
}
QVariant OpcUaValueNode::value() const
{
- if (!m_node)
+ if (!m_connection || !m_node)
return QVariant();
return m_node->attribute(QOpcUa::NodeAttribute::Value);
}
+QDateTime OpcUaValueNode::serverTimestamp() const
+{
+ return getServerTimestamp(QOpcUa::NodeAttribute::Value);
+}
+
+QDateTime OpcUaValueNode::sourceTimestamp() const
+{
+ return getSourceTimestamp(QOpcUa::NodeAttribute::Value);
+}
+
+bool OpcUaValueNode::monitored() const
+{
+ if (!m_connection || !m_node)
+ return m_monitored;
+
+ return m_monitoredState;
+}
+
+void OpcUaValueNode::updateSubscription()
+{
+ if (!m_connection || !m_node)
+ return;
+
+ QOpcUaMonitoringParameters parameters;
+ parameters.setPublishingInterval(m_publishingInterval);
+
+ if (m_filter)
+ parameters.setFilter(m_filter->filter());
+
+ if (m_monitoredState != m_monitored) {
+ if (m_monitored) {
+ m_node->enableMonitoring(QOpcUa::NodeAttribute::Value, parameters);
+ } else {
+ m_node->disableMonitoring(QOpcUa::NodeAttribute::Value);
+ }
+ }
+}
+void OpcUaValueNode::setMonitored(bool monitored)
+{
+ m_monitored = monitored;
+ updateSubscription();
+}
+
+double OpcUaValueNode::publishingInterval() const
+{
+ if (!m_connection || !m_node)
+ return 0.0;
+
+ auto monitoringStatus = node()->monitoringStatus(QOpcUa::NodeAttribute::Value);
+ if (monitoringStatus.statusCode() == QOpcUa::BadNoEntryExists)
+ return 0.0;
+ return monitoringStatus.publishingInterval();
+}
+
+OpcUaDataChangeFilter *OpcUaValueNode::filter() const
+{
+ return m_filter;
+}
+
+void OpcUaValueNode::setFilter(OpcUaDataChangeFilter *filter)
+{
+ bool changed = false;
+
+ if (m_filter) {
+ disconnect(m_filter, &OpcUaDataChangeFilter::filterChanged, this, &OpcUaValueNode::updateFilters);
+ changed = !(*m_filter == *filter);
+ } else {
+ changed = true;
+ }
+
+ m_filter = filter;
+ connect(m_filter, &OpcUaDataChangeFilter::filterChanged, this, &OpcUaValueNode::updateFilters);
+
+ if (changed)
+ emit filterChanged();
+}
+
+void OpcUaValueNode::setPublishingInterval(double publishingInterval)
+{
+ if (!m_connection || !m_node)
+ return;
+ if (qFuzzyCompare(m_publishingInterval, publishingInterval))
+ return;
+
+ m_node->modifyMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters::Parameter::PublishingInterval, publishingInterval);
+}
+
+QOpcUa::Types OpcUaValueNode::valueType() const
+{
+ return m_valueType;
+}
+
+void OpcUaValueNode::setValueType(QOpcUa::Types valueType)
+{
+ m_valueType = valueType;
+}
+
QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuavaluenode.h b/src/imports/opcua/opcuavaluenode.h
index cab3474..ff0a929 100644
--- a/src/imports/opcua/opcuavaluenode.h
+++ b/src/imports/opcua/opcuavaluenode.h
@@ -37,6 +37,8 @@
#pragma once
#include "opcuanode.h"
+#include <QDateTime>
+#include "opcuadatachangefilter.h"
QT_BEGIN_NAMESPACE
@@ -45,20 +47,52 @@ class OpcUaValueNode : public OpcUaNode
Q_OBJECT
Q_DISABLE_COPY(OpcUaValueNode)
Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
+ Q_PROPERTY(QOpcUa::Types valueType READ valueType WRITE setValueType)
+ Q_PROPERTY(QDateTime serverTimestamp READ serverTimestamp)
+ Q_PROPERTY(QDateTime sourceTimestamp READ sourceTimestamp)
+ Q_PROPERTY(bool monitored READ monitored WRITE setMonitored NOTIFY monitoredChanged)
+ Q_PROPERTY(double publishingInterval READ publishingInterval WRITE setPublishingInterval NOTIFY publishingIntervalChanged)
+ Q_PROPERTY(OpcUaDataChangeFilter *filter READ filter WRITE setFilter NOTIFY filterChanged)
public:
OpcUaValueNode(QObject *parent = nullptr);
~OpcUaValueNode();
QVariant value() const;
+ QDateTime serverTimestamp() const;
+ QDateTime sourceTimestamp() const;
+ bool monitored() const;
+ double publishingInterval() const;
+ QOpcUa::Types valueType() const;
+ OpcUaDataChangeFilter *filter() const;
+ void setFilter(OpcUaDataChangeFilter *filter);
+
public slots:
void setValue(const QVariant &);
+ void setMonitored(bool monitored);
+ void setPublishingInterval(double publishingInterval);
+ void setValueType(QOpcUa::Types valueType);
+
signals:
void valueChanged(const QVariant &value);
+ void monitoredChanged(bool monitored);
+ void publishingIntervalChanged(double publishingInterval);
+ void dataChangeOccurred(const QVariant &value);
+ void filterChanged();
private slots:
void setupNode(const QString &absolutePath) override;
+ void updateSubscription();
+ void updateFilters() const;
+
+private:
+ bool checkValidity() override;
+ bool m_monitored = true;
+ bool m_monitoredState = false;
+ double m_publishingInterval = 100;
+ QOpcUa::Types m_valueType = QOpcUa::Types::Undefined;
+ OpcUaDataChangeFilter *m_filter = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/imports/opcua/opcuawriteitem.cpp b/src/imports/opcua/opcuawriteitem.cpp
new file mode 100644
index 0000000..b86e0f9
--- /dev/null
+++ b/src/imports/opcua/opcuawriteitem.cpp
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcuawriteitem.h"
+#include "opcuawriteresult.h"
+#include <QJSValue>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype WriteItem
+ \inqmlmodule QtOpcUa
+ \brief Specifies an item to be written to the server.
+ \since QtOpcUa 5.13
+
+ This type is used to specify items to be written to the server using the function
+ \l Connection::writeNodeAttributes.
+*/
+
+/*!
+ \qmlproperty Constants.NodeAttribute WriteItem::attribute
+
+ Determines the attribute of the node to be written.
+*/
+
+/*!
+ \qmlproperty string WriteItem::indexRange
+
+ Determines the index range of the attribute to be written.
+ If not needed, leave this property empty.
+*/
+
+/*!
+ \qmlproperty string Writetem::nodeId
+
+ Determines the node id of the node to be written.
+*/
+
+/*!
+ \qmlproperty variant WriteItem::ns
+
+ Determines the namespace of the node to be written.
+ The namespace can be given by name or index.
+ If this property is given, any namespace in the node id will be
+ ignored.
+*/
+
+/*!
+ \qmlproperty datetime WriteItem::serverTimestamp
+
+ Sets the server timestamp for the value to be written.
+ If the server timestamp is invalid, it is ignored by the client and not sent to the server.
+ If the server doesn't support writing timestamps, the write operation for this item
+ will fail.
+*/
+
+/*!
+ \qmlproperty datetime WriteItem::sourceTimestamp
+
+ Sets the source timestamp for the value to write.
+ If the source timestamp is invalid, it is ignored by the client and not sent to the server.
+ If the server doesn't support writing timestamps, the write operation for this item
+ will fail.
+*/
+
+/*!
+ \qmlproperty variant WriteItem::value
+
+ Actual data that is requested to be written.
+*/
+
+/*!
+ \qmlproperty variant WriteItem::valueType
+
+ If given, the type information will be used in converting
+ the value to a SDK specific data type.
+*/
+
+/*!
+ \qmlproperty OpcUaStatus WriteItem::statusCode
+
+ Sets the status code for the value to write.
+ If no status code is set, no status code is sent to the server.
+*/
+
+class OpcUaWriteItemData : public QSharedData
+{
+public:
+ QOpcUa::NodeAttribute attribute;
+ QString indexRange;
+ QString nodeId;
+ QVariant namespaceIdentifier;
+ QDateTime serverTimestamp;
+ QDateTime sourceTimestamp;
+ QVariant value;
+ QOpcUa::Types valueType = QOpcUa::Types::Undefined;
+ OpcUaStatus::Status statusCode;
+ bool hasStatusCode = false;
+};
+
+OpcUaWriteItem::OpcUaWriteItem()
+ : data(new OpcUaWriteItemData)
+{
+ data->attribute = QOpcUa::NodeAttribute::Value;
+}
+
+OpcUaWriteItem::OpcUaWriteItem(const OpcUaWriteItem &other)
+ : data(other.data)
+{
+}
+
+OpcUaWriteItem &OpcUaWriteItem::operator=(const OpcUaWriteItem &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+OpcUaWriteItem::~OpcUaWriteItem() = default;
+
+const QString &OpcUaWriteItem::indexRange() const
+{
+ return data->indexRange;
+}
+
+void OpcUaWriteItem::setIndexRange(const QString &indexRange)
+{
+ data->indexRange = indexRange;
+}
+
+const QString &OpcUaWriteItem::nodeId() const
+{
+ return data->nodeId;
+}
+
+void OpcUaWriteItem::setNodeId(const QString &nodeId)
+{
+ data->nodeId = nodeId;
+}
+
+QOpcUa::NodeAttribute OpcUaWriteItem::attribute() const
+{
+ return data->attribute;
+}
+
+void OpcUaWriteItem::setAttribute(QOpcUa::NodeAttribute attribute)
+{
+ data->attribute = attribute;
+}
+
+const QVariant &OpcUaWriteItem::namespaceIdentifier() const
+{
+ return data->namespaceIdentifier;
+}
+
+void OpcUaWriteItem::setNamespaceIdentifier(const QVariant &namespaceIdentifier)
+{
+ data->namespaceIdentifier = namespaceIdentifier;
+}
+
+void OpcUaWriteItem::setServerTimestamp(const QDateTime &serverTimestamp)
+{
+ data->serverTimestamp = serverTimestamp;
+}
+
+const QDateTime &OpcUaWriteItem::serverTimestamp() const
+{
+ return data->serverTimestamp;
+}
+
+void OpcUaWriteItem::setSourceTimestamp(const QDateTime &sourceTimestamp)
+{
+ data->sourceTimestamp = sourceTimestamp;
+}
+
+const QDateTime &OpcUaWriteItem::sourceTimestamp() const
+{
+ return data->sourceTimestamp;
+}
+
+void OpcUaWriteItem::setValue(const QVariant &value)
+{
+ auto tmp = value;
+ // In case of an array value the type is QJSValue,
+ // which has to be unpacked to recognized.
+ if (tmp.userType() == qMetaTypeId<QJSValue>())
+ tmp = tmp.value<QJSValue>().toVariant();
+
+ data->value = tmp;
+}
+
+const QVariant &OpcUaWriteItem::value() const
+{
+ return data->value;
+}
+
+QOpcUa::Types OpcUaWriteItem::valueType() const
+{
+ return data->valueType;
+}
+
+void OpcUaWriteItem::setValueType(QOpcUa::Types type)
+{
+ data->valueType = type;
+}
+
+OpcUaStatus::Status OpcUaWriteItem::statusCode() const
+{
+ return data->statusCode;
+}
+
+bool OpcUaWriteItem::hasStatusCode() const
+{
+ return data->hasStatusCode;
+}
+
+void OpcUaWriteItem::setStatusCode(OpcUaStatus::Status statusCode)
+{
+ data->statusCode = statusCode;
+ data->hasStatusCode = true;
+}
+
+OpcUaWriteItem OpcUaWriteItemFactory::create()
+{
+ return OpcUaWriteItem();
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/imports/opcua/opcuawriteitem.h b/src/imports/opcua/opcuawriteitem.h
new file mode 100644
index 0000000..d238c61
--- /dev/null
+++ b/src/imports/opcua/opcuawriteitem.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPCUAWRITEITEM_H
+#define OPCUAWRITEITEM_H
+
+#include <QObject>
+#include <QDateTime>
+#include <QtCore/qshareddata.h>
+#include "opcuastatus.h"
+#include "qopcuatype.h"
+
+QT_BEGIN_NAMESPACE
+
+class OpcUaWriteItemData;
+class OpcUaWriteItem
+{
+ Q_GADGET
+ Q_PROPERTY(QString nodeId READ nodeId WRITE setNodeId)
+ Q_PROPERTY(QVariant ns READ namespaceIdentifier WRITE setNamespaceIdentifier)
+ Q_PROPERTY(QOpcUa::NodeAttribute attribute READ attribute WRITE setAttribute)
+ Q_PROPERTY(QString indexRange READ indexRange WRITE setIndexRange)
+ Q_PROPERTY(QVariant value READ value WRITE setValue)
+ Q_PROPERTY(QOpcUa::Types valueType READ valueType WRITE setValueType)
+ Q_PROPERTY(QDateTime sourceTimestamp READ sourceTimestamp WRITE setSourceTimestamp)
+ Q_PROPERTY(QDateTime serverTimestamp READ serverTimestamp WRITE setServerTimestamp)
+ Q_PROPERTY(OpcUaStatus::Status statusCode READ statusCode WRITE setStatusCode)
+
+public:
+ OpcUaWriteItem();
+ OpcUaWriteItem(const OpcUaWriteItem &other);
+ OpcUaWriteItem &operator=(const OpcUaWriteItem &rhs);
+ ~OpcUaWriteItem();
+
+ const QString &nodeId() const;
+ void setNodeId(const QString &nodeId);
+
+ const QVariant &namespaceIdentifier() const;
+ void setNamespaceIdentifier(const QVariant &namespaceIdentifier);
+
+ QOpcUa::NodeAttribute attribute() const;
+ void setAttribute(QOpcUa::NodeAttribute attribute);
+
+ const QString &indexRange() const;
+ void setIndexRange(const QString &indexRange);
+
+ const QVariant &value() const;
+ void setValue(const QVariant &value);
+
+ QOpcUa::Types valueType() const;
+ void setValueType(QOpcUa::Types type);
+
+ const QDateTime &sourceTimestamp() const;
+ void setSourceTimestamp(const QDateTime &sourceTimestamp);
+
+ const QDateTime &serverTimestamp() const;
+ void setServerTimestamp(const QDateTime &serverTimestamp);
+
+ OpcUaStatus::Status statusCode() const;
+ bool hasStatusCode() const;
+ void setStatusCode(OpcUaStatus::Status statusCode);
+
+private:
+ QSharedDataPointer<OpcUaWriteItemData> data;
+};
+
+class OpcUaWriteItemFactory : public QObject
+{
+ Q_OBJECT
+public:
+ Q_INVOKABLE OpcUaWriteItem create();
+};
+
+QT_END_NAMESPACE
+
+#endif // OPCUAWRITEITEM_H
diff --git a/src/imports/opcua/opcuawriteresult.cpp b/src/imports/opcua/opcuawriteresult.cpp
new file mode 100644
index 0000000..f7729e4
--- /dev/null
+++ b/src/imports/opcua/opcuawriteresult.cpp
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "opcuawriteresult.h"
+#include "universalnode.h"
+#include <QOpcUaWriteResult>
+#include <QOpcUaClient>
+#include <qopcuatype.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype WriteResult
+ \inqmlmodule QtOpcUa
+ \brief Contains result data after writing to the server.
+ \since QtOpcUa 5.13
+
+ This type is used to pass the results after writing to the server using the function
+ \l Connection::writeNodeAttributes.
+
+ \sa WriteItem
+*/
+
+/*!
+ \qmlproperty Constants.NodeAttribute WriteResult::attribute
+ \readonly
+
+ The node attribute of data that was written.
+*/
+
+/*!
+ \qmlproperty string WriteResult::indexRange
+ \readonly
+
+ The index range of the data that was written.
+*/
+
+/*!
+ \qmlproperty string WriteResult::nodeId
+ \readonly
+
+ The node id of the node that was written.
+*/
+
+/*!
+ \qmlproperty string WriteResult::namespaceName
+ \readonly
+
+ The namespace name of the node that was written.
+*/
+
+/*!
+ \qmlproperty Status WriteResult::status
+ \readonly
+
+ Result status of this WriteResult.
+ If the write request was successful the status is \l {Status::Status}
+ {Status.Good}.
+*/
+
+class OpcUaWriteResultData : public QSharedData
+{
+public:
+ OpcUaStatus status;
+ QOpcUa::NodeAttribute attribute;
+ QString indexRange;
+ QString nodeId;
+ QString namespaceName;
+};
+
+OpcUaWriteResult::OpcUaWriteResult()
+ : data(new OpcUaWriteResultData)
+{
+ data->attribute = QOpcUa::NodeAttribute::None;
+}
+
+OpcUaWriteResult::OpcUaWriteResult(const OpcUaWriteResult &other)
+ : data(other.data)
+{
+}
+
+OpcUaWriteResult::OpcUaWriteResult(const QOpcUaWriteResult &other, const QOpcUaClient *client)
+ : data(new OpcUaWriteResultData)
+{
+ data->status = OpcUaStatus(other.statusCode());
+ data->attribute = other.attribute();
+ data->indexRange = other.indexRange();
+
+ int namespaceIndex = -1;
+ UniversalNode::splitNodeIdAndNamespace(other.nodeId(), &namespaceIndex, &data->nodeId);
+ data->namespaceName = client->namespaceArray().at(namespaceIndex);
+}
+
+OpcUaWriteResult &OpcUaWriteResult::operator=(const OpcUaWriteResult &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+OpcUaWriteResult::~OpcUaWriteResult() = default;
+
+const QString &OpcUaWriteResult::indexRange() const
+{
+ return data->indexRange;
+}
+
+const QString &OpcUaWriteResult::nodeId() const
+{
+ return data->nodeId;
+}
+
+QOpcUa::NodeAttribute OpcUaWriteResult::attribute() const
+{
+ return data->attribute;
+}
+
+const QString &OpcUaWriteResult::namespaceName() const
+{
+ return data->namespaceName;
+}
+
+OpcUaStatus OpcUaWriteResult::status() const
+{
+ return data->status;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/imports/opcua/opcuawriteresult.h b/src/imports/opcua/opcuawriteresult.h
new file mode 100644
index 0000000..d34e95b
--- /dev/null
+++ b/src/imports/opcua/opcuawriteresult.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPCUAWRITERESULT_H
+#define OPCUAWRITERESULT_H
+
+#include <QObject>
+#include <QDateTime>
+#include "qopcuatype.h"
+#include "opcuastatus.h"
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaWriteResult;
+class QOpcUaClient;
+class OpcUaWriteResultData;
+class OpcUaWriteResult
+{
+ Q_GADGET
+ Q_PROPERTY(QOpcUa::NodeAttribute attribute READ attribute)
+ Q_PROPERTY(QString indexRange READ indexRange)
+ Q_PROPERTY(QString nodeId READ nodeId)
+ Q_PROPERTY(QString namespaceName READ namespaceName)
+ Q_PROPERTY(OpcUaStatus status READ status)
+
+public:
+ OpcUaWriteResult();
+ OpcUaWriteResult(const OpcUaWriteResult &other);
+ OpcUaWriteResult(const QOpcUaWriteResult &other, const QOpcUaClient *client);
+ OpcUaWriteResult &operator=(const OpcUaWriteResult &rhs);
+ ~OpcUaWriteResult();
+
+ const QString &indexRange() const;
+ const QString &nodeId() const;
+ QOpcUa::NodeAttribute attribute() const;
+ const QString &namespaceName() const;
+
+ OpcUaStatus status() const;
+
+private:
+ QSharedDataPointer<OpcUaWriteResultData> data;
+};
+
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(OpcUaWriteResult)
+
+#endif // OPCUAWRITERESULT_H
diff --git a/src/imports/opcua/plugins.qmltypes b/src/imports/opcua/plugins.qmltypes
index 922280c..d087ba7 100644
--- a/src/imports/opcua/plugins.qmltypes
+++ b/src/imports/opcua/plugins.qmltypes
@@ -4,10 +4,10 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtOpcUa 5.12'
+// 'qmlplugindump -nonrelocatable QtOpcUa 5.13'
Module {
- dependencies: ["QtQuick 2.8"]
+ dependencies: ["QtQuick 2.12"]
Component {
name: "Constants"
exports: ["QtOpcUa/Constants 5.12"]
@@ -24,9 +24,14 @@ Module {
Property { name: "backend"; type: "string" }
Property { name: "defaultConnection"; type: "bool" }
Property { name: "namespaces"; type: "QStringList"; isReadonly: true }
+ Property { name: "authenticationInformation"; type: "QOpcUaAuthenticationInformation" }
+ Signal {
+ name: "readNodeAttributesFinished"
+ Parameter { name: "value"; type: "QVariant" }
+ }
Method {
name: "connectToEndpoint"
- Parameter { name: "url"; type: "QUrl" }
+ Parameter { name: "endpointDescription"; type: "QOpcUaEndpointDescription" }
}
Method { name: "disconnectFromEndpoint" }
Method {
@@ -34,6 +39,55 @@ Module {
Parameter { name: "defaultConnection"; type: "bool" }
}
Method { name: "setDefaultConnection" }
+ Method {
+ name: "setAuthenticationInformation"
+ Parameter { name: "authenticationInformation"; type: "QOpcUaAuthenticationInformation" }
+ }
+ Method {
+ name: "readNodeAttributes"
+ type: "bool"
+ Parameter { name: "value"; type: "QJSValue" }
+ }
+ }
+ Component {
+ name: "OpcUaEndpointDiscovery"
+ prototype: "QObject"
+ exports: ["QtOpcUa/EndpointDiscovery 5.13"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "serverUrl"; type: "string" }
+ Property { name: "count"; type: "int"; isReadonly: true }
+ Property { name: "status"; type: "OpcUaStatus"; isReadonly: true }
+ Property { name: "connection"; type: "OpcUaConnection"; isPointer: true }
+ Signal {
+ name: "serverUrlChanged"
+ Parameter { name: "serverUrl"; type: "string" }
+ }
+ Signal { name: "endpointsChanged" }
+ Signal {
+ name: "connectionChanged"
+ Parameter { type: "OpcUaConnection"; isPointer: true }
+ }
+ Method {
+ name: "at"
+ type: "QOpcUaEndpointDescription"
+ Parameter { name: "row"; type: "int" }
+ }
+ }
+ Component {
+ name: "OpcUaMethodArgument"
+ prototype: "QObject"
+ exports: ["QtOpcUa/MethodArgument 5.13"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "value"; type: "QVariant" }
+ Property { name: "type"; type: "QOpcUa::Types" }
+ Method {
+ name: "setValue"
+ Parameter { name: "value"; type: "QVariant" }
+ }
+ Method {
+ name: "setType"
+ Parameter { name: "type"; type: "QOpcUa::Types" }
+ }
}
Component {
name: "OpcUaMethodNode"
@@ -41,6 +95,13 @@ Module {
exports: ["QtOpcUa/MethodNode 5.12"]
exportMetaObjectRevisions: [0]
Property { name: "objectNodeId"; type: "OpcUaNodeIdType"; isPointer: true }
+ Property { name: "inputArguments"; type: "OpcUaMethodArgument"; isList: true; isReadonly: true }
+ Property { name: "outputArguments"; type: "QVariantList"; isReadonly: true }
+ Property { name: "resultStatus"; type: "OpcUaStatus"; isReadonly: true }
+ Signal {
+ name: "resultStatusChanged"
+ Parameter { name: "status"; type: "OpcUaStatus" }
+ }
Method {
name: "setObjectNodeId"
Parameter { name: "nodeId"; type: "OpcUaNodeIdType"; isPointer: true }
@@ -52,13 +113,29 @@ Module {
prototype: "QObject"
exports: ["QtOpcUa/Node 5.12"]
exportMetaObjectRevisions: [0]
+ Enum {
+ name: "Status"
+ values: {
+ "Valid": 0,
+ "InvalidNodeId": 1,
+ "NoConnection": 2,
+ "InvalidNodeType": 3,
+ "InvalidClient": 4,
+ "FailedToResolveNode": 5,
+ "InvalidObjectNode": 6,
+ "FailedToReadAttributes": 7,
+ "FailedToSetupMonitoring": 8
+ }
+ }
Property { name: "nodeId"; type: "OpcUaNodeIdType"; isPointer: true }
Property { name: "connection"; type: "OpcUaConnection"; isPointer: true }
Property { name: "readyToUse"; type: "bool"; isReadonly: true }
+ Property { name: "status"; type: "OpcUaNode::Status"; isReadonly: true }
+ Property { name: "errorMessage"; type: "string"; isReadonly: true }
Property { name: "browseName"; type: "string" }
Property { name: "nodeClass"; type: "QOpcUa::NodeClass"; isReadonly: true }
- Property { name: "displayName"; type: "QOpcUa::QLocalizedText" }
- Property { name: "description"; type: "QOpcUa::QLocalizedText" }
+ Property { name: "displayName"; type: "QOpcUaLocalizedText" }
+ Property { name: "description"; type: "QOpcUaLocalizedText" }
Signal {
name: "nodeIdChanged"
Parameter { name: "nodeId"; type: "const OpcUaNodeIdType"; isPointer: true }
@@ -76,6 +153,16 @@ Module {
name: "setConnection"
Parameter { type: "OpcUaConnection"; isPointer: true }
}
+ Method {
+ name: "getSourceTimestamp"
+ type: "QDateTime"
+ Parameter { type: "QOpcUa::NodeAttribute" }
+ }
+ Method {
+ name: "getServerTimestamp"
+ type: "QDateTime"
+ Parameter { type: "QOpcUa::NodeAttribute" }
+ }
}
Component {
name: "OpcUaNodeId"
@@ -111,6 +198,15 @@ Module {
Signal { name: "nodeChanged" }
}
Component {
+ name: "OpcUaReadItemFactory"
+ prototype: "QObject"
+ exports: ["QtOpcUa/ReadItem 5.13"]
+ isCreatable: false
+ isSingleton: true
+ exportMetaObjectRevisions: [0]
+ Method { name: "create"; type: "OpcUaReadItem" }
+ }
+ Component {
name: "OpcUaRelativeNodeId"
prototype: "OpcUaNodeIdType"
exports: ["QtOpcUa/RelativeNodeId 5.12"]
@@ -178,11 +274,275 @@ Module {
}
}
Component {
+ name: "OpcUaServerDiscovery"
+ prototype: "QStandardItemModel"
+ exports: ["QtOpcUa/ServerDiscovery 5.13"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "discoveryUrl"; type: "string" }
+ Property { name: "count"; type: "int"; isReadonly: true }
+ Property { name: "status"; type: "OpcUaStatus"; isReadonly: true }
+ Property { name: "connection"; type: "OpcUaConnection"; isPointer: true }
+ Signal { name: "serversChanged" }
+ Signal {
+ name: "connectionChanged"
+ Parameter { type: "OpcUaConnection"; isPointer: true }
+ }
+ Method {
+ name: "at"
+ type: "QOpcUaApplicationDescription"
+ Parameter { name: "row"; type: "int" }
+ }
+ }
+ Component {
+ name: "OpcUaStatus"
+ exports: ["QtOpcUa/Status 5.13"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "Status"
+ values: {
+ "Good": 0,
+ "BadUnexpectedError": 32769,
+ "BadInternalError": 32770,
+ "BadOutOfMemory": 32771,
+ "BadResourceUnavailable": 32772,
+ "BadCommunicationError": 32773,
+ "BadEncodingError": 32774,
+ "BadDecodingError": 32775,
+ "BadEncodingLimitsExceeded": 32776,
+ "BadRequestTooLarge": 32952,
+ "BadResponseTooLarge": 32953,
+ "BadUnknownResponse": 32777,
+ "BadTimeout": 32778,
+ "BadServiceUnsupported": 32779,
+ "BadShutdown": 32780,
+ "BadServerNotConnected": 32781,
+ "BadServerHalted": 32782,
+ "BadNothingToDo": 32783,
+ "BadTooManyOperations": 32784,
+ "BadTooManyMonitoredItems": 32987,
+ "BadDataTypeIdUnknown": 32785,
+ "BadCertificateInvalid": 32786,
+ "BadSecurityChecksFailed": 32787,
+ "BadCertificateTimeInvalid": 32788,
+ "BadCertificateIssuerTimeInvalid": 32789,
+ "BadCertificateHostNameInvalid": 32790,
+ "BadCertificateUriInvalid": 32791,
+ "BadCertificateUseNotAllowed": 32792,
+ "BadCertificateIssuerUseNotAllowed": 32793,
+ "BadCertificateUntrusted": 32794,
+ "BadCertificateRevocationUnknown": 32795,
+ "BadCertificateIssuerRevocationUnknown": 32796,
+ "BadCertificateRevoked": 32797,
+ "BadCertificateIssuerRevoked": 32798,
+ "BadCertificateChainIncomplete": 33037,
+ "BadUserAccessDenied": 32799,
+ "BadIdentityTokenInvalid": 32800,
+ "BadIdentityTokenRejected": 32801,
+ "BadSecureChannelIdInvalid": 32802,
+ "BadInvalidTimestamp": 32803,
+ "BadNonceInvalid": 32804,
+ "BadSessionIdInvalid": 32805,
+ "BadSessionClosed": 32806,
+ "BadSessionNotActivated": 32807,
+ "BadSubscriptionIdInvalid": 32808,
+ "BadRequestHeaderInvalid": 32810,
+ "BadTimestampsToReturnInvalid": 32811,
+ "BadRequestCancelledByClient": 32812,
+ "BadTooManyArguments": 32997,
+ "GoodSubscriptionTransferred": 45,
+ "GoodCompletesAsynchronously": 46,
+ "GoodOverload": 47,
+ "GoodClamped": 48,
+ "BadNoCommunication": 32817,
+ "BadWaitingForInitialData": 32818,
+ "BadNodeIdInvalid": 32819,
+ "BadNodeIdUnknown": 32820,
+ "BadAttributeIdInvalid": 32821,
+ "BadIndexRangeInvalid": 32822,
+ "BadIndexRangeNoData": 32823,
+ "BadDataEncodingInvalid": 32824,
+ "BadDataEncodingUnsupported": 32825,
+ "BadNotReadable": 32826,
+ "BadNotWritable": 32827,
+ "BadOutOfRange": 32828,
+ "BadNotSupported": 32829,
+ "BadNotFound": 32830,
+ "BadObjectDeleted": 32831,
+ "BadNotImplemented": 32832,
+ "BadMonitoringModeInvalid": 32833,
+ "BadMonitoredItemIdInvalid": 32834,
+ "BadMonitoredItemFilterInvalid": 32835,
+ "BadMonitoredItemFilterUnsupported": 32836,
+ "BadFilterNotAllowed": 32837,
+ "BadStructureMissing": 32838,
+ "BadEventFilterInvalid": 32839,
+ "BadContentFilterInvalid": 32840,
+ "BadFilterOperatorInvalid": 32961,
+ "BadFilterOperatorUnsupported": 32962,
+ "BadFilterOperandCountMismatch": 32963,
+ "BadFilterOperandInvalid": 32841,
+ "BadFilterElementInvalid": 32964,
+ "BadFilterLiteralInvalid": 32965,
+ "BadContinuationPointInvalid": 32842,
+ "BadNoContinuationPoints": 32843,
+ "BadReferenceTypeIdInvalid": 32844,
+ "BadBrowseDirectionInvalid": 32845,
+ "BadNodeNotInView": 32846,
+ "BadServerUriInvalid": 32847,
+ "BadServerNameMissing": 32848,
+ "BadDiscoveryUrlMissing": 32849,
+ "BadSempahoreFileMissing": 32850,
+ "BadRequestTypeInvalid": 32851,
+ "BadSecurityModeRejected": 32852,
+ "BadSecurityPolicyRejected": 32853,
+ "BadTooManySessions": 32854,
+ "BadUserSignatureInvalid": 32855,
+ "BadApplicationSignatureInvalid": 32856,
+ "BadNoValidCertificates": 32857,
+ "BadIdentityChangeNotSupported": 32966,
+ "BadRequestCancelledByRequest": 32858,
+ "BadParentNodeIdInvalid": 32859,
+ "BadReferenceNotAllowed": 32860,
+ "BadNodeIdRejected": 32861,
+ "BadNodeIdExists": 32862,
+ "BadNodeClassInvalid": 32863,
+ "BadBrowseNameInvalid": 32864,
+ "BadBrowseNameDuplicated": 32865,
+ "BadNodeAttributesInvalid": 32866,
+ "BadTypeDefinitionInvalid": 32867,
+ "BadSourceNodeIdInvalid": 32868,
+ "BadTargetNodeIdInvalid": 32869,
+ "BadDuplicateReferenceNotAllowed": 32870,
+ "BadInvalidSelfReference": 32871,
+ "BadReferenceLocalOnly": 32872,
+ "BadNoDeleteRights": 32873,
+ "UncertainReferenceNotDeleted": 16572,
+ "BadServerIndexInvalid": 32874,
+ "BadViewIdUnknown": 32875,
+ "BadViewTimestampInvalid": 32969,
+ "BadViewParameterMismatch": 32970,
+ "BadViewVersionInvalid": 32971,
+ "UncertainNotAllNodesAvailable": 16576,
+ "GoodResultsMayBeIncomplete": 186,
+ "BadNotTypeDefinition": 32968,
+ "UncertainReferenceOutOfServer": 16492,
+ "BadTooManyMatches": 32877,
+ "BadQueryTooComplex": 32878,
+ "BadNoMatch": 32879,
+ "BadMaxAgeInvalid": 32880,
+ "BadSecurityModeInsufficient": 32998,
+ "BadHistoryOperationInvalid": 32881,
+ "BadHistoryOperationUnsupported": 32882,
+ "BadInvalidTimestampArgument": 32957,
+ "BadWriteNotSupported": 32883,
+ "BadTypeMismatch": 32884,
+ "BadMethodInvalid": 32885,
+ "BadArgumentsMissing": 32886,
+ "BadTooManySubscriptions": 32887,
+ "BadTooManyPublishRequests": 32888,
+ "BadNoSubscription": 32889,
+ "BadSequenceNumberUnknown": 32890,
+ "BadMessageNotAvailable": 32891,
+ "BadInsufficientClientProfile": 32892,
+ "BadStateNotActive": 32959,
+ "BadTcpServerTooBusy": 32893,
+ "BadTcpMessageTypeInvalid": 32894,
+ "BadTcpSecureChannelUnknown": 32895,
+ "BadTcpMessageTooLarge": 32896,
+ "BadTcpNotEnoughResources": 32897,
+ "BadTcpInternalError": 32898,
+ "BadTcpEndpointUrlInvalid": 32899,
+ "BadRequestInterrupted": 32900,
+ "BadRequestTimeout": 32901,
+ "BadSecureChannelClosed": 32902,
+ "BadSecureChannelTokenUnknown": 32903,
+ "BadSequenceNumberInvalid": 32904,
+ "BadProtocolVersionUnsupported": 32958,
+ "BadConfigurationError": 32905,
+ "BadNotConnected": 32906,
+ "BadDeviceFailure": 32907,
+ "BadSensorFailure": 32908,
+ "BadOutOfService": 32909,
+ "BadDeadbandFilterInvalid": 32910,
+ "UncertainNoCommunicationLastUsableValue": 16527,
+ "UncertainLastUsableValue": 16528,
+ "UncertainSubstituteValue": 16529,
+ "UncertainInitialValue": 16530,
+ "UncertainSensorNotAccurate": 16531,
+ "UncertainEngineeringUnitsExceeded": 16532,
+ "UncertainSubNormal": 16533,
+ "GoodLocalOverride": 150,
+ "BadRefreshInProgress": 32919,
+ "BadConditionAlreadyDisabled": 32920,
+ "BadConditionAlreadyEnabled": 32972,
+ "BadConditionDisabled": 32921,
+ "BadEventIdUnknown": 32922,
+ "BadEventNotAcknowledgeable": 32955,
+ "BadDialogNotActive": 32973,
+ "BadDialogResponseInvalid": 32974,
+ "BadConditionBranchAlreadyAcked": 32975,
+ "BadConditionBranchAlreadyConfirmed": 32976,
+ "BadConditionAlreadyShelved": 32977,
+ "BadConditionNotShelved": 32978,
+ "BadShelvingTimeOutOfRange": 32979,
+ "BadNoData": 32923,
+ "BadBoundNotFound": 32983,
+ "BadBoundNotSupported": 32984,
+ "BadDataLost": 32925,
+ "BadDataUnavailable": 32926,
+ "BadEntryExists": 32927,
+ "BadNoEntryExists": 32928,
+ "BadTimestampNotSupported": 32929,
+ "GoodEntryInserted": 162,
+ "GoodEntryReplaced": 163,
+ "UncertainDataSubNormal": 16548,
+ "GoodNoData": 165,
+ "GoodMoreData": 166,
+ "BadAggregateListMismatch": 32980,
+ "BadAggregateNotSupported": 32981,
+ "BadAggregateInvalidInputs": 32982,
+ "BadAggregateConfigurationRejected": 32986,
+ "GoodDataIgnored": 217,
+ "BadRequestNotAllowed": 32996,
+ "GoodEdited": 220,
+ "GoodPostActionFailed": 221,
+ "UncertainDominantValueChanged": 16606,
+ "GoodDependentValueChanged": 224,
+ "BadDominantValueChanged": 32993,
+ "UncertainDependentValueChanged": 16610,
+ "BadDependentValueChanged": 32995,
+ "GoodCommunicationEvent": 167,
+ "GoodShutdownEvent": 168,
+ "GoodCallAgain": 169,
+ "GoodNonCriticalTimeout": 170,
+ "BadInvalidArgument": 32939,
+ "BadConnectionRejected": 32940,
+ "BadDisconnect": 32941,
+ "BadConnectionClosed": 32942,
+ "BadInvalidState": 32943,
+ "BadEndOfStream": 32944,
+ "BadNoDataAvailable": 32945,
+ "BadWaitingForResponse": 32946,
+ "BadOperationAbandoned": 32947,
+ "BadExpectedStreamToBlock": 32948,
+ "BadWouldBlock": 32949,
+ "BadSyntaxError": 32950,
+ "BadMaxConnectionsReached": 32951
+ }
+ }
+ Property { name: "isGood"; type: "bool"; isReadonly: true }
+ Property { name: "isBad"; type: "bool"; isReadonly: true }
+ Property { name: "status"; type: "Status"; isReadonly: true }
+ }
+ Component {
name: "OpcUaValueNode"
prototype: "OpcUaNode"
exports: ["QtOpcUa/ValueNode 5.12"]
exportMetaObjectRevisions: [0]
Property { name: "value"; type: "QVariant" }
+ Property { name: "serverTimestamp"; type: "QDateTime"; isReadonly: true }
+ Property { name: "sourceTimestamp"; type: "QDateTime"; isReadonly: true }
Signal {
name: "valueChanged"
Parameter { name: "value"; type: "QVariant" }
@@ -192,4 +552,39 @@ Module {
Parameter { type: "QVariant" }
}
}
+ Component {
+ name: "QOpcUaApplicationDescription"
+ exports: ["QtOpcUa/ApplicationDescription 5.13"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "ApplicationType"
+ values: {
+ "Server": 0,
+ "Client": 1,
+ "ClientAndServer": 2,
+ "DiscoveryServer": 3
+ }
+ }
+ Property { name: "applicationUri"; type: "string"; isReadonly: true }
+ Property { name: "productUri"; type: "string"; isReadonly: true }
+ Property { name: "applicationName"; type: "QOpcUaLocalizedText"; isReadonly: true }
+ Property {
+ name: "applicationType"
+ type: "QOpcUaApplicationDescription::ApplicationType"
+ isReadonly: true
+ }
+ Property { name: "gatewayServerUri"; type: "string"; isReadonly: true }
+ Property { name: "discoveryProfileUri"; type: "string"; isReadonly: true }
+ Property { name: "discoveryUrls"; type: "QVector<QString>"; isReadonly: true }
+ }
+ Component {
+ name: "QStandardItemModel"
+ prototype: "QAbstractItemModel"
+ Property { name: "sortRole"; type: "int" }
+ Signal {
+ name: "itemChanged"
+ Parameter { name: "item"; type: "QStandardItem"; isPointer: true }
+ }
+ }
}
diff --git a/src/imports/opcua/universalnode.cpp b/src/imports/opcua/universalnode.cpp
index a56700c..90697f4 100644
--- a/src/imports/opcua/universalnode.cpp
+++ b/src/imports/opcua/universalnode.cpp
@@ -161,25 +161,35 @@ void UniversalNode::resolveNamespaceNameToIndex(QOpcUaClient *client)
if (m_namespaceIndexValid)
return; // Namespace index already resolved, nothing to do
+ int index = resolveNamespaceNameToIndex(m_namespaceName, client);
+ if (index < 0) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Could not resolve namespace for node" << (m_nodeIdentifier.isEmpty() ? QString() : (QString("(") + m_nodeIdentifier + ")"));
+ return;
+ }
+ setMembers(true, index, true, m_namespaceName, false, QString());
+}
+
+int UniversalNode::resolveNamespaceNameToIndex(const QString &namespaceName, QOpcUaClient *client)
+{
const auto namespaceArray = client->namespaceArray();
if (!namespaceArray.size()) {
qCWarning(QT_OPCUA_PLUGINS_QML) << "Namespaces table missing, unable to resolve namespace name.";
- return;
+ return -1;
}
- if (m_namespaceName.isEmpty()) {
- qCWarning(QT_OPCUA_PLUGINS_QML) << "Could not resolve namespace: Namespace name is empty" << (m_nodeIdentifier.isEmpty() ? QString() : (QString("(") + m_nodeIdentifier + ")"));
- return;
+ if (namespaceName.isEmpty()) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Could not resolve namespace: Namespace name is empty";
+ return -1;
}
- int index = namespaceArray.indexOf(m_namespaceName);
+ int index = namespaceArray.indexOf(namespaceName);
if (index < 0) {
- qCWarning(QT_OPCUA_PLUGINS_QML) << "Could not resolve namespace: Namespace" << m_namespaceName << "not found in" << namespaceArray;
- return;
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Could not resolve namespace: Namespace" << namespaceName << "not found in" << namespaceArray;
+ return -1;
}
- setMembers(true, index, true, m_namespaceName, false, QString());
+ return index;
}
bool UniversalNode::isNamespaceNameValid() const
@@ -192,12 +202,12 @@ bool UniversalNode::isNamespaceIndexValid() const
return m_namespaceIndexValid;
}
-QOpcUa::QQualifiedName UniversalNode::toQualifiedName() const
+QOpcUaQualifiedName UniversalNode::toQualifiedName() const
{
- QOpcUa::QQualifiedName qualifiedName;
+ QOpcUaQualifiedName qualifiedName;
if (!m_namespaceIndexValid || m_nodeIdentifier.isEmpty()) {
- qCWarning(QT_OPCUA_PLUGINS_QML) << "Insufficient information to create a QQualifiedName";
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Insufficient information to create a QOpcUaQualifiedName";
return qualifiedName;
}
@@ -206,12 +216,12 @@ QOpcUa::QQualifiedName UniversalNode::toQualifiedName() const
return qualifiedName;
}
-QOpcUa::QExpandedNodeId UniversalNode::toExpandedNodeId() const
+QOpcUaExpandedNodeId UniversalNode::toExpandedNodeId() const
{
- QOpcUa::QExpandedNodeId expandedNodeId;
+ QOpcUaExpandedNodeId expandedNodeId;
if (m_namespaceName.isEmpty() || m_nodeIdentifier.isEmpty()) {
- qCWarning(QT_OPCUA_PLUGINS_QML) << "Insufficient information to create a QExpandedNodeId";
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Insufficient information to create a QOpcUaExpandedNodeId";
return expandedNodeId;
}
@@ -221,17 +231,17 @@ QOpcUa::QExpandedNodeId UniversalNode::toExpandedNodeId() const
return expandedNodeId;
}
-void UniversalNode::from(const QOpcUa::QQualifiedName &qualifiedName)
+void UniversalNode::from(const QOpcUaQualifiedName &qualifiedName)
{
setMembers(true, qualifiedName.namespaceIndex(), false, QString(), true, qualifiedName.name());
}
-void UniversalNode::from(const QOpcUa::QExpandedNodeId &expandedNodeId)
+void UniversalNode::from(const QOpcUaExpandedNodeId &expandedNodeId)
{
setMembers(false, 0, true, expandedNodeId.namespaceUri(), true, expandedNodeId.nodeId());
}
-void UniversalNode::from(const QOpcUa::QBrowsePathTarget &browsePathTarget)
+void UniversalNode::from(const QOpcUaBrowsePathTarget &browsePathTarget)
{
// QExpandedNodeId is too unreliable and needs some casehandling around it to get a common information
int index = 0;
@@ -274,7 +284,7 @@ QString UniversalNode::fullNodeId() const
return QString();
}
- return QString("ns=%1;%2").arg(m_namespaceIndex).arg(m_nodeIdentifier);
+ return createNodeString(m_namespaceIndex, m_nodeIdentifier);
}
QOpcUaNode *UniversalNode::createNode(QOpcUaClient *client)
@@ -343,6 +353,13 @@ void UniversalNode::setMembers(bool setNamespaceIndex, quint16 namespaceIndex,
}
}
+/*
+ This function splits up a node identifier into namespace index and node name.
+ Returns true if successful, otherwise false.
+
+ When passing \nullptr as pointer argument, the assignment of results to that
+ pointer will be skipped.
+ */
bool UniversalNode::splitNodeIdAndNamespace(const QString nodeIdentifier, int *namespaceIndex, QString *identifier)
{
if (nodeIdentifier.startsWith(QLatin1String("ns="))) {
@@ -354,12 +371,14 @@ bool UniversalNode::splitNodeIdAndNamespace(const QString nodeIdentifier, int *n
const QString ns = token[0].mid(3);
bool ok;
- *namespaceIndex = ns.toUInt(&ok);
+ if (namespaceIndex)
+ *namespaceIndex = ns.toUInt(&ok);
if (!ok) {
qCWarning(QT_OPCUA_PLUGINS_QML) << "Namespace index is not a number:" << nodeIdentifier;
return false;
}
- *identifier = token[1];
+ if (identifier)
+ *identifier = token[1];
return true;
}
return false;
@@ -373,4 +392,26 @@ bool UniversalNode::operator==(const UniversalNode &rhs) const
this->m_namespaceIndexValid == rhs.m_namespaceIndexValid;
}
+/*
+ Constructs a full node id string out of id and namespace.
+ A string based namespace will be preferred and resolved.
+*/
+QString UniversalNode::resolveNamespaceToNode(const QString &nodeId, const QString &namespaceName, QOpcUaClient *client)
+{
+ int namespaceIndex = 0;
+ QString identifier;
+
+ if (!splitNodeIdAndNamespace(nodeId, &namespaceIndex, &identifier)) {
+ // Splitting of node id failed. Consider the whole node id as name.
+ identifier = nodeId;
+ }
+
+ if (!namespaceName.isEmpty()) {
+ namespaceIndex = resolveNamespaceNameToIndex(namespaceName, client);
+ if (namespaceIndex < 0)
+ return QString();
+ }
+ return createNodeString(namespaceIndex, identifier);
+}
+
QT_END_NAMESPACE
diff --git a/src/imports/opcua/universalnode.h b/src/imports/opcua/universalnode.h
index 0db4c9d..4772600 100644
--- a/src/imports/opcua/universalnode.h
+++ b/src/imports/opcua/universalnode.h
@@ -37,12 +37,15 @@
#pragma once
#include <QObject>
-#include "qopcuatype.h"
QT_BEGIN_NAMESPACE
class QOpcUaClient;
class QOpcUaNode;
+class QOpcUaQualifiedName;
+class QOpcUaExpandedNodeId;
+class QOpcUaBrowsePathTarget;
+class QOpcUaLocalizedText;
class OpcUaNodeIdType;
class UniversalNode : public QObject
@@ -73,14 +76,15 @@ public:
void resolveNamespaceIndexToName(QOpcUaClient *client);
void resolveNamespaceNameToIndex(QOpcUaClient *client);
void resolveNamespace(QOpcUaClient *client);
+ static int resolveNamespaceNameToIndex(const QString &namespaceName, QOpcUaClient *client);
- QOpcUa::QQualifiedName toQualifiedName() const;
- void from(const QOpcUa::QQualifiedName &qualifiedName);
+ QOpcUaQualifiedName toQualifiedName() const;
+ void from(const QOpcUaQualifiedName &qualifiedName);
- QOpcUa::QExpandedNodeId toExpandedNodeId() const;
- void from(const QOpcUa::QExpandedNodeId &expandedNodeId);
+ QOpcUaExpandedNodeId toExpandedNodeId() const;
+ void from(const QOpcUaExpandedNodeId &expandedNodeId);
- void from(const QOpcUa::QBrowsePathTarget &browsePathTarget);
+ void from(const QOpcUaBrowsePathTarget &browsePathTarget);
void from(const OpcUaNodeIdType &);
void from(const OpcUaNodeIdType *);
void from(const UniversalNode &);
@@ -91,6 +95,12 @@ public:
UniversalNode& operator=(const UniversalNode&);
bool operator==(const UniversalNode &rhs) const;
+ static QString resolveNamespaceToNode(const QString &nodeId, const QString &namespaceName, QOpcUaClient *client);
+ inline static QString createNodeString(int namespaceIndex, const QString &nodeIdentifier) {
+ return QString("ns=%1;%2").arg(namespaceIndex).arg(nodeIdentifier);
+ }
+ static bool splitNodeIdAndNamespace(const QString nodeIdentifier, int *namespaceIndex, QString *identifier);
+
signals:
void namespaceNameChanged(const QString &);
void namespaceIndexChanged(quint16);
@@ -102,7 +112,6 @@ private:
void setMembers(bool setNamespaceIndex, quint16 namespaceIndex,
bool setNamespaceName, const QString &namespaceName,
bool setNodeIdentifier, const QString &nodeIdentifier);
- bool splitNodeIdAndNamespace(const QString nodeIdentifier, int *namespaceIndex, QString *identifier);
QString m_namespaceName;
QString m_nodeIdentifier;
diff --git a/src/opcua/client/client.pri b/src/opcua/client/client.pri
index c6167d3..2363ee1 100644
--- a/src/opcua/client/client.pri
+++ b/src/opcua/client/client.pri
@@ -3,48 +3,106 @@
PUBLIC_HEADERS += \
client/qopcuaclient.h \
client/qopcuanode.h \
+ client/qopcuaapplicationidentity.h \
+ client/qopcuapkiconfiguration.h \
client/qopcuatype.h
SOURCES += \
+ client/qopcuaaddnodeitem.cpp \
+ client/qopcuaaddreferenceitem.cpp \
+ client/qopcuaapplicationdescription.cpp \
+ client/qopcuaapplicationidentity.cpp \
+ client/qopcuaargument.cpp \
+ client/qopcuaattributeoperand.cpp \
+ client/qopcuaauthenticationinformation.cpp \
+ client/qopcuaaxisinformation.cpp \
+ client/qopcuabackend.cpp \
+ client/qopcuabinarydataencoding.cpp \
+ client/qopcuabrowsepathtarget.cpp \
+ client/qopcuabrowserequest.cpp \
client/qopcuaclient.cpp \
- client/qopcuanode.cpp \
- client/qopcuatype.cpp \
client/qopcuaclientimpl.cpp \
- client/qopcuanodeimpl.cpp \
client/qopcuaclientprivate.cpp \
- client/qopcuabackend.cpp \
+ client/qopcuacomplexnumber.cpp \
+ client/qopcuacontentfilterelement.cpp \
+ client/qopcuacontentfilterelementresult.cpp \
+ client/qopcuadeletereferenceitem.cpp \
+ client/qopcuadoublecomplexnumber.cpp \
+ client/qopcuaelementoperand.cpp \
+ client/qopcuaendpointdescription.cpp \
+ client/qopcuaerrorstate.cpp \
+ client/qopcuaeuinformation.cpp \
+ client/qopcuaeventfilterresult.cpp \
+ client/qopcuaexpandednodeid.cpp \
+ client/qopcuaextensionobject.cpp \
+ client/qopcualiteraloperand.cpp \
+ client/qopcualocalizedtext.cpp \
client/qopcuamonitoringparameters.cpp \
- client/qopcuabinarydataencoding.cpp \
- client/qopcuabrowserequest.cpp \
- client/qopcuareferencedescription.cpp \
+ client/qopcuamultidimensionalarray.cpp \
+ client/qopcuanode.cpp \
+ client/qopcuanodecreationattributes.cpp \
+ client/qopcuanodeids.cpp \
+ client/qopcuanodeimpl.cpp \
+ client/qopcuapkiconfiguration.cpp \
+ client/qopcuaqualifiedname.cpp \
+ client/qopcuarange.cpp \
client/qopcuareaditem.cpp \
client/qopcuareadresult.cpp \
- client/qopcuanodeids.cpp \
+ client/qopcuareferencedescription.cpp \
+ client/qopcuarelativepathelement.cpp \
+ client/qopcuasimpleattributeoperand.cpp \
+ client/qopcuatype.cpp \
+ client/qopcuausertokenpolicy.cpp \
client/qopcuawriteitem.cpp \
client/qopcuawriteresult.cpp \
- client/qopcuanodecreationattributes.cpp \
- client/qopcuaaddreferenceitem.cpp \
- client/qopcuadeletereferenceitem.cpp \
- client/qopcuaaddnodeitem.cpp
+ client/qopcuaxvalue.cpp \
HEADERS += \
+ client/qopcuaaddnodeitem.h \
+ client/qopcuaaddreferenceitem.h \
+ client/qopcuaapplicationdescription.h \
+ client/qopcuaapplicationidentity.h \
+ client/qopcuaargument.h \
+ client/qopcuaattributeoperand.h \
+ client/qopcuaauthenticationinformation.h \
+ client/qopcuaaxisinformation.h \
+ client/qopcuabackend_p.h \
+ client/qopcuabinarydataencoding.h \
+ client/qopcuabrowsepathtarget.h \
+ client/qopcuabrowserequest.h \
client/qopcuaclient_p.h \
client/qopcuaclientimpl_p.h \
- client/qopcuanode_p.h \
- client/qopcuanodeimpl_p.h \
- client/qopcuabackend_p.h \
+ client/qopcuacomplexnumber.h \
+ client/qopcuacontentfilterelement.h \
+ client/qopcuacontentfilterelementresult.h \
+ client/qopcuadeletereferenceitem.h \
+ client/qopcuadoublecomplexnumber.h \
+ client/qopcuaelementoperand.h \
+ client/qopcuaendpointdescription.h \
+ client/qopcuaerrorstate.h \
+ client/qopcuaeuinformation.h \
+ client/qopcuaeventfilterresult.h \
+ client/qopcuaexpandednodeid.h \
+ client/qopcuaextensionobject.h \
+ client/qopcualiteraloperand.h \
+ client/qopcualocalizedtext.h \
client/qopcuamonitoringparameters.h \
client/qopcuamonitoringparameters_p.h \
- client/qopcuabinarydataencoding.h \
- client/qopcuabrowserequest.h \
- client/qopcuareferencedescription.h \
+ client/qopcuamultidimensionalarray.h \
+ client/qopcuanode_p.h \
+ client/qopcuanodecreationattributes.h \
+ client/qopcuanodecreationattributes_p.h \
+ client/qopcuanodeids.h \
+ client/qopcuanodeimpl_p.h \
+ client/qopcuapkiconfiguration.h \
+ client/qopcuaqualifiedname.h \
+ client/qopcuarange.h \
client/qopcuareaditem.h \
client/qopcuareadresult.h \
- client/qopcuanodeids.h \
+ client/qopcuareferencedescription.h \
+ client/qopcuarelativepathelement.h \
+ client/qopcuasimpleattributeoperand.h \
+ client/qopcuausertokenpolicy.h \
client/qopcuawriteitem.h \
client/qopcuawriteresult.h \
- client/qopcuanodecreationattributes.h \
- client/qopcuanodecreationattributes_p.h \
- client/qopcuaaddnodeitem.h \
- client/qopcuaaddreferenceitem.h \
- client/qopcuadeletereferenceitem.h
+ client/qopcuaxvalue.h \
diff --git a/src/opcua/client/qopcuaaddnodeitem.cpp b/src/opcua/client/qopcuaaddnodeitem.cpp
index 62eea3e..ac08f08 100644
--- a/src/opcua/client/qopcuaaddnodeitem.cpp
+++ b/src/opcua/client/qopcuaaddnodeitem.cpp
@@ -50,13 +50,13 @@ QT_BEGIN_NAMESPACE
class QOpcUaAddNodeItemData : public QSharedData
{
public:
- QOpcUa::QExpandedNodeId parentNodeId;
+ QOpcUaExpandedNodeId parentNodeId;
QString referenceTypeId;
- QOpcUa::QExpandedNodeId requestedNewNodeId;
- QOpcUa::QQualifiedName browseName;
+ QOpcUaExpandedNodeId requestedNewNodeId;
+ QOpcUaQualifiedName browseName;
QOpcUa::NodeClass nodeClass {QOpcUa::NodeClass::Object};
QOpcUaNodeCreationAttributes nodeAttributes;
- QOpcUa::QExpandedNodeId typeDefinition;
+ QOpcUaExpandedNodeId typeDefinition;
};
QOpcUaAddNodeItem::QOpcUaAddNodeItem()
@@ -89,7 +89,7 @@ QOpcUaAddNodeItem::~QOpcUaAddNodeItem()
/*!
Returns the node id of the type definition node.
*/
-QOpcUa::QExpandedNodeId QOpcUaAddNodeItem::typeDefinition() const
+QOpcUaExpandedNodeId QOpcUaAddNodeItem::typeDefinition() const
{
return data->typeDefinition;
}
@@ -98,7 +98,7 @@ QOpcUa::QExpandedNodeId QOpcUaAddNodeItem::typeDefinition() const
Sets the node id of the type definition node to \a typeDefinition. This value shall be set if the node class
is not Object or Variable.
*/
-void QOpcUaAddNodeItem::setTypeDefinition(const QOpcUa::QExpandedNodeId &typeDefinition)
+void QOpcUaAddNodeItem::setTypeDefinition(const QOpcUaExpandedNodeId &typeDefinition)
{
data->typeDefinition = typeDefinition;
}
@@ -147,7 +147,7 @@ void QOpcUaAddNodeItem::setNodeClass(const QOpcUa::NodeClass &nodeClass)
/*!
Returns the browse name of the new node.
*/
-QOpcUa::QQualifiedName QOpcUaAddNodeItem::browseName() const
+QOpcUaQualifiedName QOpcUaAddNodeItem::browseName() const
{
return data->browseName;
}
@@ -155,7 +155,7 @@ QOpcUa::QQualifiedName QOpcUaAddNodeItem::browseName() const
/*!
Sets the browse name of the new node to \a browseName.
*/
-void QOpcUaAddNodeItem::setBrowseName(const QOpcUa::QQualifiedName &browseName)
+void QOpcUaAddNodeItem::setBrowseName(const QOpcUaQualifiedName &browseName)
{
data->browseName = browseName;
}
@@ -163,7 +163,7 @@ void QOpcUaAddNodeItem::setBrowseName(const QOpcUa::QQualifiedName &browseName)
/*!
Returns the requested new node id.
*/
-QOpcUa::QExpandedNodeId QOpcUaAddNodeItem::requestedNewNodeId() const
+QOpcUaExpandedNodeId QOpcUaAddNodeItem::requestedNewNodeId() const
{
return data->requestedNewNodeId;
}
@@ -171,7 +171,7 @@ QOpcUa::QExpandedNodeId QOpcUaAddNodeItem::requestedNewNodeId() const
/*!
Sets the requested new node id to \a requestedNewNodeId.
*/
-void QOpcUaAddNodeItem::setRequestedNewNodeId(const QOpcUa::QExpandedNodeId &requestedNewNodeId)
+void QOpcUaAddNodeItem::setRequestedNewNodeId(const QOpcUaExpandedNodeId &requestedNewNodeId)
{
data->requestedNewNodeId = requestedNewNodeId;
}
@@ -196,7 +196,7 @@ void QOpcUaAddNodeItem::setReferenceTypeId(const QString &referenceTypeId)
/*!
Returns the parent node id.
*/
-QOpcUa::QExpandedNodeId QOpcUaAddNodeItem::parentNodeId() const
+QOpcUaExpandedNodeId QOpcUaAddNodeItem::parentNodeId() const
{
return data->parentNodeId;
}
@@ -207,7 +207,7 @@ QOpcUa::QExpandedNodeId QOpcUaAddNodeItem::parentNodeId() const
\sa setReferenceTypeId()
*/
-void QOpcUaAddNodeItem::setParentNodeId(const QOpcUa::QExpandedNodeId &parentNodeId)
+void QOpcUaAddNodeItem::setParentNodeId(const QOpcUaExpandedNodeId &parentNodeId)
{
data->parentNodeId = parentNodeId;
}
diff --git a/src/opcua/client/qopcuaaddnodeitem.h b/src/opcua/client/qopcuaaddnodeitem.h
index 188dba7..e21023f 100644
--- a/src/opcua/client/qopcuaaddnodeitem.h
+++ b/src/opcua/client/qopcuaaddnodeitem.h
@@ -39,6 +39,8 @@
#include <QtOpcUa/qopcuanodecreationattributes.h>
#include <QtOpcUa/qopcuatype.h>
+#include <QtOpcUa/qopcuaexpandednodeid.h>
+#include <QtOpcUa/qopcuaqualifiedname.h>
QT_BEGIN_NAMESPACE
@@ -51,17 +53,17 @@ public:
QOpcUaAddNodeItem &operator=(const QOpcUaAddNodeItem &);
~QOpcUaAddNodeItem();
- QOpcUa::QExpandedNodeId parentNodeId() const;
- void setParentNodeId(const QOpcUa::QExpandedNodeId &parentNodeId);
+ QOpcUaExpandedNodeId parentNodeId() const;
+ void setParentNodeId(const QOpcUaExpandedNodeId &parentNodeId);
QString referenceTypeId() const;
void setReferenceTypeId(const QString &referenceTypeId);
- QOpcUa::QExpandedNodeId requestedNewNodeId() const;
- void setRequestedNewNodeId(const QOpcUa::QExpandedNodeId &requestedNewNodeId);
+ QOpcUaExpandedNodeId requestedNewNodeId() const;
+ void setRequestedNewNodeId(const QOpcUaExpandedNodeId &requestedNewNodeId);
- QOpcUa::QQualifiedName browseName() const;
- void setBrowseName(const QOpcUa::QQualifiedName &browseName);
+ QOpcUaQualifiedName browseName() const;
+ void setBrowseName(const QOpcUaQualifiedName &browseName);
QOpcUa::NodeClass nodeClass() const;
void setNodeClass(const QOpcUa::NodeClass &nodeClass);
@@ -70,8 +72,8 @@ public:
QOpcUaNodeCreationAttributes &nodeAttributesRef();
void setNodeAttributes(const QOpcUaNodeCreationAttributes &nodeAttributes);
- QOpcUa::QExpandedNodeId typeDefinition() const;
- void setTypeDefinition(const QOpcUa::QExpandedNodeId &typeDefinition);
+ QOpcUaExpandedNodeId typeDefinition() const;
+ void setTypeDefinition(const QOpcUaExpandedNodeId &typeDefinition);
private:
QSharedDataPointer<QOpcUaAddNodeItemData> data;
diff --git a/src/opcua/client/qopcuaaddreferenceitem.cpp b/src/opcua/client/qopcuaaddreferenceitem.cpp
index 3d01851..5927bc0 100644
--- a/src/opcua/client/qopcuaaddreferenceitem.cpp
+++ b/src/opcua/client/qopcuaaddreferenceitem.cpp
@@ -36,6 +36,7 @@
#include "qopcuanodecreationattributes.h"
#include "qopcuaaddreferenceitem.h"
+#include "qopcuaexpandednodeid.h"
QT_BEGIN_NAMESPACE
@@ -52,7 +53,7 @@ public:
QString sourceNodeId;
QString referenceTypeId;
bool isForwardReference {true};
- QOpcUa::QExpandedNodeId targetNodeId;
+ QOpcUaExpandedNodeId targetNodeId;
QOpcUa::NodeClass targetNodeClass {QOpcUa::NodeClass::Undefined};
QString targetServerUri;
};
@@ -122,7 +123,7 @@ void QOpcUaAddReferenceItem::setTargetServerUri(const QString &targetServerUri)
/*!
Returns the target node id.
*/
-QOpcUa::QExpandedNodeId QOpcUaAddReferenceItem::targetNodeId() const
+QOpcUaExpandedNodeId QOpcUaAddReferenceItem::targetNodeId() const
{
return data->targetNodeId;
}
@@ -130,7 +131,7 @@ QOpcUa::QExpandedNodeId QOpcUaAddReferenceItem::targetNodeId() const
/*!
Sets the node id of the target node to \a targetNodeId.
*/
-void QOpcUaAddReferenceItem::setTargetNodeId(const QOpcUa::QExpandedNodeId &targetNodeId)
+void QOpcUaAddReferenceItem::setTargetNodeId(const QOpcUaExpandedNodeId &targetNodeId)
{
data->targetNodeId = targetNodeId;
}
diff --git a/src/opcua/client/qopcuaaddreferenceitem.h b/src/opcua/client/qopcuaaddreferenceitem.h
index a3673de..ceedcba 100644
--- a/src/opcua/client/qopcuaaddreferenceitem.h
+++ b/src/opcua/client/qopcuaaddreferenceitem.h
@@ -40,8 +40,12 @@
#include <QtOpcUa/qopcuanodecreationattributes.h>
#include <QtOpcUa/qopcuatype.h>
+#include <QtCore/qshareddata.h>
+
QT_BEGIN_NAMESPACE
+class QOpcUaExpandedNodeId;
+
class QOpcUaAddReferenceItemData;
class Q_OPCUA_EXPORT QOpcUaAddReferenceItem
{
@@ -60,8 +64,8 @@ public:
bool isForwardReference() const;
void setIsForwardReference(bool isForwardReference);
- QOpcUa::QExpandedNodeId targetNodeId() const;
- void setTargetNodeId(const QOpcUa::QExpandedNodeId &targetNodeId);
+ QOpcUaExpandedNodeId targetNodeId() const;
+ void setTargetNodeId(const QOpcUaExpandedNodeId &targetNodeId);
QOpcUa::NodeClass targetNodeClass() const;
void setTargetNodeClass(QOpcUa::NodeClass targetNodeClass);
diff --git a/src/opcua/client/qopcuaapplicationdescription.cpp b/src/opcua/client/qopcuaapplicationdescription.cpp
new file mode 100644
index 0000000..a3d599c
--- /dev/null
+++ b/src/opcua/client/qopcuaapplicationdescription.cpp
@@ -0,0 +1,337 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuaapplicationdescription.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaApplicationDescription
+ \inmodule QtOpcUa
+ \brief The OPC UA ApplicationDescription.
+
+ The application description contains information about an OPC UA application.
+*/
+
+/*!
+ \qmltype ApplicationDescription
+ \inqmlmodule QtOpcUa
+ \brief The OPC UA ApplicationDescription.
+ \since QtOpcUa 5.13
+
+ The application description contains information about an OPC UA application.
+*/
+
+/*!
+ \enum QOpcUaApplicationDescription::ApplicationType
+
+ This enum type holds the application type.
+
+ \value Server This application is a server.
+ \value Client This application is a client.
+ \value ClientAndServer This application is a client and a server.
+ \value DiscoveryServer This application is a discovery server.
+*/
+
+/*!
+ \qmlproperty enumeration ApplicationDescription::ApplicationType
+
+ The application type.
+
+ \value Server This application is a server.
+ \value Client This application is a client.
+ \value ClientAndServer This application is a client and a server.
+ \value DiscoveryServer This application is a discovery server.
+*/
+
+/*!
+ \property QOpcUaApplicationDescription::applicationName
+
+ Name describing the application.
+ */
+
+/*!
+ \qmlproperty LocalizedText ApplicationDescription::applicationName
+
+ Name describing the application.
+ */
+
+/*!
+ \property QOpcUaApplicationDescription::applicationType
+
+ The application's type: server, client, both, or discovery server.
+ */
+
+/*!
+ \qmlproperty ApplicationType ApplicationDescription::applicationType
+
+ The application's type: server, client, both, or discovery server.
+ */
+
+/*!
+ \property QOpcUaApplicationDescription::applicationUri
+
+ The globally unique identifier for this application instance.
+ */
+
+/*!
+ \qmlproperty string ApplicationDescription::applicationUri
+
+ The globally unique identifier for this application instance.
+ */
+
+/*!
+ \property QOpcUaApplicationDescription::discoveryProfileUri
+
+ The URI of the supported discovery profile.
+ */
+
+/*!
+ \qmlproperty string ApplicationDescription::discoveryProfileUri
+
+ The URI of the supported discovery profile.
+ */
+
+/*!
+ \property QOpcUaApplicationDescription::discoveryUrls
+
+ A list of URLs of discovery endpoints.
+ */
+
+/*!
+ \qmlproperty list ApplicationDescription::discoveryUrls
+
+ A list of URLs of discovery endpoints.
+ */
+
+/*!
+ \property QOpcUaApplicationDescription::gatewayServerUri
+
+ The URI of the gateway server.
+ */
+
+/*!
+ \qmlproperty string ApplicationDescription::gatewayServerUri
+
+ The URI of the gateway server.
+ */
+
+/*!
+ \property QOpcUaApplicationDescription::productUri
+
+ The globally unique identifier for this product.
+ */
+
+/*!
+ \qmlproperty string ApplicationDescription::productUri
+
+ The globally unique identifier for this product.
+ */
+
+class QOpcUaApplicationDescriptionData : public QSharedData
+{
+public:
+ QString applicationUri;
+ QString productUri;
+ QOpcUaLocalizedText applicationName;
+ QOpcUaApplicationDescription::ApplicationType applicationType{QOpcUaApplicationDescription::ApplicationType::Server};
+ QString gatewayServerUri;
+ QString discoveryProfileUri;
+ QVector<QString> discoveryUrls;
+};
+
+QOpcUaApplicationDescription::QOpcUaApplicationDescription()
+ : data(new QOpcUaApplicationDescriptionData)
+{
+}
+
+/*!
+ Constructs an application description from \a other.
+*/
+QOpcUaApplicationDescription::QOpcUaApplicationDescription(const QOpcUaApplicationDescription &other)
+ : data(other.data)
+{
+}
+
+/*!
+ Sets the values from \a other in this application description.
+*/
+QOpcUaApplicationDescription &QOpcUaApplicationDescription::operator=(const QOpcUaApplicationDescription &other)
+{
+ this->data = other.data;
+ return *this;
+}
+
+/*!
+ Returns \c true if this application description has the same value as \a rhs.
+*/
+bool QOpcUaApplicationDescription::operator==(const QOpcUaApplicationDescription &rhs) const
+{
+ return rhs.productUri() == productUri() &&
+ rhs.discoveryUrls() == discoveryUrls() &&
+ rhs.applicationUri() == applicationUri() &&
+ rhs.applicationName() == applicationName() &&
+ rhs.applicationType() == applicationType() &&
+ rhs.gatewayServerUri() == gatewayServerUri() &&
+ rhs.discoveryProfileUri() == rhs.discoveryProfileUri();
+}
+
+QOpcUaApplicationDescription::~QOpcUaApplicationDescription()
+{
+}
+
+/*!
+ Returns a list of URLs of discovery endpoints.
+*/
+QVector<QString> QOpcUaApplicationDescription::discoveryUrls() const
+{
+ return data->discoveryUrls;
+}
+
+/*!
+ Returns a reference to a list of URLs of discovery endpoints.
+*/
+QVector<QString> &QOpcUaApplicationDescription::discoveryUrlsRef()
+{
+ return data->discoveryUrls;
+}
+
+/*!
+ Sets the discovery URLs to \a discoveryUrls.
+*/
+void QOpcUaApplicationDescription::setDiscoveryUrls(const QVector<QString> &discoveryUrls)
+{
+ data->discoveryUrls = discoveryUrls;
+}
+
+/*!
+ Returns the URI of the supported discovery profile.
+*/
+QString QOpcUaApplicationDescription::discoveryProfileUri() const
+{
+ return data->discoveryProfileUri;
+}
+
+/*!
+ Sets the discovery profile URI to \a discoveryProfileUri.
+*/
+void QOpcUaApplicationDescription::setDiscoveryProfileUri(const QString &discoveryProfileUri)
+{
+ data->discoveryProfileUri = discoveryProfileUri;
+}
+
+/*!
+ Returns the URI of the gateway server.
+*/
+QString QOpcUaApplicationDescription::gatewayServerUri() const
+{
+ return data->gatewayServerUri;
+}
+
+/*!
+ Sets the URI of the gateway server to \a gatewayServerUri.
+*/
+void QOpcUaApplicationDescription::setGatewayServerUri(const QString &gatewayServerUri)
+{
+ data->gatewayServerUri = gatewayServerUri;
+}
+
+/*!
+ Returns the application's type (server, client, both, discovery server).
+*/
+QOpcUaApplicationDescription::ApplicationType QOpcUaApplicationDescription::applicationType() const
+{
+ return data->applicationType;
+}
+
+/*!
+ Sets the application type to \a applicationType.
+*/
+void QOpcUaApplicationDescription::setApplicationType(ApplicationType applicationType)
+{
+ data->applicationType = applicationType;
+}
+
+/*!
+ Returns a name describing the application.
+*/
+QOpcUaLocalizedText QOpcUaApplicationDescription::applicationName() const
+{
+ return data->applicationName;
+}
+
+/*!
+ Sets the application name to \a applicationName.
+*/
+void QOpcUaApplicationDescription::setApplicationName(const QOpcUaLocalizedText &applicationName)
+{
+ data->applicationName = applicationName;
+}
+
+/*!
+ Returns the globally unique identifier for this product.
+*/
+QString QOpcUaApplicationDescription::productUri() const
+{
+ return data->productUri;
+}
+
+/*!
+ Sets the globally unique identifier for this product to \a productUri.
+*/
+void QOpcUaApplicationDescription::setProductUri(const QString &productUri)
+{
+ data->productUri = productUri;
+}
+
+/*!
+ Returns the globally unique identifier for this application instance.
+*/
+QString QOpcUaApplicationDescription::applicationUri() const
+{
+ return data->applicationUri;
+}
+
+/*!
+ Sets the globally unique identifier for this application instance to \a applicationUri.
+*/
+void QOpcUaApplicationDescription::setApplicationUri(const QString &applicationUri)
+{
+ data->applicationUri = applicationUri;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaapplicationdescription.h b/src/opcua/client/qopcuaapplicationdescription.h
new file mode 100644
index 0000000..5ffac0f
--- /dev/null
+++ b/src/opcua/client/qopcuaapplicationdescription.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAAPPLICATIONDESCRIPTION_H
+#define QOPCUAAPPLICATIONDESCRIPTION_H
+
+#include <QtOpcUa/qopcualocalizedtext.h>
+
+#include <QtOpcUa/qopcuaglobal.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaApplicationDescriptionData;
+class Q_OPCUA_EXPORT QOpcUaApplicationDescription
+{
+ Q_GADGET
+ Q_PROPERTY(QString applicationUri READ applicationUri)
+ Q_PROPERTY(QString productUri READ productUri)
+ Q_PROPERTY(QOpcUaLocalizedText applicationName READ applicationName)
+ Q_PROPERTY(QOpcUaApplicationDescription::ApplicationType applicationType READ applicationType)
+ Q_PROPERTY(QString gatewayServerUri READ gatewayServerUri)
+ Q_PROPERTY(QString discoveryProfileUri READ discoveryProfileUri)
+ Q_PROPERTY(QVector<QString> discoveryUrls READ discoveryUrls)
+
+public:
+ QOpcUaApplicationDescription();
+ QOpcUaApplicationDescription(const QOpcUaApplicationDescription &);
+ QOpcUaApplicationDescription &operator=(const QOpcUaApplicationDescription &);
+ bool operator==(const QOpcUaApplicationDescription &) const;
+ ~QOpcUaApplicationDescription();
+
+ enum ApplicationType {
+ Server = 0,
+ Client = 1,
+ ClientAndServer = 2,
+ DiscoveryServer = 3
+ };
+ Q_ENUM(ApplicationType)
+
+ QString applicationUri() const;
+ void setApplicationUri(const QString &applicationUri);
+
+ QString productUri() const;
+ void setProductUri(const QString &productUri);
+
+ QOpcUaLocalizedText applicationName() const;
+ void setApplicationName(const QOpcUaLocalizedText &applicationName);
+
+ QOpcUaApplicationDescription::ApplicationType applicationType() const;
+ void setApplicationType(QOpcUaApplicationDescription::ApplicationType applicationType);
+
+ QString gatewayServerUri() const;
+ void setGatewayServerUri(const QString &gatewayServerUri);
+
+ QString discoveryProfileUri() const;
+ void setDiscoveryProfileUri(const QString &discoveryProfileUri);
+
+ QVector<QString> discoveryUrls() const;
+ QVector<QString> &discoveryUrlsRef();
+ void setDiscoveryUrls(const QVector<QString> &discoveryUrls);
+
+private:
+ QSharedDataPointer<QOpcUaApplicationDescriptionData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaApplicationDescription)
+
+#endif // QOPCUAAPPLICATIONDESCRIPTION_H
diff --git a/src/opcua/client/qopcuaapplicationidentity.cpp b/src/opcua/client/qopcuaapplicationidentity.cpp
new file mode 100644
index 0000000..74b2bfe
--- /dev/null
+++ b/src/opcua/client/qopcuaapplicationidentity.cpp
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2018 Unified Automation GmbH
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuaapplicationidentity.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaApplicationIdentity
+ \inmodule QtOpcUa
+ \since QtOpcUa 5.13
+ \brief QOpcUaApplicationIdentity defines the identity of the application.
+
+ This class is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+
+ This info must be configured using \l QOpcUaClient::setApplicationIdentity.
+ The application identity can be set up manually or derived from a certificate.
+
+ \code
+ QOpcUaApplicationIdentity identity;
+
+ const QString applicationUri = QStringLiteral("urn:%1:%2:%3")
+ .arg(QHostInfo::localHostName())
+ .arg(QCoreApplication::organizationName())
+ .arg(QCoreApplication::applicationName());
+ const QString productUri = QStringLiteral("urn:%1:%2")
+ .arg(QCoreApplication::organizationName())
+ .arg(QCoreApplication::applicationName());
+
+ identity.setProductUri(QUrl::toPercentEncoding(productUri));
+ identity.setApplicationUri(QUrl::toPercentEncoding(applicationUri));
+ identity.setApplicationName(QCoreApplication::applicationName());
+ identity.setApplicationType(QOpcUaApplicationDescription::Client);
+
+ client->setApplicationIdentity(identity);
+ \endcode
+
+ In case your application authenticates using certificates the application identity has to match
+ the used certificate. In this case all information is extracted from the certificate given in the
+ PKI configuration.
+
+ \code
+ QOpcUaApplicationIdentity identity;
+ identity = pkiConfig.applicationIdentity();
+ \endcode
+*/
+
+class QOpcUaApplicationIdentityData : public QSharedData
+{
+public:
+ QOpcUaApplicationIdentityData() {}
+
+ QOpcUaApplicationDescription::ApplicationType m_applicationType
+ {QOpcUaApplicationDescription::ApplicationType::Client};
+ QString m_applicationUri;
+ QString m_applicationName;
+ QString m_productUri;
+};
+
+QOpcUaApplicationIdentity::QOpcUaApplicationIdentity()
+ : data(new QOpcUaApplicationIdentityData())
+{}
+
+QOpcUaApplicationIdentity::~QOpcUaApplicationIdentity()
+{}
+
+/*!
+ Constructs an application identity from \a other.
+*/
+QOpcUaApplicationIdentity::QOpcUaApplicationIdentity(const QOpcUaApplicationIdentity &other)
+ : data(other.data)
+{}
+
+/*!
+ Sets the values of \a rhs in this \l QOpcUaApplicationIdentity.
+*/
+QOpcUaApplicationIdentity &QOpcUaApplicationIdentity::operator=(const QOpcUaApplicationIdentity &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns the application's application URI.
+
+ This must be unique for each installation instance of the application and must match the ApplicationURI
+ in the application's certificate.
+*/
+QString QOpcUaApplicationIdentity::applicationUri() const
+{
+ return data->m_applicationUri;
+}
+
+/*!
+ Sets the applicationUri to \a value.
+
+ \sa setApplicationName()
+*/
+void QOpcUaApplicationIdentity::setApplicationUri(const QString &value)
+{
+ data->m_applicationUri = value;
+}
+
+/*!
+ Returns the human readable name of the application.
+ This does not need to be unique.
+*/
+QString QOpcUaApplicationIdentity::applicationName() const
+{
+ return data->m_applicationName;
+}
+
+/*!
+ Sets the application name to \a value.
+*/
+void QOpcUaApplicationIdentity::setApplicationName(const QString &value)
+{
+ data->m_applicationName = value;
+}
+
+/*!
+ Returns the application's productUri.
+
+ This uniquely identifies the product.
+*/
+QString QOpcUaApplicationIdentity::productUri() const
+{
+ return data->m_productUri;
+}
+
+/*!
+ Sets the productUri to \a value.
+*/
+void QOpcUaApplicationIdentity::setProductUri(const QString &value)
+{
+ data->m_productUri = value;
+}
+
+/*!
+ Returns the application's type.
+*/
+QOpcUaApplicationDescription::ApplicationType QOpcUaApplicationIdentity::applicationType() const
+{
+ return data->m_applicationType;
+}
+
+/*!
+ Sets the type of the application.
+ Client applications should set \a value to \l {QOpcUaApplicationDescription::Client}{Client}.
+
+ The default value is \l{QOpcUaApplicationDescription::Client}{Client}.
+*/
+void QOpcUaApplicationIdentity::setApplicationType(QOpcUaApplicationDescription::ApplicationType value)
+{
+ data->m_applicationType = value;
+}
+
+/*!
+ Returns true if the application identity contains valid data.
+*/
+bool QOpcUaApplicationIdentity::isValid() const
+{
+ return !data->m_applicationUri.isEmpty() &&
+ !data->m_applicationName.isEmpty() &&
+ !data->m_productUri.isEmpty();
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaapplicationidentity.h b/src/opcua/client/qopcuaapplicationidentity.h
new file mode 100644
index 0000000..fa9e524
--- /dev/null
+++ b/src/opcua/client/qopcuaapplicationidentity.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Unified Automation GmbH
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAAPPLICATIONIDENTITY_H
+#define QOPCUAAPPLICATIONIDENTITY_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qmetatype.h>
+#include <QtOpcUa/qopcuaapplicationdescription.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaApplicationIdentityData;
+
+class Q_OPCUA_EXPORT QOpcUaApplicationIdentity
+{
+public:
+ QOpcUaApplicationIdentity();
+ ~QOpcUaApplicationIdentity();
+ QOpcUaApplicationIdentity(const QOpcUaApplicationIdentity &other);
+ QOpcUaApplicationIdentity &operator=(const QOpcUaApplicationIdentity &rhs);
+
+ QString applicationUri() const;
+ void setApplicationUri(const QString &value);
+
+ QString applicationName() const;
+ void setApplicationName(const QString &value);
+
+ QString productUri() const;
+ void setProductUri(const QString &value);
+
+ QOpcUaApplicationDescription::ApplicationType applicationType() const;
+ void setApplicationType(QOpcUaApplicationDescription::ApplicationType value);
+
+ bool isValid() const;
+
+private:
+ QSharedDataPointer<QOpcUaApplicationIdentityData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaApplicationIdentity)
+
+#endif // QOPCUAAPPLICATIONIDENTITY_H
diff --git a/src/opcua/client/qopcuaargument.cpp b/src/opcua/client/qopcuaargument.cpp
new file mode 100644
index 0000000..65c803c
--- /dev/null
+++ b/src/opcua/client/qopcuaargument.cpp
@@ -0,0 +1,235 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuaargument.h"
+#include "qopcuatype.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaArgument
+ \inmodule QtOpcUa
+ \brief The OPC UA Argument type.
+
+ This is the Qt OPC UA representation for the Argument type defined in OPC-UA part 3, 8.6.
+
+ The Argument type is mainly used for the values of the InputArguments and OutputArguments properties
+ which describe the parameters and return values of method nodes.
+*/
+class QOpcUaArgumentData : public QSharedData
+{
+public:
+ QString name;
+ QString dataTypeId;
+ qint32 valueRank{-2};
+ QVector<quint32> arrayDimensions;
+ QOpcUaLocalizedText description;
+};
+
+QOpcUaArgument::QOpcUaArgument()
+ : data(new QOpcUaArgumentData)
+{
+}
+
+QOpcUaArgument::QOpcUaArgument(const QOpcUaArgument &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Constructs an argument with name \a name, data type id \a dataTypeId, value rank \a valueRank,
+ array dimensions \a arrayDimensions and description \a description.
+*/
+QOpcUaArgument::QOpcUaArgument(const QString &name, const QString &dataTypeId, qint32 valueRank,
+ const QVector<quint32> &arrayDimensions, const QOpcUaLocalizedText &description)
+ : data(new QOpcUaArgumentData)
+{
+ setName(name);
+ setDataTypeId(dataTypeId);
+ setValueRank(valueRank);
+ setArrayDimensions(arrayDimensions);
+ setDescription(description);
+}
+
+/*!
+ Sets the values from \a rhs in this argument.
+*/
+QOpcUaArgument &QOpcUaArgument::operator=(const QOpcUaArgument &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns true if this argument has the same value as \a other.
+*/
+bool QOpcUaArgument::operator==(const QOpcUaArgument &other) const
+{
+ return data->arrayDimensions == other.arrayDimensions() &&
+ QOpcUa::nodeIdEquals(data->dataTypeId, other.dataTypeId()) &&
+ data->description == other.description() &&
+ data->name == other.name() &&
+ data->valueRank == other.valueRank();
+}
+
+/*!
+ Converts this argument to \l QVariant.
+*/
+QOpcUaArgument::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+QOpcUaArgument::~QOpcUaArgument()
+{
+}
+
+/*!
+ Returns the name of the argument.
+*/
+QString QOpcUaArgument::name() const
+{
+ return data->name;
+}
+
+/*!
+ Sets the name of the argument to \a name.
+*/
+void QOpcUaArgument::setName(const QString &name)
+{
+ data->name = name;
+}
+
+/*!
+ Returns the data type node id of the argument.
+*/
+QString QOpcUaArgument::dataTypeId() const
+{
+ return data->dataTypeId;
+}
+
+/*!
+ Sets the data type node id of the argument to \a dataTypeId.
+*/
+void QOpcUaArgument::setDataTypeId(const QString &dataTypeId)
+{
+ data->dataTypeId = dataTypeId;
+}
+
+/*!
+ Returns the value rank of the argument.
+ The value rank describes the structure of the value.
+ \table
+ \header
+ \li ValueRank
+ \li Meaning
+ \row
+ \li -3
+ \li Scalar or one dimensional array
+ \row
+ \li -2
+ \li Scalar or array with any number of dimensions
+ \row
+ \li -1
+ \li Not an array
+ \row
+ \li 0
+ \li Array with one or more dimensions
+ \row
+ \li 1
+ \li One dimensional array
+ \row
+ \li >1
+ \li Array with n dimensions
+ \endtable
+*/
+qint32 QOpcUaArgument::valueRank() const
+{
+ return data->valueRank;
+}
+
+/*!
+ Sets the value rank of the argument to \a valueRank.
+*/
+void QOpcUaArgument::setValueRank(qint32 valueRank)
+{
+ data->valueRank = valueRank;
+}
+
+/*!
+ Returns the array dimensions of the argument.
+
+ The array dimensions describe the length of each array dimension.
+*/
+QVector<quint32> QOpcUaArgument::arrayDimensions() const
+{
+ return data->arrayDimensions;
+}
+
+/*!
+ Returns a reference to the array dimensions of the argument.
+*/
+QVector<quint32> &QOpcUaArgument::arrayDimensionsRef()
+{
+ return data->arrayDimensions;
+}
+
+/*!
+ Sets the array dimensions of the argument to \a arrayDimensions.
+*/
+void QOpcUaArgument::setArrayDimensions(const QVector<quint32> &arrayDimensions)
+{
+ data->arrayDimensions = arrayDimensions;
+}
+
+/*!
+ Returns the description of the argument.
+*/
+QOpcUaLocalizedText QOpcUaArgument::description() const
+{
+ return data->description;
+}
+
+/*!
+ Sets the description of the argument to \a description.
+*/
+void QOpcUaArgument::setDescription(const QOpcUaLocalizedText &description)
+{
+ data->description = description;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaargument.h b/src/opcua/client/qopcuaargument.h
new file mode 100644
index 0000000..43156bb
--- /dev/null
+++ b/src/opcua/client/qopcuaargument.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAARGUMENT_H
+#define QOPCUAARGUMENT_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+#include <QtOpcUa/qopcualocalizedtext.h>
+
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QVariant;
+
+class QOpcUaArgumentData;
+class Q_OPCUA_EXPORT QOpcUaArgument
+{
+public:
+ QOpcUaArgument();
+ QOpcUaArgument(const QOpcUaArgument &rhs);
+ QOpcUaArgument(const QString &name, const QString &dataTypeId, qint32 valueRank,
+ const QVector<quint32> &arrayDimensions, const QOpcUaLocalizedText &description);
+ QOpcUaArgument &operator=(const QOpcUaArgument &);
+ bool operator==(const QOpcUaArgument &other) const;
+ operator QVariant() const;
+ ~QOpcUaArgument();
+
+ QString name() const;
+ void setName(const QString &name);
+
+ QString dataTypeId() const;
+ void setDataTypeId(const QString &dataTypeId);
+
+ qint32 valueRank() const;
+ void setValueRank(qint32 valueRank);
+
+ QVector<quint32> arrayDimensions() const;
+ QVector<quint32> &arrayDimensionsRef();
+ void setArrayDimensions(const QVector<quint32> &arrayDimensions);
+
+ QOpcUaLocalizedText description() const;
+ void setDescription(const QOpcUaLocalizedText &description);
+
+private:
+ QSharedDataPointer<QOpcUaArgumentData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaArgument)
+
+#endif // QOPCUAARGUMENT_H
diff --git a/src/opcua/client/qopcuaattributeoperand.cpp b/src/opcua/client/qopcuaattributeoperand.cpp
new file mode 100644
index 0000000..d085fc2
--- /dev/null
+++ b/src/opcua/client/qopcuaattributeoperand.cpp
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuaattributeoperand.h"
+#include "qopcuarelativepathelement.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaAttributeOperand
+ \inmodule QtOpcUa
+ \brief The OPC UA AttributeOperand type.
+
+ The AttributeOperand is defined in OPC-UA part 4, 7.4.4.4.
+ It has the same purpose as \l QOpcUaSimpleAttributeOperand but has more configurable options.
+*/
+
+class QOpcUaAttributeOperandData : public QSharedData
+{
+public:
+ QString nodeId;
+ QString alias;
+ QVector<QOpcUaRelativePathElement> browsePath;
+ QOpcUa::NodeAttribute attributeId {QOpcUa::NodeAttribute::Value};
+ QString indexRange;
+};
+
+QOpcUaAttributeOperand::QOpcUaAttributeOperand()
+ : data(new QOpcUaAttributeOperandData)
+{
+}
+
+/*!
+ Constructs an attribute operand from \a rhs.
+*/
+QOpcUaAttributeOperand::QOpcUaAttributeOperand(const QOpcUaAttributeOperand &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Sets the values from \a rhs in this attribute operand.
+*/
+QOpcUaAttributeOperand &QOpcUaAttributeOperand::operator=(const QOpcUaAttributeOperand &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Converts this attribute operand to \l QVariant.
+*/
+QOpcUaAttributeOperand::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+QOpcUaAttributeOperand::~QOpcUaAttributeOperand()
+{
+}
+
+/*!
+ Returns the index range string.
+*/
+QString QOpcUaAttributeOperand::indexRange() const
+{
+ return data->indexRange;
+}
+
+/*!
+ Sets the index range string used to identify a single value or subset of the attribute's value to \a indexRange.
+*/
+void QOpcUaAttributeOperand::setIndexRange(const QString &indexRange)
+{
+ data->indexRange = indexRange;
+}
+
+/*!
+ Returns the attribute id for an attribute of the node \l browsePath is pointing to.
+*/
+QOpcUa::NodeAttribute QOpcUaAttributeOperand::attributeId() const
+{
+ return data->attributeId;
+}
+
+/*!
+ Sets the attribute id to \a attributeId.
+*/
+void QOpcUaAttributeOperand::setAttributeId(QOpcUa::NodeAttribute attributeId)
+{
+ data->attributeId = attributeId;
+}
+
+/*!
+ Returns the browse path.
+*/
+QVector<QOpcUaRelativePathElement> QOpcUaAttributeOperand::browsePath() const
+{
+ return data->browsePath;
+}
+
+/*!
+ Returns a reference to the browse path.
+
+ \sa browsePath()
+*/
+QVector<QOpcUaRelativePathElement> &QOpcUaAttributeOperand::browsePathRef()
+{
+ return data->browsePath;
+}
+
+/*!
+ Sets the relative path to a node starting from \l nodeId() to \a browsePath.
+*/
+void QOpcUaAttributeOperand::setBrowsePath(const QVector<QOpcUaRelativePathElement> &browsePath)
+{
+ data->browsePath = browsePath;
+}
+
+/*!
+ Returns the alias for this QAttributeOperand.
+*/
+QString QOpcUaAttributeOperand::alias() const
+{
+ return data->alias;
+}
+
+/*!
+ Sets the alias to \a alias. This allows using this instance
+ as operand for other operations in the filter.
+*/
+void QOpcUaAttributeOperand::setAlias(const QString &alias)
+{
+ data->alias = alias;
+}
+
+/*!
+ Returns the node id of the type definition node.
+*/
+QString QOpcUaAttributeOperand::nodeId() const
+{
+ return data->nodeId;
+}
+
+/*!
+ Sets the node id of the type definition node to \a nodeId.
+*/
+void QOpcUaAttributeOperand::setNodeId(const QString &nodeId)
+{
+ data->nodeId = nodeId;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaattributeoperand.h b/src/opcua/client/qopcuaattributeoperand.h
new file mode 100644
index 0000000..80c24c0
--- /dev/null
+++ b/src/opcua/client/qopcuaattributeoperand.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAATTRIBUTEOPERAND_H
+#define QOPCUAATTRIBUTEOPERAND_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+#include <QtOpcUa/qopcuatype.h>
+
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaRelativePathElement;
+
+class QVariant;
+class QOpcUaRelativePathElement;
+
+// OPC-UA part 4, 7.4.4.4
+class QOpcUaAttributeOperandData;
+class Q_OPCUA_EXPORT QOpcUaAttributeOperand
+{
+public:
+ QOpcUaAttributeOperand();
+ QOpcUaAttributeOperand(const QOpcUaAttributeOperand &);
+ QOpcUaAttributeOperand &operator=(const QOpcUaAttributeOperand &);
+ operator QVariant() const;
+ ~QOpcUaAttributeOperand();
+
+ QString nodeId() const;
+ void setNodeId(const QString &nodeId);
+
+ QString alias() const;
+ void setAlias(const QString &alias);
+
+ QVector<QOpcUaRelativePathElement> browsePath() const;
+ QVector<QOpcUaRelativePathElement> &browsePathRef();
+ void setBrowsePath(const QVector<QOpcUaRelativePathElement> &browsePath);
+
+ QOpcUa::NodeAttribute attributeId() const;
+ void setAttributeId(QOpcUa::NodeAttribute attributeId);
+
+ QString indexRange() const;
+ void setIndexRange(const QString &indexRange);
+
+private:
+ QSharedDataPointer<QOpcUaAttributeOperandData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaAttributeOperand)
+
+#endif // QOPCUAATTRIBUTEOPERAND_H
diff --git a/src/opcua/client/qopcuaauthenticationinformation.cpp b/src/opcua/client/qopcuaauthenticationinformation.cpp
new file mode 100644
index 0000000..db59d34
--- /dev/null
+++ b/src/opcua/client/qopcuaauthenticationinformation.cpp
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuaauthenticationinformation.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaAuthenticationInformation
+ \inmodule QtOpcUa
+ \brief The OPC UA authentication information.
+ \since QtOpcUa 5.13
+
+ This class holds the information necessary to perform a login on a server.
+ Supported authentication mechanisms are
+
+ \list
+ \li Anonymous
+ \li Username
+ \li Certificate
+ \endlist
+
+ The anonymous method is used by default but also can be set manually.
+
+ This is an example authentication using username and password.
+
+ \code
+ QOpcUaAuthenticationInformation authInfo;
+ authInfo.setUsernameAuthentication("user", "password");
+
+ m_client->setAuthenticationInformation(authInfo);
+ m_client->connectToEndpoint(endpoint);
+ \endcode
+
+ \sa setAnonymousAuthentication() setUsernameAuthentication() setCertificateAuthentication()
+*/
+
+/*!
+ \qmltype AuthenticationInformation
+ \inqmlmodule QtOpcUa
+ \brief The OPC UA authentication information.
+ \since QtOpcUa 5.13
+
+ This class holds the information necessary to perform a login on a server.
+
+ \code
+ var authInfo = connection.authenticationInformation;
+ authInfo.setUsernameAuthentication("user1", "password");
+ connection.authenticationInformation = authInfo;
+ \endcode
+
+ Current supported authentication methods are:
+
+ \list
+ \li Anonymous
+ \li Usernane
+ \li Certificate
+ \endlist
+
+ \sa setAnonymousAuthentication() setUsernameAuthentication()
+*/
+
+class QOpcUaAuthenticationInformationData : public QSharedData
+{
+public:
+ QVariant authenticationData;
+ QOpcUaUserTokenPolicy::TokenType authenticationType;
+};
+
+QOpcUaAuthenticationInformation::QOpcUaAuthenticationInformation()
+ : data(new QOpcUaAuthenticationInformationData)
+{
+ setAnonymousAuthentication();
+}
+
+/*!
+ Constructs an authentication information from \a rhs.
+*/
+QOpcUaAuthenticationInformation::QOpcUaAuthenticationInformation(const QOpcUaAuthenticationInformation &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Sets the values from \a rhs in this authentication information.
+*/
+QOpcUaAuthenticationInformation &QOpcUaAuthenticationInformation::operator=(const QOpcUaAuthenticationInformation &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns \c true if this authentication information has the same value as \a rhs.
+*/
+bool QOpcUaAuthenticationInformation::operator==(const QOpcUaAuthenticationInformation &rhs) const
+{
+ return data->authenticationType == rhs.data->authenticationType &&
+ data->authenticationData == rhs.data->authenticationData;
+}
+
+QOpcUaAuthenticationInformation::~QOpcUaAuthenticationInformation()
+{
+}
+
+/*!
+ \qmlmethod AuthenticationInformation::setAnonymousAuthentication()
+
+ Sets the authentication method to anonymous.
+*/
+
+/*!
+ Sets the authentication method to anonymous.
+*/
+void QOpcUaAuthenticationInformation::setAnonymousAuthentication()
+{
+ data->authenticationType = QOpcUaUserTokenPolicy::TokenType::Anonymous;
+ data->authenticationData = QVariant();
+}
+
+/*!
+ \qmlmethod AuthenticationInformation::setUsernameAuthentication(string username, string password)
+
+ Sets the authentication method to username, using the given \a username and \a password.
+*/
+
+/*!
+ Sets the authentication method to username, using the given \a username and \a password.
+*/
+void QOpcUaAuthenticationInformation::setUsernameAuthentication(const QString &username, const QString &password)
+{
+ data->authenticationType = QOpcUaUserTokenPolicy::TokenType::Username;
+ data->authenticationData = QVariant::fromValue(qMakePair(username, password));
+}
+
+/*!
+ Sets the authentication method to use certificates.
+
+ This function is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+
+ When using this authentication type a proper configured \l QOpcUaPkiConfiguration has to be set to
+ the \l QOpcUaClient.
+
+ \sa QOpcUaPkiConfiguration QOpcUaClient::setPkiConfiguration()
+*/
+void QOpcUaAuthenticationInformation::setCertificateAuthentication()
+{
+ data->authenticationData = QVariant();
+ data->authenticationType = QOpcUaUserTokenPolicy::TokenType::Certificate;
+}
+
+/*!
+ The content of the \l QVariant returned by this method depends on the currently selected authentication method.
+ */
+const QVariant &QOpcUaAuthenticationInformation::authenticationData() const
+{
+ return data->authenticationData;
+}
+
+/*!
+ Returns the current authentication type.
+
+ \sa QOpcUaUserTokenPolicy::TokenType
+ */
+QOpcUaUserTokenPolicy::TokenType QOpcUaAuthenticationInformation::authenticationType() const
+{
+ return data->authenticationType;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaauthenticationinformation.h b/src/opcua/client/qopcuaauthenticationinformation.h
new file mode 100644
index 0000000..f72d1cd
--- /dev/null
+++ b/src/opcua/client/qopcuaauthenticationinformation.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAAUTHENTICATIONINFORMATION_H
+#define QOPCUAAUTHENTICATIONINFORMATION_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
+
+#include <QtOpcUa/QOpcUaUserTokenPolicy>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaAuthenticationInformationData;
+class Q_OPCUA_EXPORT QOpcUaAuthenticationInformation
+{
+ Q_GADGET
+
+public:
+ QOpcUaAuthenticationInformation();
+ QOpcUaAuthenticationInformation(const QOpcUaAuthenticationInformation &);
+ QOpcUaAuthenticationInformation &operator=(const QOpcUaAuthenticationInformation &);
+ bool operator==(const QOpcUaAuthenticationInformation &rhs) const;
+ ~QOpcUaAuthenticationInformation();
+
+ Q_INVOKABLE void setAnonymousAuthentication();
+ Q_INVOKABLE void setUsernameAuthentication(const QString &username, const QString &password);
+ Q_INVOKABLE void setCertificateAuthentication();
+
+ const QVariant &authenticationData() const;
+ Q_INVOKABLE QOpcUaUserTokenPolicy::TokenType authenticationType() const;
+
+private:
+ QSharedDataPointer<QOpcUaAuthenticationInformationData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaAuthenticationInformation)
+
+#endif // QOPCUAAUTHETICATIONINFORMATION_H
diff --git a/src/opcua/client/qopcuaaxisinformation.cpp b/src/opcua/client/qopcuaaxisinformation.cpp
new file mode 100644
index 0000000..1a3fd39
--- /dev/null
+++ b/src/opcua/client/qopcuaaxisinformation.cpp
@@ -0,0 +1,220 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuaaxisinformation.h"
+#include "qopcuaeuinformation.h"
+#include "qopcuarange.h"
+#include "qopcualocalizedtext.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaAxisInformation
+ \inmodule QtOpcUa
+ \brief The OPC UA AxisInformation type.
+
+ This is the Qt OPC UA representation for the OPC UA AxisInformation type defined in OPC-UA part 8, 5.6.6.
+ It contains information about an axis which can be used for multiple purposes. A common use case could
+ involve the plotting of display data. The engineering units and the title are used for the text on the plot,
+ range, axisScaleType and axisSteps provide the scaling and the axis ranges of the plot.
+*/
+
+class QOpcUaAxisInformationData : public QSharedData
+{
+public:
+ QOpcUaEUInformation engineeringUnits;
+ QOpcUaRange eURange;
+ QOpcUaLocalizedText title;
+ QOpcUa::AxisScale axisScaleType{QOpcUa::AxisScale::Linear};
+ QVector<double> axisSteps;
+};
+
+QOpcUaAxisInformation::QOpcUaAxisInformation()
+ : data(new QOpcUaAxisInformationData)
+{
+}
+
+/*!
+ Constructs axis information from \a rhs.
+*/
+QOpcUaAxisInformation::QOpcUaAxisInformation(const QOpcUaAxisInformation &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Sets the values from \a rhs in this axis information.
+*/
+QOpcUaAxisInformation &QOpcUaAxisInformation::operator=(const QOpcUaAxisInformation &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+QOpcUaAxisInformation::~QOpcUaAxisInformation()
+{
+}
+
+/*!
+ Returns the lower and upper values of this axis.
+*/
+QOpcUaRange QOpcUaAxisInformation::eURange() const
+{
+ return data->eURange;
+}
+
+/*!
+ Sets the lower and upper values of this axis to \a eURange.
+*/
+void QOpcUaAxisInformation::setEURange(const QOpcUaRange &eURange)
+{
+ data->eURange = eURange;
+}
+
+/*!
+ Returns the title of this axis.
+*/
+QOpcUaLocalizedText QOpcUaAxisInformation::title() const
+{
+ return data->title;
+}
+
+/*!
+ Sets the title to \a title.
+*/
+void QOpcUaAxisInformation::setTitle(const QOpcUaLocalizedText &title)
+{
+ data->title = title;
+}
+
+/*!
+ Returns the scaling of this axis, defined by \l QOpcUa::AxisScale.
+*/
+QOpcUa::AxisScale QOpcUaAxisInformation::axisScaleType() const
+{
+ return data->axisScaleType;
+}
+
+/*!
+ Sets the axis scale type to \a axisScaleType.
+*/
+void QOpcUaAxisInformation::setAxisScaleType(QOpcUa::AxisScale axisScaleType)
+{
+ data->axisScaleType = axisScaleType;
+}
+
+/*!
+ Returns specific values for each axis step.
+
+ This value is empty if the points are equally distributed and the step size can be
+ calculated from the number of steps and the range.
+ If the steps are different for each point but constant over a longer time, there is an entry for
+ each data point.
+*/
+QVector<double> QOpcUaAxisInformation::axisSteps() const
+{
+ return data->axisSteps;
+}
+
+/*!
+ Sets the axis steps to \a axisSteps.
+*/
+void QOpcUaAxisInformation::setAxisSteps(const QVector<double> &axisSteps)
+{
+ data->axisSteps = axisSteps;
+}
+
+/*!
+ Returns a reference to the axis steps.
+*/
+QVector<double> &QOpcUaAxisInformation::axisStepsRef()
+{
+ return data->axisSteps;
+}
+
+/*!
+ Returns the engineering units of this axis.
+*/
+QOpcUaEUInformation QOpcUaAxisInformation::engineeringUnits() const
+{
+ return data->engineeringUnits;
+}
+
+/*!
+ Sets the engineering units to \a engineeringUnits.
+*/
+void QOpcUaAxisInformation::setEngineeringUnits(const QOpcUaEUInformation &engineeringUnits)
+{
+ data->engineeringUnits = engineeringUnits;
+}
+
+/*!
+ Returns \c true if this axis information has the same value as \a rhs.
+*/
+bool QOpcUaAxisInformation::operator==(const QOpcUaAxisInformation &rhs) const
+{
+ return data->axisScaleType == rhs.axisScaleType() &&
+ data->axisSteps == rhs.axisSteps() &&
+ data->engineeringUnits == rhs.engineeringUnits() &&
+ data->eURange == rhs.eURange() &&
+ data->title == rhs.title();
+}
+
+/*!
+ Converts this axis information to \l QVariant.
+*/
+QOpcUaAxisInformation::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+/*!
+ Constructs axis information with engineering units \a engineeringUnits,
+ range \a eURange, title \a title, scaling \a axisScaleType and axis steps \a axisSteps.
+*/
+QOpcUaAxisInformation::QOpcUaAxisInformation(const QOpcUaEUInformation &engineeringUnits, const QOpcUaRange &eURange, const QOpcUaLocalizedText &title,
+ const QOpcUa::AxisScale &axisScaleType, const QVector<double> &axisSteps)
+ : data (new QOpcUaAxisInformationData)
+{
+ data->engineeringUnits = engineeringUnits;
+ data->eURange = eURange;
+ data->title = title;
+ data->axisScaleType = axisScaleType;
+ data->axisSteps = axisSteps;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaaxisinformation.h b/src/opcua/client/qopcuaaxisinformation.h
new file mode 100644
index 0000000..4afe996
--- /dev/null
+++ b/src/opcua/client/qopcuaaxisinformation.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAAXISINFORMATION_H
+#define QOPCUAAXISINFORMATION_H
+
+#include <QtOpcUa/qopcuatype.h>
+
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaEUInformation;
+class QOpcUaRange;
+class QOpcUaLocalizedText;
+
+class QOpcUaAxisInformationData;
+class Q_OPCUA_EXPORT QOpcUaAxisInformation
+{
+public:
+ QOpcUaAxisInformation();
+ QOpcUaAxisInformation(const QOpcUaAxisInformation &);
+ QOpcUaAxisInformation(const QOpcUaEUInformation &engineeringUnits, const QOpcUaRange &eURange, const QOpcUaLocalizedText &title,
+ const QOpcUa::AxisScale &axisScaleType, const QVector<double> &axisSteps);
+ QOpcUaAxisInformation &operator=(const QOpcUaAxisInformation &);
+ bool operator==(const QOpcUaAxisInformation &rhs) const;
+ operator QVariant() const;
+ ~QOpcUaAxisInformation();
+
+ QOpcUaEUInformation engineeringUnits() const;
+ void setEngineeringUnits(const QOpcUaEUInformation &engineeringUnits);
+
+ QOpcUaRange eURange() const;
+ void setEURange(const QOpcUaRange &eURange);
+
+ QOpcUaLocalizedText title() const;
+ void setTitle(const QOpcUaLocalizedText &title);
+
+ QOpcUa::AxisScale axisScaleType() const;
+ void setAxisScaleType(QOpcUa::AxisScale axisScaleType);
+
+ QVector<double> axisSteps() const;
+ void setAxisSteps(const QVector<double> &axisSteps);
+ QVector<double> &axisStepsRef();
+
+private:
+ QSharedDataPointer<QOpcUaAxisInformationData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaAxisInformation)
+
+#endif // QOPCUAAXISINFORMATION_H
diff --git a/src/opcua/client/qopcuabackend.cpp b/src/opcua/client/qopcuabackend.cpp
index b9e2c57..aedfb55 100644
--- a/src/opcua/client/qopcuabackend.cpp
+++ b/src/opcua/client/qopcuabackend.cpp
@@ -89,4 +89,19 @@ double QOpcUaBackend::revisePublishingInterval(double requestedValue, double min
return (std::max)(requestedValue, minimumValue);
}
+/*!
+ This function returns if a given endpoint description is valid.
+ If \a message is not \nullptr, an error message will be assigned to it, in case
+ the endpoint description is invalid.
+ */
+bool QOpcUaBackend::verifyEndpointDescription(const QOpcUaEndpointDescription &endpoint, QString *message)
+{
+ if (endpoint.endpointUrl().isEmpty() || endpoint.securityPolicy().isEmpty()) {
+ if (message)
+ *message = QLatin1String("Endpoint description is invalid because endpoint URL or security policy URL is empty");
+ return false;
+ }
+ return true;
+}
+
QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuabackend_p.h b/src/opcua/client/qopcuabackend_p.h
index 11c89fe..4ad748f 100644
--- a/src/opcua/client/qopcuabackend_p.h
+++ b/src/opcua/client/qopcuabackend_p.h
@@ -49,6 +49,7 @@
//
#include <QtOpcUa/qopcuaclient.h>
+#include <QtOpcUa/qopcuaendpointdescription.h>
#include <private/qopcuanodeimpl_p.h>
#include <QtCore/qobject.h>
@@ -75,6 +76,7 @@ public:
QOpcUa::Types attributeIdToTypeId(QOpcUa::NodeAttribute attr);
double revisePublishingInterval(double requestedValue, double minimumValue);
+ static bool verifyEndpointDescription(const QOpcUaEndpointDescription &endpoint, QString *message = nullptr);
Q_SIGNALS:
void stateAndOrErrorChanged(QOpcUaClient::ClientState state,
@@ -90,19 +92,21 @@ Q_SIGNALS:
QOpcUaMonitoringParameters param);
void browseFinished(quint64 handle, QVector<QOpcUaReferenceDescription> children, QOpcUa::UaStatusCode statusCode);
- void resolveBrowsePathFinished(quint64 handle, const QVector<QOpcUa::QBrowsePathTarget> &targets,
- const QVector<QOpcUa::QRelativePathElement> &path, QOpcUa::UaStatusCode statusCode);
- void endpointsRequestFinished(QVector<QOpcUa::QEndpointDescription> endpoints, QOpcUa::UaStatusCode statusCode);
- void findServersFinished(QVector<QOpcUa::QApplicationDescription> servers, QOpcUa::UaStatusCode statusCode);
- void batchReadFinished(QVector<QOpcUaReadResult> results, QOpcUa::UaStatusCode serviceResult);
- void batchWriteFinished(QVector<QOpcUaWriteResult> results, QOpcUa::UaStatusCode serviceResult);
+ void resolveBrowsePathFinished(quint64 handle, const QVector<QOpcUaBrowsePathTarget> &targets,
+ const QVector<QOpcUaRelativePathElement> &path, QOpcUa::UaStatusCode statusCode);
+ void endpointsRequestFinished(QVector<QOpcUaEndpointDescription> endpoints, QOpcUa::UaStatusCode statusCode, QUrl requestUrl);
+ void findServersFinished(QVector<QOpcUaApplicationDescription> servers, QOpcUa::UaStatusCode statusCode, QUrl requestUrl);
+ void readNodeAttributesFinished(QVector<QOpcUaReadResult> results, QOpcUa::UaStatusCode serviceResult);
+ void writeNodeAttributesFinished(QVector<QOpcUaWriteResult> results, QOpcUa::UaStatusCode serviceResult);
- void addNodeFinished(QOpcUa::QExpandedNodeId requestedNodeId, QString assignedNodeId, QOpcUa::UaStatusCode statusCode);
+ void addNodeFinished(QOpcUaExpandedNodeId requestedNodeId, QString assignedNodeId, QOpcUa::UaStatusCode statusCode);
void deleteNodeFinished(QString nodeId, QOpcUa::UaStatusCode statusCode);
- void addReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUa::QExpandedNodeId targetNodeId, bool isForwardReference,
+ void addReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUaExpandedNodeId targetNodeId, bool isForwardReference,
QOpcUa::UaStatusCode statusCode);
- void deleteReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUa::QExpandedNodeId targetNodeId, bool isForwardReference,
+ void deleteReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUaExpandedNodeId targetNodeId, bool isForwardReference,
QOpcUa::UaStatusCode statusCode);
+ void connectError(QOpcUaErrorState *errorState);
+ void passwordForPrivateKeyRequired(QString keyFilePath, QString *password, bool previousTryWasInvalid);
private:
Q_DISABLE_COPY(QOpcUaBackend)
diff --git a/src/opcua/client/qopcuabinarydataencoding.cpp b/src/opcua/client/qopcuabinarydataencoding.cpp
index 1fb09f9..3b2739b 100644
--- a/src/opcua/client/qopcuabinarydataencoding.cpp
+++ b/src/opcua/client/qopcuabinarydataencoding.cpp
@@ -85,28 +85,28 @@ QT_BEGIN_NAMESPACE
\li QString
\li String
\row
- \li QOpcUa::QQualifiedName
+ \li QOpcUaQualifiedName
\li QualifiedName
\row
- \li QOpcUa::QLocalizedText
+ \li QOpcUaLocalizedText
\li LocalizedText
\row
- \li QOpcUa::QEUInformation
+ \li QOpcUaEUInformation
\li EUInformation
\row
- \li QOpcUa::QRange
+ \li QOpcUaRange
\li Range
\row
- \li QOpcUa::QComplexNumber
+ \li QOpcUaComplexNumber
\li ComplexNumber
\row
- \li QOpcUa::QDoubleComplexNumber
+ \li QOpcUaDoubleComplexNumber
\li DoubleComplexNumber
\row
- \li QOpcUa::QAxisInformation
+ \li QOpcUaAxisInformation
\li AxisInformation
\row
- \li QOpcUa::QXValue
+ \li QOpcUaXValue
\li XV
\row
\li QUuid
@@ -124,13 +124,13 @@ QT_BEGIN_NAMESPACE
\li QOpcUa::UaStatusCode
\li StatusCode
\row
- \li QOpcUa::QExpandedNodeId
+ \li QOpcUaExpandedNodeId
\li ExpandedNodeId
\row
- \li QOpcUa::QExtensionObject
+ \li QOpcUaExtensionObject
\li ExtensionObject
\row
- \li QOpcUa::QArgument
+ \li QOpcUaArgument
\li Argument
\endtable
*/
@@ -190,7 +190,7 @@ QOpcUaBinaryDataEncoding::QOpcUaBinaryDataEncoding(QByteArray *buffer)
\a object must not be deleted as long as this binary data encoding oject is used.
*/
-QOpcUaBinaryDataEncoding::QOpcUaBinaryDataEncoding(QOpcUa::QExtensionObject &object)
+QOpcUaBinaryDataEncoding::QOpcUaBinaryDataEncoding(QOpcUaExtensionObject &object)
: m_data(&object.encodedBodyRef())
{
}
diff --git a/src/opcua/client/qopcuabinarydataencoding.h b/src/opcua/client/qopcuabinarydataencoding.h
index e22410c..3526614 100644
--- a/src/opcua/client/qopcuabinarydataencoding.h
+++ b/src/opcua/client/qopcuabinarydataencoding.h
@@ -37,12 +37,24 @@
#ifndef QOPCUABINARYDATAENCODING_H
#define QOPCUABINARYDATAENCODING_H
+#include <QtOpcUa/qopcuaargument.h>
+#include <QtOpcUa/qopcuaaxisinformation.h>
+#include <QtOpcUa/qopcuacomplexnumber.h>
+#include <QtOpcUa/qopcuadoublecomplexnumber.h>
+#include <QtOpcUa/qopcuaeuinformation.h>
+#include <QtOpcUa/qopcuaexpandednodeid.h>
+#include <QtOpcUa/qopcuaextensionobject.h>
+#include <QtOpcUa/qopcualocalizedtext.h>
+#include <QtOpcUa/qopcuaqualifiedname.h>
+#include <QtOpcUa/qopcuarange.h>
#include <QtOpcUa/qopcuatype.h>
+#include <QtOpcUa/qopcuaxvalue.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qmetatype.h>
#include <QtCore/quuid.h>
#include <QtCore/qendian.h>
+#include <QtCore/qvector.h>
#include <limits>
@@ -54,7 +66,7 @@ class Q_OPCUA_EXPORT QOpcUaBinaryDataEncoding
public:
QOpcUaBinaryDataEncoding(QByteArray *buffer);
- QOpcUaBinaryDataEncoding(QOpcUa::QExtensionObject &object);
+ QOpcUaBinaryDataEncoding(QOpcUaExtensionObject &object);
template <typename T, QOpcUa::Types OVERLAY = QOpcUa::Types::Undefined>
T decode(bool &success);
@@ -161,153 +173,153 @@ inline QString QOpcUaBinaryDataEncoding::decode<QString>(bool &success)
}
template <>
-inline QOpcUa::QQualifiedName QOpcUaBinaryDataEncoding::decode<QOpcUa::QQualifiedName>(bool &success)
+inline QOpcUaQualifiedName QOpcUaBinaryDataEncoding::decode<QOpcUaQualifiedName>(bool &success)
{
- QOpcUa::QQualifiedName temp;
+ QOpcUaQualifiedName temp;
temp.setNamespaceIndex(decode<quint16>(success));
if (!success)
- return QOpcUa::QQualifiedName();
+ return QOpcUaQualifiedName();
temp.setName(decode<QString>(success));
if (!success)
- return QOpcUa::QQualifiedName();
+ return QOpcUaQualifiedName();
return temp;
}
template <>
-inline QOpcUa::QLocalizedText QOpcUaBinaryDataEncoding::decode<QOpcUa::QLocalizedText>(bool &success)
+inline QOpcUaLocalizedText QOpcUaBinaryDataEncoding::decode<QOpcUaLocalizedText>(bool &success)
{
- QOpcUa::QLocalizedText temp;
+ QOpcUaLocalizedText temp;
quint8 encodingMask = decode<quint8>(success);
if (!success)
- return QOpcUa::QLocalizedText();
+ return QOpcUaLocalizedText();
if (encodingMask & 0x01) {
temp.setLocale(decode<QString>(success));
if (!success)
- return QOpcUa::QLocalizedText();
+ return QOpcUaLocalizedText();
}
if (encodingMask & 0x02) {
temp.setText(decode<QString>(success));
if (!success)
- return QOpcUa::QLocalizedText();
+ return QOpcUaLocalizedText();
}
return temp;
}
template <>
-inline QOpcUa::QEUInformation QOpcUaBinaryDataEncoding::decode<QOpcUa::QEUInformation>(bool &success)
+inline QOpcUaEUInformation QOpcUaBinaryDataEncoding::decode<QOpcUaEUInformation>(bool &success)
{
- QOpcUa::QEUInformation temp;
+ QOpcUaEUInformation temp;
temp.setNamespaceUri(decode<QString>(success));
if (!success)
- return QOpcUa::QEUInformation();
+ return QOpcUaEUInformation();
temp.setUnitId(decode<qint32>(success));
if (!success)
- return QOpcUa::QEUInformation();
+ return QOpcUaEUInformation();
- temp.setDisplayName(decode<QOpcUa::QLocalizedText>(success));
+ temp.setDisplayName(decode<QOpcUaLocalizedText>(success));
if (!success)
- return QOpcUa::QEUInformation();
+ return QOpcUaEUInformation();
- temp.setDescription(decode<QOpcUa::QLocalizedText>(success));
+ temp.setDescription(decode<QOpcUaLocalizedText>(success));
if (!success)
- return QOpcUa::QEUInformation();
+ return QOpcUaEUInformation();
return temp;
}
template <>
-inline QOpcUa::QRange QOpcUaBinaryDataEncoding::decode<QOpcUa::QRange>(bool &success)
+inline QOpcUaRange QOpcUaBinaryDataEncoding::decode<QOpcUaRange>(bool &success)
{
- QOpcUa::QRange temp;
+ QOpcUaRange temp;
temp.setLow(decode<double>(success));
if (!success)
- return QOpcUa::QRange();
+ return QOpcUaRange();
temp.setHigh(decode<double>(success));
if (!success)
- return QOpcUa::QRange();
+ return QOpcUaRange();
return temp;
}
template <>
-inline QOpcUa::QComplexNumber QOpcUaBinaryDataEncoding::decode<QOpcUa::QComplexNumber>(bool &success)
+inline QOpcUaComplexNumber QOpcUaBinaryDataEncoding::decode<QOpcUaComplexNumber>(bool &success)
{
- QOpcUa::QComplexNumber temp;
+ QOpcUaComplexNumber temp;
temp.setReal(decode<float>(success));
if (!success)
- return QOpcUa::QComplexNumber();
+ return QOpcUaComplexNumber();
temp.setImaginary(decode<float>(success));
if (!success)
- return QOpcUa::QComplexNumber();
+ return QOpcUaComplexNumber();
return temp;
}
template <>
-inline QOpcUa::QDoubleComplexNumber QOpcUaBinaryDataEncoding::decode<QOpcUa::QDoubleComplexNumber>(bool &success)
+inline QOpcUaDoubleComplexNumber QOpcUaBinaryDataEncoding::decode<QOpcUaDoubleComplexNumber>(bool &success)
{
- QOpcUa::QDoubleComplexNumber temp;
+ QOpcUaDoubleComplexNumber temp;
temp.setReal(decode<double>(success));
if (!success)
- return QOpcUa::QDoubleComplexNumber();
+ return QOpcUaDoubleComplexNumber();
temp.setImaginary(decode<double>(success));
if (!success)
- return QOpcUa::QDoubleComplexNumber();
+ return QOpcUaDoubleComplexNumber();
return temp;
}
template <>
-inline QOpcUa::QAxisInformation QOpcUaBinaryDataEncoding::decode<QOpcUa::QAxisInformation>(bool &success)
+inline QOpcUaAxisInformation QOpcUaBinaryDataEncoding::decode<QOpcUaAxisInformation>(bool &success)
{
- QOpcUa::QAxisInformation temp;
+ QOpcUaAxisInformation temp;
- temp.setEngineeringUnits(decode<QOpcUa::QEUInformation>(success));
+ temp.setEngineeringUnits(decode<QOpcUaEUInformation>(success));
if (!success)
- return QOpcUa::QAxisInformation();
+ return QOpcUaAxisInformation();
- temp.setEURange(decode<QOpcUa::QRange>(success));
+ temp.setEURange(decode<QOpcUaRange>(success));
if (!success)
- return QOpcUa::QAxisInformation();
+ return QOpcUaAxisInformation();
- temp.setTitle(decode<QOpcUa::QLocalizedText>(success));
+ temp.setTitle(decode<QOpcUaLocalizedText>(success));
if (!success)
- return QOpcUa::QAxisInformation();
+ return QOpcUaAxisInformation();
temp.setAxisScaleType(static_cast<QOpcUa::AxisScale>(decode<quint32>(success)));
if (!success)
- return QOpcUa::QAxisInformation();
+ return QOpcUaAxisInformation();
temp.setAxisSteps(decodeArray<double>(success));
if (!success)
- return QOpcUa::QAxisInformation();
+ return QOpcUaAxisInformation();
return temp;
}
template <>
-inline QOpcUa::QXValue QOpcUaBinaryDataEncoding::decode<QOpcUa::QXValue>(bool &success)
+inline QOpcUaXValue QOpcUaBinaryDataEncoding::decode<QOpcUaXValue>(bool &success)
{
- QOpcUa::QXValue temp;
+ QOpcUaXValue temp;
temp.setX(decode<double>(success));
if (!success)
- return QOpcUa::QXValue();
+ return QOpcUaXValue();
temp.setValue(decode<float>(success));
if (!success)
- return QOpcUa::QXValue();
+ return QOpcUaXValue();
return temp;
}
@@ -429,40 +441,40 @@ inline QString QOpcUaBinaryDataEncoding::decode<QString, QOpcUa::Types::NodeId>(
}
template <>
-inline QOpcUa::QExpandedNodeId QOpcUaBinaryDataEncoding::decode<QOpcUa::QExpandedNodeId>(bool &success)
+inline QOpcUaExpandedNodeId QOpcUaBinaryDataEncoding::decode<QOpcUaExpandedNodeId>(bool &success)
{
if (!m_data) {
success = false;
- return QOpcUa::QExpandedNodeId();
+ return QOpcUaExpandedNodeId();
}
// Don't decode the first byte, it is required for decode<QString, QOpcUa::Types::NodeId>()
if (!enoughData(sizeof(quint8))) {
success = false;
- return QOpcUa::QExpandedNodeId();
+ return QOpcUaExpandedNodeId();
}
bool hasNamespaceUri = *(reinterpret_cast<const quint8 *>(m_data->constData() + m_offset)) & 0x80;
bool hasServerIndex = *(reinterpret_cast<const quint8 *>(m_data->constData() + m_offset)) & 0x40;
QString nodeId = decode<QString, QOpcUa::Types::NodeId>(success);
if (!success)
- return QOpcUa::QExpandedNodeId();
+ return QOpcUaExpandedNodeId();
QString namespaceUri;
if (hasNamespaceUri) {
namespaceUri = decode<QString>(success);
if (!success)
- return QOpcUa::QExpandedNodeId();
+ return QOpcUaExpandedNodeId();
}
quint32 serverIndex = 0;
if (hasServerIndex) {
serverIndex = decode<quint32>(success);
if (!success)
- return QOpcUa::QExpandedNodeId();
+ return QOpcUaExpandedNodeId();
}
- return QOpcUa::QExpandedNodeId(namespaceUri, nodeId, serverIndex);
+ return QOpcUaExpandedNodeId(namespaceUri, nodeId, serverIndex);
}
template <>
@@ -491,56 +503,56 @@ inline QOpcUa::UaStatusCode QOpcUaBinaryDataEncoding::decode<QOpcUa::UaStatusCod
}
template <>
-inline QOpcUa::QExtensionObject QOpcUaBinaryDataEncoding::decode<QOpcUa::QExtensionObject>(bool &success)
+inline QOpcUaExtensionObject QOpcUaBinaryDataEncoding::decode<QOpcUaExtensionObject>(bool &success)
{
- QOpcUa::QExtensionObject temp;
+ QOpcUaExtensionObject temp;
QString typeId = decode<QString, QOpcUa::Types::NodeId>(success);
if (!success)
- return QOpcUa::QExtensionObject();
+ return QOpcUaExtensionObject();
temp.setEncodingTypeId(typeId);
quint8 encoding = decode<quint8>(success);
if (!success || encoding > 2) {
success = false;
- return QOpcUa::QExtensionObject();
+ return QOpcUaExtensionObject();
}
- temp.setEncoding(QOpcUa::QExtensionObject::Encoding(encoding));
+ temp.setEncoding(QOpcUaExtensionObject::Encoding(encoding));
if (encoding == 0)
return temp;
QByteArray body = decode<QByteArray>(success);
if (!success)
- return QOpcUa::QExtensionObject();
+ return QOpcUaExtensionObject();
temp.setEncodedBody(body);
return temp;
}
template <>
-inline QOpcUa::QArgument QOpcUaBinaryDataEncoding::decode<QOpcUa::QArgument>(bool &success)
+inline QOpcUaArgument QOpcUaBinaryDataEncoding::decode<QOpcUaArgument>(bool &success)
{
- QOpcUa::QArgument temp;
+ QOpcUaArgument temp;
temp.setName(decode<QString>(success));
if (!success)
- return QOpcUa::QArgument();
+ return QOpcUaArgument();
temp.setDataTypeId(decode<QString, QOpcUa::Types::NodeId>(success));
if (!success)
- return QOpcUa::QArgument();
+ return QOpcUaArgument();
temp.setValueRank(decode<qint32>(success));
if (!success)
- return QOpcUa::QArgument();
+ return QOpcUaArgument();
temp.setArrayDimensions(decodeArray<quint32>(success));
if (!success)
- return QOpcUa::QArgument();
+ return QOpcUaArgument();
- temp.setDescription(decode<QOpcUa::QLocalizedText>(success));
+ temp.setDescription(decode<QOpcUaLocalizedText>(success));
if (!success)
- return QOpcUa::QArgument();
+ return QOpcUaArgument();
return temp;
}
@@ -587,7 +599,7 @@ inline bool QOpcUaBinaryDataEncoding::encode<QString>(const QString &src)
}
template<>
-inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QQualifiedName>(const QOpcUa::QQualifiedName &src)
+inline bool QOpcUaBinaryDataEncoding::encode<QOpcUaQualifiedName>(const QOpcUaQualifiedName &src)
{
if (!encode<quint16>(src.namespaceIndex()))
return false;
@@ -597,7 +609,7 @@ inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QQualifiedName>(const QOpcU
}
template<>
-inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QLocalizedText>(const QOpcUa::QLocalizedText &src)
+inline bool QOpcUaBinaryDataEncoding::encode<QOpcUaLocalizedText>(const QOpcUaLocalizedText &src)
{
quint8 mask = 0;
if (src.locale().length() != 0)
@@ -616,7 +628,7 @@ inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QLocalizedText>(const QOpcU
}
template <>
-inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QRange>(const QOpcUa::QRange &src)
+inline bool QOpcUaBinaryDataEncoding::encode<QOpcUaRange>(const QOpcUaRange &src)
{
if (!encode<double>(src.low()))
return false;
@@ -626,21 +638,21 @@ inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QRange>(const QOpcUa::QRang
}
template <>
-inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QEUInformation>(const QOpcUa::QEUInformation &src)
+inline bool QOpcUaBinaryDataEncoding::encode<QOpcUaEUInformation>(const QOpcUaEUInformation &src)
{
if (!encode<QString>(src.namespaceUri()))
return false;
if (!encode<qint32>(src.unitId()))
return false;
- if (!encode<QOpcUa::QLocalizedText>(src.displayName()))
+ if (!encode<QOpcUaLocalizedText>(src.displayName()))
return false;
- if (!encode<QOpcUa::QLocalizedText>(src.description()))
+ if (!encode<QOpcUaLocalizedText>(src.description()))
return false;
return true;
}
template <>
-inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QComplexNumber>(const QOpcUa::QComplexNumber &src)
+inline bool QOpcUaBinaryDataEncoding::encode<QOpcUaComplexNumber>(const QOpcUaComplexNumber &src)
{
if (!encode<float>(src.real()))
return false;
@@ -650,7 +662,7 @@ inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QComplexNumber>(const QOpcU
}
template <>
-inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QDoubleComplexNumber>(const QOpcUa::QDoubleComplexNumber &src)
+inline bool QOpcUaBinaryDataEncoding::encode<QOpcUaDoubleComplexNumber>(const QOpcUaDoubleComplexNumber &src)
{
if (!encode<double>(src.real()))
return false;
@@ -660,13 +672,13 @@ inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QDoubleComplexNumber>(const
}
template <>
-inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QAxisInformation>(const QOpcUa::QAxisInformation &src)
+inline bool QOpcUaBinaryDataEncoding::encode<QOpcUaAxisInformation>(const QOpcUaAxisInformation &src)
{
- if (!encode<QOpcUa::QEUInformation>(src.engineeringUnits()))
+ if (!encode<QOpcUaEUInformation>(src.engineeringUnits()))
return false;
- if (!encode<QOpcUa::QRange>(src.eURange()))
+ if (!encode<QOpcUaRange>(src.eURange()))
return false;
- if (!encode<QOpcUa::QLocalizedText>(src.title()))
+ if (!encode<QOpcUaLocalizedText>(src.title()))
return false;
if (!encode<quint32>(static_cast<quint32>(src.axisScaleType())))
return false;
@@ -676,7 +688,7 @@ inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QAxisInformation>(const QOp
}
template <>
-inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QXValue>(const QOpcUa::QXValue &src)
+inline bool QOpcUaBinaryDataEncoding::encode<QOpcUaXValue>(const QOpcUaXValue &src)
{
if (!encode<double>(src.x()))
return false;
@@ -822,7 +834,7 @@ inline bool QOpcUaBinaryDataEncoding::encode<QString, QOpcUa::Types::NodeId>(con
}
template <>
-inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QExpandedNodeId>(const QOpcUa::QExpandedNodeId &src)
+inline bool QOpcUaBinaryDataEncoding::encode<QOpcUaExpandedNodeId>(const QOpcUaExpandedNodeId &src)
{
if (!m_data)
return false;
@@ -885,14 +897,14 @@ inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::UaStatusCode>(const QOpcUa:
}
template <>
-inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QExtensionObject>(const QOpcUa::QExtensionObject &src)
+inline bool QOpcUaBinaryDataEncoding::encode<QOpcUaExtensionObject>(const QOpcUaExtensionObject &src)
{
if (!encode<QString, QOpcUa::Types::NodeId>(src.encodingTypeId()))
return false;
if (!encode<quint8>(quint8(src.encoding())))
return false;
- if (src.encoding() != QOpcUa::QExtensionObject::Encoding::NoBody)
+ if (src.encoding() != QOpcUaExtensionObject::Encoding::NoBody)
if (!encode<QByteArray>(src.encodedBody()))
return false;
@@ -900,7 +912,7 @@ inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QExtensionObject>(const QOp
}
template <>
-inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QArgument>(const QOpcUa::QArgument &src)
+inline bool QOpcUaBinaryDataEncoding::encode<QOpcUaArgument>(const QOpcUaArgument &src)
{
if (!m_data)
return false;
@@ -916,7 +928,7 @@ inline bool QOpcUaBinaryDataEncoding::encode<QOpcUa::QArgument>(const QOpcUa::QA
return false;
if (!encoder.encodeArray<quint32>(src.arrayDimensions()))
return false;
- if (!encoder.encode<QOpcUa::QLocalizedText>(src.description()))
+ if (!encoder.encode<QOpcUaLocalizedText>(src.description()))
return false;
m_data->append(temp);
diff --git a/src/opcua/client/qopcuabrowsepathtarget.cpp b/src/opcua/client/qopcuabrowsepathtarget.cpp
new file mode 100644
index 0000000..cb8566d
--- /dev/null
+++ b/src/opcua/client/qopcuabrowsepathtarget.cpp
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuabrowsepathtarget.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaBrowsePathTarget
+ \inmodule QtOpcUa
+ \brief The OPC UA BrowsePathTarget.
+
+ A BrowsePathTarget contains a target of a browse path and information about the completeness of the node id resolution.
+*/
+class QOpcUaBrowsePathTargetData : public QSharedData
+{
+public:
+ QOpcUaExpandedNodeId targetId;
+ quint32 remainingPathIndex{(std::numeric_limits<quint32>::max)()};
+};
+
+QOpcUaBrowsePathTarget::QOpcUaBrowsePathTarget()
+ : data(new QOpcUaBrowsePathTargetData)
+{
+}
+
+/*!
+ Constructs a browse path target from \a rhs.
+*/
+QOpcUaBrowsePathTarget::QOpcUaBrowsePathTarget(const QOpcUaBrowsePathTarget &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Sets the values of \a rhs in this browse path target.
+*/
+QOpcUaBrowsePathTarget &QOpcUaBrowsePathTarget::operator=(const QOpcUaBrowsePathTarget &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns \c true if this browse path target has the same value as \a rhs.
+*/
+bool QOpcUaBrowsePathTarget::operator==(const QOpcUaBrowsePathTarget &rhs) const
+{
+ return data->targetId == rhs.targetId() &&
+ data->remainingPathIndex == rhs.remainingPathIndex();
+}
+
+QOpcUaBrowsePathTarget::~QOpcUaBrowsePathTarget()
+{
+}
+
+/*!
+ Returns the index of the first unprocessed element in the browse path.
+ If the path was followed to the end, remainingPathIndex has the maximum value of quint32.
+ \sa QOpcUaBrowsePathTarget::targetId()
+*/
+quint32 QOpcUaBrowsePathTarget::remainingPathIndex() const
+{
+ return data->remainingPathIndex;
+}
+
+/*!
+ Sets the remaining path index to \a remainingPathIndex.
+*/
+void QOpcUaBrowsePathTarget::setRemainingPathIndex(quint32 remainingPathIndex)
+{
+ data->remainingPathIndex = remainingPathIndex;
+}
+
+/*!
+ Returns \c true if the browse path has been fully resolved.
+*/
+bool QOpcUaBrowsePathTarget::isFullyResolved() const
+{
+ return (data->remainingPathIndex == (std::numeric_limits<quint32>::max)());
+}
+
+/*!
+ Returns the target of the last reference the server was able to follow.
+ If the reference leads to an external server, \e targetId is the id of the first node on that server.
+ \sa QOpcUaBrowsePathTarget::remainingPathIndex
+*/
+QOpcUaExpandedNodeId QOpcUaBrowsePathTarget::targetId() const
+{
+ return data->targetId;
+}
+
+/*!
+ Returns a reference to the target id.
+*/
+QOpcUaExpandedNodeId &QOpcUaBrowsePathTarget::targetIdRef()
+{
+ return data->targetId;
+}
+
+/*!
+ Sets the node id of the target node to \a targetId.
+*/
+void QOpcUaBrowsePathTarget::setTargetId(const QOpcUaExpandedNodeId &targetId)
+{
+ data->targetId = targetId;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuabrowsepathtarget.h b/src/opcua/client/qopcuabrowsepathtarget.h
new file mode 100644
index 0000000..8867a33
--- /dev/null
+++ b/src/opcua/client/qopcuabrowsepathtarget.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUABROWSEPATHTARGET_H
+#define QOPCUABROWSEPATHTARGET_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+#include <QtOpcUa/qopcuaexpandednodeid.h>
+
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaBrowsePathTargetData;
+class Q_OPCUA_EXPORT QOpcUaBrowsePathTarget
+{
+public:
+ QOpcUaBrowsePathTarget();
+ QOpcUaBrowsePathTarget(const QOpcUaBrowsePathTarget &);
+ QOpcUaBrowsePathTarget &operator=(const QOpcUaBrowsePathTarget &);
+ bool operator==(const QOpcUaBrowsePathTarget &rhs) const;
+ ~QOpcUaBrowsePathTarget();
+
+ QOpcUaExpandedNodeId targetId() const;
+ QOpcUaExpandedNodeId &targetIdRef();
+ void setTargetId(const QOpcUaExpandedNodeId &targetId);
+
+ quint32 remainingPathIndex() const;
+ void setRemainingPathIndex(quint32 remainingPathIndex);
+
+ bool isFullyResolved() const;
+
+private:
+ QSharedDataPointer<QOpcUaBrowsePathTargetData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaBrowsePathTarget)
+
+#endif // QOPCUABROWSEPATHTARGET_H
diff --git a/src/opcua/client/qopcuaclient.cpp b/src/opcua/client/qopcuaclient.cpp
index 4d70e59..501a301 100644
--- a/src/opcua/client/qopcuaclient.cpp
+++ b/src/opcua/client/qopcuaclient.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
** Contact: http://www.qt.io/licensing/
**
@@ -35,6 +36,9 @@
****************************************************************************/
#include "qopcuaclient.h"
+#include "qopcuaexpandednodeid.h"
+#include "qopcuaqualifiedname.h"
+
#include <private/qopcuaclient_p.h>
#include <QtCore/qloggingcategory.h>
@@ -58,7 +62,7 @@ Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA)
After successfully connecting to a server, QOpcUaClient allows getting \l QOpcUaNode
objects which enable further interaction with nodes on the OPC UA server.
- For operations that concern multiple nodes, QOpcUaClient offers a batch API which supports
+ For operations that concern multiple nodes, QOpcUaClient offers an API which supports
reading multiple attributes of multiple nodes in a single request to the server.
QOpcUaClient also keeps a local copy of the server's namespace array which is created after
@@ -71,7 +75,8 @@ Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA)
For an introduction to nodes and node ids, see \l QOpcUaNode.
\section1 Usage
- Create a \l QOpcUaClient using \l QOpcUaProvider and call \l connectToEndpoint() to connect to a server.
+ Create a \l QOpcUaClient using \l QOpcUaProvider, request a list of endpoints from the server
+ using \l requestEndpoints and call \l connectToEndpoint() to connect to one of the available endpoints.
After the connection is established, a \l QOpcUaNode object for the root node is requested.
\code
QOpcUaProvider provider;
@@ -89,7 +94,15 @@ Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA)
qDebug() << "A node object has been created";
}
});
- client->connectToEndpoint(QUrl("opc.tcp://127.0.0.1:4840")); // Connect the client to the server
+
+ QObject::connect(client, &QOpcUaClient::endpointsRequestFinished,
+ [client](QVector<QOpcUaEndpointDescription> endpoints) {
+ qDebug() << "Endpoints returned:" << endpoints.count();
+ if (endpoints.size())
+ client->connectToEndpoint(endpoints.first()); // Connect to the first endpoint in the list
+ });
+
+ client->requestEndpoints(QUrl("opc.tcp://127.0.0.1:4840")); // Request a list of endpoints from the server
\endcode
*/
@@ -123,6 +136,8 @@ Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA)
An error occurred with the connection.
\value UnknownError
An unknown error occurred.
+ \value UnsupportedAuthenticationInformation
+ The given type or data of authentication information is not supported.
*/
/*!
@@ -148,6 +163,44 @@ Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA)
*/
/*!
+ \fn QOpcUaClient::connectError(QOpcUaErrorState *errorState)
+ \since QtOpcUa 5.13
+
+ This function is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+
+ This signal is emitted when an error happended during connection establishment.
+ The parameter \a errorState contains information about the error.
+
+ In case of client side errors, these can be ignored by calling
+ \l QOpcUaErrorState::setIgnoreError on the object.
+
+ During execution of a slot connected to this signal the backend is stopped and
+ waits for all slots to return. This allows to pop up a user dialog to ask the
+ enduser for example if to trust an unknown certificate before the backend continues.
+ */
+
+/*!
+ \fn QOpcUaClient::passwordForPrivateKeyRequired(QString keyFilePath, QString *password, bool previousTryWasInvalid)
+ \since QtOpcUa 5.13
+
+ This function is currently available as a Technology Preview, and therefore the API
+ and functionality provided may be subject to change at any time without
+ prior notice.
+
+ This signal is emitted when a password for an encrypted private key is required.
+ The parameter \a keyFilePath contains the file path to key which is used.
+ The parameter \a previousTryWasInvalid is true if a previous try to decrypt the key failed (aka invalid pasword).
+ The parameter \a password points to a QString that has to be filled with the actual password for the key.
+ In case the previous try failed it contains the previously used password.
+
+ During execution of a slot connected to this signal the backend is stopped and
+ waits for all slots to return. This allows to pop up a user dialog to ask the
+ enduser for the password.
+ */
+
+/*!
\fn void QOpcUaClient::namespaceArrayUpdated(QStringList namespaces)
This signal is emitted after an updateNamespaceArray operation has finished.
@@ -170,39 +223,41 @@ Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA)
*/
/*!
- \fn void QOpcUaClient::endpointsRequestFinished(QVector<QOpcUa::QEndpointDescription> endpoints, QOpcUa::UaStatusCode statusCode)
+ \fn void QOpcUaClient::endpointsRequestFinished(QVector<QOpcUaEndpointDescription> endpoints, QOpcUa::UaStatusCode statusCode, QUrl requestUrl)
This signal is emitted after a \l requestEndpoints() operation has finished.
\a statusCode contains the result of the operation. If the result is \l {QOpcUa::UaStatusCode} {Good},
\a endpoints contains the descriptions of all endpoints that are available on the server.
+ \a requestUrl contains the URL that was used in the \l requestEndpoints() call.
*/
/*!
- \fn void QOpcUaClient::findServersFinished(QVector<QOpcUa::QApplicationDescription> servers, QOpcUa::UaStatusCode statusCode);
+ \fn void QOpcUaClient::findServersFinished(QVector<QOpcUaApplicationDescription> servers, QOpcUa::UaStatusCode statusCode, QUrl requestUrl);
This signal is emitted after a \l findServers() operation has finished.
\a statusCode contains the result of the operation. If the result is \l {QOpcUa::UaStatusCode} {Good},
\a servers contains the application descriptions of all servers known to the queried server that matched the filter criteria.
+ \a requestUrl contains the URL that was used in the \l findServers() call.
*/
/*!
- \fn void QOpcUaClient::batchReadFinished(QVector<QOpcUaReadResult> results, QOpcUa::UaStatusCode serviceResult)
+ \fn void QOpcUaClient::readNodeAttributesFinished(QVector<QOpcUaReadResult> results, QOpcUa::UaStatusCode serviceResult)
- This signal is emitted after a \l batchRead() operation has finished.
+ This signal is emitted after a \l readNodeAttributes() operation has finished.
The elements in \a results have the same order as the elements in the request. For each requested element,
there is a value together with timestamps and the status code in \a results.
\a serviceResult contains the status code from the OPC UA Read service.
- \sa batchRead() QOpcUaReadResult QOpcUaReadItem
+ \sa readNodeAttributes() QOpcUaReadResult QOpcUaReadItem
*/
/*!
- \fn void QOpcUaClient::batchWriteFinished(QVector<QOpcUaWriteResult> results, QOpcUa::UaStatusCode serviceResult)
+ \fn void QOpcUaClient::writeNodeAttributesFinished(QVector<QOpcUaWriteResult> results, QOpcUa::UaStatusCode serviceResult)
- This signal is emitted after a \l batchWrite() operation has finished.
+ This signal is emitted after a \l writeNodeAttributes() operation has finished.
- The elements in \a results have the same order as the elements in the batch write request.
+ The elements in \a results have the same order as the elements in the write request.
They contain the value, timestamps and status code received from the server as well as the node id,
attribute and index range from the write item. This facilitates matching the result with the request.
@@ -210,11 +265,11 @@ Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA)
\l {QOpcUa::UaStatusCode} {Good}, the entries in \a results also have an invalid status code and must
not be used.
- \sa batchWrite() QOpcUaWriteResult
+ \sa writeNodeAttributes() QOpcUaWriteResult
*/
/*!
- \fn void QOpcUaClient::addNodeFinished(QOpcUa::QExpandedNodeId requestedNodeId, QString assignedNodeId, QOpcUa::UaStatusCode statusCode)
+ \fn void QOpcUaClient::addNodeFinished(QOpcUaExpandedNodeId requestedNodeId, QString assignedNodeId, QOpcUa::UaStatusCode statusCode)
This signal is emitted after an \l addNode() operation has finished.
\a requestedNodeId is the requested node id from the \l addNode() call, \a assignedNodeId is the node id the server has assigned to the new node.
@@ -231,7 +286,7 @@ Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA)
*/
/*!
- \fn void QOpcUaClient::addReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUa::QExpandedNodeId targetNodeId, bool isForwardReference, QOpcUa::UaStatusCode statusCode)
+ \fn void QOpcUaClient::addReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUaExpandedNodeId targetNodeId, bool isForwardReference, QOpcUa::UaStatusCode statusCode)
This signal is emitted after an \l addReference() operation has finished.
\a sourceNodeId, \a referenceTypeId, \a targetNodeId and \a isForwardReference are the values from the \l addReference() call.
@@ -239,7 +294,7 @@ Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA)
*/
/*!
- \fn void QOpcUaClient::deleteReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUa::QExpandedNodeId targetNodeId, bool isForwardReference, QOpcUa::UaStatusCode statusCode)
+ \fn void QOpcUaClient::deleteReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUaExpandedNodeId targetNodeId, bool isForwardReference, QOpcUa::UaStatusCode statusCode)
This signal is emitted after a \l deleteReference() operation has finished.
\a sourceNodeId, \a referenceTypeId, \a targetNodeId and \a isForwardReference are the values from the \l deleteReference() call.
@@ -265,24 +320,89 @@ QOpcUaClient::~QOpcUaClient()
}
/*!
- Connects to the OPC UA endpoint given in \a url.
+ Sets the application identity for this \l QOpcUaClient instance to \a identity.
+ \since QtOpcUa 5.13
+
+ This function is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+*/
+void QOpcUaClient::setApplicationIdentity(const QOpcUaApplicationIdentity &identity)
+{
+ Q_D(QOpcUaClient);
+ d->setApplicationIdentity(identity);
+}
+
+/*!
+ Returns the application identity of this \l QOpcUaClient instance.
+ \since QtOpcUa 5.13
+
+ This function is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+*/
+QOpcUaApplicationIdentity QOpcUaClient::applicationIdentity() const
+{
+ Q_D(const QOpcUaClient);
+ return d->applicationIdentity();
+}
+
+/*!
+ Sets the application PKI configuration for this \l QOpcUaClient instance to \a config.
+ \since QtOpcUa 5.13
+
+ This function is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+*/
+void QOpcUaClient::setPkiConfiguration(const QOpcUaPkiConfiguration &config)
+{
+ Q_D(QOpcUaClient);
+ d->setPkiConfiguration(config);
+}
+
+/*!
+ Returns the application's PKI configuration of this \l QOpcUaClient instance.
+ \since QtOpcUa 5.13
+
+ This function is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+*/
+QOpcUaPkiConfiguration QOpcUaClient::pkiConfiguration() const
+{
+ Q_D(const QOpcUaClient);
+ return d->pkiConfiguration();
+}
+
+/*!
+ Connects to the OPC UA endpoint given in \a endpoint.
+ \since QtOpcUa 5.13
+
+ \code
+ QEndpointDescription endpointDescription;
+ ...
+ client->connectToEndpoint(endpointDescription);
+ \endcode
+
+ A list of available endpoints is usually obtained by calling \l QOpcUaClient::requestEndpoints().
- If the endpoint requires username and password, they must be included in \a url.
+ If the endpoint requires username authentication, at least a user name must be set in \l QOpcUaAuthenticationInformation.
+ Calling this function before setting an authentication information will use the anonymous authentication.
\code
- QUrl url("opc.tcp://localhost:4840");
- url.setUserName("user");
- url.setPassword("password");
+ QOpcUaAuthenticationInformation authInfo;
+ authInfo.setUsernameAuthentication("user", "password");
- m_client->connectToEndpoint(url);
+ client->setAuthenticationInformation(authInfo);
\endcode
- \sa disconnectFromEndpoint()
+ \sa setAuthenticationInformation(), QOpcUaEndpointDescription
*/
-void QOpcUaClient::connectToEndpoint(const QUrl &url)
+void QOpcUaClient::connectToEndpoint(const QOpcUaEndpointDescription &endpoint)
{
Q_D(QOpcUaClient);
- d->connectToEndpoint(url);
+ d->connectToEndpoint(endpoint);
}
/*!
@@ -296,13 +416,13 @@ void QOpcUaClient::disconnectFromEndpoint()
}
/*!
- Returns the URL of the OPC UA server the client is currently connected to
+ Returns the description of the endpoint the client is currently connected to
or was last connected to.
*/
-QUrl QOpcUaClient::url() const
+QOpcUaEndpointDescription QOpcUaClient::endpoint() const
{
Q_D(const QOpcUaClient);
- return d->m_url;
+ return d->m_endpoint;
}
QOpcUaClient::ClientState QOpcUaClient::state() const
@@ -345,7 +465,7 @@ QOpcUaNode *QOpcUaClient::node(const QString &nodeId)
\sa updateNamespaceArray()
*/
-QOpcUaNode *QOpcUaClient::node(const QOpcUa::QExpandedNodeId &expandedNodeId)
+QOpcUaNode *QOpcUaClient::node(const QOpcUaExpandedNodeId &expandedNodeId)
{
if (expandedNodeId.serverIndex()) {
qCWarning(QT_OPCUA) << "Can't create a QOpcuaNode for a node on a different server.";
@@ -398,7 +518,7 @@ QStringList QOpcUaClient::namespaceArray() const
of the expanded node id is malformed. \a ok will be set to \c true if the conversion has been successful.
If the expanded node id could not be resolved, \a ok will be set to \c false.
*/
-QString QOpcUaClient::resolveExpandedNodeId(const QOpcUa::QExpandedNodeId &expandedNodeId, bool *ok) const
+QString QOpcUaClient::resolveExpandedNodeId(const QOpcUaExpandedNodeId &expandedNodeId, bool *ok) const
{
if (expandedNodeId.serverIndex() && !expandedNodeId.namespaceUri().isEmpty()) {
qCWarning(QT_OPCUA) << "Can't resolve a namespace index on a different server.";
@@ -450,13 +570,13 @@ QString QOpcUaClient::resolveExpandedNodeId(const QOpcUa::QExpandedNodeId &expan
\a ok will be set to \c true if the namespace URI resolution has been successful.
If the namespace URI could not be resolved, \a ok will be set to \c false.
*/
-QOpcUa::QQualifiedName QOpcUaClient::qualifiedNameFromNamespaceUri(const QString &namespaceUri, const QString &name, bool *ok) const
+QOpcUaQualifiedName QOpcUaClient::qualifiedNameFromNamespaceUri(const QString &namespaceUri, const QString &name, bool *ok) const
{
if (namespaceArray().isEmpty()) {
qCWarning(QT_OPCUA) << "Namespaces table missing, unable to resolve namespace URI.";
if (ok)
*ok = false;
- return QOpcUa::QQualifiedName();
+ return QOpcUaQualifiedName();
}
int index = namespaceArray().indexOf(namespaceUri);
@@ -465,13 +585,13 @@ QOpcUa::QQualifiedName QOpcUaClient::qualifiedNameFromNamespaceUri(const QString
qCWarning(QT_OPCUA) << "Failed to resolve namespace" << namespaceUri;
if (ok)
*ok = false;
- return QOpcUa::QQualifiedName();
+ return QOpcUaQualifiedName();
}
if (ok)
*ok = true;
- return QOpcUa::QQualifiedName(index, name);
+ return QOpcUaQualifiedName(index, name);
};
/*!
@@ -485,8 +605,8 @@ QOpcUa::QQualifiedName QOpcUaClient::qualifiedNameFromNamespaceUri(const QString
\code
QOpcUaNodeCreationAttributes attributes;
- attributes.setDisplayName(QOpcUa::QLocalizedText("en", "My new Variable node"));
- attributes.setDescription(QOpcUa::QLocalizedText("en", "A node which has been added at runtime"));
+ attributes.setDisplayName(QOpcUaLocalizedText("en", "My new Variable node"));
+ attributes.setDescription(QOpcUaLocalizedText("en", "A node which has been added at runtime"));
attributes.setValue(23.0, QOpcUa::Types::Double);
attributes.setDataTypeId(QOpcUa::ns0ID(QOpcUa::NodeIds::Namespace0::Double));
attributes.setValueRank(-2); // Scalar or array
@@ -494,10 +614,10 @@ QOpcUa::QQualifiedName QOpcUaClient::qualifiedNameFromNamespaceUri(const QString
attributes.setUserAccessLevel(QOpcUa::AccessLevelBit::CurrentRead);
QOpcUaAddNodeItem item;
- item.setParentNodeId(QOpcUa::QExpandedNodeId("ns=3;s=TestFolder"));
+ item.setParentNodeId(QOpcUaExpandedNodeId("ns=3;s=TestFolder"));
item.setReferenceTypeId(QOpcUa::nodeIdFromReferenceType(QOpcUa::ReferenceTypeId::Organizes));
- item.setRequestedNewNodeId(QOpcUa::QExpandedNodeId("ns=3;s=MyNewVariableNode"));
- item.setBrowseName(QOpcUa::QQualifiedName(3, "MyNewVariableNode"));
+ item.setRequestedNewNodeId(QOpcUaExpandedNodeId("ns=3;s=MyNewVariableNode"));
+ item.setBrowseName(QOpcUaQualifiedName(3, "MyNewVariableNode"));
item.setNodeClass(QOpcUa::NodeClass::Variable);
item.setNodeAttributes(attributes);
@@ -527,7 +647,7 @@ bool QOpcUaClient::addNode(const QOpcUaAddNodeItem &nodeToAdd)
The following example code deletes a node and all references to it from the server:
\code
- m_client->deleteNode(QOpcUa::QExpandedNodeId("ns=3;s=MyNewVariableNode"), true);
+ m_client->deleteNode(QOpcUaExpandedNodeId("ns=3;s=MyNewVariableNode"), true);
\endcode
\sa addNode() deleteNodeFinished()
@@ -555,7 +675,7 @@ bool QOpcUaClient::deleteNode(const QString &nodeId, bool deleteTargetReferences
item.setSourceNodeId(QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::ObjectsFolder));
item.setReferenceTypeId(QOpcUa::nodeIdFromInteger(0, static_cast<quint32>(QOpcUa::ReferenceTypeId::Organizes)));
item.setIsForwardReference(true);
- item.setTargetNodeId(QOpcUa::QExpandedNodeId("ns=3;s=MyNewVariableNode"));
+ item.setTargetNodeId(QOpcUaExpandedNodeId("ns=3;s=MyNewVariableNode"));
item.setTargetNodeClass(QOpcUa::NodeClass::Variable);
m_client->addReference(item);
@@ -586,7 +706,7 @@ bool QOpcUaClient::addReference(const QOpcUaAddReferenceItem &referenceToAdd)
item.setSourceNodeId(QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::ObjectsFolder));
item.setReferenceTypeId(QOpcUa::nodeIdFromInteger(0, static_cast<quint32>(QOpcUa::ReferenceTypeId::Organizes)));
item.setIsForwardReference(true);
- item.setTargetNodeId(QOpcUa::QExpandedNodeId("ns=3;s=MyNewVariableNode"));
+ item.setTargetNodeId(QOpcUaExpandedNodeId("ns=3;s=MyNewVariableNode"));
item.setDeleteBidirectional(true);
m_client->deleteReference(item);
@@ -643,17 +763,17 @@ bool QOpcUaClient::findServers(const QUrl &url, const QStringList &localeIds, co
}
/*!
- Starts a batch read of multiple attributes on different nodes.
+ Starts a read of multiple attributes on different nodes.
The node id, the attribute and an index range can be specified for every entry in \a nodesToRead.
Returns true if the asynchronous request has been successfully dispatched.
- The results are returned in the \l batchReadFinished() signal.
+ The results are returned in the \l readNodeAttributesFinished() signal.
- The batch read API offers an alternative way to read attributes of nodes which can be used
+ This read function offers an alternative way to read attributes of nodes which can be used
for scenarios where the values of a large number of node attributes on different nodes must be read
without requiring the other features of the \l QOpcUaNode based API like monitoring for value changes.
All read items in the request are sent to the server in a single request and are answered in a single
- response which generates a single \l batchReadFinished() signal. This reduces the network overhead and
+ response which generates a single \l readNodeAttributesFinished() signal. This reduces the network overhead and
the number of signal slot connections if many different nodes are involved.
In the following example, the display name attribute and the two index ranges "0:2" and "5:7" of the value
@@ -667,33 +787,33 @@ bool QOpcUaClient::findServers(const QUrl &url, const QStringList &localeIds, co
request.push_back(QOpcUaReadItem("ns=1;s=MyArrayNode",
QOpcUa::NodeAttribute::Value, "5:7"));
request.push_back(QOpcUaReadItem("ns=1;s=MyScalarNode));
- m_client->batchRead(request);
+ m_client->readNodeAttributes(request);
\endcode
- \sa QOpcUaReadItem batchReadFinished()
+ \sa QOpcUaReadItem readNodeAttributesFinished()
*/
-bool QOpcUaClient::batchRead(const QVector<QOpcUaReadItem> &nodesToRead)
+bool QOpcUaClient::readNodeAttributes(const QVector<QOpcUaReadItem> &nodesToRead)
{
if (state() != QOpcUaClient::Connected)
return false;
Q_D(QOpcUaClient);
- return d->m_impl->batchRead(nodesToRead);
+ return d->m_impl->readNodeAttributes(nodesToRead);
}
/*!
- Starts a batch write for multiple attributes on different nodes.
+ Starts a write for multiple attributes on different nodes.
The node id, the attribute, the value, the value type and an index range can be specified
for every entry in \a nodesToWrite.
Returns \c true if the asynchronous request has been successfully dispatched.
- The results are returned in the \l batchWriteFinished() signal.
+ The results are returned in the \l writeNodeAttributesFinished() signal.
- The batch write API offers an alternative way to write attributes of nodes which can be used
+ This write function offers an alternative way to write attributes of nodes which can be used
for scenarios where the values of a large number of node attributes on different nodes must be written
without requiring the other features of the \l QOpcUaNode based API like monitoring for value changes.
All write items in the request are sent to the server in a single request and are answered in a single
- response which generates a single \l batchWriteFinished() signal. This reduces the network overhead and
+ response which generates a single \l writeNodeAttributesFinished() signal. This reduces the network overhead and
the number of signal slot connections if many different nodes are involved.
In the following example, the Values attributes of two different nodes are written in one call.
@@ -707,18 +827,18 @@ bool QOpcUaClient::batchRead(const QVector<QOpcUaReadItem> &nodesToRead)
request.append(QOpcUaWriteItem("ns=2;s=Demo.Static.Arrays.UInt32", QOpcUa::NodeAttribute::Value,
QVariantList({0, 1, 2}), QOpcUa::Types::UInt32, "0:2"));
- m_client->batchWrite(request);
+ m_client->writeNodeAttributes(request);
\endcode
- \sa QOpcUaWriteItem batchWriteFinished()
+ \sa QOpcUaWriteItem writeNodeAttributesFinished()
*/
-bool QOpcUaClient::batchWrite(const QVector<QOpcUaWriteItem> &nodesToWrite)
+bool QOpcUaClient::writeNodeAttributes(const QVector<QOpcUaWriteItem> &nodesToWrite)
{
if (state() != QOpcUaClient::Connected)
return false;
Q_D(QOpcUaClient);
- return d->m_impl->batchWrite(nodesToWrite);
+ return d->m_impl->writeNodeAttributes(nodesToWrite);
}
/*!
@@ -787,4 +907,56 @@ int QOpcUaClient::namespaceAutoupdateInterval() const
return d->m_namespaceArrayUpdateInterval;
}
+/*!
+ Sets the authentication information of this client to \a authenticationInformation.
+
+ \sa connectToEndpoint()
+*/
+void QOpcUaClient::setAuthenticationInformation(const QOpcUaAuthenticationInformation &authenticationInformation)
+{
+ Q_D(QOpcUaClient);
+ d->m_authenticationInformation = authenticationInformation;
+}
+
+/*!
+ Returns the current authentication information.
+*/
+const QOpcUaAuthenticationInformation &QOpcUaClient::authenticationInformation() const
+{
+ Q_D(const QOpcUaClient);
+ return d->m_authenticationInformation;
+}
+
+/*!
+ \since QtOpcUa 5.14
+
+ Returns the security policies supported by the used backend.
+
+ This function is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the function may be subject to change at any time without
+ prior notice.
+*/
+QStringList QOpcUaClient::supportedSecurityPolicies() const
+{
+ Q_D(const QOpcUaClient);
+ return d->m_impl->supportedSecurityPolicies();
+}
+
+/*!
+ \since QtOpcUa 5.14
+
+ Returns the user token types supported by the used backend.
+
+ This function is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the function may be subject to change at any time without
+ prior notice.
+
+ \sa QOpcUaUserTokenPolicy::TokenType
+*/
+QVector<QOpcUaUserTokenPolicy::TokenType> QOpcUaClient::supportedUserTokenTypes() const
+{
+ Q_D(const QOpcUaClient);
+ return d->m_impl->supportedUserTokenTypes();
+}
+
QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaclient.h b/src/opcua/client/qopcuaclient.h
index 9f5274f..2824922 100644
--- a/src/opcua/client/qopcuaclient.h
+++ b/src/opcua/client/qopcuaclient.h
@@ -38,6 +38,8 @@
#define QOPCUACLIENT_H
#include <QtOpcUa/qopcuaglobal.h>
+#include <QtOpcUa/qopcuaapplicationidentity.h>
+#include <QtOpcUa/qopcuapkiconfiguration.h>
#include <QtOpcUa/qopcuanode.h>
#include <QtOpcUa/qopcuareaditem.h>
#include <QtOpcUa/qopcuareadresult.h>
@@ -46,14 +48,21 @@
#include <QtOpcUa/qopcuaaddnodeitem.h>
#include <QtOpcUa/qopcuaaddreferenceitem.h>
#include <QtOpcUa/qopcuadeletereferenceitem.h>
+#include <QtOpcUa/qopcuaendpointdescription.h>
#include <QtCore/qobject.h>
#include <QtCore/qurl.h>
QT_BEGIN_NAMESPACE
+class QOpcUaAuthenticationInformation;
+class QOpcUaApplicationDescription;
class QOpcUaClientPrivate;
class QOpcUaClientImpl;
+class QOpcUaErrorState;
+class QOpcUaExpandedNodeId;
+class QOpcUaQualifiedName;
+class QOpcUaEndpointDescription;
class Q_OPCUA_EXPORT QOpcUaClient : public QObject
{
@@ -76,30 +85,37 @@ public:
InvalidUrl,
AccessDenied,
ConnectionError,
- UnknownError
+ UnknownError,
+ UnsupportedAuthenticationInformation
};
Q_ENUM(ClientError)
explicit QOpcUaClient(QOpcUaClientImpl *impl, QObject *parent = nullptr);
~QOpcUaClient();
- Q_INVOKABLE void connectToEndpoint(const QUrl &url);
+ void setApplicationIdentity(const QOpcUaApplicationIdentity &identity);
+ QOpcUaApplicationIdentity applicationIdentity() const;
+
+ void setPkiConfiguration(const QOpcUaPkiConfiguration &config);
+ QOpcUaPkiConfiguration pkiConfiguration() const;
+
+ Q_INVOKABLE void connectToEndpoint(const QOpcUaEndpointDescription &endpoint);
Q_INVOKABLE void disconnectFromEndpoint();
QOpcUaNode *node(const QString &nodeId);
- QOpcUaNode *node(const QOpcUa::QExpandedNodeId &expandedNodeId);
+ QOpcUaNode *node(const QOpcUaExpandedNodeId &expandedNodeId);
bool updateNamespaceArray();
QStringList namespaceArray() const;
- QString resolveExpandedNodeId(const QOpcUa::QExpandedNodeId &expandedNodeId, bool *ok = nullptr) const;
- QOpcUa::QQualifiedName qualifiedNameFromNamespaceUri(const QString &namespaceUri, const QString &name, bool *ok = nullptr) const;
+ QString resolveExpandedNodeId(const QOpcUaExpandedNodeId &expandedNodeId, bool *ok = nullptr) const;
+ QOpcUaQualifiedName qualifiedNameFromNamespaceUri(const QString &namespaceUri, const QString &name, bool *ok = nullptr) const;
bool requestEndpoints(const QUrl &url);
bool findServers(const QUrl &url, const QStringList &localeIds = QStringList(),
const QStringList &serverUris = QStringList());
- bool batchRead(const QVector<QOpcUaReadItem> &nodesToRead);
- bool batchWrite(const QVector<QOpcUaWriteItem> &nodesToWrite);
+ bool readNodeAttributes(const QVector<QOpcUaReadItem> &nodesToRead);
+ bool writeNodeAttributes(const QVector<QOpcUaWriteItem> &nodesToWrite);
bool addNode(const QOpcUaAddNodeItem &nodeToAdd);
bool deleteNode(const QString &nodeId, bool deleteTargetReferences = true);
@@ -107,7 +123,7 @@ public:
bool addReference(const QOpcUaAddReferenceItem &referenceToAdd);
bool deleteReference(const QOpcUaDeleteReferenceItem &referenceToDelete);
- QUrl url() const;
+ QOpcUaEndpointDescription endpoint() const;
ClientState state() const;
ClientError error() const;
@@ -119,23 +135,31 @@ public:
void setNamespaceAutoupdateInterval(int interval);
int namespaceAutoupdateInterval() const;
+ void setAuthenticationInformation(const QOpcUaAuthenticationInformation &authenticationInformation);
+ const QOpcUaAuthenticationInformation &authenticationInformation() const;
+
+ QStringList supportedSecurityPolicies() const;
+ QVector<QOpcUaUserTokenPolicy::TokenType> supportedUserTokenTypes() const;
+
Q_SIGNALS:
void connected();
void disconnected();
void stateChanged(QOpcUaClient::ClientState state);
void errorChanged(QOpcUaClient::ClientError error);
+ void connectError(QOpcUaErrorState *errorState);
void namespaceArrayUpdated(QStringList namespaces);
void namespaceArrayChanged(QStringList namespaces);
- void endpointsRequestFinished(QVector<QOpcUa::QEndpointDescription> endpoints, QOpcUa::UaStatusCode statusCode);
- void findServersFinished(QVector<QOpcUa::QApplicationDescription> servers, QOpcUa::UaStatusCode statusCode);
- void batchReadFinished(QVector<QOpcUaReadResult> results, QOpcUa::UaStatusCode serviceResult);
- void batchWriteFinished(QVector<QOpcUaWriteResult> results, QOpcUa::UaStatusCode serviceResult);
- void addNodeFinished(QOpcUa::QExpandedNodeId requestedNodeId, QString assignedNodeId, QOpcUa::UaStatusCode statusCode);
+ void endpointsRequestFinished(QVector<QOpcUaEndpointDescription> endpoints, QOpcUa::UaStatusCode statusCode, QUrl requestUrl);
+ void findServersFinished(QVector<QOpcUaApplicationDescription> servers, QOpcUa::UaStatusCode statusCode, QUrl requestUrl);
+ void readNodeAttributesFinished(QVector<QOpcUaReadResult> results, QOpcUa::UaStatusCode serviceResult);
+ void writeNodeAttributesFinished(QVector<QOpcUaWriteResult> results, QOpcUa::UaStatusCode serviceResult);
+ void addNodeFinished(QOpcUaExpandedNodeId requestedNodeId, QString assignedNodeId, QOpcUa::UaStatusCode statusCode);
void deleteNodeFinished(QString nodeId, QOpcUa::UaStatusCode statusCode);
- void addReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUa::QExpandedNodeId targetNodeId, bool isForwardReference,
+ void addReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUaExpandedNodeId targetNodeId, bool isForwardReference,
QOpcUa::UaStatusCode statusCode);
- void deleteReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUa::QExpandedNodeId targetNodeId, bool isForwardReference,
+ void deleteReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUaExpandedNodeId targetNodeId, bool isForwardReference,
QOpcUa::UaStatusCode statusCode);
+ void passwordForPrivateKeyRequired(QString keyFilePath, QString *password, bool previousTryWasInvalid);
private:
Q_DISABLE_COPY(QOpcUaClient)
diff --git a/src/opcua/client/qopcuaclient_p.h b/src/opcua/client/qopcuaclient_p.h
index 51ce5d0..62d8ed5 100644
--- a/src/opcua/client/qopcuaclient_p.h
+++ b/src/opcua/client/qopcuaclient_p.h
@@ -50,6 +50,7 @@
#include <QtOpcUa/qopcuaclient.h>
#include <QtOpcUa/qopcuaglobal.h>
+#include <QtOpcUa/qopcuaauthenticationinformation.h>
#include <private/qopcuaclientimpl_p.h>
#include <QtCore/qobject.h>
@@ -65,14 +66,15 @@ public:
QOpcUaClientPrivate(QOpcUaClientImpl *impl);
~QOpcUaClientPrivate() override;
- void connectToEndpoint(const QUrl &url);
+ void connectToEndpoint(const QOpcUaEndpointDescription &endpoint);
void disconnectFromEndpoint();
QScopedPointer<QOpcUaClientImpl> m_impl;
QOpcUaClient::ClientState m_state;
QOpcUaClient::ClientError m_error;
- QUrl m_url;
+ QOpcUaEndpointDescription m_endpoint;
bool m_enableNamespaceArrayAutoupdate;
+ QOpcUaAuthenticationInformation m_authenticationInformation;
bool checkAndSetUrl(const QUrl &url);
void setStateAndError(QOpcUaClient::ClientState state,
@@ -83,12 +85,20 @@ public:
void namespaceArrayUpdated(QOpcUa::NodeAttributes attr);
void setupNamespaceArrayMonitoring();
+ void setApplicationIdentity(const QOpcUaApplicationIdentity &identity);
+ QOpcUaApplicationIdentity applicationIdentity() const;
+
+ void setPkiConfiguration(const QOpcUaPkiConfiguration &config);
+ QOpcUaPkiConfiguration pkiConfiguration() const;
+
private:
Q_DECLARE_PUBLIC(QOpcUaClient)
QStringList m_namespaceArray;
QScopedPointer<QOpcUaNode> m_namespaceArrayNode;
bool m_namespaceArrayAutoupdateEnabled;
unsigned int m_namespaceArrayUpdateInterval;
+ QOpcUaApplicationIdentity m_applicationIdentity;
+ QOpcUaPkiConfiguration m_pkiConfig;
};
QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaclientimpl.cpp b/src/opcua/client/qopcuaclientimpl.cpp
index af77e72..fa18795 100644
--- a/src/opcua/client/qopcuaclientimpl.cpp
+++ b/src/opcua/client/qopcuaclientimpl.cpp
@@ -37,11 +37,14 @@
#include <private/qopcuabackend_p.h>
#include <private/qopcuaclientimpl_p.h>
#include <QtOpcUa/qopcuamonitoringparameters.h>
+#include "qopcuaclient_p.h"
+#include "qopcuaerrorstate.h"
QT_BEGIN_NAMESPACE
QOpcUaClientImpl::QOpcUaClientImpl(QObject *parent)
: QObject(parent)
+ , m_client(nullptr)
, m_handleCounter(0)
{}
@@ -83,12 +86,15 @@ void QOpcUaClientImpl::connectBackendWithClient(QOpcUaBackend *backend)
connect(backend, &QOpcUaBackend::eventOccurred, this, &QOpcUaClientImpl::handleNewEvent);
connect(backend, &QOpcUaBackend::endpointsRequestFinished, this, &QOpcUaClientImpl::endpointsRequestFinished);
connect(backend, &QOpcUaBackend::findServersFinished, this, &QOpcUaClientImpl::findServersFinished);
- connect(backend, &QOpcUaBackend::batchReadFinished, this, &QOpcUaClientImpl::batchReadFinished);
- connect(backend, &QOpcUaBackend::batchWriteFinished, this, &QOpcUaClientImpl::batchWriteFinished);
+ connect(backend, &QOpcUaBackend::readNodeAttributesFinished, this, &QOpcUaClientImpl::readNodeAttributesFinished);
+ connect(backend, &QOpcUaBackend::writeNodeAttributesFinished, this, &QOpcUaClientImpl::writeNodeAttributesFinished);
connect(backend, &QOpcUaBackend::addNodeFinished, this, &QOpcUaClientImpl::addNodeFinished);
connect(backend, &QOpcUaBackend::deleteNodeFinished, this, &QOpcUaClientImpl::deleteNodeFinished);
connect(backend, &QOpcUaBackend::addReferenceFinished, this, &QOpcUaClientImpl::addReferenceFinished);
connect(backend, &QOpcUaBackend::deleteReferenceFinished, this, &QOpcUaClientImpl::deleteReferenceFinished);
+ // This needs to be blocking queued because it is called from another thread, which needs to wait for a result.
+ connect(backend, &QOpcUaBackend::connectError, this, &QOpcUaClientImpl::connectError, Qt::BlockingQueuedConnection);
+ connect(backend, &QOpcUaBackend::passwordForPrivateKeyRequired, this, &QOpcUaClientImpl::passwordForPrivateKeyRequired, Qt::BlockingQueuedConnection);
}
void QOpcUaClientImpl::handleAttributesRead(quint64 handle, QVector<QOpcUaReadResult> attr, QOpcUa::UaStatusCode serviceResult)
@@ -140,8 +146,8 @@ void QOpcUaClientImpl::handleBrowseFinished(quint64 handle, const QVector<QOpcUa
emit (*it)->browseFinished(children, statusCode);
}
-void QOpcUaClientImpl::handleResolveBrowsePathFinished(quint64 handle, QVector<QOpcUa::QBrowsePathTarget> targets,
- QVector<QOpcUa::QRelativePathElement> path, QOpcUa::UaStatusCode status)
+void QOpcUaClientImpl::handleResolveBrowsePathFinished(quint64 handle, QVector<QOpcUaBrowsePathTarget> targets,
+ QVector<QOpcUaRelativePathElement> path, QOpcUa::UaStatusCode status)
{
auto it = m_handles.constFind(handle);
if (it != m_handles.constEnd() && !it->isNull())
diff --git a/src/opcua/client/qopcuaclientimpl_p.h b/src/opcua/client/qopcuaclientimpl_p.h
index d377a48..21d3119 100644
--- a/src/opcua/client/qopcuaclientimpl_p.h
+++ b/src/opcua/client/qopcuaclientimpl_p.h
@@ -50,6 +50,7 @@
#include <QtOpcUa/qopcuaclient.h>
#include <QtOpcUa/qopcuaglobal.h>
+#include <QtOpcUa/qopcuaendpointdescription.h>
#include <private/qopcuanodeimpl_p.h>
#include <QtCore/qobject.h>
@@ -71,14 +72,14 @@ public:
QOpcUaClientImpl(QObject *parent = 0);
virtual ~QOpcUaClientImpl();
- virtual void connectToEndpoint(const QUrl &url) = 0;
+ virtual void connectToEndpoint(const QOpcUaEndpointDescription &endpoint) = 0;
virtual void disconnectFromEndpoint() = 0;
virtual QOpcUaNode *node(const QString &nodeId) = 0;
virtual QString backend() const = 0;
virtual bool requestEndpoints(const QUrl &url) = 0;
virtual bool findServers(const QUrl &url, const QStringList &localeIds, const QStringList &serverUris) = 0;
- virtual bool batchRead(const QVector<QOpcUaReadItem> &nodesToRead) = 0;
- virtual bool batchWrite(const QVector<QOpcUaWriteItem> &nodesToWrite) = 0;
+ virtual bool readNodeAttributes(const QVector<QOpcUaReadItem> &nodesToRead) = 0;
+ virtual bool writeNodeAttributes(const QVector<QOpcUaWriteItem> &nodesToWrite) = 0;
bool registerNode(QPointer<QOpcUaNodeImpl> obj);
void unregisterNode(QPointer<QOpcUaNodeImpl> obj);
@@ -91,6 +92,9 @@ public:
void connectBackendWithClient(QOpcUaBackend *backend);
+ virtual QStringList supportedSecurityPolicies() const = 0;
+ virtual QVector<QOpcUaUserTokenPolicy::TokenType> supportedUserTokenTypes() const = 0;
+
QOpcUaClient *m_client;
private Q_SLOTS:
@@ -103,8 +107,8 @@ private Q_SLOTS:
void handleMethodCallFinished(quint64 handle, QString methodNodeId, QVariant result, QOpcUa::UaStatusCode statusCode);
void handleBrowseFinished(quint64 handle, const QVector<QOpcUaReferenceDescription> &children, QOpcUa::UaStatusCode statusCode);
- void handleResolveBrowsePathFinished(quint64 handle, QVector<QOpcUa::QBrowsePathTarget> targets,
- QVector<QOpcUa::QRelativePathElement> path, QOpcUa::UaStatusCode status);
+ void handleResolveBrowsePathFinished(quint64 handle, QVector<QOpcUaBrowsePathTarget> targets,
+ QVector<QOpcUaRelativePathElement> path, QOpcUa::UaStatusCode status);
void handleNewEvent(quint64 handle, QVariantList eventFields);
@@ -113,16 +117,18 @@ signals:
void disconnected();
void stateAndOrErrorChanged(QOpcUaClient::ClientState state,
QOpcUaClient::ClientError error);
- void endpointsRequestFinished(QVector<QOpcUa::QEndpointDescription> endpoints, QOpcUa::UaStatusCode statusCode);
- void findServersFinished(QVector<QOpcUa::QApplicationDescription> servers, QOpcUa::UaStatusCode statusCode);
- void batchReadFinished(QVector<QOpcUaReadResult> results, QOpcUa::UaStatusCode serviceResult);
- void batchWriteFinished(QVector<QOpcUaWriteResult> results, QOpcUa::UaStatusCode serviceResult);
- void addNodeFinished(QOpcUa::QExpandedNodeId requestedNodeId, QString assignedNodeId, QOpcUa::UaStatusCode statusCode);
+ void endpointsRequestFinished(QVector<QOpcUaEndpointDescription> endpoints, QOpcUa::UaStatusCode statusCode, QUrl requestUrl);
+ void findServersFinished(QVector<QOpcUaApplicationDescription> servers, QOpcUa::UaStatusCode statusCode, QUrl requestUrl);
+ void readNodeAttributesFinished(QVector<QOpcUaReadResult> results, QOpcUa::UaStatusCode serviceResult);
+ void writeNodeAttributesFinished(QVector<QOpcUaWriteResult> results, QOpcUa::UaStatusCode serviceResult);
+ void addNodeFinished(QOpcUaExpandedNodeId requestedNodeId, QString assignedNodeId, QOpcUa::UaStatusCode statusCode);
void deleteNodeFinished(QString nodeId, QOpcUa::UaStatusCode statusCode);
- void addReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUa::QExpandedNodeId targetNodeId, bool isForwardReference,
+ void addReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUaExpandedNodeId targetNodeId, bool isForwardReference,
QOpcUa::UaStatusCode statusCode);
- void deleteReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUa::QExpandedNodeId targetNodeId, bool isForwardReference,
+ void deleteReferenceFinished(QString sourceNodeId, QString referenceTypeId, QOpcUaExpandedNodeId targetNodeId, bool isForwardReference,
QOpcUa::UaStatusCode statusCode);
+ void connectError(QOpcUaErrorState *errorState);
+ void passwordForPrivateKeyRequired(const QString keyFilePath, QString *password, bool previousTryWasInvalid);
private:
Q_DISABLE_COPY(QOpcUaClientImpl)
diff --git a/src/opcua/client/qopcuaclientprivate.cpp b/src/opcua/client/qopcuaclientprivate.cpp
index db34ce4..1e4c0ae 100644
--- a/src/opcua/client/qopcuaclientprivate.cpp
+++ b/src/opcua/client/qopcuaclientprivate.cpp
@@ -37,6 +37,9 @@
#include <private/qopcuaclient_p.h>
#include <QtCore/qloggingcategory.h>
+#include <QtOpcUa/qopcuaendpointdescription.h>
+
+#include "qopcuaerrorstate.h"
QT_BEGIN_NAMESPACE
@@ -48,6 +51,7 @@ QOpcUaClientPrivate::QOpcUaClientPrivate(QOpcUaClientImpl *impl)
, m_state(QOpcUaClient::Disconnected)
, m_error(QOpcUaClient::NoError)
, m_enableNamespaceArrayAutoupdate(false)
+ , m_authenticationInformation(QOpcUaAuthenticationInformation())
, m_namespaceArrayAutoupdateEnabled(false)
, m_namespaceArrayUpdateInterval(1000)
{
@@ -62,27 +66,27 @@ QOpcUaClientPrivate::QOpcUaClientPrivate(QOpcUaClientImpl *impl)
});
QObject::connect(m_impl.data(), &QOpcUaClientImpl::endpointsRequestFinished, m_impl.data(),
- [this](const QVector<QOpcUa::QEndpointDescription> &e, QOpcUa::UaStatusCode s) {
+ [this](const QVector<QOpcUaEndpointDescription> &e, QOpcUa::UaStatusCode s, const QUrl &requestUrl) {
Q_Q(QOpcUaClient);
- emit q->endpointsRequestFinished(e, s);
+ emit q->endpointsRequestFinished(e, s, requestUrl);
});
- QObject::connect(m_impl.data(), &QOpcUaClientImpl::findServersFinished, [this](const QVector<QOpcUa::QApplicationDescription> &a, QOpcUa::UaStatusCode s) {
+ QObject::connect(m_impl.data(), &QOpcUaClientImpl::findServersFinished, [this](const QVector<QOpcUaApplicationDescription> &a, QOpcUa::UaStatusCode s, const QUrl &requestUrl) {
Q_Q(QOpcUaClient);
- emit q->findServersFinished(a, s);
+ emit q->findServersFinished(a, s, requestUrl);
});
- QObject::connect(m_impl.data(), &QOpcUaClientImpl::batchReadFinished, [this](const QVector<QOpcUaReadResult> &results, QOpcUa::UaStatusCode serviceResult) {
+ QObject::connect(m_impl.data(), &QOpcUaClientImpl::readNodeAttributesFinished, [this](const QVector<QOpcUaReadResult> &results, QOpcUa::UaStatusCode serviceResult) {
Q_Q(QOpcUaClient);
- emit q->batchReadFinished(results, serviceResult);
+ emit q->readNodeAttributesFinished(results, serviceResult);
});
- QObject::connect(m_impl.data(), &QOpcUaClientImpl::batchWriteFinished, [this](const QVector<QOpcUaWriteResult> &results, QOpcUa::UaStatusCode serviceResult) {
+ QObject::connect(m_impl.data(), &QOpcUaClientImpl::writeNodeAttributesFinished, [this](const QVector<QOpcUaWriteResult> &results, QOpcUa::UaStatusCode serviceResult) {
Q_Q(QOpcUaClient);
- emit q->batchWriteFinished(results, serviceResult);
+ emit q->writeNodeAttributesFinished(results, serviceResult);
});
- QObject::connect(m_impl.data(), &QOpcUaClientImpl::addNodeFinished, [this](const QOpcUa::QExpandedNodeId &requestedNodeId, const QString &assignedNodeId, QOpcUa::UaStatusCode statusCode) {
+ QObject::connect(m_impl.data(), &QOpcUaClientImpl::addNodeFinished, [this](const QOpcUaExpandedNodeId &requestedNodeId, const QString &assignedNodeId, QOpcUa::UaStatusCode statusCode) {
Q_Q(QOpcUaClient);
emit q->addNodeFinished(requestedNodeId, assignedNodeId, statusCode);
});
@@ -93,31 +97,36 @@ QOpcUaClientPrivate::QOpcUaClientPrivate(QOpcUaClientImpl *impl)
});
QObject::connect(m_impl.data(), &QOpcUaClientImpl::addReferenceFinished, [this](const QString &sourceNodeId, const QString &referenceTypeId,
- const QOpcUa::QExpandedNodeId &targetNodeId, bool isForwardReference, QOpcUa::UaStatusCode statusCode) {
+ const QOpcUaExpandedNodeId &targetNodeId, bool isForwardReference, QOpcUa::UaStatusCode statusCode) {
Q_Q(QOpcUaClient);
emit q->addReferenceFinished(sourceNodeId, referenceTypeId, targetNodeId, isForwardReference, statusCode);
});
QObject::connect(m_impl.data(), &QOpcUaClientImpl::deleteReferenceFinished, [this](const QString &sourceNodeId, const QString &referenceTypeId,
- const QOpcUa::QExpandedNodeId &targetNodeId, bool isForwardReference, QOpcUa::UaStatusCode statusCode) {
+ const QOpcUaExpandedNodeId &targetNodeId, bool isForwardReference, QOpcUa::UaStatusCode statusCode) {
Q_Q(QOpcUaClient);
emit q->deleteReferenceFinished(sourceNodeId, referenceTypeId, targetNodeId, isForwardReference, statusCode);
});
+
+ QObject::connect(m_impl.data(), &QOpcUaClientImpl::connectError, [this](QOpcUaErrorState *errorState) {
+ Q_Q(QOpcUaClient);
+ emit q->connectError(errorState);
+ });
+
+ QObject::connect(m_impl.data(), &QOpcUaClientImpl::passwordForPrivateKeyRequired, [this](QString privateKeyFilePath, QString *password, bool previousTryWasInvalid) {
+ Q_Q(QOpcUaClient);
+ emit q->passwordForPrivateKeyRequired(privateKeyFilePath, password, previousTryWasInvalid);
+ });
}
QOpcUaClientPrivate::~QOpcUaClientPrivate()
{
}
-void QOpcUaClientPrivate::connectToEndpoint(const QUrl &url)
+void QOpcUaClientPrivate::connectToEndpoint(const QOpcUaEndpointDescription &endpoint)
{
- bool result = checkAndSetUrl(url);
- if (result) {
- setStateAndError(QOpcUaClient::Connecting);
- m_impl->connectToEndpoint(url);
- } else {
- setStateAndError(QOpcUaClient::Disconnected, QOpcUaClient::InvalidUrl);
- }
+ m_endpoint = endpoint;
+ m_impl->connectToEndpoint(endpoint);
}
void QOpcUaClientPrivate::disconnectFromEndpoint()
@@ -131,17 +140,6 @@ void QOpcUaClientPrivate::disconnectFromEndpoint()
m_impl->disconnectFromEndpoint();
}
-bool QOpcUaClientPrivate::checkAndSetUrl(const QUrl &url)
-{
- if (url.scheme() != QStringLiteral("opc.tcp")) {
- qCWarning(QT_OPCUA) << "Wrong url scheme, could not connect";
- return false;
- }
-
- m_url = url;
- return true;
-}
-
void QOpcUaClientPrivate::setStateAndError(QOpcUaClient::ClientState state,
QOpcUaClient::ClientError error)
{
@@ -261,4 +259,24 @@ void QOpcUaClientPrivate::setupNamespaceArrayMonitoring()
}
}
+void QOpcUaClientPrivate::setApplicationIdentity(const QOpcUaApplicationIdentity &identity)
+{
+ m_applicationIdentity = identity;
+}
+
+QOpcUaApplicationIdentity QOpcUaClientPrivate::applicationIdentity() const
+{
+ return m_applicationIdentity;
+}
+
+void QOpcUaClientPrivate::setPkiConfiguration(const QOpcUaPkiConfiguration &config)
+{
+ m_pkiConfig = config;
+}
+
+QOpcUaPkiConfiguration QOpcUaClientPrivate::pkiConfiguration() const
+{
+ return m_pkiConfig;
+}
+
QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuacomplexnumber.cpp b/src/opcua/client/qopcuacomplexnumber.cpp
new file mode 100644
index 0000000..7ef2cdf
--- /dev/null
+++ b/src/opcua/client/qopcuacomplexnumber.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuacomplexnumber.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaComplexNumber
+ \inmodule QtOpcUa
+ \brief The OPC UA ComplexNumber type.
+
+ The ComplexNumberType defined in OPC-UA part 8, 5.6.4.
+ It stores a complex number with float precision.
+*/
+
+class QOpcUaComplexNumberData : public QSharedData
+{
+public:
+ float real{0};
+ float imaginary{0};
+};
+
+QOpcUaComplexNumber::QOpcUaComplexNumber()
+ : data(new QOpcUaComplexNumberData)
+{
+}
+
+QOpcUaComplexNumber::QOpcUaComplexNumber(const QOpcUaComplexNumber &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Sets the values from \a rhs in this complex number.
+*/
+QOpcUaComplexNumber &QOpcUaComplexNumber::operator=(const QOpcUaComplexNumber &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+QOpcUaComplexNumber::~QOpcUaComplexNumber()
+{
+
+}
+
+/*!
+ Returns the imaginary part of the complex number.
+*/
+float QOpcUaComplexNumber::imaginary() const
+{
+ return data->imaginary;
+}
+
+/*!
+ Sets the imaginary part of the complex number to \a imaginary.
+*/
+void QOpcUaComplexNumber::setImaginary(float imaginary)
+{
+ data->imaginary = imaginary;
+}
+
+/*!
+ Returns the real part of the complex number.
+*/
+float QOpcUaComplexNumber::real() const
+{
+ return data->real;
+}
+
+/*!
+ Sets the real part of the complex number to \a real.
+*/
+void QOpcUaComplexNumber::setReal(float real)
+{
+ data->real = real;
+}
+
+/*!
+ Constructs a complex number with real part \a real and imaginary part \a imaginary.
+*/
+QOpcUaComplexNumber::QOpcUaComplexNumber(float real, float imaginary)
+ : data(new QOpcUaComplexNumberData)
+{
+ data->real = real;
+ data->imaginary = imaginary;
+}
+
+/*!
+ Returns \c true if this complex number has the same value as \a rhs.
+*/
+bool QOpcUaComplexNumber::operator==(const QOpcUaComplexNumber &rhs) const
+{
+ return qFloatDistance(data->real, rhs.real()) == 0 &&
+ qFloatDistance(data->imaginary, rhs.imaginary()) == 0;
+}
+
+/*!
+ Converts this complex number to \l QVariant.
+*/
+QOpcUaComplexNumber::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuacomplexnumber.h b/src/opcua/client/qopcuacomplexnumber.h
new file mode 100644
index 0000000..c572887
--- /dev/null
+++ b/src/opcua/client/qopcuacomplexnumber.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUACOMPLEXNUMBER_H
+#define QOPCUACOMPLEXNUMBER_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaComplexNumberData;
+class Q_OPCUA_EXPORT QOpcUaComplexNumber
+{
+public:
+ QOpcUaComplexNumber();
+ QOpcUaComplexNumber(const QOpcUaComplexNumber &);
+ QOpcUaComplexNumber(float real, float imaginary);
+ QOpcUaComplexNumber &operator=(const QOpcUaComplexNumber &);
+ bool operator==(const QOpcUaComplexNumber &rhs) const;
+ operator QVariant() const;
+ ~QOpcUaComplexNumber();
+
+ float real() const;
+ void setReal(float real);
+
+ float imaginary() const;
+ void setImaginary(float imaginary);
+
+private:
+ QSharedDataPointer<QOpcUaComplexNumberData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaComplexNumber)
+
+#endif // QOPCUACOMPLEXNUMBER_H
diff --git a/src/opcua/client/qopcuacontentfilterelement.cpp b/src/opcua/client/qopcuacontentfilterelement.cpp
new file mode 100644
index 0000000..583a154
--- /dev/null
+++ b/src/opcua/client/qopcuacontentfilterelement.cpp
@@ -0,0 +1,225 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuacontentfilterelement.h"
+#include "qopcuasimpleattributeoperand.h"
+#include "qopcuaattributeoperand.h"
+#include "qopcualiteraloperand.h"
+#include "qopcuaelementoperand.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaContentFilterElement
+ \inmodule QtOpcUa
+ \brief The OPC UA ContentFilterElement.
+
+ A content filter element contains an operator and a list of operands.
+ There are four different operator types which contain literal values, references to
+ attributes of nodes or to other content filter elements.
+
+ A combination of one or more content filter elements makes a content filter which is used
+ by the server to filter data for the criteria defined by the content filter elements.
+ For example, the \c where clause of an event filter is a content filter which is used to decide
+ if a notification is generated for an event.
+*/
+
+/*!
+ \enum QOpcUaContentFilterElement::FilterOperator
+
+ FilterOperator enumerates all possible operators for a ContentFilterElement that are specified in
+ OPC-UA part 4, Tables 115 and 116.
+
+ \value Equals
+ \value IsNull
+ \value GreaterThan
+ \value LessThan
+ \value GreaterThanOrEqual
+ \value LessThanOrEqual
+ \value Like
+ \value Not
+ \value Between
+ \value InList
+ \value And
+ \value Or
+ \value Cast
+ \value InView
+ \value OfType
+ \value RelatedTo
+ \value BitwiseAnd
+ \value BitwiseOr
+*/
+
+class QOpcUaContentFilterElementData : public QSharedData
+{
+public:
+ QOpcUaContentFilterElement::FilterOperator filterOperator;
+ QVector<QVariant> filterOperands;
+};
+
+QOpcUaContentFilterElement::QOpcUaContentFilterElement()
+ : data(new QOpcUaContentFilterElementData)
+{
+}
+
+/*!
+ Constructs a content filter element from \a rhs.
+*/
+QOpcUaContentFilterElement::QOpcUaContentFilterElement(const QOpcUaContentFilterElement &rhs)
+ : data(rhs.data)
+{
+}
+
+QOpcUaContentFilterElement::~QOpcUaContentFilterElement() = default;
+
+/*!
+ Sets the values from \a rhs in this content filter element.
+*/
+QOpcUaContentFilterElement &QOpcUaContentFilterElement::operator=(const QOpcUaContentFilterElement &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns \c true if this content filter element has the same value as \a rhs.
+*/
+bool QOpcUaContentFilterElement::operator==(const QOpcUaContentFilterElement &rhs) const
+{
+ return filterOperator() == rhs.filterOperator() && filterOperands() == rhs.filterOperands();
+}
+
+/*!
+ Converts this content filter element to \l QVariant.
+*/
+QOpcUaContentFilterElement::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+/*!
+ Returns the operands of the filter element.
+*/
+QVector<QVariant> QOpcUaContentFilterElement::filterOperands() const
+{
+ return data->filterOperands;
+}
+
+/*!
+ Returns a reference to the filter operands.
+
+ \sa filterOperands()
+*/
+QVector<QVariant> &QOpcUaContentFilterElement::filterOperandsRef()
+{
+ return data->filterOperands;
+}
+
+/*!
+ Sets the filter operands for this content filter element to \a filterOperands.
+ Supported classes are \l QOpcUaElementOperand, \l QOpcUaLiteralOperand,
+ \l QOpcUaSimpleAttributeOperand and \l QOpcUaAttributeOperand.
+*/
+void QOpcUaContentFilterElement::setFilterOperands(const QVector<QVariant> &filterOperands)
+{
+ data->filterOperands = filterOperands;
+}
+
+/*!
+ Returns the filter operator.
+*/
+QOpcUaContentFilterElement::FilterOperator QOpcUaContentFilterElement::filterOperator() const
+{
+ return data->filterOperator;
+}
+
+/*!
+ Sets the operator that is applied to the filter operands to \a filterOperator.
+*/
+void QOpcUaContentFilterElement::setFilterOperator(QOpcUaContentFilterElement::FilterOperator filterOperator)
+{
+ data->filterOperator = filterOperator;
+}
+
+/*!
+ Sets filter operator \a op in this content filter element.
+ If multiple operators are streamed into one content filter element, only the last operator is used.
+ All others are discarded.
+*/
+QOpcUaContentFilterElement &QOpcUaContentFilterElement::operator<<(QOpcUaContentFilterElement::FilterOperator op)
+{
+ setFilterOperator(op);
+ return *this;
+}
+
+/*!
+ Adds the simple attribute operand \a op to the operands list of this content filter element.
+*/
+QOpcUaContentFilterElement &QOpcUaContentFilterElement::operator<<(const QOpcUaSimpleAttributeOperand &op)
+{
+ filterOperandsRef().append(op);
+ return *this;
+}
+
+/*!
+ Adds the attribute operand \a op to the operands list of this content filter element.
+*/
+QOpcUaContentFilterElement &QOpcUaContentFilterElement::operator<<(const QOpcUaAttributeOperand &op)
+{
+ filterOperandsRef().append(op);
+ return *this;
+}
+
+/*!
+ Adds the literal operand \a op to the operands list of this content filter element.
+*/
+QOpcUaContentFilterElement &QOpcUaContentFilterElement::operator<<(const QOpcUaLiteralOperand &op)
+{
+ filterOperandsRef().append(op);
+ return *this;
+}
+
+/*!
+ Adds the element operand \a op to the operands list of this content filter element.
+*/
+QOpcUaContentFilterElement &QOpcUaContentFilterElement::operator<<(const QOpcUaElementOperand &op)
+{
+ filterOperandsRef().append(op);
+ return *this;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuacontentfilterelement.h b/src/opcua/client/qopcuacontentfilterelement.h
new file mode 100644
index 0000000..644acf7
--- /dev/null
+++ b/src/opcua/client/qopcuacontentfilterelement.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUACONTENTFILTERELEMENT_H
+#define QOPCUACONTENTFILTERELEMENT_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaSimpleAttributeOperand;
+class QOpcUaAttributeOperand;
+class QOpcUaElementOperand;
+class QOpcUaLiteralOperand;
+
+class QOpcUaContentFilterElementData;
+class Q_OPCUA_EXPORT QOpcUaContentFilterElement
+{
+public:
+ QOpcUaContentFilterElement();
+ QOpcUaContentFilterElement(const QOpcUaContentFilterElement &);
+ QOpcUaContentFilterElement &operator=(const QOpcUaContentFilterElement &);
+ bool operator==(const QOpcUaContentFilterElement &rhs) const;
+ operator QVariant() const;
+ ~QOpcUaContentFilterElement();
+
+ // Specified in OPC-UA part 4, Tables 115 and 116
+ enum FilterOperator : quint32 {
+ Equals = 0,
+ IsNull = 1,
+ GreaterThan = 2,
+ LessThan = 3,
+ GreaterThanOrEqual = 4,
+ LessThanOrEqual = 5,
+ Like = 6,
+ Not = 7,
+ Between = 8,
+ InList = 9,
+ And = 10,
+ Or = 11,
+ Cast = 12,
+ InView = 13,
+ OfType = 14,
+ RelatedTo = 15,
+ BitwiseAnd = 16,
+ BitwiseOr = 17
+ };
+
+ QOpcUaContentFilterElement &operator<<(FilterOperator op);
+ QOpcUaContentFilterElement &operator<<(const QOpcUaSimpleAttributeOperand &op);
+ QOpcUaContentFilterElement &operator<<(const QOpcUaAttributeOperand &op);
+ QOpcUaContentFilterElement &operator<<(const QOpcUaLiteralOperand &op);
+ QOpcUaContentFilterElement &operator<<(const QOpcUaElementOperand &op);
+
+
+ QOpcUaContentFilterElement::FilterOperator filterOperator() const;
+ void setFilterOperator(QOpcUaContentFilterElement::FilterOperator filterOperator);
+
+ QVector<QVariant> filterOperands() const;
+ QVector<QVariant> &filterOperandsRef();
+ void setFilterOperands(const QVector<QVariant> &filterOperands);
+
+private:
+ QSharedDataPointer<QOpcUaContentFilterElementData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaContentFilterElement)
+
+#endif // QOPCUACONTENTFILTERELEMENT_H
diff --git a/src/opcua/client/qopcuacontentfilterelementresult.cpp b/src/opcua/client/qopcuacontentfilterelementresult.cpp
new file mode 100644
index 0000000..09802e6
--- /dev/null
+++ b/src/opcua/client/qopcuacontentfilterelementresult.cpp
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuacontentfilterelementresult.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaContentFilterElementResult
+ \inmodule QtOpcUa
+ \brief The OPC UA ContentFilterElementResult.
+
+ QOpcUaContentFilterElementResult contains the status code for a
+ filter element and all its operands.
+*/
+
+class QOpcUaContentFilterElementResultData : public QSharedData
+{
+public:
+ QOpcUa::UaStatusCode statusCode {QOpcUa::UaStatusCode::Good};
+ QVector<QOpcUa::UaStatusCode> operandStatusCodes;
+};
+
+QOpcUaContentFilterElementResult::QOpcUaContentFilterElementResult()
+ : data(new QOpcUaContentFilterElementResultData)
+{
+}
+
+/*!
+ Constructs a content filter element result from \a rhs.
+*/
+QOpcUaContentFilterElementResult::QOpcUaContentFilterElementResult(const QOpcUaContentFilterElementResult &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Sets the values from \a rhs in this content filter element result.
+*/
+QOpcUaContentFilterElementResult &QOpcUaContentFilterElementResult::operator=(const QOpcUaContentFilterElementResult &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+QOpcUaContentFilterElementResult::~QOpcUaContentFilterElementResult()
+{
+}
+
+/*!
+ Returns the status code for the filter element.
+*/
+QOpcUa::UaStatusCode QOpcUaContentFilterElementResult::statusCode() const
+{
+ return data->statusCode;
+}
+
+/*!
+ Sets the status code for the filter element to \a statusCode.
+*/
+void QOpcUaContentFilterElementResult::setStatusCode(QOpcUa::UaStatusCode statusCode)
+{
+ data->statusCode = statusCode;
+}
+
+/*!
+ Returns the status codes for all filter operands in the order that was used in the filter.
+*/
+QVector<QOpcUa::UaStatusCode> QOpcUaContentFilterElementResult::operandStatusCodes() const
+{
+ return data->operandStatusCodes;
+}
+
+/*!
+ Sets the status codes for all filter operands to \a operandStatusCodes.
+*/
+void QOpcUaContentFilterElementResult::setOperandStatusCodes(const QVector<QOpcUa::UaStatusCode> &operandStatusCodes)
+{
+ data->operandStatusCodes = operandStatusCodes;
+}
+
+/*!
+ Returns a reference to the operand status codes.
+
+ \sa operandStatusCodes()
+*/
+QVector<QOpcUa::UaStatusCode> &QOpcUaContentFilterElementResult::operandStatusCodesRef()
+{
+ return data->operandStatusCodes;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuacontentfilterelementresult.h b/src/opcua/client/qopcuacontentfilterelementresult.h
new file mode 100644
index 0000000..3798e6b
--- /dev/null
+++ b/src/opcua/client/qopcuacontentfilterelementresult.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUACONTENTFILTERELEMENTRESULT_H
+#define QOPCUACONTENTFILTERELEMENTRESULT_H
+
+#include <QtOpcUa/qopcuatype.h>
+
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaContentFilterElementResultData;
+class Q_OPCUA_EXPORT QOpcUaContentFilterElementResult
+{
+public:
+ QOpcUaContentFilterElementResult();
+ QOpcUaContentFilterElementResult(const QOpcUaContentFilterElementResult &);
+ QOpcUaContentFilterElementResult &operator=(const QOpcUaContentFilterElementResult &);
+ ~QOpcUaContentFilterElementResult();
+
+ QOpcUa::UaStatusCode statusCode() const;
+ void setStatusCode(QOpcUa::UaStatusCode statusCode);
+
+ QVector<QOpcUa::UaStatusCode> operandStatusCodes() const;
+ QVector<QOpcUa::UaStatusCode> &operandStatusCodesRef();
+ void setOperandStatusCodes(const QVector<QOpcUa::UaStatusCode> &operandStatusCodes);
+
+private:
+ QSharedDataPointer<QOpcUaContentFilterElementResultData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaContentFilterElementResult)
+
+#endif // QOPCUACONTENTFILTERELEMENTRESULT_H
diff --git a/src/opcua/client/qopcuadeletereferenceitem.cpp b/src/opcua/client/qopcuadeletereferenceitem.cpp
index 8a4fb7d..baa8200 100644
--- a/src/opcua/client/qopcuadeletereferenceitem.cpp
+++ b/src/opcua/client/qopcuadeletereferenceitem.cpp
@@ -36,6 +36,7 @@
#include "qopcuanodecreationattributes.h"
#include "qopcuadeletereferenceitem.h"
+#include "qopcuaexpandednodeid.h"
QT_BEGIN_NAMESPACE
@@ -53,7 +54,7 @@ public:
QString sourceNodeId;
QString referenceTypeId;
bool isForwardReference {true};
- QOpcUa::QExpandedNodeId targetNodeId;
+ QOpcUaExpandedNodeId targetNodeId;
bool deleteBidirectional {true};
};
@@ -105,7 +106,7 @@ void QOpcUaDeleteReferenceItem::setDeleteBidirectional(bool deleteBidirectional)
/*!
Returns the target node id.
*/
-QOpcUa::QExpandedNodeId QOpcUaDeleteReferenceItem::targetNodeId() const
+QOpcUaExpandedNodeId QOpcUaDeleteReferenceItem::targetNodeId() const
{
return data->targetNodeId;
}
@@ -113,7 +114,7 @@ QOpcUa::QExpandedNodeId QOpcUaDeleteReferenceItem::targetNodeId() const
/*!
Sets the node id of the target node to \a targetNodeId.
*/
-void QOpcUaDeleteReferenceItem::setTargetNodeId(const QOpcUa::QExpandedNodeId &targetNodeId)
+void QOpcUaDeleteReferenceItem::setTargetNodeId(const QOpcUaExpandedNodeId &targetNodeId)
{
data->targetNodeId = targetNodeId;
}
diff --git a/src/opcua/client/qopcuadeletereferenceitem.h b/src/opcua/client/qopcuadeletereferenceitem.h
index 9d36902..51ed135 100644
--- a/src/opcua/client/qopcuadeletereferenceitem.h
+++ b/src/opcua/client/qopcuadeletereferenceitem.h
@@ -38,10 +38,13 @@
#define QOPCUADELETEREFERENCEITEM_H
#include <QtOpcUa/qopcuanodecreationattributes.h>
-#include <QtOpcUa/qopcuatype.h>
+
+#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
+class QOpcUaExpandedNodeId;
+
class QOpcUaDeleteReferenceItemData;
class Q_OPCUA_EXPORT QOpcUaDeleteReferenceItem
{
@@ -60,8 +63,8 @@ public:
bool isForwardReference() const;
void setIsForwardReference(bool isForwardReference);
- QOpcUa::QExpandedNodeId targetNodeId() const;
- void setTargetNodeId(const QOpcUa::QExpandedNodeId &targetNodeId);
+ QOpcUaExpandedNodeId targetNodeId() const;
+ void setTargetNodeId(const QOpcUaExpandedNodeId &targetNodeId);
bool deleteBidirectional() const;
void setDeleteBidirectional(bool deleteBidirectional);
diff --git a/src/opcua/client/qopcuadoublecomplexnumber.cpp b/src/opcua/client/qopcuadoublecomplexnumber.cpp
new file mode 100644
index 0000000..cd17bcb
--- /dev/null
+++ b/src/opcua/client/qopcuadoublecomplexnumber.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuadoublecomplexnumber.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaDoubleComplexNumber
+ \inmodule QtOpcUa
+ \brief The OPC UA DoubleComplexNumber type.
+
+ The DoubleComplexNumberType defined in OPC-UA part 8, 5.6.5.
+ It stores a complex number with double precision.
+*/
+
+class QOpcUaDoubleComplexNumberData : public QSharedData
+{
+public:
+ double real{0};
+ double imaginary{0};
+};
+
+QOpcUaDoubleComplexNumber::QOpcUaDoubleComplexNumber()
+ : data(new QOpcUaDoubleComplexNumberData)
+{
+}
+
+QOpcUaDoubleComplexNumber::QOpcUaDoubleComplexNumber(const QOpcUaDoubleComplexNumber &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Sets the values from \a rhs in this double complex number.
+*/
+QOpcUaDoubleComplexNumber &QOpcUaDoubleComplexNumber::operator=(const QOpcUaDoubleComplexNumber &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+QOpcUaDoubleComplexNumber::~QOpcUaDoubleComplexNumber()
+{
+
+}
+
+/*!
+ Returns the imaginary part of the complex number.
+*/
+double QOpcUaDoubleComplexNumber::imaginary() const
+{
+ return data->imaginary;
+}
+
+/*!
+ Sets the imaginary part of the complex number to \a imaginary.
+*/
+void QOpcUaDoubleComplexNumber::setImaginary(double imaginary)
+{
+ data->imaginary = imaginary;
+}
+
+/*!
+ Returns the real part of the complex number.
+*/
+double QOpcUaDoubleComplexNumber::real() const
+{
+ return data->real;
+}
+
+/*!
+ Sets the real part of the complex number to \a real.
+*/
+void QOpcUaDoubleComplexNumber::setReal(double real)
+{
+ data->real = real;
+}
+
+/*!
+ Constructs a double complex number with real part \a real and imaginary part \a imaginary.
+*/
+QOpcUaDoubleComplexNumber::QOpcUaDoubleComplexNumber(double real, double imaginary)
+ : data(new QOpcUaDoubleComplexNumberData)
+{
+ data->real = real;
+ data->imaginary = imaginary;
+}
+
+/*!
+ Returns \c true if this double complex number has the same value as \a rhs.
+*/
+bool QOpcUaDoubleComplexNumber::operator==(const QOpcUaDoubleComplexNumber &rhs) const
+{
+ return qFloatDistance(data->real, rhs.real()) == 0 &&
+ qFloatDistance(data->imaginary, rhs.imaginary()) == 0;
+}
+
+/*!
+ Converts this double complex number to \l QVariant.
+*/
+QOpcUaDoubleComplexNumber::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuadoublecomplexnumber.h b/src/opcua/client/qopcuadoublecomplexnumber.h
new file mode 100644
index 0000000..43543e2
--- /dev/null
+++ b/src/opcua/client/qopcuadoublecomplexnumber.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUADOUBLECOMPLEXNUMBER_H
+#define QOPCUADOUBLECOMPLEXNUMBER_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaDoubleComplexNumberData;
+class Q_OPCUA_EXPORT QOpcUaDoubleComplexNumber
+{
+public:
+ QOpcUaDoubleComplexNumber();
+ QOpcUaDoubleComplexNumber(const QOpcUaDoubleComplexNumber &);
+ QOpcUaDoubleComplexNumber(double real, double imaginary);
+ QOpcUaDoubleComplexNumber &operator=(const QOpcUaDoubleComplexNumber &);
+ bool operator==(const QOpcUaDoubleComplexNumber &rhs) const;
+ operator QVariant() const;
+ ~QOpcUaDoubleComplexNumber();
+
+ double real() const;
+ void setReal(double real);
+
+ double imaginary() const;
+ void setImaginary(double imaginary);
+
+private:
+ QSharedDataPointer<QOpcUaDoubleComplexNumberData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaDoubleComplexNumber)
+
+#endif // QOPCUADOUBLECOMPLEXNUMBER_H
diff --git a/src/opcua/client/qopcuaelementoperand.cpp b/src/opcua/client/qopcuaelementoperand.cpp
new file mode 100644
index 0000000..096d4b2
--- /dev/null
+++ b/src/opcua/client/qopcuaelementoperand.cpp
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuaelementoperand.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaElementOperand
+ \inmodule QtOpcUa
+ \brief The OPC UA ElementOperand type.
+
+ The ElementOperand is defined in OPC-UA part 4, 7.4.4.2.
+ It is used to identify another element in the filter by its index
+ (the first element has the index 0).
+
+ This is required to create complex filters, for example to reference
+ the two operands of the AND operation in ((Severity > 500) AND (Message == "TestString")).
+ The first step is to create content filter elements for the two conditions (Severity > 500)
+ and (Message == "TestString"). A third content filter element is required to create an AND
+ combination of the two conditions. It consists of the AND operator and two element operands
+ with the indices of the two conditions created before:
+
+ \code
+ QOpcUaMonitoringParameters::EventFilter filter;
+ ...
+ // setup select clauses
+ ...
+ QOpcUaContentFilterElement condition1;
+ QOpcUaContentFilterElement condition2;
+ QOpcUaContentFilterElement condition3;
+ condition1 << QOpcUaContentFilterElement::FilterOperator::GreaterThan << QOpcUaSimpleAttributeOperand("Severity") <<
+ QOpcUaLiteralOperand(quint16(500), QOpcUa::Types::UInt16);
+ condition2 << QOpcUaContentFilterElement::FilterOperator::Equals << QOpcUaSimpleAttributeOperand("Message") <<
+ QOpcUaLiteralOperand("TestString", QOpcUa::Types::String);
+ condition3 << QOpcUaContentFilterElement::FilterOperator::And << QOpcUaElementOperand(0) << QOpcUaElementOperand(1);
+ filter << condition1 << condition2 << condition3;
+ \endcode
+*/
+
+class QOpcUaElementOperandData : public QSharedData
+{
+public:
+ quint32 index{0};
+};
+
+QOpcUaElementOperand::QOpcUaElementOperand()
+ : data(new QOpcUaElementOperandData)
+{
+}
+
+/*!
+ Constructs an element operand from \a rhs.
+*/
+QOpcUaElementOperand::QOpcUaElementOperand(const QOpcUaElementOperand &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Constructs an element operand with index \a index.
+*/
+QOpcUaElementOperand::QOpcUaElementOperand(quint32 index)
+ : data(new QOpcUaElementOperandData)
+{
+ setIndex(index);
+}
+
+/*!
+ Sets the values from \a rhs in this element operand.
+*/
+QOpcUaElementOperand &QOpcUaElementOperand::operator=(const QOpcUaElementOperand &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Converts this element operand to \l QVariant.
+*/
+QOpcUaElementOperand::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+QOpcUaElementOperand::~QOpcUaElementOperand()
+{
+}
+
+/*!
+ Returns the index of the filter element that is going to be used as operand.
+*/
+quint32 QOpcUaElementOperand::index() const
+{
+ return data->index;
+}
+
+/*!
+ Sets the index of the filter element that is going to be used as operand to \a index.
+*/
+void QOpcUaElementOperand::setIndex(quint32 index)
+{
+ data->index = index;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaelementoperand.h b/src/opcua/client/qopcuaelementoperand.h
new file mode 100644
index 0000000..bcbdb9d
--- /dev/null
+++ b/src/opcua/client/qopcuaelementoperand.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAELEMENTOPERAND_H
+#define QOPCUAELEMENTOPERAND_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+// OPC-UA part 4, 7.4.4.2
+class QOpcUaElementOperandData;
+class Q_OPCUA_EXPORT QOpcUaElementOperand
+{
+public:
+ QOpcUaElementOperand();
+ QOpcUaElementOperand(const QOpcUaElementOperand &);
+ QOpcUaElementOperand(quint32 index);
+ QOpcUaElementOperand &operator=(const QOpcUaElementOperand &);
+ operator QVariant() const;
+ ~QOpcUaElementOperand();
+
+ quint32 index() const;
+ void setIndex(quint32 index);
+
+private:
+ QSharedDataPointer<QOpcUaElementOperandData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaElementOperand)
+
+#endif // QOPCUAELEMENTOPERAND_H
diff --git a/src/opcua/client/qopcuaendpointdescription.cpp b/src/opcua/client/qopcuaendpointdescription.cpp
new file mode 100644
index 0000000..91f916e
--- /dev/null
+++ b/src/opcua/client/qopcuaendpointdescription.cpp
@@ -0,0 +1,349 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuaendpointdescription.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaEndpointDescription
+ \inmodule QtOpcUa
+ \brief The OPC UA EndpointDescription.
+
+ An endpoint description contains information about an endpoint and how to connect to it.
+*/
+
+/*!
+ \qmltype EndpointDescription
+ \inqmlmodule QtOpcUa
+ \brief The OPC UA EndpointDescription.
+ \since QtOpcUa 5.13
+
+ An endpoint description contains information about an endpoint and how to connect to it.
+*/
+
+/*!
+ \enum QOpcUaEndpointDescription::MessageSecurityMode
+
+ This enum type holds the security mode supported by the endpoint.
+
+ \value Invalid The default value, will be rejected by the server.
+ \value None No security.
+ \value Sign Messages are signed but not encrypted.
+ \value SignAndEncrypt Messages are signed and encrypted.
+*/
+
+/*!
+ \qmlproperty enumeration EndpointDescription::MessageSecurityMode
+
+ The security mode supported by the endpoint.
+
+ \value Invalid The default value, will be rejected by the server.
+ \value None No security.
+ \value Sign Messages are signed but not encrypted.
+ \value SignAndEncrypt Messages are signed and encrypted.
+*/
+
+
+/*!
+ \property QOpcUaEndpointDescription::endpointUrl
+
+ The URL for the endpoint.
+ */
+
+/*!
+ \qmlproperty string EndpointDescription::endpointUrl
+
+ The URL for the endpoint.
+ */
+
+/*!
+ \property QOpcUaEndpointDescription::securityMode
+
+ Security mode supported by this endpoint.
+ */
+
+/*!
+ \qmlproperty MessageSecurityMode EndpointDescription::securityMode
+
+ Security mode supported by this endpoint.
+ */
+
+/*!
+ \property QOpcUaEndpointDescription::securityPolicy
+
+ The URI of the security policy.
+ */
+
+/*!
+ \qmlproperty string EndpointDescription::securityPolicy
+
+ The URI of the security policy.
+ */
+
+
+/*!
+ \property QOpcUaEndpointDescription::server
+
+ The application description of the server.
+ */
+
+/*!
+ \qmlproperty ApplicationDescription EndpointDescription::server
+
+ The application description of the server.
+ */
+
+/*!
+ \property QOpcUaEndpointDescription::userIdentityTokens
+
+ List of user identity tokens the endpoint will accept.
+ */
+
+/*!
+ \qmlproperty list<UserTokenPolicy> EndpointDescription::userIdentityTokens
+
+ List of user identity tokens the endpoint will accept.
+ */
+
+class QOpcUaEndpointDescriptionData : public QSharedData
+{
+public:
+ QString endpointUrl;
+ QOpcUaApplicationDescription server;
+ QByteArray serverCertificate;
+ QOpcUaEndpointDescription::MessageSecurityMode securityMode{QOpcUaEndpointDescription::MessageSecurityMode::None};
+ QString securityPolicy;
+ QVector<QOpcUaUserTokenPolicy> userIdentityTokens;
+ QString transportProfileUri;
+ quint8 securityLevel{0};
+};
+
+QOpcUaEndpointDescription::QOpcUaEndpointDescription()
+ : data(new QOpcUaEndpointDescriptionData)
+{
+}
+
+/*!
+ Constructs an endpoint description from \a rhs.
+*/
+QOpcUaEndpointDescription::QOpcUaEndpointDescription(const QOpcUaEndpointDescription &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Sets the values from \a rhs in this endpoint description.
+*/
+QOpcUaEndpointDescription &QOpcUaEndpointDescription::operator=(const QOpcUaEndpointDescription &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns \c true if this endpoint description has the same value as \a rhs.
+ */
+bool QOpcUaEndpointDescription::operator==(const QOpcUaEndpointDescription &rhs) const
+{
+ return rhs.server() == server() &&
+ rhs.endpointUrl() == endpointUrl() &&
+ rhs.securityMode() == securityMode() &&
+ rhs.securityLevel() == securityLevel() &&
+ rhs.securityPolicy() == securityPolicy() &&
+ rhs.serverCertificate() == serverCertificate() &&
+ rhs.userIdentityTokens() == userIdentityTokens() &&
+ rhs.transportProfileUri() == transportProfileUri();
+}
+
+QOpcUaEndpointDescription::~QOpcUaEndpointDescription()
+{
+}
+
+/*!
+ Returns a relative index assigned by the server. It describes how secure this
+ endpoint is compared to other endpoints of the same server. An endpoint with strong
+ security measures has a higher security level than one with weaker or no security
+ measures.
+
+ Security level 0 indicates an endpoint for backward compatibility purposes which
+ should only be used if the client does not support the security measures required
+ by more secure endpoints.
+*/
+quint8 QOpcUaEndpointDescription::securityLevel() const
+{
+ return data->securityLevel;
+}
+
+/*!
+ Sets the security level to \a securityLevel.
+*/
+void QOpcUaEndpointDescription::setSecurityLevel(quint8 securityLevel)
+{
+ data->securityLevel = securityLevel;
+}
+
+/*!
+ Returns the URI of the transport profile supported by the endpoint.
+*/
+QString QOpcUaEndpointDescription::transportProfileUri() const
+{
+ return data->transportProfileUri;
+}
+
+/*!
+ Sets the URI of the transport profile supported by the endpoint to \a transportProfileUri.
+*/
+void QOpcUaEndpointDescription::setTransportProfileUri(const QString &transportProfileUri)
+{
+ data->transportProfileUri = transportProfileUri;
+}
+
+/*!
+ Returns a list of user identity tokens the endpoint will accept.
+*/
+QVector<QOpcUaUserTokenPolicy> QOpcUaEndpointDescription::userIdentityTokens() const
+{
+ return data->userIdentityTokens;
+}
+
+/*!
+ Returns a reference to a list of user identity tokens the endpoint will accept.
+*/
+QVector<QOpcUaUserTokenPolicy> &QOpcUaEndpointDescription::userIdentityTokensRef()
+{
+ return data->userIdentityTokens;
+}
+
+/*!
+ Sets the user identity tokens to \a userIdentityTokens.
+*/
+void QOpcUaEndpointDescription::setUserIdentityTokens(const QVector<QOpcUaUserTokenPolicy> &userIdentityTokens)
+{
+ data->userIdentityTokens = userIdentityTokens;
+}
+
+/*!
+ Returns the URI of the security policy.
+*/
+QString QOpcUaEndpointDescription::securityPolicy() const
+{
+ return data->securityPolicy;
+}
+
+/*!
+ Sets the URI of the security policy to \a securityPolicy.
+*/
+void QOpcUaEndpointDescription::setSecurityPolicy(const QString &securityPolicy)
+{
+ data->securityPolicy = securityPolicy;
+}
+
+/*!
+ Returns the security mode supported by this endpoint.
+*/
+QOpcUaEndpointDescription::MessageSecurityMode QOpcUaEndpointDescription::securityMode() const
+{
+ return data->securityMode;
+}
+
+/*!
+ Sets the security mode supported by this endpoint to \a securityMode.
+*/
+void QOpcUaEndpointDescription::setSecurityMode(MessageSecurityMode securityMode)
+{
+ data->securityMode = securityMode;
+}
+
+/*!
+ Returns the application instance certificate of the server.
+*/
+QByteArray QOpcUaEndpointDescription::serverCertificate() const
+{
+ return data->serverCertificate;
+}
+
+/*!
+ Sets the application instance certificate of the server to \a serverCertificate.
+*/
+void QOpcUaEndpointDescription::setServerCertificate(const QByteArray &serverCertificate)
+{
+ data->serverCertificate = serverCertificate;
+}
+
+/*!
+ Returns the application description of the server.
+*/
+QOpcUaApplicationDescription QOpcUaEndpointDescription::server() const
+{
+ return data->server;
+}
+
+/*!
+ Returns a reference to the application description of the server.
+*/
+QOpcUaApplicationDescription &QOpcUaEndpointDescription::serverRef()
+{
+ return data->server;
+}
+
+/*!
+ Sets the application description of the server to \a server.
+*/
+void QOpcUaEndpointDescription::setServer(const QOpcUaApplicationDescription &server)
+{
+ data->server = server;
+}
+
+/*!
+ Returns the URL for the endpoint.
+*/
+QString QOpcUaEndpointDescription::endpointUrl() const
+{
+ return data->endpointUrl;
+}
+
+/*!
+ Sets the URL for the endpoint to \a endpointUrl.
+*/
+void QOpcUaEndpointDescription::setEndpointUrl(const QString &endpointUrl)
+{
+ data->endpointUrl = endpointUrl;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaendpointdescription.h b/src/opcua/client/qopcuaendpointdescription.h
new file mode 100644
index 0000000..478b5ba
--- /dev/null
+++ b/src/opcua/client/qopcuaendpointdescription.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAENDPOINTDESCRIPTION_H
+#define QOPCUAENDPOINTDESCRIPTION_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+#include <QtOpcUa/qopcuaapplicationdescription.h>
+#include <QtOpcUa/qopcuausertokenpolicy.h>
+
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaEndpointDescriptionData;
+class Q_OPCUA_EXPORT QOpcUaEndpointDescription
+{
+ Q_GADGET
+ Q_PROPERTY(QString endpointUrl READ endpointUrl)
+ Q_PROPERTY(QOpcUaApplicationDescription server READ server)
+ Q_PROPERTY(QOpcUaEndpointDescription::MessageSecurityMode securityMode READ securityMode)
+ Q_PROPERTY(QString securityPolicy READ securityPolicy)
+ Q_PROPERTY(QVector<QOpcUaUserTokenPolicy> userIdentityTokens READ userIdentityTokens)
+
+public:
+ QOpcUaEndpointDescription();
+ QOpcUaEndpointDescription(const QOpcUaEndpointDescription &);
+ QOpcUaEndpointDescription &operator=(const QOpcUaEndpointDescription &);
+ bool operator==(const QOpcUaEndpointDescription &) const;
+ ~QOpcUaEndpointDescription();
+
+ enum MessageSecurityMode {
+ Invalid = 0,
+ None = 1,
+ Sign = 2,
+ SignAndEncrypt = 3
+ };
+ Q_ENUM(MessageSecurityMode)
+
+ QString endpointUrl() const;
+ void setEndpointUrl(const QString &endpointUrl);
+
+ QOpcUaApplicationDescription server() const;
+ QOpcUaApplicationDescription &serverRef();
+ void setServer(const QOpcUaApplicationDescription &server);
+
+ QByteArray serverCertificate() const;
+ void setServerCertificate(const QByteArray &serverCertificate);
+
+ QOpcUaEndpointDescription::MessageSecurityMode securityMode() const;
+ void setSecurityMode(QOpcUaEndpointDescription::MessageSecurityMode securityMode);
+
+ QString securityPolicy() const;
+ void setSecurityPolicy(const QString &securityPolicy);
+
+ QVector<QOpcUaUserTokenPolicy> userIdentityTokens() const;
+ QVector<QOpcUaUserTokenPolicy> &userIdentityTokensRef();
+ void setUserIdentityTokens(const QVector<QOpcUaUserTokenPolicy> &userIdentityTokens);
+
+ QString transportProfileUri() const;
+ void setTransportProfileUri(const QString &transportProfileUri);
+
+ quint8 securityLevel() const;
+ void setSecurityLevel(quint8 securityLevel);
+
+private:
+ QSharedDataPointer<QOpcUaEndpointDescriptionData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaEndpointDescription)
+
+#endif // QOPCUAENDPOINTDESCRIPTION_H
diff --git a/src/opcua/client/qopcuaerrorstate.cpp b/src/opcua/client/qopcuaerrorstate.cpp
new file mode 100644
index 0000000..006a374
--- /dev/null
+++ b/src/opcua/client/qopcuaerrorstate.cpp
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuaerrorstate.h"
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaErrorStateData : public QSharedData
+{
+public:
+ QOpcUaErrorStateData() {}
+
+ QOpcUaErrorState::ConnectionStep m_connectionStep = QOpcUaErrorState::ConnectionStep::CertificateValidation;
+ QOpcUa::UaStatusCode m_errorCode = QOpcUa::Good;
+ bool m_clientSideError = false;
+ bool m_ignoreError = false;
+};
+
+/*!
+ \class QOpcUaErrorState
+ \inmodule QtOpcUa
+ \since QtOpcUa 5.13
+ \brief QOpcUaErrorState allows investigation and interaction with error state from backends.
+
+ This class is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+
+ There is not need to instatiate this class in your code.
+ A client will emit an error state via \l QOpcUaClient::connectError in case an error has happend
+ while establishing a connection.
+
+ The error can be caused by the backend itself or by the server rejecting the connection.
+ If case of errors issued by the local backend, they can be ignored by calling the function
+ \l setIgnoreError().
+*/
+
+/*!
+ \enum QOpcUaErrorState::ConnectionStep
+
+ Specifies at which step during the connection establishment the error occurred.
+
+ \value Unknown The connection step is unknown.
+ \value CertificateValidation Error happened in the certificate validation step.
+ \value OpenSecureChannel Error happened when opening the secure channel.
+ \value CreateSession Error happened when creating the session.
+ \value ActivateSession Error happened during session acivation.
+*/
+
+QOpcUaErrorState::QOpcUaErrorState()
+ : data(new QOpcUaErrorStateData())
+{
+}
+
+/*!
+ Constructs an error state from \a other.
+*/
+QOpcUaErrorState::QOpcUaErrorState(const QOpcUaErrorState &other)
+ : data(other.data)
+{}
+
+/*!
+ Sets the values of \a rhs in this error state.
+*/
+QOpcUaErrorState &QOpcUaErrorState::operator=(const QOpcUaErrorState &rhs)
+{
+ if (this != &rhs)
+ data = rhs.data;
+ return *this;
+}
+
+QOpcUaErrorState::~QOpcUaErrorState()
+{
+
+}
+
+/*!
+ Returns the connection step in which the error occurred.
+*/
+QOpcUaErrorState::ConnectionStep QOpcUaErrorState::connectionStep() const
+{
+ return data->m_connectionStep;
+}
+
+/*!
+ Sets the connection step in which the error occurred to \a step.
+*/
+void QOpcUaErrorState::setConnectionStep(QOpcUaErrorState::ConnectionStep step)
+{
+ data->m_connectionStep = step;
+}
+
+/*!
+ Returns the OPC UA status code of the error occurred.
+*/
+QOpcUa::UaStatusCode QOpcUaErrorState::errorCode() const
+{
+ return data->m_errorCode;
+}
+
+/*!
+ Sets the OPC UA status code of the error occurred to \a error.
+*/
+void QOpcUaErrorState::setErrorCode(QOpcUa::UaStatusCode error)
+{
+ data->m_errorCode = error;
+}
+
+/*!
+ Returns if the occurred error is a client side error.
+*/
+bool QOpcUaErrorState::isClientSideError() const
+{
+ return data->m_clientSideError;
+}
+
+/*!
+ Sets if the occurred error is a client side error to \a clientSideError.
+*/
+void QOpcUaErrorState::setClientSideError(bool clientSideError)
+{
+ data->m_clientSideError = clientSideError;
+}
+
+/*!
+ Sets if this client side error should be ignored to \a ignore.
+
+ Setting this flag does only work if the error is actually a client side error.
+*/
+void QOpcUaErrorState::setIgnoreError(bool ignore)
+{
+ data->m_ignoreError = ignore;
+}
+
+/*!
+ Returns if this client side error should be ignored.
+*/
+bool QOpcUaErrorState::ignoreError() const
+{
+ return data->m_ignoreError;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaerrorstate.h b/src/opcua/client/qopcuaerrorstate.h
new file mode 100644
index 0000000..68d8a00
--- /dev/null
+++ b/src/opcua/client/qopcuaerrorstate.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAERRORSTATE_H
+#define QOPCUAERRORSTATE_H
+
+#include <QtCore/qshareddata.h>
+#include <QtOpcUa/qopcuatype.h>
+#include <QtOpcUa/qopcuaglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaErrorStateData;
+
+class Q_OPCUA_EXPORT QOpcUaErrorState
+{
+public:
+ enum class ConnectionStep {
+ Unknown = 0x00,
+ CertificateValidation,
+ OpenSecureChannel,
+ CreateSession,
+ ActivateSession
+ };
+
+ QOpcUaErrorState();
+ QOpcUaErrorState(const QOpcUaErrorState &other);
+ QOpcUaErrorState &operator =(const QOpcUaErrorState &rhs);
+ ~QOpcUaErrorState();
+
+ ConnectionStep connectionStep() const;
+ void setConnectionStep(ConnectionStep step);
+
+ QOpcUa::UaStatusCode errorCode() const;
+ void setErrorCode(QOpcUa::UaStatusCode error);
+
+ bool isClientSideError() const;
+ void setClientSideError(bool clientSideError);
+
+ void setIgnoreError(bool ignore = true);
+ bool ignoreError() const;
+
+private:
+ QSharedDataPointer<QOpcUaErrorStateData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaErrorState)
+
+#endif // QOPCUAERRORSTATE_H
diff --git a/src/opcua/client/qopcuaeuinformation.cpp b/src/opcua/client/qopcuaeuinformation.cpp
new file mode 100644
index 0000000..fdfa5ad
--- /dev/null
+++ b/src/opcua/client/qopcuaeuinformation.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuaeuinformation.h"
+#include "qopcualocalizedtext.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaEUInformation
+ \inmodule QtOpcUa
+ \brief The OPC UA EURange type.
+
+ This is the Qt OPC UA representation for the OPC UA EUInformation type defined in OPC-UA part 8, 5.6.3.
+ EUInformation values contain information about units and are mostly used as property of a node with a numeric value attribute.
+ The information can e. g. be used to add text and tooltips to GUI elements.
+*/
+
+class QOpcUaEUInformationData : public QSharedData
+{
+public:
+ QString namespaceUri;
+ qint32 unitId{0};
+ QOpcUaLocalizedText displayName;
+ QOpcUaLocalizedText description;
+};
+
+QOpcUaEUInformation::QOpcUaEUInformation()
+ : data(new QOpcUaEUInformationData)
+{
+}
+
+/*!
+ Constructs a EUinformation from \a rhs.
+*/
+QOpcUaEUInformation::QOpcUaEUInformation(const QOpcUaEUInformation &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Constructs a EUinformation with namespace URI \a namespaceUri, unit id \a unitId,
+ display name \a displayName and description \a description.
+*/
+QOpcUaEUInformation::QOpcUaEUInformation(const QString &namespaceUri, qint32 unitId, const QOpcUaLocalizedText &displayName,
+ const QOpcUaLocalizedText &description)
+ : data(new QOpcUaEUInformationData)
+{
+ data->namespaceUri = namespaceUri;
+ data->unitId = unitId;
+ data->displayName = displayName;
+ data->description = description;
+}
+
+
+/*!
+ Sets the values from \a rhs in this EUinformation.
+*/
+QOpcUaEUInformation &QOpcUaEUInformation::operator=(const QOpcUaEUInformation &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns \c true if this EUinformation has the same value as \a rhs.
+*/
+bool QOpcUaEUInformation::operator==(const QOpcUaEUInformation &rhs) const
+{
+ return data->namespaceUri == rhs.namespaceUri() &&
+ data->unitId == rhs.unitId() &&
+ data->displayName == rhs.displayName() &&
+ data->description == rhs.description();
+}
+
+QOpcUaEUInformation::~QOpcUaEUInformation()
+{
+}
+
+/*!
+ Returns the description of the unit, for example \e {degree Celsius}.
+*/
+QOpcUaLocalizedText QOpcUaEUInformation::description() const
+{
+ return data->description;
+}
+
+/*!
+ Sets the description if the unit to \a description.
+*/
+void QOpcUaEUInformation::setDescription(const QOpcUaLocalizedText &description)
+{
+ data->description = description;
+}
+
+/*!
+ Returns the display name of the unit, for example \e {°C}.
+*/
+QOpcUaLocalizedText QOpcUaEUInformation::displayName() const
+{
+ return data->displayName;
+}
+
+/*!
+ Sets the display name of the unit to \a displayName.
+*/
+void QOpcUaEUInformation::setDisplayName(const QOpcUaLocalizedText &displayName)
+{
+ data->displayName = displayName;
+}
+
+/*!
+ Returns the machine-readable identifier for the unit.
+*/
+qint32 QOpcUaEUInformation::unitId() const
+{
+ return data->unitId;
+}
+
+/*!
+ Sets the machine-readable identifier for the unit to \a unitId.
+*/
+void QOpcUaEUInformation::setUnitId(qint32 unitId)
+{
+ data->unitId = unitId;
+}
+
+/*!
+ Returns the namespace URI of the unit.
+*/
+QString QOpcUaEUInformation::namespaceUri() const
+{
+ return data->namespaceUri;
+}
+
+/*!
+ Sets the namespace URI of the unit to \a namespaceUri.
+*/
+void QOpcUaEUInformation::setNamespaceUri(const QString &namespaceUri)
+{
+ data->namespaceUri = namespaceUri;
+}
+
+/*!
+ Converts this EUinformation to \l QVariant.
+*/
+QOpcUaEUInformation::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaeuinformation.h b/src/opcua/client/qopcuaeuinformation.h
new file mode 100644
index 0000000..c9c10b9
--- /dev/null
+++ b/src/opcua/client/qopcuaeuinformation.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAEUINFORMATION_H
+#define QOPCUAEUINFORMATION_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaLocalizedText;
+
+class QOpcUaEUInformationData;
+class Q_OPCUA_EXPORT QOpcUaEUInformation
+{
+public:
+ QOpcUaEUInformation();
+ QOpcUaEUInformation(const QOpcUaEUInformation &);
+ QOpcUaEUInformation(const QString &namespaceUri, qint32 unitId,
+ const QOpcUaLocalizedText &displayName, const QOpcUaLocalizedText &description);
+ QOpcUaEUInformation &operator=(const QOpcUaEUInformation &);
+ bool operator==(const QOpcUaEUInformation &rhs) const;
+ operator QVariant() const;
+ ~QOpcUaEUInformation();
+
+ QString namespaceUri() const;
+ void setNamespaceUri(const QString &namespaceUri);
+
+ qint32 unitId() const;
+ void setUnitId(qint32 unitId);
+
+ QOpcUaLocalizedText displayName() const;
+ void setDisplayName(const QOpcUaLocalizedText &displayName);
+
+ QOpcUaLocalizedText description() const;
+ void setDescription(const QOpcUaLocalizedText &description);
+
+private:
+ QSharedDataPointer<QOpcUaEUInformationData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaEUInformation)
+
+#endif // QOPCUAEUINFORMATION_H
diff --git a/src/opcua/client/qopcuaeventfilterresult.cpp b/src/opcua/client/qopcuaeventfilterresult.cpp
new file mode 100644
index 0000000..1f2ab8d
--- /dev/null
+++ b/src/opcua/client/qopcuaeventfilterresult.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuaeventfilterresult.h"
+#include "qopcuacontentfilterelementresult.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaEventFilterResult
+ \inmodule QtOpcUa
+ \brief The OPCUA EventFilterResult.
+
+ The EventFilterResult contains status codes for all elements of the \c select clauses
+ and all elements of the \c where clause.
+*/
+
+class QOpcUaEventFilterResultData : public QSharedData
+{
+public:
+ QVector<QOpcUa::UaStatusCode> selectClauseResults;
+ QVector<QOpcUaContentFilterElementResult> whereClauseResults;
+};
+
+QOpcUaEventFilterResult::QOpcUaEventFilterResult()
+ : data(new QOpcUaEventFilterResultData)
+{
+}
+
+/*!
+ Constructs an event filter result from \a rhs.
+*/
+QOpcUaEventFilterResult::QOpcUaEventFilterResult(const QOpcUaEventFilterResult &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Sets the values from \a rhs in this event filter result.
+*/
+QOpcUaEventFilterResult &QOpcUaEventFilterResult::operator=(const QOpcUaEventFilterResult &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+QOpcUaEventFilterResult::~QOpcUaEventFilterResult()
+{
+}
+
+/*!
+ Returns \c true if this event filter result is good.
+*/
+bool QOpcUaEventFilterResult::isGood() const
+{
+ for (auto status : qAsConst(data->selectClauseResults)) {
+ if (status != QOpcUa::UaStatusCode::Good)
+ return false;
+ }
+ for (QOpcUaContentFilterElementResult element : qAsConst(data->whereClauseResults)) {
+ if (element.statusCode() != QOpcUa::UaStatusCode::Good)
+ return false;
+ for (auto status : qAsConst(element.operandStatusCodesRef())) {
+ if (status != QOpcUa::UaStatusCode::Good)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*!
+ Returns the status codes for all elements of the \c where clause in the order that was used in the filter.
+*/
+QVector<QOpcUaContentFilterElementResult> QOpcUaEventFilterResult::whereClauseResults() const
+{
+ return data->whereClauseResults;
+}
+
+/*!
+ Returns a reference to the \c where clause results.
+
+ \sa whereClauseResults()
+*/
+QVector<QOpcUaContentFilterElementResult> &QOpcUaEventFilterResult::whereClauseResultsRef()
+{
+ return data->whereClauseResults;
+}
+
+/*!
+ Sets the \c where clause results to \a whereClausesResult.
+*/
+void QOpcUaEventFilterResult::setWhereClauseResults(const QVector<QOpcUaContentFilterElementResult> &whereClausesResult)
+{
+ data->whereClauseResults = whereClausesResult;
+}
+
+/*!
+ Returns the status codes for all elements of the \c select clauses in the order that was used in the filter.
+*/
+QVector<QOpcUa::UaStatusCode> QOpcUaEventFilterResult::selectClauseResults() const
+{
+ return data->selectClauseResults;
+}
+
+/*!
+ Returns a reference to the \c select clause results.
+
+ \sa selectClauseResults()
+*/
+QVector<QOpcUa::UaStatusCode> &QOpcUaEventFilterResult::selectClauseResultsRef()
+{
+ return data->selectClauseResults;
+}
+
+/*!
+ Sets the \c select clause results to \a selectClausesResult.
+*/
+void QOpcUaEventFilterResult::setSelectClauseResults(const QVector<QOpcUa::UaStatusCode> &selectClausesResult)
+{
+ data->selectClauseResults = selectClausesResult;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaeventfilterresult.h b/src/opcua/client/qopcuaeventfilterresult.h
new file mode 100644
index 0000000..e4587ac
--- /dev/null
+++ b/src/opcua/client/qopcuaeventfilterresult.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAEVENTFILTERRESULT_H
+#define QOPCUAEVENTFILTERRESULT_H
+
+#include <QtOpcUa/qopcuatype.h>
+
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaContentFilterElementResult;
+
+class QOpcUaEventFilterResultData;
+class Q_OPCUA_EXPORT QOpcUaEventFilterResult
+{
+public:
+ QOpcUaEventFilterResult();
+ QOpcUaEventFilterResult(const QOpcUaEventFilterResult &);
+ QOpcUaEventFilterResult &operator=(const QOpcUaEventFilterResult &);
+ ~QOpcUaEventFilterResult();
+
+ bool isGood() const;
+
+ QVector<QOpcUa::UaStatusCode> selectClauseResults() const;
+ QVector<QOpcUa::UaStatusCode> &selectClauseResultsRef();
+ void setSelectClauseResults(const QVector<QOpcUa::UaStatusCode> &selectClausesResult);
+
+ QVector<QOpcUaContentFilterElementResult> whereClauseResults() const;
+ QVector<QOpcUaContentFilterElementResult> &whereClauseResultsRef();
+ void setWhereClauseResults(const QVector<QOpcUaContentFilterElementResult> &whereClauseResult);
+
+private:
+ QSharedDataPointer<QOpcUaEventFilterResultData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaEventFilterResult)
+
+#endif // QOPCUAEVENTFILTERRESULT_H
diff --git a/src/opcua/client/qopcuaexpandednodeid.cpp b/src/opcua/client/qopcuaexpandednodeid.cpp
new file mode 100644
index 0000000..1e340f1
--- /dev/null
+++ b/src/opcua/client/qopcuaexpandednodeid.cpp
@@ -0,0 +1,178 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuaexpandednodeid.h"
+#include "qopcuatype.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaExpandedNodeId
+ \inmodule QtOpcUa
+ \brief The OPC UA ExpandedNodeId.
+
+ An expanded node id is a node id where the namespace index can be given as index or as a string URI.
+ A list of namespaces and their indices on the server is provided by \l QOpcUaClient::namespaceArray().
+*/
+
+class QOpcUaExpandedNodeIdData : public QSharedData
+{
+public:
+ quint32 serverIndex{0};
+ QString namespaceUri;
+ QString nodeId;
+};
+
+QOpcUaExpandedNodeId::QOpcUaExpandedNodeId()
+ : data(new QOpcUaExpandedNodeIdData)
+{
+}
+
+/*!
+ Constructs an expanded node id from \a rhs.
+*/
+QOpcUaExpandedNodeId::QOpcUaExpandedNodeId(const QOpcUaExpandedNodeId &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Constructs an expanded node id from node id string \a nodeId.
+*/
+QOpcUaExpandedNodeId::QOpcUaExpandedNodeId(const QString &nodeId)
+ : data(new QOpcUaExpandedNodeIdData)
+{
+ data->nodeId = nodeId;
+}
+
+/*!
+ Constructs an expanded node id from namespace URI \a namespaceUri, node id string \a nodeId
+ and server index \a serverIndex.
+
+ \sa setServerIndex
+*/
+QOpcUaExpandedNodeId::QOpcUaExpandedNodeId(const QString &namespaceUri, const QString &nodeId, quint32 serverIndex)
+ : data(new QOpcUaExpandedNodeIdData)
+{
+ data->namespaceUri = namespaceUri;
+ data->nodeId = nodeId;
+ data->serverIndex = serverIndex;
+}
+
+/*!
+ Sets the values from \a rhs in this expanded node id.
+*/
+QOpcUaExpandedNodeId &QOpcUaExpandedNodeId::operator=(const QOpcUaExpandedNodeId &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns \c true if this expanded node id has the same value as \a rhs.
+*/
+bool QOpcUaExpandedNodeId::operator==(const QOpcUaExpandedNodeId &rhs) const
+{
+ return data->namespaceUri == rhs.namespaceUri() &&
+ QOpcUa::nodeIdEquals(data->nodeId, rhs.nodeId()) &&
+ data->serverIndex == rhs.serverIndex();
+}
+
+/*!
+ Converts this expanded node id to \l QVariant.
+*/
+QOpcUaExpandedNodeId::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+QOpcUaExpandedNodeId::~QOpcUaExpandedNodeId()
+{
+}
+
+/*!
+ Returns the index of the server containing the node. This index maps to an entry in the server's server table.
+ The index of the local server is always \c 0. All remote servers have indexes greater than \c 0.
+*/
+quint32 QOpcUaExpandedNodeId::serverIndex() const
+{
+ return data->serverIndex;
+}
+
+/*!
+ Sets the server index to \a serverIndex.
+ The index of the local server is always \c 0. All remote servers have indexes greater than \c 0.
+*/
+void QOpcUaExpandedNodeId::setServerIndex(quint32 serverIndex)
+{
+ data->serverIndex = serverIndex;
+}
+
+/*!
+ Returns the namespace URI of the node id. If this value is specified, the namespace index in
+ \l {QOpcUaExpandedNodeId::nodeId} {nodeId} is 0 and must be ignored.
+*/
+QString QOpcUaExpandedNodeId::namespaceUri() const
+{
+ return data->namespaceUri;
+}
+
+/*!
+ Sets the namespace URI to \a namespaceUri.
+*/
+void QOpcUaExpandedNodeId::setNamespaceUri(const QString &namespaceUri)
+{
+ data->namespaceUri = namespaceUri;
+}
+
+/*!
+ Returns the node id. If \l {QOpcUaExpandedNodeId::namespaceUri} {namespaceUri} is specified, the namespace index is invalid.
+*/
+QString QOpcUaExpandedNodeId::nodeId() const
+{
+ return data->nodeId;
+}
+
+/*!
+ Sets the node id to \a nodeId.
+*/
+void QOpcUaExpandedNodeId::setNodeId(const QString &nodeId)
+{
+ data->nodeId = nodeId;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaexpandednodeid.h b/src/opcua/client/qopcuaexpandednodeid.h
new file mode 100644
index 0000000..8889e41
--- /dev/null
+++ b/src/opcua/client/qopcuaexpandednodeid.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAEXPANDEDNODEID_H
+#define QOPCUAEXPANDEDNODEID_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaExpandedNodeIdData;
+class Q_OPCUA_EXPORT QOpcUaExpandedNodeId
+{
+public:
+ QOpcUaExpandedNodeId();
+ QOpcUaExpandedNodeId(const QOpcUaExpandedNodeId &);
+ QOpcUaExpandedNodeId(const QString &nodeId);
+ QOpcUaExpandedNodeId(const QString &namespaceUri, const QString &nodeId, quint32 serverIndex = 0);
+ QOpcUaExpandedNodeId &operator=(const QOpcUaExpandedNodeId &);
+ bool operator==(const QOpcUaExpandedNodeId &) const;
+ operator QVariant() const;
+ ~QOpcUaExpandedNodeId();
+
+ quint32 serverIndex() const;
+ void setServerIndex(quint32 serverIndex);
+
+ QString namespaceUri() const;
+ void setNamespaceUri(const QString &namespaceUri);
+
+ QString nodeId() const;
+ void setNodeId(const QString &nodeId);
+
+private:
+ QSharedDataPointer<QOpcUaExpandedNodeIdData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaExpandedNodeId)
+
+#endif // QOPCUAEXPANDEDNODEID_H
diff --git a/src/opcua/client/qopcuaextensionobject.cpp b/src/opcua/client/qopcuaextensionobject.cpp
new file mode 100644
index 0000000..fce6ab7
--- /dev/null
+++ b/src/opcua/client/qopcuaextensionobject.cpp
@@ -0,0 +1,175 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuaextensionobject.h"
+#include "qopcuatype.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaExtensionObject
+ \inmodule QtOpcUa
+ \brief The OPC UA ExtensionObject.
+
+ This is the Qt OPC UA representation for an extension object.
+ Extension objects are used as a container in OPC UA whenever a non-builtin type is stored
+ in a Variant. It contains information about the type and encoding of the data as well as
+ the data itself encoded with one of the encodings specified in OPC-UA part 6.
+ Decoders are supposed to decode extension objects if they can handle the type. If the type
+ is not supported by the decoder, the extension object is not decoded and decoding is left
+ to the user.
+*/
+
+/*!
+ \enum QOpcUaExtensionObject::Encoding
+
+ Enumerates the possible encodings of the body.
+
+ \value NoBody
+ \value ByteString
+ \value Xml
+*/
+
+class QOpcUaExtensionObjectData : public QSharedData
+{
+public:
+ QString encodingTypeId;
+ QByteArray encodedBody;
+ QOpcUaExtensionObject::Encoding encoding{QOpcUaExtensionObject::Encoding::NoBody};
+};
+
+QOpcUaExtensionObject::QOpcUaExtensionObject()
+ : data(new QOpcUaExtensionObjectData)
+{
+}
+
+/*!
+ Constructs an extension object from \a rhs.
+*/
+QOpcUaExtensionObject::QOpcUaExtensionObject(const QOpcUaExtensionObject &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Sets the values from \a rhs in this extension object.
+*/
+QOpcUaExtensionObject &QOpcUaExtensionObject::operator=(const QOpcUaExtensionObject &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns \c true if this extension object has the same value as \a rhs.
+*/
+bool QOpcUaExtensionObject::operator==(const QOpcUaExtensionObject &rhs) const
+{
+ return data->encoding == rhs.encoding() &&
+ QOpcUa::nodeIdEquals(data->encodingTypeId, rhs.encodingTypeId()) &&
+ data->encodedBody == rhs.encodedBody();
+}
+
+/*!
+ Converts this extension object to \l QVariant.
+*/
+QOpcUaExtensionObject::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+QOpcUaExtensionObject::~QOpcUaExtensionObject()
+{
+}
+
+/*!
+ Returns the \l {QOpcUaExtensionObject::Encoding} {encoding} of the body.
+*/
+QOpcUaExtensionObject::Encoding QOpcUaExtensionObject::encoding() const
+{
+ return data->encoding;
+}
+
+/*!
+ Sets the encoding of the body to \a encoding.
+*/
+void QOpcUaExtensionObject::setEncoding(QOpcUaExtensionObject::Encoding encoding)
+{
+ data->encoding = encoding;
+}
+
+/*!
+ Returns the body of this extension object. It contains the encoded data.
+*/
+QByteArray QOpcUaExtensionObject::encodedBody() const
+{
+ return data->encodedBody;
+}
+
+/*!
+ Returns a reference to the body of this extension object.
+*/
+QByteArray &QOpcUaExtensionObject::encodedBodyRef()
+{
+ return data->encodedBody;
+}
+/*!
+ Sets the body of this extension object to \a encodedBody.
+*/
+void QOpcUaExtensionObject::setEncodedBody(const QByteArray &encodedBody)
+{
+ data->encodedBody = encodedBody;
+}
+
+/*!
+ Returns the node id of the encoding for the type stored by this extension object, for example ns=0;i=886 for
+ Range_Encoding_DefaultBinary. All encoding ids are listed in \l {https://opcfoundation.org/UA/schemas/1.03/NodeIds.csv}.
+*/
+QString QOpcUaExtensionObject::encodingTypeId() const
+{
+ return data->encodingTypeId;
+}
+
+/*!
+ Sets the node id of the encoding for the type stored by this extension object to \a encodingTypeId.
+*/
+void QOpcUaExtensionObject::setEncodingTypeId(const QString &encodingTypeId)
+{
+ data->encodingTypeId = encodingTypeId;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaextensionobject.h b/src/opcua/client/qopcuaextensionobject.h
new file mode 100644
index 0000000..2d4a000
--- /dev/null
+++ b/src/opcua/client/qopcuaextensionobject.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAEXTENSIONOBJECT_H
+#define QOPCUAEXTENSIONOBJECT_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaExtensionObjectData;
+class Q_OPCUA_EXPORT QOpcUaExtensionObject
+{
+public:
+ enum Encoding {
+ NoBody = 0,
+ ByteString = 1,
+ Xml = 2
+ };
+
+ QOpcUaExtensionObject();
+ QOpcUaExtensionObject(const QOpcUaExtensionObject &);
+ ~QOpcUaExtensionObject();
+ QOpcUaExtensionObject &operator=(const QOpcUaExtensionObject &);
+ bool operator==(const QOpcUaExtensionObject &rhs) const;
+ operator QVariant() const;
+
+ QString encodingTypeId() const;
+ void setEncodingTypeId(const QString &encodingTypeId);
+
+ QByteArray encodedBody() const;
+ QByteArray &encodedBodyRef();
+ void setEncodedBody(const QByteArray &encodedBody);
+
+ QOpcUaExtensionObject::Encoding encoding() const;
+ void setEncoding(QOpcUaExtensionObject::Encoding encoding);
+
+private:
+ QSharedDataPointer<QOpcUaExtensionObjectData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaExtensionObject)
+
+#endif // QOPCUAEXTENSIONOBJECT_H
diff --git a/src/opcua/client/qopcualiteraloperand.cpp b/src/opcua/client/qopcualiteraloperand.cpp
new file mode 100644
index 0000000..36f9795
--- /dev/null
+++ b/src/opcua/client/qopcualiteraloperand.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcualiteraloperand.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaLiteralOperand
+ \inmodule QtOpcUa
+ \brief The OPC UA LiteralOperand type.
+
+ The LiteralOperand is defined in OPC-UA part 4, 7.4.4.3.
+ It contains a literal value that is to be used as operand.
+*/
+class QOpcUaLiteralOperandData : public QSharedData
+{
+public:
+ QVariant value;
+ QOpcUa::Types type {QOpcUa::Types::Undefined};
+};
+
+QOpcUaLiteralOperand::QOpcUaLiteralOperand()
+ : data(new QOpcUaLiteralOperandData)
+{
+ data->type = QOpcUa::Types::Undefined;
+}
+
+/*!
+ Constructs a literal operand from \a rhs.
+*/
+QOpcUaLiteralOperand::QOpcUaLiteralOperand(const QOpcUaLiteralOperand &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Constructs a literal operand of value \a value and type \a type.
+*/
+QOpcUaLiteralOperand::QOpcUaLiteralOperand(const QVariant &value, QOpcUa::Types type)
+ : data(new QOpcUaLiteralOperandData)
+{
+ setValue(value);
+ setType(type);
+}
+
+/*!
+ Sets the values from \a rhs in this \l QOpcUaLiteralOperand.
+*/
+QOpcUaLiteralOperand &QOpcUaLiteralOperand::operator=(const QOpcUaLiteralOperand &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Converts this literal operand to \l QVariant.
+*/
+QOpcUaLiteralOperand::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+QOpcUaLiteralOperand::~QOpcUaLiteralOperand()
+{
+}
+
+/*!
+ Returns the type of the value of the literal operand.
+*/
+QOpcUa::Types QOpcUaLiteralOperand::type() const
+{
+ return data->type;
+}
+
+/*!
+ Sets the type of the value of the literal operand to \a type.
+*/
+void QOpcUaLiteralOperand::setType(QOpcUa::Types type)
+{
+ data->type = type;
+}
+
+/*!
+ Returns the value of the literal operand.
+*/
+QVariant QOpcUaLiteralOperand::value() const
+{
+ return data->value;
+}
+
+/*!
+ Sets the value of the literal operand to \a value.
+*/
+void QOpcUaLiteralOperand::setValue(const QVariant &value)
+{
+ data->value = value;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcualiteraloperand.h b/src/opcua/client/qopcualiteraloperand.h
new file mode 100644
index 0000000..d49e778
--- /dev/null
+++ b/src/opcua/client/qopcualiteraloperand.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUALITERALOPERAND_H
+#define QOPCUALITERALOPERAND_H
+
+#include <QtOpcUa/qopcuatype.h>
+
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+// OPC-UA part 4, 7.4.4.3
+class QOpcUaLiteralOperandData;
+class Q_OPCUA_EXPORT QOpcUaLiteralOperand
+{
+public:
+ QOpcUaLiteralOperand();
+ QOpcUaLiteralOperand(const QOpcUaLiteralOperand &);
+ QOpcUaLiteralOperand(const QVariant &value, QOpcUa::Types type = QOpcUa::Types::Undefined);
+ QOpcUaLiteralOperand &operator=(const QOpcUaLiteralOperand &);
+ operator QVariant() const;
+ ~QOpcUaLiteralOperand();
+
+ QVariant value() const;
+ void setValue(const QVariant &value);
+
+ QOpcUa::Types type() const;
+ void setType(QOpcUa::Types type);
+
+private:
+ QSharedDataPointer<QOpcUaLiteralOperandData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaLiteralOperand)
+
+#endif // QOPCUALITERALOPERAND_H
diff --git a/src/opcua/client/qopcualocalizedtext.cpp b/src/opcua/client/qopcualocalizedtext.cpp
new file mode 100644
index 0000000..61f2463
--- /dev/null
+++ b/src/opcua/client/qopcualocalizedtext.cpp
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcualocalizedtext.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaLocalizedText
+ \inmodule QtOpcUa
+ \brief The OPC UA LocalizedText type.
+
+ This is the Qt OPC UA representation for the OPC UA LocalizedText type defined in OPC-UA part 3, 8.5.
+ A LocalizedText value contains a text string with associated locale information in a second string (e. g. "en" or "en-US").
+ The format of the locale information string is <language>[-<country/region>]. Language is usually given as ISO 639 two letter code,
+ country/region as ISO 3166 two letter code. Custom codes are also allowed (see OPC-UA part 3, 8.4).
+ It can be used to provide multiple text strings in different languages for a value using an array of LocalizedText elements.
+*/
+
+/*!
+ \qmltype LocalizedText
+ \inqmlmodule QtOpcUa
+ \brief Contains a text with associated locale.
+ \since QtOpcUa 5.12
+
+ The two members of this type contain the actual text and the locale of the text.
+*/
+
+/*!
+ \property QOpcUaLocalizedText::text
+
+ Textual content.
+*/
+
+/*!
+ \qmlproperty string LocalizedText::text
+
+ Textual content.
+*/
+
+/*!
+ \property QOpcUaLocalizedText::locale
+
+ Locale of the contained text.
+ This has to be in a modified ISO standard notation, for example \c en-US.
+ See OPC UA specification part 3, 8.4 for details.
+*/
+
+/*!
+ \qmlproperty string LocalizedText::locale
+
+ Locale of the contained text.
+ This has to be in a modified ISO standard notation, for example \c en-US.
+ See OPC UA specification part 3, 8.4 for details.
+*/
+
+class QOpcUaLocalizedTextData : public QSharedData
+{
+public:
+ QString locale;
+ QString text;
+};
+
+QOpcUaLocalizedText::QOpcUaLocalizedText()
+ : data(new QOpcUaLocalizedTextData)
+{
+}
+
+/*!
+ Constructs a localized text from \a rhs.
+*/
+QOpcUaLocalizedText::QOpcUaLocalizedText(const QOpcUaLocalizedText &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Constructs a localized text with the locale \a locale and the text \a text.
+*/
+QOpcUaLocalizedText::QOpcUaLocalizedText(const QString &locale, const QString &text)
+ : data(new QOpcUaLocalizedTextData)
+{
+ data->locale = locale;
+ data->text = text;
+}
+
+/*!
+ Sets the values from \a rhs in this localized text.
+*/
+QOpcUaLocalizedText &QOpcUaLocalizedText::operator=(const QOpcUaLocalizedText &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns \c true if this localized text has the same value as \a rhs.
+*/
+bool QOpcUaLocalizedText::operator==(const QOpcUaLocalizedText &rhs) const
+{
+ return data->locale == rhs.locale() &&
+ data->text == rhs.text();
+}
+
+/*!
+ Converts this localized text to \l QVariant.
+*/
+QOpcUaLocalizedText::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+QOpcUaLocalizedText::~QOpcUaLocalizedText()
+{
+}
+
+/*!
+ Returns the text.
+*/
+QString QOpcUaLocalizedText::text() const
+{
+ return data->text;
+}
+
+/*!
+ Sets the text to \a text.
+*/
+void QOpcUaLocalizedText::setText(const QString &text)
+{
+ data->text = text;
+}
+
+/*!
+ Returns the locale.
+*/
+QString QOpcUaLocalizedText::locale() const
+{
+ return data->locale;
+}
+
+/*!
+ Sets the locale to \a locale.
+*/
+void QOpcUaLocalizedText::setLocale(const QString &locale)
+{
+ data->locale = locale;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcualocalizedtext.h b/src/opcua/client/qopcualocalizedtext.h
new file mode 100644
index 0000000..4783793
--- /dev/null
+++ b/src/opcua/client/qopcualocalizedtext.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUALOCALIZEDTEXT_H
+#define QOPCUALOCALIZEDTEXT_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaLocalizedTextData;
+class Q_OPCUA_EXPORT QOpcUaLocalizedText
+{
+ Q_GADGET
+ Q_PROPERTY(QString locale READ locale WRITE setLocale)
+ Q_PROPERTY(QString text READ text WRITE setText)
+
+public:
+ QOpcUaLocalizedText();
+ QOpcUaLocalizedText(const QOpcUaLocalizedText &);
+ QOpcUaLocalizedText(const QString &locale, const QString &text);
+ QOpcUaLocalizedText &operator=(const QOpcUaLocalizedText &);
+ bool operator==(const QOpcUaLocalizedText &rhs) const;
+ operator QVariant() const;
+ ~QOpcUaLocalizedText();
+
+ QString locale() const;
+ void setLocale(const QString &locale);
+
+ QString text() const;
+ void setText(const QString &text);
+
+private:
+ QSharedDataPointer<QOpcUaLocalizedTextData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaLocalizedText)
+
+#endif // QOPCUALOCALIZEDTEXT_H
diff --git a/src/opcua/client/qopcuamonitoringparameters.cpp b/src/opcua/client/qopcuamonitoringparameters.cpp
index 6b43a90..c71dacd 100644
--- a/src/opcua/client/qopcuamonitoringparameters.cpp
+++ b/src/opcua/client/qopcuamonitoringparameters.cpp
@@ -36,6 +36,7 @@
#include "qopcuamonitoringparameters.h"
#include "private/qopcuamonitoringparameters_p.h"
+#include <QtOpcUa/qopcuaeventfilterresult.h>
QT_BEGIN_NAMESPACE
@@ -516,7 +517,7 @@ QVariant QOpcUaMonitoringParameters::filterResult() const
\sa filterResult()
*/
-void QOpcUaMonitoringParameters::setFilterResult(const QOpcUa::QEventFilterResult &eventFilterResult)
+void QOpcUaMonitoringParameters::setFilterResult(const QOpcUaEventFilterResult &eventFilterResult)
{
d_ptr->filterResult = QVariant::fromValue(eventFilterResult);
}
@@ -713,7 +714,7 @@ QOpcUaMonitoringParameters::DataChangeFilter::operator QVariant() const
It consists of \c select clauses and a \c where clause.
The \c select clauses are used to specify the data the user wants to receive when an event occurs.
- It consists of \l {QOpcUa::QSimpleAttributeOperand} simple attribute operands which select
+ It consists of \l {QOpcUaSimpleAttributeOperand} simple attribute operands which select
attributes of child nodes of an event type, for example the value attribute of the "Message"
property of BaseEventType.
@@ -721,33 +722,33 @@ QOpcUaMonitoringParameters::DataChangeFilter::operator QVariant() const
Several operators and four different operand types allow filtering based on the values of the
attributes of the child nodes of an event type.
- Filters can be constructed using the setter or the streaming operator. Streaming a \l QOpcUa::QSimpleAttributeOperand
- into an event filter adds a new \c select clause to the filter, a \l QOpcUa::QContentFilterElement is appended to the \c where clause.
- A content filter element can be constructed by streaming operands of the types \l QOpcUa::QLiteralOperand,
- \l QOpcUa::QElementOperand, \l QOpcUa::QAttributeOperand and \l QOpcUa::QSimpleAttributeOperand and an operator into a content
+ Filters can be constructed using the setter or the streaming operator. Streaming a \l QOpcUaSimpleAttributeOperand
+ into an event filter adds a new \c select clause to the filter, a \l QOpcUaContentFilterElement is appended to the \c where clause.
+ A content filter element can be constructed by streaming operands of the types \l QOpcUaLiteralOperand,
+ \l QOpcUaElementOperand, \l QOpcUaAttributeOperand and \l QOpcUaSimpleAttributeOperand and an operator into a content
filter element. Only the last operator is used, previous operators will be discarded.
The following EventFilter tells the server to report the value of the "Message" field for events that have a "Severity" field with value >= 500:
\code
QOpcUaMonitoringParameters::EventFilter filter;
- filter << QOpcUa::QSimpleAttributeOperand("Message"); // Select clause of the filter
+ filter << QOpcUaSimpleAttributeOperand("Message"); // Select clause of the filter
- QOpcUa::QContentFilterElement condition;
- condition << OpcUa::QContentFilterElement::FilterOperator::GreaterThanOrEqual;
- condition << QOpcUa::QSimpleAttributeOperand("Severity");
- condition << QOpcUa::QLiteralOperand(500, QOpcUa::Types::UInt16);
+ QOpcUaContentFilterElement condition;
+ condition << QOpcUaContentFilterElement::FilterOperator::GreaterThanOrEqual;
+ condition << QOpcUaSimpleAttributeOperand("Severity");
+ condition << QOpcUaLiteralOperand(500, QOpcUa::Types::UInt16);
filter << condition; // Where clause of the filter
\endcode
- For a more complex example with two conditions, see \l QOpcUa::QElementOperand.
+ For a more complex example with two conditions, see \l QOpcUaElementOperand.
*/
class QOpcUaMonitoringParameters::EventFilterData : public QSharedData
{
public:
- QVector<QOpcUa::QSimpleAttributeOperand> selectClauses;
- QVector<QOpcUa::QContentFilterElement> whereClause;
+ QVector<QOpcUaSimpleAttributeOperand> selectClauses;
+ QVector<QOpcUaContentFilterElement> whereClause;
};
QOpcUaMonitoringParameters::EventFilter::EventFilter()
@@ -784,7 +785,7 @@ bool QOpcUaMonitoringParameters::EventFilter::operator==(const QOpcUaMonitoringP
/*!
Adds the content filter element \a whereClauseElement to the where clause of this event filter.
*/
-QOpcUaMonitoringParameters::EventFilter &QOpcUaMonitoringParameters::EventFilter::operator<<(const QOpcUa::QContentFilterElement &whereClauseElement)
+QOpcUaMonitoringParameters::EventFilter &QOpcUaMonitoringParameters::EventFilter::operator<<(const QOpcUaContentFilterElement &whereClauseElement)
{
whereClauseRef().append(whereClauseElement);
return *this;
@@ -793,7 +794,7 @@ QOpcUaMonitoringParameters::EventFilter &QOpcUaMonitoringParameters::EventFilter
/*!
Adds the simple attribute operand \a selectClauseElement to the select clause of this content filter element.
*/
-QOpcUaMonitoringParameters::EventFilter &QOpcUaMonitoringParameters::EventFilter::operator<<(const QOpcUa::QSimpleAttributeOperand &selectClauseElement)
+QOpcUaMonitoringParameters::EventFilter &QOpcUaMonitoringParameters::EventFilter::operator<<(const QOpcUaSimpleAttributeOperand &selectClauseElement)
{
selectClausesRef().append(selectClauseElement);
return *this;
@@ -814,7 +815,7 @@ QOpcUaMonitoringParameters::EventFilter::~EventFilter()
/*!
Returns the content filter used to restrict the reported events to events matching certain criteria.
*/
-QVector<QOpcUa::QContentFilterElement> QOpcUaMonitoringParameters::EventFilter::whereClause() const
+QVector<QOpcUaContentFilterElement> QOpcUaMonitoringParameters::EventFilter::whereClause() const
{
return data->whereClause;
}
@@ -824,7 +825,7 @@ QVector<QOpcUa::QContentFilterElement> QOpcUaMonitoringParameters::EventFilter::
\sa whereClause()
*/
-QVector<QOpcUa::QContentFilterElement> &QOpcUaMonitoringParameters::EventFilter::whereClauseRef()
+QVector<QOpcUaContentFilterElement> &QOpcUaMonitoringParameters::EventFilter::whereClauseRef()
{
return data->whereClause;
}
@@ -832,7 +833,7 @@ QVector<QOpcUa::QContentFilterElement> &QOpcUaMonitoringParameters::EventFilter:
/*!
Sets the where clause to \a whereClause.
*/
-void QOpcUaMonitoringParameters::EventFilter::setWhereClause(const QVector<QOpcUa::QContentFilterElement> &whereClause)
+void QOpcUaMonitoringParameters::EventFilter::setWhereClause(const QVector<QOpcUaContentFilterElement> &whereClause)
{
data->whereClause = whereClause;
}
@@ -840,7 +841,7 @@ void QOpcUaMonitoringParameters::EventFilter::setWhereClause(const QVector<QOpcU
/*!
Returns the selected event fields that shall be included when a new event is reported.
*/
-QVector<QOpcUa::QSimpleAttributeOperand> QOpcUaMonitoringParameters::EventFilter::selectClauses() const
+QVector<QOpcUaSimpleAttributeOperand> QOpcUaMonitoringParameters::EventFilter::selectClauses() const
{
return data->selectClauses;
}
@@ -848,7 +849,7 @@ QVector<QOpcUa::QSimpleAttributeOperand> QOpcUaMonitoringParameters::EventFilter
/*!
Returns a reference to the select clauses.
*/
-QVector<QOpcUa::QSimpleAttributeOperand> &QOpcUaMonitoringParameters::EventFilter::selectClausesRef()
+QVector<QOpcUaSimpleAttributeOperand> &QOpcUaMonitoringParameters::EventFilter::selectClausesRef()
{
return data->selectClauses;
}
@@ -856,7 +857,7 @@ QVector<QOpcUa::QSimpleAttributeOperand> &QOpcUaMonitoringParameters::EventFilte
/*!
Sets the select clauses to \a selectClauses.
*/
-void QOpcUaMonitoringParameters::EventFilter::setSelectClauses(const QVector<QOpcUa::QSimpleAttributeOperand> &selectClauses)
+void QOpcUaMonitoringParameters::EventFilter::setSelectClauses(const QVector<QOpcUaSimpleAttributeOperand> &selectClauses)
{
data->selectClauses = selectClauses;
}
diff --git a/src/opcua/client/qopcuamonitoringparameters.h b/src/opcua/client/qopcuamonitoringparameters.h
index 3ebfcd5..bfbac98 100644
--- a/src/opcua/client/qopcuamonitoringparameters.h
+++ b/src/opcua/client/qopcuamonitoringparameters.h
@@ -37,12 +37,15 @@
#ifndef QOPCUAMONITORINGPARAMETERS_H
#define QOPCUAMONITORINGPARAMETERS_H
-#include <QtOpcUa/qopcuatype.h>
+#include <QtOpcUa/qopcuacontentfilterelement.h>
+#include <QtOpcUa/qopcuasimpleattributeoperand.h>
#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
+class QOpcUaEventFilterResult;
+
class QOpcUaMonitoringParametersPrivate;
class Q_OPCUA_EXPORT QOpcUaMonitoringParameters
@@ -125,17 +128,17 @@ public:
EventFilter &operator=(const EventFilter &);
operator QVariant const();
bool operator==(const QOpcUaMonitoringParameters::EventFilter &rhs) const;
- EventFilter &operator<<(const QOpcUa::QContentFilterElement &whereClauseElement);
- EventFilter &operator<<(const QOpcUa::QSimpleAttributeOperand &selectClauseElement);
+ EventFilter &operator<<(const QOpcUaContentFilterElement &whereClauseElement);
+ EventFilter &operator<<(const QOpcUaSimpleAttributeOperand &selectClauseElement);
~EventFilter();
- QVector<QOpcUa::QSimpleAttributeOperand> selectClauses() const;
- QVector<QOpcUa::QSimpleAttributeOperand> &selectClausesRef();
- void setSelectClauses(const QVector<QOpcUa::QSimpleAttributeOperand> &selectClauses);
+ QVector<QOpcUaSimpleAttributeOperand> selectClauses() const;
+ QVector<QOpcUaSimpleAttributeOperand> &selectClausesRef();
+ void setSelectClauses(const QVector<QOpcUaSimpleAttributeOperand> &selectClauses);
- QVector<QOpcUa::QContentFilterElement> whereClause() const;
- QVector<QOpcUa::QContentFilterElement> &whereClauseRef();
- void setWhereClause(const QVector<QOpcUa::QContentFilterElement> &whereClause);
+ QVector<QOpcUaContentFilterElement> whereClause() const;
+ QVector<QOpcUaContentFilterElement> &whereClauseRef();
+ void setWhereClause(const QVector<QOpcUaContentFilterElement> &whereClause);
private:
QSharedDataPointer<QOpcUaMonitoringParameters::EventFilterData> data;
@@ -154,7 +157,7 @@ public:
void setFilter(const QOpcUaMonitoringParameters::EventFilter &eventFilter);
void clearFilter();
QVariant filterResult() const;
- void setFilterResult(const QOpcUa::QEventFilterResult &eventFilterResult);
+ void setFilterResult(const QOpcUaEventFilterResult &eventFilterResult);
void clearFilterResult();
quint32 queueSize() const;
void setQueueSize(quint32 queueSize);
diff --git a/src/opcua/client/qopcuamultidimensionalarray.cpp b/src/opcua/client/qopcuamultidimensionalarray.cpp
new file mode 100644
index 0000000..74372cb
--- /dev/null
+++ b/src/opcua/client/qopcuamultidimensionalarray.cpp
@@ -0,0 +1,260 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuamultidimensionalarray.h"
+
+QT_BEGIN_NAMESPACE
+
+/*
+ This class has been modelled in the style of the Variant encoding
+ defined in OPC-UA part 6, 5.2.2.16.
+
+ This solution has been preferred to returning nested QVariantLists
+ due to the following reasons:
+ - A QVariantList inside a QVariantList is stored as a QVariant which must be converted
+ to QVariantList before the elements can be accessed. This makes it impossible to update the
+ values in place.
+ - The length of the array is encoded as a 32 bit unsigned integer.
+ Array dimensions are encoded in an array, so an array can have UINT32_MAX dimensions.
+ Depending on the number of dimensions, there could be lots of nested QVariantLists
+ which would require a huge effort when calculating the array dimensions for conversions
+ between QVariantList and the sdk specific variant type.
+*/
+
+/*!
+ \class QOpcUaMultiDimensionalArray
+ \inmodule QtOpcUa
+ \brief A container class for multidimensional arrays.
+
+ This class manages arrays of Qt OPC UA types with associated array dimensions information.
+ It is returned as value when a multidimensional array is received from the server. It can also
+ be used as a write value or as parameter for filters and method calls.
+*/
+
+class QOpcUaMultiDimensionalArrayData : public QSharedData
+{
+public:
+ QVariantList value;
+ QVector<quint32> arrayDimensions;
+ quint32 expectedArrayLength{0};
+};
+
+QOpcUaMultiDimensionalArray::QOpcUaMultiDimensionalArray()
+ : data(new QOpcUaMultiDimensionalArrayData)
+{
+}
+
+/*!
+ Constructs a multidimensional array from \a other.
+*/
+QOpcUaMultiDimensionalArray::QOpcUaMultiDimensionalArray(const QOpcUaMultiDimensionalArray &other)
+ : data(other.data)
+{
+}
+
+/*!
+ Sets the values from \a rhs in the multidimensional array.
+*/
+QOpcUaMultiDimensionalArray &QOpcUaMultiDimensionalArray::operator=(const QOpcUaMultiDimensionalArray &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Constructs a multidimensional array with value \a value and array dimensions \a arrayDimensions.
+*/
+QOpcUaMultiDimensionalArray::QOpcUaMultiDimensionalArray(const QVariantList &value, const QVector<quint32> &arrayDimensions)
+ : data(new QOpcUaMultiDimensionalArrayData)
+{
+ setValueArray(value);
+ setArrayDimensions(arrayDimensions);
+}
+
+/*!
+ Creates a multidimensional array with preallocated data fitting \a arrayDimensions.
+*/
+QOpcUaMultiDimensionalArray::QOpcUaMultiDimensionalArray(const QVector<quint32> &arrayDimensions)
+ : data(new QOpcUaMultiDimensionalArrayData)
+{
+ setArrayDimensions(arrayDimensions);
+ if (data->expectedArrayLength) {
+ data->value.reserve(data->expectedArrayLength);
+ for (size_t i = 0; i < data->expectedArrayLength; ++i)
+ data->value.append(QVariant());
+ }
+}
+
+QOpcUaMultiDimensionalArray::~QOpcUaMultiDimensionalArray()
+{
+}
+
+/*!
+ Returns the dimensions of the multidimensional array.
+ The element at position n contains the length of the n-th dimension.
+*/
+QVector<quint32> QOpcUaMultiDimensionalArray::arrayDimensions() const
+{
+ return data->arrayDimensions;
+}
+
+/*!
+ Sets the dimensions of the multidimensional array to \a arrayDimensions.
+*/
+void QOpcUaMultiDimensionalArray::setArrayDimensions(const QVector<quint32> &arrayDimensions)
+{
+ data->arrayDimensions = arrayDimensions;
+ data->expectedArrayLength = std::accumulate(data->arrayDimensions.begin(), data->arrayDimensions.end(),
+ 1, std::multiplies<quint32>());
+}
+
+/*!
+ Returns \c true if this multidimensional array has the same value as \a other.
+*/
+bool QOpcUaMultiDimensionalArray::operator==(const QOpcUaMultiDimensionalArray &other) const
+{
+ return arrayDimensions() == other.arrayDimensions() &&
+ valueArray() == other.valueArray();
+}
+
+/*!
+ Converts this multidimensional array to \l QVariant.
+*/
+QOpcUaMultiDimensionalArray::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+/*!
+ Returns the value array of the multidimensional array.
+*/
+QVariantList QOpcUaMultiDimensionalArray::valueArray() const
+{
+ return data->value;
+}
+
+/*!
+ Returns a reference to the value array of the multidimensional array.
+*/
+QVariantList &QOpcUaMultiDimensionalArray::valueArrayRef()
+{
+ return data->value;
+}
+
+/*!
+ Sets the value array of the multidimensional array to \a value.
+*/
+void QOpcUaMultiDimensionalArray::setValueArray(const QVariantList &value)
+{
+ data->value = value;
+}
+
+/*!
+ Returns the array index in \l valueArray() of the element identified by \a indices.
+ If \a indices is invalid for the array or if the array's dimensions don't match
+ the size of \l valueArray(), the invalid index \c -1 is returned.
+*/
+int QOpcUaMultiDimensionalArray::arrayIndex(const QVector<quint32> &indices) const
+{
+ // A QList can store INT_MAX values. Depending on the platform, this allows a size > UINT32_MAX
+ if (data->expectedArrayLength > static_cast<quint64>((std::numeric_limits<int>::max)()) ||
+ static_cast<quint64>(data->value.size()) > (std::numeric_limits<quint32>::max)())
+ return -1;
+
+ // Check number of dimensions and data size
+ if (indices.size() != data->arrayDimensions.size() ||
+ data->expectedArrayLength != static_cast<quint32>(data->value.size()))
+ return -1; // Missing array dimensions or array dimensions don't fit the array
+
+ quint32 index = 0;
+ quint32 stride = 1;
+ // Reverse iteration to avoid repetitions while calculating the stride
+ for (int i = data->arrayDimensions.size() - 1; i >= 0; --i) {
+ if (indices.at(i) >= data->arrayDimensions.at(i)) // Out of bounds
+ return -1;
+
+ // Arrays are encoded in row-major order: [0,0,0], [0,0,1], [0,1,0], [0,1,1], [1,0,0], [1,0,1], [1,1,0], [1,1,1]
+ // The stride for dimension i in a n dimensional array is the product of all array dimensions from i+1 to n
+ if (i < data->arrayDimensions.size() - 1)
+ stride *= data->arrayDimensions.at(i + 1);
+ index += stride * indices.at(i);
+ }
+
+ return (index <= static_cast<quint64>((std::numeric_limits<int>::max)())) ?
+ static_cast<int>(index) : -1;
+}
+
+/*!
+ Returns the value of the element identified by \a indices.
+ If the indices are invalid for the array, an empty \l QVariant is returned.
+*/
+QVariant QOpcUaMultiDimensionalArray::value(const QVector<quint32> &indices) const
+{
+ int index = arrayIndex(indices);
+
+ if (index < 0)
+ return QVariant();
+
+ return data->value.at(index);
+}
+
+/*!
+ Sets the value at position \a indices to \a value.
+ Returns \c true if the value has been successfully set.
+*/
+bool QOpcUaMultiDimensionalArray::setValue(const QVector<quint32> &indices, const QVariant &value)
+{
+ int index = arrayIndex(indices);
+
+ if (index < 0)
+ return false;
+
+ data->value[index] = value;
+ return true;
+}
+
+/*!
+ Returns \c true if the multidimensional array is valid
+*/
+bool QOpcUaMultiDimensionalArray::isValid() const
+{
+ return static_cast<quint64>(data->value.size()) == data->expectedArrayLength &&
+ static_cast<quint64>(data->value.size()) <= (std::numeric_limits<quint32>::max)() &&
+ static_cast<quint64>(data->arrayDimensions.size()) <= (std::numeric_limits<quint32>::max)();
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuamultidimensionalarray.h b/src/opcua/client/qopcuamultidimensionalarray.h
new file mode 100644
index 0000000..ee1541c
--- /dev/null
+++ b/src/opcua/client/qopcuamultidimensionalarray.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAMULTIDIMENSIONALARRAY_H
+#define QOPCUAMULTIDIMENSIONALARRAY_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaMultiDimensionalArrayData;
+class Q_OPCUA_EXPORT QOpcUaMultiDimensionalArray
+{
+public:
+ QOpcUaMultiDimensionalArray();
+ QOpcUaMultiDimensionalArray(const QOpcUaMultiDimensionalArray &other);
+ QOpcUaMultiDimensionalArray &operator=(const QOpcUaMultiDimensionalArray &rhs);
+ QOpcUaMultiDimensionalArray(const QVariantList &valueArray, const QVector<quint32> &arrayDimensions);
+ QOpcUaMultiDimensionalArray(const QVector<quint32> &arrayDimensions);
+ ~QOpcUaMultiDimensionalArray();
+
+ QVariantList valueArray() const;
+ QVariantList &valueArrayRef();
+ void setValueArray(const QVariantList &valueArray);
+
+ int arrayIndex(const QVector<quint32> &indices) const;
+ QVariant value(const QVector<quint32> &indices) const;
+ bool setValue(const QVector<quint32> &indices, const QVariant &value);
+
+ bool isValid() const;
+
+ QVector<quint32> arrayDimensions() const;
+ void setArrayDimensions(const QVector<quint32> &arrayDimensions);
+
+ bool operator==(const QOpcUaMultiDimensionalArray &other) const;
+
+ operator QVariant() const;
+
+private:
+ QSharedDataPointer<QOpcUaMultiDimensionalArrayData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaMultiDimensionalArray)
+
+#endif // QOPCUAMULTIDIMENSIONALARRAY_H
diff --git a/src/opcua/client/qopcuanode.cpp b/src/opcua/client/qopcuanode.cpp
index 666165a..772340b 100644
--- a/src/opcua/client/qopcuanode.cpp
+++ b/src/opcua/client/qopcuanode.cpp
@@ -41,6 +41,8 @@
#include <private/qopcuanode_p.h>
#include <private/qopcuanodeimpl_p.h>
+#include "qopcuarelativepathelement.h"
+
QT_BEGIN_NAMESPACE
/*!
@@ -134,7 +136,7 @@ QT_BEGIN_NAMESPACE
qDebug() << "Failed to read attribute:" << rootNode->attributeError(QOpcUa::NodeAttribute::BrowseName);
client->disconnectFromEndpoint();
}
- qDebug() << "Browse name:" << rootNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUa::QQualifiedName>().name();
+ qDebug() << "Browse name:" << rootNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>().name();
});
rootNode->readAttributes(QOpcUa::NodeAttribute::BrowseName); // Start a read operation for the node's BrowseName attribute.
\endcode
@@ -239,11 +241,11 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn void QOpcUaNode::resolveBrowsePathFinished(QVector<QOpcUa::QBrowsePathTarget> targets, QVector<QOpcUa::QRelativePathElement> path, QOpcUa::UaStatusCode statusCode)
+ \fn void QOpcUaNode::resolveBrowsePathFinished(QVector<QOpcUaBrowsePathTarget> targets, QVector<QOpcUaRelativePathElement> path, QOpcUa::UaStatusCode statusCode)
This signal is emitted after a \l resolveBrowsePath() call has finished.
- \l QOpcUa::QBrowsePathTarget \a targets contains the matches, \a statusCode is the status code of the operation.
+ \l QOpcUaBrowsePathTarget \a targets contains the matches, \a statusCode is the status code of the operation.
If \a statusCode is not \l {QOpcUa::UaStatusCode} {Good}, \a targets is empty.
The browse path \a path is the browse path from the request. It can be used to associate results with requests.
*/
@@ -721,9 +723,9 @@ bool QOpcUaNode::callMethod(const QString &methodNodeId, const QVector<QOpcUa::T
\code
QScopedPointer<QOpcUaNode> node(opcuaClient->node("ns=1;s=machine1"));
- QVector<QOpcUa::QRelativePathElement> path;
- path.append(QOpcUa::QRelativePathElement(QOpcUa::QQualifiedName(1, "Fan"), QOpcUa::ReferenceTypeId::HasComponent));
- path.append(QOpcUa::QRelativePathElement(QOpcUa::QQualifiedName(1, "RPM"), QOpcUa::ReferenceTypeId::HasComponent));
+ QVector<QOpcUaRelativePathElement> path;
+ path.append(QOpcUaRelativePathElement(QOpcUaQualifiedName(1, "Fan"), QOpcUa::ReferenceTypeId::HasComponent));
+ path.append(QOpcUaRelativePathElement(QOpcUaQualifiedName(1, "RPM"), QOpcUa::ReferenceTypeId::HasComponent));
node->resolveBrowsePath(path);
\endcode
@@ -749,7 +751,7 @@ bool QOpcUaNode::callMethod(const QString &methodNodeId, const QVector<QOpcUa::T
}
\endcode
*/
-bool QOpcUaNode::resolveBrowsePath(const QVector<QOpcUa::QRelativePathElement> &path)
+bool QOpcUaNode::resolveBrowsePath(const QVector<QOpcUaRelativePathElement> &path)
{
Q_D(QOpcUaNode);
if (d->m_client.isNull() || d->m_client->state() != QOpcUaClient::Connected)
diff --git a/src/opcua/client/qopcuanode.h b/src/opcua/client/qopcuanode.h
index 70d5886..b41a318 100644
--- a/src/opcua/client/qopcuanode.h
+++ b/src/opcua/client/qopcuanode.h
@@ -42,6 +42,8 @@
#include <QtOpcUa/qopcuamonitoringparameters.h>
#include <QtOpcUa/qopcuareferencedescription.h>
#include <QtOpcUa/qopcuatype.h>
+#include <QtOpcUa/qopcuabrowsepathtarget.h>
+#include <QtOpcUa/qopcuarelativepathelement.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qdebug.h>
@@ -98,7 +100,7 @@ public:
bool callMethod(const QString &methodNodeId, const QVector<QOpcUa::TypedVariant> &args = QVector<QOpcUa::TypedVariant>());
- bool resolveBrowsePath(const QVector<QOpcUa::QRelativePathElement> &path);
+ bool resolveBrowsePath(const QVector<QOpcUaRelativePathElement> &path);
bool browse(const QOpcUaBrowseRequest &request);
@@ -115,8 +117,8 @@ Q_SIGNALS:
void disableMonitoringFinished(QOpcUa::NodeAttribute attr, QOpcUa::UaStatusCode statusCode);
void methodCallFinished(QString methodNodeId, QVariant result, QOpcUa::UaStatusCode statusCode);
void browseFinished(QVector<QOpcUaReferenceDescription> children, QOpcUa::UaStatusCode statusCode);
- void resolveBrowsePathFinished(QVector<QOpcUa::QBrowsePathTarget> targets,
- QVector<QOpcUa::QRelativePathElement> path, QOpcUa::UaStatusCode statusCode);
+ void resolveBrowsePathFinished(QVector<QOpcUaBrowsePathTarget> targets,
+ QVector<QOpcUaRelativePathElement> path, QOpcUa::UaStatusCode statusCode);
private:
Q_DISABLE_COPY(QOpcUaNode)
diff --git a/src/opcua/client/qopcuanode_p.h b/src/opcua/client/qopcuanode_p.h
index 0f752ba..4691a43 100644
--- a/src/opcua/client/qopcuanode_p.h
+++ b/src/opcua/client/qopcuanode_p.h
@@ -50,6 +50,7 @@
#include <QtOpcUa/qopcuaclient.h>
#include <QtOpcUa/qopcuanode.h>
+#include <QtOpcUa/qopcuaeventfilterresult.h>
#include <private/qopcuanodeimpl_p.h>
#include <private/qobject_p.h>
@@ -156,8 +157,8 @@ public:
it->setFilter(param.filter().value<QOpcUaMonitoringParameters::EventFilter>());
else if (param.filter().isNull())
it->clearFilter();
- if (param.filterResult().canConvert<QOpcUa::QEventFilterResult>())
- it->setFilterResult(param.filterResult().value<QOpcUa::QEventFilterResult>());
+ if (param.filterResult().canConvert<QOpcUaEventFilterResult>())
+ it->setFilterResult(param.filterResult().value<QOpcUaEventFilterResult>());
else if (param.filterResult().isNull())
it->clearFilterResult();
}
@@ -189,7 +190,7 @@ public:
});
m_resolveBrowsePathFinishedConnection = QObject::connect(impl, &QOpcUaNodeImpl::resolveBrowsePathFinished,
- [this](QVector<QOpcUa::QBrowsePathTarget> targets, QVector<QOpcUa::QRelativePathElement> path,
+ [this](QVector<QOpcUaBrowsePathTarget> targets, QVector<QOpcUaRelativePathElement> path,
QOpcUa::UaStatusCode statusCode)
{
Q_Q(QOpcUaNode);
diff --git a/src/opcua/client/qopcuanodecreationattributes.cpp b/src/opcua/client/qopcuanodecreationattributes.cpp
index e9f2127..e9ccf83 100644
--- a/src/opcua/client/qopcuanodecreationattributes.cpp
+++ b/src/opcua/client/qopcuanodecreationattributes.cpp
@@ -383,7 +383,7 @@ bool QOpcUaNodeCreationAttributes::hasDataTypeId() const
/*!
Returns the value for the Description attribute.
*/
-QOpcUa::QLocalizedText QOpcUaNodeCreationAttributes::description() const
+QOpcUaLocalizedText QOpcUaNodeCreationAttributes::description() const
{
return data->description;
}
@@ -391,7 +391,7 @@ QOpcUa::QLocalizedText QOpcUaNodeCreationAttributes::description() const
/*!
Sets the value for the Description attribute to \a description.
*/
-void QOpcUaNodeCreationAttributes::setDescription(const QOpcUa::QLocalizedText &description)
+void QOpcUaNodeCreationAttributes::setDescription(const QOpcUaLocalizedText &description)
{
data->description = description;
data->setAttributeInMask(QOpcUaNodeCreationAttributesPrivate::BitMask::Description);
@@ -408,7 +408,7 @@ bool QOpcUaNodeCreationAttributes::hasDescription() const
/*!
Returns the value for the DisplayName attribute.
*/
-QOpcUa::QLocalizedText QOpcUaNodeCreationAttributes::displayName() const
+QOpcUaLocalizedText QOpcUaNodeCreationAttributes::displayName() const
{
return data->displayName;
}
@@ -416,7 +416,7 @@ QOpcUa::QLocalizedText QOpcUaNodeCreationAttributes::displayName() const
/*!
Sets the value for the DisplayName attribute to \a displayName.
*/
-void QOpcUaNodeCreationAttributes::setDisplayName(const QOpcUa::QLocalizedText &displayName)
+void QOpcUaNodeCreationAttributes::setDisplayName(const QOpcUaLocalizedText &displayName)
{
data->displayName = displayName;
data->setAttributeInMask(QOpcUaNodeCreationAttributesPrivate::BitMask::DisplayName);
@@ -508,7 +508,7 @@ bool QOpcUaNodeCreationAttributes::hasHistorizing() const
/*!
Returns the value for the InverseName attribute.
*/
-QOpcUa::QLocalizedText QOpcUaNodeCreationAttributes::inverseName() const
+QOpcUaLocalizedText QOpcUaNodeCreationAttributes::inverseName() const
{
return data->inverseName;
}
@@ -516,7 +516,7 @@ QOpcUa::QLocalizedText QOpcUaNodeCreationAttributes::inverseName() const
/*!
Sets the value for the InverseName attribute to \a inverseName.
*/
-void QOpcUaNodeCreationAttributes::setInverseName(const QOpcUa::QLocalizedText &inverseName)
+void QOpcUaNodeCreationAttributes::setInverseName(const QOpcUaLocalizedText &inverseName)
{
data->inverseName = inverseName;
data->setAttributeInMask(QOpcUaNodeCreationAttributesPrivate::BitMask::InverseName);
diff --git a/src/opcua/client/qopcuanodecreationattributes.h b/src/opcua/client/qopcuanodecreationattributes.h
index a0d4746..522a174 100644
--- a/src/opcua/client/qopcuanodecreationattributes.h
+++ b/src/opcua/client/qopcuanodecreationattributes.h
@@ -38,7 +38,7 @@
#define QOPCUANODECREATIONATTRIBUTES_H
#include <QtOpcUa/qopcuatype.h>
-
+#include <QtOpcUa/qopcualocalizedtext.h>
#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
@@ -70,12 +70,12 @@ public:
void setDataTypeId(const QString &dataTypeId);
bool hasDataTypeId() const;
- QOpcUa::QLocalizedText description() const;
- void setDescription(const QOpcUa::QLocalizedText &description);
+ QOpcUaLocalizedText description() const;
+ void setDescription(const QOpcUaLocalizedText &description);
bool hasDescription() const;
- QOpcUa::QLocalizedText displayName() const;
- void setDisplayName(const QOpcUa::QLocalizedText &displayName);
+ QOpcUaLocalizedText displayName() const;
+ void setDisplayName(const QOpcUaLocalizedText &displayName);
bool hasDisplayName() const;
QOpcUa::EventNotifier eventNotifier() const;
@@ -90,8 +90,8 @@ public:
void setHistorizing(bool historizing);
bool hasHistorizing() const;
- QOpcUa::QLocalizedText inverseName() const;
- void setInverseName(const QOpcUa::QLocalizedText &inverseName);
+ QOpcUaLocalizedText inverseName() const;
+ void setInverseName(const QOpcUaLocalizedText &inverseName);
bool hasInverseName() const;
bool isAbstract() const;
diff --git a/src/opcua/client/qopcuanodecreationattributes_p.h b/src/opcua/client/qopcuanodecreationattributes_p.h
index 8434175..8092c02 100644
--- a/src/opcua/client/qopcuanodecreationattributes_p.h
+++ b/src/opcua/client/qopcuanodecreationattributes_p.h
@@ -101,12 +101,12 @@ public:
QVector<quint32> arrayDimensions;
bool containsNoLoops {false};
QString dataTypeId;
- QOpcUa::QLocalizedText description;
- QOpcUa::QLocalizedText displayName;
+ QOpcUaLocalizedText description;
+ QOpcUaLocalizedText displayName;
QOpcUa::EventNotifier eventNotifier {QOpcUa::EventNotifierBit::None};
bool executable {false};
bool historizing {false};
- QOpcUa::QLocalizedText inverseName;
+ QOpcUaLocalizedText inverseName;
bool isAbstract {false};
double minimumSamplingInterval {0};
bool symmetric {false};
diff --git a/src/opcua/client/qopcuanodeimpl_p.h b/src/opcua/client/qopcuanodeimpl_p.h
index 9a9793e..e385b86 100644
--- a/src/opcua/client/qopcuanodeimpl_p.h
+++ b/src/opcua/client/qopcuanodeimpl_p.h
@@ -49,10 +49,12 @@
//
#include <QtOpcUa/qopcuaglobal.h>
+#include <QtOpcUa/qopcuabrowsepathtarget.h>
#include <QtOpcUa/qopcuamonitoringparameters.h>
#include <QtOpcUa/qopcuanode.h>
#include <QtOpcUa/qopcuareaditem.h>
#include <QtOpcUa/qopcuareadresult.h>
+#include <QtOpcUa/qopcuarelativepathelement.h>
#include <QtOpcUa/qopcuatype.h>
#include <QtCore/qvariant.h>
@@ -79,7 +81,7 @@ public:
virtual bool callMethod(const QString &methodNodeId, const QVector<QOpcUa::TypedVariant> &args) = 0;
- virtual bool resolveBrowsePath(const QVector<QOpcUa::QRelativePathElement> &path) = 0;
+ virtual bool resolveBrowsePath(const QVector<QOpcUaRelativePathElement> &path) = 0;
quint64 handle() const;
void setHandle(quint64 handle);
@@ -98,8 +100,8 @@ Q_SIGNALS:
void monitoringStatusChanged(QOpcUa::NodeAttribute attr, QOpcUaMonitoringParameters::Parameters items,
QOpcUaMonitoringParameters param);
void methodCallFinished(QString methodNodeId, QVariant result, QOpcUa::UaStatusCode statusCode);
- void resolveBrowsePathFinished(QVector<QOpcUa::QBrowsePathTarget> targets,
- QVector<QOpcUa::QRelativePathElement> path, QOpcUa::UaStatusCode status);
+ void resolveBrowsePathFinished(QVector<QOpcUaBrowsePathTarget> targets,
+ QVector<QOpcUaRelativePathElement> path, QOpcUa::UaStatusCode status);
private:
quint64 m_handle;
diff --git a/src/opcua/client/qopcuapkiconfiguration.cpp b/src/opcua/client/qopcuapkiconfiguration.cpp
new file mode 100644
index 0000000..5c92740
--- /dev/null
+++ b/src/opcua/client/qopcuapkiconfiguration.cpp
@@ -0,0 +1,270 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Unified Automation GmbH
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuapkiconfiguration.h"
+#include "qopcuaapplicationidentity.h"
+
+#include <QLoggingCategory>
+#include <QSslCertificate>
+#include <QSslCertificateExtension>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_SECURITY);
+
+/*!
+ \class QOpcUaPkiConfiguration
+ \inmodule QtOpcUa
+ \brief QOpcUaPkiConfiguration defines the PKI configuration of the application.
+ \since QtOpcUa 5.13
+
+ This class is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+
+ This info must be configured using QOpcUaClient::setPkiConfiguration.
+ The used paths and files must be created beforehand.
+
+ \code
+ QOpcUaPkiConfiguration pkiConfig;
+ const QString pkiDir = QCoreApplication::applicationDirPath() + "/pki";
+
+ pkiConfig.setClientCertificateDirectory(pkidir + "/own/certs/application.der");
+ pkiConfig.setPrivateKeyDirectory(pkidir + "/own/private/application.pem");
+ pkiConfig.setTrustListDirectory(pkidir + "/trusted/certs");
+ pkiConfig.setRevocationListLocation(pkidir + "/trusted/crl");
+ pkiConfig.setIssuerListDirectory(pkidir + "/issuers/certs");
+ pkiConfig.setIssuerRevocationListDirectory(pkidir + "/issuers/crl");
+
+ client->setPkiConfiguration(pkiConfig);
+ \endcode
+*/
+
+class QOpcUaPkiConfigurationData : public QSharedData
+{
+public:
+ QOpcUaPkiConfigurationData() {}
+
+ QString m_clientCertificateFile; /**< Own application certificate filename */
+ QString m_privateKeyFile; /**< Private key filename which belongs to m_certificateFile */
+ QString m_trustListDirectory; /**< Path to trust list directory */
+ QString m_revocationListDirectory; /**< Folder containing certificate revocation list */
+ QString m_issuerListDirectory; /**< Folder containing issuer intermediate certficates (untrusted) */
+ QString m_issuerRevocationListDirectory; /**< Folder containing issuer revocation list */
+};
+
+QOpcUaPkiConfiguration::QOpcUaPkiConfiguration()
+ : data(new QOpcUaPkiConfigurationData())
+{}
+
+QOpcUaPkiConfiguration::~QOpcUaPkiConfiguration()
+{}
+
+/*!
+ Constructs a \l QOpcUaPkiConfiguration from \a other.
+*/
+QOpcUaPkiConfiguration::QOpcUaPkiConfiguration(const QOpcUaPkiConfiguration &other)
+ : data(other.data)
+{}
+
+/*!
+ Sets the values of \a rhs in this PKI configuration.
+*/
+QOpcUaPkiConfiguration &QOpcUaPkiConfiguration::operator=(const QOpcUaPkiConfiguration &rhs)
+{
+ if (this != &rhs)
+ data = rhs.data;
+ return *this;
+}
+
+/*!
+ Returns the file path of the application's client certificate.
+ */
+QString QOpcUaPkiConfiguration::clientCertificateFile() const
+{
+ return data->m_clientCertificateFile;
+}
+
+/*!
+ Sets the file path of the application's client certificate to \a value.
+
+ This file has to be in X509 DER format.
+*/
+void QOpcUaPkiConfiguration::setClientCertificateFile(const QString &value)
+{
+ data->m_clientCertificateFile = value;
+}
+
+/*!
+ Returns the file path of the application's private key.
+*/
+QString QOpcUaPkiConfiguration::privateKeyFile() const
+{
+ return data->m_privateKeyFile;
+}
+
+/*!
+ Sets the file path of the application's private key to \a value.
+
+ This file has to be in X509 PEM format.
+*/
+void QOpcUaPkiConfiguration::setPrivateKeyFile(const QString &value)
+{
+ data->m_privateKeyFile = value;
+}
+
+/*!
+ Returns the folder of the certificate trust list.
+*/
+QString QOpcUaPkiConfiguration::trustListDirectory() const
+{
+ return data->m_trustListDirectory;
+}
+
+/*!
+ Sets the path of the certificate trust list directory to \a value.
+
+ All certificates in this directory will be trusted.
+ Certificates have to be in X509 DER format.
+*/
+void QOpcUaPkiConfiguration::setTrustListDirectory(const QString &value)
+{
+ data->m_trustListDirectory = value;
+}
+
+/*!
+ Returns the path of the certificate revocation list directory.
+*/
+QString QOpcUaPkiConfiguration::revocationListDirectory() const
+{
+ return data->m_revocationListDirectory;
+}
+
+/*!
+ Sets the path of the certificate revocation list directory to \a value.
+*/
+void QOpcUaPkiConfiguration::setRevocationListDirectory(const QString &value)
+{
+ data->m_revocationListDirectory = value;
+}
+
+/*!
+ Returns the path of the intermediate issuer list directory.
+
+ These issuers will not be trusted.
+*/
+QString QOpcUaPkiConfiguration::issuerListDirectory() const
+{
+ return data->m_issuerListDirectory;
+}
+
+/*!
+ Sets the path of the intermediate issuer list directory to \a value.
+*/
+void QOpcUaPkiConfiguration::setIssuerListDirectory(const QString &value)
+{
+ data->m_issuerListDirectory = value;
+}
+
+/*!
+ Returns the path of the intermediate issuer revocation list directory.
+*/
+QString QOpcUaPkiConfiguration::issuerRevocationListDirectory() const
+{
+ return data->m_issuerRevocationListDirectory;
+}
+
+/*!
+ Sets the path of the intermediate issuer revocation list directory to \a value.
+*/
+void QOpcUaPkiConfiguration::setIssuerRevocationListDirectory(const QString &value)
+{
+ data->m_issuerRevocationListDirectory = value;
+}
+
+/*!
+ Returns an application identity based on the application's client certificate.
+
+ The application's identity has to match the used certificate. The returned application
+ identity is prefilled by using information of the configured client certificate.
+*/
+QOpcUaApplicationIdentity QOpcUaPkiConfiguration::applicationIdentity() const
+{
+ QOpcUaApplicationIdentity identity;
+
+ auto certList = QSslCertificate::fromPath(clientCertificateFile(), QSsl::Der);
+ if (certList.isEmpty()) {
+ qCWarning(QT_OPCUA_SECURITY) << "No client certificate found at" << clientCertificateFile()
+ << ". Application identity will be invalid.";
+ return QOpcUaApplicationIdentity();
+ }
+
+ auto extensions = certList[0].extensions();
+ for (const auto extension : qAsConst(extensions)) {
+ if (extension.name() == QLatin1String("subjectAltName")) { // OID: 2.5.29.17
+ const auto value = extension.value().toMap();
+ // const QString dns = value[QLatin1String("DNS")].toString();
+ const QString uri = value[QLatin1String("URI")].toString();
+
+ const auto token = uri.split(':', QString::SkipEmptyParts);
+
+ if (token.size() != 4) {
+ qCWarning(QT_OPCUA_SECURITY) << "URI string from certificate has unexpected format:"
+ << uri << "Application identity will be invalid.";
+ return QOpcUaApplicationIdentity();
+ }
+
+ identity.setApplicationUri(uri);
+ identity.setApplicationName(token.at(3));
+ identity.setProductUri(QStringLiteral("%1:%2").arg(token.at(2), token.at(3)));
+ }
+ }
+ return identity;
+}
+
+/*!
+ Return true if the public key information required to validate the server certificate
+ is set.
+*/
+bool QOpcUaPkiConfiguration::isPkiValid() const
+{
+ return !issuerListDirectory().isEmpty() &&
+ !issuerRevocationListDirectory().isEmpty() &&
+ !revocationListDirectory().isEmpty() &&
+ !trustListDirectory().isEmpty();
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuapkiconfiguration.h b/src/opcua/client/qopcuapkiconfiguration.h
new file mode 100644
index 0000000..8c0fe7f
--- /dev/null
+++ b/src/opcua/client/qopcuapkiconfiguration.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Unified Automation GmbH
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAPKICONFIGURATION_H
+#define QOPCUAPKICONFIGURATION_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+
+#include <QtCore/qmetatype.h>
+#include <QtCore/qshareddata.h>
+
+#include <QtOpcUa/qopcuaapplicationidentity.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaPkiConfigurationData;
+class QOpcUaApplicationIdentity;
+
+class Q_OPCUA_EXPORT QOpcUaPkiConfiguration
+{
+public:
+ QOpcUaPkiConfiguration();
+ ~QOpcUaPkiConfiguration();
+ QOpcUaPkiConfiguration(const QOpcUaPkiConfiguration &other);
+ QOpcUaPkiConfiguration &operator=(const QOpcUaPkiConfiguration &rhs);
+
+ QString clientCertificateFile() const;
+ void setClientCertificateFile(const QString &value);
+
+ QString privateKeyFile() const;
+ void setPrivateKeyFile(const QString &value);
+
+ QString trustListDirectory() const;
+ void setTrustListDirectory(const QString &value);
+
+ QString revocationListDirectory() const;
+ void setRevocationListDirectory(const QString &value);
+
+ QString issuerListDirectory() const;
+ void setIssuerListDirectory(const QString &value);
+
+ QString issuerRevocationListDirectory() const;
+ void setIssuerRevocationListDirectory(const QString &value);
+
+ QOpcUaApplicationIdentity applicationIdentity() const;
+
+ bool isPkiValid() const; // Bad name, open for better ideas
+
+private:
+ QSharedDataPointer<QOpcUaPkiConfigurationData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaPkiConfiguration)
+
+#endif // QOPCUAPKICONFIGURATION_H
diff --git a/src/opcua/client/qopcuaqualifiedname.cpp b/src/opcua/client/qopcuaqualifiedname.cpp
new file mode 100644
index 0000000..aaf6bc6
--- /dev/null
+++ b/src/opcua/client/qopcuaqualifiedname.cpp
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuaqualifiedname.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaQualifiedName
+ \inmodule QtOpcUa
+ \brief The OPC UA QualifiedName type.
+
+ This is the Qt OPC UA representation for the OPC UA QualifiedName type defined in OPC-UA part 3, 8.3.
+ A QualifiedName is a name qualified by a namespace index. The namespace index corresponds to an entry in the server's namespace array.
+ QualifiedName is mainly used to represent the BrowseName attribute of a node.
+*/
+
+class QOpcUaQualifiedNameData : public QSharedData
+{
+public:
+ QString name;
+ quint16 namespaceIndex{0}; //OPC UA part 4, page 116: a string is converted to a qualified name by setting the namespace index to 0.
+};
+
+QOpcUaQualifiedName::QOpcUaQualifiedName()
+ : data(new QOpcUaQualifiedNameData)
+{
+}
+
+/*!
+ Constructs a qualified name from \a rhs.
+*/
+QOpcUaQualifiedName::QOpcUaQualifiedName(const QOpcUaQualifiedName &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Constructs a qualified name with namespace index \a namespaceIndex and the name \a name.
+*/
+QOpcUaQualifiedName::QOpcUaQualifiedName(quint16 namespaceIndex, const QString &name)
+ : data(new QOpcUaQualifiedNameData)
+{
+ data->namespaceIndex = namespaceIndex;
+ data->name = name;
+}
+
+/*!
+ Returns \c true if this qualified name has the same value as \a rhs.
+*/
+bool QOpcUaQualifiedName::operator==(const QOpcUaQualifiedName &rhs) const
+{
+ return data->namespaceIndex == rhs.namespaceIndex() &&
+ data->name == rhs.name();
+}
+
+/*!
+ Converts this qualified name to \l QVariant.
+*/
+QOpcUaQualifiedName::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+/*!
+ Sets the values from \a rhs in this qualified name.
+*/
+QOpcUaQualifiedName &QOpcUaQualifiedName::operator=(const QOpcUaQualifiedName &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+QOpcUaQualifiedName::~QOpcUaQualifiedName()
+{
+}
+
+/*!
+ Returns the namespace index.
+*/
+quint16 QOpcUaQualifiedName::namespaceIndex() const
+{
+ return data->namespaceIndex;
+}
+
+/*!
+ Sets the namespace index to \a namespaceIndex.
+*/
+void QOpcUaQualifiedName::setNamespaceIndex(quint16 namespaceIndex)
+{
+ data->namespaceIndex = namespaceIndex;
+}
+
+/*!
+ Returns the name.
+*/
+QString QOpcUaQualifiedName::name() const
+{
+ return data->name;
+}
+
+/*!
+ Sets the name to \a name.
+*/
+void QOpcUaQualifiedName::setName(const QString &name)
+{
+ data->name = name;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaqualifiedname.h b/src/opcua/client/qopcuaqualifiedname.h
new file mode 100644
index 0000000..b4dbb9d
--- /dev/null
+++ b/src/opcua/client/qopcuaqualifiedname.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAQUALIFIEDNAMEDATA_H
+#define QOPCUAQUALIFIEDNAMEDATA_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaQualifiedNameData;
+class Q_OPCUA_EXPORT QOpcUaQualifiedName
+{
+public:
+ QOpcUaQualifiedName();
+ QOpcUaQualifiedName(const QOpcUaQualifiedName &);
+ QOpcUaQualifiedName(quint16 namespaceIndex, const QString &name);
+ QOpcUaQualifiedName &operator=(const QOpcUaQualifiedName &);
+ bool operator==(const QOpcUaQualifiedName &rhs) const;
+ operator QVariant() const;
+ ~QOpcUaQualifiedName();
+
+ QString name() const;
+ void setName(const QString &name);
+
+ quint16 namespaceIndex() const;
+ void setNamespaceIndex(quint16 namespaceIndex);
+
+private:
+ QSharedDataPointer<QOpcUaQualifiedNameData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaQualifiedName)
+
+#endif // QOPCUAQUALIFIEDNAMEDATA_H
diff --git a/src/opcua/client/qopcuarange.cpp b/src/opcua/client/qopcuarange.cpp
new file mode 100644
index 0000000..a4dbe8a
--- /dev/null
+++ b/src/opcua/client/qopcuarange.cpp
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuarange.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaRange
+ \inmodule QtOpcUa
+ \brief The OPC UA Range type.
+
+ This is the Qt OPC UA representation for the OPC UA Range type defined in OPC-UA part 8, 5.6.2.
+ It consists of two double values which mark minimum and maximum of the range.
+ Ranges are mostly used to store information about acceptable values for a node.
+*/
+
+class QOpcUaRangeData : public QSharedData
+{
+public:
+ double low{0};
+ double high{0};
+};
+
+QOpcUaRange::QOpcUaRange()
+ : data(new QOpcUaRangeData)
+{
+}
+
+/*!
+ Constructs a range from \a rhs.
+*/
+QOpcUaRange::QOpcUaRange(const QOpcUaRange &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Constructs a range with low value \a low and high value \a high.
+*/
+QOpcUaRange::QOpcUaRange(double low, double high)
+ : data(new QOpcUaRangeData)
+{
+ data->low = low;
+ data->high = high;
+}
+
+/*!
+ Sets the values from \a rhs in this range.
+*/
+QOpcUaRange &QOpcUaRange::operator=(const QOpcUaRange &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns \c true if this range has the same value as \a rhs.
+*/
+bool QOpcUaRange::operator==(const QOpcUaRange &rhs) const
+{
+ return data->low == rhs.low() &&
+ data->high == rhs.high();
+}
+
+/*!
+ Converts this range to \l QVariant.
+*/
+QOpcUaRange::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+QOpcUaRange::~QOpcUaRange()
+{
+}
+
+/*!
+ Returns the high value of the range.
+*/
+double QOpcUaRange::high() const
+{
+ return data->high;
+}
+
+/*!
+ Sets the high value of the range to \a high.
+*/
+void QOpcUaRange::setHigh(double high)
+{
+ data->high = high;
+}
+
+/*!
+ Returns the low value of the range.
+*/
+double QOpcUaRange::low() const
+{
+ return data->low;
+}
+
+/*!
+ Sets the low value of the range to \a low.
+*/
+void QOpcUaRange::setLow(double low)
+{
+ data->low = low;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuarange.h b/src/opcua/client/qopcuarange.h
new file mode 100644
index 0000000..cefe1c1
--- /dev/null
+++ b/src/opcua/client/qopcuarange.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUARANGE_H
+#define QOPCUARANGE_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaRangeData;
+class Q_OPCUA_EXPORT QOpcUaRange
+{
+public:
+ QOpcUaRange();
+ QOpcUaRange(const QOpcUaRange &);
+ QOpcUaRange(double low, double high);
+ QOpcUaRange &operator=(const QOpcUaRange &);
+ bool operator==(const QOpcUaRange &rhs) const;
+ operator QVariant() const;
+ ~QOpcUaRange();
+
+ double low() const;
+ void setLow(double low);
+
+ double high() const;
+ void setHigh(double high);
+
+private:
+ QSharedDataPointer<QOpcUaRangeData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaRange)
+
+#endif // QOPCUARANGE_H
diff --git a/src/opcua/client/qopcuareaditem.cpp b/src/opcua/client/qopcuareaditem.cpp
index c9261bc..b5ce918 100644
--- a/src/opcua/client/qopcuareaditem.cpp
+++ b/src/opcua/client/qopcuareaditem.cpp
@@ -47,9 +47,9 @@ QT_BEGIN_NAMESPACE
attribute of a node on the server. This class contains the necessary information for the backend to make
a read request to the server.
- One or multiple objects of this class make up the request of a \l QOpcUaClient::batchRead() operation.
+ One or multiple objects of this class make up the request of a \l QOpcUaClient::readNodeAttributes() operation.
- \sa QOpcUaClient::batchRead() QOpcUaReadResult
+ \sa QOpcUaClient::readNodeAttributes() QOpcUaReadResult
*/
class QOpcUaReadItemData : public QSharedData
diff --git a/src/opcua/client/qopcuareaditem.h b/src/opcua/client/qopcuareaditem.h
index 35a33e7..1a202ad 100644
--- a/src/opcua/client/qopcuareaditem.h
+++ b/src/opcua/client/qopcuareaditem.h
@@ -38,6 +38,7 @@
#define QOPCUAREADITEM_H
#include <QtOpcUa/qopcuatype.h>
+#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
diff --git a/src/opcua/client/qopcuareadresult.cpp b/src/opcua/client/qopcuareadresult.cpp
index 739717f..aa5b1df 100644
--- a/src/opcua/client/qopcuareadresult.cpp
+++ b/src/opcua/client/qopcuareadresult.cpp
@@ -50,11 +50,11 @@ QT_BEGIN_NAMESPACE
In addition to the data returned by the server, this class also contains the node id, the attribute and the index
range from the request to enable a client to match the result with a request.
- Objects of this class are returned in the \l QOpcUaClient::batchReadFinished()
- signal and contain the result of a read operation that was part of a \l QOpcUaClient::batchRead()
+ Objects of this class are returned in the \l QOpcUaClient::readNodeAttributesFinished()
+ signal and contain the result of a read operation that was part of a \l QOpcUaClient::readNodeAttributes()
request.
- \sa QOpcUaClient::batchRead() QOpcUaClient::batchReadFinished() QOpcUaReadItem
+ \sa QOpcUaClient::readNodeAttributes() QOpcUaClient::readNodeAttributesFinished() QOpcUaReadItem
*/
class QOpcUaReadResultData : public QSharedData
{
diff --git a/src/opcua/client/qopcuareferencedescription.cpp b/src/opcua/client/qopcuareferencedescription.cpp
index d0d0143..b2d9766 100644
--- a/src/opcua/client/qopcuareferencedescription.cpp
+++ b/src/opcua/client/qopcuareferencedescription.cpp
@@ -35,6 +35,9 @@
****************************************************************************/
#include "qopcuareferencedescription.h"
+#include <QtOpcUa/qopcuaexpandednodeid.h>
+#include <QtOpcUa/qopcuaqualifiedname.h>
+#include <QtOpcUa/qopcualocalizedtext.h>
QT_BEGIN_NAMESPACE
@@ -67,10 +70,10 @@ class QOpcUaReferenceDescriptionPrivate : public QSharedData
{
public:
QString refTypeId;
- QOpcUa::QExpandedNodeId targetNodeId;
- QOpcUa::QExpandedNodeId typeDefinition;
- QOpcUa::QQualifiedName browseName;
- QOpcUa::QLocalizedText displayName;
+ QOpcUaExpandedNodeId targetNodeId;
+ QOpcUaExpandedNodeId typeDefinition;
+ QOpcUaQualifiedName browseName;
+ QOpcUaLocalizedText displayName;
QOpcUa::NodeClass nodeClass {QOpcUa::NodeClass::Object};
bool isForwardReference {true};
};
@@ -139,7 +142,7 @@ bool QOpcUaReferenceDescription::isForwardReference() const
/*!
Sets \a typeDefinition as id of the type definition.
*/
-void QOpcUaReferenceDescription::setTypeDefinition(const QOpcUa::QExpandedNodeId &typeDefinition)
+void QOpcUaReferenceDescription::setTypeDefinition(const QOpcUaExpandedNodeId &typeDefinition)
{
d_ptr->typeDefinition = typeDefinition;
}
@@ -147,7 +150,7 @@ void QOpcUaReferenceDescription::setTypeDefinition(const QOpcUa::QExpandedNodeId
/*!
Returns the type definition id.
*/
-QOpcUa::QExpandedNodeId QOpcUaReferenceDescription::typeDefinition() const
+QOpcUaExpandedNodeId QOpcUaReferenceDescription::typeDefinition() const
{
return d_ptr->typeDefinition;
}
@@ -155,7 +158,7 @@ QOpcUa::QExpandedNodeId QOpcUaReferenceDescription::typeDefinition() const
/*!
Returns the display name of the node.
*/
-QOpcUa::QLocalizedText QOpcUaReferenceDescription::displayName() const
+QOpcUaLocalizedText QOpcUaReferenceDescription::displayName() const
{
return d_ptr->displayName;
}
@@ -163,7 +166,7 @@ QOpcUa::QLocalizedText QOpcUaReferenceDescription::displayName() const
/*!
Sets the display name of the node to \a displayName.
*/
-void QOpcUaReferenceDescription::setDisplayName(const QOpcUa::QLocalizedText &displayName)
+void QOpcUaReferenceDescription::setDisplayName(const QOpcUaLocalizedText &displayName)
{
d_ptr->displayName = displayName;
}
@@ -171,7 +174,7 @@ void QOpcUaReferenceDescription::setDisplayName(const QOpcUa::QLocalizedText &di
/*!
Returns the browse name of the node.
*/
-QOpcUa::QQualifiedName QOpcUaReferenceDescription::browseName() const
+QOpcUaQualifiedName QOpcUaReferenceDescription::browseName() const
{
return d_ptr->browseName;
}
@@ -179,7 +182,7 @@ QOpcUa::QQualifiedName QOpcUaReferenceDescription::browseName() const
/*!
Sets the browse name of the node to \a browseName.
*/
-void QOpcUaReferenceDescription::setBrowseName(const QOpcUa::QQualifiedName &browseName)
+void QOpcUaReferenceDescription::setBrowseName(const QOpcUaQualifiedName &browseName)
{
d_ptr->browseName = browseName;
}
@@ -187,7 +190,7 @@ void QOpcUaReferenceDescription::setBrowseName(const QOpcUa::QQualifiedName &bro
/*!
Returns the node id of the node.
*/
-QOpcUa::QExpandedNodeId QOpcUaReferenceDescription::targetNodeId() const
+QOpcUaExpandedNodeId QOpcUaReferenceDescription::targetNodeId() const
{
return d_ptr->targetNodeId;
}
@@ -195,7 +198,7 @@ QOpcUa::QExpandedNodeId QOpcUaReferenceDescription::targetNodeId() const
/*!
Sets the node id of the node to \a nodeId.
*/
-void QOpcUaReferenceDescription::setTargetNodeId(const QOpcUa::QExpandedNodeId &nodeId)
+void QOpcUaReferenceDescription::setTargetNodeId(const QOpcUaExpandedNodeId &nodeId)
{
d_ptr->targetNodeId = nodeId;
}
diff --git a/src/opcua/client/qopcuareferencedescription.h b/src/opcua/client/qopcuareferencedescription.h
index 95fa6ae..09ce6a3 100644
--- a/src/opcua/client/qopcuareferencedescription.h
+++ b/src/opcua/client/qopcuareferencedescription.h
@@ -43,6 +43,10 @@
QT_BEGIN_NAMESPACE
+class QOpcUaExpandedNodeId;
+class QOpcUaQualifiedName;
+class QOpcUaLocalizedText;
+
class QOpcUaReferenceDescriptionPrivate;
class Q_OPCUA_EXPORT QOpcUaReferenceDescription
{
@@ -55,18 +59,18 @@ public:
QString refTypeId() const;
void setRefTypeId(const QString &refTypeId);
- QOpcUa::QExpandedNodeId targetNodeId() const;
- void setTargetNodeId(const QOpcUa::QExpandedNodeId &targetNodeId);
- QOpcUa::QQualifiedName browseName() const;
- void setBrowseName(const QOpcUa::QQualifiedName &browseName);
- QOpcUa::QLocalizedText displayName() const;
- void setDisplayName(const QOpcUa::QLocalizedText &displayName);
+ QOpcUaExpandedNodeId targetNodeId() const;
+ void setTargetNodeId(const QOpcUaExpandedNodeId &targetNodeId);
+ QOpcUaQualifiedName browseName() const;
+ void setBrowseName(const QOpcUaQualifiedName &browseName);
+ QOpcUaLocalizedText displayName() const;
+ void setDisplayName(const QOpcUaLocalizedText &displayName);
QOpcUa::NodeClass nodeClass() const;
void setNodeClass(QOpcUa::NodeClass nodeClass);
void setIsForwardReference(bool isForwardReference);
bool isForwardReference() const;
- void setTypeDefinition(const QOpcUa::QExpandedNodeId &typeDefinition);
- QOpcUa::QExpandedNodeId typeDefinition() const;
+ void setTypeDefinition(const QOpcUaExpandedNodeId &typeDefinition);
+ QOpcUaExpandedNodeId typeDefinition() const;
private:
QSharedDataPointer<QOpcUaReferenceDescriptionPrivate> d_ptr;
diff --git a/src/opcua/client/qopcuarelativepathelement.cpp b/src/opcua/client/qopcuarelativepathelement.cpp
new file mode 100644
index 0000000..e1fa7da
--- /dev/null
+++ b/src/opcua/client/qopcuarelativepathelement.cpp
@@ -0,0 +1,195 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuarelativepathelement.h"
+#include "qopcuaqualifiedname.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaRelativePathElement
+ \inmodule QtOpcUa
+ \brief The OPC UA RelativePathElement.
+
+ QOpcUaRelativePathElement defines an element of a relative path on an OPC UA server.
+ This is needed for resolution of browse paths to node ids in \l QOpcUaNode::resolveBrowsePath().
+*/
+
+class QOpcUaRelativePathElementData : public QSharedData
+{
+public:
+ QString referenceTypeId;
+ bool isInverse{false};
+ bool includeSubtypes{false};
+ QOpcUaQualifiedName targetName;
+};
+
+/*!
+ Constructs a relative path element with both flags set to \c false.
+*/
+QOpcUaRelativePathElement::QOpcUaRelativePathElement()
+ : data(new QOpcUaRelativePathElementData())
+{
+}
+
+/*!
+ Constructs a relative path element with targetName \a target, reference type node id \a refType and both flags set to \c false.
+*/
+QOpcUaRelativePathElement::QOpcUaRelativePathElement(const QOpcUaQualifiedName &target, const QString &refType)
+ : data(new QOpcUaRelativePathElementData())
+{
+ data->referenceTypeId = refType;
+ data->targetName = target;
+}
+
+/*!
+ Constructs a relative path element with targetName \a target, \l QOpcUa::ReferenceTypeId \a refType and both flags set to \c false.
+*/
+QOpcUaRelativePathElement::QOpcUaRelativePathElement(const QOpcUaQualifiedName &target, QOpcUa::ReferenceTypeId refType)
+ : data(new QOpcUaRelativePathElementData())
+{
+ data->referenceTypeId = QOpcUa::nodeIdFromReferenceType(refType);
+ data->targetName = target;
+}
+
+/*!
+ Constructs a relative path element from \a rhs.
+*/
+QOpcUaRelativePathElement::QOpcUaRelativePathElement(const QOpcUaRelativePathElement &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Sets the values of \a rhs in this relative path element.
+*/
+QOpcUaRelativePathElement &QOpcUaRelativePathElement::operator=(const QOpcUaRelativePathElement &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns \c true if this relative path element has the same value as \a rhs.
+*/
+bool QOpcUaRelativePathElement::operator==(const QOpcUaRelativePathElement &rhs) const
+{
+ return data->includeSubtypes == rhs.includeSubtypes() &&
+ data->isInverse == rhs.isInverse() &&
+ data->referenceTypeId == rhs.referenceTypeId() &&
+ data->targetName == rhs.targetName();
+}
+
+QOpcUaRelativePathElement::~QOpcUaRelativePathElement()
+{
+}
+
+/*!
+ Returns the qualified name of the reference's target.
+*/
+QOpcUaQualifiedName QOpcUaRelativePathElement::targetName() const
+{
+ return data->targetName;
+}
+
+/*!
+ Sets the target name to \a targetName, for example QOpcUaQualifiedName(0, "DataTypes").
+*/
+void QOpcUaRelativePathElement::setTargetName(const QOpcUaQualifiedName &targetName)
+{
+ data->targetName = targetName;
+}
+
+/*!
+ Returns the value of the includeSubtypes flag.
+*/
+bool QOpcUaRelativePathElement::includeSubtypes() const
+{
+ return data->includeSubtypes;
+}
+
+/*!
+ Sets the includeSubtypes flag to \a includeSubtypes.
+ If the flag is \c true, the lookup also follows references with subtypes of \l referenceTypeId().
+*/
+void QOpcUaRelativePathElement::setIncludeSubtypes(bool includeSubtypes)
+{
+ data->includeSubtypes = includeSubtypes;
+}
+
+/*!
+ Returns the value of the isInverse flag.
+*/
+bool QOpcUaRelativePathElement::isInverse() const
+{
+ return data->isInverse;
+}
+
+/*!
+ Sets the isInverse flag to \a isInverse.
+ If the flag is \c true, the lookup follows the reverse reference.
+*/
+void QOpcUaRelativePathElement::setIsInverse(bool isInverse)
+{
+ data->isInverse = isInverse;
+}
+
+/*!
+ Returns the type id of the reference connecting this node to the previous node.
+*/
+QString QOpcUaRelativePathElement::referenceTypeId() const
+{
+ return data->referenceTypeId;
+}
+
+/*!
+ Sets the reference type id to \a referenceTypeId.
+*/
+void QOpcUaRelativePathElement::setReferenceTypeId(const QString &referenceTypeId)
+{
+ data->referenceTypeId = referenceTypeId;
+}
+
+/*!
+ Sets the reference type id to \a referenceTypeId.
+*/
+void QOpcUaRelativePathElement::setReferenceTypeId(QOpcUa::ReferenceTypeId referenceTypeId)
+{
+ data->referenceTypeId = QOpcUa::nodeIdFromReferenceType(referenceTypeId);
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuarelativepathelement.h b/src/opcua/client/qopcuarelativepathelement.h
new file mode 100644
index 0000000..61e3ba5
--- /dev/null
+++ b/src/opcua/client/qopcuarelativepathelement.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUARELATIVEPATHELEMENT_H
+#define QOPCUARELATIVEPATHELEMENT_H
+
+#include <QtOpcUa/qopcuatype.h>
+
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaQualifiedName;
+
+class QOpcUaRelativePathElementData;
+class Q_OPCUA_EXPORT QOpcUaRelativePathElement
+{
+public:
+ QOpcUaRelativePathElement();
+ QOpcUaRelativePathElement(const QOpcUaQualifiedName &target, const QString &refType);
+ QOpcUaRelativePathElement(const QOpcUaQualifiedName &target, QOpcUa::ReferenceTypeId refType);
+ QOpcUaRelativePathElement(const QOpcUaRelativePathElement &);
+ QOpcUaRelativePathElement &operator=(const QOpcUaRelativePathElement &);
+ bool operator==(const QOpcUaRelativePathElement &rhs) const;
+ ~QOpcUaRelativePathElement();
+
+ QString referenceTypeId() const;
+ void setReferenceTypeId(const QString &referenceTypeId);
+ void setReferenceTypeId(QOpcUa::ReferenceTypeId referenceTypeId);
+
+ bool isInverse() const;
+ void setIsInverse(bool isInverse);
+
+ bool includeSubtypes() const;
+ void setIncludeSubtypes(bool includeSubtypes);
+
+ QOpcUaQualifiedName targetName() const;
+ void setTargetName(const QOpcUaQualifiedName &targetName);
+
+private:
+ QSharedDataPointer<QOpcUaRelativePathElementData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaRelativePathElement)
+
+#endif // QOPCUARELATIVEPATHELEMENT_H
diff --git a/src/opcua/client/qopcuasimpleattributeoperand.cpp b/src/opcua/client/qopcuasimpleattributeoperand.cpp
new file mode 100644
index 0000000..bf5ca52
--- /dev/null
+++ b/src/opcua/client/qopcuasimpleattributeoperand.cpp
@@ -0,0 +1,207 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuasimpleattributeoperand.h"
+#include "qopcuaqualifiedname.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaSimpleAttributeOperand
+ \inmodule QtOpcUa
+ \brief The OPC UA SimpleAttributeOperand type.
+
+ The SimpleAttributeOperand is specified in OPC-UA part 4, 7.4.4.5.
+ It is used when a node attribute is required as operand.
+
+ For example, the following simple attribute operand represents the value
+ of the "Severity" field of the base event type:
+ \code
+ QOpcUaSimpleAttributeOperand("Severity");
+ \endcode
+*/
+class QOpcUaSimpleAttributeOperandData : public QSharedData
+{
+public:
+ QString typeId{QStringLiteral("ns=0;i=2041")}; // BaseEventType
+ QVector<QOpcUaQualifiedName> browsePath;
+ QOpcUa::NodeAttribute attributeId {QOpcUa::NodeAttribute::Value};
+ QString indexRange;
+};
+
+QOpcUaSimpleAttributeOperand::QOpcUaSimpleAttributeOperand()
+ : data(new QOpcUaSimpleAttributeOperandData)
+{
+}
+
+/*!
+ Constructs a simple attribute operand from \a rhs.
+*/
+QOpcUaSimpleAttributeOperand::QOpcUaSimpleAttributeOperand(const QOpcUaSimpleAttributeOperand &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Constructs a simple attribute operand for attribute \a attributeId of the direct child with the browse name
+ \a name in namespace \a namespaceIndex. \a typeId is the node id of a type definition node. The operand will
+ be restricted to instances of type \a typeId or a subtype.
+*/
+QOpcUaSimpleAttributeOperand::QOpcUaSimpleAttributeOperand(const QString &name, quint16 namespaceIndex, const QString &typeId, QOpcUa::NodeAttribute attributeId)
+ : data(new QOpcUaSimpleAttributeOperandData)
+{
+ browsePathRef().append(QOpcUaQualifiedName(namespaceIndex, name));
+ setTypeId(typeId);
+ setAttributeId(attributeId);
+}
+
+/*!
+ Constructs a simple attribute operand for the attribute \a attributeId of an object or variable of type \a typeId.
+ This can be used for requesting the ConditionId in an event filter as described in OPC-UA part 9, Table 8.
+*/
+QOpcUaSimpleAttributeOperand::QOpcUaSimpleAttributeOperand(QOpcUa::NodeAttribute attributeId, const QString &typeId)
+ : data(new QOpcUaSimpleAttributeOperandData)
+{
+ setTypeId(typeId);
+ setAttributeId(attributeId);
+}
+
+/*!
+ Sets the values from \a rhs in this simple attribute operand.
+*/
+QOpcUaSimpleAttributeOperand &QOpcUaSimpleAttributeOperand::operator=(const QOpcUaSimpleAttributeOperand &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns \c true if this simple attribute operand has the same value as \a rhs.
+*/
+bool QOpcUaSimpleAttributeOperand::operator==(const QOpcUaSimpleAttributeOperand &rhs) const
+{
+ return attributeId() == rhs.attributeId() && browsePath() == rhs.browsePath() &&
+ indexRange() == rhs.indexRange() && typeId() == rhs.typeId();
+}
+
+/*!
+ Converts this simple attribute operand to \l QVariant.
+*/
+QOpcUaSimpleAttributeOperand::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+QOpcUaSimpleAttributeOperand::~QOpcUaSimpleAttributeOperand()
+{
+}
+
+/*!
+ Returns the index range string.
+*/
+QString QOpcUaSimpleAttributeOperand::indexRange() const
+{
+ return data->indexRange;
+}
+
+/*!
+ Sets the index range string used to identify a single value or subset of the attribute's value to \a indexRange.
+*/
+void QOpcUaSimpleAttributeOperand::setIndexRange(const QString &indexRange)
+{
+ data->indexRange = indexRange;
+}
+
+/*!
+ Returns the attribute of the node \l browsePath is pointing to.
+*/
+QOpcUa::NodeAttribute QOpcUaSimpleAttributeOperand::attributeId() const
+{
+ return data->attributeId;
+}
+
+/*!
+ Sets the attribute id to \a attributeId.
+*/
+void QOpcUaSimpleAttributeOperand::setAttributeId(QOpcUa::NodeAttribute attributeId)
+{
+ data->attributeId = attributeId;
+}
+
+/*!
+ Returns the relative path to a node starting from \l typeId.
+*/
+QVector<QOpcUaQualifiedName> QOpcUaSimpleAttributeOperand::browsePath() const
+{
+ return data->browsePath;
+}
+
+/*!
+ Returns a reference to the browse path.
+
+ \sa browsePath()
+*/
+QVector<QOpcUaQualifiedName> &QOpcUaSimpleAttributeOperand::browsePathRef()
+{
+ return data->browsePath;
+}
+
+/*!
+ Sets the browse path to the node holding the attribute to \a browsePath.
+*/
+void QOpcUaSimpleAttributeOperand::setBrowsePath(const QVector<QOpcUaQualifiedName> &browsePath)
+{
+ data->browsePath = browsePath;
+}
+
+/*!
+ Returns the node id of a type definition node.
+*/
+QString QOpcUaSimpleAttributeOperand::typeId() const
+{
+ return data->typeId;
+}
+
+/*!
+ Sets the node id of the type definition node to \a typeId. The operand will be of the type or one of its subtypes.
+*/
+void QOpcUaSimpleAttributeOperand::setTypeId(const QString &typeId)
+{
+ data->typeId = typeId;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuasimpleattributeoperand.h b/src/opcua/client/qopcuasimpleattributeoperand.h
new file mode 100644
index 0000000..711d17d
--- /dev/null
+++ b/src/opcua/client/qopcuasimpleattributeoperand.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUASIMPLEATTRIBUTEOPERAND_H
+#define QOPCUASIMPLEATTRIBUTEOPERAND_H
+
+#include <QtOpcUa/qopcuatype.h>
+
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaQualifiedName;
+
+// OPC-UA part 4, 7.4.4.5
+class QOpcUaSimpleAttributeOperandData;
+class Q_OPCUA_EXPORT QOpcUaSimpleAttributeOperand
+{
+public:
+ QOpcUaSimpleAttributeOperand();
+ QOpcUaSimpleAttributeOperand(const QOpcUaSimpleAttributeOperand &);
+ QOpcUaSimpleAttributeOperand(const QString &name, quint16 namespaceIndex = 0,
+ const QString &typeId = QStringLiteral("ns=0;i=2041"), // BaseEventType
+ QOpcUa::NodeAttribute attributeId = QOpcUa::NodeAttribute::Value);
+ QOpcUaSimpleAttributeOperand(QOpcUa::NodeAttribute attributeId,
+ const QString &typeId = QStringLiteral("ns=0;i=2041")); // BaseEventType
+ QOpcUaSimpleAttributeOperand &operator=(const QOpcUaSimpleAttributeOperand &);
+ bool operator==(const QOpcUaSimpleAttributeOperand &rhs) const;
+ operator QVariant() const;
+ ~QOpcUaSimpleAttributeOperand();
+
+ QString typeId() const;
+ void setTypeId(const QString &typeId);
+
+ QVector<QOpcUaQualifiedName> browsePath() const;
+ QVector<QOpcUaQualifiedName> &browsePathRef();
+ void setBrowsePath(const QVector<QOpcUaQualifiedName> &browsePath);
+
+ QOpcUa::NodeAttribute attributeId() const;
+ void setAttributeId(QOpcUa::NodeAttribute attributeId);
+
+ QString indexRange() const;
+ void setIndexRange(const QString &indexRange);
+
+private:
+ QSharedDataPointer<QOpcUaSimpleAttributeOperandData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaSimpleAttributeOperand)
+
+#endif // QOPCUASIMPLEATTRIBUTEOPERAND_H
diff --git a/src/opcua/client/qopcuatype.cpp b/src/opcua/client/qopcuatype.cpp
index 6f55db8..c9e1519 100644
--- a/src/opcua/client/qopcuatype.cpp
+++ b/src/opcua/client/qopcuatype.cpp
@@ -504,254 +504,6 @@ bool QOpcUa::isSuccessStatus(QOpcUa::UaStatusCode statusCode)
This is QPair<QVariant, QOpcUa::Types>.
*/
-/*!
- \class QOpcUa::QQualifiedName
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA QualifiedName type.
-
- This is the Qt OPC UA representation for the OPC UA QualifiedName type defined in OPC-UA part 3, 8.3.
- A QualifiedName is a name qualified by a namespace index. The namespace index corresponds to an entry in the server's namespace array.
- QualifiedName is mainly used to represent the BrowseName attribute of a node.
-*/
-
-class QOpcUa::QQualifiedNameData : public QSharedData
-{
-public:
- QString name;
- quint16 namespaceIndex{0}; //OPC UA part 4, page 116: a string is converted to a qualified name by setting the namespace index to 0.
-};
-
-QOpcUa::QQualifiedName::QQualifiedName()
- : data(new QOpcUa::QQualifiedNameData)
-{
-}
-
-/*!
- Constructs a qualified name from \a rhs.
-*/
-QOpcUa::QQualifiedName::QQualifiedName(const QOpcUa::QQualifiedName &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Constructs a qualified name with namespace index \a namespaceIndex and the name \a name.
-*/
-QOpcUa::QQualifiedName::QQualifiedName(quint16 namespaceIndex, const QString &name)
- : data(new QOpcUa::QQualifiedNameData)
-{
- data->namespaceIndex = namespaceIndex;
- data->name = name;
-}
-
-/*!
- Returns \c true if this qualified name has the same value as \a rhs.
-*/
-bool QOpcUa::QQualifiedName::operator==(const QOpcUa::QQualifiedName &rhs) const
-{
- return data->namespaceIndex == rhs.namespaceIndex() &&
- data->name == rhs.name();
-}
-
-/*!
- Converts this qualified name to \l QVariant.
-*/
-QOpcUa::QQualifiedName::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-/*!
- Sets the values from \a rhs in this qualified name.
-*/
-QOpcUa::QQualifiedName &QOpcUa::QQualifiedName::operator=(const QOpcUa::QQualifiedName &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-QOpcUa::QQualifiedName::~QQualifiedName()
-{
-}
-
-/*!
- Returns the namespace index.
-*/
-quint16 QOpcUa::QQualifiedName::namespaceIndex() const
-{
- return data->namespaceIndex;
-}
-
-/*!
- Sets the namespace index to \a namespaceIndex.
-*/
-void QOpcUa::QQualifiedName::setNamespaceIndex(quint16 namespaceIndex)
-{
- data->namespaceIndex = namespaceIndex;
-}
-
-/*!
- Returns the name.
-*/
-QString QOpcUa::QQualifiedName::name() const
-{
- return data->name;
-}
-
-/*!
- Sets the name to \a name.
-*/
-void QOpcUa::QQualifiedName::setName(const QString &name)
-{
- data->name = name;
-}
-
-/*!
- \class QOpcUa::QLocalizedText
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA LocalizedText type.
-
- This is the Qt OPC UA representation for the OPC UA LocalizedText type defined in OPC-UA part 3, 8.5.
- A LocalizedText value contains a text string with associated locale information in a second string (e. g. "en" or "en-US").
- The format of the locale information string is <language>[-<country/region>]. Language is usually given as ISO 639 two letter code,
- country/region as ISO 3166 two letter code. Custom codes are also allowed (see OPC-UA part 3, 8.4).
- It can be used to provide multiple text strings in different languages for a value using an array of LocalizedText elements.
-*/
-
-/*!
- \qmltype LocalizedText
- \inqmlmodule QtOpcUa
- \brief Contains a text with associated locale.
- \since QtOpcUa 5.12
-
- The two members of this type contain the actual text and the locale of the text.
-*/
-
-/*!
- \property QOpcUa::QLocalizedText::text
-
- Textual content.
-*/
-
-/*!
- \qmlproperty string LocalizedText::text
-
- Textual content.
-*/
-
-/*!
- \property QOpcUa::QLocalizedText::locale
-
- Locale of the contained text.
- This has to be in a modified ISO standard notation, for example \c en-US.
- See OPC UA specification part 3, 8.4 for details.
-*/
-
-/*!
- \qmlproperty string LocalizedText::locale
-
- Locale of the contained text.
- This has to be in a modified ISO standard notation, for example \c en-US.
- See OPC UA specification part 3, 8.4 for details.
-*/
-
-class QOpcUa::QLocalizedTextData : public QSharedData
-{
-public:
- QString locale;
- QString text;
-};
-
-QOpcUa::QLocalizedText::QLocalizedText()
- : data(new QOpcUa::QLocalizedTextData)
-{
-}
-
-/*!
- Constructs a localized text from \a rhs.
-*/
-QOpcUa::QLocalizedText::QLocalizedText(const QOpcUa::QLocalizedText &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Constructs a localized text with the locale \a locale and the text \a text.
-*/
-QOpcUa::QLocalizedText::QLocalizedText(const QString &locale, const QString &text)
- : data(new QOpcUa::QLocalizedTextData)
-{
- data->locale = locale;
- data->text = text;
-}
-
-/*!
- Sets the values from \a rhs in this localized text.
-*/
-QOpcUa::QLocalizedText &QOpcUa::QLocalizedText::operator=(const QOpcUa::QLocalizedText &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-/*!
- Returns \c true if this localized text has the same value as \a rhs.
-*/
-bool QOpcUa::QLocalizedText::operator==(const QOpcUa::QLocalizedText &rhs) const
-{
- return data->locale == rhs.locale() &&
- data->text == rhs.text();
-}
-
-/*!
- Converts this localized text to \l QVariant.
-*/
-QOpcUa::QLocalizedText::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-QOpcUa::QLocalizedText::~QLocalizedText()
-{
-}
-
-/*!
- Returns the text.
-*/
-QString QOpcUa::QLocalizedText::text() const
-{
- return data->text;
-}
-
-/*!
- Sets the text to \a text.
-
-*/
-void QOpcUa::QLocalizedText::setText(const QString &text)
-{
- data->text = text;
-}
-
-/*!
- Returns the locale.
-*/
-QString QOpcUa::QLocalizedText::locale() const
-{
- return data->locale;
-}
-
-/*!
- Sets the locale to \a locale.
-*/
-void QOpcUa::QLocalizedText::setLocale(const QString &locale)
-{
- data->locale = locale;
-}
-
static bool isNodeError(QOpcUa::UaStatusCode statusCode)
{
switch (statusCode) {
@@ -1019,456 +771,6 @@ QString QOpcUa::namespace0IdName(QOpcUa::NodeIds::Namespace0 id)
}
/*!
- \class QOpcUa::QRange
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA Range type.
-
- This is the Qt OPC UA representation for the OPC UA Range type defined in OPC-UA part 8, 5.6.2.
- It consists of two double values which mark minimum and maximum of the range.
- Ranges are mostly used to store information about acceptable values for a node.
-*/
-
-class QOpcUa::QRangeData : public QSharedData
-{
-public:
- double low{0};
- double high{0};
-};
-
-QOpcUa::QRange::QRange()
- : data(new QOpcUa::QRangeData)
-{
-}
-
-/*!
- Constructs a range from \a rhs.
-*/
-QOpcUa::QRange::QRange(const QOpcUa::QRange &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Constructs a range with low value \a low and high value \a high.
-*/
-QOpcUa::QRange::QRange(double low, double high)
- : data(new QOpcUa::QRangeData)
-{
- data->low = low;
- data->high = high;
-}
-
-/*!
- Sets the values from \a rhs in this range.
-*/
-QOpcUa::QRange &QOpcUa::QRange::operator=(const QOpcUa::QRange &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-/*!
- Returns \c true if this range has the same value as \a rhs.
-*/
-bool QOpcUa::QRange::operator==(const QOpcUa::QRange &rhs) const
-{
- return data->low == rhs.low() &&
- data->high == rhs.high();
-}
-
-/*!
- Converts this range to \l QVariant.
-*/
-QOpcUa::QRange::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-QOpcUa::QRange::~QRange()
-{
-}
-
-/*!
- Returns the high value of the range.
-*/
-double QOpcUa::QRange::high() const
-{
- return data->high;
-}
-
-/*!
- Sets the high value of the range to \a high.
-*/
-void QOpcUa::QRange::setHigh(double high)
-{
- data->high = high;
-}
-
-/*!
- Returns the low value of the range.
-*/
-double QOpcUa::QRange::low() const
-{
- return data->low;
-}
-
-/*!
- Sets the low value of the range to \a low.
-*/
-void QOpcUa::QRange::setLow(double low)
-{
- data->low = low;
-}
-
-/*!
- \class QOpcUa::QEUInformation
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA EURange type.
-
- This is the Qt OPC UA representation for the OPC UA EUInformation type defined in OPC-UA part 8, 5.6.3.
- EUInformation values contain information about units and are mostly used as property of a node with a numeric value attribute.
- The information can e. g. be used to add text and tooltips to GUI elements.
-*/
-
-class QOpcUa::QEUInformationData : public QSharedData
-{
-public:
- QString namespaceUri;
- qint32 unitId{0};
- QOpcUa::QLocalizedText displayName;
- QOpcUa::QLocalizedText description;
-};
-
-QOpcUa::QEUInformation::QEUInformation()
- : data(new QOpcUa::QEUInformationData)
-{
-}
-
-/*!
- Constructs a EUinformation from \a rhs.
-*/
-QOpcUa::QEUInformation::QEUInformation(const QOpcUa::QEUInformation &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Sets the values from \a rhs in this EUinformation.
-*/
-QOpcUa::QEUInformation &QOpcUa::QEUInformation::operator=(const QOpcUa::QEUInformation &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-QOpcUa::QEUInformation::~QEUInformation()
-{
-}
-
-/*!
- Returns the description of the unit, for example \e {degree Celsius}.
-*/
-QOpcUa::QLocalizedText QOpcUa::QEUInformation::description() const
-{
- return data->description;
-}
-
-/*!
- Sets the description if the unit to \a description.
-*/
-void QOpcUa::QEUInformation::setDescription(const QOpcUa::QLocalizedText &description)
-{
- data->description = description;
-}
-
-/*!
- Returns the display name of the unit, for example \e {°C}.
-*/
-QOpcUa::QLocalizedText QOpcUa::QEUInformation::displayName() const
-{
- return data->displayName;
-}
-
-/*!
- Sets the display name of the unit to \a displayName.
-*/
-void QOpcUa::QEUInformation::setDisplayName(const QOpcUa::QLocalizedText &displayName)
-{
- data->displayName = displayName;
-}
-
-/*!
- Returns the machine-readable identifier for the unit.
-*/
-qint32 QOpcUa::QEUInformation::unitId() const
-{
- return data->unitId;
-}
-
-/*!
- Sets the machine-readable identifier for the unit to \a unitId.
-*/
-void QOpcUa::QEUInformation::setUnitId(qint32 unitId)
-{
- data->unitId = unitId;
-}
-
-/*!
- Returns the namespace URI of the unit.
-*/
-QString QOpcUa::QEUInformation::namespaceUri() const
-{
- return data->namespaceUri;
-}
-
-/*!
- Sets the namespace URI of the unit to \a namespaceUri.
-*/
-void QOpcUa::QEUInformation::setNamespaceUri(const QString &namespaceUri)
-{
- data->namespaceUri = namespaceUri;
-}
-
-/*!
- Constructs a EUinformation with namespace URI \a namespaceUri, unit id \a unitId,
- display name \a displayName and description \a description.
-*/
-QOpcUa::QEUInformation::QEUInformation(const QString &namespaceUri, qint32 unitId, const QOpcUa::QLocalizedText &displayName,
- const QOpcUa::QLocalizedText &description)
- : data(new QOpcUa::QEUInformationData)
-{
- data->namespaceUri = namespaceUri;
- data->unitId = unitId;
- data->displayName = displayName;
- data->description = description;
-}
-
-/*!
- Returns \c true if this EUinformation has the same value as \a rhs.
-*/
-bool QOpcUa::QEUInformation::operator==(const QOpcUa::QEUInformation &rhs) const
-{
- return data->namespaceUri == rhs.namespaceUri() &&
- data->unitId == rhs.unitId() &&
- data->displayName == rhs.displayName() &&
- data->description == rhs.description();
-}
-
-/*!
- Converts this EUinformation to \l QVariant.
-*/
-QOpcUa::QEUInformation::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-/*!
- \class QOpcUa::QComplexNumber
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA ComplexNumber type.
-
- The ComplexNumberType defined in OPC-UA part 8, 5.6.4.
- It stores a complex number with float precision.
-*/
-
-class QOpcUa::QComplexNumberData : public QSharedData
-{
-public:
- float real{0};
- float imaginary{0};
-};
-
-QOpcUa::QComplexNumber::QComplexNumber()
- : data(new QOpcUa::QComplexNumberData)
-{
-}
-
-QOpcUa::QComplexNumber::QComplexNumber(const QOpcUa::QComplexNumber &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Sets the values from \a rhs in this complex number.
-*/
-QOpcUa::QComplexNumber &QOpcUa::QComplexNumber::operator=(const QOpcUa::QComplexNumber &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-QOpcUa::QComplexNumber::~QComplexNumber()
-{
-
-}
-
-/*!
- Returns the imaginary part of the complex number.
-*/
-float QOpcUa::QComplexNumber::imaginary() const
-{
- return data->imaginary;
-}
-
-/*!
- Sets the imaginary part of the complex number to \a imaginary.
-*/
-void QOpcUa::QComplexNumber::setImaginary(float imaginary)
-{
- data->imaginary = imaginary;
-}
-
-/*!
- Returns the real part of the complex number.
-*/
-float QOpcUa::QComplexNumber::real() const
-{
- return data->real;
-}
-
-/*!
- Sets the real part of the complex number to \a real.
-*/
-void QOpcUa::QComplexNumber::setReal(float real)
-{
- data->real = real;
-}
-
-/*!
- Constructs a complex number with real part \a real and imaginary part \a imaginary.
-*/
-QOpcUa::QComplexNumber::QComplexNumber(float real, float imaginary)
- : data(new QOpcUa::QComplexNumberData)
-{
- data->real = real;
- data->imaginary = imaginary;
-}
-
-/*!
- Returns \c true if this complex number has the same value as \a rhs.
-*/
-bool QOpcUa::QComplexNumber::operator==(const QOpcUa::QComplexNumber &rhs) const
-{
- return qFloatDistance(data->real, rhs.real()) == 0 &&
- qFloatDistance(data->imaginary, rhs.imaginary()) == 0;
-}
-
-/*!
- Converts this complex number to \l QVariant.
-*/
-QOpcUa::QComplexNumber::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-/*!
- \class QOpcUa::QDoubleComplexNumber
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA DoubleComplexNumber type.
-
- The DoubleComplexNumberType defined in OPC-UA part 8, 5.6.5.
- It stores a complex number with double precision.
-*/
-
-class QOpcUa::QDoubleComplexNumberData : public QSharedData
-{
-public:
- double real{0};
- double imaginary{0};
-};
-
-QOpcUa::QDoubleComplexNumber::QDoubleComplexNumber()
- : data(new QOpcUa::QDoubleComplexNumberData)
-{
-}
-
-QOpcUa::QDoubleComplexNumber::QDoubleComplexNumber(const QOpcUa::QDoubleComplexNumber &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Sets the values from \a rhs in this double complex number.
-*/
-QOpcUa::QDoubleComplexNumber &QOpcUa::QDoubleComplexNumber::operator=(const QOpcUa::QDoubleComplexNumber &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-QOpcUa::QDoubleComplexNumber::~QDoubleComplexNumber()
-{
-
-}
-
-/*!
- Returns the imaginary part of the complex number.
-*/
-double QOpcUa::QDoubleComplexNumber::imaginary() const
-{
- return data->imaginary;
-}
-
-/*!
- Sets the imaginary part of the complex number to \a imaginary.
-*/
-void QOpcUa::QDoubleComplexNumber::setImaginary(double imaginary)
-{
- data->imaginary = imaginary;
-}
-
-/*!
- Returns the real part of the complex number.
-*/
-double QOpcUa::QDoubleComplexNumber::real() const
-{
- return data->real;
-}
-
-/*!
- Sets the real part of the complex number to \a real.
-*/
-void QOpcUa::QDoubleComplexNumber::setReal(double real)
-{
- data->real = real;
-}
-
-/*!
- Constructs a double complex number with real part \a real and imaginary part \a imaginary.
-*/
-QOpcUa::QDoubleComplexNumber::QDoubleComplexNumber(double real, double imaginary)
- : data(new QOpcUa::QDoubleComplexNumberData)
-{
- data->real = real;
- data->imaginary = imaginary;
-}
-
-/*!
- Returns \c true if this double complex number has the same value as \a rhs.
-*/
-bool QOpcUa::QDoubleComplexNumber::operator==(const QOpcUa::QDoubleComplexNumber &rhs) const
-{
- return qFloatDistance(data->real, rhs.real()) == 0 &&
- qFloatDistance(data->imaginary, rhs.imaginary()) == 0;
-}
-
-/*!
- Converts this double complex number to \l QVariant.
-*/
-QOpcUa::QDoubleComplexNumber::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-/*!
\enum QOpcUa::AxisScale
The AxisScale enum as defined by OPC-UA part 8, 5.6.7.
@@ -1479,2633 +781,99 @@ QOpcUa::QDoubleComplexNumber::operator QVariant() const
*/
/*!
- \class QOpcUa::QAxisInformation
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA AxisInformation type.
-
- This is the Qt OPC UA representation for the OPC UA AxisInformation type defined in OPC-UA part 8, 5.6.6.
- It contains information about an axis which can be used for multiple purposes. A common use case could
- involve the plotting of display data. The engineering units and the title are used for the text on the plot,
- range, axisScaleType and axisSteps provide the scaling and the axis ranges of the plot.
-*/
-
-class QOpcUa::QAxisInformationData : public QSharedData
-{
-public:
- QOpcUa::QEUInformation engineeringUnits;
- QOpcUa::QRange eURange;
- QOpcUa::QLocalizedText title;
- QOpcUa::AxisScale axisScaleType{QOpcUa::AxisScale::Linear};
- QVector<double> axisSteps;
-};
-
-QOpcUa::QAxisInformation::QAxisInformation()
- : data(new QOpcUa::QAxisInformationData)
-{
-}
-
-/*!
- Constructs axis information from \a rhs.
-*/
-QOpcUa::QAxisInformation::QAxisInformation(const QOpcUa::QAxisInformation &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Sets the values from \a rhs in this axis information.
-*/
-QOpcUa::QAxisInformation &QOpcUa::QAxisInformation::operator=(const QOpcUa::QAxisInformation &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-QOpcUa::QAxisInformation::~QAxisInformation()
-{
-}
-
-/*!
- Returns the lower and upper values of this axis.
-*/
-QOpcUa::QRange QOpcUa::QAxisInformation::eURange() const
-{
- return data->eURange;
-}
-
-/*!
- Sets the lower and upper values of this axis to \a eURange.
-*/
-void QOpcUa::QAxisInformation::setEURange(const QOpcUa::QRange &eURange)
-{
- data->eURange = eURange;
-}
-
-/*!
- Returns the title of this axis.
-*/
-QOpcUa::QLocalizedText QOpcUa::QAxisInformation::title() const
-{
- return data->title;
-}
-
-/*!
- Sets the title to \a title.
-*/
-void QOpcUa::QAxisInformation::setTitle(const QOpcUa::QLocalizedText &title)
-{
- data->title = title;
-}
-
-/*!
- Returns the scaling of this axis, defined by \l QOpcUa::AxisScale.
-*/
-QOpcUa::AxisScale QOpcUa::QAxisInformation::axisScaleType() const
-{
- return data->axisScaleType;
-}
-
-/*!
- Sets the axis scale type to \a axisScaleType.
-*/
-void QOpcUa::QAxisInformation::setAxisScaleType(QOpcUa::AxisScale axisScaleType)
-{
- data->axisScaleType = axisScaleType;
-}
-
-/*!
- Returns specific values for each axis step.
-
- This value is empty if the points are equally distributed and the step size can be
- calculated from the number of steps and the range.
- If the steps are different for each point but constant over a longer time, there is an entry for
- each data point.
-*/
-QVector<double> QOpcUa::QAxisInformation::axisSteps() const
-{
- return data->axisSteps;
-}
-
-/*!
- Sets the axis steps to \a axisSteps.
-*/
-void QOpcUa::QAxisInformation::setAxisSteps(const QVector<double> &axisSteps)
-{
- data->axisSteps = axisSteps;
-}
-
-/*!
- Returns a reference to the axis steps.
-*/
-QVector<double> &QOpcUa::QAxisInformation::axisStepsRef()
-{
- return data->axisSteps;
-}
-
-/*!
- Returns the engineering units of this axis.
-*/
-QOpcUa::QEUInformation QOpcUa::QAxisInformation::engineeringUnits() const
-{
- return data->engineeringUnits;
-}
-
-/*!
- Sets the engineering units to \a engineeringUnits.
-*/
-void QOpcUa::QAxisInformation::setEngineeringUnits(const QOpcUa::QEUInformation &engineeringUnits)
-{
- data->engineeringUnits = engineeringUnits;
-}
-
-/*!
- Returns \c true if this axis information has the same value as \a rhs.
-*/
-bool QOpcUa::QAxisInformation::operator==(const QOpcUa::QAxisInformation &rhs) const
-{
- return data->axisScaleType == rhs.axisScaleType() &&
- data->axisSteps == rhs.axisSteps() &&
- data->engineeringUnits == rhs.engineeringUnits() &&
- data->eURange == rhs.eURange() &&
- data->title == rhs.title();
-}
-
-/*!
- Converts this axis information to \l QVariant.
-*/
-QOpcUa::QAxisInformation::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-/*!
- Constructs axis information with engineering units \a engineeringUnits,
- range \a eURange, title \a title, scaling \a axisScaleType and axis steps \a axisSteps.
-*/
-QOpcUa::QAxisInformation::QAxisInformation(const QOpcUa::QEUInformation &engineeringUnits, const QOpcUa::QRange &eURange, const QOpcUa::QLocalizedText &title,
- const QOpcUa::AxisScale &axisScaleType, const QVector<double> &axisSteps)
- : data (new QOpcUa::QAxisInformationData)
-{
- data->engineeringUnits = engineeringUnits;
- data->eURange = eURange;
- data->title = title;
- data->axisScaleType = axisScaleType;
- data->axisSteps = axisSteps;
-}
-
-
-/*!
- \class QOpcUa::QXValue
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA XVType.
-
- This is the Qt OPC UA representation for the OPC UA XVType type defined in OPC-UA part 8, 5.6.8.
- This type is used to position values of float precision on an axis with double precision.
-*/
-
-class QOpcUa::QXValueData : public QSharedData
-{
-public:
- double x{0};
- float value{0};
-};
-
-QOpcUa::QXValue::QXValue()
- : data(new QOpcUa::QXValueData)
-{
-}
-
-/*!
- Constructs an XValue from \a rhs.
-*/
-QOpcUa::QXValue::QXValue(const QOpcUa::QXValue &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Constructs an XValue with position \a x and value \a value.
-*/
-QOpcUa::QXValue::QXValue(double x, float value)
- : data(new QOpcUa::QXValueData)
-{
- data->x = x;
- data->value = value;
-}
-
-/*!
- Sets the values from \a rhs in this XValue.
-*/
-QOpcUa::QXValue &QOpcUa::QXValue::operator=(const QOpcUa::QXValue &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-/*!
- Returns \c true if this XValue has the same value as \a rhs.
-*/
-bool QOpcUa::QXValue::operator==(const QOpcUa::QXValue &rhs) const
-{
- return qFloatDistance(data->x, rhs.x()) == 0 &&
- qFloatDistance(data->value, rhs.value()) == 0;
-}
-
-/*!
- Converts this XValue to \l QVariant.
-*/
-QOpcUa::QXValue::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-QOpcUa::QXValue::~QXValue()
-{
-}
-
-/*!
- Returns the value for position x.
-*/
-float QOpcUa::QXValue::value() const
-{
- return data->value;
-}
-
-/*!
- Sets the value for position x to \a value.
-*/
-void QOpcUa::QXValue::setValue(float value)
-{
- data->value = value;
-}
-
-/*!
- Returns the position of the value on the axis.
-*/
-double QOpcUa::QXValue::x() const
-{
- return data->x;
-}
-
-/*!
- Sets the position of the value on the axis to \a x.
-*/
-void QOpcUa::QXValue::setX(double x)
-{
- data->x = x;
-}
-
-/*!
- \class QOpcUa::QExpandedNodeId
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA ExpandedNodeId.
-
- An expanded node id is a node id where the namespace index can be given as index or as a string URI.
- A list of namespaces and their indices on the server is provided by \l QOpcUaClient::namespaceArray().
-*/
-
-class QOpcUa::QExpandedNodeIdData : public QSharedData
-{
-public:
- quint32 serverIndex{0};
- QString namespaceUri;
- QString nodeId;
-};
-
-QOpcUa::QExpandedNodeId::QExpandedNodeId()
- : data(new QOpcUa::QExpandedNodeIdData)
-{
-}
-
-/*!
- Constructs an expanded node id from \a rhs.
-*/
-QOpcUa::QExpandedNodeId::QExpandedNodeId(const QOpcUa::QExpandedNodeId &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Constructs an expanded node id from node id string \a nodeId.
-*/
-QOpcUa::QExpandedNodeId::QExpandedNodeId(const QString &nodeId)
- : data(new QOpcUa::QExpandedNodeIdData)
-{
- data->nodeId = nodeId;
-}
-
-/*!
- Constructs an expanded node id from namespace URI \a namespaceUri, node id string \a nodeId
- and server index \a serverIndex.
-*/
-QOpcUa::QExpandedNodeId::QExpandedNodeId(const QString &namespaceUri, const QString &nodeId, quint32 serverIndex)
- : data(new QOpcUa::QExpandedNodeIdData)
-{
- data->namespaceUri = namespaceUri;
- data->nodeId = nodeId;
- data->serverIndex = serverIndex;
-}
-
-/*!
- Sets the values from \a rhs in this expanded node id.
-*/
-QOpcUa::QExpandedNodeId &QOpcUa::QExpandedNodeId::operator=(const QOpcUa::QExpandedNodeId &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-/*!
- Returns \c true if this expanded node id has the same value as \a rhs.
-*/
-bool QOpcUa::QExpandedNodeId::operator==(const QOpcUa::QExpandedNodeId &rhs) const
-{
- return data->namespaceUri == rhs.namespaceUri() &&
- nodeIdEquals(data->nodeId, rhs.nodeId()) &&
- data->serverIndex == rhs.serverIndex();
-}
-
-/*!
- Converts this expanded node id to \l QVariant.
-*/
-QOpcUa::QExpandedNodeId::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-QOpcUa::QExpandedNodeId::~QExpandedNodeId()
-{
-}
-
-/*!
- Returns the index of the server containing the node. This index maps to an entry in the server's server table.
-*/
-quint32 QOpcUa::QExpandedNodeId::serverIndex() const
-{
- return data->serverIndex;
-}
-
-/*!
- Sets the server index to \a serverIndex.
-*/
-void QOpcUa::QExpandedNodeId::setServerIndex(quint32 serverIndex)
-{
- data->serverIndex = serverIndex;
-}
-
-/*!
- Returns the namespace URI of the node id. If this value is specified, the namespace index in
- \l {QOpcUa::QExpandedNodeId::nodeId} {nodeId} is 0 and must be ignored.
-*/
-QString QOpcUa::QExpandedNodeId::namespaceUri() const
-{
- return data->namespaceUri;
-}
-
-/*!
- Sets the namespace URI to \a namespaceUri.
-*/
-void QOpcUa::QExpandedNodeId::setNamespaceUri(const QString &namespaceUri)
-{
- data->namespaceUri = namespaceUri;
-}
-
-/*!
- Returns the node id. If \l {QOpcUa::QExpandedNodeId::namespaceUri} {namespaceUri} is specified, the namespace index is invalid.
-*/
-QString QOpcUa::QExpandedNodeId::nodeId() const
-{
- return data->nodeId;
-}
-
-/*!
- Sets the node id to \a nodeId.
-*/
-void QOpcUa::QExpandedNodeId::setNodeId(const QString &nodeId)
-{
- data->nodeId = nodeId;
-}
-
-/*!
- \class QOpcUa::QRelativePathElement
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA RelativePathElement.
-
- QRelativePathElement defines an element of a relative path on an OPC UA server.
- This is needed for resolution of browse paths to node ids in \l QOpcUaNode::resolveBrowsePath().
-*/
-
-class QOpcUa::QRelativePathElementData : public QSharedData
-{
-public:
- QString referenceTypeId;
- bool isInverse{false};
- bool includeSubtypes{false};
- QOpcUa::QQualifiedName targetName;
-};
-
-/*!
- Constructs a relative path element with both flags set to \c false.
-*/
-QOpcUa::QRelativePathElement::QRelativePathElement()
- : data(new QOpcUa::QRelativePathElementData())
-{
-}
-
-/*!
- Constructs a relative path element with targetName \a target, reference type node id \a refType and both flags set to \c false.
-*/
-QOpcUa::QRelativePathElement::QRelativePathElement(const QOpcUa::QQualifiedName &target, const QString &refType)
- : data(new QOpcUa::QRelativePathElementData())
-{
- data->referenceTypeId = refType;
- data->targetName = target;
-}
-
-/*!
- Constructs a relative path element with targetName \a target, \l QOpcUa::ReferenceTypeId \a refType and both flags set to \c false.
-*/
-QOpcUa::QRelativePathElement::QRelativePathElement(const QOpcUa::QQualifiedName &target, QOpcUa::ReferenceTypeId refType)
- : data(new QOpcUa::QRelativePathElementData())
-{
- data->referenceTypeId = QOpcUa::nodeIdFromReferenceType(refType);
- data->targetName = target;
-}
-
-/*!
- Constructs a relative path element from \a rhs.
-*/
-QOpcUa::QRelativePathElement::QRelativePathElement(const QOpcUa::QRelativePathElement &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Sets the values of \a rhs in this relative path element.
-*/
-QOpcUa::QRelativePathElement &QOpcUa::QRelativePathElement::operator=(const QOpcUa::QRelativePathElement &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-/*!
- Returns \c true if this relative path element has the same value as \a rhs.
-*/
-bool QOpcUa::QRelativePathElement::operator==(const QOpcUa::QRelativePathElement &rhs) const
-{
- return data->includeSubtypes == rhs.includeSubtypes() &&
- data->isInverse == rhs.isInverse() &&
- data->referenceTypeId == rhs.referenceTypeId() &&
- data->targetName == rhs.targetName();
-}
-
-QOpcUa::QRelativePathElement::~QRelativePathElement()
-{
-}
-
-/*!
- Returns the qualified name of the reference's target.
-*/
-QOpcUa::QQualifiedName QOpcUa::QRelativePathElement::targetName() const
-{
- return data->targetName;
-}
-
-/*!
- Sets the target name to \a targetName, for example QOpcUa::QQualifiedName(0, "DataTypes").
-*/
-void QOpcUa::QRelativePathElement::setTargetName(const QOpcUa::QQualifiedName &targetName)
-{
- data->targetName = targetName;
-}
-
-/*!
- Returns the value of the includeSubtypes flag.
-*/
-bool QOpcUa::QRelativePathElement::includeSubtypes() const
-{
- return data->includeSubtypes;
-}
-
-/*!
- Sets the includeSubtypes flag to \a includeSubtypes.
- If the flag is \c true, the lookup also follows references with subtypes of \l referenceTypeId().
-*/
-void QOpcUa::QRelativePathElement::setIncludeSubtypes(bool includeSubtypes)
-{
- data->includeSubtypes = includeSubtypes;
-}
-
-/*!
- Returns the value of the isInverse flag.
-*/
-bool QOpcUa::QRelativePathElement::isInverse() const
-{
- return data->isInverse;
-}
-
-/*!
- Sets the isInverse flag to \a isInverse.
- If the flag is \c true, the lookup follows the reverse reference.
-*/
-void QOpcUa::QRelativePathElement::setIsInverse(bool isInverse)
-{
- data->isInverse = isInverse;
-}
-
-/*!
- Returns the type id of the reference connecting this node to the previous node.
-*/
-QString QOpcUa::QRelativePathElement::referenceTypeId() const
-{
- return data->referenceTypeId;
-}
-
-/*!
- Sets the reference type id to \a referenceTypeId.
-*/
-void QOpcUa::QRelativePathElement::setReferenceTypeId(const QString &referenceTypeId)
-{
- data->referenceTypeId = referenceTypeId;
-}
-
-/*!
- Sets the reference type id to \a referenceTypeId.
-*/
-void QOpcUa::QRelativePathElement::setReferenceTypeId(QOpcUa::ReferenceTypeId referenceTypeId)
-{
- data->referenceTypeId = QOpcUa::nodeIdFromReferenceType(referenceTypeId);
-}
-
-/*!
- \class QOpcUa::QBrowsePathTarget
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA BrowsePathTarget.
-
- A BrowsePathTarget contains a target of a browse path and information about the completeness of the node id resolution.
-*/
-class QOpcUa::QBrowsePathTargetData : public QSharedData
-{
-public:
- QOpcUa::QExpandedNodeId targetId;
- quint32 remainingPathIndex{(std::numeric_limits<quint32>::max)()};
-};
-
-QOpcUa::QBrowsePathTarget::QBrowsePathTarget()
- : data(new QOpcUa::QBrowsePathTargetData)
-{
-}
-
-/*!
- Constructs a browse path target from \a rhs.
-*/
-QOpcUa::QBrowsePathTarget::QBrowsePathTarget(const QOpcUa::QBrowsePathTarget &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Sets the values of \a rhs in this browse path target.
-*/
-QOpcUa::QBrowsePathTarget &QOpcUa::QBrowsePathTarget::operator=(const QOpcUa::QBrowsePathTarget &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-/*!
- Returns \c true if this browse path target has the same value as \a rhs.
-*/
-bool QOpcUa::QBrowsePathTarget::operator==(const QOpcUa::QBrowsePathTarget &rhs) const
-{
- return data->targetId == rhs.targetId() &&
- data->remainingPathIndex == rhs.remainingPathIndex();
-}
-
-QOpcUa::QBrowsePathTarget::~QBrowsePathTarget()
-{
-}
-
-/*!
- Returns the index of the first unprocessed element in the browse path.
- If the path was followed to the end, remainingPathIndex has the maximum value of quint32.
- \sa QOpcUa::QBrowsePathTarget::targetId()
-*/
-quint32 QOpcUa::QBrowsePathTarget::remainingPathIndex() const
-{
- return data->remainingPathIndex;
-}
-
-/*!
- Sets the remaining path index to \a remainingPathIndex.
-*/
-void QOpcUa::QBrowsePathTarget::setRemainingPathIndex(quint32 remainingPathIndex)
-{
- data->remainingPathIndex = remainingPathIndex;
-}
-
-/*!
- Returns \c true if the browse path has been fully resolved.
-*/
-bool QOpcUa::QBrowsePathTarget::isFullyResolved() const
-{
- return (data->remainingPathIndex == (std::numeric_limits<quint32>::max)());
-}
-
-/*!
- Returns the target of the last reference the server was able to follow.
- If the reference leads to an external server, \e targetId is the id of the first node on that server.
- \sa QOpcUa::QBrowsePathTarget::remainingPathIndex
-*/
-QOpcUa::QExpandedNodeId QOpcUa::QBrowsePathTarget::targetId() const
-{
- return data->targetId;
-}
-
-/*!
- Returns a reference to the target id.
-*/
-QOpcUa::QExpandedNodeId &QOpcUa::QBrowsePathTarget::targetIdRef()
-{
- return data->targetId;
-}
-
-/*!
- Sets the node id of the target node to \a targetId.
-*/
-void QOpcUa::QBrowsePathTarget::setTargetId(const QOpcUa::QExpandedNodeId &targetId)
-{
- data->targetId = targetId;
-}
-
-/*!
- \class QOpcUa::QContentFilterElement
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA ContentFilterElement.
-
- A content filter element contains an operator and a list of operands.
- There are four different operator types which contain literal values, references to
- attributes of nodes or to other content filter elements.
-
- A combination of one or more content filter elements makes a content filter which is used
- by the server to filter data for the criteria defined by the content filter elements.
- For example, the \c where clause of an event filter is a content filter which is used to decide
- if a notification is generated for an event.
-*/
-
-/*!
- \enum QContentFilterElement::FilterOperator
-
- FilterOperator enumerates all possible operators for a ContentFilterElement that are specified in
- OPC-UA part 4, Tables 115 and 116.
-
- \value Equals
- \value IsNull
- \value GreaterThan
- \value LessThan
- \value GreaterThanOrEqual
- \value LessThanOrEqual
- \value Like
- \value Not
- \value Between
- \value InList
- \value And
- \value Or
- \value Cast
- \value InView
- \value OfType
- \value RelatedTo
- \value BitwiseAnd
- \value BitwiseOr
-*/
-
-class QOpcUa::QContentFilterElementData : public QSharedData
-{
-public:
- QOpcUa::QContentFilterElement::FilterOperator filterOperator;
- QVector<QVariant> filterOperands;
-};
-
-QOpcUa::QContentFilterElement::QContentFilterElement()
- : data(new QContentFilterElementData)
-{
-}
-
-/*!
- Constructs a content filter element from \a rhs.
-*/
-QOpcUa::QContentFilterElement::QContentFilterElement(const QOpcUa::QContentFilterElement &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Sets the values from \a rhs in this content filter element.
-*/
-QOpcUa::QContentFilterElement &QOpcUa::QContentFilterElement::operator=(const QOpcUa::QContentFilterElement &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-/*!
- Returns \c true if this content filter element has the same value as \a rhs.
-*/
-bool QOpcUa::QContentFilterElement::operator==(const QOpcUa::QContentFilterElement &rhs) const
-{
- return filterOperator() == rhs.filterOperator() && filterOperands() == rhs.filterOperands();
-}
-
-/*!
- Converts this content filter element to \l QVariant.
-*/
-QOpcUa::QContentFilterElement::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-/*!
- Returns the operands of the filter element.
-*/
-QVector<QVariant> QOpcUa::QContentFilterElement::filterOperands() const
-{
- return data->filterOperands;
-}
-
-/*!
- Returns a reference to the filter operands.
-
- \sa filterOperands()
-*/
-QVector<QVariant> &QOpcUa::QContentFilterElement::filterOperandsRef()
-{
- return data->filterOperands;
-}
-
-/*!
- Sets the filter operands for this content filter element to \a filterOperands.
- Supported classes are \l QOpcUa::QElementOperand, \l QOpcUa::QLiteralOperand,
- \l QOpcUa::QSimpleAttributeOperand and \l QOpcUa::QAttributeOperand.
-*/
-void QOpcUa::QContentFilterElement::setFilterOperands(const QVector<QVariant> &filterOperands)
-{
- data->filterOperands = filterOperands;
-}
-
-/*!
- Returns the filter operator.
-*/
-QOpcUa::QContentFilterElement::FilterOperator QOpcUa::QContentFilterElement::filterOperator() const
-{
- return data->filterOperator;
-}
-
-/*!
- Sets the operator that is applied to the filter operands to \a filterOperator.
-*/
-void QOpcUa::QContentFilterElement::setFilterOperator(QOpcUa::QContentFilterElement::FilterOperator filterOperator)
-{
- data->filterOperator = filterOperator;
-}
-
-QOpcUa::QContentFilterElement::~QContentFilterElement()
-{
-}
-
-/*!
- Sets filter operator \a op in this content filter element.
- If multiple operators are streamed into one content filter element, only the last operator is used.
- All others are discarded.
-*/
-QOpcUa::QContentFilterElement &QOpcUa::QContentFilterElement::operator<<(QOpcUa::QContentFilterElement::FilterOperator op)
-{
- setFilterOperator(op);
- return *this;
-}
-
-/*!
- Adds the simple attribute operand \a op to the operands list of this content filter element.
-*/
-QOpcUa::QContentFilterElement &QOpcUa::QContentFilterElement::operator<<(const QOpcUa::QSimpleAttributeOperand &op)
-{
- filterOperandsRef().append(op);
- return *this;
-}
-
-/*!
- Adds the attribute operand \a op to the operands list of this content filter element.
-*/
-QOpcUa::QContentFilterElement &QOpcUa::QContentFilterElement::operator<<(const QOpcUa::QAttributeOperand &op)
-{
- filterOperandsRef().append(op);
- return *this;
-}
-
-/*!
- Adds the literal operand \a op to the operands list of this content filter element.
-*/
-QOpcUa::QContentFilterElement &QOpcUa::QContentFilterElement::operator<<(const QOpcUa::QLiteralOperand &op)
-{
- filterOperandsRef().append(op);
- return *this;
-}
-
-/*!
- Adds the element operand \a op to the operands list of this content filter element.
-*/
-QOpcUa::QContentFilterElement &QOpcUa::QContentFilterElement::operator<<(const QOpcUa::QElementOperand &op)
-{
- filterOperandsRef().append(op);
- return *this;
-}
-
-/*!
- \class QOpcUa::QElementOperand
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA ElementOperand type.
-
- The ElementOperand is defined in OPC-UA part 4, 7.4.4.2.
- It is used to identify another element in the filter by its index
- (the first element has the index 0).
-
- This is required to create complex filters, for example to reference
- the two operands of the AND operation in ((Severity > 500) AND (Message == "TestString")).
- The first step is to create content filter elements for the two conditions (Severity > 500)
- and (Message == "TestString"). A third content filter element is required to create an AND
- combination of the two conditions. It consists of the AND operator and two element operands
- with the indices of the two conditions created before:
-
- \code
- QOpcUaMonitoringParameters::EventFilter filter;
- ...
- // setup select clauses
- ...
- QOpcUa::QContentFilterElement condition1;
- QOpcUa::QContentFilterElement condition2;
- QOpcUa::QContentFilterElement condition3;
- condition1 << QOpcUa::QContentFilterElement::FilterOperator::GreaterThan << QOpcUa::QSimpleAttributeOperand("Severity") <<
- QOpcUa::QLiteralOperand(quint16(500), QOpcUa::Types::UInt16);
- condition2 << QOpcUa::QContentFilterElement::FilterOperator::Equals << QOpcUa::QSimpleAttributeOperand("Message") <<
- QOpcUa::QLiteralOperand("TestString", QOpcUa::Types::String);
- condition3 << QOpcUa::QContentFilterElement::FilterOperator::And << QOpcUa::QElementOperand(0) << QOpcUa::QElementOperand(1);
- filter << condition1 << condition2 << condition3;
- \endcode
-*/
-
-class QOpcUa::QElementOperandData : public QSharedData
-{
-public:
- quint32 index {0};
-};
-
-QOpcUa::QElementOperand::QElementOperand()
- : data(new QOpcUa::QElementOperandData)
-{
-}
-
-/*!
- Constructs an element operand from \a rhs.
-*/
-QOpcUa::QElementOperand::QElementOperand(const QOpcUa::QElementOperand &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Constructs an element operand with index \a index.
-*/
-QOpcUa::QElementOperand::QElementOperand(quint32 index)
- : data(new QOpcUa::QElementOperandData)
-{
- setIndex(index);
-}
-
-/*!
- Sets the values from \a rhs in this element operand.
-*/
-QOpcUa::QElementOperand &QOpcUa::QElementOperand::operator=(const QOpcUa::QElementOperand &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-/*!
- Converts this element operand to \l QVariant.
-*/
-QOpcUa::QElementOperand::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-QOpcUa::QElementOperand::~QElementOperand()
-{
-}
-
-/*!
- Returns the index of the filter element that is going to be used as operand.
-*/
-quint32 QOpcUa::QElementOperand::index() const
-{
- return data->index;
-}
-
-/*!
- Sets the index of the filter element that is going to be used as operand to \a index.
-*/
-void QOpcUa::QElementOperand::setIndex(quint32 index)
-{
- data->index = index;
-}
-
-/*!
- \class QOpcUa::QLiteralOperand
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA LiteralOperand type.
-
- The LiteralOperand is defined in OPC-UA part 4, 7.4.4.3.
- It contains a literal value that is to be used as operand.
-*/
-class QOpcUa::QLiteralOperandData : public QSharedData
-{
-public:
- QVariant value;
- QOpcUa::Types type {QOpcUa::Types::Undefined};
-};
-
-QOpcUa::QLiteralOperand::QLiteralOperand()
- : data(new QOpcUa::QLiteralOperandData)
-{
- data->type = QOpcUa::Types::Undefined;
-}
-
-/*!
- Constructs a literal operand from \a rhs.
-*/
-QOpcUa::QLiteralOperand::QLiteralOperand(const QLiteralOperand &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Constructs a literal operand of value \a value and type \a type.
-*/
-QOpcUa::QLiteralOperand::QLiteralOperand(const QVariant &value, QOpcUa::Types type)
- : data(new QOpcUa::QLiteralOperandData)
-{
- setValue(value);
- setType(type);
-}
-
-/*!
- Sets the values from \a rhs in this \l QLiteralOperand.
-*/
-QOpcUa::QLiteralOperand &QOpcUa::QLiteralOperand::operator=(const QOpcUa::QLiteralOperand &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-/*!
- Converts this literal operand to \l QVariant.
-*/
-QOpcUa::QLiteralOperand::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-QOpcUa::QLiteralOperand::~QLiteralOperand()
-{
-}
-
-/*!
- Returns the type of the value of the literal operand.
-*/
-QOpcUa::Types QOpcUa::QLiteralOperand::type() const
-{
- return data->type;
-}
-
-/*!
- Sets the type of the value of the literal operand to \a type.
-*/
-void QOpcUa::QLiteralOperand::setType(QOpcUa::Types type)
-{
- data->type = type;
-}
-
-/*!
- Returns the value of the literal operand.
-*/
-QVariant QOpcUa::QLiteralOperand::value() const
-{
- return data->value;
-}
-
-/*!
- Sets the value of the literal operand to \a value.
-*/
-void QOpcUa::QLiteralOperand::setValue(const QVariant &value)
-{
- data->value = value;
-}
-
-/*!
- \class QOpcUa::QSimpleAttributeOperand
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA SimpleAttributeOperand type.
-
- The SimpleAttributeOperand is specified in OPC-UA part 4, 7.4.4.5.
- It is used when a node attribute is required as operand.
-
- For example, the following simple attribute operand represents the value
- of the "Severity" field of the base event type:
- \code
- QOpcUa::QSimpleAttributeOperand("Severity");
- \endcode
-*/
-class QOpcUa::QSimpleAttributeOperandData : public QSharedData
-{
-public:
- QString typeId{QStringLiteral("ns=0;i=2041")}; // BaseEventType
- QVector<QOpcUa::QQualifiedName> browsePath;
- QOpcUa::NodeAttribute attributeId {QOpcUa::NodeAttribute::Value};
- QString indexRange;
-};
-
-QOpcUa::QSimpleAttributeOperand::QSimpleAttributeOperand()
- : data(new QSimpleAttributeOperandData)
-{
-}
-
-/*!
- Constructs a simple attribute operand from \a rhs.
-*/
-QOpcUa::QSimpleAttributeOperand::QSimpleAttributeOperand(const QOpcUa::QSimpleAttributeOperand &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Constructs a simple attribute operand for attribute \a attributeId of the direct child with the browse name
- \a name in namespace \a namespaceIndex. \a typeId is the node id of a type definition node. The operand will
- be restricted to instances of type \a typeId or a subtype.
-*/
-QOpcUa::QSimpleAttributeOperand::QSimpleAttributeOperand(const QString &name, quint16 namespaceIndex, const QString &typeId, QOpcUa::NodeAttribute attributeId)
- : data(new QOpcUa::QSimpleAttributeOperandData)
-{
- browsePathRef().append(QOpcUa::QQualifiedName(namespaceIndex, name));
- setTypeId(typeId);
- setAttributeId(attributeId);
-}
-
-/*!
- Constructs a simple attribute operand for the attribute \a attributeId of an object or variable of type \a typeId.
- This can be used for requesting the ConditionId in an event filter as described in OPC-UA part 9, Table 8.
-*/
-QOpcUa::QSimpleAttributeOperand::QSimpleAttributeOperand(QOpcUa::NodeAttribute attributeId, const QString &typeId)
- : data(new QOpcUa::QSimpleAttributeOperandData)
-{
- setTypeId(typeId);
- setAttributeId(attributeId);
-}
-
-/*!
- Sets the values from \a rhs in this simple attribute operand.
-*/
-QOpcUa::QSimpleAttributeOperand &QOpcUa::QSimpleAttributeOperand::operator=(const QOpcUa::QSimpleAttributeOperand &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-/*!
- Returns \c true if this simple attribute operand has the same value as \a rhs.
-*/
-bool QOpcUa::QSimpleAttributeOperand::operator==(const QOpcUa::QSimpleAttributeOperand &rhs) const
-{
- return attributeId() == rhs.attributeId() && browsePath() == rhs.browsePath() &&
- indexRange() == rhs.indexRange() && typeId() == rhs.typeId();
-}
-
-/*!
- Converts this simple attribute operand to \l QVariant.
-*/
-QOpcUa::QSimpleAttributeOperand::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-QOpcUa::QSimpleAttributeOperand::~QSimpleAttributeOperand()
-{
-}
-
-/*!
- Returns the index range string.
-*/
-QString QOpcUa::QSimpleAttributeOperand::indexRange() const
-{
- return data->indexRange;
-}
-
-/*!
- Sets the index range string used to identify a single value or subset of the attribute's value to \a indexRange.
-*/
-void QOpcUa::QSimpleAttributeOperand::setIndexRange(const QString &indexRange)
-{
- data->indexRange = indexRange;
-}
-
-/*!
- Returns the attribute of the node \l browsePath is pointing to.
-*/
-QOpcUa::NodeAttribute QOpcUa::QSimpleAttributeOperand::attributeId() const
-{
- return data->attributeId;
-}
-
-/*!
- Sets the attribute id to \a attributeId.
-*/
-void QOpcUa::QSimpleAttributeOperand::setAttributeId(QOpcUa::NodeAttribute attributeId)
-{
- data->attributeId = attributeId;
-}
-
-/*!
- Returns the relative path to a node starting from \l typeId.
-*/
-QVector<QOpcUa::QQualifiedName> QOpcUa::QSimpleAttributeOperand::browsePath() const
-{
- return data->browsePath;
-}
-
-/*!
- Returns a reference to the browse path.
-
- \sa browsePath()
-*/
-QVector<QOpcUa::QQualifiedName> &QOpcUa::QSimpleAttributeOperand::browsePathRef()
-{
- return data->browsePath;
-}
-
-/*!
- Sets the browse path to the node holding the attribute to \a browsePath.
-*/
-void QOpcUa::QSimpleAttributeOperand::setBrowsePath(const QVector<QOpcUa::QQualifiedName> &browsePath)
-{
- data->browsePath = browsePath;
-}
-
-/*!
- Returns the node id of a type definition node.
-*/
-QString QOpcUa::QSimpleAttributeOperand::typeId() const
-{
- return data->typeId;
-}
-
-/*!
- Sets the node id of the type definition node to \a typeId. The operand will be of the type or one of its subtypes.
-*/
-void QOpcUa::QSimpleAttributeOperand::setTypeId(const QString &typeId)
-{
- data->typeId = typeId;
-}
-
-/*!
- \class QOpcUa::QAttributeOperand
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA AttributeOperand type.
-
- The AttributeOperand is defined in OPC-UA part 4, 7.4.4.4.
- It has the same purpose as \l QSimpleAttributeOperand but has more configurable options.
-*/
-
-class QOpcUa::QAttributeOperandData : public QSharedData
-{
-public:
- QString nodeId;
- QString alias;
- QVector<QOpcUa::QRelativePathElement> browsePath;
- QOpcUa::NodeAttribute attributeId {QOpcUa::NodeAttribute::Value};
- QString indexRange;
-};
-
-QOpcUa::QAttributeOperand::QAttributeOperand()
- : data(new QAttributeOperandData)
-{
-}
-
-/*!
- Constructs an attribute operand from \a rhs.
-*/
-QOpcUa::QAttributeOperand::QAttributeOperand(const QOpcUa::QAttributeOperand &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Sets the values from \a rhs in this attribute operand.
-*/
-QOpcUa::QAttributeOperand &QOpcUa::QAttributeOperand::operator=(const QOpcUa::QAttributeOperand &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-/*!
- Converts this attribute operand to \l QVariant.
-*/
-QOpcUa::QAttributeOperand::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-QOpcUa::QAttributeOperand::~QAttributeOperand()
-{
-}
-
-/*!
- Returns the index range string.
-*/
-QString QOpcUa::QAttributeOperand::indexRange() const
-{
- return data->indexRange;
-}
-
-/*!
- Sets the index range string used to identify a single value or subset of the attribute's value to \a indexRange.
-*/
-void QOpcUa::QAttributeOperand::setIndexRange(const QString &indexRange)
-{
- data->indexRange = indexRange;
-}
-
-/*!
- Returns the attribute id for an attribute of the node \l browsePath is pointing to.
-*/
-QOpcUa::NodeAttribute QOpcUa::QAttributeOperand::attributeId() const
-{
- return data->attributeId;
-}
-
-/*!
- Sets the attribute id to \a attributeId.
-*/
-void QOpcUa::QAttributeOperand::setAttributeId(QOpcUa::NodeAttribute attributeId)
-{
- data->attributeId = attributeId;
-}
-
-/*!
- Returns the browse path.
-*/
-QVector<QOpcUa::QRelativePathElement> QOpcUa::QAttributeOperand::browsePath() const
-{
- return data->browsePath;
-}
-
-/*!
- Returns a reference to the browse path.
-
- \sa browsePath()
-*/
-QVector<QOpcUa::QRelativePathElement> &QOpcUa::QAttributeOperand::browsePathRef()
-{
- return data->browsePath;
-}
-
-/*!
- Sets the relative path to a node starting from \l nodeId() to \a browsePath.
-*/
-void QOpcUa::QAttributeOperand::setBrowsePath(const QVector<QOpcUa::QRelativePathElement> &browsePath)
-{
- data->browsePath = browsePath;
-}
-
-/*!
- Returns the alias for this QAttributeOperand.
-*/
-QString QOpcUa::QAttributeOperand::alias() const
-{
- return data->alias;
-}
-
-/*!
- Sets the alias to \a alias. This allows using this instance
- as operand for other operations in the filter.
-*/
-void QOpcUa::QAttributeOperand::setAlias(const QString &alias)
-{
- data->alias = alias;
-}
-
-/*!
- Returns the node id of the type definition node.
-*/
-QString QOpcUa::QAttributeOperand::nodeId() const
-{
- return data->nodeId;
-}
-
-/*!
- Sets the node id of the type definition node to \a nodeId.
-*/
-void QOpcUa::QAttributeOperand::setNodeId(const QString &nodeId)
-{
- data->nodeId = nodeId;
-}
-
-/*!
- \class QOpcUa::QContentFilterElementResult
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA ContentFilterElementResult.
-
- QContentFilterElementResult contains the status code for a
- filter element and all its operands.
-*/
-
-class QOpcUa::QContentFilterElementResultData : public QSharedData
-{
-public:
- QOpcUa::UaStatusCode statusCode {QOpcUa::UaStatusCode::Good};
- QVector<QOpcUa::UaStatusCode> operandStatusCodes;
-};
-
-QOpcUa::QContentFilterElementResult::QContentFilterElementResult()
- : data(new QOpcUa::QContentFilterElementResultData)
-{
-}
-
-/*!
- Constructs a content filter element result from \a rhs.
-*/
-QOpcUa::QContentFilterElementResult::QContentFilterElementResult(const QOpcUa::QContentFilterElementResult &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Sets the values from \a rhs in this content filter element result.
-*/
-QOpcUa::QContentFilterElementResult &QOpcUa::QContentFilterElementResult::operator=(const QOpcUa::QContentFilterElementResult &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-QOpcUa::QContentFilterElementResult::~QContentFilterElementResult()
-{
-}
-
-/*!
- Returns the status code for the filter element.
-*/
-QOpcUa::UaStatusCode QOpcUa::QContentFilterElementResult::statusCode() const
-{
- return data->statusCode;
-}
-
-/*!
- Sets the status code for the filter element to \a statusCode.
-*/
-void QOpcUa::QContentFilterElementResult::setStatusCode(QOpcUa::UaStatusCode statusCode)
-{
- data->statusCode = statusCode;
-}
-
-/*!
- Returns the status codes for all filter operands in the order that was used in the filter.
-*/
-QVector<QOpcUa::UaStatusCode> QOpcUa::QContentFilterElementResult::operandStatusCodes() const
-{
- return data->operandStatusCodes;
-}
-
-/*!
- Sets the status codes for all filter operands to \a operandStatusCodes.
-*/
-void QOpcUa::QContentFilterElementResult::setOperandStatusCodes(const QVector<QOpcUa::UaStatusCode> &operandStatusCodes)
-{
- data->operandStatusCodes = operandStatusCodes;
-}
-
-/*!
- Returns a reference to the operand status codes.
-
- \sa operandStatusCodes()
-*/
-QVector<QOpcUa::UaStatusCode> &QOpcUa::QContentFilterElementResult::operandStatusCodesRef()
-{
- return data->operandStatusCodes;
-}
-
-/*!
- \class QOpcUa::QEventFilterResult
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPCUA EventFilterResult.
-
- The EventFilterResult contains status codes for all elements of the \c select clauses
- and all elements of the \c where clause.
-*/
-
-class QOpcUa::QEventFilterResultData : public QSharedData
-{
-public:
- QVector<QOpcUa::UaStatusCode> selectClauseResults;
- QVector<QOpcUa::QContentFilterElementResult> whereClauseResults;
-};
-
-QOpcUa::QEventFilterResult::QEventFilterResult()
- : data(new QOpcUa::QEventFilterResultData)
-{
-}
-
-/*!
- Constructs an event filter result from \a rhs.
-*/
-QOpcUa::QEventFilterResult::QEventFilterResult(const QOpcUa::QEventFilterResult &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Sets the values from \a rhs in this event filter result.
-*/
-QOpcUa::QEventFilterResult &QOpcUa::QEventFilterResult::operator=(const QOpcUa::QEventFilterResult &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-QOpcUa::QEventFilterResult::~QEventFilterResult()
-{
-}
-
-/*!
- Returns \c true if this event filter result is good.
-*/
-bool QOpcUa::QEventFilterResult::isGood() const
-{
- for (auto status : qAsConst(data->selectClauseResults)) {
- if (status != QOpcUa::UaStatusCode::Good)
- return false;
- }
- for (QOpcUa::QContentFilterElementResult element : qAsConst(data->whereClauseResults)) {
- if (element.statusCode() != QOpcUa::UaStatusCode::Good)
- return false;
- for (auto status : qAsConst(element.operandStatusCodesRef())) {
- if (status != QOpcUa::UaStatusCode::Good)
- return false;
- }
- }
-
- return true;
-}
-
-/*!
- Returns the status codes for all elements of the \c where clause in the order that was used in the filter.
-*/
-QVector<QOpcUa::QContentFilterElementResult> QOpcUa::QEventFilterResult::whereClauseResults() const
-{
- return data->whereClauseResults;
-}
-
-/*!
- Returns a reference to the \c where clause results.
-
- \sa whereClauseResults()
-*/
-QVector<QOpcUa::QContentFilterElementResult> &QOpcUa::QEventFilterResult::whereClauseResultsRef()
-{
- return data->whereClauseResults;
-}
-
-/*!
- Sets the \c where clause results to \a whereClausesResult.
-*/
-void QOpcUa::QEventFilterResult::setWhereClauseResults(const QVector<QOpcUa::QContentFilterElementResult> &whereClausesResult)
-{
- data->whereClauseResults = whereClausesResult;
-}
-
-/*!
- Returns the status codes for all elements of the \c select clauses in the order that was used in the filter.
-*/
-QVector<QOpcUa::UaStatusCode> QOpcUa::QEventFilterResult::selectClauseResults() const
-{
- return data->selectClauseResults;
-}
-
-/*!
- Returns a reference to the \c select clause results.
-
- \sa selectClauseResults()
-*/
-QVector<QOpcUa::UaStatusCode> &QOpcUa::QEventFilterResult::selectClauseResultsRef()
-{
- return data->selectClauseResults;
-}
-
-/*!
- Sets the \c select clause results to \a selectClausesResult.
-*/
-void QOpcUa::QEventFilterResult::setSelectClauseResults(const QVector<QOpcUa::UaStatusCode> &selectClausesResult)
-{
- data->selectClauseResults = selectClausesResult;
-}
-
-/*!
- \class QOpcUa::QUserTokenPolicy
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA UserTokenPolicy.
-
- The user token policy contains information about an user token accepted by the server.
-*/
-
-/*!
- \enum QOpcUa::QUserTokenPolicy::TokenType
-
- \value Anonymous No token required.
- \value Username Username and password are required.
- \value Certificate A client certificate is required.
- \value IssuedToken Any Web Services Security (WS-Security) defined token.
-*/
-
-class QOpcUa::QUserTokenPolicyData : public QSharedData
-{
-public:
- QString policyId;
- QOpcUa::QUserTokenPolicy::TokenType tokenType{QOpcUa::QUserTokenPolicy::TokenType::Anonymous};
- QString issuedTokenType;
- QString issuerEndpointUrl;
- QString securityPolicyUri;
-};
-
-QOpcUa::QUserTokenPolicy::QUserTokenPolicy()
- : data(new QOpcUa::QUserTokenPolicyData)
-{
-}
-
-/*!
- Constructs an user token policy from \a rhs.
-*/
-QOpcUa::QUserTokenPolicy::QUserTokenPolicy(const QUserTokenPolicy &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Sets the values from \a rhs in this user token policy.
-*/
-QOpcUa::QUserTokenPolicy &QOpcUa::QUserTokenPolicy::operator=(const QOpcUa::QUserTokenPolicy &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-QOpcUa::QUserTokenPolicy::~QUserTokenPolicy()
-{
-}
-
-/*!
- Returns the URI of the security policy required when encrypting or signing the token for ActivateSession.
-*/
-QString QOpcUa::QUserTokenPolicy::securityPolicyUri() const
-{
- return data->securityPolicyUri;
-}
-
-/*!
- Sets the URI of the security policy to \a securityPolicyUri.
-*/
-void QOpcUa::QUserTokenPolicy::setSecurityPolicyUri(const QString &securityPolicyUri)
-{
- data->securityPolicyUri = securityPolicyUri;
-}
-
-/*!
- Returns the URL of a token issuing service.
-*/
-QString QOpcUa::QUserTokenPolicy::issuerEndpointUrl() const
-{
- return data->issuerEndpointUrl;
-}
-
-/*!
- Sets the URL of the token issuing service to \a issuerEndpointUrl.
-*/
-void QOpcUa::QUserTokenPolicy::setIssuerEndpointUrl(const QString &issuerEndpointUrl)
-{
- data->issuerEndpointUrl = issuerEndpointUrl;
-}
-
-/*!
- Returns the URI for the token type.
-*/
-QString QOpcUa::QUserTokenPolicy::issuedTokenType() const
-{
- return data->issuedTokenType;
-}
-
-/*!
- Sets the URI for the token type to \a issuedTokenType.
-*/
-void QOpcUa::QUserTokenPolicy::setIssuedTokenType(const QString &issuedTokenType)
-{
- data->issuedTokenType = issuedTokenType;
-}
-
-/*!
- Returns the type of the required user identity token.
-*/
-QOpcUa::QUserTokenPolicy::TokenType QOpcUa::QUserTokenPolicy::tokenType() const
-{
- return data->tokenType;
-}
-
-/*!
- Sets the type of the required user identity token to \a tokenType.
-*/
-void QOpcUa::QUserTokenPolicy::setTokenType(TokenType tokenType)
-{
- data->tokenType = tokenType;
-}
-
-/*!
- Returns a server assigned identifier for this policy.
-*/
-QString QOpcUa::QUserTokenPolicy::policyId() const
-{
- return data->policyId;
-}
-
-/*!
- Sets the identifier for this policy to \a policyId.
-*/
-void QOpcUa::QUserTokenPolicy::setPolicyId(const QString &policyId)
-{
- data->policyId = policyId;
-}
-
-/*!
- \class QOpcUa::QApplicationDescription
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA ApplicationDescription.
-
- The application description contains information about an OPC UA application.
-*/
-
-/*!
- \enum QOpcUa::QApplicationDescription::ApplicationType
-
- \value Server This application is a server.
- \value Client This application is a client.
- \value ClientAndServer This application is a client and a server.
- \value DiscoveryServer This application is a discovery server.
-*/
-
-class QOpcUa::QApplicationDescriptionData : public QSharedData
-{
-public:
- QString applicationUri;
- QString productUri;
- QOpcUa::QLocalizedText applicationName;
- QOpcUa::QApplicationDescription::ApplicationType applicationType{QOpcUa::QApplicationDescription::ApplicationType::Server};
- QString gatewayServerUri;
- QString discoveryProfileUri;
- QVector<QString> discoveryUrls;
-};
-
-QOpcUa::QApplicationDescription::QApplicationDescription()
- : data(new QOpcUa::QApplicationDescriptionData)
-{
-}
-
-/*!
- Constructs an application description from \a other.
-*/
-QOpcUa::QApplicationDescription::QApplicationDescription(const QOpcUa::QApplicationDescription &other)
- : data(other.data)
-{
-}
-
-/*!
- Sets the values from \a other in this application description.
-*/
-QOpcUa::QApplicationDescription &QOpcUa::QApplicationDescription::operator=(const QOpcUa::QApplicationDescription &other)
-{
- this->data = other.data;
- return *this;
-}
-
-QOpcUa::QApplicationDescription::~QApplicationDescription()
-{
-}
-
-/*!
- Returns a list of URLs of discovery endpoints.
-*/
-QVector<QString> QOpcUa::QApplicationDescription::discoveryUrls() const
-{
- return data->discoveryUrls;
-}
-
-/*!
- Returns a reference to a list of URLs of discovery endpoints.
-*/
-QVector<QString> &QOpcUa::QApplicationDescription::discoveryUrlsRef()
-{
- return data->discoveryUrls;
-}
-
-/*!
- Sets the discovery URLs to \a discoveryUrls.
-*/
-void QOpcUa::QApplicationDescription::setDiscoveryUrls(const QVector<QString> &discoveryUrls)
-{
- data->discoveryUrls = discoveryUrls;
-}
-
-/*!
- Returns the URI of the supported discovery profile.
-*/
-QString QOpcUa::QApplicationDescription::discoveryProfileUri() const
-{
- return data->discoveryProfileUri;
-}
-
-/*!
- Sets the discovery profile URI to \a discoveryProfileUri.
-*/
-void QOpcUa::QApplicationDescription::setDiscoveryProfileUri(const QString &discoveryProfileUri)
-{
- data->discoveryProfileUri = discoveryProfileUri;
-}
-
-/*!
- Returns the URI of the gateway server.
-*/
-QString QOpcUa::QApplicationDescription::gatewayServerUri() const
-{
- return data->gatewayServerUri;
-}
-
-/*!
- Sets the URI of the gateway server to \a gatewayServerUri.
-*/
-void QOpcUa::QApplicationDescription::setGatewayServerUri(const QString &gatewayServerUri)
-{
- data->gatewayServerUri = gatewayServerUri;
-}
-
-/*!
- Returns the application's type (server, client, both, discovery server).
-*/
-QOpcUa::QApplicationDescription::ApplicationType QOpcUa::QApplicationDescription::applicationType() const
-{
- return data->applicationType;
-}
-
-/*!
- Sets the application type to \a applicationType.
-*/
-void QOpcUa::QApplicationDescription::setApplicationType(ApplicationType applicationType)
-{
- data->applicationType = applicationType;
-}
-
-/*!
- Returns a name describing the application.
-*/
-QOpcUa::QLocalizedText QOpcUa::QApplicationDescription::applicationName() const
-{
- return data->applicationName;
-}
-
-/*!
- Sets the application name to \a applicationName.
-*/
-void QOpcUa::QApplicationDescription::setApplicationName(const QOpcUa::QLocalizedText &applicationName)
-{
- data->applicationName = applicationName;
-}
-
-/*!
- Returns the globally unique identifier for this product.
-*/
-QString QOpcUa::QApplicationDescription::productUri() const
-{
- return data->productUri;
-}
-
-/*!
- Sets the globally unique identifier for this product to \a productUri.
-*/
-void QOpcUa::QApplicationDescription::setProductUri(const QString &productUri)
-{
- data->productUri = productUri;
-}
-
-/*!
- Returns the globally unique identifier for this application instance.
-*/
-QString QOpcUa::QApplicationDescription::applicationUri() const
-{
- return data->applicationUri;
-}
-
-/*!
- Sets the globally unique identifier for this application instance to \a applicationUri.
-*/
-void QOpcUa::QApplicationDescription::setApplicationUri(const QString &applicationUri)
-{
- data->applicationUri = applicationUri;
-}
-
-/*!
- \class QOpcUa::QEndpointDescription
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA EndpointDescription.
-
- An endpoint description contains information about an endpoint and how to connect to it.
-*/
-
-/*!
- \enum QOpcUa::QEndpointDescription::MessageSecurityMode
-
- \value Invalid The default value, will be rejected by the server.
- \value None No security.
- \value Sign Messages are signed but not encrypted.
- \value SignAndEncrypt Messages are signed and encrypted.
-*/
-
-class QOpcUa::QEndpointDescriptionData : public QSharedData
-{
-public:
- QString endpointUrl;
- QOpcUa::QApplicationDescription server;
- QByteArray serverCertificate;
- QOpcUa::QEndpointDescription::MessageSecurityMode securityMode{QOpcUa::QEndpointDescription::MessageSecurityMode::None};
- QString securityPolicyUri;
- QVector<QOpcUa::QUserTokenPolicy> userIdentityTokens;
- QString transportProfileUri;
- quint8 securityLevel{0};
-};
-
-QOpcUa::QEndpointDescription::QEndpointDescription()
- : data(new QOpcUa::QEndpointDescriptionData)
-{
-}
-
-/*!
- Constructs an endpoint description from \a rhs.
-*/
-QOpcUa::QEndpointDescription::QEndpointDescription(const QOpcUa::QEndpointDescription &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Sets the values from \a rhs in this endpoint description.
-*/
-QOpcUa::QEndpointDescription &QOpcUa::QEndpointDescription::operator=(const QOpcUa::QEndpointDescription &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-QOpcUa::QEndpointDescription::~QEndpointDescription()
-{
-}
-
-/*!
- Returns a relative index assigned by the server. It describes how secure this
- endpoint is compared to other endpoints of the same server. An endpoint with strong
- security measures has a higher security level than one with weaker or no security
- measures.
-
- Security level 0 indicates an endpoint for backward compatibility purposes which
- should only be used if the client does not support the security measures required
- by more secure endpoints.
-*/
-quint8 QOpcUa::QEndpointDescription::securityLevel() const
-{
- return data->securityLevel;
-}
-
-/*!
- Sets the security level to \a securityLevel.
-*/
-void QOpcUa::QEndpointDescription::setSecurityLevel(quint8 securityLevel)
-{
- data->securityLevel = securityLevel;
-}
-
-/*!
- Returns the URI of the transport profile supported by the endpoint.
-*/
-QString QOpcUa::QEndpointDescription::transportProfileUri() const
-{
- return data->transportProfileUri;
-}
-
-/*!
- Sets the URI of the transport profile supported by the endpoint to \a transportProfileUri.
-*/
-void QOpcUa::QEndpointDescription::setTransportProfileUri(const QString &transportProfileUri)
-{
- data->transportProfileUri = transportProfileUri;
-}
-
-/*!
- Returns a list of user identity tokens the endpoint will accept.
-*/
-QVector<QOpcUa::QUserTokenPolicy> QOpcUa::QEndpointDescription::userIdentityTokens() const
-{
- return data->userIdentityTokens;
-}
-
-/*!
- Returns a reference to a list of user identity tokens the endpoint will accept.
-*/
-QVector<QOpcUa::QUserTokenPolicy> &QOpcUa::QEndpointDescription::userIdentityTokensRef()
-{
- return data->userIdentityTokens;
-}
-
-/*!
- Sets the user identity tokens to \a userIdentityTokens.
-*/
-void QOpcUa::QEndpointDescription::setUserIdentityTokens(const QVector<QOpcUa::QUserTokenPolicy> &userIdentityTokens)
-{
- data->userIdentityTokens = userIdentityTokens;
-}
-
-/*!
- Returns the URI of the security policy.
-*/
-QString QOpcUa::QEndpointDescription::securityPolicyUri() const
-{
- return data->securityPolicyUri;
-}
-
-/*!
- Sets the URI of the security policy to \a securityPolicyUri.
-*/
-void QOpcUa::QEndpointDescription::setSecurityPolicyUri(const QString &securityPolicyUri)
-{
- data->securityPolicyUri = securityPolicyUri;
-}
-
-/*!
- Returns the security mode supported by this endpoint.
-*/
-QOpcUa::QEndpointDescription::MessageSecurityMode QOpcUa::QEndpointDescription::securityMode() const
-{
- return data->securityMode;
-}
-
-/*!
- Sets the security mode supported by this endpoint to \a securityMode.
-*/
-void QOpcUa::QEndpointDescription::setSecurityMode(MessageSecurityMode securityMode)
-{
- data->securityMode = securityMode;
-}
-
-/*!
- Returns the application instance certificate of the server.
-*/
-QByteArray QOpcUa::QEndpointDescription::serverCertificate() const
-{
- return data->serverCertificate;
-}
-
-/*!
- Sets the application instance certificate of the server to \a serverCertificate.
-*/
-void QOpcUa::QEndpointDescription::setServerCertificate(const QByteArray &serverCertificate)
-{
- data->serverCertificate = serverCertificate;
-}
-
-/*!
- Returns the application description of the server.
-*/
-QOpcUa::QApplicationDescription QOpcUa::QEndpointDescription::server() const
-{
- return data->server;
-}
-
-/*!
- Returns a reference to the application description of the server.
-*/
-QOpcUa::QApplicationDescription &QOpcUa::QEndpointDescription::serverRef()
-{
- return data->server;
-}
-
-/*!
- Sets the application description of the server to \a server.
-*/
-void QOpcUa::QEndpointDescription::setServer(const QOpcUa::QApplicationDescription &server)
-{
- data->server = server;
-}
-
-/*!
- Returns the URL for the endpoint.
-*/
-QString QOpcUa::QEndpointDescription::endpointUrl() const
-{
- return data->endpointUrl;
-}
-
-/*!
- Sets the URL for the endpoint to \a endpointUrl.
-*/
-void QOpcUa::QEndpointDescription::setEndpointUrl(const QString &endpointUrl)
-{
- data->endpointUrl = endpointUrl;
-}
-
-/*!
- \class QOpcUa::QArgument
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief The OPC UA Argument type.
-
- This is the Qt OPC UA representation for the Argument type defined in OPC-UA part 3, 8.6.
-
- The Argument type is mainly used for the values of the InputArguments and OutputArguments properties
- which describe the parameters and return values of method nodes.
-*/
-class QOpcUa::QArgumentData : public QSharedData
-{
-public:
- QString name;
- QString dataTypeId;
- qint32 valueRank{-2};
- QVector<quint32> arrayDimensions;
- QOpcUa::QLocalizedText description;
-};
-
-QOpcUa::QArgument::QArgument()
- : data(new QOpcUa::QArgumentData)
-{
-}
-
-QOpcUa::QArgument::QArgument(const QOpcUa::QArgument &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Constructs an argument with name \a name, data type id \a dataTypeId, value rank \a valueRank,
- array dimensions \a arrayDimensions and description \a description.
-*/
-QOpcUa::QArgument::QArgument(const QString &name, const QString &dataTypeId, qint32 valueRank,
- const QVector<quint32> &arrayDimensions, const QOpcUa::QLocalizedText &description)
- : data(new QOpcUa::QArgumentData)
-{
- setName(name);
- setDataTypeId(dataTypeId);
- setValueRank(valueRank);
- setArrayDimensions(arrayDimensions);
- setDescription(description);
-}
-
-/*!
- Sets the values from \a rhs in this argument.
-*/
-QOpcUa::QArgument &QOpcUa::QArgument::operator=(const QOpcUa::QArgument &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-/*!
- Returns true if this argument has the same value as \a other.
-*/
-bool QOpcUa::QArgument::operator==(const QOpcUa::QArgument &other) const
-{
- return data->arrayDimensions == other.arrayDimensions() &&
- nodeIdEquals(data->dataTypeId, other.dataTypeId()) &&
- data->description == other.description() &&
- data->name == other.name() &&
- data->valueRank == other.valueRank();
-}
-
-/*!
- Converts this argument to \l QVariant.
-*/
-QOpcUa::QArgument::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-QOpcUa::QArgument::~QArgument()
-{
-}
-
-/*!
- Returns the name of the argument.
-*/
-QString QOpcUa::QArgument::name() const
-{
- return data->name;
-}
-
-/*!
- Sets the name of the argument to \a name.
-*/
-void QOpcUa::QArgument::setName(const QString &name)
-{
- data->name = name;
-}
-
-/*!
- Returns the data type node id of the argument.
-*/
-QString QOpcUa::QArgument::dataTypeId() const
-{
- return data->dataTypeId;
-}
-
-/*!
- Sets the data type node id of the argument to \a dataTypeId.
-*/
-void QOpcUa::QArgument::setDataTypeId(const QString &dataTypeId)
-{
- data->dataTypeId = dataTypeId;
-}
-
-/*!
- Returns the value rank of the argument.
- The value rank describes the structure of the value.
- \table
- \header
- \li ValueRank
- \li Meaning
- \row
- \li -3
- \li Scalar or one dimensional array
- \row
- \li -2
- \li Scalar or array with any number of dimensions
- \row
- \li -1
- \li Not an array
- \row
- \li 0
- \li Array with one or more dimensions
- \row
- \li 1
- \li One dimensional array
- \row
- \li >1
- \li Array with n dimensions
- \endtable
-*/
-qint32 QOpcUa::QArgument::valueRank() const
-{
- return data->valueRank;
-}
-
-/*!
- Sets the value rank of the argument to \a valueRank.
-*/
-void QOpcUa::QArgument::setValueRank(qint32 valueRank)
-{
- data->valueRank = valueRank;
-}
-
-/*!
- Returns the array dimensions of the argument.
-
- The array dimensions describe the length of each array dimension.
-*/
-QVector<quint32> QOpcUa::QArgument::arrayDimensions() const
-{
- return data->arrayDimensions;
-}
-
-/*!
- Returns a reference to the array dimensions of the argument.
-*/
-QVector<quint32> &QOpcUa::QArgument::arrayDimensionsRef()
-{
- return data->arrayDimensions;
-}
-
-/*!
- Sets the array dimensions of the argument to \a arrayDimensions.
-*/
-void QOpcUa::QArgument::setArrayDimensions(const QVector<quint32> &arrayDimensions)
-{
- data->arrayDimensions = arrayDimensions;
-}
-
-/*!
- Returns the description of the argument.
-*/
-QOpcUa::QLocalizedText QOpcUa::QArgument::description() const
-{
- return data->description;
-}
-
-/*!
- Sets the description of the argument to \a description.
-*/
-void QOpcUa::QArgument::setDescription(const QOpcUa::QLocalizedText &description)
-{
- data->description = description;
-}
-
-/*!
- \class QOpcUa::QExtensionObject
- \inmodule QtOpcUa
- \brief The OPC UA ExtensionObject.
-
- This is the Qt OPC UA representation for an extension object.
- Extension objects are used as a container in OPC UA whenever a non-builtin type is stored
- in a Variant. It contains information about the type and encoding of the data as well as
- the data itself encoded with one of the encodings specified in OPC-UA part 6.
- Decoders are supposed to decode extension objects if they can handle the type. If the type
- is not supported by the decoder, the extension object is not decoded and decoding is left
- to the user.
-*/
+ Returns a textual representation of \a statusCode.
-/*!
- \enum QOpcUa::QExtensionObject::Encoding
-
- Enumerates the possible encodings of the body.
-
- \value NoBody
- \value ByteString
- \value Xml
-*/
-
-class QOpcUa::QExtensionObjectData : public QSharedData
-{
-public:
- QString encodingTypeId;
- QByteArray encodedBody;
- QOpcUa::QExtensionObject::Encoding encoding{QOpcUa::QExtensionObject::Encoding::NoBody};
-};
-
-QOpcUa::QExtensionObject::QExtensionObject()
- : data(new QExtensionObjectData)
-{
-}
-
-/*!
- Constructs an extension object from \a rhs.
-*/
-QOpcUa::QExtensionObject::QExtensionObject(const QExtensionObject &rhs)
- : data(rhs.data)
-{
-}
-
-/*!
- Sets the values from \a rhs in this extension object.
-*/
-QOpcUa::QExtensionObject &QOpcUa::QExtensionObject::operator=(const QOpcUa::QExtensionObject &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-/*!
- Returns \c true if this extension object has the same value as \a rhs.
-*/
-bool QOpcUa::QExtensionObject::operator==(const QOpcUa::QExtensionObject &rhs) const
-{
- return data->encoding == rhs.encoding() &&
- nodeIdEquals(data->encodingTypeId, rhs.encodingTypeId()) &&
- data->encodedBody == rhs.encodedBody();
-}
-
-/*!
- Converts this extension object to \l QVariant.
-*/
-QOpcUa::QExtensionObject::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-QOpcUa::QExtensionObject::~QExtensionObject()
-{
-}
-
-/*!
- Returns the \l {QOpcUa::QExtensionObject::Encoding} {encoding} of the body.
-*/
-QOpcUa::QExtensionObject::Encoding QOpcUa::QExtensionObject::encoding() const
-{
- return data->encoding;
-}
-
-/*!
- Sets the encoding of the body to \a encoding.
-*/
-void QOpcUa::QExtensionObject::setEncoding(QOpcUa::QExtensionObject::Encoding encoding)
-{
- data->encoding = encoding;
-}
-
-/*!
- Returns the body of this extension object. It contains the encoded data.
-*/
-QByteArray QOpcUa::QExtensionObject::encodedBody() const
-{
- return data->encodedBody;
-}
-
-/*!
- Returns a reference to the body of this extension object.
-*/
-QByteArray &QOpcUa::QExtensionObject::encodedBodyRef()
-{
- return data->encodedBody;
-}
-/*!
- Sets the body of this extension object to \a encodedBody.
-*/
-void QOpcUa::QExtensionObject::setEncodedBody(const QByteArray &encodedBody)
-{
- data->encodedBody = encodedBody;
-}
-
-/*!
- Returns the node id of the encoding for the type stored by this extension object, for example ns=0;i=886 for
- Range_Encoding_DefaultBinary. All encoding ids are listed in \l {https://opcfoundation.org/UA/schemas/1.03/NodeIds.csv}.
+ Currently, this is the name of the enum value but may be a real message in future releases.
*/
-QString QOpcUa::QExtensionObject::encodingTypeId() const
+QString QOpcUa::statusToString(QOpcUa::UaStatusCode statusCode)
{
- return data->encodingTypeId;
-}
-
-/*!
- Sets the node id of the encoding for the type stored by this extension object to \a encodingTypeId.
-*/
-void QOpcUa::QExtensionObject::setEncodingTypeId(const QString &encodingTypeId)
-{
- data->encodingTypeId = encodingTypeId;
-}
-
-/*
- This class has been modelled in the style of the Variant encoding
- defined in OPC-UA part 6, 5.2.2.16.
-
- This solution has been preferred to returning nested QVariantLists
- due to the following reasons:
- - A QVariantList inside a QVariantList is stored as a QVariant which must be converted
- to QVariantList before the elements can be accessed. This makes it impossible to update the
- values in place.
- - The length of the array is encoded as a 32 bit unsigned integer.
- Array dimensions are encoded in an array, so an array can have UINT32_MAX dimensions.
- Depending on the number of dimensions, there could be lots of nested QVariantLists
- which would require a huge effort when calculating the array dimensions for conversions
- between QVariantList and the sdk specific variant type.
-*/
-
-/*!
- \class QOpcUa::QMultiDimensionalArray
- \inmodule QtOpcUa
- \inheaderfile QtOpcUa/qopcuatype.h
- \brief A container class for multidimensional arrays.
-
- This class manages arrays of Qt OPC UA types with associated array dimensions information.
- It is returned as value when a multidimensional array is received from the server. It can also
- be used as a write value or as parameter for filters and method calls.
-*/
-
-class QOpcUa::QMultiDimensionalArrayData : public QSharedData
-{
-public:
- QVariantList value;
- QVector<quint32> arrayDimensions;
- quint32 expectedArrayLength{0};
-};
-
-QOpcUa::QMultiDimensionalArray::QMultiDimensionalArray()
- : data(new QOpcUa::QMultiDimensionalArrayData)
-{
-}
-
-/*!
- Constructs a multidimensional array from \a other.
-*/
-QOpcUa::QMultiDimensionalArray::QMultiDimensionalArray(const QOpcUa::QMultiDimensionalArray &other)
- : data(other.data)
-{
-}
-
-/*!
- Sets the values from \a rhs in the multidimensional array.
-*/
-QOpcUa::QMultiDimensionalArray &QOpcUa::QMultiDimensionalArray::operator=(const QOpcUa::QMultiDimensionalArray &rhs)
-{
- if (this != &rhs)
- data.operator=(rhs.data);
- return *this;
-}
-
-/*!
- Constructs a multidimensional array with value \a value and array dimensions \a arrayDimensions.
-*/
-QOpcUa::QMultiDimensionalArray::QMultiDimensionalArray(const QVariantList &value, const QVector<quint32> &arrayDimensions)
- : data(new QOpcUa::QMultiDimensionalArrayData)
-{
- setValueArray(value);
- setArrayDimensions(arrayDimensions);
-}
-
-/*!
- Creates a multidimensional array with preallocated data fitting \a arrayDimensions.
-*/
-QOpcUa::QMultiDimensionalArray::QMultiDimensionalArray(const QVector<quint32> &arrayDimensions)
- : data(new QOpcUa::QMultiDimensionalArrayData)
-{
- setArrayDimensions(arrayDimensions);
- if (data->expectedArrayLength) {
- data->value.reserve(data->expectedArrayLength);
- for (size_t i = 0; i < data->expectedArrayLength; ++i)
- data->value.append(QVariant());
- }
-}
-
-QOpcUa::QMultiDimensionalArray::~QMultiDimensionalArray()
-{
-}
-
-/*!
- Returns the dimensions of the multidimensional array.
- The element at position n contains the length of the n-th dimension.
-*/
-QVector<quint32> QOpcUa::QMultiDimensionalArray::arrayDimensions() const
-{
- return data->arrayDimensions;
-}
-
-/*!
- Sets the dimensions of the multidimensional array to \a arrayDimensions.
-*/
-void QOpcUa::QMultiDimensionalArray::setArrayDimensions(const QVector<quint32> &arrayDimensions)
-{
- data->arrayDimensions = arrayDimensions;
- data->expectedArrayLength = std::accumulate(data->arrayDimensions.begin(), data->arrayDimensions.end(),
- 1, std::multiplies<quint32>());
-}
-
-/*!
- Returns \c true if this multidimensional array has the same value as \a other.
-*/
-bool QOpcUa::QMultiDimensionalArray::operator==(const QOpcUa::QMultiDimensionalArray &other) const
-{
- return arrayDimensions() == other.arrayDimensions() &&
- valueArray() == other.valueArray();
-}
-
-/*!
- Converts this multidimensional array to \l QVariant.
-*/
-QOpcUa::QMultiDimensionalArray::operator QVariant() const
-{
- return QVariant::fromValue(*this);
-}
-
-/*!
- Returns the value array of the multidimensional array.
-*/
-QVariantList QOpcUa::QMultiDimensionalArray::valueArray() const
-{
- return data->value;
-}
-
-/*!
- Returns a reference to the value array of the multidimensional array.
-*/
-QVariantList &QOpcUa::QMultiDimensionalArray::valueArrayRef()
-{
- return data->value;
-}
-
-/*!
- Sets the value array of the multidimensional array to \a value.
-*/
-void QOpcUa::QMultiDimensionalArray::setValueArray(const QVariantList &value)
-{
- data->value = value;
-}
-
-/*!
- Returns the array index in \l valueArray() of the element identified by \a indices.
- If \a indices is invalid for the array or if the array's dimensions don't match
- the size of \l valueArray(), the invalid index \c -1 is returned.
-*/
-int QOpcUa::QMultiDimensionalArray::arrayIndex(const QVector<quint32> &indices) const
-{
- // A QList can store INT_MAX values. Depending on the platform, this allows a size > UINT32_MAX
- if (data->expectedArrayLength > static_cast<quint64>((std::numeric_limits<int>::max)()) ||
- static_cast<quint64>(data->value.size()) > (std::numeric_limits<quint32>::max)())
- return -1;
-
- // Check number of dimensions and data size
- if (indices.size() != data->arrayDimensions.size() ||
- data->expectedArrayLength != static_cast<quint32>(data->value.size()))
- return -1; // Missing array dimensions or array dimensions don't fit the array
-
- quint32 index = 0;
- quint32 stride = 1;
- // Reverse iteration to avoid repetitions while calculating the stride
- for (int i = data->arrayDimensions.size() - 1; i >= 0; --i) {
- if (indices.at(i) >= data->arrayDimensions.at(i)) // Out of bounds
- return -1;
-
- // Arrays are encoded in row-major order: [0,0,0], [0,0,1], [0,1,0], [0,1,1], [1,0,0], [1,0,1], [1,1,0], [1,1,1]
- // The stride for dimension i in a n dimensional array is the product of all array dimensions from i+1 to n
- if (i < data->arrayDimensions.size() - 1)
- stride *= data->arrayDimensions.at(i + 1);
- index += stride * indices.at(i);
+ const auto enumerator = QMetaEnum::fromType<QOpcUa::UaStatusCode>();
+ const auto key = enumerator.valueToKey(statusCode);
+ if (key)
+ return QString::fromLatin1(key);
+ else
+ return QLatin1String("Invalid enum value for UaStatusCode");
+}
+
+/*!
+ \since 5.13
+
+ Returns the Qt OPC UA type from \a type.
+ In case the type does not map, \c QOpcUa::Undefined is returned.
+*/
+QOpcUa::Types QOpcUa::metaTypeToQOpcUaType(QMetaType::Type type) {
+ switch (type) {
+ case QMetaType::Bool:
+ return QOpcUa::Boolean;
+ case QMetaType::UChar:
+ return QOpcUa::Byte;
+ case QMetaType::Char:
+ return QOpcUa::SByte;
+ case QMetaType::UShort:
+ return QOpcUa::UInt16;
+ case QMetaType::Short:
+ return QOpcUa::Int16;
+ case QMetaType::Int:
+ return QOpcUa::Int32;
+ case QMetaType::UInt:
+ return QOpcUa::UInt32;
+ case QMetaType::ULongLong:
+ return QOpcUa::UInt64;
+ case QMetaType::LongLong:
+ return QOpcUa::Int64;
+ case QMetaType::Double:
+ return QOpcUa::Double;
+ case QMetaType::Float:
+ return QOpcUa::Float;
+ case QMetaType::QString:
+ return QOpcUa::String;
+ case QMetaType::QDateTime:
+ return QOpcUa::DateTime;
+ case QMetaType::QByteArray:
+ return QOpcUa::ByteString;
+ case QMetaType::QUuid:
+ return QOpcUa::Guid;
+ default:
+ break;
}
-
- return (index <= static_cast<quint64>((std::numeric_limits<int>::max)())) ?
- static_cast<int>(index) : -1;
-}
-
-/*!
- Returns the value of the element identified by \a indices.
- If the indices are invalid for the array, an empty \l QVariant is returned.
-*/
-QVariant QOpcUa::QMultiDimensionalArray::value(const QVector<quint32> &indices) const
-{
- int index = arrayIndex(indices);
-
- if (index < 0)
- return QVariant();
-
- return data->value.at(index);
-}
-
-/*!
- Sets the value at position \a indices to \a value.
- Returns \c true if the value has been successfully set.
-*/
-bool QOpcUa::QMultiDimensionalArray::setValue(const QVector<quint32> &indices, const QVariant &value)
-{
- int index = arrayIndex(indices);
-
- if (index < 0)
- return false;
-
- data->value[index] = value;
- return true;
-}
-
-/*!
- Returns \c true if the multidimensional array is valid
-*/
-bool QOpcUa::QMultiDimensionalArray::isValid() const
-{
- return static_cast<quint64>(data->value.size()) == data->expectedArrayLength &&
- static_cast<quint64>(data->value.size()) <= (std::numeric_limits<quint32>::max)() &&
- static_cast<quint64>(data->arrayDimensions.size()) <= (std::numeric_limits<quint32>::max)();
+ return QOpcUa::Undefined;
+}
+
+QOpcUa::Types QOpcUa::opcUaDataTypeToQOpcUaType(const QString &type)
+{
+ if (type == QStringLiteral("ns=0;i=1"))
+ return QOpcUa::Boolean;
+ else if (type == QStringLiteral("ns=0;i=3"))
+ return QOpcUa::Byte;
+ else if (type == QStringLiteral("ns=0;i=2"))
+ return QOpcUa::SByte;
+ else if (type == QStringLiteral("ns=0;i=5"))
+ return QOpcUa::UInt16;
+ else if (type == QStringLiteral("ns=0;i=4"))
+ return QOpcUa::Int16;
+ else if (type == QStringLiteral("ns=0;i=6"))
+ return QOpcUa::Int32;
+ else if (type == QStringLiteral("ns=0;i=7"))
+ return QOpcUa::UInt32;
+ else if (type == QStringLiteral("ns=0;i=9"))
+ return QOpcUa::UInt64;
+ else if (type == QStringLiteral("ns=0;i=8"))
+ return QOpcUa::Int64;
+ else if (type == QStringLiteral("ns=0;i=11"))
+ return QOpcUa::Double;
+ else if (type == QStringLiteral("ns=0;i=10"))
+ return QOpcUa::Float;
+ else if (type == QStringLiteral("ns=0;i=12"))
+ return QOpcUa::String;
+ else if (type == QStringLiteral("ns=0;i=13"))
+ return QOpcUa::DateTime;
+ else if (type == QStringLiteral("ns=0;i=15"))
+ return QOpcUa::ByteString;
+ else if (type == QStringLiteral("ns=0;i=14"))
+ return QOpcUa::Guid;
+ else
+ return QOpcUa::Undefined;
}
QT_END_NAMESPACE
+
diff --git a/src/opcua/client/qopcuatype.h b/src/opcua/client/qopcuatype.h
index f64ebe3..0969b1e 100644
--- a/src/opcua/client/qopcuatype.h
+++ b/src/opcua/client/qopcuatype.h
@@ -42,9 +42,7 @@
#include <QtCore/qmetatype.h>
#include <QtCore/qpair.h>
-#include <QtCore/qshareddata.h>
#include <QtCore/qvariant.h>
-#include <QtCore/qvector.h>
QT_BEGIN_NAMESPACE
@@ -225,6 +223,8 @@ enum Types
};
Q_ENUM_NS(Types)
+// OpcUa Specification Part 4, Chapter 7.34 "Status Code"
+// OpcUa Specification Part 6, Annex A.2 "Status Codes
enum UaStatusCode : quint32
{
Good = 0,
@@ -472,6 +472,7 @@ Q_ENUM_NS(ErrorCategory)
Q_OPCUA_EXPORT bool isSuccessStatus(QOpcUa::UaStatusCode statusCode);
Q_OPCUA_EXPORT QOpcUa::ErrorCategory errorCategory(QOpcUa::UaStatusCode statusCode);
+Q_OPCUA_EXPORT QString statusToString(QOpcUa::UaStatusCode statusCode);
// NodeId helpers
Q_OPCUA_EXPORT QString nodeIdFromString(quint16 ns, const QString &identifier);
@@ -488,708 +489,14 @@ Q_OPCUA_EXPORT QString namespace0IdName(QOpcUa::NodeIds::Namespace0 id);
typedef QPair<QVariant, QOpcUa::Types> TypedVariant;
-class QQualifiedNameData;
-class Q_OPCUA_EXPORT QQualifiedName
-{
-public:
- QQualifiedName();
- QQualifiedName(const QOpcUa::QQualifiedName &);
- QQualifiedName(quint16 namespaceIndex, const QString &name);
- QQualifiedName &operator=(const QOpcUa::QQualifiedName &);
- bool operator==(const QOpcUa::QQualifiedName &rhs) const;
- operator QVariant() const;
- ~QQualifiedName();
-
- QString name() const;
- void setName(const QString &name);
-
- quint16 namespaceIndex() const;
- void setNamespaceIndex(quint16 namespaceIndex);
-
-private:
- QSharedDataPointer<QOpcUa::QQualifiedNameData> data;
-};
-
-class QLocalizedTextData;
-class Q_OPCUA_EXPORT QLocalizedText
-{
- Q_GADGET
- Q_PROPERTY(QString locale READ locale WRITE setLocale)
- Q_PROPERTY(QString text READ text WRITE setText)
-
-public:
- QLocalizedText();
- QLocalizedText(const QOpcUa::QLocalizedText &);
- QLocalizedText(const QString &locale, const QString &text);
- QLocalizedText &operator=(const QOpcUa::QLocalizedText &);
- bool operator==(const QOpcUa::QLocalizedText &rhs) const;
- operator QVariant() const;
- ~QLocalizedText();
-
- QString locale() const;
- void setLocale(const QString &locale);
-
- QString text() const;
- void setText(const QString &text);
-
-private:
- QSharedDataPointer<QOpcUa::QLocalizedTextData> data;
-};
-
-class QRangeData;
-class Q_OPCUA_EXPORT QRange
-{
-public:
- QRange();
- QRange(const QOpcUa::QRange &);
- QRange(double low, double high);
- QRange &operator=(const QOpcUa::QRange &);
- bool operator==(const QOpcUa::QRange &rhs) const;
- operator QVariant() const;
- ~QRange();
-
- double low() const;
- void setLow(double low);
-
- double high() const;
- void setHigh(double high);
-
-private:
- QSharedDataPointer<QOpcUa::QRangeData> data;
-};
-
-class QEUInformationData;
-class Q_OPCUA_EXPORT QEUInformation
-{
-public:
- QEUInformation();
- QEUInformation(const QOpcUa::QEUInformation &);
- QEUInformation(const QString &namespaceUri, qint32 unitId,
- const QOpcUa::QLocalizedText &displayName, const QOpcUa::QLocalizedText &description);
- QEUInformation &operator=(const QOpcUa::QEUInformation &);
- bool operator==(const QOpcUa::QEUInformation &rhs) const;
- operator QVariant() const;
- ~QEUInformation();
-
- QString namespaceUri() const;
- void setNamespaceUri(const QString &namespaceUri);
-
- qint32 unitId() const;
- void setUnitId(qint32 unitId);
-
- QOpcUa::QLocalizedText displayName() const;
- void setDisplayName(const QOpcUa::QLocalizedText &displayName);
-
- QOpcUa::QLocalizedText description() const;
- void setDescription(const QOpcUa::QLocalizedText &description);
-
-private:
- QSharedDataPointer<QOpcUa::QEUInformationData> data;
-};
-
-class QComplexNumberData;
-class Q_OPCUA_EXPORT QComplexNumber
-{
-public:
- QComplexNumber();
- QComplexNumber(const QOpcUa::QComplexNumber &);
- QComplexNumber(float real, float imaginary);
- QComplexNumber &operator=(const QOpcUa::QComplexNumber &);
- bool operator==(const QOpcUa::QComplexNumber &rhs) const;
- operator QVariant() const;
- ~QComplexNumber();
-
- float real() const;
- void setReal(float real);
-
- float imaginary() const;
- void setImaginary(float imaginary);
-
-private:
- QSharedDataPointer<QOpcUa::QComplexNumberData> data;
-};
-
-class QDoubleComplexNumberData;
-class Q_OPCUA_EXPORT QDoubleComplexNumber
-{
-public:
- QDoubleComplexNumber();
- QDoubleComplexNumber(const QOpcUa::QDoubleComplexNumber &);
- QDoubleComplexNumber(double real, double imaginary);
- QDoubleComplexNumber &operator=(const QOpcUa::QDoubleComplexNumber &);
- bool operator==(const QOpcUa::QDoubleComplexNumber &rhs) const;
- operator QVariant() const;
- ~QDoubleComplexNumber();
-
- double real() const;
- void setReal(double real);
-
- double imaginary() const;
- void setImaginary(double imaginary);
-
-private:
- QSharedDataPointer<QOpcUa::QDoubleComplexNumberData> data;
-};
-
enum class AxisScale : quint32 {
Linear = 0,
Log = 1,
Ln = 2
};
-class QAxisInformationData;
-class Q_OPCUA_EXPORT QAxisInformation
-{
-public:
- QAxisInformation();
- QAxisInformation(const QOpcUa::QAxisInformation &);
- QAxisInformation(const QOpcUa::QEUInformation &engineeringUnits, const QOpcUa::QRange &eURange, const QOpcUa::QLocalizedText &title,
- const QOpcUa::AxisScale &axisScaleType, const QVector<double> &axisSteps);
- QAxisInformation &operator=(const QOpcUa::QAxisInformation &);
- bool operator==(const QOpcUa::QAxisInformation &rhs) const;
- operator QVariant() const;
- ~QAxisInformation();
-
- QOpcUa::QEUInformation engineeringUnits() const;
- void setEngineeringUnits(const QOpcUa::QEUInformation &engineeringUnits);
-
- QOpcUa::QRange eURange() const;
- void setEURange(const QOpcUa::QRange &eURange);
-
- QOpcUa::QLocalizedText title() const;
- void setTitle(const QOpcUa::QLocalizedText &title);
-
- QOpcUa::AxisScale axisScaleType() const;
- void setAxisScaleType(QOpcUa::AxisScale axisScaleType);
-
- QVector<double> axisSteps() const;
- void setAxisSteps(const QVector<double> &axisSteps);
- QVector<double> &axisStepsRef();
-
-private:
- QSharedDataPointer<QOpcUa::QAxisInformationData> data;
-};
-
-class QXValueData;
-class Q_OPCUA_EXPORT QXValue
-{
-public:
- QXValue();
- QXValue(const QOpcUa::QXValue &);
- QXValue(double x, float value);
- QXValue &operator=(const QOpcUa::QXValue &);
- bool operator==(const QOpcUa::QXValue &rhs) const;
- operator QVariant() const;
- ~QXValue();
-
- double x() const;
- void setX(double x);
-
- float value() const;
- void setValue(float value);
-
-private:
- QSharedDataPointer<QOpcUa::QXValueData> data;
-};
-
-class QExpandedNodeIdData;
-class Q_OPCUA_EXPORT QExpandedNodeId
-{
-public:
- QExpandedNodeId();
- QExpandedNodeId(const QOpcUa::QExpandedNodeId &);
- QExpandedNodeId(const QString &nodeId);
- QExpandedNodeId(const QString &namespaceUri, const QString &nodeId, quint32 serverIndex = 0);
- QExpandedNodeId &operator=(const QOpcUa::QExpandedNodeId &);
- bool operator==(const QOpcUa::QExpandedNodeId &) const;
- operator QVariant() const;
- ~QExpandedNodeId();
-
- quint32 serverIndex() const;
- void setServerIndex(quint32 serverIndex);
-
- QString namespaceUri() const;
- void setNamespaceUri(const QString &namespaceUri);
-
- QString nodeId() const;
- void setNodeId(const QString &nodeId);
-
-private:
- QSharedDataPointer<QOpcUa::QExpandedNodeIdData> data;
-};
-
-class QRelativePathElementData;
-class Q_OPCUA_EXPORT QRelativePathElement
-{
-public:
- QRelativePathElement();
- QRelativePathElement(const QOpcUa::QQualifiedName &target, const QString &refType);
- QRelativePathElement(const QOpcUa::QQualifiedName &target, QOpcUa::ReferenceTypeId refType);
- QRelativePathElement(const QOpcUa::QRelativePathElement &);
- QRelativePathElement &operator=(const QOpcUa::QRelativePathElement &);
- bool operator==(const QOpcUa::QRelativePathElement &rhs) const;
- ~QRelativePathElement();
-
- QString referenceTypeId() const;
- void setReferenceTypeId(const QString &referenceTypeId);
- void setReferenceTypeId(QOpcUa::ReferenceTypeId referenceTypeId);
-
- bool isInverse() const;
- void setIsInverse(bool isInverse);
-
- bool includeSubtypes() const;
- void setIncludeSubtypes(bool includeSubtypes);
-
- QOpcUa::QQualifiedName targetName() const;
- void setTargetName(const QOpcUa::QQualifiedName &targetName);
-
-private:
- QSharedDataPointer<QOpcUa::QRelativePathElementData> data;
-};
-
-class QBrowsePathTargetData;
-class Q_OPCUA_EXPORT QBrowsePathTarget
-{
-public:
- QBrowsePathTarget();
- QBrowsePathTarget(const QOpcUa::QBrowsePathTarget &);
- QBrowsePathTarget &operator=(const QOpcUa::QBrowsePathTarget &);
- bool operator==(const QOpcUa::QBrowsePathTarget &rhs) const;
- ~QBrowsePathTarget();
-
- QOpcUa::QExpandedNodeId targetId() const;
- QOpcUa::QExpandedNodeId &targetIdRef();
- void setTargetId(const QOpcUa::QExpandedNodeId &targetId);
-
- quint32 remainingPathIndex() const;
- void setRemainingPathIndex(quint32 remainingPathIndex);
-
- bool isFullyResolved() const;
-
-
-private:
- QSharedDataPointer<QOpcUa::QBrowsePathTargetData> data;
-};
-
-// OPC-UA part 4, 7.4.4.2
-class QElementOperandData;
-class Q_OPCUA_EXPORT QElementOperand
-{
-public:
- QElementOperand();
- QElementOperand(const QElementOperand &);
- QElementOperand(quint32 index);
- QElementOperand &operator=(const QElementOperand &);
- operator QVariant() const;
- ~QElementOperand();
-
- quint32 index() const;
- void setIndex(quint32 index);
-
-private:
- QSharedDataPointer<QOpcUa::QElementOperandData> data;
-};
-
-// OPC-UA part 4, 7.4.4.3
-class QLiteralOperandData;
-class Q_OPCUA_EXPORT QLiteralOperand
-{
-public:
- QLiteralOperand();
- QLiteralOperand(const QOpcUa::QLiteralOperand &);
- QLiteralOperand(const QVariant &value, QOpcUa::Types type = QOpcUa::Types::Undefined);
- QLiteralOperand &operator=(const QOpcUa::QLiteralOperand &);
- operator QVariant() const;
- ~QLiteralOperand();
-
- QVariant value() const;
- void setValue(const QVariant &value);
-
- QOpcUa::Types type() const;
- void setType(QOpcUa::Types type);
-
-private:
- QSharedDataPointer<QOpcUa::QLiteralOperandData> data;
-};
-
-// OPC-UA part 4, 7.4.4.5
-class QSimpleAttributeOperandData;
-class Q_OPCUA_EXPORT QSimpleAttributeOperand
-{
-public:
- QSimpleAttributeOperand();
- QSimpleAttributeOperand(const QOpcUa::QSimpleAttributeOperand &);
- QSimpleAttributeOperand(const QString &name, quint16 namespaceIndex = 0,
- const QString &typeId = QStringLiteral("ns=0;i=2041"), // BaseEventType
- QOpcUa::NodeAttribute attributeId = QOpcUa::NodeAttribute::Value);
- QSimpleAttributeOperand(QOpcUa::NodeAttribute attributeId,
- const QString &typeId = QStringLiteral("ns=0;i=2041")); // BaseEventType
- QSimpleAttributeOperand &operator=(const QOpcUa::QSimpleAttributeOperand &);
- bool operator==(const QSimpleAttributeOperand &rhs) const;
- operator QVariant() const;
- ~QSimpleAttributeOperand();
-
- QString typeId() const;
- void setTypeId(const QString &typeId);
-
- QVector<QOpcUa::QQualifiedName> browsePath() const;
- QVector<QOpcUa::QQualifiedName> &browsePathRef();
- void setBrowsePath(const QVector<QOpcUa::QQualifiedName> &browsePath);
-
- QOpcUa::NodeAttribute attributeId() const;
- void setAttributeId(QOpcUa::NodeAttribute attributeId);
-
- QString indexRange() const;
- void setIndexRange(const QString &indexRange);
-
-private:
- QSharedDataPointer<QOpcUa::QSimpleAttributeOperandData> data;
-};
-
-// OPC-UA part 4, 7.4.4.4
-class QAttributeOperandData;
-class Q_OPCUA_EXPORT QAttributeOperand
-{
-public:
- QAttributeOperand();
- QAttributeOperand(const QOpcUa::QAttributeOperand &);
- QAttributeOperand &operator=(const QOpcUa::QAttributeOperand &);
- operator QVariant() const;
- ~QAttributeOperand();
-
- QString nodeId() const;
- void setNodeId(const QString &nodeId);
-
- QString alias() const;
- void setAlias(const QString &alias);
-
- QVector<QOpcUa::QRelativePathElement> browsePath() const;
- QVector<QOpcUa::QRelativePathElement> &browsePathRef();
- void setBrowsePath(const QVector<QOpcUa::QRelativePathElement> &browsePath);
-
- QOpcUa::NodeAttribute attributeId() const;
- void setAttributeId(QOpcUa::NodeAttribute attributeId);
-
- QString indexRange() const;
- void setIndexRange(const QString &indexRange);
-
-private:
- QSharedDataPointer<QOpcUa::QAttributeOperandData> data;
-};
-
-class QContentFilterElementData;
-class Q_OPCUA_EXPORT QContentFilterElement
-{
-public:
- QContentFilterElement();
- QContentFilterElement(const QContentFilterElement &);
- QContentFilterElement &operator=(const QContentFilterElement &);
- bool operator==(const QContentFilterElement &rhs) const;
- operator QVariant() const;
- ~QContentFilterElement();
-
- // Specified in OPC-UA part 4, Tables 115 and 116
- enum FilterOperator : quint32 {
- Equals = 0,
- IsNull = 1,
- GreaterThan = 2,
- LessThan = 3,
- GreaterThanOrEqual = 4,
- LessThanOrEqual = 5,
- Like = 6,
- Not = 7,
- Between = 8,
- InList = 9,
- And = 10,
- Or = 11,
- Cast = 12,
- InView = 13,
- OfType = 14,
- RelatedTo = 15,
- BitwiseAnd = 16,
- BitwiseOr = 17
- };
-
- QContentFilterElement &operator<<(FilterOperator op);
- QContentFilterElement &operator<<(const QSimpleAttributeOperand &op);
- QContentFilterElement &operator<<(const QAttributeOperand &op);
- QContentFilterElement &operator<<(const QLiteralOperand &op);
- QContentFilterElement &operator<<(const QElementOperand &op);
-
-
- QOpcUa::QContentFilterElement::FilterOperator filterOperator() const;
- void setFilterOperator(QOpcUa::QContentFilterElement::FilterOperator filterOperator);
-
- QVector<QVariant> filterOperands() const;
- QVector<QVariant> &filterOperandsRef();
- void setFilterOperands(const QVector<QVariant> &filterOperands);
-
-private:
- QSharedDataPointer<QOpcUa::QContentFilterElementData> data;
-};
-
-class QContentFilterElementResultData;
-class Q_OPCUA_EXPORT QContentFilterElementResult
-{
-public:
- QContentFilterElementResult();
- QContentFilterElementResult(const QOpcUa::QContentFilterElementResult &);
- QContentFilterElementResult &operator=(const QOpcUa::QContentFilterElementResult &);
- ~QContentFilterElementResult();
-
- QOpcUa::UaStatusCode statusCode() const;
- void setStatusCode(QOpcUa::UaStatusCode statusCode);
-
- QVector<QOpcUa::UaStatusCode> operandStatusCodes() const;
- QVector<QOpcUa::UaStatusCode> &operandStatusCodesRef();
- void setOperandStatusCodes(const QVector<QOpcUa::UaStatusCode> &operandStatusCodes);
-
-private:
- QSharedDataPointer<QOpcUa::QContentFilterElementResultData> data;
-};
-
-class QEventFilterResultData;
-class Q_OPCUA_EXPORT QEventFilterResult
-{
-public:
- QEventFilterResult();
- QEventFilterResult(const QOpcUa::QEventFilterResult &);
- QEventFilterResult &operator=(const QOpcUa::QEventFilterResult &);
- ~QEventFilterResult();
-
- bool isGood() const;
-
- QVector<QOpcUa::UaStatusCode> selectClauseResults() const;
- QVector<QOpcUa::UaStatusCode> &selectClauseResultsRef();
- void setSelectClauseResults(const QVector<QOpcUa::UaStatusCode> &selectClausesResult);
-
- QVector<QOpcUa::QContentFilterElementResult> whereClauseResults() const;
- QVector<QOpcUa::QContentFilterElementResult> &whereClauseResultsRef();
- void setWhereClauseResults(const QVector<QOpcUa::QContentFilterElementResult> &whereClauseResult);
-
-private:
- QSharedDataPointer<QEventFilterResultData> data;
-};
-
-class QUserTokenPolicyData;
-class Q_OPCUA_EXPORT QUserTokenPolicy
-{
-public:
- QUserTokenPolicy();
- QUserTokenPolicy(const QUserTokenPolicy &);
- QUserTokenPolicy &operator=(const QUserTokenPolicy &);
- ~QUserTokenPolicy();
-
- enum TokenType {
- Anonymous = 0,
- Username = 1,
- Certificate = 2,
- IssuedToken = 3
- };
-
- QString policyId() const;
- void setPolicyId(const QString &policyId);
-
- TokenType tokenType() const;
- void setTokenType(QOpcUa::QUserTokenPolicy::TokenType tokenType);
-
- QString issuedTokenType() const;
- void setIssuedTokenType(const QString &issuedTokenType);
-
- QString issuerEndpointUrl() const;
- void setIssuerEndpointUrl(const QString &issuerEndpointUrl);
-
- QString securityPolicyUri() const;
- void setSecurityPolicyUri(const QString &securityPolicyUri);
-
-private:
- QSharedDataPointer<QUserTokenPolicyData> data;
-};
-
-class QApplicationDescriptionData;
-class Q_OPCUA_EXPORT QApplicationDescription
-{
-public:
- QApplicationDescription();
- QApplicationDescription(const QApplicationDescription &);
- QApplicationDescription &operator=(const QApplicationDescription &);
- ~QApplicationDescription();
-
- enum ApplicationType {
- Server = 0,
- Client = 1,
- ClientAndServer = 2,
- DiscoveryServer = 3
- };
-
- QString applicationUri() const;
- void setApplicationUri(const QString &applicationUri);
-
- QString productUri() const;
- void setProductUri(const QString &productUri);
-
- QOpcUa::QLocalizedText applicationName() const;
- void setApplicationName(const QOpcUa::QLocalizedText &applicationName);
-
- QOpcUa::QApplicationDescription::ApplicationType applicationType() const;
- void setApplicationType(QOpcUa::QApplicationDescription::ApplicationType applicationType);
-
- QString gatewayServerUri() const;
- void setGatewayServerUri(const QString &gatewayServerUri);
-
- QString discoveryProfileUri() const;
- void setDiscoveryProfileUri(const QString &discoveryProfileUri);
-
- QVector<QString> discoveryUrls() const;
- QVector<QString> &discoveryUrlsRef();
- void setDiscoveryUrls(const QVector<QString> &discoveryUrls);
-
-private:
- QSharedDataPointer<QApplicationDescriptionData> data;
-};
-
-class QEndpointDescriptionData;
-class Q_OPCUA_EXPORT QEndpointDescription
-{
-public:
- QEndpointDescription();
- QEndpointDescription(const QEndpointDescription &);
- QEndpointDescription &operator=(const QEndpointDescription &);
- ~QEndpointDescription();
-
- enum MessageSecurityMode {
- Invalid = 0,
- None = 1,
- Sign = 2,
- SignAndEncrypt = 3
- };
-
- QString endpointUrl() const;
- void setEndpointUrl(const QString &endpointUrl);
-
- QOpcUa::QApplicationDescription server() const;
- QOpcUa::QApplicationDescription &serverRef();
- void setServer(const QOpcUa::QApplicationDescription &server);
-
- QByteArray serverCertificate() const;
- void setServerCertificate(const QByteArray &serverCertificate);
-
- QOpcUa::QEndpointDescription::MessageSecurityMode securityMode() const;
- void setSecurityMode(QOpcUa::QEndpointDescription::MessageSecurityMode securityMode);
-
- QString securityPolicyUri() const;
- void setSecurityPolicyUri(const QString &securityPolicyUri);
-
- QVector<QOpcUa::QUserTokenPolicy> userIdentityTokens() const;
- QVector<QOpcUa::QUserTokenPolicy> &userIdentityTokensRef();
- void setUserIdentityTokens(const QVector<QOpcUa::QUserTokenPolicy> &userIdentityTokens);
-
- QString transportProfileUri() const;
- void setTransportProfileUri(const QString &transportProfileUri);
-
- quint8 securityLevel() const;
- void setSecurityLevel(quint8 securityLevel);
-
-private:
- QSharedDataPointer<QEndpointDescriptionData> data;
-};
-
-class QArgumentData;
-class Q_OPCUA_EXPORT QArgument
-{
-public:
- QArgument();
- QArgument(const QArgument &rhs);
- QArgument(const QString &name, const QString &dataTypeId, qint32 valueRank,
- const QVector<quint32> &arrayDimensions, const QOpcUa::QLocalizedText &description);
- QArgument &operator=(const QArgument &);
- bool operator==(const QArgument &other) const;
- operator QVariant() const;
- ~QArgument();
-
- QString name() const;
- void setName(const QString &name);
-
- QString dataTypeId() const;
- void setDataTypeId(const QString &dataTypeId);
-
- qint32 valueRank() const;
- void setValueRank(qint32 valueRank);
-
- QVector<quint32> arrayDimensions() const;
- QVector<quint32> &arrayDimensionsRef();
- void setArrayDimensions(const QVector<quint32> &arrayDimensions);
-
- QOpcUa::QLocalizedText description() const;
- void setDescription(const QOpcUa::QLocalizedText &description);
-
-private:
- QSharedDataPointer<QOpcUa::QArgumentData> data;
-};
-
-class QExtensionObjectData;
-class Q_OPCUA_EXPORT QExtensionObject
-{
-public:
- enum Encoding {
- NoBody = 0,
- ByteString = 1,
- Xml = 2
- };
-
- QExtensionObject();
- QExtensionObject(const QOpcUa::QExtensionObject &);
- ~QExtensionObject();
- QExtensionObject &operator=(const QOpcUa::QExtensionObject &);
- bool operator==(const QOpcUa::QExtensionObject &rhs) const;
- operator QVariant() const;
-
- QString encodingTypeId() const;
- void setEncodingTypeId(const QString &encodingTypeId);
-
- QByteArray encodedBody() const;
- QByteArray &encodedBodyRef();
- void setEncodedBody(const QByteArray &encodedBody);
-
- QOpcUa::QExtensionObject::Encoding encoding() const;
- void setEncoding(QOpcUa::QExtensionObject::Encoding encoding);
-
-private:
- QSharedDataPointer<QOpcUa::QExtensionObjectData> data;
-};
-
-class QMultiDimensionalArrayData;
-class Q_OPCUA_EXPORT QMultiDimensionalArray
-{
-public:
- QMultiDimensionalArray();
- QMultiDimensionalArray(const QOpcUa::QMultiDimensionalArray &other);
- QMultiDimensionalArray &operator=(const QOpcUa::QMultiDimensionalArray &rhs);
- QMultiDimensionalArray(const QVariantList &valueArray, const QVector<quint32> &arrayDimensions);
- QMultiDimensionalArray(const QVector<quint32> &arrayDimensions);
- ~QMultiDimensionalArray();
-
- QVariantList valueArray() const;
- QVariantList &valueArrayRef();
- void setValueArray(const QVariantList &valueArray);
-
- int arrayIndex(const QVector<quint32> &indices) const;
- QVariant value(const QVector<quint32> &indices) const;
- bool setValue(const QVector<quint32> &indices, const QVariant &value);
-
- bool isValid() const;
-
- QVector<quint32> arrayDimensions() const;
- void setArrayDimensions(const QVector<quint32> &arrayDimensions);
-
- bool operator==(const QOpcUa::QMultiDimensionalArray &other) const;
-
- operator QVariant() const;
-
-private:
- QSharedDataPointer<QOpcUa::QMultiDimensionalArrayData> data;
-};
-
+Q_OPCUA_EXPORT QOpcUa::Types metaTypeToQOpcUaType(QMetaType::Type type);
+Q_OPCUA_EXPORT QOpcUa::Types opcUaDataTypeToQOpcUaType(const QString &type);
}
Q_DECLARE_TYPEINFO(QOpcUa::Types, Q_PRIMITIVE_TYPE);
@@ -1209,8 +516,6 @@ QT_END_NAMESPACE
Q_DECLARE_METATYPE(QOpcUa::Types)
Q_DECLARE_METATYPE(QOpcUa::TypedVariant)
-Q_DECLARE_METATYPE(QOpcUa::QQualifiedName)
-Q_DECLARE_METATYPE(QOpcUa::QLocalizedText)
Q_DECLARE_METATYPE(QOpcUa::UaStatusCode)
Q_DECLARE_METATYPE(QOpcUa::ErrorCategory)
Q_DECLARE_METATYPE(QOpcUa::NodeClass)
@@ -1224,27 +529,5 @@ Q_DECLARE_METATYPE(QOpcUa::EventNotifierBit)
Q_DECLARE_METATYPE(QOpcUa::EventNotifier)
Q_DECLARE_METATYPE(QOpcUa::ReferenceTypeId)
Q_DECLARE_METATYPE(QOpcUa::NodeClasses)
-Q_DECLARE_METATYPE(QOpcUa::QRange)
-Q_DECLARE_METATYPE(QOpcUa::QEUInformation)
-Q_DECLARE_METATYPE(QOpcUa::QComplexNumber)
-Q_DECLARE_METATYPE(QOpcUa::QDoubleComplexNumber)
-Q_DECLARE_METATYPE(QOpcUa::QAxisInformation)
-Q_DECLARE_METATYPE(QOpcUa::QXValue)
-Q_DECLARE_METATYPE(QOpcUa::QExpandedNodeId)
-Q_DECLARE_METATYPE(QOpcUa::QRelativePathElement)
-Q_DECLARE_METATYPE(QOpcUa::QBrowsePathTarget)
-Q_DECLARE_METATYPE(QOpcUa::QContentFilterElement)
-Q_DECLARE_METATYPE(QOpcUa::QElementOperand)
-Q_DECLARE_METATYPE(QOpcUa::QLiteralOperand)
-Q_DECLARE_METATYPE(QOpcUa::QSimpleAttributeOperand)
-Q_DECLARE_METATYPE(QOpcUa::QAttributeOperand)
-Q_DECLARE_METATYPE(QOpcUa::QContentFilterElementResult)
-Q_DECLARE_METATYPE(QOpcUa::QEventFilterResult)
-Q_DECLARE_METATYPE(QOpcUa::QUserTokenPolicy)
-Q_DECLARE_METATYPE(QOpcUa::QApplicationDescription)
-Q_DECLARE_METATYPE(QOpcUa::QEndpointDescription)
-Q_DECLARE_METATYPE(QOpcUa::QArgument)
-Q_DECLARE_METATYPE(QOpcUa::QExtensionObject)
-Q_DECLARE_METATYPE(QOpcUa::QMultiDimensionalArray)
#endif // QOPCUATYPE
diff --git a/src/opcua/client/qopcuausertokenpolicy.cpp b/src/opcua/client/qopcuausertokenpolicy.cpp
new file mode 100644
index 0000000..4f36c90
--- /dev/null
+++ b/src/opcua/client/qopcuausertokenpolicy.cpp
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuausertokenpolicy.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaUserTokenPolicy
+ \inmodule QtOpcUa
+ \brief The OPC UA UserTokenPolicy.
+
+ The user token policy contains information about an user token accepted by the server.
+*/
+
+/*!
+ \qmltype UserTokenPolicy
+ \inqmlmodule QtOpcUa
+ \brief The OPC UA ApplicationDescription.
+ \since QtOpcUa 5.13
+
+ The user token policy contains information about an user token accepted by the server.
+*/
+
+/*!
+ \enum QOpcUaUserTokenPolicy::TokenType
+
+ \value Anonymous No token required.
+ \value Username Username and password are required.
+ \value Certificate A client certificate is required.
+ \value IssuedToken Any Web Services Security (WS-Security) defined token.
+*/
+
+/*!
+ \qmlproperty enumeration UserTokenPolicy::TokenType
+
+ \value Anonymous No token required.
+ \value Username Username and password are required.
+ \value Certificate A client certificate is required.
+ \value IssuedToken Any Web Services Security (WS-Security) defined token.
+*/
+
+class QOpcUaUserTokenPolicyData : public QSharedData
+{
+public:
+ QString policyId;
+ QOpcUaUserTokenPolicy::TokenType tokenType{QOpcUaUserTokenPolicy::TokenType::Anonymous};
+ QString issuedTokenType;
+ QString issuerEndpointUrl;
+ QString securityPolicy;
+};
+
+QOpcUaUserTokenPolicy::QOpcUaUserTokenPolicy()
+ : data(new QOpcUaUserTokenPolicyData)
+{
+}
+
+/*!
+ Constructs an user token policy from \a rhs.
+*/
+QOpcUaUserTokenPolicy::QOpcUaUserTokenPolicy(const QOpcUaUserTokenPolicy &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Sets the values from \a rhs in this user token policy.
+*/
+QOpcUaUserTokenPolicy &QOpcUaUserTokenPolicy::operator=(const QOpcUaUserTokenPolicy &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns \c true if this user token policy has the same value as \a rhs.
+*/
+bool QOpcUaUserTokenPolicy::operator==(const QOpcUaUserTokenPolicy &rhs) const
+{
+ return rhs.policyId() == policyId() &&
+ rhs.tokenType() == tokenType() &&
+ rhs.issuedTokenType() == issuedTokenType() &&
+ rhs.issuerEndpointUrl() == issuerEndpointUrl() &&
+ rhs.securityPolicy() == securityPolicy();
+}
+
+QOpcUaUserTokenPolicy::~QOpcUaUserTokenPolicy()
+{
+}
+
+/*!
+ Returns the URI of the security policy required when encrypting or signing the token for ActivateSession.
+*/
+QString QOpcUaUserTokenPolicy::securityPolicy() const
+{
+ return data->securityPolicy;
+}
+
+/*!
+ Sets the URI of the security policy to \a securityPolicy.
+*/
+void QOpcUaUserTokenPolicy::setSecurityPolicy(const QString &securityPolicy)
+{
+ data->securityPolicy = securityPolicy;
+}
+
+/*!
+ Returns the URL of a token issuing service.
+*/
+QString QOpcUaUserTokenPolicy::issuerEndpointUrl() const
+{
+ return data->issuerEndpointUrl;
+}
+
+/*!
+ Sets the URL of the token issuing service to \a issuerEndpointUrl.
+*/
+void QOpcUaUserTokenPolicy::setIssuerEndpointUrl(const QString &issuerEndpointUrl)
+{
+ data->issuerEndpointUrl = issuerEndpointUrl;
+}
+
+/*!
+ Returns the URI for the token type.
+*/
+QString QOpcUaUserTokenPolicy::issuedTokenType() const
+{
+ return data->issuedTokenType;
+}
+
+/*!
+ Sets the URI for the token type to \a issuedTokenType.
+*/
+void QOpcUaUserTokenPolicy::setIssuedTokenType(const QString &issuedTokenType)
+{
+ data->issuedTokenType = issuedTokenType;
+}
+
+/*!
+ Returns the type of the required user identity token.
+*/
+QOpcUaUserTokenPolicy::TokenType QOpcUaUserTokenPolicy::tokenType() const
+{
+ return data->tokenType;
+}
+
+/*!
+ Sets the type of the required user identity token to \a tokenType.
+*/
+void QOpcUaUserTokenPolicy::setTokenType(TokenType tokenType)
+{
+ data->tokenType = tokenType;
+}
+
+/*!
+ Returns a server assigned identifier for this policy.
+*/
+QString QOpcUaUserTokenPolicy::policyId() const
+{
+ return data->policyId;
+}
+
+/*!
+ Sets the identifier for this policy to \a policyId.
+*/
+void QOpcUaUserTokenPolicy::setPolicyId(const QString &policyId)
+{
+ data->policyId = policyId;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuausertokenpolicy.h b/src/opcua/client/qopcuausertokenpolicy.h
new file mode 100644
index 0000000..f48c629
--- /dev/null
+++ b/src/opcua/client/qopcuausertokenpolicy.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAUSERTOKENPOLICY_H
+#define QOPCUAUSERTOKENPOLICY_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qmetatype.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaUserTokenPolicyData;
+class Q_OPCUA_EXPORT QOpcUaUserTokenPolicy
+{
+ Q_GADGET
+public:
+ QOpcUaUserTokenPolicy();
+ QOpcUaUserTokenPolicy(const QOpcUaUserTokenPolicy &);
+ QOpcUaUserTokenPolicy &operator=(const QOpcUaUserTokenPolicy &);
+ bool operator==(const QOpcUaUserTokenPolicy &) const;
+ ~QOpcUaUserTokenPolicy();
+
+ enum TokenType {
+ Anonymous = 0,
+ Username = 1,
+ Certificate = 2,
+ IssuedToken = 3
+ };
+ Q_ENUMS(TokenType)
+
+ QString policyId() const;
+ void setPolicyId(const QString &policyId);
+
+ QOpcUaUserTokenPolicy::TokenType tokenType() const;
+ void setTokenType(QOpcUaUserTokenPolicy::TokenType tokenType);
+
+ QString issuedTokenType() const;
+ void setIssuedTokenType(const QString &issuedTokenType);
+
+ QString issuerEndpointUrl() const;
+ void setIssuerEndpointUrl(const QString &issuerEndpointUrl);
+
+ QString securityPolicy() const;
+ void setSecurityPolicy(const QString &securityPolicy);
+
+private:
+ QSharedDataPointer<QOpcUaUserTokenPolicyData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaUserTokenPolicy)
+
+#endif // QOPCUAUSERTOKENPOLICY_H
diff --git a/src/opcua/client/qopcuawriteitem.cpp b/src/opcua/client/qopcuawriteitem.cpp
index 325e655..95f32a5 100644
--- a/src/opcua/client/qopcuawriteitem.cpp
+++ b/src/opcua/client/qopcuawriteitem.cpp
@@ -47,9 +47,9 @@ QT_BEGIN_NAMESPACE
attribute of a node on the server. This class contains the necessary information for the backend to make
a write request to the server.
- One or multiple objects of this class make up the request of a \l QOpcUaClient::batchWrite() operation.
+ One or multiple objects of this class make up the request of a \l QOpcUaClient::writeNodeAttributes() operation.
- \sa QOpcUaClient::batchWrite() QOpcUaWriteResult
+ \sa QOpcUaClient::writeNodeAttributes() QOpcUaWriteResult
*/
class QOpcUaWriteItemData : public QSharedData
{
diff --git a/src/opcua/client/qopcuawriteresult.cpp b/src/opcua/client/qopcuawriteresult.cpp
index 89327d1..39461ac 100644
--- a/src/opcua/client/qopcuawriteresult.cpp
+++ b/src/opcua/client/qopcuawriteresult.cpp
@@ -49,11 +49,11 @@ QT_BEGIN_NAMESPACE
In addition to the status code returned by the server, this class also contains the node id, the attribute and the index
range from the request to enable a client to match the result with a request.
- Objects of this class are returned in the \l QOpcUaClient::batchWriteFinished()
- signal and contain the result of a write operation that was part of a \l QOpcUaClient::batchWrite()
+ Objects of this class are returned in the \l QOpcUaClient::writeNodeAttributesFinished()
+ signal and contain the result of a write operation that was part of a \l QOpcUaClient::writeNodeAttributes()
request.
- \sa QOpcUaClient::batchWrite() QOpcUaClient::batchWriteFinished() QOpcUaWriteItem
+ \sa QOpcUaClient::writeNodeAttributes() QOpcUaClient::writeNodeAttributesFinished() QOpcUaWriteItem
*/
class QOpcUaWriteResultData : public QSharedData
{
diff --git a/src/opcua/client/qopcuawriteresult.h b/src/opcua/client/qopcuawriteresult.h
index 095dbdb..cc9d211 100644
--- a/src/opcua/client/qopcuawriteresult.h
+++ b/src/opcua/client/qopcuawriteresult.h
@@ -39,6 +39,8 @@
#include <QtOpcUa/qopcuatype.h>
+#include <QtCore/qshareddata.h>
+
QT_BEGIN_NAMESPACE
class QOpcUaWriteResultData;
diff --git a/src/opcua/client/qopcuaxvalue.cpp b/src/opcua/client/qopcuaxvalue.cpp
new file mode 100644
index 0000000..2d97c6f
--- /dev/null
+++ b/src/opcua/client/qopcuaxvalue.cpp
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuaxvalue.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaXValue
+ \inmodule QtOpcUa
+ \brief The OPC UA XVType.
+
+ This is the Qt OPC UA representation for the OPC UA XVType type defined in OPC-UA part 8, 5.6.8.
+ This type is used to position values of float precision on an axis with double precision.
+*/
+
+class QOpcUaXValueData : public QSharedData
+{
+public:
+ double x{0};
+ float value{0};
+};
+
+QOpcUaXValue::QOpcUaXValue()
+ : data(new QOpcUaXValueData)
+{
+}
+
+/*!
+ Constructs an XValue from \a rhs.
+*/
+QOpcUaXValue::QOpcUaXValue(const QOpcUaXValue &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Constructs an XValue with position \a x and value \a value.
+*/
+QOpcUaXValue::QOpcUaXValue(double x, float value)
+ : data(new QOpcUaXValueData)
+{
+ data->x = x;
+ data->value = value;
+}
+
+/*!
+ Sets the values from \a rhs in this XValue.
+*/
+QOpcUaXValue &QOpcUaXValue::operator=(const QOpcUaXValue &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns \c true if this XValue has the same value as \a rhs.
+*/
+bool QOpcUaXValue::operator==(const QOpcUaXValue &rhs) const
+{
+ return qFloatDistance(data->x, rhs.x()) == 0 &&
+ qFloatDistance(data->value, rhs.value()) == 0;
+}
+
+/*!
+ Converts this XValue to \l QVariant.
+*/
+QOpcUaXValue::operator QVariant() const
+{
+ return QVariant::fromValue(*this);
+}
+
+QOpcUaXValue::~QOpcUaXValue()
+{
+}
+
+/*!
+ Returns the value for position x.
+*/
+float QOpcUaXValue::value() const
+{
+ return data->value;
+}
+
+/*!
+ Sets the value for position x to \a value.
+*/
+void QOpcUaXValue::setValue(float value)
+{
+ data->value = value;
+}
+
+/*!
+ Returns the position of the value on the axis.
+*/
+double QOpcUaXValue::x() const
+{
+ return data->x;
+}
+
+/*!
+ Sets the position of the value on the axis to \a x.
+*/
+void QOpcUaXValue::setX(double x)
+{
+ data->x = x;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/client/qopcuaxvalue.h b/src/opcua/client/qopcuaxvalue.h
new file mode 100644
index 0000000..1ab5310
--- /dev/null
+++ b/src/opcua/client/qopcuaxvalue.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAXVALUE_H
+#define QOPCUAXVALUE_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaXValueData;
+class Q_OPCUA_EXPORT QOpcUaXValue
+{
+public:
+ QOpcUaXValue();
+ QOpcUaXValue(const QOpcUaXValue &);
+ QOpcUaXValue(double x, float value);
+ QOpcUaXValue &operator=(const QOpcUaXValue &);
+ bool operator==(const QOpcUaXValue &rhs) const;
+ operator QVariant() const;
+ ~QOpcUaXValue();
+
+ double x() const;
+ void setX(double x);
+
+ float value() const;
+ void setValue(float value);
+
+private:
+ QSharedDataPointer<QOpcUaXValueData> data;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QOpcUaXValue)
+
+#endif // QOPCUAXVALUE_H
diff --git a/src/opcua/configure.json b/src/opcua/configure.json
index a2b375a..f08ded5 100644
--- a/src/opcua/configure.json
+++ b/src/opcua/configure.json
@@ -39,7 +39,7 @@
"release": " -luaclientcpp -luabasecpp -luastack -luapkicpp -lxmlparsercpp"
},
"libs": "-lCrypt32 -lOle32 -lOleAut32 -lws2_32 -llibeay32 -llibxml2",
- "condition": "config.win32 && var.QT_EDITION != 'OpenSource'"
+ "condition": "config.win32"
},
{
"type": "uacpp",
@@ -48,7 +48,16 @@
"release": "-luaclientcpp -luabasecpp -luastack -luapkicpp -lxmlparsercpp"
},
"libs": "-lcrypto -lssl -lxml2",
- "condition": "!config.win32 && var.QT_EDITION != 'OpenSource'"
+ "condition": "!config.win32"
+ }
+ ]
+ },
+ "mbedtls": {
+ "label": "mbedtls",
+ "test": "mbedtls",
+ "sources": [
+ {
+ "libs": "-lmbedx509 -lmbedcrypto"
}
]
}
@@ -71,6 +80,11 @@
"condition": "libs.uacpp",
"output": [ "privateFeature" ]
},
+ "mbedtls": {
+ "label": "mbedtls",
+ "condition": "libs.mbedtls",
+ "output": [ "privateFeature" ]
+ },
"ns0idnames": {
"label": "Support for namespace 0 NodeId names",
"purpose": "Provides names for the QOpcUa::NodeIds::Namespace0 enum.",
@@ -87,7 +101,7 @@
"summary": [
{
"section": "Qt Opcua",
- "entries": [ "open62541", "uacpp", "ns0idnames", "ns0idgenerator" ]
+ "entries": [ "open62541", "uacpp", "ns0idnames", "ns0idgenerator", "mbedtls" ]
}
]
}
diff --git a/src/opcua/configure.pri b/src/opcua/configure.pri
index cc53e43..39b6e2d 100644
--- a/src/opcua/configure.pri
+++ b/src/opcua/configure.pri
@@ -2,6 +2,16 @@ defineTest(qtConfLibrary_uacpp) {
input = $$eval($${2}.alias)
prefix = $$eval(config.input.$${input}.prefix)
+ inc = $$eval(config.input.$${input}.incdir)
+ isEmpty(inc):!isEmpty(prefix): \
+ inc = $${prefix}/include
+ !isEmpty(inc) {
+ config.input.$${input}.incdir += \
+ $$inc/uabasecpp $$inc/uaclientcpp $$inc/uastack $$inc/uapkicpp
+ } else {
+ qtLog("No UACPP_PREFIX and no UACPP_INCDIR specified; relying on global include paths.")
+ }
+
# The Windows SDK ships its dependencies and locates the libraries outside of lib
win32 {
lessThan(QMAKE_MSC_VER, 1900) {
@@ -13,6 +23,9 @@ defineTest(qtConfLibrary_uacpp) {
contains(QMAKE_TARGET.arch, x86_64): archdir = win64
else: archdir = win32
+ config.input.$${input}.incdir += \
+ $${prefix}/third-party/$${archdir}/vs2015/openssl/inc32
+
config.input.$${input}.libdir += \
$${prefix}/third-party/$${archdir}/vs2015/openssl/out32dll \
$${prefix}/third-party/$${archdir}/vs2015/libxml2/out32dll
@@ -21,16 +34,6 @@ defineTest(qtConfLibrary_uacpp) {
}
}
- inc = $$eval(config.input.$${input}.incdir)
- isEmpty(inc):!isEmpty(prefix): \
- inc = $${prefix}/include
- !isEmpty(inc) {
- config.input.$${input}.incdir += \
- $$inc/uabasecpp $$inc/uaclientcpp $$inc/uastack $$inc/uapkicpp
- } else {
- qtLog("No UACPP_PREFIX and no UACPP_INCDIR specified; relying on global include paths.")
- }
-
!qtConfLibrary_inline($$1, $$2): \
return(false)
return(true)
diff --git a/src/opcua/core/qopcuaprovider.cpp b/src/opcua/core/qopcuaprovider.cpp
index ecf6e3a..f3dc589 100644
--- a/src/opcua/core/qopcuaprovider.cpp
+++ b/src/opcua/core/qopcuaprovider.cpp
@@ -39,7 +39,22 @@
#include <QtOpcUa/qopcuaclient.h>
#include <QtOpcUa/qopcuanode.h>
#include <QtOpcUa/qopcuatype.h>
+#include <QtOpcUa/qopcuaapplicationidentity.h>
+#include <QtOpcUa/qopcuapkiconfiguration.h>
#include <private/qopcuanodeimpl_p.h>
+#include <QtOpcUa/qopcuaqualifiedname.h>
+#include <QtOpcUa/qopcuarange.h>
+#include <QtOpcUa/qopcuaeuinformation.h>
+#include <QtOpcUa/qopcuacomplexnumber.h>
+#include <QtOpcUa/qopcuadoublecomplexnumber.h>
+#include <QtOpcUa/qopcuaaxisinformation.h>
+#include <QtOpcUa/qopcuaxvalue.h>
+#include <QtOpcUa/qopcuaargument.h>
+#include <QtOpcUa/qopcuaextensionobject.h>
+#include <QtOpcUa/qopcuaendpointdescription.h>
+#include <QtOpcUa/qopcuaexpandednodeid.h>
+#include <QtOpcUa/qopcuarelativepathelement.h>
+#include <QtOpcUa/qopcuabrowsepathtarget.h>
#include <private/qfactoryloader_p.h>
#include <QtCore/qjsonarray.h>
@@ -49,6 +64,7 @@
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(QT_OPCUA, "qt.opcua")
+Q_LOGGING_CATEGORY(QT_OPCUA_SECURITY, "qt.opcua.security")
/*!
\class QOpcUaProvider
@@ -126,7 +142,7 @@ QOpcUaProvider::QOpcUaProvider(QObject *parent)
qRegisterMetaType<QOpcUa::UaStatusCode>();
qRegisterMetaType<QOpcUa::NodeClass>();
qRegisterMetaType<QOpcUa::NodeClasses>();
- qRegisterMetaType<QOpcUa::QQualifiedName>();
+ qRegisterMetaType<QOpcUaQualifiedName>();
qRegisterMetaType<QOpcUa::NodeAttribute>();
qRegisterMetaType<QOpcUa::NodeAttributes>();
qRegisterMetaType<QOpcUaNode::AttributeMap>();
@@ -141,21 +157,21 @@ QOpcUaProvider::QOpcUaProvider(QObject *parent)
qRegisterMetaType<QOpcUaReferenceDescription>();
qRegisterMetaType<QVector<QOpcUaReferenceDescription>>();
qRegisterMetaType<QOpcUa::ReferenceTypeId>();
- qRegisterMetaType<QOpcUa::QRange>();
- qRegisterMetaType<QOpcUa::QEUInformation>();
- qRegisterMetaType<QOpcUa::QComplexNumber>();
- qRegisterMetaType<QOpcUa::QDoubleComplexNumber>();
- qRegisterMetaType<QOpcUa::QAxisInformation>();
- qRegisterMetaType<QOpcUa::QXValue>();
- qRegisterMetaType<QOpcUa::QExpandedNodeId>();
- qRegisterMetaType<QOpcUa::QRelativePathElement>();
- qRegisterMetaType<QVector<QOpcUa::QRelativePathElement>>();
- qRegisterMetaType<QOpcUa::QBrowsePathTarget>();
- qRegisterMetaType<QVector<QOpcUa::QBrowsePathTarget>>();
- qRegisterMetaType<QOpcUa::QEndpointDescription>();
- qRegisterMetaType<QVector<QOpcUa::QEndpointDescription>>();
- qRegisterMetaType<QOpcUa::QArgument>();
- qRegisterMetaType<QOpcUa::QExtensionObject>();
+ qRegisterMetaType<QOpcUaRange>();
+ qRegisterMetaType<QOpcUaEUInformation>();
+ qRegisterMetaType<QOpcUaComplexNumber>();
+ qRegisterMetaType<QOpcUaDoubleComplexNumber>();
+ qRegisterMetaType<QOpcUaAxisInformation>();
+ qRegisterMetaType<QOpcUaXValue>();
+ qRegisterMetaType<QOpcUaExpandedNodeId>();
+ qRegisterMetaType<QOpcUaRelativePathElement>();
+ qRegisterMetaType<QVector<QOpcUaRelativePathElement>>();
+ qRegisterMetaType<QOpcUaBrowsePathTarget>();
+ qRegisterMetaType<QVector<QOpcUaBrowsePathTarget>>();
+ qRegisterMetaType<QOpcUaEndpointDescription>();
+ qRegisterMetaType<QVector<QOpcUaEndpointDescription>>();
+ qRegisterMetaType<QOpcUaArgument>();
+ qRegisterMetaType<QOpcUaExtensionObject>();
qRegisterMetaType<QOpcUaBrowseRequest>();
qRegisterMetaType<QOpcUaReadItem>();
qRegisterMetaType<QOpcUaReadResult>();
@@ -169,7 +185,9 @@ QOpcUaProvider::QOpcUaProvider(QObject *parent)
qRegisterMetaType<QOpcUaAddNodeItem>();
qRegisterMetaType<QOpcUaAddReferenceItem>();
qRegisterMetaType<QOpcUaDeleteReferenceItem>();
- qRegisterMetaType<QVector<QOpcUa::QApplicationDescription>>();
+ qRegisterMetaType<QVector<QOpcUaApplicationDescription>>();
+ qRegisterMetaType<QOpcUaApplicationIdentity>();
+ qRegisterMetaType<QOpcUaPkiConfiguration>();
}
QOpcUaProvider::~QOpcUaProvider()
diff --git a/src/opcua/doc/src/qtopcua.qdoc b/src/opcua/doc/src/qtopcua.qdoc
index e87db19..845efca 100644
--- a/src/opcua/doc/src/qtopcua.qdoc
+++ b/src/opcua/doc/src/qtopcua.qdoc
@@ -80,8 +80,9 @@
\li Unified Automation C++ SDK (UACpp), Commercial
\endlist
- This module is still in development but is available as a technology preview.
- This means it is unstable, likely to change, and provided as a convenience only.
+ The QML API as well as the security related C++ API are still in development but are available as a technology preview.
+ This means those parts are unstable, likely to change, and provided as a convenience only.
+ All functions and classes of the C++ API, which are related to security, state in their documentation if they are technology preview.
\section1 Getting started
@@ -166,7 +167,7 @@
\row
\li Batch read
\li X
- \li
+ \li X
\row
\li Write
\li X
@@ -174,11 +175,11 @@
\row
\li Batch write
\li X
- \li
+ \li X
\row
\li Multidimensional arrays
\li X
- \li
+ \li X
\row
\li Browse
\li X
@@ -210,11 +211,11 @@
\row
\li FindServers
\li X
- \li
+ \li X
\row
\li NodeManagement
\li X
- \li
+ \li X
\endtable
\section1 Data Types
@@ -271,7 +272,7 @@
\li LocalizedText
\li X
\li X
- \li \l QOpcUa::QLocalizedText
+ \li \l QOpcUaLocalizedText
\row
\li DateTime
\li X
@@ -301,7 +302,7 @@
\li QualifiedName
\li X
\li X
- \li \l QOpcUa::QQualifiedName
+ \li \l QOpcUaQualifiedName
\row
\li StatusCode
\li X
@@ -311,47 +312,47 @@
\li Range
\li X
\li X
- \li \l QOpcUa::QRange
+ \li \l QOpcUaRange
\row
\li EUInformation
\li X
\li X
- \li \l QOpcUa::QEUInformation
+ \li \l QOpcUaEUInformation
\row
\li ComplexNumber
\li X
\li X
- \li \l QOpcUa::QComplexNumber
+ \li \l QOpcUaComplexNumber
\row
\li DoubleComplexNumber
\li X
\li X
- \li \l QOpcUa::QDoubleComplexNumber
+ \li \l QOpcUaDoubleComplexNumber
\row
\li AxisInformation
\li X
\li X
- \li \l QOpcUa::QAxisInformation
+ \li \l QOpcUaAxisInformation
\row
\li XV
\li X
\li X
- \li \l QOpcUa::QXValue
+ \li \l QOpcUaXValue
\row
\li Argument
\li X
- \li
- \li QOpcUa::QArgument
+ \li X
+ \li QOpcUaArgument
\row
\li ExpandedNodeId
\li X
\li X
- \li QOpcUa::QExpandedNodeId
+ \li QOpcUaExpandedNodeId
\row
\li ExtensionObject
\li X
- \li
- \li QOpcUa::QExtensionObject
+ \li X
+ \li QOpcUaExtensionObject
\endtable
\section1 Classes and Ownership
@@ -401,7 +402,9 @@
\section2 UA CPP
The UA CPP plugin is available under commercial licenses from \l{The Qt Company}.
- The UA CPP library itself is available under commercial licenses from \l {https://www.unified-automation.com}{Unified Automation}.
+ In addition, it is available under the \l{GNU General Public License, version 3}.
+ The UA CPP library itself is available under commercial licenses from
+ \l {https://www.unified-automation.com}{Unified Automation}.
*/
/*!
@@ -471,6 +474,9 @@
\title Building Qt OPC UA UACPP Plugin
\brief Build instructions for the Qt OPC UA UACPP plugin.
+ See \l {Creating OPC UA Clients with security support} for detailed instructions for setting up the Unified Automation SDK including
+ security extensions.
+
When building at the top level, you have to specify the path to the UACPP SDK:
\code
diff --git a/src/opcua/doc/src/security.qdoc b/src/opcua/doc/src/security.qdoc
new file mode 100644
index 0000000..472ae3c
--- /dev/null
+++ b/src/opcua/doc/src/security.qdoc
@@ -0,0 +1,220 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page security.html
+ \title Creating OPC UA Clients with security support
+ \brief Instructions how to create OPC UA Clients with security support
+
+ One of the core features of OPC UA is the support for security,
+ which means we get cryptographically encrypted and signed protocol,
+ user authentication and authorization support.
+
+ Creating secure connections with Qt OPC UA is currently only supported using the \l {Setting up UACPP SDK} {UACPP backend plugin}.
+
+ To make this work, each application instances (installation of a program)
+ needs to have its own \c {Application Instance Certificate} and the according private key.
+
+ The applications can either generate self-signed certificates on their own, get some from a
+ certificate authority using OPC UA GDS, or simply can be configured with certificates which
+ haven been created manually by the user.
+
+ Because at the moment Qt OPC UA does not support certificate generation or GDS,
+ this tutorial describes how to generate a self-signed OPC UA certificate on the command line
+ using OpenSSL.
+
+ \section2 Create a new Application Certificate
+
+ To be able to generate a correct x509v3 certificate with all required extensions for OPC UA,
+ we need to setup a configuration file with all the necessary information first.
+
+ Remember to change \c subject and \c subjectAltName to match your case.
+
+ It is important to insert the \c ApplicationURI of the application into the \c URI field of \c subjectAltName,
+ and that the hostname of your PC or device is inserted in the \c DNS fields of \c subjectAltName.
+ Alternatively, you can use \c IP field if your device does not support host names and you are working
+ with static IPs.
+ Future versions of Qt OPC UA will be able to generate the certificate for you with correct information.
+ For now, you can create one using the OpenSSL command line tool.
+
+ Example: \c opcuaviewer.config
+ \code
+ [ req ]
+ default_bits = 2048
+ default_md = sha256
+ distinguished_name = subject
+ req_extensions = req_ext
+ x509_extensions = req_ext
+ string_mask = utf8only
+ prompt = no
+
+ [ req_ext ]
+ basicConstraints = critical, CA:FALSE
+ keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyCertSign
+ subjectAltName = URI:urn:foo.com:The%20Qt%20Company:QtOpcUaViewer,DNS:foo.com
+ subjectKeyIdentifier = hash
+ authorityKeyIdentifier=keyid:always,issuer:always
+
+ [ subject ]
+ countryName = DE
+ stateOrProvinceName = Berlin
+ localityName = Berlin
+ organizationName = The Qt Company
+ commonName = QtOpcUaViewer
+ \endcode
+
+ Using this configuration file, OpenSSL is able to create a matching certificate for local use.
+
+ \code
+ # create a self-signed certificate and private key
+ openssl req -new -x509 -config opcuaviewer.config -newkey rsa:2048 -keyout opcuaviewer.key -nodes -outform der -out opcuaviewer.der
+ # install the certificate and key into the application PKI directory
+ mv opcuaviewer.der /path/to/application/pki/own/certs/opcuaviewer.der
+ mv opcuaviewer.key /path/to/application/pki/own/private/opcuaviewer.pem
+ # secure private key file permissions
+ chmod 600 /path/to/application/pki/own/private/opcuaviewer.pem
+ \endcode
+
+ It is important to secure the file permission of the private key, so that only the UA application can read it.
+ For services (daemons), it is recommended to create dedicated unprivileged users accounts for this and make this
+ user the owner of the key. For interactive applications, this key should be individual to the user.
+ For interactive applications, it is also possible to password protect the key. In this case, the user needs to enter
+ the password every time the application is started and loading the key.
+ For this reason, password protected keys are not a good solution for unattended applications, because this would
+ required to store the password in a configuration file.
+
+ You can dump the certificate data using OpenSSL to inspect the contents of the certificate:
+
+ \code
+ openssl x509 -in opcuaviewer.der -text -noout
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ be:aa:41:79:8a:b0:4f:9a
+ Signature Algorithm: sha512WithRSAEncryption
+ Issuer: C = DE, ST = Berlin, L = Berlin, O = The Qt Company, CN = QtOpcUaViewer
+ Validity
+ Not Before: Nov 7 14:38:52 2018 GMT
+ Not After : Dec 7 14:38:52 2018 GMT
+ Subject: C = DE, ST = Berlin, L = Berlin, O = The Qt Company, CN = QtOpcUaViewer
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ [ skipped ]
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ X509v3 Key Usage: critical
+ Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment, Certificate Sign
+ X509v3 Subject Alternative Name:
+ URI:urn:foo.com:The%20Qt%20Company:QtOpcUaViewer, DNS:foo.com
+ X509v3 Subject Key Identifier:
+ B2:E8:5E:34:21:EA:67:CF:61:FC:14:94:18:C1:AD:13:89:83:CA:9B
+ X509v3 Authority Key Identifier:
+ keyid:B2:E8:5E:34:21:EA:67:CF:61:FC:14:94:18:C1:AD:13:89:83:CA:9B
+ DirName:/C=DE/ST=Berlin/L=Berlin/O=The Qt Company/CN=QtOpcUaViewer
+ serial:BE:AA:41:79:8A:B0:4F:9A
+
+ Signature Algorithm: sha512WithRSAEncryption
+ [ skipped ]
+ \endcode
+
+ \section2 Configuring the UA Application
+
+ To make security working with the certificate created in the previous step, it is important to
+
+ \list
+ \li Configure the correct Application Identity
+ \snippet ../../examples/opcua/opcuaviewer/mainwindow.cpp Application Identity
+ \li Configure PKI locations so that the SDK can find the certificate, private key, trust list etc.
+ \snippet ../../examples/opcua/opcuaviewer/mainwindow.cpp PKI Configuration
+ \endlist
+
+ \section2 PKI Folder Layout
+
+ Qt OPC UA uses the following folder layout:
+
+ \table
+ \header
+ \li Folder
+ \li Description
+ \row
+ \li own
+ \li Location to store the application's own certificates.
+ \row
+ \li trusted
+ \li A list of trusted application certificates or trusted CA certificates.
+ \row
+ \li issuer
+ \li A list of certificates for CAs which are not trusted but are needed to
+ check signatures on certificates.
+ \row
+ \li rejected
+ \li Here the application stores rejected certificates, so that they can later on be trusted by an Administrator.
+ It is important to have a configured maximum number of files here. If this is reached, the oldest
+ file should be deleted first. Without a limit, an attacker could fill the machine's hard disk with
+ invalid connection attempts.
+ \endtable
+
+ Each of the folders \c own, \c trusted, and \c issuers contain the subdirectory structure defined by the following table.
+
+ \table
+ \header
+ \li Subdirectory
+ \li Description
+ \row
+ \li certs
+ \li Contains the DER encoded X.509 v3 certificates. The files shall have a .der file extension.
+ \row
+ \li private
+ \li Contains the private keys. The format of the file may be backend specific.
+ PEM encoded files should have a .pem extension. PKCS#12 encoded files should have a .pfx extension.
+ The root file name shall be the same as the corresponding public key file in the certs directory.
+ This folder only exists inside the \c own folder.
+ \row
+ \li crl
+ \li Contains the DER encoded CRL for any CA certificates found in the certs directories.
+ The files shall have a .crl file extension.
+ \endtable
+
+ \section2 First connection
+
+ When connecting for the first time, the client needs to trust the server certificate.
+
+ The client should display a certificate warning (with cert details) and offer the possibility to save the certificate in its trust list.
+ For an example, see \l{Qt OPC UA Viewer Example}.
+
+ When the client has accepted the server certificate, you can try to connect again. Now the server may reject the client's certificate.
+ This is indicated by the generic error code \c BadSecurityChecksFailed. Server normally store rejected certificates in a special \c rejected folder.
+ Administrator can move these into the trust list to trust clients. This avoids manually copying the client certificate to the server machine.
+
+ As soon as the server has trusted the client, you should be able to connect with security.
+*/
diff --git a/src/opcua/doc/src/uacpp.qdoc b/src/opcua/doc/src/uacpp.qdoc
new file mode 100644
index 0000000..0764f3e
--- /dev/null
+++ b/src/opcua/doc/src/uacpp.qdoc
@@ -0,0 +1,234 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page uacpp-index.html
+ \title Setting up UACPP SDK
+ \brief Instructions how to setup UACPP SDK
+
+ \section1 Download and Installation
+
+ The UACPP plugin integrates the professional C++ based OPC UA SDK from Unified Automation GmbH
+ into Qt OPC UA. You can also test this using the evaluation version of the SDK,
+ but in this tutorial we show how to build the C++ SDK (full version)
+ and the Qt OPC UA plugin from source for best flexibility and portability.
+
+ By building the SDK from source, we can choose to build static
+ libraries instead of dynamic libraries, which reduces runtime
+ dependencies and code size.
+ The very same version of the OpenSSL library that was used to build Qt has to be used.
+ Otherwise there will be dynamic linker errors when loading the library.
+
+ Binaries depend on specific versions of OpenSSL and will not run on all Linux distributions.
+
+ When using the evaluation version, you can skip the step for Building the SDK,
+ but you must ensure to use the same compiler, OpenSSL and LibXML2 that were used for building the Eval SDK.
+
+ \section1 Requirements
+
+ \list
+ \li Qt 5.12 or higher
+ \li Qt OPC UA
+ \li Unified Automation C++ SDK 1.6.x or higher.
+ \li C++ Toolchain (GCC on Linux or MSVC on Windows)
+ \li CMake 2.8 or higher
+ \li Ninja (a faster make tool, GNU make would work too)
+ \endlist
+
+ When using GNU make instead of Ninja, use "-G 'Unix Makefiles'" instead of "-G Ninja" in
+ the CMake calls.
+
+ \section1 Building on Linux using GCC
+
+ \section2 Preparations
+
+ We assume that you have a development machine with a running C++ toolchain and Qt installed.
+ If not, install it now.
+
+ Example for Debian based systems:
+
+ \code
+ sudo apt install build-essential
+ sudo apt install cmake cmake-curses-gui cmake-qt-gui
+ sudo apt install ninja
+ \endcode
+
+ In this tutorial, we show example install commands using the \c apt
+ package management. On other distributions, you can install the
+ same tools, just the exact commands and package names may differ.
+
+ \section2 Building the SDK
+
+ On Linux, we want to build using the system provided OpenSSL library.
+ Therefor you need to install OpenSSL development packages. The same
+ applies for LibXML2.
+
+ \code
+ sudo apt install libssl-dev libxml2-dev
+ \endcode
+
+ At the time of writing, the pre-built Qt library was still built against OpenSSL1.0.
+ Debian Stretch and newer default to OpenSSL1.1. So we need to install the older
+ OpenSSL1.0 devel package to make the SDK and Qt use the same library version.
+ OpenSSL1.0 and OpenSSL1.1 are not binary compatible.
+
+ \code
+ sudo apt install libssl1.0-dev libxml2-dev
+ \endcode
+
+ Building the C++ OPC UA SDK:
+
+ \code
+ cd /path/to/sdk
+ export SDKDIR=$PWD
+ # force position independent code even for static libraries (to make it working in a Qt plugin)
+ export CFLAGS=-fPIC
+ export CXXFLAGS=-fPIC
+ # create out-of-source build directory
+ mkdir build
+ cd build
+ # Create Ninja build file (like a Makefile)
+ cmake -GNinja -DCMAKE_INSTALL_PREFIX=$SDKDIR -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=off -DBUILD_SHARED_STACK=off -DBUILD_UAMODELS=off -DBUILD_UAMODULE=off -DBUILD_COREMODULE=off -DBUILD_EXAMPLES=off -DBUILD_UASERVERCPP_APP=off -DBUILD_TESTING=off ..
+ # build and install the SDK
+ ninja
+ ninja install
+ # clear compiler flags again to avoid problems with other builds
+ export CFLAGS=
+ export CXXFLAGS=
+ \endcode
+
+ Note: You can replace \c Debug in \c "CMAKE_BUILD_TYPE=Debug" with \c Release, \c MinSizeRel, or \c RelWithDebInfo to build a release version.
+ See \l{https://cmake.org/cmake/help/v3.8/variable/CMAKE_BUILD_TYPE.html}{here} for more information.
+
+ \section2 Building the Qt OPC UA UACPP Plugin
+
+ \code
+ cd /path/to/qtopcua
+ qmake CONFIG+=debug -- UACPP_PREFIX=$SDKDIR
+ make -j $(nproc)
+ make install
+ \endcode
+
+ The output of the \c qmake configuration step indicates whether the detection was successful:
+
+ \code
+ Unified Automation C++ SDK ............. yes
+ \endcode
+
+ If not, you can inspect the config.log to find the reason for the problem.
+
+ \section1 Building on Windows using MSVC
+
+ \section2 Preparations
+
+ You need to install Visual Studio, Qt, CMake, and Ninja.
+ Please ensure the CMake and Ninja executables are in PATH,
+ so that the tools work on the console.
+
+ Downloads:
+
+ \list
+ \li https://cmake.org
+ \li https://ninja-build.org/
+ \endlist
+
+ \section2 Building the SDK
+
+ We assume that you have installed Visual Studio. To get a working toolchain, you need to open the Visual Studio Command Prompt.
+ It is important to run CMake also from this console, no matter if it's the \c cmake command or the CMake GUI.
+ Otherwise compiler detection may fail.
+
+ Important: All components need to be built with the same Visual Studio version.
+
+ Building the C++ OPC UA SDK:
+
+ \code
+ cd \path\to\sdk
+ set SDKDIR=%CD%
+ # create out-of-source build directory
+ mkdir build
+ cd build
+ # Create Ninja build file (like a Makefile)
+ cmake -GNinja -DCMAKE_INSTALL_PREFIX=%SDKDIR% -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=off -DBUILD_SHARED_STACK=off -DBUILD_UAMODELS=off -DBUILD_UAMODULE=off -DBUILD_COREMODULE=off -DBUILD_EXAMPLES=off -DBUILD_TESTING=off ..
+ # build and install the SDK
+ ninja
+ ninja install
+ \endcode
+
+ Note: You can replace \c Debug in \c "CMAKE_BUILD_TYPE=Debug" with \c Release, \c MinSizeRel, or \c RelWithDebInfo
+ to build a release version. See \l{https://cmake.org/cmake/help/v3.8/variable/CMAKE_BUILD_TYPE.html}{here} for more information.
+
+ Instead of building on console, you can also generate a Visual Studio solution
+ by replacing "-GNinja" with "-G 'Visual Studio 15 2017'". See "cmake --help" to get a list of available generators.
+
+ \section2 Building the Qt OPC UA UACPP Plugin
+
+ For building the Qt plugin, you need to open the Qt Command prompt for the same Visual Studio version
+ as you used for building the SDK.
+
+ \code
+ cd \path\to\qtopcua
+ qmake CONFIG+=debug -- UACPP_PREFIX=$SDKDIR
+ nmake
+ nmake install
+ \endcode
+
+ The output of the \c qmake configuration step indicates whether the detection was successful:
+
+ \code
+ Unified Automation C++ SDK ............. yes
+ \endcode
+
+ If not, you can inspect the config.log to find the reason for the problem.
+
+ \section1 Final notes
+
+ The SDK and Qt OPC UA can also be compiled with other compilers like MinGW-w64 for Windows,
+ Clang or can be cross-compiled using various cross-compilers, but this is out of scope of this document.
+
+ Please consult the documentation \l{http://documentation.unified-automation.com/uasdkcpp/1.6.3/html/CrossCompiling.html}{here} for cross-compiling the SDK
+ or contact the support if you have any questions.
+
+ \section1 Setting up the Key Infrastructure
+
+ With the UACPP Plugin, you can create secure connections with Qt OPC UA.
+ To make this work, each application instances (installation of a program),
+ needs to have its own \c {Application Instance Certificate} and the according private key.
+
+ Follow the common instructions on \l {Creating OPC UA Clients with security support} to setup the keys.
+
+ \section1 Demo Server
+
+ For testing the client with security, you can download one of Demo Servers from Unified Automation for free (Windows only).
+
+ https://www.unified-automation.com/downloads/opc-ua-servers.html
+
+ In addition, you can download evaluation versions of various OPC UA Server SDKs which also contain demo servers (Windows and Linux).
+
+ https://www.unified-automation.com/downloads/opc-ua-development.html
+
+*/
diff --git a/src/opcua/opcua.pro b/src/opcua/opcua.pro
index 2f77a5e..52daeb8 100644
--- a/src/opcua/opcua.pro
+++ b/src/opcua/opcua.pro
@@ -1,5 +1,5 @@
TARGET = QtOpcUa
-QT += core-private
+QT += core-private network
QT -= gui
include(core/core.pri)
diff --git a/src/plugins/opcua/open62541/qopen62541backend.cpp b/src/plugins/opcua/open62541/qopen62541backend.cpp
index 32b0f15..0959917 100644
--- a/src/plugins/opcua/open62541/qopen62541backend.cpp
+++ b/src/plugins/opcua/open62541/qopen62541backend.cpp
@@ -40,6 +40,9 @@
#include "qopen62541valueconverter.h"
#include <private/qopcuaclient_p.h>
+#include "qopcuaauthenticationinformation.h"
+#include <qopcuaerrorstate.h>
+
#include <QtCore/qloggingcategory.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qurl.h>
@@ -343,7 +346,7 @@ void Open62541AsyncBackend::callMethod(quint64 handle, UA_NodeId objectId, UA_No
emit methodCallFinished(handle, Open62541Utils::nodeIdToQString(methodId), result, static_cast<QOpcUa::UaStatusCode>(res));
}
-void Open62541AsyncBackend::resolveBrowsePath(quint64 handle, UA_NodeId startNode, const QVector<QOpcUa::QRelativePathElement> &path)
+void Open62541AsyncBackend::resolveBrowsePath(quint64 handle, UA_NodeId startNode, const QVector<QOpcUaRelativePathElement> &path)
{
UA_TranslateBrowsePathsToNodeIdsRequest req;
UA_TranslateBrowsePathsToNodeIdsRequest_init(&req);
@@ -371,14 +374,14 @@ void Open62541AsyncBackend::resolveBrowsePath(quint64 handle, UA_NodeId startNod
if (res.responseHeader.serviceResult != UA_STATUSCODE_GOOD || res.resultsSize != 1) {
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Translate browse path failed:" << UA_StatusCode_name(res.responseHeader.serviceResult);
- emit resolveBrowsePathFinished(handle, QVector<QOpcUa::QBrowsePathTarget>(), path,
+ emit resolveBrowsePathFinished(handle, QVector<QOpcUaBrowsePathTarget>(), path,
static_cast<QOpcUa::UaStatusCode>(res.responseHeader.serviceResult));
return;
}
- QVector<QOpcUa::QBrowsePathTarget> ret;
+ QVector<QOpcUaBrowsePathTarget> ret;
for (size_t i = 0; i < res.results[0].targetsSize ; ++i) {
- QOpcUa::QBrowsePathTarget temp;
+ QOpcUaBrowsePathTarget temp;
temp.setRemainingPathIndex(res.results[0].targets[i].remainingPathIndex);
temp.targetIdRef().setNamespaceUri(QString::fromUtf8(reinterpret_cast<char *>(res.results[0].targets[i].targetId.namespaceUri.data)));
temp.targetIdRef().setServerIndex(res.results[0].targets[i].targetId.serverIndex);
@@ -419,7 +422,7 @@ void Open62541AsyncBackend::findServers(const QUrl &url, const QStringList &loca
UaArrayDeleter<UA_TYPES_APPLICATIONDESCRIPTION> serversDeleter(servers, serversSize);
- QVector<QOpcUa::QApplicationDescription> ret;
+ QVector<QOpcUaApplicationDescription> ret;
for (size_t i = 0; i < serversSize; ++i)
ret.append(convertApplicationDescription(servers[i]));
@@ -428,13 +431,13 @@ void Open62541AsyncBackend::findServers(const QUrl &url, const QStringList &loca
qCDebug(QT_OPCUA_PLUGINS_OPEN62541) << "Failed to get servers:" << static_cast<QOpcUa::UaStatusCode>(result);
}
- emit findServersFinished(ret, static_cast<QOpcUa::UaStatusCode>(result));
+ emit findServersFinished(ret, static_cast<QOpcUa::UaStatusCode>(result), url);
}
-void Open62541AsyncBackend::batchRead(const QVector<QOpcUaReadItem> &nodesToRead)
+void Open62541AsyncBackend::readNodeAttributes(const QVector<QOpcUaReadItem> &nodesToRead)
{
if (nodesToRead.size() == 0) {
- emit batchReadFinished(QVector<QOpcUaReadResult>(), QOpcUa::UaStatusCode::BadNothingToDo);
+ emit readNodeAttributesFinished(QVector<QOpcUaReadResult>(), QOpcUa::UaStatusCode::BadNothingToDo);
return;
}
@@ -462,7 +465,7 @@ void Open62541AsyncBackend::batchRead(const QVector<QOpcUaReadItem> &nodesToRead
if (serviceResult != QOpcUa::UaStatusCode::Good) {
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Batch read failed:" << serviceResult;
- emit batchReadFinished(QVector<QOpcUaReadResult>(), serviceResult);
+ emit readNodeAttributesFinished(QVector<QOpcUaReadResult>(), serviceResult);
} else {
QVector<QOpcUaReadResult> ret;
@@ -487,14 +490,14 @@ void Open62541AsyncBackend::batchRead(const QVector<QOpcUaReadItem> &nodesToRead
}
ret.push_back(item);
}
- emit batchReadFinished(ret, serviceResult);
+ emit readNodeAttributesFinished(ret, serviceResult);
}
}
-void Open62541AsyncBackend::batchWrite(const QVector<QOpcUaWriteItem> &nodesToWrite)
+void Open62541AsyncBackend::writeNodeAttributes(const QVector<QOpcUaWriteItem> &nodesToWrite)
{
if (nodesToWrite.isEmpty()) {
- emit batchWriteFinished(QVector<QOpcUaWriteResult>(), QOpcUa::UaStatusCode::BadNothingToDo);
+ emit writeNodeAttributesFinished(QVector<QOpcUaWriteResult>(), QOpcUa::UaStatusCode::BadNothingToDo);
return;
}
@@ -539,7 +542,7 @@ void Open62541AsyncBackend::batchWrite(const QVector<QOpcUaWriteItem> &nodesToWr
if (serviceResult != QOpcUa::UaStatusCode::Good) {
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Batch write failed:" << serviceResult;
- emit batchWriteFinished(QVector<QOpcUaWriteResult>(), serviceResult);
+ emit writeNodeAttributesFinished(QVector<QOpcUaWriteResult>(), serviceResult);
} else {
QVector<QOpcUaWriteResult> ret;
@@ -554,7 +557,7 @@ void Open62541AsyncBackend::batchWrite(const QVector<QOpcUaWriteItem> &nodesToWr
item.setStatusCode(serviceResult);
ret.push_back(item);
}
- emit batchWriteFinished(ret, serviceResult);
+ emit writeNodeAttributesFinished(ret, serviceResult);
}
}
@@ -567,15 +570,15 @@ void Open62541AsyncBackend::addNode(const QOpcUaAddNodeItem &nodeToAdd)
req.nodesToAdd = UA_AddNodesItem_new();
UA_AddNodesItem_init(req.nodesToAdd);
- QOpen62541ValueConverter::scalarFromQt<UA_ExpandedNodeId, QOpcUa::QExpandedNodeId>(
+ QOpen62541ValueConverter::scalarFromQt<UA_ExpandedNodeId, QOpcUaExpandedNodeId>(
nodeToAdd.parentNodeId(), &req.nodesToAdd->parentNodeId);
req.nodesToAdd->referenceTypeId = Open62541Utils::nodeIdFromQString(nodeToAdd.referenceTypeId());
- QOpen62541ValueConverter::scalarFromQt<UA_ExpandedNodeId, QOpcUa::QExpandedNodeId>(
+ QOpen62541ValueConverter::scalarFromQt<UA_ExpandedNodeId, QOpcUaExpandedNodeId>(
nodeToAdd.requestedNewNodeId(), &req.nodesToAdd->requestedNewNodeId);
- QOpen62541ValueConverter::scalarFromQt<UA_QualifiedName, QOpcUa::QQualifiedName>(
+ QOpen62541ValueConverter::scalarFromQt<UA_QualifiedName, QOpcUaQualifiedName>(
nodeToAdd.browseName(), &req.nodesToAdd->browseName);
req.nodesToAdd->nodeClass = static_cast<UA_NodeClass>(nodeToAdd.nodeClass());
@@ -584,7 +587,7 @@ void Open62541AsyncBackend::addNode(const QOpcUaAddNodeItem &nodeToAdd)
nodeToAdd.nodeClass());
if (!nodeToAdd.typeDefinition().nodeId().isEmpty())
- QOpen62541ValueConverter::scalarFromQt<UA_ExpandedNodeId, QOpcUa::QExpandedNodeId>(
+ QOpen62541ValueConverter::scalarFromQt<UA_ExpandedNodeId, QOpcUaExpandedNodeId>(
nodeToAdd.typeDefinition(), &req.nodesToAdd->typeDefinition);
UA_AddNodesResponse res = UA_Client_Service_addNodes(m_uaclient, req);
@@ -629,7 +632,7 @@ void Open62541AsyncBackend::addReference(const QOpcUaAddReferenceItem &reference
UA_ExpandedNodeId_init(&target);
UaDeleter<UA_ExpandedNodeId> nodeIdDeleter(&target, UA_ExpandedNodeId_deleteMembers);
- QOpen62541ValueConverter::scalarFromQt<UA_ExpandedNodeId, QOpcUa::QExpandedNodeId>(
+ QOpen62541ValueConverter::scalarFromQt<UA_ExpandedNodeId, QOpcUaExpandedNodeId>(
referenceToAdd.targetNodeId(), &target);
UA_String serverUri;
@@ -659,7 +662,7 @@ void Open62541AsyncBackend::deleteReference(const QOpcUaDeleteReferenceItem &ref
UA_ExpandedNodeId target;
UA_ExpandedNodeId_init(&target);
UaDeleter<UA_ExpandedNodeId> targetDeleter(&target, UA_ExpandedNodeId_deleteMembers);
- QOpen62541ValueConverter::scalarFromQt<UA_ExpandedNodeId, QOpcUa::QExpandedNodeId>(
+ QOpen62541ValueConverter::scalarFromQt<UA_ExpandedNodeId, QOpcUaExpandedNodeId>(
referenceToDelete.targetNodeId(), &target);
UA_StatusCode res = UA_Client_deleteReference(m_uaclient,
@@ -685,12 +688,12 @@ static void convertBrowseResult(UA_BrowseResult *src, quint32 referencesSize, QV
for (size_t i = 0; i < referencesSize; ++i) {
QOpcUaReferenceDescription temp;
- temp.setTargetNodeId(QOpen62541ValueConverter::scalarToQt<QOpcUa::QExpandedNodeId>(&src->references[i].nodeId));
- temp.setTypeDefinition(QOpen62541ValueConverter::scalarToQt<QOpcUa::QExpandedNodeId>(&src->references[i].typeDefinition));
+ temp.setTargetNodeId(QOpen62541ValueConverter::scalarToQt<QOpcUaExpandedNodeId>(&src->references[i].nodeId));
+ temp.setTypeDefinition(QOpen62541ValueConverter::scalarToQt<QOpcUaExpandedNodeId>(&src->references[i].typeDefinition));
temp.setRefTypeId(Open62541Utils::nodeIdToQString(src->references[i].referenceTypeId));
temp.setNodeClass(static_cast<QOpcUa::NodeClass>(src->references[i].nodeClass));
- temp.setBrowseName(QOpen62541ValueConverter::scalarToQt<QOpcUa::QQualifiedName, UA_QualifiedName>(&src->references[i].browseName));
- temp.setDisplayName(QOpen62541ValueConverter::scalarToQt<QOpcUa::QLocalizedText, UA_LocalizedText>(&src->references[i].displayName));
+ temp.setBrowseName(QOpen62541ValueConverter::scalarToQt<QOpcUaQualifiedName, UA_QualifiedName>(&src->references[i].browseName));
+ temp.setDisplayName(QOpen62541ValueConverter::scalarToQt<QOpcUaLocalizedText, UA_LocalizedText>(&src->references[i].displayName));
temp.setIsForwardReference(src->references[i].isForward);
dst.push_back(temp);
}
@@ -762,13 +765,30 @@ static void clientStateCallback(UA_Client *client, UA_ClientState state)
}
}
-void Open62541AsyncBackend::connectToEndpoint(const QUrl &url)
+void Open62541AsyncBackend::connectToEndpoint(const QOpcUaEndpointDescription &endpoint)
{
cleanupSubscriptions();
if (m_uaclient)
UA_Client_delete(m_uaclient);
+ QString errorMessage;
+ if (!verifyEndpointDescription(endpoint, &errorMessage)) {
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << errorMessage;
+ emit stateAndOrErrorChanged(QOpcUaClient::Disconnected, QOpcUaClient::ClientError::InvalidUrl);
+ return;
+ }
+
+ const QString nonePolicyUri = QLatin1String("http://opcfoundation.org/UA/SecurityPolicy#None");
+
+ if (endpoint.securityPolicy() != nonePolicyUri) {
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "open62541 does not yet support secure connections";
+ emit stateAndOrErrorChanged(QOpcUaClient::Disconnected, QOpcUaClient::ClientError::NoError);
+ return;
+ }
+
+ emit stateAndOrErrorChanged(QOpcUaClient::Connecting, QOpcUaClient::NoError);
+
m_useStateCallback = false;
UA_ClientConfig conf = UA_ClientConfig_default;
@@ -776,18 +796,51 @@ void Open62541AsyncBackend::connectToEndpoint(const QUrl &url)
conf.stateCallback = &clientStateCallback;
m_uaclient = UA_Client_new(conf);
UA_StatusCode ret;
+ const auto authInfo = m_clientImpl->m_client->authenticationInformation();
- if (url.userName().length())
- ret = UA_Client_connect_username(m_uaclient, url.toString(QUrl::RemoveUserInfo).toUtf8().constData(),
- url.userName().toUtf8().constData(), url.password().toUtf8().constData());
- else
- ret = UA_Client_connect(m_uaclient, url.toString().toUtf8().constData());
+ if (authInfo.authenticationType() == QOpcUaUserTokenPolicy::TokenType::Anonymous) {
+ ret = UA_Client_connect(m_uaclient, endpoint.endpointUrl().toUtf8().constData());
+ } else if (authInfo.authenticationType() == QOpcUaUserTokenPolicy::TokenType::Username) {
+
+ bool suitableTokenFound = false;
+ for (const auto token : endpoint.userIdentityTokens()) {
+ if (token.tokenType() == QOpcUaUserTokenPolicy::Username && token.securityPolicy() == nonePolicyUri) {
+ suitableTokenFound = true;
+ break;
+ }
+ }
+
+ if (!suitableTokenFound) {
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "open62541 does not yet support encrypted passwords";
+ emit stateAndOrErrorChanged(QOpcUaClient::Disconnected, QOpcUaClient::ClientError::NoError);
+ return;
+ }
+
+ const auto credentials = authInfo.authenticationData().value<QPair<QString, QString>>();
+ ret = UA_Client_connect_username(m_uaclient, endpoint.endpointUrl().toUtf8().constData(),
+ credentials.first.toUtf8().constData(), credentials.second.toUtf8().constData());
+ } else {
+ emit stateAndOrErrorChanged(QOpcUaClient::Disconnected, QOpcUaClient::UnsupportedAuthenticationInformation);
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Failed to connect: Selected authentication type"
+ << authInfo.authenticationType() << "is not supported.";
+ return;
+ }
if (ret != UA_STATUSCODE_GOOD) {
UA_Client_delete(m_uaclient);
m_uaclient = nullptr;
QOpcUaClient::ClientError error = ret == UA_STATUSCODE_BADUSERACCESSDENIED ? QOpcUaClient::AccessDenied : QOpcUaClient::UnknownError;
+ QOpcUaErrorState errorState;
+ errorState.setConnectionStep(QOpcUaErrorState::ConnectionStep::Unknown);
+ errorState.setErrorCode(static_cast<QOpcUa::UaStatusCode>(ret));
+ errorState.setClientSideError(false);
+ errorState.setIgnoreError(false);
+
+ // This signal is connected using Qt::BlockingQueuedConnection. It will place a metacall to a different thread and waits
+ // until this metacall is fully handled before returning.
+ emit QOpcUaBackend::connectError(&errorState);
+
emit stateAndOrErrorChanged(QOpcUaClient::Disconnected, error);
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Open62541: Failed to connect";
return;
@@ -824,19 +877,19 @@ void Open62541AsyncBackend::requestEndpoints(const QUrl &url)
UA_EndpointDescription *endpoints = nullptr;
UA_StatusCode res = UA_Client_getEndpoints(tmpClient, url.toString(QUrl::RemoveUserInfo).toUtf8().constData(), &numEndpoints, &endpoints);
UaArrayDeleter<UA_TYPES_ENDPOINTDESCRIPTION> endpointDescriptionDeleter(endpoints, numEndpoints);
- QVector<QOpcUa::QEndpointDescription> ret;
+ QVector<QOpcUaEndpointDescription> ret;
namespace vc = QOpen62541ValueConverter;
using namespace QOpcUa;
if (res == UA_STATUSCODE_GOOD && numEndpoints) {
for (size_t i = 0; i < numEndpoints ; ++i) {
- QOpcUa::QEndpointDescription epd;
- QOpcUa::QApplicationDescription &apd = epd.serverRef();
+ QOpcUaEndpointDescription epd;
+ QOpcUaApplicationDescription &apd = epd.serverRef();
apd.setApplicationUri(vc::scalarToQt<QString, UA_String>(&endpoints[i].server.applicationUri));
apd.setProductUri(vc::scalarToQt<QString, UA_String>(&endpoints[i].server.productUri));
- apd.setApplicationName(vc::scalarToQt<QLocalizedText, UA_LocalizedText>(&endpoints[i].server.applicationName));
- apd.setApplicationType(static_cast<QApplicationDescription::ApplicationType>(endpoints[i].server.applicationType));
+ apd.setApplicationName(vc::scalarToQt<QOpcUaLocalizedText, UA_LocalizedText>(&endpoints[i].server.applicationName));
+ apd.setApplicationType(static_cast<QOpcUaApplicationDescription::ApplicationType>(endpoints[i].server.applicationType));
apd.setGatewayServerUri(vc::scalarToQt<QString, UA_String>(&endpoints[i].server.gatewayServerUri));
apd.setDiscoveryProfileUri(vc::scalarToQt<QString, UA_String>(&endpoints[i].server.discoveryProfileUri));
for (size_t j = 0; j < endpoints[i].server.discoveryUrlsSize; ++j)
@@ -844,16 +897,16 @@ void Open62541AsyncBackend::requestEndpoints(const QUrl &url)
epd.setEndpointUrl(vc::scalarToQt<QString, UA_String>(&endpoints[i].endpointUrl));
epd.setServerCertificate(vc::scalarToQt<QByteArray, UA_ByteString>(&endpoints[i].serverCertificate));
- epd.setSecurityMode(static_cast<QEndpointDescription::MessageSecurityMode>(endpoints[i].securityMode));
- epd.setSecurityPolicyUri(vc::scalarToQt<QString, UA_String>(&endpoints[i].securityPolicyUri));
+ epd.setSecurityMode(static_cast<QOpcUaEndpointDescription::MessageSecurityMode>(endpoints[i].securityMode));
+ epd.setSecurityPolicy(vc::scalarToQt<QString, UA_String>(&endpoints[i].securityPolicyUri));
for (size_t j = 0; j < endpoints[i].userIdentityTokensSize; ++j) {
- QUserTokenPolicy policy;
+ QOpcUaUserTokenPolicy policy;
UA_UserTokenPolicy *policySrc = &endpoints[i].userIdentityTokens[j];
policy.setPolicyId(vc::scalarToQt<QString, UA_String>(&policySrc->policyId));
- policy.setTokenType(static_cast<QUserTokenPolicy::TokenType>(endpoints[i].userIdentityTokens[j].tokenType));
+ policy.setTokenType(static_cast<QOpcUaUserTokenPolicy::TokenType>(endpoints[i].userIdentityTokens[j].tokenType));
policy.setIssuedTokenType(vc::scalarToQt<QString, UA_String>(&endpoints[i].userIdentityTokens[j].issuedTokenType));
policy.setIssuerEndpointUrl(vc::scalarToQt<QString, UA_String>(&endpoints[i].userIdentityTokens[j].issuerEndpointUrl));
- policy.setSecurityPolicyUri(vc::scalarToQt<QString, UA_String>(&endpoints[i].userIdentityTokens[j].securityPolicyUri));
+ policy.setSecurityPolicy(vc::scalarToQt<QString, UA_String>(&endpoints[i].userIdentityTokens[j].securityPolicyUri));
epd.userIdentityTokensRef().append(policy);
}
@@ -861,9 +914,15 @@ void Open62541AsyncBackend::requestEndpoints(const QUrl &url)
epd.setSecurityLevel(endpoints[i].securityLevel);
ret.append(epd);
}
+ } else {
+ if (res == UA_STATUSCODE_GOOD)
+ qWarning() << "Server returned an empty endpoint list";
+ else
+ qWarning() << "Failed to retrive endpoints from " << url.toString(QUrl::RemoveUserInfo).toUtf8().constData()
+ << "with status" << UA_StatusCode_name(res);
}
- emit endpointsRequestFinished(ret, static_cast<QOpcUa::UaStatusCode>(res));
+ emit endpointsRequestFinished(ret, static_cast<QOpcUa::UaStatusCode>(res), url);
UA_Client_delete(tmpClient);
}
@@ -928,14 +987,14 @@ QOpen62541Subscription *Open62541AsyncBackend::getSubscriptionForItem(quint64 ha
return subscription.value();
}
-QOpcUa::QApplicationDescription Open62541AsyncBackend::convertApplicationDescription(UA_ApplicationDescription &desc)
+QOpcUaApplicationDescription Open62541AsyncBackend::convertApplicationDescription(UA_ApplicationDescription &desc)
{
- QOpcUa::QApplicationDescription temp;
+ QOpcUaApplicationDescription temp;
temp.setApplicationUri(QOpen62541ValueConverter::scalarToQt<QString, UA_String>(&desc.applicationUri));
temp.setProductUri(QOpen62541ValueConverter::scalarToQt<QString, UA_String>(&desc.productUri));
- temp.setApplicationName(QOpen62541ValueConverter::scalarToQt<QOpcUa::QLocalizedText, UA_LocalizedText>(&desc.applicationName));
- temp.setApplicationType(static_cast<QOpcUa::QApplicationDescription::ApplicationType>(desc.applicationType));
+ temp.setApplicationName(QOpen62541ValueConverter::scalarToQt<QOpcUaLocalizedText, UA_LocalizedText>(&desc.applicationName));
+ temp.setApplicationType(static_cast<QOpcUaApplicationDescription::ApplicationType>(desc.applicationType));
temp.setGatewayServerUri(QOpen62541ValueConverter::scalarToQt<QString, UA_String>(&desc.gatewayServerUri));
temp.setDiscoveryProfileUri(QOpen62541ValueConverter::scalarToQt<QString, UA_String>(&desc.discoveryProfileUri));
@@ -1088,7 +1147,7 @@ UA_ExtensionObject Open62541AsyncBackend::assembleNodeAttributes(const QOpcUaNod
}
if (nodeAttributes.hasInverseName()) {
attr->specifiedAttributes |= UA_NODEATTRIBUTESMASK_INVERSENAME;
- QOpen62541ValueConverter::scalarFromQt<UA_LocalizedText, QOpcUa::QLocalizedText>(
+ QOpen62541ValueConverter::scalarFromQt<UA_LocalizedText, QOpcUaLocalizedText>(
nodeAttributes.inverseName(), &attr->inverseName);
}
break;
@@ -1130,12 +1189,12 @@ UA_ExtensionObject Open62541AsyncBackend::assembleNodeAttributes(const QOpcUaNod
UA_ObjectAttributes *attr = reinterpret_cast<UA_ObjectAttributes *>(obj.content.decoded.data);
if (nodeAttributes.hasDisplayName()) {
attr->specifiedAttributes |= UA_NODEATTRIBUTESMASK_DISPLAYNAME;
- QOpen62541ValueConverter::scalarFromQt<UA_LocalizedText, QOpcUa::QLocalizedText>(
+ QOpen62541ValueConverter::scalarFromQt<UA_LocalizedText, QOpcUaLocalizedText>(
nodeAttributes.displayName(), &attr->displayName);
}
if (nodeAttributes.hasDescription()) {
attr->specifiedAttributes |= UA_NODEATTRIBUTESMASK_DESCRIPTION;
- QOpen62541ValueConverter::scalarFromQt<UA_LocalizedText, QOpcUa::QLocalizedText>(
+ QOpen62541ValueConverter::scalarFromQt<UA_LocalizedText, QOpcUaLocalizedText>(
nodeAttributes.description(), &attr->description);
}
if (nodeAttributes.hasWriteMask()) {
diff --git a/src/plugins/opcua/open62541/qopen62541backend.h b/src/plugins/opcua/open62541/qopen62541backend.h
index 622f91d..6073b94 100644
--- a/src/plugins/opcua/open62541/qopen62541backend.h
+++ b/src/plugins/opcua/open62541/qopen62541backend.h
@@ -52,7 +52,7 @@ public:
~Open62541AsyncBackend();
public Q_SLOTS:
- void connectToEndpoint(const QUrl &url);
+ void connectToEndpoint(const QOpcUaEndpointDescription &endpoint);
void disconnectFromEndpoint();
void requestEndpoints(const QUrl &url);
@@ -66,11 +66,11 @@ public Q_SLOTS:
void disableMonitoring(quint64 handle, QOpcUa::NodeAttributes attr);
void modifyMonitoring(quint64 handle, QOpcUa::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, QVariant value);
void callMethod(quint64 handle, UA_NodeId objectId, UA_NodeId methodId, QVector<QOpcUa::TypedVariant> args);
- void resolveBrowsePath(quint64 handle, UA_NodeId startNode, const QVector<QOpcUa::QRelativePathElement> &path);
+ void resolveBrowsePath(quint64 handle, UA_NodeId startNode, const QVector<QOpcUaRelativePathElement> &path);
void findServers(const QUrl &url, const QStringList &localeIds, const QStringList &serverUris);
- void batchRead(const QVector<QOpcUaReadItem> &nodesToRead);
- void batchWrite(const QVector<QOpcUaWriteItem> &nodesToWrite);
+ void readNodeAttributes(const QVector<QOpcUaReadItem> &nodesToRead);
+ void writeNodeAttributes(const QVector<QOpcUaWriteItem> &nodesToWrite);
// Node management
void addNode(const QOpcUaAddNodeItem &nodeToAdd);
@@ -93,7 +93,7 @@ public:
private:
QOpen62541Subscription *getSubscriptionForItem(quint64 handle, QOpcUa::NodeAttribute attr);
- QOpcUa::QApplicationDescription convertApplicationDescription(UA_ApplicationDescription &desc);
+ QOpcUaApplicationDescription convertApplicationDescription(UA_ApplicationDescription &desc);
UA_ExtensionObject assembleNodeAttributes(const QOpcUaNodeCreationAttributes &nodeAttributes, QOpcUa::NodeClass nodeClass);
UA_UInt32 *copyArrayDimensions(const QVector<quint32> &arrayDimensions, size_t *outputSize);
diff --git a/src/plugins/opcua/open62541/qopen62541client.cpp b/src/plugins/opcua/open62541/qopen62541client.cpp
index 370bcee..d65f737 100644
--- a/src/plugins/opcua/open62541/qopen62541client.cpp
+++ b/src/plugins/opcua/open62541/qopen62541client.cpp
@@ -69,9 +69,10 @@ QOpen62541Client::~QOpen62541Client()
m_thread->quit();
}
-void QOpen62541Client::connectToEndpoint(const QUrl &url)
+void QOpen62541Client::connectToEndpoint(const QOpcUaEndpointDescription &endpoint)
{
- QMetaObject::invokeMethod(m_backend, "connectToEndpoint", Qt::QueuedConnection, Q_ARG(QUrl, url));
+ QMetaObject::invokeMethod(m_backend, "connectToEndpoint", Qt::QueuedConnection,
+ Q_ARG(QOpcUaEndpointDescription, endpoint));
}
void QOpen62541Client::disconnectFromEndpoint()
@@ -112,15 +113,15 @@ bool QOpen62541Client::findServers(const QUrl &url, const QStringList &localeIds
Q_ARG(QStringList, serverUris));
}
-bool QOpen62541Client::batchRead(const QVector<QOpcUaReadItem> &nodesToRead)
+bool QOpen62541Client::readNodeAttributes(const QVector<QOpcUaReadItem> &nodesToRead)
{
- return QMetaObject::invokeMethod(m_backend, "batchRead", Qt::QueuedConnection,
+ return QMetaObject::invokeMethod(m_backend, "readNodeAttributes", Qt::QueuedConnection,
Q_ARG(QVector<QOpcUaReadItem>, nodesToRead));
}
-bool QOpen62541Client::batchWrite(const QVector<QOpcUaWriteItem> &nodesToWrite)
+bool QOpen62541Client::writeNodeAttributes(const QVector<QOpcUaWriteItem> &nodesToWrite)
{
- return QMetaObject::invokeMethod(m_backend, "batchWrite", Qt::QueuedConnection,
+ return QMetaObject::invokeMethod(m_backend, "writeNodeAttributes", Qt::QueuedConnection,
Q_ARG(QVector<QOpcUaWriteItem>, nodesToWrite));
}
@@ -149,4 +150,19 @@ bool QOpen62541Client::deleteReference(const QOpcUaDeleteReferenceItem &referenc
Q_ARG(QOpcUaDeleteReferenceItem, referenceToDelete));
}
+QStringList QOpen62541Client::supportedSecurityPolicies() const
+{
+ return QStringList {
+ "http://opcfoundation.org/UA/SecurityPolicy#None",
+ };
+}
+
+QVector<QOpcUaUserTokenPolicy::TokenType> QOpen62541Client::supportedUserTokenTypes() const
+{
+ return QVector<QOpcUaUserTokenPolicy::TokenType> {
+ QOpcUaUserTokenPolicy::TokenType::Anonymous,
+ QOpcUaUserTokenPolicy::TokenType::Username
+ };
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/open62541/qopen62541client.h b/src/plugins/opcua/open62541/qopen62541client.h
index 466b60a..e43a745 100644
--- a/src/plugins/opcua/open62541/qopen62541client.h
+++ b/src/plugins/opcua/open62541/qopen62541client.h
@@ -54,7 +54,7 @@ public:
explicit QOpen62541Client();
~QOpen62541Client();
- void connectToEndpoint(const QUrl &url) override;
+ void connectToEndpoint(const QOpcUaEndpointDescription &endpoint) override;
void disconnectFromEndpoint() override;
QOpcUaNode *node(const QString &nodeId) override;
@@ -65,8 +65,8 @@ public:
bool findServers(const QUrl &url, const QStringList &localeIds, const QStringList &serverUris) override;
- bool batchRead(const QVector<QOpcUaReadItem> &nodesToRead) override;
- bool batchWrite(const QVector<QOpcUaWriteItem> &nodesToWrite) override;
+ bool readNodeAttributes(const QVector<QOpcUaReadItem> &nodesToRead) override;
+ bool writeNodeAttributes(const QVector<QOpcUaWriteItem> &nodesToWrite) override;
bool addNode(const QOpcUaAddNodeItem &nodeToAdd) override;
bool deleteNode(const QString &nodeId, bool deleteTargetReferences) override;
@@ -74,6 +74,9 @@ public:
bool addReference(const QOpcUaAddReferenceItem &referenceToAdd) override;
bool deleteReference(const QOpcUaDeleteReferenceItem &referenceToDelete) override;
+ QStringList supportedSecurityPolicies() const override;
+ QVector<QOpcUaUserTokenPolicy::TokenType> supportedUserTokenTypes() const override;
+
private slots:
private:
diff --git a/src/plugins/opcua/open62541/qopen62541node.cpp b/src/plugins/opcua/open62541/qopen62541node.cpp
index a258e67..80602c5 100644
--- a/src/plugins/opcua/open62541/qopen62541node.cpp
+++ b/src/plugins/opcua/open62541/qopen62541node.cpp
@@ -183,7 +183,7 @@ bool QOpen62541Node::callMethod(const QString &methodNodeId, const QVector<QOpcU
Q_ARG(QVector<QOpcUa::TypedVariant>, args));
}
-bool QOpen62541Node::resolveBrowsePath(const QVector<QOpcUa::QRelativePathElement> &path)
+bool QOpen62541Node::resolveBrowsePath(const QVector<QOpcUaRelativePathElement> &path)
{
if (!m_client)
return false;
@@ -194,7 +194,7 @@ bool QOpen62541Node::resolveBrowsePath(const QVector<QOpcUa::QRelativePathElemen
return QMetaObject::invokeMethod(m_client->m_backend, "resolveBrowsePath", Qt::QueuedConnection,
Q_ARG(quint64, handle()),
Q_ARG(UA_NodeId, start),
- Q_ARG(QVector<QOpcUa::QRelativePathElement>, path));
+ Q_ARG(QVector<QOpcUaRelativePathElement>, path));
}
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/open62541/qopen62541node.h b/src/plugins/opcua/open62541/qopen62541node.h
index 293b075..f7535d2 100644
--- a/src/plugins/opcua/open62541/qopen62541node.h
+++ b/src/plugins/opcua/open62541/qopen62541node.h
@@ -61,7 +61,7 @@ public:
bool writeAttributes(const QOpcUaNode::AttributeMap &toWrite, QOpcUa::Types valueAttributeType) override;
bool callMethod(const QString &methodNodeId, const QVector<QOpcUa::TypedVariant> &args) override;
- bool resolveBrowsePath(const QVector<QOpcUa::QRelativePathElement> &path) override;
+ bool resolveBrowsePath(const QVector<QOpcUaRelativePathElement> &path) override;
private:
QPointer<QOpen62541Client> m_client;
diff --git a/src/plugins/opcua/open62541/qopen62541subscription.cpp b/src/plugins/opcua/open62541/qopen62541subscription.cpp
index cf8ac3f..c19f798 100644
--- a/src/plugins/opcua/open62541/qopen62541subscription.cpp
+++ b/src/plugins/opcua/open62541/qopen62541subscription.cpp
@@ -43,6 +43,11 @@
#include "qopen62541utils.h"
#include <private/qopcuanode_p.h>
+#include "qopcuaelementoperand.h"
+#include "qopcualiteraloperand.h"
+#include "qopcuaattributeoperand.h"
+#include "qopcuacontentfilterelementresult.h"
+
#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
@@ -143,7 +148,7 @@ bool QOpen62541Subscription::removeOnServer()
qDeleteAll(m_itemIdToItemMapping);
m_itemIdToItemMapping.clear();
- m_handleToItemMapping.clear();
+ m_nodeHandleToItemMapping.clear();
return (res == UA_STATUSCODE_GOOD) ? true : false;
}
@@ -289,7 +294,7 @@ bool QOpen62541Subscription::addAttributeMonitoredItem(quint64 handle, QOpcUa::N
}
MonitoredItem *temp = new MonitoredItem(handle, attr, res.monitoredItemId);
- m_handleToItemMapping[handle][attr] = temp;
+ m_nodeHandleToItemMapping[handle][attr] = temp;
m_itemIdToItemMapping[res.monitoredItemId] = temp;
QOpcUaMonitoringParameters s = settings;
@@ -331,10 +336,10 @@ bool QOpen62541Subscription::removeAttributeMonitoredItem(quint64 handle, QOpcUa
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not remove monitored item" << item->monitoredItemId << "from subscription" << m_subscriptionId << ":" << UA_StatusCode_name(res);
m_itemIdToItemMapping.remove(item->monitoredItemId);
- auto it = m_handleToItemMapping.find(handle);
+ auto it = m_nodeHandleToItemMapping.find(handle);
it->remove(attr);
if (it->empty())
- m_handleToItemMapping.erase(it);
+ m_nodeHandleToItemMapping.erase(it);
delete item;
@@ -371,7 +376,7 @@ void QOpen62541Subscription::monitoredValueUpdated(UA_UInt32 monId, UA_DataValue
void QOpen62541Subscription::sendTimeoutNotification()
{
QVector<QPair<quint64, QOpcUa::NodeAttribute>> items;
- for (auto it : qAsConst(m_handleToItemMapping)) {
+ for (auto it : qAsConst(m_nodeHandleToItemMapping)) {
for (auto item : it) {
items.push_back({item->handle, item->attr});
}
@@ -408,11 +413,11 @@ QOpcUaMonitoringParameters::SubscriptionType QOpen62541Subscription::shared() co
return m_shared;
}
-QOpen62541Subscription::MonitoredItem *QOpen62541Subscription::getItemForAttribute(quint64 handle, QOpcUa::NodeAttribute attr)
+QOpen62541Subscription::MonitoredItem *QOpen62541Subscription::getItemForAttribute(quint64 nodeHandle, QOpcUa::NodeAttribute attr)
{
- auto nodeEntry = m_handleToItemMapping.constFind(handle);
+ auto nodeEntry = m_nodeHandleToItemMapping.constFind(nodeHandle);
- if (nodeEntry == m_handleToItemMapping.constEnd())
+ if (nodeEntry == m_nodeHandleToItemMapping.constEnd())
return nullptr;
auto item = nodeEntry->constFind(attr);
@@ -483,7 +488,7 @@ bool QOpen62541Subscription::convertSelectClause(const QOpcUaMonitoringParameter
select[i].browsePath = static_cast<UA_QualifiedName *>(
UA_Array_new(select[i].browsePathSize, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]));
for (size_t j = 0; j < select[i].browsePathSize; ++j)
- QOpen62541ValueConverter::scalarFromQt<UA_QualifiedName, QOpcUa::QQualifiedName>(
+ QOpen62541ValueConverter::scalarFromQt<UA_QualifiedName, QOpcUaQualifiedName>(
filter.selectClauses().at(i).browsePath().at(j), &select[i].browsePath[j]);
}
QOpen62541ValueConverter::scalarFromQt<UA_String, QString>(filter.selectClauses().at(i).indexRange(),
@@ -518,23 +523,23 @@ bool QOpen62541Subscription::convertWhereClause(const QOpcUaMonitoringParameters
UA_ExtensionObject_init(&result->elements[i].filterOperands[j]);
result->elements[i].filterOperands[j].encoding = UA_EXTENSIONOBJECT_DECODED;
const QVariant &currentOperand = filter.whereClause().at(i).filterOperands().at(j);
- if (currentOperand.canConvert<QOpcUa::QElementOperand>()) {
+ if (currentOperand.canConvert<QOpcUaElementOperand>()) {
UA_ElementOperand *op = UA_ElementOperand_new();
UA_ElementOperand_init(op);
- op->index = currentOperand.value<QOpcUa::QElementOperand>().index();
+ op->index = currentOperand.value<QOpcUaElementOperand>().index();
result->elements[i].filterOperands[j].content.decoded.data = op;
result->elements[i].filterOperands[j].content.decoded.type = &UA_TYPES[UA_TYPES_ELEMENTOPERAND];
- } else if (currentOperand.canConvert<QOpcUa::QLiteralOperand>()) {
+ } else if (currentOperand.canConvert<QOpcUaLiteralOperand>()) {
UA_LiteralOperand *op = UA_LiteralOperand_new();
UA_LiteralOperand_init(op);
- QOpcUa::QLiteralOperand litOp = currentOperand.value<QOpcUa::QLiteralOperand>();
+ QOpcUaLiteralOperand litOp = currentOperand.value<QOpcUaLiteralOperand>();
op->value = QOpen62541ValueConverter::toOpen62541Variant(litOp.value(), litOp.type());
result->elements[i].filterOperands[j].content.decoded.data = op;
result->elements[i].filterOperands[j].content.decoded.type = &UA_TYPES[UA_TYPES_LITERALOPERAND];
- } else if (currentOperand.canConvert<QOpcUa::QSimpleAttributeOperand>()) {
+ } else if (currentOperand.canConvert<QOpcUaSimpleAttributeOperand>()) {
UA_SimpleAttributeOperand *op = UA_SimpleAttributeOperand_new();
UA_SimpleAttributeOperand_init(op);
- QOpcUa::QSimpleAttributeOperand operand = currentOperand.value<QOpcUa::QSimpleAttributeOperand>();
+ QOpcUaSimpleAttributeOperand operand = currentOperand.value<QOpcUaSimpleAttributeOperand>();
op->attributeId = QOpen62541ValueConverter::toUaAttributeId(operand.attributeId());
QOpen62541ValueConverter::scalarFromQt<UA_String, QString>(operand.indexRange(), &op->indexRange);
if (!operand.typeId().isEmpty())
@@ -543,14 +548,14 @@ bool QOpen62541Subscription::convertWhereClause(const QOpcUaMonitoringParameters
op->browsePath = static_cast<UA_QualifiedName *>(UA_Array_new(operand.browsePath().size(),
&UA_TYPES[UA_TYPES_QUALIFIEDNAME]));
for (int k = 0; k < operand.browsePath().size(); ++k)
- QOpen62541ValueConverter::scalarFromQt<UA_QualifiedName, QOpcUa::QQualifiedName>(
+ QOpen62541ValueConverter::scalarFromQt<UA_QualifiedName, QOpcUaQualifiedName>(
operand.browsePath().at(k), &op->browsePath[k]);
result->elements[i].filterOperands[j].content.decoded.data = op;
result->elements[i].filterOperands[j].content.decoded.type = &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND];
- } else if (currentOperand.canConvert<QOpcUa::QAttributeOperand>()) {
+ } else if (currentOperand.canConvert<QOpcUaAttributeOperand>()) {
UA_AttributeOperand *op = UA_AttributeOperand_new();
UA_AttributeOperand_init(op);
- QOpcUa::QAttributeOperand operand = currentOperand.value<QOpcUa::QAttributeOperand>();
+ QOpcUaAttributeOperand operand = currentOperand.value<QOpcUaAttributeOperand>();
op->attributeId = QOpen62541ValueConverter::toUaAttributeId(operand.attributeId());
QOpen62541ValueConverter::scalarFromQt<UA_String, QString>(operand.indexRange(), &op->indexRange);
op->alias = UA_STRING_ALLOC(operand.alias().toUtf8().constData());
@@ -567,7 +572,7 @@ bool QOpen62541Subscription::convertWhereClause(const QOpcUaMonitoringParameters
if (!operand.browsePath().at(k).referenceTypeId().isEmpty())
op->browsePath.elements[k].referenceTypeId = Open62541Utils::nodeIdFromQString(
operand.browsePath().at(k).referenceTypeId());
- QOpen62541ValueConverter::scalarFromQt<UA_QualifiedName, QOpcUa::QQualifiedName>(
+ QOpen62541ValueConverter::scalarFromQt<UA_QualifiedName, QOpcUaQualifiedName>(
operand.browsePath().at(k).targetName(), &op->browsePath.elements[k].targetName);
}
@@ -585,9 +590,9 @@ bool QOpen62541Subscription::convertWhereClause(const QOpcUaMonitoringParameters
return true;
}
-QOpcUa::QEventFilterResult QOpen62541Subscription::convertEventFilterResult(UA_ExtensionObject *obj)
+QOpcUaEventFilterResult QOpen62541Subscription::convertEventFilterResult(UA_ExtensionObject *obj)
{
- QOpcUa::QEventFilterResult result;
+ QOpcUaEventFilterResult result;
if (!obj)
return result;
@@ -599,7 +604,7 @@ QOpcUa::QEventFilterResult QOpen62541Subscription::convertEventFilterResult(UA_E
result.selectClauseResultsRef().append(static_cast<QOpcUa::UaStatusCode>(filterResult->selectClauseResults[i]));
for (size_t i = 0; i < filterResult->whereClauseResult.elementResultsSize; ++i) {
- QOpcUa::QContentFilterElementResult temp;
+ QOpcUaContentFilterElementResult temp;
temp.setStatusCode(static_cast<QOpcUa::UaStatusCode>(filterResult->whereClauseResult.elementResults[i].statusCode));
for (size_t j = 0; j < filterResult->whereClauseResult.elementResults[i].operandStatusCodesSize; ++j)
temp.operandStatusCodesRef().append(static_cast<QOpcUa::UaStatusCode>(
@@ -611,7 +616,7 @@ QOpcUa::QEventFilterResult QOpen62541Subscription::convertEventFilterResult(UA_E
return result;
}
-bool QOpen62541Subscription::modifySubscriptionParameters(quint64 handle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value)
+bool QOpen62541Subscription::modifySubscriptionParameters(quint64 nodeHandle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value)
{
QOpcUaMonitoringParameters p;
@@ -632,7 +637,7 @@ bool QOpen62541Subscription::modifySubscriptionParameters(quint64 handle, QOpcUa
if (!ok) {
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not modify PublishingInterval, value is not a double";
p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
break;
@@ -643,7 +648,7 @@ bool QOpen62541Subscription::modifySubscriptionParameters(quint64 handle, QOpcUa
if (!ok) {
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not modify LifetimeCount, value is not an integer";
p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
break;
@@ -654,7 +659,7 @@ bool QOpen62541Subscription::modifySubscriptionParameters(quint64 handle, QOpcUa
if (!ok) {
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not modify MaxKeepAliveCount, value is not an integer";
p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
break;
@@ -665,7 +670,7 @@ bool QOpen62541Subscription::modifySubscriptionParameters(quint64 handle, QOpcUa
if (!ok) {
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not modify Priority, value is not an integer";
p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
break;
@@ -676,7 +681,7 @@ bool QOpen62541Subscription::modifySubscriptionParameters(quint64 handle, QOpcUa
if (!ok) {
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not modify MaxNotificationsPerPublish, value is not an integer";
p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
break;
@@ -691,7 +696,7 @@ bool QOpen62541Subscription::modifySubscriptionParameters(quint64 handle, QOpcUa
if (res.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
p.setStatusCode(static_cast<QOpcUa::UaStatusCode>(res.responseHeader.serviceResult));
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
} else {
QOpcUaMonitoringParameters::Parameters changed = item;
if (!qFuzzyCompare(p.publishingInterval(), m_interval))
@@ -724,9 +729,9 @@ bool QOpen62541Subscription::modifySubscriptionParameters(quint64 handle, QOpcUa
return false;
}
-bool QOpen62541Subscription::modifyMonitoredItemParameters(quint64 handle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value)
+bool QOpen62541Subscription::modifyMonitoredItemParameters(quint64 nodeHandle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value)
{
- MonitoredItem *monItem = getItemForAttribute(handle, attr);
+ MonitoredItem *monItem = getItemForAttribute(nodeHandle, attr);
QOpcUaMonitoringParameters p = monItem->parameters;
UA_ModifyMonitoredItemsRequest req;
@@ -750,7 +755,7 @@ bool QOpen62541Subscription::modifyMonitoredItemParameters(quint64 handle, QOpcU
if (value.type() != QVariant::Bool) {
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not modify DiscardOldest, value is not a bool";
p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
req.itemsToModify->requestedParameters.discardOldest = value.toBool();
@@ -760,7 +765,7 @@ bool QOpen62541Subscription::modifyMonitoredItemParameters(quint64 handle, QOpcU
if (value.type() != QVariant::UInt) {
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not modify QueueSize, value is not an integer";
p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
req.itemsToModify->requestedParameters.queueSize = value.toUInt();
@@ -770,7 +775,7 @@ bool QOpen62541Subscription::modifyMonitoredItemParameters(quint64 handle, QOpcU
if (value.type() != QVariant::Double) {
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not modify SamplingInterval, value is not a double";
p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
req.itemsToModify->requestedParameters.samplingInterval = value.toDouble();
@@ -783,7 +788,7 @@ bool QOpen62541Subscription::modifyMonitoredItemParameters(quint64 handle, QOpcU
else {
qCDebug(QT_OPCUA_PLUGINS_OPEN62541) << "Unable to modify filter, filter creation failed";
p.setStatusCode(QOpcUa::UaStatusCode::BadInternalError);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
break;
@@ -801,7 +806,7 @@ bool QOpen62541Subscription::modifyMonitoredItemParameters(quint64 handle, QOpcU
else {
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not modify monitored item, filter creation failed";
p.setStatusCode(QOpcUa::UaStatusCode::BadInternalError);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
}
@@ -812,7 +817,7 @@ bool QOpen62541Subscription::modifyMonitoredItemParameters(quint64 handle, QOpcU
if (res.responseHeader.serviceResult != UA_STATUSCODE_GOOD || res.results[0].statusCode != UA_STATUSCODE_GOOD) {
p.setStatusCode(static_cast<QOpcUa::UaStatusCode>(res.responseHeader.serviceResult == UA_STATUSCODE_GOOD ? res.results[0].statusCode : res.responseHeader.serviceResult));
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
} else {
p.setStatusCode(QOpcUa::UaStatusCode::Good);
@@ -841,7 +846,7 @@ bool QOpen62541Subscription::modifyMonitoredItemParameters(quint64 handle, QOpcU
p.setFilterResult(convertEventFilterResult(&res.results[0].filterResult));
}
- emit m_backend->monitoringStatusChanged(handle, attr, changed, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, changed, p);
monItem->parameters = p;
}
diff --git a/src/plugins/opcua/open62541/qopen62541subscription.h b/src/plugins/opcua/open62541/qopen62541subscription.h
index b20b50f..5214599 100644
--- a/src/plugins/opcua/open62541/qopen62541subscription.h
+++ b/src/plugins/opcua/open62541/qopen62541subscription.h
@@ -92,7 +92,7 @@ signals:
void timeout(QOpen62541Subscription *sub, QVector<QPair<quint64, QOpcUa::NodeAttribute>> items);
private:
- MonitoredItem *getItemForAttribute(quint64 handle, QOpcUa::NodeAttribute attr);
+ MonitoredItem *getItemForAttribute(quint64 nodeHandle, QOpcUa::NodeAttribute attr);
UA_ExtensionObject createFilter(const QVariant &filterData);
void createDataChangeFilter(const QOpcUaMonitoringParameters::DataChangeFilter &filter, UA_ExtensionObject *out);
void createEventFilter(const QOpcUaMonitoringParameters::EventFilter &filter, UA_ExtensionObject *out);
@@ -100,9 +100,9 @@ private:
UA_SimpleAttributeOperand **selectClauses, size_t *size);
bool convertWhereClause(const QOpcUaMonitoringParameters::EventFilter &filter, UA_ContentFilter *result);
- bool modifySubscriptionParameters(quint64 handle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value);
- bool modifyMonitoredItemParameters(quint64 handle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value);
- QOpcUa::QEventFilterResult convertEventFilterResult(UA_ExtensionObject *obj);
+ bool modifySubscriptionParameters(quint64 nodeHandle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value);
+ bool modifyMonitoredItemParameters(quint64 nodeHandle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value);
+ QOpcUaEventFilterResult convertEventFilterResult(UA_ExtensionObject *obj);
Open62541AsyncBackend *m_backend;
double m_interval;
@@ -113,7 +113,7 @@ private:
quint8 m_priority;
quint32 m_maxNotificationsPerPublish;
- QHash<quint64, QHash<QOpcUa::NodeAttribute, MonitoredItem *>> m_handleToItemMapping; // Handle -> Attribute -> MonitoredItem
+ QHash<quint64, QHash<QOpcUa::NodeAttribute, MonitoredItem *>> m_nodeHandleToItemMapping; // Handle -> Attribute -> MonitoredItem
QHash<UA_UInt32, MonitoredItem *> m_itemIdToItemMapping; // ItemId -> Item for fast lookup on data change
quint32 m_clientHandle;
diff --git a/src/plugins/opcua/open62541/qopen62541utils.h b/src/plugins/opcua/open62541/qopen62541utils.h
index 5a40c6c..fd13219 100644
--- a/src/plugins/opcua/open62541/qopen62541utils.h
+++ b/src/plugins/opcua/open62541/qopen62541utils.h
@@ -59,6 +59,11 @@ public:
if (m_data)
m_function(m_data);
}
+ void release()
+ {
+ m_data = nullptr;
+ m_function = nullptr;
+ }
private:
T *m_data {nullptr};
std::function<void(T *attribute)> m_function;
@@ -79,6 +84,10 @@ public:
if (m_data && m_arrayLength > 0)
UA_Array_delete(m_data, m_arrayLength, &UA_TYPES[TYPEINDEX]);
}
+ void release() {
+ m_data = nullptr;
+ m_arrayLength = 0;
+ }
private:
void *m_data {nullptr};
size_t m_arrayLength {0};
diff --git a/src/plugins/opcua/open62541/qopen62541valueconverter.cpp b/src/plugins/opcua/open62541/qopen62541valueconverter.cpp
index f342a8e..15e5b91 100644
--- a/src/plugins/opcua/open62541/qopen62541valueconverter.cpp
+++ b/src/plugins/opcua/open62541/qopen62541valueconverter.cpp
@@ -38,6 +38,8 @@
#include "qopen62541utils.h"
#include "qopen62541valueconverter.h"
+#include "qopcuamultidimensionalarray.h"
+
#include <QtCore/qdatetime.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/quuid.h>
@@ -52,53 +54,13 @@ using namespace QOpcUa::NodeIds;
namespace QOpen62541ValueConverter {
-QOpcUa::Types qvariantTypeToQOpcUaType(QMetaType::Type type)
-{
- switch (type) {
- case QMetaType::Bool:
- return QOpcUa::Boolean;
- case QMetaType::UChar:
- return QOpcUa::Byte;
- case QMetaType::Char:
- return QOpcUa::SByte;
- case QMetaType::UShort:
- return QOpcUa::UInt16;
- case QMetaType::Short:
- return QOpcUa::Int16;
- case QMetaType::Int:
- return QOpcUa::Int32;
- case QMetaType::UInt:
- return QOpcUa::UInt32;
- case QMetaType::ULongLong:
- return QOpcUa::UInt64;
- case QMetaType::LongLong:
- return QOpcUa::Int64;
- case QMetaType::Double:
- return QOpcUa::Double;
- case QMetaType::Float:
- return QOpcUa::Float;
- case QMetaType::QString:
- return QOpcUa::String;
- case QMetaType::QDateTime:
- return QOpcUa::DateTime;
- case QMetaType::QByteArray:
- return QOpcUa::ByteString;
- case QMetaType::QUuid:
- return QOpcUa::Guid;
- default:
- break;
- }
-
- return QOpcUa::Undefined;
-}
-
UA_Variant toOpen62541Variant(const QVariant &value, QOpcUa::Types type)
{
UA_Variant open62541value;
UA_Variant_init(&open62541value);
- if (value.canConvert<QOpcUa::QMultiDimensionalArray>()) {
- QOpcUa::QMultiDimensionalArray data = value.value<QOpcUa::QMultiDimensionalArray>();
+ if (value.canConvert<QOpcUaMultiDimensionalArray>()) {
+ QOpcUaMultiDimensionalArray data = value.value<QOpcUaMultiDimensionalArray>();
UA_Variant result = toOpen62541Variant(data.valueArray(), type);
if (!data.arrayDimensions().isEmpty()) {
@@ -117,7 +79,7 @@ UA_Variant toOpen62541Variant(const QVariant &value, QOpcUa::Types type)
QVariant temp = (value.type() == QVariant::List) ? value.toList().at(0) : value;
QOpcUa::Types valueType = type == QOpcUa::Undefined ?
- qvariantTypeToQOpcUaType(static_cast<QMetaType::Type>(temp.type())) : type;
+ QOpcUa::metaTypeToQOpcUaType(static_cast<QMetaType::Type>(temp.type())) : type;
const UA_DataType *dt = toDataType(valueType);
@@ -149,7 +111,7 @@ UA_Variant toOpen62541Variant(const QVariant &value, QOpcUa::Types type)
case QOpcUa::String:
return arrayFromQVariant<UA_String, QString>(value, dt);
case QOpcUa::LocalizedText:
- return arrayFromQVariant<UA_LocalizedText, QOpcUa::QLocalizedText>(value, dt);
+ return arrayFromQVariant<UA_LocalizedText, QOpcUaLocalizedText>(value, dt);
case QOpcUa::ByteString:
return arrayFromQVariant<UA_ByteString, QByteArray>(value, dt);
case QOpcUa::NodeId:
@@ -159,27 +121,27 @@ UA_Variant toOpen62541Variant(const QVariant &value, QOpcUa::Types type)
case QOpcUa::XmlElement:
return arrayFromQVariant<UA_XmlElement, QString>(value, dt);
case QOpcUa::QualifiedName:
- return arrayFromQVariant<UA_QualifiedName, QOpcUa::QQualifiedName>(value, dt);
+ return arrayFromQVariant<UA_QualifiedName, QOpcUaQualifiedName>(value, dt);
case QOpcUa::StatusCode:
return arrayFromQVariant<UA_StatusCode, QOpcUa::UaStatusCode>(value, dt);
case QOpcUa::Range:
- return arrayFromQVariant<UA_ExtensionObject, QOpcUa::QRange>(value, dt);
+ return arrayFromQVariant<UA_ExtensionObject, QOpcUaRange>(value, dt);
case QOpcUa::EUInformation:
- return arrayFromQVariant<UA_ExtensionObject, QOpcUa::QEUInformation>(value, dt);
+ return arrayFromQVariant<UA_ExtensionObject, QOpcUaEUInformation>(value, dt);
case QOpcUa::ComplexNumber:
- return arrayFromQVariant<UA_ExtensionObject, QOpcUa::QComplexNumber>(value, dt);
+ return arrayFromQVariant<UA_ExtensionObject, QOpcUaComplexNumber>(value, dt);
case QOpcUa::DoubleComplexNumber:
- return arrayFromQVariant<UA_ExtensionObject, QOpcUa::QDoubleComplexNumber>(value, dt);
+ return arrayFromQVariant<UA_ExtensionObject, QOpcUaDoubleComplexNumber>(value, dt);
case QOpcUa::AxisInformation:
- return arrayFromQVariant<UA_ExtensionObject, QOpcUa::QAxisInformation>(value, dt);
+ return arrayFromQVariant<UA_ExtensionObject, QOpcUaAxisInformation>(value, dt);
case QOpcUa::XV:
- return arrayFromQVariant<UA_ExtensionObject, QOpcUa::QXValue>(value, dt);
+ return arrayFromQVariant<UA_ExtensionObject, QOpcUaXValue>(value, dt);
case QOpcUa::ExpandedNodeId:
- return arrayFromQVariant<UA_ExpandedNodeId, QOpcUa::QExpandedNodeId>(value, dt);
+ return arrayFromQVariant<UA_ExpandedNodeId, QOpcUaExpandedNodeId>(value, dt);
case QOpcUa::Argument:
- return arrayFromQVariant<UA_Argument, QOpcUa::QArgument>(value, dt);
+ return arrayFromQVariant<UA_Argument, QOpcUaArgument>(value, dt);
case QOpcUa::ExtensionObject:
- return arrayFromQVariant<UA_ExtensionObject, QOpcUa::QExtensionObject>(value, dt);
+ return arrayFromQVariant<UA_ExtensionObject, QOpcUaExtensionObject>(value, dt);
default:
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Variant conversion to Open62541 for typeIndex" << type << " not implemented";
}
@@ -221,7 +183,7 @@ QVariant toQVariant(const UA_Variant &value)
case UA_TYPES_BYTESTRING:
return arrayToQVariant<QByteArray, UA_ByteString>(value, QMetaType::QByteArray);
case UA_TYPES_LOCALIZEDTEXT:
- return arrayToQVariant<QOpcUa::QLocalizedText, UA_LocalizedText>(value);
+ return arrayToQVariant<QOpcUaLocalizedText, UA_LocalizedText>(value);
case UA_TYPES_NODEID:
return arrayToQVariant<QString, UA_NodeId>(value, QMetaType::QString);
case UA_TYPES_DATETIME:
@@ -231,15 +193,15 @@ QVariant toQVariant(const UA_Variant &value)
case UA_TYPES_XMLELEMENT:
return arrayToQVariant<QString, UA_XmlElement>(value, QMetaType::QString);
case UA_TYPES_QUALIFIEDNAME:
- return arrayToQVariant<QOpcUa::QQualifiedName, UA_QualifiedName>(value);
+ return arrayToQVariant<QOpcUaQualifiedName, UA_QualifiedName>(value);
case UA_TYPES_STATUSCODE:
return arrayToQVariant<QOpcUa::UaStatusCode, UA_StatusCode>(value, QMetaType::UInt);
case UA_TYPES_EXTENSIONOBJECT:
return arrayToQVariant<QVariant, UA_ExtensionObject>(value);
case UA_TYPES_EXPANDEDNODEID:
- return arrayToQVariant<QOpcUa::QExpandedNodeId, UA_ExpandedNodeId>(value);
+ return arrayToQVariant<QOpcUaExpandedNodeId, UA_ExpandedNodeId>(value);
case UA_TYPES_ARGUMENT:
- return arrayToQVariant<QOpcUa::QArgument, UA_Argument>(value);
+ return arrayToQVariant<QOpcUaArgument, UA_Argument>(value);
default:
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Variant conversion from Open62541 for typeIndex" << value.type->typeIndex << " not implemented";
return QVariant();
@@ -326,9 +288,9 @@ QByteArray scalarToQt<QByteArray, UA_ByteString>(const UA_ByteString *data)
}
template<>
-QOpcUa::QLocalizedText scalarToQt<QOpcUa::QLocalizedText, UA_LocalizedText>(const UA_LocalizedText *data)
+QOpcUaLocalizedText scalarToQt<QOpcUaLocalizedText, UA_LocalizedText>(const UA_LocalizedText *data)
{
- QOpcUa::QLocalizedText lt;
+ QOpcUaLocalizedText lt;
lt.setLocale(scalarToQt<QString, UA_String>(&(data->locale)));
lt.setText(scalarToQt<QString, UA_String>(&(data->text)));
return lt;
@@ -356,22 +318,22 @@ QUuid scalarToQt<QUuid, UA_Guid>(const UA_Guid *data)
}
template<>
-QOpcUa::QQualifiedName scalarToQt<QOpcUa::QQualifiedName, UA_QualifiedName>(const UA_QualifiedName *data)
+QOpcUaQualifiedName scalarToQt<QOpcUaQualifiedName, UA_QualifiedName>(const UA_QualifiedName *data)
{
- QOpcUa::QQualifiedName temp;
+ QOpcUaQualifiedName temp;
temp.setNamespaceIndex(data->namespaceIndex);
temp.setName(scalarToQt<QString, UA_String>(&(data->name)));
return temp;
}
template<>
-QOpcUa::QArgument scalarToQt<QOpcUa::QArgument, UA_Argument>(const UA_Argument *data)
+QOpcUaArgument scalarToQt<QOpcUaArgument, UA_Argument>(const UA_Argument *data)
{
- QOpcUa::QArgument temp;
+ QOpcUaArgument temp;
temp.setValueRank(data->valueRank);
temp.setDataTypeId(Open62541Utils::nodeIdToQString(data->dataType));
temp.setName(scalarToQt<QString, UA_String>(&data->name));
- temp.setDescription(scalarToQt<QOpcUa::QLocalizedText, UA_LocalizedText>(&data->description));
+ temp.setDescription(scalarToQt<QOpcUaLocalizedText, UA_LocalizedText>(&data->description));
for (size_t i = 0; i < data->arrayDimensionsSize; ++i)
temp.arrayDimensionsRef().append(data->arrayDimensions[i]);
return temp;
@@ -385,8 +347,8 @@ QVariant scalarToQt<QVariant, UA_ExtensionObject>(const UA_ExtensionObject *data
// Handle extension object without body
if (data->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) {
- QOpcUa::QExtensionObject obj;
- obj.setEncoding(QOpcUa::QExtensionObject::Encoding::NoBody);
+ QOpcUaExtensionObject obj;
+ obj.setEncoding(QOpcUaExtensionObject::Encoding::NoBody);
return QVariant::fromValue(obj);
}
@@ -394,7 +356,7 @@ QVariant scalarToQt<QVariant, UA_ExtensionObject>(const UA_ExtensionObject *data
if (data->encoding != UA_EXTENSIONOBJECT_ENCODED_XML && data->encoding != UA_EXTENSIONOBJECT_ENCODED_BYTESTRING) {
if (data->content.decoded.type == &UA_TYPES[UA_TYPES_ARGUMENT] && data->content.decoded.data != nullptr) {
- return scalarToQt<QOpcUa::QArgument, UA_Argument>(reinterpret_cast<UA_Argument *>(data->content.decoded.data));
+ return scalarToQt<QOpcUaArgument, UA_Argument>(reinterpret_cast<UA_Argument *>(data->content.decoded.data));
}
qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Unsupported decoded extension object type, unable to convert";
@@ -416,22 +378,22 @@ QVariant scalarToQt<QVariant, UA_ExtensionObject>(const UA_ExtensionObject *data
Namespace0 objType = Namespace0(data->content.encoded.typeId.identifier.numeric);
switch (objType) {
case Namespace0::EUInformation_Encoding_DefaultBinary:
- result = decoder.decode<QOpcUa::QEUInformation>(success);
+ result = decoder.decode<QOpcUaEUInformation>(success);
break;
case Namespace0::Range_Encoding_DefaultBinary:
- result = decoder.decode<QOpcUa::QRange>(success);
+ result = decoder.decode<QOpcUaRange>(success);
break;
case Namespace0::ComplexNumberType_Encoding_DefaultBinary:
- result = decoder.decode<QOpcUa::QComplexNumber>(success);
+ result = decoder.decode<QOpcUaComplexNumber>(success);
break;
case Namespace0::DoubleComplexNumberType_Encoding_DefaultBinary:
- result = decoder.decode<QOpcUa::QDoubleComplexNumber>(success);
+ result = decoder.decode<QOpcUaDoubleComplexNumber>(success);
break;
case Namespace0::AxisInformation_Encoding_DefaultBinary:
- result = decoder.decode<QOpcUa::QAxisInformation>(success);
+ result = decoder.decode<QOpcUaAxisInformation>(success);
break;
case Namespace0::XVType_Encoding_DefaultBinary:
- result = decoder.decode<QOpcUa::QXValue>(success);
+ result = decoder.decode<QOpcUaXValue>(success);
break;
default:
break;
@@ -440,18 +402,18 @@ QVariant scalarToQt<QVariant, UA_ExtensionObject>(const UA_ExtensionObject *data
return result;
}
- // Return extension objects with binary or XML body as QOpcUa::QExtensionObject
- QOpcUa::QExtensionObject obj;
- obj.setEncoding(static_cast<QOpcUa::QExtensionObject::Encoding>(data->encoding));
+ // Return extension objects with binary or XML body as QOpcUaExtensionObject
+ QOpcUaExtensionObject obj;
+ obj.setEncoding(static_cast<QOpcUaExtensionObject::Encoding>(data->encoding));
obj.setEncodingTypeId(Open62541Utils::nodeIdToQString(data->content.encoded.typeId));
obj.setEncodedBody(QByteArray(buffer.constData(), buffer.size()));
return obj;
}
template<>
-QOpcUa::QExpandedNodeId scalarToQt<QOpcUa::QExpandedNodeId, UA_ExpandedNodeId>(const UA_ExpandedNodeId *data)
+QOpcUaExpandedNodeId scalarToQt<QOpcUaExpandedNodeId, UA_ExpandedNodeId>(const UA_ExpandedNodeId *data)
{
- QOpcUa::QExpandedNodeId temp;
+ QOpcUaExpandedNodeId temp;
temp.setServerIndex(data->serverIndex);
temp.setNodeId(Open62541Utils::nodeIdToQString(data->nodeId));
temp.setNamespaceUri(scalarToQt<QString, UA_String>(&data->namespaceUri));
@@ -475,10 +437,10 @@ QVariant arrayToQVariant(const UA_Variant &var, QMetaType::Type type)
if (var.arrayDimensionsSize > 0) {
// Ensure that the array dimensions fit in a QVector
if (var.arrayDimensionsSize > static_cast<quint64>((std::numeric_limits<int>::max)()))
- return QOpcUa::QMultiDimensionalArray();
+ return QOpcUaMultiDimensionalArray();
QVector<quint32> arrayDimensions;
std::copy(var.arrayDimensions, var.arrayDimensions+var.arrayDimensionsSize, std::back_inserter(arrayDimensions));
- return QOpcUa::QMultiDimensionalArray(list, arrayDimensions);
+ return QOpcUaMultiDimensionalArray(list, arrayDimensions);
}
if (list.size() == 1)
@@ -519,7 +481,7 @@ void scalarFromQt<UA_String, QString>(const QString &value, UA_String *ptr)
}
template<>
-void scalarFromQt<UA_LocalizedText, QOpcUa::QLocalizedText>(const QOpcUa::QLocalizedText &value, UA_LocalizedText *ptr)
+void scalarFromQt<UA_LocalizedText, QOpcUaLocalizedText>(const QOpcUaLocalizedText &value, UA_LocalizedText *ptr)
{
scalarFromQt<UA_String, QString>(value.locale(), &(ptr->locale));
scalarFromQt<UA_String, QString>(value.text(), &(ptr->text));
@@ -544,7 +506,7 @@ void scalarFromQt<UA_NodeId, QString>(const QString &value, UA_NodeId *ptr)
}
template<>
-void scalarFromQt<UA_QualifiedName, QOpcUa::QQualifiedName>(const QOpcUa::QQualifiedName &value, UA_QualifiedName *ptr)
+void scalarFromQt<UA_QualifiedName, QOpcUaQualifiedName>(const QOpcUaQualifiedName &value, UA_QualifiedName *ptr)
{
ptr->namespaceIndex = value.namespaceIndex();
scalarFromQt<UA_String, QString>(value.name(), &(ptr->name));
@@ -560,67 +522,67 @@ void scalarFromQt<UA_Guid, QUuid>(const QUuid &value, UA_Guid *ptr)
}
template<>
-void scalarFromQt<UA_ExtensionObject, QOpcUa::QRange>(const QOpcUa::QRange &value, UA_ExtensionObject *ptr)
+void scalarFromQt<UA_ExtensionObject, QOpcUaRange>(const QOpcUaRange &value, UA_ExtensionObject *ptr)
{
QByteArray temp;
QOpcUaBinaryDataEncoding encoder(&temp);
- encoder.encode<QOpcUa::QRange>(value);
+ encoder.encode<QOpcUaRange>(value);
return createExtensionObject(temp,
UA_NODEID_NUMERIC(0,static_cast<UA_UInt32>(Namespace0::Range_Encoding_DefaultBinary)), ptr);
}
template<>
-void scalarFromQt<UA_ExtensionObject, QOpcUa::QEUInformation>(const QOpcUa::QEUInformation &value, UA_ExtensionObject *ptr)
+void scalarFromQt<UA_ExtensionObject, QOpcUaEUInformation>(const QOpcUaEUInformation &value, UA_ExtensionObject *ptr)
{
QByteArray temp;
QOpcUaBinaryDataEncoding encoder(&temp);
- encoder.encode<QOpcUa::QEUInformation>(value);
+ encoder.encode<QOpcUaEUInformation>(value);
return createExtensionObject(temp,
UA_NODEID_NUMERIC(0, static_cast<UA_UInt32>(Namespace0::EUInformation_Encoding_DefaultBinary)), ptr);
}
template<>
-void scalarFromQt<UA_ExtensionObject, QOpcUa::QComplexNumber>(const QOpcUa::QComplexNumber &value, UA_ExtensionObject *ptr)
+void scalarFromQt<UA_ExtensionObject, QOpcUaComplexNumber>(const QOpcUaComplexNumber &value, UA_ExtensionObject *ptr)
{
QByteArray temp;
QOpcUaBinaryDataEncoding encoder(&temp);
- encoder.encode<QOpcUa::QComplexNumber>(value);
+ encoder.encode<QOpcUaComplexNumber>(value);
return createExtensionObject(temp,
UA_NODEID_NUMERIC(0, static_cast<UA_UInt32>(Namespace0::ComplexNumberType_Encoding_DefaultBinary)), ptr);
}
template<>
-void scalarFromQt<UA_ExtensionObject, QOpcUa::QDoubleComplexNumber>(const QOpcUa::QDoubleComplexNumber &value, UA_ExtensionObject *ptr)
+void scalarFromQt<UA_ExtensionObject, QOpcUaDoubleComplexNumber>(const QOpcUaDoubleComplexNumber &value, UA_ExtensionObject *ptr)
{
QByteArray temp;
QOpcUaBinaryDataEncoding encoder(&temp);
- encoder.encode<QOpcUa::QDoubleComplexNumber>(value);
+ encoder.encode<QOpcUaDoubleComplexNumber>(value);
return createExtensionObject(temp,
UA_NODEID_NUMERIC(0, static_cast<UA_UInt32>(Namespace0::DoubleComplexNumberType_Encoding_DefaultBinary)), ptr);
}
template<>
-void scalarFromQt<UA_ExtensionObject, QOpcUa::QAxisInformation>(const QOpcUa::QAxisInformation &value, UA_ExtensionObject *ptr)
+void scalarFromQt<UA_ExtensionObject, QOpcUaAxisInformation>(const QOpcUaAxisInformation &value, UA_ExtensionObject *ptr)
{
QByteArray temp;
QOpcUaBinaryDataEncoding encoder(&temp);
- encoder.encode<QOpcUa::QAxisInformation>(value);
+ encoder.encode<QOpcUaAxisInformation>(value);
return createExtensionObject(temp,
UA_NODEID_NUMERIC(0, static_cast<UA_UInt32>(Namespace0::AxisInformation_Encoding_DefaultBinary)), ptr);
}
template<>
-void scalarFromQt<UA_ExtensionObject, QOpcUa::QXValue>(const QOpcUa::QXValue &value, UA_ExtensionObject *ptr)
+void scalarFromQt<UA_ExtensionObject, QOpcUaXValue>(const QOpcUaXValue &value, UA_ExtensionObject *ptr)
{
QByteArray temp;
QOpcUaBinaryDataEncoding encoder(&temp);
- encoder.encode<QOpcUa::QXValue>(value);
+ encoder.encode<QOpcUaXValue>(value);
return createExtensionObject(temp,
UA_NODEID_NUMERIC(0, static_cast<UA_UInt32>(Namespace0::XVType_Encoding_DefaultBinary)), ptr);
}
template<>
-void scalarFromQt<UA_ExtensionObject, QOpcUa::QExtensionObject>(const QOpcUa::QExtensionObject &obj, UA_ExtensionObject *ptr)
+void scalarFromQt<UA_ExtensionObject, QOpcUaExtensionObject>(const QOpcUaExtensionObject &obj, UA_ExtensionObject *ptr)
{
QByteArray temp = obj.encodedBody();
UA_NodeId encodingId = Open62541Utils::nodeIdFromQString(obj.encodingTypeId());
@@ -629,7 +591,7 @@ void scalarFromQt<UA_ExtensionObject, QOpcUa::QExtensionObject>(const QOpcUa::QE
}
template<>
-void scalarFromQt<UA_ExpandedNodeId, QOpcUa::QExpandedNodeId>(const QOpcUa::QExpandedNodeId &value, UA_ExpandedNodeId *ptr)
+void scalarFromQt<UA_ExpandedNodeId, QOpcUaExpandedNodeId>(const QOpcUaExpandedNodeId &value, UA_ExpandedNodeId *ptr)
{
ptr->serverIndex = value.serverIndex();
scalarFromQt<UA_String, QString>(value.namespaceUri(), &ptr->namespaceUri);
@@ -637,10 +599,10 @@ void scalarFromQt<UA_ExpandedNodeId, QOpcUa::QExpandedNodeId>(const QOpcUa::QExp
}
template<>
-void scalarFromQt<UA_Argument, QOpcUa::QArgument>(const QOpcUa::QArgument &value, UA_Argument *ptr)
+void scalarFromQt<UA_Argument, QOpcUaArgument>(const QOpcUaArgument &value, UA_Argument *ptr)
{
ptr->valueRank = value.valueRank();
- scalarFromQt<UA_LocalizedText, QOpcUa::QLocalizedText>(value.description(), &ptr->description);
+ scalarFromQt<UA_LocalizedText, QOpcUaLocalizedText>(value.description(), &ptr->description);
scalarFromQt<UA_String, QString>(value.name(), &ptr->name);
ptr->dataType = Open62541Utils::nodeIdFromQString(value.dataTypeId());
ptr->arrayDimensionsSize = value.arrayDimensions().size();
@@ -695,11 +657,11 @@ UA_Variant arrayFromQVariant(const QVariant &var, const UA_DataType *type)
return open62541value;
}
-void createExtensionObject(QByteArray &data, const UA_NodeId &typeEncodingId, UA_ExtensionObject *ptr, QOpcUa::QExtensionObject::Encoding encoding)
+void createExtensionObject(QByteArray &data, const UA_NodeId &typeEncodingId, UA_ExtensionObject *ptr, QOpcUaExtensionObject::Encoding encoding)
{
UA_ExtensionObject obj;
UA_ExtensionObject_init(&obj);
- if (encoding != QOpcUa::QExtensionObject::Encoding::NoBody) {
+ if (encoding != QOpcUaExtensionObject::Encoding::NoBody) {
obj.encoding = static_cast<UA_ExtensionObjectEncoding>(encoding);
obj.content.encoded.body.data = reinterpret_cast<UA_Byte *>(data.data());
obj.content.encoded.body.length = data.length();
diff --git a/src/plugins/opcua/open62541/qopen62541valueconverter.h b/src/plugins/opcua/open62541/qopen62541valueconverter.h
index 8dd1253..1f2442c 100644
--- a/src/plugins/opcua/open62541/qopen62541valueconverter.h
+++ b/src/plugins/opcua/open62541/qopen62541valueconverter.h
@@ -77,7 +77,7 @@ namespace QOpen62541ValueConverter {
UA_Variant arrayFromQVariant(const QVariant &var, const UA_DataType *type);
void createExtensionObject(QByteArray &data, const UA_NodeId &typeEncodingId, UA_ExtensionObject *ptr,
- QOpcUa::QExtensionObject::Encoding encoding = QOpcUa::QExtensionObject::Encoding::ByteString);
+ QOpcUaExtensionObject::Encoding encoding = QOpcUaExtensionObject::Encoding::ByteString);
}
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/uacpp/quacppbackend.cpp b/src/plugins/opcua/uacpp/quacppbackend.cpp
index 527041e..318b2e2 100644
--- a/src/plugins/opcua/uacpp/quacppbackend.cpp
+++ b/src/plugins/opcua/uacpp/quacppbackend.cpp
@@ -1,19 +1,27 @@
/******************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:COMM$
-**
+** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -25,8 +33,12 @@
#include "quacpputils.h"
#include "quacppvalueconverter.h"
+#include "qopcuaauthenticationinformation.h"
+
#include <private/qopcuaclient_p.h>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
#include <QtCore/QLoggingCategory>
#include <QtCore/QStringList>
#include <QtCore/QUrl>
@@ -39,6 +51,7 @@
#include <uastring.h>
#include <uadiscovery.h>
#include <uadatavalue.h>
+#include <uapkicertificate.h>
#include <limits>
@@ -123,6 +136,24 @@ void UACppAsyncBackend::connectionStatusChanged(OpcUa_UInt32 clientConnectionId,
}
}
+bool UACppAsyncBackend::connectError(OpcUa_UInt32 clientConnectionId, UaClientSdk::UaClient::ConnectServiceType serviceType,
+ const UaStatus &error, bool clientSideError)
+{
+ Q_UNUSED(clientConnectionId);
+
+ QOpcUaErrorState errorState;
+ errorState.setConnectionStep(connectionStepFromUaServiceType(serviceType));
+ errorState.setErrorCode(static_cast<QOpcUa::UaStatusCode>(error.statusCode()));
+ errorState.setClientSideError(clientSideError);
+ errorState.setIgnoreError(false);
+
+ // This signal is connected using Qt::BlockingQueuedConnection. It will place a metacall to a different thread and waits
+ // until this metacall is fully handled before returning.
+ emit QOpcUaBackend::connectError(&errorState);
+
+ return errorState.ignoreError();
+}
+
void UACppAsyncBackend::browse(quint64 handle, const UaNodeId &id, const QOpcUaBrowseRequest &request)
{
UaStatus status;
@@ -158,7 +189,7 @@ void UACppAsyncBackend::browse(quint64 handle, const UaNodeId &id, const QOpcUaB
result.append(QString::fromUtf8(uastr.toUtf8(), uastr.size()));
QOpcUaReferenceDescription temp;
- QOpcUa::QExpandedNodeId expandedId;
+ QOpcUaExpandedNodeId expandedId;
expandedId.setNamespaceUri(QString::fromUtf8(UaString(referenceDescriptions[i].NodeId.NamespaceUri).toUtf8()));
expandedId.setServerIndex(referenceDescriptions[i].NodeId.ServerIndex);
expandedId.setNodeId(UACppUtils::nodeIdToQString(referenceDescriptions[i].NodeId.NodeId));
@@ -169,10 +200,10 @@ void UACppAsyncBackend::browse(quint64 handle, const UaNodeId &id, const QOpcUaB
temp.setTypeDefinition(expandedId);
temp.setRefTypeId(UACppUtils::nodeIdToQString(UaNodeId(referenceDescriptions[i].ReferenceTypeId)));
temp.setNodeClass(static_cast<QOpcUa::NodeClass>(referenceDescriptions[i].NodeClass));
- temp.setBrowseName(QUACppValueConverter::scalarToQVariant<QOpcUa::QQualifiedName, OpcUa_QualifiedName>(
- &referenceDescriptions[i].BrowseName, QMetaType::Type::UnknownType).value<QOpcUa::QQualifiedName>());
- temp.setDisplayName(QUACppValueConverter::scalarToQVariant<QOpcUa::QLocalizedText, OpcUa_LocalizedText>(
- &referenceDescriptions[i].DisplayName, QMetaType::Type::UnknownType).value<QOpcUa::QLocalizedText>());
+ temp.setBrowseName(QUACppValueConverter::scalarToQVariant<QOpcUaQualifiedName, OpcUa_QualifiedName>(
+ &referenceDescriptions[i].BrowseName, QMetaType::Type::UnknownType).value<QOpcUaQualifiedName>());
+ temp.setDisplayName(QUACppValueConverter::scalarToQVariant<QOpcUaLocalizedText, OpcUa_LocalizedText>(
+ &referenceDescriptions[i].DisplayName, QMetaType::Type::UnknownType).value<QOpcUaLocalizedText>());
temp.setIsForwardReference(referenceDescriptions[i].IsForward);
ret.append(temp);
}
@@ -181,35 +212,126 @@ void UACppAsyncBackend::browse(quint64 handle, const UaNodeId &id, const QOpcUaB
emit browseFinished(handle, ret, static_cast<QOpcUa::UaStatusCode>(status.statusCode()));
}
-void UACppAsyncBackend::connectToEndpoint(const QUrl &url)
+void UACppAsyncBackend::connectToEndpoint(const QOpcUaEndpointDescription &endpoint)
{
- UaStatus result;
+ if (m_nativeSession->isConnected())
+ disconnectFromEndpoint();
- UaString uaUrl(url.toString(QUrl::RemoveUserInfo).toUtf8().constData());
- SessionConnectInfo sessionConnectInfo;
- UaString sNodeName(QHostInfo::localHostName().toUtf8().constData());
+ QString errorMessage;
+ if (!verifyEndpointDescription(endpoint, &errorMessage)) {
+ qCWarning(QT_OPCUA_PLUGINS_UACPP) << errorMessage;
+ emit stateAndOrErrorChanged(QOpcUaClient::Disconnected, QOpcUaClient::ClientError::InvalidUrl);
+ return;
+ }
- sessionConnectInfo.sApplicationName = "QtOpcUA Unified Automation Backend";
- // Use the host name to generate a unique application URI
- sessionConnectInfo.sApplicationUri = UaString("urn:%1:Qt:OpcUAClient").arg(sNodeName);
- sessionConnectInfo.sProductUri = "urn:Qt:OpcUAClient";
+ emit stateAndOrErrorChanged(QOpcUaClient::Connecting, QOpcUaClient::NoError);
+
+ const auto identity = m_clientImpl->m_client->applicationIdentity();
+ const auto authInfo = m_clientImpl->m_client->authenticationInformation();
+ const auto pkiConfig = m_clientImpl->m_client->pkiConfiguration();
+
+ SessionConnectInfo sessionConnectInfo;
+ sessionConnectInfo.sApplicationName = identity.applicationName().toUtf8().constData();
+ sessionConnectInfo.sApplicationUri = identity.applicationUri().toUtf8().constData();
+ sessionConnectInfo.sProductUri = identity.productUri().toUtf8().constData();
sessionConnectInfo.sSessionName = sessionConnectInfo.sApplicationUri;
- sessionConnectInfo.applicationType = OpcUa_ApplicationType_Client;
sessionConnectInfo.bAutomaticReconnect = OpcUa_False;
+ sessionConnectInfo.applicationType = static_cast<OpcUa_ApplicationType>(identity.applicationType());
SessionSecurityInfo sessionSecurityInfo;
- if (url.userName().length()) {
- UaString username(url.userName().toUtf8().constData());
- UaString password(url.password().toUtf8().constData());
+
+ if (pkiConfig.isPkiValid()) {
+ auto result = sessionSecurityInfo.initializePkiProviderOpenSSL(
+ pkiConfig.revocationListDirectory().toUtf8().constData(),
+ pkiConfig.trustListDirectory().toUtf8().constData(),
+ pkiConfig.issuerRevocationListDirectory().toUtf8().constData(),
+ pkiConfig.issuerListDirectory().toUtf8().constData());
+
+ if (result.isNotGood()) {
+ qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Failed to set up PKI: " << QString::fromUtf8(result.toString().toUtf8());
+ emit stateAndOrErrorChanged(QOpcUaClient::Disconnected, QOpcUaClient::AccessDenied);
+ return;
+ }
+
+ // set server certificate from endpoint
+ sessionSecurityInfo.serverCertificate = UaByteString(endpoint.serverCertificate().length(), (OpcUa_Byte*)(endpoint.serverCertificate().constData()));
+ // set SecurityPolicy
+ sessionSecurityInfo.sSecurityPolicy = endpoint.securityPolicy().toUtf8().constData();
+ // set MessageSecurityMode
+ sessionSecurityInfo.messageSecurityMode = static_cast<OpcUa_MessageSecurityMode>(endpoint.securityMode());
+ }
+
+ if (authInfo.authenticationType() == QOpcUaUserTokenPolicy::TokenType::Anonymous) {
+ // nothing to do
+ } else if (authInfo.authenticationType() == QOpcUaUserTokenPolicy::TokenType::Username) {
+ const auto credentials = authInfo.authenticationData().value<QPair<QString, QString>>();
+ UaString username(credentials.first.toUtf8().constData());
+ UaString password(credentials.second.toUtf8().constData());
sessionSecurityInfo.setUserPasswordUserIdentity(username, password);
if (m_disableEncryptedPasswordCheck)
sessionSecurityInfo.disableEncryptedPasswordCheck = OpcUa_True;
+ } else if (authInfo.authenticationType() == QOpcUaUserTokenPolicy::TokenType::Certificate) {
+ // try to load the client certificate
+ const UaString certificateFilePath(pkiConfig.clientCertificateFile().toUtf8());
+ const UaString privateKeyFilePath(pkiConfig.privateKeyFile().toUtf8());
+ UaStatus result;
+
+ QFile certFile(certificateFilePath.toUtf8());
+ if (certFile.open(QIODevice::ReadOnly)) {
+ certFile.close();
+ } else {
+ qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Failed to load certificate: " << pkiConfig.clientCertificateFile();
+ result = OpcUa_BadNotFound;
+ }
+
+ QFile keyFile(privateKeyFilePath.toUtf8());
+ if (keyFile.open(QIODevice::ReadOnly)) {
+ keyFile.close();
+ } else {
+ qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Failed to load private key: " << pkiConfig.privateKeyFile();
+ result = OpcUa_BadNotFound;
+ }
+
+ if (result.isGood()) {
+ result = sessionSecurityInfo.loadClientCertificateOpenSSL(certificateFilePath, privateKeyFilePath);
+ if (!result.isGood()) {
+ qCWarning(QT_OPCUA_PLUGINS_UACPP) << "sessionSecurityInfo.loadClientCertificateOpenSSL failed";
+ QString password;
+
+ do {
+ // This signal is connected using Qt::BlockingQueuedConnection. It will place a metacall to a different thread and waits
+ // until this metacall is fully handled before returning.
+ emit QOpcUaBackend::passwordForPrivateKeyRequired(pkiConfig.privateKeyFile(), &password, !password.isEmpty());
+
+ if (password.isEmpty())
+ break;
+
+ result = sessionSecurityInfo.loadClientCertificateOpenSSL(certificateFilePath, privateKeyFilePath, UaString(password.toUtf8()));
+
+ if (result.isGood())
+ break;
+
+ qCWarning(QT_OPCUA_PLUGINS_UACPP) << "sessionSecurityInfo.loadClientCertificateOpenSSL failed";
+ } while (true);
+ }
+ }
+
+ if (result.isNotGood()) {
+ emit stateAndOrErrorChanged(QOpcUaClient::Disconnected, QOpcUaClient::AccessDenied);
+ qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Failed to connect using certificate authentication: " << QString::fromUtf8(result.toString().toUtf8());
+ return;
+ }
+ } else {
+ emit stateAndOrErrorChanged(QOpcUaClient::Disconnected, QOpcUaClient::UnsupportedAuthenticationInformation);
+ qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Failed to connect: Selected authentication type"
+ << authInfo.authenticationType() << "is not supported.";
+ return;
}
- result = m_nativeSession->connect(uaUrl, sessionConnectInfo, sessionSecurityInfo, this);
+ const UaString uaUrl(endpoint.endpointUrl().toUtf8().constData());
+ auto result = m_nativeSession->connect(uaUrl, sessionConnectInfo, sessionSecurityInfo, this);
if (result.isNotGood()) {
- // ### TODO: Check for bad syntax, which is the "wrong url" part
emit stateAndOrErrorChanged(QOpcUaClient::Disconnected, QOpcUaClient::AccessDenied);
qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Failed to connect: " << QString::fromUtf8(result.toString().toUtf8());
return;
@@ -240,19 +362,19 @@ void UACppAsyncBackend::requestEndpoints(const QUrl &url)
ServiceSettings ServiceSettings;
ClientSecurityInfo clientSecurityInfo;
UaEndpointDescriptions endpoints;
- QVector<QOpcUa::QEndpointDescription> ret;
+ QVector<QOpcUaEndpointDescription> ret;
UaStatus res = discovery.getEndpoints(ServiceSettings, UaString(url.toString(QUrl::RemoveUserInfo).toUtf8().data()), clientSecurityInfo, endpoints);
if (res.isGood() && endpoints.length()) {
for (size_t i = 0; i < endpoints.length() ; ++i) {
- QOpcUa::QEndpointDescription temp;
+ QOpcUaEndpointDescription temp;
temp.setEndpointUrl(QString::fromUtf8(UaString(endpoints[i].EndpointUrl).toUtf8()));
temp.serverRef().setApplicationUri(QString::fromUtf8(UaString(endpoints[i].Server.ApplicationUri).toUtf8()));
temp.serverRef().setProductUri(QString::fromUtf8(UaString(endpoints[i].Server.ProductUri).toUtf8()));
- temp.serverRef().setApplicationName(QOpcUa::QLocalizedText(QString::fromUtf8(UaString(endpoints[i].Server.ApplicationName.Locale).toUtf8()),
+ temp.serverRef().setApplicationName(QOpcUaLocalizedText(QString::fromUtf8(UaString(endpoints[i].Server.ApplicationName.Locale).toUtf8()),
QString::fromUtf8(UaString(endpoints[i].Server.ApplicationName.Text).toUtf8())));
- temp.serverRef().setApplicationType(static_cast<QOpcUa::QApplicationDescription::ApplicationType>(endpoints[i].Server.ApplicationType));
+ temp.serverRef().setApplicationType(static_cast<QOpcUaApplicationDescription::ApplicationType>(endpoints[i].Server.ApplicationType));
temp.serverRef().setGatewayServerUri(QString::fromUtf8(UaString(endpoints[i].Server.GatewayServerUri).toUtf8()));
temp.serverRef().setDiscoveryProfileUri(QString::fromUtf8(UaString(endpoints[i].Server.DiscoveryProfileUri).toUtf8()));
for (int j = 0; j < endpoints[i].Server.NoOfDiscoveryUrls; ++j) {
@@ -260,34 +382,30 @@ void UACppAsyncBackend::requestEndpoints(const QUrl &url)
temp.serverRef().discoveryUrlsRef().append(url);
}
temp.setServerCertificate(QByteArray(reinterpret_cast<char *>(endpoints[i].ServerCertificate.Data), endpoints[i].ServerCertificate.Length));
- temp.setSecurityMode(static_cast<QOpcUa::QEndpointDescription::MessageSecurityMode>(endpoints[i].SecurityMode));
- temp.setSecurityPolicyUri(QString::fromUtf8(UaString(endpoints[i].SecurityPolicyUri).toUtf8()));
+ temp.setSecurityMode(static_cast<QOpcUaEndpointDescription::MessageSecurityMode>(endpoints[i].SecurityMode));
+ temp.setSecurityPolicy(QString::fromUtf8(UaString(endpoints[i].SecurityPolicyUri).toUtf8()));
for (int j = 0; j < endpoints[i].NoOfUserIdentityTokens; ++j) {
- QOpcUa::QUserTokenPolicy policy;
+ QOpcUaUserTokenPolicy policy;
policy.setPolicyId(QString::fromUtf8(UaString(endpoints[i].UserIdentityTokens[j].PolicyId).toUtf8()));
- policy.setTokenType(static_cast<QOpcUa::QUserTokenPolicy::TokenType>(endpoints[i].UserIdentityTokens[j].TokenType));
+ policy.setTokenType(static_cast<QOpcUaUserTokenPolicy::TokenType>(endpoints[i].UserIdentityTokens[j].TokenType));
policy.setIssuedTokenType(QString::fromUtf8(UaString(endpoints[i].UserIdentityTokens[j].IssuedTokenType).toUtf8()));
policy.setIssuerEndpointUrl(QString::fromUtf8(UaString(endpoints[i].UserIdentityTokens[j].IssuerEndpointUrl).toUtf8()));
- policy.setSecurityPolicyUri(QString::fromUtf8(UaString(endpoints[i].UserIdentityTokens[j].SecurityPolicyUri).toUtf8()));
+ policy.setSecurityPolicy(QString::fromUtf8(UaString(endpoints[i].UserIdentityTokens[j].SecurityPolicyUri).toUtf8()));
temp.userIdentityTokensRef().append(policy);
}
temp.setTransportProfileUri(QString::fromUtf8(UaString(endpoints[i].TransportProfileUri).toUtf8()));
temp.setSecurityLevel(endpoints[i].SecurityLevel);
ret.append(temp);
}
+ } else {
+ if (res.isGood())
+ qWarning() << "Server returned an empty endpoint list";
+ else
+ qWarning() << "Failed to retrive endpoints from " << url.toString(QUrl::RemoveUserInfo).toUtf8().constData()
+ << "with status" << res.toString().toUtf8();
}
- emit endpointsRequestFinished(ret, static_cast<QOpcUa::UaStatusCode>(res.code()));
-}
-
-inline OpcUa_UInt32 toUaAttributeId(QOpcUa::NodeAttribute attr)
-{
- const int attributeIdUsedBits = 22;
- for (int i = 0; i < attributeIdUsedBits; ++i)
- if (static_cast<int>(attr) == (1 << i))
- return static_cast<OpcUa_UInt32>(i + 1);
-
- return static_cast<OpcUa_UInt32>(0);
+ emit endpointsRequestFinished(ret, static_cast<QOpcUa::UaStatusCode>(res.code()), url);
}
void UACppAsyncBackend::readAttributes(quint64 handle, const UaNodeId &id, QOpcUa::NodeAttributes attr, QString indexRange)
@@ -307,7 +425,7 @@ void UACppAsyncBackend::readAttributes(quint64 handle, const UaNodeId &id, QOpcU
attributeSize++;
nodeToRead.resize(attributeSize);
id.copyTo(&nodeToRead[attributeSize - 1].NodeId);
- nodeToRead[attributeSize - 1].AttributeId = toUaAttributeId(attribute);
+ nodeToRead[attributeSize - 1].AttributeId = QUACppValueConverter::toUaAttributeId(attribute);
if (indexRange.size()) {
UaString ir(indexRange.toUtf8().constData());
ir.copyTo(&nodeToRead[attributeSize - 1].IndexRange);
@@ -472,6 +590,7 @@ void UACppAsyncBackend::disableMonitoring(quint64 handle, QOpcUa::NodeAttributes
QUACppSubscription *sub = getSubscriptionForItem(handle, attribute);
if (sub) {
sub->removeAttributeMonitoredItem(handle, attribute);
+ m_attributeMapping[handle].remove(attribute);
if (sub->monitoredItemsCount() == 0)
removeSubscription(sub->subscriptionId());
}
@@ -515,7 +634,7 @@ void UACppAsyncBackend::callMethod(quint64 handle, const UaNodeId &objectId, con
emit methodCallFinished(handle, UACppUtils::nodeIdToQString(methodId), result, static_cast<QOpcUa::UaStatusCode>(status.statusCode()));
}
-void UACppAsyncBackend::resolveBrowsePath(quint64 handle, const UaNodeId &startNode, const QVector<QOpcUa::QRelativePathElement> &path)
+void UACppAsyncBackend::resolveBrowsePath(quint64 handle, const UaNodeId &startNode, const QVector<QOpcUaRelativePathElement> &path)
{
ServiceSettings settings;
UaDiagnosticInfos diagnosticInfos;
@@ -540,12 +659,12 @@ void UACppAsyncBackend::resolveBrowsePath(quint64 handle, const UaNodeId &startN
UaStatusCode serviceResult = m_nativeSession->translateBrowsePathsToNodeIds(settings, paths, result, diagnosticInfos);
QOpcUa::UaStatusCode status = static_cast<QOpcUa::UaStatusCode>(serviceResult.code());
- QVector<QOpcUa::QBrowsePathTarget> ret;
+ QVector<QOpcUaBrowsePathTarget> ret;
if (status == QOpcUa::UaStatusCode::Good && result.length()) {
status = static_cast<QOpcUa::UaStatusCode>(result[0].StatusCode);
for (int i = 0; i < result[0].NoOfTargets; ++i) {
- QOpcUa::QBrowsePathTarget temp;
+ QOpcUaBrowsePathTarget temp;
temp.setRemainingPathIndex(result[0].Targets[i].RemainingPathIndex);
temp.targetIdRef().setNamespaceUri(QString::fromUtf8(UaString(result[0].Targets[i].TargetId.NamespaceUri).toUtf8()));
temp.targetIdRef().setServerIndex(result[0].Targets[i].TargetId.ServerIndex);
@@ -612,4 +731,498 @@ bool UACppAsyncBackend::removeSubscription(quint32 subscriptionId)
return false;
}
+void UACppAsyncBackend::findServers(const QUrl &url, const QStringList &localeIds, const QStringList &serverUris)
+{
+ UaStringArray uaServerUris = QUACppValueConverter::toUaStringArray(serverUris);
+ UaStringArray uaLocaleIds = QUACppValueConverter::toUaStringArray(localeIds);
+ UaDiscovery discovery;
+ ServiceSettings serviceSettings;
+ ClientSecurityInfo clientSecurityInfo;
+ UaApplicationDescriptions applicationDescriptions;
+
+ UaStatus result = discovery.findServers(serviceSettings,
+ UaString(url.toString(QUrl::RemoveUserInfo).toUtf8().constData()),
+ clientSecurityInfo,
+ uaLocaleIds,
+ uaServerUris,
+ applicationDescriptions);
+
+ QVector<QOpcUaApplicationDescription> ret;
+
+ for (OpcUa_UInt32 i = 0; i < applicationDescriptions.length(); ++i) {
+ QOpcUaApplicationDescription temp;
+ const UaApplicationDescription desc = applicationDescriptions[i];
+
+ temp.setApplicationUri(QString::fromUtf8(desc.getApplicationUri().toUtf8()));
+ temp.setProductUri(QString::fromUtf8(desc.getProductUri().toUtf8()));
+ UaLocalizedText uaApplicationName(desc.getApplicationName());
+ temp.setApplicationName(QUACppValueConverter::toQOpcUaLocalizedText(&uaApplicationName));
+ temp.setApplicationType(static_cast<QOpcUaApplicationDescription::ApplicationType>(desc.getApplicationType()));
+ temp.setGatewayServerUri(QString::fromUtf8(desc.getGatewayServerUri().toUtf8()));
+ temp.setDiscoveryProfileUri(QString::fromUtf8(desc.getDiscoveryProfileUri().toUtf8()));
+
+ UaStringArray discoveryUrls;
+ desc.getDiscoveryUrls(discoveryUrls);
+
+ for (OpcUa_UInt32 i = 0; i < discoveryUrls.length(); ++i)
+ temp.discoveryUrlsRef().append(QString::fromUtf8(UaString(discoveryUrls[i]).toUtf8()));
+
+ ret.append(temp);
+ }
+
+ if (result.isNotGood()) {
+ qCDebug(QT_OPCUA_PLUGINS_UACPP) << "Failed to get servers:" << static_cast<QOpcUa::UaStatusCode>(result.statusCode());
+ }
+
+ emit findServersFinished(ret, static_cast<QOpcUa::UaStatusCode>(result.statusCode()), url);
+}
+
+void UACppAsyncBackend::readNodeAttributes(const QVector<QOpcUaReadItem> &nodesToRead)
+{
+ if (nodesToRead.size() == 0) {
+ emit readNodeAttributesFinished(QVector<QOpcUaReadResult>(), QOpcUa::UaStatusCode::BadNothingToDo);
+ return;
+ }
+
+ UaReadValueIds nodesToReadNativeType;
+ nodesToReadNativeType.resize(nodesToRead.size());
+
+ for (int i = 0; i < nodesToRead.size(); ++i) {
+ UACppUtils::nodeIdFromQString(nodesToRead[i].nodeId()).copyTo(&nodesToReadNativeType[i].NodeId);
+ nodesToReadNativeType[i].AttributeId = QUACppValueConverter::toUaAttributeId(nodesToRead[i].attribute());
+ if (!nodesToRead[i].indexRange().isEmpty()) {
+ UaString ir(nodesToRead[i].indexRange().toUtf8());
+ ir.copyTo(&nodesToReadNativeType[i].IndexRange);
+ }
+ }
+
+ UaDataValues values;
+ UaDiagnosticInfos diagnosticInfos;
+ ServiceSettings serviceSettings;
+
+ UaStatus result = m_nativeSession->read(serviceSettings, 0.0 /* maxAge */,
+ OpcUa_TimestampsToReturn_Both,
+ nodesToReadNativeType, values,
+ diagnosticInfos);
+ QOpcUa::UaStatusCode status = static_cast<QOpcUa::UaStatusCode>(result.code());
+
+ if (result.isBad()) {
+ qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Batch read failed:" << result.toString();
+ emit readNodeAttributesFinished(QVector<QOpcUaReadResult>(), status);
+ } else {
+ QVector<QOpcUaReadResult> ret;
+
+ for (int i = 0; i < nodesToRead.size(); ++i) {
+ QOpcUaReadResult item;
+ item.setAttribute(nodesToRead.at(i).attribute());
+ item.setNodeId(nodesToRead.at(i).nodeId());
+ item.setIndexRange(nodesToRead.at(i).indexRange());
+
+ if (static_cast<size_t>(i) < values.length()) {
+ UaDataValue dataValue(values[i]);
+ item.setValue(QUACppValueConverter::toQVariant(*dataValue.value()));
+ item.setStatusCode(static_cast<QOpcUa::UaStatusCode>(dataValue.statusCode()));
+ if (dataValue.isServerTimestampSet()) {
+ auto dt = dataValue.serverTimestamp();
+ item.setServerTimestamp(QUACppValueConverter::toQDateTime(&dt));
+ }
+ if (dataValue.isSourceTimestampSet()) {
+ auto dt = dataValue.sourceTimestamp();
+ item.setSourceTimestamp(QUACppValueConverter::toQDateTime(&dt));
+ }
+ } else {
+ item.setStatusCode(status);
+ }
+ ret.push_back(item);
+ }
+ emit readNodeAttributesFinished(ret, status);
+ }
+}
+
+void UACppAsyncBackend::writeNodeAttributes(const QVector<QOpcUaWriteItem> &nodesToWrite)
+{
+ if (nodesToWrite.isEmpty()) {
+ emit writeNodeAttributesFinished(QVector<QOpcUaWriteResult>(), QOpcUa::UaStatusCode::BadNothingToDo);
+ return;
+ }
+
+ UaWriteValues nodesToWriteNativeType;
+ nodesToWriteNativeType.create(nodesToWrite.size());
+
+ for (int i = 0; i < nodesToWrite.size(); ++i) {
+ const auto &currentItem = nodesToWrite[i];
+ UaDataValue dataValue;
+ auto value = QUACppValueConverter::toUACppVariant(currentItem.value(), currentItem.type());
+ dataValue.setValue(value, true); // true == detach value
+ if (currentItem.hasStatusCode())
+ dataValue.setStatusCode(currentItem.statusCode());
+ if (currentItem.serverTimestamp().isValid())
+ dataValue.setServerTimestamp(QUACppValueConverter::toUACppDateTime(currentItem.serverTimestamp()));
+ if (currentItem.sourceTimestamp().isValid())
+ dataValue.setSourceTimestamp(QUACppValueConverter::toUACppDateTime(currentItem.sourceTimestamp()));
+ dataValue.copyTo(&nodesToWriteNativeType[i].Value);
+ UACppUtils::nodeIdFromQString(currentItem.nodeId()).copyTo(&nodesToWriteNativeType[i].NodeId);
+ nodesToWriteNativeType[i].AttributeId = QUACppValueConverter::toUaAttributeId(currentItem.attribute());
+
+ if (!currentItem.indexRange().isEmpty()) {
+ UaString ir(currentItem.indexRange().toUtf8());
+ ir.copyTo(&nodesToWriteNativeType[i].IndexRange);
+ }
+ }
+
+ UaStatusCodeArray results;
+ UaDiagnosticInfos diagnosticInfos;
+ ServiceSettings serviceSettings;
+
+ UaStatus result = m_nativeSession->write(serviceSettings, nodesToWriteNativeType,
+ results, diagnosticInfos);
+ const QOpcUa::UaStatusCode status = static_cast<QOpcUa::UaStatusCode>(result.code());
+
+ if (result.isBad()) {
+ qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Batch write failed:" << result.toString();
+ emit writeNodeAttributesFinished(QVector<QOpcUaWriteResult>(), status);
+ } else {
+ QVector<QOpcUaWriteResult> ret;
+
+ for (int i = 0; i < nodesToWrite.size(); ++i) {
+ QOpcUaWriteResult item;
+ item.setAttribute(nodesToWrite.at(i).attribute());
+ item.setNodeId(nodesToWrite.at(i).nodeId());
+ item.setIndexRange(nodesToWrite.at(i).indexRange());
+
+ if (static_cast<size_t>(i) < results.length())
+ item.setStatusCode(static_cast<QOpcUa::UaStatusCode>(results[i]));
+ else
+ item.setStatusCode(status);
+
+ ret.push_back(item);
+ }
+ emit writeNodeAttributesFinished(ret, status);
+ }
+}
+
+void UACppAsyncBackend::addNode(const QOpcUaAddNodeItem &nodeToAdd)
+{
+ OpcUa_AddNodesItem* opcUaNodeToAdd = static_cast<OpcUa_AddNodesItem*>(OpcUa_Alloc(1 * sizeof(OpcUa_AddNodesItem)));
+ OpcUa_AddNodesItem_Initialize(opcUaNodeToAdd);
+
+ opcUaNodeToAdd->ParentNodeId = QUACppValueConverter::toUACppExpandedNodeId(nodeToAdd.parentNodeId());
+ UACppUtils::nodeIdFromQString(nodeToAdd.referenceTypeId()).detach(&opcUaNodeToAdd->ReferenceTypeId);
+ opcUaNodeToAdd->RequestedNewNodeId = QUACppValueConverter::toUACppExpandedNodeId(nodeToAdd.requestedNewNodeId());
+ opcUaNodeToAdd->BrowseName = QUACppValueConverter::toUACppQualifiedName(nodeToAdd.browseName());
+ opcUaNodeToAdd->NodeClass = static_cast<OpcUa_NodeClass>(nodeToAdd.nodeClass());
+
+ if (!assembleNodeAttributes(&opcUaNodeToAdd->NodeAttributes, nodeToAdd.nodeAttributes(), nodeToAdd.nodeClass())) {
+ qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Failed to assemble node attributes";
+ emit addNodeFinished(nodeToAdd.requestedNewNodeId(), QString(), QOpcUa::BadUnexpectedError);
+ return;
+ }
+
+ if (!nodeToAdd.typeDefinition().nodeId().isEmpty())
+ opcUaNodeToAdd->TypeDefinition = QUACppValueConverter::toUACppExpandedNodeId(nodeToAdd.typeDefinition());
+
+ UaAddNodesItems itemsToAdd;
+ itemsToAdd.attach((OpcUa_UInt32)1, opcUaNodeToAdd);
+ UaAddNodesResults results;
+ UaDiagnosticInfos diagnosticInfos;
+ ServiceSettings serviceSettings;
+
+ UaStatus result = m_nativeSession->addNodes(serviceSettings, itemsToAdd, results, diagnosticInfos);
+ QOpcUa::UaStatusCode status = static_cast<QOpcUa::UaStatusCode>(result.code());
+
+ QString resultId;
+
+ if (result.isGood() && results.length() > 0) {
+ if (OpcUa_IsGood(results[0].StatusCode)) {
+ resultId = UACppUtils::nodeIdToQString(results[0].AddedNodeId);
+ } else {
+ status = static_cast<QOpcUa::UaStatusCode>(results[0].StatusCode);
+ qCDebug(QT_OPCUA_PLUGINS_UACPP) << "Failed to add node:" << status;
+ }
+ } else {
+ qCDebug(QT_OPCUA_PLUGINS_UACPP) << "Failed to add node:" << status;
+ }
+
+ emit addNodeFinished(nodeToAdd.requestedNewNodeId(), resultId, status);
+}
+
+void UACppAsyncBackend::deleteNode(const QString &nodeId, bool deleteTargetReferences)
+{
+ UaNodeId id = UACppUtils::nodeIdFromQString(nodeId);
+
+ UaDeleteNodesItems nodesToDelete;
+ nodesToDelete.attach((OpcUa_UInt32)1, static_cast<OpcUa_DeleteNodesItem*>(OpcUa_Alloc(1 * sizeof(OpcUa_DeleteNodesItem))));
+ OpcUa_DeleteNodesItem_Initialize(&nodesToDelete[0]);
+
+ id.copyTo(&nodesToDelete[0].NodeId);
+ nodesToDelete[0].DeleteTargetReferences = deleteTargetReferences;
+
+ UaDiagnosticInfos diagnosticInfos;
+ ServiceSettings serviceSettings;
+ UaStatusCodeArray results;
+
+ UaStatus res = m_nativeSession->deleteNodes(serviceSettings, nodesToDelete, results, diagnosticInfos);
+
+ QOpcUa::UaStatusCode resultStatus = static_cast<QOpcUa::UaStatusCode>(res.statusCode());
+
+ if (resultStatus != QOpcUa::UaStatusCode::Good) {
+ qCDebug(QT_OPCUA_PLUGINS_UACPP) << "Failed to delete node" << nodeId << "with status code" << resultStatus;
+ }
+
+ emit deleteNodeFinished(nodeId, resultStatus);
+}
+
+void UACppAsyncBackend::addReference(const QOpcUaAddReferenceItem &referenceToAdd)
+{
+ UaAddReferencesItems referencesToAdd;
+ referencesToAdd.attach((OpcUa_UInt32)1, static_cast<OpcUa_AddReferencesItem*>(OpcUa_Alloc(1 * sizeof(OpcUa_AddReferencesItem))));
+ OpcUa_AddReferencesItem_Initialize(&referencesToAdd[0]);
+
+ UACppUtils::nodeIdFromQString(referenceToAdd.sourceNodeId()).copyTo(&referencesToAdd[0].SourceNodeId);
+ UACppUtils::nodeIdFromQString(referenceToAdd.referenceTypeId()).copyTo(&referencesToAdd[0].ReferenceTypeId);
+ referencesToAdd[0].IsForward = referenceToAdd.isForwardReference();
+ UaString(referenceToAdd.targetServerUri().toUtf8().constData()).detach(&referencesToAdd[0].TargetServerUri);
+ referencesToAdd[0].TargetNodeId = QUACppValueConverter::toUACppExpandedNodeId(referenceToAdd.targetNodeId());
+ referencesToAdd[0].TargetNodeClass = static_cast<OpcUa_NodeClass>(referenceToAdd.targetNodeClass());
+
+ UaDiagnosticInfos diagnosticInfos;
+ ServiceSettings serviceSettings;
+ UaStatusCodeArray results;
+
+ UaStatus res = m_nativeSession->addReferences(serviceSettings, referencesToAdd, results, diagnosticInfos);
+
+ QOpcUa::UaStatusCode statusCode = static_cast<QOpcUa::UaStatusCode>(res.statusCode());
+ if (res.isBad())
+ qCDebug(QT_OPCUA_PLUGINS_UACPP) << "Failed to add reference from" << referenceToAdd.sourceNodeId() << "to"
+ << referenceToAdd.targetNodeId().nodeId() << ":" << statusCode;
+
+ emit addReferenceFinished(referenceToAdd.sourceNodeId(), referenceToAdd.referenceTypeId(),
+ referenceToAdd.targetNodeId(),
+ referenceToAdd.isForwardReference(), statusCode);
+}
+
+void UACppAsyncBackend::deleteReference(const QOpcUaDeleteReferenceItem &referenceToDelete)
+{
+ UaDeleteReferencesItems referencesToDelete;
+ referencesToDelete.attach((OpcUa_UInt32)1, static_cast<OpcUa_DeleteReferencesItem*>(OpcUa_Alloc(1 * sizeof(OpcUa_DeleteReferencesItem))));
+ OpcUa_DeleteReferencesItem_Initialize(&referencesToDelete[0]);
+
+ UACppUtils::nodeIdFromQString(referenceToDelete.sourceNodeId()).copyTo(&referencesToDelete[0].SourceNodeId);
+ UACppUtils::nodeIdFromQString(referenceToDelete.referenceTypeId()).copyTo(&referencesToDelete[0].ReferenceTypeId);
+ referencesToDelete[0].IsForward = referenceToDelete.isForwardReference();
+ referencesToDelete[0].TargetNodeId = QUACppValueConverter::toUACppExpandedNodeId(referenceToDelete.targetNodeId());
+ referencesToDelete[0].DeleteBidirectional = referenceToDelete.deleteBidirectional();
+
+ UaDiagnosticInfos diagnosticInfos;
+ ServiceSettings serviceSettings;
+ UaStatusCodeArray results;
+
+ UaStatus res = m_nativeSession->deleteReferences(serviceSettings, referencesToDelete, results, diagnosticInfos);
+
+ QOpcUa::UaStatusCode statusCode = static_cast<QOpcUa::UaStatusCode>(res.statusCode());
+ if (res.isBad())
+ qCDebug(QT_OPCUA_PLUGINS_UACPP) << "Failed to delete reference from" << referenceToDelete.sourceNodeId() << "to"
+ << referenceToDelete.targetNodeId().nodeId() << ":" << statusCode;
+
+ emit deleteReferenceFinished(referenceToDelete.sourceNodeId(), referenceToDelete.referenceTypeId(),
+ referenceToDelete.targetNodeId(),
+ referenceToDelete.isForwardReference(), statusCode);
+}
+
+QOpcUaErrorState::ConnectionStep UACppAsyncBackend::connectionStepFromUaServiceType(
+ UaClientSdk::UaClient::ConnectServiceType type) const
+{
+ switch (type) {
+ case UaClientSdk::UaClient::ConnectServiceType::CreateSession:
+ return QOpcUaErrorState::ConnectionStep::CreateSession;
+ case UaClientSdk::UaClient::ConnectServiceType::ActivateSession:
+ return QOpcUaErrorState::ConnectionStep::ActivateSession;
+ case UaClientSdk::UaClient::ConnectServiceType::OpenSecureChannel:
+ return QOpcUaErrorState::ConnectionStep::OpenSecureChannel;
+ case UaClientSdk::UaClient::ConnectServiceType::CertificateValidation:
+ return QOpcUaErrorState::ConnectionStep::CertificateValidation;
+ default:
+ return QOpcUaErrorState::ConnectionStep::Unknown;
+ }
+}
+
+static void copyArrayDimensions(OpcUa_Int32 *noOfDimensions, OpcUa_UInt32 **arrayDimensions, const QVector<quint32> &dimensions)
+{
+ *noOfDimensions = static_cast<OpcUa_Int32>(dimensions.size());
+ *arrayDimensions = static_cast<OpcUa_UInt32 *>(OpcUa_Alloc(*noOfDimensions * sizeof(OpcUa_UInt32)));
+ std::copy(dimensions.constBegin(), dimensions.constEnd(), *arrayDimensions);
+}
+
+#define CREATE_NODE_ATTRIBUTE(TYPE) \
+ OpcUa_ ##TYPE ## Attributes* uaNodeAttributes = nullptr; \
+ OpcUa_EncodeableObject_CreateExtension(&OpcUa_ ##TYPE ## Attributes_EncodeableType, \
+ uaExtensionObject, (OpcUa_Void**)&uaNodeAttributes); \
+ if (!uaNodeAttributes) \
+ return false; \
+ \
+ OpcUa_ ##TYPE ## Attributes_Initialize(uaNodeAttributes); \
+ \
+ if (nodeAttributes.hasDisplayName()) { \
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_DisplayName; \
+ uaNodeAttributes->DisplayName = QUACppValueConverter::toUACppLocalizedText(nodeAttributes.displayName()); \
+ } \
+ if (nodeAttributes.hasDescription()) { \
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_Description; \
+ uaNodeAttributes->Description = QUACppValueConverter::toUACppLocalizedText(nodeAttributes.description()); \
+ } \
+ if (nodeAttributes.hasWriteMask()) { \
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_WriteMask; \
+ uaNodeAttributes->WriteMask = nodeAttributes.writeMask(); \
+ } \
+ if (nodeAttributes.hasUserWriteMask()) { \
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_UserWriteMask; \
+ uaNodeAttributes->UserWriteMask = nodeAttributes.userWriteMask(); \
+ } \
+
+bool UACppAsyncBackend::assembleNodeAttributes(OpcUa_ExtensionObject *uaExtensionObject, const QOpcUaNodeCreationAttributes &nodeAttributes,
+ QOpcUa::NodeClass nodeClass)
+{
+ switch (nodeClass) {
+ case QOpcUa::NodeClass::Object: {
+ CREATE_NODE_ATTRIBUTE(Object);
+
+ if (nodeAttributes.hasEventNotifier()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_EventNotifier;
+ uaNodeAttributes->EventNotifier = nodeAttributes.eventNotifier();
+ }
+ break;
+ }
+ case QOpcUa::NodeClass::Variable: {
+ CREATE_NODE_ATTRIBUTE(Variable);
+
+ if (nodeAttributes.hasValue()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_Value;
+ uaNodeAttributes->Value = QUACppValueConverter::toUACppVariant(nodeAttributes.value(),
+ nodeAttributes.valueType());
+ }
+ if (nodeAttributes.hasDataTypeId()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_DataType;
+ UACppUtils::nodeIdFromQString(nodeAttributes.dataTypeId()).detach(&uaNodeAttributes->DataType);
+ }
+ if (nodeAttributes.hasValueRank()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_ValueRank;
+ uaNodeAttributes->ValueRank = nodeAttributes.valueRank();
+ }
+ if (nodeAttributes.hasArrayDimensions()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_ArrayDimensions;
+ copyArrayDimensions(&uaNodeAttributes->NoOfArrayDimensions,&uaNodeAttributes->ArrayDimensions, nodeAttributes.arrayDimensions());
+ }
+ if (nodeAttributes.hasAccessLevel()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_AccessLevel;
+ uaNodeAttributes->AccessLevel = nodeAttributes.accessLevel();
+ }
+ if (nodeAttributes.hasUserAccessLevel()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_UserAccessLevel;
+ uaNodeAttributes->UserAccessLevel = nodeAttributes.userAccessLevel();
+ }
+ if (nodeAttributes.hasMinimumSamplingInterval()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_MinimumSamplingInterval;
+ uaNodeAttributes->MinimumSamplingInterval = nodeAttributes.minimumSamplingInterval();
+ }
+ if (nodeAttributes.hasHistorizing()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_Historizing;
+ uaNodeAttributes->Historizing = nodeAttributes.historizing();
+ }
+ break;
+ }
+ case QOpcUa::NodeClass::Method: {
+ CREATE_NODE_ATTRIBUTE(Method);
+
+ if (nodeAttributes.hasExecutable()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_Executable;
+ uaNodeAttributes->Executable = nodeAttributes.executable();
+ }
+ if (nodeAttributes.hasUserExecutable()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_UserExecutable;
+ uaNodeAttributes->UserExecutable = nodeAttributes.userExecutable();
+ }
+ break;
+ }
+ case QOpcUa::NodeClass::ObjectType: {
+ CREATE_NODE_ATTRIBUTE(ObjectType);
+
+ if (nodeAttributes.hasIsAbstract()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_IsAbstract;
+ uaNodeAttributes->IsAbstract = nodeAttributes.isAbstract();
+ }
+ break;
+ }
+ case QOpcUa::NodeClass::VariableType: {
+ CREATE_NODE_ATTRIBUTE(VariableType);
+
+ if (nodeAttributes.hasValue()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_Value;
+ uaNodeAttributes->Value = QUACppValueConverter::toUACppVariant(nodeAttributes.value(),
+ nodeAttributes.valueType());
+ }
+ if (nodeAttributes.hasDataTypeId()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_DataType;
+ UACppUtils::nodeIdFromQString(nodeAttributes.dataTypeId()).detach(&uaNodeAttributes->DataType);
+ }
+ if (nodeAttributes.hasValueRank()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_ValueRank;
+ uaNodeAttributes->ValueRank = nodeAttributes.valueRank();
+ }
+ if (nodeAttributes.hasArrayDimensions()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_ArrayDimensions;
+ copyArrayDimensions(&uaNodeAttributes->NoOfArrayDimensions, &uaNodeAttributes->ArrayDimensions, nodeAttributes.arrayDimensions());
+ }
+ if (nodeAttributes.hasIsAbstract()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_IsAbstract;
+ uaNodeAttributes->IsAbstract = nodeAttributes.isAbstract();
+ }
+ break;
+ }
+ case QOpcUa::NodeClass::ReferenceType: {
+ CREATE_NODE_ATTRIBUTE(ReferenceType);
+
+ if (nodeAttributes.hasIsAbstract()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_IsAbstract;
+ uaNodeAttributes->IsAbstract = nodeAttributes.isAbstract();
+ }
+ if (nodeAttributes.hasSymmetric()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_Symmetric;
+ uaNodeAttributes->Symmetric = nodeAttributes.symmetric();
+ }
+ if (nodeAttributes.hasInverseName()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_InverseName;
+ uaNodeAttributes->InverseName = QUACppValueConverter::toUACppLocalizedText(nodeAttributes.inverseName());
+ }
+ break;
+ }
+ case QOpcUa::NodeClass::DataType: {
+ CREATE_NODE_ATTRIBUTE(DataType);
+
+ if (nodeAttributes.hasIsAbstract()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_IsAbstract;
+ uaNodeAttributes->IsAbstract = nodeAttributes.isAbstract();
+ }
+ break;
+ }
+ case QOpcUa::NodeClass::View: {
+ CREATE_NODE_ATTRIBUTE(View);
+
+ if (nodeAttributes.hasContainsNoLoops()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_ContainsNoLoops;
+ uaNodeAttributes->ContainsNoLoops = nodeAttributes.containsNoLoops();
+ }
+ if (nodeAttributes.hasEventNotifier()) {
+ uaNodeAttributes->SpecifiedAttributes |= OpcUa_NodeAttributesMask_EventNotifier;
+ uaNodeAttributes->EventNotifier = nodeAttributes.eventNotifier();
+ }
+ break;
+ }
+ default:
+ qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Could not convert node attributes, unknown node class";
+ return false;
+ }
+
+ return true;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/uacpp/quacppbackend.h b/src/plugins/opcua/uacpp/quacppbackend.h
index 99ad5be..16c4ac1 100644
--- a/src/plugins/opcua/uacpp/quacppbackend.h
+++ b/src/plugins/opcua/uacpp/quacppbackend.h
@@ -1,19 +1,27 @@
/******************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:COMM$
-**
+** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -29,6 +37,8 @@
#include <QtCore/QString>
#include <QtCore/QTimer>
+#include <QtOpcUa/qopcuaerrorstate.h>
+#include <QtOpcUa/qopcuatype.h>
#include <uabase.h>
#include <uaclientsdk.h>
@@ -47,9 +57,10 @@ public:
~UACppAsyncBackend();
void connectionStatusChanged(OpcUa_UInt32 clientConnectionId, UaClientSdk::UaClient::ServerStatus serverStatus) override;
+ bool connectError(OpcUa_UInt32 clientConnectionId, UaClientSdk::UaClient::ConnectServiceType serviceType, const UaStatus &error, bool clientSideError) override;
public Q_SLOTS:
- void connectToEndpoint(const QUrl &url);
+ void connectToEndpoint(const QOpcUaEndpointDescription &endpoint);
void disconnectFromEndpoint();
void browse(quint64 handle, const UaNodeId &id, const QOpcUaBrowseRequest &request);
@@ -60,11 +71,25 @@ public Q_SLOTS:
void modifyMonitoring(quint64 handle, QOpcUa::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, QVariant value);
void disableMonitoring(quint64 handle, QOpcUa::NodeAttributes attr);
void callMethod(quint64 handle, const UaNodeId &objectId, const UaNodeId &methodId, QVector<QOpcUa::TypedVariant> args);
- void resolveBrowsePath(quint64 handle, const UaNodeId &startNode, const QVector<QOpcUa::QRelativePathElement> &path);
+ void resolveBrowsePath(quint64 handle, const UaNodeId &startNode, const QVector<QOpcUaRelativePathElement> &path);
void requestEndpoints(const QUrl &url);
bool removeSubscription(quint32 subscriptionId);
+ void findServers(const QUrl &url, const QStringList &localeIds, const QStringList &serverUris);
+
+ void readNodeAttributes(const QVector<QOpcUaReadItem> &nodesToRead);
+ void writeNodeAttributes(const QVector<QOpcUaWriteItem> &nodesToWrite);
+
+ // Node management
+ void addNode(const QOpcUaAddNodeItem &nodeToAdd);
+ void deleteNode(const QString &nodeId, bool deleteTargetReferences);
+ void addReference(const QOpcUaAddReferenceItem &referenceToAdd);
+ void deleteReference(const QOpcUaDeleteReferenceItem &referenceToDelete);
+
+ // Helper
+ QOpcUaErrorState::ConnectionStep connectionStepFromUaServiceType(UaClientSdk::UaClient::ConnectServiceType type) const;
+
public:
QUACppSubscription *getSubscription(const QOpcUaMonitoringParameters &settings);
QUACppSubscription *getSubscriptionForItem(quint64 handle, QOpcUa::NodeAttribute attr);
@@ -79,6 +104,9 @@ public:
QMutex m_lifecycleMutex;
double m_minPublishingInterval;
bool m_disableEncryptedPasswordCheck{false};
+
+private:
+ bool assembleNodeAttributes(OpcUa_ExtensionObject *uaExtensionObject, const QOpcUaNodeCreationAttributes &nodeAttributes, QOpcUa::NodeClass nodeClass);
};
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/uacpp/quacppclient.cpp b/src/plugins/opcua/uacpp/quacppclient.cpp
index c7d4772..dcf90a9 100644
--- a/src/plugins/opcua/uacpp/quacppclient.cpp
+++ b/src/plugins/opcua/uacpp/quacppclient.cpp
@@ -1,19 +1,27 @@
/******************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:COMM$
-**
+** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -59,9 +67,9 @@ QUACppClient::~QUACppClient()
m_thread->quit();
}
-void QUACppClient::connectToEndpoint(const QUrl &url)
+void QUACppClient::connectToEndpoint(const QOpcUaEndpointDescription &endpoint)
{
- QMetaObject::invokeMethod(m_backend, "connectToEndpoint", Qt::QueuedConnection, Q_ARG(QUrl, url));
+ QMetaObject::invokeMethod(m_backend, "connectToEndpoint", Qt::QueuedConnection, Q_ARG(QOpcUaEndpointDescription, endpoint));
}
void QUACppClient::disconnectFromEndpoint()
@@ -96,61 +104,80 @@ bool QUACppClient::requestEndpoints(const QUrl &url)
bool QUACppClient::findServers(const QUrl &url, const QStringList &localeIds, const QStringList &serverUris)
{
- Q_UNUSED(url);
- Q_UNUSED(localeIds);
- Q_UNUSED(serverUris);
-
- qCInfo(QT_OPCUA_PLUGINS_UACPP) << "The uacpp backend does not yet support the FindServers service.";
-
- return false;
+ return QMetaObject::invokeMethod(m_backend, "findServers", Qt::QueuedConnection,
+ Q_ARG(QUrl, url),
+ Q_ARG(QStringList, localeIds),
+ Q_ARG(QStringList, serverUris));
}
-bool QUACppClient::batchRead(const QVector<QOpcUaReadItem> &nodesToRead)
+bool QUACppClient::readNodeAttributes(const QVector<QOpcUaReadItem> &nodesToRead)
{
- Q_UNUSED(nodesToRead);
- qCInfo(QT_OPCUA_PLUGINS_UACPP) << "Batch read is currently not implemented in the uacpp backend";
- return false;
+ return QMetaObject::invokeMethod(m_backend, "readNodeAttributes", Qt::QueuedConnection,
+ Q_ARG(QVector<QOpcUaReadItem>, nodesToRead));
}
-bool QUACppClient::batchWrite(const QVector<QOpcUaWriteItem> &nodesToWrite)
+bool QUACppClient::writeNodeAttributes(const QVector<QOpcUaWriteItem> &nodesToWrite)
{
- Q_UNUSED(nodesToWrite);
-
- qCInfo(QT_OPCUA_PLUGINS_UACPP) << "Batch write is currently not implemented in the uacpp backend";
- return false;
+ return QMetaObject::invokeMethod(m_backend, "writeNodeAttributes", Qt::QueuedConnection,
+ Q_ARG(QVector<QOpcUaWriteItem>, nodesToWrite));
}
bool QUACppClient::addNode(const QOpcUaAddNodeItem &nodeToAdd)
{
- Q_UNUSED(nodeToAdd);
-
- qCInfo(QT_OPCUA_PLUGINS_UACPP) << "AddNode is not yet supported by the uacpp backend";
- return false;
+ return QMetaObject::invokeMethod(m_backend, "addNode", Qt::QueuedConnection,
+ Q_ARG(QOpcUaAddNodeItem, nodeToAdd));
}
bool QUACppClient::deleteNode(const QString &nodeId, bool deleteTargetReferences)
{
- Q_UNUSED(nodeId);
- Q_UNUSED(deleteTargetReferences);
-
- qCInfo(QT_OPCUA_PLUGINS_UACPP) << "DeleteNode is not yet supported by the uacpp backend";
- return false;
+ return QMetaObject::invokeMethod(m_backend, "deleteNode", Qt::QueuedConnection,
+ Q_ARG(QString, nodeId),
+ Q_ARG(bool, deleteTargetReferences));
}
bool QUACppClient::addReference(const QOpcUaAddReferenceItem &referenceToAdd)
{
- Q_UNUSED(referenceToAdd);
-
- qCInfo(QT_OPCUA_PLUGINS_UACPP) << "AddReference is not yet supported by the uacpp backend";
- return false;
+ return QMetaObject::invokeMethod(m_backend, "addReference", Qt::QueuedConnection,
+ Q_ARG(QOpcUaAddReferenceItem, referenceToAdd));
}
bool QUACppClient::deleteReference(const QOpcUaDeleteReferenceItem &referenceToDelete)
{
- Q_UNUSED(referenceToDelete);
+ return QMetaObject::invokeMethod(m_backend, "deleteReference", Qt::QueuedConnection,
+ Q_ARG(QOpcUaDeleteReferenceItem, referenceToDelete));
+}
+
+QStringList QUACppClient::supportedSecurityPolicies() const
+{
+ return QStringList {
+#if OPCUA_SUPPORT_SECURITYPOLICY_BASIC128RSA15
+ "http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15",
+#endif
+#if OPCUA_SUPPORT_SECURITYPOLICY_BASIC256
+ "http://opcfoundation.org/UA/SecurityPolicy#Basic256",
+#endif
+#if OPCUA_SUPPORT_SECURITYPOLICY_BASIC256SHA256
+ "http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256",
+#endif
+#if OPCUA_SUPPORT_SECURITYPOLICY_AES128SHA256RSAOAEP
+ "http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep",
+#endif
+#if OPCUA_SUPPORT_SECURITYPOLICY_AES256SHA256RSAPSS
+ "http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss",
+#endif
+#if OPCUA_SUPPORT_SECURITYPOLICY_NONE
+ "http://opcfoundation.org/UA/SecurityPolicy#None",
+#endif
+ };
+}
- qCInfo(QT_OPCUA_PLUGINS_UACPP) << "deleteReference is not yet supported by the uacpp backend";
- return false;
+QVector<QOpcUaUserTokenPolicy::TokenType> QUACppClient::supportedUserTokenTypes() const
+{
+ return QVector<QOpcUaUserTokenPolicy::TokenType> {
+ QOpcUaUserTokenPolicy::TokenType::Certificate,
+ QOpcUaUserTokenPolicy::TokenType::Username,
+ QOpcUaUserTokenPolicy::TokenType::Anonymous
+ };
}
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/uacpp/quacppclient.h b/src/plugins/opcua/uacpp/quacppclient.h
index 7c79970..c0f8f44 100644
--- a/src/plugins/opcua/uacpp/quacppclient.h
+++ b/src/plugins/opcua/uacpp/quacppclient.h
@@ -1,19 +1,27 @@
/******************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:COMM$
-**
+** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -38,7 +46,7 @@ public:
explicit QUACppClient(const QVariantMap &backendProperties);
~QUACppClient();
- void connectToEndpoint(const QUrl &url) override;
+ void connectToEndpoint(const QOpcUaEndpointDescription &endpoint) override;
void disconnectFromEndpoint() override;
QOpcUaNode *node(const QString &nodeId) override;
@@ -49,8 +57,8 @@ public:
bool findServers(const QUrl &url, const QStringList &localeIds, const QStringList &serverUris) override;
- bool batchRead(const QVector<QOpcUaReadItem> &nodesToRead) override;
- bool batchWrite(const QVector<QOpcUaWriteItem> &nodesToWrite) override;
+ bool readNodeAttributes(const QVector<QOpcUaReadItem> &nodesToRead) override;
+ bool writeNodeAttributes(const QVector<QOpcUaWriteItem> &nodesToWrite) override;
bool addNode(const QOpcUaAddNodeItem &nodeToAdd) override;
bool deleteNode(const QString &nodeId, bool deleteTargetReferences) override;
@@ -58,6 +66,9 @@ public:
bool addReference(const QOpcUaAddReferenceItem &referenceToAdd) override;
bool deleteReference(const QOpcUaDeleteReferenceItem &referenceToDelete) override;
+ QStringList supportedSecurityPolicies() const override;
+ QVector<QOpcUaUserTokenPolicy::TokenType> supportedUserTokenTypes() const override;
+
private:
friend class QUACppNode;
QThread *m_thread;
diff --git a/src/plugins/opcua/uacpp/quacppnode.cpp b/src/plugins/opcua/uacpp/quacppnode.cpp
index 91265f9..dd9c27c 100644
--- a/src/plugins/opcua/uacpp/quacppnode.cpp
+++ b/src/plugins/opcua/uacpp/quacppnode.cpp
@@ -1,19 +1,27 @@
/******************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:COMM$
-**
+** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -157,7 +165,7 @@ bool QUACppNode::callMethod(const QString &methodNodeId, const QVector<QOpcUa::T
Q_ARG(QVector<QOpcUa::TypedVariant>, args));
}
-bool QUACppNode::resolveBrowsePath(const QVector<QOpcUa::QRelativePathElement> &path)
+bool QUACppNode::resolveBrowsePath(const QVector<QOpcUaRelativePathElement> &path)
{
if (!m_client)
return false;
@@ -166,7 +174,7 @@ bool QUACppNode::resolveBrowsePath(const QVector<QOpcUa::QRelativePathElement> &
Qt::QueuedConnection,
Q_ARG(quint64, handle()),
Q_ARG(UaNodeId, m_nodeId),
- Q_ARG(QVector<QOpcUa::QRelativePathElement>, path));
+ Q_ARG(QVector<QOpcUaRelativePathElement>, path));
}
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/uacpp/quacppnode.h b/src/plugins/opcua/uacpp/quacppnode.h
index 71f0900..b591060 100644
--- a/src/plugins/opcua/uacpp/quacppnode.h
+++ b/src/plugins/opcua/uacpp/quacppnode.h
@@ -1,19 +1,27 @@
/******************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:COMM$
-**
+** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -50,7 +58,7 @@ public:
bool writeAttributes(const QOpcUaNode::AttributeMap &toWrite, QOpcUa::Types valueAttributeType) override;
bool callMethod(const QString &methodNodeId, const QVector<QOpcUa::TypedVariant> &args) override;
- bool resolveBrowsePath(const QVector<QOpcUa::QRelativePathElement> &path) override;
+ bool resolveBrowsePath(const QVector<QOpcUaRelativePathElement> &path) override;
private:
QPointer<QUACppClient> m_client;
diff --git a/src/plugins/opcua/uacpp/quacppplugin.cpp b/src/plugins/opcua/uacpp/quacppplugin.cpp
index 77d2709..2f6dc76 100644
--- a/src/plugins/opcua/uacpp/quacppplugin.cpp
+++ b/src/plugins/opcua/uacpp/quacppplugin.cpp
@@ -1,19 +1,27 @@
/******************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:COMM$
-**
+** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/opcua/uacpp/quacppplugin.h b/src/plugins/opcua/uacpp/quacppplugin.h
index e8c7513..1231bf7 100644
--- a/src/plugins/opcua/uacpp/quacppplugin.h
+++ b/src/plugins/opcua/uacpp/quacppplugin.h
@@ -1,19 +1,27 @@
/******************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:COMM$
-**
+** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/opcua/uacpp/quacppsubscription.cpp b/src/plugins/opcua/uacpp/quacppsubscription.cpp
index 0ab9bfa..c7d429c 100644
--- a/src/plugins/opcua/uacpp/quacppsubscription.cpp
+++ b/src/plugins/opcua/uacpp/quacppsubscription.cpp
@@ -1,19 +1,27 @@
/******************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:COMM$
-**
+** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -24,6 +32,12 @@
#include "quacpputils.h"
#include "quacppvalueconverter.h"
+#include "qopcuaattributeoperand.h"
+#include "qopcuacontentfilterelementresult.h"
+#include "qopcuaelementoperand.h"
+#include "qopcualiteraloperand.h"
+#include "qopcuaeventfilterresult.h"
+
#include <QtCore/QLoggingCategory>
#include <uasession.h>
@@ -93,7 +107,7 @@ bool QUACppSubscription::removeOnServer()
bool QUACppSubscription::addAttributeMonitoredItem(quint64 handle, QOpcUa::NodeAttribute attr, const UaNodeId &id, QOpcUaMonitoringParameters parameters)
{
- qCDebug(QT_OPCUA_PLUGINS_UACPP) << "Adding monitored Item for" << attr;
+ qCDebug(QT_OPCUA_PLUGINS_UACPP) << "Adding monitored Item for" << id.toString().toUtf8() << attr;
static quint32 monitorId = 100;
UaStatus result;
@@ -242,11 +256,11 @@ void QUACppSubscription::modifyMonitoring(quint64 handle, QOpcUa::NodeAttribute
emit m_backend->monitoringStatusChanged(handle, attr, item, p);
}
-bool QUACppSubscription::removeAttributeMonitoredItem(quint64 handle, QOpcUa::NodeAttribute attr)
+bool QUACppSubscription::removeAttributeMonitoredItem(quint64 nodeHandle, QOpcUa::NodeAttribute attr)
{
qCDebug(QT_OPCUA_PLUGINS_UACPP) << "Removing monitored Item for" << attr;
- const QPair<quint64, QOpcUa::NodeAttribute> pair(handle, attr);
+ const QPair<quint64, QOpcUa::NodeAttribute> pair(nodeHandle, attr);
if (!m_monitoredItems.contains(pair)) {
qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Trying to remove unknown monitored item for" << attr;
return false;
@@ -272,7 +286,7 @@ bool QUACppSubscription::removeAttributeMonitoredItem(quint64 handle, QOpcUa::No
s.setMaxKeepAliveCount(m_nativeSubscription->maxKeepAliveCount());
s.setLifetimeCount(m_nativeSubscription->lifetimeCount());
s.setStatusCode(static_cast<QOpcUa::UaStatusCode>(result.statusCode()));
- emit m_backend->monitoringEnableDisable(handle, attr, false, s);
+ emit m_backend->monitoringEnableDisable(nodeHandle, attr, false, s);
return true;
}
@@ -427,7 +441,7 @@ void QUACppSubscription::createEventFilter(const QOpcUaMonitoringParameters::Eve
operands.create(filter.whereClause()[i].filterOperandsRef().size());
for (int j = 0; j < filter.whereClause()[i].filterOperandsRef().size(); ++j) {
- if (filter.whereClause()[i].filterOperandsRef()[j].canConvert<QOpcUa::QElementOperand>()) {
+ if (filter.whereClause()[i].filterOperandsRef()[j].canConvert<QOpcUaElementOperand>()) {
OpcUa_ElementOperand *op;
OpcUa_EncodeableObject_CreateExtension(&OpcUa_ElementOperand_EncodeableType,
&operands[j],
@@ -437,8 +451,8 @@ void QUACppSubscription::createEventFilter(const QOpcUaMonitoringParameters::Eve
qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Could not allocate an ElementOperand for the event filter";
return;
}
- op->Index = filter.whereClause()[i].filterOperandsRef()[j].value<QOpcUa::QElementOperand>().index();
- } else if (filter.whereClause()[i].filterOperandsRef()[j].canConvert<QOpcUa::QLiteralOperand>()) {
+ op->Index = filter.whereClause()[i].filterOperandsRef()[j].value<QOpcUaElementOperand>().index();
+ } else if (filter.whereClause()[i].filterOperandsRef()[j].canConvert<QOpcUaLiteralOperand>()) {
OpcUa_LiteralOperand *op;
OpcUa_EncodeableObject_CreateExtension(&OpcUa_LiteralOperand_EncodeableType,
&operands[j],
@@ -448,9 +462,9 @@ void QUACppSubscription::createEventFilter(const QOpcUaMonitoringParameters::Eve
qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Could not allocate a LiteralOperand for the event filter";
return ;
}
- QOpcUa::QLiteralOperand litOp = filter.whereClause()[i].filterOperandsRef()[j].value<QOpcUa::QLiteralOperand>();
+ QOpcUaLiteralOperand litOp = filter.whereClause()[i].filterOperandsRef()[j].value<QOpcUaLiteralOperand>();
op->Value = QUACppValueConverter::toUACppVariant(litOp.value(), litOp.type());
- } else if (filter.whereClause()[i].filterOperandsRef()[j].canConvert<QOpcUa::QSimpleAttributeOperand>()) {
+ } else if (filter.whereClause()[i].filterOperandsRef()[j].canConvert<QOpcUaSimpleAttributeOperand>()) {
OpcUa_SimpleAttributeOperand *op;
OpcUa_EncodeableObject_CreateExtension(&OpcUa_SimpleAttributeOperand_EncodeableType,
&operands[j],
@@ -460,7 +474,7 @@ void QUACppSubscription::createEventFilter(const QOpcUaMonitoringParameters::Eve
qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Could not allocate a SimpleAttributeOperand for the event filter";
return;
}
- QOpcUa::QSimpleAttributeOperand operand = filter.whereClause()[i].filterOperandsRef()[j].value<QOpcUa::QSimpleAttributeOperand>();
+ QOpcUaSimpleAttributeOperand operand = filter.whereClause()[i].filterOperandsRef()[j].value<QOpcUaSimpleAttributeOperand>();
op->AttributeId = QUACppValueConverter::toUaAttributeId(operand.attributeId());
UaString(operand.indexRange().toUtf8().constData()).copyTo(&op->IndexRange);
if (!operand.typeId().isEmpty())
@@ -472,7 +486,7 @@ void QUACppSubscription::createEventFilter(const QOpcUaMonitoringParameters::Eve
}
op->NoOfBrowsePath = operand.browsePathRef().size();
op->BrowsePath = path.detach();
- } else if (filter.whereClause()[i].filterOperandsRef()[j].canConvert<QOpcUa::QAttributeOperand>()) {
+ } else if (filter.whereClause()[i].filterOperandsRef()[j].canConvert<QOpcUaAttributeOperand>()) {
OpcUa_AttributeOperand *op;
OpcUa_EncodeableObject_CreateExtension(&OpcUa_AttributeOperand_EncodeableType,
&operands[j],
@@ -482,7 +496,7 @@ void QUACppSubscription::createEventFilter(const QOpcUaMonitoringParameters::Eve
qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Could not allocate an AttributeOperand for the event filter";
return;
}
- QOpcUa::QAttributeOperand operand = filter.whereClause()[i].filterOperandsRef()[j].value<QOpcUa::QAttributeOperand>();
+ QOpcUaAttributeOperand operand = filter.whereClause()[i].filterOperandsRef()[j].value<QOpcUaAttributeOperand>();
op->AttributeId = QUACppValueConverter::toUaAttributeId(operand.attributeId());
UaString(operand.indexRange().toUtf8().constData()).copyTo(&op->IndexRange);
if (!operand.nodeId().isEmpty())
@@ -512,9 +526,9 @@ void QUACppSubscription::createEventFilter(const QOpcUaMonitoringParameters::Eve
}
}
-QOpcUa::QEventFilterResult QUACppSubscription::convertEventFilterResult(const OpcUa_ExtensionObject &obj)
+QOpcUaEventFilterResult QUACppSubscription::convertEventFilterResult(const OpcUa_ExtensionObject &obj)
{
- QOpcUa::QEventFilterResult result;
+ QOpcUaEventFilterResult result;
if (UaNodeId(obj.TypeId.NodeId) == UaNodeId(OpcUaId_EventFilterResult_Encoding_DefaultBinary, 0)) {
UaEventFilterResult filterResult(obj);
@@ -530,7 +544,7 @@ QOpcUa::QEventFilterResult QUACppSubscription::convertEventFilterResult(const Op
contentFilterResult.getElementResults(elementResults);
for (size_t i = 0; i < elementResults.length(); ++i) {
- QOpcUa::QContentFilterElementResult temp;
+ QOpcUaContentFilterElementResult temp;
temp.setStatusCode(static_cast<QOpcUa::UaStatusCode>(elementResults[i].StatusCode));
for (int j = 0; j < elementResults[i].NoOfOperandStatusCodes; ++j)
temp.operandStatusCodesRef().append(static_cast<QOpcUa::UaStatusCode>(elementResults[i].OperandStatusCodes[j]));
@@ -541,7 +555,7 @@ QOpcUa::QEventFilterResult QUACppSubscription::convertEventFilterResult(const Op
return result;
}
-bool QUACppSubscription::modifySubscriptionParameters(quint64 handle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value)
+bool QUACppSubscription::modifySubscriptionParameters(quint64 nodeHandle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value)
{
QOpcUaMonitoringParameters p;
SubscriptionSettings settings;
@@ -560,7 +574,7 @@ bool QUACppSubscription::modifySubscriptionParameters(quint64 handle, QOpcUa::No
if (!ok) {
qCWarning(QT_OPCUA_PLUGINS_UACPP, "Could not modify PublishingInterval, value is not a double");
p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
break;
@@ -572,7 +586,7 @@ bool QUACppSubscription::modifySubscriptionParameters(quint64 handle, QOpcUa::No
if (!ok) {
qCWarning(QT_OPCUA_PLUGINS_UACPP, "Could not modify LifetimeCount, value is not an integer");
p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
break;
@@ -584,7 +598,7 @@ bool QUACppSubscription::modifySubscriptionParameters(quint64 handle, QOpcUa::No
if (!ok) {
qCWarning(QT_OPCUA_PLUGINS_UACPP, "Could not modify MaxKeepAliveCount, value is not an integer");
p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
break;
@@ -603,7 +617,7 @@ bool QUACppSubscription::modifySubscriptionParameters(quint64 handle, QOpcUa::No
if (result.isBad()) {
p.setStatusCode(static_cast<QOpcUa::UaStatusCode>(result.statusCode()));
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
} else {
p.setStatusCode(QOpcUa::UaStatusCode::Good);
p.setPublishingInterval(settings.publishingInterval);
@@ -630,10 +644,10 @@ bool QUACppSubscription::modifySubscriptionParameters(quint64 handle, QOpcUa::No
return false;
}
-bool QUACppSubscription::modifyMonitoredItemParameters(quint64 handle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value)
+bool QUACppSubscription::modifyMonitoredItemParameters(quint64 nodeHandle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value)
{
// Get hold of OpcUa_MonitoredItemCreateResult
- const QPair<quint64, QOpcUa::NodeAttribute> key(handle, attr);
+ const QPair<quint64, QOpcUa::NodeAttribute> key(nodeHandle, attr);
if (!m_monitoredItems.contains(key)) {
qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Did not find monitored item";
return false;
@@ -655,7 +669,7 @@ bool QUACppSubscription::modifyMonitoredItemParameters(quint64 handle, QOpcUa::N
if (value.type() != QVariant::Bool) {
qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Could not modify DiscardOldest, value is not a bool";
p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
modifyRequest.RequestedParameters.DiscardOldest = value.toBool();
@@ -665,7 +679,7 @@ bool QUACppSubscription::modifyMonitoredItemParameters(quint64 handle, QOpcUa::N
if (value.type() != QVariant::UInt) {
qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Could not modify QueueSize, value is not an integer";
p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
modifyRequest.RequestedParameters.QueueSize = value.toUInt();
@@ -675,7 +689,7 @@ bool QUACppSubscription::modifyMonitoredItemParameters(quint64 handle, QOpcUa::N
if (value.type() != QVariant::Double) {
qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Could not modify SamplingInterval, value is not a double";
p.setStatusCode(QOpcUa::UaStatusCode::BadTypeMismatch);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
modifyRequest.RequestedParameters.SamplingInterval = value.toDouble();
@@ -686,7 +700,7 @@ bool QUACppSubscription::modifyMonitoredItemParameters(quint64 handle, QOpcUa::N
if (!modifyRequest.RequestedParameters.Filter.Body.EncodeableObject.Object) {
qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Could not modify the filter, filter creation failed";
p.setStatusCode(QOpcUa::UaStatusCode::BadInternalError);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
break;
@@ -702,7 +716,7 @@ bool QUACppSubscription::modifyMonitoredItemParameters(quint64 handle, QOpcUa::N
if (!modifyRequest.RequestedParameters.Filter.Body.EncodeableObject.Object) {
qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Unable to modify the monitored item, filter creation failed";
p.setStatusCode(QOpcUa::UaStatusCode::BadInternalError);
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
return true;
}
}
@@ -718,7 +732,7 @@ bool QUACppSubscription::modifyMonitoredItemParameters(quint64 handle, QOpcUa::N
p.setStatusCode(static_cast<QOpcUa::UaStatusCode>(result.isGood() ?
results[0].StatusCode :
result.statusCode()));
- emit m_backend->monitoringStatusChanged(handle, attr, item, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, item, p);
} else {
p.setStatusCode(QOpcUa::UaStatusCode::Good);
QOpcUaMonitoringParameters::Parameters changed = item;
@@ -745,7 +759,7 @@ bool QUACppSubscription::modifyMonitoredItemParameters(quint64 handle, QOpcUa::N
p.setFilterResult(convertEventFilterResult(results[0].FilterResult));
}
- emit m_backend->monitoringStatusChanged(handle, attr, changed, p);
+ emit m_backend->monitoringStatusChanged(nodeHandle, attr, changed, p);
m_monitoredItems[key].second = p;
}
diff --git a/src/plugins/opcua/uacpp/quacppsubscription.h b/src/plugins/opcua/uacpp/quacppsubscription.h
index cf4c1bf..4010c24 100644
--- a/src/plugins/opcua/uacpp/quacppsubscription.h
+++ b/src/plugins/opcua/uacpp/quacppsubscription.h
@@ -1,19 +1,27 @@
/******************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:COMM$
-**
+** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -39,9 +47,9 @@ public:
bool removeOnServer();
- bool addAttributeMonitoredItem(quint64 handle, QOpcUa::NodeAttribute attr, const UaNodeId &id, QOpcUaMonitoringParameters parameters);
- void modifyMonitoring(quint64 handle, QOpcUa::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, QVariant value);
- bool removeAttributeMonitoredItem(quint64 handle, QOpcUa::NodeAttribute attr);
+ bool addAttributeMonitoredItem(quint64 nodeHandle, QOpcUa::NodeAttribute attr, const UaNodeId &id, QOpcUaMonitoringParameters parameters);
+ void modifyMonitoring(quint64 nodeHandle, QOpcUa::NodeAttribute attr, QOpcUaMonitoringParameters::Parameter item, QVariant value);
+ bool removeAttributeMonitoredItem(quint64 nodeHandle, QOpcUa::NodeAttribute attr);
double interval() const;
quint32 subscriptionId() const;
@@ -57,10 +65,10 @@ private:
OpcUa_ExtensionObject createFilter(const QVariant &filterData);
void createDataChangeFilter(const QOpcUaMonitoringParameters::DataChangeFilter &filter, OpcUa_ExtensionObject *out);
void createEventFilter(const QOpcUaMonitoringParameters::EventFilter &filter, OpcUa_ExtensionObject *out);
- QOpcUa::QEventFilterResult convertEventFilterResult(const OpcUa_ExtensionObject &obj);
+ QOpcUaEventFilterResult convertEventFilterResult(const OpcUa_ExtensionObject &obj);
- bool modifySubscriptionParameters(quint64 handle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value);
- bool modifyMonitoredItemParameters(quint64 handle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value);
+ bool modifySubscriptionParameters(quint64 nodeHandle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value);
+ bool modifyMonitoredItemParameters(quint64 nodeHandle, QOpcUa::NodeAttribute attr, const QOpcUaMonitoringParameters::Parameter &item, const QVariant &value);
UACppAsyncBackend *m_backend;
QOpcUaMonitoringParameters m_subscriptionParameters;
diff --git a/src/plugins/opcua/uacpp/quacpputils.cpp b/src/plugins/opcua/uacpp/quacpputils.cpp
index c5661f9..a009f9c 100644
--- a/src/plugins/opcua/uacpp/quacpputils.cpp
+++ b/src/plugins/opcua/uacpp/quacpputils.cpp
@@ -1,19 +1,27 @@
/******************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:COMM$
-**
+** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/opcua/uacpp/quacpputils.h b/src/plugins/opcua/uacpp/quacpputils.h
index 8358acc..702efbe 100644
--- a/src/plugins/opcua/uacpp/quacpputils.h
+++ b/src/plugins/opcua/uacpp/quacpputils.h
@@ -1,19 +1,27 @@
/******************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:COMM$
-**
+** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/opcua/uacpp/quacppvalueconverter.cpp b/src/plugins/opcua/uacpp/quacppvalueconverter.cpp
index 6b950da..3aac31d 100644
--- a/src/plugins/opcua/uacpp/quacppvalueconverter.cpp
+++ b/src/plugins/opcua/uacpp/quacppvalueconverter.cpp
@@ -1,19 +1,27 @@
/******************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:COMM$
-**
+** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -23,6 +31,7 @@
#include "quacpputils.h"
#include <QtOpcUa/qopcuabinarydataencoding.h>
+#include <QtOpcUa/qopcuamultidimensionalarray.h>
#include <QtCore/QDateTime>
#include <QtCore/QLoggingCategory>
@@ -36,6 +45,7 @@
#include <uaextensionobject.h>
#include <uaeuinformation.h>
#include <uaaxisinformation.h>
+#include <uaargument.h>
QT_BEGIN_NAMESPACE
@@ -45,49 +55,6 @@ using namespace QOpcUa::NodeIds;
namespace QUACppValueConverter {
-QOpcUa::Types qvariantTypeToQOpcUaType(QMetaType::Type type)
-{
- switch (type) {
- case QMetaType::Bool:
- return QOpcUa::Boolean;
- case QMetaType::UChar:
- return QOpcUa::Byte;
- case QMetaType::Char:
- return QOpcUa::SByte;
- case QMetaType::UShort:
- return QOpcUa::UInt16;
- case QMetaType::Short:
- return QOpcUa::Int16;
- case QMetaType::Int:
- return QOpcUa::Int32;
- case QMetaType::UInt:
- return QOpcUa::UInt32;
- case QMetaType::ULongLong:
- return QOpcUa::UInt64;
- case QMetaType::LongLong:
- return QOpcUa::Int64;
- case QMetaType::Double:
- return QOpcUa::Double;
- case QMetaType::Float:
- return QOpcUa::Float;
- case QMetaType::QString:
- return QOpcUa::String;
- //return QOpcUa::LocalizedText; // TODO: unclear
- case QMetaType::QDateTime:
- return QOpcUa::DateTime;
- case QMetaType::QByteArray:
- return QOpcUa::ByteString;
- case QMetaType::QUuid:
- return QOpcUa::Guid;
- //return QOpcUa::XmlElement;
- //return QOpcUa::NodeId;
- default:
- break;
- }
-
- return QOpcUa::Undefined;
-}
-
OpcUa_BuiltInType toDataType(QOpcUa::Types valueType)
{
switch (valueType) {
@@ -137,6 +104,8 @@ OpcUa_BuiltInType toDataType(QOpcUa::Types valueType)
case QOpcUa::DoubleComplexNumber:
case QOpcUa::AxisInformation:
case QOpcUa::XV:
+ case QOpcUa::Argument:
+ case QOpcUa::ExtensionObject:
return OpcUa_BuiltInType::OpcUaType_ExtensionObject;
case QOpcUa::ExpandedNodeId:
return OpcUa_BuiltInType::OpcUaType_ExpandedNodeId;
@@ -179,26 +148,19 @@ template<>
QVariant scalarToQVariant<QString, OpcUa_LocalizedText>(OpcUa_LocalizedText *data, QMetaType::Type type)
{
Q_UNUSED(type)
- UaLocalizedText ualt(*data);
- const UaString ualtLocal(ualt.locale());
- const UaString ualtText(ualt.text());
-
- QOpcUa::QLocalizedText lt;
-
- lt.setLocale(QString::fromUtf8(ualtLocal.toUtf8(), ualtLocal.size()));
- lt.setText(QString::fromUtf8(ualtText.toUtf8(), ualtText.size()));
- return QVariant::fromValue(lt);
+ UaLocalizedText uaLocalizedText(*data);
+ return QVariant::fromValue(toQOpcUaLocalizedText(&uaLocalizedText));
}
template<>
-QVariant scalarToQVariant<QOpcUa::QLocalizedText, OpcUa_LocalizedText>(OpcUa_LocalizedText *data, QMetaType::Type type)
+QVariant scalarToQVariant<QOpcUaLocalizedText, OpcUa_LocalizedText>(OpcUa_LocalizedText *data, QMetaType::Type type)
{
Q_UNUSED(type)
UaLocalizedText ualt(*data);
const UaString ualtLocal(ualt.locale());
const UaString ualtText(ualt.text());
- QOpcUa::QLocalizedText lt;
+ QOpcUaLocalizedText lt;
lt.setLocale(QString::fromUtf8(ualtLocal.toUtf8(), ualtLocal.size()));
lt.setText(QString::fromUtf8(ualtText.toUtf8(), ualtText.size()));
@@ -230,10 +192,10 @@ QVariant scalarToQVariant<QUuid, OpcUa_Guid>(OpcUa_Guid *data, QMetaType::Type t
}
template<>
-QVariant scalarToQVariant<QOpcUa::QExpandedNodeId, OpcUa_ExpandedNodeId>(OpcUa_ExpandedNodeId *data, QMetaType::Type type)
+QVariant scalarToQVariant<QOpcUaExpandedNodeId, OpcUa_ExpandedNodeId>(OpcUa_ExpandedNodeId *data, QMetaType::Type type)
{
Q_UNUSED(type)
- QOpcUa::QExpandedNodeId temp;
+ QOpcUaExpandedNodeId temp;
temp.setServerIndex(data->ServerIndex);
temp.setNodeId(UACppUtils::nodeIdToQString(data->NodeId));
temp.setNamespaceUri(QString::fromUtf8(UaString(data->NamespaceUri).toUtf8(),
@@ -242,26 +204,26 @@ QVariant scalarToQVariant<QOpcUa::QExpandedNodeId, OpcUa_ExpandedNodeId>(OpcUa_E
}
template<>
-QVariant scalarToQVariant<QOpcUa::QQualifiedName, OpcUa_QualifiedName>(OpcUa_QualifiedName *data, QMetaType::Type type)
+QVariant scalarToQVariant<QOpcUaQualifiedName, OpcUa_QualifiedName>(OpcUa_QualifiedName *data, QMetaType::Type type)
{
Q_UNUSED(type);
- QOpcUa::QQualifiedName temp;
+ QOpcUaQualifiedName temp;
temp.setNamespaceIndex(data->NamespaceIndex);
temp.setName(scalarToQVariant<QString, OpcUa_String>(&data->Name, QMetaType::Type::QString).toString());
return QVariant::fromValue(temp);
}
-inline QOpcUa::QEUInformation UaEUInformationToQEUInformation(const UaEUInformation &info)
+inline QOpcUaEUInformation UaEUInformationToQOpcUaEUInformation(const UaEUInformation &info)
{
const UaLocalizedText desc = info.getDescription();
const UaLocalizedText dispName = info.getDisplayName();
const UaString namespaceUri = info.getNamespaceUri();
quint32 qunitId = info.getUnitId();
- QOpcUa::QLocalizedText qDesc = scalarToQVariant<QOpcUa::QLocalizedText, OpcUa_LocalizedText>(const_cast<OpcUa_LocalizedText *>(&*desc)).value<QOpcUa::QLocalizedText>();
- QOpcUa::QLocalizedText qDisp = scalarToQVariant<QOpcUa::QLocalizedText, OpcUa_LocalizedText>(const_cast<OpcUa_LocalizedText *>(&*dispName)).value<QOpcUa::QLocalizedText>();
+ QOpcUaLocalizedText qDesc = scalarToQVariant<QOpcUaLocalizedText, OpcUa_LocalizedText>(const_cast<OpcUa_LocalizedText *>(&*desc)).value<QOpcUaLocalizedText>();
+ QOpcUaLocalizedText qDisp = scalarToQVariant<QOpcUaLocalizedText, OpcUa_LocalizedText>(const_cast<OpcUa_LocalizedText *>(&*dispName)).value<QOpcUaLocalizedText>();
QString qNamespaceUri = QString::fromUtf8(namespaceUri.toUtf8(), namespaceUri.size());
- QOpcUa::QEUInformation euinfo(qNamespaceUri, qunitId, qDisp, qDesc);
+ QOpcUaEUInformation euinfo(qNamespaceUri, qunitId, qDisp, qDesc);
return euinfo;
}
@@ -269,6 +231,18 @@ template<>
QVariant scalarToQVariant<QVariant, OpcUa_ExtensionObject>(OpcUa_ExtensionObject *data, QMetaType::Type type)
{
Q_UNUSED(type);
+
+ if (data->Encoding == OpcUa_ExtensionObjectEncoding_Binary) {
+ QOpcUaExtensionObject obj;
+ obj.setEncoding(static_cast<QOpcUaExtensionObject::Encoding>(data->Encoding));
+ const UaExpandedNodeId uaExpandedNodeId(data->TypeId);
+ const UaNodeId uaTypeId(uaExpandedNodeId.nodeId());
+ obj.setEncodingTypeId(UACppUtils::nodeIdToQString(uaTypeId));
+ // Copy data for later use
+ obj.setEncodedBody(QByteArray(reinterpret_cast<char*>(data->Body.Binary.Data), data->Body.Binary.Length));
+ return obj;
+ }
+
if (data->TypeId.NodeId.IdentifierType != OpcUa_IdentifierType_Numeric ||
data->TypeId.NodeId.NamespaceIndex != 0 ||
data->Encoding != OpcUa_ExtensionObjectEncoding_EncodeableObject)
@@ -291,18 +265,18 @@ QVariant scalarToQVariant<QVariant, OpcUa_ExtensionObject>(OpcUa_ExtensionObject
// already decoded object. For non ns=0, we might be able to use the generic decoder from the module.
// Same for AxisInformation
UaEUInformation info(*data);
- QOpcUa::QEUInformation euinfo = UaEUInformationToQEUInformation(info);
+ QOpcUaEUInformation euinfo = UaEUInformationToQOpcUaEUInformation(info);
result = QVariant::fromValue(euinfo);
break;
}
case Namespace0::Range_Encoding_DefaultBinary:
- result = QVariant::fromValue(decoder.decode<QOpcUa::QRange>(success));
+ result = QVariant::fromValue(decoder.decode<QOpcUaRange>(success));
break;
case Namespace0::ComplexNumberType_Encoding_DefaultBinary:
- result = QVariant::fromValue(decoder.decode<QOpcUa::QComplexNumber>(success));
+ result = QVariant::fromValue(decoder.decode<QOpcUaComplexNumber>(success));
break;
case Namespace0::DoubleComplexNumberType_Encoding_DefaultBinary:
- result = QVariant::fromValue(decoder.decode<QOpcUa::QDoubleComplexNumber>(success));
+ result = QVariant::fromValue(decoder.decode<QOpcUaDoubleComplexNumber>(success));
break;
case Namespace0::AxisInformation_Encoding_DefaultBinary: {
UaAxisInformation info(*data);
@@ -311,21 +285,28 @@ QVariant scalarToQVariant<QVariant, OpcUa_ExtensionObject>(OpcUa_ExtensionObject
UaDoubleArray uaDoubleArray;
info.getAxisSteps(uaDoubleArray);
- const QOpcUa::QEUInformation qEuInfo = UaEUInformationToQEUInformation(info.getEngineeringUnits());
- const QOpcUa::QRange qRange(uaRange.getLow(), uaRange.getHigh());
- const QOpcUa::QLocalizedText qTitle = scalarToQVariant<QOpcUa::QLocalizedText, OpcUa_LocalizedText>(const_cast<OpcUa_LocalizedText *>(&*uaTitle)).value<QOpcUa::QLocalizedText>();;
+ const QOpcUaEUInformation qEuInfo = UaEUInformationToQOpcUaEUInformation(info.getEngineeringUnits());
+ const QOpcUaRange qRange(uaRange.getLow(), uaRange.getHigh());
+ const QOpcUaLocalizedText qTitle = scalarToQVariant<QOpcUaLocalizedText, OpcUa_LocalizedText>(const_cast<OpcUa_LocalizedText *>(&*uaTitle)).value<QOpcUaLocalizedText>();;
const QOpcUa::AxisScale qScale = static_cast<QOpcUa::AxisScale>(info.getAxisScaleType());
QVector<double> qAxisSteps;
for (OpcUa_UInt32 i = 0; i < uaDoubleArray.length(); ++i)
qAxisSteps.append(uaDoubleArray[i]);
- QOpcUa::QAxisInformation qAxisInfo(qEuInfo, qRange, qTitle, qScale, qAxisSteps);
+ QOpcUaAxisInformation qAxisInfo(qEuInfo, qRange, qTitle, qScale, qAxisSteps);
result = QVariant::fromValue(qAxisInfo);
break;
}
case Namespace0::XVType_Encoding_DefaultBinary:
- result = QVariant::fromValue(decoder.decode<QOpcUa::QXValue>(success));
+ result = QVariant::fromValue(decoder.decode<QOpcUaXValue>(success));
+ break;
+ case Namespace0::Argument_Encoding_DefaultBinary: {
+ // This type is decoded transparently and must not be decoded binary
+ UaArgument uaArgument(*data);
+ QOpcUaArgument argument = toQArgument(&uaArgument);
+ result = QVariant::fromValue(argument);
break;
+ }
default:
qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Unknown extension object type, returning raw data:" << UACppUtils::nodeIdToQString(data->TypeId.NodeId);
result = QByteArray(buffer.constData(), buffer.size());
@@ -341,6 +322,27 @@ QVariant scalarToQVariant<QVariant, OpcUa_ExtensionObject>(OpcUa_ExtensionObject
template<typename TARGETTYPE, typename UATYPE>
QVariant arrayToQVariant(const OpcUa_Variant &var, QMetaType::Type type)
{
+ if (var.ArrayType == OpcUa_VariantArrayType_Matrix) {
+ UaVariant variant(var);
+
+ // Ensure that the array dimensions fit in a QVector
+ if (variant.dimensionSize() > static_cast<OpcUa_Int32>((std::numeric_limits<int>::max)())) {
+ qCWarning(QT_OPCUA_PLUGINS_UACPP) << "The array dimensions do not fit in a QVector.";
+ return QOpcUaMultiDimensionalArray();
+ }
+
+ QVariantList list;
+ for (OpcUa_Int32 i = 0; i < variant.noOfMatrixElements(); ++i) {
+ UATYPE *temp = static_cast<UATYPE *>(var.Value.Matrix.Value.Array);
+ list.append(scalarToQVariant<TARGETTYPE, UATYPE>(&temp[i], type));
+ }
+
+ QVector<quint32> arrayDimensions;
+ for (qint32 i = 0; i < variant.dimensionSize(); ++i)
+ arrayDimensions.append(var.Value.Matrix.Dimensions[i]);
+ return QOpcUaMultiDimensionalArray(list, arrayDimensions);
+ }
+
if (var.ArrayType == OpcUa_VariantArrayType_Array) {
QVariantList list;
for (OpcUa_Int32 i = 0; i < var.Value.Array.Length; ++i) {
@@ -414,13 +416,13 @@ QVariant arrayToQVariant<QUuid, OpcUa_Guid *>(const OpcUa_Variant &var, QMetaTyp
}
template<>
-QVariant arrayToQVariant<QOpcUa::QQualifiedName, OpcUa_QualifiedName *>(const OpcUa_Variant &var, QMetaType::Type type)
+QVariant arrayToQVariant<QOpcUaQualifiedName, OpcUa_QualifiedName *>(const OpcUa_Variant &var, QMetaType::Type type)
{
if (var.ArrayType == OpcUa_VariantArrayType_Array) {
QVariantList list;
for (OpcUa_Int32 i = 0; i < var.Value.Array.Length; ++i) {
OpcUa_QualifiedName *temp = var.Value.Array.Value.QualifiedNameArray;
- list.append(scalarToQVariant<QOpcUa::QQualifiedName, OpcUa_QualifiedName>(&temp[i], type));
+ list.append(scalarToQVariant<QOpcUaQualifiedName, OpcUa_QualifiedName>(&temp[i], type));
}
if (list.size() == 1)
return list.at(0);
@@ -428,7 +430,7 @@ QVariant arrayToQVariant<QOpcUa::QQualifiedName, OpcUa_QualifiedName *>(const Op
return list;
}
OpcUa_QualifiedName *temp = var.Value.QualifiedName;
- return scalarToQVariant<QOpcUa::QQualifiedName, OpcUa_QualifiedName>(temp, type);
+ return scalarToQVariant<QOpcUaQualifiedName, OpcUa_QualifiedName>(temp, type);
}
template<>
@@ -450,13 +452,13 @@ QVariant arrayToQVariant<QVariant, OpcUa_ExtensionObject *>(const OpcUa_Variant
}
template<>
-QVariant arrayToQVariant<QOpcUa::QExpandedNodeId, OpcUa_ExpandedNodeId *>(const OpcUa_Variant &var, QMetaType::Type type)
+QVariant arrayToQVariant<QOpcUaExpandedNodeId, OpcUa_ExpandedNodeId *>(const OpcUa_Variant &var, QMetaType::Type type)
{
if (var.ArrayType == OpcUa_VariantArrayType_Array) {
QVariantList list;
for (OpcUa_Int32 i = 0; i < var.Value.Array.Length; ++i) {
OpcUa_ExpandedNodeId *temp = var.Value.Array.Value.ExpandedNodeIdArray;
- list.append(scalarToQVariant<QOpcUa::QExpandedNodeId, OpcUa_ExpandedNodeId>(&temp[i], type));
+ list.append(scalarToQVariant<QOpcUaExpandedNodeId, OpcUa_ExpandedNodeId>(&temp[i], type));
}
if (list.size() == 1)
return list.at(0);
@@ -464,7 +466,7 @@ QVariant arrayToQVariant<QOpcUa::QExpandedNodeId, OpcUa_ExpandedNodeId *>(const
return list;
}
OpcUa_ExpandedNodeId *temp = var.Value.ExpandedNodeId;
- return scalarToQVariant<QOpcUa::QExpandedNodeId, OpcUa_ExpandedNodeId>(temp, type);
+ return scalarToQVariant<QOpcUaExpandedNodeId, OpcUa_ExpandedNodeId>(temp, type);
}
template<typename TARGETTYPE, typename QTTYPE>
@@ -476,11 +478,7 @@ void scalarFromQVariant(const QVariant &var, TARGETTYPE *ptr)
template<>
void scalarFromQVariant<OpcUa_DateTime, QDateTime>(const QVariant &var, OpcUa_DateTime *ptr)
{
- // OPC-UA part 3, Table C.9
- const QDateTime uaEpochStart(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC);
- // OpcUa time is defined in part 6, 5.2.2.5 in 100ns which need to be converted to milliseconds.
- const UaDateTime dt = UaDateTime((var.toDateTime().toMSecsSinceEpoch() - uaEpochStart.toMSecsSinceEpoch()) * 10000);
- *ptr = dt;
+ *ptr = toUACppDateTime(var.toDateTime());
}
template<>
@@ -493,16 +491,11 @@ void scalarFromQVariant<OpcUa_String, QString>(const QVariant &var, OpcUa_String
template<>
void scalarFromQVariant<OpcUa_LocalizedText, QString>(const QVariant &var, OpcUa_LocalizedText *ptr)
{
- QOpcUa::QLocalizedText lt = var.canConvert<QOpcUa::QLocalizedText>()
- ? var.value<QOpcUa::QLocalizedText>()
- : QOpcUa::QLocalizedText(QLatin1String(""), var.value<QString>());
+ QOpcUaLocalizedText lt = var.canConvert<QOpcUaLocalizedText>()
+ ? var.value<QOpcUaLocalizedText>()
+ : QOpcUaLocalizedText(QLatin1String(""), var.value<QString>());
- UaLocalizedText ualt;
- if (lt.locale().size())
- ualt.setLocale(UaString(lt.locale().toUtf8().constData()));
- if (lt.text().size())
- ualt.setText(UaString(lt.text().toUtf8().constData()));
- ualt.copyTo(ptr);
+ *ptr = toUACppLocalizedText(lt);
}
template<>
@@ -527,12 +520,9 @@ void scalarFromQVariant<OpcUa_NodeId, QString>(const QVariant &var, OpcUa_NodeId
}
template<>
-void scalarFromQVariant<OpcUa_QualifiedName, QOpcUa::QQualifiedName>(const QVariant &var, OpcUa_QualifiedName *ptr)
+void scalarFromQVariant<OpcUa_QualifiedName, QOpcUaQualifiedName>(const QVariant &var, OpcUa_QualifiedName *ptr)
{
- QOpcUa::QQualifiedName temp = var.value<QOpcUa::QQualifiedName>();
- ptr->NamespaceIndex = temp.namespaceIndex();
- const UaString name(temp.name().toUtf8().constData());
- name.copyTo(&ptr->Name);
+ *ptr = toUACppQualifiedName(var.value<QOpcUaQualifiedName>());
}
template<>
@@ -545,84 +535,86 @@ void scalarFromQVariant<OpcUa_Guid, QUuid>(const QVariant &var, OpcUa_Guid *ptr)
memcpy(ptr->Data4, uuid.data4, sizeof(uuid.data4));
}
-void createExtensionObject(QByteArray &data, Namespace0 id, OpcUa_ExtensionObject *ptr)
+void createExtensionObject(const QByteArray &data, const UaNodeId &typeId, OpcUa_ExtensionObject *ptr)
{
OpcUa_ExtensionObject_Initialize(ptr);
UaByteArray arr(data.data(), data.length());
arr.copyTo(&ptr->Body.Binary);
ptr->Encoding = OpcUa_ExtensionObjectEncoding_Binary;
ptr->BodySize = data.length();
+ typeId.copyTo(&ptr->TypeId.NodeId);
+}
+
+void createExtensionObject(const QByteArray &data, Namespace0 id, OpcUa_ExtensionObject *ptr)
+{
const UaNodeId temp(static_cast<OpcUa_UInt32>(id));
- temp.copyTo(&ptr->TypeId.NodeId);
+ createExtensionObject(data, temp, ptr);
}
template<>
-void scalarFromQVariant<OpcUa_ExtensionObject, QOpcUa::QRange>(const QVariant &var, OpcUa_ExtensionObject *ptr)
+void scalarFromQVariant<OpcUa_ExtensionObject, QOpcUaRange>(const QVariant &var, OpcUa_ExtensionObject *ptr)
{
- const QOpcUa::QRange range = var.value<QOpcUa::QRange>();
+ const QOpcUaRange range = var.value<QOpcUaRange>();
QByteArray temp;
QOpcUaBinaryDataEncoding encoder(&temp);
- encoder.encode<QOpcUa::QRange>(range);
+ encoder.encode<QOpcUaRange>(range);
return createExtensionObject(temp, Namespace0::Range_Encoding_DefaultBinary, ptr);
}
template<>
-void scalarFromQVariant<OpcUa_ExtensionObject, QOpcUa::QEUInformation>(const QVariant &var, OpcUa_ExtensionObject *ptr)
+void scalarFromQVariant<OpcUa_ExtensionObject, QOpcUaEUInformation>(const QVariant &var, OpcUa_ExtensionObject *ptr)
{
- const QOpcUa::QEUInformation info = var.value<QOpcUa::QEUInformation>();
+ const QOpcUaEUInformation info = var.value<QOpcUaEUInformation>();
QByteArray temp;
QOpcUaBinaryDataEncoding encoder(&temp);
- encoder.encode<QOpcUa::QEUInformation>(info);
+ encoder.encode<QOpcUaEUInformation>(info);
return createExtensionObject(temp, Namespace0::EUInformation_Encoding_DefaultBinary, ptr);
}
template<>
-void scalarFromQVariant<OpcUa_ExtensionObject, QOpcUa::QComplexNumber>(const QVariant &var, OpcUa_ExtensionObject *ptr)
+void scalarFromQVariant<OpcUa_ExtensionObject, QOpcUaComplexNumber>(const QVariant &var, OpcUa_ExtensionObject *ptr)
{
- const QOpcUa::QComplexNumber num = var.value<QOpcUa::QComplexNumber>();
+ const QOpcUaComplexNumber num = var.value<QOpcUaComplexNumber>();
QByteArray temp;
QOpcUaBinaryDataEncoding encoder(&temp);
- encoder.encode<QOpcUa::QComplexNumber>(num);
+ encoder.encode<QOpcUaComplexNumber>(num);
return createExtensionObject(temp, Namespace0::ComplexNumberType_Encoding_DefaultBinary, ptr);
}
template<>
-void scalarFromQVariant<OpcUa_ExtensionObject, QOpcUa::QDoubleComplexNumber>(const QVariant &var, OpcUa_ExtensionObject *ptr)
+void scalarFromQVariant<OpcUa_ExtensionObject, QOpcUaDoubleComplexNumber>(const QVariant &var, OpcUa_ExtensionObject *ptr)
{
- const QOpcUa::QDoubleComplexNumber num = var.value<QOpcUa::QDoubleComplexNumber>();
+ const QOpcUaDoubleComplexNumber num = var.value<QOpcUaDoubleComplexNumber>();
QByteArray temp;
QOpcUaBinaryDataEncoding encoder(&temp);
- encoder.encode<QOpcUa::QDoubleComplexNumber>(num);
+ encoder.encode<QOpcUaDoubleComplexNumber>(num);
return createExtensionObject(temp, Namespace0::DoubleComplexNumberType_Encoding_DefaultBinary, ptr);
}
template<>
-void scalarFromQVariant<OpcUa_ExtensionObject, QOpcUa::QAxisInformation>(const QVariant &var, OpcUa_ExtensionObject *ptr)
+void scalarFromQVariant<OpcUa_ExtensionObject, QOpcUaAxisInformation>(const QVariant &var, OpcUa_ExtensionObject *ptr)
{
- const QOpcUa::QAxisInformation num = var.value<QOpcUa::QAxisInformation>();
+ const QOpcUaAxisInformation num = var.value<QOpcUaAxisInformation>();
QByteArray temp;
QOpcUaBinaryDataEncoding encoder(&temp);
- encoder.encode<QOpcUa::QAxisInformation>(num);
+ encoder.encode<QOpcUaAxisInformation>(num);
return createExtensionObject(temp, Namespace0::AxisInformation_Encoding_DefaultBinary, ptr);
}
template<>
-void scalarFromQVariant<OpcUa_ExtensionObject, QOpcUa::QXValue>(const QVariant &var, OpcUa_ExtensionObject *ptr)
+void scalarFromQVariant<OpcUa_ExtensionObject, QOpcUaXValue>(const QVariant &var, OpcUa_ExtensionObject *ptr)
{
- const QOpcUa::QXValue num = var.value<QOpcUa::QXValue>();
+ const QOpcUaXValue num = var.value<QOpcUaXValue>();
QByteArray temp;
QOpcUaBinaryDataEncoding encoder(&temp);
- encoder.encode<QOpcUa::QXValue>(num);
+ encoder.encode<QOpcUaXValue>(num);
return createExtensionObject(temp, Namespace0::XVType_Encoding_DefaultBinary, ptr);
}
template<>
-void scalarFromQVariant<OpcUa_ExpandedNodeId, QOpcUa::QExpandedNodeId>(const QVariant &var, OpcUa_ExpandedNodeId *ptr)
+void scalarFromQVariant<OpcUa_ExpandedNodeId, QOpcUaExpandedNodeId>(const QVariant &var, OpcUa_ExpandedNodeId *ptr)
{
- const QOpcUa::QExpandedNodeId temp = var.value<QOpcUa::QExpandedNodeId>();
- ptr->ServerIndex = temp.serverIndex();
- UACppUtils::nodeIdFromQString(temp.nodeId()).copyTo(&ptr->NodeId);
- UaString(temp.namespaceUri().toUtf8().constData()).copyTo(&ptr->NamespaceUri);
+ *ptr = toUACppExpandedNodeId(var.value<QOpcUaExpandedNodeId>());
}
template<typename TARGETTYPE, typename QTTYPE>
@@ -637,10 +629,9 @@ OpcUa_Variant arrayFromQVariant(const QVariant &var, const OpcUa_BuiltInType typ
return opcuavariant;
opcuavariant.Datatype = type;
- opcuavariant.ArrayType = OpcUa_True;
+ opcuavariant.ArrayType = OpcUa_VariantArrayType_Array;
opcuavariant.Value.Array.Length = list.size();
- // Use calloc() instead of new because the OPC UA stack uses free() internally when clearing the data
- TARGETTYPE *arr = static_cast<TARGETTYPE *>(calloc(list.size(), sizeof(TARGETTYPE)));
+ TARGETTYPE *arr = static_cast<TARGETTYPE *>(OpcUa_Alloc(list.size() * sizeof(TARGETTYPE)));
opcuavariant.Value.Array.Value.Array = arr;
for (int i = 0; i < list.size(); ++i)
@@ -670,10 +661,9 @@ OpcUa_Variant arrayFromQVariantPointer(const QVariant &var, const OpcUa_BuiltInT
return opcuavariant;
opcuavariant.Datatype = type;
- opcuavariant.ArrayType = OpcUa_True;
+ opcuavariant.ArrayType = OpcUa_VariantArrayType_Array;
opcuavariant.Value.Array.Length = list.size();
- // Use calloc() instead of new because the OPC UA stack uses free() internally when clearing the data
- TARGETTYPE *arr = static_cast<TARGETTYPE *>(calloc(list.size(), sizeof(TARGETTYPE)));
+ TARGETTYPE *arr = static_cast<TARGETTYPE *>(OpcUa_Alloc(list.size() * sizeof(TARGETTYPE)));
opcuavariant.Value.Array.Value.Array = arr;
@@ -686,8 +676,7 @@ OpcUa_Variant arrayFromQVariantPointer(const QVariant &var, const OpcUa_BuiltInT
// Taking one pointer for all as it is union
TARGETTYPE **temp = reinterpret_cast<TARGETTYPE **>(&opcuavariant.Value.Guid);
// We have to allocate, otherwise copyTo() will not do any action
- // Use calloc() instead of new because the OPC UA stack uses free() internally when clearing the data
- *temp = static_cast<TARGETTYPE *>(calloc(1, sizeof(TARGETTYPE)));
+ *temp = static_cast<TARGETTYPE *>(OpcUa_Alloc(sizeof(TARGETTYPE)));
scalarFromQVariant<TARGETTYPE, QTTYPE>(var, *temp);
opcuavariant.Datatype = type;
return opcuavariant;
@@ -700,9 +689,9 @@ OpcUa_Variant arrayFromQVariant<OpcUa_Guid, QUuid>(const QVariant &var, const Op
}
template<>
-OpcUa_Variant arrayFromQVariant<OpcUa_QualifiedName, QOpcUa::QQualifiedName>(const QVariant &var, const OpcUa_BuiltInType type)
+OpcUa_Variant arrayFromQVariant<OpcUa_QualifiedName, QOpcUaQualifiedName>(const QVariant &var, const OpcUa_BuiltInType type)
{
- return arrayFromQVariantPointer<OpcUa_QualifiedName, QOpcUa::QQualifiedName>(var, type);
+ return arrayFromQVariantPointer<OpcUa_QualifiedName, QOpcUaQualifiedName>(var, type);
}
template<>
@@ -718,45 +707,57 @@ OpcUa_Variant arrayFromQVariant<OpcUa_LocalizedText, QString>(const QVariant &va
}
template<>
-OpcUa_Variant arrayFromQVariant<OpcUa_ExtensionObject, QOpcUa::QRange>(const QVariant &var, const OpcUa_BuiltInType type)
+OpcUa_Variant arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaRange>(const QVariant &var, const OpcUa_BuiltInType type)
+{
+ return arrayFromQVariantPointer<OpcUa_ExtensionObject, QOpcUaRange>(var, type);
+}
+
+template<>
+OpcUa_Variant arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaEUInformation>(const QVariant &var, const OpcUa_BuiltInType type)
+{
+ return arrayFromQVariantPointer<OpcUa_ExtensionObject, QOpcUaEUInformation>(var, type);
+}
+
+template<>
+OpcUa_Variant arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaComplexNumber>(const QVariant &var, const OpcUa_BuiltInType type)
{
- return arrayFromQVariantPointer<OpcUa_ExtensionObject, QOpcUa::QRange>(var, type);
+ return arrayFromQVariantPointer<OpcUa_ExtensionObject, QOpcUaComplexNumber>(var, type);
}
template<>
-OpcUa_Variant arrayFromQVariant<OpcUa_ExtensionObject, QOpcUa::QEUInformation>(const QVariant &var, const OpcUa_BuiltInType type)
+OpcUa_Variant arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaDoubleComplexNumber>(const QVariant &var, const OpcUa_BuiltInType type)
{
- return arrayFromQVariantPointer<OpcUa_ExtensionObject, QOpcUa::QEUInformation>(var, type);
+ return arrayFromQVariantPointer<OpcUa_ExtensionObject, QOpcUaDoubleComplexNumber>(var, type);
}
template<>
-OpcUa_Variant arrayFromQVariant<OpcUa_ExtensionObject, QOpcUa::QComplexNumber>(const QVariant &var, const OpcUa_BuiltInType type)
+OpcUa_Variant arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaAxisInformation>(const QVariant &var, const OpcUa_BuiltInType type)
{
- return arrayFromQVariantPointer<OpcUa_ExtensionObject, QOpcUa::QComplexNumber>(var, type);
+ return arrayFromQVariantPointer<OpcUa_ExtensionObject, QOpcUaAxisInformation>(var, type);
}
template<>
-OpcUa_Variant arrayFromQVariant<OpcUa_ExtensionObject, QOpcUa::QDoubleComplexNumber>(const QVariant &var, const OpcUa_BuiltInType type)
+OpcUa_Variant arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaXValue>(const QVariant &var, const OpcUa_BuiltInType type)
{
- return arrayFromQVariantPointer<OpcUa_ExtensionObject, QOpcUa::QDoubleComplexNumber>(var, type);
+ return arrayFromQVariantPointer<OpcUa_ExtensionObject, QOpcUaXValue>(var, type);
}
template<>
-OpcUa_Variant arrayFromQVariant<OpcUa_ExtensionObject, QOpcUa::QAxisInformation>(const QVariant &var, const OpcUa_BuiltInType type)
+OpcUa_Variant arrayFromQVariant<OpcUa_ExpandedNodeId, QOpcUaExpandedNodeId>(const QVariant &var, const OpcUa_BuiltInType type)
{
- return arrayFromQVariantPointer<OpcUa_ExtensionObject, QOpcUa::QAxisInformation>(var, type);
+ return arrayFromQVariantPointer<OpcUa_ExpandedNodeId, QOpcUaExpandedNodeId>(var, type);
}
template<>
-OpcUa_Variant arrayFromQVariant<OpcUa_ExtensionObject, QOpcUa::QXValue>(const QVariant &var, const OpcUa_BuiltInType type)
+OpcUa_Variant arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaArgument>(const QVariant &var, const OpcUa_BuiltInType type)
{
- return arrayFromQVariantPointer<OpcUa_ExtensionObject, QOpcUa::QXValue>(var, type);
+ return arrayFromQVariantPointer<OpcUa_ExtensionObject, QOpcUaArgument>(var, type);
}
template<>
-OpcUa_Variant arrayFromQVariant<OpcUa_ExpandedNodeId, QOpcUa::QExpandedNodeId>(const QVariant &var, const OpcUa_BuiltInType type)
+OpcUa_Variant arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaExtensionObject>(const QVariant &var, const OpcUa_BuiltInType type)
{
- return arrayFromQVariantPointer<OpcUa_ExpandedNodeId, QOpcUa::QExpandedNodeId>(var, type);
+ return arrayFromQVariantPointer<OpcUa_ExtensionObject, QOpcUaExtensionObject>(var, type);
}
QVariant toQVariant(const OpcUa_Variant &value)
@@ -799,13 +800,13 @@ QVariant toQVariant(const OpcUa_Variant &value)
case OpcUa_BuiltInType::OpcUaType_XmlElement:
return arrayToQVariant<QString, OpcUa_XmlElement>(value, QMetaType::QString);
case OpcUa_BuiltInType::OpcUaType_QualifiedName:
- return arrayToQVariant<QOpcUa::QQualifiedName, OpcUa_QualifiedName *>(value);
+ return arrayToQVariant<QOpcUaQualifiedName, OpcUa_QualifiedName *>(value);
case OpcUa_BuiltInType::OpcUaType_StatusCode:
return arrayToQVariant<QOpcUa::UaStatusCode, OpcUa_StatusCode>(value, QMetaType::UInt);
case OpcUa_BuiltInType::OpcUaType_ExtensionObject:
return arrayToQVariant<QVariant, OpcUa_ExtensionObject *>(value);
case OpcUa_BuiltInType::OpcUaType_ExpandedNodeId:
- return arrayToQVariant<QOpcUa::QExpandedNodeId, OpcUa_ExpandedNodeId *>(value);
+ return arrayToQVariant<QOpcUaExpandedNodeId, OpcUa_ExpandedNodeId *>(value);
default:
qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Variant conversion from UACpp for typeIndex" << value.Datatype << " not implemented";
return QVariant();
@@ -877,12 +878,33 @@ OpcUa_Variant toUACppVariant(const QVariant &value, QOpcUa::Types type)
OpcUa_Variant uacppvalue;
OpcUa_Variant_Initialize(&uacppvalue);
+ if (value.canConvert<QOpcUaMultiDimensionalArray>()) {
+ const QOpcUaMultiDimensionalArray data = value.value<QOpcUaMultiDimensionalArray>();
+ OpcUa_Variant result = toUACppVariant(data.valueArray(), type);
+
+ if (!data.arrayDimensions().isEmpty()) {
+ // Ensure that the array dimensions size is < UINT32_MAX
+ if (static_cast<quint64>(data.arrayDimensions().size()) > (std::numeric_limits<qint32>::max)()){
+ qCWarning(QT_OPCUA_PLUGINS_UACPP) << "The array dimensions do not fit in a QVector.";
+ return uacppvalue;
+ }
+ result.ArrayType = OpcUa_VariantArrayType_Matrix;
+ // Reuse the allocated array from toUaCppVariant().
+ result.Value.Matrix.Value = result.Value.Array.Value;
+ // Set and copy dimension information
+ result.Value.Matrix.NoOfDimensions = static_cast<OpcUa_Int32>(data.arrayDimensions().size());
+ result.Value.Matrix.Dimensions = static_cast<OpcUa_Int32 *>(OpcUa_Alloc(result.Value.Matrix.NoOfDimensions * sizeof(OpcUa_Int32)));
+ std::copy(data.arrayDimensions().constBegin(), data.arrayDimensions().constEnd(), result.Value.Matrix.Dimensions);
+ }
+ return result;
+ }
+
if (value.type() == QVariant::List && value.toList().size() == 0)
return uacppvalue;
QVariant temp = (value.type() == QVariant::List) ? value.toList().at(0) : value;
QOpcUa::Types valueType = type == QOpcUa::Undefined ?
- qvariantTypeToQOpcUaType(static_cast<QMetaType::Type>(temp.type())) : type;
+ QOpcUa::metaTypeToQOpcUaType(static_cast<QMetaType::Type>(temp.type())) : type;
const OpcUa_BuiltInType dt = toDataType(valueType);
@@ -924,25 +946,29 @@ OpcUa_Variant toUACppVariant(const QVariant &value, QOpcUa::Types type)
case QOpcUa::XmlElement:
return arrayFromQVariant<OpcUa_XmlElement, QString>(value, dt);
case QOpcUa::QualifiedName:
- return arrayFromQVariant<OpcUa_QualifiedName, QOpcUa::QQualifiedName>(value, dt);
+ return arrayFromQVariant<OpcUa_QualifiedName, QOpcUaQualifiedName>(value, dt);
case QOpcUa::StatusCode:
return arrayFromQVariant<OpcUa_StatusCode, QOpcUa::UaStatusCode>(value, dt);
case QOpcUa::Range:
- return arrayFromQVariant<OpcUa_ExtensionObject, QOpcUa::QRange>(value, dt);
+ return arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaRange>(value, dt);
case QOpcUa::EUInformation:
- return arrayFromQVariant<OpcUa_ExtensionObject, QOpcUa::QEUInformation>(value, dt);
+ return arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaEUInformation>(value, dt);
case QOpcUa::ComplexNumber:
- return arrayFromQVariant<OpcUa_ExtensionObject, QOpcUa::QComplexNumber>(value, dt);
+ return arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaComplexNumber>(value, dt);
case QOpcUa::DoubleComplexNumber:
- return arrayFromQVariant<OpcUa_ExtensionObject, QOpcUa::QDoubleComplexNumber>(value, dt);
+ return arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaDoubleComplexNumber>(value, dt);
case QOpcUa::AxisInformation:
- return arrayFromQVariant<OpcUa_ExtensionObject, QOpcUa::QAxisInformation>(value, dt);
+ return arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaAxisInformation>(value, dt);
case QOpcUa::XV:
- return arrayFromQVariant<OpcUa_ExtensionObject, QOpcUa::QXValue>(value, dt);
+ return arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaXValue>(value, dt);
case QOpcUa::ExpandedNodeId:
- return arrayFromQVariant<OpcUa_ExpandedNodeId, QOpcUa::QExpandedNodeId>(value, dt);
+ return arrayFromQVariant<OpcUa_ExpandedNodeId, QOpcUaExpandedNodeId>(value, dt);
+ case QOpcUa::Argument:
+ return arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaArgument>(value, dt);
+ case QOpcUa::ExtensionObject:
+ return arrayFromQVariant<OpcUa_ExtensionObject, QOpcUaExtensionObject>(value, dt);
default:
- qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Variant conversion to UACpp for typeIndex" << type << " not implemented";
+ qCWarning(QT_OPCUA_PLUGINS_UACPP) << "Variant conversion of" << value << "to UACpp for typeIndex" << type << " not implemented";
}
return uacppvalue;
@@ -950,6 +976,10 @@ OpcUa_Variant toUACppVariant(const QVariant &value, QOpcUa::Types type)
QDateTime toQDateTime(const OpcUa_DateTime *dt)
{
+ // Create an invalid timestamp if both values are zero
+ if (dt->dwHighDateTime == 0 && dt->dwLowDateTime == 0)
+ return QDateTime();
+
// OPC-UA part 3, Table C.9
const QDateTime uaEpochStart(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC);
const UaDateTime temp(*dt);
@@ -958,6 +988,116 @@ QDateTime toQDateTime(const OpcUa_DateTime *dt)
return uaEpochStart.addMSecs(((quint64)temp) / 10000).toLocalTime();
}
+OpcUa_DateTime toUACppDateTime(const QDateTime &qtDateTime)
+{
+ // OPC-UA part 3, Table C.9
+ const QDateTime uaEpochStart(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC);
+ // OpcUa time is defined in part 6, 5.2.2.5 in 100ns which need to be converted to milliseconds.
+ UaDateTime tmp((qtDateTime.toMSecsSinceEpoch() - uaEpochStart.toMSecsSinceEpoch()) * 10000);
+ OpcUa_DateTime returnValue;
+ tmp.copyTo(&returnValue);
+ return returnValue;
+}
+
+QOpcUaLocalizedText toQOpcUaLocalizedText(UaLocalizedText *data)
+{
+ const UaString ualtLocal(data->locale());
+ const UaString ualtText(data->text());
+
+ QOpcUaLocalizedText lt;
+
+ lt.setLocale(QString::fromUtf8(ualtLocal.toUtf8(), ualtLocal.size()));
+ lt.setText(QString::fromUtf8(ualtText.toUtf8(), ualtText.size()));
+ return lt;
+}
+
+UaStringArray toUaStringArray(const QStringList &value)
+{
+ UaStringArray ret;
+ ret.create(value.size());
+
+ for (int i = 0; i < value.size(); ++i) {
+ OpcUa_String str;
+ const QByteArray utf8Data = value[i].toUtf8();
+
+ // Use QByteArray data buffer directly to form a OpcUa_String.
+ OpcUa_String_AttachReadOnly(&str, utf8Data.constData());
+
+ OpcUa_String_StrnCpy(&ret[i], &str, OPCUA_STRING_LENDONTCARE);
+ }
+ return ret;
+}
+
+OpcUa_ExpandedNodeId toUACppExpandedNodeId(const QOpcUaExpandedNodeId &qtExpandedNodeId)
+{
+ OpcUa_ExpandedNodeId returnValue;
+
+ returnValue.ServerIndex = qtExpandedNodeId.serverIndex();
+ UACppUtils::nodeIdFromQString(qtExpandedNodeId.nodeId()).copyTo(&returnValue.NodeId);
+ UaString namespc(qtExpandedNodeId.namespaceUri().toUtf8().constData());
+ namespc.detach(&returnValue.NamespaceUri);
+ return returnValue;
+}
+
+OpcUa_QualifiedName toUACppQualifiedName(const QOpcUaQualifiedName& qtQualifiedName)
+{
+ OpcUa_QualifiedName returnValue;
+
+ returnValue.NamespaceIndex = qtQualifiedName.namespaceIndex();
+ UaString name(qtQualifiedName.name().toUtf8().constData());
+ name.detach(&returnValue.Name);
+ return returnValue;
+}
+
+OpcUa_LocalizedText toUACppLocalizedText(const QOpcUaLocalizedText &qtLocalizedText)
+{
+ OpcUa_LocalizedText uaLocalizedText;
+ UaLocalizedText ualt;
+ if (qtLocalizedText.locale().size())
+ ualt.setLocale(UaString(qtLocalizedText.locale().toUtf8().constData()));
+ if (qtLocalizedText.text().size())
+ ualt.setText(UaString(qtLocalizedText.text().toUtf8().constData()));
+ ualt.copyTo(&uaLocalizedText);
+ return uaLocalizedText;
+}
+
+template<>
+void scalarFromQVariant<OpcUa_ExtensionObject, QOpcUaArgument>(const QVariant &var, OpcUa_ExtensionObject *ptr)
+{
+ const auto value = var.value<QOpcUaArgument>();
+ QByteArray temp;
+ QOpcUaBinaryDataEncoding encoder(&temp);
+ encoder.encode<QOpcUaArgument>(value);
+ createExtensionObject(temp, Namespace0::Argument_Encoding_DefaultBinary, ptr);
+}
+
+QOpcUaArgument toQArgument(const UaArgument *data)
+{
+ QVector<quint32> arrayDimensions;
+ UaUInt32Array dataArrayDimensions;
+ data->getArrayDimensions(dataArrayDimensions);
+ for (quint32 i = 0; i < dataArrayDimensions.length(); ++i)
+ arrayDimensions.append(dataArrayDimensions[i]);
+
+ QOpcUaArgument argument;
+ argument.setName(QString::fromUtf8(data->getName().toUtf8()));
+ argument.setDataTypeId(UACppUtils::nodeIdToQString(data->getDataType()));
+ argument.setValueRank(data->getValueRank());
+ argument.setArrayDimensions(arrayDimensions);
+
+ UaLocalizedText localizedText = data->getDescription();
+ argument.setDescription(toQOpcUaLocalizedText(&localizedText));
+ return argument;
+}
+
+template<>
+void scalarFromQVariant<OpcUa_ExtensionObject, QOpcUaExtensionObject>(const QVariant &var, OpcUa_ExtensionObject *ptr)
+{
+ const auto value = var.value<QOpcUaExtensionObject>();
+ const QByteArray temp = value.encodedBody();
+ createExtensionObject(temp, UACppUtils::nodeIdFromQString(value.encodingTypeId()), ptr);
+}
+
}
QT_END_NAMESPACE
diff --git a/src/plugins/opcua/uacpp/quacppvalueconverter.h b/src/plugins/opcua/uacpp/quacppvalueconverter.h
index d4736db..92b92c3 100644
--- a/src/plugins/opcua/uacpp/quacppvalueconverter.h
+++ b/src/plugins/opcua/uacpp/quacppvalueconverter.h
@@ -1,19 +1,27 @@
/******************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:COMM$
-**
+** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -24,6 +32,7 @@
#include "qopcuanode.h"
#include "qopcuatype.h"
+#include "qopcuaargument.h"
#include <QtCore/QVariant>
@@ -31,6 +40,7 @@
#include <uaarraytemplates.h> // for UaStringArray
class UaLocalizedText;
+class UaArgument;
QT_BEGIN_NAMESPACE
@@ -56,6 +66,16 @@ namespace QUACppValueConverter {
OpcUa_Variant arrayFromQVariant(const QVariant &var, const OpcUa_BuiltInType type);
QDateTime toQDateTime(const OpcUa_DateTime *dt);
+ OpcUa_DateTime toUACppDateTime(const QDateTime &qtDateTime);
+
+ UaStringArray toUaStringArray(const QStringList &value);
+ QOpcUaLocalizedText toQOpcUaLocalizedText(UaLocalizedText *data);
+
+ OpcUa_ExpandedNodeId toUACppExpandedNodeId(const QOpcUaExpandedNodeId &qtExpandedNodeId);
+ OpcUa_LocalizedText toUACppLocalizedText(const QOpcUaLocalizedText &qtLocalizedText);
+ OpcUa_QualifiedName toUACppQualifiedName(const QOpcUaQualifiedName& qtQualifiedName);
+
+ QOpcUaArgument toQArgument(const UaArgument *data);
}
QT_END_NAMESPACE
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 45114ce..a90406f 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -1,5 +1,5 @@
TEMPLATE = subdirs
-SUBDIRS += qopcuaclient
+SUBDIRS += qopcuaclient connection clientSetupInCpp
QT_FOR_CONFIG += opcua-private
@@ -7,3 +7,6 @@ QT_FOR_CONFIG += opcua-private
qtHaveModule(qmltest):qtConfig(open62541)|qtConfig(uacpp) {
SUBDIRS += declarative
}
+
+# This tries to check if the server supports security
+qtConfig(mbedtls): SUBDIRS += security
diff --git a/tests/auto/clientSetupInCpp/clientSetupInCpp.pro b/tests/auto/clientSetupInCpp/clientSetupInCpp.pro
new file mode 100644
index 0000000..57fb5de
--- /dev/null
+++ b/tests/auto/clientSetupInCpp/clientSetupInCpp.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+TARGET = tst_clientSetupInCpp
+CONFIG += warn_on qmltestcase
+SOURCES += tst_clientSetupInCpp.cpp
+HEADERS += $$PWD/../../common/backend_environment.h
+INCLUDEPATH += $$PWD/../../common
+IMPORTPATH += $$PWD/../../../src/plugins/declarative
+
+# This tries to check if the server has security support
+QT += opcua_private
+qtConfig(mbedtls): DEFINES += SERVER_SUPPORTS_SECURITY
diff --git a/tests/auto/clientSetupInCpp/tst_clientSetupInCpp.cpp b/tests/auto/clientSetupInCpp/tst_clientSetupInCpp.cpp
new file mode 100644
index 0000000..2e6eed7
--- /dev/null
+++ b/tests/auto/clientSetupInCpp/tst_clientSetupInCpp.cpp
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "backend_environment.h"
+#include <QtQuickTest/quicktest.h>
+#include <QObject>
+#include <QProcess>
+#include <QQmlContext>
+#include <QQmlEngine>
+#include <QTcpServer>
+#include <QTcpSocket>
+#include <QOpcUaClient>
+#include <QOpcUaProvider>
+#include <QSignalSpy>
+
+const int signalSpyTimeout = 10000;
+const quint16 defaultPort = 43344;
+const QHostAddress defaultHost(QHostAddress::LocalHost);
+
+static QString envOrDefault(const char *env, QString def)
+{
+ return qEnvironmentVariableIsSet(env) ? qgetenv(env).constData() : def;
+}
+
+class MyClass : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QOpcUaClient* connection READ connection NOTIFY connectionChanged)
+
+public:
+ MyClass (QObject* parent = nullptr) : QObject(parent) {
+ }
+
+ QOpcUaClient *connection() const {
+ return m_client;
+ }
+
+signals:
+ void connectionChanged(QOpcUaClient *);
+
+public slots:
+ void startConnection() {
+ QOpcUaProvider p;
+ QOpcUaClient *client = p.createClient("open62541");
+
+ if (!client)
+ qFatal("Failed to instantiate backend");
+
+ m_client = client;
+
+ QString host = envOrDefault("OPCUA_HOST", defaultHost.toString());
+ QString port = envOrDefault("OPCUA_PORT", QString::number(defaultPort));
+ const auto discoveryEndpoint = QString("opc.tcp://%1:%2").arg(host).arg(port);
+
+ QSignalSpy endpointSpy(client, &QOpcUaClient::endpointsRequestFinished);
+ client->requestEndpoints(discoveryEndpoint);
+ endpointSpy.wait(signalSpyTimeout);
+ QCOMPARE(endpointSpy.size(), 1);
+
+ const QVector<QOpcUaEndpointDescription> desc = endpointSpy.at(0).at(0).value<QVector<QOpcUaEndpointDescription>>();
+ QVERIFY(desc.size() > 0);
+ QCOMPARE(endpointSpy.at(0).at(2).value<QUrl>(), discoveryEndpoint);
+
+ client->connectToEndpoint(desc.first());
+ QTRY_VERIFY_WITH_TIMEOUT(client->state() == QOpcUaClient::Connected, signalSpyTimeout);
+ qDebug() << "DONE";
+ emit connectionChanged(m_client);
+ }
+
+private:
+ QOpcUaClient *m_client = nullptr;
+};
+
+class SetupClass : public QObject
+{
+ Q_OBJECT
+public:
+ SetupClass() {
+ };
+ ~SetupClass() {
+ }
+
+public slots:
+ void applicationAvailable() {
+ updateEnvironment();
+
+ if (qEnvironmentVariableIsEmpty("OPCUA_HOST") && qEnvironmentVariableIsEmpty("OPCUA_PORT")) {
+ m_testServerPath = qApp->applicationDirPath()
+
+#if defined(Q_OS_MACOS)
+ + QLatin1String("/../../open62541-testserver/open62541-testserver.app/Contents/MacOS/open62541-testserver")
+#else
+
+#ifdef Q_OS_WIN
+ + QLatin1String("/..")
+#endif
+ + QLatin1String("/../../open62541-testserver/open62541-testserver")
+#ifdef Q_OS_WIN
+ + QLatin1String(".exe")
+#endif
+
+#endif
+ ;
+ qDebug() << "Server Path:" << m_testServerPath;
+ if (!QFile::exists(m_testServerPath)) {
+ qFatal("all auto tests rely on an open62541-based test-server");
+ }
+
+ // In this case the test is supposed to open its own server.
+ // Unfortunately there is no way to check if the server has started up successfully
+ // because of missing error handling.
+ // This checks will detect other servers blocking the port.
+
+ // Check for running server
+ QTcpSocket socket;
+ socket.connectToHost(defaultHost, defaultPort);
+ QVERIFY2(socket.waitForConnected(1500) == false, "Server is already running");
+
+ // Check for running server which does not respond
+ QTcpServer server;
+ QVERIFY2(server.listen(defaultHost, defaultPort) == true, "Port is occupied by another process. Check for defunct server.");
+ server.close();
+
+ qDebug() << "Starting test server";
+ //m_serverProcess.setProcessChannelMode(QProcess::ForwardedChannels);
+ m_serverProcess.start(m_testServerPath);
+ QVERIFY2(m_serverProcess.waitForStarted(), qPrintable(m_serverProcess.errorString()));
+ // Let the server come up
+ QTest::qSleep(2000);
+ }
+ const QString host = envOrDefault("OPCUA_HOST", defaultHost.toString());
+ const QString port = envOrDefault("OPCUA_PORT", QString::number(defaultPort));
+ m_opcuaDiscoveryUrl = QString::fromLatin1("opc.tcp://%1:%2").arg(host).arg(port);
+ }
+ void qmlEngineAvailable(QQmlEngine *engine) {
+ bool value = false;
+#ifdef SERVER_SUPPORTS_SECURITY
+ value = true;
+#endif
+ engine->rootContext()->setContextProperty("SERVER_SUPPORTS_SECURITY", value);
+ engine->rootContext()->setContextProperty("OPCUA_DISCOVERY_URL", m_opcuaDiscoveryUrl);
+ qmlRegisterType<MyClass>("App", 1, 0, "MyClass");
+ }
+ void cleanupTestCase() {
+ if (m_serverProcess.state() == QProcess::Running) {
+ m_serverProcess.kill();
+ m_serverProcess.waitForFinished(2000);
+ }
+ }
+private:
+ QProcess m_serverProcess;
+ QString m_testServerPath;
+ QString m_opcuaDiscoveryUrl;
+};
+
+QUICK_TEST_MAIN_WITH_SETUP(opcua, SetupClass)
+
+#include "tst_clientSetupInCpp.moc"
diff --git a/tests/auto/clientSetupInCpp/tst_clientSetupInCpp.qml b/tests/auto/clientSetupInCpp/tst_clientSetupInCpp.qml
new file mode 100644
index 0000000..afbb8ba
--- /dev/null
+++ b/tests/auto/clientSetupInCpp/tst_clientSetupInCpp.qml
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtTest 1.0
+import QtOpcUa 5.13 as QtOpcUa
+import App 1.0
+
+Item {
+ QtOpcUa.Connection {
+ id: connection
+ connection: myclass.connection
+ }
+
+ MyClass {
+ id: myclass
+ }
+
+ Component.onCompleted: myclass.startConnection()
+
+ TestCase {
+ name: "Create String Node Id"
+ when: node1.readyToUse
+
+ function test_nodeTest() {
+ compare(node1.value, "Value", "");
+ compare(node1.browseName, "theStringId");
+ compare(node1.nodeClass, QtOpcUa.Constants.NodeClass.Variable);
+ compare(node1.displayName.text, "theStringId");
+ compare(node1.description.text, "Description for ns=3;s=theStringId");
+ compare(node1.status, QtOpcUa.Node.Status.Valid);
+ tryCompare(node1, "monitored", true);
+ compare(node1.publishingInterval, 100.0);
+
+ compare(connection.currentEndpoint.endpointUrl, "opc.tcp://127.0.0.1:43344");
+ compare(connection.currentEndpoint.securityPolicy, "http://opcfoundation.org/UA/SecurityPolicy#None");
+ compare(connection.currentEndpoint.server.applicationUri, "urn:unconfigured:application");
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=theStringId"
+ }
+ id: node1
+ }
+ }
+}
diff --git a/tests/auto/connection/connection.pro b/tests/auto/connection/connection.pro
new file mode 100644
index 0000000..2060fee
--- /dev/null
+++ b/tests/auto/connection/connection.pro
@@ -0,0 +1,14 @@
+TARGET = tst_connection
+
+QT += testlib opcua
+QT -= gui
+CONFIG += testcase
+
+SOURCES += \
+ tst_connection.cpp
+
+HEADERS += \
+ $$PWD/../../common/backend_environment.h
+
+INCLUDEPATH += \
+ $$PWD/../../common
diff --git a/tests/auto/connection/tst_connection.cpp b/tests/auto/connection/tst_connection.cpp
new file mode 100644
index 0000000..639cd5d
--- /dev/null
+++ b/tests/auto/connection/tst_connection.cpp
@@ -0,0 +1,252 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "backend_environment.h"
+
+#include <QtOpcUa/QOpcUaAuthenticationInformation>
+#include <QtOpcUa/QOpcUaClient>
+#include <QtOpcUa/QOpcUaProvider>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QProcess>
+#include <QtCore/QScopedPointer>
+
+#include <QtTest/QSignalSpy>
+#include <QtTest/QtTest>
+#include <QTcpSocket>
+#include <QTcpServer>
+
+#define defineDataMethod(name) void name()\
+{\
+ QTest::addColumn<QOpcUaClient *>("opcuaClient");\
+ for (auto *client: m_clients)\
+ QTest::newRow(client->backend().toLatin1().constData()) << client;\
+}
+
+const int signalSpyTimeout = 10000;
+
+class Tst_Connection: public QObject
+{
+ Q_OBJECT
+
+public:
+ Tst_Connection();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ // connect & disconnect
+ defineDataMethod(connectMultipleTimes_data)
+ void connectMultipleTimes();
+
+private:
+ QString envOrDefault(const char *env, QString def)
+ {
+ return qEnvironmentVariableIsSet(env) ? qgetenv(env).constData() : def;
+ }
+
+ QString m_discoveryEndpoint;
+ QOpcUaProvider m_opcUa;
+ QStringList m_backends;
+ QVector<QOpcUaClient *> m_clients;
+ QProcess m_serverProcess;
+ QString m_testServerPath;
+ QOpcUaEndpointDescription m_endpoint;
+};
+
+Tst_Connection::Tst_Connection()
+{
+ m_backends = QOpcUaProvider::availableBackends();
+}
+
+void Tst_Connection::initTestCase()
+{
+ const quint16 defaultPort = 43344;
+ const QHostAddress defaultHost(QHostAddress::LocalHost);
+
+ for (const auto &backend: m_backends) {
+ QVariantMap backendOptions;
+ if (backend == QLatin1String("uacpp"))
+ backendOptions.insert(QLatin1String("disableEncryptedPasswordCheck"), true);
+
+ QOpcUaClient *client = m_opcUa.createClient(backend, backendOptions);
+ QVERIFY2(client != nullptr,
+ QString("Loading backend failed: %1").arg(backend).toLatin1().data());
+ client->setParent(this);
+ qDebug() << "Using SDK plugin:" << client->backend();
+ m_clients.append(client);
+ }
+
+ if (qEnvironmentVariableIsEmpty("OPCUA_HOST") && qEnvironmentVariableIsEmpty("OPCUA_PORT")) {
+ m_testServerPath = qApp->applicationDirPath()
+
+#if defined(Q_OS_MACOS)
+ + QLatin1String("/../../open62541-testserver/open62541-testserver.app/Contents/MacOS/open62541-testserver")
+#else
+
+#ifdef Q_OS_WIN
+ + QLatin1String("/..")
+#endif
+ + QLatin1String("/../../open62541-testserver/open62541-testserver")
+#ifdef Q_OS_WIN
+ + QLatin1String(".exe")
+#endif
+
+#endif
+ ;
+ if (!QFile::exists(m_testServerPath)) {
+ qDebug() << "Server Path:" << m_testServerPath;
+ QSKIP("all auto tests rely on an open62541-based test-server");
+ }
+
+ // In this case the test is supposed to open its own server.
+ // Unfortunately there is no way to check if the server has started up successfully
+ // because of missing error handling.
+ // This checks will detect other servers blocking the port.
+
+ // Check for running server
+ QTcpSocket socket;
+ socket.connectToHost(defaultHost, defaultPort);
+ QVERIFY2(socket.waitForConnected(1500) == false, "Server is already running");
+
+ // Check for running server which does not respond
+ QTcpServer server;
+ QVERIFY2(server.listen(defaultHost, defaultPort) == true, "Port is occupied by another process. Check for defunct server.");
+ server.close();
+
+ m_serverProcess.start(m_testServerPath);
+ QVERIFY2(m_serverProcess.waitForStarted(), qPrintable(m_serverProcess.errorString()));
+ // Let the server come up
+ QTest::qSleep(2000);
+ }
+ QString host = envOrDefault("OPCUA_HOST", defaultHost.toString());
+ QString port = envOrDefault("OPCUA_PORT", QString::number(defaultPort));
+ m_discoveryEndpoint = QString("opc.tcp://%1:%2").arg(host).arg(port);
+ qDebug() << "Using endpoint:" << m_discoveryEndpoint;
+
+ QOpcUaClient *client = m_clients.first();
+ if (client) {
+ QSignalSpy endpointSpy(m_clients.first(), &QOpcUaClient::endpointsRequestFinished);
+
+ client->requestEndpoints(m_discoveryEndpoint);
+ endpointSpy.wait(signalSpyTimeout);
+ QCOMPARE(endpointSpy.size(), 1);
+
+ const QVector<QOpcUaEndpointDescription> desc = endpointSpy.at(0).at(0).value<QVector<QOpcUaEndpointDescription>>();
+ QVERIFY(desc.size() > 0);
+ QCOMPARE(endpointSpy.at(0).at(2).value<QUrl>(), m_discoveryEndpoint);
+
+ m_endpoint = desc.first();
+ }
+}
+
+void Tst_Connection::connectMultipleTimes()
+{
+ QFETCH(QOpcUaClient *, opcuaClient);
+
+ QVERIFY(opcuaClient != nullptr);
+ QSignalSpy connectedSpy(opcuaClient, &QOpcUaClient::connected);
+ QSignalSpy disconnectedSpy(opcuaClient, &QOpcUaClient::disconnected);
+ QSignalSpy stateSpy(opcuaClient, &QOpcUaClient::stateChanged);
+
+ QTest::qWait(500);
+
+ opcuaClient->connectToEndpoint(m_endpoint);
+ QTRY_VERIFY2(opcuaClient->state() == QOpcUaClient::Connected, "Could not connect to server");
+
+ QCOMPARE(connectedSpy.count(), 1);
+ QCOMPARE(disconnectedSpy.count(), 0);
+ QCOMPARE(stateSpy.count(), 2);
+
+ QCOMPARE(stateSpy.at(0).at(0).value<QOpcUaClient::ClientState>(),
+ QOpcUaClient::ClientState::Connecting);
+ QCOMPARE(stateSpy.at(1).at(0).value<QOpcUaClient::ClientState>(),
+ QOpcUaClient::ClientState::Connected);
+
+ stateSpy.clear();
+ connectedSpy.clear();
+ disconnectedSpy.clear();
+
+ QVERIFY(opcuaClient->endpoint() == m_endpoint);
+
+ // Connect again
+ opcuaClient->connectToEndpoint(m_endpoint);
+ stateSpy.wait(signalSpyTimeout);
+ QTRY_VERIFY2(opcuaClient->state() == QOpcUaClient::Connected, "Could not connect to server");
+
+ QCOMPARE(connectedSpy.count(), 1);
+ QCOMPARE(disconnectedSpy.count(), 1);
+ QCOMPARE(stateSpy.count(), 3);
+
+ QCOMPARE(stateSpy.at(0).at(0).value<QOpcUaClient::ClientState>(),
+ QOpcUaClient::ClientState::Disconnected);
+ QCOMPARE(stateSpy.at(1).at(0).value<QOpcUaClient::ClientState>(),
+ QOpcUaClient::ClientState::Connecting);
+ QCOMPARE(stateSpy.at(2).at(0).value<QOpcUaClient::ClientState>(),
+ QOpcUaClient::ClientState::Connected);
+
+ opcuaClient->disconnectFromEndpoint();
+}
+
+void Tst_Connection::cleanupTestCase()
+{
+ if (m_serverProcess.state() == QProcess::Running) {
+ m_serverProcess.kill();
+ m_serverProcess.waitForFinished(2000);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ updateEnvironment();
+ QCoreApplication app(argc, argv);
+
+ QTEST_SET_MAIN_SOURCE_PATH
+
+ // run tests for all available backends
+ QStringList availableBackends = QOpcUaProvider::availableBackends();
+ if (availableBackends.empty()) {
+ qDebug("No OPCUA backends found, skipping tests.");
+ return EXIT_SUCCESS;
+ }
+
+ Tst_Connection tc;
+ return QTest::qExec(&tc, argc, argv);
+}
+
+#include "tst_connection.moc"
+
diff --git a/tests/auto/declarative/AbsoluteNodeTest.qml b/tests/auto/declarative/AbsoluteNodeTest.qml
new file mode 100644
index 0000000..c1f567d
--- /dev/null
+++ b/tests/auto/declarative/AbsoluteNodeTest.qml
@@ -0,0 +1,462 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtTest 1.0
+import QtOpcUa 5.13 as QtOpcUa
+
+Item {
+ property string backendName
+ property int completedTestCases: 0
+ property int availableTestCases: 0
+ property bool completed: completedTestCases == availableTestCases && availableTestCases > 0
+ property bool shouldRun: false
+
+ onShouldRunChanged: {
+ if (shouldRun)
+ console.log("Running", parent.testName, "with", backendName);
+ }
+
+ QtOpcUa.Connection {
+ id: connection
+ backend: backendName
+ defaultConnection: true
+ }
+
+ QtOpcUa.ServerDiscovery {
+ id: serverDiscovery
+ onServersChanged: {
+ if (!count)
+ return;
+ endpointDiscovery.serverUrl = at(0).discoveryUrls[0];
+ }
+ }
+
+ QtOpcUa.EndpointDiscovery {
+ id: endpointDiscovery
+ onEndpointsChanged: {
+ if (!count)
+ return;
+ connection.connectToEndpoint(at(0));
+ }
+ }
+
+ Component.onCompleted: {
+ for (var i in children) {
+ if (children[i].objectName == "TestCase")
+ availableTestCases += 1;
+ }
+ serverDiscovery.discoveryUrl = OPCUA_DISCOVERY_URL;
+ }
+
+ CompletionLoggingTestCase {
+ name: "Create String Node Id"
+ when: node1.readyToUse && shouldRun
+
+ function test_nodeTest() {
+ compare(node1.value, "Value", "");
+ compare(node1.browseName, "theStringId");
+ compare(node1.nodeClass, QtOpcUa.Constants.NodeClass.Variable);
+ compare(node1.displayName.text, "theStringId");
+ compare(node1.description.text, "Description for ns=3;s=theStringId");
+ compare(node1.status, QtOpcUa.Node.Status.Valid);
+ tryCompare(node1, "monitored", true);
+ compare(node1.publishingInterval, 100.0);
+
+ compare(connection.currentEndpoint.endpointUrl, "opc.tcp://localhost:43344/");
+ compare(connection.currentEndpoint.securityPolicy, "http://opcfoundation.org/UA/SecurityPolicy#None");
+ compare(connection.currentEndpoint.server.applicationUri, "urn:unconfigured:application");
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=theStringId"
+ }
+ id: node1
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Create GUID Node Id"
+ when: node2.readyToUse && shouldRun
+
+ function test_nodeTest() {
+ compare(node2.value, "Value", "");
+ compare(node2.valueType, QtOpcUa.Constants.String);
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "g=08081e75-8e5e-319b-954f-f3a7613dc29b"
+ }
+ id: node2
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Create Opaque Node Id"
+ when: node3.readyToUse && shouldRun
+
+ function test_nodeTest() {
+ compare(node3.value, "Value", "");
+ compare(node3.valueType, QtOpcUa.Constants.String);
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "b=UXQgZnR3IQ=="
+ }
+ id: node3
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Create Integer Node Id"
+ when: node4.readyToUse && shouldRun
+
+ function test_nodeTest() {
+ compare(node4.value, 255, "");
+ compare(node4.valueType, QtOpcUa.Constants.Byte);
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "http://opcfoundation.org/UA/"
+ identifier: "i=2267"
+ }
+ id: node4
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Write Value Node with Multiple Listeners"
+ when: node5.readyToUse && node6.readyToUse && node7.readyToUse && shouldRun
+
+ function test_nodeTest() {
+ compare(node5.valueType, QtOpcUa.Constants.Double);
+ compare(node6.valueType, QtOpcUa.Constants.Double);
+ compare(node7.valueType, QtOpcUa.Constants.Double);
+ var oldValue = node5.value;
+ node6Spy.clear();
+ node7Spy.clear();
+ node5.value = oldValue + 1;
+ tryCompare(node5, "value", oldValue + 1);
+ tryCompare(node6, "value", oldValue + 1);
+ tryCompare(node7, "value", oldValue + 1);
+ wait(100);
+ compare(node6Spy.count, 1);
+ compare(node7Spy.count, 1);
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=TestNode.ReadWrite"
+ }
+ id: node5
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=TestNode.ReadWrite"
+ }
+ id: node6
+ }
+
+ SignalSpy {
+ id: node6Spy
+ target: node6
+ signalName: "valueChanged"
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=TestNode.ReadWrite"
+ }
+ id: node7
+ }
+
+ SignalSpy {
+ id: node7Spy
+ target: node7
+ signalName: "valueChanged"
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Emitting signals on node changes"
+ when: node8.readyToUse && shouldRun
+
+ function test_changeIdentifier() {
+ compare(node8.valueType, QtOpcUa.Constants.Double);
+ node8NamespaceSpy.clear();
+ node8IdentifierSpy.clear();
+ node8NodeIdSpy.clear();
+ node8NodeChangedSpy.clear();
+ node8NodeIdChangedSpy.clear();
+ node8ValueSpy.clear();
+ verify(node8IdentifierSpy.valid);
+ node8.nodeId.identifier = "b=UXQgZnR3IQ==";
+ node8ValueSpy.wait();
+
+ // value has to be undefined because when node IDs are changed
+ // all attributes become undefined before they get the new values.
+ if (node8ValueSpy.count < 2)
+ node8ValueSpy.wait();
+ verify(!node8ValueSpy.signalArguments[0][0]);
+ compare(node8ValueSpy.signalArguments[1][0], "Value");
+
+ compare(node8IdentifierSpy.count, 1);
+ compare(node8NodeIdSpy.count, 1);
+ compare(node8NamespaceSpy.count, 0);
+ verify(node8NodeChangedSpy.count > 0);
+ compare(node8NodeIdChangedSpy.count, 1);
+ compare(node8ValueSpy.count, 2); // first undefined, then the real value
+ compare(node8.value, "Value");
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=TestNode.ReadWrite"
+ }
+ id: node8
+ }
+
+ SignalSpy {
+ id: node8NamespaceSpy
+ target: node8.nodeId
+ signalName: "nodeNamespaceChanged"
+ }
+
+ SignalSpy {
+ id: node8IdentifierSpy
+ target: node8.nodeId
+ signalName: "identifierChanged"
+ }
+
+ SignalSpy {
+ id: node8NodeIdSpy
+ target: node8.nodeId
+ signalName: "nodeChanged"
+ }
+
+ SignalSpy {
+ id: node8NodeChangedSpy
+ target: node8
+ signalName: "nodeChanged"
+ }
+
+ SignalSpy {
+ id: node8NodeIdChangedSpy
+ target: node8
+ signalName: "nodeIdChanged"
+ }
+
+ SignalSpy {
+ id: node8ValueSpy
+ target: node8
+ signalName: "valueChanged"
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Node with namespace in Id"
+ when: node9.readyToUse && shouldRun
+
+ function test_nodeTest() {
+ compare(node9.valueType, QtOpcUa.Constants.String);
+ compare(node9.value, "Value", "");
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ identifier: "ns=3;s=theStringId"
+ }
+ id: node9
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Standard attributes on variable node"
+ when: node10.readyToUse && shouldRun
+
+ SignalSpy {
+ id: node10BrowseNameSpy
+ target: node10
+ signalName: "browseNameChanged"
+ }
+
+ SignalSpy {
+ id: node10NodeClassSpy
+ target: node10
+ signalName: "nodeClassChanged"
+ }
+
+ SignalSpy {
+ id: node10DisplayNameSpy
+ target: node10
+ signalName: "displayNameChanged"
+ }
+
+ SignalSpy {
+ id: node10DescriptionSpy
+ target: node10
+ signalName: "descriptionChanged"
+ }
+
+ function test_nodeTest() {
+ compare(node10.browseName, "FullyWritableTest");
+ compare(node10.nodeClass, QtOpcUa.Constants.NodeClass.Variable);
+ compare(node10.displayName.text, "FullyWritableTest");
+ compare(node10.description.text, "Description for ns=3;s=Demo.Static.Scalar.FullyWritable");
+ compare(node10.valueType, QtOpcUa.Constants.Double);
+
+ node10BrowseNameSpy.clear();
+ node10NodeClassSpy.clear();
+ node10DisplayNameSpy.clear();
+ node10DescriptionSpy.clear();
+
+ node10.browseName = "modifiedBrowseName";
+ node10BrowseNameSpy.wait();
+ compare(node10BrowseNameSpy.count, 1);
+ node10.browseName = "FullyWritableTest"; // Setting back to default
+
+ // node class is not supposed to be changed: skipping tests
+
+ node10.displayName.text = "modifiedDisplayName";
+ node10DisplayNameSpy.wait();
+ compare(node10DisplayNameSpy.count, 1);
+ node10.displayName.text = "FullyWritableTest"; // Setting back to default
+
+ node10.description.text = "modifiedDescription";
+ node10DescriptionSpy.wait();
+ compare(node10DescriptionSpy.count, 1);
+ node10DescriptionSpy.clear();
+ node10.description.text = "Description for ns=3;s=Demo.Static.Scalar.FullyWritable"; // Setting back to default
+ node10DescriptionSpy.wait();
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=Demo.Static.Scalar.FullyWritable"
+ }
+ id: node10
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Node timestamps"
+ when: node11.readyToUse && shouldRun
+
+ SignalSpy {
+ id: node11ValueSpy
+ target: node11
+ signalName: "valueChanged"
+ }
+
+ function test_nodeTest() {
+ compare(node11.valueType, QtOpcUa.Constants.String);
+ node11ValueSpy.wait();
+
+ var now = new Date();
+ verify((now - node11.serverTimestamp) < 10000);
+ verify((now - node11.sourceTimestamp) < 10000);
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ identifier: "ns=3;s=theStringId"
+ }
+ id: node11
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Assign int value to double node"
+ when: node12.readyToUse && shouldRun
+
+ SignalSpy {
+ id: node12ValueSpy
+ target: node12
+ signalName: "valueChanged"
+ }
+
+ function test_nodeTest() {
+ compare(node12.valueType, QtOpcUa.Constants.Double);
+ compare(node12.value, 1)
+
+ node12ValueSpy.clear();
+ node12.value = 30;
+ node12ValueSpy.wait();
+
+ compare(node12ValueSpy.count, 1);
+ compare(node12.value, 30);
+ compare(node12.value, 30.0);
+
+ node12ValueSpy.clear();
+ node12.value = 1;
+ node12ValueSpy.wait();
+ compare(node12.value, 1)
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "http://qt-project.org"
+ identifier: "s=Demo.Static.Scalar.Double"
+ }
+ id: node12
+ }
+ }
+}
diff --git a/tests/auto/declarative/AuthorizationTest.qml b/tests/auto/declarative/AuthorizationTest.qml
new file mode 100644
index 0000000..c4d680d
--- /dev/null
+++ b/tests/auto/declarative/AuthorizationTest.qml
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtTest 1.0
+import QtOpcUa 5.13 as QtOpcUa
+
+Item {
+ property string backendName
+ property int completedTestCases: 0
+ property int availableTestCases: 0
+ property bool completed: completedTestCases == availableTestCases
+ property bool shouldRun: false
+
+ onShouldRunChanged: {
+ if (shouldRun)
+ console.log("Running", parent.testName, "with", backendName);
+ }
+
+ CompletionLoggingTestCase {
+ name: "Username authentication"
+
+ QtOpcUa.Connection {
+ id: connection
+ backend: backendName
+ defaultConnection: true
+ }
+
+ QtOpcUa.ServerDiscovery {
+ id: serverDiscovery
+ onServersChanged: {
+ if (!count)
+ return;
+ endpointDiscovery.serverUrl = at(0).discoveryUrls[0];
+ }
+ }
+
+ QtOpcUa.EndpointDiscovery {
+ id: endpointDiscovery
+ onEndpointsChanged: {
+ if (!count)
+ return;
+ connection.connectToEndpoint(at(0));
+ }
+ }
+
+ Component.onCompleted: {
+ for (var i in children) {
+ if (children[i].objectName == "TestCase")
+ availableTestCases += 1;
+ }
+ serverDiscovery.discoveryUrl = OPCUA_DISCOVERY_URL;
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=theStringId"
+ }
+ id: node1
+ }
+
+ SignalSpy {
+ id: connection1ConnectedSpy
+ target: connection
+ signalName: "connectedChanged"
+ }
+
+ SignalSpy {
+ id: node1ValueChangedSpy
+ target: node1
+ signalName: "valueChanged"
+ }
+
+ function test_nodeTest() {
+ var authInfo = connection.authenticationInformation;
+ authInfo.setUsernameAuthentication("user1", "password");
+ connection.authenticationInformation = authInfo;
+
+ serverDiscovery.discoveryUrl = OPCUA_DISCOVERY_URL;
+
+ connection1ConnectedSpy.wait();
+ verify(connection.connected);
+
+ node1ValueChangedSpy.wait();
+ verify(node1ValueChangedSpy.count > 0);
+
+ compare(node1.value, "Value", "");
+ compare(node1.browseName, "theStringId");
+ }
+ }
+}
diff --git a/tests/auto/declarative/BackendTestMultiplier.qml b/tests/auto/declarative/BackendTestMultiplier.qml
new file mode 100644
index 0000000..6602ea9
--- /dev/null
+++ b/tests/auto/declarative/BackendTestMultiplier.qml
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtOpcUa 5.13 as QtOpcUa
+
+Item {
+ property int currentTest: 0
+ property string testName
+
+ QtOpcUa.Connection {
+ id: connection
+ }
+
+ Component.onCompleted: {
+ var component = Qt.createComponent(testName + ".qml")
+ if (component.status != Component.Ready) {
+ console.log("Failed to load component " + testName, component.errorString());
+ return;
+ }
+
+ for (var backendIndex in connection.availableBackends) {
+ var backend = connection.availableBackends[backendIndex];
+ console.log("Setting up", testName, "for", backend);
+ var child = component.createObject(this, { "backendName": backend });
+ if (child == null) {
+ console.log("Error creating object", testName);
+ return;
+ }
+ child.completedChanged.connect(incrementTest);
+ children.push(child);
+ }
+ children[currentTest].shouldRun = true;
+ }
+
+ function incrementTest() {
+ currentTest += 1;
+ if (currentTest < children.length)
+ children[currentTest].shouldRun = true;
+ }
+}
+
diff --git a/tests/auto/declarative/BatchReadWriteTest.qml b/tests/auto/declarative/BatchReadWriteTest.qml
new file mode 100644
index 0000000..0591ce4
--- /dev/null
+++ b/tests/auto/declarative/BatchReadWriteTest.qml
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtTest 1.0
+import QtOpcUa 5.13 as QtOpcUa
+
+Item {
+ property string backendName
+ property int completedTestCases: 0
+ property int availableTestCases: 0
+ property bool completed: completedTestCases == availableTestCases
+ property bool shouldRun: false
+
+ onShouldRunChanged: {
+ if (shouldRun)
+ console.log("Running", parent.testName, "with", backendName);
+ }
+
+ QtOpcUa.Connection {
+ id: connection
+ backend: backendName
+ defaultConnection: true
+ }
+
+ QtOpcUa.ServerDiscovery {
+ id: serverDiscovery
+ onServersChanged: {
+ if (!count)
+ return;
+ endpointDiscovery.serverUrl = at(0).discoveryUrls[0];
+ }
+ }
+
+ QtOpcUa.EndpointDiscovery {
+ id: endpointDiscovery
+ onEndpointsChanged: {
+ if (!count)
+ return;
+ connection.connectToEndpoint(at(0));
+ }
+ }
+
+ Component.onCompleted: {
+ for (var i in children) {
+ if (children[i].objectName == "TestCase")
+ availableTestCases += 1;
+ }
+ serverDiscovery.discoveryUrl = OPCUA_DISCOVERY_URL;
+ }
+
+ CompletionLoggingTestCase {
+ name: "Reading multiple items"
+ when: connection.connected && shouldRun
+
+ SignalSpy {
+ id: readNodeAttributesFinishedSpy
+ target: connection
+ signalName: "readNodeAttributesFinished"
+ }
+
+ function test_nodeTest() {
+ var readItemList = [];
+ var readItem;
+
+ // Item #0
+ readItem = QtOpcUa.ReadItem.create();
+ readItem.ns = "http://qt-project.org";
+ readItem.nodeId = "s=Demo.Static.Scalar.Double";
+ readItem.attribute = QtOpcUa.Constants.NodeAttribute.DisplayName;
+ readItemList.push(readItem);
+
+ // Item #1
+ readItem = QtOpcUa.ReadItem.create();
+ readItem.ns = "http://qt-project.org";
+ readItem.nodeId = "s=Demo.Static.Scalar.Double";
+ // Value is the default attribute to read
+ readItemList.push(readItem);
+
+ // Item #2
+ readItem = QtOpcUa.ReadItem.create();
+ readItem.ns = "http://qt-project.org";
+ readItem.nodeId = "s=Demo.Static.Arrays.UInt32";
+ // Value is the default attribute to read
+ readItem.indexRange = "0:2";
+ readItemList.push(readItem);
+
+ verify(connection.readNodeAttributes(readItemList))
+ readNodeAttributesFinishedSpy.wait();
+
+ compare(readNodeAttributesFinishedSpy.count, 1);
+ compare(readNodeAttributesFinishedSpy.signalArguments[0].length, 1);
+
+ var results = readNodeAttributesFinishedSpy.signalArguments[0][0];
+ var now = new Date();
+
+ compare(results.length, readItemList.length);
+ for (var i = 0; i < results.length; i++) {
+ console.log("Comparing result item #" + i);
+ verify(results[i].status.isGood);
+ compare(results[i].nodeId, readItemList[i].nodeId);
+ compare(results[i].namespaceName, readItemList[i].ns);
+ compare(results[i].attribute, readItemList[i].attribute);
+ verify((now - results[i].serverTimestamp) < 10000);
+ }
+
+ compare(results[0].value.text, "DoubleScalarTest");
+ compare(results[1].value, 1.0);
+ compare(results[2].value, [1, 2]);
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Writing multiple items"
+ when: connection.connected && shouldRun
+
+ SignalSpy {
+ id: writeNodeAttributesFinishedSpy
+ target: connection
+ signalName: "writeNodeAttributesFinished"
+ }
+
+ function test_nodeTest() {
+ var writeItemList = [];
+ var writeItem;
+
+ // Item #0
+ writeItem = QtOpcUa.WriteItem.create();
+ writeItem.ns = "http://qt-project.org";
+ writeItem.nodeId = "s=Demo.Static.Scalar.String";
+ writeItem.attribute = QtOpcUa.Constants.NodeAttribute.Value;
+ writeItem.value = "Writing multiple items";
+ writeItemList.push(writeItem);
+
+ // Item #1
+ writeItem = QtOpcUa.WriteItem.create();
+ writeItem.ns = "http://qt-project.org";
+ writeItem.nodeId = "s=Demo.Static.Scalar.Double";
+ writeItem.value = 15.6;
+ writeItemList.push(writeItem);
+
+ // Item #2
+ writeItem = QtOpcUa.WriteItem.create();
+ writeItem.ns = "http://qt-project.org";
+ writeItem.nodeId = "s=Demo.Static.Arrays.UInt32";
+ writeItem.indexRange = "0:1";
+ writeItem.value = [42, 43];
+ writeItem.valueType = QtOpcUa.Constants.UInt32;
+ writeItemList.push(writeItem);
+
+ verify(connection.writeNodeAttributes(writeItemList))
+ writeNodeAttributesFinishedSpy.wait();
+
+ compare(writeNodeAttributesFinishedSpy.count, 1);
+ compare(writeNodeAttributesFinishedSpy.signalArguments[0].length, 1);
+
+ var results = writeNodeAttributesFinishedSpy.signalArguments[0][0];
+
+ compare(results.length, writeItemList.length);
+ for (var i = 0; i < results.length; i++) {
+ console.log("Comparing result item #" + i);
+ verify(results[i].status.isGood);
+ compare(results[i].nodeId, writeItemList[i].nodeId);
+ compare(results[i].namespaceName, writeItemList[i].ns);
+ compare(results[i].attribute, writeItemList[i].attribute);
+ }
+
+ // Reset to default values
+ //
+ writeItemList = [];
+ // Item #0
+ writeItem = QtOpcUa.WriteItem.create();
+ writeItem.ns = "http://qt-project.org";
+ writeItem.nodeId = "s=Demo.Static.Scalar.String";
+ writeItem.attribute = QtOpcUa.Constants.NodeAttribute.Value;
+ writeItem.value = "Value";
+ writeItemList.push(writeItem);
+
+ // Item #1
+ writeItem = QtOpcUa.WriteItem.create();
+ writeItem.ns = "http://qt-project.org";
+ writeItem.nodeId = "s=Demo.Static.Scalar.Double";
+ writeItem.value = 1.0;
+ writeItem.valueType = QtOpcUa.Constants.Double;
+ writeItemList.push(writeItem);
+
+ // Item #2
+ writeItem = QtOpcUa.WriteItem.create();
+ writeItem.ns = "http://qt-project.org";
+ writeItem.nodeId = "s=Demo.Static.Arrays.UInt32";
+ writeItem.indexRange = "0:1";
+ writeItem.value = [1, 2];
+ writeItem.valueType = QtOpcUa.Constants.UInt32;
+ writeItemList.push(writeItem);
+
+ writeNodeAttributesFinishedSpy.clear();
+ verify(connection.writeNodeAttributes(writeItemList))
+ writeNodeAttributesFinishedSpy.wait();
+
+ var results = writeNodeAttributesFinishedSpy.signalArguments[0][0];
+
+ compare(results.length, writeItemList.length);
+ for (var i = 0; i < results.length; i++) {
+ console.log("Comparing result item #" + i);
+ verify(results[i].status.isGood);
+ compare(results[i].nodeId, writeItemList[i].nodeId);
+ compare(results[i].namespaceName, writeItemList[i].ns);
+ compare(results[i].attribute, writeItemList[i].attribute);
+ }
+
+ }
+ }
+}
diff --git a/tests/auto/declarative/CompletionLoggingTestCase.qml b/tests/auto/declarative/CompletionLoggingTestCase.qml
new file mode 100644
index 0000000..fe46b6a
--- /dev/null
+++ b/tests/auto/declarative/CompletionLoggingTestCase.qml
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtTest 1.0
+
+TestCase {
+ onCompletedChanged: parent.completedTestCases += (completed ? 1 : -1)
+ objectName: "TestCase"
+}
diff --git a/tests/auto/declarative/DataChangeFilterTest.qml b/tests/auto/declarative/DataChangeFilterTest.qml
new file mode 100644
index 0000000..8d0e8e8
--- /dev/null
+++ b/tests/auto/declarative/DataChangeFilterTest.qml
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtTest 1.0
+import QtOpcUa 5.13 as QtOpcUa
+
+Item {
+ property string backendName
+ property int completedTestCases: 0
+ property int availableTestCases: 0
+ property bool completed: completedTestCases == availableTestCases && availableTestCases > 0
+ property bool shouldRun: false
+
+ onShouldRunChanged: {
+ if (shouldRun)
+ console.log("Running", parent.testName, "with", backendName);
+ }
+
+ QtOpcUa.Connection {
+ id: connection
+ backend: backendName
+ defaultConnection: true
+ }
+
+ QtOpcUa.ServerDiscovery {
+ id: serverDiscovery
+ onServersChanged: {
+ if (!count)
+ return;
+ endpointDiscovery.serverUrl = at(0).discoveryUrls[0];
+ }
+
+ Binding on discoveryUrl {
+ when: shouldRun && Component.completed
+ value: OPCUA_DISCOVERY_URL
+ }
+ }
+
+ QtOpcUa.EndpointDiscovery {
+ id: endpointDiscovery
+ onEndpointsChanged: {
+ if (!count)
+ return;
+ connection.connectToEndpoint(at(0));
+ }
+ }
+
+ Component.onCompleted: {
+ for (var i in children) {
+ if (children[i].objectName == "TestCase")
+ availableTestCases += 1;
+ }
+ }
+
+ Timer {
+ id: timer
+ interval: 2000
+ }
+
+ CompletionLoggingTestCase {
+ name: "Data Change Filter"
+ when: node1.readyToUse && shouldRun
+
+ function test_nodeTest() {
+ tryCompare(node1, "monitored", true);
+ compare(node2.monitored, false);
+ compare(node1.publishingInterval, 100.0);
+
+ compare(node1.filter.deadbandType, 1);
+ compare(node1.filter.trigger, 1);
+ compare(node1.filter.deadbandValue, 1);
+ if (node1ValueSpy.count == 0)
+ node1ValueSpy.wait();
+
+ verify(node1.value != 1.5);
+
+ node1ValueSpy.clear();
+ node2ValueSpy.clear();
+ node2.value = 1.5;
+ node2ValueSpy.wait(); // wait for value written
+ timer.running = true;
+ timerSpy.wait();
+ compare(node1ValueSpy.count, 0);
+ compare(node1.value, 1.0); // still 1.0 because of filtering
+
+ node1ValueSpy.clear();
+ node2ValueSpy.clear();
+ verify(node1.value != 30);
+ node2.value = 30.0;
+ verify(node1.value != 30);
+ node2ValueSpy.wait(); // wait for value written
+ node1ValueSpy.wait();
+ compare(node1.value, 30);
+ compare(node1ValueSpy.count, 1);
+
+ // Reset values
+ node1ValueSpy.clear();
+ node2ValueSpy.clear();
+ node2.value = 1.0;
+ node2ValueSpy.wait(); // wait for value written
+ node1ValueSpy.wait();
+ compare(node1ValueSpy.count, 1);
+ compare(node1.value, 1.0);
+ }
+
+ SignalSpy {
+ id: node1ValueSpy
+ target: node1
+ signalName: "valueChanged"
+ }
+
+ SignalSpy {
+ id: node2ValueSpy
+ target: node2
+ signalName: "valueChanged"
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "http://qt-project.org"
+ identifier: "s=Demo.Static.Scalar.Double"
+ }
+ id: node1
+
+ filter: QtOpcUa.DataChangeFilter {
+ deadbandValue: 1.0
+ deadbandType: QtOpcUa.DataChangeFilter.DeadbandType.Absolute
+ trigger: QtOpcUa.DataChangeFilter.DataChangeTrigger.StatusOrValue
+ }
+
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "http://qt-project.org"
+ identifier: "s=Demo.Static.Scalar.Double"
+ }
+ id: node2
+ monitored: false
+ }
+
+ SignalSpy {
+ id: timerSpy
+ target: timer
+ signalName: "triggered"
+ }
+ }
+}
+
+
diff --git a/tests/auto/declarative/DiscoveryTest.qml b/tests/auto/declarative/DiscoveryTest.qml
new file mode 100644
index 0000000..361a135
--- /dev/null
+++ b/tests/auto/declarative/DiscoveryTest.qml
@@ -0,0 +1,278 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtTest 1.0
+import QtOpcUa 5.13 as QtOpcUa
+
+Item {
+ property string backendName
+ property int completedTestCases: 0
+ property int availableTestCases: 0
+ property bool completed: completedTestCases == availableTestCases
+ property bool shouldRun: false
+
+ onShouldRunChanged: {
+ if (shouldRun)
+ console.log("Running", parent.testName, "with", backendName);
+ }
+
+ Component.onCompleted: {
+ for (var i in children) {
+ if (children[i].objectName == "TestCase")
+ availableTestCases += 1;
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Fetch data from discovery server using default connection"
+ when: shouldRun
+
+ QtOpcUa.Connection {
+ id: connection1
+ backend: backendName
+ defaultConnection: true
+ }
+
+ QtOpcUa.ServerDiscovery {
+ // uses default connection
+ id: myServers1
+ }
+
+ QtOpcUa.EndpointDiscovery {
+ // uses default connection
+ id: myEndpoints1
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection1
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=theStringId"
+ }
+ id: node1
+ }
+
+ SignalSpy {
+ id: serversChangedSpy1
+ target: myServers1
+ signalName: "serversChanged"
+ }
+
+ SignalSpy {
+ id: serversCountSpy1
+ target: myServers1
+ signalName: "countChanged"
+ }
+
+ SignalSpy {
+ id: serversStatusSpy1
+ target: myServers1
+ signalName: "statusChanged"
+ }
+
+ SignalSpy {
+ id: endpointsChangedSpy1
+ target: myEndpoints1
+ signalName: "endpointsChanged"
+ }
+
+ SignalSpy {
+ id: endpointsCountSpy1
+ target: myEndpoints1
+ signalName: "countChanged"
+ }
+
+ SignalSpy {
+ id: endpointsStatusSpy1
+ target: myEndpoints1
+ signalName: "statusChanged"
+ }
+
+ SignalSpy {
+ id: connectedSpy1
+ target: node1
+ signalName: "readyToUseChanged"
+ }
+
+ function test_nodeTest() {
+ compare(myServers1.count, 0);
+
+ myServers1.discoveryUrl = OPCUA_DISCOVERY_URL;
+
+ serversStatusSpy1.wait();
+ compare(myServers1.status.status, QtOpcUa.Status.GoodCompletesAsynchronously);
+
+ tryVerify(function() { return myServers1.count > 0;});
+ compare(serversCountSpy1.count, 1);
+ compare(serversChangedSpy1.count, 2);
+ compare(myServers1.count, 1);
+ verify(myServers1.at(0).discoveryUrls[0].startsWith("opc.tcp://"));
+
+ compare(myEndpoints1.count, 0);
+
+ myEndpoints1.serverUrl = myServers1.at(0).discoveryUrls[0];
+ endpointsStatusSpy1.wait();
+ compare(myEndpoints1.status.status, QtOpcUa.Status.GoodCompletesAsynchronously);
+ compare(endpointsCountSpy1.count, 0);
+ if (endpointsStatusSpy1.count == 1)
+ endpointsStatusSpy1.wait();
+ compare(endpointsStatusSpy1.count, 2);
+ compare(endpointsChangedSpy1.count, 2);
+
+ tryVerify(function() { return myEndpoints1.count > 0;});
+ if (SERVER_SUPPORTS_SECURITY)
+ compare(myEndpoints1.count, 5);
+ else
+ compare(myEndpoints1.count, 1);
+ verify(myEndpoints1.at(0).endpointUrl.startsWith("opc.tcp://"));
+ compare(myEndpoints1.at(0).securityPolicy, "http://opcfoundation.org/UA/SecurityPolicy#None");
+
+ connection1.connectToEndpoint(myEndpoints1.at(0));
+
+ connectedSpy1.wait();
+ compare(node1.value, "Value", "");
+ compare(node1.browseName, "theStringId");
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Fetch data from discovery server using specified connection"
+ when: shouldRun
+
+ QtOpcUa.Connection {
+ id: connection2
+ backend: backendName
+ }
+
+ QtOpcUa.ServerDiscovery {
+ connection: connection2
+ id: myServers2
+ }
+
+ QtOpcUa.EndpointDiscovery {
+ id: myEndpoints2
+ connection: connection2
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection2
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=theStringId"
+ }
+ id: node2
+ }
+
+ SignalSpy {
+ id: serversChangedSpy2
+ target: myServers2
+ signalName: "serversChanged"
+ }
+
+ SignalSpy {
+ id: serversCountSpy2
+ target: myServers2
+ signalName: "countChanged"
+ }
+
+ SignalSpy {
+ id: serversStatusSpy2
+ target: myServers2
+ signalName: "statusChanged"
+ }
+
+ SignalSpy {
+ id: endpointsChangedSpy2
+ target: myEndpoints2
+ signalName: "endpointsChanged"
+ }
+
+ SignalSpy {
+ id: endpointsCountSpy2
+ target: myEndpoints2
+ signalName: "countChanged"
+ }
+
+ SignalSpy {
+ id: endpointsStatusSpy2
+ target: myEndpoints2
+ signalName: "statusChanged"
+ }
+
+ SignalSpy {
+ id: connectedSpy2
+ target: node2
+ signalName: "readyToUseChanged"
+ }
+
+ function test_nodeTest() {
+ compare(myServers2.count, 0);
+
+ myServers2.discoveryUrl = OPCUA_DISCOVERY_URL;
+
+ serversStatusSpy2.wait();
+ compare(myServers2.status.status, QtOpcUa.Status.GoodCompletesAsynchronously);
+
+ tryVerify(function() { return myServers2.count > 0;});
+ compare(serversStatusSpy2.count, 2);
+ compare(serversChangedSpy2.count, 2);
+ compare(myServers2.count, 1);
+ verify(myServers2.at(0).discoveryUrls[0].startsWith("opc.tcp://"));
+
+ myEndpoints2.serverUrl = myServers2.at(0).discoveryUrls[0];
+ endpointsStatusSpy2.wait();
+ compare(myEndpoints2.status.status, QtOpcUa.Status.GoodCompletesAsynchronously);
+
+ tryVerify(function() { return myEndpoints2.count > 0;});
+ compare(endpointsCountSpy2.count, 1);
+ compare(endpointsStatusSpy2.count, 2);
+ compare(endpointsChangedSpy2.count, 2);
+ if (SERVER_SUPPORTS_SECURITY)
+ compare(myEndpoints2.count, 5);
+ else
+ compare(myEndpoints2.count, 1);
+ verify(myEndpoints2.at(0).endpointUrl.startsWith("opc.tcp://"));
+ compare(myEndpoints2.at(0).securityPolicy, "http://opcfoundation.org/UA/SecurityPolicy#None");
+
+ connection2.connectToEndpoint(myEndpoints2.at(0));
+
+ connectedSpy2.wait();
+ compare(node2.value, "Value", "");
+ compare(node2.browseName, "theStringId");
+ }
+ }
+}
diff --git a/tests/auto/declarative/MethodnodeTest.qml b/tests/auto/declarative/MethodnodeTest.qml
new file mode 100644
index 0000000..918f85a
--- /dev/null
+++ b/tests/auto/declarative/MethodnodeTest.qml
@@ -0,0 +1,253 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtTest 1.0
+import QtOpcUa 5.13 as QtOpcUa
+
+Item {
+ property string backendName
+ property int completedTestCases: 0
+ property int availableTestCases: 0
+ property bool completed: completedTestCases == availableTestCases
+ property bool shouldRun: false
+
+ onShouldRunChanged: {
+ if (shouldRun)
+ console.log("Running", parent.testName, "with", backendName);
+ }
+
+ QtOpcUa.Connection {
+ id: connection
+ backend: backendName
+ defaultConnection: true
+ }
+
+ QtOpcUa.ServerDiscovery {
+ id: serverDiscovery
+ onServersChanged: {
+ if (!count)
+ return;
+ endpointDiscovery.serverUrl = at(0).discoveryUrls[0];
+ }
+ }
+
+ QtOpcUa.EndpointDiscovery {
+ id: endpointDiscovery
+ onEndpointsChanged: {
+ if (!count)
+ return;
+ connection.connectToEndpoint(at(0));
+ }
+ }
+
+ Component.onCompleted: {
+ for (var i in children) {
+ if (children[i].objectName == "TestCase")
+ availableTestCases += 1;
+ }
+ serverDiscovery.discoveryUrl = OPCUA_DISCOVERY_URL;
+ }
+
+ CompletionLoggingTestCase {
+ name: "Standard attributes on method node"
+ when: node1.readyToUse && shouldRun
+
+ SignalSpy {
+ id: node1BrowseNameSpy
+ target: node1
+ signalName: "browseNameChanged"
+ }
+
+ SignalSpy {
+ id: node1NodeClassSpy
+ target: node1
+ signalName: "nodeClassChanged"
+ }
+
+ SignalSpy {
+ id: node1DisplayNameSpy
+ target: node1
+ signalName: "displayNameChanged"
+ }
+
+ SignalSpy {
+ id: node1DescriptionSpy
+ target: node1
+ signalName: "descriptionChanged"
+ }
+
+ SignalSpy {
+ id: node1ObjectNodeIdSpy
+ target: node1
+ signalName: "objectNodeIdChanged"
+ }
+
+ function test_nodeTest() {
+ compare(node1.browseName, "multiplyArguments");
+ compare(node1.nodeClass, QtOpcUa.Constants.NodeClass.Method);
+ compare(node1.displayName.text, "ns=3;s=Test.Method.Multiply");
+ compare(node1.description.text, "MultiplyDoubles");
+ compare(node1.objectNodeId.ns, "Test Namespace");
+ compare(node1.objectNodeId.identifier, "s=TestFolder");
+
+ compare(node1BrowseNameSpy.count, 1)
+ compare(node1NodeClassSpy.count, 1)
+ compare(node1DisplayNameSpy.count, 1)
+ compare(node1DescriptionSpy.count, 1)
+ compare(node1ObjectNodeIdSpy.count, 0)
+
+ node1.objectNodeId.identifier = "s=foo";
+ node1ObjectNodeIdSpy.wait()
+ compare(node1ObjectNodeIdSpy.count, 1);
+ }
+
+ QtOpcUa.MethodNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=Test.Method.Multiply"
+ }
+ objectNodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=TestFolder"
+ }
+ id: node1
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Use method arguments"
+ when: node2.readyToUse && shouldRun
+
+ SignalSpy {
+ id: node2resultStatusSpy
+ target: node2
+ signalName: "resultStatusChanged"
+ }
+
+ function test_nodeTest() {
+ compare(node2.browseName, "multiplyArguments");
+ compare(node2.nodeClass, QtOpcUa.Constants.NodeClass.Method);
+ compare(node2.resultStatus.status, QtOpcUa.Status.Good);
+ verify(node2.resultStatus.isGood);
+
+ node2.callMethod();
+
+ node2resultStatusSpy.wait();
+ compare(node2resultStatusSpy.count, 1);
+ compare(node2.resultStatus.status, QtOpcUa.Status.Good);
+ verify(node2.resultStatus.isGood);
+ compare(node2.outputArguments.length, 1);
+ compare(node2.outputArguments[0], 12);
+ }
+
+ QtOpcUa.MethodNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=Test.Method.Multiply"
+ }
+ objectNodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=TestFolder"
+ }
+ inputArguments: [
+ QtOpcUa.MethodArgument {
+ value: 3
+ type: QtOpcUa.Constants.Double
+ },
+ QtOpcUa.MethodArgument {
+ value: 4
+ type: QtOpcUa.Constants.Double
+ }
+ ]
+ id: node2
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Multiple Output Arguments"
+ when: node3.readyToUse && shouldRun
+
+ SignalSpy {
+ id: node3resultStatusSpy
+ target: node3
+ signalName: "resultStatusChanged"
+ }
+
+ function test_nodeTest() {
+ compare(node3.browseName, "multipleOutputArguments");
+ compare(node3.nodeClass, QtOpcUa.Constants.NodeClass.Method);
+ compare(node3.resultStatus.status, QtOpcUa.Status.Good);
+ verify(node3.resultStatus.isGood);
+
+ node3.callMethod();
+
+ node3resultStatusSpy.wait();
+ compare(node3resultStatusSpy.count, 1);
+ compare(node3.resultStatus.status, QtOpcUa.Status.Good);
+ verify(node3.resultStatus.isGood);
+ // Check for two output arguments
+ compare(node3.outputArguments.length, 2);
+ compare(node3.outputArguments[0], 12);
+ compare(node3.outputArguments[1].text, "some text argument");
+ }
+
+ QtOpcUa.MethodNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=Test.Method.MultipleOutputArguments"
+ }
+ objectNodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=TestFolder"
+ }
+ inputArguments: [
+ QtOpcUa.MethodArgument {
+ value: 3
+ type: QtOpcUa.Constants.Double
+ },
+ QtOpcUa.MethodArgument {
+ value: 4
+ type: QtOpcUa.Constants.Double
+ }
+ ]
+ id: node3
+ }
+ }
+}
diff --git a/tests/auto/declarative/MonitoringFilterTest.qml b/tests/auto/declarative/MonitoringFilterTest.qml
new file mode 100644
index 0000000..a591e8b
--- /dev/null
+++ b/tests/auto/declarative/MonitoringFilterTest.qml
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtTest 1.0
+import QtOpcUa 5.13 as QtOpcUa
+
+Item {
+ property string backendName
+ property int completedTestCases: 0
+ property int availableTestCases: 0
+ property bool completed: completedTestCases == availableTestCases && availableTestCases > 0
+ property bool shouldRun: false
+
+ onShouldRunChanged: {
+ if (shouldRun)
+ console.log("Running", parent.testName, "with", backendName);
+ }
+
+ QtOpcUa.Connection {
+ id: connection
+ backend: backendName
+ defaultConnection: true
+ }
+
+ QtOpcUa.ServerDiscovery {
+ id: serverDiscovery
+ onServersChanged: {
+ if (!count)
+ return;
+ endpointDiscovery.serverUrl = at(0).discoveryUrls[0];
+ }
+
+ Binding on discoveryUrl {
+ when: shouldRun && Component.completed
+ value: OPCUA_DISCOVERY_URL
+ }
+ }
+
+ QtOpcUa.EndpointDiscovery {
+ id: endpointDiscovery
+ onEndpointsChanged: {
+ if (!count)
+ return;
+ connection.connectToEndpoint(at(0));
+ }
+ }
+
+ Component.onCompleted: {
+ for (var i in children) {
+ if (children[i].objectName == "TestCase")
+ availableTestCases += 1;
+ }
+ }
+
+ Timer {
+ id: timer
+ interval: 2000
+ }
+
+/* // In order to run this test you need to compile the example tutorial_server_event from open62541 master branch.
+ CompletionLoggingTestCase {
+ name: "Event filter"
+ when: node3.readyToUse && shouldRun
+
+ function test_nodeTest() {
+ eventSpy.clear();
+ node4.callMethod();
+ eventSpy.wait();
+ compare(eventSpy.count, 1);
+ compare(eventSpy.signalArguments[0].length, 1);
+ compare(eventSpy.signalArguments[0][0].length, 2);
+ compare(eventSpy.signalArguments[0][0][0], 100);
+ compare(eventSpy.signalArguments[0][0][1].text, "An event has been generated.");
+ }
+
+ QtOpcUa.Node {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "http://opcfoundation.org/UA/"
+ identifier: "i=2253" // Server object
+ }
+ id: node3
+
+ eventFilter: QtOpcUa.EventFilter {
+ select: [
+ QtOpcUa.SimpleAttributeOperand {
+ browsePath: [
+ QtOpcUa.NodeId {
+ identifier: "Severity"
+ ns: "http://opcfoundation.org/UA/"
+ }
+ ]
+ },
+ QtOpcUa.SimpleAttributeOperand {
+ browsePath: [
+ QtOpcUa.NodeId {
+ identifier: "Message"
+ ns: "http://opcfoundation.org/UA/"
+ }
+ ]
+ }
+ ]
+
+// Where clause is not supported by server yet
+// where: [
+// QtOpcUa.FilterElement {
+// operator: QtOpcUa.FilterElement.GreaterThanOrEqual
+// firstOperand: QtOpcUa.SimpleAttributeOperand {
+// browsePath: [
+// QtOpcUa.NodeId {
+// identifier: "Severity"
+// ns: "http://opcfoundation.org/UA/"
+// }
+// ]
+// }
+// secondOperand: QtOpcUa.LiteralOperand {
+// value: 700
+// type: QtOpcUa.Constants.UInt16
+// }
+// }
+// ]
+ }
+ }
+
+ QtOpcUa.MethodNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "http://opcfoundation.org/UA/"
+ identifier: "i=62541"
+ }
+ objectNodeId: QtOpcUa.NodeId {
+ ns: "http://opcfoundation.org/UA/"
+ identifier: "i=85"
+ }
+ id: node4
+ }
+
+ SignalSpy {
+ id: eventSpy
+ target: node3
+ signalName: "eventOccurred"
+ }
+ }
+*/
+}
+
+
diff --git a/tests/auto/declarative/RelativenodeTest.qml b/tests/auto/declarative/RelativenodeTest.qml
new file mode 100644
index 0000000..69ba3ed
--- /dev/null
+++ b/tests/auto/declarative/RelativenodeTest.qml
@@ -0,0 +1,385 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtTest 1.0
+import QtOpcUa 5.13 as QtOpcUa
+
+Item {
+ property string backendName
+ property int completedTestCases: 0
+ property int availableTestCases: 0
+ property bool completed: completedTestCases == availableTestCases
+ property bool shouldRun: false
+
+ onShouldRunChanged: {
+ if (shouldRun)
+ console.log("Running", parent.testName, "with", backendName);
+ }
+
+ QtOpcUa.Connection {
+ id: connection
+ backend: backendName
+ defaultConnection: true
+ }
+
+ QtOpcUa.ServerDiscovery {
+ id: serverDiscovery
+ onServersChanged: {
+ if (!count)
+ return;
+ endpointDiscovery.serverUrl = at(0).discoveryUrls[0];
+ }
+ }
+
+ QtOpcUa.EndpointDiscovery {
+ id: endpointDiscovery
+ onEndpointsChanged: {
+ if (!count)
+ return;
+ connection.connectToEndpoint(at(0));
+ }
+ }
+
+ Component.onCompleted: {
+ for (var i in children) {
+ if (children[i].objectName == "TestCase")
+ availableTestCases += 1;
+ }
+ serverDiscovery.discoveryUrl = OPCUA_DISCOVERY_URL;
+ }
+
+ CompletionLoggingTestCase {
+ name: "RelativeNodePath"
+ when: node1.readyToUse && shouldRun
+
+ function test_nodeRead() {
+ tryVerify(function() { return node1.value > 0 });
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.RelativeNodeId {
+ startNode: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=TestFolder"
+ }
+ path: [ QtOpcUa.RelativeNodePath {
+ ns: "Test Namespace"
+ browseName: "TestNode.ReadWrite"
+ }
+ ]
+ }
+ id: node1
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "CascadedRelativeNodePath"
+ when: node2.readyToUse && shouldRun
+
+ function test_nodeRead() {
+ tryVerify(function() { return node2.value > 0 });
+ }
+
+ QtOpcUa.RelativeNodeId {
+ startNode: QtOpcUa.NodeId {
+ ns: "http://opcfoundation.org/UA/"
+ identifier: "i=85"
+ }
+ path: [ QtOpcUa.RelativeNodePath {
+ ns: "Test Namespace"
+ browseName: "TestFolder"
+ }
+ ]
+ id: secondLevelNode
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.RelativeNodeId {
+ startNode: secondLevelNode
+ path: [ QtOpcUa.RelativeNodePath {
+ ns: "Test Namespace"
+ browseName: "TestNode.ReadWrite"
+ }
+ ]
+ }
+ id: node2
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Emitting signals on node changes"
+ when: node3.readyToUse && shouldRun
+
+ function test_changeStartNode() {
+ node3NamespaceSpy.clear();
+ node3NodeIdSpy.clear();
+ node3NodeChangedSpy.clear();
+ node3NodeIdChangedSpy.clear();
+ node3ValueSpy.clear();
+ node3PathSpy.clear();
+ node3.nodeId.startNode.identifier = "s=TestFolder2";
+ node3ValueSpy.wait();
+
+ // value has to be undefined because when node IDs are changed
+ // all attributes become undefined before they get the new values.
+ if (node3ValueSpy.count < 2)
+ node3ValueSpy.wait();
+ verify(!node3ValueSpy.signalArguments[0][0]);
+ compare(node3ValueSpy.signalArguments[1][0], 0.1);
+
+ compare(node3NodeIdSpy.count, 1);
+ compare(node3NamespaceSpy.count, 0);
+ verify(node3NodeChangedSpy.count > 0);
+ compare(node3PathSpy.count, 0);
+ compare(node3NodeIdChangedSpy.count, 1);
+ compare(node3ValueSpy.count, 2); // first undefined, then the real value
+ compare(node3.value, 0.1);
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.RelativeNodeId {
+ startNode: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=TestFolder"
+ }
+ path: [ QtOpcUa.RelativeNodePath {
+ ns: "Test Namespace"
+ browseName: "TestNode.ReadWrite"
+ }
+ ]
+ }
+ id: node3
+ }
+
+ SignalSpy {
+ id: node3NamespaceSpy
+ target: node3.nodeId
+ signalName: "nodeNamespaceChanged"
+ }
+
+ SignalSpy {
+ id: node3NodeIdSpy
+ target: node3.nodeId
+ signalName: "nodeChanged"
+ }
+
+ SignalSpy {
+ id: node3NodeChangedSpy
+ target: node3
+ signalName: "nodeChanged"
+ }
+
+ SignalSpy {
+ id: node3NodeIdChangedSpy
+ target: node3
+ signalName: "nodeIdChanged"
+ }
+
+ SignalSpy {
+ id: node3ValueSpy
+ target: node3
+ signalName: "valueChanged"
+ }
+
+ SignalSpy {
+ id: node3PathSpy
+ target: node3.nodeId
+ signalName: "pathChanged"
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Emitting signals on cascaded node changes"
+ when: node4.readyToUse && shouldRun
+
+ function test_nodeRead() {
+ node4NamespaceSpy.clear();
+ node4NodeIdSpy.clear();
+ node4NodeChangedSpy.clear();
+ node4NodeIdChangedSpy.clear();
+ node4ValueSpy.clear();
+ node4PathSpy.clear();
+ node4.nodeId.startNode.path = replacementNode.createObject(parent);
+ node4NodeChangedSpy.wait();
+ node4ValueSpy.wait();
+
+ // value has to be undefined because when node IDs are changed
+ // all attributes become undefined before they get the new values.
+ if (node4ValueSpy.count < 2)
+ node4ValueSpy.wait();
+ verify(!node4ValueSpy.signalArguments[0][0]);
+ compare(node4ValueSpy.signalArguments[1][0], 0.1);
+
+ compare(node4NodeIdSpy.count, 2);
+ compare(node4NamespaceSpy.count, 0);
+ verify(node4NodeChangedSpy.count > 0);
+ compare(node4NodeIdChangedSpy.count, 1);
+ compare(node4ValueSpy.count, 2); // first undefined, then the real value
+ compare(node4.value, 0.1);
+ compare(node4PathSpy.count, 2);
+ }
+
+ QtOpcUa.RelativeNodeId {
+ startNode: QtOpcUa.NodeId {
+ ns: "http://opcfoundation.org/UA/"
+ identifier: "i=85"
+ }
+ path: [ QtOpcUa.RelativeNodePath {
+ ns: "Test Namespace"
+ browseName: "TestFolder"
+ }
+ ]
+ id: secondLevelNode2
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.RelativeNodeId {
+ startNode: secondLevelNode2
+ path: [ QtOpcUa.RelativeNodePath {
+ ns: "Test Namespace"
+ browseName: "TestNode.ReadWrite"
+ }
+ ]
+ }
+ id: node4
+ }
+
+ Component {
+ id: replacementNode
+ QtOpcUa.RelativeNodePath {
+ ns: "Test Namespace";
+ browseName: "TestFolder2";
+ }
+ }
+
+ SignalSpy {
+ id: node4NamespaceSpy
+ target: node4.nodeId
+ signalName: "nodeNamespaceChanged"
+ }
+
+ SignalSpy {
+ id: node4NodeIdSpy
+ target: node4.nodeId
+ signalName: "nodeChanged"
+ }
+
+ SignalSpy {
+ id: node4NodeChangedSpy
+ target: node4
+ signalName: "nodeChanged"
+ }
+
+ SignalSpy {
+ id: node4NodeIdChangedSpy
+ target: node4
+ signalName: "nodeIdChanged"
+ }
+
+ SignalSpy {
+ id: node4ValueSpy
+ target: node4
+ signalName: "valueChanged"
+ }
+
+ SignalSpy {
+ id: node4PathSpy
+ target: node4.nodeId.startNode
+ signalName: "pathChanged"
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Relative Node Path with References"
+ when: node5.readyToUse && shouldRun
+
+ function test_nodeRead() {
+ tryVerify(function() { return node5.value > 0 });
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.RelativeNodeId {
+ startNode: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=TestFolder"
+ }
+ path: [ QtOpcUa.RelativeNodePath {
+ ns: "Test Namespace"
+ browseName: "TestNode.ReadWrite"
+ referenceType: QtOpcUa.Constants.ReferenceTypeId.References
+ }
+ ]
+ }
+ id: node5
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Relative Node Path with NodeId reference"
+ when: node6.readyToUse && shouldRun
+
+ function test_nodeRead() {
+ tryVerify(function() { return node6.value > 0 });
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.RelativeNodeId {
+ startNode: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=TestFolder"
+ }
+ path: [ QtOpcUa.RelativeNodePath {
+ ns: "Test Namespace"
+ browseName: "TestNode.ReadWrite"
+ referenceType: QtOpcUa.NodeId {
+ ns: "http://opcfoundation.org/UA/"
+ identifier: "i=31"
+ }
+ }
+ ]
+ }
+ id: node6
+ }
+ }
+
+}
diff --git a/tests/auto/declarative/SecurityTest.qml b/tests/auto/declarative/SecurityTest.qml
new file mode 100644
index 0000000..2e63e17
--- /dev/null
+++ b/tests/auto/declarative/SecurityTest.qml
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtTest 1.0
+import QtOpcUa 5.13 as QtOpcUa
+
+Item {
+ property string backendName
+ property int completedTestCases: 0
+ property int availableTestCases: 0
+ property bool completed: completedTestCases == availableTestCases
+ property bool shouldRun: false
+
+ onShouldRunChanged: {
+ if (shouldRun)
+ console.log("Running", parent.testName, "with", backendName);
+ }
+
+ CompletionLoggingTestCase {
+ name: "Check supported security features"
+ when: shouldRun
+
+ QtOpcUa.Connection {
+ id: connection2
+ backend: backendName
+ }
+
+ function test_nodeTest() {
+ verify(connection2.supportedSecurityPolicies.length > 0);
+ if (backendName == "uacpp") {
+ compare(connection2.supportedSecurityPolicies.length, 6);
+ compare(connection2.supportedUserTokenTypes.length, 3);
+ } else if (backendName === "open62541") {
+ compare(connection2.supportedSecurityPolicies.length, 1);
+ compare(connection2.supportedUserTokenTypes.length, 2);
+ } else {
+ fail(backendName, "is not support by this test case");
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/SubscriptionsTest.qml b/tests/auto/declarative/SubscriptionsTest.qml
new file mode 100644
index 0000000..cad8ff5
--- /dev/null
+++ b/tests/auto/declarative/SubscriptionsTest.qml
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtTest 1.0
+import QtOpcUa 5.13 as QtOpcUa
+
+Item {
+ property string backendName
+ property int completedTestCases: 0
+ property int availableTestCases: 0
+ property bool completed: completedTestCases == availableTestCases && availableTestCases > 0
+ property bool shouldRun: false
+
+ onShouldRunChanged: {
+ if (shouldRun)
+ console.log("Running", parent.testName, "with", backendName);
+ }
+
+ QtOpcUa.Connection {
+ id: connection
+ backend: backendName
+ defaultConnection: true
+ }
+
+ QtOpcUa.ServerDiscovery {
+ id: serverDiscovery
+ onServersChanged: {
+ if (!count)
+ return;
+ endpointDiscovery.serverUrl = at(0).discoveryUrls[0];
+ }
+
+ Binding on discoveryUrl {
+ when: shouldRun && Component.completed
+ value: OPCUA_DISCOVERY_URL
+ }
+ }
+
+ QtOpcUa.EndpointDiscovery {
+ id: endpointDiscovery
+ onEndpointsChanged: {
+ if (!count)
+ return;
+ connection.connectToEndpoint(at(0));
+ }
+ }
+
+ Component.onCompleted: {
+ for (var i in children) {
+ if (children[i].objectName == "TestCase")
+ availableTestCases += 1;
+ }
+ }
+
+ CompletionLoggingTestCase {
+ name: "Create String Node Id"
+ when: node1.readyToUse && shouldRun
+
+ function test_nodeTest() {
+ tryCompare(node1, "monitored", true);
+ compare(node1.publishingInterval, 100.0);
+ node1ValueSpy.clear();
+ verify(node1.value != "foo");
+ node2.value = "foo";
+ node1ValueSpy.wait(10000);
+ compare(node1ValueSpy.count, 1);
+
+ compare(node1.monitored, true);
+ node1MonitoredSpy.clear();
+ node1.monitored = false;
+ node1MonitoredSpy.wait();
+ compare(node1MonitoredSpy.count, 1);
+ compare(node1IntervalSpy.count, 0);
+ compare(node1.monitored, false);
+
+ node1ValueSpy.clear();
+ node2.value = "bar";
+ timer.running = true;
+ timerSpy.wait();
+ compare(node1ValueSpy.count, 0);
+
+ node1MonitoredSpy.clear();
+ node1.monitored = true;
+ node1MonitoredSpy.wait();
+ compare(node1MonitoredSpy.count, 1);
+ compare(node1IntervalSpy.count, 0);
+ compare(node1.monitored, true);
+
+ // This needs to be reset to "Value" for follow up tests to succeed.
+ node2.value = "Value";
+ node1ValueSpy.wait();
+ compare(node1ValueSpy.count, 1);
+
+ node1MonitoredSpy.clear();
+ node1IntervalSpy.clear();
+ node1.publishingInterval = 200.0;
+ node1IntervalSpy.wait();
+ compare(node1MonitoredSpy.count, 0);
+ compare(node1IntervalSpy.count, 1);
+ compare(node1.publishingInterval, 200.0);
+ }
+
+ SignalSpy {
+ id: node1ValueSpy
+ target: node1
+ signalName: "valueChanged"
+ }
+
+ SignalSpy {
+ id: node1IntervalSpy
+ target: node1
+ signalName: "publishingIntervalChanged"
+ }
+
+ SignalSpy {
+ id: node1MonitoredSpy
+ target: node1
+ signalName: "monitoredChanged"
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=theStringId"
+ }
+ id: node1
+ }
+
+ QtOpcUa.ValueNode {
+ connection: connection
+ nodeId: QtOpcUa.NodeId {
+ ns: "Test Namespace"
+ identifier: "s=theStringId"
+ }
+ id: node2
+ }
+
+ Timer {
+ id: timer
+ interval: 2000
+ }
+
+ SignalSpy {
+ id: timerSpy
+ target: timer
+ signalName: "triggered"
+ }
+ }
+}
diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro
index a484ccf..cebe679 100644
--- a/tests/auto/declarative/declarative.pro
+++ b/tests/auto/declarative/declarative.pro
@@ -2,4 +2,10 @@ TEMPLATE = app
TARGET = tst_opcua
CONFIG += warn_on qmltestcase
SOURCES += tst_opcua.cpp
+HEADERS += $$PWD/../../common/backend_environment.h
+INCLUDEPATH += $$PWD/../../common
IMPORTPATH += $$PWD/../../../src/plugins/declarative
+
+# This tries to check if the server has security support
+QT += opcua_private
+qtConfig(mbedtls): DEFINES += SERVER_SUPPORTS_SECURITY
diff --git a/tests/auto/declarative/tst_absolutenode.qml b/tests/auto/declarative/tst_absolutenode.qml
index 3d2f305..0737010 100644
--- a/tests/auto/declarative/tst_absolutenode.qml
+++ b/tests/auto/declarative/tst_absolutenode.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt OPC UA module.
@@ -35,312 +35,7 @@
****************************************************************************/
import QtQuick 2.3
-import QtTest 1.0
-import QtOpcUa 5.12 as QtOpcUa
-Item {
-
- QtOpcUa.Connection {
- id: connection
- backend: connection.availableBackends[0]
- defaultConnection: true
- }
-
- Component.onCompleted: {
- connection.connectToEndpoint("opc.tcp://127.0.0.1:43344");
- }
-
- TestCase {
- name: "Create String Node Id"
- when: node1.readyToUse
-
- function test_nodeTest() {
- compare(node1.value, "Value", "");
- compare(node1.browseName, "theStringId");
- compare(node1.nodeClass, QtOpcUa.Constants.NodeClass.Variable);
- compare(node1.displayName.text, "theStringId");
- compare(node1.description.text, "Description for ns=3;s=theStringId");
- }
-
- QtOpcUa.ValueNode {
- connection: connection
- nodeId: QtOpcUa.NodeId {
- ns: "Test Namespace"
- identifier: "s=theStringId"
- }
- id: node1
- }
- }
-
- TestCase {
- name: "Create GUID Node Id"
- when: node2.readyToUse
-
- function test_nodeTest() {
- compare(node2.value, "Value", "");
- }
-
- QtOpcUa.ValueNode {
- connection: connection
- nodeId: QtOpcUa.NodeId {
- ns: "Test Namespace"
- identifier: "g=08081e75-8e5e-319b-954f-f3a7613dc29b"
- }
- id: node2
- }
- }
-
- TestCase {
- name: "Create Opaque Node Id"
- when: node3.readyToUse
-
- function test_nodeTest() {
- compare(node3.value, "Value", "");
- }
-
- QtOpcUa.ValueNode {
- connection: connection
- nodeId: QtOpcUa.NodeId {
- ns: "Test Namespace"
- identifier: "b=UXQgZnR3IQ=="
- }
- id: node3
- }
- }
-
- TestCase {
- name: "Create Integer Node Id"
- when: node4.readyToUse
-
- function test_nodeTest() {
- compare(node4.value, 255, "");
- }
-
- QtOpcUa.ValueNode {
- connection: connection
- nodeId: QtOpcUa.NodeId {
- ns: "http://opcfoundation.org/UA/"
- identifier: "i=2267"
- }
- id: node4
- }
- }
-
- TestCase {
- name: "Write Value Node with Multiple Listeners"
- when: node5.readyToUse && node6.readyToUse && node7.readyToUse
-
- function test_nodeTest() {
- var oldValue = node5.value;
- node6Spy.clear();
- node7Spy.clear();
- node5.value = oldValue + 1;
- tryCompare(node5, "value", oldValue + 1);
- tryCompare(node6, "value", oldValue + 1);
- tryCompare(node7, "value", oldValue + 1);
- wait(100);
- compare(node6Spy.count, 1);
- compare(node7Spy.count, 1);
- }
-
- QtOpcUa.ValueNode {
- connection: connection
- nodeId: QtOpcUa.NodeId {
- ns: "Test Namespace"
- identifier: "s=TestNode.ReadWrite"
- }
- id: node5
- }
-
- QtOpcUa.ValueNode {
- connection: connection
- nodeId: QtOpcUa.NodeId {
- ns: "Test Namespace"
- identifier: "s=TestNode.ReadWrite"
- }
- id: node6
- }
-
- SignalSpy {
- id: node6Spy
- target: node6
- signalName: "valueChanged"
- }
-
- QtOpcUa.ValueNode {
- connection: connection
- nodeId: QtOpcUa.NodeId {
- ns: "Test Namespace"
- identifier: "s=TestNode.ReadWrite"
- }
- id: node7
- }
-
- SignalSpy {
- id: node7Spy
- target: node7
- signalName: "valueChanged"
- }
- }
-
- TestCase {
- name: "Emitting signals on node changes"
- when: node8.readyToUse
-
- function test_changeIdentifier() {
- node8NamespaceSpy.clear();
- node8IdentifierSpy.clear();
- node8NodeIdSpy.clear();
- node8NodeChangedSpy.clear();
- node8NodeIdChangedSpy.clear();
- node8ValueSpy.clear();
- verify(node8IdentifierSpy.valid);
- node8.nodeId.identifier = "b=UXQgZnR3IQ==";
- node8ValueSpy.wait();
-
- // value has to be undefined because when node IDs are changed
- // all attributes become undefined before they get the new values.
- if (node8ValueSpy.count < 2)
- node8ValueSpy.wait();
- verify(!node8ValueSpy.signalArguments[0][0]);
- compare(node8ValueSpy.signalArguments[1][0], "Value");
-
- compare(node8IdentifierSpy.count, 1);
- compare(node8NodeIdSpy.count, 1);
- compare(node8NamespaceSpy.count, 0);
- verify(node8NodeChangedSpy.count > 0);
- compare(node8NodeIdChangedSpy.count, 1);
- compare(node8ValueSpy.count, 2); // first undefined, then the real value
- compare(node8.value, "Value");
- }
-
- QtOpcUa.ValueNode {
- connection: connection
- nodeId: QtOpcUa.NodeId {
- ns: "Test Namespace"
- identifier: "s=TestNode.ReadWrite"
- }
- id: node8
- }
-
- SignalSpy {
- id: node8NamespaceSpy
- target: node8.nodeId
- signalName: "nodeNamespaceChanged"
- }
-
- SignalSpy {
- id: node8IdentifierSpy
- target: node8.nodeId
- signalName: "identifierChanged"
- }
-
- SignalSpy {
- id: node8NodeIdSpy
- target: node8.nodeId
- signalName: "nodeChanged"
- }
-
- SignalSpy {
- id: node8NodeChangedSpy
- target: node8
- signalName: "nodeChanged"
- }
-
- SignalSpy {
- id: node8NodeIdChangedSpy
- target: node8
- signalName: "nodeIdChanged"
- }
-
- SignalSpy {
- id: node8ValueSpy
- target: node8
- signalName: "valueChanged"
- }
- }
-
- TestCase {
- name: "Node with namespace in Id"
- when: node9.readyToUse
-
- function test_nodeTest() {
- compare(node9.value, "Value", "");
- }
-
- QtOpcUa.ValueNode {
- connection: connection
- nodeId: QtOpcUa.NodeId {
- identifier: "ns=3;s=theStringId"
- }
- id: node9
- }
- }
-
- TestCase {
- name: "Standard attributes on variable node"
- when: node10.readyToUse
-
- SignalSpy {
- id: node10BrowseNameSpy
- target: node10
- signalName: "browseNameChanged"
- }
-
- SignalSpy {
- id: node10NodeClassSpy
- target: node10
- signalName: "nodeClassChanged"
- }
-
- SignalSpy {
- id: node10DisplayNameSpy
- target: node10
- signalName: "displayNameChanged"
- }
-
- SignalSpy {
- id: node10DescriptionSpy
- target: node10
- signalName: "descriptionChanged"
- }
-
- function test_nodeTest() {
- compare(node10.browseName, "FullyWritableTest");
- compare(node10.nodeClass, QtOpcUa.Constants.NodeClass.Variable);
- compare(node10.displayName.text, "FullyWritableTest");
- compare(node10.description.text, "Description for ns=3;s=Demo.Static.Scalar.FullyWritable");
-
- node10BrowseNameSpy.clear();
- node10NodeClassSpy.clear();
- node10DisplayNameSpy.clear();
- node10DescriptionSpy.clear();
-
- node10.browseName = "modifiedBrowseName";
- node10BrowseNameSpy.wait();
- compare(node10BrowseNameSpy.count, 1);
- node10.browseName = "FullyWritableTest"; // Setting back to default
-
- // node class is not supposed to be changed: skipping tests
-
- node10.displayName.text = "modifiedDisplayName";
- node10DisplayNameSpy.wait();
- compare(node10DisplayNameSpy.count, 1);
- node10.displayName.text = "FullyWritableTest"; // Setting back to default
-
- node10.description.text = "modifiedDescription";
- node10DescriptionSpy.wait();
- compare(node10DescriptionSpy.count, 1);
- node10.description.text = "Description for ns=3;s=Demo.Static.Scalar.FullyWritable"; // Setting back to default
- }
-
- QtOpcUa.ValueNode {
- connection: connection
- nodeId: QtOpcUa.NodeId {
- ns: "Test Namespace"
- identifier: "s=Demo.Static.Scalar.FullyWritable"
- }
- id: node10
- }
- }
+BackendTestMultiplier {
+ testName: "AbsoluteNodeTest"
}
diff --git a/tests/auto/declarative/tst_authorization.qml b/tests/auto/declarative/tst_authorization.qml
new file mode 100644
index 0000000..ef2aad0
--- /dev/null
+++ b/tests/auto/declarative/tst_authorization.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+
+BackendTestMultiplier {
+ testName: "AuthorizationTest"
+}
diff --git a/tests/auto/declarative/tst_batchReadWrite.qml b/tests/auto/declarative/tst_batchReadWrite.qml
new file mode 100644
index 0000000..2a0a2a8
--- /dev/null
+++ b/tests/auto/declarative/tst_batchReadWrite.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+
+BackendTestMultiplier {
+ testName: "BatchReadWriteTest"
+}
diff --git a/tests/auto/declarative/tst_dataChangeFilter.qml b/tests/auto/declarative/tst_dataChangeFilter.qml
new file mode 100644
index 0000000..9e35ff0
--- /dev/null
+++ b/tests/auto/declarative/tst_dataChangeFilter.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+
+BackendTestMultiplier {
+ testName: "DataChangeFilterTest"
+}
diff --git a/tests/auto/declarative/tst_discovery.qml b/tests/auto/declarative/tst_discovery.qml
new file mode 100644
index 0000000..7cb08f7
--- /dev/null
+++ b/tests/auto/declarative/tst_discovery.qml
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+
+BackendTestMultiplier {
+ testName: "DiscoveryTest"
+}
+
diff --git a/tests/auto/declarative/tst_generic.qml b/tests/auto/declarative/tst_generic.qml
index 52a9fdb..ad9ae82 100644
--- a/tests/auto/declarative/tst_generic.qml
+++ b/tests/auto/declarative/tst_generic.qml
@@ -36,7 +36,7 @@
import QtQuick 2.3
import QtTest 1.0
-import QtOpcUa 5.12 as QtOpcUa
+import QtOpcUa 5.13 as QtOpcUa
Item {
TestCase {
@@ -45,6 +45,13 @@ Item {
function test_enumExports() {
compare(QtOpcUa.Constants.NodeClass.Method, 4);
compare(QtOpcUa.Constants.NodeAttribute.DisplayName, 8);
+ compare(QtOpcUa.Node.Status.Valid, 0);
+ compare(QtOpcUa.Status.Good, 0);
+ compare(QtOpcUa.Status.BadUnexpectedError, 0x8001);
+ compare(QtOpcUa.Constants.Double, 3);
+ compare(QtOpcUa.Constants.Certificate, 2);
+ compare(QtOpcUa.DataChangeFilter.DeadbandType.Absolute, 1);
+ compare(QtOpcUa.DataChangeFilter.DataChangeTrigger.StatusOrValueOrTimestamp, 2);
// Test return value of undefined node
compare(node1.nodeClass, QtOpcUa.Constants.NodeClass.Undefined);
diff --git a/tests/auto/declarative/tst_methodnode.qml b/tests/auto/declarative/tst_methodnode.qml
index 6b7fda3..e35d4ab 100644
--- a/tests/auto/declarative/tst_methodnode.qml
+++ b/tests/auto/declarative/tst_methodnode.qml
@@ -35,85 +35,8 @@
****************************************************************************/
import QtQuick 2.3
-import QtTest 1.0
-import QtOpcUa 5.12 as QtOpcUa
-Item {
-
- QtOpcUa.Connection {
- id: connection
- backend: connection.availableBackends[0]
- defaultConnection: true
- }
-
- Component.onCompleted: {
- connection.connectToEndpoint("opc.tcp://127.0.0.1:43344");
- }
-
- TestCase {
- name: "Standard attributes on method node"
- when: node1.readyToUse
-
- SignalSpy {
- id: node1BrowseNameSpy
- target: node1
- signalName: "browseNameChanged"
- }
-
- SignalSpy {
- id: node1NodeClassSpy
- target: node1
- signalName: "nodeClassChanged"
- }
-
- SignalSpy {
- id: node1DisplayNameSpy
- target: node1
- signalName: "displayNameChanged"
- }
-
- SignalSpy {
- id: node1DescriptionSpy
- target: node1
- signalName: "descriptionChanged"
- }
-
- SignalSpy {
- id: node1ObjectNodeIdSpy
- target: node1
- signalName: "objectNodeIdChanged"
- }
-
- function test_nodeTest() {
- compare(node1.browseName, "multiplyArguments");
- compare(node1.nodeClass, QtOpcUa.Constants.NodeClass.Method);
- compare(node1.displayName.text, "ns=3;s=Test.Method.Multiply");
- compare(node1.description.text, "MultiplyDoubles");
- compare(node1.objectNodeId.ns, "Test Namespace");
- compare(node1.objectNodeId.identifier, "s=TestFolder");
-
- compare(node1BrowseNameSpy.count, 1)
- compare(node1NodeClassSpy.count, 1)
- compare(node1DisplayNameSpy.count, 1)
- compare(node1DescriptionSpy.count, 1)
- compare(node1ObjectNodeIdSpy.count, 0)
-
- node1.objectNodeId.identifier = "s=foo";
- node1ObjectNodeIdSpy.wait()
- compare(node1ObjectNodeIdSpy.count, 1);
- }
-
- QtOpcUa.MethodNode {
- connection: connection
- nodeId: QtOpcUa.NodeId {
- ns: "Test Namespace"
- identifier: "s=Test.Method.Multiply"
- }
- objectNodeId: QtOpcUa.NodeId {
- ns: "Test Namespace"
- identifier: "s=TestFolder"
- }
- id: node1
- }
- }
+BackendTestMultiplier {
+ testName: "MethodnodeTest"
}
+
diff --git a/tests/auto/declarative/tst_monitoringFilterTest.qml b/tests/auto/declarative/tst_monitoringFilterTest.qml
new file mode 100644
index 0000000..1adfc74
--- /dev/null
+++ b/tests/auto/declarative/tst_monitoringFilterTest.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+
+BackendTestMultiplier {
+ testName: "MonitoringFilterTest"
+}
diff --git a/tests/auto/declarative/tst_opcua.cpp b/tests/auto/declarative/tst_opcua.cpp
index 2807a3f..2fc387d 100644
--- a/tests/auto/declarative/tst_opcua.cpp
+++ b/tests/auto/declarative/tst_opcua.cpp
@@ -34,14 +34,15 @@
**
****************************************************************************/
+#include "backend_environment.h"
#include <QtQuickTest/quicktest.h>
#include <QObject>
#include <QProcess>
+#include <QQmlContext>
+#include <QQmlEngine>
#include <QTcpServer>
#include <QTcpSocket>
-class QQmlEngine;
-
static QString envOrDefault(const char *env, QString def)
{
return qEnvironmentVariableIsSet(env) ? qgetenv(env).constData() : def;
@@ -58,6 +59,7 @@ public:
public slots:
void applicationAvailable() {
+ updateEnvironment();
const quint16 defaultPort = 43344;
const QHostAddress defaultHost(QHostAddress::LocalHost);
@@ -99,18 +101,23 @@ public slots:
server.close();
qDebug() << "Starting test server";
- m_serverProcess.setProcessChannelMode(QProcess::ForwardedChannels);
+ //m_serverProcess.setProcessChannelMode(QProcess::ForwardedChannels);
m_serverProcess.start(m_testServerPath);
QVERIFY2(m_serverProcess.waitForStarted(), qPrintable(m_serverProcess.errorString()));
// Let the server come up
QTest::qSleep(2000);
}
- QString host = envOrDefault("OPCUA_HOST", defaultHost.toString());
- QString port = envOrDefault("OPCUA_PORT", QString::number(defaultPort));
+ const QString host = envOrDefault("OPCUA_HOST", defaultHost.toString());
+ const QString port = envOrDefault("OPCUA_PORT", QString::number(defaultPort));
+ m_opcuaDiscoveryUrl = QString::fromLatin1("opc.tcp://%1:%2").arg(host).arg(port);
}
void qmlEngineAvailable(QQmlEngine *engine) {
- Q_UNUSED(engine);
- // nothing
+ bool value = false;
+#ifdef SERVER_SUPPORTS_SECURITY
+ value = true;
+#endif
+ engine->rootContext()->setContextProperty("SERVER_SUPPORTS_SECURITY", value);
+ engine->rootContext()->setContextProperty("OPCUA_DISCOVERY_URL", m_opcuaDiscoveryUrl);
}
void cleanupTestCase() {
if (m_serverProcess.state() == QProcess::Running) {
@@ -121,6 +128,7 @@ public slots:
private:
QProcess m_serverProcess;
QString m_testServerPath;
+ QString m_opcuaDiscoveryUrl;
};
QUICK_TEST_MAIN_WITH_SETUP(opcua, SetupClass)
diff --git a/tests/auto/declarative/tst_relativenode.qml b/tests/auto/declarative/tst_relativenode.qml
index 0aa0759..c82f36c 100644
--- a/tests/auto/declarative/tst_relativenode.qml
+++ b/tests/auto/declarative/tst_relativenode.qml
@@ -35,265 +35,7 @@
****************************************************************************/
import QtQuick 2.3
-import QtTest 1.0
-import QtOpcUa 5.12 as QtOpcUa
-Item {
-
- QtOpcUa.Connection {
- id: connection
- backend: "open62541"
- defaultConnection: true
- }
-
- Component.onCompleted: {
- connection.connectToEndpoint("opc.tcp://127.0.0.1:43344");
- }
-
- TestCase {
- name: "RelativeNodePath"
- when: node1.readyToUse
-
- function test_nodeRead() {
- tryVerify(function() { return node1.value > 0 });
- }
-
- QtOpcUa.ValueNode {
- connection: connection
- nodeId: QtOpcUa.RelativeNodeId {
- startNode: QtOpcUa.NodeId {
- ns: "Test Namespace"
- identifier: "s=TestFolder"
- }
- path: [ QtOpcUa.RelativeNodePath {
- ns: "Test Namespace"
- browseName: "TestNode.ReadWrite"
- }
- ]
- }
- id: node1
- }
- }
-
- TestCase {
- name: "CascadedRelativeNodePath"
- when: node2.readyToUse
-
- function test_nodeRead() {
- tryVerify(function() { return node2.value > 0 });
- }
-
- QtOpcUa.RelativeNodeId {
- startNode: QtOpcUa.NodeId {
- ns: "http://opcfoundation.org/UA/"
- identifier: "i=85"
- }
- path: [ QtOpcUa.RelativeNodePath {
- ns: "Test Namespace"
- browseName: "TestFolder"
- }
- ]
- id: secondLevelNode
- }
-
-
- QtOpcUa.ValueNode {
- connection: connection
- nodeId: QtOpcUa.RelativeNodeId {
- startNode: secondLevelNode
- path: [ QtOpcUa.RelativeNodePath {
- ns: "Test Namespace"
- browseName: "TestNode.ReadWrite"
- }
- ]
- }
- id: node2
- }
- }
-
- TestCase {
- name: "Emitting signals on node changes"
- when: node3.readyToUse
-
- function test_changeStartNode() {
- node3NamespaceSpy.clear();
- node3NodeIdSpy.clear();
- node3NodeChangedSpy.clear();
- node3NodeIdChangedSpy.clear();
- node3ValueSpy.clear();
- node3PathSpy.clear();
- node3.nodeId.startNode.identifier = "s=TestFolder2";
- node3ValueSpy.wait();
-
- // value has to be undefined because when node IDs are changed
- // all attributes become undefined before they get the new values.
- if (node3ValueSpy.count < 2)
- node3ValueSpy.wait();
- verify(!node3ValueSpy.signalArguments[0][0]);
- compare(node3ValueSpy.signalArguments[1][0], 0.1);
-
- compare(node3NodeIdSpy.count, 1);
- compare(node3NamespaceSpy.count, 0);
- verify(node3NodeChangedSpy.count > 0);
- compare(node3PathSpy.count, 0);
- compare(node3NodeIdChangedSpy.count, 1);
- compare(node3ValueSpy.count, 2); // first undefined, then the real value
- compare(node3.value, 0.1);
- }
-
- QtOpcUa.ValueNode {
- connection: connection
- nodeId: QtOpcUa.RelativeNodeId {
- startNode: QtOpcUa.NodeId {
- ns: "Test Namespace"
- identifier: "s=TestFolder"
- }
- path: [ QtOpcUa.RelativeNodePath {
- ns: "Test Namespace"
- browseName: "TestNode.ReadWrite"
- }
- ]
- }
- id: node3
- }
-
- SignalSpy {
- id: node3NamespaceSpy
- target: node3.nodeId
- signalName: "nodeNamespaceChanged"
- }
-
- SignalSpy {
- id: node3NodeIdSpy
- target: node3.nodeId
- signalName: "nodeChanged"
- }
-
- SignalSpy {
- id: node3NodeChangedSpy
- target: node3
- signalName: "nodeChanged"
- }
-
- SignalSpy {
- id: node3NodeIdChangedSpy
- target: node3
- signalName: "nodeIdChanged"
- }
-
- SignalSpy {
- id: node3ValueSpy
- target: node3
- signalName: "valueChanged"
- }
-
- SignalSpy {
- id: node3PathSpy
- target: node3.nodeId
- signalName: "pathChanged"
- }
- }
-
- TestCase {
- name: "Emitting signals on cascaded node changes"
- when: node4.readyToUse
-
- function test_nodeRead() {
- node4NamespaceSpy.clear();
- node4NodeIdSpy.clear();
- node4NodeChangedSpy.clear();
- node4NodeIdChangedSpy.clear();
- node4ValueSpy.clear();
- node4PathSpy.clear();
- node4.nodeId.startNode.path = replacementNode.createObject(parent);
- node4NodeChangedSpy.wait();
- node4ValueSpy.wait();
-
- // value has to be undefined because when node IDs are changed
- // all attributes become undefined before they get the new values.
- if (node4ValueSpy.count < 2)
- node4ValueSpy.wait();
- verify(!node4ValueSpy.signalArguments[0][0]);
- compare(node4ValueSpy.signalArguments[1][0], 0.1);
-
- compare(node4NodeIdSpy.count, 2);
- compare(node4NamespaceSpy.count, 0);
- verify(node4NodeChangedSpy.count > 0);
- compare(node4NodeIdChangedSpy.count, 1);
- compare(node4ValueSpy.count, 2); // first undefined, then the real value
- compare(node4.value, 0.1);
- compare(node4PathSpy.count, 2);
- }
-
- QtOpcUa.RelativeNodeId {
- startNode: QtOpcUa.NodeId {
- ns: "http://opcfoundation.org/UA/"
- identifier: "i=85"
- }
- path: [ QtOpcUa.RelativeNodePath {
- ns: "Test Namespace"
- browseName: "TestFolder"
- }
- ]
- id: secondLevelNode2
- }
-
-
- QtOpcUa.ValueNode {
- connection: connection
- nodeId: QtOpcUa.RelativeNodeId {
- startNode: secondLevelNode2
- path: [ QtOpcUa.RelativeNodePath {
- ns: "Test Namespace"
- browseName: "TestNode.ReadWrite"
- }
- ]
- }
- id: node4
- }
-
- Component {
- id: replacementNode
- QtOpcUa.RelativeNodePath {
- ns: "Test Namespace";
- browseName: "TestFolder2";
- }
- }
-
- SignalSpy {
- id: node4NamespaceSpy
- target: node4.nodeId
- signalName: "nodeNamespaceChanged"
- }
-
- SignalSpy {
- id: node4NodeIdSpy
- target: node4.nodeId
- signalName: "nodeChanged"
- }
-
- SignalSpy {
- id: node4NodeChangedSpy
- target: node4
- signalName: "nodeChanged"
- }
-
- SignalSpy {
- id: node4NodeIdChangedSpy
- target: node4
- signalName: "nodeIdChanged"
- }
-
- SignalSpy {
- id: node4ValueSpy
- target: node4
- signalName: "valueChanged"
- }
-
- SignalSpy {
- id: node4PathSpy
- target: node4.nodeId.startNode
- signalName: "pathChanged"
- }
- }
+BackendTestMultiplier {
+ testName: "RelativenodeTest"
}
diff --git a/tests/auto/declarative/tst_security.qml b/tests/auto/declarative/tst_security.qml
new file mode 100644
index 0000000..3b1ecd6
--- /dev/null
+++ b/tests/auto/declarative/tst_security.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+
+BackendTestMultiplier {
+ testName: "SecurityTest"
+}
diff --git a/tests/auto/declarative/tst_subscriptions.qml b/tests/auto/declarative/tst_subscriptions.qml
new file mode 100644
index 0000000..44a3b95
--- /dev/null
+++ b/tests/auto/declarative/tst_subscriptions.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+
+BackendTestMultiplier {
+ testName: "SubscriptionsTest"
+}
diff --git a/tests/auto/qopcuaclient/data.qrc b/tests/auto/qopcuaclient/data.qrc
new file mode 100644
index 0000000..eba56cb
--- /dev/null
+++ b/tests/auto/qopcuaclient/data.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>../../open62541-testserver/pki/own/certs/open62541-testserver.der</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/qopcuaclient/qopcuaclient.pro b/tests/auto/qopcuaclient/qopcuaclient.pro
index bae9550..62c50c7 100644
--- a/tests/auto/qopcuaclient/qopcuaclient.pro
+++ b/tests/auto/qopcuaclient/qopcuaclient.pro
@@ -1,7 +1,20 @@
TARGET = tst_qopcuaclient
-QT += testlib opcua network
+QT += testlib opcua
+QT -= gui
CONFIG += testcase
SOURCES += \
tst_client.cpp
+
+HEADERS += \
+ $$PWD/../../common/backend_environment.h
+
+INCLUDEPATH += \
+ $$PWD/../../common
+
+RESOURCES += data.qrc
+
+# This tries to check if the server supports security
+QT += opcua_private
+qtConfig(mbedtls): DEFINES += SERVER_SUPPORTS_SECURITY
diff --git a/tests/auto/qopcuaclient/tst_client.cpp b/tests/auto/qopcuaclient/tst_client.cpp
index 4dbaa15..c80d3c6 100644
--- a/tests/auto/qopcuaclient/tst_client.cpp
+++ b/tests/auto/qopcuaclient/tst_client.cpp
@@ -34,10 +34,14 @@
**
****************************************************************************/
+#include "backend_environment.h"
+
+#include <QtOpcUa/QOpcUaAuthenticationInformation>
#include <QtOpcUa/QOpcUaClient>
#include <QtOpcUa/QOpcUaNode>
#include <QtOpcUa/QOpcUaProvider>
#include <QtOpcUa/qopcuabinarydataencoding.h>
+#include <QtOpcUa/qopcuamultidimensionalarray.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QProcess>
@@ -51,10 +55,12 @@
#include <QTcpServer>
#include <QVariantMap>
+const int signalSpyTimeout = 10000;
+
class OpcuaConnector
{
public:
- OpcuaConnector(QOpcUaClient *client, const QString &endPoint)
+ OpcuaConnector(QOpcUaClient *client, const QOpcUaEndpointDescription &endPoint)
: opcuaClient(client)
{
QVERIFY(opcuaClient != nullptr);
@@ -63,7 +69,8 @@ public:
QSignalSpy stateSpy(opcuaClient, &QOpcUaClient::stateChanged);
QTest::qWait(500);
- opcuaClient->connectToEndpoint(QUrl(endPoint));
+
+ opcuaClient->connectToEndpoint(endPoint);
QTRY_VERIFY2(opcuaClient->state() == QOpcUaClient::Connected, "Could not connect to server");
QCOMPARE(connectedSpy.count(), 1); // one connected signal fired
@@ -79,7 +86,7 @@ public:
connectedSpy.clear();
disconnectedSpy.clear();
- QVERIFY(opcuaClient->url() == QUrl(endPoint));
+ QVERIFY(opcuaClient->endpoint() == endPoint);
}
~OpcuaConnector()
@@ -117,42 +124,42 @@ const QVector<QString> xmlElements = {
QStringLiteral("<?xml version=\"1\" encoding=\"UTF-8\"?>"),
QStringLiteral("<?xml version=\"2\" encoding=\"UTF-8\"?>"),
QStringLiteral("<?xml version=\"3\" encoding=\"UTF-8\"?>")};
-const QVector<QOpcUa::QLocalizedText> localizedTexts = {
- QOpcUa::QLocalizedText("en", "English"),
- QOpcUa::QLocalizedText("de", "German"),
- QOpcUa::QLocalizedText("fr", "French")};
-const QVector<QOpcUa::QRange> testRanges = {
- QOpcUa::QRange(-100, 100),
- QOpcUa::QRange(0, 100),
- QOpcUa::QRange(-200, -100)
+const QVector<QOpcUaLocalizedText> localizedTexts = {
+ QOpcUaLocalizedText("en", "English"),
+ QOpcUaLocalizedText("de", "German"),
+ QOpcUaLocalizedText("fr", "French")};
+const QVector<QOpcUaRange> testRanges = {
+ QOpcUaRange(-100, 100),
+ QOpcUaRange(0, 100),
+ QOpcUaRange(-200, -100)
};
-const QVector<QOpcUa::QEUInformation> testEUInfos = {
- QOpcUa::QEUInformation(QLatin1String("http://www.opcfoundation.org/UA/units/un/cefact"),
- 4408652, QOpcUa::QLocalizedText(QString(), QStringLiteral("°C")), QOpcUa::QLocalizedText(QString(), QLatin1String("degree Celsius"))),
- QOpcUa::QEUInformation(QLatin1String("http://www.opcfoundation.org/UA/units/un/cefact"),
- 4604232, QOpcUa::QLocalizedText(QString(), QStringLiteral("°F")), QOpcUa::QLocalizedText(QString(), QLatin1String("degree Fahrenheit"))),
- QOpcUa::QEUInformation(QLatin1String("http://www.opcfoundation.org/UA/units/un/cefact"),
- 5067858, QOpcUa::QLocalizedText(QString(), QLatin1String("m")), QOpcUa::QLocalizedText(QString(), QLatin1String("metre"))),
+const QVector<QOpcUaEUInformation> testEUInfos = {
+ QOpcUaEUInformation(QLatin1String("http://www.opcfoundation.org/UA/units/un/cefact"),
+ 4408652, QOpcUaLocalizedText(QString(), QStringLiteral("°C")), QOpcUaLocalizedText(QString(), QLatin1String("degree Celsius"))),
+ QOpcUaEUInformation(QLatin1String("http://www.opcfoundation.org/UA/units/un/cefact"),
+ 4604232, QOpcUaLocalizedText(QString(), QStringLiteral("°F")), QOpcUaLocalizedText(QString(), QLatin1String("degree Fahrenheit"))),
+ QOpcUaEUInformation(QLatin1String("http://www.opcfoundation.org/UA/units/un/cefact"),
+ 5067858, QOpcUaLocalizedText(QString(), QLatin1String("m")), QOpcUaLocalizedText(QString(), QLatin1String("metre"))),
};
-const QVector<QOpcUa::QComplexNumber> testComplex = {
- QOpcUa::QComplexNumber(1,2),
- QOpcUa::QComplexNumber(-1,2),
- QOpcUa::QComplexNumber(1,-2)
+const QVector<QOpcUaComplexNumber> testComplex = {
+ QOpcUaComplexNumber(1,2),
+ QOpcUaComplexNumber(-1,2),
+ QOpcUaComplexNumber(1,-2)
};
-const QVector<QOpcUa::QDoubleComplexNumber> testDoubleComplex = {
- QOpcUa::QDoubleComplexNumber(1,2),
- QOpcUa::QDoubleComplexNumber(-1,2),
- QOpcUa::QDoubleComplexNumber(1,-2)
+const QVector<QOpcUaDoubleComplexNumber> testDoubleComplex = {
+ QOpcUaDoubleComplexNumber(1,2),
+ QOpcUaDoubleComplexNumber(-1,2),
+ QOpcUaDoubleComplexNumber(1,-2)
};
-const QVector<QOpcUa::QAxisInformation> testAxisInfo = {
- QOpcUa::QAxisInformation(testEUInfos[0], testRanges[0], localizedTexts[0], QOpcUa::AxisScale::Linear, QVector<double>({1, 2, 3})),
- QOpcUa::QAxisInformation(testEUInfos[1], testRanges[1], localizedTexts[1], QOpcUa::AxisScale::Ln, QVector<double>({4, 5, 6})),
- QOpcUa::QAxisInformation(testEUInfos[2], testRanges[2], localizedTexts[2], QOpcUa::AxisScale::Log, QVector<double>({7, 8, 9}))
+const QVector<QOpcUaAxisInformation> testAxisInfo = {
+ QOpcUaAxisInformation(testEUInfos[0], testRanges[0], localizedTexts[0], QOpcUa::AxisScale::Linear, QVector<double>({1, 2, 3})),
+ QOpcUaAxisInformation(testEUInfos[1], testRanges[1], localizedTexts[1], QOpcUa::AxisScale::Ln, QVector<double>({4, 5, 6})),
+ QOpcUaAxisInformation(testEUInfos[2], testRanges[2], localizedTexts[2], QOpcUa::AxisScale::Log, QVector<double>({7, 8, 9}))
};
-const QVector<QOpcUa::QXValue> testXV = {
- QOpcUa::QXValue(0, 100),
- QOpcUa::QXValue(-10, 100.5),
- QOpcUa::QXValue(10, -100.5)
+const QVector<QOpcUaXValue> testXV = {
+ QOpcUaXValue(0, 100),
+ QOpcUaXValue(-10, 100.5),
+ QOpcUaXValue(10, -100.5)
};
const QVector<QUuid> testUuid = {
QUuid("e0bd5ccd-f571-4545-9352-61a0f8cb9216"),
@@ -174,29 +181,29 @@ const QVector<QOpcUa::UaStatusCode> testStatusCode = {
QOpcUa::UaStatusCode::BadInvalidArgument,
QOpcUa::UaStatusCode::BadNodeIdUnknown
};
-const QVector<QOpcUa::QExpandedNodeId> testExpandedId = {
- QOpcUa::QExpandedNodeId(QString(), QLatin1String("ns=1;i=23")),
- QOpcUa::QExpandedNodeId(QLatin1String("MyNamespace"), QLatin1String("ns=2;s=MyNode")),
- QOpcUa::QExpandedNodeId(QLatin1String("RemoteNamespace"), QLatin1String("ns=3;b=UXQgZnR3IQ=="), 1)
+const QVector<QOpcUaExpandedNodeId> testExpandedId = {
+ QOpcUaExpandedNodeId(QString(), QLatin1String("ns=1;i=23")),
+ QOpcUaExpandedNodeId(QLatin1String("MyNamespace"), QLatin1String("ns=2;s=MyNode")),
+ QOpcUaExpandedNodeId(QLatin1String("RemoteNamespace"), QLatin1String("ns=3;b=UXQgZnR3IQ=="), 1)
};
-const QVector<QOpcUa::QExpandedNodeId> testExpandedNodeId = {
- QOpcUa::QExpandedNodeId(QStringLiteral("namespace1"), QStringLiteral("ns=0;i=99"), 1),
- QOpcUa::QExpandedNodeId(QString(), QStringLiteral("ns=1;i=99")),
- QOpcUa::QExpandedNodeId(QString(), QStringLiteral("ns=1;s=test"))
+const QVector<QOpcUaExpandedNodeId> testExpandedNodeId = {
+ QOpcUaExpandedNodeId(QStringLiteral("namespace1"), QStringLiteral("ns=0;i=99"), 1),
+ QOpcUaExpandedNodeId(QString(), QStringLiteral("ns=1;i=99")),
+ QOpcUaExpandedNodeId(QString(), QStringLiteral("ns=1;s=test"))
};
-const QVector<QOpcUa::QArgument> testArguments = {
- QOpcUa::QArgument(QStringLiteral("Argument1"), QStringLiteral("ns=0;i=12"), -1,
- {},QOpcUa::QLocalizedText(QStringLiteral("en"), QStringLiteral("Description1"))),
- QOpcUa::QArgument(QStringLiteral("Argument2"), QStringLiteral("ns=0;i=12"), 2,
- {2, 2}, QOpcUa::QLocalizedText(QStringLiteral("en"), QStringLiteral("Description2"))),
- QOpcUa::QArgument(QStringLiteral("Argument3"), QStringLiteral("ns=0;i=12"), 3,
- {3, 3, 3}, QOpcUa::QLocalizedText(QStringLiteral("en"), QStringLiteral("Description3")))
+const QVector<QOpcUaArgument> testArguments = {
+ QOpcUaArgument(QStringLiteral("Argument1"), QStringLiteral("ns=0;i=12"), -1,
+ {},QOpcUaLocalizedText(QStringLiteral("en"), QStringLiteral("Description1"))),
+ QOpcUaArgument(QStringLiteral("Argument2"), QStringLiteral("ns=0;i=12"), 2,
+ {2, 2}, QOpcUaLocalizedText(QStringLiteral("en"), QStringLiteral("Description2"))),
+ QOpcUaArgument(QStringLiteral("Argument3"), QStringLiteral("ns=0;i=12"), 3,
+ {3, 3, 3}, QOpcUaLocalizedText(QStringLiteral("en"), QStringLiteral("Description3")))
};
#define ENCODE_EXTENSION_OBJECT(obj, index) \
{ \
QVERIFY(index < 3); \
- obj.setEncoding(QOpcUa::QExtensionObject::Encoding::ByteString); \
+ obj.setEncoding(QOpcUaExtensionObject::Encoding::ByteString); \
obj.setEncodingTypeId(QStringLiteral("ns=2;s=MyEncoding%1").arg(index)); \
QOpcUaBinaryDataEncoding encoder(obj); \
encoder.encode<quint8>(quint8(index)); \
@@ -211,32 +218,32 @@ const QVector<QOpcUa::QArgument> testArguments = {
encoder.encode<double>(double(index)); \
encoder.encode<bool>(bool(index)); \
encoder.encode<QString>(QStringLiteral("String %1").arg(index)); \
- encoder.encode<QOpcUa::QQualifiedName>(QOpcUa::QQualifiedName(2, QStringLiteral("QualifiedName %1").arg(index))); \
- encoder.encode<QOpcUa::QLocalizedText>(localizedTexts.at(index)); \
- encoder.encode<QOpcUa::QRange>(testRanges.at(index)); \
- encoder.encode<QOpcUa::QEUInformation>(testEUInfos.at(index)); \
- encoder.encode<QOpcUa::QComplexNumber>(testComplex.at(index)); \
- encoder.encode<QOpcUa::QDoubleComplexNumber>(testDoubleComplex.at(index)); \
- encoder.encode<QOpcUa::QAxisInformation>(testAxisInfo.at(index)); \
- encoder.encode<QOpcUa::QXValue>(testXV.at(index)); \
+ encoder.encode<QOpcUaQualifiedName>(QOpcUaQualifiedName(2, QStringLiteral("QualifiedName %1").arg(index))); \
+ encoder.encode<QOpcUaLocalizedText>(localizedTexts.at(index)); \
+ encoder.encode<QOpcUaRange>(testRanges.at(index)); \
+ encoder.encode<QOpcUaEUInformation>(testEUInfos.at(index)); \
+ encoder.encode<QOpcUaComplexNumber>(testComplex.at(index)); \
+ encoder.encode<QOpcUaDoubleComplexNumber>(testDoubleComplex.at(index)); \
+ encoder.encode<QOpcUaAxisInformation>(testAxisInfo.at(index)); \
+ encoder.encode<QOpcUaXValue>(testXV.at(index)); \
encoder.encode<QUuid>(testUuid.at(index)); \
encoder.encode<QString, QOpcUa::Types::NodeId>(testNodeId.at(index)); \
encoder.encode<QDateTime>(testDateTime.at(index)); \
encoder.encode<QOpcUa::UaStatusCode>(testStatusCode.at(index)); \
- encoder.encode<QOpcUa::QExpandedNodeId>(testExpandedId.at(index)); \
- QOpcUa::QExtensionObject ext; \
+ encoder.encode<QOpcUaExpandedNodeId>(testExpandedId.at(index)); \
+ QOpcUaExtensionObject ext; \
ext.setEncodingTypeId(obj.encodingTypeId()); \
ext.setEncoding(obj.encoding()); \
QOpcUaBinaryDataEncoding encoding2(&ext.encodedBodyRef()); \
encoding2.encode<QString>(QStringLiteral("String %1").arg(index)); \
- encoder.encode<QOpcUa::QExtensionObject>(ext); \
- encoder.encode<QOpcUa::QArgument>(testArguments.at(index)); \
+ encoder.encode<QOpcUaExtensionObject>(ext); \
+ encoder.encode<QOpcUaArgument>(testArguments.at(index)); \
}
#define VERIFY_EXTENSION_OBJECT(obj, index) \
{ \
QVERIFY(index < 3); \
- QCOMPARE(obj.encoding(), QOpcUa::QExtensionObject::Encoding::ByteString); \
+ QCOMPARE(obj.encoding(), QOpcUaExtensionObject::Encoding::ByteString); \
QCOMPARE(obj.encodingTypeId(), QStringLiteral("ns=2;s=MyEncoding%1").arg(index)); \
bool success = false; \
QOpcUaBinaryDataEncoding decoder(obj); \
@@ -265,22 +272,22 @@ const QVector<QOpcUa::QArgument> testArguments = {
QVERIFY(success == true); \
QCOMPARE(decoder.decode<QString>(success), QStringLiteral("String %1").arg(index)); \
QVERIFY(success == true); \
- QCOMPARE(decoder.decode<QOpcUa::QQualifiedName>(success), \
- QOpcUa::QQualifiedName(2, QStringLiteral("QualifiedName %1").arg(index))); \
+ QCOMPARE(decoder.decode<QOpcUaQualifiedName>(success), \
+ QOpcUaQualifiedName(2, QStringLiteral("QualifiedName %1").arg(index))); \
QVERIFY(success == true); \
- QCOMPARE(decoder.decode<QOpcUa::QLocalizedText>(success), localizedTexts.at(index)); \
+ QCOMPARE(decoder.decode<QOpcUaLocalizedText>(success), localizedTexts.at(index)); \
QVERIFY(success == true); \
- QCOMPARE(decoder.decode<QOpcUa::QRange>(success), testRanges.at(index)); \
+ QCOMPARE(decoder.decode<QOpcUaRange>(success), testRanges.at(index)); \
QVERIFY(success == true); \
- QCOMPARE(decoder.decode<QOpcUa::QEUInformation>(success), testEUInfos.at(index)); \
+ QCOMPARE(decoder.decode<QOpcUaEUInformation>(success), testEUInfos.at(index)); \
QVERIFY(success == true); \
- QCOMPARE(decoder.decode<QOpcUa::QComplexNumber>(success), testComplex.at(index)); \
+ QCOMPARE(decoder.decode<QOpcUaComplexNumber>(success), testComplex.at(index)); \
QVERIFY(success == true); \
- QCOMPARE(decoder.decode<QOpcUa::QDoubleComplexNumber>(success), testDoubleComplex.at(index)); \
+ QCOMPARE(decoder.decode<QOpcUaDoubleComplexNumber>(success), testDoubleComplex.at(index)); \
QVERIFY(success == true); \
- QCOMPARE(decoder.decode<QOpcUa::QAxisInformation>(success), testAxisInfo.at(index)); \
+ QCOMPARE(decoder.decode<QOpcUaAxisInformation>(success), testAxisInfo.at(index)); \
QVERIFY(success == true); \
- QCOMPARE(decoder.decode<QOpcUa::QXValue>(success), testXV.at(index)); \
+ QCOMPARE(decoder.decode<QOpcUaXValue>(success), testXV.at(index)); \
QVERIFY(success == true); \
QCOMPARE(decoder.decode<QUuid>(success), testUuid.at(index)); \
QVERIFY(success == true); \
@@ -295,16 +302,16 @@ const QVector<QOpcUa::QArgument> testArguments = {
QVERIFY(success == true); \
QCOMPARE(decoder.decode<QOpcUa::UaStatusCode>(success), testStatusCode.at(index)); \
QVERIFY(success == true); \
- QCOMPARE(decoder.decode<QOpcUa::QExpandedNodeId>(success), testExpandedId.at(index)); \
+ QCOMPARE(decoder.decode<QOpcUaExpandedNodeId>(success), testExpandedId.at(index)); \
QVERIFY(success == true); \
- QOpcUa::QExtensionObject ext = decoder.decode<QOpcUa::QExtensionObject>(success); \
+ QOpcUaExtensionObject ext = decoder.decode<QOpcUaExtensionObject>(success); \
QCOMPARE(ext.encodingTypeId(), obj.encodingTypeId()); \
QCOMPARE(ext.encoding(), obj.encoding()); \
QVERIFY(success == true); \
QOpcUaBinaryDataEncoding decoder2(&ext.encodedBodyRef()); \
QCOMPARE(decoder2.decode<QString>(success), QStringLiteral("String %1").arg(index)); \
QVERIFY(success == true); \
- QCOMPARE(decoder.decode<QOpcUa::QArgument>(success), testArguments.at(index)); \
+ QCOMPARE(decoder.decode<QOpcUaArgument>(success), testArguments.at(index)); \
QVERIFY(success == true); \
QCOMPARE(decoder.offset(), obj.encodedBody().size()); \
}
@@ -361,10 +368,10 @@ private slots:
void writeMultipleAttributes();
defineDataMethod(readEmptyArrayVariable_data)
void readEmptyArrayVariable();
- defineDataMethod(batchWrite_data)
- void batchWrite();
- defineDataMethod(batchRead_data)
- void batchRead();
+ defineDataMethod(writeNodeAttributes_data)
+ void writeNodeAttributes();
+ defineDataMethod(readNodeAttributes_data)
+ void readNodeAttributes();
defineDataMethod(getRootNode_data)
void getRootNode();
@@ -469,6 +476,8 @@ private slots:
defineDataMethod(resolveBrowsePath_data)
void resolveBrowsePath();
+ void statusStrings();
+
// This test case restarts the server. It must be run last to avoid
// destroying state required by other test cases.
defineDataMethod(connectionLost_data)
@@ -480,19 +489,20 @@ private:
return qEnvironmentVariableIsSet(env) ? qgetenv(env).constData() : def;
}
- QString m_endpoint;
+ QString m_discoveryEndpoint;
QOpcUaProvider m_opcUa;
QStringList m_backends;
QVector<QOpcUaClient *> m_clients;
QProcess m_serverProcess;
QString m_testServerPath;
+ QOpcUaEndpointDescription m_endpoint;
};
#define READ_MANDATORY_BASE_NODE(NODE) \
{ \
QSignalSpy attributeReadSpy(NODE.data(), &QOpcUaNode::attributeRead);\
NODE->readAttributes(QOpcUaNode::mandatoryBaseAttributes()); \
- attributeReadSpy.wait(); \
+ attributeReadSpy.wait(signalSpyTimeout); \
QCOMPARE(attributeReadSpy.count(), 1); \
QCOMPARE(attributeReadSpy.at(0).at(0).value<QOpcUa::NodeAttributes>(), QOpcUaNode::mandatoryBaseAttributes()); \
QVERIFY(QOpcUa::isSuccessStatus(NODE->attributeError(QOpcUa::NodeAttribute::NodeId)) == true); \
@@ -505,7 +515,7 @@ private:
{ \
QSignalSpy attributeReadSpy(NODE.data(), &QOpcUaNode::attributeRead);\
NODE->readAttributes(QOpcUaNode::mandatoryBaseAttributes() | QOpcUa::NodeAttribute::Value); \
- attributeReadSpy.wait(); \
+ attributeReadSpy.wait(signalSpyTimeout); \
QCOMPARE(attributeReadSpy.count(), 1); \
QCOMPARE(attributeReadSpy.at(0).at(0).value<QOpcUa::NodeAttributes>(), (QOpcUaNode::mandatoryBaseAttributes() | QOpcUa::NodeAttribute::Value)); \
QVERIFY(QOpcUa::isSuccessStatus(NODE->attributeError(QOpcUa::NodeAttribute::NodeId)) == true); \
@@ -519,7 +529,7 @@ private:
{ \
QSignalSpy resultSpy(NODE.data(), &QOpcUaNode::attributeWritten); \
NODE->writeAttribute(QOpcUa::NodeAttribute::Value, VALUE, TYPE); \
- resultSpy.wait(); \
+ resultSpy.wait(signalSpyTimeout); \
QCOMPARE(resultSpy.size(), 1); \
QCOMPARE(resultSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value); \
QCOMPARE(resultSpy.at(0).at(1).toUInt(), uint(0)); \
@@ -587,19 +597,50 @@ void Tst_QOpcUaClient::initTestCase()
m_serverProcess.start(m_testServerPath);
QVERIFY2(m_serverProcess.waitForStarted(), qPrintable(m_serverProcess.errorString()));
- // Let the server come up
- QTest::qSleep(2000);
+
+ // Check if server is up and running
+ QVERIFY(m_serverProcess.state() == QProcess::Running);
+
+ QTest::qSleep(100);
+ socket.connectToHost(defaultHost, defaultPort);
+ if (!socket.waitForConnected(5000))
+ {
+ //Try a second time
+ QTest::qSleep(5000);
+ socket.connectToHost(defaultHost, defaultPort);
+ if (!socket.waitForConnected(5000))
+ QFAIL("Server does not run");
+ }
+
+ socket.disconnectFromHost();
}
QString host = envOrDefault("OPCUA_HOST", defaultHost.toString());
QString port = envOrDefault("OPCUA_PORT", QString::number(defaultPort));
- m_endpoint = QString("opc.tcp://%1:%2").arg(host).arg(port);
- qDebug() << "Using endpoint:" << m_endpoint;
+ m_discoveryEndpoint = QString("opc.tcp://%1:%2").arg(host).arg(port);
+ qDebug() << "Using endpoint:" << m_discoveryEndpoint;
+
+ QOpcUaClient *client = m_clients.first();
+ if (client) {
+ QSignalSpy endpointSpy(m_clients.first(), &QOpcUaClient::endpointsRequestFinished);
+
+ client->requestEndpoints(m_discoveryEndpoint);
+ endpointSpy.wait(signalSpyTimeout);
+ QCOMPARE(endpointSpy.size(), 1);
+
+ const QVector<QOpcUaEndpointDescription> desc = endpointSpy.at(0).at(0).value<QVector<QOpcUaEndpointDescription>>();
+ QVERIFY(desc.size() > 0);
+ QCOMPARE(endpointSpy.at(0).at(2).value<QUrl>(), m_discoveryEndpoint);
+
+ m_endpoint = desc.first();
+ }
}
void Tst_QOpcUaClient::connectToInvalid()
{
QFETCH(QOpcUaClient *, opcuaClient);
- opcuaClient->connectToEndpoint(QUrl("opc.tcp:127.0.0.1:1234"));
+ QOpcUaEndpointDescription invalidEndpoint;
+ invalidEndpoint.setEndpointUrl(QLatin1String("opc.tcp:127.0.0.1:1234"));
+ opcuaClient->connectToEndpoint(invalidEndpoint);
// Depending on the event loop the client might have switched to Disconnected already
QVERIFY(opcuaClient->state() == QOpcUaClient::Connecting || opcuaClient->state() == QOpcUaClient::Disconnected);
@@ -612,8 +653,7 @@ void Tst_QOpcUaClient::connectToInvalid()
QVERIFY(opcuaClient->state() == QOpcUaClient::Connected ||
opcuaClient->state() == QOpcUaClient::Disconnected);
- QUrl url = opcuaClient->url();
- QCOMPARE(url, QUrl("opc.tcp:127.0.0.1:1234"));
+ QCOMPARE(opcuaClient->endpoint(), invalidEndpoint);
}
void Tst_QOpcUaClient::connectAndDisconnect()
@@ -626,18 +666,18 @@ void Tst_QOpcUaClient::connectInvalidPassword()
{
QFETCH(QOpcUaClient *, opcuaClient);
- QUrl url(m_endpoint);
- url.setUserName("invaliduser");
- url.setPassword("wrongpassword");
+ QOpcUaAuthenticationInformation authInfo;
+ authInfo.setUsernameAuthentication("invaliduser", "wrongpassword");
+ opcuaClient->setAuthenticationInformation(authInfo);
QSignalSpy connectSpy(opcuaClient, &QOpcUaClient::stateChanged);
- opcuaClient->connectToEndpoint(url);
+ opcuaClient->connectToEndpoint(m_endpoint);
QTRY_VERIFY_WITH_TIMEOUT(connectSpy.count() == 2, 3000);
QCOMPARE(connectSpy.at(0).at(0), QOpcUaClient::Connecting);
QCOMPARE(connectSpy.at(1).at(0), QOpcUaClient::Disconnected);
- QCOMPARE(opcuaClient->url(), url);
+ QCOMPARE(opcuaClient->endpoint(), m_endpoint);
QCOMPARE(opcuaClient->error(), QOpcUaClient::AccessDenied);
}
@@ -645,25 +685,25 @@ void Tst_QOpcUaClient::connectAndDisconnectPassword()
{
QFETCH(QOpcUaClient *, opcuaClient);
- QUrl url(m_endpoint);
- url.setUserName("user1");
- url.setPassword("password");
+ QOpcUaAuthenticationInformation authInfo;
+ authInfo.setUsernameAuthentication("user1", "password");
+ opcuaClient->setAuthenticationInformation(authInfo);
QSignalSpy connectSpy(opcuaClient, &QOpcUaClient::stateChanged);
- opcuaClient->connectToEndpoint(url);
- connectSpy.wait();
+ opcuaClient->connectToEndpoint(m_endpoint);
+ connectSpy.wait(signalSpyTimeout);
- QCOMPARE(connectSpy.count(), 2);
+ QTRY_COMPARE(connectSpy.count(), 2);
QCOMPARE(connectSpy.at(0).at(0), QOpcUaClient::Connecting);
QCOMPARE(connectSpy.at(1).at(0), QOpcUaClient::Connected);
- QCOMPARE(opcuaClient->url(), url);
+ QCOMPARE(opcuaClient->endpoint(), m_endpoint);
QCOMPARE(opcuaClient->error(), QOpcUaClient::NoError);
connectSpy.clear();
opcuaClient->disconnectFromEndpoint();
- connectSpy.wait();
+ connectSpy.wait(signalSpyTimeout);
QCOMPARE(connectSpy.count(), 2);
QCOMPARE(connectSpy.at(0).at(0), QOpcUaClient::Closing);
QCOMPARE(connectSpy.at(1).at(0), QOpcUaClient::Disconnected);
@@ -673,22 +713,20 @@ void Tst_QOpcUaClient::findServers()
{
QFETCH(QOpcUaClient *, opcuaClient);
- if (opcuaClient->backend() != QStringLiteral("open62541"))
- QSKIP("FindServers is not yet supported in uacpp.");
-
QSignalSpy discoverySpy(opcuaClient, &QOpcUaClient::findServersFinished);
- opcuaClient->findServers(m_endpoint);
+ opcuaClient->findServers(m_discoveryEndpoint);
- discoverySpy.wait();
+ discoverySpy.wait(signalSpyTimeout);
QCOMPARE(discoverySpy.size(), 1);
+ QCOMPARE(discoverySpy.at(0).at(2).value<QUrl>(), m_discoveryEndpoint);
QCOMPARE(discoverySpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
- QVector<QOpcUa::QApplicationDescription> servers = discoverySpy.at(0).at(0).value<QVector<QOpcUa::QApplicationDescription>>();
+ QVector<QOpcUaApplicationDescription> servers = discoverySpy.at(0).at(0).value<QVector<QOpcUaApplicationDescription>>();
QCOMPARE(servers.size(), 1);
- QCOMPARE(servers.at(0).applicationName(), QOpcUa::QLocalizedText(QStringLiteral("en"), QStringLiteral("open62541-based OPC UA Application")));
+ QCOMPARE(servers.at(0).applicationName(), QOpcUaLocalizedText(QStringLiteral("en"), QStringLiteral("open62541-based OPC UA Application")));
QCOMPARE(servers.at(0).applicationUri(), QStringLiteral("urn:unconfigured:application"));
QCOMPARE(servers.at(0).discoveryUrls().size(), 1);
}
@@ -699,28 +737,38 @@ void Tst_QOpcUaClient::requestEndpoints()
QSignalSpy endpointSpy(opcuaClient, &QOpcUaClient::endpointsRequestFinished);
- opcuaClient->requestEndpoints(m_endpoint);
- endpointSpy.wait();
+ opcuaClient->requestEndpoints(m_discoveryEndpoint);
+ endpointSpy.wait(signalSpyTimeout);
QCOMPARE(endpointSpy.size(), 1);
+ QCOMPARE(endpointSpy.at(0).at(2).value<QUrl>(), m_discoveryEndpoint);
- QVector<QOpcUa::QEndpointDescription> desc = endpointSpy.at(0).at(0).value<QVector<QOpcUa::QEndpointDescription>>();
+ QVector<QOpcUaEndpointDescription> desc = endpointSpy.at(0).at(0).value<QVector<QOpcUaEndpointDescription>>();
QVERIFY(desc.size() > 0);
QCOMPARE(QUrl(desc[0].endpointUrl()).port(), 43344);
- QCOMPARE(desc[0].securityPolicyUri(), QStringLiteral("http://opcfoundation.org/UA/SecurityPolicy#None"));
+ QCOMPARE(desc[0].securityPolicy(), QStringLiteral("http://opcfoundation.org/UA/SecurityPolicy#None"));
QCOMPARE(desc[0].transportProfileUri(), QStringLiteral("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary"));
QCOMPARE(desc[0].securityLevel(), 0);
- QCOMPARE(desc[0].securityMode(), QOpcUa::QEndpointDescription::MessageSecurityMode::None);
+ QCOMPARE(desc[0].securityMode(), QOpcUaEndpointDescription::MessageSecurityMode::None);
+#ifdef SERVER_SUPPORTS_SECURITY
+ QFile file(":/open62541-testserver/pki/own/certs/open62541-testserver.der");
+ QVERIFY(file.open(QFile::ReadOnly));
+ const auto serverCertificate = file.readAll();
+ QVERIFY(serverCertificate.size() > 0);
+ file.close();
+ QCOMPARE(desc[0].serverCertificate(), serverCertificate);
+#else
QCOMPARE(desc[0].serverCertificate(), QByteArray());
+#endif
QCOMPARE(desc[0].userIdentityTokens().size(), 2);
QCOMPARE(desc[0].userIdentityTokens()[0].policyId(), QStringLiteral("open62541-anonymous-policy"));
- QCOMPARE(desc[0].userIdentityTokens()[0].tokenType(), QOpcUa::QUserTokenPolicy::TokenType::Anonymous);
+ QCOMPARE(desc[0].userIdentityTokens()[0].tokenType(), QOpcUaUserTokenPolicy::TokenType::Anonymous);
QCOMPARE(desc[0].userIdentityTokens()[1].policyId(), QStringLiteral("open62541-username-policy"));
- QCOMPARE(desc[0].userIdentityTokens()[1].tokenType(), QOpcUa::QUserTokenPolicy::TokenType::Username);
+ QCOMPARE(desc[0].userIdentityTokens()[1].tokenType(), QOpcUaUserTokenPolicy::TokenType::Username);
QCOMPARE(desc[0].serverRef().applicationName().text(), QStringLiteral("open62541-based OPC UA Application"));
- QCOMPARE(desc[0].serverRef().applicationType(), QOpcUa::QApplicationDescription::ApplicationType::Server);
+ QCOMPARE(desc[0].serverRef().applicationType(), QOpcUaApplicationDescription::ApplicationType::Server);
QCOMPARE(desc[0].serverRef().applicationUri(), QStringLiteral("urn:unconfigured:application"));
QCOMPARE(desc[0].serverRef().productUri(), QStringLiteral("http://open62541.org"));
}
@@ -788,8 +836,8 @@ void Tst_QOpcUaClient::readNS0OmitNode()
READ_MANDATORY_BASE_NODE(node);
- QCOMPARE(node->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUa::QQualifiedName>(),
- QOpcUa::QQualifiedName(0, QStringLiteral("Root")));
+ QCOMPARE(node->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>(),
+ QOpcUaQualifiedName(0, QStringLiteral("Root")));
}
void Tst_QOpcUaClient::readInvalidNode()
@@ -800,12 +848,12 @@ void Tst_QOpcUaClient::readInvalidNode()
QScopedPointer<QOpcUaNode> node(opcuaClient->node("ns=0;s=doesnotexist"));
QVERIFY(node != nullptr);
- QCOMPARE(node->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUa::QLocalizedText>().text(), QString());
+ QCOMPARE(node->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>().text(), QString());
QSignalSpy attributeReadSpy(node.data(), &QOpcUaNode::attributeRead);
node->readAttributes(QOpcUaNode::mandatoryBaseAttributes());
- attributeReadSpy.wait();
+ attributeReadSpy.wait(signalSpyTimeout);
QCOMPARE(attributeReadSpy.count(), 1);
QCOMPARE(attributeReadSpy.at(0).at(0).value<QOpcUa::NodeAttributes>(), QOpcUaNode::mandatoryBaseAttributes());
@@ -844,7 +892,7 @@ void Tst_QOpcUaClient::writeInvalidNode()
QCOMPARE(result, true);
- responseSpy.wait();
+ responseSpy.wait(signalSpyTimeout);
QCOMPARE(responseSpy.count(), 1);
QCOMPARE(responseSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value);
@@ -860,16 +908,16 @@ void Tst_QOpcUaClient::writeMultipleAttributes()
QVERIFY(node != nullptr);
QOpcUaNode::AttributeMap map;
- map[QOpcUa::NodeAttribute::DisplayName] = QOpcUa::QLocalizedText(QStringLiteral("en"), QStringLiteral("NewDisplayName"));
- map[QOpcUa::NodeAttribute::Value] = QOpcUa::QQualifiedName(2, QStringLiteral("TestString"));
+ map[QOpcUa::NodeAttribute::DisplayName] = QOpcUaLocalizedText(QStringLiteral("en"), QStringLiteral("NewDisplayName"));
+ map[QOpcUa::NodeAttribute::Value] = QOpcUaQualifiedName(2, QStringLiteral("TestString"));
QSignalSpy writeSpy(node.data(), &QOpcUaNode::attributeWritten);
node->writeAttributes(map, QOpcUa::Types::QualifiedName);
- writeSpy.wait();
+ writeSpy.wait(signalSpyTimeout);
if (writeSpy.size() < 2)
- writeSpy.wait();
+ writeSpy.wait(signalSpyTimeout);
QCOMPARE(writeSpy.size(), 2);
QCOMPARE(writeSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::DisplayName);
@@ -880,7 +928,7 @@ void Tst_QOpcUaClient::writeMultipleAttributes()
QCOMPARE(writeSpy.at(1).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value);
QCOMPARE(writeSpy.at(1).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
QCOMPARE(node->attributeError(QOpcUa::NodeAttribute::Value), QOpcUa::UaStatusCode::Good);
- QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUa::QQualifiedName>(), QOpcUa::QQualifiedName(2, QStringLiteral("TestString")));
+ QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUaQualifiedName>(), QOpcUaQualifiedName(2, QStringLiteral("TestString")));
}
void Tst_QOpcUaClient::readEmptyArrayVariable()
@@ -902,13 +950,9 @@ void Tst_QOpcUaClient::readEmptyArrayVariable()
QVERIFY(node->attribute(QOpcUa::NodeAttribute::Value).toList().isEmpty());
}
-void Tst_QOpcUaClient::batchWrite()
+void Tst_QOpcUaClient::writeNodeAttributes()
{
QFETCH(QOpcUaClient *, opcuaClient);
-
- if (opcuaClient->backend() == QLatin1String("uacpp"))
- QSKIP("Batch write is currently not supported in the uacpp backend");
-
OpcuaConnector connector(opcuaClient, m_endpoint);
QVector<QOpcUaWriteItem> request;
@@ -928,16 +972,16 @@ void Tst_QOpcUaClient::batchWrite()
QVERIFY (node != nullptr);
WRITE_VALUE_ATTRIBUTE(node, QVariantList({1, 2, 3, 4, 5}), QOpcUa::Types::UInt32);
- QSignalSpy batchWriteSpy(opcuaClient, &QOpcUaClient::batchWriteFinished);
+ QSignalSpy writeNodeAttributesSpy(opcuaClient, &QOpcUaClient::writeNodeAttributesFinished);
- opcuaClient->batchWrite(request);
+ opcuaClient->writeNodeAttributes(request);
- batchWriteSpy.wait();
+ writeNodeAttributesSpy.wait(signalSpyTimeout);
- QCOMPARE(batchWriteSpy.size(), 1);
+ QCOMPARE(writeNodeAttributesSpy.size(), 1);
- QCOMPARE(batchWriteSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
- QVector<QOpcUaWriteResult> result = batchWriteSpy.at(0).at(0).value<QVector<QOpcUaWriteResult>>();
+ QCOMPARE(writeNodeAttributesSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+ QVector<QOpcUaWriteResult> result = writeNodeAttributesSpy.at(0).at(0).value<QVector<QOpcUaWriteResult>>();
QCOMPARE(result.size(), 3);
@@ -952,13 +996,9 @@ void Tst_QOpcUaClient::batchWrite()
}
}
-void Tst_QOpcUaClient::batchRead()
+void Tst_QOpcUaClient::readNodeAttributes()
{
QFETCH(QOpcUaClient *, opcuaClient);
-
- if (opcuaClient->backend() == QLatin1String("uacpp"))
- QSKIP("batchRead is currently not supported in the uacpp backend");
-
OpcuaConnector connector(opcuaClient, m_endpoint);
QVector<QOpcUaReadItem> request;
@@ -973,16 +1013,16 @@ void Tst_QOpcUaClient::batchRead()
request.push_back(QOpcUaReadItem(QStringLiteral("ns=2;s=Demo.Static.Arrays.UInt32"),
QOpcUa::NodeAttribute::Value, QStringLiteral("0:2")));
- QSignalSpy batchReadSpy(opcuaClient, &QOpcUaClient::batchReadFinished);
+ QSignalSpy readNodeAttributesSpy(opcuaClient, &QOpcUaClient::readNodeAttributesFinished);
- opcuaClient->batchRead(request);
+ opcuaClient->readNodeAttributes(request);
- batchReadSpy.wait();
+ readNodeAttributesSpy.wait(signalSpyTimeout);
- QCOMPARE(batchReadSpy.size(), 1);
+ QCOMPARE(readNodeAttributesSpy.size(), 1);
- QCOMPARE(batchReadSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
- QVector<QOpcUaReadResult> result = batchReadSpy.at(0).at(0).value<QVector<QOpcUaReadResult>>();
+ QCOMPARE(readNodeAttributesSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+ QVector<QOpcUaReadResult> result = readNodeAttributesSpy.at(0).at(0).value<QVector<QOpcUaReadResult>>();
QCOMPARE(result.size(), 3);
@@ -996,7 +1036,7 @@ void Tst_QOpcUaClient::batchRead()
QVERIFY(!result[0].sourceTimestamp().isValid()); // The initial DisplayName attribute doesn't have a source timestamp
QVERIFY(result[1].sourceTimestamp().isValid());
QVERIFY(result[2].sourceTimestamp().isValid());
- QCOMPARE(result[0].value().value<QOpcUa::QLocalizedText>().text(), QStringLiteral("DoubleScalarTest"));
+ QCOMPARE(result[0].value().value<QOpcUaLocalizedText>().text(), QStringLiteral("DoubleScalarTest"));
QCOMPARE(result[1].value(), 23.0);
QCOMPARE(result[2].value(), QVariantList({0, 1, 2}));
// Only check the source timestamp, the server timestamp is replaced with the current DateTime in the open62541
@@ -1014,7 +1054,7 @@ void Tst_QOpcUaClient::getRootNode()
QVERIFY(root->client() == opcuaClient);
READ_MANDATORY_BASE_NODE(root)
- QCOMPARE(root->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUa::QLocalizedText>().text(), QLatin1String("Root"));
+ QCOMPARE(root->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>().text(), QLatin1String("Root"));
QString nodeId = root->nodeId();
QCOMPARE(nodeId, QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::RootFolder));
@@ -1029,7 +1069,7 @@ void Tst_QOpcUaClient::getChildren()
QVERIFY(node != nullptr);
QSignalSpy spy(node.data(), &QOpcUaNode::browseFinished);
node->browseChildren(QOpcUa::ReferenceTypeId::HierarchicalReferences, QOpcUa::NodeClass::Object);
- spy.wait();
+ spy.wait(signalSpyTimeout);
QCOMPARE(spy.size(), 1);
QVector<QOpcUaReferenceDescription> ref = spy.at(0).at(0).value<QVector<QOpcUaReferenceDescription>>();
QCOMPARE(ref.size(), 100);
@@ -1044,7 +1084,7 @@ void Tst_QOpcUaClient::childrenIdsString()
QVERIFY(node != nullptr);
QSignalSpy spy(node.data(), &QOpcUaNode::browseFinished);
node->browseChildren(QOpcUa::ReferenceTypeId::Organizes, QOpcUa::NodeClass::Variable);
- spy.wait();
+ spy.wait(signalSpyTimeout);
QCOMPARE(spy.size(), 1);
QVector<QOpcUaReferenceDescription> ref = spy.at(0).at(0).value<QVector<QOpcUaReferenceDescription>>();
QCOMPARE(ref.size(), 1);
@@ -1060,7 +1100,7 @@ void Tst_QOpcUaClient::childrenIdsGuidNodeId()
QVERIFY(node != nullptr);
QSignalSpy spy(node.data(), &QOpcUaNode::browseFinished);
node->browseChildren(QOpcUa::ReferenceTypeId::Organizes, QOpcUa::NodeClass::Variable);
- spy.wait();
+ spy.wait(signalSpyTimeout);
QCOMPARE(spy.size(), 1);
QVector<QOpcUaReferenceDescription> ref = spy.at(0).at(0).value<QVector<QOpcUaReferenceDescription>>();
QCOMPARE(ref.size(), 1);
@@ -1076,7 +1116,7 @@ void Tst_QOpcUaClient::childrenIdsOpaqueNodeId()
QVERIFY(node != nullptr);
QSignalSpy spy(node.data(), &QOpcUaNode::browseFinished);
node->browseChildren(QOpcUa::ReferenceTypeId::Organizes, QOpcUa::NodeClass::Variable);
- spy.wait();
+ spy.wait(signalSpyTimeout);
QCOMPARE(spy.size(), 1);
QVector<QOpcUaReferenceDescription> ref = spy.at(0).at(0).value<QVector<QOpcUaReferenceDescription>>();
QCOMPARE(ref.size(), 1);
@@ -1098,7 +1138,7 @@ void Tst_QOpcUaClient::inverseBrowse()
request.setNodeClassMask(QOpcUa::NodeClass::Undefined);
request.setBrowseDirection(QOpcUaBrowseRequest::BrowseDirection::Inverse);
node->browse(request);
- spy.wait();
+ spy.wait(signalSpyTimeout);
QCOMPARE(spy.size(), 1);
QVector<QOpcUaReferenceDescription> ref = spy.at(0).at(0).value<QVector<QOpcUaReferenceDescription>>();
QCOMPARE(ref.size(), 1);
@@ -1113,25 +1153,21 @@ void Tst_QOpcUaClient::inverseBrowse()
void Tst_QOpcUaClient::addAndRemoveObjectNode()
{
QFETCH(QOpcUaClient *, opcuaClient);
-
- if (opcuaClient->backend() != QLatin1String("open62541"))
- QSKIP("NodeManagement is currently only supported in the open62541 backend");
-
OpcuaConnector connector(opcuaClient, m_endpoint);
QSignalSpy addNodeSpy(opcuaClient, &QOpcUaClient::addNodeFinished);
- QOpcUa::QExpandedNodeId parent;
+ QOpcUaExpandedNodeId parent;
parent.setNodeId(QStringLiteral("ns=3;s=TestFolder"));
- QOpcUa::QExpandedNodeId requestedNewId;
+ QOpcUaExpandedNodeId requestedNewId;
requestedNewId.setNodeId(QStringLiteral("ns=3;s=DynamicObjectNode_%1").arg(opcuaClient->backend()));
const quint16 namespaceIndex = 3;
- QOpcUa::QQualifiedName browseName(namespaceIndex, QStringLiteral("DynamicObjectNode_%1").arg(opcuaClient->backend()));
+ QOpcUaQualifiedName browseName(namespaceIndex, QStringLiteral("DynamicObjectNode_%1").arg(opcuaClient->backend()));
QOpcUaNodeCreationAttributes attributes;
- QOpcUa::QLocalizedText displayName("en", browseName.name());
- QOpcUa::QLocalizedText description("en", QStringLiteral("Node added at runtime by %1").arg(opcuaClient->backend()));
+ QOpcUaLocalizedText displayName("en", browseName.name());
+ QOpcUaLocalizedText description("en", QStringLiteral("Node added at runtime by %1").arg(opcuaClient->backend()));
attributes.setDisplayName(displayName);
attributes.setDescription(description);
@@ -1146,11 +1182,11 @@ void Tst_QOpcUaClient::addAndRemoveObjectNode()
opcuaClient->addNode(nodeInfo);
- addNodeSpy.wait();
+ addNodeSpy.wait(signalSpyTimeout);
QCOMPARE(addNodeSpy.count(), 1);
- QCOMPARE(addNodeSpy.at(0).at(0).value<QOpcUa::QExpandedNodeId>().nodeId(), requestedNewId.nodeId());
+ QCOMPARE(addNodeSpy.at(0).at(0).value<QOpcUaExpandedNodeId>().nodeId(), requestedNewId.nodeId());
QCOMPARE(addNodeSpy.at(0).at(1), requestedNewId.nodeId());
QCOMPARE(addNodeSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
@@ -1159,7 +1195,7 @@ void Tst_QOpcUaClient::addAndRemoveObjectNode()
QSignalSpy readSpy(newNode.data(), &QOpcUaNode::attributeRead);
newNode->readAttributes(QOpcUa::NodeAttribute::BrowseName | QOpcUa::NodeAttribute::DisplayName | QOpcUa::NodeAttribute::Description);
- readSpy.wait();
+ readSpy.wait(signalSpyTimeout);
QCOMPARE(readSpy.size(), 1);
@@ -1167,13 +1203,13 @@ void Tst_QOpcUaClient::addAndRemoveObjectNode()
QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::DisplayName), QOpcUa::UaStatusCode::Good);
QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Description), QOpcUa::UaStatusCode::Good);
- QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUa::QQualifiedName>(), browseName);
- QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUa::QLocalizedText>(), displayName);
- QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Description).value<QOpcUa::QLocalizedText>(), description);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>(), browseName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>(), displayName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Description).value<QOpcUaLocalizedText>(), description);
QSignalSpy removeNodeSpy(opcuaClient, &QOpcUaClient::deleteNodeFinished);
opcuaClient->deleteNode(requestedNewId.nodeId(), true);
- removeNodeSpy.wait();
+ removeNodeSpy.wait(signalSpyTimeout);
QCOMPARE(removeNodeSpy.size(), 1);
QCOMPARE(removeNodeSpy.at(0).at(0), requestedNewId.nodeId());
@@ -1185,7 +1221,7 @@ void Tst_QOpcUaClient::addAndRemoveObjectNode()
QSignalSpy unsuccessfulReadSpy(node.data(), &QOpcUaNode::attributeRead);
node->readAttributes(QOpcUa::NodeAttribute::NodeId);
- unsuccessfulReadSpy.wait();
+ unsuccessfulReadSpy.wait(signalSpyTimeout);
QCOMPARE(unsuccessfulReadSpy.size(), 1);
QVERIFY(unsuccessfulReadSpy.at(0).at(0).value<QOpcUa::NodeAttributes>() & QOpcUa::NodeAttribute::NodeId);
QCOMPARE(node->attributeError(QOpcUa::NodeAttribute::NodeId), QOpcUa::UaStatusCode::BadNodeIdUnknown);
@@ -1194,25 +1230,21 @@ void Tst_QOpcUaClient::addAndRemoveObjectNode()
void Tst_QOpcUaClient::addAndRemoveVariableNode()
{
QFETCH(QOpcUaClient *, opcuaClient);
-
- if (opcuaClient->backend() != QLatin1String("open62541"))
- QSKIP("NodeManagement is currently only supported in the open62541 backend");
-
OpcuaConnector connector(opcuaClient, m_endpoint);
QSignalSpy addNodeSpy(opcuaClient, &QOpcUaClient::addNodeFinished);
- QOpcUa::QExpandedNodeId parent;
+ QOpcUaExpandedNodeId parent;
parent.setNodeId(QStringLiteral("ns=3;s=TestFolder"));
- QOpcUa::QExpandedNodeId requestedNewId;
+ QOpcUaExpandedNodeId requestedNewId;
requestedNewId.setNodeId(QStringLiteral("ns=3;s=DynamicVariableNode_%1").arg(opcuaClient->backend()));
const quint16 namespaceIndex = 3;
- QOpcUa::QQualifiedName browseName(namespaceIndex, QStringLiteral("DynamicVariableNode_%1").arg(opcuaClient->backend()));
+ QOpcUaQualifiedName browseName(namespaceIndex, QStringLiteral("DynamicVariableNode_%1").arg(opcuaClient->backend()));
QOpcUaNodeCreationAttributes attributes;
- QOpcUa::QLocalizedText displayName("en", browseName.name());
- QOpcUa::QLocalizedText description("en", QStringLiteral("Node added at runtime by %1").arg(opcuaClient->backend()));
+ QOpcUaLocalizedText displayName("en", browseName.name());
+ QOpcUaLocalizedText description("en", QStringLiteral("Node added at runtime by %1").arg(opcuaClient->backend()));
attributes.setDisplayName(displayName);
attributes.setDescription(description);
@@ -1233,11 +1265,11 @@ void Tst_QOpcUaClient::addAndRemoveVariableNode()
opcuaClient->addNode(nodeInfo);
- addNodeSpy.wait();
+ addNodeSpy.wait(signalSpyTimeout);
QCOMPARE(addNodeSpy.count(), 1);
- QCOMPARE(addNodeSpy.at(0).at(0).value<QOpcUa::QExpandedNodeId>().nodeId(), requestedNewId.nodeId());
+ QCOMPARE(addNodeSpy.at(0).at(0).value<QOpcUaExpandedNodeId>().nodeId(), requestedNewId.nodeId());
QCOMPARE(addNodeSpy.at(0).at(1), requestedNewId.nodeId());
QCOMPARE(addNodeSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
@@ -1246,7 +1278,7 @@ void Tst_QOpcUaClient::addAndRemoveVariableNode()
QSignalSpy readSpy(newNode.data(), &QOpcUaNode::attributeRead);
newNode->readAttributes(QOpcUa::NodeAttribute::BrowseName | QOpcUa::NodeAttribute::DisplayName | QOpcUa::NodeAttribute::Description | QOpcUa::NodeAttribute::Value);
- readSpy.wait();
+ readSpy.wait(signalSpyTimeout);
QCOMPARE(readSpy.size(), 1);
@@ -1255,14 +1287,14 @@ void Tst_QOpcUaClient::addAndRemoveVariableNode()
QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Description), QOpcUa::UaStatusCode::Good);
QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Value), QOpcUa::UaStatusCode::Good);
- QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUa::QQualifiedName>(), browseName);
- QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUa::QLocalizedText>(), displayName);
- QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Description).value<QOpcUa::QLocalizedText>(), description);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>(), browseName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>(), displayName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Description).value<QOpcUaLocalizedText>(), description);
QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Value).toDouble(), 23.0);
QSignalSpy removeNodeSpy(opcuaClient, &QOpcUaClient::deleteNodeFinished);
opcuaClient->deleteNode(requestedNewId.nodeId(), true);
- removeNodeSpy.wait();
+ removeNodeSpy.wait(signalSpyTimeout);
QCOMPARE(removeNodeSpy.size(), 1);
QCOMPARE(removeNodeSpy.at(0).at(0), requestedNewId.nodeId());
@@ -1274,7 +1306,7 @@ void Tst_QOpcUaClient::addAndRemoveVariableNode()
QSignalSpy unsuccessfulReadSpy(node.data(), &QOpcUaNode::attributeRead);
node->readAttributes(QOpcUa::NodeAttribute::NodeId);
- unsuccessfulReadSpy.wait();
+ unsuccessfulReadSpy.wait(signalSpyTimeout);
QCOMPARE(unsuccessfulReadSpy.size(), 1);
QVERIFY(unsuccessfulReadSpy.at(0).at(0).value<QOpcUa::NodeAttributes>() & QOpcUa::NodeAttribute::NodeId);
QCOMPARE(node->attributeError(QOpcUa::NodeAttribute::NodeId), QOpcUa::UaStatusCode::BadNodeIdUnknown);
@@ -1282,16 +1314,13 @@ void Tst_QOpcUaClient::addAndRemoveVariableNode()
void Tst_QOpcUaClient::addAndRemoveReference()
{
- QFETCH(QOpcUaClient *, opcuaClient);
-
- if (opcuaClient->backend() != QLatin1String("open62541"))
- QSKIP("NodeManagement is currently only supported in the open62541 backend");
+ QFETCH(QOpcUaClient *, opcuaClient);
OpcuaConnector connector(opcuaClient, m_endpoint);
QSignalSpy addReferenceSpy(opcuaClient, &QOpcUaClient::addReferenceFinished);
- QOpcUa::QExpandedNodeId target;
+ QOpcUaExpandedNodeId target;
target.setNodeId(QStringLiteral("ns=3;s=TestFolder"));
QString referenceType = QOpcUa::nodeIdFromInteger(0, static_cast<quint32>(QOpcUa::ReferenceTypeId::Organizes));
@@ -1303,12 +1332,12 @@ void Tst_QOpcUaClient::addAndRemoveReference()
refInfo.setTargetNodeClass(QOpcUa::NodeClass::Variable);
opcuaClient->addReference(refInfo);
- addReferenceSpy.wait();
+ addReferenceSpy.wait(signalSpyTimeout);
QCOMPARE(addReferenceSpy.count(), 1);
QCOMPARE(addReferenceSpy.at(0).at(0), QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::RootFolder));
QCOMPARE(addReferenceSpy.at(0).at(1), referenceType);
- QCOMPARE(addReferenceSpy.at(0).at(2).value<QOpcUa::QExpandedNodeId>().nodeId(), target.nodeId());
+ QCOMPARE(addReferenceSpy.at(0).at(2).value<QOpcUaExpandedNodeId>().nodeId(), target.nodeId());
QCOMPARE(addReferenceSpy.at(0).at(3).value<bool>(), true);
QCOMPARE(addReferenceSpy.at(0).at(4).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
@@ -1320,7 +1349,7 @@ void Tst_QOpcUaClient::addAndRemoveReference()
QSignalSpy browseSpy(node.data(), &QOpcUaNode::browseFinished);
node->browseChildren(QOpcUa::ReferenceTypeId::Organizes);
- browseSpy.wait();
+ browseSpy.wait(signalSpyTimeout);
QCOMPARE(browseSpy.size(), 1);
QCOMPARE(browseSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
QVector<QOpcUaReferenceDescription> results = browseSpy.at(0).at(0).value<QVector<QOpcUaReferenceDescription>>();
@@ -1345,12 +1374,12 @@ void Tst_QOpcUaClient::addAndRemoveReference()
refDelInfo.setDeleteBidirectional(true);
opcuaClient->deleteReference(refDelInfo);
- deleteReferenceSpy.wait();
+ deleteReferenceSpy.wait(signalSpyTimeout);
QCOMPARE(deleteReferenceSpy.count(), 1);
QCOMPARE(deleteReferenceSpy.at(0).at(0), QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::RootFolder));
QCOMPARE(deleteReferenceSpy.at(0).at(1), referenceType);
- QCOMPARE(deleteReferenceSpy.at(0).at(2).value<QOpcUa::QExpandedNodeId>().nodeId(), target.nodeId());
+ QCOMPARE(deleteReferenceSpy.at(0).at(2).value<QOpcUaExpandedNodeId>().nodeId(), target.nodeId());
QCOMPARE(deleteReferenceSpy.at(0).at(3).value<bool>(), true);
QCOMPARE(deleteReferenceSpy.at(0).at(4).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
@@ -1362,7 +1391,7 @@ void Tst_QOpcUaClient::addAndRemoveReference()
QSignalSpy browseSpy(node.data(), &QOpcUaNode::browseFinished);
node->browseChildren(QOpcUa::ReferenceTypeId::Organizes);
- browseSpy.wait();
+ browseSpy.wait(signalSpyTimeout);
QCOMPARE(browseSpy.size(), 1);
QCOMPARE(browseSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
QVector<QOpcUaReferenceDescription> results = browseSpy.at(0).at(0).value<QVector<QOpcUaReferenceDescription>>();
@@ -1389,7 +1418,7 @@ void Tst_QOpcUaClient::dataChangeSubscription()
QSignalSpy monitoringEnabledSpy(node.data(), &QOpcUaNode::enableMonitoringFinished);
node->enableMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters(100, QOpcUaMonitoringParameters::SubscriptionType::Exclusive));
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
QCOMPARE(monitoringEnabledSpy.size(), 1);
QCOMPARE(monitoringEnabledSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value);
@@ -1401,9 +1430,9 @@ void Tst_QOpcUaClient::dataChangeSubscription()
QCOMPARE(valueStatus.statusCode(), QOpcUa::UaStatusCode::Good);
WRITE_VALUE_ATTRIBUTE(node, QVariant(double(42)), QOpcUa::Types::Double);
- dataChangeSpy.wait();
+ dataChangeSpy.wait(signalSpyTimeout);
if (dataChangeSpy.size() < 2)
- dataChangeSpy.wait();
+ dataChangeSpy.wait(signalSpyTimeout);
QVERIFY(dataChangeSpy.size() >= 1);
@@ -1416,7 +1445,7 @@ void Tst_QOpcUaClient::dataChangeSubscription()
node->enableMonitoring(QOpcUa::NodeAttribute::DisplayName, QOpcUaMonitoringParameters(100,QOpcUaMonitoringParameters::SubscriptionType::Exclusive,
valueStatus.subscriptionId()));
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
QCOMPARE(monitoringEnabledSpy.size(), 1);
QCOMPARE(monitoringEnabledSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::DisplayName);
@@ -1427,15 +1456,15 @@ void Tst_QOpcUaClient::dataChangeSubscription()
QVERIFY(displayNameStatus.monitoredItemId() != 0);
QCOMPARE(displayNameStatus.statusCode(), QOpcUa::UaStatusCode::Good);
- dataChangeSpy.wait();
+ dataChangeSpy.wait(signalSpyTimeout);
QCOMPARE(dataChangeSpy.size(), 1);
QCOMPARE(dataChangeSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::DisplayName);
- QCOMPARE(dataChangeSpy.at(0).at(1).value<QOpcUa::QLocalizedText>().text(), QLatin1String("TestNode.ReadWrite"));
+ QCOMPARE(dataChangeSpy.at(0).at(1).value<QOpcUaLocalizedText>().text(), QLatin1String("TestNode.ReadWrite"));
monitoringEnabledSpy.clear();
dataChangeSpy.clear();
node->enableMonitoring(QOpcUa::NodeAttribute::NodeId, QOpcUaMonitoringParameters(100));
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
QCOMPARE(monitoringEnabledSpy.size(), 1);
QCOMPARE(monitoringEnabledSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::NodeId);
QVERIFY(node->monitoringStatus(QOpcUa::NodeAttribute::NodeId).subscriptionId() != valueStatus.subscriptionId());
@@ -1446,7 +1475,7 @@ void Tst_QOpcUaClient::dataChangeSubscription()
QVERIFY(nodeIdStatus.monitoredItemId() != 0);
QCOMPARE(nodeIdStatus.statusCode(), QOpcUa::UaStatusCode::Good);
- dataChangeSpy.wait();
+ dataChangeSpy.wait(signalSpyTimeout);
QCOMPARE(dataChangeSpy.size(), 1);
QCOMPARE(dataChangeSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::NodeId);
QCOMPARE(dataChangeSpy.at(0).at(1), QLatin1String("ns=3;s=TestNode.ReadWrite"));
@@ -1456,9 +1485,9 @@ void Tst_QOpcUaClient::dataChangeSubscription()
QSignalSpy monitoringModifiedSpy(node.data(), &QOpcUaNode::monitoringStatusChanged);
node->modifyMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters::Parameter::PublishingInterval, 200);
- monitoringModifiedSpy.wait();
+ monitoringModifiedSpy.wait(signalSpyTimeout);
if (monitoringModifiedSpy.size() < 2)
- monitoringModifiedSpy.wait();
+ monitoringModifiedSpy.wait(signalSpyTimeout);
attrs = {QOpcUa::NodeAttribute::Value, QOpcUa::NodeAttribute::DisplayName};
for (auto it : qAsConst(monitoringModifiedSpy)) {
@@ -1477,11 +1506,11 @@ void Tst_QOpcUaClient::dataChangeSubscription()
QSignalSpy monitoringDisabledSpy(node.data(), &QOpcUaNode::disableMonitoringFinished);
node->disableMonitoring(QOpcUa::NodeAttribute::Value | QOpcUa::NodeAttribute::DisplayName | QOpcUa::NodeAttribute::NodeId);
- monitoringDisabledSpy.wait();
+ monitoringDisabledSpy.wait(signalSpyTimeout);
if (monitoringDisabledSpy.size() < 2)
- monitoringDisabledSpy.wait();
+ monitoringDisabledSpy.wait(signalSpyTimeout);
if (monitoringDisabledSpy.size() < 3)
- monitoringDisabledSpy.wait();
+ monitoringDisabledSpy.wait(signalSpyTimeout);
QCOMPARE(monitoringDisabledSpy.size(), 3);
@@ -1495,6 +1524,16 @@ void Tst_QOpcUaClient::dataChangeSubscription()
attrs.remove(attrs.indexOf(temp));
}
QCOMPARE(attrs.size(), 0);
+
+ // Enable the monitoring again, after it has been disabled. This triggered a bug where a previous subscription
+ // was not completeley removed from the internal data structures
+ monitoringEnabledSpy.clear();
+ node->enableMonitoring(QOpcUa::NodeAttribute::NodeId, QOpcUaMonitoringParameters(100));
+ monitoringEnabledSpy.wait(signalSpyTimeout);
+ QCOMPARE(monitoringEnabledSpy.size(), 1);
+ QCOMPARE(monitoringEnabledSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::NodeId);
+ QVERIFY(node->monitoringStatus(QOpcUa::NodeAttribute::NodeId).subscriptionId() != valueStatus.subscriptionId());
+ QCOMPARE(node->monitoringStatus(QOpcUa::NodeAttribute::NodeId).statusCode(), QOpcUa::UaStatusCode::Good);
}
void Tst_QOpcUaClient::dataChangeSubscriptionInvalidNode()
@@ -1508,7 +1547,7 @@ void Tst_QOpcUaClient::dataChangeSubscriptionInvalidNode()
QOpcUaMonitoringParameters settings;
settings.setPublishingInterval(100);
noDataNode->enableMonitoring(QOpcUa::NodeAttribute::Value, settings);
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
QCOMPARE(monitoringEnabledSpy.size(), 1);
QCOMPARE(monitoringEnabledSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value);
@@ -1530,7 +1569,7 @@ void Tst_QOpcUaClient::dataChangeSubscriptionSharing()
QSignalSpy monitoringEnabledSpy(node.data(), &QOpcUaNode::enableMonitoringFinished);
node->enableMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters(50));
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
QCOMPARE(monitoringEnabledSpy.size(), 1);
QCOMPARE(monitoringEnabledSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value);
@@ -1543,7 +1582,7 @@ void Tst_QOpcUaClient::dataChangeSubscriptionSharing()
monitoringEnabledSpy.clear();
node->enableMonitoring(QOpcUa::NodeAttribute::DisplayName, QOpcUaMonitoringParameters(25));
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
QCOMPARE(monitoringEnabledSpy.size(), 1);
QCOMPARE(monitoringEnabledSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::DisplayName);
@@ -1560,9 +1599,9 @@ void Tst_QOpcUaClient::dataChangeSubscriptionSharing()
QSignalSpy monitoringDisabledSpy(node.data(), &QOpcUaNode::disableMonitoringFinished);
node->disableMonitoring(QOpcUa::NodeAttribute::Value | QOpcUa::NodeAttribute::DisplayName | QOpcUa::NodeAttribute::NodeId);
- monitoringDisabledSpy.wait();
+ monitoringDisabledSpy.wait(signalSpyTimeout);
if (monitoringDisabledSpy.size() < 2)
- monitoringDisabledSpy.wait();
+ monitoringDisabledSpy.wait(signalSpyTimeout);
QCOMPARE(monitoringDisabledSpy.size(), 2);
@@ -1595,7 +1634,7 @@ void Tst_QOpcUaClient::methodCall()
bool success = node->callMethod("ns=3;s=Test.Method.Multiply", args);
QVERIFY(success == true);
- methodSpy.wait();
+ methodSpy.wait(signalSpyTimeout);
QCOMPARE(methodSpy.size(), 1);
QCOMPARE(methodSpy.at(0).at(0).value<QString>(), QStringLiteral("ns=3;s=Test.Method.Multiply"));
@@ -1620,14 +1659,14 @@ void Tst_QOpcUaClient::methodCallInvalid()
bool success = node->callMethod("ns=3;s=Test.Method.Divide", args); // Does not exist
QVERIFY(success == true);
- methodSpy.wait();
+ methodSpy.wait(signalSpyTimeout);
QCOMPARE(methodSpy.size(), 1);
QCOMPARE(QOpcUa::errorCategory(methodSpy.at(0).at(2).value<QOpcUa::UaStatusCode>()), QOpcUa::ErrorCategory::NodeError);
methodSpy.clear();
success = node->callMethod("ns=3;s=Test.Method.Multiply", args); // One excess argument
QVERIFY(success == true);
- methodSpy.wait();
+ methodSpy.wait(signalSpyTimeout);
QCOMPARE(methodSpy.size(), 1);
QCOMPARE(methodSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::BadTooManyArguments);
@@ -1635,7 +1674,7 @@ void Tst_QOpcUaClient::methodCallInvalid()
args.resize(1);
success = node->callMethod("ns=3;s=Test.Method.Multiply", args); // One argument missing
QVERIFY(success == true);
- methodSpy.wait();
+ methodSpy.wait(signalSpyTimeout);
QCOMPARE(methodSpy.size(), 1);
QCOMPARE(methodSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::BadArgumentsMissing);
}
@@ -1643,10 +1682,6 @@ void Tst_QOpcUaClient::methodCallInvalid()
void Tst_QOpcUaClient::readMethodArguments()
{
QFETCH(QOpcUaClient *, opcuaClient);
-
- if (opcuaClient->backend() != QStringLiteral("open62541"))
- QSKIP("The argument type is currently only supported in the open62541 backend");
-
OpcuaConnector connector(opcuaClient, m_endpoint);
QScopedPointer<QOpcUaNode> node(
@@ -1654,12 +1689,12 @@ void Tst_QOpcUaClient::readMethodArguments()
QVERIFY(node != nullptr);
READ_MANDATORY_VARIABLE_NODE(node);
- QOpcUa::QArgument argument = node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUa::QArgument>();
+ QOpcUaArgument argument = node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUaArgument>();
QCOMPARE(argument.name(), QStringLiteral("SubscriptionId"));
QCOMPARE(argument.dataTypeId(), QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::UInt32));
QCOMPARE(argument.valueRank(), -1);
QVERIFY(argument.arrayDimensions().isEmpty());
- QCOMPARE(argument.description(), QOpcUa::QLocalizedText());
+ QCOMPARE(argument.description(), QOpcUaLocalizedText());
node.reset(opcuaClient->node(QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::Server_GetMonitoredItems_OutputArguments)));
QVERIFY(node != nullptr);
@@ -1668,19 +1703,19 @@ void Tst_QOpcUaClient::readMethodArguments()
QVariantList list = node->attribute(QOpcUa::NodeAttribute::Value).toList();
QCOMPARE(list.size(), 2);
- argument = list.at(0).value<QOpcUa::QArgument>();
+ argument = list.at(0).value<QOpcUaArgument>();
QCOMPARE(argument.name(), QStringLiteral("ServerHandles"));
QCOMPARE(argument.dataTypeId(), QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::UInt32));
QCOMPARE(argument.valueRank(), 1);
QVERIFY(argument.arrayDimensions().isEmpty());
- QCOMPARE(argument.description(), QOpcUa::QLocalizedText());
+ QCOMPARE(argument.description(), QOpcUaLocalizedText());
- argument = list.at(1).value<QOpcUa::QArgument>();
+ argument = list.at(1).value<QOpcUaArgument>();
QCOMPARE(argument.name(), QStringLiteral("ClientHandles"));
QCOMPARE(argument.dataTypeId(), QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::UInt32));
QCOMPARE(argument.valueRank(), 1);
QVERIFY(argument.arrayDimensions().isEmpty());
- QCOMPARE(argument.description(), QOpcUa::QLocalizedText());
+ QCOMPARE(argument.description(), QOpcUaLocalizedText());
}
void Tst_QOpcUaClient::malformedNodeString()
@@ -1938,9 +1973,9 @@ void Tst_QOpcUaClient::writeArray()
WRITE_VALUE_ATTRIBUTE(node, list, QOpcUa::NodeId);
list.clear();
- list.append(QOpcUa::QQualifiedName(0, "Test0"));
- list.append(QOpcUa::QQualifiedName(1, "Test1"));
- list.append(QOpcUa::QQualifiedName(2, "Test2"));
+ list.append(QOpcUaQualifiedName(0, "Test0"));
+ list.append(QOpcUaQualifiedName(1, "Test1"));
+ list.append(QOpcUaQualifiedName(2, "Test2"));
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Arrays.QualifiedName"));
QVERIFY(node != nullptr);
WRITE_VALUE_ATTRIBUTE(node, list, QOpcUa::QualifiedName);
@@ -2001,23 +2036,19 @@ void Tst_QOpcUaClient::writeArray()
QVERIFY(node != nullptr);
WRITE_VALUE_ATTRIBUTE(node, list, QOpcUa::XV);
- if (opcuaClient->backend() != QLatin1String("open62541"))
- qInfo("The uacpp backend currently does not support writing extension objects");
- else {
- node.reset(opcuaClient->node(QStringLiteral("ns=2;s=Demo.Static.Arrays.ExtensionObject")));
- QVERIFY(node != nullptr);
-
- QVariantList value;
+ node.reset(opcuaClient->node(QStringLiteral("ns=2;s=Demo.Static.Arrays.ExtensionObject")));
+ QVERIFY(node != nullptr);
- for (int i = 0; i < testRanges.size(); ++i) {
- QOpcUa::QExtensionObject obj;
- ENCODE_EXTENSION_OBJECT(obj, i);
- value.append(obj);
- }
+ QVariantList value;
- WRITE_VALUE_ATTRIBUTE(node, value, QOpcUa::Types::ExtensionObject); // Write value to check for
+ for (int i = 0; i < testRanges.size(); ++i) {
+ QOpcUaExtensionObject obj;
+ ENCODE_EXTENSION_OBJECT(obj, i);
+ value.append(obj);
}
+ WRITE_VALUE_ATTRIBUTE(node, value, QOpcUa::Types::ExtensionObject); // Write value to check for
+
list.clear();
list.append(xmlElements[0]);
list.append(xmlElements[1]);
@@ -2034,17 +2065,13 @@ void Tst_QOpcUaClient::writeArray()
QVERIFY(node != nullptr);
WRITE_VALUE_ATTRIBUTE(node, list, QOpcUa::ExpandedNodeId);
- if (opcuaClient->backend() == QStringLiteral("open62541")) {
- list.clear();
- list.append(testArguments[0]);
- list.append(testArguments[1]);
- list.append(testArguments[2]);
- node.reset(opcuaClient->node("ns=2;s=Demo.Static.Arrays.Argument"));
- QVERIFY(node != nullptr);
- WRITE_VALUE_ATTRIBUTE(node, list, QOpcUa::Argument);
- } else {
- qInfo("The argument type is currently only supported in the open62541 backend");
- }
+ list.clear();
+ list.append(testArguments[0]);
+ list.append(testArguments[1]);
+ list.append(testArguments[2]);
+ node.reset(opcuaClient->node("ns=2;s=Demo.Static.Arrays.Argument"));
+ QVERIFY(node != nullptr);
+ WRITE_VALUE_ATTRIBUTE(node, list, QOpcUa::Argument);
}
void Tst_QOpcUaClient::readArray()
@@ -2132,9 +2159,9 @@ void Tst_QOpcUaClient::readArray()
QVariant ltArray = node->attribute(QOpcUa::NodeAttribute::Value);
QCOMPARE(ltArray.type(), QVariant::List);
QCOMPARE(ltArray.toList().length(), 3);
- QCOMPARE(ltArray.toList()[0].value<QOpcUa::QLocalizedText>(), localizedTexts[0]);
- QCOMPARE(ltArray.toList()[1].value<QOpcUa::QLocalizedText>(), localizedTexts[1]);
- QCOMPARE(ltArray.toList()[2].value<QOpcUa::QLocalizedText>(), localizedTexts[2]);
+ QCOMPARE(ltArray.toList()[0].value<QOpcUaLocalizedText>(), localizedTexts[0]);
+ QCOMPARE(ltArray.toList()[1].value<QOpcUaLocalizedText>(), localizedTexts[1]);
+ QCOMPARE(ltArray.toList()[2].value<QOpcUaLocalizedText>(), localizedTexts[2]);
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Arrays.UInt16"));
QVERIFY(node != nullptr);
@@ -2243,9 +2270,9 @@ void Tst_QOpcUaClient::readArray()
QVariant qualifiedNameArray = node->attribute(QOpcUa::NodeAttribute::Value);
QCOMPARE(qualifiedNameArray.type(), QVariant::List);
QCOMPARE(qualifiedNameArray.toList().length(), 3);
- QCOMPARE(qualifiedNameArray.toList()[0].value<QOpcUa::QQualifiedName>(), QOpcUa::QQualifiedName(0, "Test0"));
- QCOMPARE(qualifiedNameArray.toList()[1].value<QOpcUa::QQualifiedName>(), QOpcUa::QQualifiedName(1, "Test1"));
- QCOMPARE(qualifiedNameArray.toList()[2].value<QOpcUa::QQualifiedName>(), QOpcUa::QQualifiedName(2, "Test2"));
+ QCOMPARE(qualifiedNameArray.toList()[0].value<QOpcUaQualifiedName>(), QOpcUaQualifiedName(0, "Test0"));
+ QCOMPARE(qualifiedNameArray.toList()[1].value<QOpcUaQualifiedName>(), QOpcUaQualifiedName(1, "Test1"));
+ QCOMPARE(qualifiedNameArray.toList()[2].value<QOpcUaQualifiedName>(), QOpcUaQualifiedName(2, "Test2"));
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Arrays.StatusCode"));
QVERIFY(node != nullptr);
@@ -2263,9 +2290,9 @@ void Tst_QOpcUaClient::readArray()
QVariant rangeArray = node->attribute(QOpcUa::NodeAttribute::Value);
QCOMPARE(rangeArray.type(), QVariant::List);
QCOMPARE(rangeArray.toList().length(), 3);
- QCOMPARE(rangeArray.toList()[0].value<QOpcUa::QRange>(), testRanges[0]);
- QCOMPARE(rangeArray.toList()[1].value<QOpcUa::QRange>(), testRanges[1]);
- QCOMPARE(rangeArray.toList()[2].value<QOpcUa::QRange>(), testRanges[2]);
+ QCOMPARE(rangeArray.toList()[0].value<QOpcUaRange>(), testRanges[0]);
+ QCOMPARE(rangeArray.toList()[1].value<QOpcUaRange>(), testRanges[1]);
+ QCOMPARE(rangeArray.toList()[2].value<QOpcUaRange>(), testRanges[2]);
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Arrays.EUInformation"));
QVERIFY(node != nullptr);
@@ -2273,9 +2300,9 @@ void Tst_QOpcUaClient::readArray()
QVariant euiArray = node->attribute(QOpcUa::NodeAttribute::Value);
QCOMPARE(euiArray.type(), QVariant::List);
QCOMPARE(euiArray.toList().length(), 3);
- QCOMPARE(euiArray.toList()[0].value<QOpcUa::QEUInformation>(), testEUInfos[0]);
- QCOMPARE(euiArray.toList()[1].value<QOpcUa::QEUInformation>(), testEUInfos[1]);
- QCOMPARE(euiArray.toList()[2].value<QOpcUa::QEUInformation>(), testEUInfos[2]);
+ QCOMPARE(euiArray.toList()[0].value<QOpcUaEUInformation>(), testEUInfos[0]);
+ QCOMPARE(euiArray.toList()[1].value<QOpcUaEUInformation>(), testEUInfos[1]);
+ QCOMPARE(euiArray.toList()[2].value<QOpcUaEUInformation>(), testEUInfos[2]);
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Arrays.ComplexNumber"));
QVERIFY(node != nullptr);
@@ -2283,9 +2310,9 @@ void Tst_QOpcUaClient::readArray()
QVariant complexArray = node->attribute(QOpcUa::NodeAttribute::Value);
QCOMPARE(complexArray.type(), QVariant::List);
QCOMPARE(complexArray.toList().length(), 3);
- QCOMPARE(complexArray.toList()[0].value<QOpcUa::QComplexNumber>(), testComplex[0]);
- QCOMPARE(complexArray.toList()[1].value<QOpcUa::QComplexNumber>(), testComplex[1]);
- QCOMPARE(complexArray.toList()[2].value<QOpcUa::QComplexNumber>(), testComplex[2]);
+ QCOMPARE(complexArray.toList()[0].value<QOpcUaComplexNumber>(), testComplex[0]);
+ QCOMPARE(complexArray.toList()[1].value<QOpcUaComplexNumber>(), testComplex[1]);
+ QCOMPARE(complexArray.toList()[2].value<QOpcUaComplexNumber>(), testComplex[2]);
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Arrays.DoubleComplexNumber"));
QVERIFY(node != nullptr);
@@ -2293,9 +2320,9 @@ void Tst_QOpcUaClient::readArray()
QVariant doubleComplexArray = node->attribute(QOpcUa::NodeAttribute::Value);
QCOMPARE(doubleComplexArray.type(), QVariant::List);
QCOMPARE(doubleComplexArray.toList().length(), 3);
- QCOMPARE(doubleComplexArray.toList()[0].value<QOpcUa::QDoubleComplexNumber>(), testDoubleComplex[0]);
- QCOMPARE(doubleComplexArray.toList()[1].value<QOpcUa::QDoubleComplexNumber>(), testDoubleComplex[1]);
- QCOMPARE(doubleComplexArray.toList()[2].value<QOpcUa::QDoubleComplexNumber>(), testDoubleComplex[2]);
+ QCOMPARE(doubleComplexArray.toList()[0].value<QOpcUaDoubleComplexNumber>(), testDoubleComplex[0]);
+ QCOMPARE(doubleComplexArray.toList()[1].value<QOpcUaDoubleComplexNumber>(), testDoubleComplex[1]);
+ QCOMPARE(doubleComplexArray.toList()[2].value<QOpcUaDoubleComplexNumber>(), testDoubleComplex[2]);
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Arrays.AxisInformation"));
QVERIFY(node != nullptr);
@@ -2303,9 +2330,9 @@ void Tst_QOpcUaClient::readArray()
QVariant axisInfoArray = node->attribute(QOpcUa::NodeAttribute::Value);
QCOMPARE(axisInfoArray.type(), QVariant::List);
QCOMPARE(axisInfoArray.toList().length(), 3);
- QCOMPARE(axisInfoArray.toList()[0].value<QOpcUa::QAxisInformation>(), testAxisInfo[0]);
- QCOMPARE(axisInfoArray.toList()[1].value<QOpcUa::QAxisInformation>(), testAxisInfo[1]);
- QCOMPARE(axisInfoArray.toList()[2].value<QOpcUa::QAxisInformation>(), testAxisInfo[2]);
+ QCOMPARE(axisInfoArray.toList()[0].value<QOpcUaAxisInformation>(), testAxisInfo[0]);
+ QCOMPARE(axisInfoArray.toList()[1].value<QOpcUaAxisInformation>(), testAxisInfo[1]);
+ QCOMPARE(axisInfoArray.toList()[2].value<QOpcUaAxisInformation>(), testAxisInfo[2]);
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Arrays.XV"));
QVERIFY(node != nullptr);
@@ -2313,25 +2340,21 @@ void Tst_QOpcUaClient::readArray()
QVariant xVArray = node->attribute(QOpcUa::NodeAttribute::Value);
QCOMPARE(xVArray.type(), QVariant::List);
QCOMPARE(xVArray.toList().length(), 3);
- QCOMPARE(xVArray.toList()[0].value<QOpcUa::QXValue>(), testXV[0]);
- QCOMPARE(xVArray.toList()[1].value<QOpcUa::QXValue>(), testXV[1]);
- QCOMPARE(xVArray.toList()[2].value<QOpcUa::QXValue>(), testXV[2]);
-
- if (opcuaClient->backend() != QLatin1String("open62541"))
- qInfo("The uacpp backend currently does not support reading extension objects");
- else {
- node.reset(opcuaClient->node(QStringLiteral("ns=2;s=Demo.Static.Arrays.ExtensionObject")));
- QVERIFY(node != nullptr);
+ QCOMPARE(xVArray.toList()[0].value<QOpcUaXValue>(), testXV[0]);
+ QCOMPARE(xVArray.toList()[1].value<QOpcUaXValue>(), testXV[1]);
+ QCOMPARE(xVArray.toList()[2].value<QOpcUaXValue>(), testXV[2]);
- READ_MANDATORY_VARIABLE_NODE(node);
+ node.reset(opcuaClient->node(QStringLiteral("ns=2;s=Demo.Static.Arrays.ExtensionObject")));
+ QVERIFY(node != nullptr);
- QVariantList list = node->attribute(QOpcUa::NodeAttribute::Value).toList();
- QCOMPARE(list.size(), testRanges.size());
+ READ_MANDATORY_VARIABLE_NODE(node);
- for (int i = 0; i < testRanges.size(); ++i) {
- QOpcUa::QExtensionObject obj = list.at(i).value<QOpcUa::QExtensionObject>();
- VERIFY_EXTENSION_OBJECT(obj, i);
- }
+ QVariantList list = node->attribute(QOpcUa::NodeAttribute::Value).toList();
+ QCOMPARE(list.size(), testRanges.size());
+
+ for (int i = 0; i < testRanges.size(); ++i) {
+ QOpcUaExtensionObject obj = list.at(i).value<QOpcUaExtensionObject>();
+ VERIFY_EXTENSION_OBJECT(obj, i);
}
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Arrays.XmlElement"));
@@ -2351,23 +2374,19 @@ void Tst_QOpcUaClient::readArray()
QVariant expandedNodeIdArray = node->attribute(QOpcUa::NodeAttribute::Value);
QCOMPARE(expandedNodeIdArray.type(), QVariant::List);
QCOMPARE(expandedNodeIdArray.toList().length(), 3);
- QCOMPARE(expandedNodeIdArray.toList()[0].value<QOpcUa::QExpandedNodeId>(), testExpandedNodeId[0]);
- QCOMPARE(expandedNodeIdArray.toList()[1].value<QOpcUa::QExpandedNodeId>(), testExpandedNodeId[1]);
- QCOMPARE(expandedNodeIdArray.toList()[2].value<QOpcUa::QExpandedNodeId>(), testExpandedNodeId[2]);
+ QCOMPARE(expandedNodeIdArray.toList()[0].value<QOpcUaExpandedNodeId>(), testExpandedNodeId[0]);
+ QCOMPARE(expandedNodeIdArray.toList()[1].value<QOpcUaExpandedNodeId>(), testExpandedNodeId[1]);
+ QCOMPARE(expandedNodeIdArray.toList()[2].value<QOpcUaExpandedNodeId>(), testExpandedNodeId[2]);
- if (opcuaClient->backend() == QStringLiteral("open62541")) {
- node.reset(opcuaClient->node("ns=2;s=Demo.Static.Arrays.Argument"));
- QVERIFY(node != nullptr);
- READ_MANDATORY_VARIABLE_NODE(node)
- QVariant argumentArray = node->attribute(QOpcUa::NodeAttribute::Value);
- QCOMPARE(argumentArray.type(), QVariant::List);
- QCOMPARE(argumentArray.toList().length(), 3);
- QCOMPARE(argumentArray.toList()[0].value<QOpcUa::QArgument>(), testArguments[0]);
- QCOMPARE(argumentArray.toList()[1].value<QOpcUa::QArgument>(), testArguments[1]);
- QCOMPARE(argumentArray.toList()[2].value<QOpcUa::QArgument>(), testArguments[2]);
- } else {
- qInfo("The argument type is currently only supported in the open62541 backend");
- }
+ node.reset(opcuaClient->node("ns=2;s=Demo.Static.Arrays.Argument"));
+ QVERIFY(node != nullptr);
+ READ_MANDATORY_VARIABLE_NODE(node)
+ QVariant argumentArray = node->attribute(QOpcUa::NodeAttribute::Value);
+ QCOMPARE(argumentArray.type(), QVariant::List);
+ QCOMPARE(argumentArray.toList().length(), 3);
+ QCOMPARE(argumentArray.toList()[0].value<QOpcUaArgument>(), testArguments[0]);
+ QCOMPARE(argumentArray.toList()[1].value<QOpcUaArgument>(), testArguments[1]);
+ QCOMPARE(argumentArray.toList()[2].value<QOpcUaArgument>(), testArguments[2]);
}
void Tst_QOpcUaClient::writeScalar()
@@ -2451,7 +2470,7 @@ void Tst_QOpcUaClient::writeScalar()
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.QualifiedName"));
QVERIFY(node != nullptr);
- WRITE_VALUE_ATTRIBUTE(node, QOpcUa::QQualifiedName(0, QLatin1String("Test0")), QOpcUa::QualifiedName);
+ WRITE_VALUE_ATTRIBUTE(node, QOpcUaQualifiedName(0, QLatin1String("Test0")), QOpcUa::QualifiedName);
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.StatusCode"));
QVERIFY(node != nullptr);
@@ -2481,17 +2500,13 @@ void Tst_QOpcUaClient::writeScalar()
QVERIFY(node != nullptr);
WRITE_VALUE_ATTRIBUTE(node, QVariant::fromValue(testXV[0]), QOpcUa::XV);
- if (opcuaClient->backend() != QLatin1String("open62541"))
- qInfo("The uacpp backend currently does not support writing extension objects");
- else {
- node.reset(opcuaClient->node(QStringLiteral("ns=2;s=Demo.Static.Scalar.ExtensionObject")));
- QVERIFY(node != nullptr);
+ node.reset(opcuaClient->node(QStringLiteral("ns=2;s=Demo.Static.Scalar.ExtensionObject")));
+ QVERIFY(node != nullptr);
- QOpcUa::QExtensionObject obj;
- ENCODE_EXTENSION_OBJECT(obj, 0);
+ QOpcUaExtensionObject obj;
+ ENCODE_EXTENSION_OBJECT(obj, 0);
- WRITE_VALUE_ATTRIBUTE(node, obj, QOpcUa::Types::ExtensionObject); // Write value to check for
- }
+ WRITE_VALUE_ATTRIBUTE(node, obj, QOpcUa::Types::ExtensionObject); // Write value to check for
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.XmlElement"));
QVERIFY(node != nullptr);
@@ -2501,13 +2516,9 @@ void Tst_QOpcUaClient::writeScalar()
QVERIFY(node != nullptr);
WRITE_VALUE_ATTRIBUTE(node, testExpandedNodeId[0], QOpcUa::ExpandedNodeId);
- if (opcuaClient->backend() == QStringLiteral("open62541")) {
- node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.Argument"));
- QVERIFY(node != nullptr);
- WRITE_VALUE_ATTRIBUTE(node, testArguments[0], QOpcUa::Argument);
- } else {
- qInfo("The argument type is currently only supported in the open62541 backend");
- }
+ node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.Argument"));
+ QVERIFY(node != nullptr);
+ WRITE_VALUE_ATTRIBUTE(node, testArguments[0], QOpcUa::Argument);
}
void Tst_QOpcUaClient::readScalar()
@@ -2575,7 +2586,7 @@ void Tst_QOpcUaClient::readScalar()
READ_MANDATORY_VARIABLE_NODE(node);
QVariant ltScalar = node->attribute(QOpcUa::NodeAttribute::Value);
QVERIFY(ltScalar.isValid());
- QCOMPARE(ltScalar.value<QOpcUa::QLocalizedText>(), localizedTexts[0]);
+ QCOMPARE(ltScalar.value<QOpcUaLocalizedText>(), localizedTexts[0]);
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.UInt16"));
QVERIFY(node != nullptr);
@@ -2656,7 +2667,7 @@ void Tst_QOpcUaClient::readScalar()
QVERIFY(node != nullptr);
READ_MANDATORY_VARIABLE_NODE(node)
QVariant qualifiedNameScalar = node->attribute(QOpcUa::NodeAttribute::Value);
- QCOMPARE(qualifiedNameScalar.value<QOpcUa::QQualifiedName>(), QOpcUa::QQualifiedName(0, "Test0"));
+ QCOMPARE(qualifiedNameScalar.value<QOpcUaQualifiedName>(), QOpcUaQualifiedName(0, "Test0"));
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.StatusCode"));
QVERIFY(node != nullptr);
@@ -2668,44 +2679,40 @@ void Tst_QOpcUaClient::readScalar()
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.Range"));
QVERIFY(node != nullptr);
READ_MANDATORY_VARIABLE_NODE(node);
- QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUa::QRange>(), testRanges[0]);
+ QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUaRange>(), testRanges[0]);
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.EUInformation"));
QVERIFY(node != nullptr);
READ_MANDATORY_VARIABLE_NODE(node);
- QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUa::QEUInformation>(), testEUInfos[0]);
+ QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUaEUInformation>(), testEUInfos[0]);
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.ComplexNumber"));
QVERIFY(node != nullptr);
READ_MANDATORY_VARIABLE_NODE(node);
- QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUa::QComplexNumber>(), testComplex[0]);
+ QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUaComplexNumber>(), testComplex[0]);
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.DoubleComplexNumber"));
QVERIFY(node != nullptr);
READ_MANDATORY_VARIABLE_NODE(node);
- QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUa::QDoubleComplexNumber>(), testDoubleComplex[0]);
+ QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUaDoubleComplexNumber>(), testDoubleComplex[0]);
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.AxisInformation"));
QVERIFY(node != nullptr);
READ_MANDATORY_VARIABLE_NODE(node);
- QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUa::QAxisInformation>(), testAxisInfo[0]);
+ QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUaAxisInformation>(), testAxisInfo[0]);
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.XV"));
QVERIFY(node != nullptr);
READ_MANDATORY_VARIABLE_NODE(node);
- QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUa::QXValue>(), testXV[0]);
+ QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUaXValue>(), testXV[0]);
- if (opcuaClient->backend() != QLatin1String("open62541"))
- qInfo("The uacpp backend currently does not support reading extension objects");
- else {
- node.reset(opcuaClient->node(QStringLiteral("ns=2;s=Demo.Static.Scalar.ExtensionObject")));
- QVERIFY(node != nullptr);
+ node.reset(opcuaClient->node(QStringLiteral("ns=2;s=Demo.Static.Scalar.ExtensionObject")));
+ QVERIFY(node != nullptr);
- READ_MANDATORY_VARIABLE_NODE(node);
+ READ_MANDATORY_VARIABLE_NODE(node);
- QOpcUa::QExtensionObject obj = node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUa::QExtensionObject>();
- VERIFY_EXTENSION_OBJECT(obj, 0);
- }
+ QOpcUaExtensionObject obj = node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUaExtensionObject>();
+ VERIFY_EXTENSION_OBJECT(obj, 0);
node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.XmlElement"));
QVERIFY(node != nullptr);
@@ -2720,18 +2727,14 @@ void Tst_QOpcUaClient::readScalar()
READ_MANDATORY_VARIABLE_NODE(node)
QVariant expandedNodeIdScalar = node->attribute(QOpcUa::NodeAttribute::Value);
QVERIFY(expandedNodeIdScalar.isValid());
- QCOMPARE(expandedNodeIdScalar.value<QOpcUa::QExpandedNodeId>(), testExpandedNodeId[0]);
+ QCOMPARE(expandedNodeIdScalar.value<QOpcUaExpandedNodeId>(), testExpandedNodeId[0]);
- if (opcuaClient->backend() == QStringLiteral("open62541")) {
- node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.Argument"));
- QVERIFY(node != nullptr);
- READ_MANDATORY_VARIABLE_NODE(node)
- QVariant argumentScalar = node->attribute(QOpcUa::NodeAttribute::Value);
- QVERIFY(argumentScalar.isValid());
- QCOMPARE(argumentScalar.value<QOpcUa::QArgument>(), testArguments[0]);
- } else {
- qInfo("The argument type is currently only supported in the open62541 backend");
- }
+ node.reset(opcuaClient->node("ns=2;s=Demo.Static.Scalar.Argument"));
+ QVERIFY(node != nullptr);
+ READ_MANDATORY_VARIABLE_NODE(node)
+ QVariant argumentScalar = node->attribute(QOpcUa::NodeAttribute::Value);
+ QVERIFY(argumentScalar.isValid());
+ QCOMPARE(argumentScalar.value<QOpcUaArgument>(), testArguments[0]);
}
void Tst_QOpcUaClient::indexRange()
@@ -2748,13 +2751,13 @@ void Tst_QOpcUaClient::indexRange()
QSignalSpy attributeWrittenSpy(node.data(), &QOpcUaNode::attributeWritten);
node->writeAttributeRange(QOpcUa::NodeAttribute::Value, QVariantList({10, 11, 12, 13}), "0:3", QOpcUa::Types::Int32);
- attributeWrittenSpy.wait();
+ attributeWrittenSpy.wait(signalSpyTimeout);
QCOMPARE(attributeWrittenSpy.size(), 1);
QCOMPARE(attributeWrittenSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
QSignalSpy attributeReadSpy(node.data(), &QOpcUaNode::attributeRead);
node->readAttributeRange(QOpcUa::NodeAttribute::Value, "0:6");
- attributeReadSpy.wait();
+ attributeReadSpy.wait(signalSpyTimeout);
QCOMPARE(attributeReadSpy.count(), 1);
QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).toList(), QVariantList({10, 11, 12, 13, 4, 5, 6}));
@@ -2774,13 +2777,13 @@ void Tst_QOpcUaClient::invalidIndexRange()
QSignalSpy attributeWrittenSpy(node.data(), &QOpcUaNode::attributeWritten);
node->writeAttributeRange(QOpcUa::NodeAttribute::Value, QVariantList({10, 11, 12, 13}), "notavalidrange", QOpcUa::Types::Int32);
- attributeWrittenSpy.wait();
+ attributeWrittenSpy.wait(signalSpyTimeout);
QCOMPARE(attributeWrittenSpy.size(), 1);
QCOMPARE(attributeWrittenSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::BadIndexRangeInvalid);
QSignalSpy attributeReadSpy(node.data(), &QOpcUaNode::attributeRead);
node->readAttributeRange(QOpcUa::NodeAttribute::Value, "notavalidrange");
- attributeReadSpy.wait();
+ attributeReadSpy.wait(signalSpyTimeout);
QCOMPARE(attributeReadSpy.count(), 1);
QCOMPARE(node->attributeError(QOpcUa::NodeAttribute::Value), QOpcUa::UaStatusCode::BadIndexRangeInvalid);
@@ -2806,33 +2809,33 @@ void Tst_QOpcUaClient::subscriptionIndexRange()
writeSpy.clear();
integerArrayNode->enableMonitoring(QOpcUa::NodeAttribute::Value, p);
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
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.wait(signalSpyTimeout); // 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();
+ writeSpy.wait(signalSpyTimeout);
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();
+ dataChangeSpy.wait(signalSpyTimeout);
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();
+ writeSpy.wait(signalSpyTimeout);
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();
+ dataChangeSpy.wait(signalSpyTimeout);
QCOMPARE(dataChangeSpy.size(), 1);
QCOMPARE(integerArrayNode->attribute(QOpcUa::NodeAttribute::Value).toDouble(), 10.0);
integerArrayNode->disableMonitoring(QOpcUa::NodeAttribute::Value);
- monitoringDisabledSpy.wait();
+ monitoringDisabledSpy.wait(signalSpyTimeout);
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);
@@ -2843,6 +2846,9 @@ void Tst_QOpcUaClient::subscriptionDataChangeFilter()
QFETCH(QOpcUaClient *, opcuaClient);
OpcuaConnector connector(opcuaClient, m_endpoint);
+ QScopedPointer<QOpcUaNode> doubleWriteNode(opcuaClient->node("ns=2;s=Demo.Static.Scalar.Double"));
+ QVERIFY(doubleWriteNode != nullptr);
+
QScopedPointer<QOpcUaNode> doubleNode(opcuaClient->node("ns=2;s=Demo.Static.Scalar.Double"));
QVERIFY(doubleNode != nullptr);
@@ -2851,51 +2857,63 @@ void Tst_QOpcUaClient::subscriptionDataChangeFilter()
QSignalSpy monitoringEnabledSpy(doubleNode.data(), &QOpcUaNode::enableMonitoringFinished);
QSignalSpy monitoringDisabledSpy(doubleNode.data(), &QOpcUaNode::disableMonitoringFinished);
QSignalSpy dataChangeSpy(doubleNode.data(), &QOpcUaNode::dataChangeOccurred);
+ QSignalSpy attributeUpdatedSpy(doubleNode.data(), &QOpcUaNode::attributeUpdated);
QSignalSpy monitoringModifiedSpy(doubleNode.data(), &QOpcUaNode::monitoringStatusChanged);
- WRITE_VALUE_ATTRIBUTE(doubleNode, 1.0, QOpcUa::Types::Double);
+ WRITE_VALUE_ATTRIBUTE(doubleWriteNode, 1.0, QOpcUa::Types::Double);
doubleNode->enableMonitoring(QOpcUa::NodeAttribute::Value, p);
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
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.wait(signalSpyTimeout); // Wait for the initial data change
+ attributeUpdatedSpy.wait(signalSpyTimeout);
QCOMPARE(dataChangeSpy.size(), 1);
+ QCOMPARE(attributeUpdatedSpy.size(), 1);
dataChangeSpy.clear();
+ attributeUpdatedSpy.clear();
- WRITE_VALUE_ATTRIBUTE(doubleNode, 1.5, QOpcUa::Types::Double);
+ WRITE_VALUE_ATTRIBUTE(doubleWriteNode, 1.5, QOpcUa::Types::Double);
- dataChangeSpy.wait();
+ dataChangeSpy.wait(signalSpyTimeout);
+ attributeUpdatedSpy.wait(signalSpyTimeout);
QCOMPARE(dataChangeSpy.size(), 1); // Data change without filter
+ QCOMPARE(attributeUpdatedSpy.size(), 1);
QCOMPARE(doubleNode->attribute(QOpcUa::NodeAttribute::Value), 1.5);
dataChangeSpy.clear();
+ attributeUpdatedSpy.clear();
QOpcUaMonitoringParameters::DataChangeFilter filter;
filter.setDeadbandType(QOpcUaMonitoringParameters::DataChangeFilter::DeadbandType::Absolute);
filter.setTrigger(QOpcUaMonitoringParameters::DataChangeFilter::DataChangeTrigger::StatusOrValue);
filter.setDeadbandValue(1.0);
doubleNode->modifyDataChangeFilter(QOpcUa::NodeAttribute::Value, filter);
- monitoringModifiedSpy.wait();
+ monitoringModifiedSpy.wait(signalSpyTimeout);
QCOMPARE(monitoringModifiedSpy.size(), 1);
QCOMPARE(monitoringModifiedSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value);
QVERIFY(monitoringModifiedSpy.at(0).at(1).value<QOpcUaMonitoringParameters::Parameters>() & QOpcUaMonitoringParameters::Parameter::Filter);
QCOMPARE(monitoringModifiedSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
- WRITE_VALUE_ATTRIBUTE(doubleNode, 2.0, QOpcUa::Types::Double);
+ WRITE_VALUE_ATTRIBUTE(doubleWriteNode, 2.0, QOpcUa::Types::Double);
- dataChangeSpy.wait();
+ dataChangeSpy.wait(signalSpyTimeout);
+ attributeUpdatedSpy.wait(signalSpyTimeout);
QCOMPARE(dataChangeSpy.size(), 0); // Filter is active and delta is < 1
+ QCOMPARE(attributeUpdatedSpy.size(), 0);
+ attributeUpdatedSpy.clear();
- WRITE_VALUE_ATTRIBUTE(doubleNode, 3.0, QOpcUa::Types::Double);
+ WRITE_VALUE_ATTRIBUTE(doubleWriteNode, 3.0, QOpcUa::Types::Double);
- dataChangeSpy.wait();
+ dataChangeSpy.wait(signalSpyTimeout);
+ attributeUpdatedSpy.wait(signalSpyTimeout);
QCOMPARE(dataChangeSpy.size(), 1); // delta == 1, a data change is expected
+ QCOMPARE(attributeUpdatedSpy.size(), 1);
QCOMPARE(doubleNode->attribute(QOpcUa::NodeAttribute::Value), 3.0);
doubleNode->disableMonitoring(QOpcUa::NodeAttribute::Value);
- monitoringDisabledSpy.wait();
+ monitoringDisabledSpy.wait(signalSpyTimeout);
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);
@@ -2919,33 +2937,33 @@ void Tst_QOpcUaClient::modifyPublishingMode()
WRITE_VALUE_ATTRIBUTE(doubleNode, 1.0, QOpcUa::Types::Double);
doubleNode->enableMonitoring(QOpcUa::NodeAttribute::Value, p);
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
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.wait(signalSpyTimeout); // Wait for the initial data change
QCOMPARE(dataChangeSpy.size(), 1);
dataChangeSpy.clear();
WRITE_VALUE_ATTRIBUTE(doubleNode, 1.5, QOpcUa::Types::Double);
- dataChangeSpy.wait();
+ dataChangeSpy.wait(signalSpyTimeout);
QCOMPARE(dataChangeSpy.size(), 1);
dataChangeSpy.clear();
doubleNode->modifyMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters::Parameter::PublishingEnabled, false);
- monitoringStatusSpy.wait();
+ monitoringStatusSpy.wait(signalSpyTimeout);
QCOMPARE(monitoringStatusSpy.size(), 1);
QCOMPARE(monitoringStatusSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
WRITE_VALUE_ATTRIBUTE(doubleNode, 3.0, QOpcUa::Types::Double);
- dataChangeSpy.wait();
+ dataChangeSpy.wait(signalSpyTimeout);
QCOMPARE(dataChangeSpy.size(), 0);
doubleNode->disableMonitoring(QOpcUa::NodeAttribute::Value);
- monitoringDisabledSpy.wait();
+ monitoringDisabledSpy.wait(signalSpyTimeout);
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);
@@ -2969,34 +2987,34 @@ void Tst_QOpcUaClient::modifyMonitoringMode()
WRITE_VALUE_ATTRIBUTE(doubleNode, 1.0, QOpcUa::Types::Double);
doubleNode->enableMonitoring(QOpcUa::NodeAttribute::Value, p);
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
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.wait(signalSpyTimeout); // Wait for the initial data change
QCOMPARE(dataChangeSpy.size(), 1);
dataChangeSpy.clear();
WRITE_VALUE_ATTRIBUTE(doubleNode, 1.5, QOpcUa::Types::Double);
- dataChangeSpy.wait();
+ dataChangeSpy.wait(signalSpyTimeout);
QCOMPARE(dataChangeSpy.size(), 1);
dataChangeSpy.clear();
doubleNode->modifyMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters::Parameter::MonitoringMode,
QVariant::fromValue(QOpcUaMonitoringParameters::MonitoringMode::Disabled));
- monitoringStatusSpy.wait();
+ monitoringStatusSpy.wait(signalSpyTimeout);
QCOMPARE(monitoringStatusSpy.size(), 1);
QCOMPARE(monitoringStatusSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
WRITE_VALUE_ATTRIBUTE(doubleNode, 3.0, QOpcUa::Types::Double);
- dataChangeSpy.wait();
+ dataChangeSpy.wait(signalSpyTimeout);
QCOMPARE(dataChangeSpy.size(), 0);
doubleNode->disableMonitoring(QOpcUa::NodeAttribute::Value);
- monitoringDisabledSpy.wait();
+ monitoringDisabledSpy.wait(signalSpyTimeout);
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);
@@ -3020,24 +3038,24 @@ void Tst_QOpcUaClient::modifyMonitoredItem()
WRITE_VALUE_ATTRIBUTE(doubleNode, 1.0, QOpcUa::Types::Double);
doubleNode->enableMonitoring(QOpcUa::NodeAttribute::Value, p);
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
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.wait(signalSpyTimeout); // Wait for the initial data change
QCOMPARE(dataChangeSpy.size(), 1);
dataChangeSpy.clear();
WRITE_VALUE_ATTRIBUTE(doubleNode, 1.5, QOpcUa::Types::Double);
- dataChangeSpy.wait();
+ dataChangeSpy.wait(signalSpyTimeout);
QCOMPARE(dataChangeSpy.size(), 1);
QCOMPARE(dataChangeSpy.at(0).at(1).value<double>(), 1.5);
dataChangeSpy.clear();
doubleNode->modifyMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters::Parameter::SamplingInterval, 50.0);
- monitoringStatusSpy.wait();
+ monitoringStatusSpy.wait(signalSpyTimeout);
QCOMPARE(monitoringStatusSpy.size(), 1);
QCOMPARE(monitoringStatusSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
QCOMPARE(monitoringStatusSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value);
@@ -3045,11 +3063,11 @@ void Tst_QOpcUaClient::modifyMonitoredItem()
WRITE_VALUE_ATTRIBUTE(doubleNode, 3.0, QOpcUa::Types::Double);
- dataChangeSpy.wait();
+ dataChangeSpy.wait(signalSpyTimeout);
QCOMPARE(dataChangeSpy.size(), 1);
doubleNode->disableMonitoring(QOpcUa::NodeAttribute::Value);
- monitoringDisabledSpy.wait();
+ monitoringDisabledSpy.wait(signalSpyTimeout);
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);
@@ -3069,7 +3087,7 @@ void Tst_QOpcUaClient::addDuplicateMonitoredItem()
QSignalSpy monitoringDisabledSpy(doubleNode.data(), &QOpcUaNode::disableMonitoringFinished);
doubleNode->enableMonitoring(QOpcUa::NodeAttribute::Value, p);
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
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);
@@ -3077,14 +3095,14 @@ void Tst_QOpcUaClient::addDuplicateMonitoredItem()
monitoringEnabledSpy.clear();
doubleNode->enableMonitoring(QOpcUa::NodeAttribute::Value, p);
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
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::BadEntryExists);
QCOMPARE(doubleNode->monitoringStatus(QOpcUa::NodeAttribute::Value).statusCode(), QOpcUa::UaStatusCode::Good);
doubleNode->disableMonitoring(QOpcUa::NodeAttribute::Value);
- monitoringDisabledSpy.wait();
+ monitoringDisabledSpy.wait(signalSpyTimeout);
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);
@@ -3104,9 +3122,9 @@ void Tst_QOpcUaClient::checkMonitoredItemCleanup()
QSignalSpy monitoringEnabledSpy(readWriteNode.data(), &QOpcUaNode::enableMonitoringFinished);
QOpcUa::NodeAttributes attr = QOpcUa::NodeAttribute::Value | QOpcUa::NodeAttribute::BrowseName;
readWriteNode->enableMonitoring(attr, QOpcUaMonitoringParameters(100, QOpcUaMonitoringParameters::SubscriptionType::Exclusive));
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
if (monitoringEnabledSpy.size() != 2)
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
QCOMPARE(monitoringEnabledSpy.size(), 2);
for (auto entry : monitoringEnabledSpy) {
@@ -3122,7 +3140,7 @@ void Tst_QOpcUaClient::checkMonitoredItemCleanup()
parameter.append(QOpcUa::TypedVariant(QVariant(quint32(subscriptionId)), QOpcUa::Types::UInt32));
serverNode->callMethod(QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::Server_GetMonitoredItems), parameter);
- methodSpy.wait();
+ methodSpy.wait(signalSpyTimeout);
QCOMPARE(methodSpy.size(), 1);
for (auto entry : methodSpy) {
@@ -3134,10 +3152,10 @@ void Tst_QOpcUaClient::checkMonitoredItemCleanup()
readWriteNode.reset(); // Delete the node object
- methodSpy.wait(); // Give the backend some time to process the deletion request
+ methodSpy.wait(signalSpyTimeout); // Give the backend some time to process the deletion request
methodSpy.clear();
serverNode->callMethod(QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::Server_GetMonitoredItems), parameter);
- methodSpy.wait();
+ methodSpy.wait(signalSpyTimeout);
QCOMPARE(methodSpy.size(), 1);
QCOMPARE(methodSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::BadNoMatch);
}
@@ -3153,15 +3171,15 @@ void Tst_QOpcUaClient::checkAttributeUpdated()
QSignalSpy spy(node.data(), &QOpcUaNode::attributeUpdated);
node->readAttributes(QOpcUa::NodeAttribute::Value);
- spy.wait();
+ spy.wait(signalSpyTimeout);
QCOMPARE(spy.size(), 1);
node->writeValueAttribute(23.0, QOpcUa::Types::Double);
- spy.wait();
+ spy.wait(signalSpyTimeout);
QCOMPARE(spy.size(), 2);
node->enableMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters(100));
- spy.wait();
+ spy.wait(signalSpyTimeout);
QCOMPARE(spy.size(), 3);
for (auto it : spy) {
@@ -3186,8 +3204,8 @@ void Tst_QOpcUaClient::stringCharset()
QVERIFY(localizedArrayNode != nullptr);
QString testString = QString::fromUtf8("🞀🞁🞂🞃");
- QOpcUa::QLocalizedText lt1("en", testString);
- QOpcUa::QLocalizedText lt2("de", testString);
+ QOpcUaLocalizedText lt1("en", testString);
+ QOpcUaLocalizedText lt2("de", testString);
WRITE_VALUE_ATTRIBUTE(stringScalarNode, testString, QOpcUa::String);
WRITE_VALUE_ATTRIBUTE(localizedScalarNode, localizedTexts[0], QOpcUa::LocalizedText);
@@ -3212,7 +3230,7 @@ void Tst_QOpcUaClient::stringCharset()
QVariant result = stringScalarNode->attribute(QOpcUa::NodeAttribute::Value);
QCOMPARE(result.toString(), testString);
result = localizedScalarNode->attribute(QOpcUa::NodeAttribute::Value);
- QCOMPARE(result.value<QOpcUa::QLocalizedText>(), localizedTexts[0]);
+ QCOMPARE(result.value<QOpcUaLocalizedText>(), localizedTexts[0]);
result = stringArrayNode->attribute(QOpcUa::NodeAttribute::Value);
QCOMPARE(result.type(), QVariant::List);
@@ -3225,8 +3243,8 @@ void Tst_QOpcUaClient::stringCharset()
result = localizedArrayNode->attribute(QOpcUa::NodeAttribute::Value);
QCOMPARE(result.type(), QVariant::List);
QCOMPARE(result.toList().length(), 2);
- QCOMPARE(result.toList()[0].value<QOpcUa::QLocalizedText>(), lt1);
- QCOMPARE(result.toList()[1].value<QOpcUa::QLocalizedText>(), lt2);
+ QCOMPARE(result.toList()[0].value<QOpcUaLocalizedText>(), lt1);
+ QCOMPARE(result.toList()[1].value<QOpcUaLocalizedText>(), lt2);
}
void Tst_QOpcUaClient::namespaceArray()
@@ -3237,7 +3255,7 @@ void Tst_QOpcUaClient::namespaceArray()
QSignalSpy spy(opcuaClient, &QOpcUaClient::namespaceArrayUpdated);
QCOMPARE(opcuaClient->updateNamespaceArray(), true);
- spy.wait();
+ spy.wait(signalSpyTimeout);
QCOMPARE(spy.size(), 1);
QStringList namespaces = opcuaClient->namespaceArray();
@@ -3249,29 +3267,25 @@ void Tst_QOpcUaClient::namespaceArray()
QScopedPointer<QOpcUaNode> node(opcuaClient->node(QOpcUa::nodeIdFromString(nsIndex, QStringLiteral("Demo.Static.Scalar.String"))));
READ_MANDATORY_BASE_NODE(node);
- QCOMPARE(node->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUa::QLocalizedText>().text(), QStringLiteral("StringScalarTest"));
+ QCOMPARE(node->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>().text(), QStringLiteral("StringScalarTest"));
}
void Tst_QOpcUaClient::multiDimensionalArray()
{
QFETCH(QOpcUaClient *, opcuaClient);
-
- if (opcuaClient->backend() != QStringLiteral("open62541"))
- QSKIP("Multidimensional arrays are only supported in open62541");
-
OpcuaConnector connector(opcuaClient, m_endpoint);
QScopedPointer<QOpcUaNode> node(opcuaClient->node("ns=2;s=Demo.Static.Arrays.MultiDimensionalDouble"));
QVector<quint32> arrayDimensions({2, 2, 3});
QVariantList value({0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0});
- QOpcUa::QMultiDimensionalArray arr(value, arrayDimensions);
+ QOpcUaMultiDimensionalArray arr(value, arrayDimensions);
QVERIFY(arr.isValid());
WRITE_VALUE_ATTRIBUTE(node, arr , QOpcUa::Double);
READ_MANDATORY_VARIABLE_NODE(node);
QCOMPARE(node->attributeError(QOpcUa::NodeAttribute::Value), QOpcUa::UaStatusCode::Good);
- QOpcUa::QMultiDimensionalArray readBack = node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUa::QMultiDimensionalArray>();
+ QOpcUaMultiDimensionalArray readBack = node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUaMultiDimensionalArray>();
QVERIFY(readBack.isValid());
QCOMPARE(readBack.value({0, 0, 0}), 0.0);
@@ -3339,12 +3353,12 @@ void Tst_QOpcUaClient::timeStamps()
stringScalarNode->enableMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters(100));
- monitoringEnabledSpy.wait();
+ monitoringEnabledSpy.wait(signalSpyTimeout);
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();
+ dataChangeSpy.wait(signalSpyTimeout);
const QDateTime sourceDataChange = stringScalarNode->sourceTimestamp(QOpcUa::NodeAttribute::Value);
const QDateTime serverDataChange = stringScalarNode->serverTimestamp(QOpcUa::NodeAttribute::Value);
@@ -3354,7 +3368,7 @@ void Tst_QOpcUaClient::timeStamps()
QVERIFY(serverRead < serverDataChange);
stringScalarNode->disableMonitoring(QOpcUa::NodeAttribute::Value);
- monitoringDisabledSpy.wait();
+ monitoringDisabledSpy.wait(signalSpyTimeout);
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);
@@ -3367,12 +3381,12 @@ void Tst_QOpcUaClient::createNodeFromExpandedId()
QSignalSpy updateSpy(opcuaClient, &QOpcUaClient::namespaceArrayUpdated);
opcuaClient->updateNamespaceArray();
- updateSpy.wait();
+ updateSpy.wait(signalSpyTimeout);
QVERIFY(updateSpy.size() > 0);
QVERIFY(opcuaClient->namespaceArray().size() > 0);
// Node on a remote server, nullptr expected
- QOpcUa::QExpandedNodeId id;
+ QOpcUaExpandedNodeId id;
id.setNodeId(QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::RootFolder));
id.setServerIndex(1);
QScopedPointer<QOpcUaNode> node(opcuaClient->node(id));
@@ -3383,7 +3397,7 @@ void Tst_QOpcUaClient::createNodeFromExpandedId()
node.reset(opcuaClient->node(id));
QVERIFY(node != nullptr);
READ_MANDATORY_BASE_NODE(node);
- QCOMPARE(node->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUa::QQualifiedName>(), QOpcUa::QQualifiedName(0, QStringLiteral("Root")));
+ QCOMPARE(node->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>(), QOpcUaQualifiedName(0, QStringLiteral("Root")));
// Successful namespace substitution, valid pointer expected
id.setNodeId("ns=0;s=TestNode.ReadWrite");
@@ -3392,8 +3406,8 @@ void Tst_QOpcUaClient::createNodeFromExpandedId()
QVERIFY(node != nullptr);
QCOMPARE(node->nodeId(), QStringLiteral("ns=3;s=TestNode.ReadWrite"));
READ_MANDATORY_BASE_NODE(node);
- QCOMPARE(node->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUa::QQualifiedName>(),
- QOpcUa::QQualifiedName(3, QStringLiteral("TestNode.ReadWrite")));
+ QCOMPARE(node->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>(),
+ QOpcUaQualifiedName(3, QStringLiteral("TestNode.ReadWrite")));
// Invalid namespace, nullptr expected
id.setNodeId("ns=0;s=TestNode.ReadWrite");
@@ -3408,7 +3422,7 @@ void Tst_QOpcUaClient::checkExpandedIdConversion()
// Before the namespace array is populated, error expected
bool ok = true;
- QOpcUa::QExpandedNodeId id;
+ QOpcUaExpandedNodeId id;
id.setNodeId(QStringLiteral("ns=0;i=84"));
id.setNamespaceUri(QStringLiteral("MyNameSpace"));
QString result = opcuaClient->resolveExpandedNodeId(id, &ok);
@@ -3420,7 +3434,7 @@ void Tst_QOpcUaClient::checkExpandedIdConversion()
OpcuaConnector connector(opcuaClient, m_endpoint);
- updateSpy.wait();
+ updateSpy.wait(signalSpyTimeout);
QVERIFY(updateSpy.size() > 0);
QVERIFY(!opcuaClient->namespaceArray().isEmpty());
@@ -3458,7 +3472,7 @@ void Tst_QOpcUaClient::checkExpandedIdConversionNoOk()
QFETCH(QOpcUaClient *, opcuaClient);
// Before the namespace array is populated, empty string expected
- QOpcUa::QExpandedNodeId id;
+ QOpcUaExpandedNodeId id;
id.setNodeId(QStringLiteral("ns=0;i=84"));
id.setNamespaceUri(QStringLiteral("MyNameSpace"));
QString result = opcuaClient->resolveExpandedNodeId(id);
@@ -3469,7 +3483,7 @@ void Tst_QOpcUaClient::checkExpandedIdConversionNoOk()
OpcuaConnector connector(opcuaClient, m_endpoint);
- updateSpy.wait();
+ updateSpy.wait(signalSpyTimeout);
QVERIFY(updateSpy.size() > 0);
QVERIFY(!opcuaClient->namespaceArray().isEmpty());
@@ -3502,27 +3516,27 @@ void Tst_QOpcUaClient::createQualifiedName()
// Before the namespace array is populated, empty qualified name expected
bool ok = true;
- QOpcUa::QQualifiedName name = opcuaClient->qualifiedNameFromNamespaceUri(QStringLiteral("Test Namespace"), QStringLiteral("Name"), &ok);
+ QOpcUaQualifiedName name = opcuaClient->qualifiedNameFromNamespaceUri(QStringLiteral("Test Namespace"), QStringLiteral("Name"), &ok);
QVERIFY(ok == false);
- QCOMPARE(name, QOpcUa::QQualifiedName());
+ QCOMPARE(name, QOpcUaQualifiedName());
QSignalSpy updateSpy(opcuaClient, &QOpcUaClient::namespaceArrayUpdated);
OpcuaConnector connector(opcuaClient, m_endpoint);
- updateSpy.wait();
+ updateSpy.wait(signalSpyTimeout);
QVERIFY(updateSpy.size() > 0);
QVERIFY(!opcuaClient->namespaceArray().isEmpty());
// Valid namespace, valid qualified name expected
name = opcuaClient->qualifiedNameFromNamespaceUri(QStringLiteral("Test Namespace"), QStringLiteral("Name"), &ok);
QVERIFY(ok == true);
- QCOMPARE(name, QOpcUa::QQualifiedName(3, QStringLiteral("Name")));
+ QCOMPARE(name, QOpcUaQualifiedName(3, QStringLiteral("Name")));
// Invalid namespace, empty qualified name expected
name = opcuaClient->qualifiedNameFromNamespaceUri(QStringLiteral("InvalidNamespace"), QStringLiteral("Name"), &ok);
QVERIFY(ok == false);
- QCOMPARE(name, QOpcUa::QQualifiedName());
+ QCOMPARE(name, QOpcUaQualifiedName());
}
void Tst_QOpcUaClient::createQualifiedNameNoOk()
@@ -3530,24 +3544,24 @@ void Tst_QOpcUaClient::createQualifiedNameNoOk()
QFETCH(QOpcUaClient *, opcuaClient);
// Before the namespace array is populated, empty qualified name expected
- QOpcUa::QQualifiedName name = opcuaClient->qualifiedNameFromNamespaceUri(QStringLiteral("Test Namespace"), QStringLiteral("Name"));
- QCOMPARE(name, QOpcUa::QQualifiedName());
+ QOpcUaQualifiedName name = opcuaClient->qualifiedNameFromNamespaceUri(QStringLiteral("Test Namespace"), QStringLiteral("Name"));
+ QCOMPARE(name, QOpcUaQualifiedName());
QSignalSpy updateSpy(opcuaClient, &QOpcUaClient::namespaceArrayUpdated);
OpcuaConnector connector(opcuaClient, m_endpoint);
- updateSpy.wait();
+ updateSpy.wait(signalSpyTimeout);
QVERIFY(updateSpy.size() > 0);
QVERIFY(!opcuaClient->namespaceArray().isEmpty());
// Valid namespace, valid qualified name expected
name = opcuaClient->qualifiedNameFromNamespaceUri(QStringLiteral("Test Namespace"), QStringLiteral("Name"));
- QCOMPARE(name, QOpcUa::QQualifiedName(3, QStringLiteral("Name")));
+ QCOMPARE(name, QOpcUaQualifiedName(3, QStringLiteral("Name")));
// Invalid namespace, empty qualified name expected
name = opcuaClient->qualifiedNameFromNamespaceUri(QStringLiteral("InvalidNamespace"), QStringLiteral("Name"));
- QCOMPARE(name, QOpcUa::QQualifiedName());
+ QCOMPARE(name, QOpcUaQualifiedName());
}
void Tst_QOpcUaClient::resolveBrowsePath()
@@ -3560,25 +3574,31 @@ void Tst_QOpcUaClient::resolveBrowsePath()
QSignalSpy spy(typesNode.data(), &QOpcUaNode::resolveBrowsePathFinished);
- QVector<QOpcUa::QRelativePathElement> path;
+ QVector<QOpcUaRelativePathElement> path;
const QString referenceTypeId = QOpcUa::nodeIdFromReferenceType(QOpcUa::ReferenceTypeId::Organizes);
- path.append(QOpcUa::QRelativePathElement(QOpcUa::QQualifiedName(0, "DataTypes"), referenceTypeId));
- path.append(QOpcUa::QRelativePathElement(QOpcUa::QQualifiedName(0, "BaseDataType"), referenceTypeId));
+ path.append(QOpcUaRelativePathElement(QOpcUaQualifiedName(0, "DataTypes"), referenceTypeId));
+ path.append(QOpcUaRelativePathElement(QOpcUaQualifiedName(0, "BaseDataType"), referenceTypeId));
bool success = typesNode->resolveBrowsePath(path);
QVERIFY(success == true);
- spy.wait();
+ spy.wait(signalSpyTimeout);
QCOMPARE(spy.size(), 1);
- QVector<QOpcUa::QBrowsePathTarget> results = spy.at(0).at(0).value<QVector<QOpcUa::QBrowsePathTarget>>();
+ QVector<QOpcUaBrowsePathTarget> results = spy.at(0).at(0).value<QVector<QOpcUaBrowsePathTarget>>();
QCOMPARE(results.size(), 1);
QCOMPARE(results.at(0).remainingPathIndex(), (std::numeric_limits<quint32>::max)());
QCOMPARE(results.at(0).targetId().nodeId(), QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::BaseDataType));
QVERIFY(results.at(0).targetId().namespaceUri().isEmpty());
QCOMPARE(results.at(0).targetId().serverIndex(), 0U);
- QCOMPARE(spy.at(0).at(1).value<QVector<QOpcUa::QRelativePathElement>>(), path);
+ QCOMPARE(spy.at(0).at(1).value<QVector<QOpcUaRelativePathElement>>(), path);
QCOMPARE(spy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
}
+void Tst_QOpcUaClient::statusStrings()
+{
+ QCOMPARE(statusToString(QOpcUa::Good), "Good");
+ QCOMPARE(statusToString(QOpcUa::BadAggregateConfigurationRejected), "BadAggregateConfigurationRejected");
+}
+
void Tst_QOpcUaClient::addNamespace()
{
QFETCH(QOpcUaClient *, opcuaClient);
@@ -3589,8 +3609,8 @@ void Tst_QOpcUaClient::addNamespace()
OpcuaConnector connector(opcuaClient, m_endpoint);
opcuaClient->updateNamespaceArray();
- namespaceUpdatedSpy.wait();
- namespaceChangedSpy.wait();
+ namespaceUpdatedSpy.wait(signalSpyTimeout);
+ namespaceChangedSpy.wait(signalSpyTimeout);
QVERIFY(namespaceUpdatedSpy.count() > 0);
QCOMPARE(namespaceChangedSpy.count(), 1);
@@ -3598,8 +3618,8 @@ void Tst_QOpcUaClient::addNamespace()
namespaceChangedSpy.clear();
namespaceUpdatedSpy.clear();
opcuaClient->updateNamespaceArray();
- namespaceUpdatedSpy.wait();
- namespaceChangedSpy.wait();
+ namespaceUpdatedSpy.wait(signalSpyTimeout);
+ namespaceChangedSpy.wait(signalSpyTimeout);
QCOMPARE(namespaceUpdatedSpy.count(), 1);
QCOMPARE(namespaceChangedSpy.count(), 0);
@@ -3624,7 +3644,7 @@ void Tst_QOpcUaClient::addNamespace()
bool success = node->callMethod("ns=3;s=Test.Method.AddNamespace", args);
QVERIFY(success == true);
- methodSpy.wait();
+ methodSpy.wait(signalSpyTimeout);
QCOMPARE(methodSpy.size(), 1);
QCOMPARE(methodSpy.at(0).at(0).value<QString>(), QStringLiteral("ns=3;s=Test.Method.AddNamespace"));
@@ -3632,7 +3652,7 @@ void Tst_QOpcUaClient::addNamespace()
QCOMPARE(QOpcUa::isSuccessStatus(methodSpy.at(0).at(2).value<QOpcUa::UaStatusCode>()), true);
// Do not call updateNamespaceArray()
- namespaceChangedSpy.wait();
+ namespaceChangedSpy.wait(signalSpyTimeout);
QVERIFY(namespaceUpdatedSpy.size() > 0);
QCOMPARE(namespaceChangedSpy.size(), 1);
@@ -3681,7 +3701,7 @@ void Tst_QOpcUaClient::connectionLost()
stringNode->readAttributes(QOpcUa::NodeAttribute::BrowseName);
- readSpy.wait();
+ readSpy.wait(signalSpyTimeout);
stateSpy.wait(10000); // uacpp and open62541 use a timeout of 5 seconds for service calls, better be safe.
QCOMPARE(readSpy.size(), 1);
QVERIFY(readSpy.at(0).at(0).value<QOpcUa::NodeAttributes>() & QOpcUa::NodeAttribute::BrowseName);
@@ -3701,6 +3721,7 @@ void Tst_QOpcUaClient::cleanupTestCase()
int main(int argc, char *argv[])
{
+ updateEnvironment();
QCoreApplication app(argc, argv);
QTEST_SET_MAIN_SOURCE_PATH
diff --git a/tests/auto/security/certs.qrc b/tests/auto/security/certs.qrc
new file mode 100644
index 0000000..2805c9a
--- /dev/null
+++ b/tests/auto/security/certs.qrc
@@ -0,0 +1,10 @@
+<RCC>
+ <qresource prefix="/">
+ <file>pki/own/certs/tst_security.der</file>
+ <file>pki/own/private/privateKeyWithoutPassword.pem</file>
+ <file>pki/own/private/privateKeyWithPassword:secret.pem</file>
+ <file>pki/trusted/certs/ca.der</file>
+ <file>pki/trusted/certs/open62541-testserver.der</file>
+ <file>pki/trusted/crl/ca.crl.pem</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/security/pki/own/certs/tst_security.der b/tests/auto/security/pki/own/certs/tst_security.der
new file mode 100644
index 0000000..f7527ba
--- /dev/null
+++ b/tests/auto/security/pki/own/certs/tst_security.der
Binary files differ
diff --git a/tests/auto/security/pki/own/private/privateKeyWithPassword:secret.pem b/tests/auto/security/pki/own/private/privateKeyWithPassword:secret.pem
new file mode 100644
index 0000000..ceaedfb
--- /dev/null
+++ b/tests/auto/security/pki/own/private/privateKeyWithPassword:secret.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,F0415EA92E761E40CACE6F74AC631227
+
+n7rW1/fjLfEVwWgeXoVfvS6L8Ij1KMBd8RLoETdicwS7m7MoYmjZ6r4zR/2Cz3Rh
+oHCw2tV9tXvpuG2e13CbAqv2HXRssdBHkWCwbvWFsi6Nb78mJMvD6dYPPP/yRM6Y
+BskE15tFr3Gjih4a10fzGs8yuDkg29bmcPhwDsXfYE0rSGZXsEJ+jArQxWM7c5BM
+mCq/FhYJTnezlLo1QEU+GfddZvanG3rZbNHhaSDqtIWXBECrEjpS6Y7EnkrSGInP
+q30+ND6sO8KbnOr4b8GU+fkzSZTitJcJwMRuBxn3N98cgMpWzBgJrvHPow9eW6EW
+133I0NXwMQeC1hd8jiXDMej+RWuPiXzc9cQa1YpNEmNiSsyO9QmIhWXdrxP1bTIE
+3NogCHmLlj13czEObui/BQtIbzQC8uBvzjIJsDiLII7iuaibCOOnk3e21xA/RZ/2
+VCoXjiDwURtri+82ZRS2fm5tHpvKb4HgOOEpuNNzb+bSlg280TrKV0VZ4263dl38
+WreEiPxSghfuRYsNSqL/634tdianwW3jVShCkYoAcX1dqRtPyevA7jBIj+4JwYZw
+kEsMlIB5IiNYgwn2IORK+CpxUtBovptgrzvpKOiJcP0tPCPf7IJ0hI8+bpbjx/Wv
+xnhApQ+qK86wcW71deW5bw5z0JSLa8OW06RyALcv365Na4h1z8JxNEl89w6luh9F
+8lEqWVV9uk0uN7amOeVcx/ykKYJBVwuBgtEp+99JWIT4Ds/RVtL3PO0xv5ewJDw2
+4RlmSDFoI2c+COIPJJJuIJ6u6roQuujSkSdWq/doQAI/gbPKBEPSgQbJ2PSxMOI8
+j+qG75hDtxd5ZhKKIi488ij2SFrZCUUzv2R54jL15VVh73KHHpmkvA7ju4c42W4b
+vrBfD6ZUez8WKz/tT0aGc0Uqznk82SZBA/qvkdGR/UbXVcv7mQDEsXLy24WjEZ+j
+CCbb3is191hRMpLWeBIMSfgBChEt7nHr6DQ7SbPHPXgr96xTl/wNyxjf3D0z1p/2
+9SwhlRiO/fSQMl1If4v5rdr0/KIt3GdgefAdolc/yEdXvB+2hJUNAce1xR68MjFP
+pqWkEiiALIGz6wl82xvukNh/JVOKoiBpgrPS5bHr1AJOV6Dn1kjX389p/GU+OF6R
+cUPVeY15m3eUpsvhmVqMYCOYrIl4YQCIOtnKpXIICyQpG9jaLw0jll6g7nPzyUvx
+7og0VtLnL65aQNKt/4ox1nxWcaf0NmuNKMwO3s4flvJxpvWAeCJWwRtHVl5stM82
+2dfthSQG7A59poujjZM5z8lZRU6Q+xG9QZf2rI4820IMiukwfoLvXTMUAzXWlKbh
+9GWb54uP1O8osnQe4SH1PzeJEz9P/bJ46rsHpnHpS9aRCdAQM0jFuU584PWsfHri
+3MvF1KHgJ8H4LbK5/iJfzcNV+ORNM2dUVKsBJ/ikNNyPO/xgiXoBJqxee6zzie+T
+8xSaSJGHfWjuto3Tn9BC1HBjbaJG6xqxpQWn7kA8YVExYBQEtDJAYXANObDZmmJV
+zJQIAvDPa8afp3llzz6udrNfkRezjYLjucM05zP9MtEFfpHcRNMAPDnkQAi8Ko9A
+-----END RSA PRIVATE KEY-----
diff --git a/tests/auto/security/pki/own/private/privateKeyWithoutPassword.pem b/tests/auto/security/pki/own/private/privateKeyWithoutPassword.pem
new file mode 100644
index 0000000..1ac9d84
--- /dev/null
+++ b/tests/auto/security/pki/own/private/privateKeyWithoutPassword.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDwfehGxb7k+Z8T
+GBkhwVHk4A8qi1w5vG7oXF9QtE5vNcl6JJCbZK7bVIDzDaNb2tk7FidaI5mQsZHz
+ptlRhuV8jLGzrvSuxv4bpJDC7MOaOZasbc5g90JU24v7tKEa+k17tcn+Tk8ePRIR
+JBuf8TLKEEZIqYHe2pVM8BL0Dmud0cQlkpj3F/RAVWkwh9xJIMuMsiOffI0HzF/2
+CSgbVdJKeZgco3MEpfkvLMtYtkCDFyA4XvSKaDB88YjJtGXlMC0XB7wFeWu1y6OZ
+RgLlS4Zir5/rKsSwuhzkIBjeHMwP/gxX2Y+rlrCAwjhuJ7hvev230+8VSKaEtY/Z
+M1rUgf3RAgMBAAECggEBALEUBHQYJvdy1i65D8hLEIH2eTRaaQ4aMY/mdEh4e0hn
+0nKdedzxxc656jkNUbvQ6SMYrOEyVWC1X0KJGHtvWIrdDfvAV2paG8E+61ib/WsR
+/F/6envrlGvnPKuZ1QaIR4VP1evqvVcGoMb+T1j1wPAIC7h1F6uAR27fVxVdiOAq
+pzw+gCqF1962aj/Tz7StU51WohtmMTJHouoGOqTFSoKW5Mya6Yf99A7W5I0hKCZr
+ddyKhX6TkbosGS5CP6lMK6P9KfZzzxP8v7g2OJ6Mfpb7U+nKggHvUtUz5UzuzSY5
+Iorf8fjLQtMRWGbDzLrtll/jPv1Hdh2YwdBOx2mAOAECgYEA/qv3oPuGn2Bt8qg0
+e8gyT+U4b8ssWIjcPBWgdsJo79RdF1xrHY3T0cC6EbMCO8ZDgwv+aMl9FBfJWRYM
+ObXITh5R5xMIBFpZHkBIEMNxfnQaH7RBNuYwiCSzmSptzNk+6z2TkZFFW6JfILTe
+rAiea0DeCKJakp2/N2UincUOc40CgYEA8b8B3PFZoxxDbRPhNwlvdSWNvLslBNU2
+/OhW19MnXwY7MMZVPt7YSVDaAcZEX1mU/eUTSzIvm6Sow0EXocS7nzmuoLnsnv9f
+vhtAkp3AEpvF0zNbD8MlT8z4El8JK+tW2XEtkE5HgjQt5YQrk4nc0eJIlHOTJw7y
+cbMg6OZUIFUCgYBxQlV8mKAEXURIeJnuutf1REHXJgpwzVz0s8GLT2aP0mgcLZPN
+rveW/xlBKdVCdCguLbVVMNaZiwKWxgFl4PxWEZHnLEWSegPMOlZSbjkZPdUoaGfg
+XHsU8Q2WfpIaWjtrLxVj1bF80TdxOj8VTzf1BwI34MxbDCCwKCA+/hYxOQKBgGId
+mvz4e+AGrZsM0YCL9M/AASnTbu/qNZoqFm0cR0N6/PUL2jddLL188i58MO3eJulx
+WwZPBSGPj+tHdPb0KQ4z1Btpuo7BqTM4TlnzaqxiysSweEoKcw9Tam/SYJ+Rsbsp
+A0wpaT6APQyFO0ZzUstgowKVcekNWPsqr7W3HffNAoGAJXZlTvCq/m1Zc176a0cN
+NayUjgWTeXIk+8RqB3/UeA5DLD5XfOUJPL/XvIZ2n5mlUrbMuHuvsXo0TnQm7sT2
+dt3jl0yo2JLtKXKuR5Q9KC7ehOUozIc9vsi0YzSL1zRHL35ZNx4wx/QNCfMuwUIT
+5EL80FokYrFEWZ5qRuyAT6M=
+-----END PRIVATE KEY-----
diff --git a/tests/auto/security/pki/trusted/certs/ca.der b/tests/auto/security/pki/trusted/certs/ca.der
new file mode 100644
index 0000000..3f31274
--- /dev/null
+++ b/tests/auto/security/pki/trusted/certs/ca.der
Binary files differ
diff --git a/tests/auto/security/pki/trusted/certs/open62541-testserver.der b/tests/auto/security/pki/trusted/certs/open62541-testserver.der
new file mode 100644
index 0000000..7aac4cd
--- /dev/null
+++ b/tests/auto/security/pki/trusted/certs/open62541-testserver.der
Binary files differ
diff --git a/tests/auto/security/pki/trusted/crl/ca.crl.pem b/tests/auto/security/pki/trusted/crl/ca.crl.pem
new file mode 100644
index 0000000..5adff29
--- /dev/null
+++ b/tests/auto/security/pki/trusted/crl/ca.crl.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBtDCBnQIBATANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJERTESMBAGA1UE
+CgwJb3BlbjYyNTQxMRYwFAYDVQQDDA1vcGVuNjI1NDEub3JnFw0xOTAyMDUwOTIx
+MjZaFw0xOTAzMDcwOTIxMjZaoDAwLjAfBgNVHSMEGDAWgBT2JxGCWDhuet+WnrDX
+1SXW4O8HNTALBgNVHRQEBAICEAAwDQYJKoZIhvcNAQELBQADggEBAF31DhT8Im+Z
+QkpkFtUzmM9FfjqD4vrkrCAAA6U382mwn5KDcm4LA+FjFePHgSyk+ytLD03z7hSp
+wgyxbldg4yC4GynUp7XcbB4zus6Lym/ayDgGVQEw81c/c7YAelc8u055TBJUcmuX
+/XV/JXfSO2ZWM5MZZCev79w8Oj4hmUPp9ZpAJkxt/GYictGSkDpBTMTAWRRenPUe
+F4qvkvYMkKMrURLFMfYcqa2ePszxnyjdfi6KXHllsHl0iHduSq1acAdx1G/itoDq
+ML7QLS/M/VBYYxSGghLPetanQ+6f+OYztgTuzw2nG4DXxfMhfijoi6LbfFDvy0K+
+mHqhbQW1Go8=
+-----END X509 CRL-----
diff --git a/tests/auto/security/security.pro b/tests/auto/security/security.pro
new file mode 100644
index 0000000..d3d203e
--- /dev/null
+++ b/tests/auto/security/security.pro
@@ -0,0 +1,9 @@
+TARGET = tst_security
+
+QT += testlib opcua network
+QT -= gui
+CONFIG += testcase
+RESOURCES += certs.qrc
+
+SOURCES += \
+ tst_security.cpp
diff --git a/tests/auto/security/tst_security.cpp b/tests/auto/security/tst_security.cpp
new file mode 100644
index 0000000..9460e46
--- /dev/null
+++ b/tests/auto/security/tst_security.cpp
@@ -0,0 +1,418 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtOpcUa/QOpcUaAuthenticationInformation>
+#include <QtOpcUa/QOpcUaClient>
+#include <QtOpcUa/QOpcUaEndpointDescription>
+#include <QtOpcUa/QOpcUaProvider>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QProcess>
+#include <QtCore/QScopedPointer>
+
+#include <QtTest/QSignalSpy>
+#include <QtTest/QtTest>
+#include <QTcpSocket>
+#include <QTcpServer>
+
+const int signalSpyTimeout = 10000;
+
+class OpcuaConnector
+{
+public:
+ OpcuaConnector(QOpcUaClient *client, const QOpcUaEndpointDescription &endPoint)
+ : opcuaClient(client)
+ {
+ QVERIFY(opcuaClient != nullptr);
+ QSignalSpy connectedSpy(opcuaClient, &QOpcUaClient::connected);
+ QSignalSpy disconnectedSpy(opcuaClient, &QOpcUaClient::disconnected);
+ QSignalSpy stateSpy(opcuaClient, &QOpcUaClient::stateChanged);
+
+ QTest::qWait(500);
+
+ opcuaClient->connectToEndpoint(endPoint);
+ QTRY_VERIFY2(opcuaClient->state() == QOpcUaClient::Connected, "Could not connect to server");
+
+ QCOMPARE(connectedSpy.count(), 1); // one connected signal fired
+ QCOMPARE(disconnectedSpy.count(), 0); // zero disconnected signals fired
+ QCOMPARE(stateSpy.count(), 2);
+
+ QCOMPARE(stateSpy.at(0).at(0).value<QOpcUaClient::ClientState>(),
+ QOpcUaClient::ClientState::Connecting);
+ QCOMPARE(stateSpy.at(1).at(0).value<QOpcUaClient::ClientState>(),
+ QOpcUaClient::ClientState::Connected);
+
+ stateSpy.clear();
+ connectedSpy.clear();
+ disconnectedSpy.clear();
+
+ QVERIFY(opcuaClient->endpoint() == endPoint);
+ }
+
+ ~OpcuaConnector()
+ {
+ QSignalSpy connectedSpy(opcuaClient, &QOpcUaClient::connected);
+ QSignalSpy disconnectedSpy(opcuaClient, &QOpcUaClient::disconnected);
+ QSignalSpy stateSpy(opcuaClient, &QOpcUaClient::stateChanged);
+ QSignalSpy errorSpy(opcuaClient, &QOpcUaClient::errorChanged);
+
+ QVERIFY(opcuaClient != nullptr);
+ if (opcuaClient->state() == QOpcUaClient::Connected) {
+
+ opcuaClient->disconnectFromEndpoint();
+
+ QTRY_VERIFY(opcuaClient->state() == QOpcUaClient::Disconnected);
+
+ QCOMPARE(connectedSpy.count(), 0);
+ QCOMPARE(disconnectedSpy.count(), 1);
+ QCOMPARE(stateSpy.count(), 2);
+ QCOMPARE(stateSpy.at(0).at(0).value<QOpcUaClient::ClientState>(),
+ QOpcUaClient::ClientState::Closing);
+ QCOMPARE(stateSpy.at(1).at(0).value<QOpcUaClient::ClientState>(),
+ QOpcUaClient::ClientState::Disconnected);
+ QCOMPARE(errorSpy.size(), 0);
+ }
+
+ opcuaClient = nullptr;
+ }
+
+ QOpcUaClient *opcuaClient;
+};
+
+static QString messageSecurityModeToString(QOpcUaEndpointDescription::MessageSecurityMode msm)
+{
+ if (msm == QOpcUaEndpointDescription::None)
+ return "None";
+ else if (msm == QOpcUaEndpointDescription::Sign)
+ return "Sign";
+ else if (msm == QOpcUaEndpointDescription::SignAndEncrypt)
+ return "SignAndEncrypt";
+ return "Invalid";
+}
+
+#define defineDataMethod(name) void name()\
+{\
+ QTest::addColumn<QString>("backend");\
+ QTest::addColumn<QOpcUaEndpointDescription>("endpoint");\
+ for (auto backend : m_backends)\
+ for (auto endpoint : m_endpoints) { \
+ const QString rowName = QString("%1 using %2 %3").arg(backend).arg(endpoint.securityPolicy()).arg(messageSecurityModeToString(endpoint.securityMode())); \
+ QTest::newRow(rowName.toLatin1().constData()) << backend << endpoint; \
+ } \
+}
+
+class Tst_QOpcUaSecurity: public QObject
+{
+ Q_OBJECT
+
+public:
+ Tst_QOpcUaSecurity();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ defineDataMethod(connectAndDisconnectUsingCertificate_data)
+ void connectAndDisconnectUsingCertificate();
+
+ defineDataMethod(connectAndDisconnectUsingEncryptedPassword_data)
+ void connectAndDisconnectUsingEncryptedPassword();
+
+private:
+ QString envOrDefault(const char *env, QString def)
+ {
+ return qEnvironmentVariableIsSet(env) ? qgetenv(env).constData() : def;
+ }
+
+ QString m_testServerPath;
+ QStringList m_backends;
+ QProcess m_serverProcess;
+ QVector<QOpcUaEndpointDescription> m_endpoints;
+ QString m_discoveryEndpoint;
+ QOpcUaProvider m_opcUa;
+ QSharedPointer<QTemporaryDir> m_pkiData;
+};
+
+Tst_QOpcUaSecurity::Tst_QOpcUaSecurity()
+{
+ m_backends = QOpcUaProvider::availableBackends();
+}
+
+void Tst_QOpcUaSecurity::initTestCase()
+{
+ const quint16 defaultPort = 43344;
+ const QHostAddress defaultHost(QHostAddress::LocalHost);
+
+ m_pkiData = QTest::qExtractTestData("pki");
+ qDebug() << "PKI data available at" << m_pkiData->path();
+
+ if (qEnvironmentVariableIsEmpty("OPCUA_HOST") && qEnvironmentVariableIsEmpty("OPCUA_PORT")) {
+ m_testServerPath = qApp->applicationDirPath()
+
+#if defined(Q_OS_MACOS)
+ + QLatin1String("/../../open62541-testserver/open62541-testserver.app/Contents/MacOS/open62541-testserver")
+#else
+
+#ifdef Q_OS_WIN
+ + QLatin1String("/..")
+#endif
+ + QLatin1String("/../../open62541-testserver/open62541-testserver")
+#ifdef Q_OS_WIN
+ + QLatin1String(".exe")
+#endif
+
+#endif
+ ;
+ if (!QFile::exists(m_testServerPath)) {
+ qDebug() << "Server Path:" << m_testServerPath;
+ QSKIP("all auto tests rely on an open62541-based test-server");
+ }
+
+ // In this case the test is supposed to open its own server.
+ // Unfortunately there is no way to check if the server has started up successfully
+ // because of missing error handling.
+ // This checks will detect other servers blocking the port.
+
+ // Check for running server
+ QTcpSocket socket;
+ socket.connectToHost(defaultHost, defaultPort);
+ QVERIFY2(socket.waitForConnected(1500) == false, "Server is already running");
+
+ // Check for running server which does not respond
+ QTcpServer server;
+ QVERIFY2(server.listen(defaultHost, defaultPort) == true, "Port is occupied by another process. Check for defunct server.");
+ server.close();
+
+ m_serverProcess.start(m_testServerPath);
+ QVERIFY2(m_serverProcess.waitForStarted(), qPrintable(m_serverProcess.errorString()));
+ // Let the server come up
+ QTest::qSleep(2000);
+ }
+ QString host = envOrDefault("OPCUA_HOST", defaultHost.toString());
+ QString port = envOrDefault("OPCUA_PORT", QString::number(defaultPort));
+ m_discoveryEndpoint = QString("opc.tcp://%1:%2").arg(host).arg(port);
+ qDebug() << "Using endpoint:" << m_discoveryEndpoint;
+
+ QScopedPointer<QOpcUaClient> client(m_opcUa.createClient(m_backends.first()));
+ QVERIFY2(client, "Loading backend failed");
+
+ if (client) {
+ QSignalSpy endpointSpy(client.data(), &QOpcUaClient::endpointsRequestFinished);
+
+ client->requestEndpoints(m_discoveryEndpoint);
+ endpointSpy.wait(signalSpyTimeout);
+ QCOMPARE(endpointSpy.size(), 1);
+ QCOMPARE(endpointSpy.at(0).at(2).value<QUrl>(), m_discoveryEndpoint);
+
+ const QVector<QOpcUaEndpointDescription> desc = endpointSpy.at(0).at(0).value<QVector<QOpcUaEndpointDescription>>();
+ QVERIFY(desc.size() > 0);
+
+ m_endpoints.clear();
+
+ // Select first non-None security policy
+ for (const auto &endpoint : qAsConst(desc)) {
+ if (!endpoint.securityPolicy().endsWith("#None")) {
+ m_endpoints.append(endpoint);
+ qDebug() << endpoint.securityPolicy();
+ }
+ }
+
+ QVERIFY(m_endpoints.size() > 0);
+ }
+}
+
+void Tst_QOpcUaSecurity::connectAndDisconnectUsingCertificate()
+{
+ QFETCH(QString, backend);
+ QFETCH(QOpcUaEndpointDescription, endpoint);
+
+ QScopedPointer<QOpcUaClient> client(m_opcUa.createClient(backend));
+ QVERIFY2(client, QString("Loading backend failed: %1").arg(backend).toLatin1().data());
+
+ if (!client->supportedUserTokenTypes().contains(QOpcUaUserTokenPolicy::TokenType::Certificate))
+ QSKIP(QString("This test is skipped because backend %1 does not support certificate authentication").arg(client->backend()).toLatin1().constData());
+
+ const QString pkidir = m_pkiData->path();
+ QOpcUaPkiConfiguration pkiConfig;
+ pkiConfig.setClientCertificateFile(pkidir + "/own/certs/tst_security.der");
+ pkiConfig.setPrivateKeyFile(pkidir + "/own/private/privateKeyWithoutPassword.pem");
+ pkiConfig.setTrustListDirectory(pkidir + "/trusted/certs");
+ pkiConfig.setRevocationListDirectory(pkidir + "/trusted/crl");
+ pkiConfig.setIssuerListDirectory(pkidir + "/issuers/certs");
+ pkiConfig.setIssuerRevocationListDirectory(pkidir + "/issuers/crl");
+
+ const auto identity = pkiConfig.applicationIdentity();
+ QOpcUaAuthenticationInformation authInfo;
+ authInfo.setCertificateAuthentication();
+
+ client->setAuthenticationInformation(authInfo);
+ client->setApplicationIdentity(identity);
+ client->setPkiConfiguration(pkiConfig);
+
+ qDebug() << "Testing security policy" << endpoint.securityPolicy();
+ QSignalSpy connectSpy(client.data(), &QOpcUaClient::stateChanged);
+ int passwordRequestSpy = 0;
+ connect(client.data(), &QOpcUaClient::passwordForPrivateKeyRequired, [&passwordRequestSpy](const QString &privateKeyFilePath, QString *password, bool previousTryFailed) {
+ Q_UNUSED(privateKeyFilePath);
+ Q_UNUSED(previousTryFailed);
+ Q_UNUSED(password);
+ ++passwordRequestSpy;
+ });
+
+ client->connectToEndpoint(endpoint);
+ connectSpy.wait(signalSpyTimeout);
+ if (client->state() == QOpcUaClient::Connecting)
+ connectSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(connectSpy.count(), 2);
+ QCOMPARE(connectSpy.at(0).at(0), QOpcUaClient::Connecting);
+ connectSpy.wait(signalSpyTimeout);
+ QCOMPARE(connectSpy.at(1).at(0), QOpcUaClient::Connected);
+
+ QCOMPARE(passwordRequestSpy, 0);
+
+ QCOMPARE(client->endpoint(), endpoint);
+ QCOMPARE(client->error(), QOpcUaClient::NoError);
+ qDebug() << "connected";
+
+ connectSpy.clear();
+ client->disconnectFromEndpoint();
+ connectSpy.wait(signalSpyTimeout);
+ QCOMPARE(connectSpy.count(), 2);
+ QCOMPARE(connectSpy.at(0).at(0), QOpcUaClient::Closing);
+ QCOMPARE(connectSpy.at(1).at(0), QOpcUaClient::Disconnected);
+}
+
+void Tst_QOpcUaSecurity::connectAndDisconnectUsingEncryptedPassword()
+{
+ QFETCH(QString, backend);
+ QFETCH(QOpcUaEndpointDescription, endpoint);
+
+ QScopedPointer<QOpcUaClient> client(m_opcUa.createClient(backend));
+ QVERIFY2(client, QString("Loading backend failed: %1").arg(backend).toLatin1().data());
+
+ if (!client->supportedUserTokenTypes().contains(QOpcUaUserTokenPolicy::TokenType::Certificate))
+ QSKIP(QString("This test is skipped because backend %1 does not support certificate authentication").arg(client->backend()).toLatin1().constData());
+
+ const QString pkidir = m_pkiData->path();
+ QOpcUaPkiConfiguration pkiConfig;
+ pkiConfig.setClientCertificateFile(pkidir + "/own/certs/tst_security.der");
+ pkiConfig.setPrivateKeyFile(pkidir + "/own/private/privateKeyWithPassword:secret.pem");
+ pkiConfig.setTrustListDirectory(pkidir + "/trusted/certs");
+ pkiConfig.setRevocationListDirectory(pkidir + "/trusted/crl");
+ pkiConfig.setIssuerListDirectory(pkidir + "/issuers/certs");
+ pkiConfig.setIssuerRevocationListDirectory(pkidir + "/issuers/crl");
+
+ const auto identity = pkiConfig.applicationIdentity();
+ QOpcUaAuthenticationInformation authInfo;
+ authInfo.setCertificateAuthentication();
+
+ client->setAuthenticationInformation(authInfo);
+ client->setApplicationIdentity(identity);
+ client->setPkiConfiguration(pkiConfig);
+
+ qDebug() << "Testing security policy" << endpoint.securityPolicy();
+ QSignalSpy connectSpy(client.data(), &QOpcUaClient::stateChanged);
+ int passwordRequestSpy = 0;
+ connect(client.data(), &QOpcUaClient::passwordForPrivateKeyRequired, [&passwordRequestSpy, &pkiConfig](const QString &privateKeyFilePath, QString *password, bool previousTryFailed) {
+ qDebug() << "Password requested";
+ if (passwordRequestSpy == 0) {
+ QVERIFY(password->isEmpty());
+ QVERIFY(previousTryFailed == false);
+ } else {
+ QVERIFY(*password == QLatin1String("wrong password"));
+ QVERIFY(previousTryFailed == true);
+ }
+
+ QCOMPARE(privateKeyFilePath, pkiConfig.privateKeyFile());
+
+ if (passwordRequestSpy < 1)
+ *password = "wrong password";
+ else
+ *password = "secret";
+ ++passwordRequestSpy;
+ });
+
+ client->connectToEndpoint(endpoint);
+ connectSpy.wait(signalSpyTimeout);
+ if (client->state() == QOpcUaClient::Connecting)
+ connectSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(connectSpy.count(), 2);
+ QCOMPARE(connectSpy.at(0).at(0), QOpcUaClient::Connecting);
+ QCOMPARE(connectSpy.at(1).at(0), QOpcUaClient::Connected);
+
+ QCOMPARE(passwordRequestSpy, 2);
+
+ QCOMPARE(client->endpoint(), endpoint);
+ QCOMPARE(client->error(), QOpcUaClient::NoError);
+ qDebug() << "connected";
+
+ connectSpy.clear();
+ client->disconnectFromEndpoint();
+ connectSpy.wait(signalSpyTimeout);
+ QCOMPARE(connectSpy.count(), 2);
+ QCOMPARE(connectSpy.at(0).at(0), QOpcUaClient::Closing);
+ QCOMPARE(connectSpy.at(1).at(0), QOpcUaClient::Disconnected);
+}
+
+void Tst_QOpcUaSecurity::cleanupTestCase()
+{
+ if (m_serverProcess.state() == QProcess::Running) {
+ m_serverProcess.kill();
+ m_serverProcess.waitForFinished(2000);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+
+ QTEST_SET_MAIN_SOURCE_PATH
+
+ // run tests for all available backends
+ QStringList availableBackends = QOpcUaProvider::availableBackends();
+ if (availableBackends.empty()) {
+ qDebug("No OPCUA backends found, skipping tests.");
+ return EXIT_SUCCESS;
+ }
+
+ Tst_QOpcUaSecurity tc;
+ return QTest::qExec(&tc, argc, argv);
+}
+
+#include "tst_security.moc"
+
diff --git a/tests/common/backend_environment.h b/tests/common/backend_environment.h
new file mode 100644
index 0000000..1cd692c
--- /dev/null
+++ b/tests/common/backend_environment.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtOpcUa module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+#include <QtCore/QString>
+
+void updateEnvironment()
+{
+#ifdef Q_CC_MSVC
+ const QByteArray uaEnvVar("CI_UACPP_"
+ #if _MSC_VER >= 1900
+ "msvc2017"
+ #else
+ "msvc2015"
+ #endif
+ "_"
+ #if defined(Q_OS_WIN64)
+ "x64"
+ #else
+ "x86"
+ #endif
+ "_PREFIX");
+
+ const QString uaPath = qEnvironmentVariable(uaEnvVar.constData());
+ if (uaPath.isEmpty() || !QFileInfo(uaPath).exists())
+ qWarning() << uaPath << " pointing to a non existing location";
+
+ if (!qputenv("PATH", (uaPath + QLatin1String("\\bin;") + qEnvironmentVariable("PATH")).toLocal8Bit()))
+ qWarning() << "Could not update PATH";
+#endif
+}
diff --git a/tests/manual/eventsubscription/tst_eventsubscription.cpp b/tests/manual/eventsubscription/tst_eventsubscription.cpp
index 49ab75b..994d07e 100644
--- a/tests/manual/eventsubscription/tst_eventsubscription.cpp
+++ b/tests/manual/eventsubscription/tst_eventsubscription.cpp
@@ -42,7 +42,7 @@
class OpcuaConnector
{
public:
- OpcuaConnector(QOpcUaClient *client, const QString &endPoint)
+ OpcuaConnector(QOpcUaClient *client, const QOpcUaEndpointDescription &endPoint)
: opcuaClient(client)
{
QVERIFY(opcuaClient != nullptr);
@@ -51,7 +51,7 @@ public:
QSignalSpy stateSpy(opcuaClient, &QOpcUaClient::stateChanged);
QTest::qWait(500);
- opcuaClient->connectToEndpoint(QUrl(endPoint));
+ opcuaClient->connectToEndpoint(endPoint);
QTRY_VERIFY2(opcuaClient->state() == QOpcUaClient::Connected, "Could not connect to server");
QCOMPARE(connectedSpy.count(), 1); // one connected signal fired
@@ -67,7 +67,7 @@ public:
connectedSpy.clear();
disconnectedSpy.clear();
- QVERIFY(opcuaClient->url() == QUrl(endPoint));
+ QVERIFY(opcuaClient->endpoint() == endPoint);
}
~OpcuaConnector()
@@ -116,6 +116,7 @@ private Q_SLOTS:
private:
QVector<QOpcUaClient *> m_clients;
QString m_serverUrl;
+ QOpcUaEndpointDescription m_endpoint;
};
EventsubscriptionTest::EventsubscriptionTest()
@@ -136,6 +137,21 @@ void EventsubscriptionTest::initTestCase()
else
QFAIL(QStringLiteral("Failed to create client for backend %1").arg(it).toUtf8().constData());
}
+
+ QOpcUaClient *client = m_clients.first();
+ if (client) {
+ QSignalSpy endpointSpy(m_clients.first(), &QOpcUaClient::endpointsRequestFinished);
+
+ client->requestEndpoints(m_serverUrl);
+ endpointSpy.wait();
+ QCOMPARE(endpointSpy.size(), 1);
+ QCOMPARE(endpointSpy.at(0).at(2).value<QUrl>(), m_serverUrl);
+
+ const QVector<QOpcUaEndpointDescription> desc = endpointSpy.at(0).at(0).value<QVector<QOpcUaEndpointDescription>>();
+ QVERIFY(desc.size() > 0);
+
+ m_endpoint = desc.first();
+ }
}
void EventsubscriptionTest::cleanupTestCase()
@@ -158,7 +174,7 @@ void EventsubscriptionTest::eventSubscription_data()
void EventsubscriptionTest::eventSubscription()
{
QFETCH(QOpcUaClient *, client);
- OpcuaConnector connector(client, m_serverUrl);
+ OpcuaConnector connector(client, m_endpoint);
QScopedPointer<QOpcUaNode> serverNode(client->node("ns=0;i=2253")); // Server object
QVERIFY(serverNode != nullptr);
@@ -172,14 +188,14 @@ void EventsubscriptionTest::eventSubscription()
QSignalSpy eventSpy(serverNode.data(), &QOpcUaNode::eventOccurred);
QOpcUaMonitoringParameters::EventFilter filter;
- filter << QOpcUa::QSimpleAttributeOperand("Severity");
- filter << QOpcUa::QSimpleAttributeOperand("Message");
+ filter << QOpcUaSimpleAttributeOperand("Severity");
+ filter << QOpcUaSimpleAttributeOperand("Message");
// Where clause is not yet supported in the open62541 server
// // Only events with severity >= 700
-// QOpcUa::QContentFilterElement whereElement;
-// whereElement << QOpcUa::QContentFilterElement::FilterOperator::GreaterThanOrEqual << QOpcUa::QSimpleAttributeOperand("Severity") <<
-// QOpcUa::QLiteralOperand(quint16(700), QOpcUa::Types::UInt16);
+// QOpcUaContentFilterElement whereElement;
+// whereElement << QOpcUaContentFilterElement::FilterOperator::GreaterThanOrEqual << QOpcUaSimpleAttributeOperand("Severity") <<
+// QOpcUaLiteralOperand(quint16(700), QOpcUa::Types::UInt16);
// filter << whereElement;
QOpcUaMonitoringParameters p(0);
@@ -196,7 +212,7 @@ void EventsubscriptionTest::eventSubscription()
// Disabled because the open62541 server does not currently return an EventFilterResult
// QVERIFY(serverNode->monitoringStatus(QOpcUa::NodeAttribute::EventNotifier).filterResult().isValid());
-// QOpcUa::QEventFilterResult res = serverNode->monitoringStatus(QOpcUa::NodeAttribute::EventNotifier).filterResult().value<QOpcUa::QEventFilterResult>();
+// QOpcUaEventFilterResult res = serverNode->monitoringStatus(QOpcUa::NodeAttribute::EventNotifier).filterResult().value<QOpcUaEventFilterResult>();
// QVERIFY(res.isGood() == true);
qDebug() << "Monitoring enabled, waiting for event...";
@@ -206,21 +222,21 @@ void EventsubscriptionTest::eventSubscription()
QCOMPARE(eventSpy.size(), 1);
QCOMPARE(eventSpy.at(0).at(0).toList().size(), 2);
quint16 severity = eventSpy.at(0).at(0).toList().at(0).value<quint16>();
- QOpcUa::QLocalizedText message = eventSpy.at(0).at(0).toList().at(1).value<QOpcUa::QLocalizedText>();
+ QOpcUaLocalizedText message = eventSpy.at(0).at(0).toList().at(1).value<QOpcUaLocalizedText>();
qDebug() << "Event received";
qDebug() << "Message:" << message.locale() << message.text();
qDebug() << "Severity:" << severity;
QCOMPARE(severity, 100);
- QCOMPARE(message, QOpcUa::QLocalizedText("en-US", "An event has been generated."));
+ QCOMPARE(message, QOpcUaLocalizedText("en-US", "An event has been generated."));
qDebug() << "Modifying event filter...";
eventSpy.clear();
QSignalSpy modifySpy(serverNode.data(), &QOpcUaNode::monitoringStatusChanged);
- filter << QOpcUa::QSimpleAttributeOperand("SourceNode");
+ filter << QOpcUaSimpleAttributeOperand("SourceNode");
serverNode->modifyEventFilter(filter);
modifySpy.wait();
QCOMPARE(modifySpy.size(), 1);
@@ -236,7 +252,7 @@ void EventsubscriptionTest::eventSubscription()
QCOMPARE(eventSpy.size(), 1);
QCOMPARE(eventSpy.at(0).at(0).toList().size(), 3);
severity = eventSpy.at(0).at(0).toList().at(0).value<quint16>();
- message = eventSpy.at(0).at(0).toList().at(1).value<QOpcUa::QLocalizedText>();
+ message = eventSpy.at(0).at(0).toList().at(1).value<QOpcUaLocalizedText>();
QString sourceNode = eventSpy.at(0).at(0).toList().at(2).toString();
qDebug() << "Event received";
@@ -245,7 +261,7 @@ void EventsubscriptionTest::eventSubscription()
qDebug() << "SourceNode:" << sourceNode;
QCOMPARE(severity, 100);
- QCOMPARE(message, QOpcUa::QLocalizedText("en-US", "An event has been generated."));
+ QCOMPARE(message, QOpcUaLocalizedText("en-US", "An event has been generated."));
QCOMPARE(sourceNode, QStringLiteral("ns=0;i=2253"));
QSignalSpy disabledSpy(serverNode.data(), &QOpcUaNode::disableMonitoringFinished);
diff --git a/tests/open62541-testserver/certs.qrc b/tests/open62541-testserver/certs.qrc
new file mode 100644
index 0000000..07bde08
--- /dev/null
+++ b/tests/open62541-testserver/certs.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/">
+ <file>pki/own/private/open62541-testserver.der</file>
+ <file>pki/own/certs/open62541-testserver.der</file>
+ <file>pki/trusted/certs/opcuaviewer.der</file>
+ <file>pki/trusted/certs/tst_security.der</file>
+ </qresource>
+</RCC>
diff --git a/tests/open62541-testserver/main.cpp b/tests/open62541-testserver/main.cpp
index cec96c9..cfb93fa 100644
--- a/tests/open62541-testserver/main.cpp
+++ b/tests/open62541-testserver/main.cpp
@@ -43,6 +43,19 @@
#include <QtCore/QVariant>
#include <QUuid>
+#include <QtOpcUa/QOpcUaArgument>
+#include <QtOpcUa/QOpcUaAxisInformation>
+#include <QtOpcUa/QOpcUaComplexNumber>
+#include <QtOpcUa/QOpcUaDoubleComplexNumber>
+#include <QtOpcUa/QOpcUaExpandedNodeId>
+#include <QtOpcUa/QOpcUaExtensionObject>
+#include <QtOpcUa/QOpcUaEUInformation>
+#include <QtOpcUa/QOpcUaLocalizedText>
+#include <QtOpcUa/QOpcUaMultiDimensionalArray>
+#include <QtOpcUa/QOpcUaQualifiedName>
+#include <QtOpcUa/QOpcUaRange>
+#include <QtOpcUa/QOpcUaXValue>
+
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
@@ -90,8 +103,8 @@ int main(int argc, char **argv)
server.addVariable(testFolder, "ns=2;s=Demo.Static.Arrays.String", "StringArrayTest",
QVariantList({QStringLiteral("Value 1"), QStringLiteral("Value 2")}), QOpcUa::Types::String);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Arrays.LocalizedText", "LocalizedTextArrayTest",
- QVariantList({QVariant::fromValue(QOpcUa::QLocalizedText(QStringLiteral("en-US"), QStringLiteral("Value 1"))),
- QVariant::fromValue(QOpcUa::QLocalizedText(QStringLiteral("en-US"), QStringLiteral("Value 2")))}),
+ QVariantList({QVariant::fromValue(QOpcUaLocalizedText(QStringLiteral("en-US"), QStringLiteral("Value 1"))),
+ QVariant::fromValue(QOpcUaLocalizedText(QStringLiteral("en-US"), QStringLiteral("Value 2")))}),
QOpcUa::Types::LocalizedText);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Arrays.ByteString", "ByteStringArrayTest",
QVariantList({QByteArray("Value 1"), QByteArray("Value 2")}), QOpcUa::Types::ByteString);
@@ -106,41 +119,41 @@ int main(int argc, char **argv)
QVariantList({QStringLiteral("<?xml version=\"1\" encoding=\"UTF-8\"?>"),
QStringLiteral("<?xml version=\"1\" encoding=\"UTF-8\"?>")}), QOpcUa::Types::XmlElement);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Arrays.QualifiedName", "QualifiedNameArrayTest",
- QVariantList({QVariant::fromValue(QOpcUa::QQualifiedName(0, QStringLiteral("Value 1"))),
- QVariant::fromValue(QOpcUa::QQualifiedName(0, QStringLiteral("Value 2")))}), QOpcUa::Types::QualifiedName);
+ QVariantList({QVariant::fromValue(QOpcUaQualifiedName(0, QStringLiteral("Value 1"))),
+ QVariant::fromValue(QOpcUaQualifiedName(0, QStringLiteral("Value 2")))}), QOpcUa::Types::QualifiedName);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Arrays.StatusCode", "StatusCodeArrayTest",
QVariantList({QVariant::fromValue(QOpcUa::UaStatusCode::Good),
QVariant::fromValue(QOpcUa::UaStatusCode::BadInvalidArgument)}), QOpcUa::Types::StatusCode);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Arrays.Range", "RangeArrayTest",
- QVariantList({QVariant::fromValue(QOpcUa::QRange(0, 100)),
- QVariant::fromValue(QOpcUa::QRange(100, 200))}), QOpcUa::Types::Range);
+ QVariantList({QVariant::fromValue(QOpcUaRange(0, 100)),
+ QVariant::fromValue(QOpcUaRange(100, 200))}), QOpcUa::Types::Range);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Arrays.EUInformation", "EUInformationArrayTest",
- QVariantList({QVariant::fromValue(QOpcUa::QEUInformation()),
- QVariant::fromValue(QOpcUa::QEUInformation())}), QOpcUa::Types::EUInformation);
+ QVariantList({QVariant::fromValue(QOpcUaEUInformation()),
+ QVariant::fromValue(QOpcUaEUInformation())}), QOpcUa::Types::EUInformation);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Arrays.ComplexNumber", "ComplexNumberArrayTest",
- QVariantList({QVariant::fromValue(QOpcUa::QComplexNumber(1, 2)),
- QVariant::fromValue(QOpcUa::QComplexNumber(2, 3))}), QOpcUa::Types::ComplexNumber);
+ QVariantList({QVariant::fromValue(QOpcUaComplexNumber(1, 2)),
+ QVariant::fromValue(QOpcUaComplexNumber(2, 3))}), QOpcUa::Types::ComplexNumber);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Arrays.DoubleComplexNumber", "DoubleComplexNumberArrayTest",
- QVariantList({QVariant::fromValue(QOpcUa::QDoubleComplexNumber(1, 2)),
- QVariant::fromValue(QOpcUa::QDoubleComplexNumber(2, 3))}), QOpcUa::Types::DoubleComplexNumber);
+ QVariantList({QVariant::fromValue(QOpcUaDoubleComplexNumber(1, 2)),
+ QVariant::fromValue(QOpcUaDoubleComplexNumber(2, 3))}), QOpcUa::Types::DoubleComplexNumber);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Arrays.AxisInformation", "AxisInformationArrayTest",
- QVariantList({QVariant::fromValue(QOpcUa::QAxisInformation()),
- QVariant::fromValue(QOpcUa::QAxisInformation())}), QOpcUa::Types::AxisInformation);
+ QVariantList({QVariant::fromValue(QOpcUaAxisInformation()),
+ QVariant::fromValue(QOpcUaAxisInformation())}), QOpcUa::Types::AxisInformation);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Arrays.XV", "XVArrayTest",
- QVariantList({QVariant::fromValue(QOpcUa::QXValue(1, 2)),
- QVariant::fromValue(QOpcUa::QXValue(2, 3))}), QOpcUa::Types::XV);
+ QVariantList({QVariant::fromValue(QOpcUaXValue(1, 2)),
+ QVariant::fromValue(QOpcUaXValue(2, 3))}), QOpcUa::Types::XV);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Arrays.ExpandedNodeId", "ExpandedNodeIdArrayTest",
- QVariantList({QOpcUa::QExpandedNodeId(QStringLiteral("ns1"), QStringLiteral("ns=0;i=64"), 1),
- QOpcUa::QExpandedNodeId(QString(), QStringLiteral("ns=1;i=84"))}),
+ QVariantList({QOpcUaExpandedNodeId(QStringLiteral("ns1"), QStringLiteral("ns=0;i=64"), 1),
+ QOpcUaExpandedNodeId(QString(), QStringLiteral("ns=1;i=84"))}),
QOpcUa::Types::ExpandedNodeId);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Arrays.Argument", "ArgumentArrayTest",
- QVariantList({QOpcUa::QArgument(QStringLiteral("Argument1"), QStringLiteral("ns=0;i=12"), -1,
- {},QOpcUa::QLocalizedText(QStringLiteral("en"), QStringLiteral("Description1"))),
- QOpcUa::QArgument(QStringLiteral("Argument2"), QStringLiteral("ns=0;i=12"), 2,
- {2, 2}, QOpcUa::QLocalizedText(QStringLiteral("en"), QStringLiteral("Description2")))}),
+ QVariantList({QOpcUaArgument(QStringLiteral("Argument1"), QStringLiteral("ns=0;i=12"), -1,
+ {},QOpcUaLocalizedText(QStringLiteral("en"), QStringLiteral("Description1"))),
+ QOpcUaArgument(QStringLiteral("Argument2"), QStringLiteral("ns=0;i=12"), 2,
+ {2, 2}, QOpcUaLocalizedText(QStringLiteral("en"), QStringLiteral("Description2")))}),
QOpcUa::Types::Argument);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Arrays.ExtensionObject", "ExtensionObjectArrayTest",
- QVariantList({QOpcUa::QExtensionObject(), QOpcUa::QExtensionObject()}),
+ QVariantList({QOpcUaExtensionObject(), QOpcUaExtensionObject()}),
QOpcUa::Types::ExtensionObject);
// Test variables containing scalar values of various types
@@ -157,7 +170,7 @@ int main(int argc, char **argv)
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.UInt64", "UInt64ScalarTest", 1, QOpcUa::Types::UInt64);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.String", "StringScalarTest", QStringLiteral("Value"), QOpcUa::Types::String);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.LocalizedText", "LocalizedTextScalarTest",
- QVariant::fromValue(QOpcUa::QLocalizedText(QStringLiteral("en-US"), QStringLiteral("Value"))),
+ QVariant::fromValue(QOpcUaLocalizedText(QStringLiteral("en-US"), QStringLiteral("Value"))),
QOpcUa::Types::LocalizedText);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.ByteString", "ByteStringScalarTest", QByteArray("Value 1"), QOpcUa::Types::ByteString);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.DateTime", "DateTimeScalarTest", QDateTime::currentDateTime(), QOpcUa::Types::DateTime);
@@ -166,29 +179,29 @@ int main(int argc, char **argv)
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.XmlElement", "XmlElementScalarTest",
QStringLiteral("<?xml version=\"1\" encoding=\"UTF-8\"?>"), QOpcUa::Types::XmlElement);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.QualifiedName", "QualifiedNameScalarTest",
- QVariant::fromValue(QOpcUa::QQualifiedName(0, QStringLiteral("Value"))), QOpcUa::Types::QualifiedName);
+ QVariant::fromValue(QOpcUaQualifiedName(0, QStringLiteral("Value"))), QOpcUa::Types::QualifiedName);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.StatusCode", "StatusCodeScalarTest", QVariant::fromValue(QOpcUa::UaStatusCode::Good),
QOpcUa::Types::StatusCode);
- server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.Range", "RangeScalarTest", QVariant::fromValue(QOpcUa::QRange(0, 100)), QOpcUa::Types::Range);
+ server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.Range", "RangeScalarTest", QVariant::fromValue(QOpcUaRange(0, 100)), QOpcUa::Types::Range);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.EUInformation", "EUInformationScalarTest",
- QVariant::fromValue(QOpcUa::QEUInformation()), QOpcUa::Types::EUInformation);
+ QVariant::fromValue(QOpcUaEUInformation()), QOpcUa::Types::EUInformation);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.ComplexNumber", "ComplexNumberArrayTest",
- QVariant::fromValue(QOpcUa::QComplexNumber(1, 2)), QOpcUa::Types::ComplexNumber);
+ QVariant::fromValue(QOpcUaComplexNumber(1, 2)), QOpcUa::Types::ComplexNumber);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.DoubleComplexNumber", "DoubleComplexNumberScalarTest",
- QVariant::fromValue(QOpcUa::QDoubleComplexNumber(1, 2)), QOpcUa::Types::DoubleComplexNumber);
+ QVariant::fromValue(QOpcUaDoubleComplexNumber(1, 2)), QOpcUa::Types::DoubleComplexNumber);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.AxisInformation", "AxisInformationScalarTest",
- QVariant::fromValue(QOpcUa::QAxisInformation()), QOpcUa::Types::AxisInformation);
+ QVariant::fromValue(QOpcUaAxisInformation()), QOpcUa::Types::AxisInformation);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.XV", "XVScalarTest",
- QVariant::fromValue(QOpcUa::QXValue(1, 2)), QOpcUa::Types::XV);
+ QVariant::fromValue(QOpcUaXValue(1, 2)), QOpcUa::Types::XV);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.ExpandedNodeId", "ExpandedNodeIdScalarTest",
- QOpcUa::QExpandedNodeId(QStringLiteral("ns1"), QStringLiteral("ns=0;i=64"), 1),
+ QOpcUaExpandedNodeId(QStringLiteral("ns1"), QStringLiteral("ns=0;i=64"), 1),
QOpcUa::Types::ExpandedNodeId);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.Argument", "ArgumentScalarTest",
- QOpcUa::QArgument(QStringLiteral("Argument1"), QStringLiteral("ns=0;i=12"), -1,
- {},QOpcUa::QLocalizedText(QStringLiteral("en"), QStringLiteral("Description1"))),
+ QOpcUaArgument(QStringLiteral("Argument1"), QStringLiteral("ns=0;i=12"), -1,
+ {},QOpcUaLocalizedText(QStringLiteral("en"), QStringLiteral("Description1"))),
QOpcUa::Types::Argument);
server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.ExtensionObject", "ExtensionObjectScalarTest",
- QOpcUa::QExtensionObject(), QOpcUa::Types::ExtensionObject);
+ QOpcUaExtensionObject(), QOpcUa::Types::ExtensionObject);
server.addNodeWithFixedTimestamp(testFolder, "ns=2;s=Demo.Static.FixedTimestamp", "FixedTimestamp");
// Create folders containing child nodes with string, guid and opaque node ids
@@ -207,7 +220,7 @@ int main(int argc, char **argv)
const QVector<quint32> arrayDimensions({2, 2, 3});
const QVariantList value({0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0});
server.addVariable(testFolder, "ns=2;s=Demo.Static.Arrays.MultiDimensionalDouble", "MultiDimensionalDoubleTest",
- QOpcUa::QMultiDimensionalArray(value, arrayDimensions), QOpcUa::Types::Double, QVector<quint32>({2, 2, 3}), 3);
+ QOpcUaMultiDimensionalArray(value, arrayDimensions), QOpcUa::Types::Double, QVector<quint32>({2, 2, 3}), 3);
// Add folders for relative nodes
const UA_NodeId testFolder2 = server.addFolder("ns=3;s=TestFolder2", "TestFolder2");
diff --git a/tests/open62541-testserver/open62541-testserver.pro b/tests/open62541-testserver/open62541-testserver.pro
index 68a0069..1d66aed 100644
--- a/tests/open62541-testserver/open62541-testserver.pro
+++ b/tests/open62541-testserver/open62541-testserver.pro
@@ -11,6 +11,10 @@ CONFIG += c++11 console
QT += opcua-private
qtConfig(open62541):!qtConfig(system-open62541) {
+ qtConfig(mbedtls):{
+ QMAKE_USE_PRIVATE += mbedtls
+ DEFINES += UA_ENABLE_ENCRYPTION
+ }
include($$PWD/../../src/3rdparty/open62541.pri)
} else {
QMAKE_USE_PRIVATE += open62541
@@ -18,6 +22,17 @@ qtConfig(open62541):!qtConfig(system-open62541) {
win32: DESTDIR = ./
+# Workaround for QTBUG-75020
+QMAKE_CFLAGS_RELEASE -= -O2
+QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO -= -O2
+
+# This file can only be compiled in case of TLS support
+qtConfig(mbedtls) {
+ # Use custom compiler from src/3rdparty/open62541.pri to hide warning caused by
+ # including open62541.h
+ OPEN62541_SOURCES += security_addon.cpp
+}
+
SOURCES += \
main.cpp \
testserver.cpp \
@@ -26,4 +41,8 @@ SOURCES += \
HEADERS += \
- testserver.h
+ testserver.h \
+ security_addon.h \
+
+RESOURCES += certs.qrc
+
diff --git a/tests/open62541-testserver/pki/own/certs/open62541-testserver.der b/tests/open62541-testserver/pki/own/certs/open62541-testserver.der
new file mode 100644
index 0000000..7aac4cd
--- /dev/null
+++ b/tests/open62541-testserver/pki/own/certs/open62541-testserver.der
Binary files differ
diff --git a/tests/open62541-testserver/pki/own/private/open62541-testserver.der b/tests/open62541-testserver/pki/own/private/open62541-testserver.der
new file mode 100644
index 0000000..f396b44
--- /dev/null
+++ b/tests/open62541-testserver/pki/own/private/open62541-testserver.der
Binary files differ
diff --git a/tests/open62541-testserver/pki/trusted/certs/.gitkeep b/tests/open62541-testserver/pki/trusted/certs/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/open62541-testserver/pki/trusted/certs/.gitkeep
diff --git a/tests/open62541-testserver/pki/trusted/certs/opcuaviewer.der b/tests/open62541-testserver/pki/trusted/certs/opcuaviewer.der
new file mode 100644
index 0000000..1eeb26a
--- /dev/null
+++ b/tests/open62541-testserver/pki/trusted/certs/opcuaviewer.der
Binary files differ
diff --git a/tests/open62541-testserver/pki/trusted/certs/tst_security.der b/tests/open62541-testserver/pki/trusted/certs/tst_security.der
new file mode 100644
index 0000000..f7527ba
--- /dev/null
+++ b/tests/open62541-testserver/pki/trusted/certs/tst_security.der
Binary files differ
diff --git a/tests/open62541-testserver/qt_attribution.json b/tests/open62541-testserver/qt_attribution.json
new file mode 100644
index 0000000..7536c1c
--- /dev/null
+++ b/tests/open62541-testserver/qt_attribution.json
@@ -0,0 +1,23 @@
+{
+ "Id": "open62541",
+ "Name": "Open62541",
+ "QDocModule": "qtopcua",
+ "QtUsage": "Used in the Qt OPC UA module to build the test server.",
+ "Description": "Open62541 is an open source implementation of the OPC UA protocol.",
+ "Homepage": "https://open62541.org/",
+ "Version": "0.3",
+ "License": "Creative Commons CCZero 1.0 Universal License",
+ "LicenseId": "CC0-1.0",
+ "LicenseFile": "../../LICENSE-CC0",
+ "Copyright": "Bauer, Maximilian Ebrahimi
+ Reza <reza.ebrahimi.dev (at) gmail.com>
+ Graube, Markus <markus.graube (at) tu-dresden.de>
+ Gruener, Sten <s.gruener (at) plt.rwth-aachen.de>
+ Iatrou, Chris Paul <chris_paul.iatrou (at) tu-dresden.de>
+ Jeromin, Holger Palm, Florian <f.palm (at) plt.rwth-aachen.de>
+ Pfrommer, Julius <julius.pfrommer (at) iosb.fraunhofer.edu>
+ Profanter, Stefan <profanter (at) fortiss.org>
+ Stalder, Thomas <t.stalder (at) bluetimeconcept.ch>
+ Urbas, Leon <leon.urbas (at) tu-dresden.de>
+ "
+}
diff --git a/tests/open62541-testserver/security_addon.cpp b/tests/open62541-testserver/security_addon.cpp
new file mode 100644
index 0000000..99a8809
--- /dev/null
+++ b/tests/open62541-testserver/security_addon.cpp
@@ -0,0 +1,121 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
+ *
+ * Copyright 2017 (c) Julius Pfrommer, Fraunhofer IOSB
+ * Copyright 2017 (c) Julian Grothoff
+ * Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
+ * Copyright 2017 (c) Stefan Profanter, fortiss GmbH
+ * Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA
+ * Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG
+ */
+
+//
+// This code was mostly taken from the open62541 project from file plugins/ua_config_default.c
+//
+
+#include "security_addon.h"
+
+UA_StatusCode createSecurityPolicyNoneEndpoint(UA_ServerConfig *conf, UA_Endpoint *endpoint, const UA_ByteString localCertificate)
+{
+ UA_EndpointDescription_init(&endpoint->endpointDescription);
+
+ UA_SecurityPolicy_None(&endpoint->securityPolicy, NULL, localCertificate, conf->logger);
+ endpoint->endpointDescription.securityMode = UA_MESSAGESECURITYMODE_NONE;
+ endpoint->endpointDescription.securityPolicyUri =
+ UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
+ endpoint->endpointDescription.transportProfileUri =
+ UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
+
+ /* Enable all login mechanisms from the access control plugin */
+ UA_StatusCode retval = UA_Array_copy(conf->accessControl.userTokenPolicies,
+ conf->accessControl.userTokenPoliciesSize,
+ (void **)&endpoint->endpointDescription.userIdentityTokens,
+ &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
+ if (retval != UA_STATUSCODE_GOOD)
+ return retval;
+ endpoint->endpointDescription.userIdentityTokensSize = conf->accessControl.userTokenPoliciesSize;
+
+ UA_String_copy(&localCertificate, &endpoint->endpointDescription.serverCertificate);
+ UA_ApplicationDescription_copy(&conf->applicationDescription,
+ &endpoint->endpointDescription.server);
+
+ return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode
+createSecurityPolicyBasic128Rsa15Endpoint(UA_ServerConfig *const conf,
+ UA_Endpoint *endpoint,
+ UA_MessageSecurityMode securityMode,
+ const UA_ByteString localCertificate,
+ const UA_ByteString localPrivateKey) {
+ UA_EndpointDescription_init(&endpoint->endpointDescription);
+
+ UA_StatusCode retval =
+ UA_SecurityPolicy_Basic128Rsa15(&endpoint->securityPolicy, &conf->certificateVerification,
+ localCertificate, localPrivateKey, conf->logger);
+ if (retval != UA_STATUSCODE_GOOD) {
+ endpoint->securityPolicy.deleteMembers(&endpoint->securityPolicy);
+ return retval;
+ }
+
+ endpoint->endpointDescription.securityMode = securityMode;
+ endpoint->endpointDescription.securityPolicyUri =
+ UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15");
+ endpoint->endpointDescription.transportProfileUri =
+ UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
+
+ /* Enable all login mechanisms from the access control plugin */
+ retval = UA_Array_copy(conf->accessControl.userTokenPolicies,
+ conf->accessControl.userTokenPoliciesSize,
+ (void **)&endpoint->endpointDescription.userIdentityTokens,
+ &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
+ if (retval != UA_STATUSCODE_GOOD)
+ return retval;
+ endpoint->endpointDescription.userIdentityTokensSize =
+ conf->accessControl.userTokenPoliciesSize;
+
+ UA_String_copy(&localCertificate, &endpoint->endpointDescription.serverCertificate);
+ UA_ApplicationDescription_copy(&conf->applicationDescription,
+ &endpoint->endpointDescription.server);
+
+ return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode
+createSecurityPolicyBasic256Sha256Endpoint(UA_ServerConfig *const conf,
+ UA_Endpoint *endpoint,
+ UA_MessageSecurityMode securityMode,
+ const UA_ByteString localCertificate,
+ const UA_ByteString localPrivateKey) {
+ UA_EndpointDescription_init(&endpoint->endpointDescription);
+
+ UA_StatusCode retval =
+ UA_SecurityPolicy_Basic256Sha256(&endpoint->securityPolicy, &conf->certificateVerification, localCertificate,
+ localPrivateKey, conf->logger);
+ if (retval != UA_STATUSCODE_GOOD) {
+ endpoint->securityPolicy.deleteMembers(&endpoint->securityPolicy);
+ return retval;
+ }
+
+ endpoint->endpointDescription.securityMode = securityMode;
+ endpoint->endpointDescription.securityPolicyUri =
+ UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
+ endpoint->endpointDescription.transportProfileUri =
+ UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
+
+ /* Enable all login mechanisms from the access control plugin */
+ retval = UA_Array_copy(conf->accessControl.userTokenPolicies,
+ conf->accessControl.userTokenPoliciesSize,
+ (void **)&endpoint->endpointDescription.userIdentityTokens,
+ &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
+ if (retval != UA_STATUSCODE_GOOD)
+ return retval;
+ endpoint->endpointDescription.userIdentityTokensSize =
+ conf->accessControl.userTokenPoliciesSize;
+
+ UA_String_copy(&localCertificate, &endpoint->endpointDescription.serverCertificate);
+ UA_ApplicationDescription_copy(&conf->applicationDescription,
+ &endpoint->endpointDescription.server);
+
+ return UA_STATUSCODE_GOOD;
+}
diff --git a/tests/open62541-testserver/security_addon.h b/tests/open62541-testserver/security_addon.h
new file mode 100644
index 0000000..455092f
--- /dev/null
+++ b/tests/open62541-testserver/security_addon.h
@@ -0,0 +1,23 @@
+
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
+ *
+ * Copyright 2017 (c) Julius Pfrommer, Fraunhofer IOSB
+ * Copyright 2017 (c) Julian Grothoff
+ * Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
+ * Copyright 2017 (c) Stefan Profanter, fortiss GmbH
+ * Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA
+ * Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG
+ */
+
+//
+// This code was taken from the open62541 project from file plugins/ua_config_default.c
+//
+
+#include "open62541.h"
+
+UA_StatusCode createSecurityPolicyNoneEndpoint(UA_ServerConfig *conf, UA_Endpoint *endpoint, const UA_ByteString localCertificate);
+UA_StatusCode createSecurityPolicyBasic128Rsa15Endpoint(UA_ServerConfig *const conf, UA_Endpoint *endpoint, UA_MessageSecurityMode securityMode,
+ const UA_ByteString localCertificate, const UA_ByteString localPrivateKey);
+UA_StatusCode createSecurityPolicyBasic256Sha256Endpoint(UA_ServerConfig *const conf, UA_Endpoint *endpoint, UA_MessageSecurityMode securityMode,
+ const UA_ByteString localCertificate, const UA_ByteString localPrivateKey);
diff --git a/tests/open62541-testserver/testserver.cpp b/tests/open62541-testserver/testserver.cpp
index c3760c4..2e79d72 100644
--- a/tests/open62541-testserver/testserver.cpp
+++ b/tests/open62541-testserver/testserver.cpp
@@ -42,15 +42,24 @@
#include <QtCore/QDebug>
#include <QtCore/QLoggingCategory>
#include <QtCore/QUuid>
+#include <QDir>
+#include <QFile>
+
+#if defined UA_ENABLE_ENCRYPTION
+#include "security_addon.h"
+#endif
#include <cstring>
QT_BEGIN_NAMESPACE
+const UA_UInt16 portNumber = 43344;
+
// Node ID conversion is included from the open62541 plugin but warnings from there should be logged
// using qt.opcua.testserver instead of qt.opcua.plugins.open62541 for usage in the test server
Q_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_OPEN62541, "qt.opcua.testserver")
+
TestServer::TestServer(QObject *parent) : QObject(parent)
{
m_timer.setInterval(30);
@@ -65,12 +74,165 @@ TestServer::~TestServer()
UA_ServerConfig_delete(m_config);
}
-bool TestServer::init()
+bool TestServer::createInsecureServerConfig()
+{
+ m_config = UA_ServerConfig_new_minimal(portNumber, nullptr);
+ return m_config != nullptr;
+}
+
+#if defined UA_ENABLE_ENCRYPTION
+static UA_ByteString loadFile(const QString &filePath) {
+ UA_ByteString fileContents = UA_STRING_NULL;
+ fileContents.length = 0;
+
+ QFile file(filePath);
+ if (!file.open(QFile::ReadOnly))
+ return fileContents;
+
+ fileContents.length = file.size();
+ fileContents.data = (UA_Byte *)UA_malloc(fileContents.length * sizeof(UA_Byte));
+ if (!fileContents.data)
+ return fileContents;
+
+ if (file.read(reinterpret_cast<char*>(fileContents.data), fileContents.length) != fileContents.length) {
+ UA_ByteString_deleteMembers(&fileContents);
+ fileContents.length = 0;
+ return fileContents;
+ }
+ return fileContents;
+}
+
+bool TestServer::createSecureServerConfig()
{
- m_config = UA_ServerConfig_new_minimal(43344, nullptr);
+ const QString certificateFilePath = QLatin1String(":/pki/own/certs/open62541-testserver.der");
+ const QString privateKeyFilePath = QLatin1String(":/pki/own/private/open62541-testserver.der");
+
+ UA_ByteString certificate = loadFile(certificateFilePath);
+ UaDeleter<UA_ByteString> certificateDeleter(&certificate, UA_ByteString_deleteMembers);
+ UA_ByteString privateKey = loadFile(privateKeyFilePath);
+ UaDeleter<UA_ByteString> privateKeyDeleter(&privateKey, UA_ByteString_deleteMembers);
+
+ if (certificate.length == 0) {
+ UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "Failed to load certificate %s", certificateFilePath.toLocal8Bit().constData());
+ return false;
+ }
+ if (privateKey.length == 0) {
+ UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "Failed to load private key %s", privateKeyFilePath.toLocal8Bit().constData());
+ return false;
+ }
+
+ // Load the trustlist
+ QDir trustDir(":/pki/trusted/certs");
+ if (!trustDir.exists()) {
+ UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Trust directory does not exist");
+ return false;
+ }
+
+ const auto trustedCerts = trustDir.entryList(QDir::Files);
+ const size_t trustListSize = trustedCerts.size();
+ int i = 0;
+
+ UA_STACKARRAY(UA_ByteString, trustList, trustListSize);
+ UaArrayDeleter<UA_TYPES_BYTESTRING> trustListDeleter(&trustList, trustListSize);
+
+ for (const auto &entry : trustedCerts) {
+ trustList[i] = loadFile(trustDir.filePath(entry));
+ if (trustList[i].length == 0) {
+ UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Failed to load trusted certificate");
+ return false;
+ } else {
+ UA_LOG_DEBUG(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Trusted certificate %s loaded", entry.toLocal8Bit().constData());
+ }
+ ++i;
+ }
+
+ // Loading of a revocation list currently unsupported
+ UA_ByteString *revocationList = nullptr;
+ size_t revocationListSize = 0;
+
+ m_config = UA_ServerConfig_new_minimal(portNumber, nullptr);
if (!m_config)
return false;
+ UA_StatusCode retval = UA_CertificateVerification_Trustlist(&m_config->certificateVerification,
+ trustList, trustListSize,
+ revocationList, revocationListSize);
+
+ if (retval != UA_STATUSCODE_GOOD)
+ return false;
+
+ retval = UA_Nodestore_default_new(&m_config->nodestore);
+ if (retval != UA_STATUSCODE_GOOD)
+ return false;
+
+ if (trustListSize == 0)
+ UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "No CA trust-list provided. Any remote certificate will be accepted.");
+
+ /* Allocate the endpoints */
+ m_config->endpointsSize = 0;
+ m_config->endpoints = (UA_Endpoint *)UA_malloc(sizeof(UA_Endpoint) * 5);
+ if (!m_config->endpoints)
+ return false;
+
+ /* Populate the endpoints */
+ retval = createSecurityPolicyNoneEndpoint(m_config, &m_config->endpoints[m_config->endpointsSize], certificate);
+ ++m_config->endpointsSize;
+ if (retval != UA_STATUSCODE_GOOD)
+ return false;
+
+ retval = createSecurityPolicyBasic128Rsa15Endpoint(m_config, &m_config->endpoints[m_config->endpointsSize],
+ UA_MESSAGESECURITYMODE_SIGN, certificate, privateKey);
+ ++m_config->endpointsSize;
+ if (retval != UA_STATUSCODE_GOOD)
+ return false;
+
+ retval = createSecurityPolicyBasic128Rsa15Endpoint(m_config, &m_config->endpoints[m_config->endpointsSize],
+ UA_MESSAGESECURITYMODE_SIGNANDENCRYPT, certificate, privateKey);
+ ++m_config->endpointsSize;
+ if (retval != UA_STATUSCODE_GOOD)
+ return false;
+
+ retval = createSecurityPolicyBasic256Sha256Endpoint(m_config, &m_config->endpoints[m_config->endpointsSize],
+ UA_MESSAGESECURITYMODE_SIGN, certificate, privateKey);
+ ++m_config->endpointsSize;
+ if (retval != UA_STATUSCODE_GOOD)
+ return false;
+
+ retval = createSecurityPolicyBasic256Sha256Endpoint(m_config, &m_config->endpoints[m_config->endpointsSize],
+ UA_MESSAGESECURITYMODE_SIGNANDENCRYPT, certificate, privateKey);
+ ++m_config->endpointsSize;
+ if (retval != UA_STATUSCODE_GOOD)
+ return false;
+
+ // Do not delete items on success.
+ // They will be used by the server.
+ certificateDeleter.release();
+ privateKeyDeleter.release();
+ trustListDeleter.release();
+
+ return true;
+}
+#endif
+
+bool TestServer::init()
+{
+ bool success;
+
+#if defined UA_ENABLE_ENCRYPTION
+ success = createSecureServerConfig();
+#else
+ success = createInsecureServerConfig();
+#endif
+
+ // This is needed for COIN because the hostname returned by gethostname() is not resolvable.
+ m_config->customHostname = UA_String_fromChars("localhost");
+
+ if (!success || !m_config)
+ return false;
+
m_server = UA_Server_new(m_config);
if (!m_server)
diff --git a/tests/open62541-testserver/testserver.h b/tests/open62541-testserver/testserver.h
index 4c95359..c70fef6 100644
--- a/tests/open62541-testserver/testserver.h
+++ b/tests/open62541-testserver/testserver.h
@@ -44,6 +44,7 @@
#include <QtCore/QObject>
#include <QtCore/QTimer>
#include <QtCore/QVariant>
+#include <QtCore/QVector>
QT_BEGIN_NAMESPACE
@@ -54,6 +55,10 @@ public:
explicit TestServer(QObject *parent = nullptr);
~TestServer();
bool init();
+ bool createInsecureServerConfig();
+#if defined UA_ENABLE_ENCRYPTION
+ bool createSecureServerConfig();
+#endif
int registerNamespace(const QString &ns);
UA_NodeId addFolder(const QString &nodeString, const QString &displayName, const QString &description = QString());