diff --git a/static/doc/open62541-v1.4.0.pdf b/static/doc/open62541-v1.4.0.pdf new file mode 100644 index 0000000000..432eb60c30 Binary files /dev/null and b/static/doc/open62541-v1.4.0.pdf differ diff --git a/static/doc/v1.4.0/CMakeFiles/CMakeDirectoryInformation.cmake b/static/doc/v1.4.0/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 0000000000..8783ea2f35 --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.29 + +# Relative path conversion top directories. +set(CMAKE_RELATIVE_PATH_TOP_SOURCE "/home/runner/work/open62541/open62541") +set(CMAKE_RELATIVE_PATH_TOP_BINARY "/home/runner/work/open62541/open62541/build") + +# Force unix paths in dependencies. +set(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +set(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +set(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +set(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +set(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/static/doc/v1.4.0/CMakeFiles/doc.dir/DependInfo.cmake b/static/doc/v1.4.0/CMakeFiles/doc.dir/DependInfo.cmake new file mode 100644 index 0000000000..29b95a515e --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc.dir/DependInfo.cmake @@ -0,0 +1,22 @@ + +# Consider dependencies only in project. +set(CMAKE_DEPENDS_IN_PROJECT_ONLY OFF) + +# The set of languages for which implicit dependencies are needed: +set(CMAKE_DEPENDS_LANGUAGES + ) + +# The set of dependency files which are needed: +set(CMAKE_DEPENDS_DEPENDENCY_FILES + ) + +# Targets to which this target links which contain Fortran sources. +set(CMAKE_Fortran_TARGET_LINKED_INFO_FILES + ) + +# Targets to which this target links which contain Fortran sources. +set(CMAKE_Fortran_TARGET_FORWARD_LINKED_INFO_FILES + ) + +# Fortran module output directory. +set(CMAKE_Fortran_TARGET_MODULE_DIR "") diff --git a/static/doc/v1.4.0/CMakeFiles/doc.dir/build.make b/static/doc/v1.4.0/CMakeFiles/doc.dir/build.make new file mode 100644 index 0000000000..46ccf2936d --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc.dir/build.make @@ -0,0 +1,308 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.29 + +# Delete rule output on recipe failure. +.DELETE_ON_ERROR: + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Disable VCS-based implicit rules. +% : %,v + +# Disable VCS-based implicit rules. +% : RCS/% + +# Disable VCS-based implicit rules. +% : RCS/%,v + +# Disable VCS-based implicit rules. +% : SCCS/s.% + +# Disable VCS-based implicit rules. +% : s.% + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/local/bin/cmake + +# The command to remove a file. +RM = /usr/local/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/runner/work/open62541/open62541 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/runner/work/open62541/open62541/build + +# Utility rule file for doc. + +# Include any custom commands dependencies for this target. +include doc/CMakeFiles/doc.dir/compiler_depend.make + +# Include the progress variables for this target. +include doc/CMakeFiles/doc.dir/progress.make + +doc/CMakeFiles/doc: doc_src/types_generated.rst +doc/CMakeFiles/doc: doc_src/types.rst +doc/CMakeFiles/doc: doc_src/common.rst +doc/CMakeFiles/doc: doc_src/util.rst +doc/CMakeFiles/doc: doc_src/statuscodes.rst +doc/CMakeFiles/doc: doc_src/server.rst +doc/CMakeFiles/doc: doc_src/client_subscriptions.rst +doc/CMakeFiles/doc: doc_src/client.rst +doc/CMakeFiles/doc: doc_src/client_highlevel.rst +doc/CMakeFiles/doc: doc_src/client_highlevel_async.rst +doc/CMakeFiles/doc: doc_src/pubsub.rst +doc/CMakeFiles/doc: doc_src/plugin_accesscontrol.rst +doc/CMakeFiles/doc: doc_src/plugin_log.rst +doc/CMakeFiles/doc: doc_src/plugin_nodestore.rst +doc/CMakeFiles/doc: doc_src/plugin_eventloop.rst +doc/CMakeFiles/doc: doc_src/plugin_pki.rst +doc/CMakeFiles/doc: doc_src/plugin_securitypolicy.rst +doc/CMakeFiles/doc: doc_src/tutorial_datatypes.rst +doc/CMakeFiles/doc: doc_src/tutorial_server_firststeps.rst +doc/CMakeFiles/doc: doc_src/tutorial_server_variable.rst +doc/CMakeFiles/doc: doc_src/tutorial_server_variabletype.rst +doc/CMakeFiles/doc: doc_src/tutorial_server_datasource.rst +doc/CMakeFiles/doc: doc_src/tutorial_server_events.rst +doc/CMakeFiles/doc: doc_src/tutorial_server_alarms_conditions.rst +doc/CMakeFiles/doc: doc_src/tutorial_server_monitoreditems.rst +doc/CMakeFiles/doc: doc_src/tutorial_server_object.rst +doc/CMakeFiles/doc: doc_src/tutorial_server_method.rst +doc/CMakeFiles/doc: doc_src/tutorial_client_firststeps.rst +doc/CMakeFiles/doc: doc_src/tutorial_pubsub_publish.rst +doc/CMakeFiles/doc: doc_src/tutorial_pubsub_subscribe.rst +doc/CMakeFiles/doc: doc_src/building.rst +doc/CMakeFiles/doc: doc_src/core_concepts.rst +doc/CMakeFiles/doc: doc_src/index.rst +doc/CMakeFiles/doc: doc_src/nodeset_compiler.rst +doc/CMakeFiles/doc: doc_src/nodeset_compiler_pump.png +doc/CMakeFiles/doc: doc_src/open62541.png +doc/CMakeFiles/doc: doc_src/open62541_html.png +doc/CMakeFiles/doc: doc_src/plugin.rst +doc/CMakeFiles/doc: doc_src/toc.rst +doc/CMakeFiles/doc: doc_src/tutorials.rst +doc/CMakeFiles/doc: doc_src/ua-wireshark-pubsub.png +doc/CMakeFiles/doc: doc_src/ua-wireshark.png + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building HTML documentation with Sphinx" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/sphinx-build -b html /home/runner/work/open62541/open62541/build/doc_src /home/runner/work/open62541/open62541/build/doc + +doc_src/client.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/client.rst: /home/runner/work/open62541/open62541/include/open62541/client.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_2) "Generating ../doc_src/client.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/client.h /home/runner/work/open62541/open62541/build/doc_src/client.rst + +doc_src/client_highlevel.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/client_highlevel.rst: /home/runner/work/open62541/open62541/include/open62541/client_highlevel.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_3) "Generating ../doc_src/client_highlevel.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/client_highlevel.h /home/runner/work/open62541/open62541/build/doc_src/client_highlevel.rst + +doc_src/client_highlevel_async.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/client_highlevel_async.rst: /home/runner/work/open62541/open62541/include/open62541/client_highlevel_async.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_4) "Generating ../doc_src/client_highlevel_async.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/client_highlevel_async.h /home/runner/work/open62541/open62541/build/doc_src/client_highlevel_async.rst + +doc_src/client_subscriptions.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/client_subscriptions.rst: /home/runner/work/open62541/open62541/include/open62541/client_subscriptions.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_5) "Generating ../doc_src/client_subscriptions.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/client_subscriptions.h /home/runner/work/open62541/open62541/build/doc_src/client_subscriptions.rst + +doc_src/common.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/common.rst: /home/runner/work/open62541/open62541/include/open62541/common.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_6) "Generating ../doc_src/common.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/common.h /home/runner/work/open62541/open62541/build/doc_src/common.rst + +doc_src/plugin_accesscontrol.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/plugin_accesscontrol.rst: /home/runner/work/open62541/open62541/include/open62541/plugin/accesscontrol.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_7) "Generating ../doc_src/plugin_accesscontrol.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/plugin/accesscontrol.h /home/runner/work/open62541/open62541/build/doc_src/plugin_accesscontrol.rst + +doc_src/plugin_eventloop.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/plugin_eventloop.rst: /home/runner/work/open62541/open62541/include/open62541/plugin/eventloop.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_8) "Generating ../doc_src/plugin_eventloop.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/plugin/eventloop.h /home/runner/work/open62541/open62541/build/doc_src/plugin_eventloop.rst + +doc_src/plugin_log.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/plugin_log.rst: /home/runner/work/open62541/open62541/include/open62541/plugin/log.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_9) "Generating ../doc_src/plugin_log.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/plugin/log.h /home/runner/work/open62541/open62541/build/doc_src/plugin_log.rst + +doc_src/plugin_nodestore.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/plugin_nodestore.rst: /home/runner/work/open62541/open62541/include/open62541/plugin/nodestore.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_10) "Generating ../doc_src/plugin_nodestore.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/plugin/nodestore.h /home/runner/work/open62541/open62541/build/doc_src/plugin_nodestore.rst + +doc_src/plugin_pki.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/plugin_pki.rst: /home/runner/work/open62541/open62541/include/open62541/plugin/pki.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_11) "Generating ../doc_src/plugin_pki.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/plugin/pki.h /home/runner/work/open62541/open62541/build/doc_src/plugin_pki.rst + +doc_src/plugin_securitypolicy.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/plugin_securitypolicy.rst: /home/runner/work/open62541/open62541/include/open62541/plugin/securitypolicy.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_12) "Generating ../doc_src/plugin_securitypolicy.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/plugin/securitypolicy.h /home/runner/work/open62541/open62541/build/doc_src/plugin_securitypolicy.rst + +doc_src/pubsub.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/pubsub.rst: /home/runner/work/open62541/open62541/include/open62541/server_pubsub.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_13) "Generating ../doc_src/pubsub.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/server_pubsub.h /home/runner/work/open62541/open62541/build/doc_src/pubsub.rst + +doc_src/server.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/server.rst: /home/runner/work/open62541/open62541/include/open62541/server.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_14) "Generating ../doc_src/server.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/server.h /home/runner/work/open62541/open62541/build/doc_src/server.rst + +doc_src/statuscodes.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/statuscodes.rst: src_generated/open62541/statuscodes.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_15) "Generating ../doc_src/statuscodes.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/build/src_generated/open62541/statuscodes.h /home/runner/work/open62541/open62541/build/doc_src/statuscodes.rst + +doc_src/tutorial_client_firststeps.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_client_firststeps.rst: /home/runner/work/open62541/open62541/examples/tutorial_client_firststeps.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_16) "Generating ../doc_src/tutorial_client_firststeps.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_client_firststeps.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_client_firststeps.rst + +doc_src/tutorial_datatypes.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_datatypes.rst: /home/runner/work/open62541/open62541/examples/tutorial_datatypes.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_17) "Generating ../doc_src/tutorial_datatypes.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_datatypes.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_datatypes.rst + +doc_src/tutorial_pubsub_publish.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_pubsub_publish.rst: /home/runner/work/open62541/open62541/examples/pubsub/tutorial_pubsub_publish.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_18) "Generating ../doc_src/tutorial_pubsub_publish.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/pubsub/tutorial_pubsub_publish.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_pubsub_publish.rst + +doc_src/tutorial_pubsub_subscribe.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_pubsub_subscribe.rst: /home/runner/work/open62541/open62541/examples/pubsub/tutorial_pubsub_subscribe.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_19) "Generating ../doc_src/tutorial_pubsub_subscribe.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/pubsub/tutorial_pubsub_subscribe.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_pubsub_subscribe.rst + +doc_src/tutorial_server_alarms_conditions.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_alarms_conditions.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_alarms_conditions.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_20) "Generating ../doc_src/tutorial_server_alarms_conditions.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_alarms_conditions.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_alarms_conditions.rst + +doc_src/tutorial_server_datasource.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_datasource.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_datasource.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_21) "Generating ../doc_src/tutorial_server_datasource.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_datasource.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_datasource.rst + +doc_src/tutorial_server_events.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_events.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_events.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_22) "Generating ../doc_src/tutorial_server_events.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_events.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_events.rst + +doc_src/tutorial_server_firststeps.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_firststeps.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_firststeps.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_23) "Generating ../doc_src/tutorial_server_firststeps.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_firststeps.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_firststeps.rst + +doc_src/tutorial_server_method.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_method.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_method.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_24) "Generating ../doc_src/tutorial_server_method.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_method.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_method.rst + +doc_src/tutorial_server_monitoreditems.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_monitoreditems.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_monitoreditems.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_25) "Generating ../doc_src/tutorial_server_monitoreditems.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_monitoreditems.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_monitoreditems.rst + +doc_src/tutorial_server_object.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_object.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_object.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_26) "Generating ../doc_src/tutorial_server_object.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_object.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_object.rst + +doc_src/tutorial_server_variable.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_variable.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_variable.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_27) "Generating ../doc_src/tutorial_server_variable.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_variable.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_variable.rst + +doc_src/tutorial_server_variabletype.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_variabletype.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_variabletype.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_28) "Generating ../doc_src/tutorial_server_variabletype.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_variabletype.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_variabletype.rst + +doc_src/types.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/types.rst: /home/runner/work/open62541/open62541/include/open62541/types.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_29) "Generating ../doc_src/types.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/types.h /home/runner/work/open62541/open62541/build/doc_src/types.rst + +doc_src/types_generated.rst: src_generated/open62541/types_generated.rst + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_30) "Generating ../doc_src/types_generated.rst" + cd /home/runner/work/open62541/open62541/build/doc && /usr/local/bin/cmake -E copy /home/runner/work/open62541/open62541/build/src_generated/open62541/types_generated.rst /home/runner/work/open62541/open62541/build/doc_src + +doc_src/util.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/util.rst: /home/runner/work/open62541/open62541/include/open62541/util.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_31) "Generating ../doc_src/util.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/util.h /home/runner/work/open62541/open62541/build/doc_src/util.rst + +doc: doc/CMakeFiles/doc +doc: doc_src/client.rst +doc: doc_src/client_highlevel.rst +doc: doc_src/client_highlevel_async.rst +doc: doc_src/client_subscriptions.rst +doc: doc_src/common.rst +doc: doc_src/plugin_accesscontrol.rst +doc: doc_src/plugin_eventloop.rst +doc: doc_src/plugin_log.rst +doc: doc_src/plugin_nodestore.rst +doc: doc_src/plugin_pki.rst +doc: doc_src/plugin_securitypolicy.rst +doc: doc_src/pubsub.rst +doc: doc_src/server.rst +doc: doc_src/statuscodes.rst +doc: doc_src/tutorial_client_firststeps.rst +doc: doc_src/tutorial_datatypes.rst +doc: doc_src/tutorial_pubsub_publish.rst +doc: doc_src/tutorial_pubsub_subscribe.rst +doc: doc_src/tutorial_server_alarms_conditions.rst +doc: doc_src/tutorial_server_datasource.rst +doc: doc_src/tutorial_server_events.rst +doc: doc_src/tutorial_server_firststeps.rst +doc: doc_src/tutorial_server_method.rst +doc: doc_src/tutorial_server_monitoreditems.rst +doc: doc_src/tutorial_server_object.rst +doc: doc_src/tutorial_server_variable.rst +doc: doc_src/tutorial_server_variabletype.rst +doc: doc_src/types.rst +doc: doc_src/types_generated.rst +doc: doc_src/util.rst +doc: doc/CMakeFiles/doc.dir/build.make +.PHONY : doc + +# Rule to build all files generated by this target. +doc/CMakeFiles/doc.dir/build: doc +.PHONY : doc/CMakeFiles/doc.dir/build + +doc/CMakeFiles/doc.dir/clean: + cd /home/runner/work/open62541/open62541/build/doc && $(CMAKE_COMMAND) -P CMakeFiles/doc.dir/cmake_clean.cmake +.PHONY : doc/CMakeFiles/doc.dir/clean + +doc/CMakeFiles/doc.dir/depend: + cd /home/runner/work/open62541/open62541/build && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/runner/work/open62541/open62541 /home/runner/work/open62541/open62541/doc /home/runner/work/open62541/open62541/build /home/runner/work/open62541/open62541/build/doc /home/runner/work/open62541/open62541/build/doc/CMakeFiles/doc.dir/DependInfo.cmake "--color=$(COLOR)" +.PHONY : doc/CMakeFiles/doc.dir/depend + diff --git a/static/doc/v1.4.0/CMakeFiles/doc.dir/cmake_clean.cmake b/static/doc/v1.4.0/CMakeFiles/doc.dir/cmake_clean.cmake new file mode 100644 index 0000000000..7bf348d83b --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc.dir/cmake_clean.cmake @@ -0,0 +1,38 @@ +file(REMOVE_RECURSE + "../doc_src/client.rst" + "../doc_src/client_highlevel.rst" + "../doc_src/client_highlevel_async.rst" + "../doc_src/client_subscriptions.rst" + "../doc_src/common.rst" + "../doc_src/plugin_accesscontrol.rst" + "../doc_src/plugin_eventloop.rst" + "../doc_src/plugin_log.rst" + "../doc_src/plugin_nodestore.rst" + "../doc_src/plugin_pki.rst" + "../doc_src/plugin_securitypolicy.rst" + "../doc_src/pubsub.rst" + "../doc_src/server.rst" + "../doc_src/statuscodes.rst" + "../doc_src/tutorial_client_firststeps.rst" + "../doc_src/tutorial_datatypes.rst" + "../doc_src/tutorial_pubsub_publish.rst" + "../doc_src/tutorial_pubsub_subscribe.rst" + "../doc_src/tutorial_server_alarms_conditions.rst" + "../doc_src/tutorial_server_datasource.rst" + "../doc_src/tutorial_server_events.rst" + "../doc_src/tutorial_server_firststeps.rst" + "../doc_src/tutorial_server_method.rst" + "../doc_src/tutorial_server_monitoreditems.rst" + "../doc_src/tutorial_server_object.rst" + "../doc_src/tutorial_server_variable.rst" + "../doc_src/tutorial_server_variabletype.rst" + "../doc_src/types.rst" + "../doc_src/types_generated.rst" + "../doc_src/util.rst" + "CMakeFiles/doc" +) + +# Per-language clean rules from dependency scanning. +foreach(lang ) + include(CMakeFiles/doc.dir/cmake_clean_${lang}.cmake OPTIONAL) +endforeach() diff --git a/static/doc/v1.4.0/CMakeFiles/doc.dir/compiler_depend.make b/static/doc/v1.4.0/CMakeFiles/doc.dir/compiler_depend.make new file mode 100644 index 0000000000..585baf2797 --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc.dir/compiler_depend.make @@ -0,0 +1,2 @@ +# Empty custom commands generated dependencies file for doc. +# This may be replaced when dependencies are built. diff --git a/static/doc/v1.4.0/CMakeFiles/doc.dir/compiler_depend.ts b/static/doc/v1.4.0/CMakeFiles/doc.dir/compiler_depend.ts new file mode 100644 index 0000000000..3de913dc49 --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc.dir/compiler_depend.ts @@ -0,0 +1,2 @@ +# CMAKE generated file: DO NOT EDIT! +# Timestamp file for custom commands dependencies management for doc. diff --git a/static/doc/v1.4.0/CMakeFiles/doc.dir/progress.make b/static/doc/v1.4.0/CMakeFiles/doc.dir/progress.make new file mode 100644 index 0000000000..89206e105f --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc.dir/progress.make @@ -0,0 +1,32 @@ +CMAKE_PROGRESS_1 = +CMAKE_PROGRESS_2 = 15 +CMAKE_PROGRESS_3 = +CMAKE_PROGRESS_4 = +CMAKE_PROGRESS_5 = 16 +CMAKE_PROGRESS_6 = +CMAKE_PROGRESS_7 = 17 +CMAKE_PROGRESS_8 = +CMAKE_PROGRESS_9 = +CMAKE_PROGRESS_10 = 18 +CMAKE_PROGRESS_11 = +CMAKE_PROGRESS_12 = 19 +CMAKE_PROGRESS_13 = +CMAKE_PROGRESS_14 = +CMAKE_PROGRESS_15 = 20 +CMAKE_PROGRESS_16 = +CMAKE_PROGRESS_17 = 21 +CMAKE_PROGRESS_18 = +CMAKE_PROGRESS_19 = +CMAKE_PROGRESS_20 = 22 +CMAKE_PROGRESS_21 = +CMAKE_PROGRESS_22 = 23 +CMAKE_PROGRESS_23 = +CMAKE_PROGRESS_24 = +CMAKE_PROGRESS_25 = 24 +CMAKE_PROGRESS_26 = +CMAKE_PROGRESS_27 = 25 +CMAKE_PROGRESS_28 = +CMAKE_PROGRESS_29 = +CMAKE_PROGRESS_30 = 26 +CMAKE_PROGRESS_31 = + diff --git a/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/DependInfo.cmake b/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/DependInfo.cmake new file mode 100644 index 0000000000..29b95a515e --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/DependInfo.cmake @@ -0,0 +1,22 @@ + +# Consider dependencies only in project. +set(CMAKE_DEPENDS_IN_PROJECT_ONLY OFF) + +# The set of languages for which implicit dependencies are needed: +set(CMAKE_DEPENDS_LANGUAGES + ) + +# The set of dependency files which are needed: +set(CMAKE_DEPENDS_DEPENDENCY_FILES + ) + +# Targets to which this target links which contain Fortran sources. +set(CMAKE_Fortran_TARGET_LINKED_INFO_FILES + ) + +# Targets to which this target links which contain Fortran sources. +set(CMAKE_Fortran_TARGET_FORWARD_LINKED_INFO_FILES + ) + +# Fortran module output directory. +set(CMAKE_Fortran_TARGET_MODULE_DIR "") diff --git a/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/build.make b/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/build.make new file mode 100644 index 0000000000..a240e46438 --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/build.make @@ -0,0 +1,308 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.29 + +# Delete rule output on recipe failure. +.DELETE_ON_ERROR: + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Disable VCS-based implicit rules. +% : %,v + +# Disable VCS-based implicit rules. +% : RCS/% + +# Disable VCS-based implicit rules. +% : RCS/%,v + +# Disable VCS-based implicit rules. +% : SCCS/s.% + +# Disable VCS-based implicit rules. +% : s.% + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/local/bin/cmake + +# The command to remove a file. +RM = /usr/local/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/runner/work/open62541/open62541 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/runner/work/open62541/open62541/build + +# Utility rule file for doc_latex. + +# Include any custom commands dependencies for this target. +include doc/CMakeFiles/doc_latex.dir/compiler_depend.make + +# Include the progress variables for this target. +include doc/CMakeFiles/doc_latex.dir/progress.make + +doc/CMakeFiles/doc_latex: doc_src/types_generated.rst +doc/CMakeFiles/doc_latex: doc_src/types.rst +doc/CMakeFiles/doc_latex: doc_src/common.rst +doc/CMakeFiles/doc_latex: doc_src/util.rst +doc/CMakeFiles/doc_latex: doc_src/statuscodes.rst +doc/CMakeFiles/doc_latex: doc_src/server.rst +doc/CMakeFiles/doc_latex: doc_src/client_subscriptions.rst +doc/CMakeFiles/doc_latex: doc_src/client.rst +doc/CMakeFiles/doc_latex: doc_src/client_highlevel.rst +doc/CMakeFiles/doc_latex: doc_src/client_highlevel_async.rst +doc/CMakeFiles/doc_latex: doc_src/pubsub.rst +doc/CMakeFiles/doc_latex: doc_src/plugin_accesscontrol.rst +doc/CMakeFiles/doc_latex: doc_src/plugin_log.rst +doc/CMakeFiles/doc_latex: doc_src/plugin_nodestore.rst +doc/CMakeFiles/doc_latex: doc_src/plugin_eventloop.rst +doc/CMakeFiles/doc_latex: doc_src/plugin_pki.rst +doc/CMakeFiles/doc_latex: doc_src/plugin_securitypolicy.rst +doc/CMakeFiles/doc_latex: doc_src/tutorial_datatypes.rst +doc/CMakeFiles/doc_latex: doc_src/tutorial_server_firststeps.rst +doc/CMakeFiles/doc_latex: doc_src/tutorial_server_variable.rst +doc/CMakeFiles/doc_latex: doc_src/tutorial_server_variabletype.rst +doc/CMakeFiles/doc_latex: doc_src/tutorial_server_datasource.rst +doc/CMakeFiles/doc_latex: doc_src/tutorial_server_events.rst +doc/CMakeFiles/doc_latex: doc_src/tutorial_server_alarms_conditions.rst +doc/CMakeFiles/doc_latex: doc_src/tutorial_server_monitoreditems.rst +doc/CMakeFiles/doc_latex: doc_src/tutorial_server_object.rst +doc/CMakeFiles/doc_latex: doc_src/tutorial_server_method.rst +doc/CMakeFiles/doc_latex: doc_src/tutorial_client_firststeps.rst +doc/CMakeFiles/doc_latex: doc_src/tutorial_pubsub_publish.rst +doc/CMakeFiles/doc_latex: doc_src/tutorial_pubsub_subscribe.rst +doc/CMakeFiles/doc_latex: doc_src/building.rst +doc/CMakeFiles/doc_latex: doc_src/core_concepts.rst +doc/CMakeFiles/doc_latex: doc_src/index.rst +doc/CMakeFiles/doc_latex: doc_src/nodeset_compiler.rst +doc/CMakeFiles/doc_latex: doc_src/nodeset_compiler_pump.png +doc/CMakeFiles/doc_latex: doc_src/open62541.png +doc/CMakeFiles/doc_latex: doc_src/open62541_html.png +doc/CMakeFiles/doc_latex: doc_src/plugin.rst +doc/CMakeFiles/doc_latex: doc_src/toc.rst +doc/CMakeFiles/doc_latex: doc_src/tutorials.rst +doc/CMakeFiles/doc_latex: doc_src/ua-wireshark-pubsub.png +doc/CMakeFiles/doc_latex: doc_src/ua-wireshark.png + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building LaTeX sources for documentation with Sphinx" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/sphinx-build -b latex /home/runner/work/open62541/open62541/build/doc_src /home/runner/work/open62541/open62541/build/doc_latex + +doc_src/client.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/client.rst: /home/runner/work/open62541/open62541/include/open62541/client.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_2) "Generating ../doc_src/client.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/client.h /home/runner/work/open62541/open62541/build/doc_src/client.rst + +doc_src/client_highlevel.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/client_highlevel.rst: /home/runner/work/open62541/open62541/include/open62541/client_highlevel.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_3) "Generating ../doc_src/client_highlevel.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/client_highlevel.h /home/runner/work/open62541/open62541/build/doc_src/client_highlevel.rst + +doc_src/client_highlevel_async.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/client_highlevel_async.rst: /home/runner/work/open62541/open62541/include/open62541/client_highlevel_async.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_4) "Generating ../doc_src/client_highlevel_async.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/client_highlevel_async.h /home/runner/work/open62541/open62541/build/doc_src/client_highlevel_async.rst + +doc_src/client_subscriptions.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/client_subscriptions.rst: /home/runner/work/open62541/open62541/include/open62541/client_subscriptions.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_5) "Generating ../doc_src/client_subscriptions.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/client_subscriptions.h /home/runner/work/open62541/open62541/build/doc_src/client_subscriptions.rst + +doc_src/common.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/common.rst: /home/runner/work/open62541/open62541/include/open62541/common.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_6) "Generating ../doc_src/common.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/common.h /home/runner/work/open62541/open62541/build/doc_src/common.rst + +doc_src/plugin_accesscontrol.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/plugin_accesscontrol.rst: /home/runner/work/open62541/open62541/include/open62541/plugin/accesscontrol.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_7) "Generating ../doc_src/plugin_accesscontrol.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/plugin/accesscontrol.h /home/runner/work/open62541/open62541/build/doc_src/plugin_accesscontrol.rst + +doc_src/plugin_eventloop.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/plugin_eventloop.rst: /home/runner/work/open62541/open62541/include/open62541/plugin/eventloop.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_8) "Generating ../doc_src/plugin_eventloop.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/plugin/eventloop.h /home/runner/work/open62541/open62541/build/doc_src/plugin_eventloop.rst + +doc_src/plugin_log.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/plugin_log.rst: /home/runner/work/open62541/open62541/include/open62541/plugin/log.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_9) "Generating ../doc_src/plugin_log.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/plugin/log.h /home/runner/work/open62541/open62541/build/doc_src/plugin_log.rst + +doc_src/plugin_nodestore.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/plugin_nodestore.rst: /home/runner/work/open62541/open62541/include/open62541/plugin/nodestore.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_10) "Generating ../doc_src/plugin_nodestore.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/plugin/nodestore.h /home/runner/work/open62541/open62541/build/doc_src/plugin_nodestore.rst + +doc_src/plugin_pki.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/plugin_pki.rst: /home/runner/work/open62541/open62541/include/open62541/plugin/pki.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_11) "Generating ../doc_src/plugin_pki.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/plugin/pki.h /home/runner/work/open62541/open62541/build/doc_src/plugin_pki.rst + +doc_src/plugin_securitypolicy.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/plugin_securitypolicy.rst: /home/runner/work/open62541/open62541/include/open62541/plugin/securitypolicy.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_12) "Generating ../doc_src/plugin_securitypolicy.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/plugin/securitypolicy.h /home/runner/work/open62541/open62541/build/doc_src/plugin_securitypolicy.rst + +doc_src/pubsub.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/pubsub.rst: /home/runner/work/open62541/open62541/include/open62541/server_pubsub.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_13) "Generating ../doc_src/pubsub.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/server_pubsub.h /home/runner/work/open62541/open62541/build/doc_src/pubsub.rst + +doc_src/server.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/server.rst: /home/runner/work/open62541/open62541/include/open62541/server.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_14) "Generating ../doc_src/server.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/server.h /home/runner/work/open62541/open62541/build/doc_src/server.rst + +doc_src/statuscodes.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/statuscodes.rst: src_generated/open62541/statuscodes.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_15) "Generating ../doc_src/statuscodes.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/build/src_generated/open62541/statuscodes.h /home/runner/work/open62541/open62541/build/doc_src/statuscodes.rst + +doc_src/tutorial_client_firststeps.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_client_firststeps.rst: /home/runner/work/open62541/open62541/examples/tutorial_client_firststeps.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_16) "Generating ../doc_src/tutorial_client_firststeps.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_client_firststeps.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_client_firststeps.rst + +doc_src/tutorial_datatypes.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_datatypes.rst: /home/runner/work/open62541/open62541/examples/tutorial_datatypes.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_17) "Generating ../doc_src/tutorial_datatypes.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_datatypes.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_datatypes.rst + +doc_src/tutorial_pubsub_publish.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_pubsub_publish.rst: /home/runner/work/open62541/open62541/examples/pubsub/tutorial_pubsub_publish.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_18) "Generating ../doc_src/tutorial_pubsub_publish.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/pubsub/tutorial_pubsub_publish.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_pubsub_publish.rst + +doc_src/tutorial_pubsub_subscribe.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_pubsub_subscribe.rst: /home/runner/work/open62541/open62541/examples/pubsub/tutorial_pubsub_subscribe.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_19) "Generating ../doc_src/tutorial_pubsub_subscribe.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/pubsub/tutorial_pubsub_subscribe.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_pubsub_subscribe.rst + +doc_src/tutorial_server_alarms_conditions.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_alarms_conditions.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_alarms_conditions.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_20) "Generating ../doc_src/tutorial_server_alarms_conditions.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_alarms_conditions.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_alarms_conditions.rst + +doc_src/tutorial_server_datasource.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_datasource.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_datasource.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_21) "Generating ../doc_src/tutorial_server_datasource.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_datasource.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_datasource.rst + +doc_src/tutorial_server_events.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_events.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_events.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_22) "Generating ../doc_src/tutorial_server_events.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_events.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_events.rst + +doc_src/tutorial_server_firststeps.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_firststeps.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_firststeps.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_23) "Generating ../doc_src/tutorial_server_firststeps.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_firststeps.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_firststeps.rst + +doc_src/tutorial_server_method.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_method.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_method.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_24) "Generating ../doc_src/tutorial_server_method.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_method.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_method.rst + +doc_src/tutorial_server_monitoreditems.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_monitoreditems.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_monitoreditems.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_25) "Generating ../doc_src/tutorial_server_monitoreditems.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_monitoreditems.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_monitoreditems.rst + +doc_src/tutorial_server_object.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_object.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_object.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_26) "Generating ../doc_src/tutorial_server_object.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_object.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_object.rst + +doc_src/tutorial_server_variable.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_variable.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_variable.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_27) "Generating ../doc_src/tutorial_server_variable.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_variable.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_variable.rst + +doc_src/tutorial_server_variabletype.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/tutorial_server_variabletype.rst: /home/runner/work/open62541/open62541/examples/tutorial_server_variabletype.c + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_28) "Generating ../doc_src/tutorial_server_variabletype.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/examples/tutorial_server_variabletype.c /home/runner/work/open62541/open62541/build/doc_src/tutorial_server_variabletype.rst + +doc_src/types.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/types.rst: /home/runner/work/open62541/open62541/include/open62541/types.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_29) "Generating ../doc_src/types.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/types.h /home/runner/work/open62541/open62541/build/doc_src/types.rst + +doc_src/types_generated.rst: src_generated/open62541/types_generated.rst + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_30) "Generating ../doc_src/types_generated.rst" + cd /home/runner/work/open62541/open62541/build/doc && /usr/local/bin/cmake -E copy /home/runner/work/open62541/open62541/build/src_generated/open62541/types_generated.rst /home/runner/work/open62541/open62541/build/doc_src + +doc_src/util.rst: /home/runner/work/open62541/open62541/tools/c2rst.py +doc_src/util.rst: /home/runner/work/open62541/open62541/include/open62541/util.h + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_31) "Generating ../doc_src/util.rst" + cd /home/runner/work/open62541/open62541/build/doc && /opt/hostedtoolcache/Python/3.12.2/x64/bin/python3 /home/runner/work/open62541/open62541/tools/c2rst.py /home/runner/work/open62541/open62541/include/open62541/util.h /home/runner/work/open62541/open62541/build/doc_src/util.rst + +doc_latex: doc/CMakeFiles/doc_latex +doc_latex: doc_src/client.rst +doc_latex: doc_src/client_highlevel.rst +doc_latex: doc_src/client_highlevel_async.rst +doc_latex: doc_src/client_subscriptions.rst +doc_latex: doc_src/common.rst +doc_latex: doc_src/plugin_accesscontrol.rst +doc_latex: doc_src/plugin_eventloop.rst +doc_latex: doc_src/plugin_log.rst +doc_latex: doc_src/plugin_nodestore.rst +doc_latex: doc_src/plugin_pki.rst +doc_latex: doc_src/plugin_securitypolicy.rst +doc_latex: doc_src/pubsub.rst +doc_latex: doc_src/server.rst +doc_latex: doc_src/statuscodes.rst +doc_latex: doc_src/tutorial_client_firststeps.rst +doc_latex: doc_src/tutorial_datatypes.rst +doc_latex: doc_src/tutorial_pubsub_publish.rst +doc_latex: doc_src/tutorial_pubsub_subscribe.rst +doc_latex: doc_src/tutorial_server_alarms_conditions.rst +doc_latex: doc_src/tutorial_server_datasource.rst +doc_latex: doc_src/tutorial_server_events.rst +doc_latex: doc_src/tutorial_server_firststeps.rst +doc_latex: doc_src/tutorial_server_method.rst +doc_latex: doc_src/tutorial_server_monitoreditems.rst +doc_latex: doc_src/tutorial_server_object.rst +doc_latex: doc_src/tutorial_server_variable.rst +doc_latex: doc_src/tutorial_server_variabletype.rst +doc_latex: doc_src/types.rst +doc_latex: doc_src/types_generated.rst +doc_latex: doc_src/util.rst +doc_latex: doc/CMakeFiles/doc_latex.dir/build.make +.PHONY : doc_latex + +# Rule to build all files generated by this target. +doc/CMakeFiles/doc_latex.dir/build: doc_latex +.PHONY : doc/CMakeFiles/doc_latex.dir/build + +doc/CMakeFiles/doc_latex.dir/clean: + cd /home/runner/work/open62541/open62541/build/doc && $(CMAKE_COMMAND) -P CMakeFiles/doc_latex.dir/cmake_clean.cmake +.PHONY : doc/CMakeFiles/doc_latex.dir/clean + +doc/CMakeFiles/doc_latex.dir/depend: + cd /home/runner/work/open62541/open62541/build && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/runner/work/open62541/open62541 /home/runner/work/open62541/open62541/doc /home/runner/work/open62541/open62541/build /home/runner/work/open62541/open62541/build/doc /home/runner/work/open62541/open62541/build/doc/CMakeFiles/doc_latex.dir/DependInfo.cmake "--color=$(COLOR)" +.PHONY : doc/CMakeFiles/doc_latex.dir/depend + diff --git a/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/cmake_clean.cmake b/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/cmake_clean.cmake new file mode 100644 index 0000000000..7a886de658 --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/cmake_clean.cmake @@ -0,0 +1,38 @@ +file(REMOVE_RECURSE + "../doc_src/client.rst" + "../doc_src/client_highlevel.rst" + "../doc_src/client_highlevel_async.rst" + "../doc_src/client_subscriptions.rst" + "../doc_src/common.rst" + "../doc_src/plugin_accesscontrol.rst" + "../doc_src/plugin_eventloop.rst" + "../doc_src/plugin_log.rst" + "../doc_src/plugin_nodestore.rst" + "../doc_src/plugin_pki.rst" + "../doc_src/plugin_securitypolicy.rst" + "../doc_src/pubsub.rst" + "../doc_src/server.rst" + "../doc_src/statuscodes.rst" + "../doc_src/tutorial_client_firststeps.rst" + "../doc_src/tutorial_datatypes.rst" + "../doc_src/tutorial_pubsub_publish.rst" + "../doc_src/tutorial_pubsub_subscribe.rst" + "../doc_src/tutorial_server_alarms_conditions.rst" + "../doc_src/tutorial_server_datasource.rst" + "../doc_src/tutorial_server_events.rst" + "../doc_src/tutorial_server_firststeps.rst" + "../doc_src/tutorial_server_method.rst" + "../doc_src/tutorial_server_monitoreditems.rst" + "../doc_src/tutorial_server_object.rst" + "../doc_src/tutorial_server_variable.rst" + "../doc_src/tutorial_server_variabletype.rst" + "../doc_src/types.rst" + "../doc_src/types_generated.rst" + "../doc_src/util.rst" + "CMakeFiles/doc_latex" +) + +# Per-language clean rules from dependency scanning. +foreach(lang ) + include(CMakeFiles/doc_latex.dir/cmake_clean_${lang}.cmake OPTIONAL) +endforeach() diff --git a/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/compiler_depend.make b/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/compiler_depend.make new file mode 100644 index 0000000000..7fb9c87275 --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/compiler_depend.make @@ -0,0 +1,2 @@ +# Empty custom commands generated dependencies file for doc_latex. +# This may be replaced when dependencies are built. diff --git a/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/compiler_depend.ts b/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/compiler_depend.ts new file mode 100644 index 0000000000..ee8837e724 --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/compiler_depend.ts @@ -0,0 +1,2 @@ +# CMAKE generated file: DO NOT EDIT! +# Timestamp file for custom commands dependencies management for doc_latex. diff --git a/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/progress.make b/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/progress.make new file mode 100644 index 0000000000..59a40782a7 --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc_latex.dir/progress.make @@ -0,0 +1,32 @@ +CMAKE_PROGRESS_1 = +CMAKE_PROGRESS_2 = 27 +CMAKE_PROGRESS_3 = +CMAKE_PROGRESS_4 = 28 +CMAKE_PROGRESS_5 = +CMAKE_PROGRESS_6 = +CMAKE_PROGRESS_7 = 29 +CMAKE_PROGRESS_8 = +CMAKE_PROGRESS_9 = 30 +CMAKE_PROGRESS_10 = +CMAKE_PROGRESS_11 = +CMAKE_PROGRESS_12 = 31 +CMAKE_PROGRESS_13 = +CMAKE_PROGRESS_14 = 32 +CMAKE_PROGRESS_15 = +CMAKE_PROGRESS_16 = +CMAKE_PROGRESS_17 = 33 +CMAKE_PROGRESS_18 = +CMAKE_PROGRESS_19 = 34 +CMAKE_PROGRESS_20 = +CMAKE_PROGRESS_21 = +CMAKE_PROGRESS_22 = 35 +CMAKE_PROGRESS_23 = +CMAKE_PROGRESS_24 = 36 +CMAKE_PROGRESS_25 = +CMAKE_PROGRESS_26 = +CMAKE_PROGRESS_27 = 37 +CMAKE_PROGRESS_28 = +CMAKE_PROGRESS_29 = 38 +CMAKE_PROGRESS_30 = +CMAKE_PROGRESS_31 = + diff --git a/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/DependInfo.cmake b/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/DependInfo.cmake new file mode 100644 index 0000000000..29b95a515e --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/DependInfo.cmake @@ -0,0 +1,22 @@ + +# Consider dependencies only in project. +set(CMAKE_DEPENDS_IN_PROJECT_ONLY OFF) + +# The set of languages for which implicit dependencies are needed: +set(CMAKE_DEPENDS_LANGUAGES + ) + +# The set of dependency files which are needed: +set(CMAKE_DEPENDS_DEPENDENCY_FILES + ) + +# Targets to which this target links which contain Fortran sources. +set(CMAKE_Fortran_TARGET_LINKED_INFO_FILES + ) + +# Targets to which this target links which contain Fortran sources. +set(CMAKE_Fortran_TARGET_FORWARD_LINKED_INFO_FILES + ) + +# Fortran module output directory. +set(CMAKE_Fortran_TARGET_MODULE_DIR "") diff --git a/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/build.make b/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/build.make new file mode 100644 index 0000000000..d99792abe9 --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/build.make @@ -0,0 +1,89 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.29 + +# Delete rule output on recipe failure. +.DELETE_ON_ERROR: + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Disable VCS-based implicit rules. +% : %,v + +# Disable VCS-based implicit rules. +% : RCS/% + +# Disable VCS-based implicit rules. +% : RCS/%,v + +# Disable VCS-based implicit rules. +% : SCCS/s.% + +# Disable VCS-based implicit rules. +% : s.% + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/local/bin/cmake + +# The command to remove a file. +RM = /usr/local/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/runner/work/open62541/open62541 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/runner/work/open62541/open62541/build + +# Utility rule file for doc_pdf. + +# Include any custom commands dependencies for this target. +include doc/CMakeFiles/doc_pdf.dir/compiler_depend.make + +# Include the progress variables for this target. +include doc/CMakeFiles/doc_pdf.dir/progress.make + +doc/CMakeFiles/doc_pdf: /usr/bin/pdflatex + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --blue --bold --progress-dir=/home/runner/work/open62541/open62541/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Generating PDF documentation from LaTeX sources" + cd /home/runner/work/open62541/open62541/build/doc_latex && /usr/bin/pdflatex -interaction=batchmode open62541.tex + cd /home/runner/work/open62541/open62541/build/doc_latex && /usr/bin/pdflatex -interaction=batchmode open62541.tex + +doc_pdf: doc/CMakeFiles/doc_pdf +doc_pdf: doc/CMakeFiles/doc_pdf.dir/build.make +.PHONY : doc_pdf + +# Rule to build all files generated by this target. +doc/CMakeFiles/doc_pdf.dir/build: doc_pdf +.PHONY : doc/CMakeFiles/doc_pdf.dir/build + +doc/CMakeFiles/doc_pdf.dir/clean: + cd /home/runner/work/open62541/open62541/build/doc && $(CMAKE_COMMAND) -P CMakeFiles/doc_pdf.dir/cmake_clean.cmake +.PHONY : doc/CMakeFiles/doc_pdf.dir/clean + +doc/CMakeFiles/doc_pdf.dir/depend: + cd /home/runner/work/open62541/open62541/build && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/runner/work/open62541/open62541 /home/runner/work/open62541/open62541/doc /home/runner/work/open62541/open62541/build /home/runner/work/open62541/open62541/build/doc /home/runner/work/open62541/open62541/build/doc/CMakeFiles/doc_pdf.dir/DependInfo.cmake "--color=$(COLOR)" +.PHONY : doc/CMakeFiles/doc_pdf.dir/depend + diff --git a/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/cmake_clean.cmake b/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/cmake_clean.cmake new file mode 100644 index 0000000000..54efdd60bb --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/cmake_clean.cmake @@ -0,0 +1,8 @@ +file(REMOVE_RECURSE + "CMakeFiles/doc_pdf" +) + +# Per-language clean rules from dependency scanning. +foreach(lang ) + include(CMakeFiles/doc_pdf.dir/cmake_clean_${lang}.cmake OPTIONAL) +endforeach() diff --git a/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/compiler_depend.make b/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/compiler_depend.make new file mode 100644 index 0000000000..10fdfbe856 --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/compiler_depend.make @@ -0,0 +1,2 @@ +# Empty custom commands generated dependencies file for doc_pdf. +# This may be replaced when dependencies are built. diff --git a/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/compiler_depend.ts b/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/compiler_depend.ts new file mode 100644 index 0000000000..673ff4f9eb --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/compiler_depend.ts @@ -0,0 +1,2 @@ +# CMAKE generated file: DO NOT EDIT! +# Timestamp file for custom commands dependencies management for doc_pdf. diff --git a/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/progress.make b/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/progress.make new file mode 100644 index 0000000000..303dfaf60d --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/doc_pdf.dir/progress.make @@ -0,0 +1,2 @@ +CMAKE_PROGRESS_1 = 39 + diff --git a/static/doc/v1.4.0/CMakeFiles/progress.marks b/static/doc/v1.4.0/CMakeFiles/progress.marks new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/static/doc/v1.4.0/CMakeFiles/progress.marks @@ -0,0 +1 @@ +0 diff --git a/static/doc/v1.4.0/Makefile b/static/doc/v1.4.0/Makefile new file mode 100644 index 0000000000..dd5c173994 --- /dev/null +++ b/static/doc/v1.4.0/Makefile @@ -0,0 +1,234 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.29 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Disable VCS-based implicit rules. +% : %,v + +# Disable VCS-based implicit rules. +% : RCS/% + +# Disable VCS-based implicit rules. +% : RCS/%,v + +# Disable VCS-based implicit rules. +% : SCCS/s.% + +# Disable VCS-based implicit rules. +% : s.% + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/local/bin/cmake + +# The command to remove a file. +RM = /usr/local/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/runner/work/open62541/open62541 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/runner/work/open62541/open62541/build + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Running CMake cache editor..." + /usr/local/bin/ccmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Running CMake to regenerate build system..." + /usr/local/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Available install components are: \"Unspecified\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components +.PHONY : list_install_components/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Install the project..." + /usr/local/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Install the project..." + /usr/local/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing only the local directory..." + /usr/local/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing only the local directory..." + /usr/local/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local/fast + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing the project stripped..." + /usr/local/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing the project stripped..." + /usr/local/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip/fast + +# The main all target +all: cmake_check_build_system + cd /home/runner/work/open62541/open62541/build && $(CMAKE_COMMAND) -E cmake_progress_start /home/runner/work/open62541/open62541/build/CMakeFiles /home/runner/work/open62541/open62541/build/doc//CMakeFiles/progress.marks + cd /home/runner/work/open62541/open62541/build && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 doc/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/runner/work/open62541/open62541/build/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /home/runner/work/open62541/open62541/build && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 doc/clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /home/runner/work/open62541/open62541/build && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 doc/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /home/runner/work/open62541/open62541/build && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 doc/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /home/runner/work/open62541/open62541/build && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Convenience name for target. +doc/CMakeFiles/doc_latex.dir/rule: + cd /home/runner/work/open62541/open62541/build && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 doc/CMakeFiles/doc_latex.dir/rule +.PHONY : doc/CMakeFiles/doc_latex.dir/rule + +# Convenience name for target. +doc_latex: doc/CMakeFiles/doc_latex.dir/rule +.PHONY : doc_latex + +# fast build rule for target. +doc_latex/fast: + cd /home/runner/work/open62541/open62541/build && $(MAKE) $(MAKESILENT) -f doc/CMakeFiles/doc_latex.dir/build.make doc/CMakeFiles/doc_latex.dir/build +.PHONY : doc_latex/fast + +# Convenience name for target. +doc/CMakeFiles/doc_pdf.dir/rule: + cd /home/runner/work/open62541/open62541/build && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 doc/CMakeFiles/doc_pdf.dir/rule +.PHONY : doc/CMakeFiles/doc_pdf.dir/rule + +# Convenience name for target. +doc_pdf: doc/CMakeFiles/doc_pdf.dir/rule +.PHONY : doc_pdf + +# fast build rule for target. +doc_pdf/fast: + cd /home/runner/work/open62541/open62541/build && $(MAKE) $(MAKESILENT) -f doc/CMakeFiles/doc_pdf.dir/build.make doc/CMakeFiles/doc_pdf.dir/build +.PHONY : doc_pdf/fast + +# Convenience name for target. +doc/CMakeFiles/doc.dir/rule: + cd /home/runner/work/open62541/open62541/build && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 doc/CMakeFiles/doc.dir/rule +.PHONY : doc/CMakeFiles/doc.dir/rule + +# Convenience name for target. +doc: doc/CMakeFiles/doc.dir/rule +.PHONY : doc + +# fast build rule for target. +doc/fast: + cd /home/runner/work/open62541/open62541/build && $(MAKE) $(MAKESILENT) -f doc/CMakeFiles/doc.dir/build.make doc/CMakeFiles/doc.dir/build +.PHONY : doc/fast + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... install" + @echo "... install/local" + @echo "... install/strip" + @echo "... list_install_components" + @echo "... rebuild_cache" + @echo "... doc" + @echo "... doc_latex" + @echo "... doc_pdf" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /home/runner/work/open62541/open62541/build && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/static/doc/v1.4.0/_images/graphviz-5639351174b70f03ad8af4be8fda3f706bb801e9.png b/static/doc/v1.4.0/_images/graphviz-5639351174b70f03ad8af4be8fda3f706bb801e9.png new file mode 100644 index 0000000000..0e96af516c Binary files /dev/null and b/static/doc/v1.4.0/_images/graphviz-5639351174b70f03ad8af4be8fda3f706bb801e9.png differ diff --git a/static/doc/v1.4.0/_images/graphviz-5639351174b70f03ad8af4be8fda3f706bb801e9.png.map b/static/doc/v1.4.0/_images/graphviz-5639351174b70f03ad8af4be8fda3f706bb801e9.png.map new file mode 100644 index 0000000000..13f264120b --- /dev/null +++ b/static/doc/v1.4.0/_images/graphviz-5639351174b70f03ad8af4be8fda3f706bb801e9.png.map @@ -0,0 +1,2 @@ + + diff --git a/static/doc/v1.4.0/_images/graphviz-636571c8f167f01b140015909e18c76e3e304889.png b/static/doc/v1.4.0/_images/graphviz-636571c8f167f01b140015909e18c76e3e304889.png new file mode 100644 index 0000000000..aeaab71e72 Binary files /dev/null and b/static/doc/v1.4.0/_images/graphviz-636571c8f167f01b140015909e18c76e3e304889.png differ diff --git a/static/doc/v1.4.0/_images/graphviz-636571c8f167f01b140015909e18c76e3e304889.png.map b/static/doc/v1.4.0/_images/graphviz-636571c8f167f01b140015909e18c76e3e304889.png.map new file mode 100644 index 0000000000..13f264120b --- /dev/null +++ b/static/doc/v1.4.0/_images/graphviz-636571c8f167f01b140015909e18c76e3e304889.png.map @@ -0,0 +1,2 @@ + + diff --git a/static/doc/v1.4.0/_images/graphviz-c39dc775253d56235473b672a09ce76464bb3b4d.png b/static/doc/v1.4.0/_images/graphviz-c39dc775253d56235473b672a09ce76464bb3b4d.png new file mode 100644 index 0000000000..be89cbba36 Binary files /dev/null and b/static/doc/v1.4.0/_images/graphviz-c39dc775253d56235473b672a09ce76464bb3b4d.png differ diff --git a/static/doc/v1.4.0/_images/graphviz-c39dc775253d56235473b672a09ce76464bb3b4d.png.map b/static/doc/v1.4.0/_images/graphviz-c39dc775253d56235473b672a09ce76464bb3b4d.png.map new file mode 100644 index 0000000000..13f264120b --- /dev/null +++ b/static/doc/v1.4.0/_images/graphviz-c39dc775253d56235473b672a09ce76464bb3b4d.png.map @@ -0,0 +1,2 @@ + + diff --git a/static/doc/v1.4.0/_images/nodeset_compiler_pump.png b/static/doc/v1.4.0/_images/nodeset_compiler_pump.png new file mode 100644 index 0000000000..58ccc5cf78 Binary files /dev/null and b/static/doc/v1.4.0/_images/nodeset_compiler_pump.png differ diff --git a/static/doc/v1.4.0/_images/ua-wireshark-pubsub.png b/static/doc/v1.4.0/_images/ua-wireshark-pubsub.png new file mode 100644 index 0000000000..675c80d5ee Binary files /dev/null and b/static/doc/v1.4.0/_images/ua-wireshark-pubsub.png differ diff --git a/static/doc/v1.4.0/_images/ua-wireshark.png b/static/doc/v1.4.0/_images/ua-wireshark.png new file mode 100644 index 0000000000..a2af94f07a Binary files /dev/null and b/static/doc/v1.4.0/_images/ua-wireshark.png differ diff --git a/static/doc/v1.4.0/_sources/building.rst.txt b/static/doc/v1.4.0/_sources/building.rst.txt new file mode 100644 index 0000000000..acbc30aaa7 --- /dev/null +++ b/static/doc/v1.4.0/_sources/building.rst.txt @@ -0,0 +1,489 @@ +.. _building: + +Building open62541 +================== + +Building the Library +-------------------- + +open62541 uses CMake to build the library and binaries. CMake generates a +Makefile or a Visual Studio project. This is then used to perform the actual +build. + +Building with CMake on Ubuntu or Debian +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + sudo apt-get install git build-essential gcc pkg-config cmake python + + # enable additional features + sudo apt-get install cmake-curses-gui # for the ccmake graphical interface + sudo apt-get install libmbedtls-dev # for encryption support + sudo apt-get install check libsubunit-dev # for unit tests + sudo apt-get install python-sphinx graphviz # for documentation generation + sudo apt-get install python-sphinx-rtd-theme # documentation style + + cd open62541 + mkdir build + cd build + cmake .. + make + + # select additional features + ccmake .. + make + + # build documentation + make doc # html documentation + make doc_pdf # pdf documentation (requires LaTeX) + +You can install open62541 using the well known `make install` command. This +allows you to use pre-built libraries and headers for your own project. In order +to use open62541 as a shared library (.dll or .so) make sure to activate the +``BUILD_SHARED_LIBS`` CMake option. + +To override the default installation directory use ``cmake +-DCMAKE_INSTALL_PREFIX=/some/path``. Based on the SDK Features you selected, as +described in :ref:`build_options`, these features will also be included in the +installation. Thus we recommend to enable as many non-experimental features as +possible for the installed binary. + +In your own CMake project you can then include the open62541 library using: + +.. code-block:: cmake + + # optionally you can also specify a specific version + # e.g. find_package(open62541 1.0.0) + find_package(open62541 REQUIRED COMPONENTS Events FullNamespace) + add_executable(main main.cpp) + target_link_libraries(main open62541::open62541) + +A full list of enabled features during build time is stored in the CMake +Variable ``open62541_COMPONENTS_ALL`` + +Building with CMake on Windows +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Here we explain the build process for Visual Studio (2013 or newer). To build +with MinGW, just replace the compiler selection in the call to CMake. + +- Download and install + + - Python 2.7.x (Python 3.x works as well): https://python.org/downloads + - CMake: http://www.cmake.org/cmake/resources/software.html + - Microsoft Visual Studio: https://www.visualstudio.com/products/visual-studio-community-vs + +- Download the open62541 sources (using git or as a zipfile from github) +- Open a command shell (cmd) and run + +.. code-block:: bat + + cd \open62541 + mkdir build + cd build + \cmake.exe .. -G "Visual Studio 14 2015" + :: You can use use cmake-gui for a graphical user-interface to select features + +- Then open :file:`build\open62541.sln` in Visual Studio 2015 and build as usual + +Building on OS X +^^^^^^^^^^^^^^^^ + +- Download and install + + - Xcode: https://itunes.apple.com/us/app/xcode/id497799835?ls=1&mt=12 + - Homebrew: http://brew.sh/ + - Pip (a package manager for Python, may be preinstalled): ``sudo easy_install pip`` + +- Run the following in a shell + +.. code-block:: bash + + brew install cmake + pip install sphinx # for documentation generation + pip install sphinx_rtd_theme # documentation style + brew install graphviz # for graphics in the documentation + brew install check # for unit tests + +Follow Ubuntu instructions without the ``apt-get`` commands as these are taken care of by the above packages. + +Building on OpenBSD +^^^^^^^^^^^^^^^^^^^ + +The procedure below works on OpenBSD 5.8 with gcc version 4.8.4, cmake version +3.2.3 and Python version 2.7.10. + +- Install a recent gcc, python and cmake: + +.. code-block:: bash + + pkg_add gcc python cmake + +- Tell the system to actually use the recent gcc (it gets installed as egcc on OpenBSD): + +.. code-block:: bash + + export CC=egcc CXX=eg++ + +- Now procede as described for Ubuntu/Debian: + +.. code-block:: bash + + cd open62541 + mkdir build + cd build + cmake .. + make + +Building Debian Packages inside Docker Container with CMake on Ubuntu or Debian +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Here is an example howto build the library as Debian package inside a Docker container + +- Download and install + + - Docker Engine: https://docs.docker.com/install/linux/docker-ce/debian/ + - docker-deb-builder: https://github.com/tsaarni/docker-deb-builder.git + - open62541: https://github.com/open62541/open62541.git + +Install Docker as described at https://docs.docker.com/install/linux/docker-ce/debian/ . + +Get the docker-deb-builder utility from github and make Docker images for the needed +Debian and/or Ubuntu relases + +.. code-block:: bash + + # make and goto local development path (e.g. ~/development) + mkdir ~/development + cd ~/development + + # clone docker-deb-builder utility from github and change into builder directory + git clone https://github.com/tsaarni/docker-deb-builder.git + cd docker-deb-builder + + # make Docker builder images (e.g. Ubuntu 18.04 and 17.04) + docker build -t docker-deb-builder:18.04 -f Dockerfile-ubuntu-18.04 . + docker build -t docker-deb-builder:17.04 -f Dockerfile-ubuntu-17.04 . + +Make a local copy of the open62541 git repo and checkout a pack branch + +.. code-block:: bash + + # make a local copy of the open62541 git repo (e.g. in the home directory) + # and checkout a pack branch (e.g. pack/1.0) + cd ~ + git clone https://github.com/open62541/open62541.git + cd ~/open62541 + git checkout pack/1.0 + +Now it's all set to build Debian/Ubuntu open62541 packages + +.. code-block:: bash + + # goto local developmet path + cd ~/development + + # make a local output directory for the builder where the packages can be placed after build + mkdir output + + # build Debian/Ubuntu packages inside Docker container (e.g. Ubuntu-18.04) + ./build -i docker-deb-builder:18.04 -o output ~/open62541 + +After a successfull build the Debian/Ubuntu packages can be found at :file:`~/development/docker-deb-builder/output` + +CMake Build Options and Debian Packaging +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If the open62541 library will be build as a Debian package using a pack branch (e.g. pack/master or pack/1.0) +then altering or adding CMake build options should be done inside the :file:`debian/rules` file respectively in +the :file:`debian/rules-template` file if working with a development branch (e.g. master or 1.0). + +The section in :file:`debian/rules` where the CMake build options are defined is + +.. code-block:: bash + + ... + override_dh_auto_configure: + dh_auto_configure -- -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUA_NAMESPACE_ZERO=FULL -DUA_ENABLE_AMALGAMATION=OFF -DUA_PACK_DEBIAN=ON + ... + +This CMake build options will be passed as command line variables to CMake during Debian packaging. + +.. _build_options: + +Build Options +------------- + +The open62541 project uses CMake to manage the build options, for code +generation and to generate build projects for the different systems and IDEs. +The tools *ccmake* or *cmake-gui* can be used to graphically set the build +options. + +Most options can be changed manually in :file:`ua_config.h` (:file:`open62541.h` +for the single-file release) after the code generation. But usually there is no +need to adjust them. + +Main Build Options +^^^^^^^^^^^^^^^^^^ + +**CMAKE_BUILD_TYPE** + - ``RelWithDebInfo`` -O2 optimization with debug symbols + - ``Release`` -O2 optimization without debug symbols + - ``Debug`` -O0 optimization with debug symbols + - ``MinSizeRel`` -Os optimization without debug symbols + +**UA_LOGLEVEL** + The SDK logs events of the level defined in ``UA_LOGLEVEL`` and above only. + The logging event levels are as follows: + + - 600: Fatal + - 500: Error + - 400: Warning + - 300: Info + - 200: Debug + - 100: Trace + + This compilation flag defines which log levels get compiled into the code. In + addition, the implementations of :ref:`logging` allow to set a filter for the + logging level at runtime. So the logging level can be changed in the + configuration without recompiling. + +**UA_MULTITHREADING** + Level of multi-threading support. The supported levels are currently as follows: + + - 0-99: Multithreading support disabled. + - >=100: API functions marked with the UA_THREADSAFE-macro are protected internally with mutexes. + Multiple threads are allowed to call these functions of the SDK at the same time without causing race conditions. + Furthermore, this level support the handling of asynchronous method calls from external worker threads. + +Select build artefacts +^^^^^^^^^^^^^^^^^^^^^^ + +By default only the main library shared object libopen62541.so (open62541.dll) +or static linking archive open62541.a (open62541.lib) is built. Additional +artifacts can be specified by the following options: + +**UA_BUILD_EXAMPLES** + Compile example servers and clients from :file:`examples/*.c`. + +**UA_BUILD_UNIT_TESTS** + Compile unit tests. The tests can be executed with ``make test``. + An individual test can be executed with ``make test ARGS="-R -V"``. + The list of available tests can be displayed with ``make test ARGS="-N"``. + +**UA_BUILD_SELFSIGNED_CERTIFICATE** + Generate a self-signed certificate for the server (openSSL required) + +Detailed SDK Features +^^^^^^^^^^^^^^^^^^^^^ + +**UA_ENABLE_SUBSCRIPTIONS** + Enable subscriptions + +**UA_ENABLE_SUBSCRIPTIONS_EVENTS (EXPERIMENTAL)** + Enable the use of events for subscriptions. This is a new feature and currently marked as EXPERIMENTAL. + +**UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS (EXPERIMENTAL)** + Enable the use of A&C for subscriptions. This is a new feature build upon events and currently marked as EXPERIMENTAL. + +**UA_ENABLE_METHODCALLS** + Enable the Method service set + +**UA_ENABLE_PARSING** + Enable parsing human readable formats of builtin data types (Guid, NodeId, etc.). + Utility functions that are not essential to the SDK. + +**UA_ENABLE_NODEMANAGEMENT** + Enable dynamic addition and removal of nodes at runtime + +**UA_ENABLE_AMALGAMATION** + Compile a single-file release into the files :file:`open62541.c` and :file:`open62541.h`. Not recommended for installation. + +**UA_ENABLE_IMMUTABLE_NODES** + Nodes in the information model are not edited but copied and replaced. The + replacement is done with atomic operations so that the information model is + always consistent and can be accessed from an interrupt or parallel thread + (depends on the node storage plugin implementation). + +**UA_ENABLE_COVERAGE** + Measure the coverage of unit tests +**UA_ENABLE_DISCOVERY** + Enable Discovery Service (LDS) +**UA_ENABLE_DISCOVERY_MULTICAST** + Enable Discovery Service with multicast support (LDS-ME) +**UA_ENABLE_DISCOVERY_SEMAPHORE** + Enable Discovery Semaphore support +**UA_ENABLE_ENCRYPTION** + Enable encryption support and specify the used encryption backend. The possible + options are: + - ``OFF`` No encryption support. (default) + - ``MBEDTLS`` Encryption support using mbed TLS + - ``OPENSSL`` Encryption support using OpenSSL + - ``LIBRESSL`` EXPERIMENTAL: Encryption support using LibreSSL +**UA_ENABLE_ENCRYPTION_TPM2** + Enable TPM hardware for encryption. The possible options are: + - ``OFF`` No TPM encryption support. (default) + - ``ON`` TPM encryption support + +**UA_NAMESPACE_ZERO** + + Namespace zero contains the standard-defined nodes. The full namespace zero + may not be required for all applications. The selectable options are as follows: + + - ``MINIMAL``: A barebones namespace zero that is compatible with most + clients. But this namespace 0 is so small that it does not pass the CTT + (Conformance Testing Tools of the OPC Foundation). + - ``REDUCED``: Small namespace zero that passes the CTT. + - ``FULL``: Full namespace zero generated from the official XML definitions. + + The advanced build option ``UA_FILE_NS0`` can be used to override the XML + file used for namespace zero generation. + +Some options are marked as advanced. The advanced options need to be toggled to +be visible in the cmake GUIs. + +**UA_ENABLE_TYPEDESCRIPTION** + Add the type and member names to the UA_DataType structure. Enabled by default. + +**UA_ENABLE_STATUSCODE_DESCRIPTIONS** + Compile the human-readable name of the StatusCodes into the binary. Enabled by default. +**UA_ENABLE_FULL_NS0** + Use the full NS0 instead of a minimal Namespace 0 nodeset + ``UA_FILE_NS0`` is used to specify the file for NS0 generation from namespace0 folder. Default value is ``Opc.Ua.NodeSet2.xml`` + +PubSub Build Options +^^^^^^^^^^^^^^^^^^^^ + +**UA_ENABLE_PUBSUB** + Enable the experimental OPC UA PubSub support. The option will include the + PubSub UDP multicast plugin. Disabled by default. + +**UA_ENABLE_PUBSUB_DELTAFRAMES** + The PubSub messages differentiate between keyframe (all published values + contained) and deltaframe (only changed values contained) messages. + Deltaframe messages creation consumes some additional resources and can be + disabled with this flag. Disabled by default. + +**UA_ENABLE_PUBSUB_FILE_CONFIG** + Enable loading OPC UA PubSub configuration from File/ByteString. Enabling + PubSub informationmodel methods also will add a method to the + Publish/Subscribe object which allows configuring PubSub at runtime. + +**UA_ENABLE_PUBSUB_INFORMATIONMODEL** + Enable the information model representation of the PubSub configuration. For + more details take a look at the following section `PubSub Information Model + Representation`. Disabled by default. + +**UA_ENABLE_PUBSUB_MONITORING** + Enable the experimental PubSub monitoring. This feature provides a basic + framework to implement monitoring/timeout checks for PubSub components. + Initially the MessageReceiveTimeout check of a DataSetReader is provided. It + uses the internal server callback implementation. The monitoring backend can + be changed by the application to satisfy realtime requirements. Disabled by + default. + +Debug Build Options +^^^^^^^^^^^^^^^^^^^ + +This group contains build options mainly useful for development of the library itself. + +**UA_DEBUG** + Enable assertions and additional definitions not intended for production builds + +**UA_DEBUG_DUMP_PKGS** + Dump every package received by the server as hexdump format + +Building a shared library +^^^^^^^^^^^^^^^^^^^^^^^^^ + +open62541 is small enough that most users will want to statically link the +library into their programs. If a shared library (.dll, .so) is required, this +can be enabled in CMake with the ``BUILD_SHARED_LIBS`` option. Note that this +option modifies the :file:`ua_config.h` file that is also included in +:file:`open62541.h` for the single-file distribution. + + +Minimizing the binary size +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The size of the generated binary can be reduced considerably by adjusting the +build configuration. With open62541, it is possible to configure minimal servers +that require less than 100kB of RAM and ROM. + +The following options influence the ROM requirements: + +First, in CMake, the build type can be set to ``CMAKE_BUILD_TYPE=MinSizeRel``. +This sets the compiler flags to minimize the binary size. The build type also +strips out debug information. Second, the binary size can be reduced by removing +features via the build-flags described above. + +Second, setting ``UA_NAMESPACE_ZERO`` to ``MINIMAL`` reduces the size of the +builtin information model. Setting this option can reduce the binary size by +half in some cases. + +Third, some features might not be needed and can be disabled to reduce the +binary footprint. Examples for this are Subscriptions or encrypted +communication. + +Last, logging messages take up a lot of space in the binary and might not be +needed in embedded scenarios. Setting ``UA_LOGLEVEL`` to a value above 600 +(``FATAL``) disables all logging. In addition, the feature-flags +``UA_ENABLE_TYPEDESCRIPTION`` and ``UA_ENABLE_STATUSCODE_DESCRIPTIONS`` add static +information to the binary that is only used for human-readable logging and +debugging. + +The RAM requirements of a server are mostly due to the following settings: + +- The size of the information model +- The number of connected clients +- The configured maximum message size that is preallocated + +Prebuilt packages +----------------- + +Debian +^^^^^^ +Debian packages can be found in our official PPA: + + * Daily Builds (based on master branch): https://launchpad.net/~open62541-team/+archive/ubuntu/daily + * Release Builds (starting with Version 0.4): https://launchpad.net/~open62541-team/+archive/ubuntu/ppa + +Install them with: + +.. code-block:: bash + + sudo add-apt-repository ppa:open62541-team/ppa + sudo apt-get update + sudo apt-get install libopen62541-1-dev + +Arch +^^^^ +Arch packages are available in the AUR: + + * Stable Builds: https://aur.archlinux.org/packages/open62541/ + * Unstable Builds (current master): https://aur.archlinux.org/packages/open62541-git/ + * In order to add custom build options (:ref:`build_options`), you can set the environment variable ``OPEN62541_CMAKE_FLAGS`` + +OpenBSD +^^^^^^^ +Starting with OpenBSD 6.7 the ports directory misc/open62541 can +build the released version of open62541. +Install the binary package from the OpenBSD mirrors: + +.. code-block:: bash + + pkg_add open62541 + +Building the Examples +--------------------- + +Make sure that you have installed the shared library as explained in the +previous steps. Then the build system should automatically find the includes and +the shared library. + +.. code-block:: bash + + cp /path-to/examples/tutorial_server_firststeps.c . # copy the example server + gcc -std=c99 -o server tutorial_server_firststeps.c -lopen62541 + diff --git a/static/doc/v1.4.0/_sources/client.rst.txt b/static/doc/v1.4.0/_sources/client.rst.txt new file mode 100644 index 0000000000..e955bf9e4c --- /dev/null +++ b/static/doc/v1.4.0/_sources/client.rst.txt @@ -0,0 +1,954 @@ +.. _client: + +Client +====== + +The client implementation allows remote access to all OPC UA services. For +convenience, some functionality has been wrapped in :ref:`high-level +abstractions `. + +**However**: At this time, the client does not yet contain its own thread or +event-driven main-loop, meaning that the client will not perform any actions +automatically in the background. This is especially relevant for +connection/session management and subscriptions. The user will have to +periodically call `UA_Client_run_iterate` to ensure that asynchronous events +are handled, including keeping a secure connection established. +See more about :ref:`asynchronicity` and +:ref:`subscriptions`. + +.. _client-config: + +Client Configuration +-------------------- + +The client configuration is used for setting connection parameters and +additional settings used by the client. +The configuration should not be modified after it is passed to a client. +Currently, only one client can use a configuration at a time. + +Examples for configurations are provided in the ``/plugins`` folder. +The usual usage is as follows: + +1. Create a client configuration with default settings as a starting point +2. Modifiy the configuration, e.g. modifying the timeout +3. Instantiate a client with it +4. After shutdown of the client, clean up the configuration (free memory) + +The :ref:`tutorials` provide a good starting point for this. + +.. code-block:: c + + + struct UA_ClientConfig { + void *clientContext; /* User-defined pointer attached to the client */ + UA_Logger *logging; /* Plugin for log output */ + + /* Response timeout in ms (0 -> no timeout). If the server does not answer a + * request within this time a StatusCode UA_STATUSCODE_BADTIMEOUT is + * returned. This timeout can be overridden for individual requests by + * setting a non-null "timeoutHint" in the request header. */ + UA_UInt32 timeout; + + /* The description must be internally consistent. + * - The ApplicationUri set in the ApplicationDescription must match the + * URI set in the certificate */ + UA_ApplicationDescription clientDescription; + + /* The endpoint for the client to connect to. + * Such as "opc.tcp://host:port". */ + UA_String endpointUrl; + +Connection configuration +~~~~~~~~~~~~~~~~~~~~~~~~ + +The following configuration elements reduce the "degrees of freedom" the +client has when connecting to a server. If no connection can be made +under these restrictions, then the connection will abort with an error +message. + +.. code-block:: c + + UA_ExtensionObject userIdentityToken; /* Configured User-Identity Token */ + UA_MessageSecurityMode securityMode; /* None, Sign, SignAndEncrypt. The + * default is invalid. This indicates + * the client to select any matching + * endpoint. */ + UA_String securityPolicyUri; /* SecurityPolicy for the SecureChannel. An + * empty string indicates the client to select + * any matching SecurityPolicy. */ + + UA_Boolean noSession; /* Only open a SecureChannel, but no Session */ + UA_Boolean noReconnect; /* Don't reconnect SecureChannel when the connection + * is lost without explicitly closing. */ + UA_Boolean noNewSession; /* Don't automatically create a new Session when + * the intial one is lost. Instead abort the + * connection when the Session is lost. */ + +If either endpoint or userTokenPolicy has been set (at least one non-zero +byte in either structure), then the selected Endpoint and UserTokenPolicy +overwrite the settings in the basic connection configuration. The +userTokenPolicy array in the EndpointDescription is ignored. The selected +userTokenPolicy is set in the dedicated configuration field. + +If the advanced configuration is not set, the client will write to it the +selected Endpoint and UserTokenPolicy during GetEndpoints. + +The information in the advanced configuration is used during reconnect +when the SecureChannel was broken. + +.. code-block:: c + + UA_EndpointDescription endpoint; + UA_UserTokenPolicy userTokenPolicy; + +If the EndpointDescription has not been defined, the ApplicationURI +constrains the servers considered in the FindServers service and the +Endpoints considered in the GetEndpoints service. + +If empty the applicationURI is not used to filter. + +.. code-block:: c + + UA_String applicationUri; + +Custom Data Types +~~~~~~~~~~~~~~~~~ +The following is a linked list of arrays with custom data types. All data +types that are accessible from here are automatically considered for the +decoding of received messages. Custom data types are not cleaned up +together with the configuration. So it is possible to allocate them on +ROM. + +See the section on :ref:`generic-types`. Examples for working with custom +data types are provided in ``/examples/custom_datatype/``. + +.. code-block:: c + + const UA_DataTypeArray *customDataTypes; + +Advanced Client Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: c + + + UA_UInt32 secureChannelLifeTime; /* Lifetime in ms (then the channel needs + to be renewed) */ + UA_UInt32 requestedSessionTimeout; /* Session timeout in ms */ + UA_ConnectionConfig localConnectionConfig; + UA_UInt32 connectivityCheckInterval; /* Connectivity check interval in ms. + * 0 = background task disabled */ + + /* EventLoop */ + UA_EventLoop *eventLoop; + UA_Boolean externalEventLoop; /* The EventLoop is not deleted with the config */ + + /* Available SecurityPolicies */ + size_t securityPoliciesSize; + UA_SecurityPolicy *securityPolicies; + + /* Certificate Verification Plugin */ + UA_CertificateVerification certificateVerification; + + /* Available SecurityPolicies for Authentication. The policy defined by the + * AccessControl is selected. If no policy is defined, the policy of the + * secure channel is selected.*/ + size_t authSecurityPoliciesSize; + UA_SecurityPolicy *authSecurityPolicies; + /* SecurityPolicyUri for the Authentication. */ + UA_String authSecurityPolicyUri; + + /* Callback for state changes. The client state is differentated into the + * SecureChannel state and the Session state. The connectStatus is set if + * the client connection (including reconnects) has failed and the client + * has to "give up". If the connectStatus is not set, the client still has + * hope to connect or recover. */ + void (*stateCallback)(UA_Client *client, + UA_SecureChannelState channelState, + UA_SessionState sessionState, + UA_StatusCode connectStatus); + + /* When connectivityCheckInterval is greater than 0, every + * connectivityCheckInterval (in ms), an async read request is performed on + * the server. inactivityCallback is called when the client receive no + * response for this read request The connection can be closed, this in an + * attempt to recreate a healthy connection. */ + void (*inactivityCallback)(UA_Client *client); + + /* Number of PublishResponse queued up in the server */ + UA_UInt16 outStandingPublishRequests; + + /* If the client does not receive a PublishResponse after the defined delay + * of ``(sub->publishingInterval * sub->maxKeepAliveCount) + + * client->config.timeout)``, then subscriptionInactivityCallback is called + * for the subscription.. */ + void (*subscriptionInactivityCallback)(UA_Client *client, + UA_UInt32 subscriptionId, + void *subContext); + + /* Session config */ + UA_String sessionName; + UA_LocaleId *sessionLocaleIds; + size_t sessionLocaleIdsSize; + + #ifdef UA_ENABLE_ENCRYPTION + /* If the private key is in PEM format and password protected, this callback + * is called during initialization to get the password to decrypt the + * private key. The memory containing the password is freed by the client + * after use. The callback should be set early, other parts of the client + * config setup may depend on it. */ + UA_StatusCode (*privateKeyPasswordCallback)(UA_ClientConfig *cc, + UA_ByteString *password); + #endif + }; + +@brief It makes a partial deep copy of the clientconfig. It makes a shallow +copies of the plugins (logger, eventloop, securitypolicy). + +NOTE: It makes a shallow copy of all the plugins from source to destination. +Therefore calling _clear on the dst object will also delete the plugins in src +object. + +.. code-block:: c + + UA_StatusCode + UA_ClientConfig_copy(UA_ClientConfig const *src, UA_ClientConfig *dst); + +@brief It cleans the client config and frees the pointer. + +.. code-block:: c + + void + UA_ClientConfig_delete(UA_ClientConfig *config); + +@brief It cleans the client config and deletes the plugins, whereas +_copy makes a shallow copy of the plugins. + +.. code-block:: c + + void + UA_ClientConfig_clear(UA_ClientConfig *config); + + /* Configure Username/Password for the Session authentication. Also see + * UA_ClientConfig_setAuthenticationCert for x509-based authentication, which is + * implemented as a plugin (as it can be based on different crypto + * libraries). */ + static UA_INLINE UA_StatusCode + UA_ClientConfig_setAuthenticationUsername(UA_ClientConfig *config, + const char *username, + const char *password) { + UA_UserNameIdentityToken* identityToken = UA_UserNameIdentityToken_new(); + if(!identityToken) + return UA_STATUSCODE_BADOUTOFMEMORY; + identityToken->userName = UA_STRING_ALLOC(username); + identityToken->password = UA_STRING_ALLOC(password); + + UA_ExtensionObject_clear(&config->userIdentityToken); + UA_ExtensionObject_setValue(&config->userIdentityToken, identityToken, + &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]); + return UA_STATUSCODE_GOOD; + } + +Client Lifecycle +---------------- + +.. code-block:: c + + + /* Create a new client with a default configuration that adds plugins for + * networking, security, logging and so on. See `client_config_default.h` for + * more detailed options. + * + * The default configuration can be used as the starting point to adjust the + * client configuration to individual needs. UA_Client_new is implemented in the + * /plugins folder under the CC0 license. Furthermore the client confiugration + * only uses the public server API. + * + * @return Returns the configured client or NULL if an error occurs. */ + UA_Client * UA_Client_new(void); + + /* Creates a new client. Moves the config into the client with a shallow copy. + * The config content is cleared together with the client. */ + UA_Client * + UA_Client_newWithConfig(const UA_ClientConfig *config); + + /* Returns the current state. All arguments except ``client`` can be NULL. */ + void UA_THREADSAFE + UA_Client_getState(UA_Client *client, + UA_SecureChannelState *channelState, + UA_SessionState *sessionState, + UA_StatusCode *connectStatus); + + /* Get the client configuration */ + UA_ClientConfig * + UA_Client_getConfig(UA_Client *client); + + /* Get the client context */ + static UA_INLINE void * + UA_Client_getContext(UA_Client *client) { + return UA_Client_getConfig(client)->clientContext; /* Cannot fail */ + } + + /* (Disconnect and) delete the client */ + void + UA_Client_delete(UA_Client *client); + +Connection Attrbiutes +--------------------- + +Besides the client configuration, some attributes of the connection are +defined only at runtime. For example the choice of SecurityPolicy or the +ApplicationDescripton from the server. This API allows to access such +connection attributes. + +The currently defined connection attributes are: + +- 0:serverDescription [UA_ApplicationDescription]: Server description +- 0:securityPolicyUri [UA_String]: Uri of the SecurityPolicy used +- 0:securityMode [UA_MessageSecurityMode]: SecurityMode of the SecureChannel + +.. code-block:: c + + + /* Returns a shallow copy of the attribute. Don't _clear or _delete the value + * variant. Don't use the value after returning the control flow to the client. + * Also don't use this in a multi-threaded application. */ + UA_StatusCode + UA_Client_getConnectionAttribute(UA_Client *client, const UA_QualifiedName key, + UA_Variant *outValue); + + /* Return a deep copy of the attribute */ + UA_StatusCode UA_THREADSAFE + UA_Client_getConnectionAttributeCopy(UA_Client *client, const UA_QualifiedName key, + UA_Variant *outValue); + + /* Returns NULL if the attribute is not defined or not a scalar or not of the + * right datatype. Otherwise a shallow copy of the scalar value is created at + * the target location of the void pointer. Hence don't use this in a + * multi-threaded application. */ + UA_StatusCode + UA_Client_getConnectionAttribute_scalar(UA_Client *client, + const UA_QualifiedName key, + const UA_DataType *type, + void *outValue); + +Connect to a Server +------------------- + +Once a client is connected to an endpointUrl, it is not possible to switch to +another server. A new client has to be created for that. + +Once a connection is established, the client keeps the connection open and +reconnects if necessary. + +If the connection fails unrecoverably (state->connectStatus is set to an +error), the client is no longer usable. Create a new client if required. + +.. code-block:: c + + + /* Connect with the client configuration. For the async connection, finish + * connecting via UA_Client_run_iterate (or manually running a configured + * external EventLoop). */ + UA_StatusCode UA_THREADSAFE + __UA_Client_connect(UA_Client *client, UA_Boolean async); + + /* Connect to the server. First a SecureChannel is opened, then a Session. The + * client configuration restricts the SecureChannel selection and contains the + * UserIdentityToken for the Session. + * + * @param client to use + * @param endpointURL to connect (for example "opc.tcp://localhost:4840") + * @return Indicates whether the operation succeeded or returns an error code */ + static UA_INLINE UA_StatusCode + UA_Client_connect(UA_Client *client, const char *endpointUrl) { + /* Update the configuration */ + UA_ClientConfig *cc = UA_Client_getConfig(client); + cc->noSession = false; /* Open a Session */ + UA_String_clear(&cc->endpointUrl); + cc->endpointUrl = UA_STRING_ALLOC(endpointUrl); + + /* Connect */ + return __UA_Client_connect(client, false); + } + + /* Connect async (non-blocking) to the server. After initiating the connection, + * call UA_Client_run_iterate repeatedly until the connection is fully + * established. You can set a callback to client->config.stateCallback to be + * notified when the connection status changes. Or use UA_Client_getState to get + * the state manually. */ + static UA_INLINE UA_StatusCode + UA_Client_connectAsync(UA_Client *client, const char *endpointUrl) { + /* Update the configuration */ + UA_ClientConfig *cc = UA_Client_getConfig(client); + cc->noSession = false; /* Open a Session */ + UA_String_clear(&cc->endpointUrl); + cc->endpointUrl = UA_STRING_ALLOC(endpointUrl); + + /* Connect */ + return __UA_Client_connect(client, true); + } + + /* Connect to the server without creating a session + * + * @param client to use + * @param endpointURL to connect (for example "opc.tcp://localhost:4840") + * @return Indicates whether the operation succeeded or returns an error code */ + static UA_INLINE UA_StatusCode + UA_Client_connectSecureChannel(UA_Client *client, const char *endpointUrl) { + /* Update the configuration */ + UA_ClientConfig *cc = UA_Client_getConfig(client); + cc->noSession = true; /* Don't open a Session */ + UA_String_clear(&cc->endpointUrl); + cc->endpointUrl = UA_STRING_ALLOC(endpointUrl); + + /* Connect */ + return __UA_Client_connect(client, false); + } + + /* Connect async (non-blocking) only the SecureChannel */ + static UA_INLINE UA_StatusCode + UA_Client_connectSecureChannelAsync(UA_Client *client, const char *endpointUrl) { + /* Update the configuration */ + UA_ClientConfig *cc = UA_Client_getConfig(client); + cc->noSession = true; /* Don't open a Session */ + UA_String_clear(&cc->endpointUrl); + cc->endpointUrl = UA_STRING_ALLOC(endpointUrl); + + /* Connect */ + return __UA_Client_connect(client, false); + } + + /* Connect to the server and create+activate a Session with the given username + * and password. This first set the UserIdentityToken in the client config and + * then calls the regular connect method. */ + static UA_INLINE UA_StatusCode + UA_Client_connectUsername(UA_Client *client, const char *endpointUrl, + const char *username, const char *password) { + /* Set the user identity token */ + UA_ClientConfig *cc = UA_Client_getConfig(client); + UA_StatusCode res = + UA_ClientConfig_setAuthenticationUsername(cc, username, password); + if(res != UA_STATUSCODE_GOOD) + return res; + + /* Connect */ + return UA_Client_connect(client, endpointUrl); + } + + /* Sets up a listening socket for incoming reverse connect requests by OPC UA + * servers. After the first server has connected, the listening socket is + * removed. The client state callback is also used for reverse connect. An + * implementation could for example issue a new call to + * UA_Client_startListeningForReverseConnect after the server has closed the + * connection. If the client is connected to any server while + * UA_Client_startListeningForReverseConnect is called, the connection will be + * closed. + * + * The reverse connect is closed by calling the standard disconnect functions + * like for a "normal" connection that was initiated by the client. Calling one + * of the connect methods will also close the listening socket and the + * connection to the remote server. */ + UA_StatusCode + UA_Client_startListeningForReverseConnect( + UA_Client *client, const UA_String *listenHostnames, + size_t listenHostnamesLength, UA_UInt16 port); + + /* Disconnect and close a connection to the selected server. Disconnection is + * always performed async (without blocking). */ + UA_StatusCode UA_THREADSAFE + UA_Client_disconnect(UA_Client *client); + + /* Disconnect async. Run UA_Client_run_iterate until the callback notifies that + * all connections are closed. */ + UA_StatusCode UA_THREADSAFE + UA_Client_disconnectAsync(UA_Client *client); + + /* Disconnect the SecureChannel but keep the Session intact (if it exists). */ + UA_StatusCode UA_THREADSAFE + UA_Client_disconnectSecureChannel(UA_Client *client); + + /* Disconnect the SecureChannel but keep the Session intact (if it exists). This + * is an async operation. Iterate the client until the SecureChannel was fully + * cleaned up. */ + UA_StatusCode UA_THREADSAFE + UA_Client_disconnectSecureChannelAsync(UA_Client *client); + + /* Get the AuthenticationToken and ServerNonce required to activate the current + * Session on a different SecureChannel. */ + UA_StatusCode UA_THREADSAFE + UA_Client_getSessionAuthenticationToken( + UA_Client *client, UA_NodeId *authenticationToken, UA_ByteString *serverNonce); + + /* Re-activate the current session. A change of prefered locales can be done by + * updating the client configuration. */ + UA_StatusCode UA_THREADSAFE + UA_Client_activateCurrentSession(UA_Client *client); + + /* Async version of UA_Client_activateCurrentSession */ + UA_StatusCode UA_THREADSAFE + UA_Client_activateCurrentSessionAsync(UA_Client *client); + + /* Activate an already created Session. This allows a Session to be transferred + * from a different client instance. The AuthenticationToken and ServerNonce + * must be provided for this. Both can be retrieved for an activated Session + * with UA_Client_getSessionAuthenticationToken. + * + * The UserIdentityToken used for authentication must be identical to the + * original activation of the Session. The UserIdentityToken is set in the + * client configuration. + * + * Note the noNewSession option if there should not be a new Session + * automatically created when this one closes. */ + UA_StatusCode UA_THREADSAFE + UA_Client_activateSession(UA_Client *client, + const UA_NodeId authenticationToken, + const UA_ByteString serverNonce); + + /* Async version of UA_Client_activateSession */ + UA_StatusCode UA_THREADSAFE + UA_Client_activateSessionAsync(UA_Client *client, + const UA_NodeId authenticationToken, + const UA_ByteString serverNonce); + +Discovery +--------- + +.. code-block:: c + + + /* Gets a list of endpoints of a server + * + * @param client to use. Must be connected to the same endpoint given in + * serverUrl or otherwise in disconnected state. + * @param serverUrl url to connect (for example "opc.tcp://localhost:4840") + * @param endpointDescriptionsSize size of the array of endpoint descriptions + * @param endpointDescriptions array of endpoint descriptions that is allocated + * by the function (you need to free manually) + * @return Indicates whether the operation succeeded or returns an error code */ + UA_StatusCode UA_THREADSAFE + UA_Client_getEndpoints(UA_Client *client, const char *serverUrl, + size_t* endpointDescriptionsSize, + UA_EndpointDescription** endpointDescriptions); + + /* Gets a list of all registered servers at the given server. + * + * You can pass an optional filter for serverUris. If the given server is not + * registered, an empty array will be returned. If the server is registered, + * only that application description will be returned. + * + * Additionally you can optionally indicate which locale you want for the server + * name in the returned application description. The array indicates the order + * of preference. A server may have localized names. + * + * @param client to use. Must be connected to the same endpoint given in + * serverUrl or otherwise in disconnected state. + * @param serverUrl url to connect (for example "opc.tcp://localhost:4840") + * @param serverUrisSize Optional filter for specific server uris + * @param serverUris Optional filter for specific server uris + * @param localeIdsSize Optional indication which locale you prefer + * @param localeIds Optional indication which locale you prefer + * @param registeredServersSize size of returned array, i.e., number of + * found/registered servers + * @param registeredServers array containing found/registered servers + * @return Indicates whether the operation succeeded or returns an error code */ + UA_StatusCode UA_THREADSAFE + UA_Client_findServers(UA_Client *client, const char *serverUrl, + size_t serverUrisSize, UA_String *serverUris, + size_t localeIdsSize, UA_String *localeIds, + size_t *registeredServersSize, + UA_ApplicationDescription **registeredServers); + + /* Get a list of all known server in the network. Only supported by LDS servers. + * + * @param client to use. Must be connected to the same endpoint given in + * serverUrl or otherwise in disconnected state. + * @param serverUrl url to connect (for example "opc.tcp://localhost:4840") + * @param startingRecordId optional. Only return the records with an ID higher + * or equal the given. Can be used for pagination to only get a subset of + * the full list + * @param maxRecordsToReturn optional. Only return this number of records + + * @param serverCapabilityFilterSize optional. Filter the returned list to only + * get servers with given capabilities, e.g. "LDS" + * @param serverCapabilityFilter optional. Filter the returned list to only get + * servers with given capabilities, e.g. "LDS" + * @param serverOnNetworkSize size of returned array, i.e., number of + * known/registered servers + * @param serverOnNetwork array containing known/registered servers + * @return Indicates whether the operation succeeded or returns an error code */ + UA_StatusCode UA_THREADSAFE + UA_Client_findServersOnNetwork(UA_Client *client, const char *serverUrl, + UA_UInt32 startingRecordId, + UA_UInt32 maxRecordsToReturn, + size_t serverCapabilityFilterSize, + UA_String *serverCapabilityFilter, + size_t *serverOnNetworkSize, + UA_ServerOnNetwork **serverOnNetwork); + +.. _client-services: + +Services +-------- + +The raw OPC UA services are exposed to the client. But most of the time, it +is better to use the convenience functions from ``ua_client_highlevel.h`` +that wrap the raw services. + +.. code-block:: c + + /* Don't use this function. Use the type versions below instead. */ + void UA_THREADSAFE + __UA_Client_Service(UA_Client *client, const void *request, + const UA_DataType *requestType, void *response, + const UA_DataType *responseType); + + /* + * Attribute Service Set + * ^^^^^^^^^^^^^^^^^^^^^ */ + static UA_INLINE UA_THREADSAFE UA_ReadResponse + UA_Client_Service_read(UA_Client *client, const UA_ReadRequest request) { + UA_ReadResponse response; + __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_READREQUEST], + &response, &UA_TYPES[UA_TYPES_READRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_WriteResponse + UA_Client_Service_write(UA_Client *client, const UA_WriteRequest request) { + UA_WriteResponse response; + __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_WRITEREQUEST], + &response, &UA_TYPES[UA_TYPES_WRITERESPONSE]); + return response; + } + + /* + * Historical Access Service Set + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ + static UA_INLINE UA_THREADSAFE UA_HistoryReadResponse + UA_Client_Service_historyRead(UA_Client *client, + const UA_HistoryReadRequest request) { + UA_HistoryReadResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_HISTORYREADREQUEST], + &response, &UA_TYPES[UA_TYPES_HISTORYREADRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_HistoryUpdateResponse + UA_Client_Service_historyUpdate(UA_Client *client, + const UA_HistoryUpdateRequest request) { + UA_HistoryUpdateResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_HISTORYUPDATEREQUEST], + &response, &UA_TYPES[UA_TYPES_HISTORYUPDATERESPONSE]); + return response; + } + + /* + * Method Service Set + * ^^^^^^^^^^^^^^^^^^ */ + static UA_INLINE UA_THREADSAFE UA_CallResponse + UA_Client_Service_call(UA_Client *client, + const UA_CallRequest request) { + UA_CallResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_CALLREQUEST], + &response, &UA_TYPES[UA_TYPES_CALLRESPONSE]); + return response; + } + + /* + * NodeManagement Service Set + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ */ + static UA_INLINE UA_THREADSAFE UA_AddNodesResponse + UA_Client_Service_addNodes(UA_Client *client, + const UA_AddNodesRequest request) { + UA_AddNodesResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_ADDNODESREQUEST], + &response, &UA_TYPES[UA_TYPES_ADDNODESRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_AddReferencesResponse + UA_Client_Service_addReferences(UA_Client *client, + const UA_AddReferencesRequest request) { + UA_AddReferencesResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_ADDREFERENCESREQUEST], + &response, &UA_TYPES[UA_TYPES_ADDREFERENCESRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_DeleteNodesResponse + UA_Client_Service_deleteNodes(UA_Client *client, + const UA_DeleteNodesRequest request) { + UA_DeleteNodesResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_DELETENODESREQUEST], + &response, &UA_TYPES[UA_TYPES_DELETENODESRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_DeleteReferencesResponse + UA_Client_Service_deleteReferences( + UA_Client *client, const UA_DeleteReferencesRequest request) { + UA_DeleteReferencesResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_DELETEREFERENCESREQUEST], + &response, &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE]); + return response; + } + + /* + * View Service Set + * ^^^^^^^^^^^^^^^^ */ + static UA_INLINE UA_THREADSAFE UA_BrowseResponse + UA_Client_Service_browse(UA_Client *client, + const UA_BrowseRequest request) { + UA_BrowseResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], + &response, &UA_TYPES[UA_TYPES_BROWSERESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_BrowseNextResponse + UA_Client_Service_browseNext(UA_Client *client, + const UA_BrowseNextRequest request) { + UA_BrowseNextResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST], + &response, &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_TranslateBrowsePathsToNodeIdsResponse + UA_Client_Service_translateBrowsePathsToNodeIds( + UA_Client *client, + const UA_TranslateBrowsePathsToNodeIdsRequest request) { + UA_TranslateBrowsePathsToNodeIdsResponse response; + __UA_Client_Service( + client, &request, + &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST], + &response, + &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_RegisterNodesResponse + UA_Client_Service_registerNodes(UA_Client *client, + const UA_RegisterNodesRequest request) { + UA_RegisterNodesResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_REGISTERNODESREQUEST], + &response, &UA_TYPES[UA_TYPES_REGISTERNODESRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_UnregisterNodesResponse + UA_Client_Service_unregisterNodes( + UA_Client *client, const UA_UnregisterNodesRequest request) { + UA_UnregisterNodesResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_UNREGISTERNODESREQUEST], + &response, &UA_TYPES[UA_TYPES_UNREGISTERNODESRESPONSE]); + return response; + } + + /* + * Query Service Set + * ^^^^^^^^^^^^^^^^^ */ + #ifdef UA_ENABLE_QUERY + + static UA_INLINE UA_THREADSAFE UA_QueryFirstResponse + UA_Client_Service_queryFirst(UA_Client *client, + const UA_QueryFirstRequest request) { + UA_QueryFirstResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_QUERYFIRSTREQUEST], + &response, &UA_TYPES[UA_TYPES_QUERYFIRSTRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_QueryNextResponse + UA_Client_Service_queryNext(UA_Client *client, + const UA_QueryNextRequest request) { + UA_QueryNextResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_QUERYFIRSTREQUEST], + &response, &UA_TYPES[UA_TYPES_QUERYFIRSTRESPONSE]); + return response; + } + + #endif + +.. _client-async-services: + +Asynchronous Services +--------------------- +All OPC UA services are asynchronous in nature. So several service calls can +be made without waiting for the individual responses. Depending on the +server's priorities responses may come in a different ordering than sent. Use +the typed wrappers for async service requests instead of +`__UA_Client_AsyncService` directly. See :ref:`client_async`. However, the +general mechanism of async service calls is explained here. + +Connection and session management are performed in `UA_Client_run_iterate`, +so to keep a connection healthy any client needs to consider how and when it +is appropriate to do the call. This is especially true for the periodic +renewal of a SecureChannel's SecurityToken which is designed to have a +limited lifetime and will invalidate the connection if not renewed. + +We say that an async service call has been dispatched once +__UA_Client_AsyncService returns UA_STATUSCODE_GOOD. If there is an error +after an async service has been dispatched, the callback is called with an +"empty" response where the StatusCode has been set accordingly. This is also +done if the client is shutting down and the list of dispatched async services +is emptied. + +The StatusCode received when the client is shutting down is +UA_STATUSCODE_BADSHUTDOWN. The StatusCode received when the client doesn't +receive response after the specified in config->timeout (can be overridden +via the "timeoutHint" in the request header) is UA_STATUSCODE_BADTIMEOUT. + +The userdata and requestId arguments can be NULL. The (optional) requestId +output can be used to cancel the service while it is still pending. The +requestId is unique for each service request. Alternatively the requestHandle +can be manually set (non necessarily unique) in the request header for full +service call. This can be used to cancel all outstanding requests using that +handle together. Note that the client will auto-generate a requestHandle +>100,000 if none is defined. Avoid these when manually setting a requetHandle +in the requestHeader to avoid clashes. + +.. code-block:: c + + + typedef void + (*UA_ClientAsyncServiceCallback)(UA_Client *client, void *userdata, + UA_UInt32 requestId, void *response); + + UA_StatusCode UA_THREADSAFE + __UA_Client_AsyncService(UA_Client *client, const void *request, + const UA_DataType *requestType, + UA_ClientAsyncServiceCallback callback, + const UA_DataType *responseType, + void *userdata, UA_UInt32 *requestId); + + /* Cancel all dispatched requests with the given requestHandle. + * The number if cancelled requests is returned by the server. + * The output argument cancelCount is not set if NULL. */ + UA_THREADSAFE UA_StatusCode + UA_Client_cancelByRequestHandle(UA_Client *client, UA_UInt32 requestHandle, + UA_UInt32 *cancelCount); + + /* Map the requestId to the requestHandle used for that request and call the + * Cancel service for that requestHandle. */ + UA_THREADSAFE UA_StatusCode + UA_Client_cancelByRequestId(UA_Client *client, UA_UInt32 requestId, + UA_UInt32 *cancelCount); + + /* Set new userdata and callback for an existing request. + * + * @param client Pointer to the UA_Client + * @param requestId RequestId of the request, which was returned by + * __UA_Client_AsyncService before + * @param userdata The new userdata + * @param callback The new callback + * @return UA_StatusCode UA_STATUSCODE_GOOD on success + * UA_STATUSCODE_BADNOTFOUND when no request with requestId is found. */ + UA_StatusCode UA_THREADSAFE + UA_Client_modifyAsyncCallback(UA_Client *client, UA_UInt32 requestId, + void *userdata, UA_ClientAsyncServiceCallback callback); + + /* Listen on the network and process arriving asynchronous responses in the + * background. Internal housekeeping, renewal of SecureChannels and subscription + * management is done as well. */ + UA_StatusCode UA_THREADSAFE + UA_Client_run_iterate(UA_Client *client, UA_UInt32 timeout); + + /* Force the manual renewal of the SecureChannel. This is useful to renew the + * SecureChannel during a downtime when no time-critical operations are + * performed. This method is asynchronous. The renewal is triggered (the OPN + * message is sent) but not completed. The OPN response is handled with + * ``UA_Client_run_iterate`` or a synchronous service-call operation. + * + * @return The return value is UA_STATUSCODE_GOODCALLAGAIN if the SecureChannel + * has not elapsed at least 75% of its lifetime. Otherwise the + * ``connectStatus`` is returned. */ + UA_StatusCode UA_THREADSAFE + UA_Client_renewSecureChannel(UA_Client *client); + +Timed Callbacks +--------------- +Repeated callbacks can be attached to a client and will be executed in the +defined interval. + +.. code-block:: c + + + typedef void (*UA_ClientCallback)(UA_Client *client, void *data); + + /* Add a callback for execution at a specified time. If the indicated time lies + * in the past, then the callback is executed at the next iteration of the + * server's main loop. + * + * @param client The client object. + * @param callback The callback that shall be added. + * @param data Data that is forwarded to the callback. + * @param date The timestamp for the execution time. + * @param callbackId Set to the identifier of the repeated callback. This can + * be used to cancel the callback later on. If the pointer is null, the + * identifier is not set. + * @return Upon success, UA_STATUSCODE_GOOD is returned. An error code + * otherwise. */ + UA_StatusCode UA_THREADSAFE + UA_Client_addTimedCallback(UA_Client *client, UA_ClientCallback callback, + void *data, UA_DateTime date, UA_UInt64 *callbackId); + + /* Add a callback for cyclic repetition to the client. + * + * @param client The client object. + * @param callback The callback that shall be added. + * @param data Data that is forwarded to the callback. + * @param interval_ms The callback shall be repeatedly executed with the given + * interval (in ms). The interval must be positive. The first execution + * occurs at now() + interval at the latest. + * @param callbackId Set to the identifier of the repeated callback. This can + * be used to cancel the callback later on. If the pointer is null, the + * identifier is not set. + * @return Upon success, UA_STATUSCODE_GOOD is returned. An error code + * otherwise. */ + UA_StatusCode UA_THREADSAFE + UA_Client_addRepeatedCallback(UA_Client *client, UA_ClientCallback callback, + void *data, UA_Double interval_ms, + UA_UInt64 *callbackId); + + UA_StatusCode UA_THREADSAFE + UA_Client_changeRepeatedCallbackInterval(UA_Client *client, + UA_UInt64 callbackId, + UA_Double interval_ms); + + void UA_THREADSAFE + UA_Client_removeCallback(UA_Client *client, UA_UInt64 callbackId); + + #define UA_Client_removeRepeatedCallback(server, callbackId) \ + UA_Client_removeCallback(server, callbackId); + +Client Utility Functions +------------------------ + +.. code-block:: c + + + /* Lookup a datatype by its NodeId. Takes the custom types in the client + * configuration into account. Return NULL if none found. */ + const UA_DataType * + UA_Client_findDataType(UA_Client *client, const UA_NodeId *typeId); + +.. toctree:: + + client_highlevel + client_highlevel_async + client_subscriptions diff --git a/static/doc/v1.4.0/_sources/client_highlevel.rst.txt b/static/doc/v1.4.0/_sources/client_highlevel.rst.txt new file mode 100644 index 0000000000..f93a766f82 --- /dev/null +++ b/static/doc/v1.4.0/_sources/client_highlevel.rst.txt @@ -0,0 +1,652 @@ +.. _client-highlevel: + +Highlevel Client Functionality +------------------------------ + +The following definitions are convenience functions making use of the +standard OPC UA services in the background. This is a less flexible way of +handling the stack, because at many places sensible defaults are presumed; at +the same time using these functions is the easiest way of implementing an OPC +UA application, as you will not have to consider all the details that go into +the OPC UA services. If more flexibility is needed, you can always achieve +the same functionality using the raw :ref:`OPC UA services +`. + +Read Attributes +^^^^^^^^^^^^^^^ +The following functions can be used to retrieve a single node attribute. Use +the regular service to read several attributes at once. + +.. code-block:: c + + + /* Don't call this function, use the typed versions */ + UA_StatusCode + __UA_Client_readAttribute(UA_Client *client, const UA_NodeId *nodeId, + UA_AttributeId attributeId, void *out, + const UA_DataType *outDataType); + + static UA_INLINE UA_StatusCode + UA_Client_readNodeIdAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_NodeId *outNodeId) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_NODEID, + outNodeId, &UA_TYPES[UA_TYPES_NODEID]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readNodeClassAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_NodeClass *outNodeClass) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_NODECLASS, + outNodeClass, &UA_TYPES[UA_TYPES_NODECLASS]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readBrowseNameAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_QualifiedName *outBrowseName) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_BROWSENAME, + outBrowseName, + &UA_TYPES[UA_TYPES_QUALIFIEDNAME]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readDisplayNameAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_LocalizedText *outDisplayName) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, + outDisplayName, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readDescriptionAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_LocalizedText *outDescription) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, + outDescription, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_UInt32 *outWriteMask) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_WRITEMASK, + outWriteMask, &UA_TYPES[UA_TYPES_UINT32]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readUserWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_UInt32 *outUserWriteMask) { + return __UA_Client_readAttribute(client, &nodeId, + UA_ATTRIBUTEID_USERWRITEMASK, + outUserWriteMask, + &UA_TYPES[UA_TYPES_UINT32]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readIsAbstractAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Boolean *outIsAbstract) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, + outIsAbstract, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readSymmetricAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Boolean *outSymmetric) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC, + outSymmetric, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readInverseNameAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_LocalizedText *outInverseName) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_INVERSENAME, + outInverseName, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readContainsNoLoopsAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Boolean *outContainsNoLoops) { + return __UA_Client_readAttribute(client, &nodeId, + UA_ATTRIBUTEID_CONTAINSNOLOOPS, + outContainsNoLoops, + &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readEventNotifierAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Byte *outEventNotifier) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, + outEventNotifier, &UA_TYPES[UA_TYPES_BYTE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readValueAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Variant *outValue) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE, + outValue, &UA_TYPES[UA_TYPES_VARIANT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readDataTypeAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_NodeId *outDataType) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DATATYPE, + outDataType, &UA_TYPES[UA_TYPES_NODEID]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readValueRankAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Int32 *outValueRank) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUERANK, + outValueRank, &UA_TYPES[UA_TYPES_INT32]); + } + + UA_StatusCode + UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId, + size_t *outArrayDimensionsSize, + UA_UInt32 **outArrayDimensions); + + static UA_INLINE UA_StatusCode + UA_Client_readAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Byte *outAccessLevel) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, + outAccessLevel, &UA_TYPES[UA_TYPES_BYTE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readAccessLevelExAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_UInt32 *outAccessLevelEx) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX, + outAccessLevelEx, &UA_TYPES[UA_TYPES_UINT32]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readUserAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Byte *outUserAccessLevel) { + return __UA_Client_readAttribute(client, &nodeId, + UA_ATTRIBUTEID_USERACCESSLEVEL, + outUserAccessLevel, + &UA_TYPES[UA_TYPES_BYTE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readMinimumSamplingIntervalAttribute(UA_Client *client, + const UA_NodeId nodeId, + UA_Double *outMinSamplingInterval) { + return __UA_Client_readAttribute(client, &nodeId, + UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, + outMinSamplingInterval, + &UA_TYPES[UA_TYPES_DOUBLE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readHistorizingAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Boolean *outHistorizing) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_HISTORIZING, + outHistorizing, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readExecutableAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Boolean *outExecutable) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, + outExecutable, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readUserExecutableAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Boolean *outUserExecutable) { + return __UA_Client_readAttribute(client, &nodeId, + UA_ATTRIBUTEID_USEREXECUTABLE, + outUserExecutable, + &UA_TYPES[UA_TYPES_BOOLEAN]); + } + +Historical Access +^^^^^^^^^^^^^^^^^ +The following functions can be used to read a single node historically. +Use the regular service to read several nodes at once. + +.. code-block:: c + + + typedef UA_Boolean + (*UA_HistoricalIteratorCallback)( + UA_Client *client, const UA_NodeId *nodeId, UA_Boolean moreDataAvailable, + const UA_ExtensionObject *data, void *callbackContext); + + UA_StatusCode + UA_Client_HistoryRead_events( + UA_Client *client, const UA_NodeId *nodeId, + const UA_HistoricalIteratorCallback callback, UA_DateTime startTime, + UA_DateTime endTime, UA_String indexRange, const UA_EventFilter filter, + UA_UInt32 numValuesPerNode, UA_TimestampsToReturn timestampsToReturn, + void *callbackContext); + + UA_StatusCode + UA_Client_HistoryRead_raw( + UA_Client *client, const UA_NodeId *nodeId, + const UA_HistoricalIteratorCallback callback, UA_DateTime startTime, + UA_DateTime endTime, UA_String indexRange, UA_Boolean returnBounds, + UA_UInt32 numValuesPerNode, UA_TimestampsToReturn timestampsToReturn, + void *callbackContext); + + UA_StatusCode + UA_Client_HistoryRead_modified( + UA_Client *client, const UA_NodeId *nodeId, + const UA_HistoricalIteratorCallback callback, UA_DateTime startTime, + UA_DateTime endTime, UA_String indexRange, UA_Boolean returnBounds, + UA_UInt32 numValuesPerNode, UA_TimestampsToReturn timestampsToReturn, + void *callbackContext); + + UA_StatusCode + UA_Client_HistoryUpdate_insert( + UA_Client *client, const UA_NodeId *nodeId, UA_DataValue *value); + + UA_StatusCode + UA_Client_HistoryUpdate_replace( + UA_Client *client, const UA_NodeId *nodeId, UA_DataValue *value); + + UA_StatusCode + UA_Client_HistoryUpdate_update( + UA_Client *client, const UA_NodeId *nodeId, UA_DataValue *value); + + UA_StatusCode + UA_Client_HistoryUpdate_deleteRaw( + UA_Client *client, const UA_NodeId *nodeId, + UA_DateTime startTimestamp, UA_DateTime endTimestamp); + +Write Attributes +^^^^^^^^^^^^^^^^ + +The following functions can be use to write a single node attribute at a +time. Use the regular write service to write several attributes at once. + +.. code-block:: c + + + /* Don't call this function, use the typed versions */ + UA_StatusCode + __UA_Client_writeAttribute(UA_Client *client, const UA_NodeId *nodeId, + UA_AttributeId attributeId, const void *in, + const UA_DataType *inDataType); + + static UA_INLINE UA_StatusCode + UA_Client_writeNodeIdAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_NodeId *newNodeId) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_NODEID, + newNodeId, &UA_TYPES[UA_TYPES_NODEID]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeNodeClassAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_NodeClass *newNodeClass) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_NODECLASS, + newNodeClass, &UA_TYPES[UA_TYPES_NODECLASS]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeBrowseNameAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_QualifiedName *newBrowseName) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_BROWSENAME, + newBrowseName, + &UA_TYPES[UA_TYPES_QUALIFIEDNAME]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeDisplayNameAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_LocalizedText *newDisplayName) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, + newDisplayName, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeDescriptionAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_LocalizedText *newDescription) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, + newDescription, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_UInt32 *newWriteMask) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_WRITEMASK, + newWriteMask, &UA_TYPES[UA_TYPES_UINT32]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeUserWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_UInt32 *newUserWriteMask) { + return __UA_Client_writeAttribute(client, &nodeId, + UA_ATTRIBUTEID_USERWRITEMASK, + newUserWriteMask, + &UA_TYPES[UA_TYPES_UINT32]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeIsAbstractAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *newIsAbstract) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, + newIsAbstract, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeSymmetricAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *newSymmetric) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC, + newSymmetric, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeInverseNameAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_LocalizedText *newInverseName) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_INVERSENAME, + newInverseName, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeContainsNoLoopsAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *newContainsNoLoops) { + return __UA_Client_writeAttribute(client, &nodeId, + UA_ATTRIBUTEID_CONTAINSNOLOOPS, + newContainsNoLoops, + &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeEventNotifierAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Byte *newEventNotifier) { + return __UA_Client_writeAttribute(client, &nodeId, + UA_ATTRIBUTEID_EVENTNOTIFIER, + newEventNotifier, + &UA_TYPES[UA_TYPES_BYTE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeValueAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Variant *newValue) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE, + newValue, &UA_TYPES[UA_TYPES_VARIANT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeValueAttribute_scalar(UA_Client *client, const UA_NodeId nodeId, + const void *newValue, + const UA_DataType *valueType) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE, + newValue, valueType); + } + + /* Write a DataValue that can include timestamps and status codes */ + static UA_INLINE UA_StatusCode + UA_Client_writeValueAttributeEx(UA_Client *client, const UA_NodeId nodeId, + const UA_DataValue *newValue) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE, + newValue, &UA_TYPES[UA_TYPES_DATAVALUE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeDataTypeAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_NodeId *newDataType) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_DATATYPE, + newDataType, &UA_TYPES[UA_TYPES_NODEID]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeValueRankAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Int32 *newValueRank) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUERANK, + newValueRank, &UA_TYPES[UA_TYPES_INT32]); + } + + UA_StatusCode + UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId, + size_t newArrayDimensionsSize, + const UA_UInt32 *newArrayDimensions); + + static UA_INLINE UA_StatusCode + UA_Client_writeAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Byte *newAccessLevel) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, + newAccessLevel, &UA_TYPES[UA_TYPES_BYTE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeAccessLevelExAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_UInt32 *newAccessLevelEx) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX, + newAccessLevelEx, &UA_TYPES[UA_TYPES_UINT32]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeUserAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Byte *newUserAccessLevel) { + return __UA_Client_writeAttribute(client, &nodeId, + UA_ATTRIBUTEID_USERACCESSLEVEL, + newUserAccessLevel, + &UA_TYPES[UA_TYPES_BYTE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeMinimumSamplingIntervalAttribute(UA_Client *client, + const UA_NodeId nodeId, + const UA_Double *newMinInterval) { + return __UA_Client_writeAttribute(client, &nodeId, + UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, + newMinInterval, &UA_TYPES[UA_TYPES_DOUBLE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeHistorizingAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *newHistorizing) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_HISTORIZING, + newHistorizing, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeExecutableAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *newExecutable) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, + newExecutable, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeUserExecutableAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *newUserExecutable) { + return __UA_Client_writeAttribute(client, &nodeId, + UA_ATTRIBUTEID_USEREXECUTABLE, + newUserExecutable, + &UA_TYPES[UA_TYPES_BOOLEAN]); + } + +Method Calling +^^^^^^^^^^^^^^ + +.. code-block:: c + + + UA_StatusCode + UA_Client_call(UA_Client *client, + const UA_NodeId objectId, const UA_NodeId methodId, + size_t inputSize, const UA_Variant *input, + size_t *outputSize, UA_Variant **output); + +Node Management +^^^^^^^^^^^^^^^ +See the section on :ref:`server-side node management `. + +.. code-block:: c + + + UA_StatusCode + UA_Client_addReference(UA_Client *client, const UA_NodeId sourceNodeId, + const UA_NodeId referenceTypeId, UA_Boolean isForward, + const UA_String targetServerUri, + const UA_ExpandedNodeId targetNodeId, + UA_NodeClass targetNodeClass); + + UA_StatusCode + UA_Client_deleteReference(UA_Client *client, const UA_NodeId sourceNodeId, + const UA_NodeId referenceTypeId, UA_Boolean isForward, + const UA_ExpandedNodeId targetNodeId, + UA_Boolean deleteBidirectional); + + UA_StatusCode + UA_Client_deleteNode(UA_Client *client, const UA_NodeId nodeId, + UA_Boolean deleteTargetReferences); + + /* Don't call this function, use the typed versions */ + UA_StatusCode + __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, const UA_NodeAttributes *attr, + const UA_DataType *attributeType, UA_NodeId *outNewNodeId); + + static UA_INLINE UA_StatusCode + UA_Client_addVariableNode(UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, + const UA_VariableAttributes attr, + UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_VARIABLE, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + typeDefinition, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], + outNewNodeId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addVariableTypeNode(UA_Client *client, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_VariableTypeAttributes attr, + UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_VARIABLETYPE, + requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], + outNewNodeId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addObjectNode(UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, + const UA_ObjectAttributes attr, UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_OBJECT, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + typeDefinition, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], outNewNodeId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addObjectTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ObjectTypeAttributes attr, + UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], + outNewNodeId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addViewNode(UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ViewAttributes attr, + UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_VIEW, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], outNewNodeId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addReferenceTypeNode(UA_Client *client, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ReferenceTypeAttributes attr, + UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_REFERENCETYPE, + requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], + outNewNodeId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addDataTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_DataTypeAttributes attr, + UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_DATATYPE, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], + outNewNodeId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addMethodNode(UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_MethodAttributes attr, + UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_METHOD, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_METHODATTRIBUTES], outNewNodeId); + } + +Misc Highlevel Functionality +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + + /* Get the namespace-index of a namespace-URI + * + * @param client The UA_Client struct for this connection + * @param namespaceUri The interested namespace URI + * @param namespaceIndex The namespace index of the URI. The value is unchanged + * in case of an error + * @return Indicates whether the operation succeeded or returns an error code */ + UA_StatusCode + UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri, + UA_UInt16 *namespaceIndex); + + #ifndef HAVE_NODEITER_CALLBACK + #define HAVE_NODEITER_CALLBACK + /* Iterate over all nodes referenced by parentNodeId by calling the callback + * function for each child node */ + typedef UA_StatusCode + (*UA_NodeIteratorCallback)(UA_NodeId childId, UA_Boolean isInverse, + UA_NodeId referenceTypeId, void *handle); + #endif + + UA_StatusCode + UA_Client_forEachChildNodeCall( + UA_Client *client, UA_NodeId parentNodeId, + UA_NodeIteratorCallback callback, void *handle); diff --git a/static/doc/v1.4.0/_sources/client_highlevel_async.rst.txt b/static/doc/v1.4.0/_sources/client_highlevel_async.rst.txt new file mode 100644 index 0000000000..6581789667 --- /dev/null +++ b/static/doc/v1.4.0/_sources/client_highlevel_async.rst.txt @@ -0,0 +1,798 @@ +.. _client_async: + +Async Services +^^^^^^^^^^^^^^ + +Call OPC UA Services asynchronously with a callback. The (optional) requestId +output can be used to cancel the service while it is still pending. + +.. code-block:: c + + + typedef void + (*UA_ClientAsyncReadCallback)( + UA_Client *client, void *userdata, + UA_UInt32 requestId, UA_ReadResponse *rr); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Client_sendAsyncReadRequest( + UA_Client *client, UA_ReadRequest *request, + UA_ClientAsyncReadCallback readCallback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_AsyncService( + client, request, &UA_TYPES[UA_TYPES_READREQUEST], + (UA_ClientAsyncServiceCallback)readCallback, + &UA_TYPES[UA_TYPES_READRESPONSE], userdata, reqId); + } + + typedef void + (*UA_ClientAsyncWriteCallback)( + UA_Client *client, void *userdata, + UA_UInt32 requestId, UA_WriteResponse *wr); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Client_sendAsyncWriteRequest( + UA_Client *client, UA_WriteRequest *request, + UA_ClientAsyncWriteCallback writeCallback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_AsyncService( + client, request, &UA_TYPES[UA_TYPES_WRITEREQUEST], + (UA_ClientAsyncServiceCallback)writeCallback, + &UA_TYPES[UA_TYPES_WRITERESPONSE], userdata, reqId); + } + + typedef void + (*UA_ClientAsyncBrowseCallback)( + UA_Client *client, void *userdata, + UA_UInt32 requestId, UA_BrowseResponse *wr); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Client_sendAsyncBrowseRequest( + UA_Client *client, UA_BrowseRequest *request, + UA_ClientAsyncBrowseCallback browseCallback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_AsyncService( + client, request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], + (UA_ClientAsyncServiceCallback)browseCallback, + &UA_TYPES[UA_TYPES_BROWSERESPONSE], userdata, reqId); + } + + typedef void + (*UA_ClientAsyncBrowseNextCallback)( + UA_Client *client, void *userdata, + UA_UInt32 requestId, UA_BrowseNextResponse *wr); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Client_sendAsyncBrowseNextRequest( + UA_Client *client, UA_BrowseNextRequest *request, + UA_ClientAsyncBrowseNextCallback browseNextCallback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_AsyncService( + client, request, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST], + (UA_ClientAsyncServiceCallback)browseNextCallback, + &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE], userdata, reqId); + } + +Asynchronous Operations +^^^^^^^^^^^^^^^^^^^^^^^ + +Many Services can be called with an array of operations. For example, a +request to the Read Service contains an array of ReadValueId, each +corresponding to a single read operation. For convenience, wrappers are +provided to call single operations for the most common Services. + +All async operations have a callback of the following structure: The returned +StatusCode is split in two parts. The status indicates the overall success of +the request and the operation. The result argument is non-NULL only if the +status is no good. + +.. code-block:: c + + typedef void + (*UA_ClientAsyncOperationCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, void *result); + +Read Attribute +^^^^^^^^^^^^^^ + +Asynchronously read a single attribute. The attribute is unpacked from the +response as the datatype of the attribute is known ahead of time. Value +attributes are variants. + +Note that the last argument (value pointer) of the callbacks can be NULL if +the status of the operation is not good. + +.. code-block:: c + + + /* Reading a single attribute */ + typedef void + (*UA_ClientAsyncReadAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_DataValue *attribute); + + UA_StatusCode + UA_Client_readAttribute_async( + UA_Client *client, const UA_ReadValueId *rvi, + UA_TimestampsToReturn timestampsToReturn, + UA_ClientAsyncReadAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single Value attribute */ + typedef void + (*UA_ClientAsyncReadValueAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_DataValue *value); + + UA_StatusCode + UA_Client_readValueAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadValueAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single DataType attribute */ + typedef void + (*UA_ClientAsyncReadDataTypeAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_NodeId *dataType); + + UA_StatusCode + UA_Client_readDataTypeAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadDataTypeAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single ArrayDimensions attribute. If the status is good, the variant + * carries an UInt32 array. */ + typedef void + (*UA_ClientReadArrayDimensionsAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Variant *arrayDimensions); + + UA_StatusCode + UA_Client_readArrayDimensionsAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientReadArrayDimensionsAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single NodeClass attribute */ + typedef void + (*UA_ClientAsyncReadNodeClassAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_NodeClass *nodeClass); + + UA_StatusCode + UA_Client_readNodeClassAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadNodeClassAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single BrowseName attribute */ + typedef void + (*UA_ClientAsyncReadBrowseNameAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_QualifiedName *browseName); + + UA_StatusCode + UA_Client_readBrowseNameAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadBrowseNameAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single DisplayName attribute */ + typedef void + (*UA_ClientAsyncReadDisplayNameAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_LocalizedText *displayName); + + UA_StatusCode + UA_Client_readDisplayNameAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadDisplayNameAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single Description attribute */ + typedef void + (*UA_ClientAsyncReadDescriptionAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_LocalizedText *description); + + UA_StatusCode + UA_Client_readDescriptionAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadDescriptionAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single WriteMask attribute */ + typedef void + (*UA_ClientAsyncReadWriteMaskAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_UInt32 *writeMask); + + UA_StatusCode + UA_Client_readWriteMaskAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadWriteMaskAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single UserWriteMask attribute */ + typedef void + (*UA_ClientAsyncReadUserWriteMaskAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_UInt32 *writeMask); + + UA_StatusCode + UA_Client_readUserWriteMaskAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadUserWriteMaskAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single IsAbstract attribute */ + typedef void + (*UA_ClientAsyncReadIsAbstractAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Boolean *isAbstract); + + UA_StatusCode + UA_Client_readIsAbstractAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadIsAbstractAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single Symmetric attribute */ + typedef void + (*UA_ClientAsyncReadSymmetricAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Boolean *symmetric); + + UA_StatusCode + UA_Client_readSymmetricAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadSymmetricAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single InverseName attribute */ + typedef void + (*UA_ClientAsyncReadInverseNameAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_LocalizedText *inverseName); + + UA_StatusCode + UA_Client_readInverseNameAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadInverseNameAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single ContainsNoLoops attribute */ + typedef void + (*UA_ClientAsyncReadContainsNoLoopsAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Boolean *containsNoLoops); + + UA_StatusCode + UA_Client_readContainsNoLoopsAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadContainsNoLoopsAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single EventNotifier attribute */ + typedef void + (*UA_ClientAsyncReadEventNotifierAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Byte *eventNotifier); + + UA_StatusCode + UA_Client_readEventNotifierAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadEventNotifierAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single ValueRank attribute */ + typedef void + (*UA_ClientAsyncReadValueRankAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Int32 *valueRank); + + UA_StatusCode + UA_Client_readValueRankAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadValueRankAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single AccessLevel attribute */ + typedef void + (*UA_ClientAsyncReadAccessLevelAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Byte *accessLevel); + + UA_StatusCode + UA_Client_readAccessLevelAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadAccessLevelAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single AccessLevelEx attribute */ + typedef void + (*UA_ClientAsyncReadAccessLevelExAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_UInt32 *accessLevelEx); + + UA_StatusCode + UA_Client_readAccessLevelExAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadAccessLevelExAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single UserAccessLevel attribute */ + typedef void + (*UA_ClientAsyncReadUserAccessLevelAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Byte *userAccessLevel); + + UA_StatusCode + UA_Client_readUserAccessLevelAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadUserAccessLevelAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single MinimumSamplingInterval attribute */ + typedef void + (*UA_ClientAsyncReadMinimumSamplingIntervalAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Double *minimumSamplingInterval); + + UA_StatusCode + UA_Client_readMinimumSamplingIntervalAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadMinimumSamplingIntervalAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single Historizing attribute */ + typedef void + (*UA_ClientAsyncReadHistorizingAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Boolean *historizing); + + UA_StatusCode + UA_Client_readHistorizingAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadHistorizingAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single Executable attribute */ + typedef void + (*UA_ClientAsyncReadExecutableAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Boolean *executable); + + UA_StatusCode + UA_Client_readExecutableAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadExecutableAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single UserExecutable attribute */ + typedef void + (*UA_ClientAsyncReadUserExecutableAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Boolean *userExecutable); + + UA_StatusCode + UA_Client_readUserExecutableAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadUserExecutableAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + +Write Attribute +^^^^^^^^^^^^^^^ + +.. code-block:: c + + + UA_StatusCode + __UA_Client_writeAttribute_async( + UA_Client *client, const UA_NodeId *nodeId, + UA_AttributeId attributeId, const void *in, + const UA_DataType *inDataType, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId); + + static UA_INLINE UA_StatusCode + UA_Client_writeValueAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Variant *attr, UA_ClientAsyncWriteCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_VALUE, attr, + &UA_TYPES[UA_TYPES_VARIANT], + (UA_ClientAsyncServiceCallback)callback, + userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeNodeIdAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_NodeId *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_NODEID, attr, + &UA_TYPES[UA_TYPES_NODEID], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeNodeClassAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_NodeClass *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_NODECLASS, attr, + &UA_TYPES[UA_TYPES_NODECLASS], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeBrowseNameAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_QualifiedName *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_BROWSENAME, attr, + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeDisplayNameAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_LocalizedText *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, attr, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeDescriptionAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_LocalizedText *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, attr, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeWriteMaskAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_UInt32 *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_WRITEMASK, attr, + &UA_TYPES[UA_TYPES_UINT32], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeUserWriteMaskAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_UInt32 *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_USERWRITEMASK, attr, + &UA_TYPES[UA_TYPES_UINT32], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeIsAbstractAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, attr, + &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeSymmetricAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC, attr, + &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeInverseNameAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_LocalizedText *attr, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_INVERSENAME, attr, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeContainsNoLoopsAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, attr, + &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeEventNotifierAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Byte *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, attr, + &UA_TYPES[UA_TYPES_BYTE], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeDataTypeAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_NodeId *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_DATATYPE, attr, + &UA_TYPES[UA_TYPES_NODEID], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeValueRankAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Int32 *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_VALUERANK, attr, + &UA_TYPES[UA_TYPES_INT32], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeAccessLevelAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Byte *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, attr, + &UA_TYPES[UA_TYPES_BYTE], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeAccessLevelExAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_UInt32 *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX, attr, + &UA_TYPES[UA_TYPES_UINT32], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeUserAccessLevelAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Byte *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_USERACCESSLEVEL, attr, + &UA_TYPES[UA_TYPES_BYTE], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeMinimumSamplingIntervalAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Double *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, + attr, &UA_TYPES[UA_TYPES_DOUBLE], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeHistorizingAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_HISTORIZING, attr, + &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeExecutableAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, attr, + &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeUserExecutableAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_USEREXECUTABLE, attr, + &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId); + } + +Method Calling +^^^^^^^^^^^^^^ + +.. code-block:: c + + UA_StatusCode + __UA_Client_call_async( + UA_Client *client, + const UA_NodeId objectId, const UA_NodeId methodId, + size_t inputSize, const UA_Variant *input, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId); + + typedef void + (*UA_ClientAsyncCallCallback)( + UA_Client *client, void *userdata, + UA_UInt32 requestId, UA_CallResponse *cr); + + static UA_INLINE UA_StatusCode + UA_Client_call_async( + UA_Client *client, + const UA_NodeId objectId, const UA_NodeId methodId, + size_t inputSize, const UA_Variant *input, + UA_ClientAsyncCallCallback callback, void *userdata, + UA_UInt32 *reqId) { + return __UA_Client_call_async( + client, objectId, methodId, inputSize, input, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + +Node Management +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef void + (*UA_ClientAsyncAddNodesCallback)( + UA_Client *client, void *userdata, + UA_UInt32 requestId, UA_AddNodesResponse *ar); + + UA_StatusCode + __UA_Client_addNode_async( + UA_Client *client, const UA_NodeClass nodeClass, + const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, const UA_NodeAttributes *attr, + const UA_DataType *attributeType, UA_NodeId *outNewNodeId, + UA_ClientAsyncServiceCallback callback, void *userdata, + UA_UInt32 *reqId); + + static UA_INLINE UA_StatusCode + UA_Client_addVariableNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, const UA_NodeId typeDefinition, + const UA_VariableAttributes attr, UA_NodeId *outNewNodeId, + UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_VARIABLE, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + typeDefinition, (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], outNewNodeId, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addVariableTypeNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_VariableTypeAttributes attr, + UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_VARIABLETYPE, + requestedNewNodeId, parentNodeId, + referenceTypeId, browseName, UA_NODEID_NULL, + (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], + outNewNodeId, (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addObjectNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, const UA_NodeId typeDefinition, + const UA_ObjectAttributes attr, UA_NodeId *outNewNodeId, + UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_OBJECT, requestedNewNodeId, + parentNodeId, referenceTypeId, + browseName, typeDefinition, (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], outNewNodeId, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addObjectTypeNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ObjectTypeAttributes attr, + UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId, parentNodeId, + referenceTypeId, browseName, UA_NODEID_NULL, + (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], outNewNodeId, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addViewNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, const UA_ViewAttributes attr, + UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_VIEW, requestedNewNodeId, + parentNodeId, referenceTypeId, + browseName, UA_NODEID_NULL, (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], outNewNodeId, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addReferenceTypeNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ReferenceTypeAttributes attr, + UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_REFERENCETYPE, requestedNewNodeId, parentNodeId, + referenceTypeId, browseName, UA_NODEID_NULL, + (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], outNewNodeId, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addDataTypeNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, const UA_DataTypeAttributes attr, + UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_DATATYPE, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + UA_NODEID_NULL, (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], outNewNodeId, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addMethodNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, const UA_MethodAttributes attr, + UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_METHOD, requestedNewNodeId, parentNodeId, + referenceTypeId, browseName, UA_NODEID_NULL, + (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_METHODATTRIBUTES], outNewNodeId, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } diff --git a/static/doc/v1.4.0/_sources/client_subscriptions.rst.txt b/static/doc/v1.4.0/_sources/client_subscriptions.rst.txt new file mode 100644 index 0000000000..3f16766f4d --- /dev/null +++ b/static/doc/v1.4.0/_sources/client_subscriptions.rst.txt @@ -0,0 +1,274 @@ +.. _client-subscriptions: + +Subscriptions +------------- + +Subscriptions in OPC UA are asynchronous. That is, the client sends several +PublishRequests to the server. The server returns PublishResponses with +notifications. But only when a notification has been generated. The client +does not wait for the responses and continues normal operations. + +Note the difference between Subscriptions and MonitoredItems. Subscriptions +are used to report back notifications. MonitoredItems are used to generate +notifications. Every MonitoredItem is attached to exactly one Subscription. +And a Subscription can contain many MonitoredItems. + +The client automatically processes PublishResponses (with a callback) in the +background and keeps enough PublishRequests in transit. The PublishResponses +may be recieved during a synchronous service call or in +``UA_Client_run_iterate``. See more about +:ref:`asynchronicity`. + +.. code-block:: c + + + /* Callbacks defined for Subscriptions */ + typedef void (*UA_Client_DeleteSubscriptionCallback) + (UA_Client *client, UA_UInt32 subId, void *subContext); + + typedef void (*UA_Client_StatusChangeNotificationCallback) + (UA_Client *client, UA_UInt32 subId, void *subContext, + UA_StatusChangeNotification *notification); + + /* Provides default values for a new subscription. + * + * RequestedPublishingInterval: 500.0 [ms] + * RequestedLifetimeCount: 10000 + * RequestedMaxKeepAliveCount: 10 + * MaxNotificationsPerPublish: 0 (unlimited) + * PublishingEnabled: true + * Priority: 0 */ + static UA_INLINE UA_CreateSubscriptionRequest + UA_CreateSubscriptionRequest_default(void) { + UA_CreateSubscriptionRequest request; + UA_CreateSubscriptionRequest_init(&request); + + request.requestedPublishingInterval = 500.0; + request.requestedLifetimeCount = 10000; + request.requestedMaxKeepAliveCount = 10; + request.maxNotificationsPerPublish = 0; + request.publishingEnabled = true; + request.priority = 0; + return request; + } + + UA_CreateSubscriptionResponse + UA_Client_Subscriptions_create(UA_Client *client, + const UA_CreateSubscriptionRequest request, + void *subscriptionContext, + UA_Client_StatusChangeNotificationCallback statusChangeCallback, + UA_Client_DeleteSubscriptionCallback deleteCallback); + + UA_StatusCode + UA_Client_Subscriptions_create_async(UA_Client *client, + const UA_CreateSubscriptionRequest request, + void *subscriptionContext, + UA_Client_StatusChangeNotificationCallback statusChangeCallback, + UA_Client_DeleteSubscriptionCallback deleteCallback, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *requestId); + + UA_ModifySubscriptionResponse + UA_Client_Subscriptions_modify(UA_Client *client, + const UA_ModifySubscriptionRequest request); + + UA_StatusCode + UA_Client_Subscriptions_modify_async(UA_Client *client, + const UA_ModifySubscriptionRequest request, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *requestId); + + UA_DeleteSubscriptionsResponse + UA_Client_Subscriptions_delete(UA_Client *client, + const UA_DeleteSubscriptionsRequest request); + + UA_StatusCode + UA_Client_Subscriptions_delete_async(UA_Client *client, + const UA_DeleteSubscriptionsRequest request, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Delete a single subscription */ + UA_StatusCode + UA_Client_Subscriptions_deleteSingle(UA_Client *client, UA_UInt32 subscriptionId); + + static UA_INLINE UA_SetPublishingModeResponse + UA_Client_Subscriptions_setPublishingMode(UA_Client *client, + const UA_SetPublishingModeRequest request) { + UA_SetPublishingModeResponse response; + __UA_Client_Service(client, + &request, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODEREQUEST], + &response, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODERESPONSE]); + return response; + } + +MonitoredItems +-------------- + +MonitoredItems for Events indicate the ``EventNotifier`` attribute. This +indicates to the server not to monitor changes of the attribute, but to +forward Event notifications from that node. + +During the creation of a MonitoredItem, the server may return changed +adjusted parameters. Check the returned ``UA_CreateMonitoredItemsResponse`` +to get the current parameters. + +.. code-block:: c + + + /* Provides default values for a new monitored item. */ + static UA_INLINE UA_MonitoredItemCreateRequest + UA_MonitoredItemCreateRequest_default(UA_NodeId nodeId) { + UA_MonitoredItemCreateRequest request; + UA_MonitoredItemCreateRequest_init(&request); + request.itemToMonitor.nodeId = nodeId; + request.itemToMonitor.attributeId = UA_ATTRIBUTEID_VALUE; + request.monitoringMode = UA_MONITORINGMODE_REPORTING; + request.requestedParameters.samplingInterval = 250; + request.requestedParameters.discardOldest = true; + request.requestedParameters.queueSize = 1; + return request; + } + +The clientHandle parameter cannot be set by the user, any value will be replaced +by the client before sending the request to the server. + +.. code-block:: c + + + /* Callback for the deletion of a MonitoredItem */ + typedef void (*UA_Client_DeleteMonitoredItemCallback) + (UA_Client *client, UA_UInt32 subId, void *subContext, + UA_UInt32 monId, void *monContext); + + /* Callback for DataChange notifications */ + typedef void (*UA_Client_DataChangeNotificationCallback) + (UA_Client *client, UA_UInt32 subId, void *subContext, + UA_UInt32 monId, void *monContext, + UA_DataValue *value); + + /* Callback for Event notifications */ + typedef void (*UA_Client_EventNotificationCallback) + (UA_Client *client, UA_UInt32 subId, void *subContext, + UA_UInt32 monId, void *monContext, + size_t nEventFields, UA_Variant *eventFields); + + /* Don't use to monitor the EventNotifier attribute */ + UA_CreateMonitoredItemsResponse + UA_Client_MonitoredItems_createDataChanges(UA_Client *client, + const UA_CreateMonitoredItemsRequest request, void **contexts, + UA_Client_DataChangeNotificationCallback *callbacks, + UA_Client_DeleteMonitoredItemCallback *deleteCallbacks); + + UA_StatusCode + UA_Client_MonitoredItems_createDataChanges_async(UA_Client *client, + const UA_CreateMonitoredItemsRequest request, void **contexts, + UA_Client_DataChangeNotificationCallback *callbacks, + UA_Client_DeleteMonitoredItemCallback *deleteCallbacks, + UA_ClientAsyncServiceCallback createCallback, + void *userdata, UA_UInt32 *requestId); + + UA_MonitoredItemCreateResult + UA_Client_MonitoredItems_createDataChange(UA_Client *client, + UA_UInt32 subscriptionId, + UA_TimestampsToReturn timestampsToReturn, + const UA_MonitoredItemCreateRequest item, + void *context, UA_Client_DataChangeNotificationCallback callback, + UA_Client_DeleteMonitoredItemCallback deleteCallback); + + /* Monitor the EventNotifier attribute only */ + UA_CreateMonitoredItemsResponse + UA_Client_MonitoredItems_createEvents(UA_Client *client, + const UA_CreateMonitoredItemsRequest request, void **contexts, + UA_Client_EventNotificationCallback *callback, + UA_Client_DeleteMonitoredItemCallback *deleteCallback); + + /* Monitor the EventNotifier attribute only */ + UA_StatusCode + UA_Client_MonitoredItems_createEvents_async(UA_Client *client, + const UA_CreateMonitoredItemsRequest request, void **contexts, + UA_Client_EventNotificationCallback *callbacks, + UA_Client_DeleteMonitoredItemCallback *deleteCallbacks, + UA_ClientAsyncServiceCallback createCallback, + void *userdata, UA_UInt32 *requestId); + + UA_MonitoredItemCreateResult + UA_Client_MonitoredItems_createEvent(UA_Client *client, + UA_UInt32 subscriptionId, + UA_TimestampsToReturn timestampsToReturn, + const UA_MonitoredItemCreateRequest item, + void *context, UA_Client_EventNotificationCallback callback, + UA_Client_DeleteMonitoredItemCallback deleteCallback); + + UA_DeleteMonitoredItemsResponse + UA_Client_MonitoredItems_delete(UA_Client *client, + const UA_DeleteMonitoredItemsRequest); + + UA_StatusCode + UA_Client_MonitoredItems_delete_async(UA_Client *client, + const UA_DeleteMonitoredItemsRequest request, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *requestId); + + UA_StatusCode + UA_Client_MonitoredItems_deleteSingle(UA_Client *client, + UA_UInt32 subscriptionId, UA_UInt32 monitoredItemId); + + /* The clientHandle parameter will be filled automatically */ + UA_ModifyMonitoredItemsResponse + UA_Client_MonitoredItems_modify(UA_Client *client, + const UA_ModifyMonitoredItemsRequest request); + + UA_StatusCode + UA_Client_MonitoredItems_modify_async(UA_Client *client, + const UA_ModifyMonitoredItemsRequest request, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *requestId); + +The following service calls go directly to the server. The MonitoredItem +settings are not stored in the client. + +.. code-block:: c + + + static UA_INLINE UA_SetMonitoringModeResponse + UA_Client_MonitoredItems_setMonitoringMode(UA_Client *client, + const UA_SetMonitoringModeRequest request) { + UA_SetMonitoringModeResponse response; + __UA_Client_Service(client, + &request, &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST], + &response, &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE]); + return response; + } + + static UA_INLINE UA_StatusCode + UA_Client_MonitoredItems_setMonitoringMode_async(UA_Client *client, + const UA_SetMonitoringModeRequest request, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *requestId) { + return __UA_Client_AsyncService(client, &request, + &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST], callback, + &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE], + userdata, requestId); + } + + static UA_INLINE UA_SetTriggeringResponse + UA_Client_MonitoredItems_setTriggering(UA_Client *client, + const UA_SetTriggeringRequest request) { + UA_SetTriggeringResponse response; + __UA_Client_Service(client, + &request, &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST], + &response, &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE]); + return response; + } + + static UA_INLINE UA_StatusCode + UA_Client_MonitoredItems_setTriggering_async(UA_Client *client, + const UA_SetTriggeringRequest request, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *requestId) { + return __UA_Client_AsyncService(client, &request, + &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST], callback, + &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE], + userdata, requestId); + } diff --git a/static/doc/v1.4.0/_sources/common.rst.txt b/static/doc/v1.4.0/_sources/common.rst.txt new file mode 100644 index 0000000000..10a9c5153c --- /dev/null +++ b/static/doc/v1.4.0/_sources/common.rst.txt @@ -0,0 +1,283 @@ +Common Definitions +================== + +Common definitions for Client, Server and PubSub. + +.. _attribute-id: + +Attribute Id +------------ +Every node in an OPC UA information model contains attributes depending on +the node type. Possible attributes are as follows: + +.. code-block:: c + + + typedef enum { + UA_ATTRIBUTEID_NODEID = 1, + UA_ATTRIBUTEID_NODECLASS = 2, + UA_ATTRIBUTEID_BROWSENAME = 3, + UA_ATTRIBUTEID_DISPLAYNAME = 4, + UA_ATTRIBUTEID_DESCRIPTION = 5, + UA_ATTRIBUTEID_WRITEMASK = 6, + UA_ATTRIBUTEID_USERWRITEMASK = 7, + UA_ATTRIBUTEID_ISABSTRACT = 8, + UA_ATTRIBUTEID_SYMMETRIC = 9, + UA_ATTRIBUTEID_INVERSENAME = 10, + UA_ATTRIBUTEID_CONTAINSNOLOOPS = 11, + UA_ATTRIBUTEID_EVENTNOTIFIER = 12, + UA_ATTRIBUTEID_VALUE = 13, + UA_ATTRIBUTEID_DATATYPE = 14, + UA_ATTRIBUTEID_VALUERANK = 15, + UA_ATTRIBUTEID_ARRAYDIMENSIONS = 16, + UA_ATTRIBUTEID_ACCESSLEVEL = 17, + UA_ATTRIBUTEID_USERACCESSLEVEL = 18, + UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL = 19, + UA_ATTRIBUTEID_HISTORIZING = 20, + UA_ATTRIBUTEID_EXECUTABLE = 21, + UA_ATTRIBUTEID_USEREXECUTABLE = 22, + UA_ATTRIBUTEID_DATATYPEDEFINITION = 23, + UA_ATTRIBUTEID_ROLEPERMISSIONS = 24, + UA_ATTRIBUTEID_USERROLEPERMISSIONS = 25, + UA_ATTRIBUTEID_ACCESSRESTRICTIONS = 26, + UA_ATTRIBUTEID_ACCESSLEVELEX = 27 + } UA_AttributeId; + +.. _access-level-mask: + +Access Level Masks +------------------ +The access level to a node is given by the following constants that are ANDed +with the overall access level. + +.. code-block:: c + + + #define UA_ACCESSLEVELMASK_READ (0x01u << 0u) + #define UA_ACCESSLEVELMASK_WRITE (0x01u << 1u) + #define UA_ACCESSLEVELMASK_HISTORYREAD (0x01u << 2u) + #define UA_ACCESSLEVELMASK_HISTORYWRITE (0x01u << 3u) + #define UA_ACCESSLEVELMASK_SEMANTICCHANGE (0x01u << 4u) + #define UA_ACCESSLEVELMASK_STATUSWRITE (0x01u << 5u) + #define UA_ACCESSLEVELMASK_TIMESTAMPWRITE (0x01u << 6u) + +.. _write-mask: + +Write Masks +----------- +The write mask and user write mask is given by the following constants that +are ANDed for the overall write mask. Part 3: 5.2.7 Table 2 + +.. code-block:: c + + + #define UA_WRITEMASK_ACCESSLEVEL (0x01u << 0u) + #define UA_WRITEMASK_ARRRAYDIMENSIONS (0x01u << 1u) + #define UA_WRITEMASK_BROWSENAME (0x01u << 2u) + #define UA_WRITEMASK_CONTAINSNOLOOPS (0x01u << 3u) + #define UA_WRITEMASK_DATATYPE (0x01u << 4u) + #define UA_WRITEMASK_DESCRIPTION (0x01u << 5u) + #define UA_WRITEMASK_DISPLAYNAME (0x01u << 6u) + #define UA_WRITEMASK_EVENTNOTIFIER (0x01u << 7u) + #define UA_WRITEMASK_EXECUTABLE (0x01u << 8u) + #define UA_WRITEMASK_HISTORIZING (0x01u << 9u) + #define UA_WRITEMASK_INVERSENAME (0x01u << 10u) + #define UA_WRITEMASK_ISABSTRACT (0x01u << 11u) + #define UA_WRITEMASK_MINIMUMSAMPLINGINTERVAL (0x01u << 12u) + #define UA_WRITEMASK_NODECLASS (0x01u << 13u) + #define UA_WRITEMASK_NODEID (0x01u << 14u) + #define UA_WRITEMASK_SYMMETRIC (0x01u << 15u) + #define UA_WRITEMASK_USERACCESSLEVEL (0x01u << 16u) + #define UA_WRITEMASK_USEREXECUTABLE (0x01u << 17u) + #define UA_WRITEMASK_USERWRITEMASK (0x01u << 18u) + #define UA_WRITEMASK_VALUERANK (0x01u << 19u) + #define UA_WRITEMASK_WRITEMASK (0x01u << 20u) + #define UA_WRITEMASK_VALUEFORVARIABLETYPE (0x01u << 21u) + #define UA_WRITEMASK_ACCESSLEVELEX (0x01u << 25u) + +.. _valuerank-defines: + +ValueRank +--------- +The following are the most common ValueRanks used for Variables, +VariableTypes and method arguments. ValueRanks higher than 3 are valid as +well (but less common). + +.. code-block:: c + + + #define UA_VALUERANK_SCALAR_OR_ONE_DIMENSION -3 + #define UA_VALUERANK_ANY -2 + #define UA_VALUERANK_SCALAR -1 + #define UA_VALUERANK_ONE_OR_MORE_DIMENSIONS 0 + #define UA_VALUERANK_ONE_DIMENSION 1 + #define UA_VALUERANK_TWO_DIMENSIONS 2 + #define UA_VALUERANK_THREE_DIMENSIONS 3 + +.. _eventnotifier: + +EventNotifier +------------- +The following are the available EventNotifier used for Nodes. +The EventNotifier Attribute is used to indicate if the Node can be used +to subscribe to Events or to read / write historic Events. +Part 3: 5.4 Table 10 + +.. code-block:: c + + + #define UA_EVENTNOTIFIER_SUBSCRIBE_TO_EVENT (0x01u << 0u) + #define UA_EVENTNOTIFIER_HISTORY_READ (0x01u << 2u) + #define UA_EVENTNOTIFIER_HISTORY_WRITE (0x01u << 3u) + +.. _rule-handling: + +Rule Handling +------------- + +The RuleHanding settings define how error cases that result from rules in the +OPC UA specification shall be handled. The rule handling can be softened, +e.g. to workaround misbehaving implementations or to mitigate the impact of +additional rules that are introduced in later versions of the OPC UA +specification. + +.. code-block:: c + + typedef enum { + UA_RULEHANDLING_DEFAULT = 0, + UA_RULEHANDLING_ABORT, /* Abort the operation and return an error code */ + UA_RULEHANDLING_WARN, /* Print a message in the logs and continue */ + UA_RULEHANDLING_ACCEPT, /* Continue and disregard the broken rule */ + } UA_RuleHandling; + +Order +----- + +The Order enum is used to establish an absolute ordering between elements. + +.. code-block:: c + + + typedef enum { + UA_ORDER_LESS = -1, + UA_ORDER_EQ = 0, + UA_ORDER_MORE = 1 + } UA_Order; + +Connection State +---------------- + +.. code-block:: c + + + typedef enum { + UA_CONNECTIONSTATE_CLOSED, /* The socket has been closed and the connection + * will be deleted */ + UA_CONNECTIONSTATE_OPENING, /* The socket is open, but the HEL/ACK handshake + * is not done */ + UA_CONNECTIONSTATE_ESTABLISHED,/* The socket is open and the connection + * configured */ + UA_CONNECTIONSTATE_CLOSING /* The socket is closing down */ + } UA_ConnectionState; + + + typedef enum { + UA_SECURECHANNELSTATE_CLOSED = 0, + UA_SECURECHANNELSTATE_REVERSE_LISTENING, + UA_SECURECHANNELSTATE_CONNECTING, + UA_SECURECHANNELSTATE_CONNECTED, + UA_SECURECHANNELSTATE_REVERSE_CONNECTED, + UA_SECURECHANNELSTATE_RHE_SENT, + UA_SECURECHANNELSTATE_HEL_SENT, + UA_SECURECHANNELSTATE_HEL_RECEIVED, + UA_SECURECHANNELSTATE_ACK_SENT, + UA_SECURECHANNELSTATE_ACK_RECEIVED, + UA_SECURECHANNELSTATE_OPN_SENT, + UA_SECURECHANNELSTATE_OPEN, + UA_SECURECHANNELSTATE_CLOSING, + } UA_SecureChannelState; + + typedef enum { + UA_SESSIONSTATE_CLOSED = 0, + UA_SESSIONSTATE_CREATE_REQUESTED, + UA_SESSIONSTATE_CREATED, + UA_SESSIONSTATE_ACTIVATE_REQUESTED, + UA_SESSIONSTATE_ACTIVATED, + UA_SESSIONSTATE_CLOSING + } UA_SessionState; + +Statistic Counters +------------------ + +The stack manages statistic counters for SecureChannels and Sessions. + +The Session layer counters are matching the counters of the +ServerDiagnosticsSummaryDataType that are defined in the OPC UA Part 5 +specification. The SecureChannel counters are not defined in the OPC UA spec, +but are harmonized with the Session layer counters if possible. + +.. code-block:: c + + + typedef enum { + UA_SHUTDOWNREASON_CLOSE = 0, + UA_SHUTDOWNREASON_REJECT, + UA_SHUTDOWNREASON_SECURITYREJECT, + UA_SHUTDOWNREASON_TIMEOUT, + UA_SHUTDOWNREASON_ABORT, + UA_SHUTDOWNREASON_PURGE + } UA_ShutdownReason; + + typedef struct { + size_t currentChannelCount; + size_t cumulatedChannelCount; + size_t rejectedChannelCount; + size_t channelTimeoutCount; /* only used by servers */ + size_t channelAbortCount; + size_t channelPurgeCount; /* only used by servers */ + } UA_SecureChannelStatistics; + + typedef struct { + size_t currentSessionCount; + size_t cumulatedSessionCount; + size_t securityRejectedSessionCount; /* only used by servers */ + size_t rejectedSessionCount; + size_t sessionTimeoutCount; /* only used by servers */ + size_t sessionAbortCount; /* only used by servers */ + } UA_SessionStatistics; + +Lifecycle States +---------------- + +Generic lifecycle states. The STOPPING state indicates that the lifecycle is +being terminated. But it might take time to (asynchronously) perform a +graceful shutdown. + +.. code-block:: c + + + typedef enum { + UA_LIFECYCLESTATE_STOPPED = 0, + UA_LIFECYCLESTATE_STARTED, + UA_LIFECYCLESTATE_STOPPING + } UA_LifecycleState; + +Forward Declarations +-------------------- +Opaque pointers used in Client, Server and PubSub. + +.. code-block:: c + + + struct UA_Server; + typedef struct UA_Server UA_Server; + + struct UA_ServerConfig; + typedef struct UA_ServerConfig UA_ServerConfig; + + typedef void (*UA_ServerCallback)(UA_Server *server, void *data); + + struct UA_Client; + typedef struct UA_Client UA_Client; + +.. include:: util.rst diff --git a/static/doc/v1.4.0/_sources/core_concepts.rst.txt b/static/doc/v1.4.0/_sources/core_concepts.rst.txt new file mode 100644 index 0000000000..1e7e00726a --- /dev/null +++ b/static/doc/v1.4.0/_sources/core_concepts.rst.txt @@ -0,0 +1,765 @@ +.. _introduction: + +Core Concepts of OPC UA +======================= + +In one sentence, OPC UA (ISO 62541) defines a framework for object-oriented +information models (typically representing a physical device) that live in an +OPC UA server and a protocol with which a client can interact with the +information model over the network (read and write variables, call methods, +instantiate and delete objects, subscribe to change notifications, and so on). + +This Section introduces the core concepts of OPC UA. For the full specification +see the OPC UA standard at `https://reference.opcfoundation.org/ +`_. + +.. _protocol: + +Protocol +-------- + +We focus on the TCP-based binary protocol since it is by far the most common +transport layer for OPC UA. The general concepts also translate to HTTP and +SOAP-based communication defined in the standard. Communication in OPC UA is +best understood by starting with the following key principles: + +Request / Response + All communication is based on the Request/Response pattern. Only clients can + send a request to a server. And servers can only send responses to a matching + request. Often the server is hosted close to a (physical) device, such as a + sensor or a machine tool. + +Asynchronous Responses + A server does not have to immediately respond to requests and responses may be + sent in a different order. This keeps the server responsive when it takes time + until a specific request has been processed (e.g. a method call or when + reading from a sensor with delay). Subscriptions (push-notifications) are + implemented via special requests where the response is delayed until a + notification is published. + +.. note:: + *OPC UA PubSub* (Part 14 of the standard) is an extension for the integration + of many-to-many communication with OPC UA. PubSub does not use the + client-server protocol. Rather, OPC UA PubSub integrates with either existing + broker-based protocols such as MQTT, UDP-multicast or Ethernet-based + communication. Typically an OPC UA server (accessed via the client-server + protocol) is used to configured PubSub communication. + + Note that the client-server protocol also supports Subscriptions for + one-to-one communication and does not depend on PubSub for this feature. + +A client-server connection for the OPC UA binary protocol consists of three +nested levels: The stateful TCP connection, a SecureChannel and the Session. For +full details, see Part 6 of the OPC UA standard. + +TCP Connection + The TCP connection is opened to the corresponding hostname and port with an + initial handshake of HEL/ACK messages. The handshake establishes the basic + settings of the connection, such as the maximum message length. The *Reverse + Connect* extension of OPC UA allows the server to initiate the underlying TCP + connection. + +SecureChannel + SecureChannels are created on top of the raw TCP connection. A SecureChannel + is established with an *OpenSecureChannel* request and response message pair. + **Attention!** Even though a SecureChannel is mandatory, encryption might + still be disabled. The *SecurityMode* of a SecureChannel can be either + ``None``, ``Sign``, or ``SignAndEncrypt``. As of version 0.2 of open62541, + message signing and encryption is still under ongoing development. + + With message signing or encryption enabled, the *OpenSecureChannel* messages + are encrypted using an asymmetric encryption algorithm (public-key + cryptography) [#key-mgmnt]_. As part of the *OpenSecureChannel* messages, + client and server establish a common secret over an initially unsecure + channel. For subsequent messages, the common secret is used for symmetric + encryption, which has the advantage of being much faster. + + Different *SecurityPolicies* -- defined in part 7 of the OPC UA standard -- + specify the algorithms for asymmetric and symmetric encryption, encryption key + lengths, hash functions for message signing, and so on. Example + SecurityPolicies are ``None`` for transmission of cleartext and + ``Basic256Sha256`` which mandates a variant of RSA with SHA256 certificate + hashing for asymmetric encryption and AES256 for symmetric encryption. + + The possible SecurityPolicies of a server are described with a list of + *Endpoints*. An endpoint jointly defines the SecurityMode, SecurityPolicy and + means for authenticating a session (discussed in the next section) in order to + connect to a certain server. The *GetEndpoints* service returns a list of + available endpoints. This service can usually be invoked without a session and + from an unencrypted SecureChannel. This allows clients to first discover + available endpoints and then use an appropriate SecurityPolicy that might be + required to open a session. + +Session + Sessions are created on top of a SecureChannel. This ensures that users may + authenticate without sending their credentials, such as username and password, + in cleartext. Currently defined authentication mechanisms are anonymous login, + username/password, Kerberos and x509 certificates. The latter requires that + the request message is accompanied by a signature to prove that the sender is + in possession of the private key with which the certificate was created. + + There are two message exchanges required to establish a session: + *CreateSession* and *ActicateSession*. The ActivateSession service can be used + to switch an existing session to a different SecureChannel. This is important, + for example when the connection broke down and the existing session is + reused with a new SecureChannel. + +.. [#key-mgmnt] This entails that the client and server exchange so-called + public keys. The public keys might come with a certificate from a key-signing + authority or be verified against an external key repository. But we will not + discuss certificate management in detail in this section. + +Structure of a protocol message +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Consider the example OPC UA binary conversation in Figure +:numref:`ua-wireshark`, recorded and displayed with `Wireshark +`_. + +.. _ua-wireshark: + +.. figure:: ua-wireshark.png + :figwidth: 100 % + :alt: OPC UA conversation in Wireshark + + OPC UA conversation displayed in Wireshark + +The top part of the Wireshark window shows the messages from the conversation in +order. The green line contains the applied filter. Here, we want to see the OPC +UA protocol messages only. The first messages (from TCP packets 49 to 56) show +the client opening an unencrypted SecureChannel and retrieving the server's +endpoints. Then, starting with packet 63, a new connection and SecureChannel are +created in conformance with one of the endpoints. On top of this SecureChannel, +the client can then create and activate a session. The following *ReadRequest* +message is selected and covered in more detail in the bottom windows. + +The bottom left window shows the structure of the selected *ReadRequest* +message. The purpose of the message is invoking the *Read* :ref:`service +`. The message is structured into a header and a message body. Note +that we do not consider encryption or signing of messages here. + +Message Header + As stated before, OPC UA defines an asynchronous protocol. So responses may be + out of order. The message header contains some basic information, such as the + length of the message, as well as necessary information to relate messages to + a SecureChannel and each request to the corresponding response. "Chunking" + refers to the splitting and reassembling of messages that are longer than the + maximum network packet size. + +Message Body + Every OPC UA :ref:`service ` has a signature in the form of a + request and response data structure. These are defined according to the OPC UA + protocol :ref:`type system `. See especially the :ref:`auto-generated + type definitions` for the data types corresponding to service + requests and responses. The message body begins with the identifier of the + following data type. Then, the main payload of the message follows. + +The bottom right window shows the binary payload of the selected *ReadRequest* +message. The message header is highlighted in light-grey. The message body in +blue highlighting shows the encoded *ReadRequest* data structure. + +.. _services: + +Services +-------- + +In OPC UA, all communication is based on service calls, each consisting of a +request and a response message. These messages are defined as data structures +with a binary encoding and listed in :ref:`generated-types`. Since all +Services are pre-defined in the standard, they cannot be modified by the +user. But you can use the :ref:`Call ` service to invoke +user-defined methods on the server. + +Please refer to the :ref:`client` and :ref:`server` API where the services +are exposed to end users. Please see part 4 of the OPC UA standard for the +authoritative definition of the services and their behaviour. + +Discovery Service Set +~~~~~~~~~~~~~~~~~~~~~ +This Service Set defines Services used to discover the Endpoints implemented +by a Server and to read the security configuration for those Endpoints. + +FindServers Service + Returns the Servers known to a Server or Discovery Server. The Client may + reduce the number of results returned by specifying filter criteria + +GetEndpoints Service + Returns the Endpoints supported by a Server and all of the configuration + information required to establish a SecureChannel and a Session. + +FindServersOnNetwork Service + Returns the Servers known to a Discovery Server. Unlike FindServer, + this Service is only implemented by Discovery Servers. It additionally + returns servers which may have been detected through Multicast. + +RegisterServer + Registers a remote server in the local discovery service. + +RegisterServer2 + This Service allows a Server to register its DiscoveryUrls and capabilities + with a Discovery Server. It extends the registration information from + RegisterServer with information necessary for FindServersOnNetwork. + +SecureChannel Service Set +~~~~~~~~~~~~~~~~~~~~~~~~~ +This Service Set defines Services used to open a communication channel that +ensures the confidentiality and Integrity of all Messages exchanged with the +Server. + +OpenSecureChannel Service + Open or renew a SecureChannel that can be used to ensure Confidentiality and + Integrity for Message exchange during a Session. + +CloseSecureChannel Service + Used to terminate a SecureChannel. + +Session Service Set + This Service Set defines Services for an application layer connection + establishment in the context of a Session. + +CreateSession Service + Used by an OPC UA Client to create a Session and the Server returns two + values which uniquely identify the Session. The first value is the sessionId + which is used to identify the Session in the audit logs and in the Server's + address space. The second is the authenticationToken which is used to + associate an incoming request with a Session. + +ActivateSession + Used by the Client to submit its SoftwareCertificates to the Server for + validation and to specify the identity of the user associated with the + Session. This Service request shall be issued by the Client before it issues + any other Service request after CreateSession. Failure to do so shall cause + the Server to close the Session. + +CloseSession + Used to terminate a Session. + +Cancel Service + Used to cancel outstanding Service requests. Successfully cancelled service + requests shall respond with Bad_RequestCancelledByClient. + +NodeManagement Service Set +~~~~~~~~~~~~~~~~~~~~~~~~~~ +This Service Set defines Services to add and delete AddressSpace Nodes and +References between them. All added Nodes continue to exist in the +AddressSpace even if the Client that created them disconnects from the +Server. + +AddNodes Service + Used to add one or more Nodes into the AddressSpace hierarchy. + If the type or one of the supertypes has any HasInterface references + (see OPC 10001-7 - Amendment 7, 4.9.2), the child nodes of the interfaces + are added to the new object. + +AddReferences Service + Used to add one or more References to one or more Nodes. + +DeleteNodes Service + Used to delete one or more Nodes from the AddressSpace. + +DeleteReferences + Used to delete one or more References of a Node. + +.. _view-services: + +View Service Set +~~~~~~~~~~~~~~~~ +Clients use the browse Services of the View Service Set to navigate through +the AddressSpace or through a View which is a subset of the AddressSpace. + +Browse Service + Used to discover the References of a specified Node. The browse can be + further limited by the use of a View. This Browse Service also supports a + primitive filtering capability. + +BrowseNext Service + Used to request the next set of Browse or BrowseNext response information + that is too large to be sent in a single response. "Too large" in this + context means that the Server is not able to return a larger response or that + the number of results to return exceeds the maximum number of results to + return that was specified by the Client in the original Browse request. + +TranslateBrowsePathsToNodeIds Service + Used to translate textual node paths to their respective ids. + +RegisterNodes Service + Used by Clients to register the Nodes that they know they will access + repeatedly (e.g. Write, Call). It allows Servers to set up anything needed so + that the access operations will be more efficient. + +UnregisterNodes Service + This Service is used to unregister NodeIds that have been obtained via the + RegisterNodes service. + +Query Service Set +~~~~~~~~~~~~~~~~~ +This Service Set is used to issue a Query to a Server. OPC UA Query is +generic in that it provides an underlying storage mechanism independent Query +capability that can be used to access a wide variety of OPC UA data stores +and information management systems. OPC UA Query permits a Client to access +data maintained by a Server without any knowledge of the logical schema used +for internal storage of the data. Knowledge of the AddressSpace is +sufficient. + +QueryFirst Service (not implemented) + This Service is used to issue a Query request to the Server. + +QueryNext Service (not implemented) + This Service is used to request the next set of QueryFirst or QueryNext + response information that is too large to be sent in a single response. + +Attribute Service Set +~~~~~~~~~~~~~~~~~~~~~ +This Service Set provides Services to access Attributes that are part of +Nodes. + +Read Service + Used to read attributes of nodes. For constructed attribute values whose + elements are indexed, such as an array, this Service allows Clients to read + the entire set of indexed values as a composite, to read individual elements + or to read ranges of elements of the composite. + +Write Service + Used to write attributes of nodes. For constructed attribute values whose + elements are indexed, such as an array, this Service allows Clients to write + the entire set of indexed values as a composite, to write individual elements + or to write ranges of elements of the composite. + +HistoryRead Service + Used to read historical values or Events of one or more Nodes. Servers may + make historical values available to Clients using this Service, although the + historical values themselves are not visible in the AddressSpace. + +HistoryUpdate Service + Used to update historical values or Events of one or more Nodes. Several + request parameters indicate how the Server is to update the historical value + or Event. Valid actions are Insert, Replace or Delete. + +.. _method-services: + +Method Service Set +~~~~~~~~~~~~~~~~~~ +The Method Service Set defines the means to invoke methods. A method shall be +a component of an Object. See the section on :ref:`MethodNodes ` +for more information. + +Call Service + Used to call (invoke) a methods. Each method call is invoked within the + context of an existing Session. If the Session is terminated, the results of + the method's execution cannot be returned to the Client and are discarded. + +MonitoredItem Service Set +~~~~~~~~~~~~~~~~~~~~~~~~~ +Clients define MonitoredItems to subscribe to data and Events. Each +MonitoredItem identifies the item to be monitored and the Subscription to use +to send Notifications. The item to be monitored may be any Node Attribute. + +CreateMonitoredItems Service + Used to create and add one or more MonitoredItems to a Subscription. A + MonitoredItem is deleted automatically by the Server when the Subscription is + deleted. Deleting a MonitoredItem causes its entire set of triggered item + links to be deleted, but has no effect on the MonitoredItems referenced by + the triggered items. + +DeleteMonitoredItems Service + Used to remove one or more MonitoredItems of a Subscription. When a + MonitoredItem is deleted, its triggered item links are also deleted. + +ModifyMonitoredItems Service + Used to modify MonitoredItems of a Subscription. Changes to the MonitoredItem + settings shall be applied immediately by the Server. They take effect as soon + as practical but not later than twice the new revisedSamplingInterval. + + Illegal request values for parameters that can be revised do not generate + errors. Instead the server will choose default values and indicate them in + the corresponding revised parameter. + +SetMonitoringMode Service + Used to set the monitoring mode for one or more MonitoredItems of a + Subscription. + +SetTriggering Service + Used to create and delete triggering links for a triggering item. + +Subscription Service Set +~~~~~~~~~~~~~~~~~~~~~~~~ +Subscriptions are used to report Notifications to the Client. + +CreateSubscription Service + Used to create a Subscription. Subscriptions monitor a set of MonitoredItems + for Notifications and return them to the Client in response to Publish + requests. + +ModifySubscription Service + Used to modify a Subscription. + +SetPublishingMode Service + Used to enable sending of Notifications on one or more Subscriptions. + +Publish Service + Used for two purposes. First, it is used to acknowledge the receipt of + NotificationMessages for one or more Subscriptions. Second, it is used to + request the Server to return a NotificationMessage or a keep-alive + Message. + +Republish Service + Requests the Subscription to republish a NotificationMessage from its + retransmission queue. + +DeleteSubscriptions Service + Invoked to delete one or more Subscriptions that belong to the Client's + Session. + +TransferSubscription Service + Used to transfer a Subscription and its MonitoredItems from one Session to + another. For example, a Client may need to reopen a Session and then transfer + its Subscriptions to that Session. It may also be used by one Client to take + over a Subscription from another Client by transferring the Subscription to + its Session. + +.. _information-modelling: + +Information Modelling +--------------------- + +Information modelling in OPC UA combines concepts from object-orientation and +semantic modelling. At the core, an OPC UA information model is a graph +consisting of Nodes and References between them. + +Nodes + There are eight possible NodeClasses for Nodes (Variable, VariableType, + Object, ObjectType, ReferenceType, DataType, Method, View). The NodeClass + defines the attributes a Node can have. + +References + References are links between Nodes. References are typed (refer to a + ReferenceType) and directed. + +The original source for the following information is Part 3 of the OPC UA +specification (https://reference.opcfoundation.org/Core/Part3/). + +Each Node is identified by a unique (within the server) :ref:`nodeid` and +carries different attributes depending on the NodeClass. These attributes can be +read (and sometimes also written) via the OPC UA protocol. The protocol further +allows the creation and deletion of Nodes and References at runtime. But this is +not supported by all servers. + +Reference are triples of the form ``(source-nodeid, referencetype-nodeid, +target-nodeid)``. (The ``target-nodeid`` is actually an :ref:`expandednodeid` +which is a NodeId that can additionally point to a remote server.) An example +reference between nodes is a ``hasTypeDefinition`` reference between a Variable +and its VariableType. Some ReferenceTypes are *hierarchical* and must not form +*directed loops*. See the section on :ref:`ReferenceTypes ` +for more details on possible references and their semantics. + +The following table (adapted from Part 3 of the specification) shows which +attributes are mandatory (``M``), optional (``O``) or not defined for each +NodeClass. In open62541 all optional attributes are defined - with sensible +defaults if users do not change them. + +.. table:: Node attributes for the different NodeClasses + :width: 100% + + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | Attribute | DataType | Variable | Variable­Type | Object | Object­Type | Reference­Type | Data­Type | Method | View | + +=========================+=============================+==========+===============+========+=============+================+===========+========+=======+ + | NodeId | NodeId | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | NodeClass | NodeClass | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | BrowseName | QualifiedName | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | DisplayName | LocalizedText | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | Description | LocalizedText | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | WriteMask | UInt32 | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | + | | (:ref:`write-mask`) | | | | | | | ``M`` | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | UserWriteMask | UInt32 | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | IsAbstract | Boolean | | ``M`` | | ``M`` | ``M`` | ``M`` | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | Symmetric | Boolean | | | | | ``M`` | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | InverseName | LocalizedText | | | | | ``O`` | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | ContainsNoLoops | Boolean | | | | | | | | ``M`` | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | EventNotifier | Byte | | | ``M`` | | | | | ``M`` | + | | (:ref:`eventnotifier`) | | | | | | | ``M`` | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | Value | Variant | ``M`` | ``O`` | | | | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | DataType | NodeId | ``M`` | ``M`` | | | | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | ValueRank | Int32 | ``M`` | ``M`` | | | | | | | + | | (:ref:`valuerank-defines`) | | | | | | | ``M`` | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | ArrayDimensions | [UInt32] | ``O`` | ``O`` | | | | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | AccessLevel | Byte | ``M`` | | | | | | | | + | | (:ref:`access-level-mask`) | | | | | | | ``M`` | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | UserAccessLevel | Byte | ``M`` | | | | | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | MinimumSamplingInterval | Double | ``O`` | | | | | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | Historizing | Boolean | ``M`` | | | | | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | Executable | Boolean | | | | | | | ``M`` | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | UserExecutable | Boolean | | | | | | | ``M`` | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | DataTypeDefinition | DataTypeDefinition | | | | | | ``O`` | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + +Each attribute is referenced by a numerical :ref:`attribute-id`. + +Some numerical attributes are used as bitfields or come with special semantics. +In particular, see the sections on :ref:`access-level-mask`, :ref:`write-mask`, +:ref:`valuerank-defines` and :ref:`eventnotifier`. + +New attributes in the standard that are still unsupported in open62541 are +RolePermissions, UserRolePermissions, AccessRestrictions and AccessLevelEx. + +VariableNode +~~~~~~~~~~~~ + +Variables store values in a :ref:`datavalue` together with +metadata for introspection. Most notably, the attributes data type, value +rank and array dimensions constrain the possible values the variable can take +on. + +Variables come in two flavours: properties and datavariables. Properties are +related to a parent with a ``hasProperty`` reference and may not have child +nodes themselves. Datavariables may contain properties (``hasProperty``) and +also datavariables (``hasComponents``). + +All variables are instances of some :ref:`variabletypenode` in return +constraining the possible data type, value rank and array dimensions +attributes. + +Data Type +^^^^^^^^^ + +The (scalar) data type of the variable is constrained to be of a specific +type or one of its children in the type hierarchy. The data type is given as +a NodeId pointing to a :ref:`datatypenode` in the type hierarchy. See the +Section :ref:`datatypenode` for more details. + +If the data type attribute points to ``UInt32``, then the value attribute +must be of that exact type since ``UInt32`` does not have children in the +type hierarchy. If the data type attribute points ``Number``, then the type +of the value attribute may still be ``UInt32``, but also ``Float`` or +``Byte``. + +Consistency between the data type attribute in the variable and its +:ref:`VariableTypeNode` is ensured. + +ValueRank +^^^^^^^^^ + +This attribute indicates whether the value attribute of the variable is an +array and how many dimensions the array has. It may have the following +values: + +- ``n >= 1``: the value is an array with the specified number of dimensions +- ``n = 0``: the value is an array with one or more dimensions +- ``n = -1``: the value is a scalar +- ``n = -2``: the value can be a scalar or an array with any number of dimensions +- ``n = -3``: the value can be a scalar or a one dimensional array + +Some helper macros for ValueRanks are defined :ref:`here `. + +The consistency between the value rank attribute of a VariableNode and its +:ref:`variabletypenode` is tested within the server. + +Array Dimensions +^^^^^^^^^^^^^^^^ + +If the value rank permits the value to be a (multi-dimensional) array, the +exact length in each dimensions can be further constrained with this +attribute. + +- For positive lengths, the variable value must have a dimension length less + or equal to the array dimension length defined in the VariableNode. +- The dimension length zero is a wildcard and the actual value may have any + length in this dimension. Note that a value (variant) must have array + dimensions that are positive (not zero). + +Consistency between the array dimensions attribute in the variable and its +:ref:`variabletypenode` is ensured. However, we consider that an array of +length zero (can also be a null-array with undefined length) has implicit +array dimensions ``[0,0,...]``. These always match the required array +dimensions. + +.. _variabletypenode: + +VariableTypeNode +~~~~~~~~~~~~~~~~ + +VariableTypes are used to provide type definitions for variables. +VariableTypes constrain the data type, value rank and array dimensions +attributes of variable instances. Furthermore, instantiating from a specific +variable type may provide semantic information. For example, an instance from +``MotorTemperatureVariableType`` is more meaningful than a float variable +instantiated from ``BaseDataVariable``. + +ObjectNode +~~~~~~~~~~ + +Objects are used to represent systems, system components, real-world objects +and software objects. Objects are instances of an :ref:`object type` +and may contain variables, methods and further objects. + +.. _objecttypenode: + +ObjectTypeNode +~~~~~~~~~~~~~~ + +ObjectTypes provide definitions for Objects. Abstract objects cannot be +instantiated. See :ref:`node-lifecycle` for the use of constructor and +destructor callbacks. + +.. _referencetypenode: + +ReferenceTypeNode +~~~~~~~~~~~~~~~~~ + +Each reference between two nodes is typed with a ReferenceType that gives +meaning to the relation. The OPC UA standard defines a set of ReferenceTypes +as a mandatory part of OPC UA information models. + +- Abstract ReferenceTypes cannot be used in actual references and are only + used to structure the ReferenceTypes hierarchy +- Symmetric references have the same meaning from the perspective of the + source and target node + +The figure below shows the hierarchy of the standard ReferenceTypes (arrows +indicate a ``hasSubType`` relation). Refer to Part 3 of the OPC UA +specification for the full semantics of each ReferenceType. + +.. graphviz:: + + digraph tree { + + node [height=0, shape=box, fillcolor="#E5E5E5", concentrate=true] + + references [label="References\n(Abstract, Symmetric)"] + hierarchical_references [label="HierarchicalReferences\n(Abstract)"] + references -> hierarchical_references + + nonhierarchical_references [label="NonHierarchicalReferences\n(Abstract, Symmetric)"] + references -> nonhierarchical_references + + haschild [label="HasChild\n(Abstract)"] + hierarchical_references -> haschild + + aggregates [label="Aggregates\n(Abstract)"] + haschild -> aggregates + + organizes [label="Organizes"] + hierarchical_references -> organizes + + hascomponent [label="HasComponent"] + aggregates -> hascomponent + + hasorderedcomponent [label="HasOrderedComponent"] + hascomponent -> hasorderedcomponent + + hasproperty [label="HasProperty"] + aggregates -> hasproperty + + hassubtype [label="HasSubtype"] + haschild -> hassubtype + + hasmodellingrule [label="HasModellingRule"] + nonhierarchical_references -> hasmodellingrule + + hastypedefinition [label="HasTypeDefinition"] + nonhierarchical_references -> hastypedefinition + + hasencoding [label="HasEncoding"] + nonhierarchical_references -> hasencoding + + hasdescription [label="HasDescription"] + nonhierarchical_references -> hasdescription + + haseventsource [label="HasEventSource"] + hierarchical_references -> haseventsource + + hasnotifier [label="HasNotifier"] + hierarchical_references -> hasnotifier + + generatesevent [label="GeneratesEvent"] + nonhierarchical_references -> generatesevent + + alwaysgeneratesevent [label="AlwaysGeneratesEvent"] + generatesevent -> alwaysgeneratesevent + + {rank=same hierarchical_references nonhierarchical_references} + {rank=same generatesevent haseventsource hasmodellingrule + hasencoding hassubtype} + {rank=same alwaysgeneratesevent hasproperty} + + } + +The ReferenceType hierarchy can be extended with user-defined ReferenceTypes. +Many Companion Specifications for OPC UA define new ReferenceTypes to be used +in their domain of interest. + +For the following example of custom ReferenceTypes, we attempt to model the +structure of a technical system. For this, we introduce two custom +ReferenceTypes. First, the hierarchical ``contains`` ReferenceType indicates +that a system (represented by an OPC UA object) contains a component (or +subsystem). This gives rise to a tree-structure of containment relations. For +example, the motor (object) is contained in the car and the crankshaft is +contained in the motor. Second, the symmetric ``connectedTo`` ReferenceType +indicates that two components are connected. For example, the motor's +crankshaft is connected to the gear box. Connections are independent of the +containment hierarchy and can induce a general graph-structure. Further +subtypes of ``connectedTo`` could be used to differentiate between physical, +electrical and information related connections. A client can then learn the +layout of a (physical) system represented in an OPC UA information model +based on a common understanding of just two custom reference types. + +.. _datatypenode: + +DataTypeNode +~~~~~~~~~~~~ + +DataTypes represent simple and structured data types. DataTypes may contain +arrays. But they always describe the structure of a single instance. In +open62541, DataTypeNodes in the information model hierarchy are matched to +``UA_DataType`` type descriptions for :ref:`generic-types` via their NodeId. + +Abstract DataTypes (e.g. ``Number``) cannot be the type of actual values. +They are used to constrain values to possible child DataTypes (e.g. +``UInt32``). + +.. _methodnode: + +MethodNode +~~~~~~~~~~ + +Methods define callable functions and are invoked using the :ref:`Call ` +service. MethodNodes may have special properties (variable +children with a ``hasProperty`` reference) with the :ref:`qualifiedname` ``(0, "InputArguments")`` +and ``(0, "OutputArguments")``. The input and output +arguments are both described via an array of ``UA_Argument``. While the Call +service uses a generic array of :ref:`variant` for input and output, the +actual argument values are checked to match the signature of the MethodNode. + +Note that the same MethodNode may be referenced from several objects (and +object types). For this, the NodeId of the method *and of the object +providing context* is part of a Call request message. + +ViewNode +~~~~~~~~ + +Each View defines a subset of the Nodes in the AddressSpace. Views can be +used when browsing an information model to focus on a subset of nodes and +references only. ViewNodes can be created and be interacted with. But their +use in the :ref:`Browse` service is currently unsupported in +open62541. diff --git a/static/doc/v1.4.0/_sources/index.rst.txt b/static/doc/v1.4.0/_sources/index.rst.txt new file mode 100644 index 0000000000..94cb3b0f0b --- /dev/null +++ b/static/doc/v1.4.0/_sources/index.rst.txt @@ -0,0 +1,114 @@ +Introduction +============ + +open62541 (http://open62541.org) is an open source and free implementation of +OPC UA (OPC Unified Architecture) written in the common subset of the C99 and +C++98 languages. The library is usable with all major compilers and provides the +necessary tools to implement dedicated OPC UA clients and servers, or to +integrate OPC UA-based communication into existing applications. open62541 +library is platform independent. All platform-specific functionality is +implemented via exchangeable plugins. Plugin implementations are provided for +the major operating systems. + +open62541 is licensed under the Mozilla Public License v2.0 (MPLv2). This allows +the open62541 library to be combined and distributed with any proprietary +software. Only changes to the open62541 library itself need to be licensed under +the MPLv2 when copied and distributed. The plugins, as well as the server and +client examples are in the public domain (CC0 license). They can be reused under +any license and changes do not have to be published. + +The sample server (server_ctt) built using open62541 v1.0 is in conformance with +the 'Micro Embedded Device Server' Profile of OPC Foundation supporting OPC UA +client/server communication, subscriptions, method calls and security +(encryption) with the security policies 'Basic128Rsa15', 'Basic256' and +'Basic256Sha256' and the facets 'method server' and 'node management'. See +https://open62541.org/certified-sdk for more details. + +OPC Unified Architecture +------------------------ + +`OPC UA `_ is a protocol +for industrial communication and has been standardized in the IEC 62541 series. +At its core, OPC UA defines + +- an asynchronous :ref:`protocol` (built upon TCP, HTTP or SOAP) that + defines the exchange of messages via sessions, (on top of) secure + communication channels, (on top of) raw connections, +- a :ref:`type system` for protocol messages with a binary and XML-based + encoding scheme, +- a meta-model for :ref:`information modeling`, that + combines object-orientation with semantic triple-relations, and +- a set of 37 standard :ref:`services` to interact with server-side + information models. The signature of each service is defined as a request and + response message in the protocol type system. + +The standard itself can be purchased from IEC or downloaded for free on the +website of the OPC Foundation at https://opcfoundation.org/ (you need to +register with a valid email). + +The OPC Foundation drives the continuous improvement of the standard and the +development of companion specifications. Companion specifications translate +established concepts and reusable components from an application domain into OPC +UA. They are created jointly with an established industry council or +standardization body from the application domain. Furthermore, the OPC +Foundation organizes events for the dissemination of the standard and provides +the infrastructure and tools for compliance certification. + +open62541 Features +------------------ + +open62541 implements the OPC UA binary protocol stack as well as a client and +server SDK. It currently supports the Micro Embedded Device Server Profile plus +some additional features. Server binaries can be well under 100kb in size, +depending on the contained information model. + +- Communication Stack + + - OPC UA binary protocol + - Chunking (splitting of large messages) + - Exchangeable network layer (plugin) for using custom networking APIs (e.g. on embedded targets) + - Encrypted communication + - Asynchronous service requests in the client + +- Information model + + - Support for all OPC UA node types (including method nodes) + - Support for adding and removing nodes and references also at runtime. + - Support for inheritance and instantiation of object- and variable-types (custom constructor/destructor, instantiation of child nodes) + - Access control for individual nodes + +- Subscriptions + + - Support for subscriptions/monitoreditems for data change notifications + - Very low resource consumption for each monitored value (event-based server architecture) + +- Code-Generation + + - Support for generating data types from standard XML definitions + - Support for generating server-side information models (nodesets) from standard XML definitions + +Features on the roadmap for the 0.3 release series but missing in the initial v0.3 release are: + +- Encrypted communication in the client +- Events (notifications emitted by objects, data change notifications are implemented) +- Event-loop (background tasks) in the client + +Getting Help +------------ + +For discussion and help besides this documentation, you can reach the open62541 community via + +- the `mailing list `_ +- our `IRC channel `_ +- the `bugtracker `_ + +Contributing +------------ + +As an open source project, we invite new contributors to help improve open62541. +Issue reports, bugfixes and new features are very welcome. The following are +good starting points for new contributors: + +- `Report bugs `_ +- Improve the `documentation `_ +- Work on issues marked as `good first issue `_ diff --git a/static/doc/v1.4.0/_sources/nodeset_compiler.rst.txt b/static/doc/v1.4.0/_sources/nodeset_compiler.rst.txt new file mode 100644 index 0000000000..9cf7712cc4 --- /dev/null +++ b/static/doc/v1.4.0/_sources/nodeset_compiler.rst.txt @@ -0,0 +1,520 @@ +XML Nodeset Compiler +-------------------- + +When writing an application, it is more comfortable to create information models using some GUI tools. Most tools can export data according the OPC UA Nodeset XML schema. open62541 contains a Python based nodeset compiler that can transform these information model definitions into a working server. + +Note that the nodeset compiler you can find in the *tools/nodeset_compiler* subfolder is *not* an XML transformation tool but a compiler. That means that it will create an internal representation when parsing the XML files and attempt to understand and verify the correctness of this representation in order to generate C Code. + +Getting started +............... + +We take the following information model snippet as the starting point of the following tutorial. A more detailed tutorial on how to create your own information model and NodeSet2.xml can be found in this blog post: https://opcua.rocks/custom-information-models/ + +.. code-block:: xml + + + + http://yourorganisation.org/example_nodeset/ + + + i=1 + i=7 + i=12 + i=37 + i=40 + i=45 + i=46 + i=47 + i=296 + + + + + + + + providesInputTo + + + i=33 + + + inputProcidedBy + + + FieldDevice + + + i=58 + + ns=1;i=6001 + ns=1;i=6002 + + + + ManufacturerName + + i=63 + i=78 + + ns=1;i=1001 + + + + + ModelName + + i=63 + i=78 + + ns=1;i=1001 + + + + + Pump + + ns=1;i=6003 + ns=1;i=6004 + + ns=1;i=1001 + + ns=1;i=7001 + ns=1;i=7002 + + + + isOn + + i=63 + i=78 + + ns=1;i=1002 + + + + + MotorRPM + + i=63 + i=78 + + ns=1;i=1002 + + + + + startPump + + i=78 + ns=1;i=6005 + + ns=1;i=1002 + + + + + OutputArguments + + i=78 + ns=1;i=7001 + i=68 + + + + + + i=297 + + + + started + + i=1 + + -1 + + + + + + + + + + stopPump + + i=78 + ns=1;i=6006 + ns=1;i=1002 + + + + OutputArguments + + i=78 + + ns=1;i=7002 + + i=68 + + + + + + i=297 + + + + stopped + + i=1 + + -1 + + + + + + + + + + +Take the previous snippet and save it to a file ``myNS.xml``. To compile this nodeset into the corresponding C code, which can then be used by the open62541 stack, the nodeset compiler needs some arguments when you call it. The output of the help command gives you the following info: + +.. code-block:: bash + + $ python ./nodeset_compiler.py -h + usage: nodeset_compiler.py [-h] [-e ] [-x ] + [--internal-headers] + [-b ] [-i ] + [-t ] + [-v] + + + positional arguments: + The path/basename for the .c and .h files to be generated. This will also be the + function name used in the header and c-file. + + optional arguments: + -h, --help show this help message and exit + -e , --existing + NodeSet XML files with nodes that are already present + on the server. + -x , --xml + NodeSet XML files with nodes that shall be generated. + --internal-headers Include internal headers instead of amalgamated header + -b , --blacklist + Loads a list of NodeIDs stored in blacklistFile (one + NodeID per line). Any of the nodeIds encountered in + this file will be removed from the nodeset prior to + compilation. Any references to these nodes will also + be removed + -i , --ignore + Loads a list of NodeIDs stored in ignoreFile (one + NodeID per line). Any of the nodeIds encountered in + this file will be kept in the nodestore but not + printed in the generated code + -t , --types-array + Types array for the given namespace. Can be used + mutliple times to define (in the same order as the + .xml files, first for --existing, then --xml) the type + arrays + --max-string-length MAX_STRING_LENGTH + Maximum allowed length of a string literal. If longer, + it will be set to an empty string + -v, --verbose Make the script more verbose. Can be applied up to 4 + times + +So the resulting call looks like this: + +.. code-block:: bash + + $ python ./nodeset_compiler.py --types-array=UA_TYPES --existing ../../deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml --xml myNS.xml myNS + +And the output of the command: + +.. code-block:: bash + + INFO:__main__:Preprocessing (existing) ../../deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml + INFO:__main__:Preprocessing myNS.xml + INFO:__main__:Generating Code + INFO:__main__:NodeSet generation code successfully printed + +The first argument ``--types-array=UA_TYPES`` defines the name of the global array in open62541 which contains the corresponding types used within the nodeset in ``NodeSet2.xml``. If you do not define your own datatypes, you can always use the ``UA_TYPES`` value. More on that later in this tutorial. +The next argument ``--existing ../../deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml`` points to the XML definition of the standard-defined namespace 0 (NS0). Namespace 0 is assumed to be loaded beforehand and provides definitions for data type, reference types, and so. Since we reference nodes from NS0 in our myNS.xml we need to tell the nodeset compiler that it should also load that nodeset, but not compile it into the output. +Note that you may need to initialize the git submodule to get the ``deps/ua-nodeset`` folder (``git submodule update --init``) or download the full ``NodeSet2.xml`` manually. +The argument ``--xml myNS.xml`` points to the user-defined information model, whose nodes will be added to the abstract syntax tree. The script will then create the files ``myNS.c`` and ``myNS.h`` (indicated by the last argument ``myNS``) containing the C code necessary to instantiate those namespaces. + +Although it is possible to run the compiler this way, it is highly discouraged. If you care to examine the CMakeLists.txt (examples/nodeset/CMakeLists.txt), you will find out that the file ``server_nodeset.xml`` is compiled using the following function:: + + ua_generate_nodeset( + NAME "example" + FILE "${PROJECT_SOURCE_DIR}/examples/nodeset/server_nodeset.xml" + DEPENDS_TYPES "UA_TYPES" + DEPENDS_NS "${UA_FILE_NS0}" + ) + +If you look into the files generated by the nodeset compiler, you will see that it generated a method called ``extern UA_StatusCode myNS(UA_Server *server);``. You need to include the header and source file and then call the ``myNS(server)`` method right after creating the server instance with ``UA_Server_new``. This will automatically add all the nodes to the server and return ``UA_STATUSCODE_GOOD`` if there weren't any errors. Additionally you need to compile the open62541 stack with the full NS0 by setting ``UA_NAMESPACE_ZERO=FULL`` in CMake. Otherwise the stack uses a subset where many nodes are not included and thus adding a custom nodeset may fail. + +This is how you can use the nodeset compiler to compile simple NodeSet XMLs to be used by the open62541 stack. + +For your convenience and for simpler use we also provide a CMake function which simplifies the use of the ``ua_generate_datatypes`` and ``ua_generate_nodeset`` function even more. +It is highly recommended to use this function: ``ua_generate_nodeset_and_datatypes``. It uses some best practice settings and you only need to pass a name and the nodeset files. +Passing the .csv and .bsd files is optional and if not given, generating datatypes for that noteset will be skipped. You can also define dependencies between nodesets using the ``DEPENDS`` argument. + +Here are some examples for the ``DI`` and ``PLCOpen`` nodesets:: + + # Generate types and namespace for DI + ua_generate_nodeset_and_datatypes( + NAME "di" + FILE_CSV "${UA_NODESET_DIR}/DI/Opc.Ua.Di.NodeIds.csv" + FILE_BSD "${UA_NODESET_DIR}/DI/Opc.Ua.Di.Types.bsd" + FILE_NS "${UA_NODESET_DIR}/DI/Opc.Ua.Di.NodeSet2.xml" + ) + + # generate PLCopen namespace which is using DI + ua_generate_nodeset_and_datatypes( + NAME "plc" + # PLCopen does not define custom types. Only generate the nodeset + FILE_NS "${UA_NODESET_DIR}/PLCopen/Opc.Ua.PLCopen.NodeSet2_V1.02.xml" + # PLCopen depends on the di nodeset, which must be generated before + DEPENDS "di" + ) + +Creating object instances +......................... + +One of the key benefits of defining object types is being able to create object instances fairly easily. Object instantiation is handled automatically when the typedefinition NodeId points to a valid ObjectType node. All Attributes and Methods contained in the objectType definition will be instantiated along with the object node. + +While variables are copied from the objectType definition (allowing the user for example to attach new dataSources to them), methods are always only linked. This paradigm is identical to languages like C++: The method called is always the same piece of code, but the first argument is a pointer to an object. Likewise, in OPC UA, only one methodCallback can be attached to a specific methodNode. If that methodNode is called, the parent objectId will be passed to the method - it is the methods job to derefence which object instance it belongs to in that moment. + +Let's look at an example that will create a pump instance given the newly defined objectType from myNS.xml: + +.. code-block:: c + + /* This work is licensed under a Creative Commons CCZero 1.0 Universal License. + * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */ + + #include + #include + #include "open62541.h" + + /* Files myNS.h and myNS.c are created from myNS.xml */ + #include "myNS.h" + + UA_Boolean running = true; + + static void stopHandler(int sign) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c"); + running = false; + } + + int main(int argc, char **argv) { + signal(SIGINT, stopHandler); + signal(SIGTERM, stopHandler); + + UA_Server *server = UA_Server_new(); + UA_ServerConfig_setDefault(UA_Server_getConfig(server)); + + UA_StatusCode retval = myNS(server); + /* Create nodes from nodeset */ + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Could not add the example nodeset. " + "Check previous output for any error."); + retval = UA_STATUSCODE_BADUNEXPECTEDERROR; + } else { + UA_NodeId createdNodeId; + UA_ObjectAttributes object_attr = UA_ObjectAttributes_default; + + object_attr.description = UA_LOCALIZEDTEXT("en-US", "A pump!"); + object_attr.displayName = UA_LOCALIZEDTEXT("en-US", "Pump1"); + + // we assume that the myNS nodeset was added in namespace 2. + // You should always use UA_Server_addNamespace to check what the + // namespace index is for a given namespace URI. UA_Server_addNamespace + // will just return the index if it is already added. + UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0), + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), + UA_QUALIFIEDNAME(1, "Pump1"), + UA_NODEID_NUMERIC(2, 1002), + object_attr, NULL, &createdNodeId); + + + retval = UA_Server_run(server, &running); + } + + UA_Server_delete(server); + return (int) retval; + } + +Make sure you have updated the headers and libs in your project, then recompile and run the server. Make especially sure you have added ``myNS.h`` to your include folder. + +As you can see instantiating an object is not much different from creating an object node. The main difference is that you *must* use an objectType node as typeDefinition. + +If you start the server and inspect the nodes with UA Expert, you will find the pump in the objects folder, which look like this :numref:`nodeset-compiler-pump`. + +.. _nodeset-compiler-pump: + +.. figure:: nodeset_compiler_pump.png + :alt: Instantiated Pump Object with inherited children + + Instantiated Pump Object with inherited children + +As you can see the pump has inherited its parents attributes (ManufacturerName and ModelName). Methods, in contrast to objects and variables, are never cloned but instead only linked. The reason is that you will quite propably attach a method callback to a central method, not each object. Objects are instantiated if they are *below* the object you are creating, so any object (like an object called associatedServer of ServerType) that is part of pump will be instantiated as well. Objects *above* you object are never instantiated, so the same ServerType object in Fielddevices would have been omitted (the reason is that the recursive instantiation function protects itself from infinite recursions, which are hard to track when first ascending, then redescending into a tree). + + +Combination of multiple nodesets +................................ + +In the previous section you have seen how you can use the nodeset compiler with one single nodeset which depends on the default nodeset (NS0) ``Opc.Ua.NodeSet2.xml``. The nodeset compiler also supports nodesets which depend on more than one nodeset. We will show this use-case with the PLCopen nodeset. The PLCopen nodeset ``Opc.Ua.PLCopen.NodeSet2_V1.02.xml`` depends on the DI nodeset ``Opc.Ua.Di.NodeSet2.xml`` which then depends on NS0. This example is also shown in ``examples/nodeset/CMakeLists.txt``. + +This DI nodeset makes use of some additional data types in ``deps/ua-nodeset/DI/Opc.Ua.Di.Types.bsd``. Since we also need these types within the generated code, we first need to compile the types into C code. The generated code is mainly a definition of the binary representation of the types required for encoding and decoding. The generation can be done using the ``ua_generate_datatypes`` CMake function, which uses the ``tools/generate_datatypes.py`` script:: + + ua_generate_datatypes( + NAME "ua_types_di" + TARGET_SUFFIX "types-di" + FILE_CSV "${UA_NODESET_DIR}/DI/Opc.Ua.Di.NodeIds.csv" + FILES_BSD "${UA_NODESET_DIR}/DI/Opc.Ua.Di.Types.bsd" + ) + +The ``NAMESPACE_MAP`` parameter is an array of strings which indicates the mapping of specific namespace uris to the resulting namespace index. +This mapping is required for correct mapping of DataType nodes and their node ids. Currently we need to rely that the namespace is also added at this position in the final server. There is no automatic inferring yet (pull requests are warmly welcome). +If you are using the `DEPENDS` option on the ``ua_generate_nodeset_and_datatypes``, the ``NAMESPACE_MAP`` is also inherited and you do not need to pass all mappings for dependent types. +The CSV and BSD files contain the metadata and definition for the types. ``TARGET_SUFFIX`` is used to create a new target with the name ``open62541-generator-TARGET_SUFFIX``. + +**The ``NAMESPACE_MAP`` parameter is deprecated and no longer has any effect. The index of the nodeset is set automatically when it is loaded.** + +Now you can compile the DI nodeset XML using the following command:: + + ua_generate_nodeset( + NAME "di" + FILE "${UA_NODESET_DIR}/DI/Opc.Ua.Di.NodeSet2.xml" + TYPES_ARRAY "UA_TYPES_DI" + INTERNAL + DEPENDS_TYPES "UA_TYPES" + DEPENDS_NS "${UA_NODESET_DIR}/Schema/Opc.Ua.NodeSet2.xml" + DEPENDS_TARGET "open62541-generator-types-di" + ) + +There are now two new arguments: ``INTERNAL`` indicates that internal headers (and non public API) should be included within the generated source code. This is currently required for nodesets which use structures as data values, and will probably be fixed in the future. +The ``DEPENDS_TYPES`` types array argument is matched with the nodesets in the same order as they appear on the ``DEPENDS_TARGET`` parameter. It tells the nodeset compiler which types array it should use: ``UA_TYPES`` for ``Opc.Ua.NodeSet2.xml`` and ``UA_TYPES_DI`` for ``Opc.Ua.Di.NodeSet2.xml``. This is the type array generated by the ``generate_datatypes.py`` script. The rest is similar to the example in previous section: ``Opc.Ua.NodeSet2.xml`` is assumed to exist already and only needs to be loaded for consistency checks, ``Opc.Ua.Di.NodeSet2.xml`` will be generated in the output file ``ua_namespace_di.c/.h`` + +Next we can generate the PLCopen nodeset. Since it doesn't require any additional datatype definitions, we can immediately start with the nodeset compiler command:: + + ua_generate_nodeset( + NAME "plc" + FILE "${UA_NODESET_DIR}/PLCopen/Opc.Ua.PLCopen.NodeSet2_V1.02.xml" + INTERNAL + DEPENDS_TYPES + "UA_TYPES" "UA_TYPES_DI" + DEPENDS_NS + "${UA_NODESET_DIR}/Schema/Opc.Ua.NodeSet2.xml" + "${UA_NODESET_DIR}/DI/Opc.Ua.Di.NodeSet2.xml" + DEPENDS_TARGET "open62541-generator-ns-di" + ) + +This call is quite similar to the compilation of the DI nodeset. As you can see, we do not define any specific types array for the PLCopen nodeset. Since the PLCopen nodeset depends on the NS0 and DI nodeset, we need to tell the nodeset compiler that these two nodesets should be seen as already existing. Make sure that the order is the same as in your XML file, e.g., in this case the order indicated in ``Opc.Ua.PLCopen.NodeSet2_V1.02.xml -> UANodeSet -> Models -> Model``. + +As a result of the previous scripts you will have multiple source files: + +* ua_types_di_generated.c +* ua_types_di_generated.h +* ua_types_di_generated_encoding_binary.h +* ua_types_di_generated_handling.h +* ua_namespace_di.c +* ua_namespace_di.h +* ua_namespace_plc.c +* ua_namespace_plc.h + +Finally you need to include all these files in your build process and call the corresponding initialization methods for the nodesets. An example application could look like this: + +.. code-block:: c + + UA_Server *server = UA_Server_new(); + UA_ServerConfig_setDefault(UA_Server_getConfig(server)); + + /* Create nodes from nodeset */ + UA_StatusCode retval = ua_namespace_di(server); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Adding the DI namespace failed. Please check previous error output."); + UA_Server_delete(server); + return (int)UA_STATUSCODE_BADUNEXPECTEDERROR; + } + + retval |= ua_namespace_plc(server); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Adding the PLCopen namespace failed. Please check previous error output."); + UA_Server_delete(server); + return (int)UA_STATUSCODE_BADUNEXPECTEDERROR; + } + + retval = UA_Server_run(server, &running); + +Outstanding Companion Spec Issues +................................. + +There are some Companion Specifications that currently cannot be compiled with the Nodeset compiler. +Which Companion Specifications are affected and what causes this is described below. + +Safety, Glass, DEXPI + Do not specify a BSD file or BSD blob in the XML file. The BSD file is considered deprecated. However, it is currently still required by the Nodeser compiler. + +I4AAS, RSL, FDI + Attempting to load will result in a runtime error ("Type-checking failed with error code BadTypeMismatch" or "Parent node not found"). + +BACnet + Defines data types whose fields have the names signed or unsigned. This leads to errors when creating C structures, because signed and unsigned are keywords in C. + +Automatic Nodesetinjection +.......................... + +The nodesetinjector is a mechanism for automatically loading nodeset/companion specifications during server initialization. +It provides a fast and easy way to load nodesets in all applications, focusing on the official OPCFoundation/UANodeset Repository ( https://github.com/OPCFoundation/UA-Nodeset ). +Specify the required information models using CMake. + +Which nodesets are to be loaded is determined by the Cmake flag ``DUA_INFORMATION_MODEL_AUTOLOAD``. All nodesets that are to be loaded automatically are listed here. +The naming is based on the folder name of the Companion Specification in the ua-nodeset folder. + +A CMake call could look like this. + +.. code-block:: bash + + -DCMAKE_BUILD_TYPE=Debug + -DUA_BUILD_EXAMPLES=ON + -DUA_INFORMATION_MODEL_AUTOLOAD=DI;POWERLINK;PROFINET;MachineVision + -DUA_NAMESPACE_ZERO=FULL + +The order of nodesets is important! Nodesets that build on other nodesets must be placed after them in the list. +The following nodesets are currently supported: + +DI, CNC, ISA95-JOBCONTROL, OpenSCS, AMB, AutoID, POWERLINK, IA, Machinery, +PackML, PNEM, PLCopen, MachineTool, PROFINET, MachineVision, FDT, +CommercialKitchenEquipment, PNRIO, Scales, Weihenstephan, Pumps, CAS, TMC, IJT diff --git a/static/doc/v1.4.0/_sources/plugin.rst.txt b/static/doc/v1.4.0/_sources/plugin.rst.txt new file mode 100644 index 0000000000..ee086658b5 --- /dev/null +++ b/static/doc/v1.4.0/_sources/plugin.rst.txt @@ -0,0 +1,11 @@ +Plugin API +========== + +.. toctree:: + + plugin_log + plugin_nodestore + plugin_accesscontrol + plugin_eventloop + plugin_pki + plugin_securitypolicy diff --git a/static/doc/v1.4.0/_sources/plugin_accesscontrol.rst.txt b/static/doc/v1.4.0/_sources/plugin_accesscontrol.rst.txt new file mode 100644 index 0000000000..97da2a7749 --- /dev/null +++ b/static/doc/v1.4.0/_sources/plugin_accesscontrol.rst.txt @@ -0,0 +1,114 @@ +.. _access-control: + +Access Control Plugin API +========================= +The access control callback is used to authenticate sessions and grant access +rights accordingly. + +The ``sessionId`` and ``sessionContext`` can be both NULL. This is the case +when, for example, a MonitoredItem (the underlying Subscription) is detached +from its Session but continues to run. + +.. code-block:: c + + + struct UA_AccessControl { + void *context; + void (*clear)(UA_AccessControl *ac); + + /* Supported login mechanisms. The server endpoints are created from here. */ + size_t userTokenPoliciesSize; + UA_UserTokenPolicy *userTokenPolicies; + + /* Authenticate a session. The session context is attached to the session + * and later passed into the node-based access control callbacks. The new + * session is rejected if a StatusCode other than UA_STATUSCODE_GOOD is + * returned. + * + * Note that this callback can be called several times for a Session. For + * example when a Session is recovered (activated) on a new + * SecureChannel. */ + UA_StatusCode (*activateSession)(UA_Server *server, UA_AccessControl *ac, + const UA_EndpointDescription *endpointDescription, + const UA_ByteString *secureChannelRemoteCertificate, + const UA_NodeId *sessionId, + const UA_ExtensionObject *userIdentityToken, + void **sessionContext); + + /* Deauthenticate a session and cleanup */ + void (*closeSession)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext); + + /* Access control for all nodes*/ + UA_UInt32 (*getUserRightsMask)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext); + + /* Additional access control for variable nodes */ + UA_Byte (*getUserAccessLevel)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext); + + /* Additional access control for method nodes */ + UA_Boolean (*getUserExecutable)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *methodId, void *methodContext); + + /* Additional access control for calling a method node in the context of a + * specific object */ + UA_Boolean (*getUserExecutableOnObject)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *methodId, void *methodContext, + const UA_NodeId *objectId, void *objectContext); + + /* Allow adding a node */ + UA_Boolean (*allowAddNode)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_AddNodesItem *item); + + /* Allow adding a reference */ + UA_Boolean (*allowAddReference)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_AddReferencesItem *item); + + /* Allow deleting a node */ + UA_Boolean (*allowDeleteNode)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_DeleteNodesItem *item); + + /* Allow deleting a reference */ + UA_Boolean (*allowDeleteReference)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_DeleteReferencesItem *item); + + /* Allow browsing a node */ + UA_Boolean (*allowBrowseNode)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext); + + #ifdef UA_ENABLE_SUBSCRIPTIONS + /* Allow transfer of a subscription to another session. The Server shall + * validate that the Client of that Session is operating on behalf of the + * same user */ + UA_Boolean (*allowTransferSubscription)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *oldSessionId, void *oldSessionContext, + const UA_NodeId *newSessionId, void *newSessionContext); + #endif + + #ifdef UA_ENABLE_HISTORIZING + /* Allow insert,replace,update of historical data */ + UA_Boolean (*allowHistoryUpdateUpdateData)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, + UA_PerformUpdateType performInsertReplace, + const UA_DataValue *value); + + /* Allow delete of historical data */ + UA_Boolean (*allowHistoryUpdateDeleteRawModified)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, + UA_DateTime startTimestamp, + UA_DateTime endTimestamp, + bool isDeleteModified); + #endif + }; diff --git a/static/doc/v1.4.0/_sources/plugin_eventloop.rst.txt b/static/doc/v1.4.0/_sources/plugin_eventloop.rst.txt new file mode 100644 index 0000000000..cfed09a48b --- /dev/null +++ b/static/doc/v1.4.0/_sources/plugin_eventloop.rst.txt @@ -0,0 +1,663 @@ +Event Loop Subsystem +==================== +An OPC UA-enabled application can have several clients and servers. And +server can serve different transport-level protocols for OPC UA. The +EventLoop is a central module that provides a unified control-flow for all of +these. Hence, several applications can share an EventLoop. + +The EventLoop and the ConnectionManager implementation is +architecture-specific. The goal is to have a single call to "poll" (epoll, +kqueue, ...) in the EventLoop that covers all ConnectionManagers. Hence the +EventLoop plugin implementation must know implementation details of the +ConnectionManager implementations. So the EventLoop can extract socket +information, etc. from the ConnectionManagers. + +Timer Policies +-------------- +A timer comes with a cyclic interval in which a callback is executed. If an +application is congested the interval can be missed. Two different policies +can be used when this happens. Either schedule the next execution after the +interval has elapsed again from the current time onwards or stay within the +regular interval with respect to the original basetime. + +.. code-block:: c + + + typedef enum { + UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME, + UA_TIMER_HANDLE_CYCLEMISS_WITH_BASETIME + } UA_TimerPolicy; + +Event Loop +---------- +The EventLoop implementation is part of the selected architecture. For +example, "Win32/POSIX" stands for a Windows environment with an EventLoop +that uses the POSIX API. Several EventLoops can be instantiated in parallel. +But the globally defined functions are the same everywhere. + +.. code-block:: c + + + typedef void (*UA_Callback)(void *application, void *context); + + /* Delayed callbacks are executed not when they are registered, but in the + * following EventLoop cycle */ + typedef struct UA_DelayedCallback { + struct UA_DelayedCallback *next; /* Singly-linked list */ + UA_Callback callback; + void *application; + void *context; + } UA_DelayedCallback; + + typedef enum { + UA_EVENTLOOPSTATE_FRESH = 0, + UA_EVENTLOOPSTATE_STOPPED, + UA_EVENTLOOPSTATE_STARTED, + UA_EVENTLOOPSTATE_STOPPING /* Stopping in progress, needs EventLoop + * cycles to finish */ + } UA_EventLoopState; + + struct UA_EventLoop { + /* Configuration + * ~~~~~~~~~~~~~~~ + * The configuration should be set before the EventLoop is started */ + + const UA_Logger *logger; + UA_KeyValueMap *params; /* See the implementation-specific documentation */ + + /* EventLoop Lifecycle + * ~~~~~~~~~~~~~~~~~~~~ + * The EventLoop state also controls the state of the configured + * EventSources. Stopping the EventLoop gracefully closes e.g. the open + * network connections. The only way to process incoming events is to call + * the 'run' method. Events are then triggering their respective callbacks + * from within that method.*/ + + const volatile UA_EventLoopState state; /* Only read the state from outside */ + + /* Start the EventLoop and start all already registered EventSources */ + UA_StatusCode (*start)(UA_EventLoop *el); + + /* Stop all EventSources. This is asynchronous and might need a few + * iterations of the main-loop to succeed. */ + void (*stop)(UA_EventLoop *el); + + /* Process events for at most "timeout" ms or until an unrecoverable error + * occurs. If timeout==0, then only already received events are + * processed. */ + UA_StatusCode (*run)(UA_EventLoop *el, UA_UInt32 timeout); + + /* Clean up the EventLoop and free allocated memory. Can fail if the + * EventLoop is not stopped. */ + UA_StatusCode (*free)(UA_EventLoop *el); + + /* EventLoop Time Domain + * ~~~~~~~~~~~~~~~~~~~~~ + * Each EventLoop instance can manage its own time domain. This affects the + * execution of timed/cyclic callbacks and time-based sending of network + * packets (if this is implemented). Managing independent time domains is + * important when different parts of a system a synchronized to different + * external (network-wide) clocks. + * + * Note that the logger configured in the EventLoop generates timestamps + * internally as well. If the logger uses a different time domain than the + * EventLoop, discrepancies may appear in the logs. + * + * The time domain of the EventLoop is exposed via the following functons. + * See `open62541/types.h` for the documentation of their equivalent + * globally defined functions. */ + + UA_DateTime (*dateTime_now)(UA_EventLoop *el); + UA_DateTime (*dateTime_nowMonotonic)(UA_EventLoop *el); + UA_Int64 (*dateTime_localTimeUtcOffset)(UA_EventLoop *el); + + /* Timed Callbacks + * ~~~~~~~~~~~~~~~ + * Cyclic callbacks are executed regularly with an interval. + * A timed callback is executed only once. */ + + /* Time of the next cyclic callback. Returns the max DateTime if no cyclic + * callback is registered. */ + UA_DateTime (*nextCyclicTime)(UA_EventLoop *el); + + /* The execution interval is in ms. Returns the callbackId if the pointer is + * non-NULL. */ + UA_StatusCode + (*addCyclicCallback)(UA_EventLoop *el, UA_Callback cb, void *application, + void *data, UA_Double interval_ms, UA_DateTime *baseTime, + UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId); + + UA_StatusCode + (*modifyCyclicCallback)(UA_EventLoop *el, UA_UInt64 callbackId, + UA_Double interval_ms, UA_DateTime *baseTime, + UA_TimerPolicy timerPolicy); + + void (*removeCyclicCallback)(UA_EventLoop *el, UA_UInt64 callbackId); + + /* Like a cyclic callback, but executed only once */ + UA_StatusCode + (*addTimedCallback)(UA_EventLoop *el, UA_Callback cb, void *application, + void *data, UA_DateTime date, UA_UInt64 *callbackId); + + /* Delayed Callbacks + * ~~~~~~~~~~~~~~~~~ + * Delayed callbacks are executed once in the next iteration of the + * EventLoop and then deregistered automatically. A typical use case is to + * delay a resource cleanup to a point where it is known that the resource + * has no remaining users. + * + * The delayed callbacks are processed in each of the cycle of the EventLoop + * between the handling of timed cyclic callbacks and polling for (network) + * events. The memory for the delayed callback is *NOT* automatically freed + * after the execution. */ + + void (*addDelayedCallback)(UA_EventLoop *el, UA_DelayedCallback *dc); + void (*removeDelayedCallback)(UA_EventLoop *el, UA_DelayedCallback *dc); + + /* EventSources + * ~~~~~~~~~~~~ + * EventSources are stored in a singly-linked list for direct access. But + * only the below methods shall be used for adding and removing - this + * impacts the lifecycle of the EventSource. For example it may be + * auto-started if the EventLoop is already running. */ + + /* Linked list of EventSources */ + UA_EventSource *eventSources; + + /* Register the ES. Immediately starts the ES if the EventLoop is already + * started. Otherwise the ES is started together with the EventLoop. */ + UA_StatusCode + (*registerEventSource)(UA_EventLoop *el, UA_EventSource *es); + + /* Stops the EventSource before deregistrering it */ + UA_StatusCode + (*deregisterEventSource)(UA_EventLoop *el, UA_EventSource *es); + }; + +Event Source +------------ +Event Sources are attached to an EventLoop. Typically the event source and +the EventLoop are developed together and share a private API in the +background. + +.. code-block:: c + + + typedef enum { + UA_EVENTSOURCESTATE_FRESH = 0, + UA_EVENTSOURCESTATE_STOPPED, /* Registered but stopped */ + UA_EVENTSOURCESTATE_STARTING, + UA_EVENTSOURCESTATE_STARTED, + UA_EVENTSOURCESTATE_STOPPING /* Stopping in progress, needs + * EventLoop cycles to finish */ + } UA_EventSourceState; + + /* Type-tag for proper casting of the difference EventSource (e.g. when they are + * looked up via UA_EventLoop_findEventSource). */ + typedef enum { + UA_EVENTSOURCETYPE_CONNECTIONMANAGER, + UA_EVENTSOURCETYPE_INTERRUPTMANAGER + } UA_EventSourceType; + + struct UA_EventSource { + struct UA_EventSource *next; /* Singly-linked list for use by the + * application that registered the ES */ + + UA_EventSourceType eventSourceType; + + /* Configuration + * ~~~~~~~~~~~~~ */ + UA_String name; /* Unique name of the ES */ + UA_EventLoop *eventLoop; /* EventLoop where the ES is registered */ + UA_KeyValueMap params; + + /* Lifecycle + * ~~~~~~~~~ */ + UA_EventSourceState state; + UA_StatusCode (*start)(UA_EventSource *es); + void (*stop)(UA_EventSource *es); /* Asynchronous. Iterate theven EventLoop + * until the EventSource is stopped. */ + UA_StatusCode (*free)(UA_EventSource *es); + }; + +Connection Manager +------------------ +Every Connection is created by a ConnectionManager. Every ConnectionManager +belongs to just one application. A ConnectionManager can act purely as a +passive "Factory" for Connections. But it can also be stateful. For example, +it can keep a session to an MQTT broker open which is used by individual +connections that are each bound to an MQTT topic. + +.. code-block:: c + + + /* The ConnectionCallback is the only interface from the connection back to + * the application. + * + * - The connectionId is initially unknown to the target application and + * "announced" to the application when first used first in this callback. + * + * - The context is attached to the connection. Initially a default context + * is set. The context can be replaced within the callback (via the + * double-pointer). + * + * - The state argument indicates the lifecycle of the connection. Every + * connection calls the callback a last time with UA_CONNECTIONSTATE_CLOSING. + * Protocols individually can forward diagnostic information relevant to the + * state as part of the key-value parameters. + * + * - The parameters are a key-value list with additional information. The + * possible keys and their meaning are documented for the individual + * ConnectionManager implementations. + * + * - The msg ByteString is the message (or packet) received on the + * connection. Can be empty. */ + typedef void + (*UA_ConnectionManager_connectionCallback) + (UA_ConnectionManager *cm, uintptr_t connectionId, + void *application, void **connectionContext, UA_ConnectionState state, + const UA_KeyValueMap *params, UA_ByteString msg); + + struct UA_ConnectionManager { + /* Every ConnectionManager is treated like an EventSource from the + * perspective of the EventLoop. */ + UA_EventSource eventSource; + + /* Name of the protocol supported by the ConnectionManager. For example + * "mqtt", "udp", "mqtt". */ + UA_String protocol; + + /* Open a Connection + * ~~~~~~~~~~~~~~~~~ + * Connecting is asynchronous. The connection-callback is called when the + * connection is open (status=GOOD) or aborted (status!=GOOD) when + * connecting failed. + * + * Some ConnectionManagers can also passively listen for new connections. + * Configuration parameters for this are passed via the key-value list. The + * `context` pointer of the listening connection is also set as the initial + * context of newly opened connections. + * + * The parameters describe the connection. For example hostname and port + * (for TCP). Other protocols (e.g. MQTT, AMQP, etc.) may required + * additional arguments to open a connection in the key-value list. + * + * The provided context is set as the initial context attached to this + * connection. It is already set before the first call to + * connectionCallback. + * + * The connection can be opened synchronously or asynchronously. + * + * - For synchronous connection, the connectionCallback is called with the + * status UA_CONNECTIONSTATE_ESTABLISHED immediately from within the + * openConnection operation. + * + * - In the asynchronous case the connectionCallback is called immediately + * from within the openConnection operation with the status + * UA_CONNECTIONSTATE_OPENING. The connectionCallback is called with the + * status UA_CONNECTIONSTATE_ESTABLISHED once the connection has fully + * opened. + * + * Note that a single call to openConnection might open multiple + * connections. For example listening on IPv4 and IPv6 for a single + * hostname. Each protocol implementation documents whether multiple + * connections might be opened at once. */ + UA_StatusCode + (*openConnection)(UA_ConnectionManager *cm, const UA_KeyValueMap *params, + void *application, void *context, + UA_ConnectionManager_connectionCallback connectionCallback); + + /* Send a message over a Connection + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Sending is asynchronous. That is, the function returns before the message + * is ACKed from remote. The memory for the buffer is expected to be + * allocated with allocNetworkBuffer and is released internally (also if + * sending fails). + * + * Some ConnectionManagers can accept additional parameters for sending. For + * example a tx-time for sending in time-synchronized TSN settings. */ + UA_StatusCode + (*sendWithConnection)(UA_ConnectionManager *cm, uintptr_t connectionId, + const UA_KeyValueMap *params, UA_ByteString *buf); + + /* Close a Connection + * ~~~~~~~~~~~~~~~~~~ + * When a connection is closed its `connectionCallback` is called with + * (status=BadConnectionClosed, msg=empty). Then the connection is cleared + * up inside the ConnectionManager. This is the case both for connections + * that are actively closed and those that are closed remotely. The return + * code is non-good only if the connection is already closed. */ + UA_StatusCode + (*closeConnection)(UA_ConnectionManager *cm, uintptr_t connectionId); + + /* Buffer Management + * ~~~~~~~~~~~~~~~~~ + * Each ConnectionManager allocates and frees his own memory for the network + * buffers. This enables, for example, zero-copy neworking mechanisms. The + * connectionId is part of the API to enable cases where memory is + * statically allocated for every connection */ + UA_StatusCode + (*allocNetworkBuffer)(UA_ConnectionManager *cm, uintptr_t connectionId, + UA_ByteString *buf, size_t bufSize); + void + (*freeNetworkBuffer)(UA_ConnectionManager *cm, uintptr_t connectionId, + UA_ByteString *buf); + }; + +Interrupt Manager +----------------- +The Interrupt Manager allows to register to listen for system interrupts. +Triggering the interrupt calls the callback associated with it. + +The implementations of the interrupt manager for the different platforms +shall be designed such that: + +- Registered interrupts are only intercepted from within the running EventLoop +- Processing an interrupt in the EventLoop is handled similarly to handling a + network event: all methods and also memory allocation are available from + within the interrupt callback. + +.. code-block:: c + + + /* Interrupts can have additional key-value 'instanceInfos' for each individual + * triggering. See the architecture-specific documentation. */ + typedef void + (*UA_InterruptCallback)(UA_InterruptManager *im, + uintptr_t interruptHandle, void *interruptContext, + const UA_KeyValueMap *instanceInfos); + + struct UA_InterruptManager { + /* Every InterruptManager is treated like an EventSource from the + * perspective of the EventLoop. */ + UA_EventSource eventSource; + + /* Register an interrupt. The handle and context information is passed + * through to the callback. + * + * The interruptHandle is a numerical identifier of the interrupt. In some + * cases, such as POSIX signals, this is enough information to register + * callback. For other interrupt systems (architectures) additional + * parameters may be required and can be passed in via the parameters + * key-value list. See the implementation-specific documentation. + * + * The interruptContext is opaque user-defined information and passed + * through to the callback without modification. */ + UA_StatusCode + (*registerInterrupt)(UA_InterruptManager *im, uintptr_t interruptHandle, + const UA_KeyValueMap *params, + UA_InterruptCallback callback, void *interruptContext); + + /* Remove a registered interrupt. Returns no error code if the interrupt is + * already deregistered. */ + void + (*deregisterInterrupt)(UA_InterruptManager *im, uintptr_t interruptHandle); + }; + +POSIX-Specific Implementation +----------------------------- +The POSIX compatibility of WIN32 is 'close enough'. So a joint implementation +is provided. + +.. code-block:: c + + + #if defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) + + UA_EventLoop * + UA_EventLoop_new_POSIX(const UA_Logger *logger); + +TCP Connection Manager +~~~~~~~~~~~~~~~~~~~~~~ +Listens on the network and manages TCP connections. This should be available +for all architectures. + +The `openConnection` callback is used to create both client and server +sockets. A server socket listens and accepts incoming connections (creates an +active connection). This is distinguished by the key-value parameters passed +to `openConnection`. Note that a single call to `openConnection` for a server +connection may actually create multiple connections (one per hostname / +device). + +The `connectionCallback` of the server socket and `context` of the server +socket is reused for each new connection. But the key-value parameters for +the first callback are different between server and client connections. + +The following list defines the parameters and their type. Note that some +parameters are only set for the first callback when a new connection opens. + +**Configuration parameters for the entire ConnectionManager:** + +0:recv-bufsize [uint32] + Size of the buffer that is allocated for receiving messages (default 64kB). + +**Open Connection Parameters:** + +0:address [string | array of string] + Hostname or IPv4/v6 address for the connection (scalar parameter required + for active connections). For listen-connections the address contains the + local hostnames or IP addresses for listening. If undefined, listen on all + interfaces INADDR_ANY. (default: undefined) + +0:port [uint16] + Port of the target host (required). + +0:listen [boolean] + Listen-connection or active-connection (default: false) + +0:validate [boolean] + If true, the connection setup will act as a dry-run without actually + creating any connection but solely validating the provided parameters + (default: false) + +**Active Connection Connection Callback Parameters (first callback only):** + +0:remote-address [string] + Address of the remote side (hostname or IP address). + +**Listen Connection Connection Callback Parameters (first callback only):** + +0:listen-address [string] + Local address (IP or hostname) for the new listen-connection. + +0:listen-port [uint16] + Port on which the new connection listens. + +**Send Parameters:** + +No additional parameters for sending over an established TCP socket +defined. + +.. code-block:: c + + UA_ConnectionManager * + UA_ConnectionManager_new_POSIX_TCP(const UA_String eventSourceName); + +UDP Connection Manager +~~~~~~~~~~~~~~~~~~~~~~ +Manages UDP connections. This should be available for all architectures. The +configuration parameters have to set before calling _start to take effect. + +**Configuration Parameters:** + +0:recv-bufsize [uint32] + Size of the buffer that is allocated for receiving messages (default + 64kB). + +**Open Connection Parameters:** + +0:listen [boolean] + Use the connection for listening or for sending (default: false) + +0:address [string | string array] + Hostname (or IPv4/v6 address) for sending or receiving. A scalar is + required for sending. For listening a string array for the list-hostnames + is possible as well (default: list on all hostnames). + +0:port [uint16] + Port for sending or listening (required). + +0:interface [string] + Network interface for listening or sending (e.g. when using multicast + addresses) + +0:ttl [uint32] + Multicast time to live, (optional, default: 1 - meaning multicast is + available only to the local subnet). + +0:loopback [boolean] + Whether or not to use multicast loopback, enabling local interfaces + belonging to the multicast group to receive packages. (default: enabled). + +0:reuse [boolean] + Enables sharing of the same listening address on different sockets + (default: disabled). + +0:sockpriority [uint32] + The socket priority (optional) - only available on linux. packets with a + higher priority may be processed first depending on the selected device + queueing discipline. Setting a priority outside the range 0 to 6 requires + the CAP_NET_ADMIN capability (on Linux). + +0:validate [boolean] + If true, the connection setup will act as a dry-run without actually + creating any connection but solely validating the provided parameters + (default: false) + +**Connection Callback Paramters:** + +0:remote-address [string] + Contains the remote IP address. + +0:remote-port [uint16] + Contains the remote port. + +**Send Parameters:** + +No additional parameters for sending over an UDP connection defined. + +.. code-block:: c + + UA_ConnectionManager * + UA_ConnectionManager_new_POSIX_UDP(const UA_String eventSourceName); + +Ethernet Connection Manager +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Listens on the network and manages UDP connections. This should be available +for all architectures. The configuration parameters have to set before +calling _start to take effect. + +**Open Connection Parameters:** + +0:listen [bool] + The connection is either for sending or for listening (default: false). + +0:interface [string] + The name of the Ethernet interface to use (required). + +0:address [string] + MAC target address consisting of six groups of hexadecimal digits + separated by hyphens such as 01-23-45-67-89-ab. For sending this is a + required parameter. For listening this is a multicast address that the + connections tries to register for. + +0:ethertype [uint16] + EtherType for sending and receiving frames (optional). For listening + connections, this filters out all frames with different EtherTypes. + +0:promiscuous [bool] + Receive frames also for different target addresses. Defined only for + listening connections (default: false). + +0:vid [uint16] + 12-bit VLAN identifier (optional for send connections). + +0:pcp [byte] + 3-bit priority code point (optional for send connections). + +0:dei [bool] + 1-bit drop eligible indicator (optional for seond connections). + +0:validate [boolean] + If true, the connection setup will act as a dry-run without actually + creating any connection but solely validating the provided parameters + (default: false) + +**Send Parameters:** + +No additional parameters for sending over an Ethernet connection defined. + +.. code-block:: c + + UA_ConnectionManager * + UA_ConnectionManager_new_POSIX_Ethernet(const UA_String eventSourceName); + +MQTT Connection Manager +~~~~~~~~~~~~~~~~~~~~~~~ +The MQTT ConnectionManager reuses the TCP ConnectionManager that is +configured in the EventLoop. Hence the MQTT ConnectionManager is platform +agnostic and does not require porting. An MQTT connection is for a +combination of broker and topic. The MQTT ConnectionManager can group +connections to the same broker in the background. Hence adding multiple +connections for the same broker is "cheap". To have individual control, +separate connections are created for each topic and for each direction +(publishing / subscribing). + +**Open Connection Parameters:** + +0:address [string] + Hostname or IPv4/v6 address of the MQTT broker (required). + +0:port [uint16] + Port of the MQTT broker (default: 1883). + +0:username [string] + Username to use (default: none) + +0:password [string] + Password to use (default: none) + +0:keep-alive [uint16] + Number of seconds for the keep-alive (ping) (default: 400). + +0:validate [boolean] + If true, the connection setup will act as a dry-run without actually + creating any connection but solely validating the provided parameters + (default: false) + +0:topic [string] + Topic to which the connection is associated (required). + +0:subscribe [bool] + Subscribe to the topic (default: false). Otherwise it is only possible to + publish on the topic. Subscribed topics can also be published to. + +**Connection Callback Parameters:** + +0:topic [string] + The value set during connect. + +0:subscribe [bool] + The value set during connect. + +**Send Parameters:** + +No additional parameters for sending over an Ethernet connection defined. + +.. code-block:: c + + UA_ConnectionManager * + UA_ConnectionManager_new_MQTT(const UA_String eventSourceName); + +Signal Interrupt Manager +~~~~~~~~~~~~~~~~~~~~~~~~ +Create an instance of the interrupt manager that handles POSX signals. This +interrupt manager takes the numerical interrupt identifiers from +for the interruptHandle. + +.. code-block:: c + + UA_InterruptManager * + UA_InterruptManager_new_POSIX(const UA_String eventSourceName); + + #endif /* defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) */ diff --git a/static/doc/v1.4.0/_sources/plugin_log.rst.txt b/static/doc/v1.4.0/_sources/plugin_log.rst.txt new file mode 100644 index 0000000000..80b2361654 --- /dev/null +++ b/static/doc/v1.4.0/_sources/plugin_log.rst.txt @@ -0,0 +1,143 @@ +.. _logging: + +Logging Plugin API +================== + +Servers and clients define a logger in their configuration. The logger is a +plugin. A default plugin that logs to ``stdout`` is provided as an example. +The logger plugin is stateful and can point to custom data. So it is possible +to keep open file handlers in the logger context. + +Every log message consists of a log level, a log category and a string +message content. The timestamp of the log message is created within the +logger. + +.. code-block:: c + + + typedef enum { + UA_LOGLEVEL_TRACE = 100, + UA_LOGLEVEL_DEBUG = 200, + UA_LOGLEVEL_INFO = 300, + UA_LOGLEVEL_WARNING = 400, + UA_LOGLEVEL_ERROR = 500, + UA_LOGLEVEL_FATAL = 600 + } UA_LogLevel; + + #define UA_LOGCATEGORIES 10 + + typedef enum { + UA_LOGCATEGORY_NETWORK = 0, + UA_LOGCATEGORY_SECURECHANNEL, + UA_LOGCATEGORY_SESSION, + UA_LOGCATEGORY_SERVER, + UA_LOGCATEGORY_CLIENT, + UA_LOGCATEGORY_USERLAND, + UA_LOGCATEGORY_SECURITYPOLICY, + UA_LOGCATEGORY_EVENTLOOP, + UA_LOGCATEGORY_PUBSUB, + UA_LOGCATEGORY_DISCOVERY + } UA_LogCategory; + + typedef struct UA_Logger { + /* Log a message. The message string and following varargs are formatted + * according to the rules of the printf command. Use the convenience macros + * below that take the minimum log level defined in ua_config.h into + * account. */ + void (*log)(void *logContext, UA_LogLevel level, UA_LogCategory category, + const char *msg, va_list args); + + void *context; /* Logger state */ + + void (*clear)(struct UA_Logger *logger); /* Clean up the logger plugin */ + } UA_Logger; + + static UA_INLINE UA_FORMAT(3,4) void + UA_LOG_TRACE(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) { + #if UA_LOGLEVEL <= 100 + if(!logger || !logger->log) + return; + va_list args; va_start(args, msg); + logger->log(logger->context, UA_LOGLEVEL_TRACE, category, msg, args); + va_end(args); + #else + (void) logger; + (void) category; + (void) msg; + #endif + } + + static UA_INLINE UA_FORMAT(3,4) void + UA_LOG_DEBUG(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) { + #if UA_LOGLEVEL <= 200 + if(!logger || !logger->log) + return; + va_list args; va_start(args, msg); + logger->log(logger->context, UA_LOGLEVEL_DEBUG, category, msg, args); + va_end(args); + #else + (void) logger; + (void) category; + (void) msg; + #endif + } + + static UA_INLINE UA_FORMAT(3,4) void + UA_LOG_INFO(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) { + #if UA_LOGLEVEL <= 300 + if(!logger || !logger->log) + return; + va_list args; va_start(args, msg); + logger->log(logger->context, UA_LOGLEVEL_INFO, category, msg, args); + va_end(args); + #else + (void) logger; + (void) category; + (void) msg; + #endif + } + + static UA_INLINE UA_FORMAT(3,4) void + UA_LOG_WARNING(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) { + #if UA_LOGLEVEL <= 400 + if(!logger || !logger->log) + return; + va_list args; va_start(args, msg); + logger->log(logger->context, UA_LOGLEVEL_WARNING, category, msg, args); + va_end(args); + #else + (void) logger; + (void) category; + (void) msg; + #endif + } + + static UA_INLINE UA_FORMAT(3,4) void + UA_LOG_ERROR(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) { + #if UA_LOGLEVEL <= 500 + if(!logger || !logger->log) + return; + va_list args; va_start(args, msg); + logger->log(logger->context, UA_LOGLEVEL_ERROR, category, msg, args); + va_end(args); + #else + (void) logger; + (void) category; + (void) msg; + #endif + } + + static UA_INLINE UA_FORMAT(3,4) void + UA_LOG_FATAL(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) { + #if UA_LOGLEVEL <= 600 + if(!logger || !logger->log) + return; + va_list args; va_start(args, msg); + logger->log(logger->context, UA_LOGLEVEL_FATAL, category, msg, args); + va_end(args); + #else + (void) logger; + (void) category; + (void) msg; + #endif + } diff --git a/static/doc/v1.4.0/_sources/plugin_nodestore.rst.txt b/static/doc/v1.4.0/_sources/plugin_nodestore.rst.txt new file mode 100644 index 0000000000..739c9ed874 --- /dev/null +++ b/static/doc/v1.4.0/_sources/plugin_nodestore.rst.txt @@ -0,0 +1,868 @@ +Node Store Plugin API +===================== + +**Warning!!** The structures defined in this section are only relevant for +the developers of custom Nodestores. The interaction with the information +model is possible only via the OPC UA :ref:`services`. So the following +sections are purely informational so that users may have a clear mental +model of the underlying representation. + +.. _node-lifecycle: + +Node Lifecycle: Constructors, Destructors and Node Contexts +----------------------------------------------------------- + +To finalize the instantiation of a node, a (user-defined) constructor +callback is executed. There can be both a global constructor for all nodes +and node-type constructor specific to the TypeDefinition of the new node +(attached to an ObjectTypeNode or VariableTypeNode). + +In the hierarchy of ObjectTypes and VariableTypes, only the constructor of +the (lowest) type defined for the new node is executed. Note that every +Object and Variable can have only one ``isTypeOf`` reference. But type-nodes +can technically have several ``hasSubType`` references to implement multiple +inheritance. Issues of (multiple) inheritance in the constructor need to be +solved by the user. + +When a node is destroyed, the node-type destructor is called before the +global destructor. So the overall node lifecycle is as follows: + +1. Global Constructor (set in the server config) +2. Node-Type Constructor (for VariableType or ObjectTypes) +3. (Usage-period of the Node) +4. Node-Type Destructor +5. Global Destructor + +The constructor and destructor callbacks can be set to ``NULL`` and are not +used in that case. If the node-type constructor fails, the global destructor +will be called before removing the node. The destructors are assumed to never +fail. + +Every node carries a user-context and a constructor-context pointer. The +user-context is used to attach custom data to a node. But the (user-defined) +constructors and destructors may replace the user-context pointer if they +wish to do so. The initial value for the constructor-context is ``NULL``. +When the ``AddNodes`` service is used over the network, the user-context +pointer of the new node is also initially set to ``NULL``. + +Global Node Lifecycle +~~~~~~~~~~~~~~~~~~~~~~ +Global constructor and destructor callbacks used for every node type. +To be set in the server config. + +.. code-block:: c + + + typedef struct { + /* Can be NULL. May replace the nodeContext */ + UA_StatusCode (*constructor)(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void **nodeContext); + + /* Can be NULL. The context cannot be replaced since the node is destroyed + * immediately afterwards anyway. */ + void (*destructor)(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext); + + /* Can be NULL. Called during recursive node instantiation. While mandatory + * child nodes are automatically created if not already present, optional child + * nodes are not. This callback can be used to define whether an optional child + * node should be created. + * + * @param server The server executing the callback + * @param sessionId The identifier of the session + * @param sessionContext Additional data attached to the session in the + * access control layer + * @param sourceNodeId Source node from the type definition. If the new node + * shall be created, it will be a copy of this node. + * @param targetParentNodeId Parent of the potential new child node + * @param referenceTypeId Identifies the reference type which that the parent + * node has to the new node. + * @return Return UA_TRUE if the child node shall be instantiated, + * UA_FALSE otherwise. */ + UA_Boolean (*createOptionalChild)(UA_Server *server, + const UA_NodeId *sessionId, + void *sessionContext, + const UA_NodeId *sourceNodeId, + const UA_NodeId *targetParentNodeId, + const UA_NodeId *referenceTypeId); + + /* Can be NULL. Called when a node is to be copied during recursive + * node instantiation. Allows definition of the NodeId for the new node. + * If the callback is set to NULL or the resulting NodeId is UA_NODEID_NUMERIC(X,0) + * an unused nodeid in namespace X will be used. E.g. passing UA_NODEID_NULL will + * result in a NodeId in namespace 0. + * + * @param server The server executing the callback + * @param sessionId The identifier of the session + * @param sessionContext Additional data attached to the session in the + * access control layer + * @param sourceNodeId Source node of the copy operation + * @param targetParentNodeId Parent node of the new node + * @param referenceTypeId Identifies the reference type which that the parent + * node has to the new node. */ + UA_StatusCode (*generateChildNodeId)(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *sourceNodeId, + const UA_NodeId *targetParentNodeId, + const UA_NodeId *referenceTypeId, + UA_NodeId *targetNodeId); + } UA_GlobalNodeLifecycle; + +Node Type Lifecycle +~~~~~~~~~~~~~~~~~~~ +Constructor and destructors for specific object and variable types. + +.. code-block:: c + + typedef struct { + /* Can be NULL. May replace the nodeContext */ + UA_StatusCode (*constructor)(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *typeNodeId, void *typeNodeContext, + const UA_NodeId *nodeId, void **nodeContext); + + /* Can be NULL. May replace the nodeContext. */ + void (*destructor)(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *typeNodeId, void *typeNodeContext, + const UA_NodeId *nodeId, void **nodeContext); + } UA_NodeTypeLifecycle; + +ReferenceType Bitfield Representation +------------------------------------- +ReferenceTypes have an alternative represention as an index into a bitfield +for fast comparison. The index is generated when the corresponding +ReferenceTypeNode is added. By bounding the number of ReferenceTypes that can +exist in the server, the bitfield can represent a set of an combination of +ReferenceTypes. + +Every ReferenceTypeNode contains a bitfield with the set of all its subtypes. +This speeds up the Browse services substantially. + +The following ReferenceTypes have a fixed index. The NS0 bootstrapping +creates these ReferenceTypes in-order. + +.. code-block:: c + + #define UA_REFERENCETYPEINDEX_REFERENCES 0 + #define UA_REFERENCETYPEINDEX_HASSUBTYPE 1 + #define UA_REFERENCETYPEINDEX_AGGREGATES 2 + #define UA_REFERENCETYPEINDEX_HIERARCHICALREFERENCES 3 + #define UA_REFERENCETYPEINDEX_NONHIERARCHICALREFERENCES 4 + #define UA_REFERENCETYPEINDEX_HASCHILD 5 + #define UA_REFERENCETYPEINDEX_ORGANIZES 6 + #define UA_REFERENCETYPEINDEX_HASEVENTSOURCE 7 + #define UA_REFERENCETYPEINDEX_HASMODELLINGRULE 8 + #define UA_REFERENCETYPEINDEX_HASENCODING 9 + #define UA_REFERENCETYPEINDEX_HASDESCRIPTION 10 + #define UA_REFERENCETYPEINDEX_HASTYPEDEFINITION 11 + #define UA_REFERENCETYPEINDEX_GENERATESEVENT 12 + #define UA_REFERENCETYPEINDEX_HASPROPERTY 13 + #define UA_REFERENCETYPEINDEX_HASCOMPONENT 14 + #define UA_REFERENCETYPEINDEX_HASNOTIFIER 15 + #define UA_REFERENCETYPEINDEX_HASORDEREDCOMPONENT 16 + #define UA_REFERENCETYPEINDEX_HASINTERFACE 17 + + /* The maximum number of ReferrenceTypes. Must be a multiple of 32. */ + #define UA_REFERENCETYPESET_MAX 128 + typedef struct { + UA_UInt32 bits[UA_REFERENCETYPESET_MAX / 32]; + } UA_ReferenceTypeSet; + + extern const UA_ReferenceTypeSet UA_REFERENCETYPESET_NONE; + extern const UA_ReferenceTypeSet UA_REFERENCETYPESET_ALL; + + static UA_INLINE void + UA_ReferenceTypeSet_init(UA_ReferenceTypeSet *set) { + memset(set, 0, sizeof(UA_ReferenceTypeSet)); + } + + static UA_INLINE UA_ReferenceTypeSet + UA_REFTYPESET(UA_Byte index) { + UA_Byte i = index / 32, j = index % 32; + UA_ReferenceTypeSet set; + UA_ReferenceTypeSet_init(&set); + set.bits[i] |= ((UA_UInt32)1) << j; + return set; + } + + static UA_INLINE UA_ReferenceTypeSet + UA_ReferenceTypeSet_union(const UA_ReferenceTypeSet setA, + const UA_ReferenceTypeSet setB) { + UA_ReferenceTypeSet set; + for(size_t i = 0; i < UA_REFERENCETYPESET_MAX / 32; i++) + set.bits[i] = setA.bits[i] | setB.bits[i]; + return set; + } + + static UA_INLINE UA_Boolean + UA_ReferenceTypeSet_contains(const UA_ReferenceTypeSet *set, UA_Byte index) { + UA_Byte i = index / 32, j = index % 32; + return !!(set->bits[i] & (((UA_UInt32)1) << j)); + } + +Node Pointer +------------ + +The "native" format for reference between nodes is the ExpandedNodeId. That +is, references can also point to external servers. In practice, most +references point to local nodes using numerical NodeIds from the +standard-defined namespace zero. In order to save space (and time), +pointer-tagging is used for compressed "NodePointer" representations. +Numerical NodeIds are immediately contained in the pointer. Full NodeIds and +ExpandedNodeIds are behind a pointer indirection. If the Nodestore supports +it, a NodePointer can also be an actual pointer to the target node. + +Depending on the processor architecture, some numerical NodeIds don't fit +into an immediate encoding and are kept as pointers. ExpandedNodeIds may be +internally translated to "normal" NodeIds. Use the provided functions to +generate NodePointers that fit the assumptions for the local architecture. + +.. code-block:: c + + + /* Forward declaration. All node structures begin with the NodeHead. */ + struct UA_NodeHead; + typedef struct UA_NodeHead UA_NodeHead; + + /* Tagged Pointer structure. */ + typedef union { + uintptr_t immediate; /* 00: Small numerical NodeId */ + const UA_NodeId *id; /* 01: Pointer to NodeId */ + const UA_ExpandedNodeId *expandedId; /* 10: Pointer to ExternalNodeId */ + const UA_NodeHead *node; /* 11: Pointer to a node */ + } UA_NodePointer; + + /* Sets the pointer to an immediate NodeId "ns=0;i=0" similar to a freshly + * initialized UA_NodeId */ + static UA_INLINE void + UA_NodePointer_init(UA_NodePointer *np) { np->immediate = 0; } + + /* NodeId and ExpandedNodeId targets are freed */ + void + UA_NodePointer_clear(UA_NodePointer *np); + + /* Makes a deep copy */ + UA_StatusCode + UA_NodePointer_copy(UA_NodePointer in, UA_NodePointer *out); + + /* Test if an ExpandedNodeId or a local NodeId */ + UA_Boolean + UA_NodePointer_isLocal(UA_NodePointer np); + + UA_Order + UA_NodePointer_order(UA_NodePointer p1, UA_NodePointer p2); + + static UA_INLINE UA_Boolean + UA_NodePointer_equal(UA_NodePointer p1, UA_NodePointer p2) { + return (UA_NodePointer_order(p1, p2) == UA_ORDER_EQ); + } + + /* Cannot fail. The resulting NodePointer can point to the memory from the + * NodeId. Make a deep copy if required. */ + UA_NodePointer + UA_NodePointer_fromNodeId(const UA_NodeId *id); + + /* Cannot fail. The resulting NodePointer can point to the memory from the + * ExpandedNodeId. Make a deep copy if required. */ + UA_NodePointer + UA_NodePointer_fromExpandedNodeId(const UA_ExpandedNodeId *id); + + /* Can point to the memory from the NodePointer */ + UA_ExpandedNodeId + UA_NodePointer_toExpandedNodeId(UA_NodePointer np); + + /* Can point to the memory from the NodePointer. Discards the ServerIndex and + * NamespaceUri of a potential ExpandedNodeId inside the NodePointer. Test + * before if the NodePointer is local. */ + UA_NodeId + UA_NodePointer_toNodeId(UA_NodePointer np); + +Base Node Attributes +-------------------- + +Nodes contain attributes according to their node type. The base node +attributes are common to all node types. In the OPC UA :ref:`services`, +attributes are referred to via the :ref:`nodeid` of the containing node and +an integer :ref:`attribute-id`. + +Internally, open62541 uses ``UA_Node`` in places where the exact node type is +not known or not important. The ``nodeClass`` attribute is used to ensure the +correctness of casting from ``UA_Node`` to a specific node type. + +.. code-block:: c + + + typedef struct { + UA_NodePointer targetId; /* Has to be the first entry */ + UA_UInt32 targetNameHash; /* Hash of the target's BrowseName. Set to zero + * if the target is remote. */ + } UA_ReferenceTarget; + + typedef struct UA_ReferenceTargetTreeElem { + UA_ReferenceTarget target; /* Has to be the first entry */ + UA_UInt32 targetIdHash; /* Hash of the targetId */ + struct { + struct UA_ReferenceTargetTreeElem *left; + struct UA_ReferenceTargetTreeElem *right; + } idTreeEntry; + struct { + struct UA_ReferenceTargetTreeElem *left; + struct UA_ReferenceTargetTreeElem *right; + } nameTreeEntry; + } UA_ReferenceTargetTreeElem; + + + /* List of reference targets with the same reference type and direction. Uses + * either an array or a tree structure. The SDK will not change the type of + * reference target structure internally. The nodestore implementations may + * switch internally when a node is updated. + * + * The recommendation is to switch to a tree once the number of refs > 8. */ + typedef struct { + union { + /* Organize the references in an array. Uses less memory, but incurs + * lookups in linear time. Recommended if the number of references is + * known to be small. */ + UA_ReferenceTarget *array; + + /* Organize the references in a tree for fast lookup. Use + * UA_Node_addReference and UA_Node_deleteReference to modify the + * tree-structure. The binary tree implementation (and absolute ordering + * / duplicate browseNames are allowed) are not exposed otherwise in the + * public API. */ + struct { + UA_ReferenceTargetTreeElem *idRoot; /* Lookup based on target id */ + UA_ReferenceTargetTreeElem *nameRoot; /* Lookup based on browseName*/ + } tree; + } targets; + size_t targetsSize; + UA_Boolean hasRefTree; /* RefTree or RefArray? */ + UA_Byte referenceTypeIndex; + UA_Boolean isInverse; + } UA_NodeReferenceKind; + + /* Iterate over the references. Aborts when the first callback return a non-NULL + * pointer and returns that pointer. Do not modify the reference targets during + * the iteration. */ + typedef void * + (*UA_NodeReferenceKind_iterateCallback)(void *context, UA_ReferenceTarget *target); + + void * + UA_NodeReferenceKind_iterate(UA_NodeReferenceKind *rk, + UA_NodeReferenceKind_iterateCallback callback, + void *context); + + /* Returns the entry for the targetId or NULL if not found */ + const UA_ReferenceTarget * + UA_NodeReferenceKind_findTarget(const UA_NodeReferenceKind *rk, + const UA_ExpandedNodeId *targetId); + + /* Switch between array and tree representation. Does nothing upon error (e.g. + * out-of-memory). */ + UA_StatusCode + UA_NodeReferenceKind_switch(UA_NodeReferenceKind *rk); + + /* Singly-linked LocalizedText list */ + typedef struct UA_LocalizedTextListEntry { + struct UA_LocalizedTextListEntry *next; + UA_LocalizedText localizedText; + } UA_LocalizedTextListEntry; + + /* Every Node starts with these attributes */ + struct UA_NodeHead { + UA_NodeId nodeId; + UA_NodeClass nodeClass; + UA_QualifiedName browseName; + + /* A node can have different localizations for displayName and description. + * The server selects a suitable localization depending on the locale ids + * that are set for the current session. + * + * Locales are added simply by writing a LocalizedText value with a new + * locale. A locale can be removed by writing a LocalizedText value of the + * corresponding locale with an empty text field. */ + UA_LocalizedTextListEntry *displayName; + UA_LocalizedTextListEntry *description; + + UA_UInt32 writeMask; + size_t referencesSize; + UA_NodeReferenceKind *references; + + /* Members specific to open62541 */ + void *context; + UA_Boolean constructed; /* Constructors were called */ + #ifdef UA_ENABLE_SUBSCRIPTIONS + UA_MonitoredItem *monitoredItems; /* MonitoredItems for Events and immediate + * DataChanges (no sampling interval). */ + #endif + }; + +VariableNode +------------ + +.. code-block:: c + + + /* Indicates whether a variable contains data inline or whether it points to an + * external data source */ + typedef enum { + UA_VALUESOURCE_DATA, + UA_VALUESOURCE_DATASOURCE + } UA_ValueSource; + + typedef struct { + /* Called before the value attribute is read. It is possible to write into the + * value attribute during onRead (using the write service). The node is + * re-opened afterwards so that changes are considered in the following read + * operation. + * + * @param handle Points to user-provided data for the callback. + * @param nodeid The identifier of the node. + * @param data Points to the current node value. + * @param range Points to the numeric range the client wants to read from + * (or NULL). */ + void (*onRead)(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeid, + void *nodeContext, const UA_NumericRange *range, + const UA_DataValue *value); + + /* Called after writing the value attribute. The node is re-opened after + * writing so that the new value is visible in the callback. + * + * @param server The server executing the callback + * @sessionId The identifier of the session + * @sessionContext Additional data attached to the session + * in the access control layer + * @param nodeid The identifier of the node. + * @param nodeUserContext Additional data attached to the node by + * the user. + * @param nodeConstructorContext Additional data attached to the node + * by the type constructor(s). + * @param range Points to the numeric range the client wants to write to (or + * NULL). */ + void (*onWrite)(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeId, + void *nodeContext, const UA_NumericRange *range, + const UA_DataValue *data); + } UA_ValueCallback; + + typedef struct { + /* Copies the data from the source into the provided value. + * + * !! ZERO-COPY OPERATIONS POSSIBLE !! + * It is not required to return a copy of the actual content data. You can + * return a pointer to memory owned by the user. Memory can be reused + * between read callbacks of a DataSource, as the result is already encoded + * on the network buffer between each read operation. + * + * To use zero-copy reads, set the value of the `value->value` Variant + * without copying, e.g. with `UA_Variant_setScalar`. Then, also set + * `value->value.storageType` to `UA_VARIANT_DATA_NODELETE` to prevent the + * memory being cleaned up. Don't forget to also set `value->hasValue` to + * true to indicate the presence of a value. + * + * @param server The server executing the callback + * @param sessionId The identifier of the session + * @param sessionContext Additional data attached to the session in the + * access control layer + * @param nodeId The identifier of the node being read from + * @param nodeContext Additional data attached to the node by the user + * @param includeSourceTimeStamp If true, then the datasource is expected to + * set the source timestamp in the returned value + * @param range If not null, then the datasource shall return only a + * selection of the (nonscalar) data. Set + * UA_STATUSCODE_BADINDEXRANGEINVALID in the value if this does not + * apply + * @param value The (non-null) DataValue that is returned to the client. The + * data source sets the read data, the result status and optionally a + * sourcetimestamp. + * @return Returns a status code for logging. Error codes intended for the + * original caller are set in the value. If an error is returned, + * then no releasing of the value is done + */ + UA_StatusCode (*read)(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeId, + void *nodeContext, UA_Boolean includeSourceTimeStamp, + const UA_NumericRange *range, UA_DataValue *value); + + /* Write into a data source. This method pointer can be NULL if the + * operation is unsupported. + * + * @param server The server executing the callback + * @param sessionId The identifier of the session + * @param sessionContext Additional data attached to the session in the + * access control layer + * @param nodeId The identifier of the node being written to + * @param nodeContext Additional data attached to the node by the user + * @param range If not NULL, then the datasource shall return only a + * selection of the (nonscalar) data. Set + * UA_STATUSCODE_BADINDEXRANGEINVALID in the value if this does not + * apply + * @param value The (non-NULL) DataValue that has been written by the client. + * The data source contains the written data, the result status and + * optionally a sourcetimestamp + * @return Returns a status code for logging. Error codes intended for the + * original caller are set in the value. If an error is returned, + * then no releasing of the value is done + */ + UA_StatusCode (*write)(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeId, + void *nodeContext, const UA_NumericRange *range, + const UA_DataValue *value); + } UA_DataSource; + +.. _value-callback: + +Value Callback +~~~~~~~~~~~~~~ +Value Callbacks can be attached to variable and variable type nodes. If +not ``NULL``, they are called before reading and after writing respectively. + +.. code-block:: c + + typedef struct { + /* Called before the value attribute is read. The external value source can be + * be updated and/or locked during this notification call. After this function returns + * to the core, the external value source is readed immediately. + */ + UA_StatusCode (*notificationRead)(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeid, + void *nodeContext, const UA_NumericRange *range); + + /* Called after writing the value attribute. The node is re-opened after + * writing so that the new value is visible in the callback. + * + * @param server The server executing the callback + * @sessionId The identifier of the session + * @sessionContext Additional data attached to the session + * in the access control layer + * @param nodeid The identifier of the node. + * @param nodeUserContext Additional data attached to the node by + * the user. + * @param nodeConstructorContext Additional data attached to the node + * by the type constructor(s). + * @param range Points to the numeric range the client wants to write to (or + * NULL). */ + UA_StatusCode (*userWrite)(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeId, + void *nodeContext, const UA_NumericRange *range, + const UA_DataValue *data); + } UA_ExternalValueCallback; + + typedef enum { + UA_VALUEBACKENDTYPE_NONE, + UA_VALUEBACKENDTYPE_INTERNAL, + UA_VALUEBACKENDTYPE_DATA_SOURCE_CALLBACK, + UA_VALUEBACKENDTYPE_EXTERNAL + } UA_ValueBackendType; + + typedef struct { + UA_ValueBackendType backendType; + union { + struct { + UA_DataValue value; + UA_ValueCallback callback; + } internal; + UA_DataSource dataSource; + struct { + UA_DataValue **value; + UA_ExternalValueCallback callback; + } external; + } backend; + } UA_ValueBackend; + + #define UA_NODE_VARIABLEATTRIBUTES \ + /* Constraints on possible values */ \ + UA_NodeId dataType; \ + UA_Int32 valueRank; \ + size_t arrayDimensionsSize; \ + UA_UInt32 *arrayDimensions; \ + \ + UA_ValueBackend valueBackend; \ + \ + /* The current value */ \ + UA_ValueSource valueSource; \ + union { \ + struct { \ + UA_DataValue value; \ + UA_ValueCallback callback; \ + } data; \ + UA_DataSource dataSource; \ + } value; + + typedef struct { + UA_NodeHead head; + UA_NODE_VARIABLEATTRIBUTES + UA_Byte accessLevel; + UA_Double minimumSamplingInterval; + UA_Boolean historizing; + + /* Members specific to open62541 */ + UA_Boolean isDynamic; /* Some variables are "static" in the sense that they + * are not attached to a dynamic process in the + * background. Only dynamic variables conserve source + * and server timestamp for the value attribute. + * Static variables have timestamps of "now". */ + } UA_VariableNode; + +VariableTypeNode +---------------- + +.. code-block:: c + + + typedef struct { + UA_NodeHead head; + UA_NODE_VARIABLEATTRIBUTES + UA_Boolean isAbstract; + + /* Members specific to open62541 */ + UA_NodeTypeLifecycle lifecycle; + } UA_VariableTypeNode; + +MethodNode +---------- + +.. code-block:: c + + + typedef UA_StatusCode + (*UA_MethodCallback)(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *methodId, + void *methodContext, const UA_NodeId *objectId, + void *objectContext, size_t inputSize, + const UA_Variant *input, size_t outputSize, + UA_Variant *output); + + typedef struct { + UA_NodeHead head; + UA_Boolean executable; + + /* Members specific to open62541 */ + UA_MethodCallback method; + #if UA_MULTITHREADING >= 100 + UA_Boolean async; /* Indicates an async method call */ + #endif + } UA_MethodNode; + +ObjectNode +---------- + +.. code-block:: c + + + typedef struct { + UA_NodeHead head; + UA_Byte eventNotifier; + } UA_ObjectNode; + +ObjectTypeNode +-------------- + +.. code-block:: c + + + typedef struct { + UA_NodeHead head; + UA_Boolean isAbstract; + + /* Members specific to open62541 */ + UA_NodeTypeLifecycle lifecycle; + } UA_ObjectTypeNode; + +ReferenceTypeNode +----------------- + +.. code-block:: c + + + typedef struct { + UA_NodeHead head; + UA_Boolean isAbstract; + UA_Boolean symmetric; + UA_LocalizedText inverseName; + + /* Members specific to open62541 */ + UA_Byte referenceTypeIndex; + UA_ReferenceTypeSet subTypes; /* contains the type itself as well */ + } UA_ReferenceTypeNode; + +DataTypeNode +------------ + +.. code-block:: c + + + typedef struct { + UA_NodeHead head; + UA_Boolean isAbstract; + } UA_DataTypeNode; + +ViewNode +-------- + +.. code-block:: c + + + typedef struct { + UA_NodeHead head; + UA_Byte eventNotifier; + UA_Boolean containsNoLoops; + } UA_ViewNode; + +Node Union +---------- + +A union that represents any kind of node. The node head can always be used. +Check the NodeClass before accessing specific content. + +.. code-block:: c + + + typedef union { + UA_NodeHead head; + UA_VariableNode variableNode; + UA_VariableTypeNode variableTypeNode; + UA_MethodNode methodNode; + UA_ObjectNode objectNode; + UA_ObjectTypeNode objectTypeNode; + UA_ReferenceTypeNode referenceTypeNode; + UA_DataTypeNode dataTypeNode; + UA_ViewNode viewNode; + } UA_Node; + +Nodestore +--------- + +The following definitions are used for implementing custom node storage +backends. **Most users will want to use the default nodestore and don't need +to work with the nodestore API**. + +Outside of custom nodestore implementations, users should not manually edit +nodes. Please use the OPC UA services for that. Otherwise, all consistency +checks are omitted. This can crash the application eventually. + +.. code-block:: c + + + typedef void (*UA_NodestoreVisitor)(void *visitorCtx, const UA_Node *node); + + typedef struct { + /* Nodestore context and lifecycle */ + void *context; + void (*clear)(void *nsCtx); + + /* The following definitions are used to create empty nodes of the different + * node types. The memory is managed by the nodestore. Therefore, the node + * has to be removed via a special deleteNode function. (If the new node is + * not added to the nodestore.) */ + UA_Node * (*newNode)(void *nsCtx, UA_NodeClass nodeClass); + + void (*deleteNode)(void *nsCtx, UA_Node *node); + + /* ``Get`` returns a pointer to an immutable node. Call ``releaseNode`` to + * indicate when the pointer is no longer accessed. + * + * It can be indicated if only a subset of the attributes and referencs need + * to be accessed. That is relevant when the nodestore accesses a slow + * storage backend for the attributes. The attribute mask is a bitfield with + * ORed entries from UA_NodeAttributesMask. + * + * The returned node always contains the context-pointer and other fields + * specific to open626541 (not official attributes). + * + * The NodeStore does not complain if attributes and references that don't + * exist (for that node) are requested. Attributes and references in + * addition to those specified can be returned. For example, if the full + * node already is kept in memory by the Nodestore. */ + const UA_Node * (*getNode)(void *nsCtx, const UA_NodeId *nodeId, + UA_UInt32 attributeMask, + UA_ReferenceTypeSet references, + UA_BrowseDirection referenceDirections); + + /* Similar to the normal ``getNode``. But it can take advantage of the + * NodePointer structure, e.g. if it contains a direct pointer. */ + const UA_Node * (*getNodeFromPtr)(void *nsCtx, UA_NodePointer ptr, + UA_UInt32 attributeMask, + UA_ReferenceTypeSet references, + UA_BrowseDirection referenceDirections); + + /* Release a node that has been retrieved with ``getNode`` or + * ``getNodeFromPtr``. */ + void (*releaseNode)(void *nsCtx, const UA_Node *node); + + /* Returns an editable copy of a node (needs to be deleted with the + * deleteNode function or inserted / replaced into the nodestore). */ + UA_StatusCode (*getNodeCopy)(void *nsCtx, const UA_NodeId *nodeId, + UA_Node **outNode); + + /* Inserts a new node into the nodestore. If the NodeId is zero, then a + * fresh numeric NodeId is assigned. If insertion fails, the node is + * deleted. */ + UA_StatusCode (*insertNode)(void *nsCtx, UA_Node *node, + UA_NodeId *addedNodeId); + + /* To replace a node, get an editable copy of the node, edit and replace + * with this function. If the node was already replaced since the copy was + * made, UA_STATUSCODE_BADINTERNALERROR is returned. If the NodeId is not + * found, UA_STATUSCODE_BADNODEIDUNKNOWN is returned. In both error cases, + * the editable node is deleted. */ + UA_StatusCode (*replaceNode)(void *nsCtx, UA_Node *node); + + /* Removes a node from the nodestore. */ + UA_StatusCode (*removeNode)(void *nsCtx, const UA_NodeId *nodeId); + + /* Maps the ReferenceTypeIndex used for the references to the NodeId of the + * ReferenceType. The returned pointer is stable until the Nodestore is + * deleted. */ + const UA_NodeId * (*getReferenceTypeId)(void *nsCtx, UA_Byte refTypeIndex); + + /* Execute a callback for every node in the nodestore. */ + void (*iterate)(void *nsCtx, UA_NodestoreVisitor visitor, + void *visitorCtx); + } UA_Nodestore; + + /* Attributes must be of a matching type (VariableAttributes, ObjectAttributes, + * and so on). The attributes are copied. Note that the attributes structs do + * not contain NodeId, NodeClass and BrowseName. The NodeClass of the node needs + * to be correctly set before calling this method. UA_Node_clear is called on + * the node when an error occurs internally. */ + UA_StatusCode + UA_Node_setAttributes(UA_Node *node, const void *attributes, + const UA_DataType *attributeType); + + /* Reset the destination node and copy the content of the source */ + UA_StatusCode + UA_Node_copy(const UA_Node *src, UA_Node *dst); + + /* Allocate new node and copy the values from src */ + UA_Node * + UA_Node_copy_alloc(const UA_Node *src); + + /* Add a single reference to the node */ + UA_StatusCode + UA_Node_addReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward, + const UA_ExpandedNodeId *targetNodeId, + UA_UInt32 targetBrowseNameHash); + + /* Delete a single reference from the node */ + UA_StatusCode + UA_Node_deleteReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward, + const UA_ExpandedNodeId *targetNodeId); + + /* Deletes references from the node which are not matching any type in the given + * array. Could be used to e.g. delete all the references, except + * 'HASMODELINGRULE' */ + void + UA_Node_deleteReferencesSubset(UA_Node *node, const UA_ReferenceTypeSet *keepSet); + + /* Delete all references of the node */ + void + UA_Node_deleteReferences(UA_Node *node); + + /* Remove all malloc'ed members of the node and reset */ + void + UA_Node_clear(UA_Node *node); diff --git a/static/doc/v1.4.0/_sources/plugin_pki.rst.txt b/static/doc/v1.4.0/_sources/plugin_pki.rst.txt new file mode 100644 index 0000000000..a49adf0880 --- /dev/null +++ b/static/doc/v1.4.0/_sources/plugin_pki.rst.txt @@ -0,0 +1,59 @@ +Public Key Infrastructure Integration +===================================== +This file contains interface definitions for integration in a Public Key +Infrastructure (PKI). Currently only one plugin interface is defined. + +Certificate Verification +------------------------ +This plugin verifies that the origin of the certificate is trusted. It does +not assign any access rights/roles to the holder of the certificate. + +Usually, implementations of the certificate verification plugin provide an +initialization method that takes a trust-list and a revocation-list as input. +The lifecycle of the plugin is attached to a server or client config. The +``clear`` method is called automatically when the config is destroyed. + +.. code-block:: c + + + struct UA_CertificateVerification; + typedef struct UA_CertificateVerification UA_CertificateVerification; + + struct UA_CertificateVerification { + void *context; + + /* Verify the certificate against the configured policies and trust chain. */ + UA_StatusCode (*verifyCertificate)(const UA_CertificateVerification *cv, + const UA_ByteString *certificate); + + /* Verify that the certificate has the applicationURI in the subject name. */ + UA_StatusCode (*verifyApplicationURI)(const UA_CertificateVerification *cv, + const UA_ByteString *certificate, + const UA_String *applicationURI); + + /* Get the expire date from certificate */ + UA_StatusCode (*getExpirationDate)(UA_DateTime *expiryDateTime, + UA_ByteString *certificate); + + UA_StatusCode (*getSubjectName)(UA_String *subjectName, + UA_ByteString *certificate); + + /* Delete the certificate verification context */ + void (*clear)(UA_CertificateVerification *cv); + + /* Pointer to logging pointer in the server/client configuration. If the + * logging pointer is changed outside of the plugin, the new logger is used + * automatically*/ + const UA_Logger *logging; + }; + + /* Decrypt a private key in PEM format using a password. The output is the key + * in the binary DER format. Also succeeds if the PEM private key does not + * require a password or is already in the DER format. The outDerKey memory is + * allocated internally. + * + * Returns UA_STATUSCODE_BADSECURITYCHECKSFAILED if the password is wrong. */ + UA_StatusCode + UA_PKI_decryptPrivateKey(const UA_ByteString privateKey, + const UA_ByteString password, + UA_ByteString *outDerKey); diff --git a/static/doc/v1.4.0/_sources/plugin_securitypolicy.rst.txt b/static/doc/v1.4.0/_sources/plugin_securitypolicy.rst.txt new file mode 100644 index 0000000000..41eb1f83cc --- /dev/null +++ b/static/doc/v1.4.0/_sources/plugin_securitypolicy.rst.txt @@ -0,0 +1,358 @@ +SecurityPolicy +-------------- + +.. code-block:: c + + + typedef struct { + UA_String uri; + + /* Verifies the signature of the message using the provided keys in the context. + * + * @param channelContext the channelContext that contains the key to verify + * the supplied message with. + * @param message the message to which the signature is supposed to belong. + * @param signature the signature of the message, that should be verified. */ + UA_StatusCode (*verify)(void *channelContext, const UA_ByteString *message, + const UA_ByteString *signature); + + /* Signs the given message using this policys signing algorithm and the + * provided keys in the context. + * + * @param channelContext the channelContext that contains the key to sign + * the supplied message with. + * @param message the message to sign. + * @param signature an output buffer to which the signature is written. The + * buffer needs to be allocated by the caller. The + * necessary size can be acquired with the signatureSize + * attribute of this module. */ + UA_StatusCode (*sign)(void *channelContext, const UA_ByteString *message, + UA_ByteString *signature); + + /* Gets the signature size that depends on the local (private) key. + * + * @param channelContext the channelContext that contains the + * certificate/key. + * @return the size of the local signature. Returns 0 if no local + * certificate was set. */ + size_t (*getLocalSignatureSize)(const void *channelContext); + + /* Gets the signature size that depends on the remote (public) key. + * + * @param channelContext the context to retrieve data from. + * @return the size of the remote signature. Returns 0 if no + * remote certificate was set previousely. */ + size_t (*getRemoteSignatureSize)(const void *channelContext); + + /* Gets the local signing key length. + * + * @param channelContext the context to retrieve data from. + * @return the length of the signing key in bytes. Returns 0 if no length can be found. + */ + size_t (*getLocalKeyLength)(const void *channelContext); + + /* Gets the local signing key length. + * + * @param channelContext the context to retrieve data from. + * @return the length of the signing key in bytes. Returns 0 if no length can be found. + */ + size_t (*getRemoteKeyLength)(const void *channelContext); + } UA_SecurityPolicySignatureAlgorithm; + + typedef struct { + UA_String uri; + + /* Encrypt the given data in place. For asymmetric encryption, the block + * size for plaintext and cypher depend on the remote key (certificate). + * + * @param channelContext the channelContext which contains information about + * the keys to encrypt data. + * @param data the data that is encrypted. The encrypted data will overwrite + * the data that was supplied. */ + UA_StatusCode (*encrypt)(void *channelContext, + UA_ByteString *data); + + /* Decrypts the given ciphertext in place. For asymmetric encryption, the + * block size for plaintext and cypher depend on the local private key. + * + * @param channelContext the channelContext which contains information about + * the keys needed to decrypt the message. + * @param data the data to decrypt. The decryption is done in place. */ + UA_StatusCode (*decrypt)(void *channelContext, + UA_ByteString *data); + + /* Returns the length of the key used to encrypt messages in bits. For + * asymmetric encryption the key length is for the local private key. + * + * @param channelContext the context to retrieve data from. + * @return the length of the local key. Returns 0 if no + * key length is known. */ + size_t (*getLocalKeyLength)(const void *channelContext); + + /* Returns the length of the key to encrypt messages in bits. Depends on the + * key (certificate) from the remote side. + * + * @param channelContext the context to retrieve data from. + * @return the length of the remote key. Returns 0 if no + * key length is known. */ + size_t (*getRemoteKeyLength)(const void *channelContext); + + /* Returns the size of encrypted blocks for sending. For asymmetric + * encryption this depends on the remote key (certificate). For symmetric + * encryption the local and remote encrypted block size are identical. + * + * @param channelContext the context to retrieve data from. + * @return the size of encrypted blocks in bytes. Returns 0 if no key length is known. + */ + size_t (*getRemoteBlockSize)(const void *channelContext); + + /* Returns the size of plaintext blocks for sending. For asymmetric + * encryption this depends on the remote key (certificate). For symmetric + * encryption the local and remote plaintext block size are identical. + * + * @param channelContext the context to retrieve data from. + * @return the size of plaintext blocks in bytes. Returns 0 if no key length is known. + */ + size_t (*getRemotePlainTextBlockSize)(const void *channelContext); + } UA_SecurityPolicyEncryptionAlgorithm; + + typedef struct { + /* The algorithm used to sign and verify certificates. */ + UA_SecurityPolicySignatureAlgorithm signatureAlgorithm; + + /* The algorithm used to encrypt and decrypt messages. */ + UA_SecurityPolicyEncryptionAlgorithm encryptionAlgorithm; + + } UA_SecurityPolicyCryptoModule; + + typedef struct { + /* Generates a thumbprint for the specified certificate. + * + * @param certificate the certificate to make a thumbprint of. + * @param thumbprint an output buffer for the resulting thumbprint. Always + * has the length specified in the thumbprintLength in the + * asymmetricModule. */ + UA_StatusCode (*makeCertificateThumbprint)(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *certificate, + UA_ByteString *thumbprint) + ; + + /* Compares the supplied certificate with the certificate in the endpoint context. + * + * @param securityPolicy the policy data that contains the certificate + * to compare to. + * @param certificateThumbprint the certificate thumbprint to compare to the + * one stored in the context. + * @return if the thumbprints match UA_STATUSCODE_GOOD is returned. If they + * don't match or an error occurred an error code is returned. */ + UA_StatusCode (*compareCertificateThumbprint)(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *certificateThumbprint) + ; + + UA_SecurityPolicyCryptoModule cryptoModule; + } UA_SecurityPolicyAsymmetricModule; + + typedef struct { + /* Pseudo random function that is used to generate the symmetric keys. + * + * For information on what parameters this function receives in what situation, + * refer to the OPC UA specification 1.03 Part6 Table 33 + * + * @param policyContext The context of the policy instance + * @param secret + * @param seed + * @param out an output to write the data to. The length defines the maximum + * number of output bytes that are produced. */ + UA_StatusCode (*generateKey)(void *policyContext, const UA_ByteString *secret, + const UA_ByteString *seed, UA_ByteString *out) + ; + + /* Random generator for generating nonces. + * + * @param policyContext The context of the policy instance + * @param out pointer to a buffer to store the nonce in. Needs to be + * allocated by the caller. The buffer is filled with random + * data. */ + UA_StatusCode (*generateNonce)(void *policyContext, UA_ByteString *out) + ; + + /* + * The length of the nonce used in the SecureChannel as specified in the standard. + */ + size_t secureChannelNonceLength; + + UA_SecurityPolicyCryptoModule cryptoModule; + } UA_SecurityPolicySymmetricModule; + + typedef struct { + /* This method creates a new context data object. + * + * The caller needs to call delete on the received object to free allocated + * memory. Memory is only allocated if the function succeeds so there is no + * need to manually free the memory pointed to by *channelContext or to + * call delete in case of failure. + * + * @param securityPolicy the policy context of the endpoint that is connected + * to. It will be stored in the channelContext for + * further access by the policy. + * @param remoteCertificate the remote certificate contains the remote + * asymmetric key. The certificate will be verified + * and then stored in the context so that its + * details may be accessed. + * @param channelContext the initialized channelContext that is passed to + * functions that work on a context. */ + UA_StatusCode (*newContext)(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *remoteCertificate, + void **channelContext) + ; + + /* Deletes the the security context. */ + void (*deleteContext)(void *channelContext); + + /* Sets the local encrypting key in the supplied context. + * + * @param channelContext the context to work on. + * @param key the local encrypting key to store in the context. */ + UA_StatusCode (*setLocalSymEncryptingKey)(void *channelContext, + const UA_ByteString *key) + ; + + /* Sets the local signing key in the supplied context. + * + * @param channelContext the context to work on. + * @param key the local signing key to store in the context. */ + UA_StatusCode (*setLocalSymSigningKey)(void *channelContext, + const UA_ByteString *key) + ; + + /* Sets the local initialization vector in the supplied context. + * + * @param channelContext the context to work on. + * @param iv the local initialization vector to store in the context. */ + UA_StatusCode (*setLocalSymIv)(void *channelContext, + const UA_ByteString *iv) + ; + + /* Sets the remote encrypting key in the supplied context. + * + * @param channelContext the context to work on. + * @param key the remote encrypting key to store in the context. */ + UA_StatusCode (*setRemoteSymEncryptingKey)(void *channelContext, + const UA_ByteString *key) + ; + + /* Sets the remote signing key in the supplied context. + * + * @param channelContext the context to work on. + * @param key the remote signing key to store in the context. */ + UA_StatusCode (*setRemoteSymSigningKey)(void *channelContext, + const UA_ByteString *key) + ; + + /* Sets the remote initialization vector in the supplied context. + * + * @param channelContext the context to work on. + * @param iv the remote initialization vector to store in the context. */ + UA_StatusCode (*setRemoteSymIv)(void *channelContext, + const UA_ByteString *iv) + ; + + /* Compares the supplied certificate with the certificate in the channel + * context. + * + * @param channelContext the channel context data that contains the + * certificate to compare to. + * @param certificate the certificate to compare to the one stored in the context. + * @return if the certificates match UA_STATUSCODE_GOOD is returned. If they + * don't match or an errror occurred an error code is returned. */ + UA_StatusCode (*compareCertificate)(const void *channelContext, + const UA_ByteString *certificate) + ; + } UA_SecurityPolicyChannelModule; + + struct UA_SecurityPolicy { + /* Additional data */ + void *policyContext; + + /* The policy uri that identifies the implemented algorithms */ + UA_String policyUri; + + /* The local certificate is specific for each SecurityPolicy since it + * depends on the used key length. */ + UA_ByteString localCertificate; + + /* Function pointers grouped into modules */ + UA_SecurityPolicyAsymmetricModule asymmetricModule; + UA_SecurityPolicySymmetricModule symmetricModule; + UA_SecurityPolicySignatureAlgorithm certificateSigningAlgorithm; + UA_SecurityPolicyChannelModule channelModule; + + const UA_Logger *logger; + + /* Updates the ApplicationInstanceCertificate and the corresponding private + * key at runtime. */ + UA_StatusCode (*updateCertificateAndPrivateKey)(UA_SecurityPolicy *policy, + const UA_ByteString newCertificate, + const UA_ByteString newPrivateKey); + + /* Deletes the dynamic content of the policy */ + void (*clear)(UA_SecurityPolicy *policy); + }; + +PubSub SecurityPolicy +--------------------- + +For PubSub encryption, the message nonce is part of the (unencrypted) +SecurityHeader. The nonce is required for the de- and encryption and has to +be set in the channel context before de/encrypting. + +.. code-block:: c + + + #ifdef UA_ENABLE_PUBSUB_ENCRYPTION + struct UA_PubSubSecurityPolicy; + typedef struct UA_PubSubSecurityPolicy UA_PubSubSecurityPolicy; + + struct UA_PubSubSecurityPolicy { + UA_String policyUri; /* The policy uri that identifies the implemented + * algorithms */ + UA_SecurityPolicySymmetricModule symmetricModule; + + /* Create the context for the WriterGroup. The keys and nonce can be NULL + * here. Then they have to be set before the first encryption or signing + * operation. */ + UA_StatusCode + (*newContext)(void *policyContext, + const UA_ByteString *signingKey, + const UA_ByteString *encryptingKey, + const UA_ByteString *keyNonce, + void **wgContext); + + /* Delete the WriterGroup SecurityPolicy context */ + void (*deleteContext)(void *wgContext); + + /* Set the keys and nonce for the WriterGroup. This is returned from the + * GetSecurityKeys method of a Security Key Service (SKS). Otherwise, set + * manually via out-of-band transmission of the keys. */ + UA_StatusCode + (*setSecurityKeys)(void *wgContext, + const UA_ByteString *signingKey, + const UA_ByteString *encryptingKey, + const UA_ByteString *keyNonce) + ; + + /* The nonce is contained in the NetworkMessage SecurityHeader. Set before + * each en-/decryption step. */ + UA_StatusCode + (*setMessageNonce)(void *wgContext, + const UA_ByteString *nonce) + ; + + const UA_Logger *logger; + + /* Deletes the dynamic content of the policy */ + void (*clear)(UA_PubSubSecurityPolicy *policy); + void *policyContext; + }; + + #endif diff --git a/static/doc/v1.4.0/_sources/pubsub.rst.txt b/static/doc/v1.4.0/_sources/pubsub.rst.txt new file mode 100644 index 0000000000..7be9c7898f --- /dev/null +++ b/static/doc/v1.4.0/_sources/pubsub.rst.txt @@ -0,0 +1,977 @@ +.. _pubsub: + +PubSub +====== + +In PubSub the participating OPC UA Applications take their roles as +Publishers and Subscribers. Publishers are the sources of data, while +Subscribers consume that data. Communication in PubSub is message-based. +Publishers send messages to a Message Oriented Middleware, without knowledge +of what, if any, Subscribers there may be. Similarly, Subscribers express +interest in specific types of data, and process messages that contain this +data, without knowledge of what Publishers there are. + +Message Oriented Middleware is software or hardware infrastructure that +supports sending and receiving messages between distributed systems. OPC UA +PubSub supports two different Message Oriented Middleware variants, namely +the broker-less form and broker-based form. A broker-less form is where the +Message Oriented Middleware is the network infrastructure that is able to +route datagram-based messages. Subscribers and Publishers use datagram +protocols like UDP. In a broker-based form, the core component of the Message +Oriented Middleware is a message Broker. Subscribers and Publishers use +standard messaging protocols like AMQP or MQTT to communicate with the +Broker. + +This makes PubSub suitable for applications where location independence +and/or scalability are required. + +The Publish/Subscribe (PubSub) extension for OPC UA enables fast and +efficient 1:m communication. The PubSub extension is protocol agnostic and +can be used with broker based protocols like MQTT and AMQP or brokerless +implementations like UDP-Multicasting. + +The configuration model for PubSub uses the following components: + +.. code-block:: c + + + typedef enum { + UA_PUBSUB_COMPONENT_CONNECTION, + UA_PUBSUB_COMPONENT_WRITERGROUP, + UA_PUBSUB_COMPONENT_DATASETWRITER, + UA_PUBSUB_COMPONENT_READERGROUP, + UA_PUBSUB_COMPONENT_DATASETREADER + } UA_PubSubComponentEnumType; + +The open62541 PubSub API uses the following scheme: + +1. Create a configuration for the needed PubSub element. + +2. Call the add[element] function and pass in the configuration. + +3. The add[element] function returns the unique nodeId of the internally created element. + +Take a look on the PubSub Tutorials for more details about the API usage:: + + +-----------+ + | UA_Server | + +-----------+ + | | + | | + | | + | | +----------------------+ + | +--> UA_PubSubConnection | UA_Server_addPubSubConnection + | +----------------------+ + | | | + | | | +----------------+ + | | +----> UA_WriterGroup | UA_PubSubConnection_addWriterGroup + | | +----------------+ + | | | + | | | +------------------+ + | | +----> UA_DataSetWriter | UA_WriterGroup_addDataSetWriter +-+ + | | +------------------+ | + | | | + | | +----------------+ | r + | +---------> UA_ReaderGroup | UA_PubSubConnection_addReaderGroup | e + | +----------------+ | f + | | | + | | +------------------+ | + | +----> UA_DataSetReader | UA_ReaderGroup_addDataSetReader | + | +------------------+ | + | | | + | | +----------------------+ | + | +----> UA_SubscribedDataSet | | + | +----------------------+ | + | | | + | | +----------------------------+ | + | +----> UA_TargetVariablesDataType | | + | | +----------------------------+ | + | | | + | | +------------------------------------+ | + | +----> UA_SubscribedDataSetMirrorDataType | | + | +------------------------------------+ | + | | + | +---------------------------+ | + +-------> UA_PubSubPublishedDataSet | UA_Server_addPublishedDataSet <-+ + +---------------------------+ + | + | +-----------------+ + +----> UA_DataSetField | UA_PublishedDataSet_addDataSetField + +-----------------+ + +PubSub Information Model Representation +--------------------------------------- +.. _pubsub_informationmodel: + +The complete PubSub configuration is available inside the information model. +The entry point is the node 'PublishSubscribe', located under the Server +node. +The standard defines for PubSub no new Service set. The configuration can +optionally be done over methods inside the information model. +The information model representation of the current PubSub configuration is +generated automatically. This feature can be enabled/disabled by changing the +UA_ENABLE_PUBSUB_INFORMATIONMODEL option. + +Connections +----------- +The PubSub connections are the abstraction between the concrete transport protocol +and the PubSub functionality. It is possible to create multiple connections with +different transport protocols at runtime. + +.. code-block:: c + + + /* Valid PublisherId types from Part 14 */ + typedef enum { + UA_PUBLISHERIDTYPE_BYTE = 0, + UA_PUBLISHERIDTYPE_UINT16 = 1, + UA_PUBLISHERIDTYPE_UINT32 = 2, + UA_PUBLISHERIDTYPE_UINT64 = 3, + UA_PUBLISHERIDTYPE_STRING = 4 + } UA_PublisherIdType; + + /* Publisher Id + Valid types are defined in Part 14, 7.2.2.2.2 NetworkMessage Layout: + + Bit range 0-2: PublisherId Type + 000 The PublisherId is of DataType Byte This is the default value if ExtendedFlags1 is omitted + 001 The PublisherId is of DataType UInt16 + 010 The PublisherId is of DataType UInt32 + 011 The PublisherId is of DataType UInt64 + 100 The PublisherId is of DataType String + */ + typedef union { + UA_Byte byte; + UA_UInt16 uint16; + UA_UInt32 uint32; + UA_UInt64 uint64; + UA_String string; + } UA_PublisherId; + + typedef struct { + UA_String name; + UA_Boolean enabled; + UA_PublisherIdType publisherIdType; + UA_PublisherId publisherId; + UA_String transportProfileUri; + UA_Variant address; + UA_KeyValueMap connectionProperties; + UA_Variant connectionTransportSettings; + + UA_EventLoop *eventLoop; /* Use an external EventLoop (use the EventLoop of + * the server if this is NULL). Propagates to the + * ReaderGroup/WriterGroup attached to the + * Connection. */ + } UA_PubSubConnectionConfig; + + #ifdef UA_ENABLE_PUBSUB_MONITORING + + typedef enum { + UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT + // extend as needed + } UA_PubSubMonitoringType; + + /* PubSub monitoring interface */ + typedef struct { + UA_StatusCode (*createMonitoring)(UA_Server *server, UA_NodeId Id, + UA_PubSubComponentEnumType eComponentType, + UA_PubSubMonitoringType eMonitoringType, + void *data, UA_ServerCallback callback); + UA_StatusCode (*startMonitoring)(UA_Server *server, UA_NodeId Id, + UA_PubSubComponentEnumType eComponentType, + UA_PubSubMonitoringType eMonitoringType, void *data); + UA_StatusCode (*stopMonitoring)(UA_Server *server, UA_NodeId Id, + UA_PubSubComponentEnumType eComponentType, + UA_PubSubMonitoringType eMonitoringType, void *data); + UA_StatusCode (*updateMonitoringInterval)(UA_Server *server, UA_NodeId Id, + UA_PubSubComponentEnumType eComponentType, + UA_PubSubMonitoringType eMonitoringType, + void *data); + UA_StatusCode (*deleteMonitoring)(UA_Server *server, UA_NodeId Id, + UA_PubSubComponentEnumType eComponentType, + UA_PubSubMonitoringType eMonitoringType, void *data); + } UA_PubSubMonitoringInterface; + + #endif /* UA_ENABLE_PUBSUB_MONITORING */ + + /* General PubSub configuration */ + struct UA_PubSubConfiguration { + /* Callback for PubSub component state changes: If provided this callback + * informs the application about PubSub component state changes. E.g. state + * change from operational to error in case of a DataSetReader + * MessageReceiveTimeout. The status code provides additional + * information. */ + void (*stateChangeCallback)(UA_Server *server, UA_NodeId *id, + UA_PubSubState state, UA_StatusCode status); + + UA_Boolean enableDeltaFrames; + + #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL + UA_Boolean enableInformationModelMethods; + #endif + + #ifdef UA_ENABLE_PUBSUB_ENCRYPTION + /* PubSub security policies */ + size_t securityPoliciesSize; + UA_PubSubSecurityPolicy *securityPolicies; + #endif + + #ifdef UA_ENABLE_PUBSUB_MONITORING + UA_PubSubMonitoringInterface monitoringInterface; + #endif + }; + + /* Add a new PubSub connection to the given server and open it. + * @param server The server to add the connection to. + * @param connectionConfig The configuration for the newly added connection. + * @param connectionIdentifier If not NULL will be set to the identifier of the + * newly added connection. + * @return UA_STATUSCODE_GOOD if connection was successfully added, otherwise an + * error code. */ + UA_StatusCode UA_THREADSAFE + UA_Server_addPubSubConnection(UA_Server *server, + const UA_PubSubConnectionConfig *connectionConfig, + UA_NodeId *connectionIdentifier); + + /* Returns a deep copy of the config */ + UA_StatusCode UA_THREADSAFE + UA_Server_getPubSubConnectionConfig(UA_Server *server, + const UA_NodeId connection, + UA_PubSubConnectionConfig *config); + + /* Remove Connection, identified by the NodeId. Deletion of Connection + * removes all contained WriterGroups and Writers. */ + UA_StatusCode UA_THREADSAFE + UA_Server_removePubSubConnection(UA_Server *server, const UA_NodeId connection); + +PublishedDataSets +----------------- +The PublishedDataSets (PDS) are containers for the published information. The +PDS contain the published variables and meta information. The metadata is +commonly autogenerated or given as constant argument as part of the template +functions. The template functions are standard defined and intended for +configuration tools. You should normally create an empty PDS and call the +functions to add new fields. + +.. code-block:: c + + + /* The UA_PUBSUB_DATASET_PUBLISHEDITEMS has currently no additional members and + * thus no dedicated config structure. */ + + typedef enum { + UA_PUBSUB_DATASET_PUBLISHEDITEMS, + UA_PUBSUB_DATASET_PUBLISHEDEVENTS, + UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE, + UA_PUBSUB_DATASET_PUBLISHEDEVENTS_TEMPLATE, + } UA_PublishedDataSetType; + + typedef struct { + UA_DataSetMetaDataType metaData; + size_t variablesToAddSize; + UA_PublishedVariableDataType *variablesToAdd; + } UA_PublishedDataItemsTemplateConfig; + + typedef struct { + UA_NodeId eventNotfier; + UA_ContentFilter filter; + } UA_PublishedEventConfig; + + typedef struct { + UA_DataSetMetaDataType metaData; + UA_NodeId eventNotfier; + size_t selectedFieldsSize; + UA_SimpleAttributeOperand *selectedFields; + UA_ContentFilter filter; + } UA_PublishedEventTemplateConfig; + + /* Configuration structure for PublishedDataSet */ + typedef struct { + UA_String name; + UA_PublishedDataSetType publishedDataSetType; + union { + /* The UA_PUBSUB_DATASET_PUBLISHEDITEMS has currently no additional members + * and thus no dedicated config structure.*/ + UA_PublishedDataItemsTemplateConfig itemsTemplate; + UA_PublishedEventConfig event; + UA_PublishedEventTemplateConfig eventTemplate; + } config; + } UA_PublishedDataSetConfig; + + void + UA_PublishedDataSetConfig_clear(UA_PublishedDataSetConfig *pdsConfig); + + typedef struct { + UA_StatusCode addResult; + size_t fieldAddResultsSize; + UA_StatusCode *fieldAddResults; + UA_ConfigurationVersionDataType configurationVersion; + } UA_AddPublishedDataSetResult; + + UA_AddPublishedDataSetResult UA_THREADSAFE + UA_Server_addPublishedDataSet(UA_Server *server, + const UA_PublishedDataSetConfig *publishedDataSetConfig, + UA_NodeId *pdsIdentifier); + + /* Returns a deep copy of the config */ + UA_StatusCode UA_THREADSAFE + UA_Server_getPublishedDataSetConfig(UA_Server *server, const UA_NodeId pds, + UA_PublishedDataSetConfig *config); + + /* Returns a deep copy of the DataSetMetaData for an specific PDS */ + UA_StatusCode UA_THREADSAFE + UA_Server_getPublishedDataSetMetaData(UA_Server *server, const UA_NodeId pds, + UA_DataSetMetaDataType *metaData); + + /* Remove PublishedDataSet, identified by the NodeId. Deletion of PDS removes + * all contained and linked PDS Fields. Connected WriterGroups will be also + * removed. */ + UA_StatusCode UA_THREADSAFE + UA_Server_removePublishedDataSet(UA_Server *server, const UA_NodeId pds); + +DataSetFields +------------- +The description of published variables is named DataSetField. Each +DataSetField contains the selection of one information model node. The +DataSetField has additional parameters for the publishing, sampling and error +handling process. + +.. code-block:: c + + + typedef struct{ + UA_ConfigurationVersionDataType configurationVersion; + UA_String fieldNameAlias; + UA_Boolean promotedField; + UA_PublishedVariableDataType publishParameters; + + /* non std. field */ + struct { + UA_Boolean rtFieldSourceEnabled; + /* If the rtInformationModelNode is set, the nodeid in publishParameter must point + * to a node with external data source backend defined + * */ + UA_Boolean rtInformationModelNode; + //TODO -> decide if suppress C++ warnings and use 'UA_DataValue * * const staticValueSource;' + UA_DataValue ** staticValueSource; + } rtValueSource; + UA_UInt32 maxStringLength; + + } UA_DataSetVariableConfig; + + typedef enum { + UA_PUBSUB_DATASETFIELD_VARIABLE, + UA_PUBSUB_DATASETFIELD_EVENT + } UA_DataSetFieldType; + + typedef struct { + UA_DataSetFieldType dataSetFieldType; + union { + /* events need other config later */ + UA_DataSetVariableConfig variable; + } field; + } UA_DataSetFieldConfig; + + void + UA_DataSetFieldConfig_clear(UA_DataSetFieldConfig *dataSetFieldConfig); + + typedef struct { + UA_StatusCode result; + UA_ConfigurationVersionDataType configurationVersion; + } UA_DataSetFieldResult; + + UA_DataSetFieldResult UA_THREADSAFE + UA_Server_addDataSetField(UA_Server *server, + const UA_NodeId publishedDataSet, + const UA_DataSetFieldConfig *fieldConfig, + UA_NodeId *fieldIdentifier); + + /* Returns a deep copy of the config */ + UA_StatusCode UA_THREADSAFE + UA_Server_getDataSetFieldConfig(UA_Server *server, const UA_NodeId dsf, + UA_DataSetFieldConfig *config); + + UA_DataSetFieldResult UA_THREADSAFE + UA_Server_removeDataSetField(UA_Server *server, const UA_NodeId dsf); + +Custom Callback Implementation +------------------------------ +The user can use his own callback implementation for publishing +and subscribing. The user must take care of the callback to call for +every publishing or subscibing interval + +.. code-block:: c + + + typedef struct { + /* User's callback implementation. The user configured base time and timer policy + * will be provided as an argument to this callback so that the user can + * implement his callback (thread) considering base time and timer policies */ + UA_StatusCode (*addCustomCallback)(UA_Server *server, UA_NodeId identifier, + UA_ServerCallback callback, + void *data, UA_Double interval_ms, + UA_DateTime *baseTime, UA_TimerPolicy timerPolicy, + UA_UInt64 *callbackId); + + UA_StatusCode (*changeCustomCallback)(UA_Server *server, UA_NodeId identifier, + UA_UInt64 callbackId, UA_Double interval_ms, + UA_DateTime *baseTime, UA_TimerPolicy timerPolicy); + + void (*removeCustomCallback)(UA_Server *server, UA_NodeId identifier, UA_UInt64 callbackId); + + } UA_PubSub_CallbackLifecycle; + +WriterGroup +----------- +All WriterGroups are created within a PubSubConnection and automatically +deleted if the connection is removed. The WriterGroup is primary used as +container for :ref:`dsw` and network message settings. The WriterGroup can be +imagined as producer of the network messages. The creation of network +messages is controlled by parameters like the publish interval, which is e.g. +contained in the WriterGroup. + +.. code-block:: c + + + typedef enum { + UA_PUBSUB_ENCODING_UADP = 0, + UA_PUBSUB_ENCODING_JSON = 1, + UA_PUBSUB_ENCODING_BINARY = 2 + } UA_PubSubEncodingType; + +WriterGroup +----------- +The message publishing can be configured for realtime requirements. The RT-levels +go along with different requirements. The below listed levels can be configured: + +UA_PUBSUB_RT_NONE - +---> Description: Default "none-RT" Mode +---> Requirements: - +---> Restrictions: - +UA_PUBSUB_RT_DIRECT_VALUE_ACCESS (Preview - not implemented) +---> Description: Normally, the latest value for each DataSetField is read out of the information model. Within this RT-mode, the +value source of each field configured as static pointer to an DataValue. The publish cycle won't use call the server read function. +---> Requirements: All fields must be configured with a 'staticValueSource'. +---> Restrictions: - +UA_PUBSUB_RT_FIXED_LENGTH (Preview - not implemented) +---> Description: All DataSetFields have a known, non-changing length. The server will pre-generate some +buffers and use only memcopy operations to generate requested PubSub packages. +---> Requirements: DataSetFields with variable size cannot be used within this mode. +---> Restrictions: The configuration must be frozen and changes are not allowed while the WriterGroup is 'Operational'. +UA_PUBSUB_RT_DETERMINISTIC (Preview - not implemented) +---> Description: - +---> Requirements: - +---> Restrictions: - + +WARNING! For hard real time requirements the underlying system must be rt-capable. + + +.. code-block:: c + + typedef enum { + UA_PUBSUB_RT_NONE = 0, + UA_PUBSUB_RT_DIRECT_VALUE_ACCESS = 1, + UA_PUBSUB_RT_FIXED_SIZE = 2, + UA_PUBSUB_RT_DETERMINISTIC = 4, + } UA_PubSubRTLevel; + + typedef struct { + UA_String name; + UA_Boolean enabled; + UA_UInt16 writerGroupId; + UA_Duration publishingInterval; + UA_Double keepAliveTime; + UA_Byte priority; + UA_ExtensionObject transportSettings; + UA_ExtensionObject messageSettings; + UA_KeyValueMap groupProperties; + UA_PubSubEncodingType encodingMimeType; + /* PubSub Manager Callback */ + UA_PubSub_CallbackLifecycle pubsubManagerCallback; + /* non std. config parameter. maximum count of embedded DataSetMessage in + * one NetworkMessage */ + UA_UInt16 maxEncapsulatedDataSetMessageCount; + /* non std. field */ + UA_PubSubRTLevel rtLevel; + + /* Message are encrypted if a SecurityPolicy is configured and the + * securityMode set accordingly. The symmetric key is a runtime information + * and has to be set via UA_Server_setWriterGroupEncryptionKey. */ + UA_MessageSecurityMode securityMode; /* via the UA_WriterGroupDataType */ + #ifdef UA_ENABLE_PUBSUB_ENCRYPTION + UA_PubSubSecurityPolicy *securityPolicy; + UA_String securityGroupId; + #endif + } UA_WriterGroupConfig; + + void + UA_WriterGroupConfig_clear(UA_WriterGroupConfig *writerGroupConfig); + + /* Add a new WriterGroup to an existing Connection */ + UA_StatusCode UA_THREADSAFE + UA_Server_addWriterGroup(UA_Server *server, const UA_NodeId connection, + const UA_WriterGroupConfig *writerGroupConfig, + UA_NodeId *writerGroupIdentifier); + + /* Returns a deep copy of the config */ + UA_StatusCode UA_THREADSAFE + UA_Server_getWriterGroupConfig(UA_Server *server, const UA_NodeId writerGroup, + UA_WriterGroupConfig *config); + + UA_StatusCode UA_THREADSAFE + UA_Server_updateWriterGroupConfig(UA_Server *server, UA_NodeId writerGroupIdentifier, + const UA_WriterGroupConfig *config); + + /* Get state of WriterGroup */ + UA_StatusCode UA_THREADSAFE + UA_Server_WriterGroup_getState(UA_Server *server, UA_NodeId writerGroupIdentifier, + UA_PubSubState *state); + + UA_StatusCode UA_THREADSAFE + UA_Server_WriterGroup_publish(UA_Server *server, const UA_NodeId writerGroupIdentifier); + + UA_StatusCode UA_THREADSAFE + UA_WriterGroup_lastPublishTimestamp(UA_Server *server, const UA_NodeId writerGroupId, + UA_DateTime *timestamp); + + UA_StatusCode UA_THREADSAFE + UA_Server_removeWriterGroup(UA_Server *server, const UA_NodeId writerGroup); + + UA_StatusCode UA_THREADSAFE + UA_Server_freezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writerGroup); + + UA_StatusCode UA_THREADSAFE + UA_Server_unfreezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writerGroup); + + UA_StatusCode UA_THREADSAFE + UA_Server_setWriterGroupOperational(UA_Server *server, const UA_NodeId writerGroup); + + UA_StatusCode UA_THREADSAFE + UA_Server_setWriterGroupDisabled(UA_Server *server, const UA_NodeId writerGroup); + + #ifdef UA_ENABLE_PUBSUB_ENCRYPTION + /* Set the group key for the message encryption */ + UA_StatusCode UA_THREADSAFE + UA_Server_setWriterGroupEncryptionKeys(UA_Server *server, const UA_NodeId writerGroup, + UA_UInt32 securityTokenId, + const UA_ByteString signingKey, + const UA_ByteString encryptingKey, + const UA_ByteString keyNonce); + #endif + +.. _dsw: + +DataSetWriter +------------- +The DataSetWriters are the glue between the WriterGroups and the +PublishedDataSets. The DataSetWriter contain configuration parameters and +flags which influence the creation of DataSet messages. These messages are +encapsulated inside the network message. The DataSetWriter must be linked +with an existing PublishedDataSet and be contained within a WriterGroup. + +.. code-block:: c + + + typedef struct { + UA_String name; + UA_UInt16 dataSetWriterId; + UA_DataSetFieldContentMask dataSetFieldContentMask; + UA_UInt32 keyFrameCount; + UA_ExtensionObject messageSettings; + UA_ExtensionObject transportSettings; + UA_String dataSetName; + UA_KeyValueMap dataSetWriterProperties; + } UA_DataSetWriterConfig; + + void + UA_DataSetWriterConfig_clear(UA_DataSetWriterConfig *pdsConfig); + + /* Add a new DataSetWriter to an existing WriterGroup. The DataSetWriter must be + * coupled with a PublishedDataSet on creation. + * + * Part 14, 7.1.5.2.1 defines: The link between the PublishedDataSet and + * DataSetWriter shall be created when an instance of the DataSetWriterType is + * created. */ + UA_StatusCode UA_THREADSAFE + UA_Server_addDataSetWriter(UA_Server *server, + const UA_NodeId writerGroup, const UA_NodeId dataSet, + const UA_DataSetWriterConfig *dataSetWriterConfig, + UA_NodeId *writerIdentifier); + + /* Returns a deep copy of the config */ + UA_StatusCode UA_THREADSAFE + UA_Server_getDataSetWriterConfig(UA_Server *server, const UA_NodeId dsw, + UA_DataSetWriterConfig *config); + + /* Get state of DataSetWriter */ + UA_StatusCode UA_THREADSAFE + UA_Server_DataSetWriter_getState(UA_Server *server, UA_NodeId dataSetWriterIdentifier, + UA_PubSubState *state); + + UA_StatusCode UA_THREADSAFE + UA_Server_removeDataSetWriter(UA_Server *server, const UA_NodeId dsw); + +SubscribedDataSet +----------------- +SubscribedDataSet describes the processing of the received DataSet. +SubscribedDataSet defines which field in the DataSet is mapped to which +Variable in the OPC UA Application. SubscribedDataSet has two sub-types +called the TargetVariablesType and SubscribedDataSetMirrorType. +SubscribedDataSetMirrorType is currently not supported. SubscribedDataSet is +set to TargetVariablesType and then the list of target Variables are created +in the Subscriber AddressSpace. TargetVariables are a list of variables that +are to be added in the Subscriber AddressSpace. It defines a list of Variable +mappings between received DataSet fields and added Variables in the +Subscriber AddressSpace. + +.. code-block:: c + + + /* SubscribedDataSetDataType Definition */ + typedef enum { + UA_PUBSUB_SDS_TARGET, + UA_PUBSUB_SDS_MIRROR + } UA_SubscribedDataSetEnumType; + + typedef struct { + /* Standard-defined FieldTargetDataType */ + UA_FieldTargetDataType targetVariable; + + /* If realtime-handling is required, set this pointer non-NULL and it will be used + * to memcpy the value instead of using the Write service. + * If the beforeWrite method pointer is set, it will be called before a memcpy update + * to the value. But param externalDataValue already contains the new value. + * If the afterWrite method pointer is set, it will be called after a memcpy update + * to the value. */ + UA_DataValue **externalDataValue; + void *targetVariableContext; /* user-defined pointer */ + void (*beforeWrite)(UA_Server *server, + const UA_NodeId *readerIdentifier, + const UA_NodeId *readerGroupIdentifier, + const UA_NodeId *targetVariableIdentifier, + void *targetVariableContext, + UA_DataValue **externalDataValue); + void (*afterWrite)(UA_Server *server, + const UA_NodeId *readerIdentifier, + const UA_NodeId *readerGroupIdentifier, + const UA_NodeId *targetVariableIdentifier, + void *targetVariableContext, + UA_DataValue **externalDataValue); + } UA_FieldTargetVariable; + + typedef struct { + size_t targetVariablesSize; + UA_FieldTargetVariable *targetVariables; + } UA_TargetVariables; + + /* Return Status Code after creating TargetVariables in Subscriber AddressSpace */ + UA_StatusCode UA_THREADSAFE + UA_Server_DataSetReader_createTargetVariables(UA_Server *server, + UA_NodeId dataSetReaderIdentifier, + size_t targetVariablesSize, + const UA_FieldTargetVariable *targetVariables); + + /* To Do:Implementation of SubscribedDataSetMirrorType + * UA_StatusCode + * A_PubSubDataSetReader_createDataSetMirror(UA_Server *server, UA_NodeId dataSetReaderIdentifier, + * UA_SubscribedDataSetMirrorDataType* mirror) */ + +DataSetReader +------------- +DataSetReader can receive NetworkMessages with the DataSetMessage +of interest sent by the Publisher. DataSetReaders represent +the configuration necessary to receive and process DataSetMessages +on the Subscriber side. DataSetReader must be linked with a +SubscribedDataSet and be contained within a ReaderGroup. + +.. code-block:: c + + + typedef enum { + UA_PUBSUB_RT_UNKNOWN = 0, + UA_PUBSUB_RT_VARIANT = 1, + UA_PUBSUB_RT_DATA_VALUE = 2, + UA_PUBSUB_RT_RAW = 4, + } UA_PubSubRtEncoding; + + /* Parameters for PubSub DataSetReader Configuration */ + typedef struct { + UA_String name; + UA_Variant publisherId; + UA_UInt16 writerGroupId; + UA_UInt16 dataSetWriterId; + UA_DataSetMetaDataType dataSetMetaData; + UA_DataSetFieldContentMask dataSetFieldContentMask; + UA_Double messageReceiveTimeout; + UA_ExtensionObject messageSettings; + UA_ExtensionObject transportSettings; + UA_SubscribedDataSetEnumType subscribedDataSetType; + /* TODO UA_SubscribedDataSetMirrorDataType subscribedDataSetMirror */ + union { + UA_TargetVariables subscribedDataSetTarget; + // UA_SubscribedDataSetMirrorDataType subscribedDataSetMirror; + } subscribedDataSet; + /* non std. fields */ + UA_String linkedStandaloneSubscribedDataSetName; + UA_PubSubRtEncoding expectedEncoding; + } UA_DataSetReaderConfig; + + /* Copy the configuration of DataSetReader */ + UA_StatusCode + UA_DataSetReaderConfig_copy(const UA_DataSetReaderConfig *src, + UA_DataSetReaderConfig *dst); + + /* Clear the configuration of a DataSetReader */ + void + UA_DataSetReaderConfig_clear(UA_DataSetReaderConfig *cfg); + + /* Update configuration to the DataSetReader */ + UA_StatusCode UA_THREADSAFE + UA_Server_DataSetReader_updateConfig(UA_Server *server, UA_NodeId dataSetReaderIdentifier, + UA_NodeId readerGroupIdentifier, + const UA_DataSetReaderConfig *config); + + /* Get the configuration (copy) of the DataSetReader */ + UA_StatusCode UA_THREADSAFE + UA_Server_DataSetReader_getConfig(UA_Server *server, UA_NodeId dataSetReaderIdentifier, + UA_DataSetReaderConfig *config); + + /* Get state of DataSetReader */ + UA_StatusCode UA_THREADSAFE + UA_Server_DataSetReader_getState(UA_Server *server, UA_NodeId dataSetReaderIdentifier, + UA_PubSubState *state); + + typedef struct { + UA_String name; + UA_SubscribedDataSetEnumType subscribedDataSetType; + union { + /* datasetmirror is currently not implemented */ + UA_TargetVariablesDataType target; + } subscribedDataSet; + UA_DataSetMetaDataType dataSetMetaData; + UA_Boolean isConnected; + } UA_StandaloneSubscribedDataSetConfig; + + void + UA_StandaloneSubscribedDataSetConfig_clear(UA_StandaloneSubscribedDataSetConfig *sdsConfig); + + UA_StatusCode UA_THREADSAFE + UA_Server_addStandaloneSubscribedDataSet(UA_Server *server, + const UA_StandaloneSubscribedDataSetConfig *subscribedDataSetConfig, + UA_NodeId *sdsIdentifier); + + /* Remove StandaloneSubscribedDataSet, identified by the NodeId. */ + UA_StatusCode UA_THREADSAFE + UA_Server_removeStandaloneSubscribedDataSet(UA_Server *server, const UA_NodeId sds); + +ReaderGroup +----------- + +ReaderGroup is used to group a list of DataSetReaders. All ReaderGroups are +created within a PubSubConnection and automatically deleted if the connection +is removed. All network message related filters are only available in the +DataSetReader. + +The RT-levels go along with different requirements. The below listed levels +can be configured for a ReaderGroup. + +- UA_PUBSUB_RT_NONE: RT applied to this level +- PUBSUB_CONFIG_FASTPATH_FIXED_OFFSETS: Extends PubSub RT functionality and + implements fast path message decoding in the Subscriber. Uses a buffered + network message and only decodes the necessary offsets stored in an offset + buffer. + +.. code-block:: c + + + /* ReaderGroup configuration */ + typedef struct { + UA_String name; + + /* non std. field */ + UA_PubSubRTLevel rtLevel; + UA_KeyValueMap groupProperties; + UA_PubSubEncodingType encodingMimeType; + UA_ExtensionObject transportSettings; + + /* Messages are decrypted if a SecurityPolicy is configured and the + * securityMode set accordingly. The symmetric key is a runtime information + * and has to be set via UA_Server_setReaderGroupEncryptionKey. */ + UA_MessageSecurityMode securityMode; + #ifdef UA_ENABLE_PUBSUB_ENCRYPTION + UA_PubSubSecurityPolicy *securityPolicy; + UA_String securityGroupId; + #endif + } UA_ReaderGroupConfig; + + void + UA_ReaderGroupConfig_clear(UA_ReaderGroupConfig *readerGroupConfig); + + /* Add DataSetReader to the ReaderGroup */ + UA_StatusCode UA_THREADSAFE + UA_Server_addDataSetReader(UA_Server *server, UA_NodeId readerGroupIdentifier, + const UA_DataSetReaderConfig *dataSetReaderConfig, + UA_NodeId *readerIdentifier); + + /* Remove DataSetReader from ReaderGroup */ + UA_StatusCode UA_THREADSAFE + UA_Server_removeDataSetReader(UA_Server *server, UA_NodeId readerIdentifier); + + /* To Do: Update Configuration of ReaderGroup + * UA_StatusCode + * UA_Server_ReaderGroup_updateConfig(UA_Server *server, UA_NodeId readerGroupIdentifier, + * const UA_ReaderGroupConfig *config); + */ + + /* Get configuraiton of ReaderGroup */ + UA_StatusCode UA_THREADSAFE + UA_Server_ReaderGroup_getConfig(UA_Server *server, UA_NodeId readerGroupIdentifier, + UA_ReaderGroupConfig *config); + + /* Get state of ReaderGroup */ + UA_StatusCode UA_THREADSAFE + UA_Server_ReaderGroup_getState(UA_Server *server, UA_NodeId readerGroupIdentifier, + UA_PubSubState *state); + + /* Add ReaderGroup to the created connection */ + UA_StatusCode UA_THREADSAFE + UA_Server_addReaderGroup(UA_Server *server, UA_NodeId connectionIdentifier, + const UA_ReaderGroupConfig *readerGroupConfig, + UA_NodeId *readerGroupIdentifier); + + /* Remove ReaderGroup from connection */ + UA_StatusCode UA_THREADSAFE + UA_Server_removeReaderGroup(UA_Server *server, UA_NodeId groupIdentifier); + + UA_StatusCode UA_THREADSAFE + UA_Server_freezeReaderGroupConfiguration(UA_Server *server, const UA_NodeId readerGroupId); + + UA_StatusCode UA_THREADSAFE + UA_Server_unfreezeReaderGroupConfiguration(UA_Server *server, const UA_NodeId readerGroupId); + + UA_StatusCode UA_THREADSAFE + UA_Server_setReaderGroupOperational(UA_Server *server, const UA_NodeId readerGroupId); + + UA_StatusCode UA_THREADSAFE + UA_Server_setReaderGroupDisabled(UA_Server *server, const UA_NodeId readerGroupId); + + #ifdef UA_ENABLE_PUBSUB_ENCRYPTION + /* Set the group key for the message encryption */ + UA_StatusCode UA_THREADSAFE + UA_Server_setReaderGroupEncryptionKeys(UA_Server *server, UA_NodeId readerGroup, + UA_UInt32 securityTokenId, + UA_ByteString signingKey, + UA_ByteString encryptingKey, + UA_ByteString keyNonce); + #endif + + #ifdef UA_ENABLE_PUBSUB_SKS + +SecurityGroup +------------- + +A SecurityGroup is an abstraction that represents the message security settings and +security keys for a subset of NetworkMessages exchanged between Publishers and +Subscribers. The SecurityGroup objects are created on a Security Key Service (SKS). The +SKS manages the access to the keys based on the role permission for a user assigned to +a SecurityGroup Object. A SecurityGroup is identified with a unique identifier called +the SecurityGroupId. It is unique within the SKS. + +.. note:: The access to the SecurityGroup and therefore the securitykeys managed by SKS + requires management of Roles and Permissions in the SKS. The Role Permission + model is not supported at the time of writing. However, the access control plugin can + be used to create and manage role permission on SecurityGroup object. + +.. code-block:: c + + + typedef struct { + UA_String securityGroupName; + UA_Duration keyLifeTime; + UA_String securityPolicyUri; + UA_UInt32 maxFutureKeyCount; + UA_UInt32 maxPastKeyCount; + } UA_SecurityGroupConfig; + +@brief Creates a SecurityGroup object and add it to the list in PubSub Manager. If the +information model is enabled then the SecurityGroup object Node is also created in the +server. A keyStorage with initial list of keys is created with a SecurityGroup. A +callback is added to new SecurityGroup which updates the keys periodically at each +KeyLifeTime expire. + +@param server The server instance +@param securityGroupFolderNodeId The parent node of the SecurityGroup. It must be of +SecurityGroupFolderType +@param securityGroupConfig The security settings of a SecurityGroup +@param securityGroupNodeId The output nodeId of the new SecurityGroup +@return UA_StatusCode The return status code + +.. code-block:: c + + UA_StatusCode UA_THREADSAFE + UA_Server_addSecurityGroup(UA_Server *server, UA_NodeId securityGroupFolderNodeId, + const UA_SecurityGroupConfig *securityGroupConfig, + UA_NodeId *securityGroupNodeId); + +@brief Removes the SecurityGroup from PubSub Manager. It removes the KeyStorage +associated with the SecurityGroup from the server. + +@param server The server instance +@param securityGroup The nodeId of the securityGroup to be removed +@return UA_StatusCode The returned status code. + +.. code-block:: c + + UA_StatusCode UA_THREADSAFE + UA_Server_removeSecurityGroup(UA_Server *server, const UA_NodeId securityGroup); + +@brief This is a repeated callback which is triggered on each iteration of SKS Pull request. +The server uses this callback to notify user about the status of current Pull request iteration. +The period is calculated based on the KeylifeTime of specified in the SecurityGroup object node on +the SKS server. + +@param server The server instance managing the publisher/subscriber. +@param sksPullRequestStatus The current status of sks pull request. +@param context The pointer to user defined data passed to this callback. + +.. code-block:: c + + typedef void + (*UA_Server_sksPullRequestCallback)(UA_Server *server, UA_StatusCode sksPullRequestStatus, void* context); + +@brief Sets the SKS client config used to call the GetSecurityKeys Method on SKS and get the +initial set of keys for a SecurityGroupId and adds timedCallback for the next GetSecurityKeys +method Call. This uses async Client API for SKS Pull request. The SKS Client instance is created and destroyed at +runtime on each iteration of SKS Pull request by the server. The key Rollover mechanism will check if the new +keys are needed then it will call the getSecurityKeys Method on SKS Server. At the end of SKS Pull request +iteration, the sks client will be deleted by a delayed callback (in next server iteration). + +@note It is be called before setting Reader/Writer Group into Operational because this also allocates +a channel context for the pubsub security policy. + +@note the stateCallback of sksClientConfig will be overwritten by an internal callback. + +@param server the server instance +@param clientConfig holds the required configuration to make encrypted connection with +SKS Server. The input client config takes the lifecycle as long as SKS request are made. +It is deleted with its plugins when the server is deleted or the last Reader/Writer +Group of the securityGroupId is deleted. The input config is copied to an internal +config object and the content of input config object will be reset to zero. +@param endpointUrl holds the endpointUrl of the SKS server +@param securityGroupId the SecurityGroupId of the securityGroup on SKS and +reader/writergroups +@param callback the user defined callback to notify the user about the status of SKS +Pull request. +@param context passed to the callback function +@return UA_StatusCode the retuned status + +.. code-block:: c + + UA_StatusCode + UA_Server_setSksClient(UA_Server *server, UA_String securityGroupId, + UA_ClientConfig *clientConfig, const char *endpointUrl, + UA_Server_sksPullRequestCallback callback, void *context); + + #endif /* UA_ENABLE_PUBSUB_SKS */ + + #endif /* UA_ENABLE_PUBSUB */ diff --git a/static/doc/v1.4.0/_sources/server.rst.txt b/static/doc/v1.4.0/_sources/server.rst.txt new file mode 100644 index 0000000000..2a83e5e6aa --- /dev/null +++ b/static/doc/v1.4.0/_sources/server.rst.txt @@ -0,0 +1,2009 @@ +.. _server: + +Server +====== + +.. _server-configuration: + +Server Configuration +-------------------- +The configuration structure is passed to the server during initialization. +The server expects that the configuration is not modified during runtime. +Currently, only one server can use a configuration at a time. During +shutdown, the server will clean up the parts of the configuration that are +modified at runtime through the provided API. + +Examples for configurations are provided in the ``/plugins`` folder. +The usual usage is as follows: + +1. Create a server configuration with default settings as a starting point +2. Modifiy the configuration, e.g. by adding a server certificate +3. Instantiate a server with it +4. After shutdown of the server, clean up the configuration (free memory) + +The :ref:`tutorials` provide a good starting point for this. + +.. code-block:: c + + + struct UA_ServerConfig { + void *context; /* Used to attach custom data to a server config. This can + * then be retrieved e.g. in a callback that forwards a + * pointer to the server. */ + UA_Logger *logging; /* Plugin for log output */ + +Server Description +^^^^^^^^^^^^^^^^^^ +The description must be internally consistent. The ApplicationUri set in +the ApplicationDescription must match the URI set in the server +certificate. +The applicationType is not just descriptive, it changes the actual +functionality of the server. The RegisterServer service is available only +if the server is a DiscoveryServer and the applicationType is set to the +appropriate value.*/ + + + + +Server Lifecycle +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + /* Delay in ms from the shutdown signal (ctrl-c) until the actual shutdown. + * Clients need to be able to get a notification ahead of time. */ + UA_Double shutdownDelay; + + /* If an asynchronous server shutdown is used, this callback notifies about + * the current lifecycle state (notably the STOPPING -> STOPPED + * transition). */ + void (*notifyLifecycleState)(UA_Server *server, UA_LifecycleState state); + +Rule Handling +^^^^^^^^^^^^^ +Override the handling of standard-defined behavior. These settings are +used to balance the following contradicting requirements: + +- Strict conformance with the standard (for certification). +- Ensure interoperability with old/non-conforming implementations + encountered in the wild. + +The defaults are set for compatibility with the largest number of OPC UA +vendors (with log warnings activated). Cf. Postel's Law "be conservative +in what you send, be liberal in what you accept". + +See the section :ref:`rule-handling` for the possible settings. + +.. code-block:: c + + + /* Verify that the server sends a timestamp in the request header */ + UA_RuleHandling verifyRequestTimestamp; + + /* Variables (that don't have a DataType of BaseDataType) must not have an + * empty variant value. The default behaviour is to auto-create a matching + * zeroed-out value for empty VariableNodes when they are added. */ + UA_RuleHandling allowEmptyVariables; + +Custom Data Types +^^^^^^^^^^^^^^^^^ +The following is a linked list of arrays with custom data types. All data +types that are accessible from here are automatically considered for the +decoding of received messages. Custom data types are not cleaned up +together with the configuration. So it is possible to allocate them on +ROM. + +See the section on :ref:`generic-types`. Examples for working with custom +data types are provided in ``/examples/custom_datatype/``. + +.. code-block:: c + + const UA_DataTypeArray *customDataTypes; + +.. note:: See the section on :ref:`generic-types`. Examples for working + with custom data types are provided in + ``/examples/custom_datatype/``. + +.. code-block:: c + + +EventLoop +^^^^^^^^^ +The sever can be plugged into an external EventLoop. Otherwise the +EventLoop is considered to be attached to the server's lifecycle and will +be destroyed when the config is cleaned up. + +.. code-block:: c + + UA_EventLoop *eventLoop; + UA_Boolean externalEventLoop; /* The EventLoop is not deleted with the config */ + +Networking +^^^^^^^^^^ +The `severUrls` array contains the server URLs like +`opc.tcp://my-server:4840` or `opc.wss://localhost:443`. The URLs are +used both for discovery and to set up the server sockets based on the +defined hostnames (and ports). + +- If the list is empty: Listen on all network interfaces with TCP port 4840. +- If the hostname of a URL is empty: Use the define protocol and port and + listen on all interfaces. + +.. code-block:: c + + UA_String *serverUrls; + size_t serverUrlsSize; + +The following settings are specific to OPC UA with TCP transport. + +.. code-block:: c + + UA_Boolean tcpEnabled; + UA_UInt32 tcpBufSize; /* Max length of sent and received chunks (packets) + * (default: 64kB) */ + UA_UInt32 tcpMaxMsgSize; /* Max length of messages + * (default: 0 -> unbounded) */ + UA_UInt32 tcpMaxChunks; /* Max number of chunks per message + * (default: 0 -> unbounded) */ + UA_Boolean tcpReuseAddr; + +Security and Encryption +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + size_t securityPoliciesSize; + UA_SecurityPolicy* securityPolicies; + + /* Endpoints with combinations of SecurityPolicy and SecurityMode. If the + * UserIdentityToken array of the Endpoint is not set, then it will be + * filled by the server for all UserTokenPolicies that are configured in the + * AccessControl plugin. */ + size_t endpointsSize; + UA_EndpointDescription *endpoints; + + /* Only allow the following discovery services to be executed on a + * SecureChannel with SecurityPolicyNone: GetEndpointsRequest, + * FindServersRequest and FindServersOnNetworkRequest. + * + * Only enable this option if there is no endpoint with SecurityPolicy#None + * in the endpoints list. The SecurityPolicy#None must be present in the + * securityPolicies list. */ + UA_Boolean securityPolicyNoneDiscoveryOnly; + + /* Allow clients without encryption support to connect with username and password. + * This requires to transmit the password in plain text over the network which is + * why this option is disabled by default. + * Make sure you really need this before enabling plain text passwords. */ + UA_Boolean allowNonePolicyPassword; + + /* Different sets of certificates are trusted for SecureChannel / Session */ + UA_CertificateVerification secureChannelPKI; + UA_CertificateVerification sessionPKI; + +See the section for :ref:`access-control +handling`. + +.. code-block:: c + + UA_AccessControl accessControl; + +Nodes and Node Lifecycle +^^^^^^^^^^^^^^^^^^^^^^^^ +See the section for :ref:`node lifecycle handling`. + +.. code-block:: c + + UA_Nodestore nodestore; + UA_GlobalNodeLifecycle nodeLifecycle; + +Copy the HasModellingRule reference in instances from the type +definition in UA_Server_addObjectNode and UA_Server_addVariableNode. + +Part 3 - 6.4.4: [...] it is not required that newly created or referenced +instances based on InstanceDeclarations have a ModellingRule, however, it +is allowed that they have any ModellingRule independent of the +ModellingRule of their InstanceDeclaration + +.. code-block:: c + + UA_Boolean modellingRulesOnInstances; + +Limits +^^^^^^ + +.. code-block:: c + + /* Limits for SecureChannels */ + UA_UInt16 maxSecureChannels; + UA_UInt32 maxSecurityTokenLifetime; /* in ms */ + + /* Limits for Sessions */ + UA_UInt16 maxSessions; + UA_Double maxSessionTimeout; /* in ms */ + + /* Operation limits */ + UA_UInt32 maxNodesPerRead; + UA_UInt32 maxNodesPerWrite; + UA_UInt32 maxNodesPerMethodCall; + UA_UInt32 maxNodesPerBrowse; + UA_UInt32 maxNodesPerRegisterNodes; + UA_UInt32 maxNodesPerTranslateBrowsePathsToNodeIds; + UA_UInt32 maxNodesPerNodeManagement; + UA_UInt32 maxMonitoredItemsPerCall; + + /* Limits for Requests */ + UA_UInt32 maxReferencesPerNode; + +Async Operations +^^^^^^^^^^^^^^^^ +See the section for :ref:`async operations`. + +.. code-block:: c + + #if UA_MULTITHREADING >= 100 + UA_Double asyncOperationTimeout; /* in ms, 0 => unlimited */ + size_t maxAsyncOperationQueueSize; /* 0 => unlimited */ + /* Notify workers when an async operation was enqueued */ + UA_Server_AsyncOperationNotifyCallback asyncOperationNotifyCallback; + #endif + +Discovery +^^^^^^^^^ + +.. code-block:: c + + #ifdef UA_ENABLE_DISCOVERY + /* Timeout in seconds when to automatically remove a registered server from + * the list, if it doesn't re-register within the given time frame. A value + * of 0 disables automatic removal. Default is 60 Minutes (60*60). Must be + * bigger than 10 seconds, because cleanup is only triggered approximately + * every 10 seconds. The server will still be removed depending on the + * state of the semaphore file. */ + UA_UInt32 discoveryCleanupTimeout; + + # ifdef UA_ENABLE_DISCOVERY_MULTICAST + UA_Boolean mdnsEnabled; + UA_MdnsDiscoveryConfiguration mdnsConfig; + UA_String mdnsInterfaceIP; + # if !defined(UA_HAS_GETIFADDR) + size_t mdnsIpAddressListSize; + UA_UInt32 *mdnsIpAddressList; + # endif + # endif + #endif + +Subscriptions +^^^^^^^^^^^^^ + +.. code-block:: c + + UA_Boolean subscriptionsEnabled; + #ifdef UA_ENABLE_SUBSCRIPTIONS + /* Limits for Subscriptions */ + UA_UInt32 maxSubscriptions; + UA_UInt32 maxSubscriptionsPerSession; + UA_DurationRange publishingIntervalLimits; /* in ms (must not be less than 5) */ + UA_UInt32Range lifeTimeCountLimits; + UA_UInt32Range keepAliveCountLimits; + UA_UInt32 maxNotificationsPerPublish; + UA_Boolean enableRetransmissionQueue; + UA_UInt32 maxRetransmissionQueueSize; /* 0 -> unlimited size */ + # ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS + UA_UInt32 maxEventsPerNode; /* 0 -> unlimited size */ + # endif + + /* Limits for MonitoredItems */ + UA_UInt32 maxMonitoredItems; + UA_UInt32 maxMonitoredItemsPerSubscription; + UA_DurationRange samplingIntervalLimits; /* in ms (must not be less than 5) */ + UA_UInt32Range queueSizeLimits; /* Negotiated with the client */ + + /* Limits for PublishRequests */ + UA_UInt32 maxPublishReqPerSession; + + /* Register MonitoredItem in Userland + * + * @param server Allows the access to the server object + * @param sessionId The session id, represented as an node id + * @param sessionContext An optional pointer to user-defined data for the + * specific data source + * @param nodeid Id of the node in question + * @param nodeidContext An optional pointer to user-defined data, associated + * with the node in the nodestore. Note that, if the node has already + * been removed, this value contains a NULL pointer. + * @param attributeId Identifies which attribute (value, data type etc.) is + * monitored + * @param removed Determines if the MonitoredItem was removed or created. */ + void (*monitoredItemRegisterCallback)(UA_Server *server, + const UA_NodeId *sessionId, + void *sessionContext, + const UA_NodeId *nodeId, + void *nodeContext, + UA_UInt32 attibuteId, + UA_Boolean removed); + #endif + +PubSub +^^^^^^ + +.. code-block:: c + + UA_Boolean pubsubEnabled; + #ifdef UA_ENABLE_PUBSUB + UA_PubSubConfiguration pubSubConfig; + #endif + +Historical Access +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + UA_Boolean historizingEnabled; + #ifdef UA_ENABLE_HISTORIZING + UA_HistoryDatabase historyDatabase; + + UA_Boolean accessHistoryDataCapability; + UA_UInt32 maxReturnDataValues; /* 0 -> unlimited size */ + + UA_Boolean accessHistoryEventsCapability; + UA_UInt32 maxReturnEventValues; /* 0 -> unlimited size */ + + UA_Boolean insertDataCapability; + UA_Boolean insertEventCapability; + UA_Boolean insertAnnotationsCapability; + + UA_Boolean replaceDataCapability; + UA_Boolean replaceEventCapability; + + UA_Boolean updateDataCapability; + UA_Boolean updateEventCapability; + + UA_Boolean deleteRawCapability; + UA_Boolean deleteEventCapability; + UA_Boolean deleteAtTimeDataCapability; + #endif + +Reverse Connect +^^^^^^^^^^^^^^^ + +.. code-block:: c + + UA_UInt32 reverseReconnectInterval; /* Default is 15000 ms */ + +Certificate Password Callback +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + #ifdef UA_ENABLE_ENCRYPTION + /* If the private key is in PEM format and password protected, this callback + * is called during initialization to get the password to decrypt the + * private key. The memory containing the password is freed by the client + * after use. The callback should be set early, other parts of the client + * config setup may depend on it. */ + UA_StatusCode (*privateKeyPasswordCallback)(UA_ServerConfig *sc, + UA_ByteString *password); + #endif + }; + + void + UA_ServerConfig_clean(UA_ServerConfig *config); + +.. _server-lifecycle: + +Server Lifecycle +---------------- + +.. code-block:: c + + + /* Create a new server with a default configuration that adds plugins for + * networking, security, logging and so on. See `server_config_default.h` for + * more detailed options. + * + * The default configuration can be used as the starting point to adjust the + * server configuration to individual needs. UA_Server_new is implemented in the + * /plugins folder under the CC0 license. Furthermore the server confiugration + * only uses the public server API. + * + * @return Returns the configured server or NULL if an error occurs. */ + UA_Server * + UA_Server_new(void); + + /* Creates a new server. Moves the config into the server with a shallow copy. + * The config content is cleared together with the server. */ + UA_Server * + UA_Server_newWithConfig(UA_ServerConfig *config); + + /* Delete the server. */ + UA_StatusCode + UA_Server_delete(UA_Server *server); + + /* Get the configuration. Always succeeds as this simplfy resolves a pointer. + * Attention! Do not adjust the configuration while the server is running! */ + UA_ServerConfig * + UA_Server_getConfig(UA_Server *server); + + /* Get the current server lifecycle state */ + UA_LifecycleState + UA_Server_getLifecycleState(UA_Server *server); + + /* Runs the server until interrupted. On Unix/Windows this registers an + * interrupt for SIGINT (ctrl-c). The method only returns after having received + * the interrupt. The logical sequence is as follows: + * + * - UA_Server_run_startup + * - Loop until interrupt: UA_Server_run_iterate + * - UA_Server_run_shutdown + * + * @param server The server object. + * @return Returns a bad statuscode if an error occurred internally. */ + UA_StatusCode + UA_Server_run(UA_Server *server, const volatile UA_Boolean *running); + + /* Runs the server until interrupted. On Unix/Windows this registers an + * interrupt for SIGINT (ctrl-c). The method only returns after having received + * the interrupt or upon an error condition. The logical sequence is as follows: + * + * - Register the interrupt + * - UA_Server_run_startup + * - Loop until interrupt: UA_Server_run_iterate + * - UA_Server_run_shutdown + * - Deregister the interrupt + * + * Attention! This method is implemented individually for the different + * platforms (POSIX/Win32/etc.). The default implementation is in + * /plugins/ua_config_default.c under the CC0 license. Adjust as needed. + * + * @param server The server object. + * @return Returns a bad statuscode if an error occurred internally. */ + UA_StatusCode + UA_Server_runUntilInterrupt(UA_Server *server); + + /* The prologue part of UA_Server_run (no need to use if you call + * UA_Server_run or UA_Server_runUntilInterrupt) */ + UA_StatusCode + UA_Server_run_startup(UA_Server *server); + + /* Executes a single iteration of the server's main loop. + * + * @param server The server object. + * @param waitInternal Should we wait for messages in the networklayer? + * Otherwise, the timouts for the networklayers are set to zero. + * The default max wait time is 200ms. + * @return Returns how long we can wait until the next scheduled + * callback (in ms) */ + UA_UInt16 + UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal); + + /* The epilogue part of UA_Server_run (no need to use if you call + * UA_Server_run or UA_Server_runUntilInterrupt) */ + UA_StatusCode + UA_Server_run_shutdown(UA_Server *server); + +Timed Callbacks +--------------- +Add a callback to the server that is executed at a defined time. +The callback can also be registered with a cyclic interval. + +.. code-block:: c + + + /* Add a callback for execution at a specified time. If the indicated time lies + * in the past, then the callback is executed at the next iteration of the + * server's main loop. + * + * @param server The server object. + * @param callback The callback that shall be added. + * @param data Data that is forwarded to the callback. + * @param date The timestamp for the execution time. + * @param callbackId Set to the identifier of the repeated callback . This can + * be used to cancel the callback later on. If the pointer is null, the + * identifier is not set. + * @return Upon success, ``UA_STATUSCODE_GOOD`` is returned. An error code + * otherwise. */ + UA_StatusCode UA_THREADSAFE + UA_Server_addTimedCallback(UA_Server *server, UA_ServerCallback callback, + void *data, UA_DateTime date, UA_UInt64 *callbackId); + + /* Add a callback for cyclic repetition to the server. + * + * @param server The server object. + * @param callback The callback that shall be added. + * @param data Data that is forwarded to the callback. + * @param interval_ms The callback shall be repeatedly executed with the given + * interval (in ms). The interval must be positive. The first execution + * occurs at now() + interval at the latest. + * @param callbackId Set to the identifier of the repeated callback . This can + * be used to cancel the callback later on. If the pointer is null, the + * identifier is not set. + * @return Upon success, ``UA_STATUSCODE_GOOD`` is returned. An error code + * otherwise. */ + UA_StatusCode UA_THREADSAFE + UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback, + void *data, UA_Double interval_ms, + UA_UInt64 *callbackId); + + UA_StatusCode UA_THREADSAFE + UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId, + UA_Double interval_ms); + + /* Remove a repeated callback. Does nothing if the callback is not found. + * + * @param server The server object. + * @param callbackId The id of the callback */ + void UA_THREADSAFE + UA_Server_removeCallback(UA_Server *server, UA_UInt64 callbackId); + + #define UA_Server_removeRepeatedCallback(server, callbackId) \ + UA_Server_removeCallback(server, callbackId); + +Session Handling +---------------- +A new session is announced via the AccessControl plugin. The session +identifier is forwarded to the relevant callbacks back into userland. The +following methods enable an interaction with a particular session. + +.. code-block:: c + + + /* Manually close a session */ + UA_StatusCode UA_THREADSAFE + UA_Server_closeSession(UA_Server *server, const UA_NodeId *sessionId); + +Session attributes: Besides the user-definable session context pointer (set +by the AccessControl plugin when the Session is created), a session carries +attributes in a key-value list. Some attributes are present in every session +and shown in the list below. Additional attributes can be manually set as +meta-data. + +Always present as session attributes are: + +- 0:localeIds [UA_String]: List of preferred languages (read-only) +- 0:clientDescription [UA_ApplicationDescription]: Client description (read-only) +- 0:sessionName [String] Client-defined name of the session (read-only) +- 0:clientUserId [String] User identifier used to activate the session (read-only) + +.. code-block:: c + + + /* Returns a shallow copy of the attribute. Don't _clear or _delete the value + * variant. Don't use the value once the Session could be already closed in the + * background or the attribute of the session replaced. Hence don't use this in a + * multi-threaded application. */ + UA_StatusCode + UA_Server_getSessionAttribute(UA_Server *server, const UA_NodeId *sessionId, + const UA_QualifiedName key, UA_Variant *outValue); + + /* Return a deep copy of the attribute */ + UA_StatusCode UA_THREADSAFE + UA_Server_getSessionAttributeCopy(UA_Server *server, const UA_NodeId *sessionId, + const UA_QualifiedName key, UA_Variant *outValue); + + /* Returns NULL if the attribute is not defined or not a scalar or not of the + * right datatype. Otherwise a shallow copy of the scalar value is created at + * the target location of the void pointer. Hence don't use this in a + * multi-threaded application. */ + UA_StatusCode + UA_Server_getSessionAttribute_scalar(UA_Server *server, + const UA_NodeId *sessionId, + const UA_QualifiedName key, + const UA_DataType *type, + void *outValue); + + UA_StatusCode UA_THREADSAFE + UA_Server_setSessionAttribute(UA_Server *server, const UA_NodeId *sessionId, + const UA_QualifiedName key, + const UA_Variant *value); + + UA_StatusCode UA_THREADSAFE + UA_Server_deleteSessionAttribute(UA_Server *server, const UA_NodeId *sessionId, + const UA_QualifiedName key); + +Reading and Writing Node Attributes +----------------------------------- +The functions for reading and writing node attributes call the regular read +and write service in the background that are also used over the network. + +The following attributes cannot be read, since the local "admin" user always +has full rights. + +- UserWriteMask +- UserAccessLevel +- UserExecutable + +.. code-block:: c + + + /* Read an attribute of a node. The specialized functions below provide a more + * concise syntax. + * + * @param server The server object. + * @param item ReadValueIds contain the NodeId of the target node, the id of the + * attribute to read and (optionally) an index range to read parts + * of an array only. See the section on NumericRange for the format + * used for array ranges. + * @param timestamps Which timestamps to return for the attribute. + * @return Returns a DataValue that contains either an error code, or a variant + * with the attribute value and the timestamps. */ + UA_DataValue UA_THREADSAFE + UA_Server_read(UA_Server *server, const UA_ReadValueId *item, + UA_TimestampsToReturn timestamps); + + /* Don't use this function. There are typed versions for every supported + * attribute. */ + UA_StatusCode UA_THREADSAFE + __UA_Server_read(UA_Server *server, const UA_NodeId *nodeId, + UA_AttributeId attributeId, void *v); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readNodeId(UA_Server *server, const UA_NodeId nodeId, + UA_NodeId *outNodeId) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_NODEID, outNodeId); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readNodeClass(UA_Server *server, const UA_NodeId nodeId, + UA_NodeClass *outNodeClass) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_NODECLASS, + outNodeClass); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readBrowseName(UA_Server *server, const UA_NodeId nodeId, + UA_QualifiedName *outBrowseName) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_BROWSENAME, + outBrowseName); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readDisplayName(UA_Server *server, const UA_NodeId nodeId, + UA_LocalizedText *outDisplayName) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, + outDisplayName); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readDescription(UA_Server *server, const UA_NodeId nodeId, + UA_LocalizedText *outDescription) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, + outDescription); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readWriteMask(UA_Server *server, const UA_NodeId nodeId, + UA_UInt32 *outWriteMask) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_WRITEMASK, + outWriteMask); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readIsAbstract(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean *outIsAbstract) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, + outIsAbstract); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readSymmetric(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean *outSymmetric) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_SYMMETRIC, + outSymmetric); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readInverseName(UA_Server *server, const UA_NodeId nodeId, + UA_LocalizedText *outInverseName) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_INVERSENAME, + outInverseName); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readContainsNoLoops(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean *outContainsNoLoops) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, + outContainsNoLoops); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readEventNotifier(UA_Server *server, const UA_NodeId nodeId, + UA_Byte *outEventNotifier) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, + outEventNotifier); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readValue(UA_Server *server, const UA_NodeId nodeId, + UA_Variant *outValue) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_VALUE, outValue); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readDataType(UA_Server *server, const UA_NodeId nodeId, + UA_NodeId *outDataType) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DATATYPE, + outDataType); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readValueRank(UA_Server *server, const UA_NodeId nodeId, + UA_Int32 *outValueRank) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_VALUERANK, + outValueRank); + } + + /* Returns a variant with an int32 array */ + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readArrayDimensions(UA_Server *server, const UA_NodeId nodeId, + UA_Variant *outArrayDimensions) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS, + outArrayDimensions); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readAccessLevel(UA_Server *server, const UA_NodeId nodeId, + UA_Byte *outAccessLevel) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, + outAccessLevel); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readAccessLevelEx(UA_Server *server, const UA_NodeId nodeId, + UA_UInt32 *outAccessLevelEx) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX, + outAccessLevelEx); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readMinimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId, + UA_Double *outMinimumSamplingInterval) { + return __UA_Server_read(server, &nodeId, + UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, + outMinimumSamplingInterval); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readHistorizing(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean *outHistorizing) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_HISTORIZING, + outHistorizing); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readExecutable(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean *outExecutable) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, + outExecutable); + } + +The following node attributes cannot be changed once a node has been created: + +- NodeClass +- NodeId +- Symmetric +- ContainsNoLoops + +The following attributes cannot be written from the server, as they are +specific to the different users and set by the access control callback: + +- UserWriteMask +- UserAccessLevel +- UserExecutable + +.. code-block:: c + + + /* Overwrite an attribute of a node. The specialized functions below provide a + * more concise syntax. + * + * @param server The server object. + * @param value WriteValues contain the NodeId of the target node, the id of the + * attribute to overwritten, the actual value and (optionally) an + * index range to replace parts of an array only. of an array only. + * See the section on NumericRange for the format used for array + * ranges. + * @return Returns a status code. */ + UA_StatusCode UA_THREADSAFE + UA_Server_write(UA_Server *server, const UA_WriteValue *value); + + /* Don't use this function. There are typed versions with no additional + * overhead. */ + UA_StatusCode UA_THREADSAFE + __UA_Server_write(UA_Server *server, const UA_NodeId *nodeId, + const UA_AttributeId attributeId, + const UA_DataType *attr_type, const void *attr); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeBrowseName(UA_Server *server, const UA_NodeId nodeId, + const UA_QualifiedName browseName) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_BROWSENAME, + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], &browseName); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeDisplayName(UA_Server *server, const UA_NodeId nodeId, + const UA_LocalizedText displayName) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &displayName); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeDescription(UA_Server *server, const UA_NodeId nodeId, + const UA_LocalizedText description) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &description); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeWriteMask(UA_Server *server, const UA_NodeId nodeId, + const UA_UInt32 writeMask) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_WRITEMASK, + &UA_TYPES[UA_TYPES_UINT32], &writeMask); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeIsAbstract(UA_Server *server, const UA_NodeId nodeId, + const UA_Boolean isAbstract) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, + &UA_TYPES[UA_TYPES_BOOLEAN], &isAbstract); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeInverseName(UA_Server *server, const UA_NodeId nodeId, + const UA_LocalizedText inverseName) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_INVERSENAME, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &inverseName); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeEventNotifier(UA_Server *server, const UA_NodeId nodeId, + const UA_Byte eventNotifier) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, + &UA_TYPES[UA_TYPES_BYTE], &eventNotifier); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeValue(UA_Server *server, const UA_NodeId nodeId, + const UA_Variant value) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUE, + &UA_TYPES[UA_TYPES_VARIANT], &value); + } + + /* Writes an UA_DataValue to a variable/variableType node. In contrast to + * UA_Server_writeValue, this functions can also write SourceTimestamp, + * ServerTimestamp and StatusCode. */ + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeDataValue(UA_Server *server, const UA_NodeId nodeId, + const UA_DataValue value) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUE, + &UA_TYPES[UA_TYPES_DATAVALUE], &value); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeDataType(UA_Server *server, const UA_NodeId nodeId, + const UA_NodeId dataType) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DATATYPE, + &UA_TYPES[UA_TYPES_NODEID], &dataType); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeValueRank(UA_Server *server, const UA_NodeId nodeId, + const UA_Int32 valueRank) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUERANK, + &UA_TYPES[UA_TYPES_INT32], &valueRank); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeArrayDimensions(UA_Server *server, const UA_NodeId nodeId, + const UA_Variant arrayDimensions) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS, + &UA_TYPES[UA_TYPES_VARIANT], &arrayDimensions); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeAccessLevel(UA_Server *server, const UA_NodeId nodeId, + const UA_Byte accessLevel) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, + &UA_TYPES[UA_TYPES_BYTE], &accessLevel); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeAccessLevelEx(UA_Server *server, const UA_NodeId nodeId, + const UA_UInt32 accessLevelEx) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX, + &UA_TYPES[UA_TYPES_UINT32], &accessLevelEx); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeMinimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId, + const UA_Double miniumSamplingInterval) { + return __UA_Server_write(server, &nodeId, + UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, + &UA_TYPES[UA_TYPES_DOUBLE], + &miniumSamplingInterval); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeHistorizing(UA_Server *server, const UA_NodeId nodeId, + const UA_Boolean historizing) { + return __UA_Server_write(server, &nodeId, + UA_ATTRIBUTEID_HISTORIZING, + &UA_TYPES[UA_TYPES_BOOLEAN], + &historizing); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeExecutable(UA_Server *server, const UA_NodeId nodeId, + const UA_Boolean executable) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, + &UA_TYPES[UA_TYPES_BOOLEAN], &executable); } + +Browsing +-------- + +.. code-block:: c + + + /* Browse the references of a particular node. See the definition of + * BrowseDescription structure for details. */ + UA_BrowseResult UA_THREADSAFE + UA_Server_browse(UA_Server *server, UA_UInt32 maxReferences, + const UA_BrowseDescription *bd); + + UA_BrowseResult UA_THREADSAFE + UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint, + const UA_ByteString *continuationPoint); + + /* Non-standard version of the Browse service that recurses into child nodes. + * + * Possible loops (that can occur for non-hierarchical references) are handled + * internally. Every node is added at most once to the results array. + * + * Nodes are only added if they match the NodeClassMask in the + * BrowseDescription. However, child nodes are still recursed into if the + * NodeClass does not match. So it is possible, for example, to get all + * VariableNodes below a certain ObjectNode, with additional objects in the + * hierarchy below. */ + UA_StatusCode UA_THREADSAFE + UA_Server_browseRecursive(UA_Server *server, const UA_BrowseDescription *bd, + size_t *resultsSize, UA_ExpandedNodeId **results); + + UA_BrowsePathResult UA_THREADSAFE + UA_Server_translateBrowsePathToNodeIds(UA_Server *server, + const UA_BrowsePath *browsePath); + + /* A simplified TranslateBrowsePathsToNodeIds based on the + * SimpleAttributeOperand type (Part 4, 7.4.4.5). + * + * This specifies a relative path using a list of BrowseNames instead of the + * RelativePath structure. The list of BrowseNames is equivalent to a + * RelativePath that specifies forward references which are subtypes of the + * HierarchicalReferences ReferenceType. All Nodes followed by the browsePath + * shall be of the NodeClass Object or Variable. */ + UA_BrowsePathResult UA_THREADSAFE + UA_Server_browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin, + size_t browsePathSize, + const UA_QualifiedName *browsePath); + + #ifndef HAVE_NODEITER_CALLBACK + #define HAVE_NODEITER_CALLBACK + /* Iterate over all nodes referenced by parentNodeId by calling the callback + * function for each child node (in ifdef because GCC/CLANG handle include order + * differently) */ + typedef UA_StatusCode + (*UA_NodeIteratorCallback)(UA_NodeId childId, UA_Boolean isInverse, + UA_NodeId referenceTypeId, void *handle); + #endif + + UA_StatusCode UA_THREADSAFE + UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId, + UA_NodeIteratorCallback callback, void *handle); + + #ifdef UA_ENABLE_DISCOVERY + +Discovery +--------- + +Registering at a Discovery Server +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + + /* Register the given server instance at the discovery server. This should be + * called periodically, for example every 10 minutes, depending on the + * configuration of the discovery server. You should also call + * _unregisterDiscovery when the server shuts down. + * + * The supplied client configuration is used to create a new client to connect + * to the discovery server. The client configuration is moved over to the server + * and eventually cleaned up internally. The structure pointed at by `cc` is + * zeroed to avoid accessing outdated information. + * + * The eventloop and logging plugins in the client configuration are replaced by + * those configured in the server. */ + UA_StatusCode UA_THREADSAFE + UA_Server_registerDiscovery(UA_Server *server, UA_ClientConfig *cc, + const UA_String discoveryServerUrl, + const UA_String semaphoreFilePath); + + /* Deregister the given server instance from the discovery server. + * This should be called when the server is shutting down. */ + UA_StatusCode UA_THREADSAFE + UA_Server_deregisterDiscovery(UA_Server *server, UA_ClientConfig *cc, + const UA_String discoveryServerUrl); + +Operating a Discovery Server +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + + /* Callback for RegisterServer. Data is passed from the register call */ + typedef void + (*UA_Server_registerServerCallback)(const UA_RegisteredServer *registeredServer, + void* data); + + /* Set the callback which is called if another server registeres or unregisters + * with this instance. This callback is called every time the server gets a + * register call. This especially means that for every periodic server register + * the callback will be called. + * + * @param server + * @param cb the callback + * @param data data passed to the callback + * @return ``UA_STATUSCODE_SUCCESS`` on success */ + void UA_THREADSAFE + UA_Server_setRegisterServerCallback(UA_Server *server, + UA_Server_registerServerCallback cb, void* data); + + #ifdef UA_ENABLE_DISCOVERY_MULTICAST + + /* Callback for server detected through mDNS. Data is passed from the register + * call + * + * @param isServerAnnounce indicates if the server has just been detected. If + * set to false, this means the server is shutting down. + * @param isTxtReceived indicates if we already received the corresponding TXT + * record with the path and caps data */ + typedef void + (*UA_Server_serverOnNetworkCallback)(const UA_ServerOnNetwork *serverOnNetwork, + UA_Boolean isServerAnnounce, + UA_Boolean isTxtReceived, void* data); + + /* Set the callback which is called if another server is found through mDNS or + * deleted. It will be called for any mDNS message from the remote server, thus + * it may be called multiple times for the same instance. Also the SRV and TXT + * records may arrive later, therefore for the first call the server + * capabilities may not be set yet. If called multiple times, previous data will + * be overwritten. + * + * @param server + * @param cb the callback + * @param data data passed to the callback + * @return ``UA_STATUSCODE_SUCCESS`` on success */ + void UA_THREADSAFE + UA_Server_setServerOnNetworkCallback(UA_Server *server, + UA_Server_serverOnNetworkCallback cb, + void* data); + + #endif /* UA_ENABLE_DISCOVERY_MULTICAST */ + + #endif /* UA_ENABLE_DISCOVERY */ + +Information Model Callbacks +--------------------------- +There are three places where a callback from an information model to +user-defined code can happen. + +- Custom node constructors and destructors +- Linking VariableNodes with an external data source +- MethodNode callbacks + +.. code-block:: c + + + void + UA_Server_setAdminSessionContext(UA_Server *server, + void *context); + + UA_StatusCode UA_THREADSAFE + UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId, + UA_NodeTypeLifecycle lifecycle); + + UA_StatusCode UA_THREADSAFE + UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId, + void **nodeContext); + + /* Careful! The user has to ensure that the destructor callbacks still work. */ + UA_StatusCode UA_THREADSAFE + UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId, + void *nodeContext); + +.. _datasource: + +Data Source Callback +^^^^^^^^^^^^^^^^^^^^ +The server has a unique way of dealing with the content of variables. Instead +of storing a variant attached to the variable node, the node can point to a +function with a local data provider. Whenever the value attribute is read, +the function will be called and asked to provide a UA_DataValue return value +that contains the value content and additional timestamps. + +It is expected that the read callback is implemented. The write callback can +be set to a null-pointer. + +.. code-block:: c + + + UA_StatusCode UA_THREADSAFE + UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId, + const UA_DataSource dataSource); + + UA_StatusCode UA_THREADSAFE + UA_Server_setVariableNode_valueCallback(UA_Server *server, + const UA_NodeId nodeId, + const UA_ValueCallback callback); + + UA_StatusCode UA_THREADSAFE + UA_Server_setVariableNode_valueBackend(UA_Server *server, + const UA_NodeId nodeId, + const UA_ValueBackend valueBackend); + +.. _local-monitoreditems: + +Local MonitoredItems +^^^^^^^^^^^^^^^^^^^^ +MonitoredItems are used with the Subscription mechanism of OPC UA to +transported notifications for data changes and events. MonitoredItems can +also be registered locally. Notifications are then forwarded to a +user-defined callback instead of a remote client. + +.. code-block:: c + + + #ifdef UA_ENABLE_SUBSCRIPTIONS + + typedef void (*UA_Server_DataChangeNotificationCallback) + (UA_Server *server, UA_UInt32 monitoredItemId, void *monitoredItemContext, + const UA_NodeId *nodeId, void *nodeContext, UA_UInt32 attributeId, + const UA_DataValue *value); + + typedef void (*UA_Server_EventNotificationCallback) + (UA_Server *server, UA_UInt32 monId, void *monContext, + size_t nEventFields, const UA_Variant *eventFields); + + /* Create a local MonitoredItem with a sampling interval that detects data + * changes. + * + * @param server The server executing the MonitoredItem + * @timestampsToReturn Shall timestamps be added to the value for the callback? + * @item The parameters of the new MonitoredItem. Note that the attribute of the + * ReadValueId (the node that is monitored) can not be + * ``UA_ATTRIBUTEID_EVENTNOTIFIER``. A different callback type needs to be + * registered for event notifications. + * @monitoredItemContext A pointer that is forwarded with the callback + * @callback The callback that is executed on detected data changes + * + * @return Returns a description of the created MonitoredItem. The structure + * also contains a StatusCode (in case of an error) and the identifier of the + * new MonitoredItem. */ + UA_MonitoredItemCreateResult UA_THREADSAFE + UA_Server_createDataChangeMonitoredItem(UA_Server *server, + UA_TimestampsToReturn timestampsToReturn, + const UA_MonitoredItemCreateRequest item, + void *monitoredItemContext, + UA_Server_DataChangeNotificationCallback callback); + + /* UA_MonitoredItemCreateResult */ + /* UA_Server_createEventMonitoredItem(UA_Server *server, */ + /* UA_TimestampsToReturn timestampsToReturn, */ + /* const UA_MonitoredItemCreateRequest item, void *context, */ + /* UA_Server_EventNotificationCallback callback); */ + + UA_StatusCode UA_THREADSAFE + UA_Server_deleteMonitoredItem(UA_Server *server, UA_UInt32 monitoredItemId); + + #endif + +Method Callbacks +^^^^^^^^^^^^^^^^ +Method callbacks are set to `NULL` (not executable) when a method node is +added over the network. In theory, it is possible to add a callback via +``UA_Server_setMethodNode_callback`` within the global constructor when +adding methods over the network is really wanted. See the Section +:ref:`object-interaction` for calling methods on an object. + +.. code-block:: c + + + #ifdef UA_ENABLE_METHODCALLS + UA_StatusCode UA_THREADSAFE + UA_Server_setMethodNodeCallback(UA_Server *server, + const UA_NodeId methodNodeId, + UA_MethodCallback methodCallback); + + /* Backwards compatibility definition */ + #define UA_Server_setMethodNode_callback(server, methodNodeId, methodCallback) \ + UA_Server_setMethodNodeCallback(server, methodNodeId, methodCallback) + + UA_StatusCode UA_THREADSAFE + UA_Server_getMethodNodeCallback(UA_Server *server, + const UA_NodeId methodNodeId, + UA_MethodCallback *outMethodCallback); + + UA_CallMethodResult UA_THREADSAFE + UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request); + #endif + +.. _object-interaction: + +Interacting with Objects +------------------------ +Objects in the information model are represented as ObjectNodes. Some +convenience functions are provided to simplify the interaction with objects. + +.. code-block:: c + + + /* Write an object property. The property is represented as a VariableNode with + * a ``HasProperty`` reference from the ObjectNode. The VariableNode is + * identified by its BrowseName. Writing the property sets the value attribute + * of the VariableNode. + * + * @param server The server object + * @param objectId The identifier of the object (node) + * @param propertyName The name of the property + * @param value The value to be set for the event attribute + * @return The StatusCode for setting the event attribute */ + UA_StatusCode UA_THREADSAFE + UA_Server_writeObjectProperty(UA_Server *server, const UA_NodeId objectId, + const UA_QualifiedName propertyName, + const UA_Variant value); + + /* Directly point to the scalar value instead of a variant */ + UA_StatusCode UA_THREADSAFE + UA_Server_writeObjectProperty_scalar(UA_Server *server, const UA_NodeId objectId, + const UA_QualifiedName propertyName, + const void *value, const UA_DataType *type); + + /* Read an object property. + * + * @param server The server object + * @param objectId The identifier of the object (node) + * @param propertyName The name of the property + * @param value Contains the property value after reading. Must not be NULL. + * @return The StatusCode for setting the event attribute */ + UA_StatusCode UA_THREADSAFE + UA_Server_readObjectProperty(UA_Server *server, const UA_NodeId objectId, + const UA_QualifiedName propertyName, + UA_Variant *value); + +.. _addnodes: + +Node Addition and Deletion +-------------------------- +When creating dynamic node instances at runtime, chances are that you will +not care about the specific NodeId of the new node, as long as you can +reference it later. When passing numeric NodeIds with a numeric identifier 0, +the stack evaluates this as "select a random unassigned numeric NodeId in +that namespace". To find out which NodeId was actually assigned to the new +node, you may pass a pointer `outNewNodeId`, which will (after a successful +node insertion) contain the nodeId of the new node. You may also pass a +``NULL`` pointer if this result is not needed. + +See the Section :ref:`node-lifecycle` on constructors and on attaching +user-defined data to nodes. + +The Section :ref:`default-node-attributes` contains useful starting points +for defining node attributes. Forgetting to set the ValueRank or the +AccessLevel leads to errors that can be hard to track down for new users. The +default attributes have a high likelihood to "do the right thing". + +The methods for node addition and deletion take mostly const arguments that +are not modified. When creating a node, a deep copy of the node identifier, +node attributes, etc. is created. Therefore, it is possible to call for +example ``UA_Server_addVariablenode`` with a value attribute (a +:ref:`variant`) pointing to a memory location on the stack. If you need +changes to a variable value to manifest at a specific memory location, please +use a :ref:`datasource` or a :ref:`value-callback`. + +.. code-block:: c + + + /* Don't use this function. There are typed versions as inline functions. */ + UA_StatusCode UA_THREADSAFE + __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass, + const UA_NodeId *requestedNewNodeId, + const UA_NodeId *parentNodeId, + const UA_NodeId *referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId *typeDefinition, + const UA_NodeAttributes *attr, + const UA_DataType *attributeType, + void *nodeContext, UA_NodeId *outNewNodeId); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, + const UA_VariableAttributes attr, + void *nodeContext, UA_NodeId *outNewNodeId) { + return __UA_Server_addNode(server, UA_NODECLASS_VARIABLE, &requestedNewNodeId, + &parentNodeId, &referenceTypeId, browseName, + &typeDefinition, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], + nodeContext, outNewNodeId); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addVariableTypeNode(UA_Server *server, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, + const UA_VariableTypeAttributes attr, + void *nodeContext, UA_NodeId *outNewNodeId) { + return __UA_Server_addNode(server, UA_NODECLASS_VARIABLETYPE, + &requestedNewNodeId, &parentNodeId, &referenceTypeId, + browseName, &typeDefinition, + (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], + nodeContext, outNewNodeId); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addObjectNode(UA_Server *server, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, + const UA_ObjectAttributes attr, + void *nodeContext, UA_NodeId *outNewNodeId) { + return __UA_Server_addNode(server, UA_NODECLASS_OBJECT, &requestedNewNodeId, + &parentNodeId, &referenceTypeId, browseName, + &typeDefinition, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], + nodeContext, outNewNodeId); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addObjectTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ObjectTypeAttributes attr, + void *nodeContext, UA_NodeId *outNewNodeId) { + return __UA_Server_addNode(server, UA_NODECLASS_OBJECTTYPE, &requestedNewNodeId, + &parentNodeId, &referenceTypeId, browseName, + &UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], + nodeContext, outNewNodeId); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addViewNode(UA_Server *server, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ViewAttributes attr, + void *nodeContext, UA_NodeId *outNewNodeId) { + return __UA_Server_addNode(server, UA_NODECLASS_VIEW, &requestedNewNodeId, + &parentNodeId, &referenceTypeId, browseName, + &UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], + nodeContext, outNewNodeId); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addReferenceTypeNode(UA_Server *server, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ReferenceTypeAttributes attr, + void *nodeContext, UA_NodeId *outNewNodeId) { + return __UA_Server_addNode(server, UA_NODECLASS_REFERENCETYPE, + &requestedNewNodeId, &parentNodeId, &referenceTypeId, + browseName, &UA_NODEID_NULL, + (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], + nodeContext, outNewNodeId); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addDataTypeNode(UA_Server *server, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_DataTypeAttributes attr, + void *nodeContext, UA_NodeId *outNewNodeId) { + return __UA_Server_addNode(server, UA_NODECLASS_DATATYPE, &requestedNewNodeId, + &parentNodeId, &referenceTypeId, browseName, + &UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], + nodeContext, outNewNodeId); + } + + UA_StatusCode UA_THREADSAFE + UA_Server_addDataSourceVariableNode(UA_Server *server, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, + const UA_VariableAttributes attr, + const UA_DataSource dataSource, + void *nodeContext, UA_NodeId *outNewNodeId); + + /* VariableNodes that are "dynamic" (default for user-created variables) receive + * and store a SourceTimestamp. For non-dynamic VariableNodes the current time + * is used for the SourceTimestamp. */ + UA_StatusCode UA_THREADSAFE + UA_Server_setVariableNodeDynamic(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean isDynamic); + + #ifdef UA_ENABLE_METHODCALLS + + UA_StatusCode UA_THREADSAFE + UA_Server_addMethodNodeEx(UA_Server *server, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_MethodAttributes attr, UA_MethodCallback method, + size_t inputArgumentsSize, const UA_Argument *inputArguments, + const UA_NodeId inputArgumentsRequestedNewNodeId, + UA_NodeId *inputArgumentsOutNewNodeId, + size_t outputArgumentsSize, const UA_Argument *outputArguments, + const UA_NodeId outputArgumentsRequestedNewNodeId, + UA_NodeId *outputArgumentsOutNewNodeId, + void *nodeContext, UA_NodeId *outNewNodeId); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, const UA_MethodAttributes attr, + UA_MethodCallback method, + size_t inputArgumentsSize, const UA_Argument *inputArguments, + size_t outputArgumentsSize, const UA_Argument *outputArguments, + void *nodeContext, UA_NodeId *outNewNodeId) { + return UA_Server_addMethodNodeEx(server, requestedNewNodeId, parentNodeId, + referenceTypeId, browseName, attr, method, + inputArgumentsSize, inputArguments, + UA_NODEID_NULL, NULL, + outputArgumentsSize, outputArguments, + UA_NODEID_NULL, NULL, + nodeContext, outNewNodeId); + } + + #endif + + +The method pair UA_Server_addNode_begin and _finish splits the AddNodes +service in two parts. This is useful if the node shall be modified before +finish the instantiation. For example to add children with specific NodeIds. +Otherwise, mandatory children (e.g. of an ObjectType) are added with +pseudo-random unique NodeIds. Existing children are detected during the +_finish part via their matching BrowseName. + +The _begin method: + - prepares the node and adds it to the nodestore + - copies some unassigned attributes from the TypeDefinition node internally + - adds the references to the parent (and the TypeDefinition if applicable) + - performs type-checking of variables. + +You can add an object node without a parent if you set the parentNodeId and +referenceTypeId to UA_NODE_ID_NULL. Then you need to add the parent reference +and hasTypeDef reference yourself before calling the _finish method. +Not that this is only allowed for object nodes. + +The _finish method: + - copies mandatory children + - calls the node constructor(s) at the end + - may remove the node if it encounters an error. + +The special UA_Server_addMethodNode_finish method needs to be used for method +nodes, since there you need to explicitly specifiy the input and output +arguments which are added in the finish step (if not yet already there) + +.. code-block:: c + + + /* The ``attr`` argument must have a type according to the NodeClass. + * ``VariableAttributes`` for variables, ``ObjectAttributes`` for objects, and + * so on. Missing attributes are taken from the TypeDefinition node if + * applicable. */ + UA_StatusCode UA_THREADSAFE + UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, + const void *attr, const UA_DataType *attributeType, + void *nodeContext, UA_NodeId *outNewNodeId); + + UA_StatusCode UA_THREADSAFE + UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId); + + #ifdef UA_ENABLE_METHODCALLS + + UA_StatusCode UA_THREADSAFE + UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId, + UA_MethodCallback method, + size_t inputArgumentsSize, const UA_Argument *inputArguments, + size_t outputArgumentsSize, const UA_Argument *outputArguments); + + #endif + + /* Deletes a node and optionally all references leading to the node. */ + UA_StatusCode UA_THREADSAFE + UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean deleteReferences); + +Reference Management +-------------------- + +.. code-block:: c + + + UA_StatusCode UA_THREADSAFE + UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId, + const UA_NodeId refTypeId, + const UA_ExpandedNodeId targetId, UA_Boolean isForward); + + UA_StatusCode UA_THREADSAFE + UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId, + const UA_NodeId referenceTypeId, UA_Boolean isForward, + const UA_ExpandedNodeId targetNodeId, + UA_Boolean deleteBidirectional); + +.. _events: + +Events +------ +The method ``UA_Server_createEvent`` creates an event and represents it as +node. The node receives a unique `EventId` which is automatically added to +the node. The method returns a `NodeId` to the object node which represents +the event through ``outNodeId``. The `NodeId` can be used to set the +attributes of the event. The generated `NodeId` is always numeric. +``outNodeId`` cannot be ``NULL``. + +Note: In order to see an event in UAExpert, the field `Time` must be given a +value! + +The method ``UA_Server_triggerEvent`` "triggers" an event by adding it to all +monitored items of the specified origin node and those of all its parents. +Any filters specified by the monitored items are automatically applied. Using +this method deletes the node generated by ``UA_Server_createEvent``. The +`EventId` for the new event is generated automatically and is returned +through ``outEventId``. ``NULL`` can be passed if the `EventId` is not +needed. ``deleteEventNode`` specifies whether the node representation of the +event should be deleted after invoking the method. This can be useful if +events with the similar attributes are triggered frequently. ``UA_TRUE`` +would cause the node to be deleted. + +.. code-block:: c + + + #ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS + + /* Creates a node representation of an event + * + * @param server The server object + * @param eventType The type of the event for which a node should be created + * @param outNodeId The NodeId of the newly created node for the event + * @return The StatusCode of the UA_Server_createEvent method */ + UA_StatusCode UA_THREADSAFE + UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType, + UA_NodeId *outNodeId); + + /* Triggers a node representation of an event by applying EventFilters and + * adding the event to the appropriate queues. + * + * @param server The server object + * @param eventNodeId The NodeId of the node representation of the event which + * should be triggered + * @param outEvent the EventId of the new event + * @param deleteEventNode Specifies whether the node representation of the event + * should be deleted + * @return The StatusCode of the UA_Server_triggerEvent method */ + UA_StatusCode UA_THREADSAFE + UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, + const UA_NodeId originId, UA_ByteString *outEventId, + const UA_Boolean deleteEventNode); + + #endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */ + +Alarms & Conditions (Experimental) +---------------------------------- + +.. code-block:: c + + + #ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS + typedef enum UA_TwoStateVariableCallbackType { + UA_ENTERING_ENABLEDSTATE, + UA_ENTERING_ACKEDSTATE, + UA_ENTERING_CONFIRMEDSTATE, + UA_ENTERING_ACTIVESTATE + } UA_TwoStateVariableCallbackType; + + /* Callback prototype to set user specific callbacks */ + typedef UA_StatusCode + (*UA_TwoStateVariableChangeCallback)(UA_Server *server, const UA_NodeId *condition); + + /* Create condition instance. The function checks first whether the passed + * conditionType is a subType of ConditionType. Then checks whether the + * condition source has HasEventSource reference to its parent. If not, a + * HasEventSource reference will be created between condition source and server + * object. To expose the condition in address space, a hierarchical + * ReferenceType should be passed to create the reference to condition source. + * Otherwise, UA_NODEID_NULL should be passed to make the condition not exposed. + * + * @param server The server object + * @param conditionId The NodeId of the requested Condition Object. When passing + * UA_NODEID_NUMERIC(X,0) an unused nodeid in namespace X will be used. + * E.g. passing UA_NODEID_NULL will result in a NodeId in namespace 0. + * @param conditionType The NodeId of the node representation of the ConditionType + * @param conditionName The name of the condition to be created + * @param conditionSource The NodeId of the Condition Source (Parent of the Condition) + * @param hierarchialReferenceType The NodeId of Hierarchical ReferenceType + * between Condition and its source + * @param outConditionId The NodeId of the created Condition + * @return The StatusCode of the UA_Server_createCondition method */ + UA_StatusCode + UA_Server_createCondition(UA_Server *server, + const UA_NodeId conditionId, + const UA_NodeId conditionType, + const UA_QualifiedName conditionName, + const UA_NodeId conditionSource, + const UA_NodeId hierarchialReferenceType, + UA_NodeId *outConditionId); + + /* The method pair UA_Server_addCondition_begin and _finish splits the + * UA_Server_createCondtion in two parts similiar to the + * UA_Server_addNode_begin / _finish pair. This is useful if the node shall be + * modified before finish the instantiation. For example to add children with + * specific NodeIds. + * For details refer to the UA_Server_addNode_begin / _finish methods. + * + * Additionally to UA_Server_addNode_begin UA_Server_addCondition_begin checks + * if the passed condition type is a subtype of the OPC UA ConditionType. + * + * @param server The server object + * @param conditionId The NodeId of the requested Condition Object. When passing + * UA_NODEID_NUMERIC(X,0) an unused nodeid in namespace X will be used. + * E.g. passing UA_NODEID_NULL will result in a NodeId in namespace 0. + * @param conditionType The NodeId of the node representation of the ConditionType + * @param conditionName The name of the condition to be added + * @param outConditionId The NodeId of the added Condition + * @return The StatusCode of the UA_Server_addCondition_begin method */ + UA_StatusCode + UA_Server_addCondition_begin(UA_Server *server, + const UA_NodeId conditionId, + const UA_NodeId conditionType, + const UA_QualifiedName conditionName, + UA_NodeId *outConditionId); + + /* Second call of the UA_Server_addCondition_begin and _finish pair. + * Additionally to UA_Server_addNode_finish UA_Server_addCondition_finish: + * - checks whether the condition source has HasEventSource reference to its + * parent. If not, a HasEventSource reference will be created between + * condition source and server object + * - exposes the condition in the address space if hierarchialReferenceType is + * not UA_NODEID_NULL by adding a reference of this type from the condition + * source to the condition instance + * - initializes the standard condition fields and callbacks + * + * @param server The server object + * @param conditionId The NodeId of the unfinished Condition Object + * @param conditionSource The NodeId of the Condition Source (Parent of the Condition) + * @param hierarchialReferenceType The NodeId of Hierarchical ReferenceType + * between Condition and its source + * @return The StatusCode of the UA_Server_addCondition_finish method */ + + UA_StatusCode + UA_Server_addCondition_finish(UA_Server *server, + const UA_NodeId conditionId, + const UA_NodeId conditionSource, + const UA_NodeId hierarchialReferenceType); + + /* Set the value of condition field. + * + * @param server The server object + * @param condition The NodeId of the node representation of the Condition Instance + * @param value Variant Value to be written to the Field + * @param fieldName Name of the Field in which the value should be written + * @return The StatusCode of the UA_Server_setConditionField method*/ + UA_StatusCode UA_THREADSAFE + UA_Server_setConditionField(UA_Server *server, + const UA_NodeId condition, + const UA_Variant *value, + const UA_QualifiedName fieldName); + + /* Set the value of property of condition field. + * + * @param server The server object + * @param condition The NodeId of the node representation of the Condition + * Instance + * @param value Variant Value to be written to the Field + * @param variableFieldName Name of the Field which has a property + * @param variablePropertyName Name of the Field Property in which the value + * should be written + * @return The StatusCode of the UA_Server_setConditionVariableFieldProperty*/ + UA_StatusCode + UA_Server_setConditionVariableFieldProperty(UA_Server *server, + const UA_NodeId condition, + const UA_Variant *value, + const UA_QualifiedName variableFieldName, + const UA_QualifiedName variablePropertyName); + + /* Triggers an event only for an enabled condition. The condition list is + * updated then with the last generated EventId. + * + * @param server The server object + * @param condition The NodeId of the node representation of the Condition Instance + * @param conditionSource The NodeId of the node representation of the Condition Source + * @param outEventId last generated EventId + * @return The StatusCode of the UA_Server_triggerConditionEvent method */ + UA_StatusCode + UA_Server_triggerConditionEvent(UA_Server *server, + const UA_NodeId condition, + const UA_NodeId conditionSource, + UA_ByteString *outEventId); + + /* Add an optional condition field using its name. (TODO Adding optional methods + * is not implemented yet) + * + * @param server The server object + * @param condition The NodeId of the node representation of the Condition Instance + * @param conditionType The NodeId of the node representation of the Condition Type + * from which the optional field comes + * @param fieldName Name of the optional field + * @param outOptionalVariable The NodeId of the created field (Variable Node) + * @return The StatusCode of the UA_Server_addConditionOptionalField method */ + UA_StatusCode + UA_Server_addConditionOptionalField(UA_Server *server, + const UA_NodeId condition, + const UA_NodeId conditionType, + const UA_QualifiedName fieldName, + UA_NodeId *outOptionalVariable); + + /* Function used to set a user specific callback to TwoStateVariable Fields of a + * condition. The callbacks will be called before triggering the events when + * transition to true State of EnabledState/Id, AckedState/Id, ConfirmedState/Id + * and ActiveState/Id occurs. + * + * @param server The server object + * @param condition The NodeId of the node representation of the Condition Instance + * @param conditionSource The NodeId of the node representation of the Condition Source + * @param removeBranch (Not Implemented yet) + * @param callback User specific callback function + * @param callbackType Callback function type, indicates where it should be called + * @return The StatusCode of the UA_Server_setConditionTwoStateVariableCallback method */ + UA_StatusCode + UA_Server_setConditionTwoStateVariableCallback(UA_Server *server, + const UA_NodeId condition, + const UA_NodeId conditionSource, + UA_Boolean removeBranch, + UA_TwoStateVariableChangeCallback callback, + UA_TwoStateVariableCallbackType callbackType); + + /* Delete a condition from the address space and the internal lists. + * + * @param server The server object + * @param condition The NodeId of the node representation of the Condition Instance + * @param conditionSource The NodeId of the node representation of the Condition Source + * @return ``UA_STATUSCODE_GOOD`` on success */ + UA_StatusCode + UA_Server_deleteCondition(UA_Server *server, + const UA_NodeId condition, + const UA_NodeId conditionSource); + + /* Set the LimitState of the LimitAlarmType + * + * @param server The server object + * @param conditionId NodeId of the node representation of the Condition Instance + * @param limitValue The value from the trigger node */ + UA_StatusCode + UA_Server_setLimitState(UA_Server *server, const UA_NodeId conditionId, + UA_Double limitValue); + + /* Parse the certifcate and set Expiration date + * + * @param server The server object + * @param conditionId NodeId of the node representation of the Condition Instance + * @param cert The certificate for parsing */ + UA_StatusCode + UA_Server_setExpirationDate(UA_Server *server, const UA_NodeId conditionId, + UA_ByteString cert); + + #endif /* UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */ + +Update the Server Certificate at Runtime +---------------------------------------- + +.. code-block:: c + + + UA_StatusCode + UA_Server_updateCertificate(UA_Server *server, + const UA_ByteString *oldCertificate, + const UA_ByteString *newCertificate, + const UA_ByteString *newPrivateKey, + UA_Boolean closeSessions, + UA_Boolean closeSecureChannels); + +Utility Functions +----------------- + +.. code-block:: c + + + /* Lookup a datatype by its NodeId. Takes the custom types in the server + * configuration into account. Return NULL if none found. */ + const UA_DataType * + UA_Server_findDataType(UA_Server *server, const UA_NodeId *typeId); + + /* Add a new namespace to the server. Returns the index of the new namespace */ + UA_UInt16 UA_THREADSAFE + UA_Server_addNamespace(UA_Server *server, const char* name); + + /* Get namespace by name from the server. */ + UA_StatusCode UA_THREADSAFE + UA_Server_getNamespaceByName(UA_Server *server, const UA_String namespaceUri, + size_t* foundIndex); + + /* Get namespace by id from the server. */ + UA_StatusCode UA_THREADSAFE + UA_Server_getNamespaceByIndex(UA_Server *server, const size_t namespaceIndex, + UA_String *foundUri); + +.. _async-operations: + +Async Operations +---------------- +Some operations (such as reading out a sensor that needs to warm up) can take +quite some time. In order not to block the server during such an operation, it +can be "outsourced" to a worker thread. + +Take the example of a CallRequest. It is split into the individual method call +operations. If the method is marked as async, then the operation is put into a +queue where it is be retrieved by a worker. The worker returns the result when +ready. See the examples in ``/examples/tutorial_server_method_async.c`` for +the usage. + +Note that the operation can time out (see the asyncOperationTimeout setting in +the server config) also when it has been retrieved by the worker. + +.. code-block:: c + + + #if UA_MULTITHREADING >= 100 + + /* Set the async flag in a method node */ + UA_StatusCode + UA_Server_setMethodNodeAsync(UA_Server *server, const UA_NodeId id, + UA_Boolean isAsync); + + typedef enum { + UA_ASYNCOPERATIONTYPE_INVALID, /* 0, the default */ + UA_ASYNCOPERATIONTYPE_CALL + /* UA_ASYNCOPERATIONTYPE_READ, */ + /* UA_ASYNCOPERATIONTYPE_WRITE, */ + } UA_AsyncOperationType; + + typedef union { + UA_CallMethodRequest callMethodRequest; + /* UA_ReadValueId readValueId; */ + /* UA_WriteValue writeValue; */ + } UA_AsyncOperationRequest; + + typedef union { + UA_CallMethodResult callMethodResult; + /* UA_DataValue readResult; */ + /* UA_StatusCode writeResult; */ + } UA_AsyncOperationResponse; + + /* Get the next async operation without blocking + * + * @param server The server object + * @param type The type of the async operation + * @param request Receives pointer to the operation + * @param context Receives the pointer to the operation context + * @param timeout The timestamp when the operation times out and can + * no longer be returned to the client. The response has to + * be set in UA_Server_setAsyncOperationResult in any case. + * @return false if queue is empty, true else */ + UA_Boolean + UA_Server_getAsyncOperationNonBlocking(UA_Server *server, + UA_AsyncOperationType *type, + const UA_AsyncOperationRequest **request, + void **context, UA_DateTime *timeout); + + /* UA_Boolean */ + /* UA_Server_getAsyncOperationBlocking(UA_Server *server, */ + /* UA_AsyncOperationType *type, */ + /* const UA_AsyncOperationRequest **request, */ + /* void **context, UA_DateTime *timeout); */ + + /* Submit an async operation result + * + * @param server The server object + * @param response Pointer to the operation result + * @param context Pointer to the operation context */ + void + UA_Server_setAsyncOperationResult(UA_Server *server, + const UA_AsyncOperationResponse *response, + void *context); + + #endif /* !UA_MULTITHREADING >= 100 */ + +Statistics +---------- +Statistic counters keeping track of the current state of the stack. Counters +are structured per OPC UA communication layer. + +.. code-block:: c + + + typedef struct { + UA_SecureChannelStatistics scs; + UA_SessionStatistics ss; + } UA_ServerStatistics; + + UA_ServerStatistics + UA_Server_getStatistics(UA_Server *server); + +Reverse Connect +--------------- +The reverse connect feature of OPC UA permits the server instead of the +client to establish the connection. The client must expose the listening port +so the server is able to reach it. + +.. code-block:: c + + + /* The reverse connect state change callback is called whenever the state of a + * reverse connect is changed by a connection attempt, a successful connection + * or a connection loss. + * + * The reverse connect states reflect the state of the secure channel currently + * associated with a reverse connect. The state will remain + * UA_SECURECHANNELSTATE_CONNECTING while the server attempts repeatedly to + * establish a connection. */ + typedef void (*UA_Server_ReverseConnectStateCallback)(UA_Server *server, + UA_UInt64 handle, + UA_SecureChannelState state, + void *context); + + /* Registers a reverse connect in the server. The server periodically attempts + * to establish a connection if the initial connect fails or if the connection + * breaks. + * + * @param server The server object + * @param url The URL of the remote client + * @param stateCallback The callback which will be called on state changes + * @param callbackContext The context for the state callback + * @param handle Is set to the handle of the reverse connect if not NULL + * @return Returns UA_STATUSCODE_GOOD if the reverse connect has been registered */ + UA_StatusCode + UA_Server_addReverseConnect(UA_Server *server, UA_String url, + UA_Server_ReverseConnectStateCallback stateCallback, + void *callbackContext, UA_UInt64 *handle); + + /* Removes a reverse connect from the server and closes the connection if it is + * currently open. + * + * @param server The server object + * @param handle The handle of the reverse connect to remove + * @return Returns UA_STATUSCODE_GOOD if the reverse connect has been + * successfully removed */ + UA_StatusCode + UA_Server_removeReverseConnect(UA_Server *server, UA_UInt64 handle); diff --git a/static/doc/v1.4.0/_sources/statuscodes.rst.txt b/static/doc/v1.4.0/_sources/statuscodes.rst.txt new file mode 100644 index 0000000000..907487c3eb --- /dev/null +++ b/static/doc/v1.4.0/_sources/statuscodes.rst.txt @@ -0,0 +1,778 @@ +.. _statuscodes: + +StatusCodes +=========== + +StatusCodes are extensively used in the OPC UA protocol and in the open62541 +API. They are represented by the :ref:`statuscode` data type. The following +definitions are autogenerated from the ``Opc.Ua.StatusCodes.csv`` file provided +with the OPC UA standard. + +.. code-block:: c + + + /* These StatusCodes are manually generated. */ + #define UA_STATUSCODE_INFOTYPE_DATAVALUE 0x00000400 + #define UA_STATUSCODE_INFOBITS_OVERFLOW 0x00000080 + + /* The operation succeeded. */ + #define UA_STATUSCODE_GOOD 0x00000000 + + /* The operation was uncertain. */ + #define UA_STATUSCODE_UNCERTAIN 0x40000000 + + /* The operation failed. */ + #define UA_STATUSCODE_BAD 0x80000000 + + /* An unexpected error occurred. */ + #define UA_STATUSCODE_BADUNEXPECTEDERROR 0x80010000 + + /* An internal error occurred as a result of a programming or configuration error. */ + #define UA_STATUSCODE_BADINTERNALERROR 0x80020000 + + /* Not enough memory to complete the operation. */ + #define UA_STATUSCODE_BADOUTOFMEMORY 0x80030000 + + /* An operating system resource is not available. */ + #define UA_STATUSCODE_BADRESOURCEUNAVAILABLE 0x80040000 + + /* A low level communication error occurred. */ + #define UA_STATUSCODE_BADCOMMUNICATIONERROR 0x80050000 + + /* Encoding halted because of invalid data in the objects being serialized. */ + #define UA_STATUSCODE_BADENCODINGERROR 0x80060000 + + /* Decoding halted because of invalid data in the stream. */ + #define UA_STATUSCODE_BADDECODINGERROR 0x80070000 + + /* The message encoding/decoding limits imposed by the stack have been exceeded. */ + #define UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED 0x80080000 + + /* The request message size exceeds limits set by the server. */ + #define UA_STATUSCODE_BADREQUESTTOOLARGE 0x80B80000 + + /* The response message size exceeds limits set by the client. */ + #define UA_STATUSCODE_BADRESPONSETOOLARGE 0x80B90000 + + /* An unrecognized response was received from the server. */ + #define UA_STATUSCODE_BADUNKNOWNRESPONSE 0x80090000 + + /* The operation timed out. */ + #define UA_STATUSCODE_BADTIMEOUT 0x800A0000 + + /* The server does not support the requested service. */ + #define UA_STATUSCODE_BADSERVICEUNSUPPORTED 0x800B0000 + + /* The operation was cancelled because the application is shutting down. */ + #define UA_STATUSCODE_BADSHUTDOWN 0x800C0000 + + /* The operation could not complete because the client is not connected to the server. */ + #define UA_STATUSCODE_BADSERVERNOTCONNECTED 0x800D0000 + + /* The server has stopped and cannot process any requests. */ + #define UA_STATUSCODE_BADSERVERHALTED 0x800E0000 + + /* There was nothing to do because the client passed a list of operations with no elements. */ + #define UA_STATUSCODE_BADNOTHINGTODO 0x800F0000 + + /* The request could not be processed because it specified too many operations. */ + #define UA_STATUSCODE_BADTOOMANYOPERATIONS 0x80100000 + + /* The request could not be processed because there are too many monitored items in the subscription. */ + #define UA_STATUSCODE_BADTOOMANYMONITOREDITEMS 0x80DB0000 + + /* The extension object cannot be (de)serialized because the data type id is not recognized. */ + #define UA_STATUSCODE_BADDATATYPEIDUNKNOWN 0x80110000 + + /* The certificate provided as a parameter is not valid. */ + #define UA_STATUSCODE_BADCERTIFICATEINVALID 0x80120000 + + /* An error occurred verifying security. */ + #define UA_STATUSCODE_BADSECURITYCHECKSFAILED 0x80130000 + + /* The certificate does not meet the requirements of the security policy. */ + #define UA_STATUSCODE_BADCERTIFICATEPOLICYCHECKFAILED 0x81140000 + + /* The certificate has expired or is not yet valid. */ + #define UA_STATUSCODE_BADCERTIFICATETIMEINVALID 0x80140000 + + /* An issuer certificate has expired or is not yet valid. */ + #define UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID 0x80150000 + + /* The HostName used to connect to a server does not match a HostName in the certificate. */ + #define UA_STATUSCODE_BADCERTIFICATEHOSTNAMEINVALID 0x80160000 + + /* The URI specified in the ApplicationDescription does not match the URI in the certificate. */ + #define UA_STATUSCODE_BADCERTIFICATEURIINVALID 0x80170000 + + /* The certificate may not be used for the requested operation. */ + #define UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED 0x80180000 + + /* The issuer certificate may not be used for the requested operation. */ + #define UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED 0x80190000 + + /* The certificate is not trusted. */ + #define UA_STATUSCODE_BADCERTIFICATEUNTRUSTED 0x801A0000 + + /* It was not possible to determine if the certificate has been revoked. */ + #define UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN 0x801B0000 + + /* It was not possible to determine if the issuer certificate has been revoked. */ + #define UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN 0x801C0000 + + /* The certificate has been revoked. */ + #define UA_STATUSCODE_BADCERTIFICATEREVOKED 0x801D0000 + + /* The issuer certificate has been revoked. */ + #define UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED 0x801E0000 + + /* The certificate chain is incomplete. */ + #define UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE 0x810D0000 + + /* User does not have permission to perform the requested operation. */ + #define UA_STATUSCODE_BADUSERACCESSDENIED 0x801F0000 + + /* The user identity token is not valid. */ + #define UA_STATUSCODE_BADIDENTITYTOKENINVALID 0x80200000 + + /* The user identity token is valid but the server has rejected it. */ + #define UA_STATUSCODE_BADIDENTITYTOKENREJECTED 0x80210000 + + /* The specified secure channel is no longer valid. */ + #define UA_STATUSCODE_BADSECURECHANNELIDINVALID 0x80220000 + + /* The timestamp is outside the range allowed by the server. */ + #define UA_STATUSCODE_BADINVALIDTIMESTAMP 0x80230000 + + /* The nonce does appear to be not a random value or it is not the correct length. */ + #define UA_STATUSCODE_BADNONCEINVALID 0x80240000 + + /* The session id is not valid. */ + #define UA_STATUSCODE_BADSESSIONIDINVALID 0x80250000 + + /* The session was closed by the client. */ + #define UA_STATUSCODE_BADSESSIONCLOSED 0x80260000 + + /* The session cannot be used because ActivateSession has not been called. */ + #define UA_STATUSCODE_BADSESSIONNOTACTIVATED 0x80270000 + + /* The subscription id is not valid. */ + #define UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID 0x80280000 + + /* The header for the request is missing or invalid. */ + #define UA_STATUSCODE_BADREQUESTHEADERINVALID 0x802A0000 + + /* The timestamps to return parameter is invalid. */ + #define UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID 0x802B0000 + + /* The request was cancelled by the client. */ + #define UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT 0x802C0000 + + /* Too many arguments were provided. */ + #define UA_STATUSCODE_BADTOOMANYARGUMENTS 0x80E50000 + + /* The server requires a license to operate in general or to perform a service or operatio */ + #define UA_STATUSCODE_BADLICENSEEXPIRED 0x810E0000 + + /* The server has limits on number of allowed operations / object */ + #define UA_STATUSCODE_BADLICENSELIMITSEXCEEDED 0x810F0000 + + /* The server does not have a license which is required to operate in general or to perform a service or operation. */ + #define UA_STATUSCODE_BADLICENSENOTAVAILABLE 0x81100000 + + /* The subscription was transferred to another session. */ + #define UA_STATUSCODE_GOODSUBSCRIPTIONTRANSFERRED 0x002D0000 + + /* The processing will complete asynchronously. */ + #define UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY 0x002E0000 + + /* Sampling has slowed down due to resource limitations. */ + #define UA_STATUSCODE_GOODOVERLOAD 0x002F0000 + + /* The value written was accepted but was clamped. */ + #define UA_STATUSCODE_GOODCLAMPED 0x00300000 + + /* Communication with the data source is define */ + #define UA_STATUSCODE_BADNOCOMMUNICATION 0x80310000 + + /* Waiting for the server to obtain values from the underlying data source. */ + #define UA_STATUSCODE_BADWAITINGFORINITIALDATA 0x80320000 + + /* The syntax of the node id is not valid. */ + #define UA_STATUSCODE_BADNODEIDINVALID 0x80330000 + + /* The node id refers to a node that does not exist in the server address space. */ + #define UA_STATUSCODE_BADNODEIDUNKNOWN 0x80340000 + + /* The attribute is not supported for the specified Node. */ + #define UA_STATUSCODE_BADATTRIBUTEIDINVALID 0x80350000 + + /* The syntax of the index range parameter is invalid. */ + #define UA_STATUSCODE_BADINDEXRANGEINVALID 0x80360000 + + /* No data exists within the range of indexes specified. */ + #define UA_STATUSCODE_BADINDEXRANGENODATA 0x80370000 + + /* The data encoding is invalid. */ + #define UA_STATUSCODE_BADDATAENCODINGINVALID 0x80380000 + + /* The server does not support the requested data encoding for the node. */ + #define UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED 0x80390000 + + /* The access level does not allow reading or subscribing to the Node. */ + #define UA_STATUSCODE_BADNOTREADABLE 0x803A0000 + + /* The access level does not allow writing to the Node. */ + #define UA_STATUSCODE_BADNOTWRITABLE 0x803B0000 + + /* The value was out of range. */ + #define UA_STATUSCODE_BADOUTOFRANGE 0x803C0000 + + /* The requested operation is not supported. */ + #define UA_STATUSCODE_BADNOTSUPPORTED 0x803D0000 + + /* A requested item was not found or a search operation ended without success. */ + #define UA_STATUSCODE_BADNOTFOUND 0x803E0000 + + /* The object cannot be used because it has been deleted. */ + #define UA_STATUSCODE_BADOBJECTDELETED 0x803F0000 + + /* Requested operation is not implemented. */ + #define UA_STATUSCODE_BADNOTIMPLEMENTED 0x80400000 + + /* The monitoring mode is invalid. */ + #define UA_STATUSCODE_BADMONITORINGMODEINVALID 0x80410000 + + /* The monitoring item id does not refer to a valid monitored item. */ + #define UA_STATUSCODE_BADMONITOREDITEMIDINVALID 0x80420000 + + /* The monitored item filter parameter is not valid. */ + #define UA_STATUSCODE_BADMONITOREDITEMFILTERINVALID 0x80430000 + + /* The server does not support the requested monitored item filter. */ + #define UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED 0x80440000 + + /* A monitoring filter cannot be used in combination with the attribute specified. */ + #define UA_STATUSCODE_BADFILTERNOTALLOWED 0x80450000 + + /* A mandatory structured parameter was missing or null. */ + #define UA_STATUSCODE_BADSTRUCTUREMISSING 0x80460000 + + /* The event filter is not valid. */ + #define UA_STATUSCODE_BADEVENTFILTERINVALID 0x80470000 + + /* The content filter is not valid. */ + #define UA_STATUSCODE_BADCONTENTFILTERINVALID 0x80480000 + + /* An unrecognized operator was provided in a filter. */ + #define UA_STATUSCODE_BADFILTEROPERATORINVALID 0x80C10000 + + /* A valid operator was provide */ + #define UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED 0x80C20000 + + /* The number of operands provided for the filter operator was less then expected for the operand provided. */ + #define UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH 0x80C30000 + + /* The operand used in a content filter is not valid. */ + #define UA_STATUSCODE_BADFILTEROPERANDINVALID 0x80490000 + + /* The referenced element is not a valid element in the content filter. */ + #define UA_STATUSCODE_BADFILTERELEMENTINVALID 0x80C40000 + + /* The referenced literal is not a valid value. */ + #define UA_STATUSCODE_BADFILTERLITERALINVALID 0x80C50000 + + /* The continuation point provide is longer valid. */ + #define UA_STATUSCODE_BADCONTINUATIONPOINTINVALID 0x804A0000 + + /* The operation could not be processed because all continuation points have been allocated. */ + #define UA_STATUSCODE_BADNOCONTINUATIONPOINTS 0x804B0000 + + /* The reference type id does not refer to a valid reference type node. */ + #define UA_STATUSCODE_BADREFERENCETYPEIDINVALID 0x804C0000 + + /* The browse direction is not valid. */ + #define UA_STATUSCODE_BADBROWSEDIRECTIONINVALID 0x804D0000 + + /* The node is not part of the view. */ + #define UA_STATUSCODE_BADNODENOTINVIEW 0x804E0000 + + /* The number was not accepted because of a numeric overflow. */ + #define UA_STATUSCODE_BADNUMERICOVERFLOW 0x81120000 + + /* The ServerUri is not a valid URI. */ + #define UA_STATUSCODE_BADSERVERURIINVALID 0x804F0000 + + /* No ServerName was specified. */ + #define UA_STATUSCODE_BADSERVERNAMEMISSING 0x80500000 + + /* No DiscoveryUrl was specified. */ + #define UA_STATUSCODE_BADDISCOVERYURLMISSING 0x80510000 + + /* The semaphore file specified by the client is not valid. */ + #define UA_STATUSCODE_BADSEMPAHOREFILEMISSING 0x80520000 + + /* The security token request type is not valid. */ + #define UA_STATUSCODE_BADREQUESTTYPEINVALID 0x80530000 + + /* The security mode does not meet the requirements set by the server. */ + #define UA_STATUSCODE_BADSECURITYMODEREJECTED 0x80540000 + + /* The security policy does not meet the requirements set by the server. */ + #define UA_STATUSCODE_BADSECURITYPOLICYREJECTED 0x80550000 + + /* The server has reached its maximum number of sessions. */ + #define UA_STATUSCODE_BADTOOMANYSESSIONS 0x80560000 + + /* The user token signature is missing or invalid. */ + #define UA_STATUSCODE_BADUSERSIGNATUREINVALID 0x80570000 + + /* The signature generated with the client certificate is missing or invalid. */ + #define UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID 0x80580000 + + /* The client did not provide at least one software certificate that is valid and meets the profile requirements for the server. */ + #define UA_STATUSCODE_BADNOVALIDCERTIFICATES 0x80590000 + + /* The server does not support changing the user identity assigned to the session. */ + #define UA_STATUSCODE_BADIDENTITYCHANGENOTSUPPORTED 0x80C60000 + + /* The request was cancelled by the client with the Cancel service. */ + #define UA_STATUSCODE_BADREQUESTCANCELLEDBYREQUEST 0x805A0000 + + /* The parent node id does not to refer to a valid node. */ + #define UA_STATUSCODE_BADPARENTNODEIDINVALID 0x805B0000 + + /* The reference could not be created because it violates constraints imposed by the data model. */ + #define UA_STATUSCODE_BADREFERENCENOTALLOWED 0x805C0000 + + /* The requested node id was reject because it was either invalid or server does not allow node ids to be specified by the client. */ + #define UA_STATUSCODE_BADNODEIDREJECTED 0x805D0000 + + /* The requested node id is already used by another node. */ + #define UA_STATUSCODE_BADNODEIDEXISTS 0x805E0000 + + /* The node class is not valid. */ + #define UA_STATUSCODE_BADNODECLASSINVALID 0x805F0000 + + /* The browse name is invalid. */ + #define UA_STATUSCODE_BADBROWSENAMEINVALID 0x80600000 + + /* The browse name is not unique among nodes that share the same relationship with the parent. */ + #define UA_STATUSCODE_BADBROWSENAMEDUPLICATED 0x80610000 + + /* The node attributes are not valid for the node class. */ + #define UA_STATUSCODE_BADNODEATTRIBUTESINVALID 0x80620000 + + /* The type definition node id does not reference an appropriate type node. */ + #define UA_STATUSCODE_BADTYPEDEFINITIONINVALID 0x80630000 + + /* The source node id does not reference a valid node. */ + #define UA_STATUSCODE_BADSOURCENODEIDINVALID 0x80640000 + + /* The target node id does not reference a valid node. */ + #define UA_STATUSCODE_BADTARGETNODEIDINVALID 0x80650000 + + /* The reference type between the nodes is already defined. */ + #define UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED 0x80660000 + + /* The server does not allow this type of self reference on this node. */ + #define UA_STATUSCODE_BADINVALIDSELFREFERENCE 0x80670000 + + /* The reference type is not valid for a reference to a remote server. */ + #define UA_STATUSCODE_BADREFERENCELOCALONLY 0x80680000 + + /* The server will not allow the node to be deleted. */ + #define UA_STATUSCODE_BADNODELETERIGHTS 0x80690000 + + /* The server was not able to delete all target references. */ + #define UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED 0x40BC0000 + + /* The server index is not valid. */ + #define UA_STATUSCODE_BADSERVERINDEXINVALID 0x806A0000 + + /* The view id does not refer to a valid view node. */ + #define UA_STATUSCODE_BADVIEWIDUNKNOWN 0x806B0000 + + /* The view timestamp is not available or not supported. */ + #define UA_STATUSCODE_BADVIEWTIMESTAMPINVALID 0x80C90000 + + /* The view parameters are not consistent with each other. */ + #define UA_STATUSCODE_BADVIEWPARAMETERMISMATCH 0x80CA0000 + + /* The view version is not available or not supported. */ + #define UA_STATUSCODE_BADVIEWVERSIONINVALID 0x80CB0000 + + /* The list of references may not be complete because the underlying system is not available. */ + #define UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE 0x40C00000 + + /* The server should have followed a reference to a node in a remote server but did not. The result set may be incomplete. */ + #define UA_STATUSCODE_GOODRESULTSMAYBEINCOMPLETE 0x00BA0000 + + /* The provided Nodeid was not a type definition nodeid. */ + #define UA_STATUSCODE_BADNOTTYPEDEFINITION 0x80C80000 + + /* One of the references to follow in the relative path references to a node in the address space in another server. */ + #define UA_STATUSCODE_UNCERTAINREFERENCEOUTOFSERVER 0x406C0000 + + /* The requested operation has too many matches to return. */ + #define UA_STATUSCODE_BADTOOMANYMATCHES 0x806D0000 + + /* The requested operation requires too many resources in the server. */ + #define UA_STATUSCODE_BADQUERYTOOCOMPLEX 0x806E0000 + + /* The requested operation has no match to return. */ + #define UA_STATUSCODE_BADNOMATCH 0x806F0000 + + /* The max age parameter is invalid. */ + #define UA_STATUSCODE_BADMAXAGEINVALID 0x80700000 + + /* The operation is not permitted over the current secure channel. */ + #define UA_STATUSCODE_BADSECURITYMODEINSUFFICIENT 0x80E60000 + + /* The history details parameter is not valid. */ + #define UA_STATUSCODE_BADHISTORYOPERATIONINVALID 0x80710000 + + /* The server does not support the requested operation. */ + #define UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED 0x80720000 + + /* The defined timestamp to return was invalid. */ + #define UA_STATUSCODE_BADINVALIDTIMESTAMPARGUMENT 0x80BD0000 + + /* The server does not support writing the combination of valu */ + #define UA_STATUSCODE_BADWRITENOTSUPPORTED 0x80730000 + + /* The value supplied for the attribute is not of the same type as the attribute's value. */ + #define UA_STATUSCODE_BADTYPEMISMATCH 0x80740000 + + /* The method id does not refer to a method for the specified object. */ + #define UA_STATUSCODE_BADMETHODINVALID 0x80750000 + + /* The client did not specify all of the input arguments for the method. */ + #define UA_STATUSCODE_BADARGUMENTSMISSING 0x80760000 + + /* The executable attribute does not allow the execution of the method. */ + #define UA_STATUSCODE_BADNOTEXECUTABLE 0x81110000 + + /* The server has reached its maximum number of subscriptions. */ + #define UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS 0x80770000 + + /* The server has reached the maximum number of queued publish requests. */ + #define UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS 0x80780000 + + /* There is no subscription available for this session. */ + #define UA_STATUSCODE_BADNOSUBSCRIPTION 0x80790000 + + /* The sequence number is unknown to the server. */ + #define UA_STATUSCODE_BADSEQUENCENUMBERUNKNOWN 0x807A0000 + + /* The Server does not support retransmission queue and acknowledgement of sequence numbers is not available. */ + #define UA_STATUSCODE_GOODRETRANSMISSIONQUEUENOTSUPPORTED 0x00DF0000 + + /* The requested notification message is no longer available. */ + #define UA_STATUSCODE_BADMESSAGENOTAVAILABLE 0x807B0000 + + /* The client of the current session does not support one or more Profiles that are necessary for the subscription. */ + #define UA_STATUSCODE_BADINSUFFICIENTCLIENTPROFILE 0x807C0000 + + /* The sub-state machine is not currently active. */ + #define UA_STATUSCODE_BADSTATENOTACTIVE 0x80BF0000 + + /* An equivalent rule already exists. */ + #define UA_STATUSCODE_BADALREADYEXISTS 0x81150000 + + /* The server cannot process the request because it is too busy. */ + #define UA_STATUSCODE_BADTCPSERVERTOOBUSY 0x807D0000 + + /* The type of the message specified in the header invalid. */ + #define UA_STATUSCODE_BADTCPMESSAGETYPEINVALID 0x807E0000 + + /* The SecureChannelId and/or TokenId are not currently in use. */ + #define UA_STATUSCODE_BADTCPSECURECHANNELUNKNOWN 0x807F0000 + + /* The size of the message chunk specified in the header is too large. */ + #define UA_STATUSCODE_BADTCPMESSAGETOOLARGE 0x80800000 + + /* There are not enough resources to process the request. */ + #define UA_STATUSCODE_BADTCPNOTENOUGHRESOURCES 0x80810000 + + /* An internal error occurred. */ + #define UA_STATUSCODE_BADTCPINTERNALERROR 0x80820000 + + /* The server does not recognize the QueryString specified. */ + #define UA_STATUSCODE_BADTCPENDPOINTURLINVALID 0x80830000 + + /* The request could not be sent because of a network interruption. */ + #define UA_STATUSCODE_BADREQUESTINTERRUPTED 0x80840000 + + /* Timeout occurred while processing the request. */ + #define UA_STATUSCODE_BADREQUESTTIMEOUT 0x80850000 + + /* The secure channel has been closed. */ + #define UA_STATUSCODE_BADSECURECHANNELCLOSED 0x80860000 + + /* The token has expired or is not recognized. */ + #define UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN 0x80870000 + + /* The sequence number is not valid. */ + #define UA_STATUSCODE_BADSEQUENCENUMBERINVALID 0x80880000 + + /* The applications do not have compatible protocol versions. */ + #define UA_STATUSCODE_BADPROTOCOLVERSIONUNSUPPORTED 0x80BE0000 + + /* There is a problem with the configuration that affects the usefulness of the value. */ + #define UA_STATUSCODE_BADCONFIGURATIONERROR 0x80890000 + + /* The variable should receive its value from another variabl */ + #define UA_STATUSCODE_BADNOTCONNECTED 0x808A0000 + + /* There has been a failure in the device/data source that generates the value that has affected the value. */ + #define UA_STATUSCODE_BADDEVICEFAILURE 0x808B0000 + + /* There has been a failure in the sensor from which the value is derived by the device/data source. */ + #define UA_STATUSCODE_BADSENSORFAILURE 0x808C0000 + + /* The source of the data is not operational. */ + #define UA_STATUSCODE_BADOUTOFSERVICE 0x808D0000 + + /* The deadband filter is not valid. */ + #define UA_STATUSCODE_BADDEADBANDFILTERINVALID 0x808E0000 + + /* Communication to the data source has failed. The variable value is the last value that had a good quality. */ + #define UA_STATUSCODE_UNCERTAINNOCOMMUNICATIONLASTUSABLEVALUE 0x408F0000 + + /* Whatever was updating this value has stopped doing so. */ + #define UA_STATUSCODE_UNCERTAINLASTUSABLEVALUE 0x40900000 + + /* The value is an operational value that was manually overwritten. */ + #define UA_STATUSCODE_UNCERTAINSUBSTITUTEVALUE 0x40910000 + + /* The value is an initial value for a variable that normally receives its value from another variable. */ + #define UA_STATUSCODE_UNCERTAININITIALVALUE 0x40920000 + + /* The value is at one of the sensor limits. */ + #define UA_STATUSCODE_UNCERTAINSENSORNOTACCURATE 0x40930000 + + /* The value is outside of the range of values defined for this parameter. */ + #define UA_STATUSCODE_UNCERTAINENGINEERINGUNITSEXCEEDED 0x40940000 + + /* The value is derived from multiple sources and has less than the required number of Good sources. */ + #define UA_STATUSCODE_UNCERTAINSUBNORMAL 0x40950000 + + /* The value has been overridden. */ + #define UA_STATUSCODE_GOODLOCALOVERRIDE 0x00960000 + + /* This Condition refresh faile */ + #define UA_STATUSCODE_BADREFRESHINPROGRESS 0x80970000 + + /* This condition has already been disabled. */ + #define UA_STATUSCODE_BADCONDITIONALREADYDISABLED 0x80980000 + + /* This condition has already been enabled. */ + #define UA_STATUSCODE_BADCONDITIONALREADYENABLED 0x80CC0000 + + /* Property not availabl */ + #define UA_STATUSCODE_BADCONDITIONDISABLED 0x80990000 + + /* The specified event id is not recognized. */ + #define UA_STATUSCODE_BADEVENTIDUNKNOWN 0x809A0000 + + /* The event cannot be acknowledged. */ + #define UA_STATUSCODE_BADEVENTNOTACKNOWLEDGEABLE 0x80BB0000 + + /* The dialog condition is not active. */ + #define UA_STATUSCODE_BADDIALOGNOTACTIVE 0x80CD0000 + + /* The response is not valid for the dialog. */ + #define UA_STATUSCODE_BADDIALOGRESPONSEINVALID 0x80CE0000 + + /* The condition branch has already been acknowledged. */ + #define UA_STATUSCODE_BADCONDITIONBRANCHALREADYACKED 0x80CF0000 + + /* The condition branch has already been confirmed. */ + #define UA_STATUSCODE_BADCONDITIONBRANCHALREADYCONFIRMED 0x80D00000 + + /* The condition has already been shelved. */ + #define UA_STATUSCODE_BADCONDITIONALREADYSHELVED 0x80D10000 + + /* The condition is not currently shelved. */ + #define UA_STATUSCODE_BADCONDITIONNOTSHELVED 0x80D20000 + + /* The shelving time not within an acceptable range. */ + #define UA_STATUSCODE_BADSHELVINGTIMEOUTOFRANGE 0x80D30000 + + /* No data exists for the requested time range or event filter. */ + #define UA_STATUSCODE_BADNODATA 0x809B0000 + + /* No data found to provide upper or lower bound value. */ + #define UA_STATUSCODE_BADBOUNDNOTFOUND 0x80D70000 + + /* The server cannot retrieve a bound for the variable. */ + #define UA_STATUSCODE_BADBOUNDNOTSUPPORTED 0x80D80000 + + /* Data is missing due to collection started/stopped/lost. */ + #define UA_STATUSCODE_BADDATALOST 0x809D0000 + + /* Expected data is unavailable for the requested time range due to an un-mounted volum */ + #define UA_STATUSCODE_BADDATAUNAVAILABLE 0x809E0000 + + /* The data or event was not successfully inserted because a matching entry exists. */ + #define UA_STATUSCODE_BADENTRYEXISTS 0x809F0000 + + /* The data or event was not successfully updated because no matching entry exists. */ + #define UA_STATUSCODE_BADNOENTRYEXISTS 0x80A00000 + + /* The client requested history using a timestamp format the server does not support (i.e requested ServerTimestamp when server only supports SourceTimestamp). */ + #define UA_STATUSCODE_BADTIMESTAMPNOTSUPPORTED 0x80A10000 + + /* The data or event was successfully inserted into the historical database. */ + #define UA_STATUSCODE_GOODENTRYINSERTED 0x00A20000 + + /* The data or event field was successfully replaced in the historical database. */ + #define UA_STATUSCODE_GOODENTRYREPLACED 0x00A30000 + + /* The value is derived from multiple values and has less than the required number of Good values. */ + #define UA_STATUSCODE_UNCERTAINDATASUBNORMAL 0x40A40000 + + /* No data exists for the requested time range or event filter. */ + #define UA_STATUSCODE_GOODNODATA 0x00A50000 + + /* The data or event field was successfully replaced in the historical database. */ + #define UA_STATUSCODE_GOODMOREDATA 0x00A60000 + + /* The requested number of Aggregates does not match the requested number of NodeIds. */ + #define UA_STATUSCODE_BADAGGREGATELISTMISMATCH 0x80D40000 + + /* The requested Aggregate is not support by the server. */ + #define UA_STATUSCODE_BADAGGREGATENOTSUPPORTED 0x80D50000 + + /* The aggregate value could not be derived due to invalid data inputs. */ + #define UA_STATUSCODE_BADAGGREGATEINVALIDINPUTS 0x80D60000 + + /* The aggregate configuration is not valid for specified node. */ + #define UA_STATUSCODE_BADAGGREGATECONFIGURATIONREJECTED 0x80DA0000 + + /* The request specifies fields which are not valid for the EventType or cannot be saved by the historian. */ + #define UA_STATUSCODE_GOODDATAIGNORED 0x00D90000 + + /* The request was rejected by the server because it did not meet the criteria set by the server. */ + #define UA_STATUSCODE_BADREQUESTNOTALLOWED 0x80E40000 + + /* The request has not been processed by the server yet. */ + #define UA_STATUSCODE_BADREQUESTNOTCOMPLETE 0x81130000 + + /* The device identity needs a ticket before it can be accepted. */ + #define UA_STATUSCODE_BADTICKETREQUIRED 0x811F0000 + + /* The device identity needs a ticket before it can be accepted. */ + #define UA_STATUSCODE_BADTICKETINVALID 0x81200000 + + /* The value does not come from the real source and has been edited by the server. */ + #define UA_STATUSCODE_GOODEDITED 0x00DC0000 + + /* There was an error in execution of these post-actions. */ + #define UA_STATUSCODE_GOODPOSTACTIONFAILED 0x00DD0000 + + /* The related EngineeringUnit has been changed but the Variable Value is still provided based on the previous unit. */ + #define UA_STATUSCODE_UNCERTAINDOMINANTVALUECHANGED 0x40DE0000 + + /* A dependent value has been changed but the change has not been applied to the device. */ + #define UA_STATUSCODE_GOODDEPENDENTVALUECHANGED 0x00E00000 + + /* 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. */ + #define UA_STATUSCODE_BADDOMINANTVALUECHANGED 0x80E10000 + + /* A dependent value has been changed but the change has not been applied to the device. The quality of the dominant variable is uncertain. */ + #define UA_STATUSCODE_UNCERTAINDEPENDENTVALUECHANGED 0x40E20000 + + /* A dependent value has been changed but the change has not been applied to the device. The quality of the dominant variable is Bad. */ + #define UA_STATUSCODE_BADDEPENDENTVALUECHANGED 0x80E30000 + + /* It is delivered with a dominant Variable value when a dependent Variable has changed but the change has not been applied. */ + #define UA_STATUSCODE_GOODEDITED_DEPENDENTVALUECHANGED 0x01160000 + + /* It is delivered with a dependent Variable value when a dominant Variable has changed but the change has not been applied. */ + #define UA_STATUSCODE_GOODEDITED_DOMINANTVALUECHANGED 0x01170000 + + /* It is delivered with a dependent Variable value when a dominant or dependent Variable has changed but change has not been applied. */ + #define UA_STATUSCODE_GOODEDITED_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED 0x01180000 + + /* It is delivered with a Variable value when Variable has changed but the value is not legal. */ + #define UA_STATUSCODE_BADEDITED_OUTOFRANGE 0x81190000 + + /* It is delivered with a Variable value when a source Variable has changed but the value is not legal. */ + #define UA_STATUSCODE_BADINITIALVALUE_OUTOFRANGE 0x811A0000 + + /* It is delivered with a dependent Variable value when a dominant Variable has changed and the value is not legal. */ + #define UA_STATUSCODE_BADOUTOFRANGE_DOMINANTVALUECHANGED 0x811B0000 + + /* It is delivered with a dependent Variable value when a dominant Variable has change */ + #define UA_STATUSCODE_BADEDITED_OUTOFRANGE_DOMINANTVALUECHANGED 0x811C0000 + + /* It is delivered with a dependent Variable value when a dominant or dependent Variable has changed and the value is not legal. */ + #define UA_STATUSCODE_BADOUTOFRANGE_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED 0x811D0000 + + /* It is delivered with a dependent Variable value when a dominant or dependent Variable has change */ + #define UA_STATUSCODE_BADEDITED_OUTOFRANGE_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED 0x811E0000 + + /* The communication layer has raised an event. */ + #define UA_STATUSCODE_GOODCOMMUNICATIONEVENT 0x00A70000 + + /* The system is shutting down. */ + #define UA_STATUSCODE_GOODSHUTDOWNEVENT 0x00A80000 + + /* The operation is not finished and needs to be called again. */ + #define UA_STATUSCODE_GOODCALLAGAIN 0x00A90000 + + /* A non-critical timeout occurred. */ + #define UA_STATUSCODE_GOODNONCRITICALTIMEOUT 0x00AA0000 + + /* One or more arguments are invalid. */ + #define UA_STATUSCODE_BADINVALIDARGUMENT 0x80AB0000 + + /* Could not establish a network connection to remote server. */ + #define UA_STATUSCODE_BADCONNECTIONREJECTED 0x80AC0000 + + /* The server has disconnected from the client. */ + #define UA_STATUSCODE_BADDISCONNECT 0x80AD0000 + + /* The network connection has been closed. */ + #define UA_STATUSCODE_BADCONNECTIONCLOSED 0x80AE0000 + + /* The operation cannot be completed because the object is close */ + #define UA_STATUSCODE_BADINVALIDSTATE 0x80AF0000 + + /* Cannot move beyond end of the stream. */ + #define UA_STATUSCODE_BADENDOFSTREAM 0x80B00000 + + /* No data is currently available for reading from a non-blocking stream. */ + #define UA_STATUSCODE_BADNODATAAVAILABLE 0x80B10000 + + /* The asynchronous operation is waiting for a response. */ + #define UA_STATUSCODE_BADWAITINGFORRESPONSE 0x80B20000 + + /* The asynchronous operation was abandoned by the caller. */ + #define UA_STATUSCODE_BADOPERATIONABANDONED 0x80B30000 + + /* The stream did not return all data requested (possibly because it is a non-blocking stream). */ + #define UA_STATUSCODE_BADEXPECTEDSTREAMTOBLOCK 0x80B40000 + + /* Non blocking behaviour is required and the operation would block. */ + #define UA_STATUSCODE_BADWOULDBLOCK 0x80B50000 + + /* A value had an invalid syntax. */ + #define UA_STATUSCODE_BADSYNTAXERROR 0x80B60000 + + /* The operation could not be finished because all available connections are in use. */ + #define UA_STATUSCODE_BADMAXCONNECTIONSREACHED 0x80B70000 + + /* Depending on the version of the schema, the following might be already defined: */ + #ifndef UA_STATUSCODE_GOOD + # define UA_STATUSCODE_GOOD 0x00000000 + #endif + #ifndef UA_STATUSCODE_UNCERTAIN + # define UA_STATUSCODE_UNCERTAIN 0x40000000 + #endif + #ifndef UA_STATUSCODE_BAD + # define UA_STATUSCODE_BAD 0x80000000 + #endif + diff --git a/static/doc/v1.4.0/_sources/toc.rst.txt b/static/doc/v1.4.0/_sources/toc.rst.txt new file mode 100644 index 0000000000..ea4f44dcbe --- /dev/null +++ b/static/doc/v1.4.0/_sources/toc.rst.txt @@ -0,0 +1,17 @@ +open62541 Documentation +####################### + +.. toctree:: + + index + core_concepts + building + types + server + client + pubsub + tutorials + common + nodeset_compiler + statuscodes + plugin diff --git a/static/doc/v1.4.0/_sources/tutorial_client_firststeps.rst.txt b/static/doc/v1.4.0/_sources/tutorial_client_firststeps.rst.txt new file mode 100644 index 0000000000..4145686f98 --- /dev/null +++ b/static/doc/v1.4.0/_sources/tutorial_client_firststeps.rst.txt @@ -0,0 +1,79 @@ +Building a Simple Client +------------------------ +You should already have a basic server from the previous tutorials. open62541 +provides both a server- and clientside API, so creating a client is as easy as +creating a server. Copy the following into a file `myClient.c`: + +.. code-block:: c + + + #include + #include + #include + + int main(void) { + UA_Client *client = UA_Client_new(); + UA_ClientConfig_setDefault(UA_Client_getConfig(client)); + UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840"); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "The connection failed with status code %s", + UA_StatusCode_name(retval)); + UA_Client_delete(client); + return 0; + } + + /* Read the value attribute of the node. UA_Client_readValueAttribute is a + * wrapper for the raw read service available as UA_Client_Service_read. */ + UA_Variant value; /* Variants can hold scalar values and arrays of any type */ + UA_Variant_init(&value); + + /* NodeId of the variable holding the current time */ + const UA_NodeId nodeId = + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME); + retval = UA_Client_readValueAttribute(client, nodeId, &value); + + if(retval == UA_STATUSCODE_GOOD && + UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME])) { + UA_DateTime raw_date = *(UA_DateTime *) value.data; + UA_DateTimeStruct dts = UA_DateTime_toStruct(raw_date); + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "date is: %u-%u-%u %u:%u:%u.%03u", + dts.day, dts.month, dts.year, dts.hour, + dts.min, dts.sec, dts.milliSec); + } else { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Reading the value failed with status code %s", + UA_StatusCode_name(retval)); + } + + /* Clean up */ + UA_Variant_clear(&value); + UA_Client_delete(client); /* Disconnects the client internally */ + return 0; + } + +Compilation is similar to the server example. + +.. code-block:: bash + + $ gcc -std=c99 myClient.c -lopen62541 -o myClient + +In a MinGW environment, the Winsock library must be added. + +.. code-block:: bash + + $ gcc -std=c99 myClient.c -lopen62541 -lws2_32 -o myClient.exe + +Further tasks +^^^^^^^^^^^^^ + +- Try to connect to some other OPC UA server by changing + ``opc.tcp://localhost:4840`` to an appropriate address (remember that the + queried node is contained in any OPC UA server). + +- Try to set the value of the variable node (ns=1,i="the.answer") containing + an ``Int32`` from the example server (which is built in + :doc:`tutorial_server_firststeps`) using "UA_Client_write" function. The + example server needs some more modifications, i.e., changing request types. + The answer can be found in ``examples/client.c``. diff --git a/static/doc/v1.4.0/_sources/tutorial_datatypes.rst.txt b/static/doc/v1.4.0/_sources/tutorial_datatypes.rst.txt new file mode 100644 index 0000000000..865decc8e4 --- /dev/null +++ b/static/doc/v1.4.0/_sources/tutorial_datatypes.rst.txt @@ -0,0 +1,192 @@ +.. _types-tutorial: + +Working with Data Types +----------------------- + +OPC UA defines a type system for values that can be encoded in the protocol +messages. This tutorial shows some examples for available data types and +their use. See the section on :ref:`types` for the full definitions. + +Basic Data Handling +^^^^^^^^^^^^^^^^^^^ +This section shows the basic interaction patterns for data types. Make +sure to compare with the type definitions in ``types.h``. + +.. code-block:: c + + + #include + #include + #include + + #include + #include + + static void + variables_basic(void) { + /* Int32 */ + UA_Int32 i = 5; + UA_Int32 j; + UA_Int32_copy(&i, &j); + + UA_Int32 *ip = UA_Int32_new(); + UA_Int32_copy(&i, ip); + UA_Int32_delete(ip); + + /* String */ + UA_String s; + UA_String_init(&s); /* _init zeroes out the entire memory of the datatype */ + char *test = "test"; + s.length = strlen(test); + s.data = (UA_Byte*)test; + + UA_String s2; + UA_String_copy(&s, &s2); + UA_String_clear(&s2); /* Copying heap-allocated the dynamic content */ + + UA_String s3 = UA_STRING("test2"); + UA_String s4 = UA_STRING_ALLOC("test2"); /* Copies the content to the heap */ + UA_Boolean eq = UA_String_equal(&s3, &s4); + UA_String_clear(&s4); + if(!eq) + return; + + /* Structured Type */ + UA_ReadRequest rr; + UA_init(&rr, &UA_TYPES[UA_TYPES_READREQUEST]); /* Generic method */ + UA_ReadRequest_init(&rr); /* Shorthand for the previous line */ + + rr.requestHeader.timestamp = UA_DateTime_now(); /* Members of a structure */ + + rr.nodesToRead = (UA_ReadValueId *)UA_Array_new(5, &UA_TYPES[UA_TYPES_READVALUEID]); + rr.nodesToReadSize = 5; /* Array size needs to be made known */ + + UA_ReadRequest *rr2 = UA_ReadRequest_new(); + UA_copy(&rr, rr2, &UA_TYPES[UA_TYPES_READREQUEST]); + UA_ReadRequest_clear(&rr); + UA_ReadRequest_delete(rr2); + } + +NodeIds +^^^^^^^ +An OPC UA information model is made up of nodes and references between nodes. +Every node has a unique :ref:`nodeid`. NodeIds refer to a namespace with an +additional identifier value that can be an integer, a string, a guid or a +bytestring. + +.. code-block:: c + + + static void + variables_nodeids(void) { + UA_NodeId id1 = UA_NODEID_NUMERIC(1, 1234); + id1.namespaceIndex = 3; + + UA_NodeId id2 = UA_NODEID_STRING(1, "testid"); /* the string is static */ + UA_Boolean eq = UA_NodeId_equal(&id1, &id2); + if(eq) + return; + + UA_NodeId id3; + UA_NodeId_copy(&id2, &id3); + UA_NodeId_clear(&id3); + + UA_NodeId id4 = UA_NODEID_STRING_ALLOC(1, "testid"); /* the string is copied + to the heap */ + UA_NodeId_clear(&id4); + } + +Variants +^^^^^^^^ +The datatype :ref:`variant` belongs to the built-in datatypes of OPC UA and +is used as a container type. A variant can hold any other datatype as a +scalar (except variant) or as an array. Array variants can additionally +denote the dimensionality of the data (e.g. a 2x3 matrix) in an additional +integer array. + +.. code-block:: c + + + static void + variables_variants(void) { + /* Set a scalar value */ + UA_Variant v; + UA_Int32 i = 42; + UA_Variant_setScalar(&v, &i, &UA_TYPES[UA_TYPES_INT32]); + + /* Make a copy */ + UA_Variant v2; + UA_Variant_copy(&v, &v2); + UA_Variant_clear(&v2); + + /* Set an array value */ + UA_Variant v3; + UA_Double d[9] = {1.0, 2.0, 3.0, + 4.0, 5.0, 6.0, + 7.0, 8.0, 9.0}; + UA_Variant_setArrayCopy(&v3, d, 9, &UA_TYPES[UA_TYPES_DOUBLE]); + + /* Set array dimensions */ + v3.arrayDimensions = (UA_UInt32 *)UA_Array_new(2, &UA_TYPES[UA_TYPES_UINT32]); + v3.arrayDimensionsSize = 2; + v3.arrayDimensions[0] = 3; + v3.arrayDimensions[1] = 3; + UA_Variant_clear(&v3); + } + + #ifdef UA_ENABLE_JSON_ENCODING + static void + prettyprint(void) { + UA_ReadRequest rr; + UA_ReadRequest_init(&rr); + UA_ReadValueId rvi[2]; + UA_ReadValueId_init(rvi); + UA_ReadValueId_init(&rvi[1]); + rr.nodesToRead = rvi; + rr.nodesToReadSize = 2; + UA_String out = UA_STRING_NULL; + UA_print(&rr, &UA_TYPES[UA_TYPES_READREQUEST], &out); + + printf("%.*s\n", (int)out.length, out.data); + UA_String_clear(&out); + + UA_ReadResponse resp; + UA_ReadResponse_init(&resp); + UA_print(&resp, &UA_TYPES[UA_TYPES_READRESPONSE], &out); + + printf("%.*s\n", (int)out.length, out.data); + UA_String_clear(&out); + + UA_ReferenceDescription br; + UA_ReferenceDescription_init(&br); + br.nodeClass = (UA_NodeClass)5; + UA_print(&br, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], &out); + printf("%.*s\n", (int)out.length, out.data); + UA_String_clear(&out); + + UA_Float matrix[4] = {1.0, 2.0, 3.0, 4.0}; + UA_UInt32 matrix_dims[2] = {2, 2}; + UA_DataValue dv; + UA_DataValue_init(&dv); + UA_Variant_setArray(&dv.value, &matrix, 4, &UA_TYPES[UA_TYPES_FLOAT]); + dv.value.arrayDimensions = matrix_dims; + dv.value.arrayDimensionsSize = 2; + dv.hasValue = true; + dv.hasStatus = true; + dv.hasServerTimestamp = true; + dv.hasSourcePicoseconds = true; + UA_print(&dv, &UA_TYPES[UA_TYPES_DATAVALUE], &out); + printf("%.*s\n", (int)out.length, out.data); + UA_String_clear(&out); + } + #endif + +It follows the main function, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + variables_basic(); + variables_nodeids(); + variables_variants(); diff --git a/static/doc/v1.4.0/_sources/tutorial_pubsub_publish.rst.txt b/static/doc/v1.4.0/_sources/tutorial_pubsub_publish.rst.txt new file mode 100644 index 0000000000..9d8b5b9576 --- /dev/null +++ b/static/doc/v1.4.0/_sources/tutorial_pubsub_publish.rst.txt @@ -0,0 +1,224 @@ +.. _pubsub-tutorial: + +Working with Publish/Subscribe +------------------------------ + +Work in progress: This Tutorial will be continuously extended during the next +PubSub batches. More details about the PubSub extension and corresponding +open62541 API are located here: :ref:`pubsub`. + +Publishing Fields +^^^^^^^^^^^^^^^^^ +The PubSub publish example demonstrates the simplest way to publish +information from the information model over UDP multicast using the UADP +encoding. + +**Connection handling** + +PubSubConnections can be created and deleted on runtime. More details about +the system preconfiguration and connection can be found in +``tutorial_pubsub_connection.c``. + +.. code-block:: c + + + #include + #include + #include + + #include + #include + + UA_NodeId connectionIdent, publishedDataSetIdent, writerGroupIdent; + + static void + addPubSubConnection(UA_Server *server, UA_String *transportProfile, + UA_NetworkAddressUrlDataType *networkAddressUrl){ + /* Details about the connection configuration and handling are located + * in the pubsub connection tutorial */ + UA_PubSubConnectionConfig connectionConfig; + memset(&connectionConfig, 0, sizeof(connectionConfig)); + connectionConfig.name = UA_STRING("UADP Connection 1"); + connectionConfig.transportProfileUri = *transportProfile; + connectionConfig.enabled = UA_TRUE; + UA_Variant_setScalar(&connectionConfig.address, networkAddressUrl, + &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); + /* Changed to static publisherId from random generation to identify + * the publisher on Subscriber side */ + connectionConfig.publisherIdType = UA_PUBLISHERIDTYPE_UINT16; + connectionConfig.publisherId.uint16 = 2234; + UA_Server_addPubSubConnection(server, &connectionConfig, &connectionIdent); + } + +**PublishedDataSet handling** + +The PublishedDataSet (PDS) and PubSubConnection are the toplevel entities and +can exist alone. The PDS contains the collection of the published fields. All +other PubSub elements are directly or indirectly linked with the PDS or +connection. + +.. code-block:: c + + static void + addPublishedDataSet(UA_Server *server) { + /* The PublishedDataSetConfig contains all necessary public + * information for the creation of a new PublishedDataSet */ + UA_PublishedDataSetConfig publishedDataSetConfig; + memset(&publishedDataSetConfig, 0, sizeof(UA_PublishedDataSetConfig)); + publishedDataSetConfig.publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDITEMS; + publishedDataSetConfig.name = UA_STRING("Demo PDS"); + /* Create new PublishedDataSet based on the PublishedDataSetConfig. */ + UA_Server_addPublishedDataSet(server, &publishedDataSetConfig, &publishedDataSetIdent); + } + +**DataSetField handling** + +The DataSetField (DSF) is part of the PDS and describes exactly one published +field. + +.. code-block:: c + + static void + addDataSetField(UA_Server *server) { + /* Add a field to the previous created PublishedDataSet */ + UA_NodeId dataSetFieldIdent; + UA_DataSetFieldConfig dataSetFieldConfig; + memset(&dataSetFieldConfig, 0, sizeof(UA_DataSetFieldConfig)); + dataSetFieldConfig.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE; + dataSetFieldConfig.field.variable.fieldNameAlias = UA_STRING("Server localtime"); + dataSetFieldConfig.field.variable.promotedField = UA_FALSE; + dataSetFieldConfig.field.variable.publishParameters.publishedVariable = + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME); + dataSetFieldConfig.field.variable.publishParameters.attributeId = UA_ATTRIBUTEID_VALUE; + UA_Server_addDataSetField(server, publishedDataSetIdent, + &dataSetFieldConfig, &dataSetFieldIdent); + } + +**WriterGroup handling** + +The WriterGroup (WG) is part of the connection and contains the primary +configuration parameters for the message creation. + +.. code-block:: c + + static void + addWriterGroup(UA_Server *server) { + /* Now we create a new WriterGroupConfig and add the group to the existing + * PubSubConnection. */ + UA_WriterGroupConfig writerGroupConfig; + memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig)); + writerGroupConfig.name = UA_STRING("Demo WriterGroup"); + writerGroupConfig.publishingInterval = 100; + writerGroupConfig.enabled = UA_FALSE; + writerGroupConfig.writerGroupId = 100; + writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP; + writerGroupConfig.messageSettings.encoding = UA_EXTENSIONOBJECT_DECODED; + writerGroupConfig.messageSettings.content.decoded.type = &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE]; + /* The configuration flags for the messages are encapsulated inside the + * message- and transport settings extension objects. These extension + * objects are defined by the standard. e.g. + * UadpWriterGroupMessageDataType */ + UA_UadpWriterGroupMessageDataType *writerGroupMessage = UA_UadpWriterGroupMessageDataType_new(); + /* Change message settings of writerGroup to send PublisherId, + * WriterGroupId in GroupHeader and DataSetWriterId in PayloadHeader + * of NetworkMessage */ + writerGroupMessage->networkMessageContentMask = (UA_UadpNetworkMessageContentMask)(UA_UADPNETWORKMESSAGECONTENTMASK_PUBLISHERID | + (UA_UadpNetworkMessageContentMask)UA_UADPNETWORKMESSAGECONTENTMASK_GROUPHEADER | + (UA_UadpNetworkMessageContentMask)UA_UADPNETWORKMESSAGECONTENTMASK_WRITERGROUPID | + (UA_UadpNetworkMessageContentMask)UA_UADPNETWORKMESSAGECONTENTMASK_PAYLOADHEADER); + writerGroupConfig.messageSettings.content.decoded.data = writerGroupMessage; + UA_Server_addWriterGroup(server, connectionIdent, &writerGroupConfig, &writerGroupIdent); + UA_Server_setWriterGroupOperational(server, writerGroupIdent); + UA_UadpWriterGroupMessageDataType_delete(writerGroupMessage); + } + +**DataSetWriter handling** + +A DataSetWriter (DSW) is the glue between the WG and the PDS. The DSW is +linked to exactly one PDS and contains additional information for the +message generation. + +.. code-block:: c + + static void + addDataSetWriter(UA_Server *server) { + /* We need now a DataSetWriter within the WriterGroup. This means we must + * create a new DataSetWriterConfig and add call the addWriterGroup function. */ + UA_NodeId dataSetWriterIdent; + UA_DataSetWriterConfig dataSetWriterConfig; + memset(&dataSetWriterConfig, 0, sizeof(UA_DataSetWriterConfig)); + dataSetWriterConfig.name = UA_STRING("Demo DataSetWriter"); + dataSetWriterConfig.dataSetWriterId = 62541; + dataSetWriterConfig.keyFrameCount = 10; + UA_Server_addDataSetWriter(server, writerGroupIdent, publishedDataSetIdent, + &dataSetWriterConfig, &dataSetWriterIdent); + } + +That's it! You're now publishing the selected fields. Open a packet +inspection tool of trust e.g. wireshark and take a look on the outgoing +packages. The following graphic figures out the packages created by this +tutorial. + +.. figure:: ua-wireshark-pubsub.png + :figwidth: 100 % + :alt: OPC UA PubSub communication in wireshark + +The open62541 subscriber API will be released later. If you want to process +the the datagrams, take a look on the ``ua_network_pubsub_networkmessage.c`` +which already contains the decoding code for UADP messages. + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + static int run(UA_String *transportProfile, + UA_NetworkAddressUrlDataType *networkAddressUrl) { + UA_Server *server = UA_Server_new(); + + addPubSubConnection(server, transportProfile, networkAddressUrl); + addPublishedDataSet(server); + addDataSetField(server); + addWriterGroup(server); + addDataSetWriter(server); + + UA_StatusCode retval = UA_Server_runUntilInterrupt(server); + + UA_Server_delete(server); + return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE; + } + + static void + usage(char *progname) { + printf("usage: %s [device]\n", progname); + } + + int main(int argc, char **argv) { + UA_String transportProfile = + UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"); + UA_NetworkAddressUrlDataType networkAddressUrl = + {UA_STRING_NULL , UA_STRING("opc.udp://224.0.0.22:4840/")}; + + if (argc > 1) { + if (strcmp(argv[1], "-h") == 0) { + usage(argv[0]); + return EXIT_SUCCESS; + } else if (strncmp(argv[1], "opc.udp://", 10) == 0) { + networkAddressUrl.url = UA_STRING(argv[1]); + } else if (strncmp(argv[1], "opc.eth://", 10) == 0) { + transportProfile = + UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp"); + if (argc < 3) { + printf("Error: UADP/ETH needs an interface name\n"); + return EXIT_FAILURE; + } + networkAddressUrl.networkInterface = UA_STRING(argv[2]); + networkAddressUrl.url = UA_STRING(argv[1]); + } else { + printf("Error: unknown URI\n"); + return EXIT_FAILURE; + } + } + + return run(&transportProfile, &networkAddressUrl); + } diff --git a/static/doc/v1.4.0/_sources/tutorial_pubsub_subscribe.rst.txt b/static/doc/v1.4.0/_sources/tutorial_pubsub_subscribe.rst.txt new file mode 100644 index 0000000000..6a7c4a901e --- /dev/null +++ b/static/doc/v1.4.0/_sources/tutorial_pubsub_subscribe.rst.txt @@ -0,0 +1,328 @@ +.. _pubsub-subscribe-tutorial: + +Subscribing Fields +^^^^^^^^^^^^^^^^^^ +The PubSub subscribe example demonstrates the simplest way to receive +information over two transport layers such as UDP and Ethernet, that are +published by tutorial_pubsub_publish example and update values in the +TargetVariables of Subscriber Information Model. + +.. code-block:: c + + + #include + #include + #include + + #include + #include + + UA_NodeId connectionIdentifier; + UA_NodeId readerGroupIdentifier; + UA_NodeId readerIdentifier; + + UA_DataSetReaderConfig readerConfig; + + static void fillTestDataSetMetaData(UA_DataSetMetaDataType *pMetaData); + + /* Add new connection to the server */ + static UA_StatusCode + addPubSubConnection(UA_Server *server, UA_String *transportProfile, + UA_NetworkAddressUrlDataType *networkAddressUrl) { + if((server == NULL) || (transportProfile == NULL) || + (networkAddressUrl == NULL)) { + return UA_STATUSCODE_BADINTERNALERROR; + } + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + /* Configuration creation for the connection */ + UA_PubSubConnectionConfig connectionConfig; + memset (&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig)); + connectionConfig.name = UA_STRING("UDPMC Connection 1"); + connectionConfig.transportProfileUri = *transportProfile; + connectionConfig.enabled = UA_TRUE; + UA_Variant_setScalar(&connectionConfig.address, networkAddressUrl, + &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); + connectionConfig.publisherIdType = UA_PUBLISHERIDTYPE_UINT32; + connectionConfig.publisherId.uint32 = UA_UInt32_random(); + retval |= UA_Server_addPubSubConnection (server, &connectionConfig, &connectionIdentifier); + if (retval != UA_STATUSCODE_GOOD) { + return retval; + } + + return retval; + } + +**ReaderGroup** + +ReaderGroup is used to group a list of DataSetReaders. All ReaderGroups are +created within a PubSubConnection and automatically deleted if the connection +is removed. All network message related filters are only available in the DataSetReader. + +.. code-block:: c + + /* Add ReaderGroup to the created connection */ + static UA_StatusCode + addReaderGroup(UA_Server *server) { + if(server == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; + } + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + UA_ReaderGroupConfig readerGroupConfig; + memset (&readerGroupConfig, 0, sizeof(UA_ReaderGroupConfig)); + readerGroupConfig.name = UA_STRING("ReaderGroup1"); + retval |= UA_Server_addReaderGroup(server, connectionIdentifier, &readerGroupConfig, + &readerGroupIdentifier); + UA_Server_setReaderGroupOperational(server, readerGroupIdentifier); + return retval; + } + +**DataSetReader** + +DataSetReader can receive NetworkMessages with the DataSetMessage +of interest sent by the Publisher. DataSetReader provides +the configuration necessary to receive and process DataSetMessages +on the Subscriber side. DataSetReader must be linked with a +SubscribedDataSet and be contained within a ReaderGroup. + +.. code-block:: c + + /* Add DataSetReader to the ReaderGroup */ + static UA_StatusCode + addDataSetReader(UA_Server *server) { + if(server == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; + } + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + memset (&readerConfig, 0, sizeof(UA_DataSetReaderConfig)); + readerConfig.name = UA_STRING("DataSet Reader 1"); + /* Parameters to filter which DataSetMessage has to be processed + * by the DataSetReader */ + /* The following parameters are used to show that the data published by + * tutorial_pubsub_publish.c is being subscribed and is being updated in + * the information model */ + UA_UInt16 publisherIdentifier = 2234; + readerConfig.publisherId.type = &UA_TYPES[UA_TYPES_UINT16]; + readerConfig.publisherId.data = &publisherIdentifier; + readerConfig.writerGroupId = 100; + readerConfig.dataSetWriterId = 62541; + + /* Setting up Meta data configuration in DataSetReader */ + fillTestDataSetMetaData(&readerConfig.dataSetMetaData); + + retval |= UA_Server_addDataSetReader(server, readerGroupIdentifier, &readerConfig, + &readerIdentifier); + return retval; + } + +**SubscribedDataSet** + +Set SubscribedDataSet type to TargetVariables data type. +Add subscribedvariables to the DataSetReader + +.. code-block:: c + + static UA_StatusCode + addSubscribedVariables (UA_Server *server, UA_NodeId dataSetReaderId) { + if(server == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + UA_NodeId folderId; + UA_String folderName = readerConfig.dataSetMetaData.name; + UA_ObjectAttributes oAttr = UA_ObjectAttributes_default; + UA_QualifiedName folderBrowseName; + if(folderName.length > 0) { + oAttr.displayName.locale = UA_STRING ("en-US"); + oAttr.displayName.text = folderName; + folderBrowseName.namespaceIndex = 1; + folderBrowseName.name = folderName; + } + else { + oAttr.displayName = UA_LOCALIZEDTEXT ("en-US", "Subscribed Variables"); + folderBrowseName = UA_QUALIFIEDNAME (1, "Subscribed Variables"); + } + + UA_Server_addObjectNode (server, UA_NODEID_NULL, + UA_NODEID_NUMERIC (0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC (0, UA_NS0ID_ORGANIZES), + folderBrowseName, UA_NODEID_NUMERIC (0, + UA_NS0ID_BASEOBJECTTYPE), oAttr, NULL, &folderId); + +**TargetVariables** + +The SubscribedDataSet option TargetVariables defines a list of Variable mappings between +received DataSet fields and target Variables in the Subscriber AddressSpace. +The values subscribed from the Publisher are updated in the value field of these variables + +.. code-block:: c + + /* Create the TargetVariables with respect to DataSetMetaData fields */ + UA_FieldTargetVariable *targetVars = (UA_FieldTargetVariable *) + UA_calloc(readerConfig.dataSetMetaData.fieldsSize, sizeof(UA_FieldTargetVariable)); + for(size_t i = 0; i < readerConfig.dataSetMetaData.fieldsSize; i++) { + /* Variable to subscribe data */ + UA_VariableAttributes vAttr = UA_VariableAttributes_default; + UA_LocalizedText_copy(&readerConfig.dataSetMetaData.fields[i].description, + &vAttr.description); + vAttr.displayName.locale = UA_STRING("en-US"); + vAttr.displayName.text = readerConfig.dataSetMetaData.fields[i].name; + vAttr.dataType = readerConfig.dataSetMetaData.fields[i].dataType; + + UA_NodeId newNode; + retval |= UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, (UA_UInt32)i + 50000), + folderId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, (char *)readerConfig.dataSetMetaData.fields[i].name.data), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + vAttr, NULL, &newNode); + + /* For creating Targetvariables */ + UA_FieldTargetDataType_init(&targetVars[i].targetVariable); + targetVars[i].targetVariable.attributeId = UA_ATTRIBUTEID_VALUE; + targetVars[i].targetVariable.targetNodeId = newNode; + } + + retval = UA_Server_DataSetReader_createTargetVariables(server, dataSetReaderId, + readerConfig.dataSetMetaData.fieldsSize, targetVars); + for(size_t i = 0; i < readerConfig.dataSetMetaData.fieldsSize; i++) + UA_FieldTargetDataType_clear(&targetVars[i].targetVariable); + + UA_free(targetVars); + UA_free(readerConfig.dataSetMetaData.fields); + return retval; + } + +**DataSetMetaData** + +The DataSetMetaData describes the content of a DataSet. It provides the information necessary to decode +DataSetMessages on the Subscriber side. DataSetMessages received from the Publisher are decoded into +DataSet and each field is updated in the Subscriber based on datatype match of TargetVariable fields of Subscriber +and PublishedDataSetFields of Publisher + +.. code-block:: c + + /* Define MetaData for TargetVariables */ + static void fillTestDataSetMetaData(UA_DataSetMetaDataType *pMetaData) { + if(pMetaData == NULL) { + return; + } + + UA_DataSetMetaDataType_init (pMetaData); + pMetaData->name = UA_STRING ("DataSet 1"); + + /* Static definition of number of fields size to 4 to create four different + * targetVariables of distinct datatype + * Currently the publisher sends only DateTime data type */ + pMetaData->fieldsSize = 4; + pMetaData->fields = (UA_FieldMetaData*)UA_Array_new (pMetaData->fieldsSize, + &UA_TYPES[UA_TYPES_FIELDMETADATA]); + + /* DateTime DataType */ + UA_FieldMetaData_init (&pMetaData->fields[0]); + UA_NodeId_copy (&UA_TYPES[UA_TYPES_DATETIME].typeId, + &pMetaData->fields[0].dataType); + pMetaData->fields[0].builtInType = UA_NS0ID_DATETIME; + pMetaData->fields[0].name = UA_STRING ("DateTime"); + pMetaData->fields[0].valueRank = -1; /* scalar */ + + /* Int32 DataType */ + UA_FieldMetaData_init (&pMetaData->fields[1]); + UA_NodeId_copy(&UA_TYPES[UA_TYPES_INT32].typeId, + &pMetaData->fields[1].dataType); + pMetaData->fields[1].builtInType = UA_NS0ID_INT32; + pMetaData->fields[1].name = UA_STRING ("Int32"); + pMetaData->fields[1].valueRank = -1; /* scalar */ + + /* Int64 DataType */ + UA_FieldMetaData_init (&pMetaData->fields[2]); + UA_NodeId_copy(&UA_TYPES[UA_TYPES_INT64].typeId, + &pMetaData->fields[2].dataType); + pMetaData->fields[2].builtInType = UA_NS0ID_INT64; + pMetaData->fields[2].name = UA_STRING ("Int64"); + pMetaData->fields[2].valueRank = -1; /* scalar */ + + /* Boolean DataType */ + UA_FieldMetaData_init (&pMetaData->fields[3]); + UA_NodeId_copy (&UA_TYPES[UA_TYPES_BOOLEAN].typeId, + &pMetaData->fields[3].dataType); + pMetaData->fields[3].builtInType = UA_NS0ID_BOOLEAN; + pMetaData->fields[3].name = UA_STRING ("BoolToggle"); + pMetaData->fields[3].valueRank = -1; /* scalar */ + } + +Followed by the main server code, making use of the above definitions + +.. code-block:: c + + + static int + run(UA_String *transportProfile, UA_NetworkAddressUrlDataType *networkAddressUrl) { + /* Return value initialized to Status Good */ + UA_StatusCode retval = UA_STATUSCODE_GOOD; + UA_Server *server = UA_Server_new(); + + /* API calls */ + /* Add PubSubConnection */ + retval |= addPubSubConnection(server, transportProfile, networkAddressUrl); + if (retval != UA_STATUSCODE_GOOD) + return EXIT_FAILURE; + + /* Add ReaderGroup to the created PubSubConnection */ + retval |= addReaderGroup(server); + if (retval != UA_STATUSCODE_GOOD) + return EXIT_FAILURE; + + /* Add DataSetReader to the created ReaderGroup */ + retval |= addDataSetReader(server); + if (retval != UA_STATUSCODE_GOOD) + return EXIT_FAILURE; + + /* Add SubscribedVariables to the created DataSetReader */ + retval |= addSubscribedVariables(server, readerIdentifier); + if (retval != UA_STATUSCODE_GOOD) + return EXIT_FAILURE; + + retval = UA_Server_runUntilInterrupt(server); + + UA_Server_delete(server); + return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE; + } + + static void + usage(char *progname) { + printf("usage: %s [device]\n", progname); + } + + int main(int argc, char **argv) { + UA_String transportProfile = + UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"); + UA_NetworkAddressUrlDataType networkAddressUrl = + {UA_STRING_NULL , UA_STRING("opc.udp://224.0.0.22:4840/")}; + if(argc > 1) { + if(strcmp(argv[1], "-h") == 0) { + usage(argv[0]); + return EXIT_SUCCESS; + } else if(strncmp(argv[1], "opc.udp://", 10) == 0) { + networkAddressUrl.url = UA_STRING(argv[1]); + } else if(strncmp(argv[1], "opc.eth://", 10) == 0) { + transportProfile = + UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp"); + if(argc < 3) { + printf("Error: UADP/ETH needs an interface name\n"); + return EXIT_FAILURE; + } + + networkAddressUrl.networkInterface = UA_STRING(argv[2]); + networkAddressUrl.url = UA_STRING(argv[1]); + } else { + printf ("Error: unknown URI\n"); + return EXIT_FAILURE; + } + } + + return run(&transportProfile, &networkAddressUrl); + } + diff --git a/static/doc/v1.4.0/_sources/tutorial_server_alarms_conditions.rst.txt b/static/doc/v1.4.0/_sources/tutorial_server_alarms_conditions.rst.txt new file mode 100644 index 0000000000..75c8e2209a --- /dev/null +++ b/static/doc/v1.4.0/_sources/tutorial_server_alarms_conditions.rst.txt @@ -0,0 +1,564 @@ +Using Alarms and Conditions Server +---------------------------------- + +Besides the usage of monitored items and events to observe the changes in the +server, it is also important to make use of the Alarms and Conditions Server +Model. Alarms are events which are triggered automatically by the server +dependent on internal server logic or user specific logic when the states of +server components change. The state of a component is represented through a +condition. So the values of all the condition children (Fields) are the +actual state of the component. + +Trigger Alarm events by changing States +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following example will be based on the server events tutorial. Please +make sure to understand the principle of normal events before proceeding with +this example! + +.. code-block:: c + + + static UA_NodeId conditionSource; + static UA_NodeId conditionInstance_1; + static UA_NodeId conditionInstance_2; + + static UA_StatusCode + addConditionSourceObject(UA_Server *server) { + UA_ObjectAttributes object_attr = UA_ObjectAttributes_default; + object_attr.eventNotifier = 1; + + object_attr.displayName = UA_LOCALIZEDTEXT("en", "ConditionSourceObject"); + UA_StatusCode retval = UA_Server_addObjectNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), + UA_QUALIFIEDNAME(0, "ConditionSourceObject"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), + object_attr, NULL, &conditionSource); + + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Creating Condition Source failed. StatusCode %s", + UA_StatusCode_name(retval)); + } + + /* ConditionSource should be EventNotifier of another Object (usually the + * Server Object). If this Reference is not created by user then the A&C + * Server will create "HasEventSource" reference to the Server Object + * automatically when the condition is created*/ + retval = UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASNOTIFIER), + UA_EXPANDEDNODEID_NUMERIC(conditionSource.namespaceIndex, + conditionSource.identifier.numeric), + UA_TRUE); + + return retval; + } + +Create a condition instance from OffNormalAlarmType. The condition source is +the Object created in addConditionSourceObject(). The condition will be +exposed in Address Space through the HasComponent reference to the condition +source. + +.. code-block:: c + + static UA_StatusCode + addCondition_1(UA_Server *server) { + UA_StatusCode retval = addConditionSourceObject(server); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "creating Condition Source failed. StatusCode %s", + UA_StatusCode_name(retval)); + } + + retval = UA_Server_createCondition(server, + UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_OFFNORMALALARMTYPE), + UA_QUALIFIEDNAME(0, "Condition 1"), conditionSource, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + &conditionInstance_1); + + return retval; + } + +Create a condition instance from OffNormalAlarmType. The condition source is +the server Object. The condition won't be exposed in Address Space. + +.. code-block:: c + + static UA_StatusCode + addCondition_2(UA_Server *server) { + UA_StatusCode retval = + UA_Server_createCondition(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_OFFNORMALALARMTYPE), + UA_QUALIFIEDNAME(0, "Condition 2"), + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), + UA_NODEID_NULL, &conditionInstance_2); + + return retval; + } + + static void + addVariable_1_triggerAlarmOfCondition_1(UA_Server *server, UA_NodeId* outNodeId) { + UA_VariableAttributes attr = UA_VariableAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("en", "Activate Condition 1"); + attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + UA_Boolean tboolValue = UA_FALSE; + UA_Variant_setScalar(&attr.value, &tboolValue, &UA_TYPES[UA_TYPES_BOOLEAN]); + + UA_QualifiedName CallbackTestVariableName = UA_QUALIFIEDNAME(0, "Activate Condition 1"); + UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE); + UA_Server_addVariableNode(server, UA_NODEID_NULL, parentNodeId, + parentReferenceNodeId, CallbackTestVariableName, + variableTypeNodeId, attr, NULL, outNodeId); + } + + static void + addVariable_2_changeSeverityOfCondition_2(UA_Server *server, + UA_NodeId* outNodeId) { + UA_VariableAttributes attr = UA_VariableAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("en", "Change Severity Condition 2"); + attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + UA_UInt16 severityValue = 0; + UA_Variant_setScalar(&attr.value, &severityValue, &UA_TYPES[UA_TYPES_UINT16]); + + UA_QualifiedName CallbackTestVariableName = + UA_QUALIFIEDNAME(0, "Change Severity Condition 2"); + UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE); + UA_Server_addVariableNode(server, UA_NODEID_NULL, parentNodeId, + parentReferenceNodeId, CallbackTestVariableName, + variableTypeNodeId, attr, NULL, outNodeId); + } + + static void + addVariable_3_returnCondition_1_toNormalState(UA_Server *server, + UA_NodeId* outNodeId) { + UA_VariableAttributes attr = UA_VariableAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("en", "Return to Normal Condition 1"); + attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + UA_Boolean rtn = 0; + UA_Variant_setScalar(&attr.value, &rtn, &UA_TYPES[UA_TYPES_BOOLEAN]); + + UA_QualifiedName CallbackTestVariableName = + UA_QUALIFIEDNAME(0, "Return to Normal Condition 1"); + UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE); + UA_Server_addVariableNode(server, UA_NODEID_NULL, parentNodeId, + parentReferenceNodeId, CallbackTestVariableName, + variableTypeNodeId, attr, NULL, outNodeId); + } + + static void + afterWriteCallbackVariable_1(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeId, + void *nodeContext, const UA_NumericRange *range, + const UA_DataValue *data) { + UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState"); + UA_QualifiedName activeStateIdField = UA_QUALIFIEDNAME(0,"Id"); + UA_Variant value; + + UA_StatusCode retval = + UA_Server_writeObjectProperty_scalar(server, conditionInstance_1, + UA_QUALIFIEDNAME(0, "Time"), + &data->sourceTimestamp, + &UA_TYPES[UA_TYPES_DATETIME]); + + if(*(UA_Boolean *)(data->value.data) == true) { + /* By writing "true" in ActiveState/Id, the A&C server will set the + * related fields automatically and then will trigger event + * notification. */ + UA_Boolean activeStateId = true; + UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]); + retval |= UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1, + &value, activeStateField, + activeStateIdField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting ActiveState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + } else { + /* By writing "false" in ActiveState/Id, the A&C server will set only + * the ActiveState field automatically to the value "Inactive". The user + * should trigger the event manually by calling + * UA_Server_triggerConditionEvent inside the application or call + * ConditionRefresh method with client to update the event notification. */ + UA_Boolean activeStateId = false; + UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]); + retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1, + &value, activeStateField, + activeStateIdField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting ActiveState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + retval = UA_Server_triggerConditionEvent(server, conditionInstance_1, + conditionSource, NULL); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Triggering condition event failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + } + } + +The callback only changes the severity field of the condition 2. The severity +field is of ConditionVariableType, so changes in it triggers an event +notification automatically by the server. + +.. code-block:: c + + static void + afterWriteCallbackVariable_2(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeId, + void *nodeContext, const UA_NumericRange *range, + const UA_DataValue *data) { + /* Another way to set fields of conditions */ + UA_Server_writeObjectProperty_scalar(server, conditionInstance_2, + UA_QUALIFIEDNAME(0, "Severity"), + (UA_UInt16 *)data->value.data, + &UA_TYPES[UA_TYPES_UINT16]); + } + +RTN = return to normal. + +Retain will be set to false, thus no events will be generated for condition 1 +(although EnabledState/=true). To set Retain to true again, the disable and +enable methods should be called respectively. + +.. code-block:: c + + static void + afterWriteCallbackVariable_3(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + const UA_NumericRange *range, const UA_DataValue *data) { + + //UA_QualifiedName enabledStateField = UA_QUALIFIEDNAME(0,"EnabledState"); + UA_QualifiedName ackedStateField = UA_QUALIFIEDNAME(0,"AckedState"); + UA_QualifiedName confirmedStateField = UA_QUALIFIEDNAME(0,"ConfirmedState"); + UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState"); + UA_QualifiedName severityField = UA_QUALIFIEDNAME(0,"Severity"); + UA_QualifiedName messageField = UA_QUALIFIEDNAME(0,"Message"); + UA_QualifiedName commentField = UA_QUALIFIEDNAME(0,"Comment"); + UA_QualifiedName retainField = UA_QUALIFIEDNAME(0,"Retain"); + UA_QualifiedName idField = UA_QUALIFIEDNAME(0,"Id"); + + UA_StatusCode retval = + UA_Server_writeObjectProperty_scalar(server, conditionInstance_1, + UA_QUALIFIEDNAME(0, "Time"), + &data->serverTimestamp, + &UA_TYPES[UA_TYPES_DATETIME]); + UA_Variant value; + UA_Boolean idValue = false; + UA_Variant_setScalar(&value, &idValue, &UA_TYPES[UA_TYPES_BOOLEAN]); + retval |= UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1, + &value, activeStateField, + idField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting ActiveState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1, + &value, ackedStateField, + idField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting AckedState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1, + &value, confirmedStateField, + idField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting ConfirmedState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + UA_UInt16 severityValue = 100; + UA_Variant_setScalar(&value, &severityValue, &UA_TYPES[UA_TYPES_UINT16]); + retval = UA_Server_setConditionField(server, conditionInstance_1, + &value, severityField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting Severity Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + UA_LocalizedText messageValue = + UA_LOCALIZEDTEXT("en", "Condition returned to normal state"); + UA_Variant_setScalar(&value, &messageValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + retval = UA_Server_setConditionField(server, conditionInstance_1, + &value, messageField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting Message Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + UA_LocalizedText commentValue = UA_LOCALIZEDTEXT("en", "Normal State"); + UA_Variant_setScalar(&value, &commentValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + retval = UA_Server_setConditionField(server, conditionInstance_1, + &value, commentField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting Comment Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + UA_Boolean retainValue = false; + UA_Variant_setScalar(&value, &retainValue, &UA_TYPES[UA_TYPES_BOOLEAN]); + retval = UA_Server_setConditionField(server, conditionInstance_1, + &value, retainField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting Retain Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + retval = UA_Server_triggerConditionEvent(server, conditionInstance_1, + conditionSource, NULL); + if (retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Triggering condition event failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + } + + static UA_StatusCode + enteringEnabledStateCallback(UA_Server *server, const UA_NodeId *condition) { + UA_Boolean retain = true; + return UA_Server_writeObjectProperty_scalar(server, *condition, + UA_QUALIFIEDNAME(0, "Retain"), + &retain, + &UA_TYPES[UA_TYPES_BOOLEAN]); + } + +This is user specific function which will be called upon acknowledging an +alarm notification. In this example we will set the Alarm to Inactive state. +The server is responsible of setting standard fields related to Acknowledge +Method and triggering the alarm notification. + +.. code-block:: c + + static UA_StatusCode + enteringAckedStateCallback(UA_Server *server, const UA_NodeId *condition) { + /* deactivate Alarm when acknowledging*/ + UA_Boolean activeStateId = false; + UA_Variant value; + UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState"); + UA_QualifiedName activeStateIdField = UA_QUALIFIEDNAME(0,"Id"); + + UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]); + UA_StatusCode retval = + UA_Server_setConditionVariableFieldProperty(server, *condition, + &value, activeStateField, + activeStateIdField); + + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting ActiveState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + } + + return retval; + } + + static UA_StatusCode + enteringConfirmedStateCallback(UA_Server *server, const UA_NodeId *condition) { + /* Deactivate Alarm and put it out of the interesting state (by writing + * false to Retain field) when confirming*/ + UA_Boolean activeStateId = false; + UA_Boolean retain = false; + UA_Variant value; + UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState"); + UA_QualifiedName activeStateIdField = UA_QUALIFIEDNAME(0,"Id"); + UA_QualifiedName retainField = UA_QUALIFIEDNAME(0,"Retain"); + + UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]); + UA_StatusCode retval = + UA_Server_setConditionVariableFieldProperty(server, *condition, + &value, activeStateField, + activeStateIdField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting ActiveState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + UA_Variant_setScalar(&value, &retain, &UA_TYPES[UA_TYPES_BOOLEAN]); + retval = UA_Server_setConditionField(server, *condition, + &value, retainField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting ActiveState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + } + + return retval; + } + + static UA_StatusCode + setUpEnvironment(UA_Server *server) { + UA_NodeId variable_1; + UA_NodeId variable_2; + UA_NodeId variable_3; + UA_ValueCallback callback; + callback.onRead = NULL; + + /* Exposed condition 1. We will add to it user specific callbacks when + * entering enabled state, when acknowledging and when confirming. */ + UA_StatusCode retval = addCondition_1(server); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "adding condition 1 failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + UA_TwoStateVariableChangeCallback userSpecificCallback = enteringEnabledStateCallback; + retval = UA_Server_setConditionTwoStateVariableCallback(server, conditionInstance_1, + conditionSource, false, + userSpecificCallback, + UA_ENTERING_ENABLEDSTATE); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "adding entering enabled state callback failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + userSpecificCallback = enteringAckedStateCallback; + retval = UA_Server_setConditionTwoStateVariableCallback(server, conditionInstance_1, + conditionSource, false, + userSpecificCallback, + UA_ENTERING_ACKEDSTATE); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "adding entering acked state callback failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + userSpecificCallback = enteringConfirmedStateCallback; + retval = UA_Server_setConditionTwoStateVariableCallback(server, conditionInstance_1, + conditionSource, false, + userSpecificCallback, + UA_ENTERING_CONFIRMEDSTATE); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "adding entering confirmed state callback failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + /* Unexposed condition 2. No user specific callbacks, so the server will + * behave in a standard manner upon entering enabled state, acknowledging + * and confirming. We will set Retain field to true and enable the condition + * so we can receive event notifications (we cannot call enable method on + * unexposed condition using a client like UaExpert or Softing). */ + retval = addCondition_2(server); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "adding condition 2 failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + UA_Boolean retain = UA_TRUE; + UA_Server_writeObjectProperty_scalar(server, conditionInstance_2, + UA_QUALIFIEDNAME(0, "Retain"), + &retain, &UA_TYPES[UA_TYPES_BOOLEAN]); + + UA_Variant value; + UA_Boolean enabledStateId = true; + UA_QualifiedName enabledStateField = UA_QUALIFIEDNAME(0,"EnabledState"); + UA_QualifiedName enabledStateIdField = UA_QUALIFIEDNAME(0,"Id"); + UA_Variant_setScalar(&value, &enabledStateId, &UA_TYPES[UA_TYPES_BOOLEAN]); + retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_2, + &value, enabledStateField, + enabledStateIdField); + + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting EnabledState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + + /* Add 3 variables to trigger condition events */ + addVariable_1_triggerAlarmOfCondition_1(server, &variable_1); + + callback.onWrite = afterWriteCallbackVariable_1; + retval = UA_Server_setVariableNode_valueCallback(server, variable_1, callback); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting variable 1 Callback failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + /* Severity can change internally also when the condition disabled and + * retain is false. However, in this case no events will be generated. */ + addVariable_2_changeSeverityOfCondition_2(server, &variable_2); + + callback.onWrite = afterWriteCallbackVariable_2; + retval = UA_Server_setVariableNode_valueCallback(server, variable_2, callback); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting variable 2 Callback failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + addVariable_3_returnCondition_1_toNormalState(server, &variable_3); + + callback.onWrite = afterWriteCallbackVariable_3; + retval = UA_Server_setVariableNode_valueCallback(server, variable_3, callback); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting variable 3 Callback failed. StatusCode %s", + UA_StatusCode_name(retval)); + } + + return retval; + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main (void) { + UA_Server *server = UA_Server_new(); + + setUpEnvironment(server); + + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_sources/tutorial_server_datasource.rst.txt b/static/doc/v1.4.0/_sources/tutorial_server_datasource.rst.txt new file mode 100644 index 0000000000..69c19309cd --- /dev/null +++ b/static/doc/v1.4.0/_sources/tutorial_server_datasource.rst.txt @@ -0,0 +1,182 @@ +Connecting a Variable with a Physical Process +--------------------------------------------- + +In OPC UA-based architectures, servers are typically situated near the source +of information. In an industrial context, this translates into servers being +near the physical process and clients consuming the data at runtime. In the +previous tutorial, we saw how to add variables to an OPC UA information +model. This tutorial shows how to connect a variable to runtime information, +for example from measurements of a physical process. For simplicity, we take +the system clock as the underlying "process". + +The following code snippets are each concerned with a different way of +updating variable values at runtime. Taken together, the code snippets define +a compilable source file. + +Updating variables manually +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +As a starting point, assume that a variable for a value of type +:ref:`datetime` has been created in the server with the identifier +"ns=1,s=current-time". Assuming that our application gets triggered when a +new value arrives from the underlying process, we can just write into the +variable. + +.. code-block:: c + + + #include + #include + + static void + updateCurrentTime(UA_Server *server) { + UA_DateTime now = UA_DateTime_now(); + UA_Variant value; + UA_Variant_setScalar(&value, &now, &UA_TYPES[UA_TYPES_DATETIME]); + UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback"); + UA_Server_writeValue(server, currentNodeId, value); + } + + static void + addCurrentTimeVariable(UA_Server *server) { + UA_DateTime now = 0; + UA_VariableAttributes attr = UA_VariableAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("en-US", "Current time - value callback"); + attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + UA_Variant_setScalar(&attr.value, &now, &UA_TYPES[UA_TYPES_DATETIME]); + + UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback"); + UA_QualifiedName currentName = UA_QUALIFIEDNAME(1, "current-time-value-callback"); + UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE); + UA_Server_addVariableNode(server, currentNodeId, parentNodeId, + parentReferenceNodeId, currentName, + variableTypeNodeId, attr, NULL, NULL); + + updateCurrentTime(server); + } + +Variable Value Callback +^^^^^^^^^^^^^^^^^^^^^^^ + +When a value changes continuously, such as the system time, updating the +value in a tight loop would take up a lot of resources. Value callbacks allow +to synchronize a variable value with an external representation. They attach +callbacks to the variable that are executed before every read and after every +write operation. + +.. code-block:: c + + + static void + beforeReadTime(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeid, void *nodeContext, + const UA_NumericRange *range, const UA_DataValue *data) { + updateCurrentTime(server); + } + + static void + afterWriteTime(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + const UA_NumericRange *range, const UA_DataValue *data) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "The variable was updated"); + } + + static void + addValueCallbackToCurrentTimeVariable(UA_Server *server) { + UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback"); + UA_ValueCallback callback ; + callback.onRead = beforeReadTime; + callback.onWrite = afterWriteTime; + UA_Server_setVariableNode_valueCallback(server, currentNodeId, callback); + } + +Variable Data Sources +^^^^^^^^^^^^^^^^^^^^^ + +With value callbacks, the value is still stored in the variable node. +So-called data sources go one step further. The server redirects every read +and write request to a callback function. Upon reading, the callback provides +a copy of the current value. Internally, the data source needs to implement +its own memory management. + +.. code-block:: c + + + static UA_StatusCode + readCurrentTime(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + UA_Boolean sourceTimeStamp, const UA_NumericRange *range, + UA_DataValue *dataValue) { + UA_DateTime now = UA_DateTime_now(); + UA_Variant_setScalarCopy(&dataValue->value, &now, + &UA_TYPES[UA_TYPES_DATETIME]); + dataValue->hasValue = true; + return UA_STATUSCODE_GOOD; + } + + static UA_StatusCode + writeCurrentTime(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + const UA_NumericRange *range, const UA_DataValue *data) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Changing the system time is not implemented"); + return UA_STATUSCODE_BADINTERNALERROR; + } + + static void + addCurrentTimeDataSourceVariable(UA_Server *server) { + UA_VariableAttributes attr = UA_VariableAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("en-US", "Current time - data source"); + attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + + UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-datasource"); + UA_QualifiedName currentName = UA_QUALIFIEDNAME(1, "current-time-datasource"); + UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE); + + UA_DataSource timeDataSource; + timeDataSource.read = readCurrentTime; + timeDataSource.write = writeCurrentTime; + UA_Server_addDataSourceVariableNode(server, currentNodeId, parentNodeId, + parentReferenceNodeId, currentName, + variableTypeNodeId, attr, + timeDataSource, NULL, NULL); + } + + static UA_DataValue *externalValue; + + static void + addCurrentTimeExternalDataSource(UA_Server *server) { + UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-external-source"); + + UA_ValueBackend valueBackend; + valueBackend.backendType = UA_VALUEBACKENDTYPE_EXTERNAL; + valueBackend.backend.external.value = &externalValue; + + UA_Server_setVariableNode_valueBackend(server, currentNodeId, valueBackend); + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + UA_Server *server = UA_Server_new(); + + addCurrentTimeVariable(server); + addValueCallbackToCurrentTimeVariable(server); + addCurrentTimeDataSourceVariable(server); + addCurrentTimeExternalDataSource(server); + + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_sources/tutorial_server_events.rst.txt b/static/doc/v1.4.0/_sources/tutorial_server_events.rst.txt new file mode 100644 index 0000000000..36ab5d07b8 --- /dev/null +++ b/static/doc/v1.4.0/_sources/tutorial_server_events.rst.txt @@ -0,0 +1,161 @@ +Generating events +----------------- +To make sense of the many things going on in a server, monitoring items can +be useful. Though in many cases, data change does not convey enough +information to be the optimal solution. Events can be generated at any time, +hold a lot of information and can be filtered so the client only receives the +specific attributes of interest. + +Emitting events by calling methods +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The following example will be based on the server method tutorial. We will be +creating a method node which generates an event from the server node. + +The event we want to generate should be very simple. Since the `BaseEventType` is abstract, +we will have to create our own event type. `EventTypes` are saved internally as `ObjectTypes`, +so add the type as you would a new `ObjectType`. + +.. code-block:: c + + + static UA_NodeId eventType; + + static UA_StatusCode + addNewEventType(UA_Server *server) { + UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("en-US", "SimpleEventType"); + attr.description = UA_LOCALIZEDTEXT("en-US", "The simple event type we created"); + return UA_Server_addObjectTypeNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), + UA_QUALIFIEDNAME(0, "SimpleEventType"), + attr, NULL, &eventType); + } + +Setting up an event +^^^^^^^^^^^^^^^^^^^ +In order to set up the event, we can first use ``UA_Server_createEvent`` to +give us a node representation of the event. All we need for this is our +`EventType`. Once we have our event node, which is saved internally as an +`ObjectNode`, we can define the attributes the event has the same way we +would define the attributes of an object node. It is not necessary to define +the attributes `EventId`, `ReceiveTime`, `SourceNode` or `EventType` since +these are set automatically by the server. In this example, we will be +setting the fields 'Message' and 'Severity' in addition to `Time` which is +needed to make the example UaExpert compliant. + +.. code-block:: c + + + static UA_StatusCode + setUpEvent(UA_Server *server, UA_NodeId *outId) { + UA_StatusCode retval = UA_Server_createEvent(server, eventType, outId); + if (retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "createEvent failed. StatusCode %s", UA_StatusCode_name(retval)); + return retval; + } + + /* Set the Event Attributes */ + /* Setting the Time is required or else the event will not show up in UAExpert! */ + UA_DateTime eventTime = UA_DateTime_now(); + UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "Time"), + &eventTime, &UA_TYPES[UA_TYPES_DATETIME]); + + UA_UInt16 eventSeverity = 100; + UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "Severity"), + &eventSeverity, &UA_TYPES[UA_TYPES_UINT16]); + + UA_LocalizedText eventMessage = UA_LOCALIZEDTEXT("en-US", "An event has been generated."); + UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "Message"), + &eventMessage, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + + UA_String eventSourceName = UA_STRING("Server"); + UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "SourceName"), + &eventSourceName, &UA_TYPES[UA_TYPES_STRING]); + + return UA_STATUSCODE_GOOD; + } + +Triggering an event +^^^^^^^^^^^^^^^^^^^ +First a node representing an event is generated using ``setUpEvent``. Once +our event is good to go, we specify a node which emits the event - in this +case the server node. We can use ``UA_Server_triggerEvent`` to trigger our +event onto said node. Passing ``NULL`` as the second-last argument means we +will not receive the `EventId`. The last boolean argument states whether the +node should be deleted. + +.. code-block:: c + + + static UA_StatusCode + generateEventMethodCallback(UA_Server *server, + const UA_NodeId *sessionId, void *sessionHandle, + const UA_NodeId *methodId, void *methodContext, + const UA_NodeId *objectId, void *objectContext, + size_t inputSize, const UA_Variant *input, + size_t outputSize, UA_Variant *output) { + + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Creating event"); + + /* set up event */ + UA_NodeId eventNodeId; + UA_StatusCode retval = setUpEvent(server, &eventNodeId); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Creating event failed. StatusCode %s", UA_StatusCode_name(retval)); + return retval; + } + + retval = UA_Server_triggerEvent(server, eventNodeId, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), + NULL, UA_TRUE); + if(retval != UA_STATUSCODE_GOOD) + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Triggering event failed. StatusCode %s", UA_StatusCode_name(retval)); + + return retval; + } + +Now, all that is left to do is to create a method node which uses our +callback. We do not require any input and as output we will be using the +`EventId` we receive from ``triggerEvent``. The `EventId` is generated by the +server internally and is a random unique ID which identifies that specific +event. + +This method node will be added to a basic server setup. + +.. code-block:: c + + + static void + addGenerateEventMethod(UA_Server *server) { + UA_MethodAttributes generateAttr = UA_MethodAttributes_default; + generateAttr.description = UA_LOCALIZEDTEXT("en-US","Generate an event."); + generateAttr.displayName = UA_LOCALIZEDTEXT("en-US","Generate Event"); + generateAttr.executable = true; + generateAttr.userExecutable = true; + UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, 62541), + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "Generate Event"), + generateAttr, &generateEventMethodCallback, + 0, NULL, 0, NULL, NULL, NULL); + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + UA_Server *server = UA_Server_new(); + + addNewEventType(server); + addGenerateEventMethod(server); + + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_sources/tutorial_server_firststeps.rst.txt b/static/doc/v1.4.0/_sources/tutorial_server_firststeps.rst.txt new file mode 100644 index 0000000000..6763279b74 --- /dev/null +++ b/static/doc/v1.4.0/_sources/tutorial_server_firststeps.rst.txt @@ -0,0 +1,84 @@ +Building a Simple Server +------------------------ + +This series of tutorial guide you through your first steps with open62541. +For compiling the examples, you need a compiler (MS Visual Studio 2015 or +newer, GCC, Clang and MinGW32 are all known to be working). The compilation +instructions are given for GCC but should be straightforward to adapt. + +It will also be very helpful to install an OPC UA Client with a graphical +frontend, such as UAExpert by Unified Automation. That will enable you to +examine the information model of any OPC UA server. + +To get started, downdload the open62541 single-file release from +http://open62541.org or generate it according to the :ref:`build instructions +` with the "amalgamation" option enabled. From now on, we assume +you have the ``open62541.c/.h`` files in the current folder. Now create a new +C source-file called ``myServer.c`` with the following content: + +.. code-block:: c + + + #include + + int main(void) { + UA_Server *server = UA_Server_new(); + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } + +This is all that is needed for a simple OPC UA server. With the GCC compiler, +the following command produces an executable: + +.. code-block:: bash + + $ gcc -std=c99 myServer.c -lopen62541 -o myServer + +In a MinGW environment, the Winsock library must be added. + +.. code-block:: bash + + $ gcc -std=c99 myServer.c -lopen62541 -lws2_32 -o myServer.exe + +Now start the server (stop with ctrl-c): + +.. code-block:: bash + + $ ./myServer + +You have now compiled and run your first OPC UA server. You can go ahead and +browse the information model with client. The server is listening on +``opc.tcp://localhost:4840``. + + +Server Configuration and Plugins +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*open62541* provides a flexible framework for building OPC UA servers and +clients. The goals is to have a core library that accommodates for all use +cases and runs on all platforms. Users can then adjust the library to fit +their use case via configuration and by developing (platform-specific) +plugins. The core library is based on C99 only and does not even require +basic POSIX support. For example, the lowlevel networking code is implemented +as an exchangeable plugin. But don't worry. *open62541* provides plugin +implementations for most platforms and sensible default configurations +out-of-the-box. + +In the above server code, we simply take the default server configuration and +add a single TCP network layer that is listerning on port 4840. + +Server Lifecycle +^^^^^^^^^^^^^^^^ + +The code in this example shows the three parts for server lifecycle +management: Creating a server, running the server, and deleting the server. +Creating and deleting a server is trivial once the configuration is set up. +The server is started with ``UA_Server_run``. Internally, the server +schedules regular tasks. Between the timeouts, the server listens on the +network layer for incoming messages. + +In order to integrate OPC UA in a single-threaded application with its own +mainloop (for example provided by a GUI toolkit), one can alternatively drive +the server manually. See the section of the server documentation on +:ref:`server-lifecycle` for details. diff --git a/static/doc/v1.4.0/_sources/tutorial_server_method.rst.txt b/static/doc/v1.4.0/_sources/tutorial_server_method.rst.txt new file mode 100644 index 0000000000..d5f1453d88 --- /dev/null +++ b/static/doc/v1.4.0/_sources/tutorial_server_method.rst.txt @@ -0,0 +1,176 @@ +Adding Methods to Objects +------------------------- + +An object in an OPC UA information model may contain methods similar to +objects in a programming language. Methods are represented by a MethodNode. +Note that several objects may reference the same MethodNode. When an object +type is instantiated, a reference to the method is added instead of copying +the MethodNode. Therefore, the identifier of the context object is always +explicitly stated when a method is called. + +The method callback takes as input a custom data pointer attached to the +method node, the identifier of the object from which the method is called, +and two arrays for the input and output arguments. The input and output +arguments are all of type :ref:`variant`. Each variant may in turn contain a +(multi-dimensional) array or scalar of any data type. + +Constraints for the method arguments are defined in terms of data type, value +rank and array dimension (similar to variable definitions). The argument +definitions are stored in child VariableNodes of the MethodNode with the +respective BrowseNames ``(0, "InputArguments")`` and ``(0, +"OutputArguments")``. + +Example: Hello World Method +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The method takes a string scalar and returns a string scalar with "Hello " +prepended. The type and length of the input arguments is checked internally +by the SDK, so that we don't have to verify the arguments in the callback. + +.. code-block:: c + + + #include + #include + #include + + static UA_StatusCode + helloWorldMethodCallback(UA_Server *server, + const UA_NodeId *sessionId, void *sessionHandle, + const UA_NodeId *methodId, void *methodContext, + const UA_NodeId *objectId, void *objectContext, + size_t inputSize, const UA_Variant *input, + size_t outputSize, UA_Variant *output) { + UA_String *inputStr = (UA_String*)input->data; + UA_String tmp = UA_STRING_ALLOC("Hello "); + if(inputStr->length > 0) { + tmp.data = (UA_Byte *)UA_realloc(tmp.data, tmp.length + inputStr->length); + memcpy(&tmp.data[tmp.length], inputStr->data, inputStr->length); + tmp.length += inputStr->length; + } + UA_Variant_setScalarCopy(output, &tmp, &UA_TYPES[UA_TYPES_STRING]); + UA_String_clear(&tmp); + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Hello World was called"); + return UA_STATUSCODE_GOOD; + } + + static void + addHelloWorldMethod(UA_Server *server) { + UA_Argument inputArgument; + UA_Argument_init(&inputArgument); + inputArgument.description = UA_LOCALIZEDTEXT("en-US", "A String"); + inputArgument.name = UA_STRING("MyInput"); + inputArgument.dataType = UA_TYPES[UA_TYPES_STRING].typeId; + inputArgument.valueRank = UA_VALUERANK_SCALAR; + + UA_Argument outputArgument; + UA_Argument_init(&outputArgument); + outputArgument.description = UA_LOCALIZEDTEXT("en-US", "A String"); + outputArgument.name = UA_STRING("MyOutput"); + outputArgument.dataType = UA_TYPES[UA_TYPES_STRING].typeId; + outputArgument.valueRank = UA_VALUERANK_SCALAR; + + UA_MethodAttributes helloAttr = UA_MethodAttributes_default; + helloAttr.description = UA_LOCALIZEDTEXT("en-US","Say `Hello World`"); + helloAttr.displayName = UA_LOCALIZEDTEXT("en-US","Hello World"); + helloAttr.executable = true; + helloAttr.userExecutable = true; + UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1,62541), + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "hello world"), + helloAttr, &helloWorldMethodCallback, + 1, &inputArgument, 1, &outputArgument, NULL, NULL); + } + +Increase Array Values Method +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The method takes an array of 5 integers and a scalar as input. It returns a +copy of the array with every entry increased by the scalar. + +.. code-block:: c + + + static UA_StatusCode + IncInt32ArrayMethodCallback(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *methodId, void *methodContext, + const UA_NodeId *objectId, void *objectContext, + size_t inputSize, const UA_Variant *input, + size_t outputSize, UA_Variant *output) { + UA_Int32 *inputArray = (UA_Int32*)input[0].data; + UA_Int32 delta = *(UA_Int32*)input[1].data; + + /* Copy the input array */ + UA_StatusCode retval = UA_Variant_setArrayCopy(output, inputArray, 5, + &UA_TYPES[UA_TYPES_INT32]); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Increate the elements */ + UA_Int32 *outputArray = (UA_Int32*)output->data; + for(size_t i = 0; i < input->arrayLength; i++) + outputArray[i] = inputArray[i] + delta; + + return UA_STATUSCODE_GOOD; + } + + static void + addIncInt32ArrayMethod(UA_Server *server) { + /* Two input arguments */ + UA_Argument inputArguments[2]; + UA_Argument_init(&inputArguments[0]); + inputArguments[0].description = UA_LOCALIZEDTEXT("en-US", "int32[5] array"); + inputArguments[0].name = UA_STRING("int32 array"); + inputArguments[0].dataType = UA_TYPES[UA_TYPES_INT32].typeId; + inputArguments[0].valueRank = UA_VALUERANK_ONE_DIMENSION; + UA_UInt32 pInputDimension = 5; + inputArguments[0].arrayDimensionsSize = 1; + inputArguments[0].arrayDimensions = &pInputDimension; + + UA_Argument_init(&inputArguments[1]); + inputArguments[1].description = UA_LOCALIZEDTEXT("en-US", "int32 delta"); + inputArguments[1].name = UA_STRING("int32 delta"); + inputArguments[1].dataType = UA_TYPES[UA_TYPES_INT32].typeId; + inputArguments[1].valueRank = UA_VALUERANK_SCALAR; + + /* One output argument */ + UA_Argument outputArgument; + UA_Argument_init(&outputArgument); + outputArgument.description = UA_LOCALIZEDTEXT("en-US", "int32[5] array"); + outputArgument.name = UA_STRING("each entry is incremented by the delta"); + outputArgument.dataType = UA_TYPES[UA_TYPES_INT32].typeId; + outputArgument.valueRank = UA_VALUERANK_ONE_DIMENSION; + UA_UInt32 pOutputDimension = 5; + outputArgument.arrayDimensionsSize = 1; + outputArgument.arrayDimensions = &pOutputDimension; + + /* Add the method node */ + UA_MethodAttributes incAttr = UA_MethodAttributes_default; + incAttr.description = UA_LOCALIZEDTEXT("en-US", "IncInt32ArrayValues"); + incAttr.displayName = UA_LOCALIZEDTEXT("en-US", "IncInt32ArrayValues"); + incAttr.executable = true; + incAttr.userExecutable = true; + UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "IncInt32ArrayValues"), + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "IncInt32ArrayValues"), + incAttr, &IncInt32ArrayMethodCallback, + 2, inputArguments, 1, &outputArgument, + NULL, NULL); + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + UA_Server *server = UA_Server_new(); + + addHelloWorldMethod(server); + addIncInt32ArrayMethod(server); + + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_sources/tutorial_server_monitoreditems.rst.txt b/static/doc/v1.4.0/_sources/tutorial_server_monitoreditems.rst.txt new file mode 100644 index 0000000000..12bdc07919 --- /dev/null +++ b/static/doc/v1.4.0/_sources/tutorial_server_monitoreditems.rst.txt @@ -0,0 +1,57 @@ +Observing Attributes with Local MonitoredItems +---------------------------------------------- + +A client that is interested in the current value of a variable does not need +to regularly poll the variable. Instead, the client can use the Subscription +mechanism to be notified about changes. + +So-called MonitoredItems define which values (node attributes) and events the +client wants to monitor. Under the right conditions, a notification is +created and added to the Subscription. The notifications currently in the +queue are regularly sent to the client. + +The local user can add MonitoredItems as well. Locally, the MonitoredItems do +not go via a Subscription and each have an individual callback method and a +context pointer. + +.. code-block:: c + + + #include + #include + #include + + static void + dataChangeNotificationCallback(UA_Server *server, UA_UInt32 monitoredItemId, + void *monitoredItemContext, const UA_NodeId *nodeId, + void *nodeContext, UA_UInt32 attributeId, + const UA_DataValue *value) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Received Notification"); + } + + static void + addMonitoredItemToCurrentTimeVariable(UA_Server *server) { + UA_NodeId currentTimeNodeId = + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME); + UA_MonitoredItemCreateRequest monRequest = + UA_MonitoredItemCreateRequest_default(currentTimeNodeId); + monRequest.requestedParameters.samplingInterval = 100.0; /* 100 ms interval */ + UA_Server_createDataChangeMonitoredItem(server, UA_TIMESTAMPSTORETURN_SOURCE, + monRequest, NULL, + dataChangeNotificationCallback); + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + UA_Server *server = UA_Server_new(); + + addMonitoredItemToCurrentTimeVariable(server); + + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_sources/tutorial_server_object.rst.txt b/static/doc/v1.4.0/_sources/tutorial_server_object.rst.txt new file mode 100644 index 0000000000..bd225c6d9b --- /dev/null +++ b/static/doc/v1.4.0/_sources/tutorial_server_object.rst.txt @@ -0,0 +1,334 @@ +Working with Objects and Object Types +------------------------------------- + +Using objects to structure information models +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Assume a situation where we want to model a set of pumps and their runtime +state in an OPC UA information model. Of course, all pump representations +should follow the same basic structure, For example, we might have graphical +representation of pumps in a SCADA visualisation that shall be resuable for +all pumps. + +Following the object-oriented programming paradigm, every pump is represented +by an object with the following layout: + +.. graphviz:: + + digraph tree { + + fixedsize=true; + node [width=2, height=0, shape=box, fillcolor="#E5E5E5", concentrate=true] + + node_root [label=< ObjectNode
Pump >] + + { rank=same + point_1 [shape=point] + node_1 [label=< VariableNode
ManufacturerName >] } + node_root -> point_1 [arrowhead=none] + point_1 -> node_1 [label="hasComponent"] + + { rank=same + point_2 [shape=point] + node_2 [label=< VariableNode
ModelName >] } + point_1 -> point_2 [arrowhead=none] + point_2 -> node_2 [label="hasComponent"] + + { rank=same + point_4 [shape=point] + node_4 [label=< VariableNode
Status >] } + point_2 -> point_4 [arrowhead=none] + point_4 -> node_4 [label="hasComponent"] + + { rank=same + point_5 [shape=point] + node_5 [label=< VariableNode
MotorRPM >] } + point_4 -> point_5 [arrowhead=none] + point_5 -> node_5 [label="hasComponent"] + + } + +The following code manually defines a pump and its member variables. We omit +setting constraints on the variable values as this is not the focus of this +tutorial and was already covered. + +.. code-block:: c + + + static void + manuallyDefinePump(UA_Server *server) { + UA_NodeId pumpId; /* get the nodeid assigned by the server */ + UA_ObjectAttributes oAttr = UA_ObjectAttributes_default; + oAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Pump (Manual)"); + UA_Server_addObjectNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), + UA_QUALIFIEDNAME(1, "Pump (Manual)"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), + oAttr, NULL, &pumpId); + + UA_VariableAttributes mnAttr = UA_VariableAttributes_default; + UA_String manufacturerName = UA_STRING("Pump King Ltd."); + UA_Variant_setScalar(&mnAttr.value, &manufacturerName, &UA_TYPES[UA_TYPES_STRING]); + mnAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ManufacturerName"); + UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "ManufacturerName"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + mnAttr, NULL, NULL); + + UA_VariableAttributes modelAttr = UA_VariableAttributes_default; + UA_String modelName = UA_STRING("Mega Pump 3000"); + UA_Variant_setScalar(&modelAttr.value, &modelName, &UA_TYPES[UA_TYPES_STRING]); + modelAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ModelName"); + UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "ModelName"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + modelAttr, NULL, NULL); + + UA_VariableAttributes statusAttr = UA_VariableAttributes_default; + UA_Boolean status = true; + UA_Variant_setScalar(&statusAttr.value, &status, &UA_TYPES[UA_TYPES_BOOLEAN]); + statusAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Status"); + UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "Status"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + statusAttr, NULL, NULL); + + UA_VariableAttributes rpmAttr = UA_VariableAttributes_default; + UA_Double rpm = 50.0; + UA_Variant_setScalar(&rpmAttr.value, &rpm, &UA_TYPES[UA_TYPES_DOUBLE]); + rpmAttr.displayName = UA_LOCALIZEDTEXT("en-US", "MotorRPM"); + UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "MotorRPMs"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + rpmAttr, NULL, NULL); + } + +Object types, type hierarchies and instantiation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Building up each object manually requires us to write a lot of code. +Furthermore, there is no way for clients to detect that an object represents +a pump. (We might use naming conventions or similar to detect pumps. But +that's not exactly a clean solution.) Furthermore, we might have more devices +than just pumps. And we require all devices to share some common structure. +The solution is to define ObjectTypes in a hierarchy with inheritance +relations. + +.. graphviz:: + + digraph tree { + + fixedsize=true; + node [width=2, height=0, shape=box, fillcolor="#E5E5E5", concentrate=true] + + node_root [label=< ObjectTypeNode
Device >] + + { rank=same + point_1 [shape=point] + node_1 [label=< VariableNode
ManufacturerName
(mandatory) >] } + node_root -> point_1 [arrowhead=none] + point_1 -> node_1 [label="hasComponent"] + + { rank=same + point_2 [shape=point] + node_2 [label=< VariableNode
ModelName >] } + point_1 -> point_2 [arrowhead=none] + point_2 -> node_2 [label="hasComponent"] + + { rank=same + point_3 [shape=point] + node_3 [label=< ObjectTypeNode
Pump >] } + point_2 -> point_3 [arrowhead=none] + point_3 -> node_3 [label="hasSubtype"] + + { rank=same + point_4 [shape=point] + node_4 [label=< VariableNode
Status
(mandatory) >] } + node_3 -> point_4 [arrowhead=none] + point_4 -> node_4 [label="hasComponent"] + + { rank=same + point_5 [shape=point] + node_5 [label=< VariableNode
MotorRPM >] } + point_4 -> point_5 [arrowhead=none] + point_5 -> node_5 [label="hasComponent"] + + } + +Children that are marked mandatory are automatically instantiated together +with the parent object. This is indicated by a `hasModellingRule` reference +to an object that representes the `mandatory` modelling rule. + +.. code-block:: c + + + /* predefined identifier for later use */ + UA_NodeId pumpTypeId = {1, UA_NODEIDTYPE_NUMERIC, {1001}}; + + static void + defineObjectTypes(UA_Server *server) { + /* Define the object type for "Device" */ + UA_NodeId deviceTypeId; /* get the nodeid assigned by the server */ + UA_ObjectTypeAttributes dtAttr = UA_ObjectTypeAttributes_default; + dtAttr.displayName = UA_LOCALIZEDTEXT("en-US", "DeviceType"); + UA_Server_addObjectTypeNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), + UA_QUALIFIEDNAME(1, "DeviceType"), dtAttr, + NULL, &deviceTypeId); + + UA_VariableAttributes mnAttr = UA_VariableAttributes_default; + mnAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ManufacturerName"); + UA_NodeId manufacturerNameId; + UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "ManufacturerName"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + mnAttr, NULL, &manufacturerNameId); + /* Make the manufacturer name mandatory */ + UA_Server_addReference(server, manufacturerNameId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE), + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true); + + + UA_VariableAttributes modelAttr = UA_VariableAttributes_default; + modelAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ModelName"); + UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "ModelName"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + modelAttr, NULL, NULL); + + /* Define the object type for "Pump" */ + UA_ObjectTypeAttributes ptAttr = UA_ObjectTypeAttributes_default; + ptAttr.displayName = UA_LOCALIZEDTEXT("en-US", "PumpType"); + UA_Server_addObjectTypeNode(server, pumpTypeId, + deviceTypeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), + UA_QUALIFIEDNAME(1, "PumpType"), ptAttr, + NULL, NULL); + + UA_VariableAttributes statusAttr = UA_VariableAttributes_default; + statusAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Status"); + statusAttr.valueRank = UA_VALUERANK_SCALAR; + UA_NodeId statusId; + UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "Status"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + statusAttr, NULL, &statusId); + /* Make the status variable mandatory */ + UA_Server_addReference(server, statusId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE), + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true); + + UA_VariableAttributes rpmAttr = UA_VariableAttributes_default; + rpmAttr.displayName = UA_LOCALIZEDTEXT("en-US", "MotorRPM"); + rpmAttr.valueRank = UA_VALUERANK_SCALAR; + UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "MotorRPMs"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + rpmAttr, NULL, NULL); + } + +Now we add the derived ObjectType for the pump that inherits from the device +object type. The resulting object contains all mandatory child variables. +These are simply copied over from the object type. The object has a reference +of type ``hasTypeDefinition`` to the object type, so that clients can detect +the type-instance relation at runtime. + +.. code-block:: c + + + static void + addPumpObjectInstance(UA_Server *server, char *name) { + UA_ObjectAttributes oAttr = UA_ObjectAttributes_default; + oAttr.displayName = UA_LOCALIZEDTEXT("en-US", name); + UA_Server_addObjectNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), + UA_QUALIFIEDNAME(1, name), + pumpTypeId, /* this refers to the object type + identifier */ + oAttr, NULL, NULL); + } + +Often we want to run a constructor function on a new object. This is +especially useful when an object is instantiated at runtime (with the +AddNodes service) and the integration with an underlying process cannot be +manually defined. In the following constructor example, we simply set the +pump status to on. + +.. code-block:: c + + + static UA_StatusCode + pumpTypeConstructor(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *typeId, void *typeContext, + const UA_NodeId *nodeId, void **nodeContext) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "New pump created"); + + /* Find the NodeId of the status child variable */ + UA_RelativePathElement rpe; + UA_RelativePathElement_init(&rpe); + rpe.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT); + rpe.isInverse = false; + rpe.includeSubtypes = false; + rpe.targetName = UA_QUALIFIEDNAME(1, "Status"); + + UA_BrowsePath bp; + UA_BrowsePath_init(&bp); + bp.startingNode = *nodeId; + bp.relativePath.elementsSize = 1; + bp.relativePath.elements = &rpe; + + UA_BrowsePathResult bpr = + UA_Server_translateBrowsePathToNodeIds(server, &bp); + if(bpr.statusCode != UA_STATUSCODE_GOOD || + bpr.targetsSize < 1) + return bpr.statusCode; + + /* Set the status value */ + UA_Boolean status = true; + UA_Variant value; + UA_Variant_setScalar(&value, &status, &UA_TYPES[UA_TYPES_BOOLEAN]); + UA_Server_writeValue(server, bpr.targets[0].targetId.nodeId, value); + UA_BrowsePathResult_clear(&bpr); + + /* At this point we could replace the node context .. */ + + return UA_STATUSCODE_GOOD; + } + + static void + addPumpTypeConstructor(UA_Server *server) { + UA_NodeTypeLifecycle lifecycle; + lifecycle.constructor = pumpTypeConstructor; + lifecycle.destructor = NULL; + UA_Server_setNodeTypeLifecycle(server, pumpTypeId, lifecycle); + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + UA_Server *server = UA_Server_new(); + + manuallyDefinePump(server); + defineObjectTypes(server); + addPumpObjectInstance(server, "pump2"); + addPumpObjectInstance(server, "pump3"); + addPumpTypeConstructor(server); + addPumpObjectInstance(server, "pump4"); + addPumpObjectInstance(server, "pump5"); + + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_sources/tutorial_server_variable.rst.txt b/static/doc/v1.4.0/_sources/tutorial_server_variable.rst.txt new file mode 100644 index 0000000000..c6c79e6f3b --- /dev/null +++ b/static/doc/v1.4.0/_sources/tutorial_server_variable.rst.txt @@ -0,0 +1,142 @@ +Adding Variables to a Server +---------------------------- + +This tutorial shows how to work with data types and how to add variable nodes +to a server. First, we add a new variable to the server. Take a look at the +definition of the ``UA_VariableAttributes`` structure to see the list of all +attributes defined for VariableNodes. + +Note that the default settings have the AccessLevel of the variable value as +read only. See below for making the variable writable. + +.. code-block:: c + + + #include + #include + #include + + static void + addVariable(UA_Server *server) { + /* Define the attribute of the myInteger variable node */ + UA_VariableAttributes attr = UA_VariableAttributes_default; + UA_Int32 myInteger = 42; + UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]); + attr.description = UA_LOCALIZEDTEXT("en-US","the answer"); + attr.displayName = UA_LOCALIZEDTEXT("en-US","the answer"); + attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId; + attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + + /* Add the variable node to the information model */ + UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); + UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer"); + UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, + parentReferenceNodeId, myIntegerName, + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), attr, NULL, NULL); + } + + static void + addMatrixVariable(UA_Server *server) { + UA_VariableAttributes attr = UA_VariableAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("en-US", "Double Matrix"); + attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + + /* Set the variable value constraints */ + attr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId; + attr.valueRank = UA_VALUERANK_TWO_DIMENSIONS; + UA_UInt32 arrayDims[2] = {2,2}; + attr.arrayDimensions = arrayDims; + attr.arrayDimensionsSize = 2; + + /* Set the value. The array dimensions need to be the same for the value. */ + UA_Double zero[4] = {0.0, 0.0, 0.0, 0.0}; + UA_Variant_setArray(&attr.value, zero, 4, &UA_TYPES[UA_TYPES_DOUBLE]); + attr.value.arrayDimensions = arrayDims; + attr.value.arrayDimensionsSize = 2; + + UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "double.matrix"); + UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "double matrix"); + UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, + parentReferenceNodeId, myIntegerName, + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + attr, NULL, NULL); + } + +Now we change the value with the write service. This uses the same service +implementation that can also be reached over the network by an OPC UA client. + +.. code-block:: c + + + static void + writeVariable(UA_Server *server) { + UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); + + /* Write a different integer value */ + UA_Int32 myInteger = 43; + UA_Variant myVar; + UA_Variant_init(&myVar); + UA_Variant_setScalar(&myVar, &myInteger, &UA_TYPES[UA_TYPES_INT32]); + UA_Server_writeValue(server, myIntegerNodeId, myVar); + + /* Set the status code of the value to an error code. The function + * UA_Server_write provides access to the raw service. The above + * UA_Server_writeValue is syntactic sugar for writing a specific node + * attribute with the write service. */ + UA_WriteValue wv; + UA_WriteValue_init(&wv); + wv.nodeId = myIntegerNodeId; + wv.attributeId = UA_ATTRIBUTEID_VALUE; + wv.value.status = UA_STATUSCODE_BADNOTCONNECTED; + wv.value.hasStatus = true; + UA_Server_write(server, &wv); + + /* Reset the variable to a good statuscode with a value */ + wv.value.hasStatus = false; + wv.value.value = myVar; + wv.value.hasValue = true; + UA_Server_write(server, &wv); + } + +Note how we initially set the DataType attribute of the variable node to the +NodeId of the Int32 data type. This forbids writing values that are not an +Int32. The following code shows how this consistency check is performed for +every write. + +.. code-block:: c + + + static void + writeWrongVariable(UA_Server *server) { + UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); + + /* Write a string */ + UA_String myString = UA_STRING("test"); + UA_Variant myVar; + UA_Variant_init(&myVar); + UA_Variant_setScalar(&myVar, &myString, &UA_TYPES[UA_TYPES_STRING]); + UA_StatusCode retval = UA_Server_writeValue(server, myIntegerNodeId, myVar); + printf("Writing a string returned statuscode %s\n", UA_StatusCode_name(retval)); + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + UA_Server *server = UA_Server_new(); + + addVariable(server); + addMatrixVariable(server); + writeVariable(server); + writeWrongVariable(server); + + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_sources/tutorial_server_variabletype.rst.txt b/static/doc/v1.4.0/_sources/tutorial_server_variabletype.rst.txt new file mode 100644 index 0000000000..0a59bcdf74 --- /dev/null +++ b/static/doc/v1.4.0/_sources/tutorial_server_variabletype.rst.txt @@ -0,0 +1,133 @@ +Working with Variable Types +--------------------------- + +Variable types have three functions: + +- Constrain the possible data type, value rank and array dimensions of the + variables of that type. This allows interface code to be written against + the generic type definition, so it is applicable for all instances. +- Provide a sensible default value +- Enable a semantic interpretation of the variable based on its type + +In the example of this tutorial, we represent a point in 2D space by an array +of double values. The following function adds the corresponding +VariableTypeNode to the hierarchy of variable types. + +.. code-block:: c + + + #include + #include + + static UA_NodeId pointTypeId; + + static void + addVariableType2DPoint(UA_Server *server) { + UA_VariableTypeAttributes vtAttr = UA_VariableTypeAttributes_default; + vtAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId; + vtAttr.valueRank = UA_VALUERANK_ONE_DIMENSION; + UA_UInt32 arrayDims[1] = {2}; + vtAttr.arrayDimensions = arrayDims; + vtAttr.arrayDimensionsSize = 1; + vtAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Type"); + + /* a matching default value is required */ + UA_Double zero[2] = {0.0, 0.0}; + UA_Variant_setArray(&vtAttr.value, zero, 2, &UA_TYPES[UA_TYPES_DOUBLE]); + + UA_Server_addVariableTypeNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), + UA_QUALIFIEDNAME(1, "2DPoint Type"), UA_NODEID_NULL, + vtAttr, NULL, &pointTypeId); + } + +Now the new variable type for *2DPoint* can be referenced during the creation +of a new variable. If no value is given, the default from the variable type +is copied during instantiation. + +.. code-block:: c + + + static UA_NodeId pointVariableId; + + static void + addVariable(UA_Server *server) { + /* Prepare the node attributes */ + UA_VariableAttributes vAttr = UA_VariableAttributes_default; + vAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId; + vAttr.valueRank = UA_VALUERANK_ONE_DIMENSION; + UA_UInt32 arrayDims[1] = {2}; + vAttr.arrayDimensions = arrayDims; + vAttr.arrayDimensionsSize = 1; + vAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Variable"); + vAttr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + /* vAttr.value is left empty, the server instantiates with the default value */ + + /* Add the node */ + UA_Server_addVariableNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "2DPoint Type"), pointTypeId, + vAttr, NULL, &pointVariableId); + } + +The constraints of the variable type are enforced when creating new variable +instances of the type. In the following function, adding a variable of +*2DPoint* type with a string value fails because the value does not match the +variable type constraints. + +.. code-block:: c + + + static void + addVariableFail(UA_Server *server) { + /* Prepare the node attributes */ + UA_VariableAttributes vAttr = UA_VariableAttributes_default; + vAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId; + vAttr.valueRank = UA_VALUERANK_SCALAR; /* a scalar. this is not allowed per + * the variable type */ + vAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Variable (fail)"); + UA_String s = UA_STRING("2dpoint?"); + UA_Variant_setScalar(&vAttr.value, &s, &UA_TYPES[UA_TYPES_STRING]); + + /* Add the node will return UA_STATUSCODE_BADTYPEMISMATCH*/ + UA_Server_addVariableNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "2DPoint Type (fail)"), pointTypeId, + vAttr, NULL, NULL); + } + +The constraints of the variable type are enforced when writing the datatype, +valuerank and arraydimensions attributes of the variable. This, in turn, +constrains the value attribute of the variable. + +.. code-block:: c + + + static void + writeVariable(UA_Server *server) { + UA_StatusCode retval = + UA_Server_writeValueRank(server, pointVariableId, + UA_VALUERANK_ONE_OR_MORE_DIMENSIONS); + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting the Value Rank failed with Status Code %s", + UA_StatusCode_name(retval)); + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + UA_Server *server = UA_Server_new(); + addVariableType2DPoint(server); + addVariable(server); + addVariableFail(server); + writeVariable(server); + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_sources/tutorials.rst.txt b/static/doc/v1.4.0/_sources/tutorials.rst.txt new file mode 100644 index 0000000000..8c23338045 --- /dev/null +++ b/static/doc/v1.4.0/_sources/tutorials.rst.txt @@ -0,0 +1,20 @@ +.. _tutorials: + +Tutorials +========= + +.. toctree:: + + tutorial_datatypes.rst + tutorial_server_firststeps.rst + tutorial_server_variable.rst + tutorial_server_datasource.rst + tutorial_server_variabletype.rst + tutorial_server_object.rst + tutorial_server_method.rst + tutorial_server_monitoreditems.rst + tutorial_server_events.rst + tutorial_server_alarms_conditions.rst + tutorial_client_firststeps.rst + tutorial_pubsub_publish.rst + tutorial_pubsub_subscribe.rst diff --git a/static/doc/v1.4.0/_sources/types.rst.txt b/static/doc/v1.4.0/_sources/types.rst.txt new file mode 100644 index 0000000000..dce31cb1d0 --- /dev/null +++ b/static/doc/v1.4.0/_sources/types.rst.txt @@ -0,0 +1,1545 @@ +.. _types: + +Data Types +========== + +The OPC UA protocol defines 25 builtin data types and three ways of combining +them into higher-order types: arrays, structures and unions. In open62541, +only the builtin data types are defined manually. All other data types are +generated from standard XML definitions. Their exact definitions can be +looked up at https://opcfoundation.org/UA/schemas/Opc.Ua.Types.bsd. + +For users that are new to open62541, take a look at the :ref:`tutorial for +working with data types` before diving into the +implementation details. + +Builtin Types +------------- + +Boolean +^^^^^^^ +A two-state logical value (true or false). + +.. code-block:: c + + typedef bool UA_Boolean; + #define UA_TRUE true UA_INTERNAL_DEPRECATED + #define UA_FALSE false UA_INTERNAL_DEPRECATED + +SByte +^^^^^ +An integer value between -128 and 127. + +.. code-block:: c + + typedef int8_t UA_SByte; + #define UA_SBYTE_MIN (-128) + #define UA_SBYTE_MAX 127 + +Byte +^^^^ +An integer value between 0 and 255. + +.. code-block:: c + + typedef uint8_t UA_Byte; + #define UA_BYTE_MIN 0 + #define UA_BYTE_MAX 255 + +Int16 +^^^^^ +An integer value between -32 768 and 32 767. + +.. code-block:: c + + typedef int16_t UA_Int16; + #define UA_INT16_MIN (-32768) + #define UA_INT16_MAX 32767 + +UInt16 +^^^^^^ +An integer value between 0 and 65 535. + +.. code-block:: c + + typedef uint16_t UA_UInt16; + #define UA_UINT16_MIN 0 + #define UA_UINT16_MAX 65535 + +Int32 +^^^^^ +An integer value between -2 147 483 648 and 2 147 483 647. + +.. code-block:: c + + typedef int32_t UA_Int32; + #define UA_INT32_MIN ((int32_t)-2147483648LL) + #define UA_INT32_MAX 2147483647L + +UInt32 +^^^^^^ +An integer value between 0 and 4 294 967 295. + +.. code-block:: c + + typedef uint32_t UA_UInt32; + #define UA_UINT32_MIN 0 + #define UA_UINT32_MAX 4294967295UL + +Int64 +^^^^^ +An integer value between -9 223 372 036 854 775 808 and +9 223 372 036 854 775 807. + +.. code-block:: c + + typedef int64_t UA_Int64; + #define UA_INT64_MAX (int64_t)9223372036854775807LL + #define UA_INT64_MIN ((int64_t)-UA_INT64_MAX-1LL) + +UInt64 +^^^^^^ +An integer value between 0 and 18 446 744 073 709 551 615. + +.. code-block:: c + + typedef uint64_t UA_UInt64; + #define UA_UINT64_MIN 0 + #define UA_UINT64_MAX (uint64_t)18446744073709551615ULL + +Float +^^^^^ +An IEEE single precision (32 bit) floating point value. + +.. code-block:: c + + typedef float UA_Float; + #define UA_FLOAT_MIN FLT_MIN; + #define UA_FLOAT_MAX FLT_MAX; + +Double +^^^^^^ +An IEEE double precision (64 bit) floating point value. + +.. code-block:: c + + typedef double UA_Double; + #define UA_DOUBLE_MIN DBL_MIN; + #define UA_DOUBLE_MAX DBL_MAX; + +.. _statuscode: + +StatusCode +^^^^^^^^^^ +A numeric identifier for an error or condition that is associated with a +value or an operation. See the section :ref:`statuscodes` for the meaning of +a specific code. + +Each StatusCode has one of three "severity" bit-flags: +Good, Uncertain, Bad. An additional reason is indicated by the SubCode +bitfield. + +- A StatusCode with severity Good means that the value is of good quality. +- A StatusCode with severity Uncertain means that the quality of the value is + uncertain for reasons indicated by the SubCode. +- A StatusCode with severity Bad means that the value is not usable for + reasons indicated by the SubCode. + +.. code-block:: c + + typedef uint32_t UA_StatusCode; + + /* Returns the human-readable name of the StatusCode. If no matching StatusCode + * is found, a default string for "Unknown" is returned. This feature might be + * disabled to create a smaller binary with the + * UA_ENABLE_STATUSCODE_DESCRIPTIONS build-flag. Then the function returns an + * empty string for every StatusCode. */ + const char * + UA_StatusCode_name(UA_StatusCode code); + + /* Extracts the severity from a StatusCode. See Part 4, Section 7.34 for + * details. */ + UA_INLINABLE(UA_Boolean + UA_StatusCode_isBad(UA_StatusCode code), { + return ((code >> 30) >= 0x02); + }) + + UA_INLINABLE(UA_Boolean + UA_StatusCode_isUncertain(UA_StatusCode code), { + return ((code >> 30) == 0x01); + }) + + UA_INLINABLE(UA_Boolean + UA_StatusCode_isGood(UA_StatusCode code), { + return ((code >> 30) == 0x00); + }) + + /* Compares the top 16 bits of two StatusCodes for equality. This should only + * be used when processing user-defined StatusCodes e.g when processing a ReadResponse. + * As a convention, the lower bits of StatusCodes should not be used internally, meaning + * can compare them without the use of this function. */ + UA_INLINABLE(UA_Boolean + UA_StatusCode_isEqualTop(UA_StatusCode s1, UA_StatusCode s2), { + return ((s1 & 0xFFFF0000) == (s2 & 0xFFFF0000)); + }) + +String +^^^^^^ +A sequence of Unicode characters. Strings are just an array of UA_Byte. + +.. code-block:: c + + typedef struct { + size_t length; /* The length of the string */ + UA_Byte *data; /* The content (not null-terminated) */ + } UA_String; + + /* Copies the content on the heap. Returns a null-string when alloc fails */ + UA_String + UA_String_fromChars(const char *src); + + UA_Boolean + UA_String_isEmpty(const UA_String *s); + + extern const UA_String UA_STRING_NULL; + +``UA_STRING`` returns a string pointing to the original char-array. +``UA_STRING_ALLOC`` is shorthand for ``UA_String_fromChars`` and makes a copy +of the char-array. + +.. code-block:: c + + UA_INLINABLE(UA_String + UA_STRING(char *chars), { + UA_String s; + memset(&s, 0, sizeof(s)); + if(!chars) + return s; + s.length = strlen(chars); s.data = (UA_Byte*)chars; + return s; + }) + + #define UA_STRING_ALLOC(CHARS) UA_String_fromChars(CHARS) + + /* Define strings at compile time (in ROM) */ + #define UA_STRING_STATIC(CHARS) {sizeof(CHARS)-1, (UA_Byte*)CHARS} + +.. _datetime: + +DateTime +^^^^^^^^ +An instance in time. A DateTime value is encoded as a 64-bit signed integer +which represents the number of 100 nanosecond intervals since January 1, 1601 +(UTC). + +The methods providing an interface to the system clock are architecture- +specific. Usually, they provide a UTC clock that includes leap seconds. The +OPC UA standard allows the use of International Atomic Time (TAI) for the +DateTime instead. But this is still unusual and not implemented for most +SDKs. Currently (2019), UTC and TAI are 37 seconds apart due to leap +seconds. + +.. code-block:: c + + + typedef int64_t UA_DateTime; + + /* Multiples to convert durations to DateTime */ + #define UA_DATETIME_USEC 10LL + #define UA_DATETIME_MSEC (UA_DATETIME_USEC * 1000LL) + #define UA_DATETIME_SEC (UA_DATETIME_MSEC * 1000LL) + + /* The current time in UTC time */ + UA_DateTime UA_DateTime_now(void); + + /* Offset between local time and UTC time */ + UA_Int64 UA_DateTime_localTimeUtcOffset(void); + + /* CPU clock invariant to system time changes. Use only to measure durations, + * not absolute time. */ + UA_DateTime UA_DateTime_nowMonotonic(void); + + /* Represents a Datetime as a structure */ + typedef struct UA_DateTimeStruct { + UA_UInt16 nanoSec; + UA_UInt16 microSec; + UA_UInt16 milliSec; + UA_UInt16 sec; + UA_UInt16 min; + UA_UInt16 hour; + UA_UInt16 day; /* From 1 to 31 */ + UA_UInt16 month; /* From 1 to 12 */ + UA_Int16 year; /* Can be negative (BC) */ + } UA_DateTimeStruct; + + UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime t); + UA_DateTime UA_DateTime_fromStruct(UA_DateTimeStruct ts); + + /* The C99 standard (7.23.1) says: "The range and precision of times + * representable in clock_t and time_t are implementation-defined." On most + * systems, time_t is a 4 or 8 byte integer counting seconds since the UTC Unix + * epoch. The following methods are used for conversion. */ + + /* Datetime of 1 Jan 1970 00:00 */ + #define UA_DATETIME_UNIX_EPOCH (11644473600LL * UA_DATETIME_SEC) + + UA_INLINABLE(UA_Int64 + UA_DateTime_toUnixTime(UA_DateTime date), { + return (date - UA_DATETIME_UNIX_EPOCH) / UA_DATETIME_SEC; + }) + + UA_INLINABLE(UA_DateTime + UA_DateTime_fromUnixTime(UA_Int64 unixDate), { + return (unixDate * UA_DATETIME_SEC) + UA_DATETIME_UNIX_EPOCH; + }) + +Guid +^^^^ +A 16 byte value that can be used as a globally unique identifier. + +.. code-block:: c + + typedef struct { + UA_UInt32 data1; + UA_UInt16 data2; + UA_UInt16 data3; + UA_Byte data4[8]; + } UA_Guid; + + extern const UA_Guid UA_GUID_NULL; + + /* Print a Guid in the human-readable format defined in Part 6, 5.1.3 + * + * Format: C496578A-0DFE-4B8F-870A-745238C6AEAE + * | | | | | | + * 0 8 13 18 23 36 + * + * This allocates memory if the output argument is an empty string. Tries to use + * the given buffer otherwise. */ + UA_StatusCode + UA_Guid_print(const UA_Guid *guid, UA_String *output); + + /* Parse the humand-readable Guid format */ + #ifdef UA_ENABLE_PARSING + UA_StatusCode + UA_Guid_parse(UA_Guid *guid, const UA_String str); + + UA_INLINABLE(UA_Guid + UA_GUID(const char *chars), { + UA_Guid guid; + UA_Guid_parse(&guid, UA_STRING((char*)(uintptr_t)chars)); + return guid; + }) + #endif + +ByteString +^^^^^^^^^^ +A sequence of octets. + +.. code-block:: c + + typedef UA_String UA_ByteString; + + extern const UA_ByteString UA_BYTESTRING_NULL; + + /* Allocates memory of size length for the bytestring. + * The content is not set to zero. */ + UA_StatusCode + UA_ByteString_allocBuffer(UA_ByteString *bs, size_t length); + + /* Converts a ByteString to the corresponding + * base64 representation */ + UA_StatusCode + UA_ByteString_toBase64(const UA_ByteString *bs, UA_String *output); + + /* Parse a ByteString from a base64 representation */ + UA_StatusCode + UA_ByteString_fromBase64(UA_ByteString *bs, + const UA_String *input); + + #define UA_BYTESTRING(chars) UA_STRING(chars) + #define UA_BYTESTRING_ALLOC(chars) UA_STRING_ALLOC(chars) + + /* Returns a non-cryptographic hash of a bytestring */ + UA_UInt32 + UA_ByteString_hash(UA_UInt32 initialHashValue, + const UA_Byte *data, size_t size); + +XmlElement +^^^^^^^^^^ +An XML element. + +.. code-block:: c + + typedef UA_String UA_XmlElement; + +.. _nodeid: + +NodeId +^^^^^^ +An identifier for a node in the address space of an OPC UA Server. + +.. code-block:: c + + enum UA_NodeIdType { + UA_NODEIDTYPE_NUMERIC = 0, /* In the binary encoding, this can also + * become 1 or 2 (two-byte and four-byte + * encoding of small numeric nodeids) */ + UA_NODEIDTYPE_STRING = 3, + UA_NODEIDTYPE_GUID = 4, + UA_NODEIDTYPE_BYTESTRING = 5 + }; + + typedef struct { + UA_UInt16 namespaceIndex; + enum UA_NodeIdType identifierType; + union { + UA_UInt32 numeric; + UA_String string; + UA_Guid guid; + UA_ByteString byteString; + } identifier; + } UA_NodeId; + + extern const UA_NodeId UA_NODEID_NULL; + + UA_Boolean UA_NodeId_isNull(const UA_NodeId *p); + + /* Print the NodeId in the human-readable format defined in Part 6, + * 5.3.1.10. + * + * Examples: + * UA_NODEID("i=13") + * UA_NODEID("ns=10;i=1") + * UA_NODEID("ns=10;s=Hello:World") + * UA_NODEID("g=09087e75-8e5e-499b-954f-f2a9603db28a") + * UA_NODEID("ns=1;b=b3BlbjYyNTQxIQ==") // base64 + * + * The method can either use a pre-allocated string buffer or allocates memory + * internally if called with an empty output string. */ + UA_StatusCode + UA_NodeId_print(const UA_NodeId *id, UA_String *output); + + /* Parse the human-readable NodeId format. Attention! String and + * ByteString NodeIds have their identifier malloc'ed and need to be + * cleaned up. */ + #ifdef UA_ENABLE_PARSING + UA_StatusCode + UA_NodeId_parse(UA_NodeId *id, const UA_String str); + + UA_INLINABLE(UA_NodeId + UA_NODEID(const char *chars), { + UA_NodeId id; + UA_NodeId_parse(&id, UA_STRING((char*)(uintptr_t)chars)); + return id; + }) + #endif + +The following methods are a shorthand for creating NodeIds. + +.. code-block:: c + + UA_INLINABLE(UA_NodeId + UA_NODEID_NUMERIC(UA_UInt16 nsIndex, + UA_UInt32 identifier), { + UA_NodeId id; + memset(&id, 0, sizeof(UA_NodeId)); + id.namespaceIndex = nsIndex; + id.identifierType = UA_NODEIDTYPE_NUMERIC; + id.identifier.numeric = identifier; + return id; + }) + + UA_INLINABLE(UA_NodeId + UA_NODEID_STRING(UA_UInt16 nsIndex, char *chars), { + UA_NodeId id; + memset(&id, 0, sizeof(UA_NodeId)); + id.namespaceIndex = nsIndex; + id.identifierType = UA_NODEIDTYPE_STRING; + id.identifier.string = UA_STRING(chars); + return id; + }) + + UA_INLINABLE(UA_NodeId + UA_NODEID_STRING_ALLOC(UA_UInt16 nsIndex, + const char *chars), { + UA_NodeId id; + memset(&id, 0, sizeof(UA_NodeId)); + id.namespaceIndex = nsIndex; + id.identifierType = UA_NODEIDTYPE_STRING; + id.identifier.string = UA_STRING_ALLOC(chars); + return id; + }) + + UA_INLINABLE(UA_NodeId + UA_NODEID_GUID(UA_UInt16 nsIndex, UA_Guid guid), { + UA_NodeId id; + memset(&id, 0, sizeof(UA_NodeId)); + id.namespaceIndex = nsIndex; + id.identifierType = UA_NODEIDTYPE_GUID; + id.identifier.guid = guid; + return id; + }) + + UA_INLINABLE(UA_NodeId + UA_NODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars), { + UA_NodeId id; + memset(&id, 0, sizeof(UA_NodeId)); + id.namespaceIndex = nsIndex; + id.identifierType = UA_NODEIDTYPE_BYTESTRING; + id.identifier.byteString = UA_BYTESTRING(chars); + return id; + }) + + UA_INLINABLE(UA_NodeId + UA_NODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex, + const char *chars), { + UA_NodeId id; + memset(&id, 0, sizeof(UA_NodeId)); + id.namespaceIndex = nsIndex; + id.identifierType = UA_NODEIDTYPE_BYTESTRING; + id.identifier.byteString = UA_BYTESTRING_ALLOC(chars); + return id; + }) + + /* Total ordering of NodeId */ + UA_Order + UA_NodeId_order(const UA_NodeId *n1, const UA_NodeId *n2); + + /* Returns a non-cryptographic hash for NodeId */ + UA_UInt32 UA_NodeId_hash(const UA_NodeId *n); + +.. _expandednodeid: + +ExpandedNodeId +^^^^^^^^^^^^^^ +A NodeId that allows the namespace URI to be specified instead of an index. + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_String namespaceUri; + UA_UInt32 serverIndex; + } UA_ExpandedNodeId; + + extern const UA_ExpandedNodeId UA_EXPANDEDNODEID_NULL; + + /* Print the ExpandedNodeId in the humand-readable format defined in Part 6, + * 5.3.1.11: + * + * svr=;ns=;= + * or + * svr=;nsu=;= + * + * The definitions for svr, ns and nsu is omitted if zero / the empty string. + * + * The method can either use a pre-allocated string buffer or allocates memory + * internally if called with an empty output string. */ + UA_StatusCode + UA_ExpandedNodeId_print(const UA_ExpandedNodeId *id, UA_String *output); + + /* Parse the human-readable NodeId format. Attention! String and + * ByteString NodeIds have their identifier malloc'ed and need to be + * cleaned up. */ + #ifdef UA_ENABLE_PARSING + UA_StatusCode + UA_ExpandedNodeId_parse(UA_ExpandedNodeId *id, const UA_String str); + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID(const char *chars), { + UA_ExpandedNodeId id; + UA_ExpandedNodeId_parse(&id, UA_STRING((char*)(uintptr_t)chars)); + return id; + }) + #endif + +The following functions are shorthand for creating ExpandedNodeIds. + +.. code-block:: c + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID_NUMERIC(UA_UInt16 nsIndex, UA_UInt32 identifier), { + UA_ExpandedNodeId id; id.nodeId = UA_NODEID_NUMERIC(nsIndex, identifier); + id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; + }) + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID_STRING(UA_UInt16 nsIndex, char *chars), { + UA_ExpandedNodeId id; id.nodeId = UA_NODEID_STRING(nsIndex, chars); + id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; + }) + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID_STRING_ALLOC(UA_UInt16 nsIndex, const char *chars), { + UA_ExpandedNodeId id; id.nodeId = UA_NODEID_STRING_ALLOC(nsIndex, chars); + id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; + }) + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID_STRING_GUID(UA_UInt16 nsIndex, UA_Guid guid), { + UA_ExpandedNodeId id; id.nodeId = UA_NODEID_GUID(nsIndex, guid); + id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; + }) + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars), { + UA_ExpandedNodeId id; id.nodeId = UA_NODEID_BYTESTRING(nsIndex, chars); + id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; + }) + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex, const char *chars), { + UA_ExpandedNodeId id; id.nodeId = UA_NODEID_BYTESTRING_ALLOC(nsIndex, chars); + id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; + }) + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID_NODEID(UA_NodeId nodeId), { + UA_ExpandedNodeId id; memset(&id, 0, sizeof(UA_ExpandedNodeId)); + id.nodeId = nodeId; return id; + }) + + /* Does the ExpandedNodeId point to a local node? That is, are namespaceUri and + * serverIndex empty? */ + UA_Boolean + UA_ExpandedNodeId_isLocal(const UA_ExpandedNodeId *n); + + /* Total ordering of ExpandedNodeId */ + UA_Order + UA_ExpandedNodeId_order(const UA_ExpandedNodeId *n1, + const UA_ExpandedNodeId *n2); + + /* Returns a non-cryptographic hash for ExpandedNodeId. The hash of an + * ExpandedNodeId is identical to the hash of the embedded (simple) NodeId if + * the ServerIndex is zero and no NamespaceUri is set. */ + UA_UInt32 + UA_ExpandedNodeId_hash(const UA_ExpandedNodeId *n); + +.. _qualifiedname: + +QualifiedName +^^^^^^^^^^^^^ +A name qualified by a namespace. + +.. code-block:: c + + typedef struct { + UA_UInt16 namespaceIndex; + UA_String name; + } UA_QualifiedName; + + UA_INLINABLE(UA_Boolean + UA_QualifiedName_isNull(const UA_QualifiedName *q), { + return (q->namespaceIndex == 0 && q->name.length == 0); + }) + + /* Returns a non-cryptographic hash for QualifiedName */ + UA_UInt32 + UA_QualifiedName_hash(const UA_QualifiedName *q); + + UA_INLINABLE(UA_QualifiedName + UA_QUALIFIEDNAME(UA_UInt16 nsIndex, char *chars), { + UA_QualifiedName qn; + qn.namespaceIndex = nsIndex; + qn.name = UA_STRING(chars); + return qn; + }) + + UA_INLINABLE(UA_QualifiedName + UA_QUALIFIEDNAME_ALLOC(UA_UInt16 nsIndex, const char *chars), { + UA_QualifiedName qn; + qn.namespaceIndex = nsIndex; + qn.name = UA_STRING_ALLOC(chars); + return qn; + }) + +LocalizedText +^^^^^^^^^^^^^ +Human readable text with an optional locale identifier. + +.. code-block:: c + + typedef struct { + UA_String locale; + UA_String text; + } UA_LocalizedText; + + UA_INLINABLE(UA_LocalizedText + UA_LOCALIZEDTEXT(char *locale, char *text), { + UA_LocalizedText lt; + lt.locale = UA_STRING(locale); + lt.text = UA_STRING(text); + return lt; + }) + + UA_INLINABLE(UA_LocalizedText + UA_LOCALIZEDTEXT_ALLOC(const char *locale, const char *text), { + UA_LocalizedText lt; + lt.locale = UA_STRING_ALLOC(locale); + lt.text = UA_STRING_ALLOC(text); + return lt; + }) + +.. _numericrange: + +NumericRange +^^^^^^^^^^^^ + +NumericRanges are used to indicate subsets of a (multidimensional) array. +They no official data type in the OPC UA standard and are transmitted only +with a string encoding, such as "1:2,0:3,5". The colon separates min/max +index and the comma separates dimensions. A single value indicates a range +with a single element (min==max). + +.. code-block:: c + + typedef struct { + UA_UInt32 min; + UA_UInt32 max; + } UA_NumericRangeDimension; + + typedef struct { + size_t dimensionsSize; + UA_NumericRangeDimension *dimensions; + } UA_NumericRange; + + UA_StatusCode + UA_NumericRange_parse(UA_NumericRange *range, const UA_String str); + + UA_INLINABLE(UA_NumericRange + UA_NUMERICRANGE(const char *s), { + UA_NumericRange nr; + memset(&nr, 0, sizeof(nr)); + UA_NumericRange_parse(&nr, UA_STRING((char*)(uintptr_t)s)); + return nr; + }) + +.. _variant: + +Variant +^^^^^^^ + +Variants may contain values of any type together with a description of the +content. See the section on :ref:`generic-types` on how types are described. +The standard mandates that variants contain built-in data types only. If the +value is not of a builtin type, it is wrapped into an :ref:`extensionobject`. +open62541 hides this wrapping transparently in the encoding layer. If the +data type is unknown to the receiver, the variant contains the original +ExtensionObject in binary or XML encoding. + +Variants may contain a scalar value or an array. For details on the handling +of arrays, see the section on :ref:`array-handling`. Array variants can have +an additional dimensionality (matrix, 3-tensor, ...) defined in an array of +dimension lengths. The actual values are kept in an array of dimensions one. +For users who work with higher-dimensions arrays directly, keep in mind that +dimensions of higher rank are serialized first (the highest rank dimension +has stride 1 and elements follow each other directly). Usually it is simplest +to interact with higher-dimensional arrays via ``UA_NumericRange`` +descriptions (see :ref:`array-handling`). + +To differentiate between scalar / array variants, the following definition is +used. ``UA_Variant_isScalar`` provides simplified access to these checks. + +- ``arrayLength == 0 && data == NULL``: undefined array of length -1 +- ``arrayLength == 0 && data == UA_EMPTY_ARRAY_SENTINEL``: array of length 0 +- ``arrayLength == 0 && data > UA_EMPTY_ARRAY_SENTINEL``: scalar value +- ``arrayLength > 0``: array of the given length + +Variants can also be *empty*. Then, the pointer to the type description is +``NULL``. + +.. code-block:: c + + /* Forward declaration. See the section on Generic Type Handling */ + struct UA_DataType; + typedef struct UA_DataType UA_DataType; + + #define UA_EMPTY_ARRAY_SENTINEL ((void*)0x01) + + typedef enum { + UA_VARIANT_DATA, /* The data has the same lifecycle as the variant */ + UA_VARIANT_DATA_NODELETE /* The data is "borrowed" by the variant and is + * not deleted when the variant is cleared up. + * The array dimensions also borrowed. */ + } UA_VariantStorageType; + + typedef struct { + const UA_DataType *type; /* The data type description */ + UA_VariantStorageType storageType; + size_t arrayLength; /* The number of elements in the data array */ + void *data; /* Points to the scalar or array data */ + size_t arrayDimensionsSize; /* The number of dimensions */ + UA_UInt32 *arrayDimensions; /* The length of each dimension */ + } UA_Variant; + + /* Returns true if the variant has no value defined (contains neither an array + * nor a scalar value). + * + * @param v The variant + * @return Is the variant empty */ + UA_INLINABLE(UA_Boolean + UA_Variant_isEmpty(const UA_Variant *v), { + return v->type == NULL; + }) + + /* Returns true if the variant contains a scalar value. Note that empty variants + * contain an array of length -1 (undefined). + * + * @param v The variant + * @return Does the variant contain a scalar value */ + UA_INLINABLE(UA_Boolean + UA_Variant_isScalar(const UA_Variant *v), { + return (v->arrayLength == 0 && v->data > UA_EMPTY_ARRAY_SENTINEL); + }) + + /* Returns true if the variant contains a scalar value of the given type. + * + * @param v The variant + * @param type The data type + * @return Does the variant contain a scalar value of the given type */ + UA_INLINABLE(UA_Boolean + UA_Variant_hasScalarType(const UA_Variant *v, + const UA_DataType *type), { + return UA_Variant_isScalar(v) && type == v->type; + }) + + /* Returns true if the variant contains an array of the given type. + * + * @param v The variant + * @param type The data type + * @return Does the variant contain an array of the given type */ + UA_INLINABLE(UA_Boolean + UA_Variant_hasArrayType(const UA_Variant *v, + const UA_DataType *type), { + return (!UA_Variant_isScalar(v)) && type == v->type; + }) + + /* Set the variant to a scalar value that already resides in memory. The value + * takes on the lifecycle of the variant and is deleted with it. + * + * @param v The variant + * @param p A pointer to the value data + * @param type The datatype of the value in question */ + void + UA_Variant_setScalar(UA_Variant *v, void *p, + const UA_DataType *type); + + /* Set the variant to a scalar value that is copied from an existing variable. + * @param v The variant + * @param p A pointer to the value data + * @param type The datatype of the value + * @return Indicates whether the operation succeeded or returns an error code */ + UA_StatusCode + UA_Variant_setScalarCopy(UA_Variant *v, const void *p, + const UA_DataType *type); + + /* Set the variant to an array that already resides in memory. The array takes + * on the lifecycle of the variant and is deleted with it. + * + * @param v The variant + * @param array A pointer to the array data + * @param arraySize The size of the array + * @param type The datatype of the array */ + void + UA_Variant_setArray(UA_Variant *v, void *array, + size_t arraySize, const UA_DataType *type); + + /* Set the variant to an array that is copied from an existing array. + * + * @param v The variant + * @param array A pointer to the array data + * @param arraySize The size of the array + * @param type The datatype of the array + * @return Indicates whether the operation succeeded or returns an error code */ + UA_StatusCode + UA_Variant_setArrayCopy(UA_Variant *v, const void *array, + size_t arraySize, const UA_DataType *type); + + /* Copy the variant, but use only a subset of the (multidimensional) array into + * a variant. Returns an error code if the variant is not an array or if the + * indicated range does not fit. + * + * @param src The source variant + * @param dst The target variant + * @param range The range of the copied data + * @return Returns UA_STATUSCODE_GOOD or an error code */ + UA_StatusCode + UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, + const UA_NumericRange range); + + /* Insert a range of data into an existing variant. The data array cannot be + * reused afterwards if it contains types without a fixed size (e.g. strings) + * since the members are moved into the variant and take on its lifecycle. + * + * @param v The variant + * @param dataArray The data array. The type must match the variant + * @param dataArraySize The length of the data array. This is checked to match + * the range size. + * @param range The range of where the new data is inserted + * @return Returns UA_STATUSCODE_GOOD or an error code */ + UA_StatusCode + UA_Variant_setRange(UA_Variant *v, void *array, + size_t arraySize, const UA_NumericRange range); + + /* Deep-copy a range of data into an existing variant. + * + * @param v The variant + * @param dataArray The data array. The type must match the variant + * @param dataArraySize The length of the data array. This is checked to match + * the range size. + * @param range The range of where the new data is inserted + * @return Returns UA_STATUSCODE_GOOD or an error code */ + UA_StatusCode + UA_Variant_setRangeCopy(UA_Variant *v, const void *array, + size_t arraySize, const UA_NumericRange range); + +.. _extensionobject: + +ExtensionObject +^^^^^^^^^^^^^^^ + +ExtensionObjects may contain scalars of any data type. Even those that are +unknown to the receiver. See the section on :ref:`generic-types` on how types +are described. If the received data type is unknown, the encoded string and +target NodeId is stored instead of the decoded value. + +.. code-block:: c + + typedef enum { + UA_EXTENSIONOBJECT_ENCODED_NOBODY = 0, + UA_EXTENSIONOBJECT_ENCODED_BYTESTRING = 1, + UA_EXTENSIONOBJECT_ENCODED_XML = 2, + UA_EXTENSIONOBJECT_DECODED = 3, + UA_EXTENSIONOBJECT_DECODED_NODELETE = 4 /* Don't delete the content + together with the + ExtensionObject */ + } UA_ExtensionObjectEncoding; + + typedef struct { + UA_ExtensionObjectEncoding encoding; + union { + struct { + UA_NodeId typeId; /* The nodeid of the datatype */ + UA_ByteString body; /* The bytestring of the encoded data */ + } encoded; + struct { + const UA_DataType *type; + void *data; + } decoded; + } content; + } UA_ExtensionObject; + + /* Initialize the ExtensionObject and set the "decoded" value to the given + * pointer. The value will be deleted when the ExtensionObject is cleared. */ + void + UA_ExtensionObject_setValue(UA_ExtensionObject *eo, + void *p, + const UA_DataType *type); + + /* Initialize the ExtensionObject and set the "decoded" value to the given + * pointer. The value will *not* be deleted when the ExtensionObject is + * cleared. */ + void + UA_ExtensionObject_setValueNoDelete(UA_ExtensionObject *eo, + void *p, + const UA_DataType *type); + + /* Initialize the ExtensionObject and set the "decoded" value to a fresh copy of + * the given value pointer. The value will be deleted when the ExtensionObject + * is cleared. */ + UA_StatusCode + UA_ExtensionObject_setValueCopy(UA_ExtensionObject *eo, + void *p, + const UA_DataType *type); + +.. _datavalue: + +DataValue +^^^^^^^^^ +A data value with an associated status code and timestamps. + +.. code-block:: c + + typedef struct { + UA_Variant value; + UA_DateTime sourceTimestamp; + UA_DateTime serverTimestamp; + UA_UInt16 sourcePicoseconds; + UA_UInt16 serverPicoseconds; + UA_StatusCode status; + UA_Boolean hasValue : 1; + UA_Boolean hasStatus : 1; + UA_Boolean hasSourceTimestamp : 1; + UA_Boolean hasServerTimestamp : 1; + UA_Boolean hasSourcePicoseconds : 1; + UA_Boolean hasServerPicoseconds : 1; + } UA_DataValue; + + /* Copy the DataValue, but use only a subset of the (multidimensional) array of + * of the variant of the source DataValue. Returns an error code if the variant + * of the DataValue is not an array or if the indicated range does not fit. + * + * @param src The source DataValue + * @param dst The target DataValue + * @param range The range of the variant of the DataValue to copy + * @return Returns UA_STATUSCODE_GOOD or an error code */ + UA_StatusCode + UA_DataValue_copyVariantRange(const UA_DataValue *src, UA_DataValue *dst, + const UA_NumericRange range); + +DiagnosticInfo +^^^^^^^^^^^^^^ +A structure that contains detailed error and diagnostic information +associated with a StatusCode. + +.. code-block:: c + + typedef struct UA_DiagnosticInfo { + UA_Boolean hasSymbolicId : 1; + UA_Boolean hasNamespaceUri : 1; + UA_Boolean hasLocalizedText : 1; + UA_Boolean hasLocale : 1; + UA_Boolean hasAdditionalInfo : 1; + UA_Boolean hasInnerStatusCode : 1; + UA_Boolean hasInnerDiagnosticInfo : 1; + UA_Int32 symbolicId; + UA_Int32 namespaceUri; + UA_Int32 localizedText; + UA_Int32 locale; + UA_String additionalInfo; + UA_StatusCode innerStatusCode; + struct UA_DiagnosticInfo *innerDiagnosticInfo; + } UA_DiagnosticInfo; + +.. _generic-types: + +Generic Type Handling +--------------------- + +All information about a (builtin/structured) data type is stored in a +``UA_DataType``. The array ``UA_TYPES`` contains the description of all +standard-defined types. This type description is used for the following +generic operations that work on all types: + +- ``void T_init(T *ptr)``: Initialize the data type. This is synonymous with + zeroing out the memory, i.e. ``memset(ptr, 0, sizeof(T))``. +- ``T* T_new()``: Allocate and return the memory for the data type. The + value is already initialized. +- ``UA_StatusCode T_copy(const T *src, T *dst)``: Copy the content of the + data type. Returns ``UA_STATUSCODE_GOOD`` or + ``UA_STATUSCODE_BADOUTOFMEMORY``. +- ``void T_clear(T *ptr)``: Delete the dynamically allocated content + of the data type and perform a ``T_init`` to reset the type. +- ``void T_delete(T *ptr)``: Delete the content of the data type and the + memory for the data type itself. +- ``void T_equal(T *p1, T *p2)``: Compare whether ``p1`` and ``p2`` have + identical content. You can use ``UA_order`` if an absolute ordering + is required. + +Specializations, such as ``UA_Int32_new()`` are derived from the generic +type operations as static inline functions. + +.. code-block:: c + + + typedef struct { + #ifdef UA_ENABLE_TYPEDESCRIPTION + const char *memberName; /* Human-readable member name */ + #endif + const UA_DataType *memberType;/* The member data type description */ + UA_Byte padding : 6; /* How much padding is there before this + member element? For arrays this is the + padding before the size_t length member. + (No padding between size_t and the + following ptr.) For unions, the padding + includes the size of the switchfield (the + offset from the start of the union + type). */ + UA_Byte isArray : 1; /* The member is an array */ + UA_Byte isOptional : 1; /* The member is an optional field */ + } UA_DataTypeMember; + + /* The DataType "kind" is an internal type classification. It is used to + * dispatch handling to the correct routines. */ + #define UA_DATATYPEKINDS 31 + typedef enum { + UA_DATATYPEKIND_BOOLEAN = 0, + UA_DATATYPEKIND_SBYTE = 1, + UA_DATATYPEKIND_BYTE = 2, + UA_DATATYPEKIND_INT16 = 3, + UA_DATATYPEKIND_UINT16 = 4, + UA_DATATYPEKIND_INT32 = 5, + UA_DATATYPEKIND_UINT32 = 6, + UA_DATATYPEKIND_INT64 = 7, + UA_DATATYPEKIND_UINT64 = 8, + UA_DATATYPEKIND_FLOAT = 9, + UA_DATATYPEKIND_DOUBLE = 10, + UA_DATATYPEKIND_STRING = 11, + UA_DATATYPEKIND_DATETIME = 12, + UA_DATATYPEKIND_GUID = 13, + UA_DATATYPEKIND_BYTESTRING = 14, + UA_DATATYPEKIND_XMLELEMENT = 15, + UA_DATATYPEKIND_NODEID = 16, + UA_DATATYPEKIND_EXPANDEDNODEID = 17, + UA_DATATYPEKIND_STATUSCODE = 18, + UA_DATATYPEKIND_QUALIFIEDNAME = 19, + UA_DATATYPEKIND_LOCALIZEDTEXT = 20, + UA_DATATYPEKIND_EXTENSIONOBJECT = 21, + UA_DATATYPEKIND_DATAVALUE = 22, + UA_DATATYPEKIND_VARIANT = 23, + UA_DATATYPEKIND_DIAGNOSTICINFO = 24, + UA_DATATYPEKIND_DECIMAL = 25, + UA_DATATYPEKIND_ENUM = 26, + UA_DATATYPEKIND_STRUCTURE = 27, + UA_DATATYPEKIND_OPTSTRUCT = 28, /* struct with optional fields */ + UA_DATATYPEKIND_UNION = 29, + UA_DATATYPEKIND_BITFIELDCLUSTER = 30 /* bitfields + padding */ + } UA_DataTypeKind; + + struct UA_DataType { + #ifdef UA_ENABLE_TYPEDESCRIPTION + const char *typeName; + #endif + UA_NodeId typeId; /* The nodeid of the type */ + UA_NodeId binaryEncodingId; /* NodeId of datatype when encoded as binary */ + //UA_NodeId xmlEncodingId; /* NodeId of datatype when encoded as XML */ + UA_UInt32 memSize : 16; /* Size of the struct in memory */ + UA_UInt32 typeKind : 6; /* Dispatch index for the handling routines */ + UA_UInt32 pointerFree : 1; /* The type (and its members) contains no + * pointers that need to be freed */ + UA_UInt32 overlayable : 1; /* The type has the identical memory layout + * in memory and on the binary stream. */ + UA_UInt32 membersSize : 8; /* How many members does the type have? */ + UA_DataTypeMember *members; + }; + + /* Datatype arrays with custom type definitions can be added in a linked list to + * the client or server configuration. */ + typedef struct UA_DataTypeArray { + const struct UA_DataTypeArray *next; + const size_t typesSize; + const UA_DataType *types; + UA_Boolean cleanup; /* Free the array structure and its content + when the client or server configuration + containing it is cleaned up */ + } UA_DataTypeArray; + + /* Returns the offset and type of a structure member. The return value is false + * if the member was not found. + * + * If the member is an array, the offset points to the (size_t) length field. + * (The array pointer comes after the length field without any padding.) */ + #ifdef UA_ENABLE_TYPEDESCRIPTION + UA_Boolean + UA_DataType_getStructMember(const UA_DataType *type, + const char *memberName, + size_t *outOffset, + const UA_DataType **outMemberType, + UA_Boolean *outIsArray); + #endif + + /* Test if the data type is a numeric builtin data type (via the typeKind field + * of UA_DataType). This includes integers and floating point numbers. Not + * included are Boolean, DateTime, StatusCode and Enums. */ + UA_Boolean + UA_DataType_isNumeric(const UA_DataType *type); + +Builtin data types can be accessed as UA_TYPES[UA_TYPES_XXX], where XXX is +the name of the data type. If only the NodeId of a type is known, use the +following method to retrieve the data type description. + +.. code-block:: c + + + /* Returns the data type description for the type's identifier or NULL if no + * matching data type was found. */ + const UA_DataType * + UA_findDataType(const UA_NodeId *typeId); + + /* + * Add custom data types to the search scope of UA_findDataType. */ + + const UA_DataType * + UA_findDataTypeWithCustom(const UA_NodeId *typeId, + const UA_DataTypeArray *customTypes); + +The following functions are used for generic handling of data types. + +.. code-block:: c + + + /* Allocates and initializes a variable of type dataType + * + * @param type The datatype description + * @return Returns the memory location of the variable or NULL if no + * memory could be allocated */ + void * UA_new(const UA_DataType *type); + + /* Initializes a variable to default values + * + * @param p The memory location of the variable + * @param type The datatype description */ + UA_INLINABLE(void + UA_init(void *p, const UA_DataType *type), { + memset(p, 0, type->memSize); + }) + + /* Copies the content of two variables. If copying fails (e.g. because no memory + * was available for an array), then dst is emptied and initialized to prevent + * memory leaks. + * + * @param src The memory location of the source variable + * @param dst The memory location of the destination variable + * @param type The datatype description + * @return Indicates whether the operation succeeded or returns an error code */ + UA_StatusCode + UA_copy(const void *src, void *dst, const UA_DataType *type); + + /* Deletes the dynamically allocated content of a variable (e.g. resets all + * arrays to undefined arrays). Afterwards, the variable can be safely deleted + * without causing memory leaks. But the variable is not initialized and may + * contain old data that is not memory-relevant. + * + * @param p The memory location of the variable + * @param type The datatype description of the variable */ + void UA_clear(void *p, const UA_DataType *type); + + #define UA_deleteMembers(p, type) UA_clear(p, type) + + /* Frees a variable and all of its content. + * + * @param p The memory location of the variable + * @param type The datatype description of the variable */ + void UA_delete(void *p, const UA_DataType *type); + + /* Pretty-print the value from the datatype. The output is pretty-printed JSON5. + * Note that this format is non-standard and should not be sent over the + * network. It can however be read by our own JSON decoding. + * + * @param p The memory location of the variable + * @param type The datatype description of the variable + * @param output A string that is used for the pretty-printed output. If the + * memory for string is already allocated, we try to use the existing + * string (the length is adjusted). If the string is empty, memory + * is allocated for it. + * @return Indicates whether the operation succeeded */ + #ifdef UA_ENABLE_JSON_ENCODING + UA_StatusCode + UA_print(const void *p, const UA_DataType *type, UA_String *output); + #endif + + /* Compare two values and return their order. + * + * For numerical types (including StatusCodes and Enums), their natural order is + * used. NaN is the "smallest" value for floating point values. Different bit + * representations of NaN are considered identical. + * + * All other types have *some* absolute ordering so that a < b, b < c -> a < c. + * + * The ordering of arrays (also strings) is in "shortlex": A shorter array is + * always smaller than a longer array. Otherwise the first different element + * defines the order. + * + * When members of different types are permitted (in Variants and + * ExtensionObjects), the memory address in the "UA_DataType*" pointer + * determines which variable is smaller. + * + * @param p1 The memory location of the first value + * @param p2 The memory location of the first value + * @param type The datatype description of both values */ + UA_Order + UA_order(const void *p1, const void *p2, const UA_DataType *type); + + /* Compare if two values have identical content. */ + UA_INLINABLE(UA_Boolean + UA_equal(const void *p1, const void *p2, const UA_DataType *type), { + return (UA_order(p1, p2, type) == UA_ORDER_EQ); + }) + +Binary Encoding/Decoding +------------------------ + +Encoding and decoding routines for the binary format. For the binary decoding +additional data types can be forwarded. + +.. code-block:: c + + + /* Returns the number of bytes the value p takes in binary encoding. Returns + * zero if an error occurs. */ + size_t + UA_calcSizeBinary(const void *p, const UA_DataType *type); + + /* Encodes a data-structure in the binary format. If outBuf has a length of + * zero, a buffer of the required size is allocated. Otherwise, encoding into + * the existing outBuf is attempted (and may fail if the buffer is too + * small). */ + UA_StatusCode + UA_encodeBinary(const void *p, const UA_DataType *type, + UA_ByteString *outBuf); + + /* The structure with the decoding options may be extended in the future. + * Zero-out the entire structure initially to ensure code-compatibility when + * more fields are added in a later release. */ + typedef struct { + const UA_DataTypeArray *customTypes; /* Begin of a linked list with custom + * datatype definitions */ + } UA_DecodeBinaryOptions; + + /* Decodes a data structure from the input buffer in the binary format. It is + * assumed that `p` points to valid memory (not necessarily zeroed out). The + * options can be NULL and will be disregarded in that case. */ + UA_StatusCode + UA_decodeBinary(const UA_ByteString *inBuf, + void *p, const UA_DataType *type, + const UA_DecodeBinaryOptions *options); + +JSON En/Decoding +---------------- + +The JSON decoding can parse the official encoding from the OPC UA +specification. It further allows the following extensions: + +- The strict JSON format is relaxed to also allow the JSON5 extensions + (https://json5.org/). This allows for more human-readable encoding and adds + convenience features such as trailing commas in arrays and comments within + JSON documents. +- Int64/UInt64 don't necessarily have to be wrapped into a string. +- If `UA_ENABLE_PARSING` is set, NodeIds and ExpandedNodeIds can be given in + the string encoding (e.g. "ns=1;i=42", see `UA_NodeId_parse`). The standard + encoding is to express NodeIds as JSON objects. + +These extensions are not intended to be used for the OPC UA protocol on the +network. They were rather added to allow more convenient configuration file +formats that also include data in the OPC UA type system. + +.. code-block:: c + + + #ifdef UA_ENABLE_JSON_ENCODING + + typedef struct { + const UA_String *namespaces; + size_t namespacesSize; + const UA_String *serverUris; + size_t serverUrisSize; + UA_Boolean useReversible; + + UA_Boolean prettyPrint; /* Add newlines and spaces for legibility */ + + /* Enabling the following options leads to non-standard compatible JSON5 + * encoding! Use it for pretty-printing, but not for sending messages over + * the network. (Our own decoding can still parse it.) */ + + UA_Boolean unquotedKeys; /* Don't print quotes around object element keys */ + UA_Boolean stringNodeIds; /* String encoding for NodeIds, like "ns=1;i=42" */ + } UA_EncodeJsonOptions; + + /* Returns the number of bytes the value src takes in json encoding. Returns + * zero if an error occurs. */ + size_t + UA_calcSizeJson(const void *src, const UA_DataType *type, + const UA_EncodeJsonOptions *options); + + /* Encodes the scalar value described by type to json encoding. + * + * @param src The value. Must not be NULL. + * @param type The value type. Must not be NULL. + * @param outBuf Pointer to ByteString containing the result if the encoding + * was successful + * @return Returns a statuscode whether encoding succeeded. */ + UA_StatusCode + UA_encodeJson(const void *src, const UA_DataType *type, UA_ByteString *outBuf, + const UA_EncodeJsonOptions *options); + + /* The structure with the decoding options may be extended in the future. + * Zero-out the entire structure initially to ensure code-compatibility when + * more fields are added in a later release. */ + typedef struct { + const UA_String *namespaces; + size_t namespacesSize; + const UA_String *serverUris; + size_t serverUrisSize; + const UA_DataTypeArray *customTypes; /* Begin of a linked list with custom + * datatype definitions */ + } UA_DecodeJsonOptions; + + /* Decodes a scalar value described by type from json encoding. + * + * @param src The buffer with the json encoded value. Must not be NULL. + * @param dst The target value. Must not be NULL. The target is assumed to have + * size type->memSize. The value is reset to zero before decoding. If + * decoding fails, members are deleted and the value is reset (zeroed) + * again. + * @param type The value type. Must not be NULL. + * @param options The options struct for decoding, currently unused + * @return Returns a statuscode whether decoding succeeded. */ + UA_StatusCode + UA_decodeJson(const UA_ByteString *src, void *dst, const UA_DataType *type, + const UA_DecodeJsonOptions *options); + + #endif /* UA_ENABLE_JSON_ENCODING */ + +XML En/Decoding +---------------- + +The XML decoding can parse the official encoding from the OPC UA +specification. + +These extensions are not intended to be used for the OPC UA protocol on the +network. They were rather added to allow more convenient configuration file +formats that also include data in the OPC UA type system. + +.. code-block:: c + + + #ifdef UA_ENABLE_XML_ENCODING + + typedef struct { + UA_Boolean prettyPrint; /* Add newlines and spaces for legibility */ + } UA_EncodeXmlOptions; + + /* Returns the number of bytes the value src takes in xml encoding. Returns + * zero if an error occurs. */ + size_t + UA_calcSizeXml(const void *src, const UA_DataType *type, + const UA_EncodeXmlOptions *options); + + /* Encodes the scalar value described by type to xml encoding. + * + * @param src The value. Must not be NULL. + * @param type The value type. Must not be NULL. + * @param outBuf Pointer to ByteString containing the result if the encoding + * was successful + * @return Returns a statuscode whether encoding succeeded. */ + UA_StatusCode + UA_encodeXml(const void *src, const UA_DataType *type, UA_ByteString *outBuf, + const UA_EncodeXmlOptions *options); + + /* The structure with the decoding options may be extended in the future. + * Zero-out the entire structure initially to ensure code-compatibility when + * more fields are added in a later release. */ + typedef struct { + const UA_DataTypeArray *customTypes; /* Begin of a linked list with custom + * datatype definitions */ + } UA_DecodeXmlOptions; + + /* Decodes a scalar value described by type from xml encoding. + * + * @param src The buffer with the xml encoded value. Must not be NULL. + * @param dst The target value. Must not be NULL. The target is assumed to have + * size type->memSize. The value is reset to zero before decoding. If + * decoding fails, members are deleted and the value is reset (zeroed) + * again. + * @param type The value type. Must not be NULL. + * @param options The options struct for decoding, currently unused + * @return Returns a statuscode whether decoding succeeded. */ + UA_StatusCode + UA_decodeXml(const UA_ByteString *src, void *dst, const UA_DataType *type, + const UA_DecodeXmlOptions *options); + + #endif /* UA_ENABLE_XML_ENCODING */ + +.. _array-handling: + +Array handling +-------------- +In OPC UA, arrays can have a length of zero or more with the usual meaning. +In addition, arrays can be undefined. Then, they don't even have a length. In +the binary encoding, this is indicated by an array of length -1. + +In open62541 however, we use ``size_t`` for array lengths. An undefined array +has length 0 and the data pointer is ``NULL``. An array of length 0 also has +length 0 but a data pointer ``UA_EMPTY_ARRAY_SENTINEL``. + +.. code-block:: c + + + /* Allocates and initializes an array of variables of a specific type + * + * @param size The requested array length + * @param type The datatype description + * @return Returns the memory location of the variable or NULL if no memory + * could be allocated */ + void * + UA_Array_new(size_t size, const UA_DataType *type); + + /* Allocates and copies an array + * + * @param src The memory location of the source array + * @param size The size of the array + * @param dst The location of the pointer to the new array + * @param type The datatype of the array members + * @return Returns UA_STATUSCODE_GOOD or UA_STATUSCODE_BADOUTOFMEMORY */ + UA_StatusCode + UA_Array_copy(const void *src, size_t size, void **dst, + const UA_DataType *type); + + /* Resizes (and reallocates) an array. The last entries are initialized to zero + * if the array length is increased. If the array length is decreased, the last + * entries are removed if the size is decreased. + * + * @param p Double pointer to the array memory. Can be overwritten by the result + * of a realloc. + * @param size The current size of the array. Overwritten in case of success. + * @param newSize The new size of the array + * @param type The datatype of the array members + * @return Returns UA_STATUSCODE_GOOD or UA_STATUSCODE_BADOUTOFMEMORY. The + * original array is left untouched in the failure case. */ + UA_StatusCode + UA_Array_resize(void **p, size_t *size, size_t newSize, + const UA_DataType *type); + + /* Append the given element at the end of the array. The content is moved + * (shallow copy) and the original memory is _init'ed if appending is + * successful. + * + * @param p Double pointer to the array memory. Can be overwritten by the result + * of a realloc. + * @param size The current size of the array. Overwritten in case of success. + * @param newElem The element to be appended. The memory is reset upon success. + * @param type The datatype of the array members + * @return Returns UA_STATUSCODE_GOOD or UA_STATUSCODE_BADOUTOFMEMORY. The + * original array is left untouched in the failure case. */ + UA_StatusCode + UA_Array_append(void **p, size_t *size, void *newElem, + const UA_DataType *type); + + /* Append a copy of the given element at the end of the array. + * + * @param p Double pointer to the array memory. Can be overwritten by the result + * of a realloc. + * @param size The current size of the array. Overwritten in case of success. + * @param newElem The element to be appended. + * @param type The datatype of the array members + * @return Returns UA_STATUSCODE_GOOD or UA_STATUSCODE_BADOUTOFMEMORY. The + * original array is left untouched in the failure case. */ + + UA_StatusCode + UA_Array_appendCopy(void **p, size_t *size, const void *newElem, + const UA_DataType *type); + + /* Deletes an array. + * + * @param p The memory location of the array + * @param size The size of the array + * @param type The datatype of the array members */ + void + UA_Array_delete(void *p, size_t size, const UA_DataType *type); + +.. _generated-types: + +Generated Data Type Definitions +------------------------------- + +The following standard-defined datatypes are auto-generated from XML files +that are part of the OPC UA standard. All datatypes are built up from the 25 +builtin-in datatypes from the :ref:`types` section. + +.. include:: types_generated.rst + +.. code-block:: c + + + /* stop-doc-generation */ diff --git a/static/doc/v1.4.0/_sources/types_generated.rst.txt b/static/doc/v1.4.0/_sources/types_generated.rst.txt new file mode 100644 index 0000000000..481b438eba --- /dev/null +++ b/static/doc/v1.4.0/_sources/types_generated.rst.txt @@ -0,0 +1,2596 @@ +NamingRuleType +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_NAMINGRULETYPE_MANDATORY = 1, + UA_NAMINGRULETYPE_OPTIONAL = 2, + UA_NAMINGRULETYPE_CONSTRAINT = 3 + } UA_NamingRuleType; + +KeyValuePair +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_QualifiedName key; + UA_Variant value; + } UA_KeyValuePair; + +NodeClass +^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_NODECLASS_UNSPECIFIED = 0, + UA_NODECLASS_OBJECT = 1, + UA_NODECLASS_VARIABLE = 2, + UA_NODECLASS_METHOD = 4, + UA_NODECLASS_OBJECTTYPE = 8, + UA_NODECLASS_VARIABLETYPE = 16, + UA_NODECLASS_REFERENCETYPE = 32, + UA_NODECLASS_DATATYPE = 64, + UA_NODECLASS_VIEW = 128 + } UA_NodeClass; + +StructureType +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_STRUCTURETYPE_STRUCTURE = 0, + UA_STRUCTURETYPE_STRUCTUREWITHOPTIONALFIELDS = 1, + UA_STRUCTURETYPE_UNION = 2, + UA_STRUCTURETYPE_STRUCTUREWITHSUBTYPEDVALUES = 3, + UA_STRUCTURETYPE_UNIONWITHSUBTYPEDVALUES = 4 + } UA_StructureType; + +StructureField +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String name; + UA_LocalizedText description; + UA_NodeId dataType; + UA_Int32 valueRank; + size_t arrayDimensionsSize; + UA_UInt32 *arrayDimensions; + UA_UInt32 maxStringLength; + UA_Boolean isOptional; + } UA_StructureField; + +StructureDefinition +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId defaultEncodingId; + UA_NodeId baseDataType; + UA_StructureType structureType; + size_t fieldsSize; + UA_StructureField *fields; + } UA_StructureDefinition; + +Argument +^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String name; + UA_NodeId dataType; + UA_Int32 valueRank; + size_t arrayDimensionsSize; + UA_UInt32 *arrayDimensions; + UA_LocalizedText description; + } UA_Argument; + +EnumValueType +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Int64 value; + UA_LocalizedText displayName; + UA_LocalizedText description; + } UA_EnumValueType; + +EnumField +^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Int64 value; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_String name; + } UA_EnumField; + +Duration +^^^^^^^^ + +.. code-block:: c + + typedef UA_Double UA_Duration; + +UtcTime +^^^^^^^ + +.. code-block:: c + + typedef UA_DateTime UA_UtcTime; + +LocaleId +^^^^^^^^ + +.. code-block:: c + + typedef UA_String UA_LocaleId; + +TimeZoneDataType +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Int16 offset; + UA_Boolean daylightSavingInOffset; + } UA_TimeZoneDataType; + +ApplicationType +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_APPLICATIONTYPE_SERVER = 0, + UA_APPLICATIONTYPE_CLIENT = 1, + UA_APPLICATIONTYPE_CLIENTANDSERVER = 2, + UA_APPLICATIONTYPE_DISCOVERYSERVER = 3 + } UA_ApplicationType; + +ApplicationDescription +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String applicationUri; + UA_String productUri; + UA_LocalizedText applicationName; + UA_ApplicationType applicationType; + UA_String gatewayServerUri; + UA_String discoveryProfileUri; + size_t discoveryUrlsSize; + UA_String *discoveryUrls; + } UA_ApplicationDescription; + +RequestHeader +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId authenticationToken; + UA_DateTime timestamp; + UA_UInt32 requestHandle; + UA_UInt32 returnDiagnostics; + UA_String auditEntryId; + UA_UInt32 timeoutHint; + UA_ExtensionObject additionalHeader; + } UA_RequestHeader; + +ResponseHeader +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_DateTime timestamp; + UA_UInt32 requestHandle; + UA_StatusCode serviceResult; + UA_DiagnosticInfo serviceDiagnostics; + size_t stringTableSize; + UA_String *stringTable; + UA_ExtensionObject additionalHeader; + } UA_ResponseHeader; + +ServiceFault +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + } UA_ServiceFault; + +FindServersRequest +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_String endpointUrl; + size_t localeIdsSize; + UA_String *localeIds; + size_t serverUrisSize; + UA_String *serverUris; + } UA_FindServersRequest; + +FindServersResponse +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t serversSize; + UA_ApplicationDescription *servers; + } UA_FindServersResponse; + +ServerOnNetwork +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 recordId; + UA_String serverName; + UA_String discoveryUrl; + size_t serverCapabilitiesSize; + UA_String *serverCapabilities; + } UA_ServerOnNetwork; + +FindServersOnNetworkRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 startingRecordId; + UA_UInt32 maxRecordsToReturn; + size_t serverCapabilityFilterSize; + UA_String *serverCapabilityFilter; + } UA_FindServersOnNetworkRequest; + +FindServersOnNetworkResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_DateTime lastCounterResetTime; + size_t serversSize; + UA_ServerOnNetwork *servers; + } UA_FindServersOnNetworkResponse; + +MessageSecurityMode +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_MESSAGESECURITYMODE_INVALID = 0, + UA_MESSAGESECURITYMODE_NONE = 1, + UA_MESSAGESECURITYMODE_SIGN = 2, + UA_MESSAGESECURITYMODE_SIGNANDENCRYPT = 3 + } UA_MessageSecurityMode; + +UserTokenType +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_USERTOKENTYPE_ANONYMOUS = 0, + UA_USERTOKENTYPE_USERNAME = 1, + UA_USERTOKENTYPE_CERTIFICATE = 2, + UA_USERTOKENTYPE_ISSUEDTOKEN = 3 + } UA_UserTokenType; + +UserTokenPolicy +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String policyId; + UA_UserTokenType tokenType; + UA_String issuedTokenType; + UA_String issuerEndpointUrl; + UA_String securityPolicyUri; + } UA_UserTokenPolicy; + +EndpointDescription +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String endpointUrl; + UA_ApplicationDescription server; + UA_ByteString serverCertificate; + UA_MessageSecurityMode securityMode; + UA_String securityPolicyUri; + size_t userIdentityTokensSize; + UA_UserTokenPolicy *userIdentityTokens; + UA_String transportProfileUri; + UA_Byte securityLevel; + } UA_EndpointDescription; + +GetEndpointsRequest +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_String endpointUrl; + size_t localeIdsSize; + UA_String *localeIds; + size_t profileUrisSize; + UA_String *profileUris; + } UA_GetEndpointsRequest; + +GetEndpointsResponse +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t endpointsSize; + UA_EndpointDescription *endpoints; + } UA_GetEndpointsResponse; + +RegisteredServer +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String serverUri; + UA_String productUri; + size_t serverNamesSize; + UA_LocalizedText *serverNames; + UA_ApplicationType serverType; + UA_String gatewayServerUri; + size_t discoveryUrlsSize; + UA_String *discoveryUrls; + UA_String semaphoreFilePath; + UA_Boolean isOnline; + } UA_RegisteredServer; + +RegisterServerRequest +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_RegisteredServer server; + } UA_RegisterServerRequest; + +RegisterServerResponse +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + } UA_RegisterServerResponse; + +MdnsDiscoveryConfiguration +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String mdnsServerName; + size_t serverCapabilitiesSize; + UA_String *serverCapabilities; + } UA_MdnsDiscoveryConfiguration; + +RegisterServer2Request +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_RegisteredServer server; + size_t discoveryConfigurationSize; + UA_ExtensionObject *discoveryConfiguration; + } UA_RegisterServer2Request; + +RegisterServer2Response +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t configurationResultsSize; + UA_StatusCode *configurationResults; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_RegisterServer2Response; + +SecurityTokenRequestType +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_SECURITYTOKENREQUESTTYPE_ISSUE = 0, + UA_SECURITYTOKENREQUESTTYPE_RENEW = 1 + } UA_SecurityTokenRequestType; + +ChannelSecurityToken +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 channelId; + UA_UInt32 tokenId; + UA_DateTime createdAt; + UA_UInt32 revisedLifetime; + } UA_ChannelSecurityToken; + +OpenSecureChannelRequest +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 clientProtocolVersion; + UA_SecurityTokenRequestType requestType; + UA_MessageSecurityMode securityMode; + UA_ByteString clientNonce; + UA_UInt32 requestedLifetime; + } UA_OpenSecureChannelRequest; + +OpenSecureChannelResponse +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_UInt32 serverProtocolVersion; + UA_ChannelSecurityToken securityToken; + UA_ByteString serverNonce; + } UA_OpenSecureChannelResponse; + +CloseSecureChannelRequest +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + } UA_CloseSecureChannelRequest; + +CloseSecureChannelResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + } UA_CloseSecureChannelResponse; + +SignedSoftwareCertificate +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ByteString certificateData; + UA_ByteString signature; + } UA_SignedSoftwareCertificate; + +SignatureData +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String algorithm; + UA_ByteString signature; + } UA_SignatureData; + +CreateSessionRequest +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_ApplicationDescription clientDescription; + UA_String serverUri; + UA_String endpointUrl; + UA_String sessionName; + UA_ByteString clientNonce; + UA_ByteString clientCertificate; + UA_Double requestedSessionTimeout; + UA_UInt32 maxResponseMessageSize; + } UA_CreateSessionRequest; + +CreateSessionResponse +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_NodeId sessionId; + UA_NodeId authenticationToken; + UA_Double revisedSessionTimeout; + UA_ByteString serverNonce; + UA_ByteString serverCertificate; + size_t serverEndpointsSize; + UA_EndpointDescription *serverEndpoints; + size_t serverSoftwareCertificatesSize; + UA_SignedSoftwareCertificate *serverSoftwareCertificates; + UA_SignatureData serverSignature; + UA_UInt32 maxRequestMessageSize; + } UA_CreateSessionResponse; + +UserIdentityToken +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String policyId; + } UA_UserIdentityToken; + +AnonymousIdentityToken +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String policyId; + } UA_AnonymousIdentityToken; + +UserNameIdentityToken +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String policyId; + UA_String userName; + UA_ByteString password; + UA_String encryptionAlgorithm; + } UA_UserNameIdentityToken; + +X509IdentityToken +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String policyId; + UA_ByteString certificateData; + } UA_X509IdentityToken; + +IssuedIdentityToken +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String policyId; + UA_ByteString tokenData; + UA_String encryptionAlgorithm; + } UA_IssuedIdentityToken; + +ActivateSessionRequest +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_SignatureData clientSignature; + size_t clientSoftwareCertificatesSize; + UA_SignedSoftwareCertificate *clientSoftwareCertificates; + size_t localeIdsSize; + UA_String *localeIds; + UA_ExtensionObject userIdentityToken; + UA_SignatureData userTokenSignature; + } UA_ActivateSessionRequest; + +ActivateSessionResponse +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_ByteString serverNonce; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_ActivateSessionResponse; + +CloseSessionRequest +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_Boolean deleteSubscriptions; + } UA_CloseSessionRequest; + +CloseSessionResponse +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + } UA_CloseSessionResponse; + +CancelRequest +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 requestHandle; + } UA_CancelRequest; + +CancelResponse +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_UInt32 cancelCount; + } UA_CancelResponse; + +NodeAttributesMask +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_NODEATTRIBUTESMASK_NONE = 0, + UA_NODEATTRIBUTESMASK_ACCESSLEVEL = 1, + UA_NODEATTRIBUTESMASK_ARRAYDIMENSIONS = 2, + UA_NODEATTRIBUTESMASK_BROWSENAME = 4, + UA_NODEATTRIBUTESMASK_CONTAINSNOLOOPS = 8, + UA_NODEATTRIBUTESMASK_DATATYPE = 16, + UA_NODEATTRIBUTESMASK_DESCRIPTION = 32, + UA_NODEATTRIBUTESMASK_DISPLAYNAME = 64, + UA_NODEATTRIBUTESMASK_EVENTNOTIFIER = 128, + UA_NODEATTRIBUTESMASK_EXECUTABLE = 256, + UA_NODEATTRIBUTESMASK_HISTORIZING = 512, + UA_NODEATTRIBUTESMASK_INVERSENAME = 1024, + UA_NODEATTRIBUTESMASK_ISABSTRACT = 2048, + UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL = 4096, + UA_NODEATTRIBUTESMASK_NODECLASS = 8192, + UA_NODEATTRIBUTESMASK_NODEID = 16384, + UA_NODEATTRIBUTESMASK_SYMMETRIC = 32768, + UA_NODEATTRIBUTESMASK_USERACCESSLEVEL = 65536, + UA_NODEATTRIBUTESMASK_USEREXECUTABLE = 131072, + UA_NODEATTRIBUTESMASK_USERWRITEMASK = 262144, + UA_NODEATTRIBUTESMASK_VALUERANK = 524288, + UA_NODEATTRIBUTESMASK_WRITEMASK = 1048576, + UA_NODEATTRIBUTESMASK_VALUE = 2097152, + UA_NODEATTRIBUTESMASK_DATATYPEDEFINITION = 4194304, + UA_NODEATTRIBUTESMASK_ROLEPERMISSIONS = 8388608, + UA_NODEATTRIBUTESMASK_ACCESSRESTRICTIONS = 16777216, + UA_NODEATTRIBUTESMASK_ALL = 33554431, + UA_NODEATTRIBUTESMASK_BASENODE = 26501220, + UA_NODEATTRIBUTESMASK_OBJECT = 26501348, + UA_NODEATTRIBUTESMASK_OBJECTTYPE = 26503268, + UA_NODEATTRIBUTESMASK_VARIABLE = 26571383, + UA_NODEATTRIBUTESMASK_VARIABLETYPE = 28600438, + UA_NODEATTRIBUTESMASK_METHOD = 26632548, + UA_NODEATTRIBUTESMASK_REFERENCETYPE = 26537060, + UA_NODEATTRIBUTESMASK_VIEW = 26501356 + } UA_NodeAttributesMask; + +NodeAttributes +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + } UA_NodeAttributes; + +ObjectAttributes +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Byte eventNotifier; + } UA_ObjectAttributes; + +VariableAttributes +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Variant value; + UA_NodeId dataType; + UA_Int32 valueRank; + size_t arrayDimensionsSize; + UA_UInt32 *arrayDimensions; + UA_Byte accessLevel; + UA_Byte userAccessLevel; + UA_Double minimumSamplingInterval; + UA_Boolean historizing; + } UA_VariableAttributes; + +MethodAttributes +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Boolean executable; + UA_Boolean userExecutable; + } UA_MethodAttributes; + +ObjectTypeAttributes +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Boolean isAbstract; + } UA_ObjectTypeAttributes; + +VariableTypeAttributes +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Variant value; + UA_NodeId dataType; + UA_Int32 valueRank; + size_t arrayDimensionsSize; + UA_UInt32 *arrayDimensions; + UA_Boolean isAbstract; + } UA_VariableTypeAttributes; + +ReferenceTypeAttributes +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Boolean isAbstract; + UA_Boolean symmetric; + UA_LocalizedText inverseName; + } UA_ReferenceTypeAttributes; + +DataTypeAttributes +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Boolean isAbstract; + } UA_DataTypeAttributes; + +ViewAttributes +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Boolean containsNoLoops; + UA_Byte eventNotifier; + } UA_ViewAttributes; + +AddNodesItem +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ExpandedNodeId parentNodeId; + UA_NodeId referenceTypeId; + UA_ExpandedNodeId requestedNewNodeId; + UA_QualifiedName browseName; + UA_NodeClass nodeClass; + UA_ExtensionObject nodeAttributes; + UA_ExpandedNodeId typeDefinition; + } UA_AddNodesItem; + +AddNodesResult +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + UA_NodeId addedNodeId; + } UA_AddNodesResult; + +AddNodesRequest +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t nodesToAddSize; + UA_AddNodesItem *nodesToAdd; + } UA_AddNodesRequest; + +AddNodesResponse +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_AddNodesResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_AddNodesResponse; + +AddReferencesItem +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId sourceNodeId; + UA_NodeId referenceTypeId; + UA_Boolean isForward; + UA_String targetServerUri; + UA_ExpandedNodeId targetNodeId; + UA_NodeClass targetNodeClass; + } UA_AddReferencesItem; + +AddReferencesRequest +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t referencesToAddSize; + UA_AddReferencesItem *referencesToAdd; + } UA_AddReferencesRequest; + +AddReferencesResponse +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_AddReferencesResponse; + +DeleteNodesItem +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_Boolean deleteTargetReferences; + } UA_DeleteNodesItem; + +DeleteNodesRequest +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t nodesToDeleteSize; + UA_DeleteNodesItem *nodesToDelete; + } UA_DeleteNodesRequest; + +DeleteNodesResponse +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_DeleteNodesResponse; + +DeleteReferencesItem +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId sourceNodeId; + UA_NodeId referenceTypeId; + UA_Boolean isForward; + UA_ExpandedNodeId targetNodeId; + UA_Boolean deleteBidirectional; + } UA_DeleteReferencesItem; + +DeleteReferencesRequest +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t referencesToDeleteSize; + UA_DeleteReferencesItem *referencesToDelete; + } UA_DeleteReferencesRequest; + +DeleteReferencesResponse +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_DeleteReferencesResponse; + +BrowseDirection +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_BROWSEDIRECTION_FORWARD = 0, + UA_BROWSEDIRECTION_INVERSE = 1, + UA_BROWSEDIRECTION_BOTH = 2, + UA_BROWSEDIRECTION_INVALID = 3 + } UA_BrowseDirection; + +ViewDescription +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId viewId; + UA_DateTime timestamp; + UA_UInt32 viewVersion; + } UA_ViewDescription; + +BrowseDescription +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_BrowseDirection browseDirection; + UA_NodeId referenceTypeId; + UA_Boolean includeSubtypes; + UA_UInt32 nodeClassMask; + UA_UInt32 resultMask; + } UA_BrowseDescription; + +BrowseResultMask +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_BROWSERESULTMASK_NONE = 0, + UA_BROWSERESULTMASK_REFERENCETYPEID = 1, + UA_BROWSERESULTMASK_ISFORWARD = 2, + UA_BROWSERESULTMASK_NODECLASS = 4, + UA_BROWSERESULTMASK_BROWSENAME = 8, + UA_BROWSERESULTMASK_DISPLAYNAME = 16, + UA_BROWSERESULTMASK_TYPEDEFINITION = 32, + UA_BROWSERESULTMASK_ALL = 63, + UA_BROWSERESULTMASK_REFERENCETYPEINFO = 3, + UA_BROWSERESULTMASK_TARGETINFO = 60 + } UA_BrowseResultMask; + +ReferenceDescription +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId referenceTypeId; + UA_Boolean isForward; + UA_ExpandedNodeId nodeId; + UA_QualifiedName browseName; + UA_LocalizedText displayName; + UA_NodeClass nodeClass; + UA_ExpandedNodeId typeDefinition; + } UA_ReferenceDescription; + +BrowseResult +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + UA_ByteString continuationPoint; + size_t referencesSize; + UA_ReferenceDescription *references; + } UA_BrowseResult; + +BrowseRequest +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_ViewDescription view; + UA_UInt32 requestedMaxReferencesPerNode; + size_t nodesToBrowseSize; + UA_BrowseDescription *nodesToBrowse; + } UA_BrowseRequest; + +BrowseResponse +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_BrowseResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_BrowseResponse; + +BrowseNextRequest +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_Boolean releaseContinuationPoints; + size_t continuationPointsSize; + UA_ByteString *continuationPoints; + } UA_BrowseNextRequest; + +BrowseNextResponse +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_BrowseResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_BrowseNextResponse; + +RelativePathElement +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId referenceTypeId; + UA_Boolean isInverse; + UA_Boolean includeSubtypes; + UA_QualifiedName targetName; + } UA_RelativePathElement; + +RelativePath +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t elementsSize; + UA_RelativePathElement *elements; + } UA_RelativePath; + +BrowsePath +^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId startingNode; + UA_RelativePath relativePath; + } UA_BrowsePath; + +BrowsePathTarget +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ExpandedNodeId targetId; + UA_UInt32 remainingPathIndex; + } UA_BrowsePathTarget; + +BrowsePathResult +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + size_t targetsSize; + UA_BrowsePathTarget *targets; + } UA_BrowsePathResult; + +TranslateBrowsePathsToNodeIdsRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t browsePathsSize; + UA_BrowsePath *browsePaths; + } UA_TranslateBrowsePathsToNodeIdsRequest; + +TranslateBrowsePathsToNodeIdsResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_BrowsePathResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_TranslateBrowsePathsToNodeIdsResponse; + +RegisterNodesRequest +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t nodesToRegisterSize; + UA_NodeId *nodesToRegister; + } UA_RegisterNodesRequest; + +RegisterNodesResponse +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t registeredNodeIdsSize; + UA_NodeId *registeredNodeIds; + } UA_RegisterNodesResponse; + +UnregisterNodesRequest +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t nodesToUnregisterSize; + UA_NodeId *nodesToUnregister; + } UA_UnregisterNodesRequest; + +UnregisterNodesResponse +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + } UA_UnregisterNodesResponse; + +FilterOperator +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_FILTEROPERATOR_EQUALS = 0, + UA_FILTEROPERATOR_ISNULL = 1, + UA_FILTEROPERATOR_GREATERTHAN = 2, + UA_FILTEROPERATOR_LESSTHAN = 3, + UA_FILTEROPERATOR_GREATERTHANOREQUAL = 4, + UA_FILTEROPERATOR_LESSTHANOREQUAL = 5, + UA_FILTEROPERATOR_LIKE = 6, + UA_FILTEROPERATOR_NOT = 7, + UA_FILTEROPERATOR_BETWEEN = 8, + UA_FILTEROPERATOR_INLIST = 9, + UA_FILTEROPERATOR_AND = 10, + UA_FILTEROPERATOR_OR = 11, + UA_FILTEROPERATOR_CAST = 12, + UA_FILTEROPERATOR_INVIEW = 13, + UA_FILTEROPERATOR_OFTYPE = 14, + UA_FILTEROPERATOR_RELATEDTO = 15, + UA_FILTEROPERATOR_BITWISEAND = 16, + UA_FILTEROPERATOR_BITWISEOR = 17 + } UA_FilterOperator; + +ContentFilterElement +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_FilterOperator filterOperator; + size_t filterOperandsSize; + UA_ExtensionObject *filterOperands; + } UA_ContentFilterElement; + +ContentFilter +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t elementsSize; + UA_ContentFilterElement *elements; + } UA_ContentFilter; + +ElementOperand +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 index; + } UA_ElementOperand; + +LiteralOperand +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Variant value; + } UA_LiteralOperand; + +AttributeOperand +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_String alias; + UA_RelativePath browsePath; + UA_UInt32 attributeId; + UA_String indexRange; + } UA_AttributeOperand; + +SimpleAttributeOperand +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId typeDefinitionId; + size_t browsePathSize; + UA_QualifiedName *browsePath; + UA_UInt32 attributeId; + UA_String indexRange; + } UA_SimpleAttributeOperand; + +ContentFilterElementResult +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + size_t operandStatusCodesSize; + UA_StatusCode *operandStatusCodes; + size_t operandDiagnosticInfosSize; + UA_DiagnosticInfo *operandDiagnosticInfos; + } UA_ContentFilterElementResult; + +ContentFilterResult +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t elementResultsSize; + UA_ContentFilterElementResult *elementResults; + size_t elementDiagnosticInfosSize; + UA_DiagnosticInfo *elementDiagnosticInfos; + } UA_ContentFilterResult; + +TimestampsToReturn +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_TIMESTAMPSTORETURN_SOURCE = 0, + UA_TIMESTAMPSTORETURN_SERVER = 1, + UA_TIMESTAMPSTORETURN_BOTH = 2, + UA_TIMESTAMPSTORETURN_NEITHER = 3, + UA_TIMESTAMPSTORETURN_INVALID = 4 + } UA_TimestampsToReturn; + +ReadValueId +^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_UInt32 attributeId; + UA_String indexRange; + UA_QualifiedName dataEncoding; + } UA_ReadValueId; + +ReadRequest +^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_Double maxAge; + UA_TimestampsToReturn timestampsToReturn; + size_t nodesToReadSize; + UA_ReadValueId *nodesToRead; + } UA_ReadRequest; + +ReadResponse +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_DataValue *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_ReadResponse; + +HistoryReadValueId +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_String indexRange; + UA_QualifiedName dataEncoding; + UA_ByteString continuationPoint; + } UA_HistoryReadValueId; + +HistoryReadResult +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + UA_ByteString continuationPoint; + UA_ExtensionObject historyData; + } UA_HistoryReadResult; + +ReadRawModifiedDetails +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Boolean isReadModified; + UA_DateTime startTime; + UA_DateTime endTime; + UA_UInt32 numValuesPerNode; + UA_Boolean returnBounds; + } UA_ReadRawModifiedDetails; + +ReadAtTimeDetails +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t reqTimesSize; + UA_DateTime *reqTimes; + UA_Boolean useSimpleBounds; + } UA_ReadAtTimeDetails; + +HistoryData +^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t dataValuesSize; + UA_DataValue *dataValues; + } UA_HistoryData; + +HistoryReadRequest +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_ExtensionObject historyReadDetails; + UA_TimestampsToReturn timestampsToReturn; + UA_Boolean releaseContinuationPoints; + size_t nodesToReadSize; + UA_HistoryReadValueId *nodesToRead; + } UA_HistoryReadRequest; + +HistoryReadResponse +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_HistoryReadResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_HistoryReadResponse; + +WriteValue +^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_UInt32 attributeId; + UA_String indexRange; + UA_DataValue value; + } UA_WriteValue; + +WriteRequest +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t nodesToWriteSize; + UA_WriteValue *nodesToWrite; + } UA_WriteRequest; + +WriteResponse +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_WriteResponse; + +HistoryUpdateType +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_HISTORYUPDATETYPE_INSERT = 1, + UA_HISTORYUPDATETYPE_REPLACE = 2, + UA_HISTORYUPDATETYPE_UPDATE = 3, + UA_HISTORYUPDATETYPE_DELETE = 4 + } UA_HistoryUpdateType; + +PerformUpdateType +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_PERFORMUPDATETYPE_INSERT = 1, + UA_PERFORMUPDATETYPE_REPLACE = 2, + UA_PERFORMUPDATETYPE_UPDATE = 3, + UA_PERFORMUPDATETYPE_REMOVE = 4 + } UA_PerformUpdateType; + +UpdateDataDetails +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_PerformUpdateType performInsertReplace; + size_t updateValuesSize; + UA_DataValue *updateValues; + } UA_UpdateDataDetails; + +DeleteRawModifiedDetails +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_Boolean isDeleteModified; + UA_DateTime startTime; + UA_DateTime endTime; + } UA_DeleteRawModifiedDetails; + +HistoryUpdateResult +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + size_t operationResultsSize; + UA_StatusCode *operationResults; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_HistoryUpdateResult; + +HistoryUpdateRequest +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t historyUpdateDetailsSize; + UA_ExtensionObject *historyUpdateDetails; + } UA_HistoryUpdateRequest; + +HistoryUpdateResponse +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_HistoryUpdateResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_HistoryUpdateResponse; + +CallMethodRequest +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId objectId; + UA_NodeId methodId; + size_t inputArgumentsSize; + UA_Variant *inputArguments; + } UA_CallMethodRequest; + +CallMethodResult +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + size_t inputArgumentResultsSize; + UA_StatusCode *inputArgumentResults; + size_t inputArgumentDiagnosticInfosSize; + UA_DiagnosticInfo *inputArgumentDiagnosticInfos; + size_t outputArgumentsSize; + UA_Variant *outputArguments; + } UA_CallMethodResult; + +CallRequest +^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t methodsToCallSize; + UA_CallMethodRequest *methodsToCall; + } UA_CallRequest; + +CallResponse +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_CallMethodResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_CallResponse; + +MonitoringMode +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_MONITORINGMODE_DISABLED = 0, + UA_MONITORINGMODE_SAMPLING = 1, + UA_MONITORINGMODE_REPORTING = 2 + } UA_MonitoringMode; + +DataChangeTrigger +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_DATACHANGETRIGGER_STATUS = 0, + UA_DATACHANGETRIGGER_STATUSVALUE = 1, + UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP = 2 + } UA_DataChangeTrigger; + +DeadbandType +^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_DEADBANDTYPE_NONE = 0, + UA_DEADBANDTYPE_ABSOLUTE = 1, + UA_DEADBANDTYPE_PERCENT = 2 + } UA_DeadbandType; + +DataChangeFilter +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_DataChangeTrigger trigger; + UA_UInt32 deadbandType; + UA_Double deadbandValue; + } UA_DataChangeFilter; + +EventFilter +^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t selectClausesSize; + UA_SimpleAttributeOperand *selectClauses; + UA_ContentFilter whereClause; + } UA_EventFilter; + +AggregateConfiguration +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Boolean useServerCapabilitiesDefaults; + UA_Boolean treatUncertainAsBad; + UA_Byte percentDataBad; + UA_Byte percentDataGood; + UA_Boolean useSlopedExtrapolation; + } UA_AggregateConfiguration; + +AggregateFilter +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_DateTime startTime; + UA_NodeId aggregateType; + UA_Double processingInterval; + UA_AggregateConfiguration aggregateConfiguration; + } UA_AggregateFilter; + +EventFilterResult +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t selectClauseResultsSize; + UA_StatusCode *selectClauseResults; + size_t selectClauseDiagnosticInfosSize; + UA_DiagnosticInfo *selectClauseDiagnosticInfos; + UA_ContentFilterResult whereClauseResult; + } UA_EventFilterResult; + +MonitoringParameters +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 clientHandle; + UA_Double samplingInterval; + UA_ExtensionObject filter; + UA_UInt32 queueSize; + UA_Boolean discardOldest; + } UA_MonitoringParameters; + +MonitoredItemCreateRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ReadValueId itemToMonitor; + UA_MonitoringMode monitoringMode; + UA_MonitoringParameters requestedParameters; + } UA_MonitoredItemCreateRequest; + +MonitoredItemCreateResult +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + UA_UInt32 monitoredItemId; + UA_Double revisedSamplingInterval; + UA_UInt32 revisedQueueSize; + UA_ExtensionObject filterResult; + } UA_MonitoredItemCreateResult; + +CreateMonitoredItemsRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 subscriptionId; + UA_TimestampsToReturn timestampsToReturn; + size_t itemsToCreateSize; + UA_MonitoredItemCreateRequest *itemsToCreate; + } UA_CreateMonitoredItemsRequest; + +CreateMonitoredItemsResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_MonitoredItemCreateResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_CreateMonitoredItemsResponse; + +MonitoredItemModifyRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 monitoredItemId; + UA_MonitoringParameters requestedParameters; + } UA_MonitoredItemModifyRequest; + +MonitoredItemModifyResult +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + UA_Double revisedSamplingInterval; + UA_UInt32 revisedQueueSize; + UA_ExtensionObject filterResult; + } UA_MonitoredItemModifyResult; + +ModifyMonitoredItemsRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 subscriptionId; + UA_TimestampsToReturn timestampsToReturn; + size_t itemsToModifySize; + UA_MonitoredItemModifyRequest *itemsToModify; + } UA_ModifyMonitoredItemsRequest; + +ModifyMonitoredItemsResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_MonitoredItemModifyResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_ModifyMonitoredItemsResponse; + +SetMonitoringModeRequest +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 subscriptionId; + UA_MonitoringMode monitoringMode; + size_t monitoredItemIdsSize; + UA_UInt32 *monitoredItemIds; + } UA_SetMonitoringModeRequest; + +SetMonitoringModeResponse +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_SetMonitoringModeResponse; + +SetTriggeringRequest +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 subscriptionId; + UA_UInt32 triggeringItemId; + size_t linksToAddSize; + UA_UInt32 *linksToAdd; + size_t linksToRemoveSize; + UA_UInt32 *linksToRemove; + } UA_SetTriggeringRequest; + +SetTriggeringResponse +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t addResultsSize; + UA_StatusCode *addResults; + size_t addDiagnosticInfosSize; + UA_DiagnosticInfo *addDiagnosticInfos; + size_t removeResultsSize; + UA_StatusCode *removeResults; + size_t removeDiagnosticInfosSize; + UA_DiagnosticInfo *removeDiagnosticInfos; + } UA_SetTriggeringResponse; + +DeleteMonitoredItemsRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 subscriptionId; + size_t monitoredItemIdsSize; + UA_UInt32 *monitoredItemIds; + } UA_DeleteMonitoredItemsRequest; + +DeleteMonitoredItemsResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_DeleteMonitoredItemsResponse; + +CreateSubscriptionRequest +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_Double requestedPublishingInterval; + UA_UInt32 requestedLifetimeCount; + UA_UInt32 requestedMaxKeepAliveCount; + UA_UInt32 maxNotificationsPerPublish; + UA_Boolean publishingEnabled; + UA_Byte priority; + } UA_CreateSubscriptionRequest; + +CreateSubscriptionResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_UInt32 subscriptionId; + UA_Double revisedPublishingInterval; + UA_UInt32 revisedLifetimeCount; + UA_UInt32 revisedMaxKeepAliveCount; + } UA_CreateSubscriptionResponse; + +ModifySubscriptionRequest +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 subscriptionId; + UA_Double requestedPublishingInterval; + UA_UInt32 requestedLifetimeCount; + UA_UInt32 requestedMaxKeepAliveCount; + UA_UInt32 maxNotificationsPerPublish; + UA_Byte priority; + } UA_ModifySubscriptionRequest; + +ModifySubscriptionResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_Double revisedPublishingInterval; + UA_UInt32 revisedLifetimeCount; + UA_UInt32 revisedMaxKeepAliveCount; + } UA_ModifySubscriptionResponse; + +SetPublishingModeRequest +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_Boolean publishingEnabled; + size_t subscriptionIdsSize; + UA_UInt32 *subscriptionIds; + } UA_SetPublishingModeRequest; + +SetPublishingModeResponse +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_SetPublishingModeResponse; + +NotificationMessage +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 sequenceNumber; + UA_DateTime publishTime; + size_t notificationDataSize; + UA_ExtensionObject *notificationData; + } UA_NotificationMessage; + +MonitoredItemNotification +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 clientHandle; + UA_DataValue value; + } UA_MonitoredItemNotification; + +EventFieldList +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 clientHandle; + size_t eventFieldsSize; + UA_Variant *eventFields; + } UA_EventFieldList; + +HistoryEventFieldList +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t eventFieldsSize; + UA_Variant *eventFields; + } UA_HistoryEventFieldList; + +StatusChangeNotification +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode status; + UA_DiagnosticInfo diagnosticInfo; + } UA_StatusChangeNotification; + +SubscriptionAcknowledgement +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 subscriptionId; + UA_UInt32 sequenceNumber; + } UA_SubscriptionAcknowledgement; + +PublishRequest +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t subscriptionAcknowledgementsSize; + UA_SubscriptionAcknowledgement *subscriptionAcknowledgements; + } UA_PublishRequest; + +PublishResponse +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_UInt32 subscriptionId; + size_t availableSequenceNumbersSize; + UA_UInt32 *availableSequenceNumbers; + UA_Boolean moreNotifications; + UA_NotificationMessage notificationMessage; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_PublishResponse; + +RepublishRequest +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 subscriptionId; + UA_UInt32 retransmitSequenceNumber; + } UA_RepublishRequest; + +RepublishResponse +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_NotificationMessage notificationMessage; + } UA_RepublishResponse; + +TransferResult +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + size_t availableSequenceNumbersSize; + UA_UInt32 *availableSequenceNumbers; + } UA_TransferResult; + +TransferSubscriptionsRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t subscriptionIdsSize; + UA_UInt32 *subscriptionIds; + UA_Boolean sendInitialValues; + } UA_TransferSubscriptionsRequest; + +TransferSubscriptionsResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_TransferResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_TransferSubscriptionsResponse; + +DeleteSubscriptionsRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t subscriptionIdsSize; + UA_UInt32 *subscriptionIds; + } UA_DeleteSubscriptionsRequest; + +DeleteSubscriptionsResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_DeleteSubscriptionsResponse; + +BuildInfo +^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String productUri; + UA_String manufacturerName; + UA_String productName; + UA_String softwareVersion; + UA_String buildNumber; + UA_DateTime buildDate; + } UA_BuildInfo; + +RedundancySupport +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_REDUNDANCYSUPPORT_NONE = 0, + UA_REDUNDANCYSUPPORT_COLD = 1, + UA_REDUNDANCYSUPPORT_WARM = 2, + UA_REDUNDANCYSUPPORT_HOT = 3, + UA_REDUNDANCYSUPPORT_TRANSPARENT = 4, + UA_REDUNDANCYSUPPORT_HOTANDMIRRORED = 5 + } UA_RedundancySupport; + +ServerState +^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_SERVERSTATE_RUNNING = 0, + UA_SERVERSTATE_FAILED = 1, + UA_SERVERSTATE_NOCONFIGURATION = 2, + UA_SERVERSTATE_SUSPENDED = 3, + UA_SERVERSTATE_SHUTDOWN = 4, + UA_SERVERSTATE_TEST = 5, + UA_SERVERSTATE_COMMUNICATIONFAULT = 6, + UA_SERVERSTATE_UNKNOWN = 7 + } UA_ServerState; + +ServerDiagnosticsSummaryDataType +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 serverViewCount; + UA_UInt32 currentSessionCount; + UA_UInt32 cumulatedSessionCount; + UA_UInt32 securityRejectedSessionCount; + UA_UInt32 rejectedSessionCount; + UA_UInt32 sessionTimeoutCount; + UA_UInt32 sessionAbortCount; + UA_UInt32 currentSubscriptionCount; + UA_UInt32 cumulatedSubscriptionCount; + UA_UInt32 publishingIntervalCount; + UA_UInt32 securityRejectedRequestsCount; + UA_UInt32 rejectedRequestsCount; + } UA_ServerDiagnosticsSummaryDataType; + +ServerStatusDataType +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_DateTime startTime; + UA_DateTime currentTime; + UA_ServerState state; + UA_BuildInfo buildInfo; + UA_UInt32 secondsTillShutdown; + UA_LocalizedText shutdownReason; + } UA_ServerStatusDataType; + +SessionSecurityDiagnosticsDataType +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId sessionId; + UA_String clientUserIdOfSession; + size_t clientUserIdHistorySize; + UA_String *clientUserIdHistory; + UA_String authenticationMechanism; + UA_String encoding; + UA_String transportProtocol; + UA_MessageSecurityMode securityMode; + UA_String securityPolicyUri; + UA_ByteString clientCertificate; + } UA_SessionSecurityDiagnosticsDataType; + +ServiceCounterDataType +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 totalCount; + UA_UInt32 errorCount; + } UA_ServiceCounterDataType; + +SubscriptionDiagnosticsDataType +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId sessionId; + UA_UInt32 subscriptionId; + UA_Byte priority; + UA_Double publishingInterval; + UA_UInt32 maxKeepAliveCount; + UA_UInt32 maxLifetimeCount; + UA_UInt32 maxNotificationsPerPublish; + UA_Boolean publishingEnabled; + UA_UInt32 modifyCount; + UA_UInt32 enableCount; + UA_UInt32 disableCount; + UA_UInt32 republishRequestCount; + UA_UInt32 republishMessageRequestCount; + UA_UInt32 republishMessageCount; + UA_UInt32 transferRequestCount; + UA_UInt32 transferredToAltClientCount; + UA_UInt32 transferredToSameClientCount; + UA_UInt32 publishRequestCount; + UA_UInt32 dataChangeNotificationsCount; + UA_UInt32 eventNotificationsCount; + UA_UInt32 notificationsCount; + UA_UInt32 latePublishRequestCount; + UA_UInt32 currentKeepAliveCount; + UA_UInt32 currentLifetimeCount; + UA_UInt32 unacknowledgedMessageCount; + UA_UInt32 discardedMessageCount; + UA_UInt32 monitoredItemCount; + UA_UInt32 disabledMonitoredItemCount; + UA_UInt32 monitoringQueueOverflowCount; + UA_UInt32 nextSequenceNumber; + UA_UInt32 eventQueueOverFlowCount; + } UA_SubscriptionDiagnosticsDataType; + +Range +^^^^^ + +.. code-block:: c + + typedef struct { + UA_Double low; + UA_Double high; + } UA_Range; + +EUInformation +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String namespaceUri; + UA_Int32 unitId; + UA_LocalizedText displayName; + UA_LocalizedText description; + } UA_EUInformation; + +AxisScaleEnumeration +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_AXISSCALEENUMERATION_LINEAR = 0, + UA_AXISSCALEENUMERATION_LOG = 1, + UA_AXISSCALEENUMERATION_LN = 2 + } UA_AxisScaleEnumeration; + +ComplexNumberType +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Float real; + UA_Float imaginary; + } UA_ComplexNumberType; + +DoubleComplexNumberType +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Double real; + UA_Double imaginary; + } UA_DoubleComplexNumberType; + +AxisInformation +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_EUInformation engineeringUnits; + UA_Range eURange; + UA_LocalizedText title; + UA_AxisScaleEnumeration axisScaleType; + size_t axisStepsSize; + UA_Double *axisSteps; + } UA_AxisInformation; + +XVType +^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Double x; + UA_Float value; + } UA_XVType; + +EnumDefinition +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t fieldsSize; + UA_EnumField *fields; + } UA_EnumDefinition; + +ReadEventDetails +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 numValuesPerNode; + UA_DateTime startTime; + UA_DateTime endTime; + UA_EventFilter filter; + } UA_ReadEventDetails; + +ReadProcessedDetails +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_DateTime startTime; + UA_DateTime endTime; + UA_Double processingInterval; + size_t aggregateTypeSize; + UA_NodeId *aggregateType; + UA_AggregateConfiguration aggregateConfiguration; + } UA_ReadProcessedDetails; + +ModificationInfo +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_DateTime modificationTime; + UA_HistoryUpdateType updateType; + UA_String userName; + } UA_ModificationInfo; + +HistoryModifiedData +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t dataValuesSize; + UA_DataValue *dataValues; + size_t modificationInfosSize; + UA_ModificationInfo *modificationInfos; + } UA_HistoryModifiedData; + +HistoryEvent +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t eventsSize; + UA_HistoryEventFieldList *events; + } UA_HistoryEvent; + +DataChangeNotification +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t monitoredItemsSize; + UA_MonitoredItemNotification *monitoredItems; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_DataChangeNotification; + +EventNotificationList +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t eventsSize; + UA_EventFieldList *events; + } UA_EventNotificationList; + +SessionDiagnosticsDataType +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId sessionId; + UA_String sessionName; + UA_ApplicationDescription clientDescription; + UA_String serverUri; + UA_String endpointUrl; + size_t localeIdsSize; + UA_String *localeIds; + UA_Double actualSessionTimeout; + UA_UInt32 maxResponseMessageSize; + UA_DateTime clientConnectionTime; + UA_DateTime clientLastContactTime; + UA_UInt32 currentSubscriptionsCount; + UA_UInt32 currentMonitoredItemsCount; + UA_UInt32 currentPublishRequestsInQueue; + UA_ServiceCounterDataType totalRequestCount; + UA_UInt32 unauthorizedRequestCount; + UA_ServiceCounterDataType readCount; + UA_ServiceCounterDataType historyReadCount; + UA_ServiceCounterDataType writeCount; + UA_ServiceCounterDataType historyUpdateCount; + UA_ServiceCounterDataType callCount; + UA_ServiceCounterDataType createMonitoredItemsCount; + UA_ServiceCounterDataType modifyMonitoredItemsCount; + UA_ServiceCounterDataType setMonitoringModeCount; + UA_ServiceCounterDataType setTriggeringCount; + UA_ServiceCounterDataType deleteMonitoredItemsCount; + UA_ServiceCounterDataType createSubscriptionCount; + UA_ServiceCounterDataType modifySubscriptionCount; + UA_ServiceCounterDataType setPublishingModeCount; + UA_ServiceCounterDataType publishCount; + UA_ServiceCounterDataType republishCount; + UA_ServiceCounterDataType transferSubscriptionsCount; + UA_ServiceCounterDataType deleteSubscriptionsCount; + UA_ServiceCounterDataType addNodesCount; + UA_ServiceCounterDataType addReferencesCount; + UA_ServiceCounterDataType deleteNodesCount; + UA_ServiceCounterDataType deleteReferencesCount; + UA_ServiceCounterDataType browseCount; + UA_ServiceCounterDataType browseNextCount; + UA_ServiceCounterDataType translateBrowsePathsToNodeIdsCount; + UA_ServiceCounterDataType queryFirstCount; + UA_ServiceCounterDataType queryNextCount; + UA_ServiceCounterDataType registerNodesCount; + UA_ServiceCounterDataType unregisterNodesCount; + } UA_SessionDiagnosticsDataType; + diff --git a/static/doc/v1.4.0/_sources/util.rst.txt b/static/doc/v1.4.0/_sources/util.rst.txt new file mode 100644 index 0000000000..451c45addd --- /dev/null +++ b/static/doc/v1.4.0/_sources/util.rst.txt @@ -0,0 +1,289 @@ +Range Definition +---------------- + +.. code-block:: c + + + typedef struct { + UA_UInt32 min; + UA_UInt32 max; + } UA_UInt32Range; + + typedef struct { + UA_Duration min; + UA_Duration max; + } UA_DurationRange; + +Random Number Generator +----------------------- +If UA_MULTITHREADING is defined, then the seed is stored in thread +local storage. The seed is initialized for every thread in the +server/client. + +.. code-block:: c + + + void + UA_random_seed(UA_UInt64 seed); + + UA_UInt32 + UA_UInt32_random(void); /* no cryptographic entropy */ + + UA_Guid + UA_Guid_random(void); /* no cryptographic entropy */ + +Key Value Map +------------- +Helper functions to work with configuration parameters in an array of +UA_KeyValuePair. Lookup is linear. So this is for small numbers of keys. The +methods below that accept a `const UA_KeyValueMap` as an argument also accept +NULL for that argument and treat it as an empty map. + +.. code-block:: c + + + typedef struct { + size_t mapSize; + UA_KeyValuePair *map; + } UA_KeyValueMap; + + extern const UA_KeyValueMap UA_KEYVALUEMAP_NULL; + + UA_KeyValueMap * + UA_KeyValueMap_new(void); + + void + UA_KeyValueMap_clear(UA_KeyValueMap *map); + + void + UA_KeyValueMap_delete(UA_KeyValueMap *map); + + /* Is the map empty (or NULL)? */ + UA_Boolean + UA_KeyValueMap_isEmpty(const UA_KeyValueMap *map); + + /* Does the map contain an entry for the key? */ + UA_Boolean + UA_KeyValueMap_contains(const UA_KeyValueMap *map, const UA_QualifiedName key); + + /* Insert a copy of the value. Can reallocate the underlying array. This + * invalidates pointers into the previous array. If the key exists already, the + * value is overwritten (upsert semantics). */ + UA_StatusCode + UA_KeyValueMap_set(UA_KeyValueMap *map, + const UA_QualifiedName key, + const UA_Variant *value); + + /* Helper function for scalar insertion that internally calls + * `UA_KeyValueMap_set` */ + UA_StatusCode + UA_KeyValueMap_setScalar(UA_KeyValueMap *map, + const UA_QualifiedName key, + void *p, + const UA_DataType *type); + + /* Returns a pointer to the value or NULL if the key is not found */ + const UA_Variant * + UA_KeyValueMap_get(const UA_KeyValueMap *map, + const UA_QualifiedName key); + + /* Returns NULL if the value for the key is not defined, not of the right + * datatype or not a scalar */ + const void * + UA_KeyValueMap_getScalar(const UA_KeyValueMap *map, + const UA_QualifiedName key, + const UA_DataType *type); + + /* Remove a single entry. To delete the entire map, use `UA_KeyValueMap_clear`. */ + UA_StatusCode + UA_KeyValueMap_remove(UA_KeyValueMap *map, + const UA_QualifiedName key); + + /* Create a deep copy of the given KeyValueMap */ + UA_StatusCode + UA_KeyValueMap_copy(const UA_KeyValueMap *src, UA_KeyValueMap *dst); + + /* Copy entries from the right-hand-side into the left-hand-size. Reallocates + * previous memory in the left-hand-side. If the operation fails, both maps are + * left untouched. */ + UA_StatusCode + UA_KeyValueMap_merge(UA_KeyValueMap *lhs, const UA_KeyValueMap *rhs); + +Binary Connection Config Parameters +----------------------------------- + +.. code-block:: c + + + typedef struct { + UA_UInt32 protocolVersion; + UA_UInt32 recvBufferSize; + UA_UInt32 sendBufferSize; + UA_UInt32 localMaxMessageSize; /* (0 = unbounded) */ + UA_UInt32 remoteMaxMessageSize; /* (0 = unbounded) */ + UA_UInt32 localMaxChunkCount; /* (0 = unbounded) */ + UA_UInt32 remoteMaxChunkCount; /* (0 = unbounded) */ + } UA_ConnectionConfig; + +.. _default-node-attributes: + +Default Node Attributes +----------------------- +Default node attributes to simplify the use of the AddNodes services. For +example, Setting the ValueRank and AccessLevel to zero is often an unintended +setting and leads to errors that are hard to track down. + +.. code-block:: c + + + /* The default for variables is "BaseDataType" for the datatype, -2 for the + * valuerank and a read-accesslevel. */ + extern const UA_VariableAttributes UA_VariableAttributes_default; + extern const UA_VariableTypeAttributes UA_VariableTypeAttributes_default; + + /* Methods are executable by default */ + extern const UA_MethodAttributes UA_MethodAttributes_default; + + /* The remaining attribute definitions are currently all zeroed out */ + extern const UA_ObjectAttributes UA_ObjectAttributes_default; + extern const UA_ObjectTypeAttributes UA_ObjectTypeAttributes_default; + extern const UA_ReferenceTypeAttributes UA_ReferenceTypeAttributes_default; + extern const UA_DataTypeAttributes UA_DataTypeAttributes_default; + extern const UA_ViewAttributes UA_ViewAttributes_default; + +Endpoint URL Parser +------------------- +The endpoint URL parser is generally useful for the implementation of network +layer plugins. + +.. code-block:: c + + + /* Split the given endpoint url into hostname, port and path. All arguments must + * be non-NULL. EndpointUrls have the form "opc.tcp://hostname:port/path", port + * and path may be omitted (together with the prefix colon and slash). + * + * @param endpointUrl The endpoint URL. + * @param outHostname Set to the parsed hostname. The string points into the + * original endpointUrl, so no memory is allocated. If an IPv6 address is + * given, hostname contains e.g. '[2001:0db8:85a3::8a2e:0370:7334]' + * @param outPort Set to the port of the url or left unchanged. + * @param outPath Set to the path if one is present in the endpointUrl. Can be + * NULL. Then not path is returned. Starting or trailing '/' are NOT + * included in the path. The string points into the original endpointUrl, + * so no memory is allocated. + * @return Returns UA_STATUSCODE_BADTCPENDPOINTURLINVALID if parsing failed. */ + UA_StatusCode + UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname, + UA_UInt16 *outPort, UA_String *outPath); + + /* Split the given endpoint url into hostname, vid and pcp. All arguments must + * be non-NULL. EndpointUrls have the form "opc.eth://[:[.PCP]]". + * The host is a MAC address, an IP address or a registered name like a + * hostname. The format of a MAC address is six groups of hexadecimal digits, + * separated by hyphens (e.g. 01-23-45-67-89-ab). A system may also accept + * hostnames and/or IP addresses if it provides means to resolve it to a MAC + * address (e.g. DNS and Reverse-ARP). + * + * Note: currently only parsing MAC address is supported. + * + * @param endpointUrl The endpoint URL. + * @param vid Set to VLAN ID. + * @param pcp Set to Priority Code Point. + * @return Returns UA_STATUSCODE_BADINTERNALERROR if parsing failed. */ + UA_StatusCode + UA_parseEndpointUrlEthernet(const UA_String *endpointUrl, UA_String *target, + UA_UInt16 *vid, UA_Byte *pcp); + + /* Convert given byte string to a positive number. Returns the number of valid + * digits. Stops if a non-digit char is found and returns the number of digits + * up to that point. */ + size_t + UA_readNumber(const UA_Byte *buf, size_t buflen, UA_UInt32 *number); + + /* Same as UA_ReadNumber but with a base parameter */ + size_t + UA_readNumberWithBase(const UA_Byte *buf, size_t buflen, + UA_UInt32 *number, UA_Byte base); + + #ifndef UA_MIN + #define UA_MIN(A, B) ((A) > (B) ? (B) : (A)) + #endif + + #ifndef UA_MAX + #define UA_MAX(A, B) ((A) > (B) ? (A) : (B)) + #endif + +Parse RelativePath Expressions +------------------------------ + +Parse a RelativePath according to the format defined in Part 4, A2. This is +used e.g. for the BrowsePath structure. For now, only the standard +ReferenceTypes from Namespace 0 are recognized (see Part 3). + + ``RelativePath := ( ReferenceType [BrowseName]? )*`` + +The ReferenceTypes have either of the following formats: + +- ``/``: *HierarchicalReferences* and subtypes +- ``.``: *Aggregates* ReferenceTypesand subtypes +- ``< [!#]* BrowseName >``: The ReferenceType is indicated by its BrowseName + (a QualifiedName). Prefixed modifiers can be as follows: ``!`` switches to + inverse References. ``#`` excludes subtypes of the ReferenceType. + +QualifiedNames consist of an optional NamespaceIndex and the nameitself: + + ``QualifiedName := ([0-9]+ ":")? Name`` + +The QualifiedName representation for RelativePaths uses ``&`` as the escape +character. Occurences of the characters ``/.<>:#!&`` in a QualifiedName have +to be escaped (prefixed with ``&``). + +Example RelativePaths +````````````````````` + +- ``/2:Block&.Output`` +- ``/3:Truck.0:NodeVersion`` +- ``<0:HasProperty>1:Boiler/1:HeatSensor`` +- ``<0:HasChild>2:Wheel`` +- ``<#Aggregates>1:Boiler/`` +- ``Truck`` +- ```` + +.. code-block:: c + + #ifdef UA_ENABLE_PARSING + UA_StatusCode + UA_RelativePath_parse(UA_RelativePath *rp, const UA_String str); + #endif + +Convenience macros for complex types +------------------------------------ + +.. code-block:: c + + #define UA_PRINTF_GUID_FORMAT "%08" PRIx32 "-%04" PRIx16 "-%04" PRIx16 \ + "-%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 + #define UA_PRINTF_GUID_DATA(GUID) (GUID).data1, (GUID).data2, (GUID).data3, \ + (GUID).data4[0], (GUID).data4[1], (GUID).data4[2], (GUID).data4[3], \ + (GUID).data4[4], (GUID).data4[5], (GUID).data4[6], (GUID).data4[7] + + #define UA_PRINTF_STRING_FORMAT "\"%.*s\"" + #define UA_PRINTF_STRING_DATA(STRING) (int)(STRING).length, (STRING).data + +Cryptography Helpers +-------------------- + +.. code-block:: c + + + /* Compare memory in constant time to mitigate timing attacks. + * Returns true if ptr1 and ptr2 are equal for length bytes. */ + UA_Boolean + UA_constantTimeEqual(const void *ptr1, const void *ptr2, size_t length); + + /* Zero-out memory in a way that is not removed by compiler-optimizations. Use + * this to ensure cryptographic secrets don't leave traces after the memory was + * freed. */ + void + UA_ByteString_memZero(UA_ByteString *bs); diff --git a/static/doc/v1.4.0/_static/basic.css b/static/doc/v1.4.0/_static/basic.css new file mode 100644 index 0000000000..30fee9d0f7 --- /dev/null +++ b/static/doc/v1.4.0/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/static/doc/v1.4.0/_static/building.rst b/static/doc/v1.4.0/_static/building.rst new file mode 100644 index 0000000000..acbc30aaa7 --- /dev/null +++ b/static/doc/v1.4.0/_static/building.rst @@ -0,0 +1,489 @@ +.. _building: + +Building open62541 +================== + +Building the Library +-------------------- + +open62541 uses CMake to build the library and binaries. CMake generates a +Makefile or a Visual Studio project. This is then used to perform the actual +build. + +Building with CMake on Ubuntu or Debian +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + sudo apt-get install git build-essential gcc pkg-config cmake python + + # enable additional features + sudo apt-get install cmake-curses-gui # for the ccmake graphical interface + sudo apt-get install libmbedtls-dev # for encryption support + sudo apt-get install check libsubunit-dev # for unit tests + sudo apt-get install python-sphinx graphviz # for documentation generation + sudo apt-get install python-sphinx-rtd-theme # documentation style + + cd open62541 + mkdir build + cd build + cmake .. + make + + # select additional features + ccmake .. + make + + # build documentation + make doc # html documentation + make doc_pdf # pdf documentation (requires LaTeX) + +You can install open62541 using the well known `make install` command. This +allows you to use pre-built libraries and headers for your own project. In order +to use open62541 as a shared library (.dll or .so) make sure to activate the +``BUILD_SHARED_LIBS`` CMake option. + +To override the default installation directory use ``cmake +-DCMAKE_INSTALL_PREFIX=/some/path``. Based on the SDK Features you selected, as +described in :ref:`build_options`, these features will also be included in the +installation. Thus we recommend to enable as many non-experimental features as +possible for the installed binary. + +In your own CMake project you can then include the open62541 library using: + +.. code-block:: cmake + + # optionally you can also specify a specific version + # e.g. find_package(open62541 1.0.0) + find_package(open62541 REQUIRED COMPONENTS Events FullNamespace) + add_executable(main main.cpp) + target_link_libraries(main open62541::open62541) + +A full list of enabled features during build time is stored in the CMake +Variable ``open62541_COMPONENTS_ALL`` + +Building with CMake on Windows +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Here we explain the build process for Visual Studio (2013 or newer). To build +with MinGW, just replace the compiler selection in the call to CMake. + +- Download and install + + - Python 2.7.x (Python 3.x works as well): https://python.org/downloads + - CMake: http://www.cmake.org/cmake/resources/software.html + - Microsoft Visual Studio: https://www.visualstudio.com/products/visual-studio-community-vs + +- Download the open62541 sources (using git or as a zipfile from github) +- Open a command shell (cmd) and run + +.. code-block:: bat + + cd \open62541 + mkdir build + cd build + \cmake.exe .. -G "Visual Studio 14 2015" + :: You can use use cmake-gui for a graphical user-interface to select features + +- Then open :file:`build\open62541.sln` in Visual Studio 2015 and build as usual + +Building on OS X +^^^^^^^^^^^^^^^^ + +- Download and install + + - Xcode: https://itunes.apple.com/us/app/xcode/id497799835?ls=1&mt=12 + - Homebrew: http://brew.sh/ + - Pip (a package manager for Python, may be preinstalled): ``sudo easy_install pip`` + +- Run the following in a shell + +.. code-block:: bash + + brew install cmake + pip install sphinx # for documentation generation + pip install sphinx_rtd_theme # documentation style + brew install graphviz # for graphics in the documentation + brew install check # for unit tests + +Follow Ubuntu instructions without the ``apt-get`` commands as these are taken care of by the above packages. + +Building on OpenBSD +^^^^^^^^^^^^^^^^^^^ + +The procedure below works on OpenBSD 5.8 with gcc version 4.8.4, cmake version +3.2.3 and Python version 2.7.10. + +- Install a recent gcc, python and cmake: + +.. code-block:: bash + + pkg_add gcc python cmake + +- Tell the system to actually use the recent gcc (it gets installed as egcc on OpenBSD): + +.. code-block:: bash + + export CC=egcc CXX=eg++ + +- Now procede as described for Ubuntu/Debian: + +.. code-block:: bash + + cd open62541 + mkdir build + cd build + cmake .. + make + +Building Debian Packages inside Docker Container with CMake on Ubuntu or Debian +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Here is an example howto build the library as Debian package inside a Docker container + +- Download and install + + - Docker Engine: https://docs.docker.com/install/linux/docker-ce/debian/ + - docker-deb-builder: https://github.com/tsaarni/docker-deb-builder.git + - open62541: https://github.com/open62541/open62541.git + +Install Docker as described at https://docs.docker.com/install/linux/docker-ce/debian/ . + +Get the docker-deb-builder utility from github and make Docker images for the needed +Debian and/or Ubuntu relases + +.. code-block:: bash + + # make and goto local development path (e.g. ~/development) + mkdir ~/development + cd ~/development + + # clone docker-deb-builder utility from github and change into builder directory + git clone https://github.com/tsaarni/docker-deb-builder.git + cd docker-deb-builder + + # make Docker builder images (e.g. Ubuntu 18.04 and 17.04) + docker build -t docker-deb-builder:18.04 -f Dockerfile-ubuntu-18.04 . + docker build -t docker-deb-builder:17.04 -f Dockerfile-ubuntu-17.04 . + +Make a local copy of the open62541 git repo and checkout a pack branch + +.. code-block:: bash + + # make a local copy of the open62541 git repo (e.g. in the home directory) + # and checkout a pack branch (e.g. pack/1.0) + cd ~ + git clone https://github.com/open62541/open62541.git + cd ~/open62541 + git checkout pack/1.0 + +Now it's all set to build Debian/Ubuntu open62541 packages + +.. code-block:: bash + + # goto local developmet path + cd ~/development + + # make a local output directory for the builder where the packages can be placed after build + mkdir output + + # build Debian/Ubuntu packages inside Docker container (e.g. Ubuntu-18.04) + ./build -i docker-deb-builder:18.04 -o output ~/open62541 + +After a successfull build the Debian/Ubuntu packages can be found at :file:`~/development/docker-deb-builder/output` + +CMake Build Options and Debian Packaging +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If the open62541 library will be build as a Debian package using a pack branch (e.g. pack/master or pack/1.0) +then altering or adding CMake build options should be done inside the :file:`debian/rules` file respectively in +the :file:`debian/rules-template` file if working with a development branch (e.g. master or 1.0). + +The section in :file:`debian/rules` where the CMake build options are defined is + +.. code-block:: bash + + ... + override_dh_auto_configure: + dh_auto_configure -- -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUA_NAMESPACE_ZERO=FULL -DUA_ENABLE_AMALGAMATION=OFF -DUA_PACK_DEBIAN=ON + ... + +This CMake build options will be passed as command line variables to CMake during Debian packaging. + +.. _build_options: + +Build Options +------------- + +The open62541 project uses CMake to manage the build options, for code +generation and to generate build projects for the different systems and IDEs. +The tools *ccmake* or *cmake-gui* can be used to graphically set the build +options. + +Most options can be changed manually in :file:`ua_config.h` (:file:`open62541.h` +for the single-file release) after the code generation. But usually there is no +need to adjust them. + +Main Build Options +^^^^^^^^^^^^^^^^^^ + +**CMAKE_BUILD_TYPE** + - ``RelWithDebInfo`` -O2 optimization with debug symbols + - ``Release`` -O2 optimization without debug symbols + - ``Debug`` -O0 optimization with debug symbols + - ``MinSizeRel`` -Os optimization without debug symbols + +**UA_LOGLEVEL** + The SDK logs events of the level defined in ``UA_LOGLEVEL`` and above only. + The logging event levels are as follows: + + - 600: Fatal + - 500: Error + - 400: Warning + - 300: Info + - 200: Debug + - 100: Trace + + This compilation flag defines which log levels get compiled into the code. In + addition, the implementations of :ref:`logging` allow to set a filter for the + logging level at runtime. So the logging level can be changed in the + configuration without recompiling. + +**UA_MULTITHREADING** + Level of multi-threading support. The supported levels are currently as follows: + + - 0-99: Multithreading support disabled. + - >=100: API functions marked with the UA_THREADSAFE-macro are protected internally with mutexes. + Multiple threads are allowed to call these functions of the SDK at the same time without causing race conditions. + Furthermore, this level support the handling of asynchronous method calls from external worker threads. + +Select build artefacts +^^^^^^^^^^^^^^^^^^^^^^ + +By default only the main library shared object libopen62541.so (open62541.dll) +or static linking archive open62541.a (open62541.lib) is built. Additional +artifacts can be specified by the following options: + +**UA_BUILD_EXAMPLES** + Compile example servers and clients from :file:`examples/*.c`. + +**UA_BUILD_UNIT_TESTS** + Compile unit tests. The tests can be executed with ``make test``. + An individual test can be executed with ``make test ARGS="-R -V"``. + The list of available tests can be displayed with ``make test ARGS="-N"``. + +**UA_BUILD_SELFSIGNED_CERTIFICATE** + Generate a self-signed certificate for the server (openSSL required) + +Detailed SDK Features +^^^^^^^^^^^^^^^^^^^^^ + +**UA_ENABLE_SUBSCRIPTIONS** + Enable subscriptions + +**UA_ENABLE_SUBSCRIPTIONS_EVENTS (EXPERIMENTAL)** + Enable the use of events for subscriptions. This is a new feature and currently marked as EXPERIMENTAL. + +**UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS (EXPERIMENTAL)** + Enable the use of A&C for subscriptions. This is a new feature build upon events and currently marked as EXPERIMENTAL. + +**UA_ENABLE_METHODCALLS** + Enable the Method service set + +**UA_ENABLE_PARSING** + Enable parsing human readable formats of builtin data types (Guid, NodeId, etc.). + Utility functions that are not essential to the SDK. + +**UA_ENABLE_NODEMANAGEMENT** + Enable dynamic addition and removal of nodes at runtime + +**UA_ENABLE_AMALGAMATION** + Compile a single-file release into the files :file:`open62541.c` and :file:`open62541.h`. Not recommended for installation. + +**UA_ENABLE_IMMUTABLE_NODES** + Nodes in the information model are not edited but copied and replaced. The + replacement is done with atomic operations so that the information model is + always consistent and can be accessed from an interrupt or parallel thread + (depends on the node storage plugin implementation). + +**UA_ENABLE_COVERAGE** + Measure the coverage of unit tests +**UA_ENABLE_DISCOVERY** + Enable Discovery Service (LDS) +**UA_ENABLE_DISCOVERY_MULTICAST** + Enable Discovery Service with multicast support (LDS-ME) +**UA_ENABLE_DISCOVERY_SEMAPHORE** + Enable Discovery Semaphore support +**UA_ENABLE_ENCRYPTION** + Enable encryption support and specify the used encryption backend. The possible + options are: + - ``OFF`` No encryption support. (default) + - ``MBEDTLS`` Encryption support using mbed TLS + - ``OPENSSL`` Encryption support using OpenSSL + - ``LIBRESSL`` EXPERIMENTAL: Encryption support using LibreSSL +**UA_ENABLE_ENCRYPTION_TPM2** + Enable TPM hardware for encryption. The possible options are: + - ``OFF`` No TPM encryption support. (default) + - ``ON`` TPM encryption support + +**UA_NAMESPACE_ZERO** + + Namespace zero contains the standard-defined nodes. The full namespace zero + may not be required for all applications. The selectable options are as follows: + + - ``MINIMAL``: A barebones namespace zero that is compatible with most + clients. But this namespace 0 is so small that it does not pass the CTT + (Conformance Testing Tools of the OPC Foundation). + - ``REDUCED``: Small namespace zero that passes the CTT. + - ``FULL``: Full namespace zero generated from the official XML definitions. + + The advanced build option ``UA_FILE_NS0`` can be used to override the XML + file used for namespace zero generation. + +Some options are marked as advanced. The advanced options need to be toggled to +be visible in the cmake GUIs. + +**UA_ENABLE_TYPEDESCRIPTION** + Add the type and member names to the UA_DataType structure. Enabled by default. + +**UA_ENABLE_STATUSCODE_DESCRIPTIONS** + Compile the human-readable name of the StatusCodes into the binary. Enabled by default. +**UA_ENABLE_FULL_NS0** + Use the full NS0 instead of a minimal Namespace 0 nodeset + ``UA_FILE_NS0`` is used to specify the file for NS0 generation from namespace0 folder. Default value is ``Opc.Ua.NodeSet2.xml`` + +PubSub Build Options +^^^^^^^^^^^^^^^^^^^^ + +**UA_ENABLE_PUBSUB** + Enable the experimental OPC UA PubSub support. The option will include the + PubSub UDP multicast plugin. Disabled by default. + +**UA_ENABLE_PUBSUB_DELTAFRAMES** + The PubSub messages differentiate between keyframe (all published values + contained) and deltaframe (only changed values contained) messages. + Deltaframe messages creation consumes some additional resources and can be + disabled with this flag. Disabled by default. + +**UA_ENABLE_PUBSUB_FILE_CONFIG** + Enable loading OPC UA PubSub configuration from File/ByteString. Enabling + PubSub informationmodel methods also will add a method to the + Publish/Subscribe object which allows configuring PubSub at runtime. + +**UA_ENABLE_PUBSUB_INFORMATIONMODEL** + Enable the information model representation of the PubSub configuration. For + more details take a look at the following section `PubSub Information Model + Representation`. Disabled by default. + +**UA_ENABLE_PUBSUB_MONITORING** + Enable the experimental PubSub monitoring. This feature provides a basic + framework to implement monitoring/timeout checks for PubSub components. + Initially the MessageReceiveTimeout check of a DataSetReader is provided. It + uses the internal server callback implementation. The monitoring backend can + be changed by the application to satisfy realtime requirements. Disabled by + default. + +Debug Build Options +^^^^^^^^^^^^^^^^^^^ + +This group contains build options mainly useful for development of the library itself. + +**UA_DEBUG** + Enable assertions and additional definitions not intended for production builds + +**UA_DEBUG_DUMP_PKGS** + Dump every package received by the server as hexdump format + +Building a shared library +^^^^^^^^^^^^^^^^^^^^^^^^^ + +open62541 is small enough that most users will want to statically link the +library into their programs. If a shared library (.dll, .so) is required, this +can be enabled in CMake with the ``BUILD_SHARED_LIBS`` option. Note that this +option modifies the :file:`ua_config.h` file that is also included in +:file:`open62541.h` for the single-file distribution. + + +Minimizing the binary size +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The size of the generated binary can be reduced considerably by adjusting the +build configuration. With open62541, it is possible to configure minimal servers +that require less than 100kB of RAM and ROM. + +The following options influence the ROM requirements: + +First, in CMake, the build type can be set to ``CMAKE_BUILD_TYPE=MinSizeRel``. +This sets the compiler flags to minimize the binary size. The build type also +strips out debug information. Second, the binary size can be reduced by removing +features via the build-flags described above. + +Second, setting ``UA_NAMESPACE_ZERO`` to ``MINIMAL`` reduces the size of the +builtin information model. Setting this option can reduce the binary size by +half in some cases. + +Third, some features might not be needed and can be disabled to reduce the +binary footprint. Examples for this are Subscriptions or encrypted +communication. + +Last, logging messages take up a lot of space in the binary and might not be +needed in embedded scenarios. Setting ``UA_LOGLEVEL`` to a value above 600 +(``FATAL``) disables all logging. In addition, the feature-flags +``UA_ENABLE_TYPEDESCRIPTION`` and ``UA_ENABLE_STATUSCODE_DESCRIPTIONS`` add static +information to the binary that is only used for human-readable logging and +debugging. + +The RAM requirements of a server are mostly due to the following settings: + +- The size of the information model +- The number of connected clients +- The configured maximum message size that is preallocated + +Prebuilt packages +----------------- + +Debian +^^^^^^ +Debian packages can be found in our official PPA: + + * Daily Builds (based on master branch): https://launchpad.net/~open62541-team/+archive/ubuntu/daily + * Release Builds (starting with Version 0.4): https://launchpad.net/~open62541-team/+archive/ubuntu/ppa + +Install them with: + +.. code-block:: bash + + sudo add-apt-repository ppa:open62541-team/ppa + sudo apt-get update + sudo apt-get install libopen62541-1-dev + +Arch +^^^^ +Arch packages are available in the AUR: + + * Stable Builds: https://aur.archlinux.org/packages/open62541/ + * Unstable Builds (current master): https://aur.archlinux.org/packages/open62541-git/ + * In order to add custom build options (:ref:`build_options`), you can set the environment variable ``OPEN62541_CMAKE_FLAGS`` + +OpenBSD +^^^^^^^ +Starting with OpenBSD 6.7 the ports directory misc/open62541 can +build the released version of open62541. +Install the binary package from the OpenBSD mirrors: + +.. code-block:: bash + + pkg_add open62541 + +Building the Examples +--------------------- + +Make sure that you have installed the shared library as explained in the +previous steps. Then the build system should automatically find the includes and +the shared library. + +.. code-block:: bash + + cp /path-to/examples/tutorial_server_firststeps.c . # copy the example server + gcc -std=c99 -o server tutorial_server_firststeps.c -lopen62541 + diff --git a/static/doc/v1.4.0/_static/client.rst b/static/doc/v1.4.0/_static/client.rst new file mode 100644 index 0000000000..e955bf9e4c --- /dev/null +++ b/static/doc/v1.4.0/_static/client.rst @@ -0,0 +1,954 @@ +.. _client: + +Client +====== + +The client implementation allows remote access to all OPC UA services. For +convenience, some functionality has been wrapped in :ref:`high-level +abstractions `. + +**However**: At this time, the client does not yet contain its own thread or +event-driven main-loop, meaning that the client will not perform any actions +automatically in the background. This is especially relevant for +connection/session management and subscriptions. The user will have to +periodically call `UA_Client_run_iterate` to ensure that asynchronous events +are handled, including keeping a secure connection established. +See more about :ref:`asynchronicity` and +:ref:`subscriptions`. + +.. _client-config: + +Client Configuration +-------------------- + +The client configuration is used for setting connection parameters and +additional settings used by the client. +The configuration should not be modified after it is passed to a client. +Currently, only one client can use a configuration at a time. + +Examples for configurations are provided in the ``/plugins`` folder. +The usual usage is as follows: + +1. Create a client configuration with default settings as a starting point +2. Modifiy the configuration, e.g. modifying the timeout +3. Instantiate a client with it +4. After shutdown of the client, clean up the configuration (free memory) + +The :ref:`tutorials` provide a good starting point for this. + +.. code-block:: c + + + struct UA_ClientConfig { + void *clientContext; /* User-defined pointer attached to the client */ + UA_Logger *logging; /* Plugin for log output */ + + /* Response timeout in ms (0 -> no timeout). If the server does not answer a + * request within this time a StatusCode UA_STATUSCODE_BADTIMEOUT is + * returned. This timeout can be overridden for individual requests by + * setting a non-null "timeoutHint" in the request header. */ + UA_UInt32 timeout; + + /* The description must be internally consistent. + * - The ApplicationUri set in the ApplicationDescription must match the + * URI set in the certificate */ + UA_ApplicationDescription clientDescription; + + /* The endpoint for the client to connect to. + * Such as "opc.tcp://host:port". */ + UA_String endpointUrl; + +Connection configuration +~~~~~~~~~~~~~~~~~~~~~~~~ + +The following configuration elements reduce the "degrees of freedom" the +client has when connecting to a server. If no connection can be made +under these restrictions, then the connection will abort with an error +message. + +.. code-block:: c + + UA_ExtensionObject userIdentityToken; /* Configured User-Identity Token */ + UA_MessageSecurityMode securityMode; /* None, Sign, SignAndEncrypt. The + * default is invalid. This indicates + * the client to select any matching + * endpoint. */ + UA_String securityPolicyUri; /* SecurityPolicy for the SecureChannel. An + * empty string indicates the client to select + * any matching SecurityPolicy. */ + + UA_Boolean noSession; /* Only open a SecureChannel, but no Session */ + UA_Boolean noReconnect; /* Don't reconnect SecureChannel when the connection + * is lost without explicitly closing. */ + UA_Boolean noNewSession; /* Don't automatically create a new Session when + * the intial one is lost. Instead abort the + * connection when the Session is lost. */ + +If either endpoint or userTokenPolicy has been set (at least one non-zero +byte in either structure), then the selected Endpoint and UserTokenPolicy +overwrite the settings in the basic connection configuration. The +userTokenPolicy array in the EndpointDescription is ignored. The selected +userTokenPolicy is set in the dedicated configuration field. + +If the advanced configuration is not set, the client will write to it the +selected Endpoint and UserTokenPolicy during GetEndpoints. + +The information in the advanced configuration is used during reconnect +when the SecureChannel was broken. + +.. code-block:: c + + UA_EndpointDescription endpoint; + UA_UserTokenPolicy userTokenPolicy; + +If the EndpointDescription has not been defined, the ApplicationURI +constrains the servers considered in the FindServers service and the +Endpoints considered in the GetEndpoints service. + +If empty the applicationURI is not used to filter. + +.. code-block:: c + + UA_String applicationUri; + +Custom Data Types +~~~~~~~~~~~~~~~~~ +The following is a linked list of arrays with custom data types. All data +types that are accessible from here are automatically considered for the +decoding of received messages. Custom data types are not cleaned up +together with the configuration. So it is possible to allocate them on +ROM. + +See the section on :ref:`generic-types`. Examples for working with custom +data types are provided in ``/examples/custom_datatype/``. + +.. code-block:: c + + const UA_DataTypeArray *customDataTypes; + +Advanced Client Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: c + + + UA_UInt32 secureChannelLifeTime; /* Lifetime in ms (then the channel needs + to be renewed) */ + UA_UInt32 requestedSessionTimeout; /* Session timeout in ms */ + UA_ConnectionConfig localConnectionConfig; + UA_UInt32 connectivityCheckInterval; /* Connectivity check interval in ms. + * 0 = background task disabled */ + + /* EventLoop */ + UA_EventLoop *eventLoop; + UA_Boolean externalEventLoop; /* The EventLoop is not deleted with the config */ + + /* Available SecurityPolicies */ + size_t securityPoliciesSize; + UA_SecurityPolicy *securityPolicies; + + /* Certificate Verification Plugin */ + UA_CertificateVerification certificateVerification; + + /* Available SecurityPolicies for Authentication. The policy defined by the + * AccessControl is selected. If no policy is defined, the policy of the + * secure channel is selected.*/ + size_t authSecurityPoliciesSize; + UA_SecurityPolicy *authSecurityPolicies; + /* SecurityPolicyUri for the Authentication. */ + UA_String authSecurityPolicyUri; + + /* Callback for state changes. The client state is differentated into the + * SecureChannel state and the Session state. The connectStatus is set if + * the client connection (including reconnects) has failed and the client + * has to "give up". If the connectStatus is not set, the client still has + * hope to connect or recover. */ + void (*stateCallback)(UA_Client *client, + UA_SecureChannelState channelState, + UA_SessionState sessionState, + UA_StatusCode connectStatus); + + /* When connectivityCheckInterval is greater than 0, every + * connectivityCheckInterval (in ms), an async read request is performed on + * the server. inactivityCallback is called when the client receive no + * response for this read request The connection can be closed, this in an + * attempt to recreate a healthy connection. */ + void (*inactivityCallback)(UA_Client *client); + + /* Number of PublishResponse queued up in the server */ + UA_UInt16 outStandingPublishRequests; + + /* If the client does not receive a PublishResponse after the defined delay + * of ``(sub->publishingInterval * sub->maxKeepAliveCount) + + * client->config.timeout)``, then subscriptionInactivityCallback is called + * for the subscription.. */ + void (*subscriptionInactivityCallback)(UA_Client *client, + UA_UInt32 subscriptionId, + void *subContext); + + /* Session config */ + UA_String sessionName; + UA_LocaleId *sessionLocaleIds; + size_t sessionLocaleIdsSize; + + #ifdef UA_ENABLE_ENCRYPTION + /* If the private key is in PEM format and password protected, this callback + * is called during initialization to get the password to decrypt the + * private key. The memory containing the password is freed by the client + * after use. The callback should be set early, other parts of the client + * config setup may depend on it. */ + UA_StatusCode (*privateKeyPasswordCallback)(UA_ClientConfig *cc, + UA_ByteString *password); + #endif + }; + +@brief It makes a partial deep copy of the clientconfig. It makes a shallow +copies of the plugins (logger, eventloop, securitypolicy). + +NOTE: It makes a shallow copy of all the plugins from source to destination. +Therefore calling _clear on the dst object will also delete the plugins in src +object. + +.. code-block:: c + + UA_StatusCode + UA_ClientConfig_copy(UA_ClientConfig const *src, UA_ClientConfig *dst); + +@brief It cleans the client config and frees the pointer. + +.. code-block:: c + + void + UA_ClientConfig_delete(UA_ClientConfig *config); + +@brief It cleans the client config and deletes the plugins, whereas +_copy makes a shallow copy of the plugins. + +.. code-block:: c + + void + UA_ClientConfig_clear(UA_ClientConfig *config); + + /* Configure Username/Password for the Session authentication. Also see + * UA_ClientConfig_setAuthenticationCert for x509-based authentication, which is + * implemented as a plugin (as it can be based on different crypto + * libraries). */ + static UA_INLINE UA_StatusCode + UA_ClientConfig_setAuthenticationUsername(UA_ClientConfig *config, + const char *username, + const char *password) { + UA_UserNameIdentityToken* identityToken = UA_UserNameIdentityToken_new(); + if(!identityToken) + return UA_STATUSCODE_BADOUTOFMEMORY; + identityToken->userName = UA_STRING_ALLOC(username); + identityToken->password = UA_STRING_ALLOC(password); + + UA_ExtensionObject_clear(&config->userIdentityToken); + UA_ExtensionObject_setValue(&config->userIdentityToken, identityToken, + &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]); + return UA_STATUSCODE_GOOD; + } + +Client Lifecycle +---------------- + +.. code-block:: c + + + /* Create a new client with a default configuration that adds plugins for + * networking, security, logging and so on. See `client_config_default.h` for + * more detailed options. + * + * The default configuration can be used as the starting point to adjust the + * client configuration to individual needs. UA_Client_new is implemented in the + * /plugins folder under the CC0 license. Furthermore the client confiugration + * only uses the public server API. + * + * @return Returns the configured client or NULL if an error occurs. */ + UA_Client * UA_Client_new(void); + + /* Creates a new client. Moves the config into the client with a shallow copy. + * The config content is cleared together with the client. */ + UA_Client * + UA_Client_newWithConfig(const UA_ClientConfig *config); + + /* Returns the current state. All arguments except ``client`` can be NULL. */ + void UA_THREADSAFE + UA_Client_getState(UA_Client *client, + UA_SecureChannelState *channelState, + UA_SessionState *sessionState, + UA_StatusCode *connectStatus); + + /* Get the client configuration */ + UA_ClientConfig * + UA_Client_getConfig(UA_Client *client); + + /* Get the client context */ + static UA_INLINE void * + UA_Client_getContext(UA_Client *client) { + return UA_Client_getConfig(client)->clientContext; /* Cannot fail */ + } + + /* (Disconnect and) delete the client */ + void + UA_Client_delete(UA_Client *client); + +Connection Attrbiutes +--------------------- + +Besides the client configuration, some attributes of the connection are +defined only at runtime. For example the choice of SecurityPolicy or the +ApplicationDescripton from the server. This API allows to access such +connection attributes. + +The currently defined connection attributes are: + +- 0:serverDescription [UA_ApplicationDescription]: Server description +- 0:securityPolicyUri [UA_String]: Uri of the SecurityPolicy used +- 0:securityMode [UA_MessageSecurityMode]: SecurityMode of the SecureChannel + +.. code-block:: c + + + /* Returns a shallow copy of the attribute. Don't _clear or _delete the value + * variant. Don't use the value after returning the control flow to the client. + * Also don't use this in a multi-threaded application. */ + UA_StatusCode + UA_Client_getConnectionAttribute(UA_Client *client, const UA_QualifiedName key, + UA_Variant *outValue); + + /* Return a deep copy of the attribute */ + UA_StatusCode UA_THREADSAFE + UA_Client_getConnectionAttributeCopy(UA_Client *client, const UA_QualifiedName key, + UA_Variant *outValue); + + /* Returns NULL if the attribute is not defined or not a scalar or not of the + * right datatype. Otherwise a shallow copy of the scalar value is created at + * the target location of the void pointer. Hence don't use this in a + * multi-threaded application. */ + UA_StatusCode + UA_Client_getConnectionAttribute_scalar(UA_Client *client, + const UA_QualifiedName key, + const UA_DataType *type, + void *outValue); + +Connect to a Server +------------------- + +Once a client is connected to an endpointUrl, it is not possible to switch to +another server. A new client has to be created for that. + +Once a connection is established, the client keeps the connection open and +reconnects if necessary. + +If the connection fails unrecoverably (state->connectStatus is set to an +error), the client is no longer usable. Create a new client if required. + +.. code-block:: c + + + /* Connect with the client configuration. For the async connection, finish + * connecting via UA_Client_run_iterate (or manually running a configured + * external EventLoop). */ + UA_StatusCode UA_THREADSAFE + __UA_Client_connect(UA_Client *client, UA_Boolean async); + + /* Connect to the server. First a SecureChannel is opened, then a Session. The + * client configuration restricts the SecureChannel selection and contains the + * UserIdentityToken for the Session. + * + * @param client to use + * @param endpointURL to connect (for example "opc.tcp://localhost:4840") + * @return Indicates whether the operation succeeded or returns an error code */ + static UA_INLINE UA_StatusCode + UA_Client_connect(UA_Client *client, const char *endpointUrl) { + /* Update the configuration */ + UA_ClientConfig *cc = UA_Client_getConfig(client); + cc->noSession = false; /* Open a Session */ + UA_String_clear(&cc->endpointUrl); + cc->endpointUrl = UA_STRING_ALLOC(endpointUrl); + + /* Connect */ + return __UA_Client_connect(client, false); + } + + /* Connect async (non-blocking) to the server. After initiating the connection, + * call UA_Client_run_iterate repeatedly until the connection is fully + * established. You can set a callback to client->config.stateCallback to be + * notified when the connection status changes. Or use UA_Client_getState to get + * the state manually. */ + static UA_INLINE UA_StatusCode + UA_Client_connectAsync(UA_Client *client, const char *endpointUrl) { + /* Update the configuration */ + UA_ClientConfig *cc = UA_Client_getConfig(client); + cc->noSession = false; /* Open a Session */ + UA_String_clear(&cc->endpointUrl); + cc->endpointUrl = UA_STRING_ALLOC(endpointUrl); + + /* Connect */ + return __UA_Client_connect(client, true); + } + + /* Connect to the server without creating a session + * + * @param client to use + * @param endpointURL to connect (for example "opc.tcp://localhost:4840") + * @return Indicates whether the operation succeeded or returns an error code */ + static UA_INLINE UA_StatusCode + UA_Client_connectSecureChannel(UA_Client *client, const char *endpointUrl) { + /* Update the configuration */ + UA_ClientConfig *cc = UA_Client_getConfig(client); + cc->noSession = true; /* Don't open a Session */ + UA_String_clear(&cc->endpointUrl); + cc->endpointUrl = UA_STRING_ALLOC(endpointUrl); + + /* Connect */ + return __UA_Client_connect(client, false); + } + + /* Connect async (non-blocking) only the SecureChannel */ + static UA_INLINE UA_StatusCode + UA_Client_connectSecureChannelAsync(UA_Client *client, const char *endpointUrl) { + /* Update the configuration */ + UA_ClientConfig *cc = UA_Client_getConfig(client); + cc->noSession = true; /* Don't open a Session */ + UA_String_clear(&cc->endpointUrl); + cc->endpointUrl = UA_STRING_ALLOC(endpointUrl); + + /* Connect */ + return __UA_Client_connect(client, false); + } + + /* Connect to the server and create+activate a Session with the given username + * and password. This first set the UserIdentityToken in the client config and + * then calls the regular connect method. */ + static UA_INLINE UA_StatusCode + UA_Client_connectUsername(UA_Client *client, const char *endpointUrl, + const char *username, const char *password) { + /* Set the user identity token */ + UA_ClientConfig *cc = UA_Client_getConfig(client); + UA_StatusCode res = + UA_ClientConfig_setAuthenticationUsername(cc, username, password); + if(res != UA_STATUSCODE_GOOD) + return res; + + /* Connect */ + return UA_Client_connect(client, endpointUrl); + } + + /* Sets up a listening socket for incoming reverse connect requests by OPC UA + * servers. After the first server has connected, the listening socket is + * removed. The client state callback is also used for reverse connect. An + * implementation could for example issue a new call to + * UA_Client_startListeningForReverseConnect after the server has closed the + * connection. If the client is connected to any server while + * UA_Client_startListeningForReverseConnect is called, the connection will be + * closed. + * + * The reverse connect is closed by calling the standard disconnect functions + * like for a "normal" connection that was initiated by the client. Calling one + * of the connect methods will also close the listening socket and the + * connection to the remote server. */ + UA_StatusCode + UA_Client_startListeningForReverseConnect( + UA_Client *client, const UA_String *listenHostnames, + size_t listenHostnamesLength, UA_UInt16 port); + + /* Disconnect and close a connection to the selected server. Disconnection is + * always performed async (without blocking). */ + UA_StatusCode UA_THREADSAFE + UA_Client_disconnect(UA_Client *client); + + /* Disconnect async. Run UA_Client_run_iterate until the callback notifies that + * all connections are closed. */ + UA_StatusCode UA_THREADSAFE + UA_Client_disconnectAsync(UA_Client *client); + + /* Disconnect the SecureChannel but keep the Session intact (if it exists). */ + UA_StatusCode UA_THREADSAFE + UA_Client_disconnectSecureChannel(UA_Client *client); + + /* Disconnect the SecureChannel but keep the Session intact (if it exists). This + * is an async operation. Iterate the client until the SecureChannel was fully + * cleaned up. */ + UA_StatusCode UA_THREADSAFE + UA_Client_disconnectSecureChannelAsync(UA_Client *client); + + /* Get the AuthenticationToken and ServerNonce required to activate the current + * Session on a different SecureChannel. */ + UA_StatusCode UA_THREADSAFE + UA_Client_getSessionAuthenticationToken( + UA_Client *client, UA_NodeId *authenticationToken, UA_ByteString *serverNonce); + + /* Re-activate the current session. A change of prefered locales can be done by + * updating the client configuration. */ + UA_StatusCode UA_THREADSAFE + UA_Client_activateCurrentSession(UA_Client *client); + + /* Async version of UA_Client_activateCurrentSession */ + UA_StatusCode UA_THREADSAFE + UA_Client_activateCurrentSessionAsync(UA_Client *client); + + /* Activate an already created Session. This allows a Session to be transferred + * from a different client instance. The AuthenticationToken and ServerNonce + * must be provided for this. Both can be retrieved for an activated Session + * with UA_Client_getSessionAuthenticationToken. + * + * The UserIdentityToken used for authentication must be identical to the + * original activation of the Session. The UserIdentityToken is set in the + * client configuration. + * + * Note the noNewSession option if there should not be a new Session + * automatically created when this one closes. */ + UA_StatusCode UA_THREADSAFE + UA_Client_activateSession(UA_Client *client, + const UA_NodeId authenticationToken, + const UA_ByteString serverNonce); + + /* Async version of UA_Client_activateSession */ + UA_StatusCode UA_THREADSAFE + UA_Client_activateSessionAsync(UA_Client *client, + const UA_NodeId authenticationToken, + const UA_ByteString serverNonce); + +Discovery +--------- + +.. code-block:: c + + + /* Gets a list of endpoints of a server + * + * @param client to use. Must be connected to the same endpoint given in + * serverUrl or otherwise in disconnected state. + * @param serverUrl url to connect (for example "opc.tcp://localhost:4840") + * @param endpointDescriptionsSize size of the array of endpoint descriptions + * @param endpointDescriptions array of endpoint descriptions that is allocated + * by the function (you need to free manually) + * @return Indicates whether the operation succeeded or returns an error code */ + UA_StatusCode UA_THREADSAFE + UA_Client_getEndpoints(UA_Client *client, const char *serverUrl, + size_t* endpointDescriptionsSize, + UA_EndpointDescription** endpointDescriptions); + + /* Gets a list of all registered servers at the given server. + * + * You can pass an optional filter for serverUris. If the given server is not + * registered, an empty array will be returned. If the server is registered, + * only that application description will be returned. + * + * Additionally you can optionally indicate which locale you want for the server + * name in the returned application description. The array indicates the order + * of preference. A server may have localized names. + * + * @param client to use. Must be connected to the same endpoint given in + * serverUrl or otherwise in disconnected state. + * @param serverUrl url to connect (for example "opc.tcp://localhost:4840") + * @param serverUrisSize Optional filter for specific server uris + * @param serverUris Optional filter for specific server uris + * @param localeIdsSize Optional indication which locale you prefer + * @param localeIds Optional indication which locale you prefer + * @param registeredServersSize size of returned array, i.e., number of + * found/registered servers + * @param registeredServers array containing found/registered servers + * @return Indicates whether the operation succeeded or returns an error code */ + UA_StatusCode UA_THREADSAFE + UA_Client_findServers(UA_Client *client, const char *serverUrl, + size_t serverUrisSize, UA_String *serverUris, + size_t localeIdsSize, UA_String *localeIds, + size_t *registeredServersSize, + UA_ApplicationDescription **registeredServers); + + /* Get a list of all known server in the network. Only supported by LDS servers. + * + * @param client to use. Must be connected to the same endpoint given in + * serverUrl or otherwise in disconnected state. + * @param serverUrl url to connect (for example "opc.tcp://localhost:4840") + * @param startingRecordId optional. Only return the records with an ID higher + * or equal the given. Can be used for pagination to only get a subset of + * the full list + * @param maxRecordsToReturn optional. Only return this number of records + + * @param serverCapabilityFilterSize optional. Filter the returned list to only + * get servers with given capabilities, e.g. "LDS" + * @param serverCapabilityFilter optional. Filter the returned list to only get + * servers with given capabilities, e.g. "LDS" + * @param serverOnNetworkSize size of returned array, i.e., number of + * known/registered servers + * @param serverOnNetwork array containing known/registered servers + * @return Indicates whether the operation succeeded or returns an error code */ + UA_StatusCode UA_THREADSAFE + UA_Client_findServersOnNetwork(UA_Client *client, const char *serverUrl, + UA_UInt32 startingRecordId, + UA_UInt32 maxRecordsToReturn, + size_t serverCapabilityFilterSize, + UA_String *serverCapabilityFilter, + size_t *serverOnNetworkSize, + UA_ServerOnNetwork **serverOnNetwork); + +.. _client-services: + +Services +-------- + +The raw OPC UA services are exposed to the client. But most of the time, it +is better to use the convenience functions from ``ua_client_highlevel.h`` +that wrap the raw services. + +.. code-block:: c + + /* Don't use this function. Use the type versions below instead. */ + void UA_THREADSAFE + __UA_Client_Service(UA_Client *client, const void *request, + const UA_DataType *requestType, void *response, + const UA_DataType *responseType); + + /* + * Attribute Service Set + * ^^^^^^^^^^^^^^^^^^^^^ */ + static UA_INLINE UA_THREADSAFE UA_ReadResponse + UA_Client_Service_read(UA_Client *client, const UA_ReadRequest request) { + UA_ReadResponse response; + __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_READREQUEST], + &response, &UA_TYPES[UA_TYPES_READRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_WriteResponse + UA_Client_Service_write(UA_Client *client, const UA_WriteRequest request) { + UA_WriteResponse response; + __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_WRITEREQUEST], + &response, &UA_TYPES[UA_TYPES_WRITERESPONSE]); + return response; + } + + /* + * Historical Access Service Set + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ + static UA_INLINE UA_THREADSAFE UA_HistoryReadResponse + UA_Client_Service_historyRead(UA_Client *client, + const UA_HistoryReadRequest request) { + UA_HistoryReadResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_HISTORYREADREQUEST], + &response, &UA_TYPES[UA_TYPES_HISTORYREADRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_HistoryUpdateResponse + UA_Client_Service_historyUpdate(UA_Client *client, + const UA_HistoryUpdateRequest request) { + UA_HistoryUpdateResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_HISTORYUPDATEREQUEST], + &response, &UA_TYPES[UA_TYPES_HISTORYUPDATERESPONSE]); + return response; + } + + /* + * Method Service Set + * ^^^^^^^^^^^^^^^^^^ */ + static UA_INLINE UA_THREADSAFE UA_CallResponse + UA_Client_Service_call(UA_Client *client, + const UA_CallRequest request) { + UA_CallResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_CALLREQUEST], + &response, &UA_TYPES[UA_TYPES_CALLRESPONSE]); + return response; + } + + /* + * NodeManagement Service Set + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ */ + static UA_INLINE UA_THREADSAFE UA_AddNodesResponse + UA_Client_Service_addNodes(UA_Client *client, + const UA_AddNodesRequest request) { + UA_AddNodesResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_ADDNODESREQUEST], + &response, &UA_TYPES[UA_TYPES_ADDNODESRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_AddReferencesResponse + UA_Client_Service_addReferences(UA_Client *client, + const UA_AddReferencesRequest request) { + UA_AddReferencesResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_ADDREFERENCESREQUEST], + &response, &UA_TYPES[UA_TYPES_ADDREFERENCESRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_DeleteNodesResponse + UA_Client_Service_deleteNodes(UA_Client *client, + const UA_DeleteNodesRequest request) { + UA_DeleteNodesResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_DELETENODESREQUEST], + &response, &UA_TYPES[UA_TYPES_DELETENODESRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_DeleteReferencesResponse + UA_Client_Service_deleteReferences( + UA_Client *client, const UA_DeleteReferencesRequest request) { + UA_DeleteReferencesResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_DELETEREFERENCESREQUEST], + &response, &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE]); + return response; + } + + /* + * View Service Set + * ^^^^^^^^^^^^^^^^ */ + static UA_INLINE UA_THREADSAFE UA_BrowseResponse + UA_Client_Service_browse(UA_Client *client, + const UA_BrowseRequest request) { + UA_BrowseResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], + &response, &UA_TYPES[UA_TYPES_BROWSERESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_BrowseNextResponse + UA_Client_Service_browseNext(UA_Client *client, + const UA_BrowseNextRequest request) { + UA_BrowseNextResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST], + &response, &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_TranslateBrowsePathsToNodeIdsResponse + UA_Client_Service_translateBrowsePathsToNodeIds( + UA_Client *client, + const UA_TranslateBrowsePathsToNodeIdsRequest request) { + UA_TranslateBrowsePathsToNodeIdsResponse response; + __UA_Client_Service( + client, &request, + &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST], + &response, + &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_RegisterNodesResponse + UA_Client_Service_registerNodes(UA_Client *client, + const UA_RegisterNodesRequest request) { + UA_RegisterNodesResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_REGISTERNODESREQUEST], + &response, &UA_TYPES[UA_TYPES_REGISTERNODESRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_UnregisterNodesResponse + UA_Client_Service_unregisterNodes( + UA_Client *client, const UA_UnregisterNodesRequest request) { + UA_UnregisterNodesResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_UNREGISTERNODESREQUEST], + &response, &UA_TYPES[UA_TYPES_UNREGISTERNODESRESPONSE]); + return response; + } + + /* + * Query Service Set + * ^^^^^^^^^^^^^^^^^ */ + #ifdef UA_ENABLE_QUERY + + static UA_INLINE UA_THREADSAFE UA_QueryFirstResponse + UA_Client_Service_queryFirst(UA_Client *client, + const UA_QueryFirstRequest request) { + UA_QueryFirstResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_QUERYFIRSTREQUEST], + &response, &UA_TYPES[UA_TYPES_QUERYFIRSTRESPONSE]); + return response; + } + + static UA_INLINE UA_THREADSAFE UA_QueryNextResponse + UA_Client_Service_queryNext(UA_Client *client, + const UA_QueryNextRequest request) { + UA_QueryNextResponse response; + __UA_Client_Service( + client, &request, &UA_TYPES[UA_TYPES_QUERYFIRSTREQUEST], + &response, &UA_TYPES[UA_TYPES_QUERYFIRSTRESPONSE]); + return response; + } + + #endif + +.. _client-async-services: + +Asynchronous Services +--------------------- +All OPC UA services are asynchronous in nature. So several service calls can +be made without waiting for the individual responses. Depending on the +server's priorities responses may come in a different ordering than sent. Use +the typed wrappers for async service requests instead of +`__UA_Client_AsyncService` directly. See :ref:`client_async`. However, the +general mechanism of async service calls is explained here. + +Connection and session management are performed in `UA_Client_run_iterate`, +so to keep a connection healthy any client needs to consider how and when it +is appropriate to do the call. This is especially true for the periodic +renewal of a SecureChannel's SecurityToken which is designed to have a +limited lifetime and will invalidate the connection if not renewed. + +We say that an async service call has been dispatched once +__UA_Client_AsyncService returns UA_STATUSCODE_GOOD. If there is an error +after an async service has been dispatched, the callback is called with an +"empty" response where the StatusCode has been set accordingly. This is also +done if the client is shutting down and the list of dispatched async services +is emptied. + +The StatusCode received when the client is shutting down is +UA_STATUSCODE_BADSHUTDOWN. The StatusCode received when the client doesn't +receive response after the specified in config->timeout (can be overridden +via the "timeoutHint" in the request header) is UA_STATUSCODE_BADTIMEOUT. + +The userdata and requestId arguments can be NULL. The (optional) requestId +output can be used to cancel the service while it is still pending. The +requestId is unique for each service request. Alternatively the requestHandle +can be manually set (non necessarily unique) in the request header for full +service call. This can be used to cancel all outstanding requests using that +handle together. Note that the client will auto-generate a requestHandle +>100,000 if none is defined. Avoid these when manually setting a requetHandle +in the requestHeader to avoid clashes. + +.. code-block:: c + + + typedef void + (*UA_ClientAsyncServiceCallback)(UA_Client *client, void *userdata, + UA_UInt32 requestId, void *response); + + UA_StatusCode UA_THREADSAFE + __UA_Client_AsyncService(UA_Client *client, const void *request, + const UA_DataType *requestType, + UA_ClientAsyncServiceCallback callback, + const UA_DataType *responseType, + void *userdata, UA_UInt32 *requestId); + + /* Cancel all dispatched requests with the given requestHandle. + * The number if cancelled requests is returned by the server. + * The output argument cancelCount is not set if NULL. */ + UA_THREADSAFE UA_StatusCode + UA_Client_cancelByRequestHandle(UA_Client *client, UA_UInt32 requestHandle, + UA_UInt32 *cancelCount); + + /* Map the requestId to the requestHandle used for that request and call the + * Cancel service for that requestHandle. */ + UA_THREADSAFE UA_StatusCode + UA_Client_cancelByRequestId(UA_Client *client, UA_UInt32 requestId, + UA_UInt32 *cancelCount); + + /* Set new userdata and callback for an existing request. + * + * @param client Pointer to the UA_Client + * @param requestId RequestId of the request, which was returned by + * __UA_Client_AsyncService before + * @param userdata The new userdata + * @param callback The new callback + * @return UA_StatusCode UA_STATUSCODE_GOOD on success + * UA_STATUSCODE_BADNOTFOUND when no request with requestId is found. */ + UA_StatusCode UA_THREADSAFE + UA_Client_modifyAsyncCallback(UA_Client *client, UA_UInt32 requestId, + void *userdata, UA_ClientAsyncServiceCallback callback); + + /* Listen on the network and process arriving asynchronous responses in the + * background. Internal housekeeping, renewal of SecureChannels and subscription + * management is done as well. */ + UA_StatusCode UA_THREADSAFE + UA_Client_run_iterate(UA_Client *client, UA_UInt32 timeout); + + /* Force the manual renewal of the SecureChannel. This is useful to renew the + * SecureChannel during a downtime when no time-critical operations are + * performed. This method is asynchronous. The renewal is triggered (the OPN + * message is sent) but not completed. The OPN response is handled with + * ``UA_Client_run_iterate`` or a synchronous service-call operation. + * + * @return The return value is UA_STATUSCODE_GOODCALLAGAIN if the SecureChannel + * has not elapsed at least 75% of its lifetime. Otherwise the + * ``connectStatus`` is returned. */ + UA_StatusCode UA_THREADSAFE + UA_Client_renewSecureChannel(UA_Client *client); + +Timed Callbacks +--------------- +Repeated callbacks can be attached to a client and will be executed in the +defined interval. + +.. code-block:: c + + + typedef void (*UA_ClientCallback)(UA_Client *client, void *data); + + /* Add a callback for execution at a specified time. If the indicated time lies + * in the past, then the callback is executed at the next iteration of the + * server's main loop. + * + * @param client The client object. + * @param callback The callback that shall be added. + * @param data Data that is forwarded to the callback. + * @param date The timestamp for the execution time. + * @param callbackId Set to the identifier of the repeated callback. This can + * be used to cancel the callback later on. If the pointer is null, the + * identifier is not set. + * @return Upon success, UA_STATUSCODE_GOOD is returned. An error code + * otherwise. */ + UA_StatusCode UA_THREADSAFE + UA_Client_addTimedCallback(UA_Client *client, UA_ClientCallback callback, + void *data, UA_DateTime date, UA_UInt64 *callbackId); + + /* Add a callback for cyclic repetition to the client. + * + * @param client The client object. + * @param callback The callback that shall be added. + * @param data Data that is forwarded to the callback. + * @param interval_ms The callback shall be repeatedly executed with the given + * interval (in ms). The interval must be positive. The first execution + * occurs at now() + interval at the latest. + * @param callbackId Set to the identifier of the repeated callback. This can + * be used to cancel the callback later on. If the pointer is null, the + * identifier is not set. + * @return Upon success, UA_STATUSCODE_GOOD is returned. An error code + * otherwise. */ + UA_StatusCode UA_THREADSAFE + UA_Client_addRepeatedCallback(UA_Client *client, UA_ClientCallback callback, + void *data, UA_Double interval_ms, + UA_UInt64 *callbackId); + + UA_StatusCode UA_THREADSAFE + UA_Client_changeRepeatedCallbackInterval(UA_Client *client, + UA_UInt64 callbackId, + UA_Double interval_ms); + + void UA_THREADSAFE + UA_Client_removeCallback(UA_Client *client, UA_UInt64 callbackId); + + #define UA_Client_removeRepeatedCallback(server, callbackId) \ + UA_Client_removeCallback(server, callbackId); + +Client Utility Functions +------------------------ + +.. code-block:: c + + + /* Lookup a datatype by its NodeId. Takes the custom types in the client + * configuration into account. Return NULL if none found. */ + const UA_DataType * + UA_Client_findDataType(UA_Client *client, const UA_NodeId *typeId); + +.. toctree:: + + client_highlevel + client_highlevel_async + client_subscriptions diff --git a/static/doc/v1.4.0/_static/client_highlevel.rst b/static/doc/v1.4.0/_static/client_highlevel.rst new file mode 100644 index 0000000000..f93a766f82 --- /dev/null +++ b/static/doc/v1.4.0/_static/client_highlevel.rst @@ -0,0 +1,652 @@ +.. _client-highlevel: + +Highlevel Client Functionality +------------------------------ + +The following definitions are convenience functions making use of the +standard OPC UA services in the background. This is a less flexible way of +handling the stack, because at many places sensible defaults are presumed; at +the same time using these functions is the easiest way of implementing an OPC +UA application, as you will not have to consider all the details that go into +the OPC UA services. If more flexibility is needed, you can always achieve +the same functionality using the raw :ref:`OPC UA services +`. + +Read Attributes +^^^^^^^^^^^^^^^ +The following functions can be used to retrieve a single node attribute. Use +the regular service to read several attributes at once. + +.. code-block:: c + + + /* Don't call this function, use the typed versions */ + UA_StatusCode + __UA_Client_readAttribute(UA_Client *client, const UA_NodeId *nodeId, + UA_AttributeId attributeId, void *out, + const UA_DataType *outDataType); + + static UA_INLINE UA_StatusCode + UA_Client_readNodeIdAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_NodeId *outNodeId) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_NODEID, + outNodeId, &UA_TYPES[UA_TYPES_NODEID]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readNodeClassAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_NodeClass *outNodeClass) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_NODECLASS, + outNodeClass, &UA_TYPES[UA_TYPES_NODECLASS]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readBrowseNameAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_QualifiedName *outBrowseName) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_BROWSENAME, + outBrowseName, + &UA_TYPES[UA_TYPES_QUALIFIEDNAME]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readDisplayNameAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_LocalizedText *outDisplayName) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, + outDisplayName, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readDescriptionAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_LocalizedText *outDescription) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, + outDescription, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_UInt32 *outWriteMask) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_WRITEMASK, + outWriteMask, &UA_TYPES[UA_TYPES_UINT32]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readUserWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_UInt32 *outUserWriteMask) { + return __UA_Client_readAttribute(client, &nodeId, + UA_ATTRIBUTEID_USERWRITEMASK, + outUserWriteMask, + &UA_TYPES[UA_TYPES_UINT32]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readIsAbstractAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Boolean *outIsAbstract) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, + outIsAbstract, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readSymmetricAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Boolean *outSymmetric) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC, + outSymmetric, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readInverseNameAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_LocalizedText *outInverseName) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_INVERSENAME, + outInverseName, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readContainsNoLoopsAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Boolean *outContainsNoLoops) { + return __UA_Client_readAttribute(client, &nodeId, + UA_ATTRIBUTEID_CONTAINSNOLOOPS, + outContainsNoLoops, + &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readEventNotifierAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Byte *outEventNotifier) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, + outEventNotifier, &UA_TYPES[UA_TYPES_BYTE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readValueAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Variant *outValue) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE, + outValue, &UA_TYPES[UA_TYPES_VARIANT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readDataTypeAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_NodeId *outDataType) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DATATYPE, + outDataType, &UA_TYPES[UA_TYPES_NODEID]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readValueRankAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Int32 *outValueRank) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUERANK, + outValueRank, &UA_TYPES[UA_TYPES_INT32]); + } + + UA_StatusCode + UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId, + size_t *outArrayDimensionsSize, + UA_UInt32 **outArrayDimensions); + + static UA_INLINE UA_StatusCode + UA_Client_readAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Byte *outAccessLevel) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, + outAccessLevel, &UA_TYPES[UA_TYPES_BYTE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readAccessLevelExAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_UInt32 *outAccessLevelEx) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX, + outAccessLevelEx, &UA_TYPES[UA_TYPES_UINT32]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readUserAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Byte *outUserAccessLevel) { + return __UA_Client_readAttribute(client, &nodeId, + UA_ATTRIBUTEID_USERACCESSLEVEL, + outUserAccessLevel, + &UA_TYPES[UA_TYPES_BYTE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readMinimumSamplingIntervalAttribute(UA_Client *client, + const UA_NodeId nodeId, + UA_Double *outMinSamplingInterval) { + return __UA_Client_readAttribute(client, &nodeId, + UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, + outMinSamplingInterval, + &UA_TYPES[UA_TYPES_DOUBLE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readHistorizingAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Boolean *outHistorizing) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_HISTORIZING, + outHistorizing, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readExecutableAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Boolean *outExecutable) { + return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, + outExecutable, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_readUserExecutableAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_Boolean *outUserExecutable) { + return __UA_Client_readAttribute(client, &nodeId, + UA_ATTRIBUTEID_USEREXECUTABLE, + outUserExecutable, + &UA_TYPES[UA_TYPES_BOOLEAN]); + } + +Historical Access +^^^^^^^^^^^^^^^^^ +The following functions can be used to read a single node historically. +Use the regular service to read several nodes at once. + +.. code-block:: c + + + typedef UA_Boolean + (*UA_HistoricalIteratorCallback)( + UA_Client *client, const UA_NodeId *nodeId, UA_Boolean moreDataAvailable, + const UA_ExtensionObject *data, void *callbackContext); + + UA_StatusCode + UA_Client_HistoryRead_events( + UA_Client *client, const UA_NodeId *nodeId, + const UA_HistoricalIteratorCallback callback, UA_DateTime startTime, + UA_DateTime endTime, UA_String indexRange, const UA_EventFilter filter, + UA_UInt32 numValuesPerNode, UA_TimestampsToReturn timestampsToReturn, + void *callbackContext); + + UA_StatusCode + UA_Client_HistoryRead_raw( + UA_Client *client, const UA_NodeId *nodeId, + const UA_HistoricalIteratorCallback callback, UA_DateTime startTime, + UA_DateTime endTime, UA_String indexRange, UA_Boolean returnBounds, + UA_UInt32 numValuesPerNode, UA_TimestampsToReturn timestampsToReturn, + void *callbackContext); + + UA_StatusCode + UA_Client_HistoryRead_modified( + UA_Client *client, const UA_NodeId *nodeId, + const UA_HistoricalIteratorCallback callback, UA_DateTime startTime, + UA_DateTime endTime, UA_String indexRange, UA_Boolean returnBounds, + UA_UInt32 numValuesPerNode, UA_TimestampsToReturn timestampsToReturn, + void *callbackContext); + + UA_StatusCode + UA_Client_HistoryUpdate_insert( + UA_Client *client, const UA_NodeId *nodeId, UA_DataValue *value); + + UA_StatusCode + UA_Client_HistoryUpdate_replace( + UA_Client *client, const UA_NodeId *nodeId, UA_DataValue *value); + + UA_StatusCode + UA_Client_HistoryUpdate_update( + UA_Client *client, const UA_NodeId *nodeId, UA_DataValue *value); + + UA_StatusCode + UA_Client_HistoryUpdate_deleteRaw( + UA_Client *client, const UA_NodeId *nodeId, + UA_DateTime startTimestamp, UA_DateTime endTimestamp); + +Write Attributes +^^^^^^^^^^^^^^^^ + +The following functions can be use to write a single node attribute at a +time. Use the regular write service to write several attributes at once. + +.. code-block:: c + + + /* Don't call this function, use the typed versions */ + UA_StatusCode + __UA_Client_writeAttribute(UA_Client *client, const UA_NodeId *nodeId, + UA_AttributeId attributeId, const void *in, + const UA_DataType *inDataType); + + static UA_INLINE UA_StatusCode + UA_Client_writeNodeIdAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_NodeId *newNodeId) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_NODEID, + newNodeId, &UA_TYPES[UA_TYPES_NODEID]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeNodeClassAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_NodeClass *newNodeClass) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_NODECLASS, + newNodeClass, &UA_TYPES[UA_TYPES_NODECLASS]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeBrowseNameAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_QualifiedName *newBrowseName) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_BROWSENAME, + newBrowseName, + &UA_TYPES[UA_TYPES_QUALIFIEDNAME]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeDisplayNameAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_LocalizedText *newDisplayName) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, + newDisplayName, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeDescriptionAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_LocalizedText *newDescription) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, + newDescription, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_UInt32 *newWriteMask) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_WRITEMASK, + newWriteMask, &UA_TYPES[UA_TYPES_UINT32]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeUserWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_UInt32 *newUserWriteMask) { + return __UA_Client_writeAttribute(client, &nodeId, + UA_ATTRIBUTEID_USERWRITEMASK, + newUserWriteMask, + &UA_TYPES[UA_TYPES_UINT32]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeIsAbstractAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *newIsAbstract) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, + newIsAbstract, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeSymmetricAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *newSymmetric) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC, + newSymmetric, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeInverseNameAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_LocalizedText *newInverseName) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_INVERSENAME, + newInverseName, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeContainsNoLoopsAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *newContainsNoLoops) { + return __UA_Client_writeAttribute(client, &nodeId, + UA_ATTRIBUTEID_CONTAINSNOLOOPS, + newContainsNoLoops, + &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeEventNotifierAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Byte *newEventNotifier) { + return __UA_Client_writeAttribute(client, &nodeId, + UA_ATTRIBUTEID_EVENTNOTIFIER, + newEventNotifier, + &UA_TYPES[UA_TYPES_BYTE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeValueAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Variant *newValue) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE, + newValue, &UA_TYPES[UA_TYPES_VARIANT]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeValueAttribute_scalar(UA_Client *client, const UA_NodeId nodeId, + const void *newValue, + const UA_DataType *valueType) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE, + newValue, valueType); + } + + /* Write a DataValue that can include timestamps and status codes */ + static UA_INLINE UA_StatusCode + UA_Client_writeValueAttributeEx(UA_Client *client, const UA_NodeId nodeId, + const UA_DataValue *newValue) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE, + newValue, &UA_TYPES[UA_TYPES_DATAVALUE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeDataTypeAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_NodeId *newDataType) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_DATATYPE, + newDataType, &UA_TYPES[UA_TYPES_NODEID]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeValueRankAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Int32 *newValueRank) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUERANK, + newValueRank, &UA_TYPES[UA_TYPES_INT32]); + } + + UA_StatusCode + UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId, + size_t newArrayDimensionsSize, + const UA_UInt32 *newArrayDimensions); + + static UA_INLINE UA_StatusCode + UA_Client_writeAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Byte *newAccessLevel) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, + newAccessLevel, &UA_TYPES[UA_TYPES_BYTE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeAccessLevelExAttribute(UA_Client *client, const UA_NodeId nodeId, + UA_UInt32 *newAccessLevelEx) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX, + newAccessLevelEx, &UA_TYPES[UA_TYPES_UINT32]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeUserAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Byte *newUserAccessLevel) { + return __UA_Client_writeAttribute(client, &nodeId, + UA_ATTRIBUTEID_USERACCESSLEVEL, + newUserAccessLevel, + &UA_TYPES[UA_TYPES_BYTE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeMinimumSamplingIntervalAttribute(UA_Client *client, + const UA_NodeId nodeId, + const UA_Double *newMinInterval) { + return __UA_Client_writeAttribute(client, &nodeId, + UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, + newMinInterval, &UA_TYPES[UA_TYPES_DOUBLE]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeHistorizingAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *newHistorizing) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_HISTORIZING, + newHistorizing, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeExecutableAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *newExecutable) { + return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, + newExecutable, &UA_TYPES[UA_TYPES_BOOLEAN]); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeUserExecutableAttribute(UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *newUserExecutable) { + return __UA_Client_writeAttribute(client, &nodeId, + UA_ATTRIBUTEID_USEREXECUTABLE, + newUserExecutable, + &UA_TYPES[UA_TYPES_BOOLEAN]); + } + +Method Calling +^^^^^^^^^^^^^^ + +.. code-block:: c + + + UA_StatusCode + UA_Client_call(UA_Client *client, + const UA_NodeId objectId, const UA_NodeId methodId, + size_t inputSize, const UA_Variant *input, + size_t *outputSize, UA_Variant **output); + +Node Management +^^^^^^^^^^^^^^^ +See the section on :ref:`server-side node management `. + +.. code-block:: c + + + UA_StatusCode + UA_Client_addReference(UA_Client *client, const UA_NodeId sourceNodeId, + const UA_NodeId referenceTypeId, UA_Boolean isForward, + const UA_String targetServerUri, + const UA_ExpandedNodeId targetNodeId, + UA_NodeClass targetNodeClass); + + UA_StatusCode + UA_Client_deleteReference(UA_Client *client, const UA_NodeId sourceNodeId, + const UA_NodeId referenceTypeId, UA_Boolean isForward, + const UA_ExpandedNodeId targetNodeId, + UA_Boolean deleteBidirectional); + + UA_StatusCode + UA_Client_deleteNode(UA_Client *client, const UA_NodeId nodeId, + UA_Boolean deleteTargetReferences); + + /* Don't call this function, use the typed versions */ + UA_StatusCode + __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, const UA_NodeAttributes *attr, + const UA_DataType *attributeType, UA_NodeId *outNewNodeId); + + static UA_INLINE UA_StatusCode + UA_Client_addVariableNode(UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, + const UA_VariableAttributes attr, + UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_VARIABLE, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + typeDefinition, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], + outNewNodeId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addVariableTypeNode(UA_Client *client, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_VariableTypeAttributes attr, + UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_VARIABLETYPE, + requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], + outNewNodeId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addObjectNode(UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, + const UA_ObjectAttributes attr, UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_OBJECT, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + typeDefinition, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], outNewNodeId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addObjectTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ObjectTypeAttributes attr, + UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], + outNewNodeId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addViewNode(UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ViewAttributes attr, + UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_VIEW, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], outNewNodeId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addReferenceTypeNode(UA_Client *client, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ReferenceTypeAttributes attr, + UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_REFERENCETYPE, + requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], + outNewNodeId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addDataTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_DataTypeAttributes attr, + UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_DATATYPE, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], + outNewNodeId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addMethodNode(UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_MethodAttributes attr, + UA_NodeId *outNewNodeId) { + return __UA_Client_addNode(client, UA_NODECLASS_METHOD, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_METHODATTRIBUTES], outNewNodeId); + } + +Misc Highlevel Functionality +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + + /* Get the namespace-index of a namespace-URI + * + * @param client The UA_Client struct for this connection + * @param namespaceUri The interested namespace URI + * @param namespaceIndex The namespace index of the URI. The value is unchanged + * in case of an error + * @return Indicates whether the operation succeeded or returns an error code */ + UA_StatusCode + UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri, + UA_UInt16 *namespaceIndex); + + #ifndef HAVE_NODEITER_CALLBACK + #define HAVE_NODEITER_CALLBACK + /* Iterate over all nodes referenced by parentNodeId by calling the callback + * function for each child node */ + typedef UA_StatusCode + (*UA_NodeIteratorCallback)(UA_NodeId childId, UA_Boolean isInverse, + UA_NodeId referenceTypeId, void *handle); + #endif + + UA_StatusCode + UA_Client_forEachChildNodeCall( + UA_Client *client, UA_NodeId parentNodeId, + UA_NodeIteratorCallback callback, void *handle); diff --git a/static/doc/v1.4.0/_static/client_highlevel_async.rst b/static/doc/v1.4.0/_static/client_highlevel_async.rst new file mode 100644 index 0000000000..6581789667 --- /dev/null +++ b/static/doc/v1.4.0/_static/client_highlevel_async.rst @@ -0,0 +1,798 @@ +.. _client_async: + +Async Services +^^^^^^^^^^^^^^ + +Call OPC UA Services asynchronously with a callback. The (optional) requestId +output can be used to cancel the service while it is still pending. + +.. code-block:: c + + + typedef void + (*UA_ClientAsyncReadCallback)( + UA_Client *client, void *userdata, + UA_UInt32 requestId, UA_ReadResponse *rr); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Client_sendAsyncReadRequest( + UA_Client *client, UA_ReadRequest *request, + UA_ClientAsyncReadCallback readCallback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_AsyncService( + client, request, &UA_TYPES[UA_TYPES_READREQUEST], + (UA_ClientAsyncServiceCallback)readCallback, + &UA_TYPES[UA_TYPES_READRESPONSE], userdata, reqId); + } + + typedef void + (*UA_ClientAsyncWriteCallback)( + UA_Client *client, void *userdata, + UA_UInt32 requestId, UA_WriteResponse *wr); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Client_sendAsyncWriteRequest( + UA_Client *client, UA_WriteRequest *request, + UA_ClientAsyncWriteCallback writeCallback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_AsyncService( + client, request, &UA_TYPES[UA_TYPES_WRITEREQUEST], + (UA_ClientAsyncServiceCallback)writeCallback, + &UA_TYPES[UA_TYPES_WRITERESPONSE], userdata, reqId); + } + + typedef void + (*UA_ClientAsyncBrowseCallback)( + UA_Client *client, void *userdata, + UA_UInt32 requestId, UA_BrowseResponse *wr); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Client_sendAsyncBrowseRequest( + UA_Client *client, UA_BrowseRequest *request, + UA_ClientAsyncBrowseCallback browseCallback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_AsyncService( + client, request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], + (UA_ClientAsyncServiceCallback)browseCallback, + &UA_TYPES[UA_TYPES_BROWSERESPONSE], userdata, reqId); + } + + typedef void + (*UA_ClientAsyncBrowseNextCallback)( + UA_Client *client, void *userdata, + UA_UInt32 requestId, UA_BrowseNextResponse *wr); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Client_sendAsyncBrowseNextRequest( + UA_Client *client, UA_BrowseNextRequest *request, + UA_ClientAsyncBrowseNextCallback browseNextCallback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_AsyncService( + client, request, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST], + (UA_ClientAsyncServiceCallback)browseNextCallback, + &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE], userdata, reqId); + } + +Asynchronous Operations +^^^^^^^^^^^^^^^^^^^^^^^ + +Many Services can be called with an array of operations. For example, a +request to the Read Service contains an array of ReadValueId, each +corresponding to a single read operation. For convenience, wrappers are +provided to call single operations for the most common Services. + +All async operations have a callback of the following structure: The returned +StatusCode is split in two parts. The status indicates the overall success of +the request and the operation. The result argument is non-NULL only if the +status is no good. + +.. code-block:: c + + typedef void + (*UA_ClientAsyncOperationCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, void *result); + +Read Attribute +^^^^^^^^^^^^^^ + +Asynchronously read a single attribute. The attribute is unpacked from the +response as the datatype of the attribute is known ahead of time. Value +attributes are variants. + +Note that the last argument (value pointer) of the callbacks can be NULL if +the status of the operation is not good. + +.. code-block:: c + + + /* Reading a single attribute */ + typedef void + (*UA_ClientAsyncReadAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_DataValue *attribute); + + UA_StatusCode + UA_Client_readAttribute_async( + UA_Client *client, const UA_ReadValueId *rvi, + UA_TimestampsToReturn timestampsToReturn, + UA_ClientAsyncReadAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single Value attribute */ + typedef void + (*UA_ClientAsyncReadValueAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_DataValue *value); + + UA_StatusCode + UA_Client_readValueAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadValueAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single DataType attribute */ + typedef void + (*UA_ClientAsyncReadDataTypeAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_NodeId *dataType); + + UA_StatusCode + UA_Client_readDataTypeAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadDataTypeAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single ArrayDimensions attribute. If the status is good, the variant + * carries an UInt32 array. */ + typedef void + (*UA_ClientReadArrayDimensionsAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Variant *arrayDimensions); + + UA_StatusCode + UA_Client_readArrayDimensionsAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientReadArrayDimensionsAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single NodeClass attribute */ + typedef void + (*UA_ClientAsyncReadNodeClassAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_NodeClass *nodeClass); + + UA_StatusCode + UA_Client_readNodeClassAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadNodeClassAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single BrowseName attribute */ + typedef void + (*UA_ClientAsyncReadBrowseNameAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_QualifiedName *browseName); + + UA_StatusCode + UA_Client_readBrowseNameAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadBrowseNameAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single DisplayName attribute */ + typedef void + (*UA_ClientAsyncReadDisplayNameAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_LocalizedText *displayName); + + UA_StatusCode + UA_Client_readDisplayNameAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadDisplayNameAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single Description attribute */ + typedef void + (*UA_ClientAsyncReadDescriptionAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_LocalizedText *description); + + UA_StatusCode + UA_Client_readDescriptionAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadDescriptionAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single WriteMask attribute */ + typedef void + (*UA_ClientAsyncReadWriteMaskAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_UInt32 *writeMask); + + UA_StatusCode + UA_Client_readWriteMaskAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadWriteMaskAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single UserWriteMask attribute */ + typedef void + (*UA_ClientAsyncReadUserWriteMaskAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_UInt32 *writeMask); + + UA_StatusCode + UA_Client_readUserWriteMaskAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadUserWriteMaskAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single IsAbstract attribute */ + typedef void + (*UA_ClientAsyncReadIsAbstractAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Boolean *isAbstract); + + UA_StatusCode + UA_Client_readIsAbstractAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadIsAbstractAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single Symmetric attribute */ + typedef void + (*UA_ClientAsyncReadSymmetricAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Boolean *symmetric); + + UA_StatusCode + UA_Client_readSymmetricAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadSymmetricAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single InverseName attribute */ + typedef void + (*UA_ClientAsyncReadInverseNameAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_LocalizedText *inverseName); + + UA_StatusCode + UA_Client_readInverseNameAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadInverseNameAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single ContainsNoLoops attribute */ + typedef void + (*UA_ClientAsyncReadContainsNoLoopsAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Boolean *containsNoLoops); + + UA_StatusCode + UA_Client_readContainsNoLoopsAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadContainsNoLoopsAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single EventNotifier attribute */ + typedef void + (*UA_ClientAsyncReadEventNotifierAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Byte *eventNotifier); + + UA_StatusCode + UA_Client_readEventNotifierAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadEventNotifierAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single ValueRank attribute */ + typedef void + (*UA_ClientAsyncReadValueRankAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Int32 *valueRank); + + UA_StatusCode + UA_Client_readValueRankAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadValueRankAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single AccessLevel attribute */ + typedef void + (*UA_ClientAsyncReadAccessLevelAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Byte *accessLevel); + + UA_StatusCode + UA_Client_readAccessLevelAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadAccessLevelAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single AccessLevelEx attribute */ + typedef void + (*UA_ClientAsyncReadAccessLevelExAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_UInt32 *accessLevelEx); + + UA_StatusCode + UA_Client_readAccessLevelExAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadAccessLevelExAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single UserAccessLevel attribute */ + typedef void + (*UA_ClientAsyncReadUserAccessLevelAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Byte *userAccessLevel); + + UA_StatusCode + UA_Client_readUserAccessLevelAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadUserAccessLevelAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single MinimumSamplingInterval attribute */ + typedef void + (*UA_ClientAsyncReadMinimumSamplingIntervalAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Double *minimumSamplingInterval); + + UA_StatusCode + UA_Client_readMinimumSamplingIntervalAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadMinimumSamplingIntervalAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single Historizing attribute */ + typedef void + (*UA_ClientAsyncReadHistorizingAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Boolean *historizing); + + UA_StatusCode + UA_Client_readHistorizingAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadHistorizingAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single Executable attribute */ + typedef void + (*UA_ClientAsyncReadExecutableAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Boolean *executable); + + UA_StatusCode + UA_Client_readExecutableAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadExecutableAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Read a single UserExecutable attribute */ + typedef void + (*UA_ClientAsyncReadUserExecutableAttributeCallback)( + UA_Client *client, void *userdata, UA_UInt32 requestId, + UA_StatusCode status, UA_Boolean *userExecutable); + + UA_StatusCode + UA_Client_readUserExecutableAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadUserExecutableAttributeCallback callback, + void *userdata, UA_UInt32 *requestId); + +Write Attribute +^^^^^^^^^^^^^^^ + +.. code-block:: c + + + UA_StatusCode + __UA_Client_writeAttribute_async( + UA_Client *client, const UA_NodeId *nodeId, + UA_AttributeId attributeId, const void *in, + const UA_DataType *inDataType, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId); + + static UA_INLINE UA_StatusCode + UA_Client_writeValueAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Variant *attr, UA_ClientAsyncWriteCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_VALUE, attr, + &UA_TYPES[UA_TYPES_VARIANT], + (UA_ClientAsyncServiceCallback)callback, + userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeNodeIdAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_NodeId *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_NODEID, attr, + &UA_TYPES[UA_TYPES_NODEID], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeNodeClassAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_NodeClass *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_NODECLASS, attr, + &UA_TYPES[UA_TYPES_NODECLASS], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeBrowseNameAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_QualifiedName *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_BROWSENAME, attr, + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeDisplayNameAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_LocalizedText *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, attr, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeDescriptionAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_LocalizedText *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, attr, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeWriteMaskAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_UInt32 *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_WRITEMASK, attr, + &UA_TYPES[UA_TYPES_UINT32], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeUserWriteMaskAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_UInt32 *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_USERWRITEMASK, attr, + &UA_TYPES[UA_TYPES_UINT32], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeIsAbstractAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, attr, + &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeSymmetricAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC, attr, + &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeInverseNameAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_LocalizedText *attr, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_INVERSENAME, attr, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeContainsNoLoopsAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, attr, + &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeEventNotifierAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Byte *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, attr, + &UA_TYPES[UA_TYPES_BYTE], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeDataTypeAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_NodeId *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_DATATYPE, attr, + &UA_TYPES[UA_TYPES_NODEID], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeValueRankAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Int32 *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_VALUERANK, attr, + &UA_TYPES[UA_TYPES_INT32], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeAccessLevelAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Byte *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, attr, + &UA_TYPES[UA_TYPES_BYTE], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeAccessLevelExAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_UInt32 *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX, attr, + &UA_TYPES[UA_TYPES_UINT32], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeUserAccessLevelAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Byte *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_USERACCESSLEVEL, attr, + &UA_TYPES[UA_TYPES_BYTE], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeMinimumSamplingIntervalAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Double *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, + attr, &UA_TYPES[UA_TYPES_DOUBLE], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeHistorizingAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_HISTORIZING, attr, + &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeExecutableAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, attr, + &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_writeUserExecutableAttribute_async( + UA_Client *client, const UA_NodeId nodeId, + const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_writeAttribute_async( + client, &nodeId, UA_ATTRIBUTEID_USEREXECUTABLE, attr, + &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId); + } + +Method Calling +^^^^^^^^^^^^^^ + +.. code-block:: c + + UA_StatusCode + __UA_Client_call_async( + UA_Client *client, + const UA_NodeId objectId, const UA_NodeId methodId, + size_t inputSize, const UA_Variant *input, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *reqId); + + typedef void + (*UA_ClientAsyncCallCallback)( + UA_Client *client, void *userdata, + UA_UInt32 requestId, UA_CallResponse *cr); + + static UA_INLINE UA_StatusCode + UA_Client_call_async( + UA_Client *client, + const UA_NodeId objectId, const UA_NodeId methodId, + size_t inputSize, const UA_Variant *input, + UA_ClientAsyncCallCallback callback, void *userdata, + UA_UInt32 *reqId) { + return __UA_Client_call_async( + client, objectId, methodId, inputSize, input, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + +Node Management +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef void + (*UA_ClientAsyncAddNodesCallback)( + UA_Client *client, void *userdata, + UA_UInt32 requestId, UA_AddNodesResponse *ar); + + UA_StatusCode + __UA_Client_addNode_async( + UA_Client *client, const UA_NodeClass nodeClass, + const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, const UA_NodeAttributes *attr, + const UA_DataType *attributeType, UA_NodeId *outNewNodeId, + UA_ClientAsyncServiceCallback callback, void *userdata, + UA_UInt32 *reqId); + + static UA_INLINE UA_StatusCode + UA_Client_addVariableNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, const UA_NodeId typeDefinition, + const UA_VariableAttributes attr, UA_NodeId *outNewNodeId, + UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_VARIABLE, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + typeDefinition, (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], outNewNodeId, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addVariableTypeNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_VariableTypeAttributes attr, + UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_VARIABLETYPE, + requestedNewNodeId, parentNodeId, + referenceTypeId, browseName, UA_NODEID_NULL, + (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], + outNewNodeId, (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addObjectNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, const UA_NodeId typeDefinition, + const UA_ObjectAttributes attr, UA_NodeId *outNewNodeId, + UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_OBJECT, requestedNewNodeId, + parentNodeId, referenceTypeId, + browseName, typeDefinition, (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], outNewNodeId, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addObjectTypeNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ObjectTypeAttributes attr, + UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId, parentNodeId, + referenceTypeId, browseName, UA_NODEID_NULL, + (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], outNewNodeId, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addViewNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, const UA_ViewAttributes attr, + UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_VIEW, requestedNewNodeId, + parentNodeId, referenceTypeId, + browseName, UA_NODEID_NULL, (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], outNewNodeId, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addReferenceTypeNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ReferenceTypeAttributes attr, + UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_REFERENCETYPE, requestedNewNodeId, parentNodeId, + referenceTypeId, browseName, UA_NODEID_NULL, + (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], outNewNodeId, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addDataTypeNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, const UA_DataTypeAttributes attr, + UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_DATATYPE, requestedNewNodeId, + parentNodeId, referenceTypeId, browseName, + UA_NODEID_NULL, (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], outNewNodeId, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } + + static UA_INLINE UA_StatusCode + UA_Client_addMethodNode_async( + UA_Client *client, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, const UA_MethodAttributes attr, + UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback, + void *userdata, UA_UInt32 *reqId) { + return __UA_Client_addNode_async( + client, UA_NODECLASS_METHOD, requestedNewNodeId, parentNodeId, + referenceTypeId, browseName, UA_NODEID_NULL, + (const UA_NodeAttributes *)&attr, + &UA_TYPES[UA_TYPES_METHODATTRIBUTES], outNewNodeId, + (UA_ClientAsyncServiceCallback)callback, userdata, reqId); + } diff --git a/static/doc/v1.4.0/_static/client_subscriptions.rst b/static/doc/v1.4.0/_static/client_subscriptions.rst new file mode 100644 index 0000000000..3f16766f4d --- /dev/null +++ b/static/doc/v1.4.0/_static/client_subscriptions.rst @@ -0,0 +1,274 @@ +.. _client-subscriptions: + +Subscriptions +------------- + +Subscriptions in OPC UA are asynchronous. That is, the client sends several +PublishRequests to the server. The server returns PublishResponses with +notifications. But only when a notification has been generated. The client +does not wait for the responses and continues normal operations. + +Note the difference between Subscriptions and MonitoredItems. Subscriptions +are used to report back notifications. MonitoredItems are used to generate +notifications. Every MonitoredItem is attached to exactly one Subscription. +And a Subscription can contain many MonitoredItems. + +The client automatically processes PublishResponses (with a callback) in the +background and keeps enough PublishRequests in transit. The PublishResponses +may be recieved during a synchronous service call or in +``UA_Client_run_iterate``. See more about +:ref:`asynchronicity`. + +.. code-block:: c + + + /* Callbacks defined for Subscriptions */ + typedef void (*UA_Client_DeleteSubscriptionCallback) + (UA_Client *client, UA_UInt32 subId, void *subContext); + + typedef void (*UA_Client_StatusChangeNotificationCallback) + (UA_Client *client, UA_UInt32 subId, void *subContext, + UA_StatusChangeNotification *notification); + + /* Provides default values for a new subscription. + * + * RequestedPublishingInterval: 500.0 [ms] + * RequestedLifetimeCount: 10000 + * RequestedMaxKeepAliveCount: 10 + * MaxNotificationsPerPublish: 0 (unlimited) + * PublishingEnabled: true + * Priority: 0 */ + static UA_INLINE UA_CreateSubscriptionRequest + UA_CreateSubscriptionRequest_default(void) { + UA_CreateSubscriptionRequest request; + UA_CreateSubscriptionRequest_init(&request); + + request.requestedPublishingInterval = 500.0; + request.requestedLifetimeCount = 10000; + request.requestedMaxKeepAliveCount = 10; + request.maxNotificationsPerPublish = 0; + request.publishingEnabled = true; + request.priority = 0; + return request; + } + + UA_CreateSubscriptionResponse + UA_Client_Subscriptions_create(UA_Client *client, + const UA_CreateSubscriptionRequest request, + void *subscriptionContext, + UA_Client_StatusChangeNotificationCallback statusChangeCallback, + UA_Client_DeleteSubscriptionCallback deleteCallback); + + UA_StatusCode + UA_Client_Subscriptions_create_async(UA_Client *client, + const UA_CreateSubscriptionRequest request, + void *subscriptionContext, + UA_Client_StatusChangeNotificationCallback statusChangeCallback, + UA_Client_DeleteSubscriptionCallback deleteCallback, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *requestId); + + UA_ModifySubscriptionResponse + UA_Client_Subscriptions_modify(UA_Client *client, + const UA_ModifySubscriptionRequest request); + + UA_StatusCode + UA_Client_Subscriptions_modify_async(UA_Client *client, + const UA_ModifySubscriptionRequest request, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *requestId); + + UA_DeleteSubscriptionsResponse + UA_Client_Subscriptions_delete(UA_Client *client, + const UA_DeleteSubscriptionsRequest request); + + UA_StatusCode + UA_Client_Subscriptions_delete_async(UA_Client *client, + const UA_DeleteSubscriptionsRequest request, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *requestId); + + /* Delete a single subscription */ + UA_StatusCode + UA_Client_Subscriptions_deleteSingle(UA_Client *client, UA_UInt32 subscriptionId); + + static UA_INLINE UA_SetPublishingModeResponse + UA_Client_Subscriptions_setPublishingMode(UA_Client *client, + const UA_SetPublishingModeRequest request) { + UA_SetPublishingModeResponse response; + __UA_Client_Service(client, + &request, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODEREQUEST], + &response, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODERESPONSE]); + return response; + } + +MonitoredItems +-------------- + +MonitoredItems for Events indicate the ``EventNotifier`` attribute. This +indicates to the server not to monitor changes of the attribute, but to +forward Event notifications from that node. + +During the creation of a MonitoredItem, the server may return changed +adjusted parameters. Check the returned ``UA_CreateMonitoredItemsResponse`` +to get the current parameters. + +.. code-block:: c + + + /* Provides default values for a new monitored item. */ + static UA_INLINE UA_MonitoredItemCreateRequest + UA_MonitoredItemCreateRequest_default(UA_NodeId nodeId) { + UA_MonitoredItemCreateRequest request; + UA_MonitoredItemCreateRequest_init(&request); + request.itemToMonitor.nodeId = nodeId; + request.itemToMonitor.attributeId = UA_ATTRIBUTEID_VALUE; + request.monitoringMode = UA_MONITORINGMODE_REPORTING; + request.requestedParameters.samplingInterval = 250; + request.requestedParameters.discardOldest = true; + request.requestedParameters.queueSize = 1; + return request; + } + +The clientHandle parameter cannot be set by the user, any value will be replaced +by the client before sending the request to the server. + +.. code-block:: c + + + /* Callback for the deletion of a MonitoredItem */ + typedef void (*UA_Client_DeleteMonitoredItemCallback) + (UA_Client *client, UA_UInt32 subId, void *subContext, + UA_UInt32 monId, void *monContext); + + /* Callback for DataChange notifications */ + typedef void (*UA_Client_DataChangeNotificationCallback) + (UA_Client *client, UA_UInt32 subId, void *subContext, + UA_UInt32 monId, void *monContext, + UA_DataValue *value); + + /* Callback for Event notifications */ + typedef void (*UA_Client_EventNotificationCallback) + (UA_Client *client, UA_UInt32 subId, void *subContext, + UA_UInt32 monId, void *monContext, + size_t nEventFields, UA_Variant *eventFields); + + /* Don't use to monitor the EventNotifier attribute */ + UA_CreateMonitoredItemsResponse + UA_Client_MonitoredItems_createDataChanges(UA_Client *client, + const UA_CreateMonitoredItemsRequest request, void **contexts, + UA_Client_DataChangeNotificationCallback *callbacks, + UA_Client_DeleteMonitoredItemCallback *deleteCallbacks); + + UA_StatusCode + UA_Client_MonitoredItems_createDataChanges_async(UA_Client *client, + const UA_CreateMonitoredItemsRequest request, void **contexts, + UA_Client_DataChangeNotificationCallback *callbacks, + UA_Client_DeleteMonitoredItemCallback *deleteCallbacks, + UA_ClientAsyncServiceCallback createCallback, + void *userdata, UA_UInt32 *requestId); + + UA_MonitoredItemCreateResult + UA_Client_MonitoredItems_createDataChange(UA_Client *client, + UA_UInt32 subscriptionId, + UA_TimestampsToReturn timestampsToReturn, + const UA_MonitoredItemCreateRequest item, + void *context, UA_Client_DataChangeNotificationCallback callback, + UA_Client_DeleteMonitoredItemCallback deleteCallback); + + /* Monitor the EventNotifier attribute only */ + UA_CreateMonitoredItemsResponse + UA_Client_MonitoredItems_createEvents(UA_Client *client, + const UA_CreateMonitoredItemsRequest request, void **contexts, + UA_Client_EventNotificationCallback *callback, + UA_Client_DeleteMonitoredItemCallback *deleteCallback); + + /* Monitor the EventNotifier attribute only */ + UA_StatusCode + UA_Client_MonitoredItems_createEvents_async(UA_Client *client, + const UA_CreateMonitoredItemsRequest request, void **contexts, + UA_Client_EventNotificationCallback *callbacks, + UA_Client_DeleteMonitoredItemCallback *deleteCallbacks, + UA_ClientAsyncServiceCallback createCallback, + void *userdata, UA_UInt32 *requestId); + + UA_MonitoredItemCreateResult + UA_Client_MonitoredItems_createEvent(UA_Client *client, + UA_UInt32 subscriptionId, + UA_TimestampsToReturn timestampsToReturn, + const UA_MonitoredItemCreateRequest item, + void *context, UA_Client_EventNotificationCallback callback, + UA_Client_DeleteMonitoredItemCallback deleteCallback); + + UA_DeleteMonitoredItemsResponse + UA_Client_MonitoredItems_delete(UA_Client *client, + const UA_DeleteMonitoredItemsRequest); + + UA_StatusCode + UA_Client_MonitoredItems_delete_async(UA_Client *client, + const UA_DeleteMonitoredItemsRequest request, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *requestId); + + UA_StatusCode + UA_Client_MonitoredItems_deleteSingle(UA_Client *client, + UA_UInt32 subscriptionId, UA_UInt32 monitoredItemId); + + /* The clientHandle parameter will be filled automatically */ + UA_ModifyMonitoredItemsResponse + UA_Client_MonitoredItems_modify(UA_Client *client, + const UA_ModifyMonitoredItemsRequest request); + + UA_StatusCode + UA_Client_MonitoredItems_modify_async(UA_Client *client, + const UA_ModifyMonitoredItemsRequest request, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *requestId); + +The following service calls go directly to the server. The MonitoredItem +settings are not stored in the client. + +.. code-block:: c + + + static UA_INLINE UA_SetMonitoringModeResponse + UA_Client_MonitoredItems_setMonitoringMode(UA_Client *client, + const UA_SetMonitoringModeRequest request) { + UA_SetMonitoringModeResponse response; + __UA_Client_Service(client, + &request, &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST], + &response, &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE]); + return response; + } + + static UA_INLINE UA_StatusCode + UA_Client_MonitoredItems_setMonitoringMode_async(UA_Client *client, + const UA_SetMonitoringModeRequest request, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *requestId) { + return __UA_Client_AsyncService(client, &request, + &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST], callback, + &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE], + userdata, requestId); + } + + static UA_INLINE UA_SetTriggeringResponse + UA_Client_MonitoredItems_setTriggering(UA_Client *client, + const UA_SetTriggeringRequest request) { + UA_SetTriggeringResponse response; + __UA_Client_Service(client, + &request, &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST], + &response, &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE]); + return response; + } + + static UA_INLINE UA_StatusCode + UA_Client_MonitoredItems_setTriggering_async(UA_Client *client, + const UA_SetTriggeringRequest request, + UA_ClientAsyncServiceCallback callback, + void *userdata, UA_UInt32 *requestId) { + return __UA_Client_AsyncService(client, &request, + &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST], callback, + &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE], + userdata, requestId); + } diff --git a/static/doc/v1.4.0/_static/common.rst b/static/doc/v1.4.0/_static/common.rst new file mode 100644 index 0000000000..10a9c5153c --- /dev/null +++ b/static/doc/v1.4.0/_static/common.rst @@ -0,0 +1,283 @@ +Common Definitions +================== + +Common definitions for Client, Server and PubSub. + +.. _attribute-id: + +Attribute Id +------------ +Every node in an OPC UA information model contains attributes depending on +the node type. Possible attributes are as follows: + +.. code-block:: c + + + typedef enum { + UA_ATTRIBUTEID_NODEID = 1, + UA_ATTRIBUTEID_NODECLASS = 2, + UA_ATTRIBUTEID_BROWSENAME = 3, + UA_ATTRIBUTEID_DISPLAYNAME = 4, + UA_ATTRIBUTEID_DESCRIPTION = 5, + UA_ATTRIBUTEID_WRITEMASK = 6, + UA_ATTRIBUTEID_USERWRITEMASK = 7, + UA_ATTRIBUTEID_ISABSTRACT = 8, + UA_ATTRIBUTEID_SYMMETRIC = 9, + UA_ATTRIBUTEID_INVERSENAME = 10, + UA_ATTRIBUTEID_CONTAINSNOLOOPS = 11, + UA_ATTRIBUTEID_EVENTNOTIFIER = 12, + UA_ATTRIBUTEID_VALUE = 13, + UA_ATTRIBUTEID_DATATYPE = 14, + UA_ATTRIBUTEID_VALUERANK = 15, + UA_ATTRIBUTEID_ARRAYDIMENSIONS = 16, + UA_ATTRIBUTEID_ACCESSLEVEL = 17, + UA_ATTRIBUTEID_USERACCESSLEVEL = 18, + UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL = 19, + UA_ATTRIBUTEID_HISTORIZING = 20, + UA_ATTRIBUTEID_EXECUTABLE = 21, + UA_ATTRIBUTEID_USEREXECUTABLE = 22, + UA_ATTRIBUTEID_DATATYPEDEFINITION = 23, + UA_ATTRIBUTEID_ROLEPERMISSIONS = 24, + UA_ATTRIBUTEID_USERROLEPERMISSIONS = 25, + UA_ATTRIBUTEID_ACCESSRESTRICTIONS = 26, + UA_ATTRIBUTEID_ACCESSLEVELEX = 27 + } UA_AttributeId; + +.. _access-level-mask: + +Access Level Masks +------------------ +The access level to a node is given by the following constants that are ANDed +with the overall access level. + +.. code-block:: c + + + #define UA_ACCESSLEVELMASK_READ (0x01u << 0u) + #define UA_ACCESSLEVELMASK_WRITE (0x01u << 1u) + #define UA_ACCESSLEVELMASK_HISTORYREAD (0x01u << 2u) + #define UA_ACCESSLEVELMASK_HISTORYWRITE (0x01u << 3u) + #define UA_ACCESSLEVELMASK_SEMANTICCHANGE (0x01u << 4u) + #define UA_ACCESSLEVELMASK_STATUSWRITE (0x01u << 5u) + #define UA_ACCESSLEVELMASK_TIMESTAMPWRITE (0x01u << 6u) + +.. _write-mask: + +Write Masks +----------- +The write mask and user write mask is given by the following constants that +are ANDed for the overall write mask. Part 3: 5.2.7 Table 2 + +.. code-block:: c + + + #define UA_WRITEMASK_ACCESSLEVEL (0x01u << 0u) + #define UA_WRITEMASK_ARRRAYDIMENSIONS (0x01u << 1u) + #define UA_WRITEMASK_BROWSENAME (0x01u << 2u) + #define UA_WRITEMASK_CONTAINSNOLOOPS (0x01u << 3u) + #define UA_WRITEMASK_DATATYPE (0x01u << 4u) + #define UA_WRITEMASK_DESCRIPTION (0x01u << 5u) + #define UA_WRITEMASK_DISPLAYNAME (0x01u << 6u) + #define UA_WRITEMASK_EVENTNOTIFIER (0x01u << 7u) + #define UA_WRITEMASK_EXECUTABLE (0x01u << 8u) + #define UA_WRITEMASK_HISTORIZING (0x01u << 9u) + #define UA_WRITEMASK_INVERSENAME (0x01u << 10u) + #define UA_WRITEMASK_ISABSTRACT (0x01u << 11u) + #define UA_WRITEMASK_MINIMUMSAMPLINGINTERVAL (0x01u << 12u) + #define UA_WRITEMASK_NODECLASS (0x01u << 13u) + #define UA_WRITEMASK_NODEID (0x01u << 14u) + #define UA_WRITEMASK_SYMMETRIC (0x01u << 15u) + #define UA_WRITEMASK_USERACCESSLEVEL (0x01u << 16u) + #define UA_WRITEMASK_USEREXECUTABLE (0x01u << 17u) + #define UA_WRITEMASK_USERWRITEMASK (0x01u << 18u) + #define UA_WRITEMASK_VALUERANK (0x01u << 19u) + #define UA_WRITEMASK_WRITEMASK (0x01u << 20u) + #define UA_WRITEMASK_VALUEFORVARIABLETYPE (0x01u << 21u) + #define UA_WRITEMASK_ACCESSLEVELEX (0x01u << 25u) + +.. _valuerank-defines: + +ValueRank +--------- +The following are the most common ValueRanks used for Variables, +VariableTypes and method arguments. ValueRanks higher than 3 are valid as +well (but less common). + +.. code-block:: c + + + #define UA_VALUERANK_SCALAR_OR_ONE_DIMENSION -3 + #define UA_VALUERANK_ANY -2 + #define UA_VALUERANK_SCALAR -1 + #define UA_VALUERANK_ONE_OR_MORE_DIMENSIONS 0 + #define UA_VALUERANK_ONE_DIMENSION 1 + #define UA_VALUERANK_TWO_DIMENSIONS 2 + #define UA_VALUERANK_THREE_DIMENSIONS 3 + +.. _eventnotifier: + +EventNotifier +------------- +The following are the available EventNotifier used for Nodes. +The EventNotifier Attribute is used to indicate if the Node can be used +to subscribe to Events or to read / write historic Events. +Part 3: 5.4 Table 10 + +.. code-block:: c + + + #define UA_EVENTNOTIFIER_SUBSCRIBE_TO_EVENT (0x01u << 0u) + #define UA_EVENTNOTIFIER_HISTORY_READ (0x01u << 2u) + #define UA_EVENTNOTIFIER_HISTORY_WRITE (0x01u << 3u) + +.. _rule-handling: + +Rule Handling +------------- + +The RuleHanding settings define how error cases that result from rules in the +OPC UA specification shall be handled. The rule handling can be softened, +e.g. to workaround misbehaving implementations or to mitigate the impact of +additional rules that are introduced in later versions of the OPC UA +specification. + +.. code-block:: c + + typedef enum { + UA_RULEHANDLING_DEFAULT = 0, + UA_RULEHANDLING_ABORT, /* Abort the operation and return an error code */ + UA_RULEHANDLING_WARN, /* Print a message in the logs and continue */ + UA_RULEHANDLING_ACCEPT, /* Continue and disregard the broken rule */ + } UA_RuleHandling; + +Order +----- + +The Order enum is used to establish an absolute ordering between elements. + +.. code-block:: c + + + typedef enum { + UA_ORDER_LESS = -1, + UA_ORDER_EQ = 0, + UA_ORDER_MORE = 1 + } UA_Order; + +Connection State +---------------- + +.. code-block:: c + + + typedef enum { + UA_CONNECTIONSTATE_CLOSED, /* The socket has been closed and the connection + * will be deleted */ + UA_CONNECTIONSTATE_OPENING, /* The socket is open, but the HEL/ACK handshake + * is not done */ + UA_CONNECTIONSTATE_ESTABLISHED,/* The socket is open and the connection + * configured */ + UA_CONNECTIONSTATE_CLOSING /* The socket is closing down */ + } UA_ConnectionState; + + + typedef enum { + UA_SECURECHANNELSTATE_CLOSED = 0, + UA_SECURECHANNELSTATE_REVERSE_LISTENING, + UA_SECURECHANNELSTATE_CONNECTING, + UA_SECURECHANNELSTATE_CONNECTED, + UA_SECURECHANNELSTATE_REVERSE_CONNECTED, + UA_SECURECHANNELSTATE_RHE_SENT, + UA_SECURECHANNELSTATE_HEL_SENT, + UA_SECURECHANNELSTATE_HEL_RECEIVED, + UA_SECURECHANNELSTATE_ACK_SENT, + UA_SECURECHANNELSTATE_ACK_RECEIVED, + UA_SECURECHANNELSTATE_OPN_SENT, + UA_SECURECHANNELSTATE_OPEN, + UA_SECURECHANNELSTATE_CLOSING, + } UA_SecureChannelState; + + typedef enum { + UA_SESSIONSTATE_CLOSED = 0, + UA_SESSIONSTATE_CREATE_REQUESTED, + UA_SESSIONSTATE_CREATED, + UA_SESSIONSTATE_ACTIVATE_REQUESTED, + UA_SESSIONSTATE_ACTIVATED, + UA_SESSIONSTATE_CLOSING + } UA_SessionState; + +Statistic Counters +------------------ + +The stack manages statistic counters for SecureChannels and Sessions. + +The Session layer counters are matching the counters of the +ServerDiagnosticsSummaryDataType that are defined in the OPC UA Part 5 +specification. The SecureChannel counters are not defined in the OPC UA spec, +but are harmonized with the Session layer counters if possible. + +.. code-block:: c + + + typedef enum { + UA_SHUTDOWNREASON_CLOSE = 0, + UA_SHUTDOWNREASON_REJECT, + UA_SHUTDOWNREASON_SECURITYREJECT, + UA_SHUTDOWNREASON_TIMEOUT, + UA_SHUTDOWNREASON_ABORT, + UA_SHUTDOWNREASON_PURGE + } UA_ShutdownReason; + + typedef struct { + size_t currentChannelCount; + size_t cumulatedChannelCount; + size_t rejectedChannelCount; + size_t channelTimeoutCount; /* only used by servers */ + size_t channelAbortCount; + size_t channelPurgeCount; /* only used by servers */ + } UA_SecureChannelStatistics; + + typedef struct { + size_t currentSessionCount; + size_t cumulatedSessionCount; + size_t securityRejectedSessionCount; /* only used by servers */ + size_t rejectedSessionCount; + size_t sessionTimeoutCount; /* only used by servers */ + size_t sessionAbortCount; /* only used by servers */ + } UA_SessionStatistics; + +Lifecycle States +---------------- + +Generic lifecycle states. The STOPPING state indicates that the lifecycle is +being terminated. But it might take time to (asynchronously) perform a +graceful shutdown. + +.. code-block:: c + + + typedef enum { + UA_LIFECYCLESTATE_STOPPED = 0, + UA_LIFECYCLESTATE_STARTED, + UA_LIFECYCLESTATE_STOPPING + } UA_LifecycleState; + +Forward Declarations +-------------------- +Opaque pointers used in Client, Server and PubSub. + +.. code-block:: c + + + struct UA_Server; + typedef struct UA_Server UA_Server; + + struct UA_ServerConfig; + typedef struct UA_ServerConfig UA_ServerConfig; + + typedef void (*UA_ServerCallback)(UA_Server *server, void *data); + + struct UA_Client; + typedef struct UA_Client UA_Client; + +.. include:: util.rst diff --git a/static/doc/v1.4.0/_static/conf.py b/static/doc/v1.4.0/_static/conf.py new file mode 100644 index 0000000000..f80430af7e --- /dev/null +++ b/static/doc/v1.4.0/_static/conf.py @@ -0,0 +1,333 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# -*- coding: utf-8 -*- +# +# open62541 documentation build configuration file, created by +# sphinx-quickstart on Sat May 23 19:39:37 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex +import sphinx_rtd_theme + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx.ext.graphviz'] + +numfig = True + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'toc' + +# General information about the project. +project = u'open62541' +author = u'The open62541 authors' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = "1.4" +# The full version, including alpha/beta/rc tags. +release = "1.4.0" +# The full version, including alpha/beta/rc tags. + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = "en" + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +#exclude_patterns = ["client_config.rst", "server_config.rst"] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = "open62541_html.png" + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['.'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'doc/open62541doc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +'papersize': 'a4paper', + +# Font settings +'fontpkg': r""" +\usepackage[scaled=.98,varqu,varl]{zi4} +\usepackage[default,semibold]{sourcesanspro} +""", + +# The font size ('10pt', '11pt' or '12pt'). +'pointsize': '11pt', + +# Clean up the header and footer +'preamble': r""" +\fancypagestyle{normal}{ + \fancyhf{} + \fancyfoot[RO,LE]{\thepage} + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{0pt} +} +\fancypagestyle{plain}{ + \fancyhf{} + \fancyfoot[RO,LE]{\thepage} + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{0pt} +}""", + +'maketitle': r""" + \makeatletter + \begin{titlepage}% + \begingroup % for PDF information dictionary + \def\endgraf{ }\def\and{\& }% + \pdfstringdefDisableCommands{\def\\{, }}% overwrite hyperref setup + \hypersetup{pdfauthor={\@author}, pdftitle={\@title}}% + \endgroup + \begin{flushright}% + \vspace*{2\baselineskip} + \begin{minipage}{.75\linewidth} + \sphinxlogo + \end{minipage} \bigskip \par + \py@HeaderFamily + {\Huge \@title \par} + {\itshape\LARGE \py@release\releaseinfo \par} + \bigskip + {\large \@date \par}% + \end{flushright} + \end{titlepage}% + \if@openright\cleardoublepage\else\clearpage\fi +\makeatother +""", + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'open62541.tex', u'open62541 Documentation', + u'The open62541 authors', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +latex_logo = "open62541.png" + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'open62541', u'open62541 Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'open62541', u'open62541 Documentation', + author, 'open62541', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False diff --git a/static/doc/v1.4.0/_static/core_concepts.rst b/static/doc/v1.4.0/_static/core_concepts.rst new file mode 100644 index 0000000000..1e7e00726a --- /dev/null +++ b/static/doc/v1.4.0/_static/core_concepts.rst @@ -0,0 +1,765 @@ +.. _introduction: + +Core Concepts of OPC UA +======================= + +In one sentence, OPC UA (ISO 62541) defines a framework for object-oriented +information models (typically representing a physical device) that live in an +OPC UA server and a protocol with which a client can interact with the +information model over the network (read and write variables, call methods, +instantiate and delete objects, subscribe to change notifications, and so on). + +This Section introduces the core concepts of OPC UA. For the full specification +see the OPC UA standard at `https://reference.opcfoundation.org/ +`_. + +.. _protocol: + +Protocol +-------- + +We focus on the TCP-based binary protocol since it is by far the most common +transport layer for OPC UA. The general concepts also translate to HTTP and +SOAP-based communication defined in the standard. Communication in OPC UA is +best understood by starting with the following key principles: + +Request / Response + All communication is based on the Request/Response pattern. Only clients can + send a request to a server. And servers can only send responses to a matching + request. Often the server is hosted close to a (physical) device, such as a + sensor or a machine tool. + +Asynchronous Responses + A server does not have to immediately respond to requests and responses may be + sent in a different order. This keeps the server responsive when it takes time + until a specific request has been processed (e.g. a method call or when + reading from a sensor with delay). Subscriptions (push-notifications) are + implemented via special requests where the response is delayed until a + notification is published. + +.. note:: + *OPC UA PubSub* (Part 14 of the standard) is an extension for the integration + of many-to-many communication with OPC UA. PubSub does not use the + client-server protocol. Rather, OPC UA PubSub integrates with either existing + broker-based protocols such as MQTT, UDP-multicast or Ethernet-based + communication. Typically an OPC UA server (accessed via the client-server + protocol) is used to configured PubSub communication. + + Note that the client-server protocol also supports Subscriptions for + one-to-one communication and does not depend on PubSub for this feature. + +A client-server connection for the OPC UA binary protocol consists of three +nested levels: The stateful TCP connection, a SecureChannel and the Session. For +full details, see Part 6 of the OPC UA standard. + +TCP Connection + The TCP connection is opened to the corresponding hostname and port with an + initial handshake of HEL/ACK messages. The handshake establishes the basic + settings of the connection, such as the maximum message length. The *Reverse + Connect* extension of OPC UA allows the server to initiate the underlying TCP + connection. + +SecureChannel + SecureChannels are created on top of the raw TCP connection. A SecureChannel + is established with an *OpenSecureChannel* request and response message pair. + **Attention!** Even though a SecureChannel is mandatory, encryption might + still be disabled. The *SecurityMode* of a SecureChannel can be either + ``None``, ``Sign``, or ``SignAndEncrypt``. As of version 0.2 of open62541, + message signing and encryption is still under ongoing development. + + With message signing or encryption enabled, the *OpenSecureChannel* messages + are encrypted using an asymmetric encryption algorithm (public-key + cryptography) [#key-mgmnt]_. As part of the *OpenSecureChannel* messages, + client and server establish a common secret over an initially unsecure + channel. For subsequent messages, the common secret is used for symmetric + encryption, which has the advantage of being much faster. + + Different *SecurityPolicies* -- defined in part 7 of the OPC UA standard -- + specify the algorithms for asymmetric and symmetric encryption, encryption key + lengths, hash functions for message signing, and so on. Example + SecurityPolicies are ``None`` for transmission of cleartext and + ``Basic256Sha256`` which mandates a variant of RSA with SHA256 certificate + hashing for asymmetric encryption and AES256 for symmetric encryption. + + The possible SecurityPolicies of a server are described with a list of + *Endpoints*. An endpoint jointly defines the SecurityMode, SecurityPolicy and + means for authenticating a session (discussed in the next section) in order to + connect to a certain server. The *GetEndpoints* service returns a list of + available endpoints. This service can usually be invoked without a session and + from an unencrypted SecureChannel. This allows clients to first discover + available endpoints and then use an appropriate SecurityPolicy that might be + required to open a session. + +Session + Sessions are created on top of a SecureChannel. This ensures that users may + authenticate without sending their credentials, such as username and password, + in cleartext. Currently defined authentication mechanisms are anonymous login, + username/password, Kerberos and x509 certificates. The latter requires that + the request message is accompanied by a signature to prove that the sender is + in possession of the private key with which the certificate was created. + + There are two message exchanges required to establish a session: + *CreateSession* and *ActicateSession*. The ActivateSession service can be used + to switch an existing session to a different SecureChannel. This is important, + for example when the connection broke down and the existing session is + reused with a new SecureChannel. + +.. [#key-mgmnt] This entails that the client and server exchange so-called + public keys. The public keys might come with a certificate from a key-signing + authority or be verified against an external key repository. But we will not + discuss certificate management in detail in this section. + +Structure of a protocol message +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Consider the example OPC UA binary conversation in Figure +:numref:`ua-wireshark`, recorded and displayed with `Wireshark +`_. + +.. _ua-wireshark: + +.. figure:: ua-wireshark.png + :figwidth: 100 % + :alt: OPC UA conversation in Wireshark + + OPC UA conversation displayed in Wireshark + +The top part of the Wireshark window shows the messages from the conversation in +order. The green line contains the applied filter. Here, we want to see the OPC +UA protocol messages only. The first messages (from TCP packets 49 to 56) show +the client opening an unencrypted SecureChannel and retrieving the server's +endpoints. Then, starting with packet 63, a new connection and SecureChannel are +created in conformance with one of the endpoints. On top of this SecureChannel, +the client can then create and activate a session. The following *ReadRequest* +message is selected and covered in more detail in the bottom windows. + +The bottom left window shows the structure of the selected *ReadRequest* +message. The purpose of the message is invoking the *Read* :ref:`service +`. The message is structured into a header and a message body. Note +that we do not consider encryption or signing of messages here. + +Message Header + As stated before, OPC UA defines an asynchronous protocol. So responses may be + out of order. The message header contains some basic information, such as the + length of the message, as well as necessary information to relate messages to + a SecureChannel and each request to the corresponding response. "Chunking" + refers to the splitting and reassembling of messages that are longer than the + maximum network packet size. + +Message Body + Every OPC UA :ref:`service ` has a signature in the form of a + request and response data structure. These are defined according to the OPC UA + protocol :ref:`type system `. See especially the :ref:`auto-generated + type definitions` for the data types corresponding to service + requests and responses. The message body begins with the identifier of the + following data type. Then, the main payload of the message follows. + +The bottom right window shows the binary payload of the selected *ReadRequest* +message. The message header is highlighted in light-grey. The message body in +blue highlighting shows the encoded *ReadRequest* data structure. + +.. _services: + +Services +-------- + +In OPC UA, all communication is based on service calls, each consisting of a +request and a response message. These messages are defined as data structures +with a binary encoding and listed in :ref:`generated-types`. Since all +Services are pre-defined in the standard, they cannot be modified by the +user. But you can use the :ref:`Call ` service to invoke +user-defined methods on the server. + +Please refer to the :ref:`client` and :ref:`server` API where the services +are exposed to end users. Please see part 4 of the OPC UA standard for the +authoritative definition of the services and their behaviour. + +Discovery Service Set +~~~~~~~~~~~~~~~~~~~~~ +This Service Set defines Services used to discover the Endpoints implemented +by a Server and to read the security configuration for those Endpoints. + +FindServers Service + Returns the Servers known to a Server or Discovery Server. The Client may + reduce the number of results returned by specifying filter criteria + +GetEndpoints Service + Returns the Endpoints supported by a Server and all of the configuration + information required to establish a SecureChannel and a Session. + +FindServersOnNetwork Service + Returns the Servers known to a Discovery Server. Unlike FindServer, + this Service is only implemented by Discovery Servers. It additionally + returns servers which may have been detected through Multicast. + +RegisterServer + Registers a remote server in the local discovery service. + +RegisterServer2 + This Service allows a Server to register its DiscoveryUrls and capabilities + with a Discovery Server. It extends the registration information from + RegisterServer with information necessary for FindServersOnNetwork. + +SecureChannel Service Set +~~~~~~~~~~~~~~~~~~~~~~~~~ +This Service Set defines Services used to open a communication channel that +ensures the confidentiality and Integrity of all Messages exchanged with the +Server. + +OpenSecureChannel Service + Open or renew a SecureChannel that can be used to ensure Confidentiality and + Integrity for Message exchange during a Session. + +CloseSecureChannel Service + Used to terminate a SecureChannel. + +Session Service Set + This Service Set defines Services for an application layer connection + establishment in the context of a Session. + +CreateSession Service + Used by an OPC UA Client to create a Session and the Server returns two + values which uniquely identify the Session. The first value is the sessionId + which is used to identify the Session in the audit logs and in the Server's + address space. The second is the authenticationToken which is used to + associate an incoming request with a Session. + +ActivateSession + Used by the Client to submit its SoftwareCertificates to the Server for + validation and to specify the identity of the user associated with the + Session. This Service request shall be issued by the Client before it issues + any other Service request after CreateSession. Failure to do so shall cause + the Server to close the Session. + +CloseSession + Used to terminate a Session. + +Cancel Service + Used to cancel outstanding Service requests. Successfully cancelled service + requests shall respond with Bad_RequestCancelledByClient. + +NodeManagement Service Set +~~~~~~~~~~~~~~~~~~~~~~~~~~ +This Service Set defines Services to add and delete AddressSpace Nodes and +References between them. All added Nodes continue to exist in the +AddressSpace even if the Client that created them disconnects from the +Server. + +AddNodes Service + Used to add one or more Nodes into the AddressSpace hierarchy. + If the type or one of the supertypes has any HasInterface references + (see OPC 10001-7 - Amendment 7, 4.9.2), the child nodes of the interfaces + are added to the new object. + +AddReferences Service + Used to add one or more References to one or more Nodes. + +DeleteNodes Service + Used to delete one or more Nodes from the AddressSpace. + +DeleteReferences + Used to delete one or more References of a Node. + +.. _view-services: + +View Service Set +~~~~~~~~~~~~~~~~ +Clients use the browse Services of the View Service Set to navigate through +the AddressSpace or through a View which is a subset of the AddressSpace. + +Browse Service + Used to discover the References of a specified Node. The browse can be + further limited by the use of a View. This Browse Service also supports a + primitive filtering capability. + +BrowseNext Service + Used to request the next set of Browse or BrowseNext response information + that is too large to be sent in a single response. "Too large" in this + context means that the Server is not able to return a larger response or that + the number of results to return exceeds the maximum number of results to + return that was specified by the Client in the original Browse request. + +TranslateBrowsePathsToNodeIds Service + Used to translate textual node paths to their respective ids. + +RegisterNodes Service + Used by Clients to register the Nodes that they know they will access + repeatedly (e.g. Write, Call). It allows Servers to set up anything needed so + that the access operations will be more efficient. + +UnregisterNodes Service + This Service is used to unregister NodeIds that have been obtained via the + RegisterNodes service. + +Query Service Set +~~~~~~~~~~~~~~~~~ +This Service Set is used to issue a Query to a Server. OPC UA Query is +generic in that it provides an underlying storage mechanism independent Query +capability that can be used to access a wide variety of OPC UA data stores +and information management systems. OPC UA Query permits a Client to access +data maintained by a Server without any knowledge of the logical schema used +for internal storage of the data. Knowledge of the AddressSpace is +sufficient. + +QueryFirst Service (not implemented) + This Service is used to issue a Query request to the Server. + +QueryNext Service (not implemented) + This Service is used to request the next set of QueryFirst or QueryNext + response information that is too large to be sent in a single response. + +Attribute Service Set +~~~~~~~~~~~~~~~~~~~~~ +This Service Set provides Services to access Attributes that are part of +Nodes. + +Read Service + Used to read attributes of nodes. For constructed attribute values whose + elements are indexed, such as an array, this Service allows Clients to read + the entire set of indexed values as a composite, to read individual elements + or to read ranges of elements of the composite. + +Write Service + Used to write attributes of nodes. For constructed attribute values whose + elements are indexed, such as an array, this Service allows Clients to write + the entire set of indexed values as a composite, to write individual elements + or to write ranges of elements of the composite. + +HistoryRead Service + Used to read historical values or Events of one or more Nodes. Servers may + make historical values available to Clients using this Service, although the + historical values themselves are not visible in the AddressSpace. + +HistoryUpdate Service + Used to update historical values or Events of one or more Nodes. Several + request parameters indicate how the Server is to update the historical value + or Event. Valid actions are Insert, Replace or Delete. + +.. _method-services: + +Method Service Set +~~~~~~~~~~~~~~~~~~ +The Method Service Set defines the means to invoke methods. A method shall be +a component of an Object. See the section on :ref:`MethodNodes ` +for more information. + +Call Service + Used to call (invoke) a methods. Each method call is invoked within the + context of an existing Session. If the Session is terminated, the results of + the method's execution cannot be returned to the Client and are discarded. + +MonitoredItem Service Set +~~~~~~~~~~~~~~~~~~~~~~~~~ +Clients define MonitoredItems to subscribe to data and Events. Each +MonitoredItem identifies the item to be monitored and the Subscription to use +to send Notifications. The item to be monitored may be any Node Attribute. + +CreateMonitoredItems Service + Used to create and add one or more MonitoredItems to a Subscription. A + MonitoredItem is deleted automatically by the Server when the Subscription is + deleted. Deleting a MonitoredItem causes its entire set of triggered item + links to be deleted, but has no effect on the MonitoredItems referenced by + the triggered items. + +DeleteMonitoredItems Service + Used to remove one or more MonitoredItems of a Subscription. When a + MonitoredItem is deleted, its triggered item links are also deleted. + +ModifyMonitoredItems Service + Used to modify MonitoredItems of a Subscription. Changes to the MonitoredItem + settings shall be applied immediately by the Server. They take effect as soon + as practical but not later than twice the new revisedSamplingInterval. + + Illegal request values for parameters that can be revised do not generate + errors. Instead the server will choose default values and indicate them in + the corresponding revised parameter. + +SetMonitoringMode Service + Used to set the monitoring mode for one or more MonitoredItems of a + Subscription. + +SetTriggering Service + Used to create and delete triggering links for a triggering item. + +Subscription Service Set +~~~~~~~~~~~~~~~~~~~~~~~~ +Subscriptions are used to report Notifications to the Client. + +CreateSubscription Service + Used to create a Subscription. Subscriptions monitor a set of MonitoredItems + for Notifications and return them to the Client in response to Publish + requests. + +ModifySubscription Service + Used to modify a Subscription. + +SetPublishingMode Service + Used to enable sending of Notifications on one or more Subscriptions. + +Publish Service + Used for two purposes. First, it is used to acknowledge the receipt of + NotificationMessages for one or more Subscriptions. Second, it is used to + request the Server to return a NotificationMessage or a keep-alive + Message. + +Republish Service + Requests the Subscription to republish a NotificationMessage from its + retransmission queue. + +DeleteSubscriptions Service + Invoked to delete one or more Subscriptions that belong to the Client's + Session. + +TransferSubscription Service + Used to transfer a Subscription and its MonitoredItems from one Session to + another. For example, a Client may need to reopen a Session and then transfer + its Subscriptions to that Session. It may also be used by one Client to take + over a Subscription from another Client by transferring the Subscription to + its Session. + +.. _information-modelling: + +Information Modelling +--------------------- + +Information modelling in OPC UA combines concepts from object-orientation and +semantic modelling. At the core, an OPC UA information model is a graph +consisting of Nodes and References between them. + +Nodes + There are eight possible NodeClasses for Nodes (Variable, VariableType, + Object, ObjectType, ReferenceType, DataType, Method, View). The NodeClass + defines the attributes a Node can have. + +References + References are links between Nodes. References are typed (refer to a + ReferenceType) and directed. + +The original source for the following information is Part 3 of the OPC UA +specification (https://reference.opcfoundation.org/Core/Part3/). + +Each Node is identified by a unique (within the server) :ref:`nodeid` and +carries different attributes depending on the NodeClass. These attributes can be +read (and sometimes also written) via the OPC UA protocol. The protocol further +allows the creation and deletion of Nodes and References at runtime. But this is +not supported by all servers. + +Reference are triples of the form ``(source-nodeid, referencetype-nodeid, +target-nodeid)``. (The ``target-nodeid`` is actually an :ref:`expandednodeid` +which is a NodeId that can additionally point to a remote server.) An example +reference between nodes is a ``hasTypeDefinition`` reference between a Variable +and its VariableType. Some ReferenceTypes are *hierarchical* and must not form +*directed loops*. See the section on :ref:`ReferenceTypes ` +for more details on possible references and their semantics. + +The following table (adapted from Part 3 of the specification) shows which +attributes are mandatory (``M``), optional (``O``) or not defined for each +NodeClass. In open62541 all optional attributes are defined - with sensible +defaults if users do not change them. + +.. table:: Node attributes for the different NodeClasses + :width: 100% + + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | Attribute | DataType | Variable | Variable­Type | Object | Object­Type | Reference­Type | Data­Type | Method | View | + +=========================+=============================+==========+===============+========+=============+================+===========+========+=======+ + | NodeId | NodeId | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | NodeClass | NodeClass | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | BrowseName | QualifiedName | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | DisplayName | LocalizedText | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | ``M`` | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | Description | LocalizedText | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | WriteMask | UInt32 | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | + | | (:ref:`write-mask`) | | | | | | | ``M`` | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | UserWriteMask | UInt32 | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | ``O`` | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | IsAbstract | Boolean | | ``M`` | | ``M`` | ``M`` | ``M`` | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | Symmetric | Boolean | | | | | ``M`` | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | InverseName | LocalizedText | | | | | ``O`` | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | ContainsNoLoops | Boolean | | | | | | | | ``M`` | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | EventNotifier | Byte | | | ``M`` | | | | | ``M`` | + | | (:ref:`eventnotifier`) | | | | | | | ``M`` | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | Value | Variant | ``M`` | ``O`` | | | | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | DataType | NodeId | ``M`` | ``M`` | | | | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | ValueRank | Int32 | ``M`` | ``M`` | | | | | | | + | | (:ref:`valuerank-defines`) | | | | | | | ``M`` | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | ArrayDimensions | [UInt32] | ``O`` | ``O`` | | | | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | AccessLevel | Byte | ``M`` | | | | | | | | + | | (:ref:`access-level-mask`) | | | | | | | ``M`` | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | UserAccessLevel | Byte | ``M`` | | | | | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | MinimumSamplingInterval | Double | ``O`` | | | | | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | Historizing | Boolean | ``M`` | | | | | | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | Executable | Boolean | | | | | | | ``M`` | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | UserExecutable | Boolean | | | | | | | ``M`` | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + | DataTypeDefinition | DataTypeDefinition | | | | | | ``O`` | | | + +-------------------------+-----------------------------+----------+---------------+--------+-------------+----------------+-----------+--------+-------+ + +Each attribute is referenced by a numerical :ref:`attribute-id`. + +Some numerical attributes are used as bitfields or come with special semantics. +In particular, see the sections on :ref:`access-level-mask`, :ref:`write-mask`, +:ref:`valuerank-defines` and :ref:`eventnotifier`. + +New attributes in the standard that are still unsupported in open62541 are +RolePermissions, UserRolePermissions, AccessRestrictions and AccessLevelEx. + +VariableNode +~~~~~~~~~~~~ + +Variables store values in a :ref:`datavalue` together with +metadata for introspection. Most notably, the attributes data type, value +rank and array dimensions constrain the possible values the variable can take +on. + +Variables come in two flavours: properties and datavariables. Properties are +related to a parent with a ``hasProperty`` reference and may not have child +nodes themselves. Datavariables may contain properties (``hasProperty``) and +also datavariables (``hasComponents``). + +All variables are instances of some :ref:`variabletypenode` in return +constraining the possible data type, value rank and array dimensions +attributes. + +Data Type +^^^^^^^^^ + +The (scalar) data type of the variable is constrained to be of a specific +type or one of its children in the type hierarchy. The data type is given as +a NodeId pointing to a :ref:`datatypenode` in the type hierarchy. See the +Section :ref:`datatypenode` for more details. + +If the data type attribute points to ``UInt32``, then the value attribute +must be of that exact type since ``UInt32`` does not have children in the +type hierarchy. If the data type attribute points ``Number``, then the type +of the value attribute may still be ``UInt32``, but also ``Float`` or +``Byte``. + +Consistency between the data type attribute in the variable and its +:ref:`VariableTypeNode` is ensured. + +ValueRank +^^^^^^^^^ + +This attribute indicates whether the value attribute of the variable is an +array and how many dimensions the array has. It may have the following +values: + +- ``n >= 1``: the value is an array with the specified number of dimensions +- ``n = 0``: the value is an array with one or more dimensions +- ``n = -1``: the value is a scalar +- ``n = -2``: the value can be a scalar or an array with any number of dimensions +- ``n = -3``: the value can be a scalar or a one dimensional array + +Some helper macros for ValueRanks are defined :ref:`here `. + +The consistency between the value rank attribute of a VariableNode and its +:ref:`variabletypenode` is tested within the server. + +Array Dimensions +^^^^^^^^^^^^^^^^ + +If the value rank permits the value to be a (multi-dimensional) array, the +exact length in each dimensions can be further constrained with this +attribute. + +- For positive lengths, the variable value must have a dimension length less + or equal to the array dimension length defined in the VariableNode. +- The dimension length zero is a wildcard and the actual value may have any + length in this dimension. Note that a value (variant) must have array + dimensions that are positive (not zero). + +Consistency between the array dimensions attribute in the variable and its +:ref:`variabletypenode` is ensured. However, we consider that an array of +length zero (can also be a null-array with undefined length) has implicit +array dimensions ``[0,0,...]``. These always match the required array +dimensions. + +.. _variabletypenode: + +VariableTypeNode +~~~~~~~~~~~~~~~~ + +VariableTypes are used to provide type definitions for variables. +VariableTypes constrain the data type, value rank and array dimensions +attributes of variable instances. Furthermore, instantiating from a specific +variable type may provide semantic information. For example, an instance from +``MotorTemperatureVariableType`` is more meaningful than a float variable +instantiated from ``BaseDataVariable``. + +ObjectNode +~~~~~~~~~~ + +Objects are used to represent systems, system components, real-world objects +and software objects. Objects are instances of an :ref:`object type` +and may contain variables, methods and further objects. + +.. _objecttypenode: + +ObjectTypeNode +~~~~~~~~~~~~~~ + +ObjectTypes provide definitions for Objects. Abstract objects cannot be +instantiated. See :ref:`node-lifecycle` for the use of constructor and +destructor callbacks. + +.. _referencetypenode: + +ReferenceTypeNode +~~~~~~~~~~~~~~~~~ + +Each reference between two nodes is typed with a ReferenceType that gives +meaning to the relation. The OPC UA standard defines a set of ReferenceTypes +as a mandatory part of OPC UA information models. + +- Abstract ReferenceTypes cannot be used in actual references and are only + used to structure the ReferenceTypes hierarchy +- Symmetric references have the same meaning from the perspective of the + source and target node + +The figure below shows the hierarchy of the standard ReferenceTypes (arrows +indicate a ``hasSubType`` relation). Refer to Part 3 of the OPC UA +specification for the full semantics of each ReferenceType. + +.. graphviz:: + + digraph tree { + + node [height=0, shape=box, fillcolor="#E5E5E5", concentrate=true] + + references [label="References\n(Abstract, Symmetric)"] + hierarchical_references [label="HierarchicalReferences\n(Abstract)"] + references -> hierarchical_references + + nonhierarchical_references [label="NonHierarchicalReferences\n(Abstract, Symmetric)"] + references -> nonhierarchical_references + + haschild [label="HasChild\n(Abstract)"] + hierarchical_references -> haschild + + aggregates [label="Aggregates\n(Abstract)"] + haschild -> aggregates + + organizes [label="Organizes"] + hierarchical_references -> organizes + + hascomponent [label="HasComponent"] + aggregates -> hascomponent + + hasorderedcomponent [label="HasOrderedComponent"] + hascomponent -> hasorderedcomponent + + hasproperty [label="HasProperty"] + aggregates -> hasproperty + + hassubtype [label="HasSubtype"] + haschild -> hassubtype + + hasmodellingrule [label="HasModellingRule"] + nonhierarchical_references -> hasmodellingrule + + hastypedefinition [label="HasTypeDefinition"] + nonhierarchical_references -> hastypedefinition + + hasencoding [label="HasEncoding"] + nonhierarchical_references -> hasencoding + + hasdescription [label="HasDescription"] + nonhierarchical_references -> hasdescription + + haseventsource [label="HasEventSource"] + hierarchical_references -> haseventsource + + hasnotifier [label="HasNotifier"] + hierarchical_references -> hasnotifier + + generatesevent [label="GeneratesEvent"] + nonhierarchical_references -> generatesevent + + alwaysgeneratesevent [label="AlwaysGeneratesEvent"] + generatesevent -> alwaysgeneratesevent + + {rank=same hierarchical_references nonhierarchical_references} + {rank=same generatesevent haseventsource hasmodellingrule + hasencoding hassubtype} + {rank=same alwaysgeneratesevent hasproperty} + + } + +The ReferenceType hierarchy can be extended with user-defined ReferenceTypes. +Many Companion Specifications for OPC UA define new ReferenceTypes to be used +in their domain of interest. + +For the following example of custom ReferenceTypes, we attempt to model the +structure of a technical system. For this, we introduce two custom +ReferenceTypes. First, the hierarchical ``contains`` ReferenceType indicates +that a system (represented by an OPC UA object) contains a component (or +subsystem). This gives rise to a tree-structure of containment relations. For +example, the motor (object) is contained in the car and the crankshaft is +contained in the motor. Second, the symmetric ``connectedTo`` ReferenceType +indicates that two components are connected. For example, the motor's +crankshaft is connected to the gear box. Connections are independent of the +containment hierarchy and can induce a general graph-structure. Further +subtypes of ``connectedTo`` could be used to differentiate between physical, +electrical and information related connections. A client can then learn the +layout of a (physical) system represented in an OPC UA information model +based on a common understanding of just two custom reference types. + +.. _datatypenode: + +DataTypeNode +~~~~~~~~~~~~ + +DataTypes represent simple and structured data types. DataTypes may contain +arrays. But they always describe the structure of a single instance. In +open62541, DataTypeNodes in the information model hierarchy are matched to +``UA_DataType`` type descriptions for :ref:`generic-types` via their NodeId. + +Abstract DataTypes (e.g. ``Number``) cannot be the type of actual values. +They are used to constrain values to possible child DataTypes (e.g. +``UInt32``). + +.. _methodnode: + +MethodNode +~~~~~~~~~~ + +Methods define callable functions and are invoked using the :ref:`Call ` +service. MethodNodes may have special properties (variable +children with a ``hasProperty`` reference) with the :ref:`qualifiedname` ``(0, "InputArguments")`` +and ``(0, "OutputArguments")``. The input and output +arguments are both described via an array of ``UA_Argument``. While the Call +service uses a generic array of :ref:`variant` for input and output, the +actual argument values are checked to match the signature of the MethodNode. + +Note that the same MethodNode may be referenced from several objects (and +object types). For this, the NodeId of the method *and of the object +providing context* is part of a Call request message. + +ViewNode +~~~~~~~~ + +Each View defines a subset of the Nodes in the AddressSpace. Views can be +used when browsing an information model to focus on a subset of nodes and +references only. ViewNodes can be created and be interacted with. But their +use in the :ref:`Browse` service is currently unsupported in +open62541. diff --git a/static/doc/v1.4.0/_static/css/badge_only.css b/static/doc/v1.4.0/_static/css/badge_only.css new file mode 100644 index 0000000000..c718cee441 --- /dev/null +++ b/static/doc/v1.4.0/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/static/doc/v1.4.0/_static/css/fonts/Roboto-Slab-Bold.woff b/static/doc/v1.4.0/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 0000000000..6cb6000018 Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/static/doc/v1.4.0/_static/css/fonts/Roboto-Slab-Bold.woff2 b/static/doc/v1.4.0/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 0000000000..7059e23142 Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/static/doc/v1.4.0/_static/css/fonts/Roboto-Slab-Regular.woff b/static/doc/v1.4.0/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 0000000000..f815f63f99 Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/static/doc/v1.4.0/_static/css/fonts/Roboto-Slab-Regular.woff2 b/static/doc/v1.4.0/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 0000000000..f2c76e5bda Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/static/doc/v1.4.0/_static/css/fonts/fontawesome-webfont.eot b/static/doc/v1.4.0/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000000..e9f60ca953 Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/static/doc/v1.4.0/_static/css/fonts/fontawesome-webfont.svg b/static/doc/v1.4.0/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 0000000000..855c845e53 --- /dev/null +++ b/static/doc/v1.4.0/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/doc/v1.4.0/_static/css/fonts/fontawesome-webfont.ttf b/static/doc/v1.4.0/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000000..35acda2fa1 Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/static/doc/v1.4.0/_static/css/fonts/fontawesome-webfont.woff b/static/doc/v1.4.0/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000000..400014a4b0 Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/static/doc/v1.4.0/_static/css/fonts/fontawesome-webfont.woff2 b/static/doc/v1.4.0/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000000..4d13fc6040 Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/static/doc/v1.4.0/_static/css/fonts/lato-bold-italic.woff b/static/doc/v1.4.0/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 0000000000..88ad05b9ff Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/lato-bold-italic.woff differ diff --git a/static/doc/v1.4.0/_static/css/fonts/lato-bold-italic.woff2 b/static/doc/v1.4.0/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 0000000000..c4e3d804b5 Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/static/doc/v1.4.0/_static/css/fonts/lato-bold.woff b/static/doc/v1.4.0/_static/css/fonts/lato-bold.woff new file mode 100644 index 0000000000..c6dff51f06 Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/lato-bold.woff differ diff --git a/static/doc/v1.4.0/_static/css/fonts/lato-bold.woff2 b/static/doc/v1.4.0/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 0000000000..bb195043cf Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/lato-bold.woff2 differ diff --git a/static/doc/v1.4.0/_static/css/fonts/lato-normal-italic.woff b/static/doc/v1.4.0/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 0000000000..76114bc033 Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/lato-normal-italic.woff differ diff --git a/static/doc/v1.4.0/_static/css/fonts/lato-normal-italic.woff2 b/static/doc/v1.4.0/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 0000000000..3404f37e2e Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/static/doc/v1.4.0/_static/css/fonts/lato-normal.woff b/static/doc/v1.4.0/_static/css/fonts/lato-normal.woff new file mode 100644 index 0000000000..ae1307ff5f Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/lato-normal.woff differ diff --git a/static/doc/v1.4.0/_static/css/fonts/lato-normal.woff2 b/static/doc/v1.4.0/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 0000000000..3bf9843328 Binary files /dev/null and b/static/doc/v1.4.0/_static/css/fonts/lato-normal.woff2 differ diff --git a/static/doc/v1.4.0/_static/css/theme.css b/static/doc/v1.4.0/_static/css/theme.css new file mode 100644 index 0000000000..19a446a0e7 --- /dev/null +++ b/static/doc/v1.4.0/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/static/doc/v1.4.0/_static/doctools.js b/static/doc/v1.4.0/_static/doctools.js new file mode 100644 index 0000000000..d06a71d751 --- /dev/null +++ b/static/doc/v1.4.0/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/static/doc/v1.4.0/_static/documentation_options.js b/static/doc/v1.4.0/_static/documentation_options.js new file mode 100644 index 0000000000..55bfe5a249 --- /dev/null +++ b/static/doc/v1.4.0/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '1.4.0', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/static/doc/v1.4.0/_static/file.png b/static/doc/v1.4.0/_static/file.png new file mode 100644 index 0000000000..a858a410e4 Binary files /dev/null and b/static/doc/v1.4.0/_static/file.png differ diff --git a/static/doc/v1.4.0/_static/graphviz.css b/static/doc/v1.4.0/_static/graphviz.css new file mode 100644 index 0000000000..8d81c02ed9 --- /dev/null +++ b/static/doc/v1.4.0/_static/graphviz.css @@ -0,0 +1,19 @@ +/* + * graphviz.css + * ~~~~~~~~~~~~ + * + * Sphinx stylesheet -- graphviz extension. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +img.graphviz { + border: 0; + max-width: 100%; +} + +object.graphviz { + max-width: 100%; +} diff --git a/static/doc/v1.4.0/_static/index.rst b/static/doc/v1.4.0/_static/index.rst new file mode 100644 index 0000000000..94cb3b0f0b --- /dev/null +++ b/static/doc/v1.4.0/_static/index.rst @@ -0,0 +1,114 @@ +Introduction +============ + +open62541 (http://open62541.org) is an open source and free implementation of +OPC UA (OPC Unified Architecture) written in the common subset of the C99 and +C++98 languages. The library is usable with all major compilers and provides the +necessary tools to implement dedicated OPC UA clients and servers, or to +integrate OPC UA-based communication into existing applications. open62541 +library is platform independent. All platform-specific functionality is +implemented via exchangeable plugins. Plugin implementations are provided for +the major operating systems. + +open62541 is licensed under the Mozilla Public License v2.0 (MPLv2). This allows +the open62541 library to be combined and distributed with any proprietary +software. Only changes to the open62541 library itself need to be licensed under +the MPLv2 when copied and distributed. The plugins, as well as the server and +client examples are in the public domain (CC0 license). They can be reused under +any license and changes do not have to be published. + +The sample server (server_ctt) built using open62541 v1.0 is in conformance with +the 'Micro Embedded Device Server' Profile of OPC Foundation supporting OPC UA +client/server communication, subscriptions, method calls and security +(encryption) with the security policies 'Basic128Rsa15', 'Basic256' and +'Basic256Sha256' and the facets 'method server' and 'node management'. See +https://open62541.org/certified-sdk for more details. + +OPC Unified Architecture +------------------------ + +`OPC UA `_ is a protocol +for industrial communication and has been standardized in the IEC 62541 series. +At its core, OPC UA defines + +- an asynchronous :ref:`protocol` (built upon TCP, HTTP or SOAP) that + defines the exchange of messages via sessions, (on top of) secure + communication channels, (on top of) raw connections, +- a :ref:`type system` for protocol messages with a binary and XML-based + encoding scheme, +- a meta-model for :ref:`information modeling`, that + combines object-orientation with semantic triple-relations, and +- a set of 37 standard :ref:`services` to interact with server-side + information models. The signature of each service is defined as a request and + response message in the protocol type system. + +The standard itself can be purchased from IEC or downloaded for free on the +website of the OPC Foundation at https://opcfoundation.org/ (you need to +register with a valid email). + +The OPC Foundation drives the continuous improvement of the standard and the +development of companion specifications. Companion specifications translate +established concepts and reusable components from an application domain into OPC +UA. They are created jointly with an established industry council or +standardization body from the application domain. Furthermore, the OPC +Foundation organizes events for the dissemination of the standard and provides +the infrastructure and tools for compliance certification. + +open62541 Features +------------------ + +open62541 implements the OPC UA binary protocol stack as well as a client and +server SDK. It currently supports the Micro Embedded Device Server Profile plus +some additional features. Server binaries can be well under 100kb in size, +depending on the contained information model. + +- Communication Stack + + - OPC UA binary protocol + - Chunking (splitting of large messages) + - Exchangeable network layer (plugin) for using custom networking APIs (e.g. on embedded targets) + - Encrypted communication + - Asynchronous service requests in the client + +- Information model + + - Support for all OPC UA node types (including method nodes) + - Support for adding and removing nodes and references also at runtime. + - Support for inheritance and instantiation of object- and variable-types (custom constructor/destructor, instantiation of child nodes) + - Access control for individual nodes + +- Subscriptions + + - Support for subscriptions/monitoreditems for data change notifications + - Very low resource consumption for each monitored value (event-based server architecture) + +- Code-Generation + + - Support for generating data types from standard XML definitions + - Support for generating server-side information models (nodesets) from standard XML definitions + +Features on the roadmap for the 0.3 release series but missing in the initial v0.3 release are: + +- Encrypted communication in the client +- Events (notifications emitted by objects, data change notifications are implemented) +- Event-loop (background tasks) in the client + +Getting Help +------------ + +For discussion and help besides this documentation, you can reach the open62541 community via + +- the `mailing list `_ +- our `IRC channel `_ +- the `bugtracker `_ + +Contributing +------------ + +As an open source project, we invite new contributors to help improve open62541. +Issue reports, bugfixes and new features are very welcome. The following are +good starting points for new contributors: + +- `Report bugs `_ +- Improve the `documentation `_ +- Work on issues marked as `good first issue `_ diff --git a/static/doc/v1.4.0/_static/js/badge_only.js b/static/doc/v1.4.0/_static/js/badge_only.js new file mode 100644 index 0000000000..526d7234b6 --- /dev/null +++ b/static/doc/v1.4.0/_static/js/badge_only.js @@ -0,0 +1 @@ +!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}}); \ No newline at end of file diff --git a/static/doc/v1.4.0/_static/js/html5shiv-printshiv.min.js b/static/doc/v1.4.0/_static/js/html5shiv-printshiv.min.js new file mode 100644 index 0000000000..2b43bd062e --- /dev/null +++ b/static/doc/v1.4.0/_static/js/html5shiv-printshiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/static/doc/v1.4.0/_static/js/html5shiv.min.js b/static/doc/v1.4.0/_static/js/html5shiv.min.js new file mode 100644 index 0000000000..cd1c674f5e --- /dev/null +++ b/static/doc/v1.4.0/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/static/doc/v1.4.0/_static/js/theme.js b/static/doc/v1.4.0/_static/js/theme.js new file mode 100644 index 0000000000..1fddb6ee4a --- /dev/null +++ b/static/doc/v1.4.0/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/static/doc/v1.4.0/_static/minus.png b/static/doc/v1.4.0/_static/minus.png new file mode 100644 index 0000000000..d96755fdaf Binary files /dev/null and b/static/doc/v1.4.0/_static/minus.png differ diff --git a/static/doc/v1.4.0/_static/nodeset_compiler.rst b/static/doc/v1.4.0/_static/nodeset_compiler.rst new file mode 100644 index 0000000000..9cf7712cc4 --- /dev/null +++ b/static/doc/v1.4.0/_static/nodeset_compiler.rst @@ -0,0 +1,520 @@ +XML Nodeset Compiler +-------------------- + +When writing an application, it is more comfortable to create information models using some GUI tools. Most tools can export data according the OPC UA Nodeset XML schema. open62541 contains a Python based nodeset compiler that can transform these information model definitions into a working server. + +Note that the nodeset compiler you can find in the *tools/nodeset_compiler* subfolder is *not* an XML transformation tool but a compiler. That means that it will create an internal representation when parsing the XML files and attempt to understand and verify the correctness of this representation in order to generate C Code. + +Getting started +............... + +We take the following information model snippet as the starting point of the following tutorial. A more detailed tutorial on how to create your own information model and NodeSet2.xml can be found in this blog post: https://opcua.rocks/custom-information-models/ + +.. code-block:: xml + + + + http://yourorganisation.org/example_nodeset/ + + + i=1 + i=7 + i=12 + i=37 + i=40 + i=45 + i=46 + i=47 + i=296 + + + + + + + + providesInputTo + + + i=33 + + + inputProcidedBy + + + FieldDevice + + + i=58 + + ns=1;i=6001 + ns=1;i=6002 + + + + ManufacturerName + + i=63 + i=78 + + ns=1;i=1001 + + + + + ModelName + + i=63 + i=78 + + ns=1;i=1001 + + + + + Pump + + ns=1;i=6003 + ns=1;i=6004 + + ns=1;i=1001 + + ns=1;i=7001 + ns=1;i=7002 + + + + isOn + + i=63 + i=78 + + ns=1;i=1002 + + + + + MotorRPM + + i=63 + i=78 + + ns=1;i=1002 + + + + + startPump + + i=78 + ns=1;i=6005 + + ns=1;i=1002 + + + + + OutputArguments + + i=78 + ns=1;i=7001 + i=68 + + + + + + i=297 + + + + started + + i=1 + + -1 + + + + + + + + + + stopPump + + i=78 + ns=1;i=6006 + ns=1;i=1002 + + + + OutputArguments + + i=78 + + ns=1;i=7002 + + i=68 + + + + + + i=297 + + + + stopped + + i=1 + + -1 + + + + + + + + + + +Take the previous snippet and save it to a file ``myNS.xml``. To compile this nodeset into the corresponding C code, which can then be used by the open62541 stack, the nodeset compiler needs some arguments when you call it. The output of the help command gives you the following info: + +.. code-block:: bash + + $ python ./nodeset_compiler.py -h + usage: nodeset_compiler.py [-h] [-e ] [-x ] + [--internal-headers] + [-b ] [-i ] + [-t ] + [-v] + + + positional arguments: + The path/basename for the .c and .h files to be generated. This will also be the + function name used in the header and c-file. + + optional arguments: + -h, --help show this help message and exit + -e , --existing + NodeSet XML files with nodes that are already present + on the server. + -x , --xml + NodeSet XML files with nodes that shall be generated. + --internal-headers Include internal headers instead of amalgamated header + -b , --blacklist + Loads a list of NodeIDs stored in blacklistFile (one + NodeID per line). Any of the nodeIds encountered in + this file will be removed from the nodeset prior to + compilation. Any references to these nodes will also + be removed + -i , --ignore + Loads a list of NodeIDs stored in ignoreFile (one + NodeID per line). Any of the nodeIds encountered in + this file will be kept in the nodestore but not + printed in the generated code + -t , --types-array + Types array for the given namespace. Can be used + mutliple times to define (in the same order as the + .xml files, first for --existing, then --xml) the type + arrays + --max-string-length MAX_STRING_LENGTH + Maximum allowed length of a string literal. If longer, + it will be set to an empty string + -v, --verbose Make the script more verbose. Can be applied up to 4 + times + +So the resulting call looks like this: + +.. code-block:: bash + + $ python ./nodeset_compiler.py --types-array=UA_TYPES --existing ../../deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml --xml myNS.xml myNS + +And the output of the command: + +.. code-block:: bash + + INFO:__main__:Preprocessing (existing) ../../deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml + INFO:__main__:Preprocessing myNS.xml + INFO:__main__:Generating Code + INFO:__main__:NodeSet generation code successfully printed + +The first argument ``--types-array=UA_TYPES`` defines the name of the global array in open62541 which contains the corresponding types used within the nodeset in ``NodeSet2.xml``. If you do not define your own datatypes, you can always use the ``UA_TYPES`` value. More on that later in this tutorial. +The next argument ``--existing ../../deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml`` points to the XML definition of the standard-defined namespace 0 (NS0). Namespace 0 is assumed to be loaded beforehand and provides definitions for data type, reference types, and so. Since we reference nodes from NS0 in our myNS.xml we need to tell the nodeset compiler that it should also load that nodeset, but not compile it into the output. +Note that you may need to initialize the git submodule to get the ``deps/ua-nodeset`` folder (``git submodule update --init``) or download the full ``NodeSet2.xml`` manually. +The argument ``--xml myNS.xml`` points to the user-defined information model, whose nodes will be added to the abstract syntax tree. The script will then create the files ``myNS.c`` and ``myNS.h`` (indicated by the last argument ``myNS``) containing the C code necessary to instantiate those namespaces. + +Although it is possible to run the compiler this way, it is highly discouraged. If you care to examine the CMakeLists.txt (examples/nodeset/CMakeLists.txt), you will find out that the file ``server_nodeset.xml`` is compiled using the following function:: + + ua_generate_nodeset( + NAME "example" + FILE "${PROJECT_SOURCE_DIR}/examples/nodeset/server_nodeset.xml" + DEPENDS_TYPES "UA_TYPES" + DEPENDS_NS "${UA_FILE_NS0}" + ) + +If you look into the files generated by the nodeset compiler, you will see that it generated a method called ``extern UA_StatusCode myNS(UA_Server *server);``. You need to include the header and source file and then call the ``myNS(server)`` method right after creating the server instance with ``UA_Server_new``. This will automatically add all the nodes to the server and return ``UA_STATUSCODE_GOOD`` if there weren't any errors. Additionally you need to compile the open62541 stack with the full NS0 by setting ``UA_NAMESPACE_ZERO=FULL`` in CMake. Otherwise the stack uses a subset where many nodes are not included and thus adding a custom nodeset may fail. + +This is how you can use the nodeset compiler to compile simple NodeSet XMLs to be used by the open62541 stack. + +For your convenience and for simpler use we also provide a CMake function which simplifies the use of the ``ua_generate_datatypes`` and ``ua_generate_nodeset`` function even more. +It is highly recommended to use this function: ``ua_generate_nodeset_and_datatypes``. It uses some best practice settings and you only need to pass a name and the nodeset files. +Passing the .csv and .bsd files is optional and if not given, generating datatypes for that noteset will be skipped. You can also define dependencies between nodesets using the ``DEPENDS`` argument. + +Here are some examples for the ``DI`` and ``PLCOpen`` nodesets:: + + # Generate types and namespace for DI + ua_generate_nodeset_and_datatypes( + NAME "di" + FILE_CSV "${UA_NODESET_DIR}/DI/Opc.Ua.Di.NodeIds.csv" + FILE_BSD "${UA_NODESET_DIR}/DI/Opc.Ua.Di.Types.bsd" + FILE_NS "${UA_NODESET_DIR}/DI/Opc.Ua.Di.NodeSet2.xml" + ) + + # generate PLCopen namespace which is using DI + ua_generate_nodeset_and_datatypes( + NAME "plc" + # PLCopen does not define custom types. Only generate the nodeset + FILE_NS "${UA_NODESET_DIR}/PLCopen/Opc.Ua.PLCopen.NodeSet2_V1.02.xml" + # PLCopen depends on the di nodeset, which must be generated before + DEPENDS "di" + ) + +Creating object instances +......................... + +One of the key benefits of defining object types is being able to create object instances fairly easily. Object instantiation is handled automatically when the typedefinition NodeId points to a valid ObjectType node. All Attributes and Methods contained in the objectType definition will be instantiated along with the object node. + +While variables are copied from the objectType definition (allowing the user for example to attach new dataSources to them), methods are always only linked. This paradigm is identical to languages like C++: The method called is always the same piece of code, but the first argument is a pointer to an object. Likewise, in OPC UA, only one methodCallback can be attached to a specific methodNode. If that methodNode is called, the parent objectId will be passed to the method - it is the methods job to derefence which object instance it belongs to in that moment. + +Let's look at an example that will create a pump instance given the newly defined objectType from myNS.xml: + +.. code-block:: c + + /* This work is licensed under a Creative Commons CCZero 1.0 Universal License. + * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */ + + #include + #include + #include "open62541.h" + + /* Files myNS.h and myNS.c are created from myNS.xml */ + #include "myNS.h" + + UA_Boolean running = true; + + static void stopHandler(int sign) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c"); + running = false; + } + + int main(int argc, char **argv) { + signal(SIGINT, stopHandler); + signal(SIGTERM, stopHandler); + + UA_Server *server = UA_Server_new(); + UA_ServerConfig_setDefault(UA_Server_getConfig(server)); + + UA_StatusCode retval = myNS(server); + /* Create nodes from nodeset */ + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Could not add the example nodeset. " + "Check previous output for any error."); + retval = UA_STATUSCODE_BADUNEXPECTEDERROR; + } else { + UA_NodeId createdNodeId; + UA_ObjectAttributes object_attr = UA_ObjectAttributes_default; + + object_attr.description = UA_LOCALIZEDTEXT("en-US", "A pump!"); + object_attr.displayName = UA_LOCALIZEDTEXT("en-US", "Pump1"); + + // we assume that the myNS nodeset was added in namespace 2. + // You should always use UA_Server_addNamespace to check what the + // namespace index is for a given namespace URI. UA_Server_addNamespace + // will just return the index if it is already added. + UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0), + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), + UA_QUALIFIEDNAME(1, "Pump1"), + UA_NODEID_NUMERIC(2, 1002), + object_attr, NULL, &createdNodeId); + + + retval = UA_Server_run(server, &running); + } + + UA_Server_delete(server); + return (int) retval; + } + +Make sure you have updated the headers and libs in your project, then recompile and run the server. Make especially sure you have added ``myNS.h`` to your include folder. + +As you can see instantiating an object is not much different from creating an object node. The main difference is that you *must* use an objectType node as typeDefinition. + +If you start the server and inspect the nodes with UA Expert, you will find the pump in the objects folder, which look like this :numref:`nodeset-compiler-pump`. + +.. _nodeset-compiler-pump: + +.. figure:: nodeset_compiler_pump.png + :alt: Instantiated Pump Object with inherited children + + Instantiated Pump Object with inherited children + +As you can see the pump has inherited its parents attributes (ManufacturerName and ModelName). Methods, in contrast to objects and variables, are never cloned but instead only linked. The reason is that you will quite propably attach a method callback to a central method, not each object. Objects are instantiated if they are *below* the object you are creating, so any object (like an object called associatedServer of ServerType) that is part of pump will be instantiated as well. Objects *above* you object are never instantiated, so the same ServerType object in Fielddevices would have been omitted (the reason is that the recursive instantiation function protects itself from infinite recursions, which are hard to track when first ascending, then redescending into a tree). + + +Combination of multiple nodesets +................................ + +In the previous section you have seen how you can use the nodeset compiler with one single nodeset which depends on the default nodeset (NS0) ``Opc.Ua.NodeSet2.xml``. The nodeset compiler also supports nodesets which depend on more than one nodeset. We will show this use-case with the PLCopen nodeset. The PLCopen nodeset ``Opc.Ua.PLCopen.NodeSet2_V1.02.xml`` depends on the DI nodeset ``Opc.Ua.Di.NodeSet2.xml`` which then depends on NS0. This example is also shown in ``examples/nodeset/CMakeLists.txt``. + +This DI nodeset makes use of some additional data types in ``deps/ua-nodeset/DI/Opc.Ua.Di.Types.bsd``. Since we also need these types within the generated code, we first need to compile the types into C code. The generated code is mainly a definition of the binary representation of the types required for encoding and decoding. The generation can be done using the ``ua_generate_datatypes`` CMake function, which uses the ``tools/generate_datatypes.py`` script:: + + ua_generate_datatypes( + NAME "ua_types_di" + TARGET_SUFFIX "types-di" + FILE_CSV "${UA_NODESET_DIR}/DI/Opc.Ua.Di.NodeIds.csv" + FILES_BSD "${UA_NODESET_DIR}/DI/Opc.Ua.Di.Types.bsd" + ) + +The ``NAMESPACE_MAP`` parameter is an array of strings which indicates the mapping of specific namespace uris to the resulting namespace index. +This mapping is required for correct mapping of DataType nodes and their node ids. Currently we need to rely that the namespace is also added at this position in the final server. There is no automatic inferring yet (pull requests are warmly welcome). +If you are using the `DEPENDS` option on the ``ua_generate_nodeset_and_datatypes``, the ``NAMESPACE_MAP`` is also inherited and you do not need to pass all mappings for dependent types. +The CSV and BSD files contain the metadata and definition for the types. ``TARGET_SUFFIX`` is used to create a new target with the name ``open62541-generator-TARGET_SUFFIX``. + +**The ``NAMESPACE_MAP`` parameter is deprecated and no longer has any effect. The index of the nodeset is set automatically when it is loaded.** + +Now you can compile the DI nodeset XML using the following command:: + + ua_generate_nodeset( + NAME "di" + FILE "${UA_NODESET_DIR}/DI/Opc.Ua.Di.NodeSet2.xml" + TYPES_ARRAY "UA_TYPES_DI" + INTERNAL + DEPENDS_TYPES "UA_TYPES" + DEPENDS_NS "${UA_NODESET_DIR}/Schema/Opc.Ua.NodeSet2.xml" + DEPENDS_TARGET "open62541-generator-types-di" + ) + +There are now two new arguments: ``INTERNAL`` indicates that internal headers (and non public API) should be included within the generated source code. This is currently required for nodesets which use structures as data values, and will probably be fixed in the future. +The ``DEPENDS_TYPES`` types array argument is matched with the nodesets in the same order as they appear on the ``DEPENDS_TARGET`` parameter. It tells the nodeset compiler which types array it should use: ``UA_TYPES`` for ``Opc.Ua.NodeSet2.xml`` and ``UA_TYPES_DI`` for ``Opc.Ua.Di.NodeSet2.xml``. This is the type array generated by the ``generate_datatypes.py`` script. The rest is similar to the example in previous section: ``Opc.Ua.NodeSet2.xml`` is assumed to exist already and only needs to be loaded for consistency checks, ``Opc.Ua.Di.NodeSet2.xml`` will be generated in the output file ``ua_namespace_di.c/.h`` + +Next we can generate the PLCopen nodeset. Since it doesn't require any additional datatype definitions, we can immediately start with the nodeset compiler command:: + + ua_generate_nodeset( + NAME "plc" + FILE "${UA_NODESET_DIR}/PLCopen/Opc.Ua.PLCopen.NodeSet2_V1.02.xml" + INTERNAL + DEPENDS_TYPES + "UA_TYPES" "UA_TYPES_DI" + DEPENDS_NS + "${UA_NODESET_DIR}/Schema/Opc.Ua.NodeSet2.xml" + "${UA_NODESET_DIR}/DI/Opc.Ua.Di.NodeSet2.xml" + DEPENDS_TARGET "open62541-generator-ns-di" + ) + +This call is quite similar to the compilation of the DI nodeset. As you can see, we do not define any specific types array for the PLCopen nodeset. Since the PLCopen nodeset depends on the NS0 and DI nodeset, we need to tell the nodeset compiler that these two nodesets should be seen as already existing. Make sure that the order is the same as in your XML file, e.g., in this case the order indicated in ``Opc.Ua.PLCopen.NodeSet2_V1.02.xml -> UANodeSet -> Models -> Model``. + +As a result of the previous scripts you will have multiple source files: + +* ua_types_di_generated.c +* ua_types_di_generated.h +* ua_types_di_generated_encoding_binary.h +* ua_types_di_generated_handling.h +* ua_namespace_di.c +* ua_namespace_di.h +* ua_namespace_plc.c +* ua_namespace_plc.h + +Finally you need to include all these files in your build process and call the corresponding initialization methods for the nodesets. An example application could look like this: + +.. code-block:: c + + UA_Server *server = UA_Server_new(); + UA_ServerConfig_setDefault(UA_Server_getConfig(server)); + + /* Create nodes from nodeset */ + UA_StatusCode retval = ua_namespace_di(server); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Adding the DI namespace failed. Please check previous error output."); + UA_Server_delete(server); + return (int)UA_STATUSCODE_BADUNEXPECTEDERROR; + } + + retval |= ua_namespace_plc(server); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Adding the PLCopen namespace failed. Please check previous error output."); + UA_Server_delete(server); + return (int)UA_STATUSCODE_BADUNEXPECTEDERROR; + } + + retval = UA_Server_run(server, &running); + +Outstanding Companion Spec Issues +................................. + +There are some Companion Specifications that currently cannot be compiled with the Nodeset compiler. +Which Companion Specifications are affected and what causes this is described below. + +Safety, Glass, DEXPI + Do not specify a BSD file or BSD blob in the XML file. The BSD file is considered deprecated. However, it is currently still required by the Nodeser compiler. + +I4AAS, RSL, FDI + Attempting to load will result in a runtime error ("Type-checking failed with error code BadTypeMismatch" or "Parent node not found"). + +BACnet + Defines data types whose fields have the names signed or unsigned. This leads to errors when creating C structures, because signed and unsigned are keywords in C. + +Automatic Nodesetinjection +.......................... + +The nodesetinjector is a mechanism for automatically loading nodeset/companion specifications during server initialization. +It provides a fast and easy way to load nodesets in all applications, focusing on the official OPCFoundation/UANodeset Repository ( https://github.com/OPCFoundation/UA-Nodeset ). +Specify the required information models using CMake. + +Which nodesets are to be loaded is determined by the Cmake flag ``DUA_INFORMATION_MODEL_AUTOLOAD``. All nodesets that are to be loaded automatically are listed here. +The naming is based on the folder name of the Companion Specification in the ua-nodeset folder. + +A CMake call could look like this. + +.. code-block:: bash + + -DCMAKE_BUILD_TYPE=Debug + -DUA_BUILD_EXAMPLES=ON + -DUA_INFORMATION_MODEL_AUTOLOAD=DI;POWERLINK;PROFINET;MachineVision + -DUA_NAMESPACE_ZERO=FULL + +The order of nodesets is important! Nodesets that build on other nodesets must be placed after them in the list. +The following nodesets are currently supported: + +DI, CNC, ISA95-JOBCONTROL, OpenSCS, AMB, AutoID, POWERLINK, IA, Machinery, +PackML, PNEM, PLCopen, MachineTool, PROFINET, MachineVision, FDT, +CommercialKitchenEquipment, PNRIO, Scales, Weihenstephan, Pumps, CAS, TMC, IJT diff --git a/static/doc/v1.4.0/_static/nodeset_compiler_pump.png b/static/doc/v1.4.0/_static/nodeset_compiler_pump.png new file mode 100644 index 0000000000..58ccc5cf78 Binary files /dev/null and b/static/doc/v1.4.0/_static/nodeset_compiler_pump.png differ diff --git a/static/doc/v1.4.0/_static/open62541.png b/static/doc/v1.4.0/_static/open62541.png new file mode 100644 index 0000000000..41b12a6222 Binary files /dev/null and b/static/doc/v1.4.0/_static/open62541.png differ diff --git a/static/doc/v1.4.0/_static/open62541_html.png b/static/doc/v1.4.0/_static/open62541_html.png new file mode 100644 index 0000000000..5e3e732c05 Binary files /dev/null and b/static/doc/v1.4.0/_static/open62541_html.png differ diff --git a/static/doc/v1.4.0/_static/plugin.rst b/static/doc/v1.4.0/_static/plugin.rst new file mode 100644 index 0000000000..ee086658b5 --- /dev/null +++ b/static/doc/v1.4.0/_static/plugin.rst @@ -0,0 +1,11 @@ +Plugin API +========== + +.. toctree:: + + plugin_log + plugin_nodestore + plugin_accesscontrol + plugin_eventloop + plugin_pki + plugin_securitypolicy diff --git a/static/doc/v1.4.0/_static/plugin_accesscontrol.rst b/static/doc/v1.4.0/_static/plugin_accesscontrol.rst new file mode 100644 index 0000000000..97da2a7749 --- /dev/null +++ b/static/doc/v1.4.0/_static/plugin_accesscontrol.rst @@ -0,0 +1,114 @@ +.. _access-control: + +Access Control Plugin API +========================= +The access control callback is used to authenticate sessions and grant access +rights accordingly. + +The ``sessionId`` and ``sessionContext`` can be both NULL. This is the case +when, for example, a MonitoredItem (the underlying Subscription) is detached +from its Session but continues to run. + +.. code-block:: c + + + struct UA_AccessControl { + void *context; + void (*clear)(UA_AccessControl *ac); + + /* Supported login mechanisms. The server endpoints are created from here. */ + size_t userTokenPoliciesSize; + UA_UserTokenPolicy *userTokenPolicies; + + /* Authenticate a session. The session context is attached to the session + * and later passed into the node-based access control callbacks. The new + * session is rejected if a StatusCode other than UA_STATUSCODE_GOOD is + * returned. + * + * Note that this callback can be called several times for a Session. For + * example when a Session is recovered (activated) on a new + * SecureChannel. */ + UA_StatusCode (*activateSession)(UA_Server *server, UA_AccessControl *ac, + const UA_EndpointDescription *endpointDescription, + const UA_ByteString *secureChannelRemoteCertificate, + const UA_NodeId *sessionId, + const UA_ExtensionObject *userIdentityToken, + void **sessionContext); + + /* Deauthenticate a session and cleanup */ + void (*closeSession)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext); + + /* Access control for all nodes*/ + UA_UInt32 (*getUserRightsMask)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext); + + /* Additional access control for variable nodes */ + UA_Byte (*getUserAccessLevel)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext); + + /* Additional access control for method nodes */ + UA_Boolean (*getUserExecutable)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *methodId, void *methodContext); + + /* Additional access control for calling a method node in the context of a + * specific object */ + UA_Boolean (*getUserExecutableOnObject)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *methodId, void *methodContext, + const UA_NodeId *objectId, void *objectContext); + + /* Allow adding a node */ + UA_Boolean (*allowAddNode)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_AddNodesItem *item); + + /* Allow adding a reference */ + UA_Boolean (*allowAddReference)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_AddReferencesItem *item); + + /* Allow deleting a node */ + UA_Boolean (*allowDeleteNode)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_DeleteNodesItem *item); + + /* Allow deleting a reference */ + UA_Boolean (*allowDeleteReference)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_DeleteReferencesItem *item); + + /* Allow browsing a node */ + UA_Boolean (*allowBrowseNode)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext); + + #ifdef UA_ENABLE_SUBSCRIPTIONS + /* Allow transfer of a subscription to another session. The Server shall + * validate that the Client of that Session is operating on behalf of the + * same user */ + UA_Boolean (*allowTransferSubscription)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *oldSessionId, void *oldSessionContext, + const UA_NodeId *newSessionId, void *newSessionContext); + #endif + + #ifdef UA_ENABLE_HISTORIZING + /* Allow insert,replace,update of historical data */ + UA_Boolean (*allowHistoryUpdateUpdateData)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, + UA_PerformUpdateType performInsertReplace, + const UA_DataValue *value); + + /* Allow delete of historical data */ + UA_Boolean (*allowHistoryUpdateDeleteRawModified)(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, + UA_DateTime startTimestamp, + UA_DateTime endTimestamp, + bool isDeleteModified); + #endif + }; diff --git a/static/doc/v1.4.0/_static/plugin_eventloop.rst b/static/doc/v1.4.0/_static/plugin_eventloop.rst new file mode 100644 index 0000000000..cfed09a48b --- /dev/null +++ b/static/doc/v1.4.0/_static/plugin_eventloop.rst @@ -0,0 +1,663 @@ +Event Loop Subsystem +==================== +An OPC UA-enabled application can have several clients and servers. And +server can serve different transport-level protocols for OPC UA. The +EventLoop is a central module that provides a unified control-flow for all of +these. Hence, several applications can share an EventLoop. + +The EventLoop and the ConnectionManager implementation is +architecture-specific. The goal is to have a single call to "poll" (epoll, +kqueue, ...) in the EventLoop that covers all ConnectionManagers. Hence the +EventLoop plugin implementation must know implementation details of the +ConnectionManager implementations. So the EventLoop can extract socket +information, etc. from the ConnectionManagers. + +Timer Policies +-------------- +A timer comes with a cyclic interval in which a callback is executed. If an +application is congested the interval can be missed. Two different policies +can be used when this happens. Either schedule the next execution after the +interval has elapsed again from the current time onwards or stay within the +regular interval with respect to the original basetime. + +.. code-block:: c + + + typedef enum { + UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME, + UA_TIMER_HANDLE_CYCLEMISS_WITH_BASETIME + } UA_TimerPolicy; + +Event Loop +---------- +The EventLoop implementation is part of the selected architecture. For +example, "Win32/POSIX" stands for a Windows environment with an EventLoop +that uses the POSIX API. Several EventLoops can be instantiated in parallel. +But the globally defined functions are the same everywhere. + +.. code-block:: c + + + typedef void (*UA_Callback)(void *application, void *context); + + /* Delayed callbacks are executed not when they are registered, but in the + * following EventLoop cycle */ + typedef struct UA_DelayedCallback { + struct UA_DelayedCallback *next; /* Singly-linked list */ + UA_Callback callback; + void *application; + void *context; + } UA_DelayedCallback; + + typedef enum { + UA_EVENTLOOPSTATE_FRESH = 0, + UA_EVENTLOOPSTATE_STOPPED, + UA_EVENTLOOPSTATE_STARTED, + UA_EVENTLOOPSTATE_STOPPING /* Stopping in progress, needs EventLoop + * cycles to finish */ + } UA_EventLoopState; + + struct UA_EventLoop { + /* Configuration + * ~~~~~~~~~~~~~~~ + * The configuration should be set before the EventLoop is started */ + + const UA_Logger *logger; + UA_KeyValueMap *params; /* See the implementation-specific documentation */ + + /* EventLoop Lifecycle + * ~~~~~~~~~~~~~~~~~~~~ + * The EventLoop state also controls the state of the configured + * EventSources. Stopping the EventLoop gracefully closes e.g. the open + * network connections. The only way to process incoming events is to call + * the 'run' method. Events are then triggering their respective callbacks + * from within that method.*/ + + const volatile UA_EventLoopState state; /* Only read the state from outside */ + + /* Start the EventLoop and start all already registered EventSources */ + UA_StatusCode (*start)(UA_EventLoop *el); + + /* Stop all EventSources. This is asynchronous and might need a few + * iterations of the main-loop to succeed. */ + void (*stop)(UA_EventLoop *el); + + /* Process events for at most "timeout" ms or until an unrecoverable error + * occurs. If timeout==0, then only already received events are + * processed. */ + UA_StatusCode (*run)(UA_EventLoop *el, UA_UInt32 timeout); + + /* Clean up the EventLoop and free allocated memory. Can fail if the + * EventLoop is not stopped. */ + UA_StatusCode (*free)(UA_EventLoop *el); + + /* EventLoop Time Domain + * ~~~~~~~~~~~~~~~~~~~~~ + * Each EventLoop instance can manage its own time domain. This affects the + * execution of timed/cyclic callbacks and time-based sending of network + * packets (if this is implemented). Managing independent time domains is + * important when different parts of a system a synchronized to different + * external (network-wide) clocks. + * + * Note that the logger configured in the EventLoop generates timestamps + * internally as well. If the logger uses a different time domain than the + * EventLoop, discrepancies may appear in the logs. + * + * The time domain of the EventLoop is exposed via the following functons. + * See `open62541/types.h` for the documentation of their equivalent + * globally defined functions. */ + + UA_DateTime (*dateTime_now)(UA_EventLoop *el); + UA_DateTime (*dateTime_nowMonotonic)(UA_EventLoop *el); + UA_Int64 (*dateTime_localTimeUtcOffset)(UA_EventLoop *el); + + /* Timed Callbacks + * ~~~~~~~~~~~~~~~ + * Cyclic callbacks are executed regularly with an interval. + * A timed callback is executed only once. */ + + /* Time of the next cyclic callback. Returns the max DateTime if no cyclic + * callback is registered. */ + UA_DateTime (*nextCyclicTime)(UA_EventLoop *el); + + /* The execution interval is in ms. Returns the callbackId if the pointer is + * non-NULL. */ + UA_StatusCode + (*addCyclicCallback)(UA_EventLoop *el, UA_Callback cb, void *application, + void *data, UA_Double interval_ms, UA_DateTime *baseTime, + UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId); + + UA_StatusCode + (*modifyCyclicCallback)(UA_EventLoop *el, UA_UInt64 callbackId, + UA_Double interval_ms, UA_DateTime *baseTime, + UA_TimerPolicy timerPolicy); + + void (*removeCyclicCallback)(UA_EventLoop *el, UA_UInt64 callbackId); + + /* Like a cyclic callback, but executed only once */ + UA_StatusCode + (*addTimedCallback)(UA_EventLoop *el, UA_Callback cb, void *application, + void *data, UA_DateTime date, UA_UInt64 *callbackId); + + /* Delayed Callbacks + * ~~~~~~~~~~~~~~~~~ + * Delayed callbacks are executed once in the next iteration of the + * EventLoop and then deregistered automatically. A typical use case is to + * delay a resource cleanup to a point where it is known that the resource + * has no remaining users. + * + * The delayed callbacks are processed in each of the cycle of the EventLoop + * between the handling of timed cyclic callbacks and polling for (network) + * events. The memory for the delayed callback is *NOT* automatically freed + * after the execution. */ + + void (*addDelayedCallback)(UA_EventLoop *el, UA_DelayedCallback *dc); + void (*removeDelayedCallback)(UA_EventLoop *el, UA_DelayedCallback *dc); + + /* EventSources + * ~~~~~~~~~~~~ + * EventSources are stored in a singly-linked list for direct access. But + * only the below methods shall be used for adding and removing - this + * impacts the lifecycle of the EventSource. For example it may be + * auto-started if the EventLoop is already running. */ + + /* Linked list of EventSources */ + UA_EventSource *eventSources; + + /* Register the ES. Immediately starts the ES if the EventLoop is already + * started. Otherwise the ES is started together with the EventLoop. */ + UA_StatusCode + (*registerEventSource)(UA_EventLoop *el, UA_EventSource *es); + + /* Stops the EventSource before deregistrering it */ + UA_StatusCode + (*deregisterEventSource)(UA_EventLoop *el, UA_EventSource *es); + }; + +Event Source +------------ +Event Sources are attached to an EventLoop. Typically the event source and +the EventLoop are developed together and share a private API in the +background. + +.. code-block:: c + + + typedef enum { + UA_EVENTSOURCESTATE_FRESH = 0, + UA_EVENTSOURCESTATE_STOPPED, /* Registered but stopped */ + UA_EVENTSOURCESTATE_STARTING, + UA_EVENTSOURCESTATE_STARTED, + UA_EVENTSOURCESTATE_STOPPING /* Stopping in progress, needs + * EventLoop cycles to finish */ + } UA_EventSourceState; + + /* Type-tag for proper casting of the difference EventSource (e.g. when they are + * looked up via UA_EventLoop_findEventSource). */ + typedef enum { + UA_EVENTSOURCETYPE_CONNECTIONMANAGER, + UA_EVENTSOURCETYPE_INTERRUPTMANAGER + } UA_EventSourceType; + + struct UA_EventSource { + struct UA_EventSource *next; /* Singly-linked list for use by the + * application that registered the ES */ + + UA_EventSourceType eventSourceType; + + /* Configuration + * ~~~~~~~~~~~~~ */ + UA_String name; /* Unique name of the ES */ + UA_EventLoop *eventLoop; /* EventLoop where the ES is registered */ + UA_KeyValueMap params; + + /* Lifecycle + * ~~~~~~~~~ */ + UA_EventSourceState state; + UA_StatusCode (*start)(UA_EventSource *es); + void (*stop)(UA_EventSource *es); /* Asynchronous. Iterate theven EventLoop + * until the EventSource is stopped. */ + UA_StatusCode (*free)(UA_EventSource *es); + }; + +Connection Manager +------------------ +Every Connection is created by a ConnectionManager. Every ConnectionManager +belongs to just one application. A ConnectionManager can act purely as a +passive "Factory" for Connections. But it can also be stateful. For example, +it can keep a session to an MQTT broker open which is used by individual +connections that are each bound to an MQTT topic. + +.. code-block:: c + + + /* The ConnectionCallback is the only interface from the connection back to + * the application. + * + * - The connectionId is initially unknown to the target application and + * "announced" to the application when first used first in this callback. + * + * - The context is attached to the connection. Initially a default context + * is set. The context can be replaced within the callback (via the + * double-pointer). + * + * - The state argument indicates the lifecycle of the connection. Every + * connection calls the callback a last time with UA_CONNECTIONSTATE_CLOSING. + * Protocols individually can forward diagnostic information relevant to the + * state as part of the key-value parameters. + * + * - The parameters are a key-value list with additional information. The + * possible keys and their meaning are documented for the individual + * ConnectionManager implementations. + * + * - The msg ByteString is the message (or packet) received on the + * connection. Can be empty. */ + typedef void + (*UA_ConnectionManager_connectionCallback) + (UA_ConnectionManager *cm, uintptr_t connectionId, + void *application, void **connectionContext, UA_ConnectionState state, + const UA_KeyValueMap *params, UA_ByteString msg); + + struct UA_ConnectionManager { + /* Every ConnectionManager is treated like an EventSource from the + * perspective of the EventLoop. */ + UA_EventSource eventSource; + + /* Name of the protocol supported by the ConnectionManager. For example + * "mqtt", "udp", "mqtt". */ + UA_String protocol; + + /* Open a Connection + * ~~~~~~~~~~~~~~~~~ + * Connecting is asynchronous. The connection-callback is called when the + * connection is open (status=GOOD) or aborted (status!=GOOD) when + * connecting failed. + * + * Some ConnectionManagers can also passively listen for new connections. + * Configuration parameters for this are passed via the key-value list. The + * `context` pointer of the listening connection is also set as the initial + * context of newly opened connections. + * + * The parameters describe the connection. For example hostname and port + * (for TCP). Other protocols (e.g. MQTT, AMQP, etc.) may required + * additional arguments to open a connection in the key-value list. + * + * The provided context is set as the initial context attached to this + * connection. It is already set before the first call to + * connectionCallback. + * + * The connection can be opened synchronously or asynchronously. + * + * - For synchronous connection, the connectionCallback is called with the + * status UA_CONNECTIONSTATE_ESTABLISHED immediately from within the + * openConnection operation. + * + * - In the asynchronous case the connectionCallback is called immediately + * from within the openConnection operation with the status + * UA_CONNECTIONSTATE_OPENING. The connectionCallback is called with the + * status UA_CONNECTIONSTATE_ESTABLISHED once the connection has fully + * opened. + * + * Note that a single call to openConnection might open multiple + * connections. For example listening on IPv4 and IPv6 for a single + * hostname. Each protocol implementation documents whether multiple + * connections might be opened at once. */ + UA_StatusCode + (*openConnection)(UA_ConnectionManager *cm, const UA_KeyValueMap *params, + void *application, void *context, + UA_ConnectionManager_connectionCallback connectionCallback); + + /* Send a message over a Connection + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Sending is asynchronous. That is, the function returns before the message + * is ACKed from remote. The memory for the buffer is expected to be + * allocated with allocNetworkBuffer and is released internally (also if + * sending fails). + * + * Some ConnectionManagers can accept additional parameters for sending. For + * example a tx-time for sending in time-synchronized TSN settings. */ + UA_StatusCode + (*sendWithConnection)(UA_ConnectionManager *cm, uintptr_t connectionId, + const UA_KeyValueMap *params, UA_ByteString *buf); + + /* Close a Connection + * ~~~~~~~~~~~~~~~~~~ + * When a connection is closed its `connectionCallback` is called with + * (status=BadConnectionClosed, msg=empty). Then the connection is cleared + * up inside the ConnectionManager. This is the case both for connections + * that are actively closed and those that are closed remotely. The return + * code is non-good only if the connection is already closed. */ + UA_StatusCode + (*closeConnection)(UA_ConnectionManager *cm, uintptr_t connectionId); + + /* Buffer Management + * ~~~~~~~~~~~~~~~~~ + * Each ConnectionManager allocates and frees his own memory for the network + * buffers. This enables, for example, zero-copy neworking mechanisms. The + * connectionId is part of the API to enable cases where memory is + * statically allocated for every connection */ + UA_StatusCode + (*allocNetworkBuffer)(UA_ConnectionManager *cm, uintptr_t connectionId, + UA_ByteString *buf, size_t bufSize); + void + (*freeNetworkBuffer)(UA_ConnectionManager *cm, uintptr_t connectionId, + UA_ByteString *buf); + }; + +Interrupt Manager +----------------- +The Interrupt Manager allows to register to listen for system interrupts. +Triggering the interrupt calls the callback associated with it. + +The implementations of the interrupt manager for the different platforms +shall be designed such that: + +- Registered interrupts are only intercepted from within the running EventLoop +- Processing an interrupt in the EventLoop is handled similarly to handling a + network event: all methods and also memory allocation are available from + within the interrupt callback. + +.. code-block:: c + + + /* Interrupts can have additional key-value 'instanceInfos' for each individual + * triggering. See the architecture-specific documentation. */ + typedef void + (*UA_InterruptCallback)(UA_InterruptManager *im, + uintptr_t interruptHandle, void *interruptContext, + const UA_KeyValueMap *instanceInfos); + + struct UA_InterruptManager { + /* Every InterruptManager is treated like an EventSource from the + * perspective of the EventLoop. */ + UA_EventSource eventSource; + + /* Register an interrupt. The handle and context information is passed + * through to the callback. + * + * The interruptHandle is a numerical identifier of the interrupt. In some + * cases, such as POSIX signals, this is enough information to register + * callback. For other interrupt systems (architectures) additional + * parameters may be required and can be passed in via the parameters + * key-value list. See the implementation-specific documentation. + * + * The interruptContext is opaque user-defined information and passed + * through to the callback without modification. */ + UA_StatusCode + (*registerInterrupt)(UA_InterruptManager *im, uintptr_t interruptHandle, + const UA_KeyValueMap *params, + UA_InterruptCallback callback, void *interruptContext); + + /* Remove a registered interrupt. Returns no error code if the interrupt is + * already deregistered. */ + void + (*deregisterInterrupt)(UA_InterruptManager *im, uintptr_t interruptHandle); + }; + +POSIX-Specific Implementation +----------------------------- +The POSIX compatibility of WIN32 is 'close enough'. So a joint implementation +is provided. + +.. code-block:: c + + + #if defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) + + UA_EventLoop * + UA_EventLoop_new_POSIX(const UA_Logger *logger); + +TCP Connection Manager +~~~~~~~~~~~~~~~~~~~~~~ +Listens on the network and manages TCP connections. This should be available +for all architectures. + +The `openConnection` callback is used to create both client and server +sockets. A server socket listens and accepts incoming connections (creates an +active connection). This is distinguished by the key-value parameters passed +to `openConnection`. Note that a single call to `openConnection` for a server +connection may actually create multiple connections (one per hostname / +device). + +The `connectionCallback` of the server socket and `context` of the server +socket is reused for each new connection. But the key-value parameters for +the first callback are different between server and client connections. + +The following list defines the parameters and their type. Note that some +parameters are only set for the first callback when a new connection opens. + +**Configuration parameters for the entire ConnectionManager:** + +0:recv-bufsize [uint32] + Size of the buffer that is allocated for receiving messages (default 64kB). + +**Open Connection Parameters:** + +0:address [string | array of string] + Hostname or IPv4/v6 address for the connection (scalar parameter required + for active connections). For listen-connections the address contains the + local hostnames or IP addresses for listening. If undefined, listen on all + interfaces INADDR_ANY. (default: undefined) + +0:port [uint16] + Port of the target host (required). + +0:listen [boolean] + Listen-connection or active-connection (default: false) + +0:validate [boolean] + If true, the connection setup will act as a dry-run without actually + creating any connection but solely validating the provided parameters + (default: false) + +**Active Connection Connection Callback Parameters (first callback only):** + +0:remote-address [string] + Address of the remote side (hostname or IP address). + +**Listen Connection Connection Callback Parameters (first callback only):** + +0:listen-address [string] + Local address (IP or hostname) for the new listen-connection. + +0:listen-port [uint16] + Port on which the new connection listens. + +**Send Parameters:** + +No additional parameters for sending over an established TCP socket +defined. + +.. code-block:: c + + UA_ConnectionManager * + UA_ConnectionManager_new_POSIX_TCP(const UA_String eventSourceName); + +UDP Connection Manager +~~~~~~~~~~~~~~~~~~~~~~ +Manages UDP connections. This should be available for all architectures. The +configuration parameters have to set before calling _start to take effect. + +**Configuration Parameters:** + +0:recv-bufsize [uint32] + Size of the buffer that is allocated for receiving messages (default + 64kB). + +**Open Connection Parameters:** + +0:listen [boolean] + Use the connection for listening or for sending (default: false) + +0:address [string | string array] + Hostname (or IPv4/v6 address) for sending or receiving. A scalar is + required for sending. For listening a string array for the list-hostnames + is possible as well (default: list on all hostnames). + +0:port [uint16] + Port for sending or listening (required). + +0:interface [string] + Network interface for listening or sending (e.g. when using multicast + addresses) + +0:ttl [uint32] + Multicast time to live, (optional, default: 1 - meaning multicast is + available only to the local subnet). + +0:loopback [boolean] + Whether or not to use multicast loopback, enabling local interfaces + belonging to the multicast group to receive packages. (default: enabled). + +0:reuse [boolean] + Enables sharing of the same listening address on different sockets + (default: disabled). + +0:sockpriority [uint32] + The socket priority (optional) - only available on linux. packets with a + higher priority may be processed first depending on the selected device + queueing discipline. Setting a priority outside the range 0 to 6 requires + the CAP_NET_ADMIN capability (on Linux). + +0:validate [boolean] + If true, the connection setup will act as a dry-run without actually + creating any connection but solely validating the provided parameters + (default: false) + +**Connection Callback Paramters:** + +0:remote-address [string] + Contains the remote IP address. + +0:remote-port [uint16] + Contains the remote port. + +**Send Parameters:** + +No additional parameters for sending over an UDP connection defined. + +.. code-block:: c + + UA_ConnectionManager * + UA_ConnectionManager_new_POSIX_UDP(const UA_String eventSourceName); + +Ethernet Connection Manager +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Listens on the network and manages UDP connections. This should be available +for all architectures. The configuration parameters have to set before +calling _start to take effect. + +**Open Connection Parameters:** + +0:listen [bool] + The connection is either for sending or for listening (default: false). + +0:interface [string] + The name of the Ethernet interface to use (required). + +0:address [string] + MAC target address consisting of six groups of hexadecimal digits + separated by hyphens such as 01-23-45-67-89-ab. For sending this is a + required parameter. For listening this is a multicast address that the + connections tries to register for. + +0:ethertype [uint16] + EtherType for sending and receiving frames (optional). For listening + connections, this filters out all frames with different EtherTypes. + +0:promiscuous [bool] + Receive frames also for different target addresses. Defined only for + listening connections (default: false). + +0:vid [uint16] + 12-bit VLAN identifier (optional for send connections). + +0:pcp [byte] + 3-bit priority code point (optional for send connections). + +0:dei [bool] + 1-bit drop eligible indicator (optional for seond connections). + +0:validate [boolean] + If true, the connection setup will act as a dry-run without actually + creating any connection but solely validating the provided parameters + (default: false) + +**Send Parameters:** + +No additional parameters for sending over an Ethernet connection defined. + +.. code-block:: c + + UA_ConnectionManager * + UA_ConnectionManager_new_POSIX_Ethernet(const UA_String eventSourceName); + +MQTT Connection Manager +~~~~~~~~~~~~~~~~~~~~~~~ +The MQTT ConnectionManager reuses the TCP ConnectionManager that is +configured in the EventLoop. Hence the MQTT ConnectionManager is platform +agnostic and does not require porting. An MQTT connection is for a +combination of broker and topic. The MQTT ConnectionManager can group +connections to the same broker in the background. Hence adding multiple +connections for the same broker is "cheap". To have individual control, +separate connections are created for each topic and for each direction +(publishing / subscribing). + +**Open Connection Parameters:** + +0:address [string] + Hostname or IPv4/v6 address of the MQTT broker (required). + +0:port [uint16] + Port of the MQTT broker (default: 1883). + +0:username [string] + Username to use (default: none) + +0:password [string] + Password to use (default: none) + +0:keep-alive [uint16] + Number of seconds for the keep-alive (ping) (default: 400). + +0:validate [boolean] + If true, the connection setup will act as a dry-run without actually + creating any connection but solely validating the provided parameters + (default: false) + +0:topic [string] + Topic to which the connection is associated (required). + +0:subscribe [bool] + Subscribe to the topic (default: false). Otherwise it is only possible to + publish on the topic. Subscribed topics can also be published to. + +**Connection Callback Parameters:** + +0:topic [string] + The value set during connect. + +0:subscribe [bool] + The value set during connect. + +**Send Parameters:** + +No additional parameters for sending over an Ethernet connection defined. + +.. code-block:: c + + UA_ConnectionManager * + UA_ConnectionManager_new_MQTT(const UA_String eventSourceName); + +Signal Interrupt Manager +~~~~~~~~~~~~~~~~~~~~~~~~ +Create an instance of the interrupt manager that handles POSX signals. This +interrupt manager takes the numerical interrupt identifiers from +for the interruptHandle. + +.. code-block:: c + + UA_InterruptManager * + UA_InterruptManager_new_POSIX(const UA_String eventSourceName); + + #endif /* defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) */ diff --git a/static/doc/v1.4.0/_static/plugin_log.rst b/static/doc/v1.4.0/_static/plugin_log.rst new file mode 100644 index 0000000000..80b2361654 --- /dev/null +++ b/static/doc/v1.4.0/_static/plugin_log.rst @@ -0,0 +1,143 @@ +.. _logging: + +Logging Plugin API +================== + +Servers and clients define a logger in their configuration. The logger is a +plugin. A default plugin that logs to ``stdout`` is provided as an example. +The logger plugin is stateful and can point to custom data. So it is possible +to keep open file handlers in the logger context. + +Every log message consists of a log level, a log category and a string +message content. The timestamp of the log message is created within the +logger. + +.. code-block:: c + + + typedef enum { + UA_LOGLEVEL_TRACE = 100, + UA_LOGLEVEL_DEBUG = 200, + UA_LOGLEVEL_INFO = 300, + UA_LOGLEVEL_WARNING = 400, + UA_LOGLEVEL_ERROR = 500, + UA_LOGLEVEL_FATAL = 600 + } UA_LogLevel; + + #define UA_LOGCATEGORIES 10 + + typedef enum { + UA_LOGCATEGORY_NETWORK = 0, + UA_LOGCATEGORY_SECURECHANNEL, + UA_LOGCATEGORY_SESSION, + UA_LOGCATEGORY_SERVER, + UA_LOGCATEGORY_CLIENT, + UA_LOGCATEGORY_USERLAND, + UA_LOGCATEGORY_SECURITYPOLICY, + UA_LOGCATEGORY_EVENTLOOP, + UA_LOGCATEGORY_PUBSUB, + UA_LOGCATEGORY_DISCOVERY + } UA_LogCategory; + + typedef struct UA_Logger { + /* Log a message. The message string and following varargs are formatted + * according to the rules of the printf command. Use the convenience macros + * below that take the minimum log level defined in ua_config.h into + * account. */ + void (*log)(void *logContext, UA_LogLevel level, UA_LogCategory category, + const char *msg, va_list args); + + void *context; /* Logger state */ + + void (*clear)(struct UA_Logger *logger); /* Clean up the logger plugin */ + } UA_Logger; + + static UA_INLINE UA_FORMAT(3,4) void + UA_LOG_TRACE(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) { + #if UA_LOGLEVEL <= 100 + if(!logger || !logger->log) + return; + va_list args; va_start(args, msg); + logger->log(logger->context, UA_LOGLEVEL_TRACE, category, msg, args); + va_end(args); + #else + (void) logger; + (void) category; + (void) msg; + #endif + } + + static UA_INLINE UA_FORMAT(3,4) void + UA_LOG_DEBUG(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) { + #if UA_LOGLEVEL <= 200 + if(!logger || !logger->log) + return; + va_list args; va_start(args, msg); + logger->log(logger->context, UA_LOGLEVEL_DEBUG, category, msg, args); + va_end(args); + #else + (void) logger; + (void) category; + (void) msg; + #endif + } + + static UA_INLINE UA_FORMAT(3,4) void + UA_LOG_INFO(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) { + #if UA_LOGLEVEL <= 300 + if(!logger || !logger->log) + return; + va_list args; va_start(args, msg); + logger->log(logger->context, UA_LOGLEVEL_INFO, category, msg, args); + va_end(args); + #else + (void) logger; + (void) category; + (void) msg; + #endif + } + + static UA_INLINE UA_FORMAT(3,4) void + UA_LOG_WARNING(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) { + #if UA_LOGLEVEL <= 400 + if(!logger || !logger->log) + return; + va_list args; va_start(args, msg); + logger->log(logger->context, UA_LOGLEVEL_WARNING, category, msg, args); + va_end(args); + #else + (void) logger; + (void) category; + (void) msg; + #endif + } + + static UA_INLINE UA_FORMAT(3,4) void + UA_LOG_ERROR(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) { + #if UA_LOGLEVEL <= 500 + if(!logger || !logger->log) + return; + va_list args; va_start(args, msg); + logger->log(logger->context, UA_LOGLEVEL_ERROR, category, msg, args); + va_end(args); + #else + (void) logger; + (void) category; + (void) msg; + #endif + } + + static UA_INLINE UA_FORMAT(3,4) void + UA_LOG_FATAL(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) { + #if UA_LOGLEVEL <= 600 + if(!logger || !logger->log) + return; + va_list args; va_start(args, msg); + logger->log(logger->context, UA_LOGLEVEL_FATAL, category, msg, args); + va_end(args); + #else + (void) logger; + (void) category; + (void) msg; + #endif + } diff --git a/static/doc/v1.4.0/_static/plugin_nodestore.rst b/static/doc/v1.4.0/_static/plugin_nodestore.rst new file mode 100644 index 0000000000..739c9ed874 --- /dev/null +++ b/static/doc/v1.4.0/_static/plugin_nodestore.rst @@ -0,0 +1,868 @@ +Node Store Plugin API +===================== + +**Warning!!** The structures defined in this section are only relevant for +the developers of custom Nodestores. The interaction with the information +model is possible only via the OPC UA :ref:`services`. So the following +sections are purely informational so that users may have a clear mental +model of the underlying representation. + +.. _node-lifecycle: + +Node Lifecycle: Constructors, Destructors and Node Contexts +----------------------------------------------------------- + +To finalize the instantiation of a node, a (user-defined) constructor +callback is executed. There can be both a global constructor for all nodes +and node-type constructor specific to the TypeDefinition of the new node +(attached to an ObjectTypeNode or VariableTypeNode). + +In the hierarchy of ObjectTypes and VariableTypes, only the constructor of +the (lowest) type defined for the new node is executed. Note that every +Object and Variable can have only one ``isTypeOf`` reference. But type-nodes +can technically have several ``hasSubType`` references to implement multiple +inheritance. Issues of (multiple) inheritance in the constructor need to be +solved by the user. + +When a node is destroyed, the node-type destructor is called before the +global destructor. So the overall node lifecycle is as follows: + +1. Global Constructor (set in the server config) +2. Node-Type Constructor (for VariableType or ObjectTypes) +3. (Usage-period of the Node) +4. Node-Type Destructor +5. Global Destructor + +The constructor and destructor callbacks can be set to ``NULL`` and are not +used in that case. If the node-type constructor fails, the global destructor +will be called before removing the node. The destructors are assumed to never +fail. + +Every node carries a user-context and a constructor-context pointer. The +user-context is used to attach custom data to a node. But the (user-defined) +constructors and destructors may replace the user-context pointer if they +wish to do so. The initial value for the constructor-context is ``NULL``. +When the ``AddNodes`` service is used over the network, the user-context +pointer of the new node is also initially set to ``NULL``. + +Global Node Lifecycle +~~~~~~~~~~~~~~~~~~~~~~ +Global constructor and destructor callbacks used for every node type. +To be set in the server config. + +.. code-block:: c + + + typedef struct { + /* Can be NULL. May replace the nodeContext */ + UA_StatusCode (*constructor)(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void **nodeContext); + + /* Can be NULL. The context cannot be replaced since the node is destroyed + * immediately afterwards anyway. */ + void (*destructor)(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext); + + /* Can be NULL. Called during recursive node instantiation. While mandatory + * child nodes are automatically created if not already present, optional child + * nodes are not. This callback can be used to define whether an optional child + * node should be created. + * + * @param server The server executing the callback + * @param sessionId The identifier of the session + * @param sessionContext Additional data attached to the session in the + * access control layer + * @param sourceNodeId Source node from the type definition. If the new node + * shall be created, it will be a copy of this node. + * @param targetParentNodeId Parent of the potential new child node + * @param referenceTypeId Identifies the reference type which that the parent + * node has to the new node. + * @return Return UA_TRUE if the child node shall be instantiated, + * UA_FALSE otherwise. */ + UA_Boolean (*createOptionalChild)(UA_Server *server, + const UA_NodeId *sessionId, + void *sessionContext, + const UA_NodeId *sourceNodeId, + const UA_NodeId *targetParentNodeId, + const UA_NodeId *referenceTypeId); + + /* Can be NULL. Called when a node is to be copied during recursive + * node instantiation. Allows definition of the NodeId for the new node. + * If the callback is set to NULL or the resulting NodeId is UA_NODEID_NUMERIC(X,0) + * an unused nodeid in namespace X will be used. E.g. passing UA_NODEID_NULL will + * result in a NodeId in namespace 0. + * + * @param server The server executing the callback + * @param sessionId The identifier of the session + * @param sessionContext Additional data attached to the session in the + * access control layer + * @param sourceNodeId Source node of the copy operation + * @param targetParentNodeId Parent node of the new node + * @param referenceTypeId Identifies the reference type which that the parent + * node has to the new node. */ + UA_StatusCode (*generateChildNodeId)(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *sourceNodeId, + const UA_NodeId *targetParentNodeId, + const UA_NodeId *referenceTypeId, + UA_NodeId *targetNodeId); + } UA_GlobalNodeLifecycle; + +Node Type Lifecycle +~~~~~~~~~~~~~~~~~~~ +Constructor and destructors for specific object and variable types. + +.. code-block:: c + + typedef struct { + /* Can be NULL. May replace the nodeContext */ + UA_StatusCode (*constructor)(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *typeNodeId, void *typeNodeContext, + const UA_NodeId *nodeId, void **nodeContext); + + /* Can be NULL. May replace the nodeContext. */ + void (*destructor)(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *typeNodeId, void *typeNodeContext, + const UA_NodeId *nodeId, void **nodeContext); + } UA_NodeTypeLifecycle; + +ReferenceType Bitfield Representation +------------------------------------- +ReferenceTypes have an alternative represention as an index into a bitfield +for fast comparison. The index is generated when the corresponding +ReferenceTypeNode is added. By bounding the number of ReferenceTypes that can +exist in the server, the bitfield can represent a set of an combination of +ReferenceTypes. + +Every ReferenceTypeNode contains a bitfield with the set of all its subtypes. +This speeds up the Browse services substantially. + +The following ReferenceTypes have a fixed index. The NS0 bootstrapping +creates these ReferenceTypes in-order. + +.. code-block:: c + + #define UA_REFERENCETYPEINDEX_REFERENCES 0 + #define UA_REFERENCETYPEINDEX_HASSUBTYPE 1 + #define UA_REFERENCETYPEINDEX_AGGREGATES 2 + #define UA_REFERENCETYPEINDEX_HIERARCHICALREFERENCES 3 + #define UA_REFERENCETYPEINDEX_NONHIERARCHICALREFERENCES 4 + #define UA_REFERENCETYPEINDEX_HASCHILD 5 + #define UA_REFERENCETYPEINDEX_ORGANIZES 6 + #define UA_REFERENCETYPEINDEX_HASEVENTSOURCE 7 + #define UA_REFERENCETYPEINDEX_HASMODELLINGRULE 8 + #define UA_REFERENCETYPEINDEX_HASENCODING 9 + #define UA_REFERENCETYPEINDEX_HASDESCRIPTION 10 + #define UA_REFERENCETYPEINDEX_HASTYPEDEFINITION 11 + #define UA_REFERENCETYPEINDEX_GENERATESEVENT 12 + #define UA_REFERENCETYPEINDEX_HASPROPERTY 13 + #define UA_REFERENCETYPEINDEX_HASCOMPONENT 14 + #define UA_REFERENCETYPEINDEX_HASNOTIFIER 15 + #define UA_REFERENCETYPEINDEX_HASORDEREDCOMPONENT 16 + #define UA_REFERENCETYPEINDEX_HASINTERFACE 17 + + /* The maximum number of ReferrenceTypes. Must be a multiple of 32. */ + #define UA_REFERENCETYPESET_MAX 128 + typedef struct { + UA_UInt32 bits[UA_REFERENCETYPESET_MAX / 32]; + } UA_ReferenceTypeSet; + + extern const UA_ReferenceTypeSet UA_REFERENCETYPESET_NONE; + extern const UA_ReferenceTypeSet UA_REFERENCETYPESET_ALL; + + static UA_INLINE void + UA_ReferenceTypeSet_init(UA_ReferenceTypeSet *set) { + memset(set, 0, sizeof(UA_ReferenceTypeSet)); + } + + static UA_INLINE UA_ReferenceTypeSet + UA_REFTYPESET(UA_Byte index) { + UA_Byte i = index / 32, j = index % 32; + UA_ReferenceTypeSet set; + UA_ReferenceTypeSet_init(&set); + set.bits[i] |= ((UA_UInt32)1) << j; + return set; + } + + static UA_INLINE UA_ReferenceTypeSet + UA_ReferenceTypeSet_union(const UA_ReferenceTypeSet setA, + const UA_ReferenceTypeSet setB) { + UA_ReferenceTypeSet set; + for(size_t i = 0; i < UA_REFERENCETYPESET_MAX / 32; i++) + set.bits[i] = setA.bits[i] | setB.bits[i]; + return set; + } + + static UA_INLINE UA_Boolean + UA_ReferenceTypeSet_contains(const UA_ReferenceTypeSet *set, UA_Byte index) { + UA_Byte i = index / 32, j = index % 32; + return !!(set->bits[i] & (((UA_UInt32)1) << j)); + } + +Node Pointer +------------ + +The "native" format for reference between nodes is the ExpandedNodeId. That +is, references can also point to external servers. In practice, most +references point to local nodes using numerical NodeIds from the +standard-defined namespace zero. In order to save space (and time), +pointer-tagging is used for compressed "NodePointer" representations. +Numerical NodeIds are immediately contained in the pointer. Full NodeIds and +ExpandedNodeIds are behind a pointer indirection. If the Nodestore supports +it, a NodePointer can also be an actual pointer to the target node. + +Depending on the processor architecture, some numerical NodeIds don't fit +into an immediate encoding and are kept as pointers. ExpandedNodeIds may be +internally translated to "normal" NodeIds. Use the provided functions to +generate NodePointers that fit the assumptions for the local architecture. + +.. code-block:: c + + + /* Forward declaration. All node structures begin with the NodeHead. */ + struct UA_NodeHead; + typedef struct UA_NodeHead UA_NodeHead; + + /* Tagged Pointer structure. */ + typedef union { + uintptr_t immediate; /* 00: Small numerical NodeId */ + const UA_NodeId *id; /* 01: Pointer to NodeId */ + const UA_ExpandedNodeId *expandedId; /* 10: Pointer to ExternalNodeId */ + const UA_NodeHead *node; /* 11: Pointer to a node */ + } UA_NodePointer; + + /* Sets the pointer to an immediate NodeId "ns=0;i=0" similar to a freshly + * initialized UA_NodeId */ + static UA_INLINE void + UA_NodePointer_init(UA_NodePointer *np) { np->immediate = 0; } + + /* NodeId and ExpandedNodeId targets are freed */ + void + UA_NodePointer_clear(UA_NodePointer *np); + + /* Makes a deep copy */ + UA_StatusCode + UA_NodePointer_copy(UA_NodePointer in, UA_NodePointer *out); + + /* Test if an ExpandedNodeId or a local NodeId */ + UA_Boolean + UA_NodePointer_isLocal(UA_NodePointer np); + + UA_Order + UA_NodePointer_order(UA_NodePointer p1, UA_NodePointer p2); + + static UA_INLINE UA_Boolean + UA_NodePointer_equal(UA_NodePointer p1, UA_NodePointer p2) { + return (UA_NodePointer_order(p1, p2) == UA_ORDER_EQ); + } + + /* Cannot fail. The resulting NodePointer can point to the memory from the + * NodeId. Make a deep copy if required. */ + UA_NodePointer + UA_NodePointer_fromNodeId(const UA_NodeId *id); + + /* Cannot fail. The resulting NodePointer can point to the memory from the + * ExpandedNodeId. Make a deep copy if required. */ + UA_NodePointer + UA_NodePointer_fromExpandedNodeId(const UA_ExpandedNodeId *id); + + /* Can point to the memory from the NodePointer */ + UA_ExpandedNodeId + UA_NodePointer_toExpandedNodeId(UA_NodePointer np); + + /* Can point to the memory from the NodePointer. Discards the ServerIndex and + * NamespaceUri of a potential ExpandedNodeId inside the NodePointer. Test + * before if the NodePointer is local. */ + UA_NodeId + UA_NodePointer_toNodeId(UA_NodePointer np); + +Base Node Attributes +-------------------- + +Nodes contain attributes according to their node type. The base node +attributes are common to all node types. In the OPC UA :ref:`services`, +attributes are referred to via the :ref:`nodeid` of the containing node and +an integer :ref:`attribute-id`. + +Internally, open62541 uses ``UA_Node`` in places where the exact node type is +not known or not important. The ``nodeClass`` attribute is used to ensure the +correctness of casting from ``UA_Node`` to a specific node type. + +.. code-block:: c + + + typedef struct { + UA_NodePointer targetId; /* Has to be the first entry */ + UA_UInt32 targetNameHash; /* Hash of the target's BrowseName. Set to zero + * if the target is remote. */ + } UA_ReferenceTarget; + + typedef struct UA_ReferenceTargetTreeElem { + UA_ReferenceTarget target; /* Has to be the first entry */ + UA_UInt32 targetIdHash; /* Hash of the targetId */ + struct { + struct UA_ReferenceTargetTreeElem *left; + struct UA_ReferenceTargetTreeElem *right; + } idTreeEntry; + struct { + struct UA_ReferenceTargetTreeElem *left; + struct UA_ReferenceTargetTreeElem *right; + } nameTreeEntry; + } UA_ReferenceTargetTreeElem; + + + /* List of reference targets with the same reference type and direction. Uses + * either an array or a tree structure. The SDK will not change the type of + * reference target structure internally. The nodestore implementations may + * switch internally when a node is updated. + * + * The recommendation is to switch to a tree once the number of refs > 8. */ + typedef struct { + union { + /* Organize the references in an array. Uses less memory, but incurs + * lookups in linear time. Recommended if the number of references is + * known to be small. */ + UA_ReferenceTarget *array; + + /* Organize the references in a tree for fast lookup. Use + * UA_Node_addReference and UA_Node_deleteReference to modify the + * tree-structure. The binary tree implementation (and absolute ordering + * / duplicate browseNames are allowed) are not exposed otherwise in the + * public API. */ + struct { + UA_ReferenceTargetTreeElem *idRoot; /* Lookup based on target id */ + UA_ReferenceTargetTreeElem *nameRoot; /* Lookup based on browseName*/ + } tree; + } targets; + size_t targetsSize; + UA_Boolean hasRefTree; /* RefTree or RefArray? */ + UA_Byte referenceTypeIndex; + UA_Boolean isInverse; + } UA_NodeReferenceKind; + + /* Iterate over the references. Aborts when the first callback return a non-NULL + * pointer and returns that pointer. Do not modify the reference targets during + * the iteration. */ + typedef void * + (*UA_NodeReferenceKind_iterateCallback)(void *context, UA_ReferenceTarget *target); + + void * + UA_NodeReferenceKind_iterate(UA_NodeReferenceKind *rk, + UA_NodeReferenceKind_iterateCallback callback, + void *context); + + /* Returns the entry for the targetId or NULL if not found */ + const UA_ReferenceTarget * + UA_NodeReferenceKind_findTarget(const UA_NodeReferenceKind *rk, + const UA_ExpandedNodeId *targetId); + + /* Switch between array and tree representation. Does nothing upon error (e.g. + * out-of-memory). */ + UA_StatusCode + UA_NodeReferenceKind_switch(UA_NodeReferenceKind *rk); + + /* Singly-linked LocalizedText list */ + typedef struct UA_LocalizedTextListEntry { + struct UA_LocalizedTextListEntry *next; + UA_LocalizedText localizedText; + } UA_LocalizedTextListEntry; + + /* Every Node starts with these attributes */ + struct UA_NodeHead { + UA_NodeId nodeId; + UA_NodeClass nodeClass; + UA_QualifiedName browseName; + + /* A node can have different localizations for displayName and description. + * The server selects a suitable localization depending on the locale ids + * that are set for the current session. + * + * Locales are added simply by writing a LocalizedText value with a new + * locale. A locale can be removed by writing a LocalizedText value of the + * corresponding locale with an empty text field. */ + UA_LocalizedTextListEntry *displayName; + UA_LocalizedTextListEntry *description; + + UA_UInt32 writeMask; + size_t referencesSize; + UA_NodeReferenceKind *references; + + /* Members specific to open62541 */ + void *context; + UA_Boolean constructed; /* Constructors were called */ + #ifdef UA_ENABLE_SUBSCRIPTIONS + UA_MonitoredItem *monitoredItems; /* MonitoredItems for Events and immediate + * DataChanges (no sampling interval). */ + #endif + }; + +VariableNode +------------ + +.. code-block:: c + + + /* Indicates whether a variable contains data inline or whether it points to an + * external data source */ + typedef enum { + UA_VALUESOURCE_DATA, + UA_VALUESOURCE_DATASOURCE + } UA_ValueSource; + + typedef struct { + /* Called before the value attribute is read. It is possible to write into the + * value attribute during onRead (using the write service). The node is + * re-opened afterwards so that changes are considered in the following read + * operation. + * + * @param handle Points to user-provided data for the callback. + * @param nodeid The identifier of the node. + * @param data Points to the current node value. + * @param range Points to the numeric range the client wants to read from + * (or NULL). */ + void (*onRead)(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeid, + void *nodeContext, const UA_NumericRange *range, + const UA_DataValue *value); + + /* Called after writing the value attribute. The node is re-opened after + * writing so that the new value is visible in the callback. + * + * @param server The server executing the callback + * @sessionId The identifier of the session + * @sessionContext Additional data attached to the session + * in the access control layer + * @param nodeid The identifier of the node. + * @param nodeUserContext Additional data attached to the node by + * the user. + * @param nodeConstructorContext Additional data attached to the node + * by the type constructor(s). + * @param range Points to the numeric range the client wants to write to (or + * NULL). */ + void (*onWrite)(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeId, + void *nodeContext, const UA_NumericRange *range, + const UA_DataValue *data); + } UA_ValueCallback; + + typedef struct { + /* Copies the data from the source into the provided value. + * + * !! ZERO-COPY OPERATIONS POSSIBLE !! + * It is not required to return a copy of the actual content data. You can + * return a pointer to memory owned by the user. Memory can be reused + * between read callbacks of a DataSource, as the result is already encoded + * on the network buffer between each read operation. + * + * To use zero-copy reads, set the value of the `value->value` Variant + * without copying, e.g. with `UA_Variant_setScalar`. Then, also set + * `value->value.storageType` to `UA_VARIANT_DATA_NODELETE` to prevent the + * memory being cleaned up. Don't forget to also set `value->hasValue` to + * true to indicate the presence of a value. + * + * @param server The server executing the callback + * @param sessionId The identifier of the session + * @param sessionContext Additional data attached to the session in the + * access control layer + * @param nodeId The identifier of the node being read from + * @param nodeContext Additional data attached to the node by the user + * @param includeSourceTimeStamp If true, then the datasource is expected to + * set the source timestamp in the returned value + * @param range If not null, then the datasource shall return only a + * selection of the (nonscalar) data. Set + * UA_STATUSCODE_BADINDEXRANGEINVALID in the value if this does not + * apply + * @param value The (non-null) DataValue that is returned to the client. The + * data source sets the read data, the result status and optionally a + * sourcetimestamp. + * @return Returns a status code for logging. Error codes intended for the + * original caller are set in the value. If an error is returned, + * then no releasing of the value is done + */ + UA_StatusCode (*read)(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeId, + void *nodeContext, UA_Boolean includeSourceTimeStamp, + const UA_NumericRange *range, UA_DataValue *value); + + /* Write into a data source. This method pointer can be NULL if the + * operation is unsupported. + * + * @param server The server executing the callback + * @param sessionId The identifier of the session + * @param sessionContext Additional data attached to the session in the + * access control layer + * @param nodeId The identifier of the node being written to + * @param nodeContext Additional data attached to the node by the user + * @param range If not NULL, then the datasource shall return only a + * selection of the (nonscalar) data. Set + * UA_STATUSCODE_BADINDEXRANGEINVALID in the value if this does not + * apply + * @param value The (non-NULL) DataValue that has been written by the client. + * The data source contains the written data, the result status and + * optionally a sourcetimestamp + * @return Returns a status code for logging. Error codes intended for the + * original caller are set in the value. If an error is returned, + * then no releasing of the value is done + */ + UA_StatusCode (*write)(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeId, + void *nodeContext, const UA_NumericRange *range, + const UA_DataValue *value); + } UA_DataSource; + +.. _value-callback: + +Value Callback +~~~~~~~~~~~~~~ +Value Callbacks can be attached to variable and variable type nodes. If +not ``NULL``, they are called before reading and after writing respectively. + +.. code-block:: c + + typedef struct { + /* Called before the value attribute is read. The external value source can be + * be updated and/or locked during this notification call. After this function returns + * to the core, the external value source is readed immediately. + */ + UA_StatusCode (*notificationRead)(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeid, + void *nodeContext, const UA_NumericRange *range); + + /* Called after writing the value attribute. The node is re-opened after + * writing so that the new value is visible in the callback. + * + * @param server The server executing the callback + * @sessionId The identifier of the session + * @sessionContext Additional data attached to the session + * in the access control layer + * @param nodeid The identifier of the node. + * @param nodeUserContext Additional data attached to the node by + * the user. + * @param nodeConstructorContext Additional data attached to the node + * by the type constructor(s). + * @param range Points to the numeric range the client wants to write to (or + * NULL). */ + UA_StatusCode (*userWrite)(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeId, + void *nodeContext, const UA_NumericRange *range, + const UA_DataValue *data); + } UA_ExternalValueCallback; + + typedef enum { + UA_VALUEBACKENDTYPE_NONE, + UA_VALUEBACKENDTYPE_INTERNAL, + UA_VALUEBACKENDTYPE_DATA_SOURCE_CALLBACK, + UA_VALUEBACKENDTYPE_EXTERNAL + } UA_ValueBackendType; + + typedef struct { + UA_ValueBackendType backendType; + union { + struct { + UA_DataValue value; + UA_ValueCallback callback; + } internal; + UA_DataSource dataSource; + struct { + UA_DataValue **value; + UA_ExternalValueCallback callback; + } external; + } backend; + } UA_ValueBackend; + + #define UA_NODE_VARIABLEATTRIBUTES \ + /* Constraints on possible values */ \ + UA_NodeId dataType; \ + UA_Int32 valueRank; \ + size_t arrayDimensionsSize; \ + UA_UInt32 *arrayDimensions; \ + \ + UA_ValueBackend valueBackend; \ + \ + /* The current value */ \ + UA_ValueSource valueSource; \ + union { \ + struct { \ + UA_DataValue value; \ + UA_ValueCallback callback; \ + } data; \ + UA_DataSource dataSource; \ + } value; + + typedef struct { + UA_NodeHead head; + UA_NODE_VARIABLEATTRIBUTES + UA_Byte accessLevel; + UA_Double minimumSamplingInterval; + UA_Boolean historizing; + + /* Members specific to open62541 */ + UA_Boolean isDynamic; /* Some variables are "static" in the sense that they + * are not attached to a dynamic process in the + * background. Only dynamic variables conserve source + * and server timestamp for the value attribute. + * Static variables have timestamps of "now". */ + } UA_VariableNode; + +VariableTypeNode +---------------- + +.. code-block:: c + + + typedef struct { + UA_NodeHead head; + UA_NODE_VARIABLEATTRIBUTES + UA_Boolean isAbstract; + + /* Members specific to open62541 */ + UA_NodeTypeLifecycle lifecycle; + } UA_VariableTypeNode; + +MethodNode +---------- + +.. code-block:: c + + + typedef UA_StatusCode + (*UA_MethodCallback)(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *methodId, + void *methodContext, const UA_NodeId *objectId, + void *objectContext, size_t inputSize, + const UA_Variant *input, size_t outputSize, + UA_Variant *output); + + typedef struct { + UA_NodeHead head; + UA_Boolean executable; + + /* Members specific to open62541 */ + UA_MethodCallback method; + #if UA_MULTITHREADING >= 100 + UA_Boolean async; /* Indicates an async method call */ + #endif + } UA_MethodNode; + +ObjectNode +---------- + +.. code-block:: c + + + typedef struct { + UA_NodeHead head; + UA_Byte eventNotifier; + } UA_ObjectNode; + +ObjectTypeNode +-------------- + +.. code-block:: c + + + typedef struct { + UA_NodeHead head; + UA_Boolean isAbstract; + + /* Members specific to open62541 */ + UA_NodeTypeLifecycle lifecycle; + } UA_ObjectTypeNode; + +ReferenceTypeNode +----------------- + +.. code-block:: c + + + typedef struct { + UA_NodeHead head; + UA_Boolean isAbstract; + UA_Boolean symmetric; + UA_LocalizedText inverseName; + + /* Members specific to open62541 */ + UA_Byte referenceTypeIndex; + UA_ReferenceTypeSet subTypes; /* contains the type itself as well */ + } UA_ReferenceTypeNode; + +DataTypeNode +------------ + +.. code-block:: c + + + typedef struct { + UA_NodeHead head; + UA_Boolean isAbstract; + } UA_DataTypeNode; + +ViewNode +-------- + +.. code-block:: c + + + typedef struct { + UA_NodeHead head; + UA_Byte eventNotifier; + UA_Boolean containsNoLoops; + } UA_ViewNode; + +Node Union +---------- + +A union that represents any kind of node. The node head can always be used. +Check the NodeClass before accessing specific content. + +.. code-block:: c + + + typedef union { + UA_NodeHead head; + UA_VariableNode variableNode; + UA_VariableTypeNode variableTypeNode; + UA_MethodNode methodNode; + UA_ObjectNode objectNode; + UA_ObjectTypeNode objectTypeNode; + UA_ReferenceTypeNode referenceTypeNode; + UA_DataTypeNode dataTypeNode; + UA_ViewNode viewNode; + } UA_Node; + +Nodestore +--------- + +The following definitions are used for implementing custom node storage +backends. **Most users will want to use the default nodestore and don't need +to work with the nodestore API**. + +Outside of custom nodestore implementations, users should not manually edit +nodes. Please use the OPC UA services for that. Otherwise, all consistency +checks are omitted. This can crash the application eventually. + +.. code-block:: c + + + typedef void (*UA_NodestoreVisitor)(void *visitorCtx, const UA_Node *node); + + typedef struct { + /* Nodestore context and lifecycle */ + void *context; + void (*clear)(void *nsCtx); + + /* The following definitions are used to create empty nodes of the different + * node types. The memory is managed by the nodestore. Therefore, the node + * has to be removed via a special deleteNode function. (If the new node is + * not added to the nodestore.) */ + UA_Node * (*newNode)(void *nsCtx, UA_NodeClass nodeClass); + + void (*deleteNode)(void *nsCtx, UA_Node *node); + + /* ``Get`` returns a pointer to an immutable node. Call ``releaseNode`` to + * indicate when the pointer is no longer accessed. + * + * It can be indicated if only a subset of the attributes and referencs need + * to be accessed. That is relevant when the nodestore accesses a slow + * storage backend for the attributes. The attribute mask is a bitfield with + * ORed entries from UA_NodeAttributesMask. + * + * The returned node always contains the context-pointer and other fields + * specific to open626541 (not official attributes). + * + * The NodeStore does not complain if attributes and references that don't + * exist (for that node) are requested. Attributes and references in + * addition to those specified can be returned. For example, if the full + * node already is kept in memory by the Nodestore. */ + const UA_Node * (*getNode)(void *nsCtx, const UA_NodeId *nodeId, + UA_UInt32 attributeMask, + UA_ReferenceTypeSet references, + UA_BrowseDirection referenceDirections); + + /* Similar to the normal ``getNode``. But it can take advantage of the + * NodePointer structure, e.g. if it contains a direct pointer. */ + const UA_Node * (*getNodeFromPtr)(void *nsCtx, UA_NodePointer ptr, + UA_UInt32 attributeMask, + UA_ReferenceTypeSet references, + UA_BrowseDirection referenceDirections); + + /* Release a node that has been retrieved with ``getNode`` or + * ``getNodeFromPtr``. */ + void (*releaseNode)(void *nsCtx, const UA_Node *node); + + /* Returns an editable copy of a node (needs to be deleted with the + * deleteNode function or inserted / replaced into the nodestore). */ + UA_StatusCode (*getNodeCopy)(void *nsCtx, const UA_NodeId *nodeId, + UA_Node **outNode); + + /* Inserts a new node into the nodestore. If the NodeId is zero, then a + * fresh numeric NodeId is assigned. If insertion fails, the node is + * deleted. */ + UA_StatusCode (*insertNode)(void *nsCtx, UA_Node *node, + UA_NodeId *addedNodeId); + + /* To replace a node, get an editable copy of the node, edit and replace + * with this function. If the node was already replaced since the copy was + * made, UA_STATUSCODE_BADINTERNALERROR is returned. If the NodeId is not + * found, UA_STATUSCODE_BADNODEIDUNKNOWN is returned. In both error cases, + * the editable node is deleted. */ + UA_StatusCode (*replaceNode)(void *nsCtx, UA_Node *node); + + /* Removes a node from the nodestore. */ + UA_StatusCode (*removeNode)(void *nsCtx, const UA_NodeId *nodeId); + + /* Maps the ReferenceTypeIndex used for the references to the NodeId of the + * ReferenceType. The returned pointer is stable until the Nodestore is + * deleted. */ + const UA_NodeId * (*getReferenceTypeId)(void *nsCtx, UA_Byte refTypeIndex); + + /* Execute a callback for every node in the nodestore. */ + void (*iterate)(void *nsCtx, UA_NodestoreVisitor visitor, + void *visitorCtx); + } UA_Nodestore; + + /* Attributes must be of a matching type (VariableAttributes, ObjectAttributes, + * and so on). The attributes are copied. Note that the attributes structs do + * not contain NodeId, NodeClass and BrowseName. The NodeClass of the node needs + * to be correctly set before calling this method. UA_Node_clear is called on + * the node when an error occurs internally. */ + UA_StatusCode + UA_Node_setAttributes(UA_Node *node, const void *attributes, + const UA_DataType *attributeType); + + /* Reset the destination node and copy the content of the source */ + UA_StatusCode + UA_Node_copy(const UA_Node *src, UA_Node *dst); + + /* Allocate new node and copy the values from src */ + UA_Node * + UA_Node_copy_alloc(const UA_Node *src); + + /* Add a single reference to the node */ + UA_StatusCode + UA_Node_addReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward, + const UA_ExpandedNodeId *targetNodeId, + UA_UInt32 targetBrowseNameHash); + + /* Delete a single reference from the node */ + UA_StatusCode + UA_Node_deleteReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward, + const UA_ExpandedNodeId *targetNodeId); + + /* Deletes references from the node which are not matching any type in the given + * array. Could be used to e.g. delete all the references, except + * 'HASMODELINGRULE' */ + void + UA_Node_deleteReferencesSubset(UA_Node *node, const UA_ReferenceTypeSet *keepSet); + + /* Delete all references of the node */ + void + UA_Node_deleteReferences(UA_Node *node); + + /* Remove all malloc'ed members of the node and reset */ + void + UA_Node_clear(UA_Node *node); diff --git a/static/doc/v1.4.0/_static/plugin_pki.rst b/static/doc/v1.4.0/_static/plugin_pki.rst new file mode 100644 index 0000000000..a49adf0880 --- /dev/null +++ b/static/doc/v1.4.0/_static/plugin_pki.rst @@ -0,0 +1,59 @@ +Public Key Infrastructure Integration +===================================== +This file contains interface definitions for integration in a Public Key +Infrastructure (PKI). Currently only one plugin interface is defined. + +Certificate Verification +------------------------ +This plugin verifies that the origin of the certificate is trusted. It does +not assign any access rights/roles to the holder of the certificate. + +Usually, implementations of the certificate verification plugin provide an +initialization method that takes a trust-list and a revocation-list as input. +The lifecycle of the plugin is attached to a server or client config. The +``clear`` method is called automatically when the config is destroyed. + +.. code-block:: c + + + struct UA_CertificateVerification; + typedef struct UA_CertificateVerification UA_CertificateVerification; + + struct UA_CertificateVerification { + void *context; + + /* Verify the certificate against the configured policies and trust chain. */ + UA_StatusCode (*verifyCertificate)(const UA_CertificateVerification *cv, + const UA_ByteString *certificate); + + /* Verify that the certificate has the applicationURI in the subject name. */ + UA_StatusCode (*verifyApplicationURI)(const UA_CertificateVerification *cv, + const UA_ByteString *certificate, + const UA_String *applicationURI); + + /* Get the expire date from certificate */ + UA_StatusCode (*getExpirationDate)(UA_DateTime *expiryDateTime, + UA_ByteString *certificate); + + UA_StatusCode (*getSubjectName)(UA_String *subjectName, + UA_ByteString *certificate); + + /* Delete the certificate verification context */ + void (*clear)(UA_CertificateVerification *cv); + + /* Pointer to logging pointer in the server/client configuration. If the + * logging pointer is changed outside of the plugin, the new logger is used + * automatically*/ + const UA_Logger *logging; + }; + + /* Decrypt a private key in PEM format using a password. The output is the key + * in the binary DER format. Also succeeds if the PEM private key does not + * require a password or is already in the DER format. The outDerKey memory is + * allocated internally. + * + * Returns UA_STATUSCODE_BADSECURITYCHECKSFAILED if the password is wrong. */ + UA_StatusCode + UA_PKI_decryptPrivateKey(const UA_ByteString privateKey, + const UA_ByteString password, + UA_ByteString *outDerKey); diff --git a/static/doc/v1.4.0/_static/plugin_securitypolicy.rst b/static/doc/v1.4.0/_static/plugin_securitypolicy.rst new file mode 100644 index 0000000000..41eb1f83cc --- /dev/null +++ b/static/doc/v1.4.0/_static/plugin_securitypolicy.rst @@ -0,0 +1,358 @@ +SecurityPolicy +-------------- + +.. code-block:: c + + + typedef struct { + UA_String uri; + + /* Verifies the signature of the message using the provided keys in the context. + * + * @param channelContext the channelContext that contains the key to verify + * the supplied message with. + * @param message the message to which the signature is supposed to belong. + * @param signature the signature of the message, that should be verified. */ + UA_StatusCode (*verify)(void *channelContext, const UA_ByteString *message, + const UA_ByteString *signature); + + /* Signs the given message using this policys signing algorithm and the + * provided keys in the context. + * + * @param channelContext the channelContext that contains the key to sign + * the supplied message with. + * @param message the message to sign. + * @param signature an output buffer to which the signature is written. The + * buffer needs to be allocated by the caller. The + * necessary size can be acquired with the signatureSize + * attribute of this module. */ + UA_StatusCode (*sign)(void *channelContext, const UA_ByteString *message, + UA_ByteString *signature); + + /* Gets the signature size that depends on the local (private) key. + * + * @param channelContext the channelContext that contains the + * certificate/key. + * @return the size of the local signature. Returns 0 if no local + * certificate was set. */ + size_t (*getLocalSignatureSize)(const void *channelContext); + + /* Gets the signature size that depends on the remote (public) key. + * + * @param channelContext the context to retrieve data from. + * @return the size of the remote signature. Returns 0 if no + * remote certificate was set previousely. */ + size_t (*getRemoteSignatureSize)(const void *channelContext); + + /* Gets the local signing key length. + * + * @param channelContext the context to retrieve data from. + * @return the length of the signing key in bytes. Returns 0 if no length can be found. + */ + size_t (*getLocalKeyLength)(const void *channelContext); + + /* Gets the local signing key length. + * + * @param channelContext the context to retrieve data from. + * @return the length of the signing key in bytes. Returns 0 if no length can be found. + */ + size_t (*getRemoteKeyLength)(const void *channelContext); + } UA_SecurityPolicySignatureAlgorithm; + + typedef struct { + UA_String uri; + + /* Encrypt the given data in place. For asymmetric encryption, the block + * size for plaintext and cypher depend on the remote key (certificate). + * + * @param channelContext the channelContext which contains information about + * the keys to encrypt data. + * @param data the data that is encrypted. The encrypted data will overwrite + * the data that was supplied. */ + UA_StatusCode (*encrypt)(void *channelContext, + UA_ByteString *data); + + /* Decrypts the given ciphertext in place. For asymmetric encryption, the + * block size for plaintext and cypher depend on the local private key. + * + * @param channelContext the channelContext which contains information about + * the keys needed to decrypt the message. + * @param data the data to decrypt. The decryption is done in place. */ + UA_StatusCode (*decrypt)(void *channelContext, + UA_ByteString *data); + + /* Returns the length of the key used to encrypt messages in bits. For + * asymmetric encryption the key length is for the local private key. + * + * @param channelContext the context to retrieve data from. + * @return the length of the local key. Returns 0 if no + * key length is known. */ + size_t (*getLocalKeyLength)(const void *channelContext); + + /* Returns the length of the key to encrypt messages in bits. Depends on the + * key (certificate) from the remote side. + * + * @param channelContext the context to retrieve data from. + * @return the length of the remote key. Returns 0 if no + * key length is known. */ + size_t (*getRemoteKeyLength)(const void *channelContext); + + /* Returns the size of encrypted blocks for sending. For asymmetric + * encryption this depends on the remote key (certificate). For symmetric + * encryption the local and remote encrypted block size are identical. + * + * @param channelContext the context to retrieve data from. + * @return the size of encrypted blocks in bytes. Returns 0 if no key length is known. + */ + size_t (*getRemoteBlockSize)(const void *channelContext); + + /* Returns the size of plaintext blocks for sending. For asymmetric + * encryption this depends on the remote key (certificate). For symmetric + * encryption the local and remote plaintext block size are identical. + * + * @param channelContext the context to retrieve data from. + * @return the size of plaintext blocks in bytes. Returns 0 if no key length is known. + */ + size_t (*getRemotePlainTextBlockSize)(const void *channelContext); + } UA_SecurityPolicyEncryptionAlgorithm; + + typedef struct { + /* The algorithm used to sign and verify certificates. */ + UA_SecurityPolicySignatureAlgorithm signatureAlgorithm; + + /* The algorithm used to encrypt and decrypt messages. */ + UA_SecurityPolicyEncryptionAlgorithm encryptionAlgorithm; + + } UA_SecurityPolicyCryptoModule; + + typedef struct { + /* Generates a thumbprint for the specified certificate. + * + * @param certificate the certificate to make a thumbprint of. + * @param thumbprint an output buffer for the resulting thumbprint. Always + * has the length specified in the thumbprintLength in the + * asymmetricModule. */ + UA_StatusCode (*makeCertificateThumbprint)(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *certificate, + UA_ByteString *thumbprint) + ; + + /* Compares the supplied certificate with the certificate in the endpoint context. + * + * @param securityPolicy the policy data that contains the certificate + * to compare to. + * @param certificateThumbprint the certificate thumbprint to compare to the + * one stored in the context. + * @return if the thumbprints match UA_STATUSCODE_GOOD is returned. If they + * don't match or an error occurred an error code is returned. */ + UA_StatusCode (*compareCertificateThumbprint)(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *certificateThumbprint) + ; + + UA_SecurityPolicyCryptoModule cryptoModule; + } UA_SecurityPolicyAsymmetricModule; + + typedef struct { + /* Pseudo random function that is used to generate the symmetric keys. + * + * For information on what parameters this function receives in what situation, + * refer to the OPC UA specification 1.03 Part6 Table 33 + * + * @param policyContext The context of the policy instance + * @param secret + * @param seed + * @param out an output to write the data to. The length defines the maximum + * number of output bytes that are produced. */ + UA_StatusCode (*generateKey)(void *policyContext, const UA_ByteString *secret, + const UA_ByteString *seed, UA_ByteString *out) + ; + + /* Random generator for generating nonces. + * + * @param policyContext The context of the policy instance + * @param out pointer to a buffer to store the nonce in. Needs to be + * allocated by the caller. The buffer is filled with random + * data. */ + UA_StatusCode (*generateNonce)(void *policyContext, UA_ByteString *out) + ; + + /* + * The length of the nonce used in the SecureChannel as specified in the standard. + */ + size_t secureChannelNonceLength; + + UA_SecurityPolicyCryptoModule cryptoModule; + } UA_SecurityPolicySymmetricModule; + + typedef struct { + /* This method creates a new context data object. + * + * The caller needs to call delete on the received object to free allocated + * memory. Memory is only allocated if the function succeeds so there is no + * need to manually free the memory pointed to by *channelContext or to + * call delete in case of failure. + * + * @param securityPolicy the policy context of the endpoint that is connected + * to. It will be stored in the channelContext for + * further access by the policy. + * @param remoteCertificate the remote certificate contains the remote + * asymmetric key. The certificate will be verified + * and then stored in the context so that its + * details may be accessed. + * @param channelContext the initialized channelContext that is passed to + * functions that work on a context. */ + UA_StatusCode (*newContext)(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *remoteCertificate, + void **channelContext) + ; + + /* Deletes the the security context. */ + void (*deleteContext)(void *channelContext); + + /* Sets the local encrypting key in the supplied context. + * + * @param channelContext the context to work on. + * @param key the local encrypting key to store in the context. */ + UA_StatusCode (*setLocalSymEncryptingKey)(void *channelContext, + const UA_ByteString *key) + ; + + /* Sets the local signing key in the supplied context. + * + * @param channelContext the context to work on. + * @param key the local signing key to store in the context. */ + UA_StatusCode (*setLocalSymSigningKey)(void *channelContext, + const UA_ByteString *key) + ; + + /* Sets the local initialization vector in the supplied context. + * + * @param channelContext the context to work on. + * @param iv the local initialization vector to store in the context. */ + UA_StatusCode (*setLocalSymIv)(void *channelContext, + const UA_ByteString *iv) + ; + + /* Sets the remote encrypting key in the supplied context. + * + * @param channelContext the context to work on. + * @param key the remote encrypting key to store in the context. */ + UA_StatusCode (*setRemoteSymEncryptingKey)(void *channelContext, + const UA_ByteString *key) + ; + + /* Sets the remote signing key in the supplied context. + * + * @param channelContext the context to work on. + * @param key the remote signing key to store in the context. */ + UA_StatusCode (*setRemoteSymSigningKey)(void *channelContext, + const UA_ByteString *key) + ; + + /* Sets the remote initialization vector in the supplied context. + * + * @param channelContext the context to work on. + * @param iv the remote initialization vector to store in the context. */ + UA_StatusCode (*setRemoteSymIv)(void *channelContext, + const UA_ByteString *iv) + ; + + /* Compares the supplied certificate with the certificate in the channel + * context. + * + * @param channelContext the channel context data that contains the + * certificate to compare to. + * @param certificate the certificate to compare to the one stored in the context. + * @return if the certificates match UA_STATUSCODE_GOOD is returned. If they + * don't match or an errror occurred an error code is returned. */ + UA_StatusCode (*compareCertificate)(const void *channelContext, + const UA_ByteString *certificate) + ; + } UA_SecurityPolicyChannelModule; + + struct UA_SecurityPolicy { + /* Additional data */ + void *policyContext; + + /* The policy uri that identifies the implemented algorithms */ + UA_String policyUri; + + /* The local certificate is specific for each SecurityPolicy since it + * depends on the used key length. */ + UA_ByteString localCertificate; + + /* Function pointers grouped into modules */ + UA_SecurityPolicyAsymmetricModule asymmetricModule; + UA_SecurityPolicySymmetricModule symmetricModule; + UA_SecurityPolicySignatureAlgorithm certificateSigningAlgorithm; + UA_SecurityPolicyChannelModule channelModule; + + const UA_Logger *logger; + + /* Updates the ApplicationInstanceCertificate and the corresponding private + * key at runtime. */ + UA_StatusCode (*updateCertificateAndPrivateKey)(UA_SecurityPolicy *policy, + const UA_ByteString newCertificate, + const UA_ByteString newPrivateKey); + + /* Deletes the dynamic content of the policy */ + void (*clear)(UA_SecurityPolicy *policy); + }; + +PubSub SecurityPolicy +--------------------- + +For PubSub encryption, the message nonce is part of the (unencrypted) +SecurityHeader. The nonce is required for the de- and encryption and has to +be set in the channel context before de/encrypting. + +.. code-block:: c + + + #ifdef UA_ENABLE_PUBSUB_ENCRYPTION + struct UA_PubSubSecurityPolicy; + typedef struct UA_PubSubSecurityPolicy UA_PubSubSecurityPolicy; + + struct UA_PubSubSecurityPolicy { + UA_String policyUri; /* The policy uri that identifies the implemented + * algorithms */ + UA_SecurityPolicySymmetricModule symmetricModule; + + /* Create the context for the WriterGroup. The keys and nonce can be NULL + * here. Then they have to be set before the first encryption or signing + * operation. */ + UA_StatusCode + (*newContext)(void *policyContext, + const UA_ByteString *signingKey, + const UA_ByteString *encryptingKey, + const UA_ByteString *keyNonce, + void **wgContext); + + /* Delete the WriterGroup SecurityPolicy context */ + void (*deleteContext)(void *wgContext); + + /* Set the keys and nonce for the WriterGroup. This is returned from the + * GetSecurityKeys method of a Security Key Service (SKS). Otherwise, set + * manually via out-of-band transmission of the keys. */ + UA_StatusCode + (*setSecurityKeys)(void *wgContext, + const UA_ByteString *signingKey, + const UA_ByteString *encryptingKey, + const UA_ByteString *keyNonce) + ; + + /* The nonce is contained in the NetworkMessage SecurityHeader. Set before + * each en-/decryption step. */ + UA_StatusCode + (*setMessageNonce)(void *wgContext, + const UA_ByteString *nonce) + ; + + const UA_Logger *logger; + + /* Deletes the dynamic content of the policy */ + void (*clear)(UA_PubSubSecurityPolicy *policy); + void *policyContext; + }; + + #endif diff --git a/static/doc/v1.4.0/_static/plus.png b/static/doc/v1.4.0/_static/plus.png new file mode 100644 index 0000000000..7107cec93a Binary files /dev/null and b/static/doc/v1.4.0/_static/plus.png differ diff --git a/static/doc/v1.4.0/_static/pubsub.rst b/static/doc/v1.4.0/_static/pubsub.rst new file mode 100644 index 0000000000..7be9c7898f --- /dev/null +++ b/static/doc/v1.4.0/_static/pubsub.rst @@ -0,0 +1,977 @@ +.. _pubsub: + +PubSub +====== + +In PubSub the participating OPC UA Applications take their roles as +Publishers and Subscribers. Publishers are the sources of data, while +Subscribers consume that data. Communication in PubSub is message-based. +Publishers send messages to a Message Oriented Middleware, without knowledge +of what, if any, Subscribers there may be. Similarly, Subscribers express +interest in specific types of data, and process messages that contain this +data, without knowledge of what Publishers there are. + +Message Oriented Middleware is software or hardware infrastructure that +supports sending and receiving messages between distributed systems. OPC UA +PubSub supports two different Message Oriented Middleware variants, namely +the broker-less form and broker-based form. A broker-less form is where the +Message Oriented Middleware is the network infrastructure that is able to +route datagram-based messages. Subscribers and Publishers use datagram +protocols like UDP. In a broker-based form, the core component of the Message +Oriented Middleware is a message Broker. Subscribers and Publishers use +standard messaging protocols like AMQP or MQTT to communicate with the +Broker. + +This makes PubSub suitable for applications where location independence +and/or scalability are required. + +The Publish/Subscribe (PubSub) extension for OPC UA enables fast and +efficient 1:m communication. The PubSub extension is protocol agnostic and +can be used with broker based protocols like MQTT and AMQP or brokerless +implementations like UDP-Multicasting. + +The configuration model for PubSub uses the following components: + +.. code-block:: c + + + typedef enum { + UA_PUBSUB_COMPONENT_CONNECTION, + UA_PUBSUB_COMPONENT_WRITERGROUP, + UA_PUBSUB_COMPONENT_DATASETWRITER, + UA_PUBSUB_COMPONENT_READERGROUP, + UA_PUBSUB_COMPONENT_DATASETREADER + } UA_PubSubComponentEnumType; + +The open62541 PubSub API uses the following scheme: + +1. Create a configuration for the needed PubSub element. + +2. Call the add[element] function and pass in the configuration. + +3. The add[element] function returns the unique nodeId of the internally created element. + +Take a look on the PubSub Tutorials for more details about the API usage:: + + +-----------+ + | UA_Server | + +-----------+ + | | + | | + | | + | | +----------------------+ + | +--> UA_PubSubConnection | UA_Server_addPubSubConnection + | +----------------------+ + | | | + | | | +----------------+ + | | +----> UA_WriterGroup | UA_PubSubConnection_addWriterGroup + | | +----------------+ + | | | + | | | +------------------+ + | | +----> UA_DataSetWriter | UA_WriterGroup_addDataSetWriter +-+ + | | +------------------+ | + | | | + | | +----------------+ | r + | +---------> UA_ReaderGroup | UA_PubSubConnection_addReaderGroup | e + | +----------------+ | f + | | | + | | +------------------+ | + | +----> UA_DataSetReader | UA_ReaderGroup_addDataSetReader | + | +------------------+ | + | | | + | | +----------------------+ | + | +----> UA_SubscribedDataSet | | + | +----------------------+ | + | | | + | | +----------------------------+ | + | +----> UA_TargetVariablesDataType | | + | | +----------------------------+ | + | | | + | | +------------------------------------+ | + | +----> UA_SubscribedDataSetMirrorDataType | | + | +------------------------------------+ | + | | + | +---------------------------+ | + +-------> UA_PubSubPublishedDataSet | UA_Server_addPublishedDataSet <-+ + +---------------------------+ + | + | +-----------------+ + +----> UA_DataSetField | UA_PublishedDataSet_addDataSetField + +-----------------+ + +PubSub Information Model Representation +--------------------------------------- +.. _pubsub_informationmodel: + +The complete PubSub configuration is available inside the information model. +The entry point is the node 'PublishSubscribe', located under the Server +node. +The standard defines for PubSub no new Service set. The configuration can +optionally be done over methods inside the information model. +The information model representation of the current PubSub configuration is +generated automatically. This feature can be enabled/disabled by changing the +UA_ENABLE_PUBSUB_INFORMATIONMODEL option. + +Connections +----------- +The PubSub connections are the abstraction between the concrete transport protocol +and the PubSub functionality. It is possible to create multiple connections with +different transport protocols at runtime. + +.. code-block:: c + + + /* Valid PublisherId types from Part 14 */ + typedef enum { + UA_PUBLISHERIDTYPE_BYTE = 0, + UA_PUBLISHERIDTYPE_UINT16 = 1, + UA_PUBLISHERIDTYPE_UINT32 = 2, + UA_PUBLISHERIDTYPE_UINT64 = 3, + UA_PUBLISHERIDTYPE_STRING = 4 + } UA_PublisherIdType; + + /* Publisher Id + Valid types are defined in Part 14, 7.2.2.2.2 NetworkMessage Layout: + + Bit range 0-2: PublisherId Type + 000 The PublisherId is of DataType Byte This is the default value if ExtendedFlags1 is omitted + 001 The PublisherId is of DataType UInt16 + 010 The PublisherId is of DataType UInt32 + 011 The PublisherId is of DataType UInt64 + 100 The PublisherId is of DataType String + */ + typedef union { + UA_Byte byte; + UA_UInt16 uint16; + UA_UInt32 uint32; + UA_UInt64 uint64; + UA_String string; + } UA_PublisherId; + + typedef struct { + UA_String name; + UA_Boolean enabled; + UA_PublisherIdType publisherIdType; + UA_PublisherId publisherId; + UA_String transportProfileUri; + UA_Variant address; + UA_KeyValueMap connectionProperties; + UA_Variant connectionTransportSettings; + + UA_EventLoop *eventLoop; /* Use an external EventLoop (use the EventLoop of + * the server if this is NULL). Propagates to the + * ReaderGroup/WriterGroup attached to the + * Connection. */ + } UA_PubSubConnectionConfig; + + #ifdef UA_ENABLE_PUBSUB_MONITORING + + typedef enum { + UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT + // extend as needed + } UA_PubSubMonitoringType; + + /* PubSub monitoring interface */ + typedef struct { + UA_StatusCode (*createMonitoring)(UA_Server *server, UA_NodeId Id, + UA_PubSubComponentEnumType eComponentType, + UA_PubSubMonitoringType eMonitoringType, + void *data, UA_ServerCallback callback); + UA_StatusCode (*startMonitoring)(UA_Server *server, UA_NodeId Id, + UA_PubSubComponentEnumType eComponentType, + UA_PubSubMonitoringType eMonitoringType, void *data); + UA_StatusCode (*stopMonitoring)(UA_Server *server, UA_NodeId Id, + UA_PubSubComponentEnumType eComponentType, + UA_PubSubMonitoringType eMonitoringType, void *data); + UA_StatusCode (*updateMonitoringInterval)(UA_Server *server, UA_NodeId Id, + UA_PubSubComponentEnumType eComponentType, + UA_PubSubMonitoringType eMonitoringType, + void *data); + UA_StatusCode (*deleteMonitoring)(UA_Server *server, UA_NodeId Id, + UA_PubSubComponentEnumType eComponentType, + UA_PubSubMonitoringType eMonitoringType, void *data); + } UA_PubSubMonitoringInterface; + + #endif /* UA_ENABLE_PUBSUB_MONITORING */ + + /* General PubSub configuration */ + struct UA_PubSubConfiguration { + /* Callback for PubSub component state changes: If provided this callback + * informs the application about PubSub component state changes. E.g. state + * change from operational to error in case of a DataSetReader + * MessageReceiveTimeout. The status code provides additional + * information. */ + void (*stateChangeCallback)(UA_Server *server, UA_NodeId *id, + UA_PubSubState state, UA_StatusCode status); + + UA_Boolean enableDeltaFrames; + + #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL + UA_Boolean enableInformationModelMethods; + #endif + + #ifdef UA_ENABLE_PUBSUB_ENCRYPTION + /* PubSub security policies */ + size_t securityPoliciesSize; + UA_PubSubSecurityPolicy *securityPolicies; + #endif + + #ifdef UA_ENABLE_PUBSUB_MONITORING + UA_PubSubMonitoringInterface monitoringInterface; + #endif + }; + + /* Add a new PubSub connection to the given server and open it. + * @param server The server to add the connection to. + * @param connectionConfig The configuration for the newly added connection. + * @param connectionIdentifier If not NULL will be set to the identifier of the + * newly added connection. + * @return UA_STATUSCODE_GOOD if connection was successfully added, otherwise an + * error code. */ + UA_StatusCode UA_THREADSAFE + UA_Server_addPubSubConnection(UA_Server *server, + const UA_PubSubConnectionConfig *connectionConfig, + UA_NodeId *connectionIdentifier); + + /* Returns a deep copy of the config */ + UA_StatusCode UA_THREADSAFE + UA_Server_getPubSubConnectionConfig(UA_Server *server, + const UA_NodeId connection, + UA_PubSubConnectionConfig *config); + + /* Remove Connection, identified by the NodeId. Deletion of Connection + * removes all contained WriterGroups and Writers. */ + UA_StatusCode UA_THREADSAFE + UA_Server_removePubSubConnection(UA_Server *server, const UA_NodeId connection); + +PublishedDataSets +----------------- +The PublishedDataSets (PDS) are containers for the published information. The +PDS contain the published variables and meta information. The metadata is +commonly autogenerated or given as constant argument as part of the template +functions. The template functions are standard defined and intended for +configuration tools. You should normally create an empty PDS and call the +functions to add new fields. + +.. code-block:: c + + + /* The UA_PUBSUB_DATASET_PUBLISHEDITEMS has currently no additional members and + * thus no dedicated config structure. */ + + typedef enum { + UA_PUBSUB_DATASET_PUBLISHEDITEMS, + UA_PUBSUB_DATASET_PUBLISHEDEVENTS, + UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE, + UA_PUBSUB_DATASET_PUBLISHEDEVENTS_TEMPLATE, + } UA_PublishedDataSetType; + + typedef struct { + UA_DataSetMetaDataType metaData; + size_t variablesToAddSize; + UA_PublishedVariableDataType *variablesToAdd; + } UA_PublishedDataItemsTemplateConfig; + + typedef struct { + UA_NodeId eventNotfier; + UA_ContentFilter filter; + } UA_PublishedEventConfig; + + typedef struct { + UA_DataSetMetaDataType metaData; + UA_NodeId eventNotfier; + size_t selectedFieldsSize; + UA_SimpleAttributeOperand *selectedFields; + UA_ContentFilter filter; + } UA_PublishedEventTemplateConfig; + + /* Configuration structure for PublishedDataSet */ + typedef struct { + UA_String name; + UA_PublishedDataSetType publishedDataSetType; + union { + /* The UA_PUBSUB_DATASET_PUBLISHEDITEMS has currently no additional members + * and thus no dedicated config structure.*/ + UA_PublishedDataItemsTemplateConfig itemsTemplate; + UA_PublishedEventConfig event; + UA_PublishedEventTemplateConfig eventTemplate; + } config; + } UA_PublishedDataSetConfig; + + void + UA_PublishedDataSetConfig_clear(UA_PublishedDataSetConfig *pdsConfig); + + typedef struct { + UA_StatusCode addResult; + size_t fieldAddResultsSize; + UA_StatusCode *fieldAddResults; + UA_ConfigurationVersionDataType configurationVersion; + } UA_AddPublishedDataSetResult; + + UA_AddPublishedDataSetResult UA_THREADSAFE + UA_Server_addPublishedDataSet(UA_Server *server, + const UA_PublishedDataSetConfig *publishedDataSetConfig, + UA_NodeId *pdsIdentifier); + + /* Returns a deep copy of the config */ + UA_StatusCode UA_THREADSAFE + UA_Server_getPublishedDataSetConfig(UA_Server *server, const UA_NodeId pds, + UA_PublishedDataSetConfig *config); + + /* Returns a deep copy of the DataSetMetaData for an specific PDS */ + UA_StatusCode UA_THREADSAFE + UA_Server_getPublishedDataSetMetaData(UA_Server *server, const UA_NodeId pds, + UA_DataSetMetaDataType *metaData); + + /* Remove PublishedDataSet, identified by the NodeId. Deletion of PDS removes + * all contained and linked PDS Fields. Connected WriterGroups will be also + * removed. */ + UA_StatusCode UA_THREADSAFE + UA_Server_removePublishedDataSet(UA_Server *server, const UA_NodeId pds); + +DataSetFields +------------- +The description of published variables is named DataSetField. Each +DataSetField contains the selection of one information model node. The +DataSetField has additional parameters for the publishing, sampling and error +handling process. + +.. code-block:: c + + + typedef struct{ + UA_ConfigurationVersionDataType configurationVersion; + UA_String fieldNameAlias; + UA_Boolean promotedField; + UA_PublishedVariableDataType publishParameters; + + /* non std. field */ + struct { + UA_Boolean rtFieldSourceEnabled; + /* If the rtInformationModelNode is set, the nodeid in publishParameter must point + * to a node with external data source backend defined + * */ + UA_Boolean rtInformationModelNode; + //TODO -> decide if suppress C++ warnings and use 'UA_DataValue * * const staticValueSource;' + UA_DataValue ** staticValueSource; + } rtValueSource; + UA_UInt32 maxStringLength; + + } UA_DataSetVariableConfig; + + typedef enum { + UA_PUBSUB_DATASETFIELD_VARIABLE, + UA_PUBSUB_DATASETFIELD_EVENT + } UA_DataSetFieldType; + + typedef struct { + UA_DataSetFieldType dataSetFieldType; + union { + /* events need other config later */ + UA_DataSetVariableConfig variable; + } field; + } UA_DataSetFieldConfig; + + void + UA_DataSetFieldConfig_clear(UA_DataSetFieldConfig *dataSetFieldConfig); + + typedef struct { + UA_StatusCode result; + UA_ConfigurationVersionDataType configurationVersion; + } UA_DataSetFieldResult; + + UA_DataSetFieldResult UA_THREADSAFE + UA_Server_addDataSetField(UA_Server *server, + const UA_NodeId publishedDataSet, + const UA_DataSetFieldConfig *fieldConfig, + UA_NodeId *fieldIdentifier); + + /* Returns a deep copy of the config */ + UA_StatusCode UA_THREADSAFE + UA_Server_getDataSetFieldConfig(UA_Server *server, const UA_NodeId dsf, + UA_DataSetFieldConfig *config); + + UA_DataSetFieldResult UA_THREADSAFE + UA_Server_removeDataSetField(UA_Server *server, const UA_NodeId dsf); + +Custom Callback Implementation +------------------------------ +The user can use his own callback implementation for publishing +and subscribing. The user must take care of the callback to call for +every publishing or subscibing interval + +.. code-block:: c + + + typedef struct { + /* User's callback implementation. The user configured base time and timer policy + * will be provided as an argument to this callback so that the user can + * implement his callback (thread) considering base time and timer policies */ + UA_StatusCode (*addCustomCallback)(UA_Server *server, UA_NodeId identifier, + UA_ServerCallback callback, + void *data, UA_Double interval_ms, + UA_DateTime *baseTime, UA_TimerPolicy timerPolicy, + UA_UInt64 *callbackId); + + UA_StatusCode (*changeCustomCallback)(UA_Server *server, UA_NodeId identifier, + UA_UInt64 callbackId, UA_Double interval_ms, + UA_DateTime *baseTime, UA_TimerPolicy timerPolicy); + + void (*removeCustomCallback)(UA_Server *server, UA_NodeId identifier, UA_UInt64 callbackId); + + } UA_PubSub_CallbackLifecycle; + +WriterGroup +----------- +All WriterGroups are created within a PubSubConnection and automatically +deleted if the connection is removed. The WriterGroup is primary used as +container for :ref:`dsw` and network message settings. The WriterGroup can be +imagined as producer of the network messages. The creation of network +messages is controlled by parameters like the publish interval, which is e.g. +contained in the WriterGroup. + +.. code-block:: c + + + typedef enum { + UA_PUBSUB_ENCODING_UADP = 0, + UA_PUBSUB_ENCODING_JSON = 1, + UA_PUBSUB_ENCODING_BINARY = 2 + } UA_PubSubEncodingType; + +WriterGroup +----------- +The message publishing can be configured for realtime requirements. The RT-levels +go along with different requirements. The below listed levels can be configured: + +UA_PUBSUB_RT_NONE - +---> Description: Default "none-RT" Mode +---> Requirements: - +---> Restrictions: - +UA_PUBSUB_RT_DIRECT_VALUE_ACCESS (Preview - not implemented) +---> Description: Normally, the latest value for each DataSetField is read out of the information model. Within this RT-mode, the +value source of each field configured as static pointer to an DataValue. The publish cycle won't use call the server read function. +---> Requirements: All fields must be configured with a 'staticValueSource'. +---> Restrictions: - +UA_PUBSUB_RT_FIXED_LENGTH (Preview - not implemented) +---> Description: All DataSetFields have a known, non-changing length. The server will pre-generate some +buffers and use only memcopy operations to generate requested PubSub packages. +---> Requirements: DataSetFields with variable size cannot be used within this mode. +---> Restrictions: The configuration must be frozen and changes are not allowed while the WriterGroup is 'Operational'. +UA_PUBSUB_RT_DETERMINISTIC (Preview - not implemented) +---> Description: - +---> Requirements: - +---> Restrictions: - + +WARNING! For hard real time requirements the underlying system must be rt-capable. + + +.. code-block:: c + + typedef enum { + UA_PUBSUB_RT_NONE = 0, + UA_PUBSUB_RT_DIRECT_VALUE_ACCESS = 1, + UA_PUBSUB_RT_FIXED_SIZE = 2, + UA_PUBSUB_RT_DETERMINISTIC = 4, + } UA_PubSubRTLevel; + + typedef struct { + UA_String name; + UA_Boolean enabled; + UA_UInt16 writerGroupId; + UA_Duration publishingInterval; + UA_Double keepAliveTime; + UA_Byte priority; + UA_ExtensionObject transportSettings; + UA_ExtensionObject messageSettings; + UA_KeyValueMap groupProperties; + UA_PubSubEncodingType encodingMimeType; + /* PubSub Manager Callback */ + UA_PubSub_CallbackLifecycle pubsubManagerCallback; + /* non std. config parameter. maximum count of embedded DataSetMessage in + * one NetworkMessage */ + UA_UInt16 maxEncapsulatedDataSetMessageCount; + /* non std. field */ + UA_PubSubRTLevel rtLevel; + + /* Message are encrypted if a SecurityPolicy is configured and the + * securityMode set accordingly. The symmetric key is a runtime information + * and has to be set via UA_Server_setWriterGroupEncryptionKey. */ + UA_MessageSecurityMode securityMode; /* via the UA_WriterGroupDataType */ + #ifdef UA_ENABLE_PUBSUB_ENCRYPTION + UA_PubSubSecurityPolicy *securityPolicy; + UA_String securityGroupId; + #endif + } UA_WriterGroupConfig; + + void + UA_WriterGroupConfig_clear(UA_WriterGroupConfig *writerGroupConfig); + + /* Add a new WriterGroup to an existing Connection */ + UA_StatusCode UA_THREADSAFE + UA_Server_addWriterGroup(UA_Server *server, const UA_NodeId connection, + const UA_WriterGroupConfig *writerGroupConfig, + UA_NodeId *writerGroupIdentifier); + + /* Returns a deep copy of the config */ + UA_StatusCode UA_THREADSAFE + UA_Server_getWriterGroupConfig(UA_Server *server, const UA_NodeId writerGroup, + UA_WriterGroupConfig *config); + + UA_StatusCode UA_THREADSAFE + UA_Server_updateWriterGroupConfig(UA_Server *server, UA_NodeId writerGroupIdentifier, + const UA_WriterGroupConfig *config); + + /* Get state of WriterGroup */ + UA_StatusCode UA_THREADSAFE + UA_Server_WriterGroup_getState(UA_Server *server, UA_NodeId writerGroupIdentifier, + UA_PubSubState *state); + + UA_StatusCode UA_THREADSAFE + UA_Server_WriterGroup_publish(UA_Server *server, const UA_NodeId writerGroupIdentifier); + + UA_StatusCode UA_THREADSAFE + UA_WriterGroup_lastPublishTimestamp(UA_Server *server, const UA_NodeId writerGroupId, + UA_DateTime *timestamp); + + UA_StatusCode UA_THREADSAFE + UA_Server_removeWriterGroup(UA_Server *server, const UA_NodeId writerGroup); + + UA_StatusCode UA_THREADSAFE + UA_Server_freezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writerGroup); + + UA_StatusCode UA_THREADSAFE + UA_Server_unfreezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writerGroup); + + UA_StatusCode UA_THREADSAFE + UA_Server_setWriterGroupOperational(UA_Server *server, const UA_NodeId writerGroup); + + UA_StatusCode UA_THREADSAFE + UA_Server_setWriterGroupDisabled(UA_Server *server, const UA_NodeId writerGroup); + + #ifdef UA_ENABLE_PUBSUB_ENCRYPTION + /* Set the group key for the message encryption */ + UA_StatusCode UA_THREADSAFE + UA_Server_setWriterGroupEncryptionKeys(UA_Server *server, const UA_NodeId writerGroup, + UA_UInt32 securityTokenId, + const UA_ByteString signingKey, + const UA_ByteString encryptingKey, + const UA_ByteString keyNonce); + #endif + +.. _dsw: + +DataSetWriter +------------- +The DataSetWriters are the glue between the WriterGroups and the +PublishedDataSets. The DataSetWriter contain configuration parameters and +flags which influence the creation of DataSet messages. These messages are +encapsulated inside the network message. The DataSetWriter must be linked +with an existing PublishedDataSet and be contained within a WriterGroup. + +.. code-block:: c + + + typedef struct { + UA_String name; + UA_UInt16 dataSetWriterId; + UA_DataSetFieldContentMask dataSetFieldContentMask; + UA_UInt32 keyFrameCount; + UA_ExtensionObject messageSettings; + UA_ExtensionObject transportSettings; + UA_String dataSetName; + UA_KeyValueMap dataSetWriterProperties; + } UA_DataSetWriterConfig; + + void + UA_DataSetWriterConfig_clear(UA_DataSetWriterConfig *pdsConfig); + + /* Add a new DataSetWriter to an existing WriterGroup. The DataSetWriter must be + * coupled with a PublishedDataSet on creation. + * + * Part 14, 7.1.5.2.1 defines: The link between the PublishedDataSet and + * DataSetWriter shall be created when an instance of the DataSetWriterType is + * created. */ + UA_StatusCode UA_THREADSAFE + UA_Server_addDataSetWriter(UA_Server *server, + const UA_NodeId writerGroup, const UA_NodeId dataSet, + const UA_DataSetWriterConfig *dataSetWriterConfig, + UA_NodeId *writerIdentifier); + + /* Returns a deep copy of the config */ + UA_StatusCode UA_THREADSAFE + UA_Server_getDataSetWriterConfig(UA_Server *server, const UA_NodeId dsw, + UA_DataSetWriterConfig *config); + + /* Get state of DataSetWriter */ + UA_StatusCode UA_THREADSAFE + UA_Server_DataSetWriter_getState(UA_Server *server, UA_NodeId dataSetWriterIdentifier, + UA_PubSubState *state); + + UA_StatusCode UA_THREADSAFE + UA_Server_removeDataSetWriter(UA_Server *server, const UA_NodeId dsw); + +SubscribedDataSet +----------------- +SubscribedDataSet describes the processing of the received DataSet. +SubscribedDataSet defines which field in the DataSet is mapped to which +Variable in the OPC UA Application. SubscribedDataSet has two sub-types +called the TargetVariablesType and SubscribedDataSetMirrorType. +SubscribedDataSetMirrorType is currently not supported. SubscribedDataSet is +set to TargetVariablesType and then the list of target Variables are created +in the Subscriber AddressSpace. TargetVariables are a list of variables that +are to be added in the Subscriber AddressSpace. It defines a list of Variable +mappings between received DataSet fields and added Variables in the +Subscriber AddressSpace. + +.. code-block:: c + + + /* SubscribedDataSetDataType Definition */ + typedef enum { + UA_PUBSUB_SDS_TARGET, + UA_PUBSUB_SDS_MIRROR + } UA_SubscribedDataSetEnumType; + + typedef struct { + /* Standard-defined FieldTargetDataType */ + UA_FieldTargetDataType targetVariable; + + /* If realtime-handling is required, set this pointer non-NULL and it will be used + * to memcpy the value instead of using the Write service. + * If the beforeWrite method pointer is set, it will be called before a memcpy update + * to the value. But param externalDataValue already contains the new value. + * If the afterWrite method pointer is set, it will be called after a memcpy update + * to the value. */ + UA_DataValue **externalDataValue; + void *targetVariableContext; /* user-defined pointer */ + void (*beforeWrite)(UA_Server *server, + const UA_NodeId *readerIdentifier, + const UA_NodeId *readerGroupIdentifier, + const UA_NodeId *targetVariableIdentifier, + void *targetVariableContext, + UA_DataValue **externalDataValue); + void (*afterWrite)(UA_Server *server, + const UA_NodeId *readerIdentifier, + const UA_NodeId *readerGroupIdentifier, + const UA_NodeId *targetVariableIdentifier, + void *targetVariableContext, + UA_DataValue **externalDataValue); + } UA_FieldTargetVariable; + + typedef struct { + size_t targetVariablesSize; + UA_FieldTargetVariable *targetVariables; + } UA_TargetVariables; + + /* Return Status Code after creating TargetVariables in Subscriber AddressSpace */ + UA_StatusCode UA_THREADSAFE + UA_Server_DataSetReader_createTargetVariables(UA_Server *server, + UA_NodeId dataSetReaderIdentifier, + size_t targetVariablesSize, + const UA_FieldTargetVariable *targetVariables); + + /* To Do:Implementation of SubscribedDataSetMirrorType + * UA_StatusCode + * A_PubSubDataSetReader_createDataSetMirror(UA_Server *server, UA_NodeId dataSetReaderIdentifier, + * UA_SubscribedDataSetMirrorDataType* mirror) */ + +DataSetReader +------------- +DataSetReader can receive NetworkMessages with the DataSetMessage +of interest sent by the Publisher. DataSetReaders represent +the configuration necessary to receive and process DataSetMessages +on the Subscriber side. DataSetReader must be linked with a +SubscribedDataSet and be contained within a ReaderGroup. + +.. code-block:: c + + + typedef enum { + UA_PUBSUB_RT_UNKNOWN = 0, + UA_PUBSUB_RT_VARIANT = 1, + UA_PUBSUB_RT_DATA_VALUE = 2, + UA_PUBSUB_RT_RAW = 4, + } UA_PubSubRtEncoding; + + /* Parameters for PubSub DataSetReader Configuration */ + typedef struct { + UA_String name; + UA_Variant publisherId; + UA_UInt16 writerGroupId; + UA_UInt16 dataSetWriterId; + UA_DataSetMetaDataType dataSetMetaData; + UA_DataSetFieldContentMask dataSetFieldContentMask; + UA_Double messageReceiveTimeout; + UA_ExtensionObject messageSettings; + UA_ExtensionObject transportSettings; + UA_SubscribedDataSetEnumType subscribedDataSetType; + /* TODO UA_SubscribedDataSetMirrorDataType subscribedDataSetMirror */ + union { + UA_TargetVariables subscribedDataSetTarget; + // UA_SubscribedDataSetMirrorDataType subscribedDataSetMirror; + } subscribedDataSet; + /* non std. fields */ + UA_String linkedStandaloneSubscribedDataSetName; + UA_PubSubRtEncoding expectedEncoding; + } UA_DataSetReaderConfig; + + /* Copy the configuration of DataSetReader */ + UA_StatusCode + UA_DataSetReaderConfig_copy(const UA_DataSetReaderConfig *src, + UA_DataSetReaderConfig *dst); + + /* Clear the configuration of a DataSetReader */ + void + UA_DataSetReaderConfig_clear(UA_DataSetReaderConfig *cfg); + + /* Update configuration to the DataSetReader */ + UA_StatusCode UA_THREADSAFE + UA_Server_DataSetReader_updateConfig(UA_Server *server, UA_NodeId dataSetReaderIdentifier, + UA_NodeId readerGroupIdentifier, + const UA_DataSetReaderConfig *config); + + /* Get the configuration (copy) of the DataSetReader */ + UA_StatusCode UA_THREADSAFE + UA_Server_DataSetReader_getConfig(UA_Server *server, UA_NodeId dataSetReaderIdentifier, + UA_DataSetReaderConfig *config); + + /* Get state of DataSetReader */ + UA_StatusCode UA_THREADSAFE + UA_Server_DataSetReader_getState(UA_Server *server, UA_NodeId dataSetReaderIdentifier, + UA_PubSubState *state); + + typedef struct { + UA_String name; + UA_SubscribedDataSetEnumType subscribedDataSetType; + union { + /* datasetmirror is currently not implemented */ + UA_TargetVariablesDataType target; + } subscribedDataSet; + UA_DataSetMetaDataType dataSetMetaData; + UA_Boolean isConnected; + } UA_StandaloneSubscribedDataSetConfig; + + void + UA_StandaloneSubscribedDataSetConfig_clear(UA_StandaloneSubscribedDataSetConfig *sdsConfig); + + UA_StatusCode UA_THREADSAFE + UA_Server_addStandaloneSubscribedDataSet(UA_Server *server, + const UA_StandaloneSubscribedDataSetConfig *subscribedDataSetConfig, + UA_NodeId *sdsIdentifier); + + /* Remove StandaloneSubscribedDataSet, identified by the NodeId. */ + UA_StatusCode UA_THREADSAFE + UA_Server_removeStandaloneSubscribedDataSet(UA_Server *server, const UA_NodeId sds); + +ReaderGroup +----------- + +ReaderGroup is used to group a list of DataSetReaders. All ReaderGroups are +created within a PubSubConnection and automatically deleted if the connection +is removed. All network message related filters are only available in the +DataSetReader. + +The RT-levels go along with different requirements. The below listed levels +can be configured for a ReaderGroup. + +- UA_PUBSUB_RT_NONE: RT applied to this level +- PUBSUB_CONFIG_FASTPATH_FIXED_OFFSETS: Extends PubSub RT functionality and + implements fast path message decoding in the Subscriber. Uses a buffered + network message and only decodes the necessary offsets stored in an offset + buffer. + +.. code-block:: c + + + /* ReaderGroup configuration */ + typedef struct { + UA_String name; + + /* non std. field */ + UA_PubSubRTLevel rtLevel; + UA_KeyValueMap groupProperties; + UA_PubSubEncodingType encodingMimeType; + UA_ExtensionObject transportSettings; + + /* Messages are decrypted if a SecurityPolicy is configured and the + * securityMode set accordingly. The symmetric key is a runtime information + * and has to be set via UA_Server_setReaderGroupEncryptionKey. */ + UA_MessageSecurityMode securityMode; + #ifdef UA_ENABLE_PUBSUB_ENCRYPTION + UA_PubSubSecurityPolicy *securityPolicy; + UA_String securityGroupId; + #endif + } UA_ReaderGroupConfig; + + void + UA_ReaderGroupConfig_clear(UA_ReaderGroupConfig *readerGroupConfig); + + /* Add DataSetReader to the ReaderGroup */ + UA_StatusCode UA_THREADSAFE + UA_Server_addDataSetReader(UA_Server *server, UA_NodeId readerGroupIdentifier, + const UA_DataSetReaderConfig *dataSetReaderConfig, + UA_NodeId *readerIdentifier); + + /* Remove DataSetReader from ReaderGroup */ + UA_StatusCode UA_THREADSAFE + UA_Server_removeDataSetReader(UA_Server *server, UA_NodeId readerIdentifier); + + /* To Do: Update Configuration of ReaderGroup + * UA_StatusCode + * UA_Server_ReaderGroup_updateConfig(UA_Server *server, UA_NodeId readerGroupIdentifier, + * const UA_ReaderGroupConfig *config); + */ + + /* Get configuraiton of ReaderGroup */ + UA_StatusCode UA_THREADSAFE + UA_Server_ReaderGroup_getConfig(UA_Server *server, UA_NodeId readerGroupIdentifier, + UA_ReaderGroupConfig *config); + + /* Get state of ReaderGroup */ + UA_StatusCode UA_THREADSAFE + UA_Server_ReaderGroup_getState(UA_Server *server, UA_NodeId readerGroupIdentifier, + UA_PubSubState *state); + + /* Add ReaderGroup to the created connection */ + UA_StatusCode UA_THREADSAFE + UA_Server_addReaderGroup(UA_Server *server, UA_NodeId connectionIdentifier, + const UA_ReaderGroupConfig *readerGroupConfig, + UA_NodeId *readerGroupIdentifier); + + /* Remove ReaderGroup from connection */ + UA_StatusCode UA_THREADSAFE + UA_Server_removeReaderGroup(UA_Server *server, UA_NodeId groupIdentifier); + + UA_StatusCode UA_THREADSAFE + UA_Server_freezeReaderGroupConfiguration(UA_Server *server, const UA_NodeId readerGroupId); + + UA_StatusCode UA_THREADSAFE + UA_Server_unfreezeReaderGroupConfiguration(UA_Server *server, const UA_NodeId readerGroupId); + + UA_StatusCode UA_THREADSAFE + UA_Server_setReaderGroupOperational(UA_Server *server, const UA_NodeId readerGroupId); + + UA_StatusCode UA_THREADSAFE + UA_Server_setReaderGroupDisabled(UA_Server *server, const UA_NodeId readerGroupId); + + #ifdef UA_ENABLE_PUBSUB_ENCRYPTION + /* Set the group key for the message encryption */ + UA_StatusCode UA_THREADSAFE + UA_Server_setReaderGroupEncryptionKeys(UA_Server *server, UA_NodeId readerGroup, + UA_UInt32 securityTokenId, + UA_ByteString signingKey, + UA_ByteString encryptingKey, + UA_ByteString keyNonce); + #endif + + #ifdef UA_ENABLE_PUBSUB_SKS + +SecurityGroup +------------- + +A SecurityGroup is an abstraction that represents the message security settings and +security keys for a subset of NetworkMessages exchanged between Publishers and +Subscribers. The SecurityGroup objects are created on a Security Key Service (SKS). The +SKS manages the access to the keys based on the role permission for a user assigned to +a SecurityGroup Object. A SecurityGroup is identified with a unique identifier called +the SecurityGroupId. It is unique within the SKS. + +.. note:: The access to the SecurityGroup and therefore the securitykeys managed by SKS + requires management of Roles and Permissions in the SKS. The Role Permission + model is not supported at the time of writing. However, the access control plugin can + be used to create and manage role permission on SecurityGroup object. + +.. code-block:: c + + + typedef struct { + UA_String securityGroupName; + UA_Duration keyLifeTime; + UA_String securityPolicyUri; + UA_UInt32 maxFutureKeyCount; + UA_UInt32 maxPastKeyCount; + } UA_SecurityGroupConfig; + +@brief Creates a SecurityGroup object and add it to the list in PubSub Manager. If the +information model is enabled then the SecurityGroup object Node is also created in the +server. A keyStorage with initial list of keys is created with a SecurityGroup. A +callback is added to new SecurityGroup which updates the keys periodically at each +KeyLifeTime expire. + +@param server The server instance +@param securityGroupFolderNodeId The parent node of the SecurityGroup. It must be of +SecurityGroupFolderType +@param securityGroupConfig The security settings of a SecurityGroup +@param securityGroupNodeId The output nodeId of the new SecurityGroup +@return UA_StatusCode The return status code + +.. code-block:: c + + UA_StatusCode UA_THREADSAFE + UA_Server_addSecurityGroup(UA_Server *server, UA_NodeId securityGroupFolderNodeId, + const UA_SecurityGroupConfig *securityGroupConfig, + UA_NodeId *securityGroupNodeId); + +@brief Removes the SecurityGroup from PubSub Manager. It removes the KeyStorage +associated with the SecurityGroup from the server. + +@param server The server instance +@param securityGroup The nodeId of the securityGroup to be removed +@return UA_StatusCode The returned status code. + +.. code-block:: c + + UA_StatusCode UA_THREADSAFE + UA_Server_removeSecurityGroup(UA_Server *server, const UA_NodeId securityGroup); + +@brief This is a repeated callback which is triggered on each iteration of SKS Pull request. +The server uses this callback to notify user about the status of current Pull request iteration. +The period is calculated based on the KeylifeTime of specified in the SecurityGroup object node on +the SKS server. + +@param server The server instance managing the publisher/subscriber. +@param sksPullRequestStatus The current status of sks pull request. +@param context The pointer to user defined data passed to this callback. + +.. code-block:: c + + typedef void + (*UA_Server_sksPullRequestCallback)(UA_Server *server, UA_StatusCode sksPullRequestStatus, void* context); + +@brief Sets the SKS client config used to call the GetSecurityKeys Method on SKS and get the +initial set of keys for a SecurityGroupId and adds timedCallback for the next GetSecurityKeys +method Call. This uses async Client API for SKS Pull request. The SKS Client instance is created and destroyed at +runtime on each iteration of SKS Pull request by the server. The key Rollover mechanism will check if the new +keys are needed then it will call the getSecurityKeys Method on SKS Server. At the end of SKS Pull request +iteration, the sks client will be deleted by a delayed callback (in next server iteration). + +@note It is be called before setting Reader/Writer Group into Operational because this also allocates +a channel context for the pubsub security policy. + +@note the stateCallback of sksClientConfig will be overwritten by an internal callback. + +@param server the server instance +@param clientConfig holds the required configuration to make encrypted connection with +SKS Server. The input client config takes the lifecycle as long as SKS request are made. +It is deleted with its plugins when the server is deleted or the last Reader/Writer +Group of the securityGroupId is deleted. The input config is copied to an internal +config object and the content of input config object will be reset to zero. +@param endpointUrl holds the endpointUrl of the SKS server +@param securityGroupId the SecurityGroupId of the securityGroup on SKS and +reader/writergroups +@param callback the user defined callback to notify the user about the status of SKS +Pull request. +@param context passed to the callback function +@return UA_StatusCode the retuned status + +.. code-block:: c + + UA_StatusCode + UA_Server_setSksClient(UA_Server *server, UA_String securityGroupId, + UA_ClientConfig *clientConfig, const char *endpointUrl, + UA_Server_sksPullRequestCallback callback, void *context); + + #endif /* UA_ENABLE_PUBSUB_SKS */ + + #endif /* UA_ENABLE_PUBSUB */ diff --git a/static/doc/v1.4.0/_static/pygments.css b/static/doc/v1.4.0/_static/pygments.css new file mode 100644 index 0000000000..0d49244eda --- /dev/null +++ b/static/doc/v1.4.0/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/static/doc/v1.4.0/_static/searchtools.js b/static/doc/v1.4.0/_static/searchtools.js new file mode 100644 index 0000000000..7918c3fab3 --- /dev/null +++ b/static/doc/v1.4.0/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/static/doc/v1.4.0/_static/server.rst b/static/doc/v1.4.0/_static/server.rst new file mode 100644 index 0000000000..2a83e5e6aa --- /dev/null +++ b/static/doc/v1.4.0/_static/server.rst @@ -0,0 +1,2009 @@ +.. _server: + +Server +====== + +.. _server-configuration: + +Server Configuration +-------------------- +The configuration structure is passed to the server during initialization. +The server expects that the configuration is not modified during runtime. +Currently, only one server can use a configuration at a time. During +shutdown, the server will clean up the parts of the configuration that are +modified at runtime through the provided API. + +Examples for configurations are provided in the ``/plugins`` folder. +The usual usage is as follows: + +1. Create a server configuration with default settings as a starting point +2. Modifiy the configuration, e.g. by adding a server certificate +3. Instantiate a server with it +4. After shutdown of the server, clean up the configuration (free memory) + +The :ref:`tutorials` provide a good starting point for this. + +.. code-block:: c + + + struct UA_ServerConfig { + void *context; /* Used to attach custom data to a server config. This can + * then be retrieved e.g. in a callback that forwards a + * pointer to the server. */ + UA_Logger *logging; /* Plugin for log output */ + +Server Description +^^^^^^^^^^^^^^^^^^ +The description must be internally consistent. The ApplicationUri set in +the ApplicationDescription must match the URI set in the server +certificate. +The applicationType is not just descriptive, it changes the actual +functionality of the server. The RegisterServer service is available only +if the server is a DiscoveryServer and the applicationType is set to the +appropriate value.*/ + + + + +Server Lifecycle +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + /* Delay in ms from the shutdown signal (ctrl-c) until the actual shutdown. + * Clients need to be able to get a notification ahead of time. */ + UA_Double shutdownDelay; + + /* If an asynchronous server shutdown is used, this callback notifies about + * the current lifecycle state (notably the STOPPING -> STOPPED + * transition). */ + void (*notifyLifecycleState)(UA_Server *server, UA_LifecycleState state); + +Rule Handling +^^^^^^^^^^^^^ +Override the handling of standard-defined behavior. These settings are +used to balance the following contradicting requirements: + +- Strict conformance with the standard (for certification). +- Ensure interoperability with old/non-conforming implementations + encountered in the wild. + +The defaults are set for compatibility with the largest number of OPC UA +vendors (with log warnings activated). Cf. Postel's Law "be conservative +in what you send, be liberal in what you accept". + +See the section :ref:`rule-handling` for the possible settings. + +.. code-block:: c + + + /* Verify that the server sends a timestamp in the request header */ + UA_RuleHandling verifyRequestTimestamp; + + /* Variables (that don't have a DataType of BaseDataType) must not have an + * empty variant value. The default behaviour is to auto-create a matching + * zeroed-out value for empty VariableNodes when they are added. */ + UA_RuleHandling allowEmptyVariables; + +Custom Data Types +^^^^^^^^^^^^^^^^^ +The following is a linked list of arrays with custom data types. All data +types that are accessible from here are automatically considered for the +decoding of received messages. Custom data types are not cleaned up +together with the configuration. So it is possible to allocate them on +ROM. + +See the section on :ref:`generic-types`. Examples for working with custom +data types are provided in ``/examples/custom_datatype/``. + +.. code-block:: c + + const UA_DataTypeArray *customDataTypes; + +.. note:: See the section on :ref:`generic-types`. Examples for working + with custom data types are provided in + ``/examples/custom_datatype/``. + +.. code-block:: c + + +EventLoop +^^^^^^^^^ +The sever can be plugged into an external EventLoop. Otherwise the +EventLoop is considered to be attached to the server's lifecycle and will +be destroyed when the config is cleaned up. + +.. code-block:: c + + UA_EventLoop *eventLoop; + UA_Boolean externalEventLoop; /* The EventLoop is not deleted with the config */ + +Networking +^^^^^^^^^^ +The `severUrls` array contains the server URLs like +`opc.tcp://my-server:4840` or `opc.wss://localhost:443`. The URLs are +used both for discovery and to set up the server sockets based on the +defined hostnames (and ports). + +- If the list is empty: Listen on all network interfaces with TCP port 4840. +- If the hostname of a URL is empty: Use the define protocol and port and + listen on all interfaces. + +.. code-block:: c + + UA_String *serverUrls; + size_t serverUrlsSize; + +The following settings are specific to OPC UA with TCP transport. + +.. code-block:: c + + UA_Boolean tcpEnabled; + UA_UInt32 tcpBufSize; /* Max length of sent and received chunks (packets) + * (default: 64kB) */ + UA_UInt32 tcpMaxMsgSize; /* Max length of messages + * (default: 0 -> unbounded) */ + UA_UInt32 tcpMaxChunks; /* Max number of chunks per message + * (default: 0 -> unbounded) */ + UA_Boolean tcpReuseAddr; + +Security and Encryption +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + size_t securityPoliciesSize; + UA_SecurityPolicy* securityPolicies; + + /* Endpoints with combinations of SecurityPolicy and SecurityMode. If the + * UserIdentityToken array of the Endpoint is not set, then it will be + * filled by the server for all UserTokenPolicies that are configured in the + * AccessControl plugin. */ + size_t endpointsSize; + UA_EndpointDescription *endpoints; + + /* Only allow the following discovery services to be executed on a + * SecureChannel with SecurityPolicyNone: GetEndpointsRequest, + * FindServersRequest and FindServersOnNetworkRequest. + * + * Only enable this option if there is no endpoint with SecurityPolicy#None + * in the endpoints list. The SecurityPolicy#None must be present in the + * securityPolicies list. */ + UA_Boolean securityPolicyNoneDiscoveryOnly; + + /* Allow clients without encryption support to connect with username and password. + * This requires to transmit the password in plain text over the network which is + * why this option is disabled by default. + * Make sure you really need this before enabling plain text passwords. */ + UA_Boolean allowNonePolicyPassword; + + /* Different sets of certificates are trusted for SecureChannel / Session */ + UA_CertificateVerification secureChannelPKI; + UA_CertificateVerification sessionPKI; + +See the section for :ref:`access-control +handling`. + +.. code-block:: c + + UA_AccessControl accessControl; + +Nodes and Node Lifecycle +^^^^^^^^^^^^^^^^^^^^^^^^ +See the section for :ref:`node lifecycle handling`. + +.. code-block:: c + + UA_Nodestore nodestore; + UA_GlobalNodeLifecycle nodeLifecycle; + +Copy the HasModellingRule reference in instances from the type +definition in UA_Server_addObjectNode and UA_Server_addVariableNode. + +Part 3 - 6.4.4: [...] it is not required that newly created or referenced +instances based on InstanceDeclarations have a ModellingRule, however, it +is allowed that they have any ModellingRule independent of the +ModellingRule of their InstanceDeclaration + +.. code-block:: c + + UA_Boolean modellingRulesOnInstances; + +Limits +^^^^^^ + +.. code-block:: c + + /* Limits for SecureChannels */ + UA_UInt16 maxSecureChannels; + UA_UInt32 maxSecurityTokenLifetime; /* in ms */ + + /* Limits for Sessions */ + UA_UInt16 maxSessions; + UA_Double maxSessionTimeout; /* in ms */ + + /* Operation limits */ + UA_UInt32 maxNodesPerRead; + UA_UInt32 maxNodesPerWrite; + UA_UInt32 maxNodesPerMethodCall; + UA_UInt32 maxNodesPerBrowse; + UA_UInt32 maxNodesPerRegisterNodes; + UA_UInt32 maxNodesPerTranslateBrowsePathsToNodeIds; + UA_UInt32 maxNodesPerNodeManagement; + UA_UInt32 maxMonitoredItemsPerCall; + + /* Limits for Requests */ + UA_UInt32 maxReferencesPerNode; + +Async Operations +^^^^^^^^^^^^^^^^ +See the section for :ref:`async operations`. + +.. code-block:: c + + #if UA_MULTITHREADING >= 100 + UA_Double asyncOperationTimeout; /* in ms, 0 => unlimited */ + size_t maxAsyncOperationQueueSize; /* 0 => unlimited */ + /* Notify workers when an async operation was enqueued */ + UA_Server_AsyncOperationNotifyCallback asyncOperationNotifyCallback; + #endif + +Discovery +^^^^^^^^^ + +.. code-block:: c + + #ifdef UA_ENABLE_DISCOVERY + /* Timeout in seconds when to automatically remove a registered server from + * the list, if it doesn't re-register within the given time frame. A value + * of 0 disables automatic removal. Default is 60 Minutes (60*60). Must be + * bigger than 10 seconds, because cleanup is only triggered approximately + * every 10 seconds. The server will still be removed depending on the + * state of the semaphore file. */ + UA_UInt32 discoveryCleanupTimeout; + + # ifdef UA_ENABLE_DISCOVERY_MULTICAST + UA_Boolean mdnsEnabled; + UA_MdnsDiscoveryConfiguration mdnsConfig; + UA_String mdnsInterfaceIP; + # if !defined(UA_HAS_GETIFADDR) + size_t mdnsIpAddressListSize; + UA_UInt32 *mdnsIpAddressList; + # endif + # endif + #endif + +Subscriptions +^^^^^^^^^^^^^ + +.. code-block:: c + + UA_Boolean subscriptionsEnabled; + #ifdef UA_ENABLE_SUBSCRIPTIONS + /* Limits for Subscriptions */ + UA_UInt32 maxSubscriptions; + UA_UInt32 maxSubscriptionsPerSession; + UA_DurationRange publishingIntervalLimits; /* in ms (must not be less than 5) */ + UA_UInt32Range lifeTimeCountLimits; + UA_UInt32Range keepAliveCountLimits; + UA_UInt32 maxNotificationsPerPublish; + UA_Boolean enableRetransmissionQueue; + UA_UInt32 maxRetransmissionQueueSize; /* 0 -> unlimited size */ + # ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS + UA_UInt32 maxEventsPerNode; /* 0 -> unlimited size */ + # endif + + /* Limits for MonitoredItems */ + UA_UInt32 maxMonitoredItems; + UA_UInt32 maxMonitoredItemsPerSubscription; + UA_DurationRange samplingIntervalLimits; /* in ms (must not be less than 5) */ + UA_UInt32Range queueSizeLimits; /* Negotiated with the client */ + + /* Limits for PublishRequests */ + UA_UInt32 maxPublishReqPerSession; + + /* Register MonitoredItem in Userland + * + * @param server Allows the access to the server object + * @param sessionId The session id, represented as an node id + * @param sessionContext An optional pointer to user-defined data for the + * specific data source + * @param nodeid Id of the node in question + * @param nodeidContext An optional pointer to user-defined data, associated + * with the node in the nodestore. Note that, if the node has already + * been removed, this value contains a NULL pointer. + * @param attributeId Identifies which attribute (value, data type etc.) is + * monitored + * @param removed Determines if the MonitoredItem was removed or created. */ + void (*monitoredItemRegisterCallback)(UA_Server *server, + const UA_NodeId *sessionId, + void *sessionContext, + const UA_NodeId *nodeId, + void *nodeContext, + UA_UInt32 attibuteId, + UA_Boolean removed); + #endif + +PubSub +^^^^^^ + +.. code-block:: c + + UA_Boolean pubsubEnabled; + #ifdef UA_ENABLE_PUBSUB + UA_PubSubConfiguration pubSubConfig; + #endif + +Historical Access +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + UA_Boolean historizingEnabled; + #ifdef UA_ENABLE_HISTORIZING + UA_HistoryDatabase historyDatabase; + + UA_Boolean accessHistoryDataCapability; + UA_UInt32 maxReturnDataValues; /* 0 -> unlimited size */ + + UA_Boolean accessHistoryEventsCapability; + UA_UInt32 maxReturnEventValues; /* 0 -> unlimited size */ + + UA_Boolean insertDataCapability; + UA_Boolean insertEventCapability; + UA_Boolean insertAnnotationsCapability; + + UA_Boolean replaceDataCapability; + UA_Boolean replaceEventCapability; + + UA_Boolean updateDataCapability; + UA_Boolean updateEventCapability; + + UA_Boolean deleteRawCapability; + UA_Boolean deleteEventCapability; + UA_Boolean deleteAtTimeDataCapability; + #endif + +Reverse Connect +^^^^^^^^^^^^^^^ + +.. code-block:: c + + UA_UInt32 reverseReconnectInterval; /* Default is 15000 ms */ + +Certificate Password Callback +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + #ifdef UA_ENABLE_ENCRYPTION + /* If the private key is in PEM format and password protected, this callback + * is called during initialization to get the password to decrypt the + * private key. The memory containing the password is freed by the client + * after use. The callback should be set early, other parts of the client + * config setup may depend on it. */ + UA_StatusCode (*privateKeyPasswordCallback)(UA_ServerConfig *sc, + UA_ByteString *password); + #endif + }; + + void + UA_ServerConfig_clean(UA_ServerConfig *config); + +.. _server-lifecycle: + +Server Lifecycle +---------------- + +.. code-block:: c + + + /* Create a new server with a default configuration that adds plugins for + * networking, security, logging and so on. See `server_config_default.h` for + * more detailed options. + * + * The default configuration can be used as the starting point to adjust the + * server configuration to individual needs. UA_Server_new is implemented in the + * /plugins folder under the CC0 license. Furthermore the server confiugration + * only uses the public server API. + * + * @return Returns the configured server or NULL if an error occurs. */ + UA_Server * + UA_Server_new(void); + + /* Creates a new server. Moves the config into the server with a shallow copy. + * The config content is cleared together with the server. */ + UA_Server * + UA_Server_newWithConfig(UA_ServerConfig *config); + + /* Delete the server. */ + UA_StatusCode + UA_Server_delete(UA_Server *server); + + /* Get the configuration. Always succeeds as this simplfy resolves a pointer. + * Attention! Do not adjust the configuration while the server is running! */ + UA_ServerConfig * + UA_Server_getConfig(UA_Server *server); + + /* Get the current server lifecycle state */ + UA_LifecycleState + UA_Server_getLifecycleState(UA_Server *server); + + /* Runs the server until interrupted. On Unix/Windows this registers an + * interrupt for SIGINT (ctrl-c). The method only returns after having received + * the interrupt. The logical sequence is as follows: + * + * - UA_Server_run_startup + * - Loop until interrupt: UA_Server_run_iterate + * - UA_Server_run_shutdown + * + * @param server The server object. + * @return Returns a bad statuscode if an error occurred internally. */ + UA_StatusCode + UA_Server_run(UA_Server *server, const volatile UA_Boolean *running); + + /* Runs the server until interrupted. On Unix/Windows this registers an + * interrupt for SIGINT (ctrl-c). The method only returns after having received + * the interrupt or upon an error condition. The logical sequence is as follows: + * + * - Register the interrupt + * - UA_Server_run_startup + * - Loop until interrupt: UA_Server_run_iterate + * - UA_Server_run_shutdown + * - Deregister the interrupt + * + * Attention! This method is implemented individually for the different + * platforms (POSIX/Win32/etc.). The default implementation is in + * /plugins/ua_config_default.c under the CC0 license. Adjust as needed. + * + * @param server The server object. + * @return Returns a bad statuscode if an error occurred internally. */ + UA_StatusCode + UA_Server_runUntilInterrupt(UA_Server *server); + + /* The prologue part of UA_Server_run (no need to use if you call + * UA_Server_run or UA_Server_runUntilInterrupt) */ + UA_StatusCode + UA_Server_run_startup(UA_Server *server); + + /* Executes a single iteration of the server's main loop. + * + * @param server The server object. + * @param waitInternal Should we wait for messages in the networklayer? + * Otherwise, the timouts for the networklayers are set to zero. + * The default max wait time is 200ms. + * @return Returns how long we can wait until the next scheduled + * callback (in ms) */ + UA_UInt16 + UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal); + + /* The epilogue part of UA_Server_run (no need to use if you call + * UA_Server_run or UA_Server_runUntilInterrupt) */ + UA_StatusCode + UA_Server_run_shutdown(UA_Server *server); + +Timed Callbacks +--------------- +Add a callback to the server that is executed at a defined time. +The callback can also be registered with a cyclic interval. + +.. code-block:: c + + + /* Add a callback for execution at a specified time. If the indicated time lies + * in the past, then the callback is executed at the next iteration of the + * server's main loop. + * + * @param server The server object. + * @param callback The callback that shall be added. + * @param data Data that is forwarded to the callback. + * @param date The timestamp for the execution time. + * @param callbackId Set to the identifier of the repeated callback . This can + * be used to cancel the callback later on. If the pointer is null, the + * identifier is not set. + * @return Upon success, ``UA_STATUSCODE_GOOD`` is returned. An error code + * otherwise. */ + UA_StatusCode UA_THREADSAFE + UA_Server_addTimedCallback(UA_Server *server, UA_ServerCallback callback, + void *data, UA_DateTime date, UA_UInt64 *callbackId); + + /* Add a callback for cyclic repetition to the server. + * + * @param server The server object. + * @param callback The callback that shall be added. + * @param data Data that is forwarded to the callback. + * @param interval_ms The callback shall be repeatedly executed with the given + * interval (in ms). The interval must be positive. The first execution + * occurs at now() + interval at the latest. + * @param callbackId Set to the identifier of the repeated callback . This can + * be used to cancel the callback later on. If the pointer is null, the + * identifier is not set. + * @return Upon success, ``UA_STATUSCODE_GOOD`` is returned. An error code + * otherwise. */ + UA_StatusCode UA_THREADSAFE + UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback, + void *data, UA_Double interval_ms, + UA_UInt64 *callbackId); + + UA_StatusCode UA_THREADSAFE + UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId, + UA_Double interval_ms); + + /* Remove a repeated callback. Does nothing if the callback is not found. + * + * @param server The server object. + * @param callbackId The id of the callback */ + void UA_THREADSAFE + UA_Server_removeCallback(UA_Server *server, UA_UInt64 callbackId); + + #define UA_Server_removeRepeatedCallback(server, callbackId) \ + UA_Server_removeCallback(server, callbackId); + +Session Handling +---------------- +A new session is announced via the AccessControl plugin. The session +identifier is forwarded to the relevant callbacks back into userland. The +following methods enable an interaction with a particular session. + +.. code-block:: c + + + /* Manually close a session */ + UA_StatusCode UA_THREADSAFE + UA_Server_closeSession(UA_Server *server, const UA_NodeId *sessionId); + +Session attributes: Besides the user-definable session context pointer (set +by the AccessControl plugin when the Session is created), a session carries +attributes in a key-value list. Some attributes are present in every session +and shown in the list below. Additional attributes can be manually set as +meta-data. + +Always present as session attributes are: + +- 0:localeIds [UA_String]: List of preferred languages (read-only) +- 0:clientDescription [UA_ApplicationDescription]: Client description (read-only) +- 0:sessionName [String] Client-defined name of the session (read-only) +- 0:clientUserId [String] User identifier used to activate the session (read-only) + +.. code-block:: c + + + /* Returns a shallow copy of the attribute. Don't _clear or _delete the value + * variant. Don't use the value once the Session could be already closed in the + * background or the attribute of the session replaced. Hence don't use this in a + * multi-threaded application. */ + UA_StatusCode + UA_Server_getSessionAttribute(UA_Server *server, const UA_NodeId *sessionId, + const UA_QualifiedName key, UA_Variant *outValue); + + /* Return a deep copy of the attribute */ + UA_StatusCode UA_THREADSAFE + UA_Server_getSessionAttributeCopy(UA_Server *server, const UA_NodeId *sessionId, + const UA_QualifiedName key, UA_Variant *outValue); + + /* Returns NULL if the attribute is not defined or not a scalar or not of the + * right datatype. Otherwise a shallow copy of the scalar value is created at + * the target location of the void pointer. Hence don't use this in a + * multi-threaded application. */ + UA_StatusCode + UA_Server_getSessionAttribute_scalar(UA_Server *server, + const UA_NodeId *sessionId, + const UA_QualifiedName key, + const UA_DataType *type, + void *outValue); + + UA_StatusCode UA_THREADSAFE + UA_Server_setSessionAttribute(UA_Server *server, const UA_NodeId *sessionId, + const UA_QualifiedName key, + const UA_Variant *value); + + UA_StatusCode UA_THREADSAFE + UA_Server_deleteSessionAttribute(UA_Server *server, const UA_NodeId *sessionId, + const UA_QualifiedName key); + +Reading and Writing Node Attributes +----------------------------------- +The functions for reading and writing node attributes call the regular read +and write service in the background that are also used over the network. + +The following attributes cannot be read, since the local "admin" user always +has full rights. + +- UserWriteMask +- UserAccessLevel +- UserExecutable + +.. code-block:: c + + + /* Read an attribute of a node. The specialized functions below provide a more + * concise syntax. + * + * @param server The server object. + * @param item ReadValueIds contain the NodeId of the target node, the id of the + * attribute to read and (optionally) an index range to read parts + * of an array only. See the section on NumericRange for the format + * used for array ranges. + * @param timestamps Which timestamps to return for the attribute. + * @return Returns a DataValue that contains either an error code, or a variant + * with the attribute value and the timestamps. */ + UA_DataValue UA_THREADSAFE + UA_Server_read(UA_Server *server, const UA_ReadValueId *item, + UA_TimestampsToReturn timestamps); + + /* Don't use this function. There are typed versions for every supported + * attribute. */ + UA_StatusCode UA_THREADSAFE + __UA_Server_read(UA_Server *server, const UA_NodeId *nodeId, + UA_AttributeId attributeId, void *v); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readNodeId(UA_Server *server, const UA_NodeId nodeId, + UA_NodeId *outNodeId) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_NODEID, outNodeId); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readNodeClass(UA_Server *server, const UA_NodeId nodeId, + UA_NodeClass *outNodeClass) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_NODECLASS, + outNodeClass); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readBrowseName(UA_Server *server, const UA_NodeId nodeId, + UA_QualifiedName *outBrowseName) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_BROWSENAME, + outBrowseName); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readDisplayName(UA_Server *server, const UA_NodeId nodeId, + UA_LocalizedText *outDisplayName) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, + outDisplayName); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readDescription(UA_Server *server, const UA_NodeId nodeId, + UA_LocalizedText *outDescription) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, + outDescription); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readWriteMask(UA_Server *server, const UA_NodeId nodeId, + UA_UInt32 *outWriteMask) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_WRITEMASK, + outWriteMask); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readIsAbstract(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean *outIsAbstract) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, + outIsAbstract); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readSymmetric(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean *outSymmetric) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_SYMMETRIC, + outSymmetric); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readInverseName(UA_Server *server, const UA_NodeId nodeId, + UA_LocalizedText *outInverseName) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_INVERSENAME, + outInverseName); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readContainsNoLoops(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean *outContainsNoLoops) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, + outContainsNoLoops); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readEventNotifier(UA_Server *server, const UA_NodeId nodeId, + UA_Byte *outEventNotifier) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, + outEventNotifier); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readValue(UA_Server *server, const UA_NodeId nodeId, + UA_Variant *outValue) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_VALUE, outValue); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readDataType(UA_Server *server, const UA_NodeId nodeId, + UA_NodeId *outDataType) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DATATYPE, + outDataType); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readValueRank(UA_Server *server, const UA_NodeId nodeId, + UA_Int32 *outValueRank) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_VALUERANK, + outValueRank); + } + + /* Returns a variant with an int32 array */ + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readArrayDimensions(UA_Server *server, const UA_NodeId nodeId, + UA_Variant *outArrayDimensions) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS, + outArrayDimensions); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readAccessLevel(UA_Server *server, const UA_NodeId nodeId, + UA_Byte *outAccessLevel) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, + outAccessLevel); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readAccessLevelEx(UA_Server *server, const UA_NodeId nodeId, + UA_UInt32 *outAccessLevelEx) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX, + outAccessLevelEx); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readMinimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId, + UA_Double *outMinimumSamplingInterval) { + return __UA_Server_read(server, &nodeId, + UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, + outMinimumSamplingInterval); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readHistorizing(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean *outHistorizing) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_HISTORIZING, + outHistorizing); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_readExecutable(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean *outExecutable) { + return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, + outExecutable); + } + +The following node attributes cannot be changed once a node has been created: + +- NodeClass +- NodeId +- Symmetric +- ContainsNoLoops + +The following attributes cannot be written from the server, as they are +specific to the different users and set by the access control callback: + +- UserWriteMask +- UserAccessLevel +- UserExecutable + +.. code-block:: c + + + /* Overwrite an attribute of a node. The specialized functions below provide a + * more concise syntax. + * + * @param server The server object. + * @param value WriteValues contain the NodeId of the target node, the id of the + * attribute to overwritten, the actual value and (optionally) an + * index range to replace parts of an array only. of an array only. + * See the section on NumericRange for the format used for array + * ranges. + * @return Returns a status code. */ + UA_StatusCode UA_THREADSAFE + UA_Server_write(UA_Server *server, const UA_WriteValue *value); + + /* Don't use this function. There are typed versions with no additional + * overhead. */ + UA_StatusCode UA_THREADSAFE + __UA_Server_write(UA_Server *server, const UA_NodeId *nodeId, + const UA_AttributeId attributeId, + const UA_DataType *attr_type, const void *attr); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeBrowseName(UA_Server *server, const UA_NodeId nodeId, + const UA_QualifiedName browseName) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_BROWSENAME, + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], &browseName); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeDisplayName(UA_Server *server, const UA_NodeId nodeId, + const UA_LocalizedText displayName) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &displayName); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeDescription(UA_Server *server, const UA_NodeId nodeId, + const UA_LocalizedText description) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &description); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeWriteMask(UA_Server *server, const UA_NodeId nodeId, + const UA_UInt32 writeMask) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_WRITEMASK, + &UA_TYPES[UA_TYPES_UINT32], &writeMask); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeIsAbstract(UA_Server *server, const UA_NodeId nodeId, + const UA_Boolean isAbstract) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, + &UA_TYPES[UA_TYPES_BOOLEAN], &isAbstract); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeInverseName(UA_Server *server, const UA_NodeId nodeId, + const UA_LocalizedText inverseName) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_INVERSENAME, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &inverseName); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeEventNotifier(UA_Server *server, const UA_NodeId nodeId, + const UA_Byte eventNotifier) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, + &UA_TYPES[UA_TYPES_BYTE], &eventNotifier); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeValue(UA_Server *server, const UA_NodeId nodeId, + const UA_Variant value) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUE, + &UA_TYPES[UA_TYPES_VARIANT], &value); + } + + /* Writes an UA_DataValue to a variable/variableType node. In contrast to + * UA_Server_writeValue, this functions can also write SourceTimestamp, + * ServerTimestamp and StatusCode. */ + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeDataValue(UA_Server *server, const UA_NodeId nodeId, + const UA_DataValue value) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUE, + &UA_TYPES[UA_TYPES_DATAVALUE], &value); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeDataType(UA_Server *server, const UA_NodeId nodeId, + const UA_NodeId dataType) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DATATYPE, + &UA_TYPES[UA_TYPES_NODEID], &dataType); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeValueRank(UA_Server *server, const UA_NodeId nodeId, + const UA_Int32 valueRank) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUERANK, + &UA_TYPES[UA_TYPES_INT32], &valueRank); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeArrayDimensions(UA_Server *server, const UA_NodeId nodeId, + const UA_Variant arrayDimensions) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS, + &UA_TYPES[UA_TYPES_VARIANT], &arrayDimensions); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeAccessLevel(UA_Server *server, const UA_NodeId nodeId, + const UA_Byte accessLevel) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, + &UA_TYPES[UA_TYPES_BYTE], &accessLevel); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeAccessLevelEx(UA_Server *server, const UA_NodeId nodeId, + const UA_UInt32 accessLevelEx) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX, + &UA_TYPES[UA_TYPES_UINT32], &accessLevelEx); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeMinimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId, + const UA_Double miniumSamplingInterval) { + return __UA_Server_write(server, &nodeId, + UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, + &UA_TYPES[UA_TYPES_DOUBLE], + &miniumSamplingInterval); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeHistorizing(UA_Server *server, const UA_NodeId nodeId, + const UA_Boolean historizing) { + return __UA_Server_write(server, &nodeId, + UA_ATTRIBUTEID_HISTORIZING, + &UA_TYPES[UA_TYPES_BOOLEAN], + &historizing); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_writeExecutable(UA_Server *server, const UA_NodeId nodeId, + const UA_Boolean executable) { + return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, + &UA_TYPES[UA_TYPES_BOOLEAN], &executable); } + +Browsing +-------- + +.. code-block:: c + + + /* Browse the references of a particular node. See the definition of + * BrowseDescription structure for details. */ + UA_BrowseResult UA_THREADSAFE + UA_Server_browse(UA_Server *server, UA_UInt32 maxReferences, + const UA_BrowseDescription *bd); + + UA_BrowseResult UA_THREADSAFE + UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint, + const UA_ByteString *continuationPoint); + + /* Non-standard version of the Browse service that recurses into child nodes. + * + * Possible loops (that can occur for non-hierarchical references) are handled + * internally. Every node is added at most once to the results array. + * + * Nodes are only added if they match the NodeClassMask in the + * BrowseDescription. However, child nodes are still recursed into if the + * NodeClass does not match. So it is possible, for example, to get all + * VariableNodes below a certain ObjectNode, with additional objects in the + * hierarchy below. */ + UA_StatusCode UA_THREADSAFE + UA_Server_browseRecursive(UA_Server *server, const UA_BrowseDescription *bd, + size_t *resultsSize, UA_ExpandedNodeId **results); + + UA_BrowsePathResult UA_THREADSAFE + UA_Server_translateBrowsePathToNodeIds(UA_Server *server, + const UA_BrowsePath *browsePath); + + /* A simplified TranslateBrowsePathsToNodeIds based on the + * SimpleAttributeOperand type (Part 4, 7.4.4.5). + * + * This specifies a relative path using a list of BrowseNames instead of the + * RelativePath structure. The list of BrowseNames is equivalent to a + * RelativePath that specifies forward references which are subtypes of the + * HierarchicalReferences ReferenceType. All Nodes followed by the browsePath + * shall be of the NodeClass Object or Variable. */ + UA_BrowsePathResult UA_THREADSAFE + UA_Server_browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin, + size_t browsePathSize, + const UA_QualifiedName *browsePath); + + #ifndef HAVE_NODEITER_CALLBACK + #define HAVE_NODEITER_CALLBACK + /* Iterate over all nodes referenced by parentNodeId by calling the callback + * function for each child node (in ifdef because GCC/CLANG handle include order + * differently) */ + typedef UA_StatusCode + (*UA_NodeIteratorCallback)(UA_NodeId childId, UA_Boolean isInverse, + UA_NodeId referenceTypeId, void *handle); + #endif + + UA_StatusCode UA_THREADSAFE + UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId, + UA_NodeIteratorCallback callback, void *handle); + + #ifdef UA_ENABLE_DISCOVERY + +Discovery +--------- + +Registering at a Discovery Server +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + + /* Register the given server instance at the discovery server. This should be + * called periodically, for example every 10 minutes, depending on the + * configuration of the discovery server. You should also call + * _unregisterDiscovery when the server shuts down. + * + * The supplied client configuration is used to create a new client to connect + * to the discovery server. The client configuration is moved over to the server + * and eventually cleaned up internally. The structure pointed at by `cc` is + * zeroed to avoid accessing outdated information. + * + * The eventloop and logging plugins in the client configuration are replaced by + * those configured in the server. */ + UA_StatusCode UA_THREADSAFE + UA_Server_registerDiscovery(UA_Server *server, UA_ClientConfig *cc, + const UA_String discoveryServerUrl, + const UA_String semaphoreFilePath); + + /* Deregister the given server instance from the discovery server. + * This should be called when the server is shutting down. */ + UA_StatusCode UA_THREADSAFE + UA_Server_deregisterDiscovery(UA_Server *server, UA_ClientConfig *cc, + const UA_String discoveryServerUrl); + +Operating a Discovery Server +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + + /* Callback for RegisterServer. Data is passed from the register call */ + typedef void + (*UA_Server_registerServerCallback)(const UA_RegisteredServer *registeredServer, + void* data); + + /* Set the callback which is called if another server registeres or unregisters + * with this instance. This callback is called every time the server gets a + * register call. This especially means that for every periodic server register + * the callback will be called. + * + * @param server + * @param cb the callback + * @param data data passed to the callback + * @return ``UA_STATUSCODE_SUCCESS`` on success */ + void UA_THREADSAFE + UA_Server_setRegisterServerCallback(UA_Server *server, + UA_Server_registerServerCallback cb, void* data); + + #ifdef UA_ENABLE_DISCOVERY_MULTICAST + + /* Callback for server detected through mDNS. Data is passed from the register + * call + * + * @param isServerAnnounce indicates if the server has just been detected. If + * set to false, this means the server is shutting down. + * @param isTxtReceived indicates if we already received the corresponding TXT + * record with the path and caps data */ + typedef void + (*UA_Server_serverOnNetworkCallback)(const UA_ServerOnNetwork *serverOnNetwork, + UA_Boolean isServerAnnounce, + UA_Boolean isTxtReceived, void* data); + + /* Set the callback which is called if another server is found through mDNS or + * deleted. It will be called for any mDNS message from the remote server, thus + * it may be called multiple times for the same instance. Also the SRV and TXT + * records may arrive later, therefore for the first call the server + * capabilities may not be set yet. If called multiple times, previous data will + * be overwritten. + * + * @param server + * @param cb the callback + * @param data data passed to the callback + * @return ``UA_STATUSCODE_SUCCESS`` on success */ + void UA_THREADSAFE + UA_Server_setServerOnNetworkCallback(UA_Server *server, + UA_Server_serverOnNetworkCallback cb, + void* data); + + #endif /* UA_ENABLE_DISCOVERY_MULTICAST */ + + #endif /* UA_ENABLE_DISCOVERY */ + +Information Model Callbacks +--------------------------- +There are three places where a callback from an information model to +user-defined code can happen. + +- Custom node constructors and destructors +- Linking VariableNodes with an external data source +- MethodNode callbacks + +.. code-block:: c + + + void + UA_Server_setAdminSessionContext(UA_Server *server, + void *context); + + UA_StatusCode UA_THREADSAFE + UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId, + UA_NodeTypeLifecycle lifecycle); + + UA_StatusCode UA_THREADSAFE + UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId, + void **nodeContext); + + /* Careful! The user has to ensure that the destructor callbacks still work. */ + UA_StatusCode UA_THREADSAFE + UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId, + void *nodeContext); + +.. _datasource: + +Data Source Callback +^^^^^^^^^^^^^^^^^^^^ +The server has a unique way of dealing with the content of variables. Instead +of storing a variant attached to the variable node, the node can point to a +function with a local data provider. Whenever the value attribute is read, +the function will be called and asked to provide a UA_DataValue return value +that contains the value content and additional timestamps. + +It is expected that the read callback is implemented. The write callback can +be set to a null-pointer. + +.. code-block:: c + + + UA_StatusCode UA_THREADSAFE + UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId, + const UA_DataSource dataSource); + + UA_StatusCode UA_THREADSAFE + UA_Server_setVariableNode_valueCallback(UA_Server *server, + const UA_NodeId nodeId, + const UA_ValueCallback callback); + + UA_StatusCode UA_THREADSAFE + UA_Server_setVariableNode_valueBackend(UA_Server *server, + const UA_NodeId nodeId, + const UA_ValueBackend valueBackend); + +.. _local-monitoreditems: + +Local MonitoredItems +^^^^^^^^^^^^^^^^^^^^ +MonitoredItems are used with the Subscription mechanism of OPC UA to +transported notifications for data changes and events. MonitoredItems can +also be registered locally. Notifications are then forwarded to a +user-defined callback instead of a remote client. + +.. code-block:: c + + + #ifdef UA_ENABLE_SUBSCRIPTIONS + + typedef void (*UA_Server_DataChangeNotificationCallback) + (UA_Server *server, UA_UInt32 monitoredItemId, void *monitoredItemContext, + const UA_NodeId *nodeId, void *nodeContext, UA_UInt32 attributeId, + const UA_DataValue *value); + + typedef void (*UA_Server_EventNotificationCallback) + (UA_Server *server, UA_UInt32 monId, void *monContext, + size_t nEventFields, const UA_Variant *eventFields); + + /* Create a local MonitoredItem with a sampling interval that detects data + * changes. + * + * @param server The server executing the MonitoredItem + * @timestampsToReturn Shall timestamps be added to the value for the callback? + * @item The parameters of the new MonitoredItem. Note that the attribute of the + * ReadValueId (the node that is monitored) can not be + * ``UA_ATTRIBUTEID_EVENTNOTIFIER``. A different callback type needs to be + * registered for event notifications. + * @monitoredItemContext A pointer that is forwarded with the callback + * @callback The callback that is executed on detected data changes + * + * @return Returns a description of the created MonitoredItem. The structure + * also contains a StatusCode (in case of an error) and the identifier of the + * new MonitoredItem. */ + UA_MonitoredItemCreateResult UA_THREADSAFE + UA_Server_createDataChangeMonitoredItem(UA_Server *server, + UA_TimestampsToReturn timestampsToReturn, + const UA_MonitoredItemCreateRequest item, + void *monitoredItemContext, + UA_Server_DataChangeNotificationCallback callback); + + /* UA_MonitoredItemCreateResult */ + /* UA_Server_createEventMonitoredItem(UA_Server *server, */ + /* UA_TimestampsToReturn timestampsToReturn, */ + /* const UA_MonitoredItemCreateRequest item, void *context, */ + /* UA_Server_EventNotificationCallback callback); */ + + UA_StatusCode UA_THREADSAFE + UA_Server_deleteMonitoredItem(UA_Server *server, UA_UInt32 monitoredItemId); + + #endif + +Method Callbacks +^^^^^^^^^^^^^^^^ +Method callbacks are set to `NULL` (not executable) when a method node is +added over the network. In theory, it is possible to add a callback via +``UA_Server_setMethodNode_callback`` within the global constructor when +adding methods over the network is really wanted. See the Section +:ref:`object-interaction` for calling methods on an object. + +.. code-block:: c + + + #ifdef UA_ENABLE_METHODCALLS + UA_StatusCode UA_THREADSAFE + UA_Server_setMethodNodeCallback(UA_Server *server, + const UA_NodeId methodNodeId, + UA_MethodCallback methodCallback); + + /* Backwards compatibility definition */ + #define UA_Server_setMethodNode_callback(server, methodNodeId, methodCallback) \ + UA_Server_setMethodNodeCallback(server, methodNodeId, methodCallback) + + UA_StatusCode UA_THREADSAFE + UA_Server_getMethodNodeCallback(UA_Server *server, + const UA_NodeId methodNodeId, + UA_MethodCallback *outMethodCallback); + + UA_CallMethodResult UA_THREADSAFE + UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request); + #endif + +.. _object-interaction: + +Interacting with Objects +------------------------ +Objects in the information model are represented as ObjectNodes. Some +convenience functions are provided to simplify the interaction with objects. + +.. code-block:: c + + + /* Write an object property. The property is represented as a VariableNode with + * a ``HasProperty`` reference from the ObjectNode. The VariableNode is + * identified by its BrowseName. Writing the property sets the value attribute + * of the VariableNode. + * + * @param server The server object + * @param objectId The identifier of the object (node) + * @param propertyName The name of the property + * @param value The value to be set for the event attribute + * @return The StatusCode for setting the event attribute */ + UA_StatusCode UA_THREADSAFE + UA_Server_writeObjectProperty(UA_Server *server, const UA_NodeId objectId, + const UA_QualifiedName propertyName, + const UA_Variant value); + + /* Directly point to the scalar value instead of a variant */ + UA_StatusCode UA_THREADSAFE + UA_Server_writeObjectProperty_scalar(UA_Server *server, const UA_NodeId objectId, + const UA_QualifiedName propertyName, + const void *value, const UA_DataType *type); + + /* Read an object property. + * + * @param server The server object + * @param objectId The identifier of the object (node) + * @param propertyName The name of the property + * @param value Contains the property value after reading. Must not be NULL. + * @return The StatusCode for setting the event attribute */ + UA_StatusCode UA_THREADSAFE + UA_Server_readObjectProperty(UA_Server *server, const UA_NodeId objectId, + const UA_QualifiedName propertyName, + UA_Variant *value); + +.. _addnodes: + +Node Addition and Deletion +-------------------------- +When creating dynamic node instances at runtime, chances are that you will +not care about the specific NodeId of the new node, as long as you can +reference it later. When passing numeric NodeIds with a numeric identifier 0, +the stack evaluates this as "select a random unassigned numeric NodeId in +that namespace". To find out which NodeId was actually assigned to the new +node, you may pass a pointer `outNewNodeId`, which will (after a successful +node insertion) contain the nodeId of the new node. You may also pass a +``NULL`` pointer if this result is not needed. + +See the Section :ref:`node-lifecycle` on constructors and on attaching +user-defined data to nodes. + +The Section :ref:`default-node-attributes` contains useful starting points +for defining node attributes. Forgetting to set the ValueRank or the +AccessLevel leads to errors that can be hard to track down for new users. The +default attributes have a high likelihood to "do the right thing". + +The methods for node addition and deletion take mostly const arguments that +are not modified. When creating a node, a deep copy of the node identifier, +node attributes, etc. is created. Therefore, it is possible to call for +example ``UA_Server_addVariablenode`` with a value attribute (a +:ref:`variant`) pointing to a memory location on the stack. If you need +changes to a variable value to manifest at a specific memory location, please +use a :ref:`datasource` or a :ref:`value-callback`. + +.. code-block:: c + + + /* Don't use this function. There are typed versions as inline functions. */ + UA_StatusCode UA_THREADSAFE + __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass, + const UA_NodeId *requestedNewNodeId, + const UA_NodeId *parentNodeId, + const UA_NodeId *referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId *typeDefinition, + const UA_NodeAttributes *attr, + const UA_DataType *attributeType, + void *nodeContext, UA_NodeId *outNewNodeId); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, + const UA_VariableAttributes attr, + void *nodeContext, UA_NodeId *outNewNodeId) { + return __UA_Server_addNode(server, UA_NODECLASS_VARIABLE, &requestedNewNodeId, + &parentNodeId, &referenceTypeId, browseName, + &typeDefinition, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], + nodeContext, outNewNodeId); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addVariableTypeNode(UA_Server *server, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, + const UA_VariableTypeAttributes attr, + void *nodeContext, UA_NodeId *outNewNodeId) { + return __UA_Server_addNode(server, UA_NODECLASS_VARIABLETYPE, + &requestedNewNodeId, &parentNodeId, &referenceTypeId, + browseName, &typeDefinition, + (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], + nodeContext, outNewNodeId); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addObjectNode(UA_Server *server, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, + const UA_ObjectAttributes attr, + void *nodeContext, UA_NodeId *outNewNodeId) { + return __UA_Server_addNode(server, UA_NODECLASS_OBJECT, &requestedNewNodeId, + &parentNodeId, &referenceTypeId, browseName, + &typeDefinition, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], + nodeContext, outNewNodeId); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addObjectTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ObjectTypeAttributes attr, + void *nodeContext, UA_NodeId *outNewNodeId) { + return __UA_Server_addNode(server, UA_NODECLASS_OBJECTTYPE, &requestedNewNodeId, + &parentNodeId, &referenceTypeId, browseName, + &UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], + nodeContext, outNewNodeId); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addViewNode(UA_Server *server, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ViewAttributes attr, + void *nodeContext, UA_NodeId *outNewNodeId) { + return __UA_Server_addNode(server, UA_NODECLASS_VIEW, &requestedNewNodeId, + &parentNodeId, &referenceTypeId, browseName, + &UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], + nodeContext, outNewNodeId); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addReferenceTypeNode(UA_Server *server, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_ReferenceTypeAttributes attr, + void *nodeContext, UA_NodeId *outNewNodeId) { + return __UA_Server_addNode(server, UA_NODECLASS_REFERENCETYPE, + &requestedNewNodeId, &parentNodeId, &referenceTypeId, + browseName, &UA_NODEID_NULL, + (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], + nodeContext, outNewNodeId); + } + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addDataTypeNode(UA_Server *server, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_DataTypeAttributes attr, + void *nodeContext, UA_NodeId *outNewNodeId) { + return __UA_Server_addNode(server, UA_NODECLASS_DATATYPE, &requestedNewNodeId, + &parentNodeId, &referenceTypeId, browseName, + &UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], + nodeContext, outNewNodeId); + } + + UA_StatusCode UA_THREADSAFE + UA_Server_addDataSourceVariableNode(UA_Server *server, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, + const UA_VariableAttributes attr, + const UA_DataSource dataSource, + void *nodeContext, UA_NodeId *outNewNodeId); + + /* VariableNodes that are "dynamic" (default for user-created variables) receive + * and store a SourceTimestamp. For non-dynamic VariableNodes the current time + * is used for the SourceTimestamp. */ + UA_StatusCode UA_THREADSAFE + UA_Server_setVariableNodeDynamic(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean isDynamic); + + #ifdef UA_ENABLE_METHODCALLS + + UA_StatusCode UA_THREADSAFE + UA_Server_addMethodNodeEx(UA_Server *server, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_MethodAttributes attr, UA_MethodCallback method, + size_t inputArgumentsSize, const UA_Argument *inputArguments, + const UA_NodeId inputArgumentsRequestedNewNodeId, + UA_NodeId *inputArgumentsOutNewNodeId, + size_t outputArgumentsSize, const UA_Argument *outputArguments, + const UA_NodeId outputArgumentsRequestedNewNodeId, + UA_NodeId *outputArgumentsOutNewNodeId, + void *nodeContext, UA_NodeId *outNewNodeId); + + static UA_INLINE UA_THREADSAFE UA_StatusCode + UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, const UA_MethodAttributes attr, + UA_MethodCallback method, + size_t inputArgumentsSize, const UA_Argument *inputArguments, + size_t outputArgumentsSize, const UA_Argument *outputArguments, + void *nodeContext, UA_NodeId *outNewNodeId) { + return UA_Server_addMethodNodeEx(server, requestedNewNodeId, parentNodeId, + referenceTypeId, browseName, attr, method, + inputArgumentsSize, inputArguments, + UA_NODEID_NULL, NULL, + outputArgumentsSize, outputArguments, + UA_NODEID_NULL, NULL, + nodeContext, outNewNodeId); + } + + #endif + + +The method pair UA_Server_addNode_begin and _finish splits the AddNodes +service in two parts. This is useful if the node shall be modified before +finish the instantiation. For example to add children with specific NodeIds. +Otherwise, mandatory children (e.g. of an ObjectType) are added with +pseudo-random unique NodeIds. Existing children are detected during the +_finish part via their matching BrowseName. + +The _begin method: + - prepares the node and adds it to the nodestore + - copies some unassigned attributes from the TypeDefinition node internally + - adds the references to the parent (and the TypeDefinition if applicable) + - performs type-checking of variables. + +You can add an object node without a parent if you set the parentNodeId and +referenceTypeId to UA_NODE_ID_NULL. Then you need to add the parent reference +and hasTypeDef reference yourself before calling the _finish method. +Not that this is only allowed for object nodes. + +The _finish method: + - copies mandatory children + - calls the node constructor(s) at the end + - may remove the node if it encounters an error. + +The special UA_Server_addMethodNode_finish method needs to be used for method +nodes, since there you need to explicitly specifiy the input and output +arguments which are added in the finish step (if not yet already there) + +.. code-block:: c + + + /* The ``attr`` argument must have a type according to the NodeClass. + * ``VariableAttributes`` for variables, ``ObjectAttributes`` for objects, and + * so on. Missing attributes are taken from the TypeDefinition node if + * applicable. */ + UA_StatusCode UA_THREADSAFE + UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass, + const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, + const void *attr, const UA_DataType *attributeType, + void *nodeContext, UA_NodeId *outNewNodeId); + + UA_StatusCode UA_THREADSAFE + UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId); + + #ifdef UA_ENABLE_METHODCALLS + + UA_StatusCode UA_THREADSAFE + UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId, + UA_MethodCallback method, + size_t inputArgumentsSize, const UA_Argument *inputArguments, + size_t outputArgumentsSize, const UA_Argument *outputArguments); + + #endif + + /* Deletes a node and optionally all references leading to the node. */ + UA_StatusCode UA_THREADSAFE + UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean deleteReferences); + +Reference Management +-------------------- + +.. code-block:: c + + + UA_StatusCode UA_THREADSAFE + UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId, + const UA_NodeId refTypeId, + const UA_ExpandedNodeId targetId, UA_Boolean isForward); + + UA_StatusCode UA_THREADSAFE + UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId, + const UA_NodeId referenceTypeId, UA_Boolean isForward, + const UA_ExpandedNodeId targetNodeId, + UA_Boolean deleteBidirectional); + +.. _events: + +Events +------ +The method ``UA_Server_createEvent`` creates an event and represents it as +node. The node receives a unique `EventId` which is automatically added to +the node. The method returns a `NodeId` to the object node which represents +the event through ``outNodeId``. The `NodeId` can be used to set the +attributes of the event. The generated `NodeId` is always numeric. +``outNodeId`` cannot be ``NULL``. + +Note: In order to see an event in UAExpert, the field `Time` must be given a +value! + +The method ``UA_Server_triggerEvent`` "triggers" an event by adding it to all +monitored items of the specified origin node and those of all its parents. +Any filters specified by the monitored items are automatically applied. Using +this method deletes the node generated by ``UA_Server_createEvent``. The +`EventId` for the new event is generated automatically and is returned +through ``outEventId``. ``NULL`` can be passed if the `EventId` is not +needed. ``deleteEventNode`` specifies whether the node representation of the +event should be deleted after invoking the method. This can be useful if +events with the similar attributes are triggered frequently. ``UA_TRUE`` +would cause the node to be deleted. + +.. code-block:: c + + + #ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS + + /* Creates a node representation of an event + * + * @param server The server object + * @param eventType The type of the event for which a node should be created + * @param outNodeId The NodeId of the newly created node for the event + * @return The StatusCode of the UA_Server_createEvent method */ + UA_StatusCode UA_THREADSAFE + UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType, + UA_NodeId *outNodeId); + + /* Triggers a node representation of an event by applying EventFilters and + * adding the event to the appropriate queues. + * + * @param server The server object + * @param eventNodeId The NodeId of the node representation of the event which + * should be triggered + * @param outEvent the EventId of the new event + * @param deleteEventNode Specifies whether the node representation of the event + * should be deleted + * @return The StatusCode of the UA_Server_triggerEvent method */ + UA_StatusCode UA_THREADSAFE + UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, + const UA_NodeId originId, UA_ByteString *outEventId, + const UA_Boolean deleteEventNode); + + #endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */ + +Alarms & Conditions (Experimental) +---------------------------------- + +.. code-block:: c + + + #ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS + typedef enum UA_TwoStateVariableCallbackType { + UA_ENTERING_ENABLEDSTATE, + UA_ENTERING_ACKEDSTATE, + UA_ENTERING_CONFIRMEDSTATE, + UA_ENTERING_ACTIVESTATE + } UA_TwoStateVariableCallbackType; + + /* Callback prototype to set user specific callbacks */ + typedef UA_StatusCode + (*UA_TwoStateVariableChangeCallback)(UA_Server *server, const UA_NodeId *condition); + + /* Create condition instance. The function checks first whether the passed + * conditionType is a subType of ConditionType. Then checks whether the + * condition source has HasEventSource reference to its parent. If not, a + * HasEventSource reference will be created between condition source and server + * object. To expose the condition in address space, a hierarchical + * ReferenceType should be passed to create the reference to condition source. + * Otherwise, UA_NODEID_NULL should be passed to make the condition not exposed. + * + * @param server The server object + * @param conditionId The NodeId of the requested Condition Object. When passing + * UA_NODEID_NUMERIC(X,0) an unused nodeid in namespace X will be used. + * E.g. passing UA_NODEID_NULL will result in a NodeId in namespace 0. + * @param conditionType The NodeId of the node representation of the ConditionType + * @param conditionName The name of the condition to be created + * @param conditionSource The NodeId of the Condition Source (Parent of the Condition) + * @param hierarchialReferenceType The NodeId of Hierarchical ReferenceType + * between Condition and its source + * @param outConditionId The NodeId of the created Condition + * @return The StatusCode of the UA_Server_createCondition method */ + UA_StatusCode + UA_Server_createCondition(UA_Server *server, + const UA_NodeId conditionId, + const UA_NodeId conditionType, + const UA_QualifiedName conditionName, + const UA_NodeId conditionSource, + const UA_NodeId hierarchialReferenceType, + UA_NodeId *outConditionId); + + /* The method pair UA_Server_addCondition_begin and _finish splits the + * UA_Server_createCondtion in two parts similiar to the + * UA_Server_addNode_begin / _finish pair. This is useful if the node shall be + * modified before finish the instantiation. For example to add children with + * specific NodeIds. + * For details refer to the UA_Server_addNode_begin / _finish methods. + * + * Additionally to UA_Server_addNode_begin UA_Server_addCondition_begin checks + * if the passed condition type is a subtype of the OPC UA ConditionType. + * + * @param server The server object + * @param conditionId The NodeId of the requested Condition Object. When passing + * UA_NODEID_NUMERIC(X,0) an unused nodeid in namespace X will be used. + * E.g. passing UA_NODEID_NULL will result in a NodeId in namespace 0. + * @param conditionType The NodeId of the node representation of the ConditionType + * @param conditionName The name of the condition to be added + * @param outConditionId The NodeId of the added Condition + * @return The StatusCode of the UA_Server_addCondition_begin method */ + UA_StatusCode + UA_Server_addCondition_begin(UA_Server *server, + const UA_NodeId conditionId, + const UA_NodeId conditionType, + const UA_QualifiedName conditionName, + UA_NodeId *outConditionId); + + /* Second call of the UA_Server_addCondition_begin and _finish pair. + * Additionally to UA_Server_addNode_finish UA_Server_addCondition_finish: + * - checks whether the condition source has HasEventSource reference to its + * parent. If not, a HasEventSource reference will be created between + * condition source and server object + * - exposes the condition in the address space if hierarchialReferenceType is + * not UA_NODEID_NULL by adding a reference of this type from the condition + * source to the condition instance + * - initializes the standard condition fields and callbacks + * + * @param server The server object + * @param conditionId The NodeId of the unfinished Condition Object + * @param conditionSource The NodeId of the Condition Source (Parent of the Condition) + * @param hierarchialReferenceType The NodeId of Hierarchical ReferenceType + * between Condition and its source + * @return The StatusCode of the UA_Server_addCondition_finish method */ + + UA_StatusCode + UA_Server_addCondition_finish(UA_Server *server, + const UA_NodeId conditionId, + const UA_NodeId conditionSource, + const UA_NodeId hierarchialReferenceType); + + /* Set the value of condition field. + * + * @param server The server object + * @param condition The NodeId of the node representation of the Condition Instance + * @param value Variant Value to be written to the Field + * @param fieldName Name of the Field in which the value should be written + * @return The StatusCode of the UA_Server_setConditionField method*/ + UA_StatusCode UA_THREADSAFE + UA_Server_setConditionField(UA_Server *server, + const UA_NodeId condition, + const UA_Variant *value, + const UA_QualifiedName fieldName); + + /* Set the value of property of condition field. + * + * @param server The server object + * @param condition The NodeId of the node representation of the Condition + * Instance + * @param value Variant Value to be written to the Field + * @param variableFieldName Name of the Field which has a property + * @param variablePropertyName Name of the Field Property in which the value + * should be written + * @return The StatusCode of the UA_Server_setConditionVariableFieldProperty*/ + UA_StatusCode + UA_Server_setConditionVariableFieldProperty(UA_Server *server, + const UA_NodeId condition, + const UA_Variant *value, + const UA_QualifiedName variableFieldName, + const UA_QualifiedName variablePropertyName); + + /* Triggers an event only for an enabled condition. The condition list is + * updated then with the last generated EventId. + * + * @param server The server object + * @param condition The NodeId of the node representation of the Condition Instance + * @param conditionSource The NodeId of the node representation of the Condition Source + * @param outEventId last generated EventId + * @return The StatusCode of the UA_Server_triggerConditionEvent method */ + UA_StatusCode + UA_Server_triggerConditionEvent(UA_Server *server, + const UA_NodeId condition, + const UA_NodeId conditionSource, + UA_ByteString *outEventId); + + /* Add an optional condition field using its name. (TODO Adding optional methods + * is not implemented yet) + * + * @param server The server object + * @param condition The NodeId of the node representation of the Condition Instance + * @param conditionType The NodeId of the node representation of the Condition Type + * from which the optional field comes + * @param fieldName Name of the optional field + * @param outOptionalVariable The NodeId of the created field (Variable Node) + * @return The StatusCode of the UA_Server_addConditionOptionalField method */ + UA_StatusCode + UA_Server_addConditionOptionalField(UA_Server *server, + const UA_NodeId condition, + const UA_NodeId conditionType, + const UA_QualifiedName fieldName, + UA_NodeId *outOptionalVariable); + + /* Function used to set a user specific callback to TwoStateVariable Fields of a + * condition. The callbacks will be called before triggering the events when + * transition to true State of EnabledState/Id, AckedState/Id, ConfirmedState/Id + * and ActiveState/Id occurs. + * + * @param server The server object + * @param condition The NodeId of the node representation of the Condition Instance + * @param conditionSource The NodeId of the node representation of the Condition Source + * @param removeBranch (Not Implemented yet) + * @param callback User specific callback function + * @param callbackType Callback function type, indicates where it should be called + * @return The StatusCode of the UA_Server_setConditionTwoStateVariableCallback method */ + UA_StatusCode + UA_Server_setConditionTwoStateVariableCallback(UA_Server *server, + const UA_NodeId condition, + const UA_NodeId conditionSource, + UA_Boolean removeBranch, + UA_TwoStateVariableChangeCallback callback, + UA_TwoStateVariableCallbackType callbackType); + + /* Delete a condition from the address space and the internal lists. + * + * @param server The server object + * @param condition The NodeId of the node representation of the Condition Instance + * @param conditionSource The NodeId of the node representation of the Condition Source + * @return ``UA_STATUSCODE_GOOD`` on success */ + UA_StatusCode + UA_Server_deleteCondition(UA_Server *server, + const UA_NodeId condition, + const UA_NodeId conditionSource); + + /* Set the LimitState of the LimitAlarmType + * + * @param server The server object + * @param conditionId NodeId of the node representation of the Condition Instance + * @param limitValue The value from the trigger node */ + UA_StatusCode + UA_Server_setLimitState(UA_Server *server, const UA_NodeId conditionId, + UA_Double limitValue); + + /* Parse the certifcate and set Expiration date + * + * @param server The server object + * @param conditionId NodeId of the node representation of the Condition Instance + * @param cert The certificate for parsing */ + UA_StatusCode + UA_Server_setExpirationDate(UA_Server *server, const UA_NodeId conditionId, + UA_ByteString cert); + + #endif /* UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */ + +Update the Server Certificate at Runtime +---------------------------------------- + +.. code-block:: c + + + UA_StatusCode + UA_Server_updateCertificate(UA_Server *server, + const UA_ByteString *oldCertificate, + const UA_ByteString *newCertificate, + const UA_ByteString *newPrivateKey, + UA_Boolean closeSessions, + UA_Boolean closeSecureChannels); + +Utility Functions +----------------- + +.. code-block:: c + + + /* Lookup a datatype by its NodeId. Takes the custom types in the server + * configuration into account. Return NULL if none found. */ + const UA_DataType * + UA_Server_findDataType(UA_Server *server, const UA_NodeId *typeId); + + /* Add a new namespace to the server. Returns the index of the new namespace */ + UA_UInt16 UA_THREADSAFE + UA_Server_addNamespace(UA_Server *server, const char* name); + + /* Get namespace by name from the server. */ + UA_StatusCode UA_THREADSAFE + UA_Server_getNamespaceByName(UA_Server *server, const UA_String namespaceUri, + size_t* foundIndex); + + /* Get namespace by id from the server. */ + UA_StatusCode UA_THREADSAFE + UA_Server_getNamespaceByIndex(UA_Server *server, const size_t namespaceIndex, + UA_String *foundUri); + +.. _async-operations: + +Async Operations +---------------- +Some operations (such as reading out a sensor that needs to warm up) can take +quite some time. In order not to block the server during such an operation, it +can be "outsourced" to a worker thread. + +Take the example of a CallRequest. It is split into the individual method call +operations. If the method is marked as async, then the operation is put into a +queue where it is be retrieved by a worker. The worker returns the result when +ready. See the examples in ``/examples/tutorial_server_method_async.c`` for +the usage. + +Note that the operation can time out (see the asyncOperationTimeout setting in +the server config) also when it has been retrieved by the worker. + +.. code-block:: c + + + #if UA_MULTITHREADING >= 100 + + /* Set the async flag in a method node */ + UA_StatusCode + UA_Server_setMethodNodeAsync(UA_Server *server, const UA_NodeId id, + UA_Boolean isAsync); + + typedef enum { + UA_ASYNCOPERATIONTYPE_INVALID, /* 0, the default */ + UA_ASYNCOPERATIONTYPE_CALL + /* UA_ASYNCOPERATIONTYPE_READ, */ + /* UA_ASYNCOPERATIONTYPE_WRITE, */ + } UA_AsyncOperationType; + + typedef union { + UA_CallMethodRequest callMethodRequest; + /* UA_ReadValueId readValueId; */ + /* UA_WriteValue writeValue; */ + } UA_AsyncOperationRequest; + + typedef union { + UA_CallMethodResult callMethodResult; + /* UA_DataValue readResult; */ + /* UA_StatusCode writeResult; */ + } UA_AsyncOperationResponse; + + /* Get the next async operation without blocking + * + * @param server The server object + * @param type The type of the async operation + * @param request Receives pointer to the operation + * @param context Receives the pointer to the operation context + * @param timeout The timestamp when the operation times out and can + * no longer be returned to the client. The response has to + * be set in UA_Server_setAsyncOperationResult in any case. + * @return false if queue is empty, true else */ + UA_Boolean + UA_Server_getAsyncOperationNonBlocking(UA_Server *server, + UA_AsyncOperationType *type, + const UA_AsyncOperationRequest **request, + void **context, UA_DateTime *timeout); + + /* UA_Boolean */ + /* UA_Server_getAsyncOperationBlocking(UA_Server *server, */ + /* UA_AsyncOperationType *type, */ + /* const UA_AsyncOperationRequest **request, */ + /* void **context, UA_DateTime *timeout); */ + + /* Submit an async operation result + * + * @param server The server object + * @param response Pointer to the operation result + * @param context Pointer to the operation context */ + void + UA_Server_setAsyncOperationResult(UA_Server *server, + const UA_AsyncOperationResponse *response, + void *context); + + #endif /* !UA_MULTITHREADING >= 100 */ + +Statistics +---------- +Statistic counters keeping track of the current state of the stack. Counters +are structured per OPC UA communication layer. + +.. code-block:: c + + + typedef struct { + UA_SecureChannelStatistics scs; + UA_SessionStatistics ss; + } UA_ServerStatistics; + + UA_ServerStatistics + UA_Server_getStatistics(UA_Server *server); + +Reverse Connect +--------------- +The reverse connect feature of OPC UA permits the server instead of the +client to establish the connection. The client must expose the listening port +so the server is able to reach it. + +.. code-block:: c + + + /* The reverse connect state change callback is called whenever the state of a + * reverse connect is changed by a connection attempt, a successful connection + * or a connection loss. + * + * The reverse connect states reflect the state of the secure channel currently + * associated with a reverse connect. The state will remain + * UA_SECURECHANNELSTATE_CONNECTING while the server attempts repeatedly to + * establish a connection. */ + typedef void (*UA_Server_ReverseConnectStateCallback)(UA_Server *server, + UA_UInt64 handle, + UA_SecureChannelState state, + void *context); + + /* Registers a reverse connect in the server. The server periodically attempts + * to establish a connection if the initial connect fails or if the connection + * breaks. + * + * @param server The server object + * @param url The URL of the remote client + * @param stateCallback The callback which will be called on state changes + * @param callbackContext The context for the state callback + * @param handle Is set to the handle of the reverse connect if not NULL + * @return Returns UA_STATUSCODE_GOOD if the reverse connect has been registered */ + UA_StatusCode + UA_Server_addReverseConnect(UA_Server *server, UA_String url, + UA_Server_ReverseConnectStateCallback stateCallback, + void *callbackContext, UA_UInt64 *handle); + + /* Removes a reverse connect from the server and closes the connection if it is + * currently open. + * + * @param server The server object + * @param handle The handle of the reverse connect to remove + * @return Returns UA_STATUSCODE_GOOD if the reverse connect has been + * successfully removed */ + UA_StatusCode + UA_Server_removeReverseConnect(UA_Server *server, UA_UInt64 handle); diff --git a/static/doc/v1.4.0/_static/sphinx_highlight.js b/static/doc/v1.4.0/_static/sphinx_highlight.js new file mode 100644 index 0000000000..8a96c69a19 --- /dev/null +++ b/static/doc/v1.4.0/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/static/doc/v1.4.0/_static/statuscodes.rst b/static/doc/v1.4.0/_static/statuscodes.rst new file mode 100644 index 0000000000..907487c3eb --- /dev/null +++ b/static/doc/v1.4.0/_static/statuscodes.rst @@ -0,0 +1,778 @@ +.. _statuscodes: + +StatusCodes +=========== + +StatusCodes are extensively used in the OPC UA protocol and in the open62541 +API. They are represented by the :ref:`statuscode` data type. The following +definitions are autogenerated from the ``Opc.Ua.StatusCodes.csv`` file provided +with the OPC UA standard. + +.. code-block:: c + + + /* These StatusCodes are manually generated. */ + #define UA_STATUSCODE_INFOTYPE_DATAVALUE 0x00000400 + #define UA_STATUSCODE_INFOBITS_OVERFLOW 0x00000080 + + /* The operation succeeded. */ + #define UA_STATUSCODE_GOOD 0x00000000 + + /* The operation was uncertain. */ + #define UA_STATUSCODE_UNCERTAIN 0x40000000 + + /* The operation failed. */ + #define UA_STATUSCODE_BAD 0x80000000 + + /* An unexpected error occurred. */ + #define UA_STATUSCODE_BADUNEXPECTEDERROR 0x80010000 + + /* An internal error occurred as a result of a programming or configuration error. */ + #define UA_STATUSCODE_BADINTERNALERROR 0x80020000 + + /* Not enough memory to complete the operation. */ + #define UA_STATUSCODE_BADOUTOFMEMORY 0x80030000 + + /* An operating system resource is not available. */ + #define UA_STATUSCODE_BADRESOURCEUNAVAILABLE 0x80040000 + + /* A low level communication error occurred. */ + #define UA_STATUSCODE_BADCOMMUNICATIONERROR 0x80050000 + + /* Encoding halted because of invalid data in the objects being serialized. */ + #define UA_STATUSCODE_BADENCODINGERROR 0x80060000 + + /* Decoding halted because of invalid data in the stream. */ + #define UA_STATUSCODE_BADDECODINGERROR 0x80070000 + + /* The message encoding/decoding limits imposed by the stack have been exceeded. */ + #define UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED 0x80080000 + + /* The request message size exceeds limits set by the server. */ + #define UA_STATUSCODE_BADREQUESTTOOLARGE 0x80B80000 + + /* The response message size exceeds limits set by the client. */ + #define UA_STATUSCODE_BADRESPONSETOOLARGE 0x80B90000 + + /* An unrecognized response was received from the server. */ + #define UA_STATUSCODE_BADUNKNOWNRESPONSE 0x80090000 + + /* The operation timed out. */ + #define UA_STATUSCODE_BADTIMEOUT 0x800A0000 + + /* The server does not support the requested service. */ + #define UA_STATUSCODE_BADSERVICEUNSUPPORTED 0x800B0000 + + /* The operation was cancelled because the application is shutting down. */ + #define UA_STATUSCODE_BADSHUTDOWN 0x800C0000 + + /* The operation could not complete because the client is not connected to the server. */ + #define UA_STATUSCODE_BADSERVERNOTCONNECTED 0x800D0000 + + /* The server has stopped and cannot process any requests. */ + #define UA_STATUSCODE_BADSERVERHALTED 0x800E0000 + + /* There was nothing to do because the client passed a list of operations with no elements. */ + #define UA_STATUSCODE_BADNOTHINGTODO 0x800F0000 + + /* The request could not be processed because it specified too many operations. */ + #define UA_STATUSCODE_BADTOOMANYOPERATIONS 0x80100000 + + /* The request could not be processed because there are too many monitored items in the subscription. */ + #define UA_STATUSCODE_BADTOOMANYMONITOREDITEMS 0x80DB0000 + + /* The extension object cannot be (de)serialized because the data type id is not recognized. */ + #define UA_STATUSCODE_BADDATATYPEIDUNKNOWN 0x80110000 + + /* The certificate provided as a parameter is not valid. */ + #define UA_STATUSCODE_BADCERTIFICATEINVALID 0x80120000 + + /* An error occurred verifying security. */ + #define UA_STATUSCODE_BADSECURITYCHECKSFAILED 0x80130000 + + /* The certificate does not meet the requirements of the security policy. */ + #define UA_STATUSCODE_BADCERTIFICATEPOLICYCHECKFAILED 0x81140000 + + /* The certificate has expired or is not yet valid. */ + #define UA_STATUSCODE_BADCERTIFICATETIMEINVALID 0x80140000 + + /* An issuer certificate has expired or is not yet valid. */ + #define UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID 0x80150000 + + /* The HostName used to connect to a server does not match a HostName in the certificate. */ + #define UA_STATUSCODE_BADCERTIFICATEHOSTNAMEINVALID 0x80160000 + + /* The URI specified in the ApplicationDescription does not match the URI in the certificate. */ + #define UA_STATUSCODE_BADCERTIFICATEURIINVALID 0x80170000 + + /* The certificate may not be used for the requested operation. */ + #define UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED 0x80180000 + + /* The issuer certificate may not be used for the requested operation. */ + #define UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED 0x80190000 + + /* The certificate is not trusted. */ + #define UA_STATUSCODE_BADCERTIFICATEUNTRUSTED 0x801A0000 + + /* It was not possible to determine if the certificate has been revoked. */ + #define UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN 0x801B0000 + + /* It was not possible to determine if the issuer certificate has been revoked. */ + #define UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN 0x801C0000 + + /* The certificate has been revoked. */ + #define UA_STATUSCODE_BADCERTIFICATEREVOKED 0x801D0000 + + /* The issuer certificate has been revoked. */ + #define UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED 0x801E0000 + + /* The certificate chain is incomplete. */ + #define UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE 0x810D0000 + + /* User does not have permission to perform the requested operation. */ + #define UA_STATUSCODE_BADUSERACCESSDENIED 0x801F0000 + + /* The user identity token is not valid. */ + #define UA_STATUSCODE_BADIDENTITYTOKENINVALID 0x80200000 + + /* The user identity token is valid but the server has rejected it. */ + #define UA_STATUSCODE_BADIDENTITYTOKENREJECTED 0x80210000 + + /* The specified secure channel is no longer valid. */ + #define UA_STATUSCODE_BADSECURECHANNELIDINVALID 0x80220000 + + /* The timestamp is outside the range allowed by the server. */ + #define UA_STATUSCODE_BADINVALIDTIMESTAMP 0x80230000 + + /* The nonce does appear to be not a random value or it is not the correct length. */ + #define UA_STATUSCODE_BADNONCEINVALID 0x80240000 + + /* The session id is not valid. */ + #define UA_STATUSCODE_BADSESSIONIDINVALID 0x80250000 + + /* The session was closed by the client. */ + #define UA_STATUSCODE_BADSESSIONCLOSED 0x80260000 + + /* The session cannot be used because ActivateSession has not been called. */ + #define UA_STATUSCODE_BADSESSIONNOTACTIVATED 0x80270000 + + /* The subscription id is not valid. */ + #define UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID 0x80280000 + + /* The header for the request is missing or invalid. */ + #define UA_STATUSCODE_BADREQUESTHEADERINVALID 0x802A0000 + + /* The timestamps to return parameter is invalid. */ + #define UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID 0x802B0000 + + /* The request was cancelled by the client. */ + #define UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT 0x802C0000 + + /* Too many arguments were provided. */ + #define UA_STATUSCODE_BADTOOMANYARGUMENTS 0x80E50000 + + /* The server requires a license to operate in general or to perform a service or operatio */ + #define UA_STATUSCODE_BADLICENSEEXPIRED 0x810E0000 + + /* The server has limits on number of allowed operations / object */ + #define UA_STATUSCODE_BADLICENSELIMITSEXCEEDED 0x810F0000 + + /* The server does not have a license which is required to operate in general or to perform a service or operation. */ + #define UA_STATUSCODE_BADLICENSENOTAVAILABLE 0x81100000 + + /* The subscription was transferred to another session. */ + #define UA_STATUSCODE_GOODSUBSCRIPTIONTRANSFERRED 0x002D0000 + + /* The processing will complete asynchronously. */ + #define UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY 0x002E0000 + + /* Sampling has slowed down due to resource limitations. */ + #define UA_STATUSCODE_GOODOVERLOAD 0x002F0000 + + /* The value written was accepted but was clamped. */ + #define UA_STATUSCODE_GOODCLAMPED 0x00300000 + + /* Communication with the data source is define */ + #define UA_STATUSCODE_BADNOCOMMUNICATION 0x80310000 + + /* Waiting for the server to obtain values from the underlying data source. */ + #define UA_STATUSCODE_BADWAITINGFORINITIALDATA 0x80320000 + + /* The syntax of the node id is not valid. */ + #define UA_STATUSCODE_BADNODEIDINVALID 0x80330000 + + /* The node id refers to a node that does not exist in the server address space. */ + #define UA_STATUSCODE_BADNODEIDUNKNOWN 0x80340000 + + /* The attribute is not supported for the specified Node. */ + #define UA_STATUSCODE_BADATTRIBUTEIDINVALID 0x80350000 + + /* The syntax of the index range parameter is invalid. */ + #define UA_STATUSCODE_BADINDEXRANGEINVALID 0x80360000 + + /* No data exists within the range of indexes specified. */ + #define UA_STATUSCODE_BADINDEXRANGENODATA 0x80370000 + + /* The data encoding is invalid. */ + #define UA_STATUSCODE_BADDATAENCODINGINVALID 0x80380000 + + /* The server does not support the requested data encoding for the node. */ + #define UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED 0x80390000 + + /* The access level does not allow reading or subscribing to the Node. */ + #define UA_STATUSCODE_BADNOTREADABLE 0x803A0000 + + /* The access level does not allow writing to the Node. */ + #define UA_STATUSCODE_BADNOTWRITABLE 0x803B0000 + + /* The value was out of range. */ + #define UA_STATUSCODE_BADOUTOFRANGE 0x803C0000 + + /* The requested operation is not supported. */ + #define UA_STATUSCODE_BADNOTSUPPORTED 0x803D0000 + + /* A requested item was not found or a search operation ended without success. */ + #define UA_STATUSCODE_BADNOTFOUND 0x803E0000 + + /* The object cannot be used because it has been deleted. */ + #define UA_STATUSCODE_BADOBJECTDELETED 0x803F0000 + + /* Requested operation is not implemented. */ + #define UA_STATUSCODE_BADNOTIMPLEMENTED 0x80400000 + + /* The monitoring mode is invalid. */ + #define UA_STATUSCODE_BADMONITORINGMODEINVALID 0x80410000 + + /* The monitoring item id does not refer to a valid monitored item. */ + #define UA_STATUSCODE_BADMONITOREDITEMIDINVALID 0x80420000 + + /* The monitored item filter parameter is not valid. */ + #define UA_STATUSCODE_BADMONITOREDITEMFILTERINVALID 0x80430000 + + /* The server does not support the requested monitored item filter. */ + #define UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED 0x80440000 + + /* A monitoring filter cannot be used in combination with the attribute specified. */ + #define UA_STATUSCODE_BADFILTERNOTALLOWED 0x80450000 + + /* A mandatory structured parameter was missing or null. */ + #define UA_STATUSCODE_BADSTRUCTUREMISSING 0x80460000 + + /* The event filter is not valid. */ + #define UA_STATUSCODE_BADEVENTFILTERINVALID 0x80470000 + + /* The content filter is not valid. */ + #define UA_STATUSCODE_BADCONTENTFILTERINVALID 0x80480000 + + /* An unrecognized operator was provided in a filter. */ + #define UA_STATUSCODE_BADFILTEROPERATORINVALID 0x80C10000 + + /* A valid operator was provide */ + #define UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED 0x80C20000 + + /* The number of operands provided for the filter operator was less then expected for the operand provided. */ + #define UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH 0x80C30000 + + /* The operand used in a content filter is not valid. */ + #define UA_STATUSCODE_BADFILTEROPERANDINVALID 0x80490000 + + /* The referenced element is not a valid element in the content filter. */ + #define UA_STATUSCODE_BADFILTERELEMENTINVALID 0x80C40000 + + /* The referenced literal is not a valid value. */ + #define UA_STATUSCODE_BADFILTERLITERALINVALID 0x80C50000 + + /* The continuation point provide is longer valid. */ + #define UA_STATUSCODE_BADCONTINUATIONPOINTINVALID 0x804A0000 + + /* The operation could not be processed because all continuation points have been allocated. */ + #define UA_STATUSCODE_BADNOCONTINUATIONPOINTS 0x804B0000 + + /* The reference type id does not refer to a valid reference type node. */ + #define UA_STATUSCODE_BADREFERENCETYPEIDINVALID 0x804C0000 + + /* The browse direction is not valid. */ + #define UA_STATUSCODE_BADBROWSEDIRECTIONINVALID 0x804D0000 + + /* The node is not part of the view. */ + #define UA_STATUSCODE_BADNODENOTINVIEW 0x804E0000 + + /* The number was not accepted because of a numeric overflow. */ + #define UA_STATUSCODE_BADNUMERICOVERFLOW 0x81120000 + + /* The ServerUri is not a valid URI. */ + #define UA_STATUSCODE_BADSERVERURIINVALID 0x804F0000 + + /* No ServerName was specified. */ + #define UA_STATUSCODE_BADSERVERNAMEMISSING 0x80500000 + + /* No DiscoveryUrl was specified. */ + #define UA_STATUSCODE_BADDISCOVERYURLMISSING 0x80510000 + + /* The semaphore file specified by the client is not valid. */ + #define UA_STATUSCODE_BADSEMPAHOREFILEMISSING 0x80520000 + + /* The security token request type is not valid. */ + #define UA_STATUSCODE_BADREQUESTTYPEINVALID 0x80530000 + + /* The security mode does not meet the requirements set by the server. */ + #define UA_STATUSCODE_BADSECURITYMODEREJECTED 0x80540000 + + /* The security policy does not meet the requirements set by the server. */ + #define UA_STATUSCODE_BADSECURITYPOLICYREJECTED 0x80550000 + + /* The server has reached its maximum number of sessions. */ + #define UA_STATUSCODE_BADTOOMANYSESSIONS 0x80560000 + + /* The user token signature is missing or invalid. */ + #define UA_STATUSCODE_BADUSERSIGNATUREINVALID 0x80570000 + + /* The signature generated with the client certificate is missing or invalid. */ + #define UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID 0x80580000 + + /* The client did not provide at least one software certificate that is valid and meets the profile requirements for the server. */ + #define UA_STATUSCODE_BADNOVALIDCERTIFICATES 0x80590000 + + /* The server does not support changing the user identity assigned to the session. */ + #define UA_STATUSCODE_BADIDENTITYCHANGENOTSUPPORTED 0x80C60000 + + /* The request was cancelled by the client with the Cancel service. */ + #define UA_STATUSCODE_BADREQUESTCANCELLEDBYREQUEST 0x805A0000 + + /* The parent node id does not to refer to a valid node. */ + #define UA_STATUSCODE_BADPARENTNODEIDINVALID 0x805B0000 + + /* The reference could not be created because it violates constraints imposed by the data model. */ + #define UA_STATUSCODE_BADREFERENCENOTALLOWED 0x805C0000 + + /* The requested node id was reject because it was either invalid or server does not allow node ids to be specified by the client. */ + #define UA_STATUSCODE_BADNODEIDREJECTED 0x805D0000 + + /* The requested node id is already used by another node. */ + #define UA_STATUSCODE_BADNODEIDEXISTS 0x805E0000 + + /* The node class is not valid. */ + #define UA_STATUSCODE_BADNODECLASSINVALID 0x805F0000 + + /* The browse name is invalid. */ + #define UA_STATUSCODE_BADBROWSENAMEINVALID 0x80600000 + + /* The browse name is not unique among nodes that share the same relationship with the parent. */ + #define UA_STATUSCODE_BADBROWSENAMEDUPLICATED 0x80610000 + + /* The node attributes are not valid for the node class. */ + #define UA_STATUSCODE_BADNODEATTRIBUTESINVALID 0x80620000 + + /* The type definition node id does not reference an appropriate type node. */ + #define UA_STATUSCODE_BADTYPEDEFINITIONINVALID 0x80630000 + + /* The source node id does not reference a valid node. */ + #define UA_STATUSCODE_BADSOURCENODEIDINVALID 0x80640000 + + /* The target node id does not reference a valid node. */ + #define UA_STATUSCODE_BADTARGETNODEIDINVALID 0x80650000 + + /* The reference type between the nodes is already defined. */ + #define UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED 0x80660000 + + /* The server does not allow this type of self reference on this node. */ + #define UA_STATUSCODE_BADINVALIDSELFREFERENCE 0x80670000 + + /* The reference type is not valid for a reference to a remote server. */ + #define UA_STATUSCODE_BADREFERENCELOCALONLY 0x80680000 + + /* The server will not allow the node to be deleted. */ + #define UA_STATUSCODE_BADNODELETERIGHTS 0x80690000 + + /* The server was not able to delete all target references. */ + #define UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED 0x40BC0000 + + /* The server index is not valid. */ + #define UA_STATUSCODE_BADSERVERINDEXINVALID 0x806A0000 + + /* The view id does not refer to a valid view node. */ + #define UA_STATUSCODE_BADVIEWIDUNKNOWN 0x806B0000 + + /* The view timestamp is not available or not supported. */ + #define UA_STATUSCODE_BADVIEWTIMESTAMPINVALID 0x80C90000 + + /* The view parameters are not consistent with each other. */ + #define UA_STATUSCODE_BADVIEWPARAMETERMISMATCH 0x80CA0000 + + /* The view version is not available or not supported. */ + #define UA_STATUSCODE_BADVIEWVERSIONINVALID 0x80CB0000 + + /* The list of references may not be complete because the underlying system is not available. */ + #define UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE 0x40C00000 + + /* The server should have followed a reference to a node in a remote server but did not. The result set may be incomplete. */ + #define UA_STATUSCODE_GOODRESULTSMAYBEINCOMPLETE 0x00BA0000 + + /* The provided Nodeid was not a type definition nodeid. */ + #define UA_STATUSCODE_BADNOTTYPEDEFINITION 0x80C80000 + + /* One of the references to follow in the relative path references to a node in the address space in another server. */ + #define UA_STATUSCODE_UNCERTAINREFERENCEOUTOFSERVER 0x406C0000 + + /* The requested operation has too many matches to return. */ + #define UA_STATUSCODE_BADTOOMANYMATCHES 0x806D0000 + + /* The requested operation requires too many resources in the server. */ + #define UA_STATUSCODE_BADQUERYTOOCOMPLEX 0x806E0000 + + /* The requested operation has no match to return. */ + #define UA_STATUSCODE_BADNOMATCH 0x806F0000 + + /* The max age parameter is invalid. */ + #define UA_STATUSCODE_BADMAXAGEINVALID 0x80700000 + + /* The operation is not permitted over the current secure channel. */ + #define UA_STATUSCODE_BADSECURITYMODEINSUFFICIENT 0x80E60000 + + /* The history details parameter is not valid. */ + #define UA_STATUSCODE_BADHISTORYOPERATIONINVALID 0x80710000 + + /* The server does not support the requested operation. */ + #define UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED 0x80720000 + + /* The defined timestamp to return was invalid. */ + #define UA_STATUSCODE_BADINVALIDTIMESTAMPARGUMENT 0x80BD0000 + + /* The server does not support writing the combination of valu */ + #define UA_STATUSCODE_BADWRITENOTSUPPORTED 0x80730000 + + /* The value supplied for the attribute is not of the same type as the attribute's value. */ + #define UA_STATUSCODE_BADTYPEMISMATCH 0x80740000 + + /* The method id does not refer to a method for the specified object. */ + #define UA_STATUSCODE_BADMETHODINVALID 0x80750000 + + /* The client did not specify all of the input arguments for the method. */ + #define UA_STATUSCODE_BADARGUMENTSMISSING 0x80760000 + + /* The executable attribute does not allow the execution of the method. */ + #define UA_STATUSCODE_BADNOTEXECUTABLE 0x81110000 + + /* The server has reached its maximum number of subscriptions. */ + #define UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS 0x80770000 + + /* The server has reached the maximum number of queued publish requests. */ + #define UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS 0x80780000 + + /* There is no subscription available for this session. */ + #define UA_STATUSCODE_BADNOSUBSCRIPTION 0x80790000 + + /* The sequence number is unknown to the server. */ + #define UA_STATUSCODE_BADSEQUENCENUMBERUNKNOWN 0x807A0000 + + /* The Server does not support retransmission queue and acknowledgement of sequence numbers is not available. */ + #define UA_STATUSCODE_GOODRETRANSMISSIONQUEUENOTSUPPORTED 0x00DF0000 + + /* The requested notification message is no longer available. */ + #define UA_STATUSCODE_BADMESSAGENOTAVAILABLE 0x807B0000 + + /* The client of the current session does not support one or more Profiles that are necessary for the subscription. */ + #define UA_STATUSCODE_BADINSUFFICIENTCLIENTPROFILE 0x807C0000 + + /* The sub-state machine is not currently active. */ + #define UA_STATUSCODE_BADSTATENOTACTIVE 0x80BF0000 + + /* An equivalent rule already exists. */ + #define UA_STATUSCODE_BADALREADYEXISTS 0x81150000 + + /* The server cannot process the request because it is too busy. */ + #define UA_STATUSCODE_BADTCPSERVERTOOBUSY 0x807D0000 + + /* The type of the message specified in the header invalid. */ + #define UA_STATUSCODE_BADTCPMESSAGETYPEINVALID 0x807E0000 + + /* The SecureChannelId and/or TokenId are not currently in use. */ + #define UA_STATUSCODE_BADTCPSECURECHANNELUNKNOWN 0x807F0000 + + /* The size of the message chunk specified in the header is too large. */ + #define UA_STATUSCODE_BADTCPMESSAGETOOLARGE 0x80800000 + + /* There are not enough resources to process the request. */ + #define UA_STATUSCODE_BADTCPNOTENOUGHRESOURCES 0x80810000 + + /* An internal error occurred. */ + #define UA_STATUSCODE_BADTCPINTERNALERROR 0x80820000 + + /* The server does not recognize the QueryString specified. */ + #define UA_STATUSCODE_BADTCPENDPOINTURLINVALID 0x80830000 + + /* The request could not be sent because of a network interruption. */ + #define UA_STATUSCODE_BADREQUESTINTERRUPTED 0x80840000 + + /* Timeout occurred while processing the request. */ + #define UA_STATUSCODE_BADREQUESTTIMEOUT 0x80850000 + + /* The secure channel has been closed. */ + #define UA_STATUSCODE_BADSECURECHANNELCLOSED 0x80860000 + + /* The token has expired or is not recognized. */ + #define UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN 0x80870000 + + /* The sequence number is not valid. */ + #define UA_STATUSCODE_BADSEQUENCENUMBERINVALID 0x80880000 + + /* The applications do not have compatible protocol versions. */ + #define UA_STATUSCODE_BADPROTOCOLVERSIONUNSUPPORTED 0x80BE0000 + + /* There is a problem with the configuration that affects the usefulness of the value. */ + #define UA_STATUSCODE_BADCONFIGURATIONERROR 0x80890000 + + /* The variable should receive its value from another variabl */ + #define UA_STATUSCODE_BADNOTCONNECTED 0x808A0000 + + /* There has been a failure in the device/data source that generates the value that has affected the value. */ + #define UA_STATUSCODE_BADDEVICEFAILURE 0x808B0000 + + /* There has been a failure in the sensor from which the value is derived by the device/data source. */ + #define UA_STATUSCODE_BADSENSORFAILURE 0x808C0000 + + /* The source of the data is not operational. */ + #define UA_STATUSCODE_BADOUTOFSERVICE 0x808D0000 + + /* The deadband filter is not valid. */ + #define UA_STATUSCODE_BADDEADBANDFILTERINVALID 0x808E0000 + + /* Communication to the data source has failed. The variable value is the last value that had a good quality. */ + #define UA_STATUSCODE_UNCERTAINNOCOMMUNICATIONLASTUSABLEVALUE 0x408F0000 + + /* Whatever was updating this value has stopped doing so. */ + #define UA_STATUSCODE_UNCERTAINLASTUSABLEVALUE 0x40900000 + + /* The value is an operational value that was manually overwritten. */ + #define UA_STATUSCODE_UNCERTAINSUBSTITUTEVALUE 0x40910000 + + /* The value is an initial value for a variable that normally receives its value from another variable. */ + #define UA_STATUSCODE_UNCERTAININITIALVALUE 0x40920000 + + /* The value is at one of the sensor limits. */ + #define UA_STATUSCODE_UNCERTAINSENSORNOTACCURATE 0x40930000 + + /* The value is outside of the range of values defined for this parameter. */ + #define UA_STATUSCODE_UNCERTAINENGINEERINGUNITSEXCEEDED 0x40940000 + + /* The value is derived from multiple sources and has less than the required number of Good sources. */ + #define UA_STATUSCODE_UNCERTAINSUBNORMAL 0x40950000 + + /* The value has been overridden. */ + #define UA_STATUSCODE_GOODLOCALOVERRIDE 0x00960000 + + /* This Condition refresh faile */ + #define UA_STATUSCODE_BADREFRESHINPROGRESS 0x80970000 + + /* This condition has already been disabled. */ + #define UA_STATUSCODE_BADCONDITIONALREADYDISABLED 0x80980000 + + /* This condition has already been enabled. */ + #define UA_STATUSCODE_BADCONDITIONALREADYENABLED 0x80CC0000 + + /* Property not availabl */ + #define UA_STATUSCODE_BADCONDITIONDISABLED 0x80990000 + + /* The specified event id is not recognized. */ + #define UA_STATUSCODE_BADEVENTIDUNKNOWN 0x809A0000 + + /* The event cannot be acknowledged. */ + #define UA_STATUSCODE_BADEVENTNOTACKNOWLEDGEABLE 0x80BB0000 + + /* The dialog condition is not active. */ + #define UA_STATUSCODE_BADDIALOGNOTACTIVE 0x80CD0000 + + /* The response is not valid for the dialog. */ + #define UA_STATUSCODE_BADDIALOGRESPONSEINVALID 0x80CE0000 + + /* The condition branch has already been acknowledged. */ + #define UA_STATUSCODE_BADCONDITIONBRANCHALREADYACKED 0x80CF0000 + + /* The condition branch has already been confirmed. */ + #define UA_STATUSCODE_BADCONDITIONBRANCHALREADYCONFIRMED 0x80D00000 + + /* The condition has already been shelved. */ + #define UA_STATUSCODE_BADCONDITIONALREADYSHELVED 0x80D10000 + + /* The condition is not currently shelved. */ + #define UA_STATUSCODE_BADCONDITIONNOTSHELVED 0x80D20000 + + /* The shelving time not within an acceptable range. */ + #define UA_STATUSCODE_BADSHELVINGTIMEOUTOFRANGE 0x80D30000 + + /* No data exists for the requested time range or event filter. */ + #define UA_STATUSCODE_BADNODATA 0x809B0000 + + /* No data found to provide upper or lower bound value. */ + #define UA_STATUSCODE_BADBOUNDNOTFOUND 0x80D70000 + + /* The server cannot retrieve a bound for the variable. */ + #define UA_STATUSCODE_BADBOUNDNOTSUPPORTED 0x80D80000 + + /* Data is missing due to collection started/stopped/lost. */ + #define UA_STATUSCODE_BADDATALOST 0x809D0000 + + /* Expected data is unavailable for the requested time range due to an un-mounted volum */ + #define UA_STATUSCODE_BADDATAUNAVAILABLE 0x809E0000 + + /* The data or event was not successfully inserted because a matching entry exists. */ + #define UA_STATUSCODE_BADENTRYEXISTS 0x809F0000 + + /* The data or event was not successfully updated because no matching entry exists. */ + #define UA_STATUSCODE_BADNOENTRYEXISTS 0x80A00000 + + /* The client requested history using a timestamp format the server does not support (i.e requested ServerTimestamp when server only supports SourceTimestamp). */ + #define UA_STATUSCODE_BADTIMESTAMPNOTSUPPORTED 0x80A10000 + + /* The data or event was successfully inserted into the historical database. */ + #define UA_STATUSCODE_GOODENTRYINSERTED 0x00A20000 + + /* The data or event field was successfully replaced in the historical database. */ + #define UA_STATUSCODE_GOODENTRYREPLACED 0x00A30000 + + /* The value is derived from multiple values and has less than the required number of Good values. */ + #define UA_STATUSCODE_UNCERTAINDATASUBNORMAL 0x40A40000 + + /* No data exists for the requested time range or event filter. */ + #define UA_STATUSCODE_GOODNODATA 0x00A50000 + + /* The data or event field was successfully replaced in the historical database. */ + #define UA_STATUSCODE_GOODMOREDATA 0x00A60000 + + /* The requested number of Aggregates does not match the requested number of NodeIds. */ + #define UA_STATUSCODE_BADAGGREGATELISTMISMATCH 0x80D40000 + + /* The requested Aggregate is not support by the server. */ + #define UA_STATUSCODE_BADAGGREGATENOTSUPPORTED 0x80D50000 + + /* The aggregate value could not be derived due to invalid data inputs. */ + #define UA_STATUSCODE_BADAGGREGATEINVALIDINPUTS 0x80D60000 + + /* The aggregate configuration is not valid for specified node. */ + #define UA_STATUSCODE_BADAGGREGATECONFIGURATIONREJECTED 0x80DA0000 + + /* The request specifies fields which are not valid for the EventType or cannot be saved by the historian. */ + #define UA_STATUSCODE_GOODDATAIGNORED 0x00D90000 + + /* The request was rejected by the server because it did not meet the criteria set by the server. */ + #define UA_STATUSCODE_BADREQUESTNOTALLOWED 0x80E40000 + + /* The request has not been processed by the server yet. */ + #define UA_STATUSCODE_BADREQUESTNOTCOMPLETE 0x81130000 + + /* The device identity needs a ticket before it can be accepted. */ + #define UA_STATUSCODE_BADTICKETREQUIRED 0x811F0000 + + /* The device identity needs a ticket before it can be accepted. */ + #define UA_STATUSCODE_BADTICKETINVALID 0x81200000 + + /* The value does not come from the real source and has been edited by the server. */ + #define UA_STATUSCODE_GOODEDITED 0x00DC0000 + + /* There was an error in execution of these post-actions. */ + #define UA_STATUSCODE_GOODPOSTACTIONFAILED 0x00DD0000 + + /* The related EngineeringUnit has been changed but the Variable Value is still provided based on the previous unit. */ + #define UA_STATUSCODE_UNCERTAINDOMINANTVALUECHANGED 0x40DE0000 + + /* A dependent value has been changed but the change has not been applied to the device. */ + #define UA_STATUSCODE_GOODDEPENDENTVALUECHANGED 0x00E00000 + + /* 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. */ + #define UA_STATUSCODE_BADDOMINANTVALUECHANGED 0x80E10000 + + /* A dependent value has been changed but the change has not been applied to the device. The quality of the dominant variable is uncertain. */ + #define UA_STATUSCODE_UNCERTAINDEPENDENTVALUECHANGED 0x40E20000 + + /* A dependent value has been changed but the change has not been applied to the device. The quality of the dominant variable is Bad. */ + #define UA_STATUSCODE_BADDEPENDENTVALUECHANGED 0x80E30000 + + /* It is delivered with a dominant Variable value when a dependent Variable has changed but the change has not been applied. */ + #define UA_STATUSCODE_GOODEDITED_DEPENDENTVALUECHANGED 0x01160000 + + /* It is delivered with a dependent Variable value when a dominant Variable has changed but the change has not been applied. */ + #define UA_STATUSCODE_GOODEDITED_DOMINANTVALUECHANGED 0x01170000 + + /* It is delivered with a dependent Variable value when a dominant or dependent Variable has changed but change has not been applied. */ + #define UA_STATUSCODE_GOODEDITED_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED 0x01180000 + + /* It is delivered with a Variable value when Variable has changed but the value is not legal. */ + #define UA_STATUSCODE_BADEDITED_OUTOFRANGE 0x81190000 + + /* It is delivered with a Variable value when a source Variable has changed but the value is not legal. */ + #define UA_STATUSCODE_BADINITIALVALUE_OUTOFRANGE 0x811A0000 + + /* It is delivered with a dependent Variable value when a dominant Variable has changed and the value is not legal. */ + #define UA_STATUSCODE_BADOUTOFRANGE_DOMINANTVALUECHANGED 0x811B0000 + + /* It is delivered with a dependent Variable value when a dominant Variable has change */ + #define UA_STATUSCODE_BADEDITED_OUTOFRANGE_DOMINANTVALUECHANGED 0x811C0000 + + /* It is delivered with a dependent Variable value when a dominant or dependent Variable has changed and the value is not legal. */ + #define UA_STATUSCODE_BADOUTOFRANGE_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED 0x811D0000 + + /* It is delivered with a dependent Variable value when a dominant or dependent Variable has change */ + #define UA_STATUSCODE_BADEDITED_OUTOFRANGE_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED 0x811E0000 + + /* The communication layer has raised an event. */ + #define UA_STATUSCODE_GOODCOMMUNICATIONEVENT 0x00A70000 + + /* The system is shutting down. */ + #define UA_STATUSCODE_GOODSHUTDOWNEVENT 0x00A80000 + + /* The operation is not finished and needs to be called again. */ + #define UA_STATUSCODE_GOODCALLAGAIN 0x00A90000 + + /* A non-critical timeout occurred. */ + #define UA_STATUSCODE_GOODNONCRITICALTIMEOUT 0x00AA0000 + + /* One or more arguments are invalid. */ + #define UA_STATUSCODE_BADINVALIDARGUMENT 0x80AB0000 + + /* Could not establish a network connection to remote server. */ + #define UA_STATUSCODE_BADCONNECTIONREJECTED 0x80AC0000 + + /* The server has disconnected from the client. */ + #define UA_STATUSCODE_BADDISCONNECT 0x80AD0000 + + /* The network connection has been closed. */ + #define UA_STATUSCODE_BADCONNECTIONCLOSED 0x80AE0000 + + /* The operation cannot be completed because the object is close */ + #define UA_STATUSCODE_BADINVALIDSTATE 0x80AF0000 + + /* Cannot move beyond end of the stream. */ + #define UA_STATUSCODE_BADENDOFSTREAM 0x80B00000 + + /* No data is currently available for reading from a non-blocking stream. */ + #define UA_STATUSCODE_BADNODATAAVAILABLE 0x80B10000 + + /* The asynchronous operation is waiting for a response. */ + #define UA_STATUSCODE_BADWAITINGFORRESPONSE 0x80B20000 + + /* The asynchronous operation was abandoned by the caller. */ + #define UA_STATUSCODE_BADOPERATIONABANDONED 0x80B30000 + + /* The stream did not return all data requested (possibly because it is a non-blocking stream). */ + #define UA_STATUSCODE_BADEXPECTEDSTREAMTOBLOCK 0x80B40000 + + /* Non blocking behaviour is required and the operation would block. */ + #define UA_STATUSCODE_BADWOULDBLOCK 0x80B50000 + + /* A value had an invalid syntax. */ + #define UA_STATUSCODE_BADSYNTAXERROR 0x80B60000 + + /* The operation could not be finished because all available connections are in use. */ + #define UA_STATUSCODE_BADMAXCONNECTIONSREACHED 0x80B70000 + + /* Depending on the version of the schema, the following might be already defined: */ + #ifndef UA_STATUSCODE_GOOD + # define UA_STATUSCODE_GOOD 0x00000000 + #endif + #ifndef UA_STATUSCODE_UNCERTAIN + # define UA_STATUSCODE_UNCERTAIN 0x40000000 + #endif + #ifndef UA_STATUSCODE_BAD + # define UA_STATUSCODE_BAD 0x80000000 + #endif + diff --git a/static/doc/v1.4.0/_static/toc.rst b/static/doc/v1.4.0/_static/toc.rst new file mode 100644 index 0000000000..ea4f44dcbe --- /dev/null +++ b/static/doc/v1.4.0/_static/toc.rst @@ -0,0 +1,17 @@ +open62541 Documentation +####################### + +.. toctree:: + + index + core_concepts + building + types + server + client + pubsub + tutorials + common + nodeset_compiler + statuscodes + plugin diff --git a/static/doc/v1.4.0/_static/tutorial_client_firststeps.rst b/static/doc/v1.4.0/_static/tutorial_client_firststeps.rst new file mode 100644 index 0000000000..4145686f98 --- /dev/null +++ b/static/doc/v1.4.0/_static/tutorial_client_firststeps.rst @@ -0,0 +1,79 @@ +Building a Simple Client +------------------------ +You should already have a basic server from the previous tutorials. open62541 +provides both a server- and clientside API, so creating a client is as easy as +creating a server. Copy the following into a file `myClient.c`: + +.. code-block:: c + + + #include + #include + #include + + int main(void) { + UA_Client *client = UA_Client_new(); + UA_ClientConfig_setDefault(UA_Client_getConfig(client)); + UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840"); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "The connection failed with status code %s", + UA_StatusCode_name(retval)); + UA_Client_delete(client); + return 0; + } + + /* Read the value attribute of the node. UA_Client_readValueAttribute is a + * wrapper for the raw read service available as UA_Client_Service_read. */ + UA_Variant value; /* Variants can hold scalar values and arrays of any type */ + UA_Variant_init(&value); + + /* NodeId of the variable holding the current time */ + const UA_NodeId nodeId = + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME); + retval = UA_Client_readValueAttribute(client, nodeId, &value); + + if(retval == UA_STATUSCODE_GOOD && + UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME])) { + UA_DateTime raw_date = *(UA_DateTime *) value.data; + UA_DateTimeStruct dts = UA_DateTime_toStruct(raw_date); + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "date is: %u-%u-%u %u:%u:%u.%03u", + dts.day, dts.month, dts.year, dts.hour, + dts.min, dts.sec, dts.milliSec); + } else { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Reading the value failed with status code %s", + UA_StatusCode_name(retval)); + } + + /* Clean up */ + UA_Variant_clear(&value); + UA_Client_delete(client); /* Disconnects the client internally */ + return 0; + } + +Compilation is similar to the server example. + +.. code-block:: bash + + $ gcc -std=c99 myClient.c -lopen62541 -o myClient + +In a MinGW environment, the Winsock library must be added. + +.. code-block:: bash + + $ gcc -std=c99 myClient.c -lopen62541 -lws2_32 -o myClient.exe + +Further tasks +^^^^^^^^^^^^^ + +- Try to connect to some other OPC UA server by changing + ``opc.tcp://localhost:4840`` to an appropriate address (remember that the + queried node is contained in any OPC UA server). + +- Try to set the value of the variable node (ns=1,i="the.answer") containing + an ``Int32`` from the example server (which is built in + :doc:`tutorial_server_firststeps`) using "UA_Client_write" function. The + example server needs some more modifications, i.e., changing request types. + The answer can be found in ``examples/client.c``. diff --git a/static/doc/v1.4.0/_static/tutorial_datatypes.rst b/static/doc/v1.4.0/_static/tutorial_datatypes.rst new file mode 100644 index 0000000000..865decc8e4 --- /dev/null +++ b/static/doc/v1.4.0/_static/tutorial_datatypes.rst @@ -0,0 +1,192 @@ +.. _types-tutorial: + +Working with Data Types +----------------------- + +OPC UA defines a type system for values that can be encoded in the protocol +messages. This tutorial shows some examples for available data types and +their use. See the section on :ref:`types` for the full definitions. + +Basic Data Handling +^^^^^^^^^^^^^^^^^^^ +This section shows the basic interaction patterns for data types. Make +sure to compare with the type definitions in ``types.h``. + +.. code-block:: c + + + #include + #include + #include + + #include + #include + + static void + variables_basic(void) { + /* Int32 */ + UA_Int32 i = 5; + UA_Int32 j; + UA_Int32_copy(&i, &j); + + UA_Int32 *ip = UA_Int32_new(); + UA_Int32_copy(&i, ip); + UA_Int32_delete(ip); + + /* String */ + UA_String s; + UA_String_init(&s); /* _init zeroes out the entire memory of the datatype */ + char *test = "test"; + s.length = strlen(test); + s.data = (UA_Byte*)test; + + UA_String s2; + UA_String_copy(&s, &s2); + UA_String_clear(&s2); /* Copying heap-allocated the dynamic content */ + + UA_String s3 = UA_STRING("test2"); + UA_String s4 = UA_STRING_ALLOC("test2"); /* Copies the content to the heap */ + UA_Boolean eq = UA_String_equal(&s3, &s4); + UA_String_clear(&s4); + if(!eq) + return; + + /* Structured Type */ + UA_ReadRequest rr; + UA_init(&rr, &UA_TYPES[UA_TYPES_READREQUEST]); /* Generic method */ + UA_ReadRequest_init(&rr); /* Shorthand for the previous line */ + + rr.requestHeader.timestamp = UA_DateTime_now(); /* Members of a structure */ + + rr.nodesToRead = (UA_ReadValueId *)UA_Array_new(5, &UA_TYPES[UA_TYPES_READVALUEID]); + rr.nodesToReadSize = 5; /* Array size needs to be made known */ + + UA_ReadRequest *rr2 = UA_ReadRequest_new(); + UA_copy(&rr, rr2, &UA_TYPES[UA_TYPES_READREQUEST]); + UA_ReadRequest_clear(&rr); + UA_ReadRequest_delete(rr2); + } + +NodeIds +^^^^^^^ +An OPC UA information model is made up of nodes and references between nodes. +Every node has a unique :ref:`nodeid`. NodeIds refer to a namespace with an +additional identifier value that can be an integer, a string, a guid or a +bytestring. + +.. code-block:: c + + + static void + variables_nodeids(void) { + UA_NodeId id1 = UA_NODEID_NUMERIC(1, 1234); + id1.namespaceIndex = 3; + + UA_NodeId id2 = UA_NODEID_STRING(1, "testid"); /* the string is static */ + UA_Boolean eq = UA_NodeId_equal(&id1, &id2); + if(eq) + return; + + UA_NodeId id3; + UA_NodeId_copy(&id2, &id3); + UA_NodeId_clear(&id3); + + UA_NodeId id4 = UA_NODEID_STRING_ALLOC(1, "testid"); /* the string is copied + to the heap */ + UA_NodeId_clear(&id4); + } + +Variants +^^^^^^^^ +The datatype :ref:`variant` belongs to the built-in datatypes of OPC UA and +is used as a container type. A variant can hold any other datatype as a +scalar (except variant) or as an array. Array variants can additionally +denote the dimensionality of the data (e.g. a 2x3 matrix) in an additional +integer array. + +.. code-block:: c + + + static void + variables_variants(void) { + /* Set a scalar value */ + UA_Variant v; + UA_Int32 i = 42; + UA_Variant_setScalar(&v, &i, &UA_TYPES[UA_TYPES_INT32]); + + /* Make a copy */ + UA_Variant v2; + UA_Variant_copy(&v, &v2); + UA_Variant_clear(&v2); + + /* Set an array value */ + UA_Variant v3; + UA_Double d[9] = {1.0, 2.0, 3.0, + 4.0, 5.0, 6.0, + 7.0, 8.0, 9.0}; + UA_Variant_setArrayCopy(&v3, d, 9, &UA_TYPES[UA_TYPES_DOUBLE]); + + /* Set array dimensions */ + v3.arrayDimensions = (UA_UInt32 *)UA_Array_new(2, &UA_TYPES[UA_TYPES_UINT32]); + v3.arrayDimensionsSize = 2; + v3.arrayDimensions[0] = 3; + v3.arrayDimensions[1] = 3; + UA_Variant_clear(&v3); + } + + #ifdef UA_ENABLE_JSON_ENCODING + static void + prettyprint(void) { + UA_ReadRequest rr; + UA_ReadRequest_init(&rr); + UA_ReadValueId rvi[2]; + UA_ReadValueId_init(rvi); + UA_ReadValueId_init(&rvi[1]); + rr.nodesToRead = rvi; + rr.nodesToReadSize = 2; + UA_String out = UA_STRING_NULL; + UA_print(&rr, &UA_TYPES[UA_TYPES_READREQUEST], &out); + + printf("%.*s\n", (int)out.length, out.data); + UA_String_clear(&out); + + UA_ReadResponse resp; + UA_ReadResponse_init(&resp); + UA_print(&resp, &UA_TYPES[UA_TYPES_READRESPONSE], &out); + + printf("%.*s\n", (int)out.length, out.data); + UA_String_clear(&out); + + UA_ReferenceDescription br; + UA_ReferenceDescription_init(&br); + br.nodeClass = (UA_NodeClass)5; + UA_print(&br, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], &out); + printf("%.*s\n", (int)out.length, out.data); + UA_String_clear(&out); + + UA_Float matrix[4] = {1.0, 2.0, 3.0, 4.0}; + UA_UInt32 matrix_dims[2] = {2, 2}; + UA_DataValue dv; + UA_DataValue_init(&dv); + UA_Variant_setArray(&dv.value, &matrix, 4, &UA_TYPES[UA_TYPES_FLOAT]); + dv.value.arrayDimensions = matrix_dims; + dv.value.arrayDimensionsSize = 2; + dv.hasValue = true; + dv.hasStatus = true; + dv.hasServerTimestamp = true; + dv.hasSourcePicoseconds = true; + UA_print(&dv, &UA_TYPES[UA_TYPES_DATAVALUE], &out); + printf("%.*s\n", (int)out.length, out.data); + UA_String_clear(&out); + } + #endif + +It follows the main function, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + variables_basic(); + variables_nodeids(); + variables_variants(); diff --git a/static/doc/v1.4.0/_static/tutorial_pubsub_publish.rst b/static/doc/v1.4.0/_static/tutorial_pubsub_publish.rst new file mode 100644 index 0000000000..9d8b5b9576 --- /dev/null +++ b/static/doc/v1.4.0/_static/tutorial_pubsub_publish.rst @@ -0,0 +1,224 @@ +.. _pubsub-tutorial: + +Working with Publish/Subscribe +------------------------------ + +Work in progress: This Tutorial will be continuously extended during the next +PubSub batches. More details about the PubSub extension and corresponding +open62541 API are located here: :ref:`pubsub`. + +Publishing Fields +^^^^^^^^^^^^^^^^^ +The PubSub publish example demonstrates the simplest way to publish +information from the information model over UDP multicast using the UADP +encoding. + +**Connection handling** + +PubSubConnections can be created and deleted on runtime. More details about +the system preconfiguration and connection can be found in +``tutorial_pubsub_connection.c``. + +.. code-block:: c + + + #include + #include + #include + + #include + #include + + UA_NodeId connectionIdent, publishedDataSetIdent, writerGroupIdent; + + static void + addPubSubConnection(UA_Server *server, UA_String *transportProfile, + UA_NetworkAddressUrlDataType *networkAddressUrl){ + /* Details about the connection configuration and handling are located + * in the pubsub connection tutorial */ + UA_PubSubConnectionConfig connectionConfig; + memset(&connectionConfig, 0, sizeof(connectionConfig)); + connectionConfig.name = UA_STRING("UADP Connection 1"); + connectionConfig.transportProfileUri = *transportProfile; + connectionConfig.enabled = UA_TRUE; + UA_Variant_setScalar(&connectionConfig.address, networkAddressUrl, + &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); + /* Changed to static publisherId from random generation to identify + * the publisher on Subscriber side */ + connectionConfig.publisherIdType = UA_PUBLISHERIDTYPE_UINT16; + connectionConfig.publisherId.uint16 = 2234; + UA_Server_addPubSubConnection(server, &connectionConfig, &connectionIdent); + } + +**PublishedDataSet handling** + +The PublishedDataSet (PDS) and PubSubConnection are the toplevel entities and +can exist alone. The PDS contains the collection of the published fields. All +other PubSub elements are directly or indirectly linked with the PDS or +connection. + +.. code-block:: c + + static void + addPublishedDataSet(UA_Server *server) { + /* The PublishedDataSetConfig contains all necessary public + * information for the creation of a new PublishedDataSet */ + UA_PublishedDataSetConfig publishedDataSetConfig; + memset(&publishedDataSetConfig, 0, sizeof(UA_PublishedDataSetConfig)); + publishedDataSetConfig.publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDITEMS; + publishedDataSetConfig.name = UA_STRING("Demo PDS"); + /* Create new PublishedDataSet based on the PublishedDataSetConfig. */ + UA_Server_addPublishedDataSet(server, &publishedDataSetConfig, &publishedDataSetIdent); + } + +**DataSetField handling** + +The DataSetField (DSF) is part of the PDS and describes exactly one published +field. + +.. code-block:: c + + static void + addDataSetField(UA_Server *server) { + /* Add a field to the previous created PublishedDataSet */ + UA_NodeId dataSetFieldIdent; + UA_DataSetFieldConfig dataSetFieldConfig; + memset(&dataSetFieldConfig, 0, sizeof(UA_DataSetFieldConfig)); + dataSetFieldConfig.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE; + dataSetFieldConfig.field.variable.fieldNameAlias = UA_STRING("Server localtime"); + dataSetFieldConfig.field.variable.promotedField = UA_FALSE; + dataSetFieldConfig.field.variable.publishParameters.publishedVariable = + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME); + dataSetFieldConfig.field.variable.publishParameters.attributeId = UA_ATTRIBUTEID_VALUE; + UA_Server_addDataSetField(server, publishedDataSetIdent, + &dataSetFieldConfig, &dataSetFieldIdent); + } + +**WriterGroup handling** + +The WriterGroup (WG) is part of the connection and contains the primary +configuration parameters for the message creation. + +.. code-block:: c + + static void + addWriterGroup(UA_Server *server) { + /* Now we create a new WriterGroupConfig and add the group to the existing + * PubSubConnection. */ + UA_WriterGroupConfig writerGroupConfig; + memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig)); + writerGroupConfig.name = UA_STRING("Demo WriterGroup"); + writerGroupConfig.publishingInterval = 100; + writerGroupConfig.enabled = UA_FALSE; + writerGroupConfig.writerGroupId = 100; + writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP; + writerGroupConfig.messageSettings.encoding = UA_EXTENSIONOBJECT_DECODED; + writerGroupConfig.messageSettings.content.decoded.type = &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE]; + /* The configuration flags for the messages are encapsulated inside the + * message- and transport settings extension objects. These extension + * objects are defined by the standard. e.g. + * UadpWriterGroupMessageDataType */ + UA_UadpWriterGroupMessageDataType *writerGroupMessage = UA_UadpWriterGroupMessageDataType_new(); + /* Change message settings of writerGroup to send PublisherId, + * WriterGroupId in GroupHeader and DataSetWriterId in PayloadHeader + * of NetworkMessage */ + writerGroupMessage->networkMessageContentMask = (UA_UadpNetworkMessageContentMask)(UA_UADPNETWORKMESSAGECONTENTMASK_PUBLISHERID | + (UA_UadpNetworkMessageContentMask)UA_UADPNETWORKMESSAGECONTENTMASK_GROUPHEADER | + (UA_UadpNetworkMessageContentMask)UA_UADPNETWORKMESSAGECONTENTMASK_WRITERGROUPID | + (UA_UadpNetworkMessageContentMask)UA_UADPNETWORKMESSAGECONTENTMASK_PAYLOADHEADER); + writerGroupConfig.messageSettings.content.decoded.data = writerGroupMessage; + UA_Server_addWriterGroup(server, connectionIdent, &writerGroupConfig, &writerGroupIdent); + UA_Server_setWriterGroupOperational(server, writerGroupIdent); + UA_UadpWriterGroupMessageDataType_delete(writerGroupMessage); + } + +**DataSetWriter handling** + +A DataSetWriter (DSW) is the glue between the WG and the PDS. The DSW is +linked to exactly one PDS and contains additional information for the +message generation. + +.. code-block:: c + + static void + addDataSetWriter(UA_Server *server) { + /* We need now a DataSetWriter within the WriterGroup. This means we must + * create a new DataSetWriterConfig and add call the addWriterGroup function. */ + UA_NodeId dataSetWriterIdent; + UA_DataSetWriterConfig dataSetWriterConfig; + memset(&dataSetWriterConfig, 0, sizeof(UA_DataSetWriterConfig)); + dataSetWriterConfig.name = UA_STRING("Demo DataSetWriter"); + dataSetWriterConfig.dataSetWriterId = 62541; + dataSetWriterConfig.keyFrameCount = 10; + UA_Server_addDataSetWriter(server, writerGroupIdent, publishedDataSetIdent, + &dataSetWriterConfig, &dataSetWriterIdent); + } + +That's it! You're now publishing the selected fields. Open a packet +inspection tool of trust e.g. wireshark and take a look on the outgoing +packages. The following graphic figures out the packages created by this +tutorial. + +.. figure:: ua-wireshark-pubsub.png + :figwidth: 100 % + :alt: OPC UA PubSub communication in wireshark + +The open62541 subscriber API will be released later. If you want to process +the the datagrams, take a look on the ``ua_network_pubsub_networkmessage.c`` +which already contains the decoding code for UADP messages. + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + static int run(UA_String *transportProfile, + UA_NetworkAddressUrlDataType *networkAddressUrl) { + UA_Server *server = UA_Server_new(); + + addPubSubConnection(server, transportProfile, networkAddressUrl); + addPublishedDataSet(server); + addDataSetField(server); + addWriterGroup(server); + addDataSetWriter(server); + + UA_StatusCode retval = UA_Server_runUntilInterrupt(server); + + UA_Server_delete(server); + return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE; + } + + static void + usage(char *progname) { + printf("usage: %s [device]\n", progname); + } + + int main(int argc, char **argv) { + UA_String transportProfile = + UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"); + UA_NetworkAddressUrlDataType networkAddressUrl = + {UA_STRING_NULL , UA_STRING("opc.udp://224.0.0.22:4840/")}; + + if (argc > 1) { + if (strcmp(argv[1], "-h") == 0) { + usage(argv[0]); + return EXIT_SUCCESS; + } else if (strncmp(argv[1], "opc.udp://", 10) == 0) { + networkAddressUrl.url = UA_STRING(argv[1]); + } else if (strncmp(argv[1], "opc.eth://", 10) == 0) { + transportProfile = + UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp"); + if (argc < 3) { + printf("Error: UADP/ETH needs an interface name\n"); + return EXIT_FAILURE; + } + networkAddressUrl.networkInterface = UA_STRING(argv[2]); + networkAddressUrl.url = UA_STRING(argv[1]); + } else { + printf("Error: unknown URI\n"); + return EXIT_FAILURE; + } + } + + return run(&transportProfile, &networkAddressUrl); + } diff --git a/static/doc/v1.4.0/_static/tutorial_pubsub_subscribe.rst b/static/doc/v1.4.0/_static/tutorial_pubsub_subscribe.rst new file mode 100644 index 0000000000..6a7c4a901e --- /dev/null +++ b/static/doc/v1.4.0/_static/tutorial_pubsub_subscribe.rst @@ -0,0 +1,328 @@ +.. _pubsub-subscribe-tutorial: + +Subscribing Fields +^^^^^^^^^^^^^^^^^^ +The PubSub subscribe example demonstrates the simplest way to receive +information over two transport layers such as UDP and Ethernet, that are +published by tutorial_pubsub_publish example and update values in the +TargetVariables of Subscriber Information Model. + +.. code-block:: c + + + #include + #include + #include + + #include + #include + + UA_NodeId connectionIdentifier; + UA_NodeId readerGroupIdentifier; + UA_NodeId readerIdentifier; + + UA_DataSetReaderConfig readerConfig; + + static void fillTestDataSetMetaData(UA_DataSetMetaDataType *pMetaData); + + /* Add new connection to the server */ + static UA_StatusCode + addPubSubConnection(UA_Server *server, UA_String *transportProfile, + UA_NetworkAddressUrlDataType *networkAddressUrl) { + if((server == NULL) || (transportProfile == NULL) || + (networkAddressUrl == NULL)) { + return UA_STATUSCODE_BADINTERNALERROR; + } + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + /* Configuration creation for the connection */ + UA_PubSubConnectionConfig connectionConfig; + memset (&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig)); + connectionConfig.name = UA_STRING("UDPMC Connection 1"); + connectionConfig.transportProfileUri = *transportProfile; + connectionConfig.enabled = UA_TRUE; + UA_Variant_setScalar(&connectionConfig.address, networkAddressUrl, + &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); + connectionConfig.publisherIdType = UA_PUBLISHERIDTYPE_UINT32; + connectionConfig.publisherId.uint32 = UA_UInt32_random(); + retval |= UA_Server_addPubSubConnection (server, &connectionConfig, &connectionIdentifier); + if (retval != UA_STATUSCODE_GOOD) { + return retval; + } + + return retval; + } + +**ReaderGroup** + +ReaderGroup is used to group a list of DataSetReaders. All ReaderGroups are +created within a PubSubConnection and automatically deleted if the connection +is removed. All network message related filters are only available in the DataSetReader. + +.. code-block:: c + + /* Add ReaderGroup to the created connection */ + static UA_StatusCode + addReaderGroup(UA_Server *server) { + if(server == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; + } + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + UA_ReaderGroupConfig readerGroupConfig; + memset (&readerGroupConfig, 0, sizeof(UA_ReaderGroupConfig)); + readerGroupConfig.name = UA_STRING("ReaderGroup1"); + retval |= UA_Server_addReaderGroup(server, connectionIdentifier, &readerGroupConfig, + &readerGroupIdentifier); + UA_Server_setReaderGroupOperational(server, readerGroupIdentifier); + return retval; + } + +**DataSetReader** + +DataSetReader can receive NetworkMessages with the DataSetMessage +of interest sent by the Publisher. DataSetReader provides +the configuration necessary to receive and process DataSetMessages +on the Subscriber side. DataSetReader must be linked with a +SubscribedDataSet and be contained within a ReaderGroup. + +.. code-block:: c + + /* Add DataSetReader to the ReaderGroup */ + static UA_StatusCode + addDataSetReader(UA_Server *server) { + if(server == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; + } + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + memset (&readerConfig, 0, sizeof(UA_DataSetReaderConfig)); + readerConfig.name = UA_STRING("DataSet Reader 1"); + /* Parameters to filter which DataSetMessage has to be processed + * by the DataSetReader */ + /* The following parameters are used to show that the data published by + * tutorial_pubsub_publish.c is being subscribed and is being updated in + * the information model */ + UA_UInt16 publisherIdentifier = 2234; + readerConfig.publisherId.type = &UA_TYPES[UA_TYPES_UINT16]; + readerConfig.publisherId.data = &publisherIdentifier; + readerConfig.writerGroupId = 100; + readerConfig.dataSetWriterId = 62541; + + /* Setting up Meta data configuration in DataSetReader */ + fillTestDataSetMetaData(&readerConfig.dataSetMetaData); + + retval |= UA_Server_addDataSetReader(server, readerGroupIdentifier, &readerConfig, + &readerIdentifier); + return retval; + } + +**SubscribedDataSet** + +Set SubscribedDataSet type to TargetVariables data type. +Add subscribedvariables to the DataSetReader + +.. code-block:: c + + static UA_StatusCode + addSubscribedVariables (UA_Server *server, UA_NodeId dataSetReaderId) { + if(server == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + UA_NodeId folderId; + UA_String folderName = readerConfig.dataSetMetaData.name; + UA_ObjectAttributes oAttr = UA_ObjectAttributes_default; + UA_QualifiedName folderBrowseName; + if(folderName.length > 0) { + oAttr.displayName.locale = UA_STRING ("en-US"); + oAttr.displayName.text = folderName; + folderBrowseName.namespaceIndex = 1; + folderBrowseName.name = folderName; + } + else { + oAttr.displayName = UA_LOCALIZEDTEXT ("en-US", "Subscribed Variables"); + folderBrowseName = UA_QUALIFIEDNAME (1, "Subscribed Variables"); + } + + UA_Server_addObjectNode (server, UA_NODEID_NULL, + UA_NODEID_NUMERIC (0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC (0, UA_NS0ID_ORGANIZES), + folderBrowseName, UA_NODEID_NUMERIC (0, + UA_NS0ID_BASEOBJECTTYPE), oAttr, NULL, &folderId); + +**TargetVariables** + +The SubscribedDataSet option TargetVariables defines a list of Variable mappings between +received DataSet fields and target Variables in the Subscriber AddressSpace. +The values subscribed from the Publisher are updated in the value field of these variables + +.. code-block:: c + + /* Create the TargetVariables with respect to DataSetMetaData fields */ + UA_FieldTargetVariable *targetVars = (UA_FieldTargetVariable *) + UA_calloc(readerConfig.dataSetMetaData.fieldsSize, sizeof(UA_FieldTargetVariable)); + for(size_t i = 0; i < readerConfig.dataSetMetaData.fieldsSize; i++) { + /* Variable to subscribe data */ + UA_VariableAttributes vAttr = UA_VariableAttributes_default; + UA_LocalizedText_copy(&readerConfig.dataSetMetaData.fields[i].description, + &vAttr.description); + vAttr.displayName.locale = UA_STRING("en-US"); + vAttr.displayName.text = readerConfig.dataSetMetaData.fields[i].name; + vAttr.dataType = readerConfig.dataSetMetaData.fields[i].dataType; + + UA_NodeId newNode; + retval |= UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, (UA_UInt32)i + 50000), + folderId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, (char *)readerConfig.dataSetMetaData.fields[i].name.data), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + vAttr, NULL, &newNode); + + /* For creating Targetvariables */ + UA_FieldTargetDataType_init(&targetVars[i].targetVariable); + targetVars[i].targetVariable.attributeId = UA_ATTRIBUTEID_VALUE; + targetVars[i].targetVariable.targetNodeId = newNode; + } + + retval = UA_Server_DataSetReader_createTargetVariables(server, dataSetReaderId, + readerConfig.dataSetMetaData.fieldsSize, targetVars); + for(size_t i = 0; i < readerConfig.dataSetMetaData.fieldsSize; i++) + UA_FieldTargetDataType_clear(&targetVars[i].targetVariable); + + UA_free(targetVars); + UA_free(readerConfig.dataSetMetaData.fields); + return retval; + } + +**DataSetMetaData** + +The DataSetMetaData describes the content of a DataSet. It provides the information necessary to decode +DataSetMessages on the Subscriber side. DataSetMessages received from the Publisher are decoded into +DataSet and each field is updated in the Subscriber based on datatype match of TargetVariable fields of Subscriber +and PublishedDataSetFields of Publisher + +.. code-block:: c + + /* Define MetaData for TargetVariables */ + static void fillTestDataSetMetaData(UA_DataSetMetaDataType *pMetaData) { + if(pMetaData == NULL) { + return; + } + + UA_DataSetMetaDataType_init (pMetaData); + pMetaData->name = UA_STRING ("DataSet 1"); + + /* Static definition of number of fields size to 4 to create four different + * targetVariables of distinct datatype + * Currently the publisher sends only DateTime data type */ + pMetaData->fieldsSize = 4; + pMetaData->fields = (UA_FieldMetaData*)UA_Array_new (pMetaData->fieldsSize, + &UA_TYPES[UA_TYPES_FIELDMETADATA]); + + /* DateTime DataType */ + UA_FieldMetaData_init (&pMetaData->fields[0]); + UA_NodeId_copy (&UA_TYPES[UA_TYPES_DATETIME].typeId, + &pMetaData->fields[0].dataType); + pMetaData->fields[0].builtInType = UA_NS0ID_DATETIME; + pMetaData->fields[0].name = UA_STRING ("DateTime"); + pMetaData->fields[0].valueRank = -1; /* scalar */ + + /* Int32 DataType */ + UA_FieldMetaData_init (&pMetaData->fields[1]); + UA_NodeId_copy(&UA_TYPES[UA_TYPES_INT32].typeId, + &pMetaData->fields[1].dataType); + pMetaData->fields[1].builtInType = UA_NS0ID_INT32; + pMetaData->fields[1].name = UA_STRING ("Int32"); + pMetaData->fields[1].valueRank = -1; /* scalar */ + + /* Int64 DataType */ + UA_FieldMetaData_init (&pMetaData->fields[2]); + UA_NodeId_copy(&UA_TYPES[UA_TYPES_INT64].typeId, + &pMetaData->fields[2].dataType); + pMetaData->fields[2].builtInType = UA_NS0ID_INT64; + pMetaData->fields[2].name = UA_STRING ("Int64"); + pMetaData->fields[2].valueRank = -1; /* scalar */ + + /* Boolean DataType */ + UA_FieldMetaData_init (&pMetaData->fields[3]); + UA_NodeId_copy (&UA_TYPES[UA_TYPES_BOOLEAN].typeId, + &pMetaData->fields[3].dataType); + pMetaData->fields[3].builtInType = UA_NS0ID_BOOLEAN; + pMetaData->fields[3].name = UA_STRING ("BoolToggle"); + pMetaData->fields[3].valueRank = -1; /* scalar */ + } + +Followed by the main server code, making use of the above definitions + +.. code-block:: c + + + static int + run(UA_String *transportProfile, UA_NetworkAddressUrlDataType *networkAddressUrl) { + /* Return value initialized to Status Good */ + UA_StatusCode retval = UA_STATUSCODE_GOOD; + UA_Server *server = UA_Server_new(); + + /* API calls */ + /* Add PubSubConnection */ + retval |= addPubSubConnection(server, transportProfile, networkAddressUrl); + if (retval != UA_STATUSCODE_GOOD) + return EXIT_FAILURE; + + /* Add ReaderGroup to the created PubSubConnection */ + retval |= addReaderGroup(server); + if (retval != UA_STATUSCODE_GOOD) + return EXIT_FAILURE; + + /* Add DataSetReader to the created ReaderGroup */ + retval |= addDataSetReader(server); + if (retval != UA_STATUSCODE_GOOD) + return EXIT_FAILURE; + + /* Add SubscribedVariables to the created DataSetReader */ + retval |= addSubscribedVariables(server, readerIdentifier); + if (retval != UA_STATUSCODE_GOOD) + return EXIT_FAILURE; + + retval = UA_Server_runUntilInterrupt(server); + + UA_Server_delete(server); + return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE; + } + + static void + usage(char *progname) { + printf("usage: %s [device]\n", progname); + } + + int main(int argc, char **argv) { + UA_String transportProfile = + UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"); + UA_NetworkAddressUrlDataType networkAddressUrl = + {UA_STRING_NULL , UA_STRING("opc.udp://224.0.0.22:4840/")}; + if(argc > 1) { + if(strcmp(argv[1], "-h") == 0) { + usage(argv[0]); + return EXIT_SUCCESS; + } else if(strncmp(argv[1], "opc.udp://", 10) == 0) { + networkAddressUrl.url = UA_STRING(argv[1]); + } else if(strncmp(argv[1], "opc.eth://", 10) == 0) { + transportProfile = + UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp"); + if(argc < 3) { + printf("Error: UADP/ETH needs an interface name\n"); + return EXIT_FAILURE; + } + + networkAddressUrl.networkInterface = UA_STRING(argv[2]); + networkAddressUrl.url = UA_STRING(argv[1]); + } else { + printf ("Error: unknown URI\n"); + return EXIT_FAILURE; + } + } + + return run(&transportProfile, &networkAddressUrl); + } + diff --git a/static/doc/v1.4.0/_static/tutorial_server_alarms_conditions.rst b/static/doc/v1.4.0/_static/tutorial_server_alarms_conditions.rst new file mode 100644 index 0000000000..75c8e2209a --- /dev/null +++ b/static/doc/v1.4.0/_static/tutorial_server_alarms_conditions.rst @@ -0,0 +1,564 @@ +Using Alarms and Conditions Server +---------------------------------- + +Besides the usage of monitored items and events to observe the changes in the +server, it is also important to make use of the Alarms and Conditions Server +Model. Alarms are events which are triggered automatically by the server +dependent on internal server logic or user specific logic when the states of +server components change. The state of a component is represented through a +condition. So the values of all the condition children (Fields) are the +actual state of the component. + +Trigger Alarm events by changing States +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following example will be based on the server events tutorial. Please +make sure to understand the principle of normal events before proceeding with +this example! + +.. code-block:: c + + + static UA_NodeId conditionSource; + static UA_NodeId conditionInstance_1; + static UA_NodeId conditionInstance_2; + + static UA_StatusCode + addConditionSourceObject(UA_Server *server) { + UA_ObjectAttributes object_attr = UA_ObjectAttributes_default; + object_attr.eventNotifier = 1; + + object_attr.displayName = UA_LOCALIZEDTEXT("en", "ConditionSourceObject"); + UA_StatusCode retval = UA_Server_addObjectNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), + UA_QUALIFIEDNAME(0, "ConditionSourceObject"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), + object_attr, NULL, &conditionSource); + + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Creating Condition Source failed. StatusCode %s", + UA_StatusCode_name(retval)); + } + + /* ConditionSource should be EventNotifier of another Object (usually the + * Server Object). If this Reference is not created by user then the A&C + * Server will create "HasEventSource" reference to the Server Object + * automatically when the condition is created*/ + retval = UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASNOTIFIER), + UA_EXPANDEDNODEID_NUMERIC(conditionSource.namespaceIndex, + conditionSource.identifier.numeric), + UA_TRUE); + + return retval; + } + +Create a condition instance from OffNormalAlarmType. The condition source is +the Object created in addConditionSourceObject(). The condition will be +exposed in Address Space through the HasComponent reference to the condition +source. + +.. code-block:: c + + static UA_StatusCode + addCondition_1(UA_Server *server) { + UA_StatusCode retval = addConditionSourceObject(server); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "creating Condition Source failed. StatusCode %s", + UA_StatusCode_name(retval)); + } + + retval = UA_Server_createCondition(server, + UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_OFFNORMALALARMTYPE), + UA_QUALIFIEDNAME(0, "Condition 1"), conditionSource, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + &conditionInstance_1); + + return retval; + } + +Create a condition instance from OffNormalAlarmType. The condition source is +the server Object. The condition won't be exposed in Address Space. + +.. code-block:: c + + static UA_StatusCode + addCondition_2(UA_Server *server) { + UA_StatusCode retval = + UA_Server_createCondition(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_OFFNORMALALARMTYPE), + UA_QUALIFIEDNAME(0, "Condition 2"), + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), + UA_NODEID_NULL, &conditionInstance_2); + + return retval; + } + + static void + addVariable_1_triggerAlarmOfCondition_1(UA_Server *server, UA_NodeId* outNodeId) { + UA_VariableAttributes attr = UA_VariableAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("en", "Activate Condition 1"); + attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + UA_Boolean tboolValue = UA_FALSE; + UA_Variant_setScalar(&attr.value, &tboolValue, &UA_TYPES[UA_TYPES_BOOLEAN]); + + UA_QualifiedName CallbackTestVariableName = UA_QUALIFIEDNAME(0, "Activate Condition 1"); + UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE); + UA_Server_addVariableNode(server, UA_NODEID_NULL, parentNodeId, + parentReferenceNodeId, CallbackTestVariableName, + variableTypeNodeId, attr, NULL, outNodeId); + } + + static void + addVariable_2_changeSeverityOfCondition_2(UA_Server *server, + UA_NodeId* outNodeId) { + UA_VariableAttributes attr = UA_VariableAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("en", "Change Severity Condition 2"); + attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + UA_UInt16 severityValue = 0; + UA_Variant_setScalar(&attr.value, &severityValue, &UA_TYPES[UA_TYPES_UINT16]); + + UA_QualifiedName CallbackTestVariableName = + UA_QUALIFIEDNAME(0, "Change Severity Condition 2"); + UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE); + UA_Server_addVariableNode(server, UA_NODEID_NULL, parentNodeId, + parentReferenceNodeId, CallbackTestVariableName, + variableTypeNodeId, attr, NULL, outNodeId); + } + + static void + addVariable_3_returnCondition_1_toNormalState(UA_Server *server, + UA_NodeId* outNodeId) { + UA_VariableAttributes attr = UA_VariableAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("en", "Return to Normal Condition 1"); + attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + UA_Boolean rtn = 0; + UA_Variant_setScalar(&attr.value, &rtn, &UA_TYPES[UA_TYPES_BOOLEAN]); + + UA_QualifiedName CallbackTestVariableName = + UA_QUALIFIEDNAME(0, "Return to Normal Condition 1"); + UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE); + UA_Server_addVariableNode(server, UA_NODEID_NULL, parentNodeId, + parentReferenceNodeId, CallbackTestVariableName, + variableTypeNodeId, attr, NULL, outNodeId); + } + + static void + afterWriteCallbackVariable_1(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeId, + void *nodeContext, const UA_NumericRange *range, + const UA_DataValue *data) { + UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState"); + UA_QualifiedName activeStateIdField = UA_QUALIFIEDNAME(0,"Id"); + UA_Variant value; + + UA_StatusCode retval = + UA_Server_writeObjectProperty_scalar(server, conditionInstance_1, + UA_QUALIFIEDNAME(0, "Time"), + &data->sourceTimestamp, + &UA_TYPES[UA_TYPES_DATETIME]); + + if(*(UA_Boolean *)(data->value.data) == true) { + /* By writing "true" in ActiveState/Id, the A&C server will set the + * related fields automatically and then will trigger event + * notification. */ + UA_Boolean activeStateId = true; + UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]); + retval |= UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1, + &value, activeStateField, + activeStateIdField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting ActiveState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + } else { + /* By writing "false" in ActiveState/Id, the A&C server will set only + * the ActiveState field automatically to the value "Inactive". The user + * should trigger the event manually by calling + * UA_Server_triggerConditionEvent inside the application or call + * ConditionRefresh method with client to update the event notification. */ + UA_Boolean activeStateId = false; + UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]); + retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1, + &value, activeStateField, + activeStateIdField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting ActiveState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + retval = UA_Server_triggerConditionEvent(server, conditionInstance_1, + conditionSource, NULL); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Triggering condition event failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + } + } + +The callback only changes the severity field of the condition 2. The severity +field is of ConditionVariableType, so changes in it triggers an event +notification automatically by the server. + +.. code-block:: c + + static void + afterWriteCallbackVariable_2(UA_Server *server, const UA_NodeId *sessionId, + void *sessionContext, const UA_NodeId *nodeId, + void *nodeContext, const UA_NumericRange *range, + const UA_DataValue *data) { + /* Another way to set fields of conditions */ + UA_Server_writeObjectProperty_scalar(server, conditionInstance_2, + UA_QUALIFIEDNAME(0, "Severity"), + (UA_UInt16 *)data->value.data, + &UA_TYPES[UA_TYPES_UINT16]); + } + +RTN = return to normal. + +Retain will be set to false, thus no events will be generated for condition 1 +(although EnabledState/=true). To set Retain to true again, the disable and +enable methods should be called respectively. + +.. code-block:: c + + static void + afterWriteCallbackVariable_3(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + const UA_NumericRange *range, const UA_DataValue *data) { + + //UA_QualifiedName enabledStateField = UA_QUALIFIEDNAME(0,"EnabledState"); + UA_QualifiedName ackedStateField = UA_QUALIFIEDNAME(0,"AckedState"); + UA_QualifiedName confirmedStateField = UA_QUALIFIEDNAME(0,"ConfirmedState"); + UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState"); + UA_QualifiedName severityField = UA_QUALIFIEDNAME(0,"Severity"); + UA_QualifiedName messageField = UA_QUALIFIEDNAME(0,"Message"); + UA_QualifiedName commentField = UA_QUALIFIEDNAME(0,"Comment"); + UA_QualifiedName retainField = UA_QUALIFIEDNAME(0,"Retain"); + UA_QualifiedName idField = UA_QUALIFIEDNAME(0,"Id"); + + UA_StatusCode retval = + UA_Server_writeObjectProperty_scalar(server, conditionInstance_1, + UA_QUALIFIEDNAME(0, "Time"), + &data->serverTimestamp, + &UA_TYPES[UA_TYPES_DATETIME]); + UA_Variant value; + UA_Boolean idValue = false; + UA_Variant_setScalar(&value, &idValue, &UA_TYPES[UA_TYPES_BOOLEAN]); + retval |= UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1, + &value, activeStateField, + idField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting ActiveState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1, + &value, ackedStateField, + idField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting AckedState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1, + &value, confirmedStateField, + idField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting ConfirmedState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + UA_UInt16 severityValue = 100; + UA_Variant_setScalar(&value, &severityValue, &UA_TYPES[UA_TYPES_UINT16]); + retval = UA_Server_setConditionField(server, conditionInstance_1, + &value, severityField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting Severity Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + UA_LocalizedText messageValue = + UA_LOCALIZEDTEXT("en", "Condition returned to normal state"); + UA_Variant_setScalar(&value, &messageValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + retval = UA_Server_setConditionField(server, conditionInstance_1, + &value, messageField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting Message Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + UA_LocalizedText commentValue = UA_LOCALIZEDTEXT("en", "Normal State"); + UA_Variant_setScalar(&value, &commentValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + retval = UA_Server_setConditionField(server, conditionInstance_1, + &value, commentField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting Comment Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + UA_Boolean retainValue = false; + UA_Variant_setScalar(&value, &retainValue, &UA_TYPES[UA_TYPES_BOOLEAN]); + retval = UA_Server_setConditionField(server, conditionInstance_1, + &value, retainField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting Retain Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + retval = UA_Server_triggerConditionEvent(server, conditionInstance_1, + conditionSource, NULL); + if (retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Triggering condition event failed. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + } + + static UA_StatusCode + enteringEnabledStateCallback(UA_Server *server, const UA_NodeId *condition) { + UA_Boolean retain = true; + return UA_Server_writeObjectProperty_scalar(server, *condition, + UA_QUALIFIEDNAME(0, "Retain"), + &retain, + &UA_TYPES[UA_TYPES_BOOLEAN]); + } + +This is user specific function which will be called upon acknowledging an +alarm notification. In this example we will set the Alarm to Inactive state. +The server is responsible of setting standard fields related to Acknowledge +Method and triggering the alarm notification. + +.. code-block:: c + + static UA_StatusCode + enteringAckedStateCallback(UA_Server *server, const UA_NodeId *condition) { + /* deactivate Alarm when acknowledging*/ + UA_Boolean activeStateId = false; + UA_Variant value; + UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState"); + UA_QualifiedName activeStateIdField = UA_QUALIFIEDNAME(0,"Id"); + + UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]); + UA_StatusCode retval = + UA_Server_setConditionVariableFieldProperty(server, *condition, + &value, activeStateField, + activeStateIdField); + + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting ActiveState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + } + + return retval; + } + + static UA_StatusCode + enteringConfirmedStateCallback(UA_Server *server, const UA_NodeId *condition) { + /* Deactivate Alarm and put it out of the interesting state (by writing + * false to Retain field) when confirming*/ + UA_Boolean activeStateId = false; + UA_Boolean retain = false; + UA_Variant value; + UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState"); + UA_QualifiedName activeStateIdField = UA_QUALIFIEDNAME(0,"Id"); + UA_QualifiedName retainField = UA_QUALIFIEDNAME(0,"Retain"); + + UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]); + UA_StatusCode retval = + UA_Server_setConditionVariableFieldProperty(server, *condition, + &value, activeStateField, + activeStateIdField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting ActiveState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + UA_Variant_setScalar(&value, &retain, &UA_TYPES[UA_TYPES_BOOLEAN]); + retval = UA_Server_setConditionField(server, *condition, + &value, retainField); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting ActiveState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + } + + return retval; + } + + static UA_StatusCode + setUpEnvironment(UA_Server *server) { + UA_NodeId variable_1; + UA_NodeId variable_2; + UA_NodeId variable_3; + UA_ValueCallback callback; + callback.onRead = NULL; + + /* Exposed condition 1. We will add to it user specific callbacks when + * entering enabled state, when acknowledging and when confirming. */ + UA_StatusCode retval = addCondition_1(server); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "adding condition 1 failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + UA_TwoStateVariableChangeCallback userSpecificCallback = enteringEnabledStateCallback; + retval = UA_Server_setConditionTwoStateVariableCallback(server, conditionInstance_1, + conditionSource, false, + userSpecificCallback, + UA_ENTERING_ENABLEDSTATE); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "adding entering enabled state callback failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + userSpecificCallback = enteringAckedStateCallback; + retval = UA_Server_setConditionTwoStateVariableCallback(server, conditionInstance_1, + conditionSource, false, + userSpecificCallback, + UA_ENTERING_ACKEDSTATE); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "adding entering acked state callback failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + userSpecificCallback = enteringConfirmedStateCallback; + retval = UA_Server_setConditionTwoStateVariableCallback(server, conditionInstance_1, + conditionSource, false, + userSpecificCallback, + UA_ENTERING_CONFIRMEDSTATE); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "adding entering confirmed state callback failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + /* Unexposed condition 2. No user specific callbacks, so the server will + * behave in a standard manner upon entering enabled state, acknowledging + * and confirming. We will set Retain field to true and enable the condition + * so we can receive event notifications (we cannot call enable method on + * unexposed condition using a client like UaExpert or Softing). */ + retval = addCondition_2(server); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "adding condition 2 failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + UA_Boolean retain = UA_TRUE; + UA_Server_writeObjectProperty_scalar(server, conditionInstance_2, + UA_QUALIFIEDNAME(0, "Retain"), + &retain, &UA_TYPES[UA_TYPES_BOOLEAN]); + + UA_Variant value; + UA_Boolean enabledStateId = true; + UA_QualifiedName enabledStateField = UA_QUALIFIEDNAME(0,"EnabledState"); + UA_QualifiedName enabledStateIdField = UA_QUALIFIEDNAME(0,"Id"); + UA_Variant_setScalar(&value, &enabledStateId, &UA_TYPES[UA_TYPES_BOOLEAN]); + retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_2, + &value, enabledStateField, + enabledStateIdField); + + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting EnabledState/Id Field failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + + /* Add 3 variables to trigger condition events */ + addVariable_1_triggerAlarmOfCondition_1(server, &variable_1); + + callback.onWrite = afterWriteCallbackVariable_1; + retval = UA_Server_setVariableNode_valueCallback(server, variable_1, callback); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting variable 1 Callback failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + /* Severity can change internally also when the condition disabled and + * retain is false. However, in this case no events will be generated. */ + addVariable_2_changeSeverityOfCondition_2(server, &variable_2); + + callback.onWrite = afterWriteCallbackVariable_2; + retval = UA_Server_setVariableNode_valueCallback(server, variable_2, callback); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting variable 2 Callback failed. StatusCode %s", + UA_StatusCode_name(retval)); + return retval; + } + + addVariable_3_returnCondition_1_toNormalState(server, &variable_3); + + callback.onWrite = afterWriteCallbackVariable_3; + retval = UA_Server_setVariableNode_valueCallback(server, variable_3, callback); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting variable 3 Callback failed. StatusCode %s", + UA_StatusCode_name(retval)); + } + + return retval; + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main (void) { + UA_Server *server = UA_Server_new(); + + setUpEnvironment(server); + + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_static/tutorial_server_datasource.rst b/static/doc/v1.4.0/_static/tutorial_server_datasource.rst new file mode 100644 index 0000000000..69c19309cd --- /dev/null +++ b/static/doc/v1.4.0/_static/tutorial_server_datasource.rst @@ -0,0 +1,182 @@ +Connecting a Variable with a Physical Process +--------------------------------------------- + +In OPC UA-based architectures, servers are typically situated near the source +of information. In an industrial context, this translates into servers being +near the physical process and clients consuming the data at runtime. In the +previous tutorial, we saw how to add variables to an OPC UA information +model. This tutorial shows how to connect a variable to runtime information, +for example from measurements of a physical process. For simplicity, we take +the system clock as the underlying "process". + +The following code snippets are each concerned with a different way of +updating variable values at runtime. Taken together, the code snippets define +a compilable source file. + +Updating variables manually +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +As a starting point, assume that a variable for a value of type +:ref:`datetime` has been created in the server with the identifier +"ns=1,s=current-time". Assuming that our application gets triggered when a +new value arrives from the underlying process, we can just write into the +variable. + +.. code-block:: c + + + #include + #include + + static void + updateCurrentTime(UA_Server *server) { + UA_DateTime now = UA_DateTime_now(); + UA_Variant value; + UA_Variant_setScalar(&value, &now, &UA_TYPES[UA_TYPES_DATETIME]); + UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback"); + UA_Server_writeValue(server, currentNodeId, value); + } + + static void + addCurrentTimeVariable(UA_Server *server) { + UA_DateTime now = 0; + UA_VariableAttributes attr = UA_VariableAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("en-US", "Current time - value callback"); + attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + UA_Variant_setScalar(&attr.value, &now, &UA_TYPES[UA_TYPES_DATETIME]); + + UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback"); + UA_QualifiedName currentName = UA_QUALIFIEDNAME(1, "current-time-value-callback"); + UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE); + UA_Server_addVariableNode(server, currentNodeId, parentNodeId, + parentReferenceNodeId, currentName, + variableTypeNodeId, attr, NULL, NULL); + + updateCurrentTime(server); + } + +Variable Value Callback +^^^^^^^^^^^^^^^^^^^^^^^ + +When a value changes continuously, such as the system time, updating the +value in a tight loop would take up a lot of resources. Value callbacks allow +to synchronize a variable value with an external representation. They attach +callbacks to the variable that are executed before every read and after every +write operation. + +.. code-block:: c + + + static void + beforeReadTime(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeid, void *nodeContext, + const UA_NumericRange *range, const UA_DataValue *data) { + updateCurrentTime(server); + } + + static void + afterWriteTime(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + const UA_NumericRange *range, const UA_DataValue *data) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "The variable was updated"); + } + + static void + addValueCallbackToCurrentTimeVariable(UA_Server *server) { + UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback"); + UA_ValueCallback callback ; + callback.onRead = beforeReadTime; + callback.onWrite = afterWriteTime; + UA_Server_setVariableNode_valueCallback(server, currentNodeId, callback); + } + +Variable Data Sources +^^^^^^^^^^^^^^^^^^^^^ + +With value callbacks, the value is still stored in the variable node. +So-called data sources go one step further. The server redirects every read +and write request to a callback function. Upon reading, the callback provides +a copy of the current value. Internally, the data source needs to implement +its own memory management. + +.. code-block:: c + + + static UA_StatusCode + readCurrentTime(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + UA_Boolean sourceTimeStamp, const UA_NumericRange *range, + UA_DataValue *dataValue) { + UA_DateTime now = UA_DateTime_now(); + UA_Variant_setScalarCopy(&dataValue->value, &now, + &UA_TYPES[UA_TYPES_DATETIME]); + dataValue->hasValue = true; + return UA_STATUSCODE_GOOD; + } + + static UA_StatusCode + writeCurrentTime(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + const UA_NumericRange *range, const UA_DataValue *data) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Changing the system time is not implemented"); + return UA_STATUSCODE_BADINTERNALERROR; + } + + static void + addCurrentTimeDataSourceVariable(UA_Server *server) { + UA_VariableAttributes attr = UA_VariableAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("en-US", "Current time - data source"); + attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + + UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-datasource"); + UA_QualifiedName currentName = UA_QUALIFIEDNAME(1, "current-time-datasource"); + UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE); + + UA_DataSource timeDataSource; + timeDataSource.read = readCurrentTime; + timeDataSource.write = writeCurrentTime; + UA_Server_addDataSourceVariableNode(server, currentNodeId, parentNodeId, + parentReferenceNodeId, currentName, + variableTypeNodeId, attr, + timeDataSource, NULL, NULL); + } + + static UA_DataValue *externalValue; + + static void + addCurrentTimeExternalDataSource(UA_Server *server) { + UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-external-source"); + + UA_ValueBackend valueBackend; + valueBackend.backendType = UA_VALUEBACKENDTYPE_EXTERNAL; + valueBackend.backend.external.value = &externalValue; + + UA_Server_setVariableNode_valueBackend(server, currentNodeId, valueBackend); + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + UA_Server *server = UA_Server_new(); + + addCurrentTimeVariable(server); + addValueCallbackToCurrentTimeVariable(server); + addCurrentTimeDataSourceVariable(server); + addCurrentTimeExternalDataSource(server); + + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_static/tutorial_server_events.rst b/static/doc/v1.4.0/_static/tutorial_server_events.rst new file mode 100644 index 0000000000..36ab5d07b8 --- /dev/null +++ b/static/doc/v1.4.0/_static/tutorial_server_events.rst @@ -0,0 +1,161 @@ +Generating events +----------------- +To make sense of the many things going on in a server, monitoring items can +be useful. Though in many cases, data change does not convey enough +information to be the optimal solution. Events can be generated at any time, +hold a lot of information and can be filtered so the client only receives the +specific attributes of interest. + +Emitting events by calling methods +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The following example will be based on the server method tutorial. We will be +creating a method node which generates an event from the server node. + +The event we want to generate should be very simple. Since the `BaseEventType` is abstract, +we will have to create our own event type. `EventTypes` are saved internally as `ObjectTypes`, +so add the type as you would a new `ObjectType`. + +.. code-block:: c + + + static UA_NodeId eventType; + + static UA_StatusCode + addNewEventType(UA_Server *server) { + UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("en-US", "SimpleEventType"); + attr.description = UA_LOCALIZEDTEXT("en-US", "The simple event type we created"); + return UA_Server_addObjectTypeNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), + UA_QUALIFIEDNAME(0, "SimpleEventType"), + attr, NULL, &eventType); + } + +Setting up an event +^^^^^^^^^^^^^^^^^^^ +In order to set up the event, we can first use ``UA_Server_createEvent`` to +give us a node representation of the event. All we need for this is our +`EventType`. Once we have our event node, which is saved internally as an +`ObjectNode`, we can define the attributes the event has the same way we +would define the attributes of an object node. It is not necessary to define +the attributes `EventId`, `ReceiveTime`, `SourceNode` or `EventType` since +these are set automatically by the server. In this example, we will be +setting the fields 'Message' and 'Severity' in addition to `Time` which is +needed to make the example UaExpert compliant. + +.. code-block:: c + + + static UA_StatusCode + setUpEvent(UA_Server *server, UA_NodeId *outId) { + UA_StatusCode retval = UA_Server_createEvent(server, eventType, outId); + if (retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "createEvent failed. StatusCode %s", UA_StatusCode_name(retval)); + return retval; + } + + /* Set the Event Attributes */ + /* Setting the Time is required or else the event will not show up in UAExpert! */ + UA_DateTime eventTime = UA_DateTime_now(); + UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "Time"), + &eventTime, &UA_TYPES[UA_TYPES_DATETIME]); + + UA_UInt16 eventSeverity = 100; + UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "Severity"), + &eventSeverity, &UA_TYPES[UA_TYPES_UINT16]); + + UA_LocalizedText eventMessage = UA_LOCALIZEDTEXT("en-US", "An event has been generated."); + UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "Message"), + &eventMessage, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + + UA_String eventSourceName = UA_STRING("Server"); + UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "SourceName"), + &eventSourceName, &UA_TYPES[UA_TYPES_STRING]); + + return UA_STATUSCODE_GOOD; + } + +Triggering an event +^^^^^^^^^^^^^^^^^^^ +First a node representing an event is generated using ``setUpEvent``. Once +our event is good to go, we specify a node which emits the event - in this +case the server node. We can use ``UA_Server_triggerEvent`` to trigger our +event onto said node. Passing ``NULL`` as the second-last argument means we +will not receive the `EventId`. The last boolean argument states whether the +node should be deleted. + +.. code-block:: c + + + static UA_StatusCode + generateEventMethodCallback(UA_Server *server, + const UA_NodeId *sessionId, void *sessionHandle, + const UA_NodeId *methodId, void *methodContext, + const UA_NodeId *objectId, void *objectContext, + size_t inputSize, const UA_Variant *input, + size_t outputSize, UA_Variant *output) { + + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Creating event"); + + /* set up event */ + UA_NodeId eventNodeId; + UA_StatusCode retval = setUpEvent(server, &eventNodeId); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Creating event failed. StatusCode %s", UA_StatusCode_name(retval)); + return retval; + } + + retval = UA_Server_triggerEvent(server, eventNodeId, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), + NULL, UA_TRUE); + if(retval != UA_STATUSCODE_GOOD) + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Triggering event failed. StatusCode %s", UA_StatusCode_name(retval)); + + return retval; + } + +Now, all that is left to do is to create a method node which uses our +callback. We do not require any input and as output we will be using the +`EventId` we receive from ``triggerEvent``. The `EventId` is generated by the +server internally and is a random unique ID which identifies that specific +event. + +This method node will be added to a basic server setup. + +.. code-block:: c + + + static void + addGenerateEventMethod(UA_Server *server) { + UA_MethodAttributes generateAttr = UA_MethodAttributes_default; + generateAttr.description = UA_LOCALIZEDTEXT("en-US","Generate an event."); + generateAttr.displayName = UA_LOCALIZEDTEXT("en-US","Generate Event"); + generateAttr.executable = true; + generateAttr.userExecutable = true; + UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, 62541), + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "Generate Event"), + generateAttr, &generateEventMethodCallback, + 0, NULL, 0, NULL, NULL, NULL); + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + UA_Server *server = UA_Server_new(); + + addNewEventType(server); + addGenerateEventMethod(server); + + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_static/tutorial_server_firststeps.rst b/static/doc/v1.4.0/_static/tutorial_server_firststeps.rst new file mode 100644 index 0000000000..6763279b74 --- /dev/null +++ b/static/doc/v1.4.0/_static/tutorial_server_firststeps.rst @@ -0,0 +1,84 @@ +Building a Simple Server +------------------------ + +This series of tutorial guide you through your first steps with open62541. +For compiling the examples, you need a compiler (MS Visual Studio 2015 or +newer, GCC, Clang and MinGW32 are all known to be working). The compilation +instructions are given for GCC but should be straightforward to adapt. + +It will also be very helpful to install an OPC UA Client with a graphical +frontend, such as UAExpert by Unified Automation. That will enable you to +examine the information model of any OPC UA server. + +To get started, downdload the open62541 single-file release from +http://open62541.org or generate it according to the :ref:`build instructions +` with the "amalgamation" option enabled. From now on, we assume +you have the ``open62541.c/.h`` files in the current folder. Now create a new +C source-file called ``myServer.c`` with the following content: + +.. code-block:: c + + + #include + + int main(void) { + UA_Server *server = UA_Server_new(); + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } + +This is all that is needed for a simple OPC UA server. With the GCC compiler, +the following command produces an executable: + +.. code-block:: bash + + $ gcc -std=c99 myServer.c -lopen62541 -o myServer + +In a MinGW environment, the Winsock library must be added. + +.. code-block:: bash + + $ gcc -std=c99 myServer.c -lopen62541 -lws2_32 -o myServer.exe + +Now start the server (stop with ctrl-c): + +.. code-block:: bash + + $ ./myServer + +You have now compiled and run your first OPC UA server. You can go ahead and +browse the information model with client. The server is listening on +``opc.tcp://localhost:4840``. + + +Server Configuration and Plugins +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*open62541* provides a flexible framework for building OPC UA servers and +clients. The goals is to have a core library that accommodates for all use +cases and runs on all platforms. Users can then adjust the library to fit +their use case via configuration and by developing (platform-specific) +plugins. The core library is based on C99 only and does not even require +basic POSIX support. For example, the lowlevel networking code is implemented +as an exchangeable plugin. But don't worry. *open62541* provides plugin +implementations for most platforms and sensible default configurations +out-of-the-box. + +In the above server code, we simply take the default server configuration and +add a single TCP network layer that is listerning on port 4840. + +Server Lifecycle +^^^^^^^^^^^^^^^^ + +The code in this example shows the three parts for server lifecycle +management: Creating a server, running the server, and deleting the server. +Creating and deleting a server is trivial once the configuration is set up. +The server is started with ``UA_Server_run``. Internally, the server +schedules regular tasks. Between the timeouts, the server listens on the +network layer for incoming messages. + +In order to integrate OPC UA in a single-threaded application with its own +mainloop (for example provided by a GUI toolkit), one can alternatively drive +the server manually. See the section of the server documentation on +:ref:`server-lifecycle` for details. diff --git a/static/doc/v1.4.0/_static/tutorial_server_method.rst b/static/doc/v1.4.0/_static/tutorial_server_method.rst new file mode 100644 index 0000000000..d5f1453d88 --- /dev/null +++ b/static/doc/v1.4.0/_static/tutorial_server_method.rst @@ -0,0 +1,176 @@ +Adding Methods to Objects +------------------------- + +An object in an OPC UA information model may contain methods similar to +objects in a programming language. Methods are represented by a MethodNode. +Note that several objects may reference the same MethodNode. When an object +type is instantiated, a reference to the method is added instead of copying +the MethodNode. Therefore, the identifier of the context object is always +explicitly stated when a method is called. + +The method callback takes as input a custom data pointer attached to the +method node, the identifier of the object from which the method is called, +and two arrays for the input and output arguments. The input and output +arguments are all of type :ref:`variant`. Each variant may in turn contain a +(multi-dimensional) array or scalar of any data type. + +Constraints for the method arguments are defined in terms of data type, value +rank and array dimension (similar to variable definitions). The argument +definitions are stored in child VariableNodes of the MethodNode with the +respective BrowseNames ``(0, "InputArguments")`` and ``(0, +"OutputArguments")``. + +Example: Hello World Method +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The method takes a string scalar and returns a string scalar with "Hello " +prepended. The type and length of the input arguments is checked internally +by the SDK, so that we don't have to verify the arguments in the callback. + +.. code-block:: c + + + #include + #include + #include + + static UA_StatusCode + helloWorldMethodCallback(UA_Server *server, + const UA_NodeId *sessionId, void *sessionHandle, + const UA_NodeId *methodId, void *methodContext, + const UA_NodeId *objectId, void *objectContext, + size_t inputSize, const UA_Variant *input, + size_t outputSize, UA_Variant *output) { + UA_String *inputStr = (UA_String*)input->data; + UA_String tmp = UA_STRING_ALLOC("Hello "); + if(inputStr->length > 0) { + tmp.data = (UA_Byte *)UA_realloc(tmp.data, tmp.length + inputStr->length); + memcpy(&tmp.data[tmp.length], inputStr->data, inputStr->length); + tmp.length += inputStr->length; + } + UA_Variant_setScalarCopy(output, &tmp, &UA_TYPES[UA_TYPES_STRING]); + UA_String_clear(&tmp); + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Hello World was called"); + return UA_STATUSCODE_GOOD; + } + + static void + addHelloWorldMethod(UA_Server *server) { + UA_Argument inputArgument; + UA_Argument_init(&inputArgument); + inputArgument.description = UA_LOCALIZEDTEXT("en-US", "A String"); + inputArgument.name = UA_STRING("MyInput"); + inputArgument.dataType = UA_TYPES[UA_TYPES_STRING].typeId; + inputArgument.valueRank = UA_VALUERANK_SCALAR; + + UA_Argument outputArgument; + UA_Argument_init(&outputArgument); + outputArgument.description = UA_LOCALIZEDTEXT("en-US", "A String"); + outputArgument.name = UA_STRING("MyOutput"); + outputArgument.dataType = UA_TYPES[UA_TYPES_STRING].typeId; + outputArgument.valueRank = UA_VALUERANK_SCALAR; + + UA_MethodAttributes helloAttr = UA_MethodAttributes_default; + helloAttr.description = UA_LOCALIZEDTEXT("en-US","Say `Hello World`"); + helloAttr.displayName = UA_LOCALIZEDTEXT("en-US","Hello World"); + helloAttr.executable = true; + helloAttr.userExecutable = true; + UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1,62541), + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "hello world"), + helloAttr, &helloWorldMethodCallback, + 1, &inputArgument, 1, &outputArgument, NULL, NULL); + } + +Increase Array Values Method +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The method takes an array of 5 integers and a scalar as input. It returns a +copy of the array with every entry increased by the scalar. + +.. code-block:: c + + + static UA_StatusCode + IncInt32ArrayMethodCallback(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *methodId, void *methodContext, + const UA_NodeId *objectId, void *objectContext, + size_t inputSize, const UA_Variant *input, + size_t outputSize, UA_Variant *output) { + UA_Int32 *inputArray = (UA_Int32*)input[0].data; + UA_Int32 delta = *(UA_Int32*)input[1].data; + + /* Copy the input array */ + UA_StatusCode retval = UA_Variant_setArrayCopy(output, inputArray, 5, + &UA_TYPES[UA_TYPES_INT32]); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Increate the elements */ + UA_Int32 *outputArray = (UA_Int32*)output->data; + for(size_t i = 0; i < input->arrayLength; i++) + outputArray[i] = inputArray[i] + delta; + + return UA_STATUSCODE_GOOD; + } + + static void + addIncInt32ArrayMethod(UA_Server *server) { + /* Two input arguments */ + UA_Argument inputArguments[2]; + UA_Argument_init(&inputArguments[0]); + inputArguments[0].description = UA_LOCALIZEDTEXT("en-US", "int32[5] array"); + inputArguments[0].name = UA_STRING("int32 array"); + inputArguments[0].dataType = UA_TYPES[UA_TYPES_INT32].typeId; + inputArguments[0].valueRank = UA_VALUERANK_ONE_DIMENSION; + UA_UInt32 pInputDimension = 5; + inputArguments[0].arrayDimensionsSize = 1; + inputArguments[0].arrayDimensions = &pInputDimension; + + UA_Argument_init(&inputArguments[1]); + inputArguments[1].description = UA_LOCALIZEDTEXT("en-US", "int32 delta"); + inputArguments[1].name = UA_STRING("int32 delta"); + inputArguments[1].dataType = UA_TYPES[UA_TYPES_INT32].typeId; + inputArguments[1].valueRank = UA_VALUERANK_SCALAR; + + /* One output argument */ + UA_Argument outputArgument; + UA_Argument_init(&outputArgument); + outputArgument.description = UA_LOCALIZEDTEXT("en-US", "int32[5] array"); + outputArgument.name = UA_STRING("each entry is incremented by the delta"); + outputArgument.dataType = UA_TYPES[UA_TYPES_INT32].typeId; + outputArgument.valueRank = UA_VALUERANK_ONE_DIMENSION; + UA_UInt32 pOutputDimension = 5; + outputArgument.arrayDimensionsSize = 1; + outputArgument.arrayDimensions = &pOutputDimension; + + /* Add the method node */ + UA_MethodAttributes incAttr = UA_MethodAttributes_default; + incAttr.description = UA_LOCALIZEDTEXT("en-US", "IncInt32ArrayValues"); + incAttr.displayName = UA_LOCALIZEDTEXT("en-US", "IncInt32ArrayValues"); + incAttr.executable = true; + incAttr.userExecutable = true; + UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "IncInt32ArrayValues"), + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "IncInt32ArrayValues"), + incAttr, &IncInt32ArrayMethodCallback, + 2, inputArguments, 1, &outputArgument, + NULL, NULL); + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + UA_Server *server = UA_Server_new(); + + addHelloWorldMethod(server); + addIncInt32ArrayMethod(server); + + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_static/tutorial_server_monitoreditems.rst b/static/doc/v1.4.0/_static/tutorial_server_monitoreditems.rst new file mode 100644 index 0000000000..12bdc07919 --- /dev/null +++ b/static/doc/v1.4.0/_static/tutorial_server_monitoreditems.rst @@ -0,0 +1,57 @@ +Observing Attributes with Local MonitoredItems +---------------------------------------------- + +A client that is interested in the current value of a variable does not need +to regularly poll the variable. Instead, the client can use the Subscription +mechanism to be notified about changes. + +So-called MonitoredItems define which values (node attributes) and events the +client wants to monitor. Under the right conditions, a notification is +created and added to the Subscription. The notifications currently in the +queue are regularly sent to the client. + +The local user can add MonitoredItems as well. Locally, the MonitoredItems do +not go via a Subscription and each have an individual callback method and a +context pointer. + +.. code-block:: c + + + #include + #include + #include + + static void + dataChangeNotificationCallback(UA_Server *server, UA_UInt32 monitoredItemId, + void *monitoredItemContext, const UA_NodeId *nodeId, + void *nodeContext, UA_UInt32 attributeId, + const UA_DataValue *value) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Received Notification"); + } + + static void + addMonitoredItemToCurrentTimeVariable(UA_Server *server) { + UA_NodeId currentTimeNodeId = + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME); + UA_MonitoredItemCreateRequest monRequest = + UA_MonitoredItemCreateRequest_default(currentTimeNodeId); + monRequest.requestedParameters.samplingInterval = 100.0; /* 100 ms interval */ + UA_Server_createDataChangeMonitoredItem(server, UA_TIMESTAMPSTORETURN_SOURCE, + monRequest, NULL, + dataChangeNotificationCallback); + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + UA_Server *server = UA_Server_new(); + + addMonitoredItemToCurrentTimeVariable(server); + + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_static/tutorial_server_object.rst b/static/doc/v1.4.0/_static/tutorial_server_object.rst new file mode 100644 index 0000000000..bd225c6d9b --- /dev/null +++ b/static/doc/v1.4.0/_static/tutorial_server_object.rst @@ -0,0 +1,334 @@ +Working with Objects and Object Types +------------------------------------- + +Using objects to structure information models +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Assume a situation where we want to model a set of pumps and their runtime +state in an OPC UA information model. Of course, all pump representations +should follow the same basic structure, For example, we might have graphical +representation of pumps in a SCADA visualisation that shall be resuable for +all pumps. + +Following the object-oriented programming paradigm, every pump is represented +by an object with the following layout: + +.. graphviz:: + + digraph tree { + + fixedsize=true; + node [width=2, height=0, shape=box, fillcolor="#E5E5E5", concentrate=true] + + node_root [label=< ObjectNode
Pump >] + + { rank=same + point_1 [shape=point] + node_1 [label=< VariableNode
ManufacturerName >] } + node_root -> point_1 [arrowhead=none] + point_1 -> node_1 [label="hasComponent"] + + { rank=same + point_2 [shape=point] + node_2 [label=< VariableNode
ModelName >] } + point_1 -> point_2 [arrowhead=none] + point_2 -> node_2 [label="hasComponent"] + + { rank=same + point_4 [shape=point] + node_4 [label=< VariableNode
Status >] } + point_2 -> point_4 [arrowhead=none] + point_4 -> node_4 [label="hasComponent"] + + { rank=same + point_5 [shape=point] + node_5 [label=< VariableNode
MotorRPM >] } + point_4 -> point_5 [arrowhead=none] + point_5 -> node_5 [label="hasComponent"] + + } + +The following code manually defines a pump and its member variables. We omit +setting constraints on the variable values as this is not the focus of this +tutorial and was already covered. + +.. code-block:: c + + + static void + manuallyDefinePump(UA_Server *server) { + UA_NodeId pumpId; /* get the nodeid assigned by the server */ + UA_ObjectAttributes oAttr = UA_ObjectAttributes_default; + oAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Pump (Manual)"); + UA_Server_addObjectNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), + UA_QUALIFIEDNAME(1, "Pump (Manual)"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), + oAttr, NULL, &pumpId); + + UA_VariableAttributes mnAttr = UA_VariableAttributes_default; + UA_String manufacturerName = UA_STRING("Pump King Ltd."); + UA_Variant_setScalar(&mnAttr.value, &manufacturerName, &UA_TYPES[UA_TYPES_STRING]); + mnAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ManufacturerName"); + UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "ManufacturerName"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + mnAttr, NULL, NULL); + + UA_VariableAttributes modelAttr = UA_VariableAttributes_default; + UA_String modelName = UA_STRING("Mega Pump 3000"); + UA_Variant_setScalar(&modelAttr.value, &modelName, &UA_TYPES[UA_TYPES_STRING]); + modelAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ModelName"); + UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "ModelName"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + modelAttr, NULL, NULL); + + UA_VariableAttributes statusAttr = UA_VariableAttributes_default; + UA_Boolean status = true; + UA_Variant_setScalar(&statusAttr.value, &status, &UA_TYPES[UA_TYPES_BOOLEAN]); + statusAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Status"); + UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "Status"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + statusAttr, NULL, NULL); + + UA_VariableAttributes rpmAttr = UA_VariableAttributes_default; + UA_Double rpm = 50.0; + UA_Variant_setScalar(&rpmAttr.value, &rpm, &UA_TYPES[UA_TYPES_DOUBLE]); + rpmAttr.displayName = UA_LOCALIZEDTEXT("en-US", "MotorRPM"); + UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "MotorRPMs"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + rpmAttr, NULL, NULL); + } + +Object types, type hierarchies and instantiation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Building up each object manually requires us to write a lot of code. +Furthermore, there is no way for clients to detect that an object represents +a pump. (We might use naming conventions or similar to detect pumps. But +that's not exactly a clean solution.) Furthermore, we might have more devices +than just pumps. And we require all devices to share some common structure. +The solution is to define ObjectTypes in a hierarchy with inheritance +relations. + +.. graphviz:: + + digraph tree { + + fixedsize=true; + node [width=2, height=0, shape=box, fillcolor="#E5E5E5", concentrate=true] + + node_root [label=< ObjectTypeNode
Device >] + + { rank=same + point_1 [shape=point] + node_1 [label=< VariableNode
ManufacturerName
(mandatory) >] } + node_root -> point_1 [arrowhead=none] + point_1 -> node_1 [label="hasComponent"] + + { rank=same + point_2 [shape=point] + node_2 [label=< VariableNode
ModelName >] } + point_1 -> point_2 [arrowhead=none] + point_2 -> node_2 [label="hasComponent"] + + { rank=same + point_3 [shape=point] + node_3 [label=< ObjectTypeNode
Pump >] } + point_2 -> point_3 [arrowhead=none] + point_3 -> node_3 [label="hasSubtype"] + + { rank=same + point_4 [shape=point] + node_4 [label=< VariableNode
Status
(mandatory) >] } + node_3 -> point_4 [arrowhead=none] + point_4 -> node_4 [label="hasComponent"] + + { rank=same + point_5 [shape=point] + node_5 [label=< VariableNode
MotorRPM >] } + point_4 -> point_5 [arrowhead=none] + point_5 -> node_5 [label="hasComponent"] + + } + +Children that are marked mandatory are automatically instantiated together +with the parent object. This is indicated by a `hasModellingRule` reference +to an object that representes the `mandatory` modelling rule. + +.. code-block:: c + + + /* predefined identifier for later use */ + UA_NodeId pumpTypeId = {1, UA_NODEIDTYPE_NUMERIC, {1001}}; + + static void + defineObjectTypes(UA_Server *server) { + /* Define the object type for "Device" */ + UA_NodeId deviceTypeId; /* get the nodeid assigned by the server */ + UA_ObjectTypeAttributes dtAttr = UA_ObjectTypeAttributes_default; + dtAttr.displayName = UA_LOCALIZEDTEXT("en-US", "DeviceType"); + UA_Server_addObjectTypeNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), + UA_QUALIFIEDNAME(1, "DeviceType"), dtAttr, + NULL, &deviceTypeId); + + UA_VariableAttributes mnAttr = UA_VariableAttributes_default; + mnAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ManufacturerName"); + UA_NodeId manufacturerNameId; + UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "ManufacturerName"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + mnAttr, NULL, &manufacturerNameId); + /* Make the manufacturer name mandatory */ + UA_Server_addReference(server, manufacturerNameId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE), + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true); + + + UA_VariableAttributes modelAttr = UA_VariableAttributes_default; + modelAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ModelName"); + UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "ModelName"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + modelAttr, NULL, NULL); + + /* Define the object type for "Pump" */ + UA_ObjectTypeAttributes ptAttr = UA_ObjectTypeAttributes_default; + ptAttr.displayName = UA_LOCALIZEDTEXT("en-US", "PumpType"); + UA_Server_addObjectTypeNode(server, pumpTypeId, + deviceTypeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), + UA_QUALIFIEDNAME(1, "PumpType"), ptAttr, + NULL, NULL); + + UA_VariableAttributes statusAttr = UA_VariableAttributes_default; + statusAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Status"); + statusAttr.valueRank = UA_VALUERANK_SCALAR; + UA_NodeId statusId; + UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "Status"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + statusAttr, NULL, &statusId); + /* Make the status variable mandatory */ + UA_Server_addReference(server, statusId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE), + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true); + + UA_VariableAttributes rpmAttr = UA_VariableAttributes_default; + rpmAttr.displayName = UA_LOCALIZEDTEXT("en-US", "MotorRPM"); + rpmAttr.valueRank = UA_VALUERANK_SCALAR; + UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "MotorRPMs"), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + rpmAttr, NULL, NULL); + } + +Now we add the derived ObjectType for the pump that inherits from the device +object type. The resulting object contains all mandatory child variables. +These are simply copied over from the object type. The object has a reference +of type ``hasTypeDefinition`` to the object type, so that clients can detect +the type-instance relation at runtime. + +.. code-block:: c + + + static void + addPumpObjectInstance(UA_Server *server, char *name) { + UA_ObjectAttributes oAttr = UA_ObjectAttributes_default; + oAttr.displayName = UA_LOCALIZEDTEXT("en-US", name); + UA_Server_addObjectNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), + UA_QUALIFIEDNAME(1, name), + pumpTypeId, /* this refers to the object type + identifier */ + oAttr, NULL, NULL); + } + +Often we want to run a constructor function on a new object. This is +especially useful when an object is instantiated at runtime (with the +AddNodes service) and the integration with an underlying process cannot be +manually defined. In the following constructor example, we simply set the +pump status to on. + +.. code-block:: c + + + static UA_StatusCode + pumpTypeConstructor(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *typeId, void *typeContext, + const UA_NodeId *nodeId, void **nodeContext) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "New pump created"); + + /* Find the NodeId of the status child variable */ + UA_RelativePathElement rpe; + UA_RelativePathElement_init(&rpe); + rpe.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT); + rpe.isInverse = false; + rpe.includeSubtypes = false; + rpe.targetName = UA_QUALIFIEDNAME(1, "Status"); + + UA_BrowsePath bp; + UA_BrowsePath_init(&bp); + bp.startingNode = *nodeId; + bp.relativePath.elementsSize = 1; + bp.relativePath.elements = &rpe; + + UA_BrowsePathResult bpr = + UA_Server_translateBrowsePathToNodeIds(server, &bp); + if(bpr.statusCode != UA_STATUSCODE_GOOD || + bpr.targetsSize < 1) + return bpr.statusCode; + + /* Set the status value */ + UA_Boolean status = true; + UA_Variant value; + UA_Variant_setScalar(&value, &status, &UA_TYPES[UA_TYPES_BOOLEAN]); + UA_Server_writeValue(server, bpr.targets[0].targetId.nodeId, value); + UA_BrowsePathResult_clear(&bpr); + + /* At this point we could replace the node context .. */ + + return UA_STATUSCODE_GOOD; + } + + static void + addPumpTypeConstructor(UA_Server *server) { + UA_NodeTypeLifecycle lifecycle; + lifecycle.constructor = pumpTypeConstructor; + lifecycle.destructor = NULL; + UA_Server_setNodeTypeLifecycle(server, pumpTypeId, lifecycle); + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + UA_Server *server = UA_Server_new(); + + manuallyDefinePump(server); + defineObjectTypes(server); + addPumpObjectInstance(server, "pump2"); + addPumpObjectInstance(server, "pump3"); + addPumpTypeConstructor(server); + addPumpObjectInstance(server, "pump4"); + addPumpObjectInstance(server, "pump5"); + + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_static/tutorial_server_variable.rst b/static/doc/v1.4.0/_static/tutorial_server_variable.rst new file mode 100644 index 0000000000..c6c79e6f3b --- /dev/null +++ b/static/doc/v1.4.0/_static/tutorial_server_variable.rst @@ -0,0 +1,142 @@ +Adding Variables to a Server +---------------------------- + +This tutorial shows how to work with data types and how to add variable nodes +to a server. First, we add a new variable to the server. Take a look at the +definition of the ``UA_VariableAttributes`` structure to see the list of all +attributes defined for VariableNodes. + +Note that the default settings have the AccessLevel of the variable value as +read only. See below for making the variable writable. + +.. code-block:: c + + + #include + #include + #include + + static void + addVariable(UA_Server *server) { + /* Define the attribute of the myInteger variable node */ + UA_VariableAttributes attr = UA_VariableAttributes_default; + UA_Int32 myInteger = 42; + UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]); + attr.description = UA_LOCALIZEDTEXT("en-US","the answer"); + attr.displayName = UA_LOCALIZEDTEXT("en-US","the answer"); + attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId; + attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + + /* Add the variable node to the information model */ + UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); + UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer"); + UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, + parentReferenceNodeId, myIntegerName, + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), attr, NULL, NULL); + } + + static void + addMatrixVariable(UA_Server *server) { + UA_VariableAttributes attr = UA_VariableAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("en-US", "Double Matrix"); + attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + + /* Set the variable value constraints */ + attr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId; + attr.valueRank = UA_VALUERANK_TWO_DIMENSIONS; + UA_UInt32 arrayDims[2] = {2,2}; + attr.arrayDimensions = arrayDims; + attr.arrayDimensionsSize = 2; + + /* Set the value. The array dimensions need to be the same for the value. */ + UA_Double zero[4] = {0.0, 0.0, 0.0, 0.0}; + UA_Variant_setArray(&attr.value, zero, 4, &UA_TYPES[UA_TYPES_DOUBLE]); + attr.value.arrayDimensions = arrayDims; + attr.value.arrayDimensionsSize = 2; + + UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "double.matrix"); + UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "double matrix"); + UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, + parentReferenceNodeId, myIntegerName, + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + attr, NULL, NULL); + } + +Now we change the value with the write service. This uses the same service +implementation that can also be reached over the network by an OPC UA client. + +.. code-block:: c + + + static void + writeVariable(UA_Server *server) { + UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); + + /* Write a different integer value */ + UA_Int32 myInteger = 43; + UA_Variant myVar; + UA_Variant_init(&myVar); + UA_Variant_setScalar(&myVar, &myInteger, &UA_TYPES[UA_TYPES_INT32]); + UA_Server_writeValue(server, myIntegerNodeId, myVar); + + /* Set the status code of the value to an error code. The function + * UA_Server_write provides access to the raw service. The above + * UA_Server_writeValue is syntactic sugar for writing a specific node + * attribute with the write service. */ + UA_WriteValue wv; + UA_WriteValue_init(&wv); + wv.nodeId = myIntegerNodeId; + wv.attributeId = UA_ATTRIBUTEID_VALUE; + wv.value.status = UA_STATUSCODE_BADNOTCONNECTED; + wv.value.hasStatus = true; + UA_Server_write(server, &wv); + + /* Reset the variable to a good statuscode with a value */ + wv.value.hasStatus = false; + wv.value.value = myVar; + wv.value.hasValue = true; + UA_Server_write(server, &wv); + } + +Note how we initially set the DataType attribute of the variable node to the +NodeId of the Int32 data type. This forbids writing values that are not an +Int32. The following code shows how this consistency check is performed for +every write. + +.. code-block:: c + + + static void + writeWrongVariable(UA_Server *server) { + UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); + + /* Write a string */ + UA_String myString = UA_STRING("test"); + UA_Variant myVar; + UA_Variant_init(&myVar); + UA_Variant_setScalar(&myVar, &myString, &UA_TYPES[UA_TYPES_STRING]); + UA_StatusCode retval = UA_Server_writeValue(server, myIntegerNodeId, myVar); + printf("Writing a string returned statuscode %s\n", UA_StatusCode_name(retval)); + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + UA_Server *server = UA_Server_new(); + + addVariable(server); + addMatrixVariable(server); + writeVariable(server); + writeWrongVariable(server); + + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_static/tutorial_server_variabletype.rst b/static/doc/v1.4.0/_static/tutorial_server_variabletype.rst new file mode 100644 index 0000000000..0a59bcdf74 --- /dev/null +++ b/static/doc/v1.4.0/_static/tutorial_server_variabletype.rst @@ -0,0 +1,133 @@ +Working with Variable Types +--------------------------- + +Variable types have three functions: + +- Constrain the possible data type, value rank and array dimensions of the + variables of that type. This allows interface code to be written against + the generic type definition, so it is applicable for all instances. +- Provide a sensible default value +- Enable a semantic interpretation of the variable based on its type + +In the example of this tutorial, we represent a point in 2D space by an array +of double values. The following function adds the corresponding +VariableTypeNode to the hierarchy of variable types. + +.. code-block:: c + + + #include + #include + + static UA_NodeId pointTypeId; + + static void + addVariableType2DPoint(UA_Server *server) { + UA_VariableTypeAttributes vtAttr = UA_VariableTypeAttributes_default; + vtAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId; + vtAttr.valueRank = UA_VALUERANK_ONE_DIMENSION; + UA_UInt32 arrayDims[1] = {2}; + vtAttr.arrayDimensions = arrayDims; + vtAttr.arrayDimensionsSize = 1; + vtAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Type"); + + /* a matching default value is required */ + UA_Double zero[2] = {0.0, 0.0}; + UA_Variant_setArray(&vtAttr.value, zero, 2, &UA_TYPES[UA_TYPES_DOUBLE]); + + UA_Server_addVariableTypeNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), + UA_QUALIFIEDNAME(1, "2DPoint Type"), UA_NODEID_NULL, + vtAttr, NULL, &pointTypeId); + } + +Now the new variable type for *2DPoint* can be referenced during the creation +of a new variable. If no value is given, the default from the variable type +is copied during instantiation. + +.. code-block:: c + + + static UA_NodeId pointVariableId; + + static void + addVariable(UA_Server *server) { + /* Prepare the node attributes */ + UA_VariableAttributes vAttr = UA_VariableAttributes_default; + vAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId; + vAttr.valueRank = UA_VALUERANK_ONE_DIMENSION; + UA_UInt32 arrayDims[1] = {2}; + vAttr.arrayDimensions = arrayDims; + vAttr.arrayDimensionsSize = 1; + vAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Variable"); + vAttr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + /* vAttr.value is left empty, the server instantiates with the default value */ + + /* Add the node */ + UA_Server_addVariableNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "2DPoint Type"), pointTypeId, + vAttr, NULL, &pointVariableId); + } + +The constraints of the variable type are enforced when creating new variable +instances of the type. In the following function, adding a variable of +*2DPoint* type with a string value fails because the value does not match the +variable type constraints. + +.. code-block:: c + + + static void + addVariableFail(UA_Server *server) { + /* Prepare the node attributes */ + UA_VariableAttributes vAttr = UA_VariableAttributes_default; + vAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId; + vAttr.valueRank = UA_VALUERANK_SCALAR; /* a scalar. this is not allowed per + * the variable type */ + vAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Variable (fail)"); + UA_String s = UA_STRING("2dpoint?"); + UA_Variant_setScalar(&vAttr.value, &s, &UA_TYPES[UA_TYPES_STRING]); + + /* Add the node will return UA_STATUSCODE_BADTYPEMISMATCH*/ + UA_Server_addVariableNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, "2DPoint Type (fail)"), pointTypeId, + vAttr, NULL, NULL); + } + +The constraints of the variable type are enforced when writing the datatype, +valuerank and arraydimensions attributes of the variable. This, in turn, +constrains the value attribute of the variable. + +.. code-block:: c + + + static void + writeVariable(UA_Server *server) { + UA_StatusCode retval = + UA_Server_writeValueRank(server, pointVariableId, + UA_VALUERANK_ONE_OR_MORE_DIMENSIONS); + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Setting the Value Rank failed with Status Code %s", + UA_StatusCode_name(retval)); + } + +It follows the main server code, making use of the above definitions. + +.. code-block:: c + + + int main(void) { + UA_Server *server = UA_Server_new(); + addVariableType2DPoint(server); + addVariable(server); + addVariableFail(server); + writeVariable(server); + UA_Server_runUntilInterrupt(server); + UA_Server_delete(server); + return 0; + } diff --git a/static/doc/v1.4.0/_static/tutorials.rst b/static/doc/v1.4.0/_static/tutorials.rst new file mode 100644 index 0000000000..8c23338045 --- /dev/null +++ b/static/doc/v1.4.0/_static/tutorials.rst @@ -0,0 +1,20 @@ +.. _tutorials: + +Tutorials +========= + +.. toctree:: + + tutorial_datatypes.rst + tutorial_server_firststeps.rst + tutorial_server_variable.rst + tutorial_server_datasource.rst + tutorial_server_variabletype.rst + tutorial_server_object.rst + tutorial_server_method.rst + tutorial_server_monitoreditems.rst + tutorial_server_events.rst + tutorial_server_alarms_conditions.rst + tutorial_client_firststeps.rst + tutorial_pubsub_publish.rst + tutorial_pubsub_subscribe.rst diff --git a/static/doc/v1.4.0/_static/types.rst b/static/doc/v1.4.0/_static/types.rst new file mode 100644 index 0000000000..dce31cb1d0 --- /dev/null +++ b/static/doc/v1.4.0/_static/types.rst @@ -0,0 +1,1545 @@ +.. _types: + +Data Types +========== + +The OPC UA protocol defines 25 builtin data types and three ways of combining +them into higher-order types: arrays, structures and unions. In open62541, +only the builtin data types are defined manually. All other data types are +generated from standard XML definitions. Their exact definitions can be +looked up at https://opcfoundation.org/UA/schemas/Opc.Ua.Types.bsd. + +For users that are new to open62541, take a look at the :ref:`tutorial for +working with data types` before diving into the +implementation details. + +Builtin Types +------------- + +Boolean +^^^^^^^ +A two-state logical value (true or false). + +.. code-block:: c + + typedef bool UA_Boolean; + #define UA_TRUE true UA_INTERNAL_DEPRECATED + #define UA_FALSE false UA_INTERNAL_DEPRECATED + +SByte +^^^^^ +An integer value between -128 and 127. + +.. code-block:: c + + typedef int8_t UA_SByte; + #define UA_SBYTE_MIN (-128) + #define UA_SBYTE_MAX 127 + +Byte +^^^^ +An integer value between 0 and 255. + +.. code-block:: c + + typedef uint8_t UA_Byte; + #define UA_BYTE_MIN 0 + #define UA_BYTE_MAX 255 + +Int16 +^^^^^ +An integer value between -32 768 and 32 767. + +.. code-block:: c + + typedef int16_t UA_Int16; + #define UA_INT16_MIN (-32768) + #define UA_INT16_MAX 32767 + +UInt16 +^^^^^^ +An integer value between 0 and 65 535. + +.. code-block:: c + + typedef uint16_t UA_UInt16; + #define UA_UINT16_MIN 0 + #define UA_UINT16_MAX 65535 + +Int32 +^^^^^ +An integer value between -2 147 483 648 and 2 147 483 647. + +.. code-block:: c + + typedef int32_t UA_Int32; + #define UA_INT32_MIN ((int32_t)-2147483648LL) + #define UA_INT32_MAX 2147483647L + +UInt32 +^^^^^^ +An integer value between 0 and 4 294 967 295. + +.. code-block:: c + + typedef uint32_t UA_UInt32; + #define UA_UINT32_MIN 0 + #define UA_UINT32_MAX 4294967295UL + +Int64 +^^^^^ +An integer value between -9 223 372 036 854 775 808 and +9 223 372 036 854 775 807. + +.. code-block:: c + + typedef int64_t UA_Int64; + #define UA_INT64_MAX (int64_t)9223372036854775807LL + #define UA_INT64_MIN ((int64_t)-UA_INT64_MAX-1LL) + +UInt64 +^^^^^^ +An integer value between 0 and 18 446 744 073 709 551 615. + +.. code-block:: c + + typedef uint64_t UA_UInt64; + #define UA_UINT64_MIN 0 + #define UA_UINT64_MAX (uint64_t)18446744073709551615ULL + +Float +^^^^^ +An IEEE single precision (32 bit) floating point value. + +.. code-block:: c + + typedef float UA_Float; + #define UA_FLOAT_MIN FLT_MIN; + #define UA_FLOAT_MAX FLT_MAX; + +Double +^^^^^^ +An IEEE double precision (64 bit) floating point value. + +.. code-block:: c + + typedef double UA_Double; + #define UA_DOUBLE_MIN DBL_MIN; + #define UA_DOUBLE_MAX DBL_MAX; + +.. _statuscode: + +StatusCode +^^^^^^^^^^ +A numeric identifier for an error or condition that is associated with a +value or an operation. See the section :ref:`statuscodes` for the meaning of +a specific code. + +Each StatusCode has one of three "severity" bit-flags: +Good, Uncertain, Bad. An additional reason is indicated by the SubCode +bitfield. + +- A StatusCode with severity Good means that the value is of good quality. +- A StatusCode with severity Uncertain means that the quality of the value is + uncertain for reasons indicated by the SubCode. +- A StatusCode with severity Bad means that the value is not usable for + reasons indicated by the SubCode. + +.. code-block:: c + + typedef uint32_t UA_StatusCode; + + /* Returns the human-readable name of the StatusCode. If no matching StatusCode + * is found, a default string for "Unknown" is returned. This feature might be + * disabled to create a smaller binary with the + * UA_ENABLE_STATUSCODE_DESCRIPTIONS build-flag. Then the function returns an + * empty string for every StatusCode. */ + const char * + UA_StatusCode_name(UA_StatusCode code); + + /* Extracts the severity from a StatusCode. See Part 4, Section 7.34 for + * details. */ + UA_INLINABLE(UA_Boolean + UA_StatusCode_isBad(UA_StatusCode code), { + return ((code >> 30) >= 0x02); + }) + + UA_INLINABLE(UA_Boolean + UA_StatusCode_isUncertain(UA_StatusCode code), { + return ((code >> 30) == 0x01); + }) + + UA_INLINABLE(UA_Boolean + UA_StatusCode_isGood(UA_StatusCode code), { + return ((code >> 30) == 0x00); + }) + + /* Compares the top 16 bits of two StatusCodes for equality. This should only + * be used when processing user-defined StatusCodes e.g when processing a ReadResponse. + * As a convention, the lower bits of StatusCodes should not be used internally, meaning + * can compare them without the use of this function. */ + UA_INLINABLE(UA_Boolean + UA_StatusCode_isEqualTop(UA_StatusCode s1, UA_StatusCode s2), { + return ((s1 & 0xFFFF0000) == (s2 & 0xFFFF0000)); + }) + +String +^^^^^^ +A sequence of Unicode characters. Strings are just an array of UA_Byte. + +.. code-block:: c + + typedef struct { + size_t length; /* The length of the string */ + UA_Byte *data; /* The content (not null-terminated) */ + } UA_String; + + /* Copies the content on the heap. Returns a null-string when alloc fails */ + UA_String + UA_String_fromChars(const char *src); + + UA_Boolean + UA_String_isEmpty(const UA_String *s); + + extern const UA_String UA_STRING_NULL; + +``UA_STRING`` returns a string pointing to the original char-array. +``UA_STRING_ALLOC`` is shorthand for ``UA_String_fromChars`` and makes a copy +of the char-array. + +.. code-block:: c + + UA_INLINABLE(UA_String + UA_STRING(char *chars), { + UA_String s; + memset(&s, 0, sizeof(s)); + if(!chars) + return s; + s.length = strlen(chars); s.data = (UA_Byte*)chars; + return s; + }) + + #define UA_STRING_ALLOC(CHARS) UA_String_fromChars(CHARS) + + /* Define strings at compile time (in ROM) */ + #define UA_STRING_STATIC(CHARS) {sizeof(CHARS)-1, (UA_Byte*)CHARS} + +.. _datetime: + +DateTime +^^^^^^^^ +An instance in time. A DateTime value is encoded as a 64-bit signed integer +which represents the number of 100 nanosecond intervals since January 1, 1601 +(UTC). + +The methods providing an interface to the system clock are architecture- +specific. Usually, they provide a UTC clock that includes leap seconds. The +OPC UA standard allows the use of International Atomic Time (TAI) for the +DateTime instead. But this is still unusual and not implemented for most +SDKs. Currently (2019), UTC and TAI are 37 seconds apart due to leap +seconds. + +.. code-block:: c + + + typedef int64_t UA_DateTime; + + /* Multiples to convert durations to DateTime */ + #define UA_DATETIME_USEC 10LL + #define UA_DATETIME_MSEC (UA_DATETIME_USEC * 1000LL) + #define UA_DATETIME_SEC (UA_DATETIME_MSEC * 1000LL) + + /* The current time in UTC time */ + UA_DateTime UA_DateTime_now(void); + + /* Offset between local time and UTC time */ + UA_Int64 UA_DateTime_localTimeUtcOffset(void); + + /* CPU clock invariant to system time changes. Use only to measure durations, + * not absolute time. */ + UA_DateTime UA_DateTime_nowMonotonic(void); + + /* Represents a Datetime as a structure */ + typedef struct UA_DateTimeStruct { + UA_UInt16 nanoSec; + UA_UInt16 microSec; + UA_UInt16 milliSec; + UA_UInt16 sec; + UA_UInt16 min; + UA_UInt16 hour; + UA_UInt16 day; /* From 1 to 31 */ + UA_UInt16 month; /* From 1 to 12 */ + UA_Int16 year; /* Can be negative (BC) */ + } UA_DateTimeStruct; + + UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime t); + UA_DateTime UA_DateTime_fromStruct(UA_DateTimeStruct ts); + + /* The C99 standard (7.23.1) says: "The range and precision of times + * representable in clock_t and time_t are implementation-defined." On most + * systems, time_t is a 4 or 8 byte integer counting seconds since the UTC Unix + * epoch. The following methods are used for conversion. */ + + /* Datetime of 1 Jan 1970 00:00 */ + #define UA_DATETIME_UNIX_EPOCH (11644473600LL * UA_DATETIME_SEC) + + UA_INLINABLE(UA_Int64 + UA_DateTime_toUnixTime(UA_DateTime date), { + return (date - UA_DATETIME_UNIX_EPOCH) / UA_DATETIME_SEC; + }) + + UA_INLINABLE(UA_DateTime + UA_DateTime_fromUnixTime(UA_Int64 unixDate), { + return (unixDate * UA_DATETIME_SEC) + UA_DATETIME_UNIX_EPOCH; + }) + +Guid +^^^^ +A 16 byte value that can be used as a globally unique identifier. + +.. code-block:: c + + typedef struct { + UA_UInt32 data1; + UA_UInt16 data2; + UA_UInt16 data3; + UA_Byte data4[8]; + } UA_Guid; + + extern const UA_Guid UA_GUID_NULL; + + /* Print a Guid in the human-readable format defined in Part 6, 5.1.3 + * + * Format: C496578A-0DFE-4B8F-870A-745238C6AEAE + * | | | | | | + * 0 8 13 18 23 36 + * + * This allocates memory if the output argument is an empty string. Tries to use + * the given buffer otherwise. */ + UA_StatusCode + UA_Guid_print(const UA_Guid *guid, UA_String *output); + + /* Parse the humand-readable Guid format */ + #ifdef UA_ENABLE_PARSING + UA_StatusCode + UA_Guid_parse(UA_Guid *guid, const UA_String str); + + UA_INLINABLE(UA_Guid + UA_GUID(const char *chars), { + UA_Guid guid; + UA_Guid_parse(&guid, UA_STRING((char*)(uintptr_t)chars)); + return guid; + }) + #endif + +ByteString +^^^^^^^^^^ +A sequence of octets. + +.. code-block:: c + + typedef UA_String UA_ByteString; + + extern const UA_ByteString UA_BYTESTRING_NULL; + + /* Allocates memory of size length for the bytestring. + * The content is not set to zero. */ + UA_StatusCode + UA_ByteString_allocBuffer(UA_ByteString *bs, size_t length); + + /* Converts a ByteString to the corresponding + * base64 representation */ + UA_StatusCode + UA_ByteString_toBase64(const UA_ByteString *bs, UA_String *output); + + /* Parse a ByteString from a base64 representation */ + UA_StatusCode + UA_ByteString_fromBase64(UA_ByteString *bs, + const UA_String *input); + + #define UA_BYTESTRING(chars) UA_STRING(chars) + #define UA_BYTESTRING_ALLOC(chars) UA_STRING_ALLOC(chars) + + /* Returns a non-cryptographic hash of a bytestring */ + UA_UInt32 + UA_ByteString_hash(UA_UInt32 initialHashValue, + const UA_Byte *data, size_t size); + +XmlElement +^^^^^^^^^^ +An XML element. + +.. code-block:: c + + typedef UA_String UA_XmlElement; + +.. _nodeid: + +NodeId +^^^^^^ +An identifier for a node in the address space of an OPC UA Server. + +.. code-block:: c + + enum UA_NodeIdType { + UA_NODEIDTYPE_NUMERIC = 0, /* In the binary encoding, this can also + * become 1 or 2 (two-byte and four-byte + * encoding of small numeric nodeids) */ + UA_NODEIDTYPE_STRING = 3, + UA_NODEIDTYPE_GUID = 4, + UA_NODEIDTYPE_BYTESTRING = 5 + }; + + typedef struct { + UA_UInt16 namespaceIndex; + enum UA_NodeIdType identifierType; + union { + UA_UInt32 numeric; + UA_String string; + UA_Guid guid; + UA_ByteString byteString; + } identifier; + } UA_NodeId; + + extern const UA_NodeId UA_NODEID_NULL; + + UA_Boolean UA_NodeId_isNull(const UA_NodeId *p); + + /* Print the NodeId in the human-readable format defined in Part 6, + * 5.3.1.10. + * + * Examples: + * UA_NODEID("i=13") + * UA_NODEID("ns=10;i=1") + * UA_NODEID("ns=10;s=Hello:World") + * UA_NODEID("g=09087e75-8e5e-499b-954f-f2a9603db28a") + * UA_NODEID("ns=1;b=b3BlbjYyNTQxIQ==") // base64 + * + * The method can either use a pre-allocated string buffer or allocates memory + * internally if called with an empty output string. */ + UA_StatusCode + UA_NodeId_print(const UA_NodeId *id, UA_String *output); + + /* Parse the human-readable NodeId format. Attention! String and + * ByteString NodeIds have their identifier malloc'ed and need to be + * cleaned up. */ + #ifdef UA_ENABLE_PARSING + UA_StatusCode + UA_NodeId_parse(UA_NodeId *id, const UA_String str); + + UA_INLINABLE(UA_NodeId + UA_NODEID(const char *chars), { + UA_NodeId id; + UA_NodeId_parse(&id, UA_STRING((char*)(uintptr_t)chars)); + return id; + }) + #endif + +The following methods are a shorthand for creating NodeIds. + +.. code-block:: c + + UA_INLINABLE(UA_NodeId + UA_NODEID_NUMERIC(UA_UInt16 nsIndex, + UA_UInt32 identifier), { + UA_NodeId id; + memset(&id, 0, sizeof(UA_NodeId)); + id.namespaceIndex = nsIndex; + id.identifierType = UA_NODEIDTYPE_NUMERIC; + id.identifier.numeric = identifier; + return id; + }) + + UA_INLINABLE(UA_NodeId + UA_NODEID_STRING(UA_UInt16 nsIndex, char *chars), { + UA_NodeId id; + memset(&id, 0, sizeof(UA_NodeId)); + id.namespaceIndex = nsIndex; + id.identifierType = UA_NODEIDTYPE_STRING; + id.identifier.string = UA_STRING(chars); + return id; + }) + + UA_INLINABLE(UA_NodeId + UA_NODEID_STRING_ALLOC(UA_UInt16 nsIndex, + const char *chars), { + UA_NodeId id; + memset(&id, 0, sizeof(UA_NodeId)); + id.namespaceIndex = nsIndex; + id.identifierType = UA_NODEIDTYPE_STRING; + id.identifier.string = UA_STRING_ALLOC(chars); + return id; + }) + + UA_INLINABLE(UA_NodeId + UA_NODEID_GUID(UA_UInt16 nsIndex, UA_Guid guid), { + UA_NodeId id; + memset(&id, 0, sizeof(UA_NodeId)); + id.namespaceIndex = nsIndex; + id.identifierType = UA_NODEIDTYPE_GUID; + id.identifier.guid = guid; + return id; + }) + + UA_INLINABLE(UA_NodeId + UA_NODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars), { + UA_NodeId id; + memset(&id, 0, sizeof(UA_NodeId)); + id.namespaceIndex = nsIndex; + id.identifierType = UA_NODEIDTYPE_BYTESTRING; + id.identifier.byteString = UA_BYTESTRING(chars); + return id; + }) + + UA_INLINABLE(UA_NodeId + UA_NODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex, + const char *chars), { + UA_NodeId id; + memset(&id, 0, sizeof(UA_NodeId)); + id.namespaceIndex = nsIndex; + id.identifierType = UA_NODEIDTYPE_BYTESTRING; + id.identifier.byteString = UA_BYTESTRING_ALLOC(chars); + return id; + }) + + /* Total ordering of NodeId */ + UA_Order + UA_NodeId_order(const UA_NodeId *n1, const UA_NodeId *n2); + + /* Returns a non-cryptographic hash for NodeId */ + UA_UInt32 UA_NodeId_hash(const UA_NodeId *n); + +.. _expandednodeid: + +ExpandedNodeId +^^^^^^^^^^^^^^ +A NodeId that allows the namespace URI to be specified instead of an index. + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_String namespaceUri; + UA_UInt32 serverIndex; + } UA_ExpandedNodeId; + + extern const UA_ExpandedNodeId UA_EXPANDEDNODEID_NULL; + + /* Print the ExpandedNodeId in the humand-readable format defined in Part 6, + * 5.3.1.11: + * + * svr=;ns=;= + * or + * svr=;nsu=;= + * + * The definitions for svr, ns and nsu is omitted if zero / the empty string. + * + * The method can either use a pre-allocated string buffer or allocates memory + * internally if called with an empty output string. */ + UA_StatusCode + UA_ExpandedNodeId_print(const UA_ExpandedNodeId *id, UA_String *output); + + /* Parse the human-readable NodeId format. Attention! String and + * ByteString NodeIds have their identifier malloc'ed and need to be + * cleaned up. */ + #ifdef UA_ENABLE_PARSING + UA_StatusCode + UA_ExpandedNodeId_parse(UA_ExpandedNodeId *id, const UA_String str); + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID(const char *chars), { + UA_ExpandedNodeId id; + UA_ExpandedNodeId_parse(&id, UA_STRING((char*)(uintptr_t)chars)); + return id; + }) + #endif + +The following functions are shorthand for creating ExpandedNodeIds. + +.. code-block:: c + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID_NUMERIC(UA_UInt16 nsIndex, UA_UInt32 identifier), { + UA_ExpandedNodeId id; id.nodeId = UA_NODEID_NUMERIC(nsIndex, identifier); + id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; + }) + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID_STRING(UA_UInt16 nsIndex, char *chars), { + UA_ExpandedNodeId id; id.nodeId = UA_NODEID_STRING(nsIndex, chars); + id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; + }) + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID_STRING_ALLOC(UA_UInt16 nsIndex, const char *chars), { + UA_ExpandedNodeId id; id.nodeId = UA_NODEID_STRING_ALLOC(nsIndex, chars); + id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; + }) + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID_STRING_GUID(UA_UInt16 nsIndex, UA_Guid guid), { + UA_ExpandedNodeId id; id.nodeId = UA_NODEID_GUID(nsIndex, guid); + id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; + }) + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars), { + UA_ExpandedNodeId id; id.nodeId = UA_NODEID_BYTESTRING(nsIndex, chars); + id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; + }) + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex, const char *chars), { + UA_ExpandedNodeId id; id.nodeId = UA_NODEID_BYTESTRING_ALLOC(nsIndex, chars); + id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; + }) + + UA_INLINABLE(UA_ExpandedNodeId + UA_EXPANDEDNODEID_NODEID(UA_NodeId nodeId), { + UA_ExpandedNodeId id; memset(&id, 0, sizeof(UA_ExpandedNodeId)); + id.nodeId = nodeId; return id; + }) + + /* Does the ExpandedNodeId point to a local node? That is, are namespaceUri and + * serverIndex empty? */ + UA_Boolean + UA_ExpandedNodeId_isLocal(const UA_ExpandedNodeId *n); + + /* Total ordering of ExpandedNodeId */ + UA_Order + UA_ExpandedNodeId_order(const UA_ExpandedNodeId *n1, + const UA_ExpandedNodeId *n2); + + /* Returns a non-cryptographic hash for ExpandedNodeId. The hash of an + * ExpandedNodeId is identical to the hash of the embedded (simple) NodeId if + * the ServerIndex is zero and no NamespaceUri is set. */ + UA_UInt32 + UA_ExpandedNodeId_hash(const UA_ExpandedNodeId *n); + +.. _qualifiedname: + +QualifiedName +^^^^^^^^^^^^^ +A name qualified by a namespace. + +.. code-block:: c + + typedef struct { + UA_UInt16 namespaceIndex; + UA_String name; + } UA_QualifiedName; + + UA_INLINABLE(UA_Boolean + UA_QualifiedName_isNull(const UA_QualifiedName *q), { + return (q->namespaceIndex == 0 && q->name.length == 0); + }) + + /* Returns a non-cryptographic hash for QualifiedName */ + UA_UInt32 + UA_QualifiedName_hash(const UA_QualifiedName *q); + + UA_INLINABLE(UA_QualifiedName + UA_QUALIFIEDNAME(UA_UInt16 nsIndex, char *chars), { + UA_QualifiedName qn; + qn.namespaceIndex = nsIndex; + qn.name = UA_STRING(chars); + return qn; + }) + + UA_INLINABLE(UA_QualifiedName + UA_QUALIFIEDNAME_ALLOC(UA_UInt16 nsIndex, const char *chars), { + UA_QualifiedName qn; + qn.namespaceIndex = nsIndex; + qn.name = UA_STRING_ALLOC(chars); + return qn; + }) + +LocalizedText +^^^^^^^^^^^^^ +Human readable text with an optional locale identifier. + +.. code-block:: c + + typedef struct { + UA_String locale; + UA_String text; + } UA_LocalizedText; + + UA_INLINABLE(UA_LocalizedText + UA_LOCALIZEDTEXT(char *locale, char *text), { + UA_LocalizedText lt; + lt.locale = UA_STRING(locale); + lt.text = UA_STRING(text); + return lt; + }) + + UA_INLINABLE(UA_LocalizedText + UA_LOCALIZEDTEXT_ALLOC(const char *locale, const char *text), { + UA_LocalizedText lt; + lt.locale = UA_STRING_ALLOC(locale); + lt.text = UA_STRING_ALLOC(text); + return lt; + }) + +.. _numericrange: + +NumericRange +^^^^^^^^^^^^ + +NumericRanges are used to indicate subsets of a (multidimensional) array. +They no official data type in the OPC UA standard and are transmitted only +with a string encoding, such as "1:2,0:3,5". The colon separates min/max +index and the comma separates dimensions. A single value indicates a range +with a single element (min==max). + +.. code-block:: c + + typedef struct { + UA_UInt32 min; + UA_UInt32 max; + } UA_NumericRangeDimension; + + typedef struct { + size_t dimensionsSize; + UA_NumericRangeDimension *dimensions; + } UA_NumericRange; + + UA_StatusCode + UA_NumericRange_parse(UA_NumericRange *range, const UA_String str); + + UA_INLINABLE(UA_NumericRange + UA_NUMERICRANGE(const char *s), { + UA_NumericRange nr; + memset(&nr, 0, sizeof(nr)); + UA_NumericRange_parse(&nr, UA_STRING((char*)(uintptr_t)s)); + return nr; + }) + +.. _variant: + +Variant +^^^^^^^ + +Variants may contain values of any type together with a description of the +content. See the section on :ref:`generic-types` on how types are described. +The standard mandates that variants contain built-in data types only. If the +value is not of a builtin type, it is wrapped into an :ref:`extensionobject`. +open62541 hides this wrapping transparently in the encoding layer. If the +data type is unknown to the receiver, the variant contains the original +ExtensionObject in binary or XML encoding. + +Variants may contain a scalar value or an array. For details on the handling +of arrays, see the section on :ref:`array-handling`. Array variants can have +an additional dimensionality (matrix, 3-tensor, ...) defined in an array of +dimension lengths. The actual values are kept in an array of dimensions one. +For users who work with higher-dimensions arrays directly, keep in mind that +dimensions of higher rank are serialized first (the highest rank dimension +has stride 1 and elements follow each other directly). Usually it is simplest +to interact with higher-dimensional arrays via ``UA_NumericRange`` +descriptions (see :ref:`array-handling`). + +To differentiate between scalar / array variants, the following definition is +used. ``UA_Variant_isScalar`` provides simplified access to these checks. + +- ``arrayLength == 0 && data == NULL``: undefined array of length -1 +- ``arrayLength == 0 && data == UA_EMPTY_ARRAY_SENTINEL``: array of length 0 +- ``arrayLength == 0 && data > UA_EMPTY_ARRAY_SENTINEL``: scalar value +- ``arrayLength > 0``: array of the given length + +Variants can also be *empty*. Then, the pointer to the type description is +``NULL``. + +.. code-block:: c + + /* Forward declaration. See the section on Generic Type Handling */ + struct UA_DataType; + typedef struct UA_DataType UA_DataType; + + #define UA_EMPTY_ARRAY_SENTINEL ((void*)0x01) + + typedef enum { + UA_VARIANT_DATA, /* The data has the same lifecycle as the variant */ + UA_VARIANT_DATA_NODELETE /* The data is "borrowed" by the variant and is + * not deleted when the variant is cleared up. + * The array dimensions also borrowed. */ + } UA_VariantStorageType; + + typedef struct { + const UA_DataType *type; /* The data type description */ + UA_VariantStorageType storageType; + size_t arrayLength; /* The number of elements in the data array */ + void *data; /* Points to the scalar or array data */ + size_t arrayDimensionsSize; /* The number of dimensions */ + UA_UInt32 *arrayDimensions; /* The length of each dimension */ + } UA_Variant; + + /* Returns true if the variant has no value defined (contains neither an array + * nor a scalar value). + * + * @param v The variant + * @return Is the variant empty */ + UA_INLINABLE(UA_Boolean + UA_Variant_isEmpty(const UA_Variant *v), { + return v->type == NULL; + }) + + /* Returns true if the variant contains a scalar value. Note that empty variants + * contain an array of length -1 (undefined). + * + * @param v The variant + * @return Does the variant contain a scalar value */ + UA_INLINABLE(UA_Boolean + UA_Variant_isScalar(const UA_Variant *v), { + return (v->arrayLength == 0 && v->data > UA_EMPTY_ARRAY_SENTINEL); + }) + + /* Returns true if the variant contains a scalar value of the given type. + * + * @param v The variant + * @param type The data type + * @return Does the variant contain a scalar value of the given type */ + UA_INLINABLE(UA_Boolean + UA_Variant_hasScalarType(const UA_Variant *v, + const UA_DataType *type), { + return UA_Variant_isScalar(v) && type == v->type; + }) + + /* Returns true if the variant contains an array of the given type. + * + * @param v The variant + * @param type The data type + * @return Does the variant contain an array of the given type */ + UA_INLINABLE(UA_Boolean + UA_Variant_hasArrayType(const UA_Variant *v, + const UA_DataType *type), { + return (!UA_Variant_isScalar(v)) && type == v->type; + }) + + /* Set the variant to a scalar value that already resides in memory. The value + * takes on the lifecycle of the variant and is deleted with it. + * + * @param v The variant + * @param p A pointer to the value data + * @param type The datatype of the value in question */ + void + UA_Variant_setScalar(UA_Variant *v, void *p, + const UA_DataType *type); + + /* Set the variant to a scalar value that is copied from an existing variable. + * @param v The variant + * @param p A pointer to the value data + * @param type The datatype of the value + * @return Indicates whether the operation succeeded or returns an error code */ + UA_StatusCode + UA_Variant_setScalarCopy(UA_Variant *v, const void *p, + const UA_DataType *type); + + /* Set the variant to an array that already resides in memory. The array takes + * on the lifecycle of the variant and is deleted with it. + * + * @param v The variant + * @param array A pointer to the array data + * @param arraySize The size of the array + * @param type The datatype of the array */ + void + UA_Variant_setArray(UA_Variant *v, void *array, + size_t arraySize, const UA_DataType *type); + + /* Set the variant to an array that is copied from an existing array. + * + * @param v The variant + * @param array A pointer to the array data + * @param arraySize The size of the array + * @param type The datatype of the array + * @return Indicates whether the operation succeeded or returns an error code */ + UA_StatusCode + UA_Variant_setArrayCopy(UA_Variant *v, const void *array, + size_t arraySize, const UA_DataType *type); + + /* Copy the variant, but use only a subset of the (multidimensional) array into + * a variant. Returns an error code if the variant is not an array or if the + * indicated range does not fit. + * + * @param src The source variant + * @param dst The target variant + * @param range The range of the copied data + * @return Returns UA_STATUSCODE_GOOD or an error code */ + UA_StatusCode + UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, + const UA_NumericRange range); + + /* Insert a range of data into an existing variant. The data array cannot be + * reused afterwards if it contains types without a fixed size (e.g. strings) + * since the members are moved into the variant and take on its lifecycle. + * + * @param v The variant + * @param dataArray The data array. The type must match the variant + * @param dataArraySize The length of the data array. This is checked to match + * the range size. + * @param range The range of where the new data is inserted + * @return Returns UA_STATUSCODE_GOOD or an error code */ + UA_StatusCode + UA_Variant_setRange(UA_Variant *v, void *array, + size_t arraySize, const UA_NumericRange range); + + /* Deep-copy a range of data into an existing variant. + * + * @param v The variant + * @param dataArray The data array. The type must match the variant + * @param dataArraySize The length of the data array. This is checked to match + * the range size. + * @param range The range of where the new data is inserted + * @return Returns UA_STATUSCODE_GOOD or an error code */ + UA_StatusCode + UA_Variant_setRangeCopy(UA_Variant *v, const void *array, + size_t arraySize, const UA_NumericRange range); + +.. _extensionobject: + +ExtensionObject +^^^^^^^^^^^^^^^ + +ExtensionObjects may contain scalars of any data type. Even those that are +unknown to the receiver. See the section on :ref:`generic-types` on how types +are described. If the received data type is unknown, the encoded string and +target NodeId is stored instead of the decoded value. + +.. code-block:: c + + typedef enum { + UA_EXTENSIONOBJECT_ENCODED_NOBODY = 0, + UA_EXTENSIONOBJECT_ENCODED_BYTESTRING = 1, + UA_EXTENSIONOBJECT_ENCODED_XML = 2, + UA_EXTENSIONOBJECT_DECODED = 3, + UA_EXTENSIONOBJECT_DECODED_NODELETE = 4 /* Don't delete the content + together with the + ExtensionObject */ + } UA_ExtensionObjectEncoding; + + typedef struct { + UA_ExtensionObjectEncoding encoding; + union { + struct { + UA_NodeId typeId; /* The nodeid of the datatype */ + UA_ByteString body; /* The bytestring of the encoded data */ + } encoded; + struct { + const UA_DataType *type; + void *data; + } decoded; + } content; + } UA_ExtensionObject; + + /* Initialize the ExtensionObject and set the "decoded" value to the given + * pointer. The value will be deleted when the ExtensionObject is cleared. */ + void + UA_ExtensionObject_setValue(UA_ExtensionObject *eo, + void *p, + const UA_DataType *type); + + /* Initialize the ExtensionObject and set the "decoded" value to the given + * pointer. The value will *not* be deleted when the ExtensionObject is + * cleared. */ + void + UA_ExtensionObject_setValueNoDelete(UA_ExtensionObject *eo, + void *p, + const UA_DataType *type); + + /* Initialize the ExtensionObject and set the "decoded" value to a fresh copy of + * the given value pointer. The value will be deleted when the ExtensionObject + * is cleared. */ + UA_StatusCode + UA_ExtensionObject_setValueCopy(UA_ExtensionObject *eo, + void *p, + const UA_DataType *type); + +.. _datavalue: + +DataValue +^^^^^^^^^ +A data value with an associated status code and timestamps. + +.. code-block:: c + + typedef struct { + UA_Variant value; + UA_DateTime sourceTimestamp; + UA_DateTime serverTimestamp; + UA_UInt16 sourcePicoseconds; + UA_UInt16 serverPicoseconds; + UA_StatusCode status; + UA_Boolean hasValue : 1; + UA_Boolean hasStatus : 1; + UA_Boolean hasSourceTimestamp : 1; + UA_Boolean hasServerTimestamp : 1; + UA_Boolean hasSourcePicoseconds : 1; + UA_Boolean hasServerPicoseconds : 1; + } UA_DataValue; + + /* Copy the DataValue, but use only a subset of the (multidimensional) array of + * of the variant of the source DataValue. Returns an error code if the variant + * of the DataValue is not an array or if the indicated range does not fit. + * + * @param src The source DataValue + * @param dst The target DataValue + * @param range The range of the variant of the DataValue to copy + * @return Returns UA_STATUSCODE_GOOD or an error code */ + UA_StatusCode + UA_DataValue_copyVariantRange(const UA_DataValue *src, UA_DataValue *dst, + const UA_NumericRange range); + +DiagnosticInfo +^^^^^^^^^^^^^^ +A structure that contains detailed error and diagnostic information +associated with a StatusCode. + +.. code-block:: c + + typedef struct UA_DiagnosticInfo { + UA_Boolean hasSymbolicId : 1; + UA_Boolean hasNamespaceUri : 1; + UA_Boolean hasLocalizedText : 1; + UA_Boolean hasLocale : 1; + UA_Boolean hasAdditionalInfo : 1; + UA_Boolean hasInnerStatusCode : 1; + UA_Boolean hasInnerDiagnosticInfo : 1; + UA_Int32 symbolicId; + UA_Int32 namespaceUri; + UA_Int32 localizedText; + UA_Int32 locale; + UA_String additionalInfo; + UA_StatusCode innerStatusCode; + struct UA_DiagnosticInfo *innerDiagnosticInfo; + } UA_DiagnosticInfo; + +.. _generic-types: + +Generic Type Handling +--------------------- + +All information about a (builtin/structured) data type is stored in a +``UA_DataType``. The array ``UA_TYPES`` contains the description of all +standard-defined types. This type description is used for the following +generic operations that work on all types: + +- ``void T_init(T *ptr)``: Initialize the data type. This is synonymous with + zeroing out the memory, i.e. ``memset(ptr, 0, sizeof(T))``. +- ``T* T_new()``: Allocate and return the memory for the data type. The + value is already initialized. +- ``UA_StatusCode T_copy(const T *src, T *dst)``: Copy the content of the + data type. Returns ``UA_STATUSCODE_GOOD`` or + ``UA_STATUSCODE_BADOUTOFMEMORY``. +- ``void T_clear(T *ptr)``: Delete the dynamically allocated content + of the data type and perform a ``T_init`` to reset the type. +- ``void T_delete(T *ptr)``: Delete the content of the data type and the + memory for the data type itself. +- ``void T_equal(T *p1, T *p2)``: Compare whether ``p1`` and ``p2`` have + identical content. You can use ``UA_order`` if an absolute ordering + is required. + +Specializations, such as ``UA_Int32_new()`` are derived from the generic +type operations as static inline functions. + +.. code-block:: c + + + typedef struct { + #ifdef UA_ENABLE_TYPEDESCRIPTION + const char *memberName; /* Human-readable member name */ + #endif + const UA_DataType *memberType;/* The member data type description */ + UA_Byte padding : 6; /* How much padding is there before this + member element? For arrays this is the + padding before the size_t length member. + (No padding between size_t and the + following ptr.) For unions, the padding + includes the size of the switchfield (the + offset from the start of the union + type). */ + UA_Byte isArray : 1; /* The member is an array */ + UA_Byte isOptional : 1; /* The member is an optional field */ + } UA_DataTypeMember; + + /* The DataType "kind" is an internal type classification. It is used to + * dispatch handling to the correct routines. */ + #define UA_DATATYPEKINDS 31 + typedef enum { + UA_DATATYPEKIND_BOOLEAN = 0, + UA_DATATYPEKIND_SBYTE = 1, + UA_DATATYPEKIND_BYTE = 2, + UA_DATATYPEKIND_INT16 = 3, + UA_DATATYPEKIND_UINT16 = 4, + UA_DATATYPEKIND_INT32 = 5, + UA_DATATYPEKIND_UINT32 = 6, + UA_DATATYPEKIND_INT64 = 7, + UA_DATATYPEKIND_UINT64 = 8, + UA_DATATYPEKIND_FLOAT = 9, + UA_DATATYPEKIND_DOUBLE = 10, + UA_DATATYPEKIND_STRING = 11, + UA_DATATYPEKIND_DATETIME = 12, + UA_DATATYPEKIND_GUID = 13, + UA_DATATYPEKIND_BYTESTRING = 14, + UA_DATATYPEKIND_XMLELEMENT = 15, + UA_DATATYPEKIND_NODEID = 16, + UA_DATATYPEKIND_EXPANDEDNODEID = 17, + UA_DATATYPEKIND_STATUSCODE = 18, + UA_DATATYPEKIND_QUALIFIEDNAME = 19, + UA_DATATYPEKIND_LOCALIZEDTEXT = 20, + UA_DATATYPEKIND_EXTENSIONOBJECT = 21, + UA_DATATYPEKIND_DATAVALUE = 22, + UA_DATATYPEKIND_VARIANT = 23, + UA_DATATYPEKIND_DIAGNOSTICINFO = 24, + UA_DATATYPEKIND_DECIMAL = 25, + UA_DATATYPEKIND_ENUM = 26, + UA_DATATYPEKIND_STRUCTURE = 27, + UA_DATATYPEKIND_OPTSTRUCT = 28, /* struct with optional fields */ + UA_DATATYPEKIND_UNION = 29, + UA_DATATYPEKIND_BITFIELDCLUSTER = 30 /* bitfields + padding */ + } UA_DataTypeKind; + + struct UA_DataType { + #ifdef UA_ENABLE_TYPEDESCRIPTION + const char *typeName; + #endif + UA_NodeId typeId; /* The nodeid of the type */ + UA_NodeId binaryEncodingId; /* NodeId of datatype when encoded as binary */ + //UA_NodeId xmlEncodingId; /* NodeId of datatype when encoded as XML */ + UA_UInt32 memSize : 16; /* Size of the struct in memory */ + UA_UInt32 typeKind : 6; /* Dispatch index for the handling routines */ + UA_UInt32 pointerFree : 1; /* The type (and its members) contains no + * pointers that need to be freed */ + UA_UInt32 overlayable : 1; /* The type has the identical memory layout + * in memory and on the binary stream. */ + UA_UInt32 membersSize : 8; /* How many members does the type have? */ + UA_DataTypeMember *members; + }; + + /* Datatype arrays with custom type definitions can be added in a linked list to + * the client or server configuration. */ + typedef struct UA_DataTypeArray { + const struct UA_DataTypeArray *next; + const size_t typesSize; + const UA_DataType *types; + UA_Boolean cleanup; /* Free the array structure and its content + when the client or server configuration + containing it is cleaned up */ + } UA_DataTypeArray; + + /* Returns the offset and type of a structure member. The return value is false + * if the member was not found. + * + * If the member is an array, the offset points to the (size_t) length field. + * (The array pointer comes after the length field without any padding.) */ + #ifdef UA_ENABLE_TYPEDESCRIPTION + UA_Boolean + UA_DataType_getStructMember(const UA_DataType *type, + const char *memberName, + size_t *outOffset, + const UA_DataType **outMemberType, + UA_Boolean *outIsArray); + #endif + + /* Test if the data type is a numeric builtin data type (via the typeKind field + * of UA_DataType). This includes integers and floating point numbers. Not + * included are Boolean, DateTime, StatusCode and Enums. */ + UA_Boolean + UA_DataType_isNumeric(const UA_DataType *type); + +Builtin data types can be accessed as UA_TYPES[UA_TYPES_XXX], where XXX is +the name of the data type. If only the NodeId of a type is known, use the +following method to retrieve the data type description. + +.. code-block:: c + + + /* Returns the data type description for the type's identifier or NULL if no + * matching data type was found. */ + const UA_DataType * + UA_findDataType(const UA_NodeId *typeId); + + /* + * Add custom data types to the search scope of UA_findDataType. */ + + const UA_DataType * + UA_findDataTypeWithCustom(const UA_NodeId *typeId, + const UA_DataTypeArray *customTypes); + +The following functions are used for generic handling of data types. + +.. code-block:: c + + + /* Allocates and initializes a variable of type dataType + * + * @param type The datatype description + * @return Returns the memory location of the variable or NULL if no + * memory could be allocated */ + void * UA_new(const UA_DataType *type); + + /* Initializes a variable to default values + * + * @param p The memory location of the variable + * @param type The datatype description */ + UA_INLINABLE(void + UA_init(void *p, const UA_DataType *type), { + memset(p, 0, type->memSize); + }) + + /* Copies the content of two variables. If copying fails (e.g. because no memory + * was available for an array), then dst is emptied and initialized to prevent + * memory leaks. + * + * @param src The memory location of the source variable + * @param dst The memory location of the destination variable + * @param type The datatype description + * @return Indicates whether the operation succeeded or returns an error code */ + UA_StatusCode + UA_copy(const void *src, void *dst, const UA_DataType *type); + + /* Deletes the dynamically allocated content of a variable (e.g. resets all + * arrays to undefined arrays). Afterwards, the variable can be safely deleted + * without causing memory leaks. But the variable is not initialized and may + * contain old data that is not memory-relevant. + * + * @param p The memory location of the variable + * @param type The datatype description of the variable */ + void UA_clear(void *p, const UA_DataType *type); + + #define UA_deleteMembers(p, type) UA_clear(p, type) + + /* Frees a variable and all of its content. + * + * @param p The memory location of the variable + * @param type The datatype description of the variable */ + void UA_delete(void *p, const UA_DataType *type); + + /* Pretty-print the value from the datatype. The output is pretty-printed JSON5. + * Note that this format is non-standard and should not be sent over the + * network. It can however be read by our own JSON decoding. + * + * @param p The memory location of the variable + * @param type The datatype description of the variable + * @param output A string that is used for the pretty-printed output. If the + * memory for string is already allocated, we try to use the existing + * string (the length is adjusted). If the string is empty, memory + * is allocated for it. + * @return Indicates whether the operation succeeded */ + #ifdef UA_ENABLE_JSON_ENCODING + UA_StatusCode + UA_print(const void *p, const UA_DataType *type, UA_String *output); + #endif + + /* Compare two values and return their order. + * + * For numerical types (including StatusCodes and Enums), their natural order is + * used. NaN is the "smallest" value for floating point values. Different bit + * representations of NaN are considered identical. + * + * All other types have *some* absolute ordering so that a < b, b < c -> a < c. + * + * The ordering of arrays (also strings) is in "shortlex": A shorter array is + * always smaller than a longer array. Otherwise the first different element + * defines the order. + * + * When members of different types are permitted (in Variants and + * ExtensionObjects), the memory address in the "UA_DataType*" pointer + * determines which variable is smaller. + * + * @param p1 The memory location of the first value + * @param p2 The memory location of the first value + * @param type The datatype description of both values */ + UA_Order + UA_order(const void *p1, const void *p2, const UA_DataType *type); + + /* Compare if two values have identical content. */ + UA_INLINABLE(UA_Boolean + UA_equal(const void *p1, const void *p2, const UA_DataType *type), { + return (UA_order(p1, p2, type) == UA_ORDER_EQ); + }) + +Binary Encoding/Decoding +------------------------ + +Encoding and decoding routines for the binary format. For the binary decoding +additional data types can be forwarded. + +.. code-block:: c + + + /* Returns the number of bytes the value p takes in binary encoding. Returns + * zero if an error occurs. */ + size_t + UA_calcSizeBinary(const void *p, const UA_DataType *type); + + /* Encodes a data-structure in the binary format. If outBuf has a length of + * zero, a buffer of the required size is allocated. Otherwise, encoding into + * the existing outBuf is attempted (and may fail if the buffer is too + * small). */ + UA_StatusCode + UA_encodeBinary(const void *p, const UA_DataType *type, + UA_ByteString *outBuf); + + /* The structure with the decoding options may be extended in the future. + * Zero-out the entire structure initially to ensure code-compatibility when + * more fields are added in a later release. */ + typedef struct { + const UA_DataTypeArray *customTypes; /* Begin of a linked list with custom + * datatype definitions */ + } UA_DecodeBinaryOptions; + + /* Decodes a data structure from the input buffer in the binary format. It is + * assumed that `p` points to valid memory (not necessarily zeroed out). The + * options can be NULL and will be disregarded in that case. */ + UA_StatusCode + UA_decodeBinary(const UA_ByteString *inBuf, + void *p, const UA_DataType *type, + const UA_DecodeBinaryOptions *options); + +JSON En/Decoding +---------------- + +The JSON decoding can parse the official encoding from the OPC UA +specification. It further allows the following extensions: + +- The strict JSON format is relaxed to also allow the JSON5 extensions + (https://json5.org/). This allows for more human-readable encoding and adds + convenience features such as trailing commas in arrays and comments within + JSON documents. +- Int64/UInt64 don't necessarily have to be wrapped into a string. +- If `UA_ENABLE_PARSING` is set, NodeIds and ExpandedNodeIds can be given in + the string encoding (e.g. "ns=1;i=42", see `UA_NodeId_parse`). The standard + encoding is to express NodeIds as JSON objects. + +These extensions are not intended to be used for the OPC UA protocol on the +network. They were rather added to allow more convenient configuration file +formats that also include data in the OPC UA type system. + +.. code-block:: c + + + #ifdef UA_ENABLE_JSON_ENCODING + + typedef struct { + const UA_String *namespaces; + size_t namespacesSize; + const UA_String *serverUris; + size_t serverUrisSize; + UA_Boolean useReversible; + + UA_Boolean prettyPrint; /* Add newlines and spaces for legibility */ + + /* Enabling the following options leads to non-standard compatible JSON5 + * encoding! Use it for pretty-printing, but not for sending messages over + * the network. (Our own decoding can still parse it.) */ + + UA_Boolean unquotedKeys; /* Don't print quotes around object element keys */ + UA_Boolean stringNodeIds; /* String encoding for NodeIds, like "ns=1;i=42" */ + } UA_EncodeJsonOptions; + + /* Returns the number of bytes the value src takes in json encoding. Returns + * zero if an error occurs. */ + size_t + UA_calcSizeJson(const void *src, const UA_DataType *type, + const UA_EncodeJsonOptions *options); + + /* Encodes the scalar value described by type to json encoding. + * + * @param src The value. Must not be NULL. + * @param type The value type. Must not be NULL. + * @param outBuf Pointer to ByteString containing the result if the encoding + * was successful + * @return Returns a statuscode whether encoding succeeded. */ + UA_StatusCode + UA_encodeJson(const void *src, const UA_DataType *type, UA_ByteString *outBuf, + const UA_EncodeJsonOptions *options); + + /* The structure with the decoding options may be extended in the future. + * Zero-out the entire structure initially to ensure code-compatibility when + * more fields are added in a later release. */ + typedef struct { + const UA_String *namespaces; + size_t namespacesSize; + const UA_String *serverUris; + size_t serverUrisSize; + const UA_DataTypeArray *customTypes; /* Begin of a linked list with custom + * datatype definitions */ + } UA_DecodeJsonOptions; + + /* Decodes a scalar value described by type from json encoding. + * + * @param src The buffer with the json encoded value. Must not be NULL. + * @param dst The target value. Must not be NULL. The target is assumed to have + * size type->memSize. The value is reset to zero before decoding. If + * decoding fails, members are deleted and the value is reset (zeroed) + * again. + * @param type The value type. Must not be NULL. + * @param options The options struct for decoding, currently unused + * @return Returns a statuscode whether decoding succeeded. */ + UA_StatusCode + UA_decodeJson(const UA_ByteString *src, void *dst, const UA_DataType *type, + const UA_DecodeJsonOptions *options); + + #endif /* UA_ENABLE_JSON_ENCODING */ + +XML En/Decoding +---------------- + +The XML decoding can parse the official encoding from the OPC UA +specification. + +These extensions are not intended to be used for the OPC UA protocol on the +network. They were rather added to allow more convenient configuration file +formats that also include data in the OPC UA type system. + +.. code-block:: c + + + #ifdef UA_ENABLE_XML_ENCODING + + typedef struct { + UA_Boolean prettyPrint; /* Add newlines and spaces for legibility */ + } UA_EncodeXmlOptions; + + /* Returns the number of bytes the value src takes in xml encoding. Returns + * zero if an error occurs. */ + size_t + UA_calcSizeXml(const void *src, const UA_DataType *type, + const UA_EncodeXmlOptions *options); + + /* Encodes the scalar value described by type to xml encoding. + * + * @param src The value. Must not be NULL. + * @param type The value type. Must not be NULL. + * @param outBuf Pointer to ByteString containing the result if the encoding + * was successful + * @return Returns a statuscode whether encoding succeeded. */ + UA_StatusCode + UA_encodeXml(const void *src, const UA_DataType *type, UA_ByteString *outBuf, + const UA_EncodeXmlOptions *options); + + /* The structure with the decoding options may be extended in the future. + * Zero-out the entire structure initially to ensure code-compatibility when + * more fields are added in a later release. */ + typedef struct { + const UA_DataTypeArray *customTypes; /* Begin of a linked list with custom + * datatype definitions */ + } UA_DecodeXmlOptions; + + /* Decodes a scalar value described by type from xml encoding. + * + * @param src The buffer with the xml encoded value. Must not be NULL. + * @param dst The target value. Must not be NULL. The target is assumed to have + * size type->memSize. The value is reset to zero before decoding. If + * decoding fails, members are deleted and the value is reset (zeroed) + * again. + * @param type The value type. Must not be NULL. + * @param options The options struct for decoding, currently unused + * @return Returns a statuscode whether decoding succeeded. */ + UA_StatusCode + UA_decodeXml(const UA_ByteString *src, void *dst, const UA_DataType *type, + const UA_DecodeXmlOptions *options); + + #endif /* UA_ENABLE_XML_ENCODING */ + +.. _array-handling: + +Array handling +-------------- +In OPC UA, arrays can have a length of zero or more with the usual meaning. +In addition, arrays can be undefined. Then, they don't even have a length. In +the binary encoding, this is indicated by an array of length -1. + +In open62541 however, we use ``size_t`` for array lengths. An undefined array +has length 0 and the data pointer is ``NULL``. An array of length 0 also has +length 0 but a data pointer ``UA_EMPTY_ARRAY_SENTINEL``. + +.. code-block:: c + + + /* Allocates and initializes an array of variables of a specific type + * + * @param size The requested array length + * @param type The datatype description + * @return Returns the memory location of the variable or NULL if no memory + * could be allocated */ + void * + UA_Array_new(size_t size, const UA_DataType *type); + + /* Allocates and copies an array + * + * @param src The memory location of the source array + * @param size The size of the array + * @param dst The location of the pointer to the new array + * @param type The datatype of the array members + * @return Returns UA_STATUSCODE_GOOD or UA_STATUSCODE_BADOUTOFMEMORY */ + UA_StatusCode + UA_Array_copy(const void *src, size_t size, void **dst, + const UA_DataType *type); + + /* Resizes (and reallocates) an array. The last entries are initialized to zero + * if the array length is increased. If the array length is decreased, the last + * entries are removed if the size is decreased. + * + * @param p Double pointer to the array memory. Can be overwritten by the result + * of a realloc. + * @param size The current size of the array. Overwritten in case of success. + * @param newSize The new size of the array + * @param type The datatype of the array members + * @return Returns UA_STATUSCODE_GOOD or UA_STATUSCODE_BADOUTOFMEMORY. The + * original array is left untouched in the failure case. */ + UA_StatusCode + UA_Array_resize(void **p, size_t *size, size_t newSize, + const UA_DataType *type); + + /* Append the given element at the end of the array. The content is moved + * (shallow copy) and the original memory is _init'ed if appending is + * successful. + * + * @param p Double pointer to the array memory. Can be overwritten by the result + * of a realloc. + * @param size The current size of the array. Overwritten in case of success. + * @param newElem The element to be appended. The memory is reset upon success. + * @param type The datatype of the array members + * @return Returns UA_STATUSCODE_GOOD or UA_STATUSCODE_BADOUTOFMEMORY. The + * original array is left untouched in the failure case. */ + UA_StatusCode + UA_Array_append(void **p, size_t *size, void *newElem, + const UA_DataType *type); + + /* Append a copy of the given element at the end of the array. + * + * @param p Double pointer to the array memory. Can be overwritten by the result + * of a realloc. + * @param size The current size of the array. Overwritten in case of success. + * @param newElem The element to be appended. + * @param type The datatype of the array members + * @return Returns UA_STATUSCODE_GOOD or UA_STATUSCODE_BADOUTOFMEMORY. The + * original array is left untouched in the failure case. */ + + UA_StatusCode + UA_Array_appendCopy(void **p, size_t *size, const void *newElem, + const UA_DataType *type); + + /* Deletes an array. + * + * @param p The memory location of the array + * @param size The size of the array + * @param type The datatype of the array members */ + void + UA_Array_delete(void *p, size_t size, const UA_DataType *type); + +.. _generated-types: + +Generated Data Type Definitions +------------------------------- + +The following standard-defined datatypes are auto-generated from XML files +that are part of the OPC UA standard. All datatypes are built up from the 25 +builtin-in datatypes from the :ref:`types` section. + +.. include:: types_generated.rst + +.. code-block:: c + + + /* stop-doc-generation */ diff --git a/static/doc/v1.4.0/_static/types_generated.rst b/static/doc/v1.4.0/_static/types_generated.rst new file mode 100644 index 0000000000..481b438eba --- /dev/null +++ b/static/doc/v1.4.0/_static/types_generated.rst @@ -0,0 +1,2596 @@ +NamingRuleType +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_NAMINGRULETYPE_MANDATORY = 1, + UA_NAMINGRULETYPE_OPTIONAL = 2, + UA_NAMINGRULETYPE_CONSTRAINT = 3 + } UA_NamingRuleType; + +KeyValuePair +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_QualifiedName key; + UA_Variant value; + } UA_KeyValuePair; + +NodeClass +^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_NODECLASS_UNSPECIFIED = 0, + UA_NODECLASS_OBJECT = 1, + UA_NODECLASS_VARIABLE = 2, + UA_NODECLASS_METHOD = 4, + UA_NODECLASS_OBJECTTYPE = 8, + UA_NODECLASS_VARIABLETYPE = 16, + UA_NODECLASS_REFERENCETYPE = 32, + UA_NODECLASS_DATATYPE = 64, + UA_NODECLASS_VIEW = 128 + } UA_NodeClass; + +StructureType +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_STRUCTURETYPE_STRUCTURE = 0, + UA_STRUCTURETYPE_STRUCTUREWITHOPTIONALFIELDS = 1, + UA_STRUCTURETYPE_UNION = 2, + UA_STRUCTURETYPE_STRUCTUREWITHSUBTYPEDVALUES = 3, + UA_STRUCTURETYPE_UNIONWITHSUBTYPEDVALUES = 4 + } UA_StructureType; + +StructureField +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String name; + UA_LocalizedText description; + UA_NodeId dataType; + UA_Int32 valueRank; + size_t arrayDimensionsSize; + UA_UInt32 *arrayDimensions; + UA_UInt32 maxStringLength; + UA_Boolean isOptional; + } UA_StructureField; + +StructureDefinition +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId defaultEncodingId; + UA_NodeId baseDataType; + UA_StructureType structureType; + size_t fieldsSize; + UA_StructureField *fields; + } UA_StructureDefinition; + +Argument +^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String name; + UA_NodeId dataType; + UA_Int32 valueRank; + size_t arrayDimensionsSize; + UA_UInt32 *arrayDimensions; + UA_LocalizedText description; + } UA_Argument; + +EnumValueType +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Int64 value; + UA_LocalizedText displayName; + UA_LocalizedText description; + } UA_EnumValueType; + +EnumField +^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Int64 value; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_String name; + } UA_EnumField; + +Duration +^^^^^^^^ + +.. code-block:: c + + typedef UA_Double UA_Duration; + +UtcTime +^^^^^^^ + +.. code-block:: c + + typedef UA_DateTime UA_UtcTime; + +LocaleId +^^^^^^^^ + +.. code-block:: c + + typedef UA_String UA_LocaleId; + +TimeZoneDataType +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Int16 offset; + UA_Boolean daylightSavingInOffset; + } UA_TimeZoneDataType; + +ApplicationType +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_APPLICATIONTYPE_SERVER = 0, + UA_APPLICATIONTYPE_CLIENT = 1, + UA_APPLICATIONTYPE_CLIENTANDSERVER = 2, + UA_APPLICATIONTYPE_DISCOVERYSERVER = 3 + } UA_ApplicationType; + +ApplicationDescription +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String applicationUri; + UA_String productUri; + UA_LocalizedText applicationName; + UA_ApplicationType applicationType; + UA_String gatewayServerUri; + UA_String discoveryProfileUri; + size_t discoveryUrlsSize; + UA_String *discoveryUrls; + } UA_ApplicationDescription; + +RequestHeader +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId authenticationToken; + UA_DateTime timestamp; + UA_UInt32 requestHandle; + UA_UInt32 returnDiagnostics; + UA_String auditEntryId; + UA_UInt32 timeoutHint; + UA_ExtensionObject additionalHeader; + } UA_RequestHeader; + +ResponseHeader +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_DateTime timestamp; + UA_UInt32 requestHandle; + UA_StatusCode serviceResult; + UA_DiagnosticInfo serviceDiagnostics; + size_t stringTableSize; + UA_String *stringTable; + UA_ExtensionObject additionalHeader; + } UA_ResponseHeader; + +ServiceFault +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + } UA_ServiceFault; + +FindServersRequest +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_String endpointUrl; + size_t localeIdsSize; + UA_String *localeIds; + size_t serverUrisSize; + UA_String *serverUris; + } UA_FindServersRequest; + +FindServersResponse +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t serversSize; + UA_ApplicationDescription *servers; + } UA_FindServersResponse; + +ServerOnNetwork +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 recordId; + UA_String serverName; + UA_String discoveryUrl; + size_t serverCapabilitiesSize; + UA_String *serverCapabilities; + } UA_ServerOnNetwork; + +FindServersOnNetworkRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 startingRecordId; + UA_UInt32 maxRecordsToReturn; + size_t serverCapabilityFilterSize; + UA_String *serverCapabilityFilter; + } UA_FindServersOnNetworkRequest; + +FindServersOnNetworkResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_DateTime lastCounterResetTime; + size_t serversSize; + UA_ServerOnNetwork *servers; + } UA_FindServersOnNetworkResponse; + +MessageSecurityMode +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_MESSAGESECURITYMODE_INVALID = 0, + UA_MESSAGESECURITYMODE_NONE = 1, + UA_MESSAGESECURITYMODE_SIGN = 2, + UA_MESSAGESECURITYMODE_SIGNANDENCRYPT = 3 + } UA_MessageSecurityMode; + +UserTokenType +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_USERTOKENTYPE_ANONYMOUS = 0, + UA_USERTOKENTYPE_USERNAME = 1, + UA_USERTOKENTYPE_CERTIFICATE = 2, + UA_USERTOKENTYPE_ISSUEDTOKEN = 3 + } UA_UserTokenType; + +UserTokenPolicy +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String policyId; + UA_UserTokenType tokenType; + UA_String issuedTokenType; + UA_String issuerEndpointUrl; + UA_String securityPolicyUri; + } UA_UserTokenPolicy; + +EndpointDescription +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String endpointUrl; + UA_ApplicationDescription server; + UA_ByteString serverCertificate; + UA_MessageSecurityMode securityMode; + UA_String securityPolicyUri; + size_t userIdentityTokensSize; + UA_UserTokenPolicy *userIdentityTokens; + UA_String transportProfileUri; + UA_Byte securityLevel; + } UA_EndpointDescription; + +GetEndpointsRequest +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_String endpointUrl; + size_t localeIdsSize; + UA_String *localeIds; + size_t profileUrisSize; + UA_String *profileUris; + } UA_GetEndpointsRequest; + +GetEndpointsResponse +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t endpointsSize; + UA_EndpointDescription *endpoints; + } UA_GetEndpointsResponse; + +RegisteredServer +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String serverUri; + UA_String productUri; + size_t serverNamesSize; + UA_LocalizedText *serverNames; + UA_ApplicationType serverType; + UA_String gatewayServerUri; + size_t discoveryUrlsSize; + UA_String *discoveryUrls; + UA_String semaphoreFilePath; + UA_Boolean isOnline; + } UA_RegisteredServer; + +RegisterServerRequest +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_RegisteredServer server; + } UA_RegisterServerRequest; + +RegisterServerResponse +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + } UA_RegisterServerResponse; + +MdnsDiscoveryConfiguration +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String mdnsServerName; + size_t serverCapabilitiesSize; + UA_String *serverCapabilities; + } UA_MdnsDiscoveryConfiguration; + +RegisterServer2Request +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_RegisteredServer server; + size_t discoveryConfigurationSize; + UA_ExtensionObject *discoveryConfiguration; + } UA_RegisterServer2Request; + +RegisterServer2Response +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t configurationResultsSize; + UA_StatusCode *configurationResults; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_RegisterServer2Response; + +SecurityTokenRequestType +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_SECURITYTOKENREQUESTTYPE_ISSUE = 0, + UA_SECURITYTOKENREQUESTTYPE_RENEW = 1 + } UA_SecurityTokenRequestType; + +ChannelSecurityToken +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 channelId; + UA_UInt32 tokenId; + UA_DateTime createdAt; + UA_UInt32 revisedLifetime; + } UA_ChannelSecurityToken; + +OpenSecureChannelRequest +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 clientProtocolVersion; + UA_SecurityTokenRequestType requestType; + UA_MessageSecurityMode securityMode; + UA_ByteString clientNonce; + UA_UInt32 requestedLifetime; + } UA_OpenSecureChannelRequest; + +OpenSecureChannelResponse +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_UInt32 serverProtocolVersion; + UA_ChannelSecurityToken securityToken; + UA_ByteString serverNonce; + } UA_OpenSecureChannelResponse; + +CloseSecureChannelRequest +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + } UA_CloseSecureChannelRequest; + +CloseSecureChannelResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + } UA_CloseSecureChannelResponse; + +SignedSoftwareCertificate +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ByteString certificateData; + UA_ByteString signature; + } UA_SignedSoftwareCertificate; + +SignatureData +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String algorithm; + UA_ByteString signature; + } UA_SignatureData; + +CreateSessionRequest +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_ApplicationDescription clientDescription; + UA_String serverUri; + UA_String endpointUrl; + UA_String sessionName; + UA_ByteString clientNonce; + UA_ByteString clientCertificate; + UA_Double requestedSessionTimeout; + UA_UInt32 maxResponseMessageSize; + } UA_CreateSessionRequest; + +CreateSessionResponse +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_NodeId sessionId; + UA_NodeId authenticationToken; + UA_Double revisedSessionTimeout; + UA_ByteString serverNonce; + UA_ByteString serverCertificate; + size_t serverEndpointsSize; + UA_EndpointDescription *serverEndpoints; + size_t serverSoftwareCertificatesSize; + UA_SignedSoftwareCertificate *serverSoftwareCertificates; + UA_SignatureData serverSignature; + UA_UInt32 maxRequestMessageSize; + } UA_CreateSessionResponse; + +UserIdentityToken +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String policyId; + } UA_UserIdentityToken; + +AnonymousIdentityToken +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String policyId; + } UA_AnonymousIdentityToken; + +UserNameIdentityToken +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String policyId; + UA_String userName; + UA_ByteString password; + UA_String encryptionAlgorithm; + } UA_UserNameIdentityToken; + +X509IdentityToken +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String policyId; + UA_ByteString certificateData; + } UA_X509IdentityToken; + +IssuedIdentityToken +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String policyId; + UA_ByteString tokenData; + UA_String encryptionAlgorithm; + } UA_IssuedIdentityToken; + +ActivateSessionRequest +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_SignatureData clientSignature; + size_t clientSoftwareCertificatesSize; + UA_SignedSoftwareCertificate *clientSoftwareCertificates; + size_t localeIdsSize; + UA_String *localeIds; + UA_ExtensionObject userIdentityToken; + UA_SignatureData userTokenSignature; + } UA_ActivateSessionRequest; + +ActivateSessionResponse +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_ByteString serverNonce; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_ActivateSessionResponse; + +CloseSessionRequest +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_Boolean deleteSubscriptions; + } UA_CloseSessionRequest; + +CloseSessionResponse +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + } UA_CloseSessionResponse; + +CancelRequest +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 requestHandle; + } UA_CancelRequest; + +CancelResponse +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_UInt32 cancelCount; + } UA_CancelResponse; + +NodeAttributesMask +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_NODEATTRIBUTESMASK_NONE = 0, + UA_NODEATTRIBUTESMASK_ACCESSLEVEL = 1, + UA_NODEATTRIBUTESMASK_ARRAYDIMENSIONS = 2, + UA_NODEATTRIBUTESMASK_BROWSENAME = 4, + UA_NODEATTRIBUTESMASK_CONTAINSNOLOOPS = 8, + UA_NODEATTRIBUTESMASK_DATATYPE = 16, + UA_NODEATTRIBUTESMASK_DESCRIPTION = 32, + UA_NODEATTRIBUTESMASK_DISPLAYNAME = 64, + UA_NODEATTRIBUTESMASK_EVENTNOTIFIER = 128, + UA_NODEATTRIBUTESMASK_EXECUTABLE = 256, + UA_NODEATTRIBUTESMASK_HISTORIZING = 512, + UA_NODEATTRIBUTESMASK_INVERSENAME = 1024, + UA_NODEATTRIBUTESMASK_ISABSTRACT = 2048, + UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL = 4096, + UA_NODEATTRIBUTESMASK_NODECLASS = 8192, + UA_NODEATTRIBUTESMASK_NODEID = 16384, + UA_NODEATTRIBUTESMASK_SYMMETRIC = 32768, + UA_NODEATTRIBUTESMASK_USERACCESSLEVEL = 65536, + UA_NODEATTRIBUTESMASK_USEREXECUTABLE = 131072, + UA_NODEATTRIBUTESMASK_USERWRITEMASK = 262144, + UA_NODEATTRIBUTESMASK_VALUERANK = 524288, + UA_NODEATTRIBUTESMASK_WRITEMASK = 1048576, + UA_NODEATTRIBUTESMASK_VALUE = 2097152, + UA_NODEATTRIBUTESMASK_DATATYPEDEFINITION = 4194304, + UA_NODEATTRIBUTESMASK_ROLEPERMISSIONS = 8388608, + UA_NODEATTRIBUTESMASK_ACCESSRESTRICTIONS = 16777216, + UA_NODEATTRIBUTESMASK_ALL = 33554431, + UA_NODEATTRIBUTESMASK_BASENODE = 26501220, + UA_NODEATTRIBUTESMASK_OBJECT = 26501348, + UA_NODEATTRIBUTESMASK_OBJECTTYPE = 26503268, + UA_NODEATTRIBUTESMASK_VARIABLE = 26571383, + UA_NODEATTRIBUTESMASK_VARIABLETYPE = 28600438, + UA_NODEATTRIBUTESMASK_METHOD = 26632548, + UA_NODEATTRIBUTESMASK_REFERENCETYPE = 26537060, + UA_NODEATTRIBUTESMASK_VIEW = 26501356 + } UA_NodeAttributesMask; + +NodeAttributes +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + } UA_NodeAttributes; + +ObjectAttributes +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Byte eventNotifier; + } UA_ObjectAttributes; + +VariableAttributes +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Variant value; + UA_NodeId dataType; + UA_Int32 valueRank; + size_t arrayDimensionsSize; + UA_UInt32 *arrayDimensions; + UA_Byte accessLevel; + UA_Byte userAccessLevel; + UA_Double minimumSamplingInterval; + UA_Boolean historizing; + } UA_VariableAttributes; + +MethodAttributes +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Boolean executable; + UA_Boolean userExecutable; + } UA_MethodAttributes; + +ObjectTypeAttributes +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Boolean isAbstract; + } UA_ObjectTypeAttributes; + +VariableTypeAttributes +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Variant value; + UA_NodeId dataType; + UA_Int32 valueRank; + size_t arrayDimensionsSize; + UA_UInt32 *arrayDimensions; + UA_Boolean isAbstract; + } UA_VariableTypeAttributes; + +ReferenceTypeAttributes +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Boolean isAbstract; + UA_Boolean symmetric; + UA_LocalizedText inverseName; + } UA_ReferenceTypeAttributes; + +DataTypeAttributes +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Boolean isAbstract; + } UA_DataTypeAttributes; + +ViewAttributes +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 specifiedAttributes; + UA_LocalizedText displayName; + UA_LocalizedText description; + UA_UInt32 writeMask; + UA_UInt32 userWriteMask; + UA_Boolean containsNoLoops; + UA_Byte eventNotifier; + } UA_ViewAttributes; + +AddNodesItem +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ExpandedNodeId parentNodeId; + UA_NodeId referenceTypeId; + UA_ExpandedNodeId requestedNewNodeId; + UA_QualifiedName browseName; + UA_NodeClass nodeClass; + UA_ExtensionObject nodeAttributes; + UA_ExpandedNodeId typeDefinition; + } UA_AddNodesItem; + +AddNodesResult +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + UA_NodeId addedNodeId; + } UA_AddNodesResult; + +AddNodesRequest +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t nodesToAddSize; + UA_AddNodesItem *nodesToAdd; + } UA_AddNodesRequest; + +AddNodesResponse +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_AddNodesResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_AddNodesResponse; + +AddReferencesItem +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId sourceNodeId; + UA_NodeId referenceTypeId; + UA_Boolean isForward; + UA_String targetServerUri; + UA_ExpandedNodeId targetNodeId; + UA_NodeClass targetNodeClass; + } UA_AddReferencesItem; + +AddReferencesRequest +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t referencesToAddSize; + UA_AddReferencesItem *referencesToAdd; + } UA_AddReferencesRequest; + +AddReferencesResponse +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_AddReferencesResponse; + +DeleteNodesItem +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_Boolean deleteTargetReferences; + } UA_DeleteNodesItem; + +DeleteNodesRequest +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t nodesToDeleteSize; + UA_DeleteNodesItem *nodesToDelete; + } UA_DeleteNodesRequest; + +DeleteNodesResponse +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_DeleteNodesResponse; + +DeleteReferencesItem +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId sourceNodeId; + UA_NodeId referenceTypeId; + UA_Boolean isForward; + UA_ExpandedNodeId targetNodeId; + UA_Boolean deleteBidirectional; + } UA_DeleteReferencesItem; + +DeleteReferencesRequest +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t referencesToDeleteSize; + UA_DeleteReferencesItem *referencesToDelete; + } UA_DeleteReferencesRequest; + +DeleteReferencesResponse +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_DeleteReferencesResponse; + +BrowseDirection +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_BROWSEDIRECTION_FORWARD = 0, + UA_BROWSEDIRECTION_INVERSE = 1, + UA_BROWSEDIRECTION_BOTH = 2, + UA_BROWSEDIRECTION_INVALID = 3 + } UA_BrowseDirection; + +ViewDescription +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId viewId; + UA_DateTime timestamp; + UA_UInt32 viewVersion; + } UA_ViewDescription; + +BrowseDescription +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_BrowseDirection browseDirection; + UA_NodeId referenceTypeId; + UA_Boolean includeSubtypes; + UA_UInt32 nodeClassMask; + UA_UInt32 resultMask; + } UA_BrowseDescription; + +BrowseResultMask +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_BROWSERESULTMASK_NONE = 0, + UA_BROWSERESULTMASK_REFERENCETYPEID = 1, + UA_BROWSERESULTMASK_ISFORWARD = 2, + UA_BROWSERESULTMASK_NODECLASS = 4, + UA_BROWSERESULTMASK_BROWSENAME = 8, + UA_BROWSERESULTMASK_DISPLAYNAME = 16, + UA_BROWSERESULTMASK_TYPEDEFINITION = 32, + UA_BROWSERESULTMASK_ALL = 63, + UA_BROWSERESULTMASK_REFERENCETYPEINFO = 3, + UA_BROWSERESULTMASK_TARGETINFO = 60 + } UA_BrowseResultMask; + +ReferenceDescription +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId referenceTypeId; + UA_Boolean isForward; + UA_ExpandedNodeId nodeId; + UA_QualifiedName browseName; + UA_LocalizedText displayName; + UA_NodeClass nodeClass; + UA_ExpandedNodeId typeDefinition; + } UA_ReferenceDescription; + +BrowseResult +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + UA_ByteString continuationPoint; + size_t referencesSize; + UA_ReferenceDescription *references; + } UA_BrowseResult; + +BrowseRequest +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_ViewDescription view; + UA_UInt32 requestedMaxReferencesPerNode; + size_t nodesToBrowseSize; + UA_BrowseDescription *nodesToBrowse; + } UA_BrowseRequest; + +BrowseResponse +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_BrowseResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_BrowseResponse; + +BrowseNextRequest +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_Boolean releaseContinuationPoints; + size_t continuationPointsSize; + UA_ByteString *continuationPoints; + } UA_BrowseNextRequest; + +BrowseNextResponse +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_BrowseResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_BrowseNextResponse; + +RelativePathElement +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId referenceTypeId; + UA_Boolean isInverse; + UA_Boolean includeSubtypes; + UA_QualifiedName targetName; + } UA_RelativePathElement; + +RelativePath +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t elementsSize; + UA_RelativePathElement *elements; + } UA_RelativePath; + +BrowsePath +^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId startingNode; + UA_RelativePath relativePath; + } UA_BrowsePath; + +BrowsePathTarget +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ExpandedNodeId targetId; + UA_UInt32 remainingPathIndex; + } UA_BrowsePathTarget; + +BrowsePathResult +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + size_t targetsSize; + UA_BrowsePathTarget *targets; + } UA_BrowsePathResult; + +TranslateBrowsePathsToNodeIdsRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t browsePathsSize; + UA_BrowsePath *browsePaths; + } UA_TranslateBrowsePathsToNodeIdsRequest; + +TranslateBrowsePathsToNodeIdsResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_BrowsePathResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_TranslateBrowsePathsToNodeIdsResponse; + +RegisterNodesRequest +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t nodesToRegisterSize; + UA_NodeId *nodesToRegister; + } UA_RegisterNodesRequest; + +RegisterNodesResponse +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t registeredNodeIdsSize; + UA_NodeId *registeredNodeIds; + } UA_RegisterNodesResponse; + +UnregisterNodesRequest +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t nodesToUnregisterSize; + UA_NodeId *nodesToUnregister; + } UA_UnregisterNodesRequest; + +UnregisterNodesResponse +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + } UA_UnregisterNodesResponse; + +FilterOperator +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_FILTEROPERATOR_EQUALS = 0, + UA_FILTEROPERATOR_ISNULL = 1, + UA_FILTEROPERATOR_GREATERTHAN = 2, + UA_FILTEROPERATOR_LESSTHAN = 3, + UA_FILTEROPERATOR_GREATERTHANOREQUAL = 4, + UA_FILTEROPERATOR_LESSTHANOREQUAL = 5, + UA_FILTEROPERATOR_LIKE = 6, + UA_FILTEROPERATOR_NOT = 7, + UA_FILTEROPERATOR_BETWEEN = 8, + UA_FILTEROPERATOR_INLIST = 9, + UA_FILTEROPERATOR_AND = 10, + UA_FILTEROPERATOR_OR = 11, + UA_FILTEROPERATOR_CAST = 12, + UA_FILTEROPERATOR_INVIEW = 13, + UA_FILTEROPERATOR_OFTYPE = 14, + UA_FILTEROPERATOR_RELATEDTO = 15, + UA_FILTEROPERATOR_BITWISEAND = 16, + UA_FILTEROPERATOR_BITWISEOR = 17 + } UA_FilterOperator; + +ContentFilterElement +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_FilterOperator filterOperator; + size_t filterOperandsSize; + UA_ExtensionObject *filterOperands; + } UA_ContentFilterElement; + +ContentFilter +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t elementsSize; + UA_ContentFilterElement *elements; + } UA_ContentFilter; + +ElementOperand +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 index; + } UA_ElementOperand; + +LiteralOperand +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Variant value; + } UA_LiteralOperand; + +AttributeOperand +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_String alias; + UA_RelativePath browsePath; + UA_UInt32 attributeId; + UA_String indexRange; + } UA_AttributeOperand; + +SimpleAttributeOperand +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId typeDefinitionId; + size_t browsePathSize; + UA_QualifiedName *browsePath; + UA_UInt32 attributeId; + UA_String indexRange; + } UA_SimpleAttributeOperand; + +ContentFilterElementResult +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + size_t operandStatusCodesSize; + UA_StatusCode *operandStatusCodes; + size_t operandDiagnosticInfosSize; + UA_DiagnosticInfo *operandDiagnosticInfos; + } UA_ContentFilterElementResult; + +ContentFilterResult +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t elementResultsSize; + UA_ContentFilterElementResult *elementResults; + size_t elementDiagnosticInfosSize; + UA_DiagnosticInfo *elementDiagnosticInfos; + } UA_ContentFilterResult; + +TimestampsToReturn +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_TIMESTAMPSTORETURN_SOURCE = 0, + UA_TIMESTAMPSTORETURN_SERVER = 1, + UA_TIMESTAMPSTORETURN_BOTH = 2, + UA_TIMESTAMPSTORETURN_NEITHER = 3, + UA_TIMESTAMPSTORETURN_INVALID = 4 + } UA_TimestampsToReturn; + +ReadValueId +^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_UInt32 attributeId; + UA_String indexRange; + UA_QualifiedName dataEncoding; + } UA_ReadValueId; + +ReadRequest +^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_Double maxAge; + UA_TimestampsToReturn timestampsToReturn; + size_t nodesToReadSize; + UA_ReadValueId *nodesToRead; + } UA_ReadRequest; + +ReadResponse +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_DataValue *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_ReadResponse; + +HistoryReadValueId +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_String indexRange; + UA_QualifiedName dataEncoding; + UA_ByteString continuationPoint; + } UA_HistoryReadValueId; + +HistoryReadResult +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + UA_ByteString continuationPoint; + UA_ExtensionObject historyData; + } UA_HistoryReadResult; + +ReadRawModifiedDetails +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Boolean isReadModified; + UA_DateTime startTime; + UA_DateTime endTime; + UA_UInt32 numValuesPerNode; + UA_Boolean returnBounds; + } UA_ReadRawModifiedDetails; + +ReadAtTimeDetails +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t reqTimesSize; + UA_DateTime *reqTimes; + UA_Boolean useSimpleBounds; + } UA_ReadAtTimeDetails; + +HistoryData +^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t dataValuesSize; + UA_DataValue *dataValues; + } UA_HistoryData; + +HistoryReadRequest +^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_ExtensionObject historyReadDetails; + UA_TimestampsToReturn timestampsToReturn; + UA_Boolean releaseContinuationPoints; + size_t nodesToReadSize; + UA_HistoryReadValueId *nodesToRead; + } UA_HistoryReadRequest; + +HistoryReadResponse +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_HistoryReadResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_HistoryReadResponse; + +WriteValue +^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_UInt32 attributeId; + UA_String indexRange; + UA_DataValue value; + } UA_WriteValue; + +WriteRequest +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t nodesToWriteSize; + UA_WriteValue *nodesToWrite; + } UA_WriteRequest; + +WriteResponse +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_WriteResponse; + +HistoryUpdateType +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_HISTORYUPDATETYPE_INSERT = 1, + UA_HISTORYUPDATETYPE_REPLACE = 2, + UA_HISTORYUPDATETYPE_UPDATE = 3, + UA_HISTORYUPDATETYPE_DELETE = 4 + } UA_HistoryUpdateType; + +PerformUpdateType +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_PERFORMUPDATETYPE_INSERT = 1, + UA_PERFORMUPDATETYPE_REPLACE = 2, + UA_PERFORMUPDATETYPE_UPDATE = 3, + UA_PERFORMUPDATETYPE_REMOVE = 4 + } UA_PerformUpdateType; + +UpdateDataDetails +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_PerformUpdateType performInsertReplace; + size_t updateValuesSize; + UA_DataValue *updateValues; + } UA_UpdateDataDetails; + +DeleteRawModifiedDetails +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId nodeId; + UA_Boolean isDeleteModified; + UA_DateTime startTime; + UA_DateTime endTime; + } UA_DeleteRawModifiedDetails; + +HistoryUpdateResult +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + size_t operationResultsSize; + UA_StatusCode *operationResults; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_HistoryUpdateResult; + +HistoryUpdateRequest +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t historyUpdateDetailsSize; + UA_ExtensionObject *historyUpdateDetails; + } UA_HistoryUpdateRequest; + +HistoryUpdateResponse +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_HistoryUpdateResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_HistoryUpdateResponse; + +CallMethodRequest +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId objectId; + UA_NodeId methodId; + size_t inputArgumentsSize; + UA_Variant *inputArguments; + } UA_CallMethodRequest; + +CallMethodResult +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + size_t inputArgumentResultsSize; + UA_StatusCode *inputArgumentResults; + size_t inputArgumentDiagnosticInfosSize; + UA_DiagnosticInfo *inputArgumentDiagnosticInfos; + size_t outputArgumentsSize; + UA_Variant *outputArguments; + } UA_CallMethodResult; + +CallRequest +^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t methodsToCallSize; + UA_CallMethodRequest *methodsToCall; + } UA_CallRequest; + +CallResponse +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_CallMethodResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_CallResponse; + +MonitoringMode +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_MONITORINGMODE_DISABLED = 0, + UA_MONITORINGMODE_SAMPLING = 1, + UA_MONITORINGMODE_REPORTING = 2 + } UA_MonitoringMode; + +DataChangeTrigger +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_DATACHANGETRIGGER_STATUS = 0, + UA_DATACHANGETRIGGER_STATUSVALUE = 1, + UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP = 2 + } UA_DataChangeTrigger; + +DeadbandType +^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_DEADBANDTYPE_NONE = 0, + UA_DEADBANDTYPE_ABSOLUTE = 1, + UA_DEADBANDTYPE_PERCENT = 2 + } UA_DeadbandType; + +DataChangeFilter +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_DataChangeTrigger trigger; + UA_UInt32 deadbandType; + UA_Double deadbandValue; + } UA_DataChangeFilter; + +EventFilter +^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t selectClausesSize; + UA_SimpleAttributeOperand *selectClauses; + UA_ContentFilter whereClause; + } UA_EventFilter; + +AggregateConfiguration +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Boolean useServerCapabilitiesDefaults; + UA_Boolean treatUncertainAsBad; + UA_Byte percentDataBad; + UA_Byte percentDataGood; + UA_Boolean useSlopedExtrapolation; + } UA_AggregateConfiguration; + +AggregateFilter +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_DateTime startTime; + UA_NodeId aggregateType; + UA_Double processingInterval; + UA_AggregateConfiguration aggregateConfiguration; + } UA_AggregateFilter; + +EventFilterResult +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t selectClauseResultsSize; + UA_StatusCode *selectClauseResults; + size_t selectClauseDiagnosticInfosSize; + UA_DiagnosticInfo *selectClauseDiagnosticInfos; + UA_ContentFilterResult whereClauseResult; + } UA_EventFilterResult; + +MonitoringParameters +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 clientHandle; + UA_Double samplingInterval; + UA_ExtensionObject filter; + UA_UInt32 queueSize; + UA_Boolean discardOldest; + } UA_MonitoringParameters; + +MonitoredItemCreateRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ReadValueId itemToMonitor; + UA_MonitoringMode monitoringMode; + UA_MonitoringParameters requestedParameters; + } UA_MonitoredItemCreateRequest; + +MonitoredItemCreateResult +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + UA_UInt32 monitoredItemId; + UA_Double revisedSamplingInterval; + UA_UInt32 revisedQueueSize; + UA_ExtensionObject filterResult; + } UA_MonitoredItemCreateResult; + +CreateMonitoredItemsRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 subscriptionId; + UA_TimestampsToReturn timestampsToReturn; + size_t itemsToCreateSize; + UA_MonitoredItemCreateRequest *itemsToCreate; + } UA_CreateMonitoredItemsRequest; + +CreateMonitoredItemsResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_MonitoredItemCreateResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_CreateMonitoredItemsResponse; + +MonitoredItemModifyRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 monitoredItemId; + UA_MonitoringParameters requestedParameters; + } UA_MonitoredItemModifyRequest; + +MonitoredItemModifyResult +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + UA_Double revisedSamplingInterval; + UA_UInt32 revisedQueueSize; + UA_ExtensionObject filterResult; + } UA_MonitoredItemModifyResult; + +ModifyMonitoredItemsRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 subscriptionId; + UA_TimestampsToReturn timestampsToReturn; + size_t itemsToModifySize; + UA_MonitoredItemModifyRequest *itemsToModify; + } UA_ModifyMonitoredItemsRequest; + +ModifyMonitoredItemsResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_MonitoredItemModifyResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_ModifyMonitoredItemsResponse; + +SetMonitoringModeRequest +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 subscriptionId; + UA_MonitoringMode monitoringMode; + size_t monitoredItemIdsSize; + UA_UInt32 *monitoredItemIds; + } UA_SetMonitoringModeRequest; + +SetMonitoringModeResponse +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_SetMonitoringModeResponse; + +SetTriggeringRequest +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 subscriptionId; + UA_UInt32 triggeringItemId; + size_t linksToAddSize; + UA_UInt32 *linksToAdd; + size_t linksToRemoveSize; + UA_UInt32 *linksToRemove; + } UA_SetTriggeringRequest; + +SetTriggeringResponse +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t addResultsSize; + UA_StatusCode *addResults; + size_t addDiagnosticInfosSize; + UA_DiagnosticInfo *addDiagnosticInfos; + size_t removeResultsSize; + UA_StatusCode *removeResults; + size_t removeDiagnosticInfosSize; + UA_DiagnosticInfo *removeDiagnosticInfos; + } UA_SetTriggeringResponse; + +DeleteMonitoredItemsRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 subscriptionId; + size_t monitoredItemIdsSize; + UA_UInt32 *monitoredItemIds; + } UA_DeleteMonitoredItemsRequest; + +DeleteMonitoredItemsResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_DeleteMonitoredItemsResponse; + +CreateSubscriptionRequest +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_Double requestedPublishingInterval; + UA_UInt32 requestedLifetimeCount; + UA_UInt32 requestedMaxKeepAliveCount; + UA_UInt32 maxNotificationsPerPublish; + UA_Boolean publishingEnabled; + UA_Byte priority; + } UA_CreateSubscriptionRequest; + +CreateSubscriptionResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_UInt32 subscriptionId; + UA_Double revisedPublishingInterval; + UA_UInt32 revisedLifetimeCount; + UA_UInt32 revisedMaxKeepAliveCount; + } UA_CreateSubscriptionResponse; + +ModifySubscriptionRequest +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 subscriptionId; + UA_Double requestedPublishingInterval; + UA_UInt32 requestedLifetimeCount; + UA_UInt32 requestedMaxKeepAliveCount; + UA_UInt32 maxNotificationsPerPublish; + UA_Byte priority; + } UA_ModifySubscriptionRequest; + +ModifySubscriptionResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_Double revisedPublishingInterval; + UA_UInt32 revisedLifetimeCount; + UA_UInt32 revisedMaxKeepAliveCount; + } UA_ModifySubscriptionResponse; + +SetPublishingModeRequest +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_Boolean publishingEnabled; + size_t subscriptionIdsSize; + UA_UInt32 *subscriptionIds; + } UA_SetPublishingModeRequest; + +SetPublishingModeResponse +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_SetPublishingModeResponse; + +NotificationMessage +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 sequenceNumber; + UA_DateTime publishTime; + size_t notificationDataSize; + UA_ExtensionObject *notificationData; + } UA_NotificationMessage; + +MonitoredItemNotification +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 clientHandle; + UA_DataValue value; + } UA_MonitoredItemNotification; + +EventFieldList +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 clientHandle; + size_t eventFieldsSize; + UA_Variant *eventFields; + } UA_EventFieldList; + +HistoryEventFieldList +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t eventFieldsSize; + UA_Variant *eventFields; + } UA_HistoryEventFieldList; + +StatusChangeNotification +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode status; + UA_DiagnosticInfo diagnosticInfo; + } UA_StatusChangeNotification; + +SubscriptionAcknowledgement +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 subscriptionId; + UA_UInt32 sequenceNumber; + } UA_SubscriptionAcknowledgement; + +PublishRequest +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t subscriptionAcknowledgementsSize; + UA_SubscriptionAcknowledgement *subscriptionAcknowledgements; + } UA_PublishRequest; + +PublishResponse +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_UInt32 subscriptionId; + size_t availableSequenceNumbersSize; + UA_UInt32 *availableSequenceNumbers; + UA_Boolean moreNotifications; + UA_NotificationMessage notificationMessage; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_PublishResponse; + +RepublishRequest +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + UA_UInt32 subscriptionId; + UA_UInt32 retransmitSequenceNumber; + } UA_RepublishRequest; + +RepublishResponse +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + UA_NotificationMessage notificationMessage; + } UA_RepublishResponse; + +TransferResult +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_StatusCode statusCode; + size_t availableSequenceNumbersSize; + UA_UInt32 *availableSequenceNumbers; + } UA_TransferResult; + +TransferSubscriptionsRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t subscriptionIdsSize; + UA_UInt32 *subscriptionIds; + UA_Boolean sendInitialValues; + } UA_TransferSubscriptionsRequest; + +TransferSubscriptionsResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_TransferResult *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_TransferSubscriptionsResponse; + +DeleteSubscriptionsRequest +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_RequestHeader requestHeader; + size_t subscriptionIdsSize; + UA_UInt32 *subscriptionIds; + } UA_DeleteSubscriptionsRequest; + +DeleteSubscriptionsResponse +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_ResponseHeader responseHeader; + size_t resultsSize; + UA_StatusCode *results; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_DeleteSubscriptionsResponse; + +BuildInfo +^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String productUri; + UA_String manufacturerName; + UA_String productName; + UA_String softwareVersion; + UA_String buildNumber; + UA_DateTime buildDate; + } UA_BuildInfo; + +RedundancySupport +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_REDUNDANCYSUPPORT_NONE = 0, + UA_REDUNDANCYSUPPORT_COLD = 1, + UA_REDUNDANCYSUPPORT_WARM = 2, + UA_REDUNDANCYSUPPORT_HOT = 3, + UA_REDUNDANCYSUPPORT_TRANSPARENT = 4, + UA_REDUNDANCYSUPPORT_HOTANDMIRRORED = 5 + } UA_RedundancySupport; + +ServerState +^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_SERVERSTATE_RUNNING = 0, + UA_SERVERSTATE_FAILED = 1, + UA_SERVERSTATE_NOCONFIGURATION = 2, + UA_SERVERSTATE_SUSPENDED = 3, + UA_SERVERSTATE_SHUTDOWN = 4, + UA_SERVERSTATE_TEST = 5, + UA_SERVERSTATE_COMMUNICATIONFAULT = 6, + UA_SERVERSTATE_UNKNOWN = 7 + } UA_ServerState; + +ServerDiagnosticsSummaryDataType +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 serverViewCount; + UA_UInt32 currentSessionCount; + UA_UInt32 cumulatedSessionCount; + UA_UInt32 securityRejectedSessionCount; + UA_UInt32 rejectedSessionCount; + UA_UInt32 sessionTimeoutCount; + UA_UInt32 sessionAbortCount; + UA_UInt32 currentSubscriptionCount; + UA_UInt32 cumulatedSubscriptionCount; + UA_UInt32 publishingIntervalCount; + UA_UInt32 securityRejectedRequestsCount; + UA_UInt32 rejectedRequestsCount; + } UA_ServerDiagnosticsSummaryDataType; + +ServerStatusDataType +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_DateTime startTime; + UA_DateTime currentTime; + UA_ServerState state; + UA_BuildInfo buildInfo; + UA_UInt32 secondsTillShutdown; + UA_LocalizedText shutdownReason; + } UA_ServerStatusDataType; + +SessionSecurityDiagnosticsDataType +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId sessionId; + UA_String clientUserIdOfSession; + size_t clientUserIdHistorySize; + UA_String *clientUserIdHistory; + UA_String authenticationMechanism; + UA_String encoding; + UA_String transportProtocol; + UA_MessageSecurityMode securityMode; + UA_String securityPolicyUri; + UA_ByteString clientCertificate; + } UA_SessionSecurityDiagnosticsDataType; + +ServiceCounterDataType +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 totalCount; + UA_UInt32 errorCount; + } UA_ServiceCounterDataType; + +SubscriptionDiagnosticsDataType +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId sessionId; + UA_UInt32 subscriptionId; + UA_Byte priority; + UA_Double publishingInterval; + UA_UInt32 maxKeepAliveCount; + UA_UInt32 maxLifetimeCount; + UA_UInt32 maxNotificationsPerPublish; + UA_Boolean publishingEnabled; + UA_UInt32 modifyCount; + UA_UInt32 enableCount; + UA_UInt32 disableCount; + UA_UInt32 republishRequestCount; + UA_UInt32 republishMessageRequestCount; + UA_UInt32 republishMessageCount; + UA_UInt32 transferRequestCount; + UA_UInt32 transferredToAltClientCount; + UA_UInt32 transferredToSameClientCount; + UA_UInt32 publishRequestCount; + UA_UInt32 dataChangeNotificationsCount; + UA_UInt32 eventNotificationsCount; + UA_UInt32 notificationsCount; + UA_UInt32 latePublishRequestCount; + UA_UInt32 currentKeepAliveCount; + UA_UInt32 currentLifetimeCount; + UA_UInt32 unacknowledgedMessageCount; + UA_UInt32 discardedMessageCount; + UA_UInt32 monitoredItemCount; + UA_UInt32 disabledMonitoredItemCount; + UA_UInt32 monitoringQueueOverflowCount; + UA_UInt32 nextSequenceNumber; + UA_UInt32 eventQueueOverFlowCount; + } UA_SubscriptionDiagnosticsDataType; + +Range +^^^^^ + +.. code-block:: c + + typedef struct { + UA_Double low; + UA_Double high; + } UA_Range; + +EUInformation +^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_String namespaceUri; + UA_Int32 unitId; + UA_LocalizedText displayName; + UA_LocalizedText description; + } UA_EUInformation; + +AxisScaleEnumeration +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef enum { + UA_AXISSCALEENUMERATION_LINEAR = 0, + UA_AXISSCALEENUMERATION_LOG = 1, + UA_AXISSCALEENUMERATION_LN = 2 + } UA_AxisScaleEnumeration; + +ComplexNumberType +^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Float real; + UA_Float imaginary; + } UA_ComplexNumberType; + +DoubleComplexNumberType +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Double real; + UA_Double imaginary; + } UA_DoubleComplexNumberType; + +AxisInformation +^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_EUInformation engineeringUnits; + UA_Range eURange; + UA_LocalizedText title; + UA_AxisScaleEnumeration axisScaleType; + size_t axisStepsSize; + UA_Double *axisSteps; + } UA_AxisInformation; + +XVType +^^^^^^ + +.. code-block:: c + + typedef struct { + UA_Double x; + UA_Float value; + } UA_XVType; + +EnumDefinition +^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t fieldsSize; + UA_EnumField *fields; + } UA_EnumDefinition; + +ReadEventDetails +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_UInt32 numValuesPerNode; + UA_DateTime startTime; + UA_DateTime endTime; + UA_EventFilter filter; + } UA_ReadEventDetails; + +ReadProcessedDetails +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_DateTime startTime; + UA_DateTime endTime; + UA_Double processingInterval; + size_t aggregateTypeSize; + UA_NodeId *aggregateType; + UA_AggregateConfiguration aggregateConfiguration; + } UA_ReadProcessedDetails; + +ModificationInfo +^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_DateTime modificationTime; + UA_HistoryUpdateType updateType; + UA_String userName; + } UA_ModificationInfo; + +HistoryModifiedData +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t dataValuesSize; + UA_DataValue *dataValues; + size_t modificationInfosSize; + UA_ModificationInfo *modificationInfos; + } UA_HistoryModifiedData; + +HistoryEvent +^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t eventsSize; + UA_HistoryEventFieldList *events; + } UA_HistoryEvent; + +DataChangeNotification +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t monitoredItemsSize; + UA_MonitoredItemNotification *monitoredItems; + size_t diagnosticInfosSize; + UA_DiagnosticInfo *diagnosticInfos; + } UA_DataChangeNotification; + +EventNotificationList +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + size_t eventsSize; + UA_EventFieldList *events; + } UA_EventNotificationList; + +SessionDiagnosticsDataType +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct { + UA_NodeId sessionId; + UA_String sessionName; + UA_ApplicationDescription clientDescription; + UA_String serverUri; + UA_String endpointUrl; + size_t localeIdsSize; + UA_String *localeIds; + UA_Double actualSessionTimeout; + UA_UInt32 maxResponseMessageSize; + UA_DateTime clientConnectionTime; + UA_DateTime clientLastContactTime; + UA_UInt32 currentSubscriptionsCount; + UA_UInt32 currentMonitoredItemsCount; + UA_UInt32 currentPublishRequestsInQueue; + UA_ServiceCounterDataType totalRequestCount; + UA_UInt32 unauthorizedRequestCount; + UA_ServiceCounterDataType readCount; + UA_ServiceCounterDataType historyReadCount; + UA_ServiceCounterDataType writeCount; + UA_ServiceCounterDataType historyUpdateCount; + UA_ServiceCounterDataType callCount; + UA_ServiceCounterDataType createMonitoredItemsCount; + UA_ServiceCounterDataType modifyMonitoredItemsCount; + UA_ServiceCounterDataType setMonitoringModeCount; + UA_ServiceCounterDataType setTriggeringCount; + UA_ServiceCounterDataType deleteMonitoredItemsCount; + UA_ServiceCounterDataType createSubscriptionCount; + UA_ServiceCounterDataType modifySubscriptionCount; + UA_ServiceCounterDataType setPublishingModeCount; + UA_ServiceCounterDataType publishCount; + UA_ServiceCounterDataType republishCount; + UA_ServiceCounterDataType transferSubscriptionsCount; + UA_ServiceCounterDataType deleteSubscriptionsCount; + UA_ServiceCounterDataType addNodesCount; + UA_ServiceCounterDataType addReferencesCount; + UA_ServiceCounterDataType deleteNodesCount; + UA_ServiceCounterDataType deleteReferencesCount; + UA_ServiceCounterDataType browseCount; + UA_ServiceCounterDataType browseNextCount; + UA_ServiceCounterDataType translateBrowsePathsToNodeIdsCount; + UA_ServiceCounterDataType queryFirstCount; + UA_ServiceCounterDataType queryNextCount; + UA_ServiceCounterDataType registerNodesCount; + UA_ServiceCounterDataType unregisterNodesCount; + } UA_SessionDiagnosticsDataType; + diff --git a/static/doc/v1.4.0/_static/ua-wireshark-pubsub.png b/static/doc/v1.4.0/_static/ua-wireshark-pubsub.png new file mode 100644 index 0000000000..675c80d5ee Binary files /dev/null and b/static/doc/v1.4.0/_static/ua-wireshark-pubsub.png differ diff --git a/static/doc/v1.4.0/_static/ua-wireshark.png b/static/doc/v1.4.0/_static/ua-wireshark.png new file mode 100644 index 0000000000..a2af94f07a Binary files /dev/null and b/static/doc/v1.4.0/_static/ua-wireshark.png differ diff --git a/static/doc/v1.4.0/_static/util.rst b/static/doc/v1.4.0/_static/util.rst new file mode 100644 index 0000000000..451c45addd --- /dev/null +++ b/static/doc/v1.4.0/_static/util.rst @@ -0,0 +1,289 @@ +Range Definition +---------------- + +.. code-block:: c + + + typedef struct { + UA_UInt32 min; + UA_UInt32 max; + } UA_UInt32Range; + + typedef struct { + UA_Duration min; + UA_Duration max; + } UA_DurationRange; + +Random Number Generator +----------------------- +If UA_MULTITHREADING is defined, then the seed is stored in thread +local storage. The seed is initialized for every thread in the +server/client. + +.. code-block:: c + + + void + UA_random_seed(UA_UInt64 seed); + + UA_UInt32 + UA_UInt32_random(void); /* no cryptographic entropy */ + + UA_Guid + UA_Guid_random(void); /* no cryptographic entropy */ + +Key Value Map +------------- +Helper functions to work with configuration parameters in an array of +UA_KeyValuePair. Lookup is linear. So this is for small numbers of keys. The +methods below that accept a `const UA_KeyValueMap` as an argument also accept +NULL for that argument and treat it as an empty map. + +.. code-block:: c + + + typedef struct { + size_t mapSize; + UA_KeyValuePair *map; + } UA_KeyValueMap; + + extern const UA_KeyValueMap UA_KEYVALUEMAP_NULL; + + UA_KeyValueMap * + UA_KeyValueMap_new(void); + + void + UA_KeyValueMap_clear(UA_KeyValueMap *map); + + void + UA_KeyValueMap_delete(UA_KeyValueMap *map); + + /* Is the map empty (or NULL)? */ + UA_Boolean + UA_KeyValueMap_isEmpty(const UA_KeyValueMap *map); + + /* Does the map contain an entry for the key? */ + UA_Boolean + UA_KeyValueMap_contains(const UA_KeyValueMap *map, const UA_QualifiedName key); + + /* Insert a copy of the value. Can reallocate the underlying array. This + * invalidates pointers into the previous array. If the key exists already, the + * value is overwritten (upsert semantics). */ + UA_StatusCode + UA_KeyValueMap_set(UA_KeyValueMap *map, + const UA_QualifiedName key, + const UA_Variant *value); + + /* Helper function for scalar insertion that internally calls + * `UA_KeyValueMap_set` */ + UA_StatusCode + UA_KeyValueMap_setScalar(UA_KeyValueMap *map, + const UA_QualifiedName key, + void *p, + const UA_DataType *type); + + /* Returns a pointer to the value or NULL if the key is not found */ + const UA_Variant * + UA_KeyValueMap_get(const UA_KeyValueMap *map, + const UA_QualifiedName key); + + /* Returns NULL if the value for the key is not defined, not of the right + * datatype or not a scalar */ + const void * + UA_KeyValueMap_getScalar(const UA_KeyValueMap *map, + const UA_QualifiedName key, + const UA_DataType *type); + + /* Remove a single entry. To delete the entire map, use `UA_KeyValueMap_clear`. */ + UA_StatusCode + UA_KeyValueMap_remove(UA_KeyValueMap *map, + const UA_QualifiedName key); + + /* Create a deep copy of the given KeyValueMap */ + UA_StatusCode + UA_KeyValueMap_copy(const UA_KeyValueMap *src, UA_KeyValueMap *dst); + + /* Copy entries from the right-hand-side into the left-hand-size. Reallocates + * previous memory in the left-hand-side. If the operation fails, both maps are + * left untouched. */ + UA_StatusCode + UA_KeyValueMap_merge(UA_KeyValueMap *lhs, const UA_KeyValueMap *rhs); + +Binary Connection Config Parameters +----------------------------------- + +.. code-block:: c + + + typedef struct { + UA_UInt32 protocolVersion; + UA_UInt32 recvBufferSize; + UA_UInt32 sendBufferSize; + UA_UInt32 localMaxMessageSize; /* (0 = unbounded) */ + UA_UInt32 remoteMaxMessageSize; /* (0 = unbounded) */ + UA_UInt32 localMaxChunkCount; /* (0 = unbounded) */ + UA_UInt32 remoteMaxChunkCount; /* (0 = unbounded) */ + } UA_ConnectionConfig; + +.. _default-node-attributes: + +Default Node Attributes +----------------------- +Default node attributes to simplify the use of the AddNodes services. For +example, Setting the ValueRank and AccessLevel to zero is often an unintended +setting and leads to errors that are hard to track down. + +.. code-block:: c + + + /* The default for variables is "BaseDataType" for the datatype, -2 for the + * valuerank and a read-accesslevel. */ + extern const UA_VariableAttributes UA_VariableAttributes_default; + extern const UA_VariableTypeAttributes UA_VariableTypeAttributes_default; + + /* Methods are executable by default */ + extern const UA_MethodAttributes UA_MethodAttributes_default; + + /* The remaining attribute definitions are currently all zeroed out */ + extern const UA_ObjectAttributes UA_ObjectAttributes_default; + extern const UA_ObjectTypeAttributes UA_ObjectTypeAttributes_default; + extern const UA_ReferenceTypeAttributes UA_ReferenceTypeAttributes_default; + extern const UA_DataTypeAttributes UA_DataTypeAttributes_default; + extern const UA_ViewAttributes UA_ViewAttributes_default; + +Endpoint URL Parser +------------------- +The endpoint URL parser is generally useful for the implementation of network +layer plugins. + +.. code-block:: c + + + /* Split the given endpoint url into hostname, port and path. All arguments must + * be non-NULL. EndpointUrls have the form "opc.tcp://hostname:port/path", port + * and path may be omitted (together with the prefix colon and slash). + * + * @param endpointUrl The endpoint URL. + * @param outHostname Set to the parsed hostname. The string points into the + * original endpointUrl, so no memory is allocated. If an IPv6 address is + * given, hostname contains e.g. '[2001:0db8:85a3::8a2e:0370:7334]' + * @param outPort Set to the port of the url or left unchanged. + * @param outPath Set to the path if one is present in the endpointUrl. Can be + * NULL. Then not path is returned. Starting or trailing '/' are NOT + * included in the path. The string points into the original endpointUrl, + * so no memory is allocated. + * @return Returns UA_STATUSCODE_BADTCPENDPOINTURLINVALID if parsing failed. */ + UA_StatusCode + UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname, + UA_UInt16 *outPort, UA_String *outPath); + + /* Split the given endpoint url into hostname, vid and pcp. All arguments must + * be non-NULL. EndpointUrls have the form "opc.eth://[:[.PCP]]". + * The host is a MAC address, an IP address or a registered name like a + * hostname. The format of a MAC address is six groups of hexadecimal digits, + * separated by hyphens (e.g. 01-23-45-67-89-ab). A system may also accept + * hostnames and/or IP addresses if it provides means to resolve it to a MAC + * address (e.g. DNS and Reverse-ARP). + * + * Note: currently only parsing MAC address is supported. + * + * @param endpointUrl The endpoint URL. + * @param vid Set to VLAN ID. + * @param pcp Set to Priority Code Point. + * @return Returns UA_STATUSCODE_BADINTERNALERROR if parsing failed. */ + UA_StatusCode + UA_parseEndpointUrlEthernet(const UA_String *endpointUrl, UA_String *target, + UA_UInt16 *vid, UA_Byte *pcp); + + /* Convert given byte string to a positive number. Returns the number of valid + * digits. Stops if a non-digit char is found and returns the number of digits + * up to that point. */ + size_t + UA_readNumber(const UA_Byte *buf, size_t buflen, UA_UInt32 *number); + + /* Same as UA_ReadNumber but with a base parameter */ + size_t + UA_readNumberWithBase(const UA_Byte *buf, size_t buflen, + UA_UInt32 *number, UA_Byte base); + + #ifndef UA_MIN + #define UA_MIN(A, B) ((A) > (B) ? (B) : (A)) + #endif + + #ifndef UA_MAX + #define UA_MAX(A, B) ((A) > (B) ? (A) : (B)) + #endif + +Parse RelativePath Expressions +------------------------------ + +Parse a RelativePath according to the format defined in Part 4, A2. This is +used e.g. for the BrowsePath structure. For now, only the standard +ReferenceTypes from Namespace 0 are recognized (see Part 3). + + ``RelativePath := ( ReferenceType [BrowseName]? )*`` + +The ReferenceTypes have either of the following formats: + +- ``/``: *HierarchicalReferences* and subtypes +- ``.``: *Aggregates* ReferenceTypesand subtypes +- ``< [!#]* BrowseName >``: The ReferenceType is indicated by its BrowseName + (a QualifiedName). Prefixed modifiers can be as follows: ``!`` switches to + inverse References. ``#`` excludes subtypes of the ReferenceType. + +QualifiedNames consist of an optional NamespaceIndex and the nameitself: + + ``QualifiedName := ([0-9]+ ":")? Name`` + +The QualifiedName representation for RelativePaths uses ``&`` as the escape +character. Occurences of the characters ``/.<>:#!&`` in a QualifiedName have +to be escaped (prefixed with ``&``). + +Example RelativePaths +````````````````````` + +- ``/2:Block&.Output`` +- ``/3:Truck.0:NodeVersion`` +- ``<0:HasProperty>1:Boiler/1:HeatSensor`` +- ``<0:HasChild>2:Wheel`` +- ``<#Aggregates>1:Boiler/`` +- ``Truck`` +- ```` + +.. code-block:: c + + #ifdef UA_ENABLE_PARSING + UA_StatusCode + UA_RelativePath_parse(UA_RelativePath *rp, const UA_String str); + #endif + +Convenience macros for complex types +------------------------------------ + +.. code-block:: c + + #define UA_PRINTF_GUID_FORMAT "%08" PRIx32 "-%04" PRIx16 "-%04" PRIx16 \ + "-%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 + #define UA_PRINTF_GUID_DATA(GUID) (GUID).data1, (GUID).data2, (GUID).data3, \ + (GUID).data4[0], (GUID).data4[1], (GUID).data4[2], (GUID).data4[3], \ + (GUID).data4[4], (GUID).data4[5], (GUID).data4[6], (GUID).data4[7] + + #define UA_PRINTF_STRING_FORMAT "\"%.*s\"" + #define UA_PRINTF_STRING_DATA(STRING) (int)(STRING).length, (STRING).data + +Cryptography Helpers +-------------------- + +.. code-block:: c + + + /* Compare memory in constant time to mitigate timing attacks. + * Returns true if ptr1 and ptr2 are equal for length bytes. */ + UA_Boolean + UA_constantTimeEqual(const void *ptr1, const void *ptr2, size_t length); + + /* Zero-out memory in a way that is not removed by compiler-optimizations. Use + * this to ensure cryptographic secrets don't leave traces after the memory was + * freed. */ + void + UA_ByteString_memZero(UA_ByteString *bs); diff --git a/static/doc/v1.4.0/building.html b/static/doc/v1.4.0/building.html new file mode 100644 index 0000000000..4b01c72bdf --- /dev/null +++ b/static/doc/v1.4.0/building.html @@ -0,0 +1,602 @@ + + + + + + + Building open62541 — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Building open62541

+
+

Building the Library

+

open62541 uses CMake to build the library and binaries. CMake generates a +Makefile or a Visual Studio project. This is then used to perform the actual +build.

+
+

Building with CMake on Ubuntu or Debian

+
sudo apt-get install git build-essential gcc pkg-config cmake python
+
+# enable additional features
+sudo apt-get install cmake-curses-gui # for the ccmake graphical interface
+sudo apt-get install libmbedtls-dev # for encryption support
+sudo apt-get install check libsubunit-dev # for unit tests
+sudo apt-get install python-sphinx graphviz # for documentation generation
+sudo apt-get install python-sphinx-rtd-theme # documentation style
+
+cd open62541
+mkdir build
+cd build
+cmake ..
+make
+
+# select additional features
+ccmake ..
+make
+
+# build documentation
+make doc # html documentation
+make doc_pdf # pdf documentation (requires LaTeX)
+
+
+

You can install open62541 using the well known make install command. This +allows you to use pre-built libraries and headers for your own project. In order +to use open62541 as a shared library (.dll or .so) make sure to activate the +BUILD_SHARED_LIBS CMake option.

+

To override the default installation directory use cmake +-DCMAKE_INSTALL_PREFIX=/some/path. Based on the SDK Features you selected, as +described in Build Options, these features will also be included in the +installation. Thus we recommend to enable as many non-experimental features as +possible for the installed binary.

+

In your own CMake project you can then include the open62541 library using:

+
# optionally you can also specify a specific version
+# e.g. find_package(open62541 1.0.0)
+find_package(open62541 REQUIRED COMPONENTS Events FullNamespace)
+add_executable(main main.cpp)
+target_link_libraries(main open62541::open62541)
+
+
+

A full list of enabled features during build time is stored in the CMake +Variable open62541_COMPONENTS_ALL

+
+
+

Building with CMake on Windows

+

Here we explain the build process for Visual Studio (2013 or newer). To build +with MinGW, just replace the compiler selection in the call to CMake.

+ +
cd <path-to>\open62541
+mkdir build
+cd build
+<path-to>\cmake.exe .. -G "Visual Studio 14 2015"
+:: You can use use cmake-gui for a graphical user-interface to select features
+
+
+
    +
  • Then open buildopen62541.sln in Visual Studio 2015 and build as usual

  • +
+
+
+

Building on OS X

+ +
brew install cmake
+pip install sphinx # for documentation generation
+pip install sphinx_rtd_theme # documentation style
+brew install graphviz # for graphics in the documentation
+brew install check # for unit tests
+
+
+

Follow Ubuntu instructions without the apt-get commands as these are taken care of by the above packages.

+
+
+

Building on OpenBSD

+

The procedure below works on OpenBSD 5.8 with gcc version 4.8.4, cmake version +3.2.3 and Python version 2.7.10.

+
    +
  • Install a recent gcc, python and cmake:

  • +
+
pkg_add gcc python cmake
+
+
+
    +
  • Tell the system to actually use the recent gcc (it gets installed as egcc on OpenBSD):

  • +
+
export CC=egcc CXX=eg++
+
+
+
    +
  • Now procede as described for Ubuntu/Debian:

  • +
+
cd open62541
+mkdir build
+cd build
+cmake ..
+make
+
+
+
+
+

Building Debian Packages inside Docker Container with CMake on Ubuntu or Debian

+

Here is an example howto build the library as Debian package inside a Docker container

+ +

Install Docker as described at https://docs.docker.com/install/linux/docker-ce/debian/ .

+

Get the docker-deb-builder utility from github and make Docker images for the needed +Debian and/or Ubuntu relases

+
# make and goto local development path (e.g. ~/development)
+mkdir ~/development
+cd ~/development
+
+# clone docker-deb-builder utility from github and change into builder directory
+git clone https://github.com/tsaarni/docker-deb-builder.git
+cd docker-deb-builder
+
+# make Docker builder images (e.g. Ubuntu 18.04 and 17.04)
+docker build -t docker-deb-builder:18.04 -f Dockerfile-ubuntu-18.04 .
+docker build -t docker-deb-builder:17.04 -f Dockerfile-ubuntu-17.04 .
+
+
+

Make a local copy of the open62541 git repo and checkout a pack branch

+
# make a local copy of the open62541 git repo (e.g. in the home directory)
+# and checkout a pack branch (e.g. pack/1.0)
+cd ~
+git clone https://github.com/open62541/open62541.git
+cd ~/open62541
+git checkout pack/1.0
+
+
+

Now it’s all set to build Debian/Ubuntu open62541 packages

+
# goto local developmet path
+cd ~/development
+
+# make a local output directory for the builder where the packages can be placed after build
+mkdir output
+
+# build Debian/Ubuntu packages inside Docker container (e.g. Ubuntu-18.04)
+./build -i docker-deb-builder:18.04 -o output ~/open62541
+
+
+

After a successfull build the Debian/Ubuntu packages can be found at ~/development/docker-deb-builder/output

+
+
+

CMake Build Options and Debian Packaging

+

If the open62541 library will be build as a Debian package using a pack branch (e.g. pack/master or pack/1.0) +then altering or adding CMake build options should be done inside the debian/rules file respectively in +the debian/rules-template file if working with a development branch (e.g. master or 1.0).

+

The section in debian/rules where the CMake build options are defined is

+
...
+override_dh_auto_configure:
+    dh_auto_configure -- -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUA_NAMESPACE_ZERO=FULL -DUA_ENABLE_AMALGAMATION=OFF -DUA_PACK_DEBIAN=ON
+...
+
+
+

This CMake build options will be passed as command line variables to CMake during Debian packaging.

+
+
+
+

Build Options

+

The open62541 project uses CMake to manage the build options, for code +generation and to generate build projects for the different systems and IDEs. +The tools ccmake or cmake-gui can be used to graphically set the build +options.

+

Most options can be changed manually in ua_config.h (open62541.h +for the single-file release) after the code generation. But usually there is no +need to adjust them.

+
+

Main Build Options

+
+
CMAKE_BUILD_TYPE
    +
  • RelWithDebInfo -O2 optimization with debug symbols

  • +
  • Release -O2 optimization without debug symbols

  • +
  • Debug -O0 optimization with debug symbols

  • +
  • MinSizeRel -Os optimization without debug symbols

  • +
+
+
UA_LOGLEVEL

The SDK logs events of the level defined in UA_LOGLEVEL and above only. +The logging event levels are as follows:

+
    +
  • 600: Fatal

  • +
  • 500: Error

  • +
  • 400: Warning

  • +
  • 300: Info

  • +
  • 200: Debug

  • +
  • 100: Trace

  • +
+

This compilation flag defines which log levels get compiled into the code. In +addition, the implementations of Logging Plugin API allow to set a filter for the +logging level at runtime. So the logging level can be changed in the +configuration without recompiling.

+
+
UA_MULTITHREADING
+

Level of multi-threading support. The supported levels are currently as follows:

+
+
    +
  • 0-99: Multithreading support disabled.

  • +
  • >=100: API functions marked with the UA_THREADSAFE-macro are protected internally with mutexes. +Multiple threads are allowed to call these functions of the SDK at the same time without causing race conditions. +Furthermore, this level support the handling of asynchronous method calls from external worker threads.

  • +
+
+
+
+
+

Select build artefacts

+

By default only the main library shared object libopen62541.so (open62541.dll) +or static linking archive open62541.a (open62541.lib) is built. Additional +artifacts can be specified by the following options:

+
+
UA_BUILD_EXAMPLES

Compile example servers and clients from examples/*.c.

+
+
UA_BUILD_UNIT_TESTS

Compile unit tests. The tests can be executed with make test. +An individual test can be executed with make test ARGS="-R <test_name> -V". +The list of available tests can be displayed with make test ARGS="-N".

+
+
UA_BUILD_SELFSIGNED_CERTIFICATE

Generate a self-signed certificate for the server (openSSL required)

+
+
+
+
+

Detailed SDK Features

+
+
UA_ENABLE_SUBSCRIPTIONS

Enable subscriptions

+
+
UA_ENABLE_SUBSCRIPTIONS_EVENTS (EXPERIMENTAL)

Enable the use of events for subscriptions. This is a new feature and currently marked as EXPERIMENTAL.

+
+
UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS (EXPERIMENTAL)

Enable the use of A&C for subscriptions. This is a new feature build upon events and currently marked as EXPERIMENTAL.

+
+
UA_ENABLE_METHODCALLS

Enable the Method service set

+
+
UA_ENABLE_PARSING

Enable parsing human readable formats of builtin data types (Guid, NodeId, etc.). +Utility functions that are not essential to the SDK.

+
+
UA_ENABLE_NODEMANAGEMENT

Enable dynamic addition and removal of nodes at runtime

+
+
UA_ENABLE_AMALGAMATION

Compile a single-file release into the files open62541.c and open62541.h. Not recommended for installation.

+
+
UA_ENABLE_IMMUTABLE_NODES

Nodes in the information model are not edited but copied and replaced. The +replacement is done with atomic operations so that the information model is +always consistent and can be accessed from an interrupt or parallel thread +(depends on the node storage plugin implementation).

+
+
UA_ENABLE_COVERAGE

Measure the coverage of unit tests

+
+
UA_ENABLE_DISCOVERY

Enable Discovery Service (LDS)

+
+
UA_ENABLE_DISCOVERY_MULTICAST

Enable Discovery Service with multicast support (LDS-ME)

+
+
UA_ENABLE_DISCOVERY_SEMAPHORE

Enable Discovery Semaphore support

+
+
UA_ENABLE_ENCRYPTION

Enable encryption support and specify the used encryption backend. The possible +options are: +- OFF No encryption support. (default) +- MBEDTLS Encryption support using mbed TLS +- OPENSSL Encryption support using OpenSSL +- LIBRESSL EXPERIMENTAL: Encryption support using LibreSSL

+
+
UA_ENABLE_ENCRYPTION_TPM2
+
Enable TPM hardware for encryption. The possible options are:
    +
  • OFF No TPM encryption support. (default)

  • +
  • ON TPM encryption support

  • +
+
+
+
+
+

UA_NAMESPACE_ZERO

+
+

Namespace zero contains the standard-defined nodes. The full namespace zero +may not be required for all applications. The selectable options are as follows:

+
    +
  • MINIMAL: A barebones namespace zero that is compatible with most +clients. But this namespace 0 is so small that it does not pass the CTT +(Conformance Testing Tools of the OPC Foundation).

  • +
  • REDUCED: Small namespace zero that passes the CTT.

  • +
  • FULL: Full namespace zero generated from the official XML definitions.

  • +
+

The advanced build option UA_FILE_NS0 can be used to override the XML +file used for namespace zero generation.

+
+

Some options are marked as advanced. The advanced options need to be toggled to +be visible in the cmake GUIs.

+
+
UA_ENABLE_TYPEDESCRIPTION

Add the type and member names to the UA_DataType structure. Enabled by default.

+
+
UA_ENABLE_STATUSCODE_DESCRIPTIONS

Compile the human-readable name of the StatusCodes into the binary. Enabled by default.

+
+
UA_ENABLE_FULL_NS0

Use the full NS0 instead of a minimal Namespace 0 nodeset +UA_FILE_NS0 is used to specify the file for NS0 generation from namespace0 folder. Default value is Opc.Ua.NodeSet2.xml

+
+
+
+
+

PubSub Build Options

+
+
UA_ENABLE_PUBSUB

Enable the experimental OPC UA PubSub support. The option will include the +PubSub UDP multicast plugin. Disabled by default.

+
+
UA_ENABLE_PUBSUB_DELTAFRAMES

The PubSub messages differentiate between keyframe (all published values +contained) and deltaframe (only changed values contained) messages. +Deltaframe messages creation consumes some additional resources and can be +disabled with this flag. Disabled by default.

+
+
UA_ENABLE_PUBSUB_FILE_CONFIG

Enable loading OPC UA PubSub configuration from File/ByteString. Enabling +PubSub informationmodel methods also will add a method to the +Publish/Subscribe object which allows configuring PubSub at runtime.

+
+
UA_ENABLE_PUBSUB_INFORMATIONMODEL

Enable the information model representation of the PubSub configuration. For +more details take a look at the following section PubSub Information Model +Representation. Disabled by default.

+
+
UA_ENABLE_PUBSUB_MONITORING

Enable the experimental PubSub monitoring. This feature provides a basic +framework to implement monitoring/timeout checks for PubSub components. +Initially the MessageReceiveTimeout check of a DataSetReader is provided. It +uses the internal server callback implementation. The monitoring backend can +be changed by the application to satisfy realtime requirements. Disabled by +default.

+
+
+
+
+

Debug Build Options

+

This group contains build options mainly useful for development of the library itself.

+
+
UA_DEBUG

Enable assertions and additional definitions not intended for production builds

+
+
UA_DEBUG_DUMP_PKGS

Dump every package received by the server as hexdump format

+
+
+
+
+

Building a shared library

+

open62541 is small enough that most users will want to statically link the +library into their programs. If a shared library (.dll, .so) is required, this +can be enabled in CMake with the BUILD_SHARED_LIBS option. Note that this +option modifies the ua_config.h file that is also included in +open62541.h for the single-file distribution.

+
+
+

Minimizing the binary size

+

The size of the generated binary can be reduced considerably by adjusting the +build configuration. With open62541, it is possible to configure minimal servers +that require less than 100kB of RAM and ROM.

+

The following options influence the ROM requirements:

+

First, in CMake, the build type can be set to CMAKE_BUILD_TYPE=MinSizeRel. +This sets the compiler flags to minimize the binary size. The build type also +strips out debug information. Second, the binary size can be reduced by removing +features via the build-flags described above.

+

Second, setting UA_NAMESPACE_ZERO to MINIMAL reduces the size of the +builtin information model. Setting this option can reduce the binary size by +half in some cases.

+

Third, some features might not be needed and can be disabled to reduce the +binary footprint. Examples for this are Subscriptions or encrypted +communication.

+

Last, logging messages take up a lot of space in the binary and might not be +needed in embedded scenarios. Setting UA_LOGLEVEL to a value above 600 +(FATAL) disables all logging. In addition, the feature-flags +UA_ENABLE_TYPEDESCRIPTION and UA_ENABLE_STATUSCODE_DESCRIPTIONS add static +information to the binary that is only used for human-readable logging and +debugging.

+

The RAM requirements of a server are mostly due to the following settings:

+
    +
  • The size of the information model

  • +
  • The number of connected clients

  • +
  • The configured maximum message size that is preallocated

  • +
+
+
+
+

Prebuilt packages

+
+

Debian

+

Debian packages can be found in our official PPA:

+
+
+
+

Install them with:

+
sudo add-apt-repository ppa:open62541-team/ppa
+sudo apt-get update
+sudo apt-get install libopen62541-1-dev
+
+
+
+
+

Arch

+

Arch packages are available in the AUR:

+
+
+
+
+
+

OpenBSD

+

Starting with OpenBSD 6.7 the ports directory misc/open62541 can +build the released version of open62541. +Install the binary package from the OpenBSD mirrors:

+
pkg_add open62541
+
+
+
+
+
+

Building the Examples

+

Make sure that you have installed the shared library as explained in the +previous steps. Then the build system should automatically find the includes and +the shared library.

+
cp /path-to/examples/tutorial_server_firststeps.c . # copy the example server
+gcc -std=c99 -o server tutorial_server_firststeps.c -lopen62541
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/client.html b/static/doc/v1.4.0/client.html new file mode 100644 index 0000000000..756a747f9c --- /dev/null +++ b/static/doc/v1.4.0/client.html @@ -0,0 +1,1060 @@ + + + + + + + Client — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Client

+

The client implementation allows remote access to all OPC UA services. For +convenience, some functionality has been wrapped in high-level +abstractions.

+

However: At this time, the client does not yet contain its own thread or +event-driven main-loop, meaning that the client will not perform any actions +automatically in the background. This is especially relevant for +connection/session management and subscriptions. The user will have to +periodically call UA_Client_run_iterate to ensure that asynchronous events +are handled, including keeping a secure connection established. +See more about asynchronicity and +subscriptions.

+
+

Client Configuration

+

The client configuration is used for setting connection parameters and +additional settings used by the client. +The configuration should not be modified after it is passed to a client. +Currently, only one client can use a configuration at a time.

+

Examples for configurations are provided in the /plugins folder. +The usual usage is as follows:

+
    +
  1. Create a client configuration with default settings as a starting point

  2. +
  3. Modifiy the configuration, e.g. modifying the timeout

  4. +
  5. Instantiate a client with it

  6. +
  7. After shutdown of the client, clean up the configuration (free memory)

  8. +
+

The Tutorials provide a good starting point for this.

+
struct UA_ClientConfig {
+    void *clientContext; /* User-defined pointer attached to the client */
+    UA_Logger *logging;  /* Plugin for log output */
+
+    /* Response timeout in ms (0 -> no timeout). If the server does not answer a
+     * request within this time a StatusCode UA_STATUSCODE_BADTIMEOUT is
+     * returned. This timeout can be overridden for individual requests by
+     * setting a non-null "timeoutHint" in the request header. */
+    UA_UInt32 timeout;
+
+    /* The description must be internally consistent.
+     * - The ApplicationUri set in the ApplicationDescription must match the
+     *   URI set in the certificate */
+    UA_ApplicationDescription clientDescription;
+
+    /* The endpoint for the client to connect to.
+     * Such as "opc.tcp://host:port". */
+    UA_String endpointUrl;
+
+
+
+

Connection configuration

+

The following configuration elements reduce the “degrees of freedom” the +client has when connecting to a server. If no connection can be made +under these restrictions, then the connection will abort with an error +message.

+
UA_ExtensionObject userIdentityToken; /* Configured User-Identity Token */
+UA_MessageSecurityMode securityMode;  /* None, Sign, SignAndEncrypt. The
+                                       * default is invalid. This indicates
+                                       * the client to select any matching
+                                       * endpoint. */
+UA_String securityPolicyUri; /* SecurityPolicy for the SecureChannel. An
+                              * empty string indicates the client to select
+                              * any matching SecurityPolicy. */
+
+UA_Boolean noSession;   /* Only open a SecureChannel, but no Session */
+UA_Boolean noReconnect; /* Don't reconnect SecureChannel when the connection
+                         * is lost without explicitly closing. */
+UA_Boolean noNewSession; /* Don't automatically create a new Session when
+                          * the intial one is lost. Instead abort the
+                          * connection when the Session is lost. */
+
+
+

If either endpoint or userTokenPolicy has been set (at least one non-zero +byte in either structure), then the selected Endpoint and UserTokenPolicy +overwrite the settings in the basic connection configuration. The +userTokenPolicy array in the EndpointDescription is ignored. The selected +userTokenPolicy is set in the dedicated configuration field.

+

If the advanced configuration is not set, the client will write to it the +selected Endpoint and UserTokenPolicy during GetEndpoints.

+

The information in the advanced configuration is used during reconnect +when the SecureChannel was broken.

+
UA_EndpointDescription endpoint;
+UA_UserTokenPolicy userTokenPolicy;
+
+
+

If the EndpointDescription has not been defined, the ApplicationURI +constrains the servers considered in the FindServers service and the +Endpoints considered in the GetEndpoints service.

+

If empty the applicationURI is not used to filter.

+
UA_String applicationUri;
+
+
+
+
+

Custom Data Types

+

The following is a linked list of arrays with custom data types. All data +types that are accessible from here are automatically considered for the +decoding of received messages. Custom data types are not cleaned up +together with the configuration. So it is possible to allocate them on +ROM.

+

See the section on Generic Type Handling. Examples for working with custom +data types are provided in /examples/custom_datatype/.

+
const UA_DataTypeArray *customDataTypes;
+
+
+
+
+

Advanced Client Configuration

+
    UA_UInt32 secureChannelLifeTime; /* Lifetime in ms (then the channel needs
+                                        to be renewed) */
+    UA_UInt32 requestedSessionTimeout; /* Session timeout in ms */
+    UA_ConnectionConfig localConnectionConfig;
+    UA_UInt32 connectivityCheckInterval;     /* Connectivity check interval in ms.
+                                              * 0 = background task disabled */
+
+    /* EventLoop */
+    UA_EventLoop *eventLoop;
+    UA_Boolean externalEventLoop; /* The EventLoop is not deleted with the config */
+
+    /* Available SecurityPolicies */
+    size_t securityPoliciesSize;
+    UA_SecurityPolicy *securityPolicies;
+
+    /* Certificate Verification Plugin */
+    UA_CertificateVerification certificateVerification;
+
+    /* Available SecurityPolicies for Authentication. The policy defined by the
+     * AccessControl is selected. If no policy is defined, the policy of the
+     * secure channel is selected.*/
+    size_t authSecurityPoliciesSize;
+    UA_SecurityPolicy *authSecurityPolicies;
+    /* SecurityPolicyUri for the Authentication. */
+    UA_String authSecurityPolicyUri;
+
+    /* Callback for state changes. The client state is differentated into the
+     * SecureChannel state and the Session state. The connectStatus is set if
+     * the client connection (including reconnects) has failed and the client
+     * has to "give up". If the connectStatus is not set, the client still has
+     * hope to connect or recover. */
+    void (*stateCallback)(UA_Client *client,
+                          UA_SecureChannelState channelState,
+                          UA_SessionState sessionState,
+                          UA_StatusCode connectStatus);
+
+    /* When connectivityCheckInterval is greater than 0, every
+     * connectivityCheckInterval (in ms), an async read request is performed on
+     * the server. inactivityCallback is called when the client receive no
+     * response for this read request The connection can be closed, this in an
+     * attempt to recreate a healthy connection. */
+    void (*inactivityCallback)(UA_Client *client);
+
+    /* Number of PublishResponse queued up in the server */
+    UA_UInt16 outStandingPublishRequests;
+
+    /* If the client does not receive a PublishResponse after the defined delay
+     * of ``(sub->publishingInterval * sub->maxKeepAliveCount) +
+     * client->config.timeout)``, then subscriptionInactivityCallback is called
+     * for the subscription.. */
+    void (*subscriptionInactivityCallback)(UA_Client *client,
+                                           UA_UInt32 subscriptionId,
+                                           void *subContext);
+
+    /* Session config */
+    UA_String sessionName;
+    UA_LocaleId *sessionLocaleIds;
+    size_t sessionLocaleIdsSize;
+
+#ifdef UA_ENABLE_ENCRYPTION
+    /* If the private key is in PEM format and password protected, this callback
+     * is called during initialization to get the password to decrypt the
+     * private key. The memory containing the password is freed by the client
+     * after use. The callback should be set early, other parts of the client
+     * config setup may depend on it. */
+    UA_StatusCode (*privateKeyPasswordCallback)(UA_ClientConfig *cc,
+                                                UA_ByteString *password);
+#endif
+};
+
+
+

@brief It makes a partial deep copy of the clientconfig. It makes a shallow +copies of the plugins (logger, eventloop, securitypolicy).

+

NOTE: It makes a shallow copy of all the plugins from source to destination. +Therefore calling _clear on the dst object will also delete the plugins in src +object.

+
UA_StatusCode
+UA_ClientConfig_copy(UA_ClientConfig const *src, UA_ClientConfig *dst);
+
+
+

@brief It cleans the client config and frees the pointer.

+
void
+UA_ClientConfig_delete(UA_ClientConfig *config);
+
+
+

@brief It cleans the client config and deletes the plugins, whereas +_copy makes a shallow copy of the plugins.

+
void
+UA_ClientConfig_clear(UA_ClientConfig *config);
+
+/* Configure Username/Password for the Session authentication. Also see
+ * UA_ClientConfig_setAuthenticationCert for x509-based authentication, which is
+ * implemented as a plugin (as it can be based on different crypto
+ * libraries). */
+static UA_INLINE UA_StatusCode
+UA_ClientConfig_setAuthenticationUsername(UA_ClientConfig *config,
+                                          const char *username,
+                                          const char *password) {
+    UA_UserNameIdentityToken* identityToken = UA_UserNameIdentityToken_new();
+    if(!identityToken)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    identityToken->userName = UA_STRING_ALLOC(username);
+    identityToken->password = UA_STRING_ALLOC(password);
+
+    UA_ExtensionObject_clear(&config->userIdentityToken);
+    UA_ExtensionObject_setValue(&config->userIdentityToken, identityToken,
+                                &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]);
+    return UA_STATUSCODE_GOOD;
+}
+
+
+
+
+
+

Client Lifecycle

+
/* Create a new client with a default configuration that adds plugins for
+ * networking, security, logging and so on. See `client_config_default.h` for
+ * more detailed options.
+ *
+ * The default configuration can be used as the starting point to adjust the
+ * client configuration to individual needs. UA_Client_new is implemented in the
+ * /plugins folder under the CC0 license. Furthermore the client confiugration
+ * only uses the public server API.
+ *
+ * @return Returns the configured client or NULL if an error occurs. */
+UA_Client * UA_Client_new(void);
+
+/* Creates a new client. Moves the config into the client with a shallow copy.
+ * The config content is cleared together with the client. */
+UA_Client *
+UA_Client_newWithConfig(const UA_ClientConfig *config);
+
+/* Returns the current state. All arguments except ``client`` can be NULL. */
+void UA_THREADSAFE
+UA_Client_getState(UA_Client *client,
+                   UA_SecureChannelState *channelState,
+                   UA_SessionState *sessionState,
+                   UA_StatusCode *connectStatus);
+
+/* Get the client configuration */
+UA_ClientConfig *
+UA_Client_getConfig(UA_Client *client);
+
+/* Get the client context */
+static UA_INLINE void *
+UA_Client_getContext(UA_Client *client) {
+    return UA_Client_getConfig(client)->clientContext; /* Cannot fail */
+}
+
+/* (Disconnect and) delete the client */
+void
+UA_Client_delete(UA_Client *client);
+
+
+
+
+

Connection Attrbiutes

+

Besides the client configuration, some attributes of the connection are +defined only at runtime. For example the choice of SecurityPolicy or the +ApplicationDescripton from the server. This API allows to access such +connection attributes.

+

The currently defined connection attributes are:

+
    +
  • 0:serverDescription [UA_ApplicationDescription]: Server description

  • +
  • 0:securityPolicyUri [UA_String]: Uri of the SecurityPolicy used

  • +
  • 0:securityMode [UA_MessageSecurityMode]: SecurityMode of the SecureChannel

  • +
+
/* Returns a shallow copy of the attribute. Don't _clear or _delete the value
+ * variant. Don't use the value after returning the control flow to the client.
+ * Also don't use this in a multi-threaded application. */
+UA_StatusCode
+UA_Client_getConnectionAttribute(UA_Client *client, const UA_QualifiedName key,
+                                 UA_Variant *outValue);
+
+/* Return a deep copy of the attribute */
+UA_StatusCode UA_THREADSAFE
+UA_Client_getConnectionAttributeCopy(UA_Client *client, const UA_QualifiedName key,
+                                     UA_Variant *outValue);
+
+/* Returns NULL if the attribute is not defined or not a scalar or not of the
+ * right datatype. Otherwise a shallow copy of the scalar value is created at
+ * the target location of the void pointer. Hence don't use this in a
+ * multi-threaded application. */
+UA_StatusCode
+UA_Client_getConnectionAttribute_scalar(UA_Client *client,
+                                        const UA_QualifiedName key,
+                                        const UA_DataType *type,
+                                        void *outValue);
+
+
+
+
+

Connect to a Server

+

Once a client is connected to an endpointUrl, it is not possible to switch to +another server. A new client has to be created for that.

+

Once a connection is established, the client keeps the connection open and +reconnects if necessary.

+

If the connection fails unrecoverably (state->connectStatus is set to an +error), the client is no longer usable. Create a new client if required.

+
/* Connect with the client configuration. For the async connection, finish
+ * connecting via UA_Client_run_iterate (or manually running a configured
+ * external EventLoop). */
+UA_StatusCode UA_THREADSAFE
+__UA_Client_connect(UA_Client *client, UA_Boolean async);
+
+/* Connect to the server. First a SecureChannel is opened, then a Session. The
+ * client configuration restricts the SecureChannel selection and contains the
+ * UserIdentityToken for the Session.
+ *
+ * @param client to use
+ * @param endpointURL to connect (for example "opc.tcp://localhost:4840")
+ * @return Indicates whether the operation succeeded or returns an error code */
+static UA_INLINE UA_StatusCode
+UA_Client_connect(UA_Client *client, const char *endpointUrl) {
+    /* Update the configuration */
+    UA_ClientConfig *cc = UA_Client_getConfig(client);
+    cc->noSession = false; /* Open a Session */
+    UA_String_clear(&cc->endpointUrl);
+    cc->endpointUrl = UA_STRING_ALLOC(endpointUrl);
+
+    /* Connect */
+    return __UA_Client_connect(client, false);
+}
+
+/* Connect async (non-blocking) to the server. After initiating the connection,
+ * call UA_Client_run_iterate repeatedly until the connection is fully
+ * established. You can set a callback to client->config.stateCallback to be
+ * notified when the connection status changes. Or use UA_Client_getState to get
+ * the state manually. */
+static UA_INLINE UA_StatusCode
+UA_Client_connectAsync(UA_Client *client, const char *endpointUrl) {
+    /* Update the configuration */
+    UA_ClientConfig *cc = UA_Client_getConfig(client);
+    cc->noSession = false; /* Open a Session */
+    UA_String_clear(&cc->endpointUrl);
+    cc->endpointUrl = UA_STRING_ALLOC(endpointUrl);
+
+    /* Connect */
+    return __UA_Client_connect(client, true);
+}
+
+/* Connect to the server without creating a session
+ *
+ * @param client to use
+ * @param endpointURL to connect (for example "opc.tcp://localhost:4840")
+ * @return Indicates whether the operation succeeded or returns an error code */
+static UA_INLINE UA_StatusCode
+UA_Client_connectSecureChannel(UA_Client *client, const char *endpointUrl) {
+    /* Update the configuration */
+    UA_ClientConfig *cc = UA_Client_getConfig(client);
+    cc->noSession = true; /* Don't open a Session */
+    UA_String_clear(&cc->endpointUrl);
+    cc->endpointUrl = UA_STRING_ALLOC(endpointUrl);
+
+    /* Connect */
+    return __UA_Client_connect(client, false);
+}
+
+/* Connect async (non-blocking) only the SecureChannel */
+static UA_INLINE UA_StatusCode
+UA_Client_connectSecureChannelAsync(UA_Client *client, const char *endpointUrl) {
+    /* Update the configuration */
+    UA_ClientConfig *cc = UA_Client_getConfig(client);
+    cc->noSession = true; /* Don't open a Session */
+    UA_String_clear(&cc->endpointUrl);
+    cc->endpointUrl = UA_STRING_ALLOC(endpointUrl);
+
+    /* Connect */
+    return __UA_Client_connect(client, false);
+}
+
+/* Connect to the server and create+activate a Session with the given username
+ * and password. This first set the UserIdentityToken in the client config and
+ * then calls the regular connect method. */
+static UA_INLINE UA_StatusCode
+UA_Client_connectUsername(UA_Client *client, const char *endpointUrl,
+                          const char *username, const char *password) {
+    /* Set the user identity token */
+    UA_ClientConfig *cc = UA_Client_getConfig(client);
+    UA_StatusCode res =
+        UA_ClientConfig_setAuthenticationUsername(cc, username, password);
+    if(res != UA_STATUSCODE_GOOD)
+        return res;
+
+    /* Connect */
+    return UA_Client_connect(client, endpointUrl);
+}
+
+/* Sets up a listening socket for incoming reverse connect requests by OPC UA
+ * servers. After the first server has connected, the listening socket is
+ * removed. The client state callback is also used for reverse connect. An
+ * implementation could for example issue a new call to
+ * UA_Client_startListeningForReverseConnect after the server has closed the
+ * connection. If the client is connected to any server while
+ * UA_Client_startListeningForReverseConnect is called, the connection will be
+ * closed.
+ *
+ * The reverse connect is closed by calling the standard disconnect functions
+ * like for a "normal" connection that was initiated by the client. Calling one
+ * of the connect methods will also close the listening socket and the
+ * connection to the remote server. */
+UA_StatusCode
+UA_Client_startListeningForReverseConnect(
+    UA_Client *client, const UA_String *listenHostnames,
+    size_t listenHostnamesLength, UA_UInt16 port);
+
+/* Disconnect and close a connection to the selected server. Disconnection is
+ * always performed async (without blocking). */
+UA_StatusCode UA_THREADSAFE
+UA_Client_disconnect(UA_Client *client);
+
+/* Disconnect async. Run UA_Client_run_iterate until the callback notifies that
+ * all connections are closed. */
+UA_StatusCode UA_THREADSAFE
+UA_Client_disconnectAsync(UA_Client *client);
+
+/* Disconnect the SecureChannel but keep the Session intact (if it exists). */
+UA_StatusCode UA_THREADSAFE
+UA_Client_disconnectSecureChannel(UA_Client *client);
+
+/* Disconnect the SecureChannel but keep the Session intact (if it exists). This
+ * is an async operation. Iterate the client until the SecureChannel was fully
+ * cleaned up. */
+UA_StatusCode UA_THREADSAFE
+UA_Client_disconnectSecureChannelAsync(UA_Client *client);
+
+/* Get the AuthenticationToken and ServerNonce required to activate the current
+ * Session on a different SecureChannel. */
+UA_StatusCode UA_THREADSAFE
+UA_Client_getSessionAuthenticationToken(
+    UA_Client *client, UA_NodeId *authenticationToken, UA_ByteString *serverNonce);
+
+/* Re-activate the current session. A change of prefered locales can be done by
+ * updating the client configuration. */
+UA_StatusCode UA_THREADSAFE
+UA_Client_activateCurrentSession(UA_Client *client);
+
+/* Async version of UA_Client_activateCurrentSession */
+UA_StatusCode UA_THREADSAFE
+UA_Client_activateCurrentSessionAsync(UA_Client *client);
+
+/* Activate an already created Session. This allows a Session to be transferred
+ * from a different client instance. The AuthenticationToken and ServerNonce
+ * must be provided for this. Both can be retrieved for an activated Session
+ * with UA_Client_getSessionAuthenticationToken.
+ *
+ * The UserIdentityToken used for authentication must be identical to the
+ * original activation of the Session. The UserIdentityToken is set in the
+ * client configuration.
+ *
+ * Note the noNewSession option if there should not be a new Session
+ * automatically created when this one closes. */
+UA_StatusCode UA_THREADSAFE
+UA_Client_activateSession(UA_Client *client,
+                          const UA_NodeId authenticationToken,
+                          const UA_ByteString serverNonce);
+
+/* Async version of UA_Client_activateSession */
+UA_StatusCode UA_THREADSAFE
+UA_Client_activateSessionAsync(UA_Client *client,
+                               const UA_NodeId authenticationToken,
+                               const UA_ByteString serverNonce);
+
+
+
+
+

Discovery

+
/* Gets a list of endpoints of a server
+ *
+ * @param client to use. Must be connected to the same endpoint given in
+ *        serverUrl or otherwise in disconnected state.
+ * @param serverUrl url to connect (for example "opc.tcp://localhost:4840")
+ * @param endpointDescriptionsSize size of the array of endpoint descriptions
+ * @param endpointDescriptions array of endpoint descriptions that is allocated
+ *        by the function (you need to free manually)
+ * @return Indicates whether the operation succeeded or returns an error code */
+UA_StatusCode UA_THREADSAFE
+UA_Client_getEndpoints(UA_Client *client, const char *serverUrl,
+                       size_t* endpointDescriptionsSize,
+                       UA_EndpointDescription** endpointDescriptions);
+
+/* Gets a list of all registered servers at the given server.
+ *
+ * You can pass an optional filter for serverUris. If the given server is not
+ * registered, an empty array will be returned. If the server is registered,
+ * only that application description will be returned.
+ *
+ * Additionally you can optionally indicate which locale you want for the server
+ * name in the returned application description. The array indicates the order
+ * of preference. A server may have localized names.
+ *
+ * @param client to use. Must be connected to the same endpoint given in
+ *        serverUrl or otherwise in disconnected state.
+ * @param serverUrl url to connect (for example "opc.tcp://localhost:4840")
+ * @param serverUrisSize Optional filter for specific server uris
+ * @param serverUris Optional filter for specific server uris
+ * @param localeIdsSize Optional indication which locale you prefer
+ * @param localeIds Optional indication which locale you prefer
+ * @param registeredServersSize size of returned array, i.e., number of
+ *        found/registered servers
+ * @param registeredServers array containing found/registered servers
+ * @return Indicates whether the operation succeeded or returns an error code */
+UA_StatusCode UA_THREADSAFE
+UA_Client_findServers(UA_Client *client, const char *serverUrl,
+                      size_t serverUrisSize, UA_String *serverUris,
+                      size_t localeIdsSize, UA_String *localeIds,
+                      size_t *registeredServersSize,
+                      UA_ApplicationDescription **registeredServers);
+
+/* Get a list of all known server in the network. Only supported by LDS servers.
+ *
+ * @param client to use. Must be connected to the same endpoint given in
+ * serverUrl or otherwise in disconnected state.
+ * @param serverUrl url to connect (for example "opc.tcp://localhost:4840")
+ * @param startingRecordId optional. Only return the records with an ID higher
+ *        or equal the given. Can be used for pagination to only get a subset of
+ *        the full list
+ * @param maxRecordsToReturn optional. Only return this number of records
+
+ * @param serverCapabilityFilterSize optional. Filter the returned list to only
+ *        get servers with given capabilities, e.g. "LDS"
+ * @param serverCapabilityFilter optional. Filter the returned list to only get
+ *        servers with given capabilities, e.g. "LDS"
+ * @param serverOnNetworkSize size of returned array, i.e., number of
+ *        known/registered servers
+ * @param serverOnNetwork array containing known/registered servers
+ * @return Indicates whether the operation succeeded or returns an error code */
+UA_StatusCode UA_THREADSAFE
+UA_Client_findServersOnNetwork(UA_Client *client, const char *serverUrl,
+                               UA_UInt32 startingRecordId,
+                               UA_UInt32 maxRecordsToReturn,
+                               size_t serverCapabilityFilterSize,
+                               UA_String *serverCapabilityFilter,
+                               size_t *serverOnNetworkSize,
+                               UA_ServerOnNetwork **serverOnNetwork);
+
+
+
+
+

Services

+

The raw OPC UA services are exposed to the client. But most of the time, it +is better to use the convenience functions from ua_client_highlevel.h +that wrap the raw services.

+
/* Don't use this function. Use the type versions below instead. */
+void UA_THREADSAFE
+__UA_Client_Service(UA_Client *client, const void *request,
+                    const UA_DataType *requestType, void *response,
+                    const UA_DataType *responseType);
+
+/*
+ * Attribute Service Set
+ * ^^^^^^^^^^^^^^^^^^^^^ */
+static UA_INLINE UA_THREADSAFE UA_ReadResponse
+UA_Client_Service_read(UA_Client *client, const UA_ReadRequest request) {
+    UA_ReadResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_READREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_READRESPONSE]);
+    return response;
+}
+
+static UA_INLINE UA_THREADSAFE UA_WriteResponse
+UA_Client_Service_write(UA_Client *client, const UA_WriteRequest request) {
+    UA_WriteResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_WRITEREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_WRITERESPONSE]);
+    return response;
+}
+
+/*
+ * Historical Access Service Set
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
+static UA_INLINE UA_THREADSAFE UA_HistoryReadResponse
+UA_Client_Service_historyRead(UA_Client *client,
+                              const UA_HistoryReadRequest request) {
+    UA_HistoryReadResponse response;
+    __UA_Client_Service(
+        client, &request, &UA_TYPES[UA_TYPES_HISTORYREADREQUEST],
+        &response, &UA_TYPES[UA_TYPES_HISTORYREADRESPONSE]);
+    return response;
+}
+
+static UA_INLINE UA_THREADSAFE UA_HistoryUpdateResponse
+UA_Client_Service_historyUpdate(UA_Client *client,
+                                const UA_HistoryUpdateRequest request) {
+    UA_HistoryUpdateResponse response;
+    __UA_Client_Service(
+        client, &request, &UA_TYPES[UA_TYPES_HISTORYUPDATEREQUEST],
+        &response, &UA_TYPES[UA_TYPES_HISTORYUPDATERESPONSE]);
+    return response;
+}
+
+/*
+ * Method Service Set
+ * ^^^^^^^^^^^^^^^^^^ */
+static UA_INLINE UA_THREADSAFE UA_CallResponse
+UA_Client_Service_call(UA_Client *client,
+                       const UA_CallRequest request) {
+    UA_CallResponse response;
+    __UA_Client_Service(
+        client, &request, &UA_TYPES[UA_TYPES_CALLREQUEST],
+        &response, &UA_TYPES[UA_TYPES_CALLRESPONSE]);
+    return response;
+}
+
+/*
+ * NodeManagement Service Set
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ */
+static UA_INLINE UA_THREADSAFE UA_AddNodesResponse
+UA_Client_Service_addNodes(UA_Client *client,
+                           const UA_AddNodesRequest request) {
+    UA_AddNodesResponse response;
+    __UA_Client_Service(
+        client, &request, &UA_TYPES[UA_TYPES_ADDNODESREQUEST],
+        &response, &UA_TYPES[UA_TYPES_ADDNODESRESPONSE]);
+    return response;
+}
+
+static UA_INLINE UA_THREADSAFE UA_AddReferencesResponse
+UA_Client_Service_addReferences(UA_Client *client,
+                                const UA_AddReferencesRequest request) {
+    UA_AddReferencesResponse response;
+    __UA_Client_Service(
+        client, &request, &UA_TYPES[UA_TYPES_ADDREFERENCESREQUEST],
+        &response, &UA_TYPES[UA_TYPES_ADDREFERENCESRESPONSE]);
+    return response;
+}
+
+static UA_INLINE UA_THREADSAFE UA_DeleteNodesResponse
+UA_Client_Service_deleteNodes(UA_Client *client,
+                              const UA_DeleteNodesRequest request) {
+    UA_DeleteNodesResponse response;
+    __UA_Client_Service(
+        client, &request, &UA_TYPES[UA_TYPES_DELETENODESREQUEST],
+        &response, &UA_TYPES[UA_TYPES_DELETENODESRESPONSE]);
+    return response;
+}
+
+static UA_INLINE UA_THREADSAFE UA_DeleteReferencesResponse
+UA_Client_Service_deleteReferences(
+    UA_Client *client, const UA_DeleteReferencesRequest request) {
+    UA_DeleteReferencesResponse response;
+    __UA_Client_Service(
+        client, &request, &UA_TYPES[UA_TYPES_DELETEREFERENCESREQUEST],
+        &response, &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE]);
+    return response;
+}
+
+/*
+ * View Service Set
+ * ^^^^^^^^^^^^^^^^ */
+static UA_INLINE UA_THREADSAFE UA_BrowseResponse
+UA_Client_Service_browse(UA_Client *client,
+                         const UA_BrowseRequest request) {
+    UA_BrowseResponse response;
+    __UA_Client_Service(
+        client, &request, &UA_TYPES[UA_TYPES_BROWSEREQUEST],
+        &response, &UA_TYPES[UA_TYPES_BROWSERESPONSE]);
+    return response;
+}
+
+static UA_INLINE UA_THREADSAFE UA_BrowseNextResponse
+UA_Client_Service_browseNext(UA_Client *client,
+                             const UA_BrowseNextRequest request) {
+    UA_BrowseNextResponse response;
+    __UA_Client_Service(
+        client, &request, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST],
+        &response, &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE]);
+    return response;
+}
+
+static UA_INLINE UA_THREADSAFE UA_TranslateBrowsePathsToNodeIdsResponse
+UA_Client_Service_translateBrowsePathsToNodeIds(
+    UA_Client *client,
+    const UA_TranslateBrowsePathsToNodeIdsRequest request) {
+    UA_TranslateBrowsePathsToNodeIdsResponse response;
+    __UA_Client_Service(
+        client, &request,
+        &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST],
+        &response,
+        &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE]);
+    return response;
+}
+
+static UA_INLINE UA_THREADSAFE UA_RegisterNodesResponse
+UA_Client_Service_registerNodes(UA_Client *client,
+                                const UA_RegisterNodesRequest request) {
+    UA_RegisterNodesResponse response;
+    __UA_Client_Service(
+        client, &request, &UA_TYPES[UA_TYPES_REGISTERNODESREQUEST],
+        &response, &UA_TYPES[UA_TYPES_REGISTERNODESRESPONSE]);
+    return response;
+}
+
+static UA_INLINE UA_THREADSAFE UA_UnregisterNodesResponse
+UA_Client_Service_unregisterNodes(
+    UA_Client *client, const UA_UnregisterNodesRequest request) {
+    UA_UnregisterNodesResponse response;
+    __UA_Client_Service(
+        client, &request, &UA_TYPES[UA_TYPES_UNREGISTERNODESREQUEST],
+        &response, &UA_TYPES[UA_TYPES_UNREGISTERNODESRESPONSE]);
+    return response;
+}
+
+/*
+ * Query Service Set
+ * ^^^^^^^^^^^^^^^^^ */
+#ifdef UA_ENABLE_QUERY
+
+static UA_INLINE UA_THREADSAFE UA_QueryFirstResponse
+UA_Client_Service_queryFirst(UA_Client *client,
+                             const UA_QueryFirstRequest request) {
+    UA_QueryFirstResponse response;
+    __UA_Client_Service(
+        client, &request, &UA_TYPES[UA_TYPES_QUERYFIRSTREQUEST],
+        &response, &UA_TYPES[UA_TYPES_QUERYFIRSTRESPONSE]);
+    return response;
+}
+
+static UA_INLINE UA_THREADSAFE UA_QueryNextResponse
+UA_Client_Service_queryNext(UA_Client *client,
+                            const UA_QueryNextRequest request) {
+    UA_QueryNextResponse response;
+    __UA_Client_Service(
+        client, &request, &UA_TYPES[UA_TYPES_QUERYFIRSTREQUEST],
+        &response, &UA_TYPES[UA_TYPES_QUERYFIRSTRESPONSE]);
+    return response;
+}
+
+#endif
+
+
+
+
+

Asynchronous Services

+

All OPC UA services are asynchronous in nature. So several service calls can +be made without waiting for the individual responses. Depending on the +server’s priorities responses may come in a different ordering than sent. Use +the typed wrappers for async service requests instead of +__UA_Client_AsyncService directly. See Async Services. However, the +general mechanism of async service calls is explained here.

+

Connection and session management are performed in UA_Client_run_iterate, +so to keep a connection healthy any client needs to consider how and when it +is appropriate to do the call. This is especially true for the periodic +renewal of a SecureChannel’s SecurityToken which is designed to have a +limited lifetime and will invalidate the connection if not renewed.

+

We say that an async service call has been dispatched once +__UA_Client_AsyncService returns UA_STATUSCODE_GOOD. If there is an error +after an async service has been dispatched, the callback is called with an +“empty” response where the StatusCode has been set accordingly. This is also +done if the client is shutting down and the list of dispatched async services +is emptied.

+

The StatusCode received when the client is shutting down is +UA_STATUSCODE_BADSHUTDOWN. The StatusCode received when the client doesn’t +receive response after the specified in config->timeout (can be overridden +via the “timeoutHint” in the request header) is UA_STATUSCODE_BADTIMEOUT.

+

The userdata and requestId arguments can be NULL. The (optional) requestId +output can be used to cancel the service while it is still pending. The +requestId is unique for each service request. Alternatively the requestHandle +can be manually set (non necessarily unique) in the request header for full +service call. This can be used to cancel all outstanding requests using that +handle together. Note that the client will auto-generate a requestHandle +>100,000 if none is defined. Avoid these when manually setting a requetHandle +in the requestHeader to avoid clashes.

+
typedef void
+(*UA_ClientAsyncServiceCallback)(UA_Client *client, void *userdata,
+                                 UA_UInt32 requestId, void *response);
+
+UA_StatusCode UA_THREADSAFE
+__UA_Client_AsyncService(UA_Client *client, const void *request,
+                         const UA_DataType *requestType,
+                         UA_ClientAsyncServiceCallback callback,
+                         const UA_DataType *responseType,
+                         void *userdata, UA_UInt32 *requestId);
+
+/* Cancel all dispatched requests with the given requestHandle.
+ * The number if cancelled requests is returned by the server.
+ * The output argument cancelCount is not set if NULL. */
+UA_THREADSAFE UA_StatusCode
+UA_Client_cancelByRequestHandle(UA_Client *client, UA_UInt32 requestHandle,
+                                UA_UInt32 *cancelCount);
+
+/* Map the requestId to the requestHandle used for that request and call the
+ * Cancel service for that requestHandle. */
+UA_THREADSAFE UA_StatusCode
+UA_Client_cancelByRequestId(UA_Client *client, UA_UInt32 requestId,
+                            UA_UInt32 *cancelCount);
+
+/* Set new userdata and callback for an existing request.
+ *
+ * @param client Pointer to the UA_Client
+ * @param requestId RequestId of the request, which was returned by
+ *        __UA_Client_AsyncService before
+ * @param userdata The new userdata
+ * @param callback The new callback
+ * @return UA_StatusCode UA_STATUSCODE_GOOD on success
+ *         UA_STATUSCODE_BADNOTFOUND when no request with requestId is found. */
+UA_StatusCode UA_THREADSAFE
+UA_Client_modifyAsyncCallback(UA_Client *client, UA_UInt32 requestId,
+                              void *userdata, UA_ClientAsyncServiceCallback callback);
+
+/* Listen on the network and process arriving asynchronous responses in the
+ * background. Internal housekeeping, renewal of SecureChannels and subscription
+ * management is done as well. */
+UA_StatusCode UA_THREADSAFE
+UA_Client_run_iterate(UA_Client *client, UA_UInt32 timeout);
+
+/* Force the manual renewal of the SecureChannel. This is useful to renew the
+ * SecureChannel during a downtime when no time-critical operations are
+ * performed. This method is asynchronous. The renewal is triggered (the OPN
+ * message is sent) but not completed. The OPN response is handled with
+ * ``UA_Client_run_iterate`` or a synchronous service-call operation.
+ *
+ * @return The return value is UA_STATUSCODE_GOODCALLAGAIN if the SecureChannel
+ *         has not elapsed at least 75% of its lifetime. Otherwise the
+ *         ``connectStatus`` is returned. */
+UA_StatusCode UA_THREADSAFE
+UA_Client_renewSecureChannel(UA_Client *client);
+
+
+
+
+

Timed Callbacks

+

Repeated callbacks can be attached to a client and will be executed in the +defined interval.

+
typedef void (*UA_ClientCallback)(UA_Client *client, void *data);
+
+/* Add a callback for execution at a specified time. If the indicated time lies
+ * in the past, then the callback is executed at the next iteration of the
+ * server's main loop.
+ *
+ * @param client The client object.
+ * @param callback The callback that shall be added.
+ * @param data Data that is forwarded to the callback.
+ * @param date The timestamp for the execution time.
+ * @param callbackId Set to the identifier of the repeated callback. This can
+ *        be used to cancel the callback later on. If the pointer is null, the
+ *        identifier is not set.
+ * @return Upon success, UA_STATUSCODE_GOOD is returned. An error code
+ *         otherwise. */
+UA_StatusCode UA_THREADSAFE
+UA_Client_addTimedCallback(UA_Client *client, UA_ClientCallback callback,
+                           void *data, UA_DateTime date, UA_UInt64 *callbackId);
+
+/* Add a callback for cyclic repetition to the client.
+ *
+ * @param client The client object.
+ * @param callback The callback that shall be added.
+ * @param data Data that is forwarded to the callback.
+ * @param interval_ms The callback shall be repeatedly executed with the given
+ *        interval (in ms). The interval must be positive. The first execution
+ *        occurs at now() + interval at the latest.
+ * @param callbackId Set to the identifier of the repeated callback. This can
+ *        be used to cancel the callback later on. If the pointer is null, the
+ *        identifier is not set.
+ * @return Upon success, UA_STATUSCODE_GOOD is returned. An error code
+ *         otherwise. */
+UA_StatusCode UA_THREADSAFE
+UA_Client_addRepeatedCallback(UA_Client *client, UA_ClientCallback callback,
+                              void *data, UA_Double interval_ms,
+                              UA_UInt64 *callbackId);
+
+UA_StatusCode UA_THREADSAFE
+UA_Client_changeRepeatedCallbackInterval(UA_Client *client,
+                                         UA_UInt64 callbackId,
+                                         UA_Double interval_ms);
+
+void UA_THREADSAFE
+UA_Client_removeCallback(UA_Client *client, UA_UInt64 callbackId);
+
+#define UA_Client_removeRepeatedCallback(server, callbackId)    \
+    UA_Client_removeCallback(server, callbackId);
+
+
+
+
+

Client Utility Functions

+
/* Lookup a datatype by its NodeId. Takes the custom types in the client
+ * configuration into account. Return NULL if none found. */
+const UA_DataType *
+UA_Client_findDataType(UA_Client *client, const UA_NodeId *typeId);
+
+
+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/client_highlevel.html b/static/doc/v1.4.0/client_highlevel.html new file mode 100644 index 0000000000..dee2d490d1 --- /dev/null +++ b/static/doc/v1.4.0/client_highlevel.html @@ -0,0 +1,788 @@ + + + + + + + Highlevel Client Functionality — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Highlevel Client Functionality

+

The following definitions are convenience functions making use of the +standard OPC UA services in the background. This is a less flexible way of +handling the stack, because at many places sensible defaults are presumed; at +the same time using these functions is the easiest way of implementing an OPC +UA application, as you will not have to consider all the details that go into +the OPC UA services. If more flexibility is needed, you can always achieve +the same functionality using the raw OPC UA services.

+
+

Read Attributes

+

The following functions can be used to retrieve a single node attribute. Use +the regular service to read several attributes at once.

+
/* Don't call this function, use the typed versions */
+UA_StatusCode
+__UA_Client_readAttribute(UA_Client *client, const UA_NodeId *nodeId,
+                          UA_AttributeId attributeId, void *out,
+                          const UA_DataType *outDataType);
+
+static UA_INLINE UA_StatusCode
+UA_Client_readNodeIdAttribute(UA_Client *client, const UA_NodeId nodeId,
+                              UA_NodeId *outNodeId) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_NODEID,
+                                     outNodeId, &UA_TYPES[UA_TYPES_NODEID]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readNodeClassAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                 UA_NodeClass *outNodeClass) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_NODECLASS,
+                                     outNodeClass, &UA_TYPES[UA_TYPES_NODECLASS]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readBrowseNameAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                  UA_QualifiedName *outBrowseName) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_BROWSENAME,
+                                     outBrowseName,
+                                     &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readDisplayNameAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                   UA_LocalizedText *outDisplayName) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME,
+                                     outDisplayName,
+                                     &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readDescriptionAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                   UA_LocalizedText *outDescription) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION,
+                                     outDescription,
+                                     &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                 UA_UInt32 *outWriteMask) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_WRITEMASK,
+                                     outWriteMask, &UA_TYPES[UA_TYPES_UINT32]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readUserWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                     UA_UInt32 *outUserWriteMask) {
+    return __UA_Client_readAttribute(client, &nodeId,
+                                     UA_ATTRIBUTEID_USERWRITEMASK,
+                                     outUserWriteMask,
+                                     &UA_TYPES[UA_TYPES_UINT32]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readIsAbstractAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                  UA_Boolean *outIsAbstract) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT,
+                                     outIsAbstract, &UA_TYPES[UA_TYPES_BOOLEAN]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readSymmetricAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                 UA_Boolean *outSymmetric) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC,
+                                     outSymmetric, &UA_TYPES[UA_TYPES_BOOLEAN]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readInverseNameAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                   UA_LocalizedText *outInverseName) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_INVERSENAME,
+                                     outInverseName,
+                                     &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readContainsNoLoopsAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                       UA_Boolean *outContainsNoLoops) {
+    return __UA_Client_readAttribute(client, &nodeId,
+                                     UA_ATTRIBUTEID_CONTAINSNOLOOPS,
+                                     outContainsNoLoops,
+                                     &UA_TYPES[UA_TYPES_BOOLEAN]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readEventNotifierAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                     UA_Byte *outEventNotifier) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER,
+                                     outEventNotifier, &UA_TYPES[UA_TYPES_BYTE]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readValueAttribute(UA_Client *client, const UA_NodeId nodeId,
+                             UA_Variant *outValue) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE,
+                                     outValue, &UA_TYPES[UA_TYPES_VARIANT]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readDataTypeAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                UA_NodeId *outDataType) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DATATYPE,
+                                     outDataType, &UA_TYPES[UA_TYPES_NODEID]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readValueRankAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                 UA_Int32 *outValueRank) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUERANK,
+                                     outValueRank, &UA_TYPES[UA_TYPES_INT32]);
+}
+
+UA_StatusCode
+UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                       size_t *outArrayDimensionsSize,
+                                       UA_UInt32 **outArrayDimensions);
+
+static UA_INLINE UA_StatusCode
+UA_Client_readAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                   UA_Byte *outAccessLevel) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL,
+                                     outAccessLevel, &UA_TYPES[UA_TYPES_BYTE]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readAccessLevelExAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                     UA_UInt32 *outAccessLevelEx) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX,
+                                     outAccessLevelEx, &UA_TYPES[UA_TYPES_UINT32]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readUserAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                       UA_Byte *outUserAccessLevel) {
+    return __UA_Client_readAttribute(client, &nodeId,
+                                     UA_ATTRIBUTEID_USERACCESSLEVEL,
+                                     outUserAccessLevel,
+                                     &UA_TYPES[UA_TYPES_BYTE]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readMinimumSamplingIntervalAttribute(UA_Client *client,
+                                               const UA_NodeId nodeId,
+                                               UA_Double *outMinSamplingInterval) {
+    return __UA_Client_readAttribute(client, &nodeId,
+                                     UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
+                                     outMinSamplingInterval,
+                                     &UA_TYPES[UA_TYPES_DOUBLE]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readHistorizingAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                   UA_Boolean *outHistorizing) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_HISTORIZING,
+                                     outHistorizing, &UA_TYPES[UA_TYPES_BOOLEAN]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readExecutableAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                  UA_Boolean *outExecutable) {
+    return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE,
+                                     outExecutable, &UA_TYPES[UA_TYPES_BOOLEAN]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_readUserExecutableAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                      UA_Boolean *outUserExecutable) {
+    return __UA_Client_readAttribute(client, &nodeId,
+                                     UA_ATTRIBUTEID_USEREXECUTABLE,
+                                     outUserExecutable,
+                                     &UA_TYPES[UA_TYPES_BOOLEAN]);
+}
+
+
+
+
+

Historical Access

+

The following functions can be used to read a single node historically. +Use the regular service to read several nodes at once.

+
typedef UA_Boolean
+(*UA_HistoricalIteratorCallback)(
+    UA_Client *client, const UA_NodeId *nodeId, UA_Boolean moreDataAvailable,
+    const UA_ExtensionObject *data, void *callbackContext);
+
+UA_StatusCode
+UA_Client_HistoryRead_events(
+    UA_Client *client, const UA_NodeId *nodeId,
+    const UA_HistoricalIteratorCallback callback, UA_DateTime startTime,
+    UA_DateTime endTime, UA_String indexRange, const UA_EventFilter filter,
+    UA_UInt32 numValuesPerNode, UA_TimestampsToReturn timestampsToReturn,
+    void *callbackContext);
+
+UA_StatusCode
+UA_Client_HistoryRead_raw(
+    UA_Client *client, const UA_NodeId *nodeId,
+    const UA_HistoricalIteratorCallback callback, UA_DateTime startTime,
+    UA_DateTime endTime, UA_String indexRange, UA_Boolean returnBounds,
+    UA_UInt32 numValuesPerNode, UA_TimestampsToReturn timestampsToReturn,
+    void *callbackContext);
+
+UA_StatusCode
+UA_Client_HistoryRead_modified(
+    UA_Client *client, const UA_NodeId *nodeId,
+    const UA_HistoricalIteratorCallback callback, UA_DateTime startTime,
+    UA_DateTime endTime, UA_String indexRange, UA_Boolean returnBounds,
+    UA_UInt32 numValuesPerNode, UA_TimestampsToReturn timestampsToReturn,
+    void *callbackContext);
+
+UA_StatusCode
+UA_Client_HistoryUpdate_insert(
+    UA_Client *client, const UA_NodeId *nodeId, UA_DataValue *value);
+
+UA_StatusCode
+UA_Client_HistoryUpdate_replace(
+    UA_Client *client, const UA_NodeId *nodeId, UA_DataValue *value);
+
+UA_StatusCode
+UA_Client_HistoryUpdate_update(
+    UA_Client *client, const UA_NodeId *nodeId, UA_DataValue *value);
+
+UA_StatusCode
+UA_Client_HistoryUpdate_deleteRaw(
+    UA_Client *client, const UA_NodeId *nodeId,
+    UA_DateTime startTimestamp, UA_DateTime endTimestamp);
+
+
+
+
+

Write Attributes

+

The following functions can be use to write a single node attribute at a +time. Use the regular write service to write several attributes at once.

+
/* Don't call this function, use the typed versions */
+UA_StatusCode
+__UA_Client_writeAttribute(UA_Client *client, const UA_NodeId *nodeId,
+                           UA_AttributeId attributeId, const void *in,
+                           const UA_DataType *inDataType);
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeNodeIdAttribute(UA_Client *client, const UA_NodeId nodeId,
+                               const UA_NodeId *newNodeId) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_NODEID,
+                                      newNodeId, &UA_TYPES[UA_TYPES_NODEID]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeNodeClassAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                  const UA_NodeClass *newNodeClass) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_NODECLASS,
+                                      newNodeClass, &UA_TYPES[UA_TYPES_NODECLASS]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeBrowseNameAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                   const UA_QualifiedName *newBrowseName) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_BROWSENAME,
+                                      newBrowseName,
+                                      &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeDisplayNameAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                    const UA_LocalizedText *newDisplayName) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME,
+                                      newDisplayName,
+                                      &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeDescriptionAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                    const UA_LocalizedText *newDescription) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION,
+                                      newDescription,
+                                      &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                  const UA_UInt32 *newWriteMask) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_WRITEMASK,
+                                      newWriteMask, &UA_TYPES[UA_TYPES_UINT32]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeUserWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                      const UA_UInt32 *newUserWriteMask) {
+    return __UA_Client_writeAttribute(client, &nodeId,
+                                      UA_ATTRIBUTEID_USERWRITEMASK,
+                                      newUserWriteMask,
+                                      &UA_TYPES[UA_TYPES_UINT32]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeIsAbstractAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                   const UA_Boolean *newIsAbstract) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT,
+                                      newIsAbstract, &UA_TYPES[UA_TYPES_BOOLEAN]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeSymmetricAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                  const UA_Boolean *newSymmetric) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC,
+                                      newSymmetric, &UA_TYPES[UA_TYPES_BOOLEAN]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeInverseNameAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                    const UA_LocalizedText *newInverseName) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_INVERSENAME,
+                                      newInverseName,
+                                      &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeContainsNoLoopsAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                        const UA_Boolean *newContainsNoLoops) {
+    return __UA_Client_writeAttribute(client, &nodeId,
+                                      UA_ATTRIBUTEID_CONTAINSNOLOOPS,
+                                      newContainsNoLoops,
+                                      &UA_TYPES[UA_TYPES_BOOLEAN]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeEventNotifierAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                      const UA_Byte *newEventNotifier) {
+    return __UA_Client_writeAttribute(client, &nodeId,
+                                      UA_ATTRIBUTEID_EVENTNOTIFIER,
+                                      newEventNotifier,
+                                      &UA_TYPES[UA_TYPES_BYTE]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeValueAttribute(UA_Client *client, const UA_NodeId nodeId,
+                              const UA_Variant *newValue) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE,
+                                      newValue, &UA_TYPES[UA_TYPES_VARIANT]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeValueAttribute_scalar(UA_Client *client, const UA_NodeId nodeId,
+                                     const void *newValue,
+                                     const UA_DataType *valueType) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE,
+                                      newValue, valueType);
+}
+
+/* Write a DataValue that can include timestamps and status codes */
+static UA_INLINE UA_StatusCode
+UA_Client_writeValueAttributeEx(UA_Client *client, const UA_NodeId nodeId,
+                                const UA_DataValue *newValue) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE,
+                                      newValue, &UA_TYPES[UA_TYPES_DATAVALUE]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeDataTypeAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                 const UA_NodeId *newDataType) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_DATATYPE,
+                                      newDataType, &UA_TYPES[UA_TYPES_NODEID]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeValueRankAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                  const UA_Int32 *newValueRank) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUERANK,
+                                      newValueRank, &UA_TYPES[UA_TYPES_INT32]);
+}
+
+UA_StatusCode
+UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                        size_t newArrayDimensionsSize,
+                                        const UA_UInt32 *newArrayDimensions);
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                    const UA_Byte *newAccessLevel) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL,
+                                      newAccessLevel, &UA_TYPES[UA_TYPES_BYTE]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeAccessLevelExAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                      UA_UInt32 *newAccessLevelEx) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX,
+                                      newAccessLevelEx, &UA_TYPES[UA_TYPES_UINT32]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeUserAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                        const UA_Byte *newUserAccessLevel) {
+    return __UA_Client_writeAttribute(client, &nodeId,
+                                      UA_ATTRIBUTEID_USERACCESSLEVEL,
+                                      newUserAccessLevel,
+                                      &UA_TYPES[UA_TYPES_BYTE]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeMinimumSamplingIntervalAttribute(UA_Client *client,
+                                                const UA_NodeId nodeId,
+                                                const UA_Double *newMinInterval) {
+    return __UA_Client_writeAttribute(client, &nodeId,
+                                      UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
+                                      newMinInterval, &UA_TYPES[UA_TYPES_DOUBLE]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeHistorizingAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                    const UA_Boolean *newHistorizing) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_HISTORIZING,
+                                      newHistorizing, &UA_TYPES[UA_TYPES_BOOLEAN]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeExecutableAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                   const UA_Boolean *newExecutable) {
+    return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE,
+                                      newExecutable, &UA_TYPES[UA_TYPES_BOOLEAN]);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeUserExecutableAttribute(UA_Client *client, const UA_NodeId nodeId,
+                                       const UA_Boolean *newUserExecutable) {
+    return __UA_Client_writeAttribute(client, &nodeId,
+                                      UA_ATTRIBUTEID_USEREXECUTABLE,
+                                      newUserExecutable,
+                                      &UA_TYPES[UA_TYPES_BOOLEAN]);
+}
+
+
+
+
+

Method Calling

+
UA_StatusCode
+UA_Client_call(UA_Client *client,
+               const UA_NodeId objectId, const UA_NodeId methodId,
+               size_t inputSize, const UA_Variant *input,
+               size_t *outputSize, UA_Variant **output);
+
+
+
+
+

Node Management

+

See the section on server-side node management.

+
UA_StatusCode
+UA_Client_addReference(UA_Client *client, const UA_NodeId sourceNodeId,
+                       const UA_NodeId referenceTypeId, UA_Boolean isForward,
+                       const UA_String targetServerUri,
+                       const UA_ExpandedNodeId targetNodeId,
+                       UA_NodeClass targetNodeClass);
+
+UA_StatusCode
+UA_Client_deleteReference(UA_Client *client, const UA_NodeId sourceNodeId,
+                          const UA_NodeId referenceTypeId, UA_Boolean isForward,
+                          const UA_ExpandedNodeId targetNodeId,
+                          UA_Boolean deleteBidirectional);
+
+UA_StatusCode
+UA_Client_deleteNode(UA_Client *client, const UA_NodeId nodeId,
+                     UA_Boolean deleteTargetReferences);
+
+/* Don't call this function, use the typed versions */
+UA_StatusCode
+__UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass,
+                    const UA_NodeId requestedNewNodeId,
+                    const UA_NodeId parentNodeId,
+                    const UA_NodeId referenceTypeId,
+                    const UA_QualifiedName browseName,
+                    const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
+                    const UA_DataType *attributeType, UA_NodeId *outNewNodeId);
+
+static UA_INLINE UA_StatusCode
+UA_Client_addVariableNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
+                          const UA_NodeId parentNodeId,
+                          const UA_NodeId referenceTypeId,
+                          const UA_QualifiedName browseName,
+                          const UA_NodeId typeDefinition,
+                          const UA_VariableAttributes attr,
+                          UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_VARIABLE, requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName,
+                               typeDefinition, (const UA_NodeAttributes*)&attr,
+                               &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
+                               outNewNodeId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_addVariableTypeNode(UA_Client *client,
+                              const UA_NodeId requestedNewNodeId,
+                              const UA_NodeId parentNodeId,
+                              const UA_NodeId referenceTypeId,
+                              const UA_QualifiedName browseName,
+                              const UA_VariableTypeAttributes attr,
+                              UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_VARIABLETYPE,
+                               requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName,
+                               UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                               &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],
+                               outNewNodeId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_addObjectNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
+                        const UA_NodeId parentNodeId,
+                        const UA_NodeId referenceTypeId,
+                        const UA_QualifiedName browseName,
+                        const UA_NodeId typeDefinition,
+                        const UA_ObjectAttributes attr, UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_OBJECT, requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName,
+                               typeDefinition, (const UA_NodeAttributes*)&attr,
+                               &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], outNewNodeId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_addObjectTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
+                            const UA_NodeId parentNodeId,
+                            const UA_NodeId referenceTypeId,
+                            const UA_QualifiedName browseName,
+                            const UA_ObjectTypeAttributes attr,
+                            UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName,
+                               UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                               &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],
+                               outNewNodeId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_addViewNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
+                      const UA_NodeId parentNodeId,
+                      const UA_NodeId referenceTypeId,
+                      const UA_QualifiedName browseName,
+                      const UA_ViewAttributes attr,
+                      UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_VIEW, requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName,
+                               UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                               &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], outNewNodeId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_addReferenceTypeNode(UA_Client *client,
+                               const UA_NodeId requestedNewNodeId,
+                               const UA_NodeId parentNodeId,
+                               const UA_NodeId referenceTypeId,
+                               const UA_QualifiedName browseName,
+                               const UA_ReferenceTypeAttributes attr,
+                               UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_REFERENCETYPE,
+                               requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName,
+                               UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                               &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],
+                               outNewNodeId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_addDataTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
+                          const UA_NodeId parentNodeId,
+                          const UA_NodeId referenceTypeId,
+                          const UA_QualifiedName browseName,
+                          const UA_DataTypeAttributes attr,
+                          UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_DATATYPE, requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName,
+                               UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                               &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],
+                               outNewNodeId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_addMethodNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
+                        const UA_NodeId parentNodeId,
+                        const UA_NodeId referenceTypeId,
+                        const UA_QualifiedName browseName,
+                        const UA_MethodAttributes attr,
+                        UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_METHOD, requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName,
+                               UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                               &UA_TYPES[UA_TYPES_METHODATTRIBUTES], outNewNodeId);
+}
+
+
+
+
+

Misc Highlevel Functionality

+
/* Get the namespace-index of a namespace-URI
+ *
+ * @param client The UA_Client struct for this connection
+ * @param namespaceUri The interested namespace URI
+ * @param namespaceIndex The namespace index of the URI. The value is unchanged
+ *        in case of an error
+ * @return Indicates whether the operation succeeded or returns an error code */
+UA_StatusCode
+UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri,
+                            UA_UInt16 *namespaceIndex);
+
+#ifndef HAVE_NODEITER_CALLBACK
+#define HAVE_NODEITER_CALLBACK
+/* Iterate over all nodes referenced by parentNodeId by calling the callback
+ * function for each child node */
+typedef UA_StatusCode
+(*UA_NodeIteratorCallback)(UA_NodeId childId, UA_Boolean isInverse,
+                           UA_NodeId referenceTypeId, void *handle);
+#endif
+
+UA_StatusCode
+UA_Client_forEachChildNodeCall(
+    UA_Client *client, UA_NodeId parentNodeId,
+    UA_NodeIteratorCallback callback, void *handle);
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/client_highlevel_async.html b/static/doc/v1.4.0/client_highlevel_async.html new file mode 100644 index 0000000000..ca78cdda94 --- /dev/null +++ b/static/doc/v1.4.0/client_highlevel_async.html @@ -0,0 +1,927 @@ + + + + + + + Async Services — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Async Services

+

Call OPC UA Services asynchronously with a callback. The (optional) requestId +output can be used to cancel the service while it is still pending.

+
typedef void
+(*UA_ClientAsyncReadCallback)(
+    UA_Client *client, void *userdata,
+    UA_UInt32 requestId, UA_ReadResponse *rr);
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Client_sendAsyncReadRequest(
+    UA_Client *client, UA_ReadRequest *request,
+    UA_ClientAsyncReadCallback readCallback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_AsyncService(
+        client, request, &UA_TYPES[UA_TYPES_READREQUEST],
+        (UA_ClientAsyncServiceCallback)readCallback,
+        &UA_TYPES[UA_TYPES_READRESPONSE], userdata, reqId);
+}
+
+typedef void
+(*UA_ClientAsyncWriteCallback)(
+    UA_Client *client, void *userdata,
+    UA_UInt32 requestId, UA_WriteResponse *wr);
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Client_sendAsyncWriteRequest(
+    UA_Client *client, UA_WriteRequest *request,
+    UA_ClientAsyncWriteCallback writeCallback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_AsyncService(
+        client, request, &UA_TYPES[UA_TYPES_WRITEREQUEST],
+        (UA_ClientAsyncServiceCallback)writeCallback,
+        &UA_TYPES[UA_TYPES_WRITERESPONSE], userdata, reqId);
+}
+
+typedef void
+(*UA_ClientAsyncBrowseCallback)(
+    UA_Client *client, void *userdata,
+    UA_UInt32 requestId, UA_BrowseResponse *wr);
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Client_sendAsyncBrowseRequest(
+    UA_Client *client, UA_BrowseRequest *request,
+    UA_ClientAsyncBrowseCallback browseCallback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_AsyncService(
+        client, request, &UA_TYPES[UA_TYPES_BROWSEREQUEST],
+        (UA_ClientAsyncServiceCallback)browseCallback,
+        &UA_TYPES[UA_TYPES_BROWSERESPONSE], userdata, reqId);
+}
+
+typedef void
+(*UA_ClientAsyncBrowseNextCallback)(
+    UA_Client *client, void *userdata,
+    UA_UInt32 requestId, UA_BrowseNextResponse *wr);
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Client_sendAsyncBrowseNextRequest(
+    UA_Client *client, UA_BrowseNextRequest *request,
+    UA_ClientAsyncBrowseNextCallback browseNextCallback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_AsyncService(
+        client, request, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST],
+        (UA_ClientAsyncServiceCallback)browseNextCallback,
+        &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE], userdata, reqId);
+}
+
+
+
+
+

Asynchronous Operations

+

Many Services can be called with an array of operations. For example, a +request to the Read Service contains an array of ReadValueId, each +corresponding to a single read operation. For convenience, wrappers are +provided to call single operations for the most common Services.

+

All async operations have a callback of the following structure: The returned +StatusCode is split in two parts. The status indicates the overall success of +the request and the operation. The result argument is non-NULL only if the +status is no good.

+
typedef void
+(*UA_ClientAsyncOperationCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, void *result);
+
+
+
+
+

Read Attribute

+

Asynchronously read a single attribute. The attribute is unpacked from the +response as the datatype of the attribute is known ahead of time. Value +attributes are variants.

+

Note that the last argument (value pointer) of the callbacks can be NULL if +the status of the operation is not good.

+
/* Reading a single attribute */
+typedef void
+(*UA_ClientAsyncReadAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_DataValue *attribute);
+
+UA_StatusCode
+UA_Client_readAttribute_async(
+    UA_Client *client, const UA_ReadValueId *rvi,
+    UA_TimestampsToReturn timestampsToReturn,
+    UA_ClientAsyncReadAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single Value attribute */
+typedef void
+(*UA_ClientAsyncReadValueAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_DataValue *value);
+
+UA_StatusCode
+UA_Client_readValueAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadValueAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single DataType attribute */
+typedef void
+(*UA_ClientAsyncReadDataTypeAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_NodeId *dataType);
+
+UA_StatusCode
+UA_Client_readDataTypeAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadDataTypeAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single ArrayDimensions attribute. If the status is good, the variant
+ * carries an UInt32 array. */
+typedef void
+(*UA_ClientReadArrayDimensionsAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_Variant *arrayDimensions);
+
+UA_StatusCode
+UA_Client_readArrayDimensionsAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientReadArrayDimensionsAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single NodeClass attribute */
+typedef void
+(*UA_ClientAsyncReadNodeClassAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_NodeClass *nodeClass);
+
+UA_StatusCode
+UA_Client_readNodeClassAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadNodeClassAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single BrowseName attribute */
+typedef void
+(*UA_ClientAsyncReadBrowseNameAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_QualifiedName *browseName);
+
+UA_StatusCode
+UA_Client_readBrowseNameAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadBrowseNameAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single DisplayName attribute */
+typedef void
+(*UA_ClientAsyncReadDisplayNameAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_LocalizedText *displayName);
+
+UA_StatusCode
+UA_Client_readDisplayNameAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadDisplayNameAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single Description attribute */
+typedef void
+(*UA_ClientAsyncReadDescriptionAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_LocalizedText *description);
+
+UA_StatusCode
+UA_Client_readDescriptionAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadDescriptionAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single WriteMask attribute */
+typedef void
+(*UA_ClientAsyncReadWriteMaskAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_UInt32 *writeMask);
+
+UA_StatusCode
+UA_Client_readWriteMaskAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadWriteMaskAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single UserWriteMask attribute */
+typedef void
+(*UA_ClientAsyncReadUserWriteMaskAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_UInt32 *writeMask);
+
+UA_StatusCode
+UA_Client_readUserWriteMaskAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadUserWriteMaskAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single IsAbstract attribute */
+typedef void
+(*UA_ClientAsyncReadIsAbstractAttributeCallback)(
+      UA_Client *client, void *userdata, UA_UInt32 requestId,
+      UA_StatusCode status, UA_Boolean *isAbstract);
+
+UA_StatusCode
+UA_Client_readIsAbstractAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadIsAbstractAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single Symmetric attribute */
+typedef void
+(*UA_ClientAsyncReadSymmetricAttributeCallback)(
+      UA_Client *client, void *userdata, UA_UInt32 requestId,
+      UA_StatusCode status, UA_Boolean *symmetric);
+
+UA_StatusCode
+UA_Client_readSymmetricAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadSymmetricAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single InverseName attribute */
+typedef void
+(*UA_ClientAsyncReadInverseNameAttributeCallback)(
+      UA_Client *client, void *userdata, UA_UInt32 requestId,
+      UA_StatusCode status, UA_LocalizedText *inverseName);
+
+UA_StatusCode
+UA_Client_readInverseNameAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadInverseNameAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single ContainsNoLoops attribute */
+typedef void
+(*UA_ClientAsyncReadContainsNoLoopsAttributeCallback)(
+      UA_Client *client, void *userdata, UA_UInt32 requestId,
+      UA_StatusCode status, UA_Boolean *containsNoLoops);
+
+UA_StatusCode
+UA_Client_readContainsNoLoopsAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadContainsNoLoopsAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single EventNotifier attribute */
+typedef void
+(*UA_ClientAsyncReadEventNotifierAttributeCallback)(
+      UA_Client *client, void *userdata, UA_UInt32 requestId,
+      UA_StatusCode status, UA_Byte *eventNotifier);
+
+UA_StatusCode
+UA_Client_readEventNotifierAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadEventNotifierAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single ValueRank attribute */
+typedef void
+(*UA_ClientAsyncReadValueRankAttributeCallback)(
+      UA_Client *client, void *userdata, UA_UInt32 requestId,
+      UA_StatusCode status, UA_Int32 *valueRank);
+
+UA_StatusCode
+UA_Client_readValueRankAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadValueRankAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single AccessLevel attribute */
+typedef void
+(*UA_ClientAsyncReadAccessLevelAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_Byte *accessLevel);
+
+UA_StatusCode
+UA_Client_readAccessLevelAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadAccessLevelAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single AccessLevelEx attribute */
+typedef void
+(*UA_ClientAsyncReadAccessLevelExAttributeCallback)(
+      UA_Client *client, void *userdata, UA_UInt32 requestId,
+      UA_StatusCode status, UA_UInt32 *accessLevelEx);
+
+UA_StatusCode
+UA_Client_readAccessLevelExAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadAccessLevelExAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single UserAccessLevel attribute */
+typedef void
+(*UA_ClientAsyncReadUserAccessLevelAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_Byte *userAccessLevel);
+
+UA_StatusCode
+UA_Client_readUserAccessLevelAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadUserAccessLevelAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single MinimumSamplingInterval attribute */
+typedef void
+(*UA_ClientAsyncReadMinimumSamplingIntervalAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_Double *minimumSamplingInterval);
+
+UA_StatusCode
+UA_Client_readMinimumSamplingIntervalAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadMinimumSamplingIntervalAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single Historizing attribute */
+typedef void
+(*UA_ClientAsyncReadHistorizingAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_Boolean *historizing);
+
+UA_StatusCode
+UA_Client_readHistorizingAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadHistorizingAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single Executable attribute */
+typedef void
+(*UA_ClientAsyncReadExecutableAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_Boolean *executable);
+
+UA_StatusCode
+UA_Client_readExecutableAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadExecutableAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Read a single UserExecutable attribute */
+typedef void
+(*UA_ClientAsyncReadUserExecutableAttributeCallback)(
+    UA_Client *client, void *userdata, UA_UInt32 requestId,
+    UA_StatusCode status, UA_Boolean *userExecutable);
+
+UA_StatusCode
+UA_Client_readUserExecutableAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    UA_ClientAsyncReadUserExecutableAttributeCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+
+
+
+

Write Attribute

+
UA_StatusCode
+__UA_Client_writeAttribute_async(
+    UA_Client *client, const UA_NodeId *nodeId,
+    UA_AttributeId attributeId, const void *in,
+    const UA_DataType *inDataType,
+    UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId);
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeValueAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_Variant *attr, UA_ClientAsyncWriteCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_VALUE, attr,
+        &UA_TYPES[UA_TYPES_VARIANT],
+        (UA_ClientAsyncServiceCallback)callback,
+        userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeNodeIdAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_NodeId *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_NODEID, attr,
+        &UA_TYPES[UA_TYPES_NODEID], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeNodeClassAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_NodeClass *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_NODECLASS, attr,
+        &UA_TYPES[UA_TYPES_NODECLASS], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeBrowseNameAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_QualifiedName *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_BROWSENAME, attr,
+        &UA_TYPES[UA_TYPES_QUALIFIEDNAME], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeDisplayNameAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_LocalizedText *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, attr,
+        &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeDescriptionAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_LocalizedText *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, attr,
+        &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeWriteMaskAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_UInt32 *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_WRITEMASK, attr,
+        &UA_TYPES[UA_TYPES_UINT32], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeUserWriteMaskAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_UInt32 *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_USERWRITEMASK, attr,
+        &UA_TYPES[UA_TYPES_UINT32], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeIsAbstractAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, attr,
+        &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeSymmetricAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC, attr,
+        &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeInverseNameAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_LocalizedText *attr,
+    UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_INVERSENAME, attr,
+        &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeContainsNoLoopsAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, attr,
+        &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeEventNotifierAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_Byte *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, attr,
+        &UA_TYPES[UA_TYPES_BYTE], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeDataTypeAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_NodeId *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_DATATYPE, attr,
+        &UA_TYPES[UA_TYPES_NODEID], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeValueRankAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_Int32 *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_VALUERANK, attr,
+        &UA_TYPES[UA_TYPES_INT32], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeAccessLevelAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_Byte *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, attr,
+        &UA_TYPES[UA_TYPES_BYTE], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeAccessLevelExAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_UInt32 *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX, attr,
+        &UA_TYPES[UA_TYPES_UINT32], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeUserAccessLevelAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_Byte *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_USERACCESSLEVEL, attr,
+        &UA_TYPES[UA_TYPES_BYTE], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeMinimumSamplingIntervalAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_Double *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
+        attr, &UA_TYPES[UA_TYPES_DOUBLE], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeHistorizingAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_HISTORIZING, attr,
+        &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeExecutableAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, attr,
+        &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_writeUserExecutableAttribute_async(
+    UA_Client *client, const UA_NodeId nodeId,
+    const UA_Boolean *attr, UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_writeAttribute_async(
+        client, &nodeId, UA_ATTRIBUTEID_USEREXECUTABLE, attr,
+        &UA_TYPES[UA_TYPES_BOOLEAN], callback, userdata, reqId);
+}
+
+
+
+
+

Method Calling

+
UA_StatusCode
+__UA_Client_call_async(
+    UA_Client *client,
+    const UA_NodeId objectId, const UA_NodeId methodId,
+    size_t inputSize, const UA_Variant *input,
+    UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *reqId);
+
+typedef void
+(*UA_ClientAsyncCallCallback)(
+    UA_Client *client, void *userdata,
+    UA_UInt32 requestId, UA_CallResponse *cr);
+
+static UA_INLINE UA_StatusCode
+UA_Client_call_async(
+    UA_Client *client,
+    const UA_NodeId objectId, const UA_NodeId methodId,
+    size_t inputSize, const UA_Variant *input,
+    UA_ClientAsyncCallCallback callback, void *userdata,
+    UA_UInt32 *reqId) {
+    return __UA_Client_call_async(
+        client, objectId, methodId, inputSize, input,
+        (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
+}
+
+
+
+
+

Node Management

+
typedef void
+(*UA_ClientAsyncAddNodesCallback)(
+    UA_Client *client, void *userdata,
+    UA_UInt32 requestId, UA_AddNodesResponse *ar);
+
+UA_StatusCode
+__UA_Client_addNode_async(
+    UA_Client *client, const UA_NodeClass nodeClass,
+    const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
+    const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
+    const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
+    const UA_DataType *attributeType, UA_NodeId *outNewNodeId,
+    UA_ClientAsyncServiceCallback callback, void *userdata,
+    UA_UInt32 *reqId);
+
+static UA_INLINE UA_StatusCode
+UA_Client_addVariableNode_async(
+    UA_Client *client, const UA_NodeId requestedNewNodeId,
+    const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+    const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
+    const UA_VariableAttributes attr, UA_NodeId *outNewNodeId,
+    UA_ClientAsyncAddNodesCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_addNode_async(
+        client, UA_NODECLASS_VARIABLE, requestedNewNodeId,
+        parentNodeId, referenceTypeId, browseName,
+        typeDefinition, (const UA_NodeAttributes *)&attr,
+        &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], outNewNodeId,
+        (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_addVariableTypeNode_async(
+    UA_Client *client, const UA_NodeId requestedNewNodeId,
+    const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+    const UA_QualifiedName browseName,
+    const UA_VariableTypeAttributes attr,
+    UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_addNode_async(
+        client, UA_NODECLASS_VARIABLETYPE,
+        requestedNewNodeId, parentNodeId,
+        referenceTypeId, browseName, UA_NODEID_NULL,
+        (const UA_NodeAttributes *)&attr,
+        &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],
+        outNewNodeId, (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_addObjectNode_async(
+    UA_Client *client, const UA_NodeId requestedNewNodeId,
+    const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+    const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
+    const UA_ObjectAttributes attr, UA_NodeId *outNewNodeId,
+    UA_ClientAsyncAddNodesCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_addNode_async(
+        client, UA_NODECLASS_OBJECT, requestedNewNodeId,
+        parentNodeId, referenceTypeId,
+        browseName, typeDefinition, (const UA_NodeAttributes *)&attr,
+        &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], outNewNodeId,
+        (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_addObjectTypeNode_async(
+    UA_Client *client, const UA_NodeId requestedNewNodeId,
+    const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+    const UA_QualifiedName browseName,
+    const UA_ObjectTypeAttributes attr,
+    UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_addNode_async(
+        client, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId, parentNodeId,
+        referenceTypeId, browseName, UA_NODEID_NULL,
+        (const UA_NodeAttributes *)&attr,
+        &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], outNewNodeId,
+        (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_addViewNode_async(
+    UA_Client *client, const UA_NodeId requestedNewNodeId,
+    const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+    const UA_QualifiedName browseName, const UA_ViewAttributes attr,
+    UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_addNode_async(
+        client, UA_NODECLASS_VIEW, requestedNewNodeId,
+        parentNodeId, referenceTypeId,
+        browseName, UA_NODEID_NULL, (const UA_NodeAttributes *)&attr,
+        &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], outNewNodeId,
+        (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_addReferenceTypeNode_async(
+    UA_Client *client, const UA_NodeId requestedNewNodeId,
+    const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+    const UA_QualifiedName browseName,
+    const UA_ReferenceTypeAttributes attr,
+    UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_addNode_async(
+        client, UA_NODECLASS_REFERENCETYPE, requestedNewNodeId, parentNodeId,
+        referenceTypeId, browseName, UA_NODEID_NULL,
+        (const UA_NodeAttributes *)&attr,
+        &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], outNewNodeId,
+        (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_addDataTypeNode_async(
+    UA_Client *client, const UA_NodeId requestedNewNodeId,
+    const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+    const UA_QualifiedName browseName, const UA_DataTypeAttributes attr,
+    UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_addNode_async(
+        client, UA_NODECLASS_DATATYPE, requestedNewNodeId,
+        parentNodeId, referenceTypeId, browseName,
+        UA_NODEID_NULL, (const UA_NodeAttributes *)&attr,
+        &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], outNewNodeId,
+        (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_addMethodNode_async(
+    UA_Client *client, const UA_NodeId requestedNewNodeId,
+    const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+    const UA_QualifiedName browseName, const UA_MethodAttributes attr,
+    UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback,
+    void *userdata, UA_UInt32 *reqId) {
+    return __UA_Client_addNode_async(
+        client, UA_NODECLASS_METHOD, requestedNewNodeId, parentNodeId,
+        referenceTypeId, browseName, UA_NODEID_NULL,
+        (const UA_NodeAttributes *)&attr,
+        &UA_TYPES[UA_TYPES_METHODATTRIBUTES], outNewNodeId,
+        (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
+}
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/client_subscriptions.html b/static/doc/v1.4.0/client_subscriptions.html new file mode 100644 index 0000000000..1c9ba5ff57 --- /dev/null +++ b/static/doc/v1.4.0/client_subscriptions.html @@ -0,0 +1,402 @@ + + + + + + + Subscriptions — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Subscriptions

+

Subscriptions in OPC UA are asynchronous. That is, the client sends several +PublishRequests to the server. The server returns PublishResponses with +notifications. But only when a notification has been generated. The client +does not wait for the responses and continues normal operations.

+

Note the difference between Subscriptions and MonitoredItems. Subscriptions +are used to report back notifications. MonitoredItems are used to generate +notifications. Every MonitoredItem is attached to exactly one Subscription. +And a Subscription can contain many MonitoredItems.

+

The client automatically processes PublishResponses (with a callback) in the +background and keeps enough PublishRequests in transit. The PublishResponses +may be recieved during a synchronous service call or in +UA_Client_run_iterate. See more about +asynchronicity.

+
/* Callbacks defined for Subscriptions */
+typedef void (*UA_Client_DeleteSubscriptionCallback)
+    (UA_Client *client, UA_UInt32 subId, void *subContext);
+
+typedef void (*UA_Client_StatusChangeNotificationCallback)
+    (UA_Client *client, UA_UInt32 subId, void *subContext,
+     UA_StatusChangeNotification *notification);
+
+/* Provides default values for a new subscription.
+ *
+ * RequestedPublishingInterval:  500.0 [ms]
+ * RequestedLifetimeCount: 10000
+ * RequestedMaxKeepAliveCount: 10
+ * MaxNotificationsPerPublish: 0 (unlimited)
+ * PublishingEnabled: true
+ * Priority: 0 */
+static UA_INLINE UA_CreateSubscriptionRequest
+UA_CreateSubscriptionRequest_default(void) {
+    UA_CreateSubscriptionRequest request;
+    UA_CreateSubscriptionRequest_init(&request);
+
+    request.requestedPublishingInterval = 500.0;
+    request.requestedLifetimeCount = 10000;
+    request.requestedMaxKeepAliveCount = 10;
+    request.maxNotificationsPerPublish = 0;
+    request.publishingEnabled = true;
+    request.priority = 0;
+    return request;
+}
+
+UA_CreateSubscriptionResponse
+UA_Client_Subscriptions_create(UA_Client *client,
+    const UA_CreateSubscriptionRequest request,
+    void *subscriptionContext,
+    UA_Client_StatusChangeNotificationCallback statusChangeCallback,
+    UA_Client_DeleteSubscriptionCallback deleteCallback);
+
+UA_StatusCode
+UA_Client_Subscriptions_create_async(UA_Client *client,
+    const UA_CreateSubscriptionRequest request,
+    void *subscriptionContext,
+    UA_Client_StatusChangeNotificationCallback statusChangeCallback,
+    UA_Client_DeleteSubscriptionCallback deleteCallback,
+    UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+UA_ModifySubscriptionResponse
+UA_Client_Subscriptions_modify(UA_Client *client,
+    const UA_ModifySubscriptionRequest request);
+
+UA_StatusCode
+UA_Client_Subscriptions_modify_async(UA_Client *client,
+    const UA_ModifySubscriptionRequest request,
+    UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+UA_DeleteSubscriptionsResponse
+UA_Client_Subscriptions_delete(UA_Client *client,
+    const UA_DeleteSubscriptionsRequest request);
+
+UA_StatusCode
+UA_Client_Subscriptions_delete_async(UA_Client *client,
+    const UA_DeleteSubscriptionsRequest request,
+    UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+/* Delete a single subscription */
+UA_StatusCode
+UA_Client_Subscriptions_deleteSingle(UA_Client *client, UA_UInt32 subscriptionId);
+
+static UA_INLINE UA_SetPublishingModeResponse
+UA_Client_Subscriptions_setPublishingMode(UA_Client *client,
+    const UA_SetPublishingModeRequest request) {
+    UA_SetPublishingModeResponse response;
+    __UA_Client_Service(client,
+        &request, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODEREQUEST],
+        &response, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODERESPONSE]);
+    return response;
+}
+
+
+
+
+

MonitoredItems

+

MonitoredItems for Events indicate the EventNotifier attribute. This +indicates to the server not to monitor changes of the attribute, but to +forward Event notifications from that node.

+

During the creation of a MonitoredItem, the server may return changed +adjusted parameters. Check the returned UA_CreateMonitoredItemsResponse +to get the current parameters.

+
/* Provides default values for a new monitored item. */
+static UA_INLINE UA_MonitoredItemCreateRequest
+UA_MonitoredItemCreateRequest_default(UA_NodeId nodeId) {
+    UA_MonitoredItemCreateRequest request;
+    UA_MonitoredItemCreateRequest_init(&request);
+    request.itemToMonitor.nodeId = nodeId;
+    request.itemToMonitor.attributeId = UA_ATTRIBUTEID_VALUE;
+    request.monitoringMode = UA_MONITORINGMODE_REPORTING;
+    request.requestedParameters.samplingInterval = 250;
+    request.requestedParameters.discardOldest = true;
+    request.requestedParameters.queueSize = 1;
+    return request;
+}
+
+
+

The clientHandle parameter cannot be set by the user, any value will be replaced +by the client before sending the request to the server.

+
/* Callback for the deletion of a MonitoredItem */
+typedef void (*UA_Client_DeleteMonitoredItemCallback)
+    (UA_Client *client, UA_UInt32 subId, void *subContext,
+     UA_UInt32 monId, void *monContext);
+
+/* Callback for DataChange notifications */
+typedef void (*UA_Client_DataChangeNotificationCallback)
+    (UA_Client *client, UA_UInt32 subId, void *subContext,
+     UA_UInt32 monId, void *monContext,
+     UA_DataValue *value);
+
+/* Callback for Event notifications */
+typedef void (*UA_Client_EventNotificationCallback)
+    (UA_Client *client, UA_UInt32 subId, void *subContext,
+     UA_UInt32 monId, void *monContext,
+     size_t nEventFields, UA_Variant *eventFields);
+
+/* Don't use to monitor the EventNotifier attribute */
+UA_CreateMonitoredItemsResponse
+UA_Client_MonitoredItems_createDataChanges(UA_Client *client,
+    const UA_CreateMonitoredItemsRequest request, void **contexts,
+    UA_Client_DataChangeNotificationCallback *callbacks,
+    UA_Client_DeleteMonitoredItemCallback *deleteCallbacks);
+
+UA_StatusCode
+UA_Client_MonitoredItems_createDataChanges_async(UA_Client *client,
+    const UA_CreateMonitoredItemsRequest request, void **contexts,
+    UA_Client_DataChangeNotificationCallback *callbacks,
+    UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
+    UA_ClientAsyncServiceCallback createCallback,
+    void *userdata, UA_UInt32 *requestId);
+
+UA_MonitoredItemCreateResult
+UA_Client_MonitoredItems_createDataChange(UA_Client *client,
+    UA_UInt32 subscriptionId,
+    UA_TimestampsToReturn timestampsToReturn,
+    const UA_MonitoredItemCreateRequest item,
+    void *context, UA_Client_DataChangeNotificationCallback callback,
+    UA_Client_DeleteMonitoredItemCallback deleteCallback);
+
+/* Monitor the EventNotifier attribute only */
+UA_CreateMonitoredItemsResponse
+UA_Client_MonitoredItems_createEvents(UA_Client *client,
+    const UA_CreateMonitoredItemsRequest request, void **contexts,
+    UA_Client_EventNotificationCallback *callback,
+    UA_Client_DeleteMonitoredItemCallback *deleteCallback);
+
+/* Monitor the EventNotifier attribute only */
+UA_StatusCode
+UA_Client_MonitoredItems_createEvents_async(UA_Client *client,
+    const UA_CreateMonitoredItemsRequest request, void **contexts,
+    UA_Client_EventNotificationCallback *callbacks,
+    UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
+    UA_ClientAsyncServiceCallback createCallback,
+    void *userdata, UA_UInt32 *requestId);
+
+UA_MonitoredItemCreateResult
+UA_Client_MonitoredItems_createEvent(UA_Client *client,
+    UA_UInt32 subscriptionId,
+    UA_TimestampsToReturn timestampsToReturn,
+    const UA_MonitoredItemCreateRequest item,
+    void *context, UA_Client_EventNotificationCallback callback,
+    UA_Client_DeleteMonitoredItemCallback deleteCallback);
+
+UA_DeleteMonitoredItemsResponse
+UA_Client_MonitoredItems_delete(UA_Client *client,
+    const UA_DeleteMonitoredItemsRequest);
+
+UA_StatusCode
+UA_Client_MonitoredItems_delete_async(UA_Client *client,
+    const UA_DeleteMonitoredItemsRequest request,
+    UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+UA_StatusCode
+UA_Client_MonitoredItems_deleteSingle(UA_Client *client,
+    UA_UInt32 subscriptionId, UA_UInt32 monitoredItemId);
+
+/* The clientHandle parameter will be filled automatically */
+UA_ModifyMonitoredItemsResponse
+UA_Client_MonitoredItems_modify(UA_Client *client,
+    const UA_ModifyMonitoredItemsRequest request);
+
+UA_StatusCode
+UA_Client_MonitoredItems_modify_async(UA_Client *client,
+    const UA_ModifyMonitoredItemsRequest request,
+    UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *requestId);
+
+
+

The following service calls go directly to the server. The MonitoredItem +settings are not stored in the client.

+
static UA_INLINE UA_SetMonitoringModeResponse
+UA_Client_MonitoredItems_setMonitoringMode(UA_Client *client,
+    const UA_SetMonitoringModeRequest request) {
+    UA_SetMonitoringModeResponse response;
+    __UA_Client_Service(client,
+        &request, &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST],
+        &response, &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE]);
+    return response;
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_MonitoredItems_setMonitoringMode_async(UA_Client *client,
+    const UA_SetMonitoringModeRequest request,
+    UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *requestId) {
+    return __UA_Client_AsyncService(client, &request,
+        &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST], callback,
+        &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE],
+        userdata, requestId);
+}
+
+static UA_INLINE UA_SetTriggeringResponse
+UA_Client_MonitoredItems_setTriggering(UA_Client *client,
+    const UA_SetTriggeringRequest request) {
+    UA_SetTriggeringResponse response;
+    __UA_Client_Service(client,
+        &request, &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST],
+        &response, &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE]);
+    return response;
+}
+
+static UA_INLINE UA_StatusCode
+UA_Client_MonitoredItems_setTriggering_async(UA_Client *client,
+    const UA_SetTriggeringRequest request,
+    UA_ClientAsyncServiceCallback callback,
+    void *userdata, UA_UInt32 *requestId) {
+    return __UA_Client_AsyncService(client, &request,
+        &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST], callback,
+        &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE],
+        userdata, requestId);
+}
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/cmake_install.cmake b/static/doc/v1.4.0/cmake_install.cmake new file mode 100644 index 0000000000..7a1554a691 --- /dev/null +++ b/static/doc/v1.4.0/cmake_install.cmake @@ -0,0 +1,44 @@ +# Install script for directory: /home/runner/work/open62541/open62541/doc + +# Set the install prefix +if(NOT DEFINED CMAKE_INSTALL_PREFIX) + set(CMAKE_INSTALL_PREFIX "/usr/local") +endif() +string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + if(BUILD_TYPE) + string(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + else() + set(CMAKE_INSTALL_CONFIG_NAME "Release") + endif() + message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +endif() + +# Set the component getting installed. +if(NOT CMAKE_INSTALL_COMPONENT) + if(COMPONENT) + message(STATUS "Install component: \"${COMPONENT}\"") + set(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + else() + set(CMAKE_INSTALL_COMPONENT) + endif() +endif() + +# Install shared libraries without execute permission? +if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + set(CMAKE_INSTALL_SO_NO_EXE "1") +endif() + +# Is this installation the result of a crosscompile? +if(NOT DEFINED CMAKE_CROSSCOMPILING) + set(CMAKE_CROSSCOMPILING "FALSE") +endif() + +# Set default install directory permissions. +if(NOT DEFINED CMAKE_OBJDUMP) + set(CMAKE_OBJDUMP "/usr/bin/objdump") +endif() + diff --git a/static/doc/v1.4.0/common.html b/static/doc/v1.4.0/common.html new file mode 100644 index 0000000000..b00be8a4d6 --- /dev/null +++ b/static/doc/v1.4.0/common.html @@ -0,0 +1,661 @@ + + + + + + + Common Definitions — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Common Definitions

+

Common definitions for Client, Server and PubSub.

+
+

Attribute Id

+

Every node in an OPC UA information model contains attributes depending on +the node type. Possible attributes are as follows:

+
typedef enum {
+    UA_ATTRIBUTEID_NODEID                  = 1,
+    UA_ATTRIBUTEID_NODECLASS               = 2,
+    UA_ATTRIBUTEID_BROWSENAME              = 3,
+    UA_ATTRIBUTEID_DISPLAYNAME             = 4,
+    UA_ATTRIBUTEID_DESCRIPTION             = 5,
+    UA_ATTRIBUTEID_WRITEMASK               = 6,
+    UA_ATTRIBUTEID_USERWRITEMASK           = 7,
+    UA_ATTRIBUTEID_ISABSTRACT              = 8,
+    UA_ATTRIBUTEID_SYMMETRIC               = 9,
+    UA_ATTRIBUTEID_INVERSENAME             = 10,
+    UA_ATTRIBUTEID_CONTAINSNOLOOPS         = 11,
+    UA_ATTRIBUTEID_EVENTNOTIFIER           = 12,
+    UA_ATTRIBUTEID_VALUE                   = 13,
+    UA_ATTRIBUTEID_DATATYPE                = 14,
+    UA_ATTRIBUTEID_VALUERANK               = 15,
+    UA_ATTRIBUTEID_ARRAYDIMENSIONS         = 16,
+    UA_ATTRIBUTEID_ACCESSLEVEL             = 17,
+    UA_ATTRIBUTEID_USERACCESSLEVEL         = 18,
+    UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL = 19,
+    UA_ATTRIBUTEID_HISTORIZING             = 20,
+    UA_ATTRIBUTEID_EXECUTABLE              = 21,
+    UA_ATTRIBUTEID_USEREXECUTABLE          = 22,
+    UA_ATTRIBUTEID_DATATYPEDEFINITION      = 23,
+    UA_ATTRIBUTEID_ROLEPERMISSIONS         = 24,
+    UA_ATTRIBUTEID_USERROLEPERMISSIONS     = 25,
+    UA_ATTRIBUTEID_ACCESSRESTRICTIONS      = 26,
+    UA_ATTRIBUTEID_ACCESSLEVELEX           = 27
+} UA_AttributeId;
+
+
+
+
+

Access Level Masks

+

The access level to a node is given by the following constants that are ANDed +with the overall access level.

+
#define UA_ACCESSLEVELMASK_READ           (0x01u << 0u)
+#define UA_ACCESSLEVELMASK_WRITE          (0x01u << 1u)
+#define UA_ACCESSLEVELMASK_HISTORYREAD    (0x01u << 2u)
+#define UA_ACCESSLEVELMASK_HISTORYWRITE   (0x01u << 3u)
+#define UA_ACCESSLEVELMASK_SEMANTICCHANGE (0x01u << 4u)
+#define UA_ACCESSLEVELMASK_STATUSWRITE    (0x01u << 5u)
+#define UA_ACCESSLEVELMASK_TIMESTAMPWRITE (0x01u << 6u)
+
+
+
+
+

Write Masks

+

The write mask and user write mask is given by the following constants that +are ANDed for the overall write mask. Part 3: 5.2.7 Table 2

+
#define UA_WRITEMASK_ACCESSLEVEL             (0x01u << 0u)
+#define UA_WRITEMASK_ARRRAYDIMENSIONS        (0x01u << 1u)
+#define UA_WRITEMASK_BROWSENAME              (0x01u << 2u)
+#define UA_WRITEMASK_CONTAINSNOLOOPS         (0x01u << 3u)
+#define UA_WRITEMASK_DATATYPE                (0x01u << 4u)
+#define UA_WRITEMASK_DESCRIPTION             (0x01u << 5u)
+#define UA_WRITEMASK_DISPLAYNAME             (0x01u << 6u)
+#define UA_WRITEMASK_EVENTNOTIFIER           (0x01u << 7u)
+#define UA_WRITEMASK_EXECUTABLE              (0x01u << 8u)
+#define UA_WRITEMASK_HISTORIZING             (0x01u << 9u)
+#define UA_WRITEMASK_INVERSENAME             (0x01u << 10u)
+#define UA_WRITEMASK_ISABSTRACT              (0x01u << 11u)
+#define UA_WRITEMASK_MINIMUMSAMPLINGINTERVAL (0x01u << 12u)
+#define UA_WRITEMASK_NODECLASS               (0x01u << 13u)
+#define UA_WRITEMASK_NODEID                  (0x01u << 14u)
+#define UA_WRITEMASK_SYMMETRIC               (0x01u << 15u)
+#define UA_WRITEMASK_USERACCESSLEVEL         (0x01u << 16u)
+#define UA_WRITEMASK_USEREXECUTABLE          (0x01u << 17u)
+#define UA_WRITEMASK_USERWRITEMASK           (0x01u << 18u)
+#define UA_WRITEMASK_VALUERANK               (0x01u << 19u)
+#define UA_WRITEMASK_WRITEMASK               (0x01u << 20u)
+#define UA_WRITEMASK_VALUEFORVARIABLETYPE    (0x01u << 21u)
+#define UA_WRITEMASK_ACCESSLEVELEX           (0x01u << 25u)
+
+
+
+
+

ValueRank

+

The following are the most common ValueRanks used for Variables, +VariableTypes and method arguments. ValueRanks higher than 3 are valid as +well (but less common).

+
#define UA_VALUERANK_SCALAR_OR_ONE_DIMENSION  -3
+#define UA_VALUERANK_ANY                      -2
+#define UA_VALUERANK_SCALAR                   -1
+#define UA_VALUERANK_ONE_OR_MORE_DIMENSIONS    0
+#define UA_VALUERANK_ONE_DIMENSION             1
+#define UA_VALUERANK_TWO_DIMENSIONS            2
+#define UA_VALUERANK_THREE_DIMENSIONS          3
+
+
+
+
+

EventNotifier

+

The following are the available EventNotifier used for Nodes. +The EventNotifier Attribute is used to indicate if the Node can be used +to subscribe to Events or to read / write historic Events. +Part 3: 5.4 Table 10

+
#define UA_EVENTNOTIFIER_SUBSCRIBE_TO_EVENT (0x01u << 0u)
+#define UA_EVENTNOTIFIER_HISTORY_READ       (0x01u << 2u)
+#define UA_EVENTNOTIFIER_HISTORY_WRITE      (0x01u << 3u)
+
+
+
+
+

Rule Handling

+

The RuleHanding settings define how error cases that result from rules in the +OPC UA specification shall be handled. The rule handling can be softened, +e.g. to workaround misbehaving implementations or to mitigate the impact of +additional rules that are introduced in later versions of the OPC UA +specification.

+
typedef enum {
+    UA_RULEHANDLING_DEFAULT = 0,
+    UA_RULEHANDLING_ABORT,  /* Abort the operation and return an error code */
+    UA_RULEHANDLING_WARN,   /* Print a message in the logs and continue */
+    UA_RULEHANDLING_ACCEPT, /* Continue and disregard the broken rule */
+} UA_RuleHandling;
+
+
+
+
+

Order

+

The Order enum is used to establish an absolute ordering between elements.

+
typedef enum {
+    UA_ORDER_LESS = -1,
+    UA_ORDER_EQ = 0,
+    UA_ORDER_MORE = 1
+} UA_Order;
+
+
+
+
+

Connection State

+
typedef enum {
+    UA_CONNECTIONSTATE_CLOSED,     /* The socket has been closed and the connection
+                                    * will be deleted */
+    UA_CONNECTIONSTATE_OPENING,    /* The socket is open, but the HEL/ACK handshake
+                                    * is not done */
+    UA_CONNECTIONSTATE_ESTABLISHED,/* The socket is open and the connection
+                                    * configured */
+    UA_CONNECTIONSTATE_CLOSING     /* The socket is closing down */
+} UA_ConnectionState;
+
+
+typedef enum {
+    UA_SECURECHANNELSTATE_CLOSED = 0,
+    UA_SECURECHANNELSTATE_REVERSE_LISTENING,
+    UA_SECURECHANNELSTATE_CONNECTING,
+    UA_SECURECHANNELSTATE_CONNECTED,
+    UA_SECURECHANNELSTATE_REVERSE_CONNECTED,
+    UA_SECURECHANNELSTATE_RHE_SENT,
+    UA_SECURECHANNELSTATE_HEL_SENT,
+    UA_SECURECHANNELSTATE_HEL_RECEIVED,
+    UA_SECURECHANNELSTATE_ACK_SENT,
+    UA_SECURECHANNELSTATE_ACK_RECEIVED,
+    UA_SECURECHANNELSTATE_OPN_SENT,
+    UA_SECURECHANNELSTATE_OPEN,
+    UA_SECURECHANNELSTATE_CLOSING,
+} UA_SecureChannelState;
+
+typedef enum {
+    UA_SESSIONSTATE_CLOSED = 0,
+    UA_SESSIONSTATE_CREATE_REQUESTED,
+    UA_SESSIONSTATE_CREATED,
+    UA_SESSIONSTATE_ACTIVATE_REQUESTED,
+    UA_SESSIONSTATE_ACTIVATED,
+    UA_SESSIONSTATE_CLOSING
+} UA_SessionState;
+
+
+
+
+

Statistic Counters

+

The stack manages statistic counters for SecureChannels and Sessions.

+

The Session layer counters are matching the counters of the +ServerDiagnosticsSummaryDataType that are defined in the OPC UA Part 5 +specification. The SecureChannel counters are not defined in the OPC UA spec, +but are harmonized with the Session layer counters if possible.

+
typedef enum {
+    UA_SHUTDOWNREASON_CLOSE = 0,
+    UA_SHUTDOWNREASON_REJECT,
+    UA_SHUTDOWNREASON_SECURITYREJECT,
+    UA_SHUTDOWNREASON_TIMEOUT,
+    UA_SHUTDOWNREASON_ABORT,
+    UA_SHUTDOWNREASON_PURGE
+} UA_ShutdownReason;
+
+typedef struct {
+    size_t currentChannelCount;
+    size_t cumulatedChannelCount;
+    size_t rejectedChannelCount;
+    size_t channelTimeoutCount; /* only used by servers */
+    size_t channelAbortCount;
+    size_t channelPurgeCount;   /* only used by servers */
+} UA_SecureChannelStatistics;
+
+typedef struct {
+    size_t currentSessionCount;
+    size_t cumulatedSessionCount;
+    size_t securityRejectedSessionCount; /* only used by servers */
+    size_t rejectedSessionCount;
+    size_t sessionTimeoutCount;          /* only used by servers */
+    size_t sessionAbortCount;            /* only used by servers */
+} UA_SessionStatistics;
+
+
+
+
+

Lifecycle States

+

Generic lifecycle states. The STOPPING state indicates that the lifecycle is +being terminated. But it might take time to (asynchronously) perform a +graceful shutdown.

+
typedef enum {
+    UA_LIFECYCLESTATE_STOPPED = 0,
+    UA_LIFECYCLESTATE_STARTED,
+    UA_LIFECYCLESTATE_STOPPING
+} UA_LifecycleState;
+
+
+
+
+

Forward Declarations

+

Opaque pointers used in Client, Server and PubSub.

+
struct UA_Server;
+typedef struct UA_Server UA_Server;
+
+struct UA_ServerConfig;
+typedef struct UA_ServerConfig UA_ServerConfig;
+
+typedef void (*UA_ServerCallback)(UA_Server *server, void *data);
+
+struct UA_Client;
+typedef struct UA_Client UA_Client;
+
+
+
+
+

Range Definition

+
typedef struct {
+    UA_UInt32 min;
+    UA_UInt32 max;
+} UA_UInt32Range;
+
+typedef struct {
+    UA_Duration min;
+    UA_Duration max;
+} UA_DurationRange;
+
+
+
+
+

Random Number Generator

+

If UA_MULTITHREADING is defined, then the seed is stored in thread +local storage. The seed is initialized for every thread in the +server/client.

+
void
+UA_random_seed(UA_UInt64 seed);
+
+UA_UInt32
+UA_UInt32_random(void); /* no cryptographic entropy */
+
+UA_Guid
+UA_Guid_random(void);   /* no cryptographic entropy */
+
+
+
+
+

Key Value Map

+

Helper functions to work with configuration parameters in an array of +UA_KeyValuePair. Lookup is linear. So this is for small numbers of keys. The +methods below that accept a const UA_KeyValueMap as an argument also accept +NULL for that argument and treat it as an empty map.

+
typedef struct {
+    size_t mapSize;
+    UA_KeyValuePair *map;
+} UA_KeyValueMap;
+
+extern const UA_KeyValueMap UA_KEYVALUEMAP_NULL;
+
+UA_KeyValueMap *
+UA_KeyValueMap_new(void);
+
+void
+UA_KeyValueMap_clear(UA_KeyValueMap *map);
+
+void
+UA_KeyValueMap_delete(UA_KeyValueMap *map);
+
+/* Is the map empty (or NULL)? */
+UA_Boolean
+UA_KeyValueMap_isEmpty(const UA_KeyValueMap *map);
+
+/* Does the map contain an entry for the key? */
+UA_Boolean
+UA_KeyValueMap_contains(const UA_KeyValueMap *map, const UA_QualifiedName key);
+
+/* Insert a copy of the value. Can reallocate the underlying array. This
+ * invalidates pointers into the previous array. If the key exists already, the
+ * value is overwritten (upsert semantics). */
+UA_StatusCode
+UA_KeyValueMap_set(UA_KeyValueMap *map,
+                   const UA_QualifiedName key,
+                   const UA_Variant *value);
+
+/* Helper function for scalar insertion that internally calls
+ * `UA_KeyValueMap_set` */
+UA_StatusCode
+UA_KeyValueMap_setScalar(UA_KeyValueMap *map,
+                         const UA_QualifiedName key,
+                         void *p,
+                         const UA_DataType *type);
+
+/* Returns a pointer to the value or NULL if the key is not found */
+const UA_Variant *
+UA_KeyValueMap_get(const UA_KeyValueMap *map,
+                   const UA_QualifiedName key);
+
+/* Returns NULL if the value for the key is not defined, not of the right
+ * datatype or not a scalar */
+const void *
+UA_KeyValueMap_getScalar(const UA_KeyValueMap *map,
+                         const UA_QualifiedName key,
+                         const UA_DataType *type);
+
+/* Remove a single entry. To delete the entire map, use `UA_KeyValueMap_clear`. */
+UA_StatusCode
+UA_KeyValueMap_remove(UA_KeyValueMap *map,
+                      const UA_QualifiedName key);
+
+/* Create a deep copy of the given KeyValueMap */
+UA_StatusCode
+UA_KeyValueMap_copy(const UA_KeyValueMap *src, UA_KeyValueMap *dst);
+
+/* Copy entries from the right-hand-side into the left-hand-size. Reallocates
+ * previous memory in the left-hand-side. If the operation fails, both maps are
+ * left untouched. */
+UA_StatusCode
+UA_KeyValueMap_merge(UA_KeyValueMap *lhs, const UA_KeyValueMap *rhs);
+
+
+
+
+

Binary Connection Config Parameters

+
typedef struct {
+    UA_UInt32 protocolVersion;
+    UA_UInt32 recvBufferSize;
+    UA_UInt32 sendBufferSize;
+    UA_UInt32 localMaxMessageSize;  /* (0 = unbounded) */
+    UA_UInt32 remoteMaxMessageSize; /* (0 = unbounded) */
+    UA_UInt32 localMaxChunkCount;   /* (0 = unbounded) */
+    UA_UInt32 remoteMaxChunkCount;  /* (0 = unbounded) */
+} UA_ConnectionConfig;
+
+
+
+
+

Default Node Attributes

+

Default node attributes to simplify the use of the AddNodes services. For +example, Setting the ValueRank and AccessLevel to zero is often an unintended +setting and leads to errors that are hard to track down.

+
/* The default for variables is "BaseDataType" for the datatype, -2 for the
+ * valuerank and a read-accesslevel. */
+extern const UA_VariableAttributes UA_VariableAttributes_default;
+extern const UA_VariableTypeAttributes UA_VariableTypeAttributes_default;
+
+/* Methods are executable by default */
+extern const UA_MethodAttributes UA_MethodAttributes_default;
+
+/* The remaining attribute definitions are currently all zeroed out */
+extern const UA_ObjectAttributes UA_ObjectAttributes_default;
+extern const UA_ObjectTypeAttributes UA_ObjectTypeAttributes_default;
+extern const UA_ReferenceTypeAttributes UA_ReferenceTypeAttributes_default;
+extern const UA_DataTypeAttributes UA_DataTypeAttributes_default;
+extern const UA_ViewAttributes UA_ViewAttributes_default;
+
+
+
+
+

Endpoint URL Parser

+

The endpoint URL parser is generally useful for the implementation of network +layer plugins.

+
/* Split the given endpoint url into hostname, port and path. All arguments must
+ * be non-NULL. EndpointUrls have the form "opc.tcp://hostname:port/path", port
+ * and path may be omitted (together with the prefix colon and slash).
+ *
+ * @param endpointUrl The endpoint URL.
+ * @param outHostname Set to the parsed hostname. The string points into the
+ *        original endpointUrl, so no memory is allocated. If an IPv6 address is
+ *        given, hostname contains e.g. '[2001:0db8:85a3::8a2e:0370:7334]'
+ * @param outPort Set to the port of the url or left unchanged.
+ * @param outPath Set to the path if one is present in the endpointUrl. Can be
+ *        NULL. Then not path is returned. Starting or trailing '/' are NOT
+ *        included in the path. The string points into the original endpointUrl,
+ *        so no memory is allocated.
+ * @return Returns UA_STATUSCODE_BADTCPENDPOINTURLINVALID if parsing failed. */
+UA_StatusCode
+UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname,
+                    UA_UInt16 *outPort, UA_String *outPath);
+
+/* Split the given endpoint url into hostname, vid and pcp. All arguments must
+ * be non-NULL. EndpointUrls have the form "opc.eth://<host>[:<VID>[.PCP]]".
+ * The host is a MAC address, an IP address or a registered name like a
+ * hostname. The format of a MAC address is six groups of hexadecimal digits,
+ * separated by hyphens (e.g. 01-23-45-67-89-ab). A system may also accept
+ * hostnames and/or IP addresses if it provides means to resolve it to a MAC
+ * address (e.g. DNS and Reverse-ARP).
+ *
+ * Note: currently only parsing MAC address is supported.
+ *
+ * @param endpointUrl The endpoint URL.
+ * @param vid Set to VLAN ID.
+ * @param pcp Set to Priority Code Point.
+ * @return Returns UA_STATUSCODE_BADINTERNALERROR if parsing failed. */
+UA_StatusCode
+UA_parseEndpointUrlEthernet(const UA_String *endpointUrl, UA_String *target,
+                            UA_UInt16 *vid, UA_Byte *pcp);
+
+/* Convert given byte string to a positive number. Returns the number of valid
+ * digits. Stops if a non-digit char is found and returns the number of digits
+ * up to that point. */
+size_t
+UA_readNumber(const UA_Byte *buf, size_t buflen, UA_UInt32 *number);
+
+/* Same as UA_ReadNumber but with a base parameter */
+size_t
+UA_readNumberWithBase(const UA_Byte *buf, size_t buflen,
+                      UA_UInt32 *number, UA_Byte base);
+
+#ifndef UA_MIN
+#define UA_MIN(A, B) ((A) > (B) ? (B) : (A))
+#endif
+
+#ifndef UA_MAX
+#define UA_MAX(A, B) ((A) > (B) ? (A) : (B))
+#endif
+
+
+
+
+

Parse RelativePath Expressions

+

Parse a RelativePath according to the format defined in Part 4, A2. This is +used e.g. for the BrowsePath structure. For now, only the standard +ReferenceTypes from Namespace 0 are recognized (see Part 3).

+
+

RelativePath := ( ReferenceType [BrowseName]? )*

+
+

The ReferenceTypes have either of the following formats:

+
    +
  • /: HierarchicalReferences and subtypes

  • +
  • .: Aggregates ReferenceTypesand subtypes

  • +
  • < [!#]* BrowseName >: The ReferenceType is indicated by its BrowseName +(a QualifiedName). Prefixed modifiers can be as follows: ! switches to +inverse References. # excludes subtypes of the ReferenceType.

  • +
+

QualifiedNames consist of an optional NamespaceIndex and the nameitself:

+
+

QualifiedName := ([0-9]+ ":")? Name

+
+

The QualifiedName representation for RelativePaths uses & as the escape +character. Occurences of the characters /.<>:#!& in a QualifiedName have +to be escaped (prefixed with &).

+
+

Example RelativePaths

+
    +
  • /2:Block&.Output

  • +
  • /3:Truck.0:NodeVersion

  • +
  • <0:HasProperty>1:Boiler/1:HeatSensor

  • +
  • <0:HasChild>2:Wheel

  • +
  • <#Aggregates>1:Boiler/

  • +
  • <!HasChild>Truck

  • +
  • <HasChild>

  • +
+
#ifdef UA_ENABLE_PARSING
+UA_StatusCode
+UA_RelativePath_parse(UA_RelativePath *rp, const UA_String str);
+#endif
+
+
+
+
+
+

Convenience macros for complex types

+
#define UA_PRINTF_GUID_FORMAT "%08" PRIx32 "-%04" PRIx16 "-%04" PRIx16 \
+    "-%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8
+#define UA_PRINTF_GUID_DATA(GUID) (GUID).data1, (GUID).data2, (GUID).data3, \
+        (GUID).data4[0], (GUID).data4[1], (GUID).data4[2], (GUID).data4[3], \
+        (GUID).data4[4], (GUID).data4[5], (GUID).data4[6], (GUID).data4[7]
+
+#define UA_PRINTF_STRING_FORMAT "\"%.*s\""
+#define UA_PRINTF_STRING_DATA(STRING) (int)(STRING).length, (STRING).data
+
+
+
+
+

Cryptography Helpers

+
/* Compare memory in constant time to mitigate timing attacks.
+ * Returns true if ptr1 and ptr2 are equal for length bytes. */
+UA_Boolean
+UA_constantTimeEqual(const void *ptr1, const void *ptr2, size_t length);
+
+/* Zero-out memory in a way that is not removed by compiler-optimizations. Use
+ * this to ensure cryptographic secrets don't leave traces after the memory was
+ * freed. */
+void
+UA_ByteString_memZero(UA_ByteString *bs);
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/core_concepts.html b/static/doc/v1.4.0/core_concepts.html new file mode 100644 index 0000000000..9312423d9b --- /dev/null +++ b/static/doc/v1.4.0/core_concepts.html @@ -0,0 +1,1048 @@ + + + + + + + Core Concepts of OPC UA — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Core Concepts of OPC UA

+

In one sentence, OPC UA (ISO 62541) defines a framework for object-oriented +information models (typically representing a physical device) that live in an +OPC UA server and a protocol with which a client can interact with the +information model over the network (read and write variables, call methods, +instantiate and delete objects, subscribe to change notifications, and so on).

+

This Section introduces the core concepts of OPC UA. For the full specification +see the OPC UA standard at https://reference.opcfoundation.org/.

+
+

Protocol

+

We focus on the TCP-based binary protocol since it is by far the most common +transport layer for OPC UA. The general concepts also translate to HTTP and +SOAP-based communication defined in the standard. Communication in OPC UA is +best understood by starting with the following key principles:

+
+
Request / Response

All communication is based on the Request/Response pattern. Only clients can +send a request to a server. And servers can only send responses to a matching +request. Often the server is hosted close to a (physical) device, such as a +sensor or a machine tool.

+
+
Asynchronous Responses

A server does not have to immediately respond to requests and responses may be +sent in a different order. This keeps the server responsive when it takes time +until a specific request has been processed (e.g. a method call or when +reading from a sensor with delay). Subscriptions (push-notifications) are +implemented via special requests where the response is delayed until a +notification is published.

+
+
+
+

Note

+

OPC UA PubSub (Part 14 of the standard) is an extension for the integration +of many-to-many communication with OPC UA. PubSub does not use the +client-server protocol. Rather, OPC UA PubSub integrates with either existing +broker-based protocols such as MQTT, UDP-multicast or Ethernet-based +communication. Typically an OPC UA server (accessed via the client-server +protocol) is used to configured PubSub communication.

+

Note that the client-server protocol also supports Subscriptions for +one-to-one communication and does not depend on PubSub for this feature.

+
+

A client-server connection for the OPC UA binary protocol consists of three +nested levels: The stateful TCP connection, a SecureChannel and the Session. For +full details, see Part 6 of the OPC UA standard.

+
+
TCP Connection

The TCP connection is opened to the corresponding hostname and port with an +initial handshake of HEL/ACK messages. The handshake establishes the basic +settings of the connection, such as the maximum message length. The Reverse +Connect extension of OPC UA allows the server to initiate the underlying TCP +connection.

+
+
SecureChannel

SecureChannels are created on top of the raw TCP connection. A SecureChannel +is established with an OpenSecureChannel request and response message pair. +Attention! Even though a SecureChannel is mandatory, encryption might +still be disabled. The SecurityMode of a SecureChannel can be either +None, Sign, or SignAndEncrypt. As of version 0.2 of open62541, +message signing and encryption is still under ongoing development.

+

With message signing or encryption enabled, the OpenSecureChannel messages +are encrypted using an asymmetric encryption algorithm (public-key +cryptography) [1]. As part of the OpenSecureChannel messages, +client and server establish a common secret over an initially unsecure +channel. For subsequent messages, the common secret is used for symmetric +encryption, which has the advantage of being much faster.

+

Different SecurityPolicies – defined in part 7 of the OPC UA standard – +specify the algorithms for asymmetric and symmetric encryption, encryption key +lengths, hash functions for message signing, and so on. Example +SecurityPolicies are None for transmission of cleartext and +Basic256Sha256 which mandates a variant of RSA with SHA256 certificate +hashing for asymmetric encryption and AES256 for symmetric encryption.

+

The possible SecurityPolicies of a server are described with a list of +Endpoints. An endpoint jointly defines the SecurityMode, SecurityPolicy and +means for authenticating a session (discussed in the next section) in order to +connect to a certain server. The GetEndpoints service returns a list of +available endpoints. This service can usually be invoked without a session and +from an unencrypted SecureChannel. This allows clients to first discover +available endpoints and then use an appropriate SecurityPolicy that might be +required to open a session.

+
+
Session

Sessions are created on top of a SecureChannel. This ensures that users may +authenticate without sending their credentials, such as username and password, +in cleartext. Currently defined authentication mechanisms are anonymous login, +username/password, Kerberos and x509 certificates. The latter requires that +the request message is accompanied by a signature to prove that the sender is +in possession of the private key with which the certificate was created.

+

There are two message exchanges required to establish a session: +CreateSession and ActicateSession. The ActivateSession service can be used +to switch an existing session to a different SecureChannel. This is important, +for example when the connection broke down and the existing session is +reused with a new SecureChannel.

+
+
+ +
+

Structure of a protocol message

+

Consider the example OPC UA binary conversation in Figure +Fig. 1, recorded and displayed with Wireshark.

+
+OPC UA conversation in Wireshark +
+

Fig. 1 OPC UA conversation displayed in Wireshark

+
+
+

The top part of the Wireshark window shows the messages from the conversation in +order. The green line contains the applied filter. Here, we want to see the OPC +UA protocol messages only. The first messages (from TCP packets 49 to 56) show +the client opening an unencrypted SecureChannel and retrieving the server’s +endpoints. Then, starting with packet 63, a new connection and SecureChannel are +created in conformance with one of the endpoints. On top of this SecureChannel, +the client can then create and activate a session. The following ReadRequest +message is selected and covered in more detail in the bottom windows.

+

The bottom left window shows the structure of the selected ReadRequest +message. The purpose of the message is invoking the Read service. The message is structured into a header and a message body. Note +that we do not consider encryption or signing of messages here.

+
+
Message Header

As stated before, OPC UA defines an asynchronous protocol. So responses may be +out of order. The message header contains some basic information, such as the +length of the message, as well as necessary information to relate messages to +a SecureChannel and each request to the corresponding response. “Chunking” +refers to the splitting and reassembling of messages that are longer than the +maximum network packet size.

+
+
Message Body

Every OPC UA service has a signature in the form of a +request and response data structure. These are defined according to the OPC UA +protocol type system. See especially the auto-generated +type definitions for the data types corresponding to service +requests and responses. The message body begins with the identifier of the +following data type. Then, the main payload of the message follows.

+
+
+

The bottom right window shows the binary payload of the selected ReadRequest +message. The message header is highlighted in light-grey. The message body in +blue highlighting shows the encoded ReadRequest data structure.

+
+
+
+

Services

+

In OPC UA, all communication is based on service calls, each consisting of a +request and a response message. These messages are defined as data structures +with a binary encoding and listed in Generated Data Type Definitions. Since all +Services are pre-defined in the standard, they cannot be modified by the +user. But you can use the Call service to invoke +user-defined methods on the server.

+

Please refer to the Client and Server API where the services +are exposed to end users. Please see part 4 of the OPC UA standard for the +authoritative definition of the services and their behaviour.

+
+

Discovery Service Set

+

This Service Set defines Services used to discover the Endpoints implemented +by a Server and to read the security configuration for those Endpoints.

+
+
FindServers Service

Returns the Servers known to a Server or Discovery Server. The Client may +reduce the number of results returned by specifying filter criteria

+
+
GetEndpoints Service

Returns the Endpoints supported by a Server and all of the configuration +information required to establish a SecureChannel and a Session.

+
+
FindServersOnNetwork Service

Returns the Servers known to a Discovery Server. Unlike FindServer, +this Service is only implemented by Discovery Servers. It additionally +returns servers which may have been detected through Multicast.

+
+
RegisterServer

Registers a remote server in the local discovery service.

+
+
RegisterServer2

This Service allows a Server to register its DiscoveryUrls and capabilities +with a Discovery Server. It extends the registration information from +RegisterServer with information necessary for FindServersOnNetwork.

+
+
+
+
+

SecureChannel Service Set

+

This Service Set defines Services used to open a communication channel that +ensures the confidentiality and Integrity of all Messages exchanged with the +Server.

+
+
OpenSecureChannel Service

Open or renew a SecureChannel that can be used to ensure Confidentiality and +Integrity for Message exchange during a Session.

+
+
CloseSecureChannel Service

Used to terminate a SecureChannel.

+
+
Session Service Set

This Service Set defines Services for an application layer connection +establishment in the context of a Session.

+
+
CreateSession Service

Used by an OPC UA Client to create a Session and the Server returns two +values which uniquely identify the Session. The first value is the sessionId +which is used to identify the Session in the audit logs and in the Server’s +address space. The second is the authenticationToken which is used to +associate an incoming request with a Session.

+
+
ActivateSession

Used by the Client to submit its SoftwareCertificates to the Server for +validation and to specify the identity of the user associated with the +Session. This Service request shall be issued by the Client before it issues +any other Service request after CreateSession. Failure to do so shall cause +the Server to close the Session.

+
+
CloseSession

Used to terminate a Session.

+
+
Cancel Service

Used to cancel outstanding Service requests. Successfully cancelled service +requests shall respond with Bad_RequestCancelledByClient.

+
+
+
+
+

NodeManagement Service Set

+

This Service Set defines Services to add and delete AddressSpace Nodes and +References between them. All added Nodes continue to exist in the +AddressSpace even if the Client that created them disconnects from the +Server.

+
+
AddNodes Service

Used to add one or more Nodes into the AddressSpace hierarchy. +If the type or one of the supertypes has any HasInterface references +(see OPC 10001-7 - Amendment 7, 4.9.2), the child nodes of the interfaces +are added to the new object.

+
+
AddReferences Service

Used to add one or more References to one or more Nodes.

+
+
DeleteNodes Service

Used to delete one or more Nodes from the AddressSpace.

+
+
DeleteReferences

Used to delete one or more References of a Node.

+
+
+
+
+

View Service Set

+

Clients use the browse Services of the View Service Set to navigate through +the AddressSpace or through a View which is a subset of the AddressSpace.

+
+
Browse Service

Used to discover the References of a specified Node. The browse can be +further limited by the use of a View. This Browse Service also supports a +primitive filtering capability.

+
+
BrowseNext Service

Used to request the next set of Browse or BrowseNext response information +that is too large to be sent in a single response. “Too large” in this +context means that the Server is not able to return a larger response or that +the number of results to return exceeds the maximum number of results to +return that was specified by the Client in the original Browse request.

+
+
TranslateBrowsePathsToNodeIds Service

Used to translate textual node paths to their respective ids.

+
+
RegisterNodes Service

Used by Clients to register the Nodes that they know they will access +repeatedly (e.g. Write, Call). It allows Servers to set up anything needed so +that the access operations will be more efficient.

+
+
UnregisterNodes Service

This Service is used to unregister NodeIds that have been obtained via the +RegisterNodes service.

+
+
+
+
+

Query Service Set

+

This Service Set is used to issue a Query to a Server. OPC UA Query is +generic in that it provides an underlying storage mechanism independent Query +capability that can be used to access a wide variety of OPC UA data stores +and information management systems. OPC UA Query permits a Client to access +data maintained by a Server without any knowledge of the logical schema used +for internal storage of the data. Knowledge of the AddressSpace is +sufficient.

+
+
QueryFirst Service (not implemented)

This Service is used to issue a Query request to the Server.

+
+
QueryNext Service (not implemented)

This Service is used to request the next set of QueryFirst or QueryNext +response information that is too large to be sent in a single response.

+
+
+
+
+

Attribute Service Set

+

This Service Set provides Services to access Attributes that are part of +Nodes.

+
+
Read Service

Used to read attributes of nodes. For constructed attribute values whose +elements are indexed, such as an array, this Service allows Clients to read +the entire set of indexed values as a composite, to read individual elements +or to read ranges of elements of the composite.

+
+
Write Service

Used to write attributes of nodes. For constructed attribute values whose +elements are indexed, such as an array, this Service allows Clients to write +the entire set of indexed values as a composite, to write individual elements +or to write ranges of elements of the composite.

+
+
HistoryRead Service

Used to read historical values or Events of one or more Nodes. Servers may +make historical values available to Clients using this Service, although the +historical values themselves are not visible in the AddressSpace.

+
+
HistoryUpdate Service

Used to update historical values or Events of one or more Nodes. Several +request parameters indicate how the Server is to update the historical value +or Event. Valid actions are Insert, Replace or Delete.

+
+
+
+
+

Method Service Set

+

The Method Service Set defines the means to invoke methods. A method shall be +a component of an Object. See the section on MethodNodes +for more information.

+
+
Call Service

Used to call (invoke) a methods. Each method call is invoked within the +context of an existing Session. If the Session is terminated, the results of +the method’s execution cannot be returned to the Client and are discarded.

+
+
+
+
+

MonitoredItem Service Set

+

Clients define MonitoredItems to subscribe to data and Events. Each +MonitoredItem identifies the item to be monitored and the Subscription to use +to send Notifications. The item to be monitored may be any Node Attribute.

+
+
CreateMonitoredItems Service

Used to create and add one or more MonitoredItems to a Subscription. A +MonitoredItem is deleted automatically by the Server when the Subscription is +deleted. Deleting a MonitoredItem causes its entire set of triggered item +links to be deleted, but has no effect on the MonitoredItems referenced by +the triggered items.

+
+
DeleteMonitoredItems Service

Used to remove one or more MonitoredItems of a Subscription. When a +MonitoredItem is deleted, its triggered item links are also deleted.

+
+
ModifyMonitoredItems Service

Used to modify MonitoredItems of a Subscription. Changes to the MonitoredItem +settings shall be applied immediately by the Server. They take effect as soon +as practical but not later than twice the new revisedSamplingInterval.

+

Illegal request values for parameters that can be revised do not generate +errors. Instead the server will choose default values and indicate them in +the corresponding revised parameter.

+
+
SetMonitoringMode Service

Used to set the monitoring mode for one or more MonitoredItems of a +Subscription.

+
+
SetTriggering Service

Used to create and delete triggering links for a triggering item.

+
+
+
+
+

Subscription Service Set

+

Subscriptions are used to report Notifications to the Client.

+
+
CreateSubscription Service

Used to create a Subscription. Subscriptions monitor a set of MonitoredItems +for Notifications and return them to the Client in response to Publish +requests.

+
+
ModifySubscription Service

Used to modify a Subscription.

+
+
SetPublishingMode Service

Used to enable sending of Notifications on one or more Subscriptions.

+
+
Publish Service

Used for two purposes. First, it is used to acknowledge the receipt of +NotificationMessages for one or more Subscriptions. Second, it is used to +request the Server to return a NotificationMessage or a keep-alive +Message.

+
+
Republish Service

Requests the Subscription to republish a NotificationMessage from its +retransmission queue.

+
+
DeleteSubscriptions Service

Invoked to delete one or more Subscriptions that belong to the Client’s +Session.

+
+
TransferSubscription Service

Used to transfer a Subscription and its MonitoredItems from one Session to +another. For example, a Client may need to reopen a Session and then transfer +its Subscriptions to that Session. It may also be used by one Client to take +over a Subscription from another Client by transferring the Subscription to +its Session.

+
+
+
+
+
+

Information Modelling

+

Information modelling in OPC UA combines concepts from object-orientation and +semantic modelling. At the core, an OPC UA information model is a graph +consisting of Nodes and References between them.

+
+
Nodes

There are eight possible NodeClasses for Nodes (Variable, VariableType, +Object, ObjectType, ReferenceType, DataType, Method, View). The NodeClass +defines the attributes a Node can have.

+
+
References

References are links between Nodes. References are typed (refer to a +ReferenceType) and directed.

+
+
+

The original source for the following information is Part 3 of the OPC UA +specification (https://reference.opcfoundation.org/Core/Part3/).

+

Each Node is identified by a unique (within the server) NodeId and +carries different attributes depending on the NodeClass. These attributes can be +read (and sometimes also written) via the OPC UA protocol. The protocol further +allows the creation and deletion of Nodes and References at runtime. But this is +not supported by all servers.

+

Reference are triples of the form (source-nodeid, referencetype-nodeid, +target-nodeid). (The target-nodeid is actually an ExpandedNodeId +which is a NodeId that can additionally point to a remote server.) An example +reference between nodes is a hasTypeDefinition reference between a Variable +and its VariableType. Some ReferenceTypes are hierarchical and must not form +directed loops. See the section on ReferenceTypes +for more details on possible references and their semantics.

+

The following table (adapted from Part 3 of the specification) shows which +attributes are mandatory (M), optional (O) or not defined for each +NodeClass. In open62541 all optional attributes are defined - with sensible +defaults if users do not change them.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 1 Node attributes for the different NodeClasses

Attribute

DataType

Variable

Variable­Type

Object

Object­Type

Reference­Type

Data­Type

Method

View

NodeId

NodeId

M

M

M

M

M

M

M

M

NodeClass

NodeClass

M

M

M

M

M

M

M

M

BrowseName

QualifiedName

M

M

M

M

M

M

M

M

DisplayName

LocalizedText

M

M

M

M

M

M

M

M

Description

LocalizedText

O

O

O

O

O

O

O

O

WriteMask

UInt32 +(Write Masks)

O

O

O

O

O

O

O +M

O

UserWriteMask

UInt32

O

O

O

O

O

O

O

O

IsAbstract

Boolean

M

M

M

M

Symmetric

Boolean

M

InverseName

LocalizedText

O

ContainsNoLoops

Boolean

M

EventNotifier

Byte +(EventNotifier)

M

M

M

Value

Variant

M

O

DataType

NodeId

M

M

ValueRank

Int32 +(ValueRank)

M

M

M

ArrayDimensions

[UInt32]

O

O

AccessLevel

Byte +(Access Level Masks)

M

M

UserAccessLevel

Byte

M

MinimumSamplingInterval

Double

O

Historizing

Boolean

M

Executable

Boolean

M

UserExecutable

Boolean

M

DataTypeDefinition

DataTypeDefinition

O

+

Each attribute is referenced by a numerical Attribute Id.

+

Some numerical attributes are used as bitfields or come with special semantics. +In particular, see the sections on Access Level Masks, Write Masks, +ValueRank and EventNotifier.

+

New attributes in the standard that are still unsupported in open62541 are +RolePermissions, UserRolePermissions, AccessRestrictions and AccessLevelEx.

+
+

VariableNode

+

Variables store values in a DataValue together with +metadata for introspection. Most notably, the attributes data type, value +rank and array dimensions constrain the possible values the variable can take +on.

+

Variables come in two flavours: properties and datavariables. Properties are +related to a parent with a hasProperty reference and may not have child +nodes themselves. Datavariables may contain properties (hasProperty) and +also datavariables (hasComponents).

+

All variables are instances of some VariableTypeNode in return +constraining the possible data type, value rank and array dimensions +attributes.

+
+

Data Type

+

The (scalar) data type of the variable is constrained to be of a specific +type or one of its children in the type hierarchy. The data type is given as +a NodeId pointing to a DataTypeNode in the type hierarchy. See the +Section DataTypeNode for more details.

+

If the data type attribute points to UInt32, then the value attribute +must be of that exact type since UInt32 does not have children in the +type hierarchy. If the data type attribute points Number, then the type +of the value attribute may still be UInt32, but also Float or +Byte.

+

Consistency between the data type attribute in the variable and its +VariableTypeNode is ensured.

+
+
+

ValueRank

+

This attribute indicates whether the value attribute of the variable is an +array and how many dimensions the array has. It may have the following +values:

+
    +
  • n >= 1: the value is an array with the specified number of dimensions

  • +
  • n =  0: the value is an array with one or more dimensions

  • +
  • n = -1: the value is a scalar

  • +
  • n = -2: the value can be a scalar or an array with any number of dimensions

  • +
  • n = -3: the value can be a scalar or a one dimensional array

  • +
+

Some helper macros for ValueRanks are defined here.

+

The consistency between the value rank attribute of a VariableNode and its +VariableTypeNode is tested within the server.

+
+
+

Array Dimensions

+

If the value rank permits the value to be a (multi-dimensional) array, the +exact length in each dimensions can be further constrained with this +attribute.

+
    +
  • For positive lengths, the variable value must have a dimension length less +or equal to the array dimension length defined in the VariableNode.

  • +
  • The dimension length zero is a wildcard and the actual value may have any +length in this dimension. Note that a value (variant) must have array +dimensions that are positive (not zero).

  • +
+

Consistency between the array dimensions attribute in the variable and its +VariableTypeNode is ensured. However, we consider that an array of +length zero (can also be a null-array with undefined length) has implicit +array dimensions [0,0,...]. These always match the required array +dimensions.

+
+
+
+

VariableTypeNode

+

VariableTypes are used to provide type definitions for variables. +VariableTypes constrain the data type, value rank and array dimensions +attributes of variable instances. Furthermore, instantiating from a specific +variable type may provide semantic information. For example, an instance from +MotorTemperatureVariableType is more meaningful than a float variable +instantiated from BaseDataVariable.

+
+
+

ObjectNode

+

Objects are used to represent systems, system components, real-world objects +and software objects. Objects are instances of an object type +and may contain variables, methods and further objects.

+
+
+

ObjectTypeNode

+

ObjectTypes provide definitions for Objects. Abstract objects cannot be +instantiated. See Node Lifecycle: Constructors, Destructors and Node Contexts for the use of constructor and +destructor callbacks.

+
+
+

ReferenceTypeNode

+

Each reference between two nodes is typed with a ReferenceType that gives +meaning to the relation. The OPC UA standard defines a set of ReferenceTypes +as a mandatory part of OPC UA information models.

+
    +
  • Abstract ReferenceTypes cannot be used in actual references and are only +used to structure the ReferenceTypes hierarchy

  • +
  • Symmetric references have the same meaning from the perspective of the +source and target node

  • +
+

The figure below shows the hierarchy of the standard ReferenceTypes (arrows +indicate a hasSubType relation). Refer to Part 3 of the OPC UA +specification for the full semantics of each ReferenceType.

+
digraph tree {
+
+node [height=0, shape=box, fillcolor="#E5E5E5", concentrate=true]
+
+references [label="References\n(Abstract, Symmetric)"]
+hierarchical_references [label="HierarchicalReferences\n(Abstract)"]
+references -> hierarchical_references
+
+nonhierarchical_references [label="NonHierarchicalReferences\n(Abstract, Symmetric)"]
+references -> nonhierarchical_references
+
+haschild [label="HasChild\n(Abstract)"]
+hierarchical_references -> haschild
+
+aggregates [label="Aggregates\n(Abstract)"]
+haschild -> aggregates
+
+organizes [label="Organizes"]
+hierarchical_references -> organizes
+
+hascomponent [label="HasComponent"]
+aggregates -> hascomponent
+
+hasorderedcomponent [label="HasOrderedComponent"]
+hascomponent -> hasorderedcomponent
+
+hasproperty [label="HasProperty"]
+aggregates -> hasproperty
+
+hassubtype [label="HasSubtype"]
+haschild -> hassubtype
+
+hasmodellingrule [label="HasModellingRule"]
+nonhierarchical_references -> hasmodellingrule
+
+hastypedefinition [label="HasTypeDefinition"]
+nonhierarchical_references -> hastypedefinition
+
+hasencoding [label="HasEncoding"]
+nonhierarchical_references -> hasencoding
+
+hasdescription [label="HasDescription"]
+nonhierarchical_references -> hasdescription
+
+haseventsource [label="HasEventSource"]
+hierarchical_references -> haseventsource
+
+hasnotifier [label="HasNotifier"]
+hierarchical_references -> hasnotifier
+
+generatesevent [label="GeneratesEvent"]
+nonhierarchical_references -> generatesevent
+
+alwaysgeneratesevent [label="AlwaysGeneratesEvent"]
+generatesevent -> alwaysgeneratesevent
+
+{rank=same hierarchical_references nonhierarchical_references}
+{rank=same generatesevent haseventsource hasmodellingrule
+           hasencoding hassubtype}
+{rank=same alwaysgeneratesevent hasproperty}
+
+}
+

The ReferenceType hierarchy can be extended with user-defined ReferenceTypes. +Many Companion Specifications for OPC UA define new ReferenceTypes to be used +in their domain of interest.

+

For the following example of custom ReferenceTypes, we attempt to model the +structure of a technical system. For this, we introduce two custom +ReferenceTypes. First, the hierarchical contains ReferenceType indicates +that a system (represented by an OPC UA object) contains a component (or +subsystem). This gives rise to a tree-structure of containment relations. For +example, the motor (object) is contained in the car and the crankshaft is +contained in the motor. Second, the symmetric connectedTo ReferenceType +indicates that two components are connected. For example, the motor’s +crankshaft is connected to the gear box. Connections are independent of the +containment hierarchy and can induce a general graph-structure. Further +subtypes of connectedTo could be used to differentiate between physical, +electrical and information related connections. A client can then learn the +layout of a (physical) system represented in an OPC UA information model +based on a common understanding of just two custom reference types.

+
+
+

DataTypeNode

+

DataTypes represent simple and structured data types. DataTypes may contain +arrays. But they always describe the structure of a single instance. In +open62541, DataTypeNodes in the information model hierarchy are matched to +UA_DataType type descriptions for Generic Type Handling via their NodeId.

+

Abstract DataTypes (e.g. Number) cannot be the type of actual values. +They are used to constrain values to possible child DataTypes (e.g. +UInt32).

+
+
+

MethodNode

+

Methods define callable functions and are invoked using the Call +service. MethodNodes may have special properties (variable +children with a hasProperty reference) with the QualifiedName (0, "InputArguments") +and (0, "OutputArguments"). The input and output +arguments are both described via an array of UA_Argument. While the Call +service uses a generic array of Variant for input and output, the +actual argument values are checked to match the signature of the MethodNode.

+

Note that the same MethodNode may be referenced from several objects (and +object types). For this, the NodeId of the method and of the object +providing context is part of a Call request message.

+
+
+

ViewNode

+

Each View defines a subset of the Nodes in the AddressSpace. Views can be +used when browsing an information model to focus on a subset of nodes and +references only. ViewNodes can be created and be interacted with. But their +use in the Browse service is currently unsupported in +open62541.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/genindex.html b/static/doc/v1.4.0/genindex.html new file mode 100644 index 0000000000..c1d407a0af --- /dev/null +++ b/static/doc/v1.4.0/genindex.html @@ -0,0 +1,120 @@ + + + + + + Index — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Index

+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/index.html b/static/doc/v1.4.0/index.html new file mode 100644 index 0000000000..f30043622f --- /dev/null +++ b/static/doc/v1.4.0/index.html @@ -0,0 +1,242 @@ + + + + + + + Introduction — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Introduction

+

open62541 (http://open62541.org) is an open source and free implementation of +OPC UA (OPC Unified Architecture) written in the common subset of the C99 and +C++98 languages. The library is usable with all major compilers and provides the +necessary tools to implement dedicated OPC UA clients and servers, or to +integrate OPC UA-based communication into existing applications. open62541 +library is platform independent. All platform-specific functionality is +implemented via exchangeable plugins. Plugin implementations are provided for +the major operating systems.

+

open62541 is licensed under the Mozilla Public License v2.0 (MPLv2). This allows +the open62541 library to be combined and distributed with any proprietary +software. Only changes to the open62541 library itself need to be licensed under +the MPLv2 when copied and distributed. The plugins, as well as the server and +client examples are in the public domain (CC0 license). They can be reused under +any license and changes do not have to be published.

+

The sample server (server_ctt) built using open62541 v1.0 is in conformance with +the ‘Micro Embedded Device Server’ Profile of OPC Foundation supporting OPC UA +client/server communication, subscriptions, method calls and security +(encryption) with the security policies ‘Basic128Rsa15’, ‘Basic256’ and +‘Basic256Sha256’ and the facets ‘method server’ and ‘node management’. See +https://open62541.org/certified-sdk for more details.

+
+

OPC Unified Architecture

+

OPC UA is a protocol +for industrial communication and has been standardized in the IEC 62541 series. +At its core, OPC UA defines

+
    +
  • an asynchronous protocol (built upon TCP, HTTP or SOAP) that +defines the exchange of messages via sessions, (on top of) secure +communication channels, (on top of) raw connections,

  • +
  • a type system for protocol messages with a binary and XML-based +encoding scheme,

  • +
  • a meta-model for information modeling, that +combines object-orientation with semantic triple-relations, and

  • +
  • a set of 37 standard services to interact with server-side +information models. The signature of each service is defined as a request and +response message in the protocol type system.

  • +
+

The standard itself can be purchased from IEC or downloaded for free on the +website of the OPC Foundation at https://opcfoundation.org/ (you need to +register with a valid email).

+

The OPC Foundation drives the continuous improvement of the standard and the +development of companion specifications. Companion specifications translate +established concepts and reusable components from an application domain into OPC +UA. They are created jointly with an established industry council or +standardization body from the application domain. Furthermore, the OPC +Foundation organizes events for the dissemination of the standard and provides +the infrastructure and tools for compliance certification.

+
+
+

open62541 Features

+

open62541 implements the OPC UA binary protocol stack as well as a client and +server SDK. It currently supports the Micro Embedded Device Server Profile plus +some additional features. Server binaries can be well under 100kb in size, +depending on the contained information model.

+
    +
  • Communication Stack

    +
      +
    • OPC UA binary protocol

    • +
    • Chunking (splitting of large messages)

    • +
    • Exchangeable network layer (plugin) for using custom networking APIs (e.g. on embedded targets)

    • +
    • Encrypted communication

    • +
    • Asynchronous service requests in the client

    • +
    +
  • +
  • Information model

    +
      +
    • Support for all OPC UA node types (including method nodes)

    • +
    • Support for adding and removing nodes and references also at runtime.

    • +
    • Support for inheritance and instantiation of object- and variable-types (custom constructor/destructor, instantiation of child nodes)

    • +
    • Access control for individual nodes

    • +
    +
  • +
  • Subscriptions

    +
      +
    • Support for subscriptions/monitoreditems for data change notifications

    • +
    • Very low resource consumption for each monitored value (event-based server architecture)

    • +
    +
  • +
  • Code-Generation

    +
      +
    • Support for generating data types from standard XML definitions

    • +
    • Support for generating server-side information models (nodesets) from standard XML definitions

    • +
    +
  • +
+

Features on the roadmap for the 0.3 release series but missing in the initial v0.3 release are:

+
    +
  • Encrypted communication in the client

  • +
  • Events (notifications emitted by objects, data change notifications are implemented)

  • +
  • Event-loop (background tasks) in the client

  • +
+
+
+

Getting Help

+

For discussion and help besides this documentation, you can reach the open62541 community via

+ +
+
+

Contributing

+

As an open source project, we invite new contributors to help improve open62541. +Issue reports, bugfixes and new features are very welcome. The following are +good starting points for new contributors:

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/nodeset_compiler.html b/static/doc/v1.4.0/nodeset_compiler.html new file mode 100644 index 0000000000..0088022052 --- /dev/null +++ b/static/doc/v1.4.0/nodeset_compiler.html @@ -0,0 +1,610 @@ + + + + + + + XML Nodeset Compiler — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

XML Nodeset Compiler

+

When writing an application, it is more comfortable to create information models using some GUI tools. Most tools can export data according the OPC UA Nodeset XML schema. open62541 contains a Python based nodeset compiler that can transform these information model definitions into a working server.

+

Note that the nodeset compiler you can find in the tools/nodeset_compiler subfolder is not an XML transformation tool but a compiler. That means that it will create an internal representation when parsing the XML files and attempt to understand and verify the correctness of this representation in order to generate C Code.

+
+

Getting started

+

We take the following information model snippet as the starting point of the following tutorial. A more detailed tutorial on how to create your own information model and NodeSet2.xml can be found in this blog post: https://opcua.rocks/custom-information-models/

+
<UANodeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+           xmlns:uax="http://opcfoundation.org/UA/2008/02/Types.xsd"
+           xmlns="http://opcfoundation.org/UA/2011/03/UANodeSet.xsd"
+           xmlns:s1="http://yourorganisation.org/example_nodeset/"
+           xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+    <NamespaceUris>
+        <Uri>http://yourorganisation.org/example_nodeset/</Uri>
+    </NamespaceUris>
+    <Aliases>
+        <Alias Alias="Boolean">i=1</Alias>
+        <Alias Alias="UInt32">i=7</Alias>
+        <Alias Alias="String">i=12</Alias>
+        <Alias Alias="HasModellingRule">i=37</Alias>
+        <Alias Alias="HasTypeDefinition">i=40</Alias>
+        <Alias Alias="HasSubtype">i=45</Alias>
+        <Alias Alias="HasProperty">i=46</Alias>
+        <Alias Alias="HasComponent">i=47</Alias>
+        <Alias Alias="Argument">i=296</Alias>
+    </Aliases>
+    <Extensions>
+        <Extension>
+            <ModelInfo Tool="UaModeler" Hash="Zs8w1AQI71W8P/GOk3k/xQ=="
+                       Version="1.3.4"/>
+        </Extension>
+    </Extensions>
+    <UAReferenceType NodeId="ns=1;i=4001" BrowseName="1:providesInputTo">
+        <DisplayName>providesInputTo</DisplayName>
+        <References>
+            <Reference ReferenceType="HasSubtype" IsForward="false">
+                i=33
+            </Reference>
+        </References>
+        <InverseName Locale="en-US">inputProcidedBy</InverseName>
+    </UAReferenceType>
+    <UAObjectType IsAbstract="true" NodeId="ns=1;i=1001"
+                  BrowseName="1:FieldDevice">
+        <DisplayName>FieldDevice</DisplayName>
+        <References>
+            <Reference ReferenceType="HasSubtype" IsForward="false">
+                i=58
+            </Reference>
+            <Reference ReferenceType="HasComponent">ns=1;i=6001</Reference>
+            <Reference ReferenceType="HasComponent">ns=1;i=6002</Reference>
+        </References>
+    </UAObjectType>
+    <UAVariable DataType="String" ParentNodeId="ns=1;i=1001"
+                NodeId="ns=1;i=6001" BrowseName="1:ManufacturerName"
+                UserAccessLevel="3" AccessLevel="3">
+        <DisplayName>ManufacturerName</DisplayName>
+        <References>
+            <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
+            <Reference ReferenceType="HasModellingRule">i=78</Reference>
+            <Reference ReferenceType="HasComponent" IsForward="false">
+                ns=1;i=1001
+            </Reference>
+        </References>
+    </UAVariable>
+    <UAVariable DataType="String" ParentNodeId="ns=1;i=1001"
+                NodeId="ns=1;i=6002" BrowseName="1:ModelName"
+                UserAccessLevel="3" AccessLevel="3">
+        <DisplayName>ModelName</DisplayName>
+        <References>
+            <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
+            <Reference ReferenceType="HasModellingRule">i=78</Reference>
+            <Reference ReferenceType="HasComponent" IsForward="false">
+                ns=1;i=1001
+            </Reference>
+        </References>
+    </UAVariable>
+    <UAObjectType NodeId="ns=1;i=1002" BrowseName="1:Pump">
+        <DisplayName>Pump</DisplayName>
+        <References>
+            <Reference ReferenceType="HasComponent">ns=1;i=6003</Reference>
+            <Reference ReferenceType="HasComponent">ns=1;i=6004</Reference>
+            <Reference ReferenceType="HasSubtype" IsForward="false">
+                ns=1;i=1001
+            </Reference>
+            <Reference ReferenceType="HasComponent">ns=1;i=7001</Reference>
+            <Reference ReferenceType="HasComponent">ns=1;i=7002</Reference>
+        </References>
+    </UAObjectType>
+    <UAVariable DataType="Boolean" ParentNodeId="ns=1;i=1002"
+                NodeId="ns=1;i=6003" BrowseName="1:isOn" UserAccessLevel="3"
+                AccessLevel="3">
+        <DisplayName>isOn</DisplayName>
+        <References>
+            <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
+            <Reference ReferenceType="HasModellingRule">i=78</Reference>
+            <Reference ReferenceType="HasComponent" IsForward="false">
+                ns=1;i=1002
+            </Reference>
+        </References>
+    </UAVariable>
+    <UAVariable DataType="UInt32" ParentNodeId="ns=1;i=1002"
+                NodeId="ns=1;i=6004" BrowseName="1:MotorRPM"
+                UserAccessLevel="3" AccessLevel="3">
+        <DisplayName>MotorRPM</DisplayName>
+        <References>
+            <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
+            <Reference ReferenceType="HasModellingRule">i=78</Reference>
+            <Reference ReferenceType="HasComponent" IsForward="false">
+                ns=1;i=1002
+            </Reference>
+        </References>
+    </UAVariable>
+    <UAMethod ParentNodeId="ns=1;i=1002" NodeId="ns=1;i=7001"
+              BrowseName="1:startPump">
+        <DisplayName>startPump</DisplayName>
+        <References>
+            <Reference ReferenceType="HasModellingRule">i=78</Reference>
+            <Reference ReferenceType="HasProperty">ns=1;i=6005</Reference>
+            <Reference ReferenceType="HasComponent" IsForward="false">
+                ns=1;i=1002
+            </Reference>
+        </References>
+    </UAMethod>
+    <UAVariable DataType="Argument" ParentNodeId="ns=1;i=7001" ValueRank="1"
+                NodeId="ns=1;i=6005" ArrayDimensions="1"
+                BrowseName="OutputArguments">
+        <DisplayName>OutputArguments</DisplayName>
+        <References>
+            <Reference ReferenceType="HasModellingRule">i=78</Reference>
+            <Reference ReferenceType="HasProperty"
+                       IsForward="false">ns=1;i=7001</Reference>
+            <Reference ReferenceType="HasTypeDefinition">i=68</Reference>
+        </References>
+        <Value>
+            <ListOfExtensionObject>
+                <ExtensionObject>
+                    <TypeId>
+                        <Identifier>i=297</Identifier>
+                    </TypeId>
+                    <Body>
+                        <Argument>
+                            <Name>started</Name>
+                            <DataType>
+                                <Identifier>i=1</Identifier>
+                            </DataType>
+                            <ValueRank>-1</ValueRank>
+                            <ArrayDimensions></ArrayDimensions>
+                            <Description/>
+                        </Argument>
+                    </Body>
+                </ExtensionObject>
+            </ListOfExtensionObject>
+        </Value>
+    </UAVariable>
+    <UAMethod ParentNodeId="ns=1;i=1002" NodeId="ns=1;i=7002"
+              BrowseName="1:stopPump">
+        <DisplayName>stopPump</DisplayName>
+        <References>
+            <Reference ReferenceType="HasModellingRule">i=78</Reference>
+            <Reference ReferenceType="HasProperty">ns=1;i=6006</Reference>
+            <Reference ReferenceType="HasComponent"
+                       IsForward="false">ns=1;i=1002</Reference>
+        </References>
+    </UAMethod>
+    <UAVariable DataType="Argument" ParentNodeId="ns=1;i=7002" ValueRank="1"
+                NodeId="ns=1;i=6006" ArrayDimensions="1"
+                BrowseName="OutputArguments">
+        <DisplayName>OutputArguments</DisplayName>
+        <References>
+            <Reference ReferenceType="HasModellingRule">i=78</Reference>
+            <Reference ReferenceType="HasProperty" IsForward="false">
+                ns=1;i=7002
+            </Reference>
+            <Reference ReferenceType="HasTypeDefinition">i=68</Reference>
+        </References>
+        <Value>
+            <ListOfExtensionObject>
+                <ExtensionObject>
+                    <TypeId>
+                        <Identifier>i=297</Identifier>
+                    </TypeId>
+                    <Body>
+                        <Argument>
+                            <Name>stopped</Name>
+                            <DataType>
+                                <Identifier>i=1</Identifier>
+                            </DataType>
+                            <ValueRank>-1</ValueRank>
+                            <ArrayDimensions></ArrayDimensions>
+                            <Description/>
+                        </Argument>
+                    </Body>
+                </ExtensionObject>
+            </ListOfExtensionObject>
+        </Value>
+    </UAVariable>
+</UANodeSet>
+
+
+

Take the previous snippet and save it to a file myNS.xml. To compile this nodeset into the corresponding C code, which can then be used by the open62541 stack, the nodeset compiler needs some arguments when you call it. The output of the help command gives you the following info:

+
$ python ./nodeset_compiler.py -h
+usage: nodeset_compiler.py [-h] [-e <existingNodeSetXML>] [-x <nodeSetXML>]
+                           [--internal-headers]
+                           [-b <blacklistFile>] [-i <ignoreFile>]
+                           [-t <typesArray>]
+                           [-v]
+                           <outputFile>
+
+positional arguments:
+  <outputFile>          The path/basename for the <output file>.c and <output
+                        file>.h files to be generated. This will also be the
+                        function name used in the header and c-file.
+
+optional arguments:
+  -h, --help            show this help message and exit
+  -e <existingNodeSetXML>, --existing <existingNodeSetXML>
+                        NodeSet XML files with nodes that are already present
+                        on the server.
+  -x <nodeSetXML>, --xml <nodeSetXML>
+                        NodeSet XML files with nodes that shall be generated.
+  --internal-headers    Include internal headers instead of amalgamated header
+  -b <blacklistFile>, --blacklist <blacklistFile>
+                        Loads a list of NodeIDs stored in blacklistFile (one
+                        NodeID per line). Any of the nodeIds encountered in
+                        this file will be removed from the nodeset prior to
+                        compilation. Any references to these nodes will also
+                        be removed
+  -i <ignoreFile>, --ignore <ignoreFile>
+                        Loads a list of NodeIDs stored in ignoreFile (one
+                        NodeID per line). Any of the nodeIds encountered in
+                        this file will be kept in the nodestore but not
+                        printed in the generated code
+  -t <typesArray>, --types-array <typesArray>
+                        Types array for the given namespace. Can be used
+                        mutliple times to define (in the same order as the
+                        .xml files, first for --existing, then --xml) the type
+                        arrays
+  --max-string-length MAX_STRING_LENGTH
+                        Maximum allowed length of a string literal. If longer,
+                        it will be set to an empty string
+  -v, --verbose         Make the script more verbose. Can be applied up to 4
+                        times
+
+
+

So the resulting call looks like this:

+
$ python ./nodeset_compiler.py --types-array=UA_TYPES --existing ../../deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml --xml myNS.xml myNS
+
+
+

And the output of the command:

+
INFO:__main__:Preprocessing (existing) ../../deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml
+INFO:__main__:Preprocessing myNS.xml
+INFO:__main__:Generating Code
+INFO:__main__:NodeSet generation code successfully printed
+
+
+

The first argument --types-array=UA_TYPES defines the name of the global array in open62541 which contains the corresponding types used within the nodeset in NodeSet2.xml. If you do not define your own datatypes, you can always use the UA_TYPES value. More on that later in this tutorial. +The next argument --existing ../../deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml points to the XML definition of the standard-defined namespace 0 (NS0). Namespace 0 is assumed to be loaded beforehand and provides definitions for data type, reference types, and so. Since we reference nodes from NS0 in our myNS.xml we need to tell the nodeset compiler that it should also load that nodeset, but not compile it into the output. +Note that you may need to initialize the git submodule to get the deps/ua-nodeset folder (git submodule update --init) or download the full NodeSet2.xml manually. +The argument --xml myNS.xml points to the user-defined information model, whose nodes will be added to the abstract syntax tree. The script will then create the files myNS.c and myNS.h (indicated by the last argument myNS) containing the C code necessary to instantiate those namespaces.

+

Although it is possible to run the compiler this way, it is highly discouraged. If you care to examine the CMakeLists.txt (examples/nodeset/CMakeLists.txt), you will find out that the file server_nodeset.xml is compiled using the following function:

+
ua_generate_nodeset(
+    NAME "example"
+    FILE "${PROJECT_SOURCE_DIR}/examples/nodeset/server_nodeset.xml"
+    DEPENDS_TYPES "UA_TYPES"
+    DEPENDS_NS    "${UA_FILE_NS0}"
+)
+
+
+

If you look into the files generated by the nodeset compiler, you will see that it generated a method called extern UA_StatusCode myNS(UA_Server *server);. You need to include the header and source file and then call the myNS(server) method right after creating the server instance with UA_Server_new. This will automatically add all the nodes to the server and return UA_STATUSCODE_GOOD if there weren’t any errors. Additionally you need to compile the open62541 stack with the full NS0 by setting UA_NAMESPACE_ZERO=FULL in CMake. Otherwise the stack uses a subset where many nodes are not included and thus adding a custom nodeset may fail.

+

This is how you can use the nodeset compiler to compile simple NodeSet XMLs to be used by the open62541 stack.

+

For your convenience and for simpler use we also provide a CMake function which simplifies the use of the ua_generate_datatypes and ua_generate_nodeset function even more. +It is highly recommended to use this function: ua_generate_nodeset_and_datatypes. It uses some best practice settings and you only need to pass a name and the nodeset files. +Passing the .csv and .bsd files is optional and if not given, generating datatypes for that noteset will be skipped. You can also define dependencies between nodesets using the DEPENDS argument.

+

Here are some examples for the DI and PLCOpen nodesets:

+
# Generate types and namespace for DI
+ua_generate_nodeset_and_datatypes(
+    NAME "di"
+    FILE_CSV "${UA_NODESET_DIR}/DI/Opc.Ua.Di.NodeIds.csv"
+    FILE_BSD "${UA_NODESET_DIR}/DI/Opc.Ua.Di.Types.bsd"
+    FILE_NS "${UA_NODESET_DIR}/DI/Opc.Ua.Di.NodeSet2.xml"
+)
+
+# generate PLCopen namespace which is using DI
+ua_generate_nodeset_and_datatypes(
+    NAME "plc"
+    # PLCopen does not define custom types. Only generate the nodeset
+    FILE_NS "${UA_NODESET_DIR}/PLCopen/Opc.Ua.PLCopen.NodeSet2_V1.02.xml"
+    # PLCopen depends on the di nodeset, which must be generated before
+    DEPENDS "di"
+)
+
+
+
+
+

Creating object instances

+

One of the key benefits of defining object types is being able to create object instances fairly easily. Object instantiation is handled automatically when the typedefinition NodeId points to a valid ObjectType node. All Attributes and Methods contained in the objectType definition will be instantiated along with the object node.

+

While variables are copied from the objectType definition (allowing the user for example to attach new dataSources to them), methods are always only linked. This paradigm is identical to languages like C++: The method called is always the same piece of code, but the first argument is a pointer to an object. Likewise, in OPC UA, only one methodCallback can be attached to a specific methodNode. If that methodNode is called, the parent objectId will be passed to the method - it is the methods job to derefence which object instance it belongs to in that moment.

+

Let’s look at an example that will create a pump instance given the newly defined objectType from myNS.xml:

+
/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#include <signal.h>
+#include <stdio.h>
+#include "open62541.h"
+
+/* Files myNS.h and myNS.c are created from myNS.xml */
+#include "myNS.h"
+
+UA_Boolean running = true;
+
+static void stopHandler(int sign) {
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
+    running = false;
+}
+
+int main(int argc, char **argv) {
+    signal(SIGINT, stopHandler);
+    signal(SIGTERM, stopHandler);
+
+    UA_Server *server = UA_Server_new();
+    UA_ServerConfig_setDefault(UA_Server_getConfig(server));
+
+    UA_StatusCode retval = myNS(server);
+    /* Create nodes from nodeset */
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Could not add the example nodeset. "
+            "Check previous output for any error.");
+        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
+    } else {
+        UA_NodeId createdNodeId;
+        UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
+
+        object_attr.description = UA_LOCALIZEDTEXT("en-US", "A pump!");
+        object_attr.displayName = UA_LOCALIZEDTEXT("en-US", "Pump1");
+
+        // we assume that the myNS nodeset was added in namespace 2.
+        // You should always use UA_Server_addNamespace to check what the
+        // namespace index is for a given namespace URI. UA_Server_addNamespace
+        // will just return the index if it is already added.
+        UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0),
+                                UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                UA_QUALIFIEDNAME(1, "Pump1"),
+                                UA_NODEID_NUMERIC(2, 1002),
+                                object_attr, NULL, &createdNodeId);
+
+
+        retval = UA_Server_run(server, &running);
+    }
+
+    UA_Server_delete(server);
+    return (int) retval;
+}
+
+
+

Make sure you have updated the headers and libs in your project, then recompile and run the server. Make especially sure you have added myNS.h to your include folder.

+

As you can see instantiating an object is not much different from creating an object node. The main difference is that you must use an objectType node as typeDefinition.

+

If you start the server and inspect the nodes with UA Expert, you will find the pump in the objects folder, which look like this Fig. 2.

+
+Instantiated Pump Object with inherited children +
+

Fig. 2 Instantiated Pump Object with inherited children

+
+
+

As you can see the pump has inherited its parents attributes (ManufacturerName and ModelName). Methods, in contrast to objects and variables, are never cloned but instead only linked. The reason is that you will quite propably attach a method callback to a central method, not each object. Objects are instantiated if they are below the object you are creating, so any object (like an object called associatedServer of ServerType) that is part of pump will be instantiated as well. Objects above you object are never instantiated, so the same ServerType object in Fielddevices would have been omitted (the reason is that the recursive instantiation function protects itself from infinite recursions, which are hard to track when first ascending, then redescending into a tree).

+
+
+

Combination of multiple nodesets

+

In the previous section you have seen how you can use the nodeset compiler with one single nodeset which depends on the default nodeset (NS0) Opc.Ua.NodeSet2.xml. The nodeset compiler also supports nodesets which depend on more than one nodeset. We will show this use-case with the PLCopen nodeset. The PLCopen nodeset Opc.Ua.PLCopen.NodeSet2_V1.02.xml depends on the DI nodeset Opc.Ua.Di.NodeSet2.xml which then depends on NS0. This example is also shown in examples/nodeset/CMakeLists.txt.

+

This DI nodeset makes use of some additional data types in deps/ua-nodeset/DI/Opc.Ua.Di.Types.bsd. Since we also need these types within the generated code, we first need to compile the types into C code. The generated code is mainly a definition of the binary representation of the types required for encoding and decoding. The generation can be done using the ua_generate_datatypes CMake function, which uses the tools/generate_datatypes.py script:

+
ua_generate_datatypes(
+    NAME "ua_types_di"
+    TARGET_SUFFIX "types-di"
+    FILE_CSV "${UA_NODESET_DIR}/DI/Opc.Ua.Di.NodeIds.csv"
+    FILES_BSD "${UA_NODESET_DIR}/DI/Opc.Ua.Di.Types.bsd"
+)
+
+
+

The NAMESPACE_MAP parameter is an array of strings which indicates the mapping of specific namespace uris to the resulting namespace index. +This mapping is required for correct mapping of DataType nodes and their node ids. Currently we need to rely that the namespace is also added at this position in the final server. There is no automatic inferring yet (pull requests are warmly welcome). +If you are using the DEPENDS option on the ua_generate_nodeset_and_datatypes, the NAMESPACE_MAP is also inherited and you do not need to pass all mappings for dependent types. +The CSV and BSD files contain the metadata and definition for the types. TARGET_SUFFIX is used to create a new target with the name open62541-generator-TARGET_SUFFIX.

+

The ``NAMESPACE_MAP`` parameter is deprecated and no longer has any effect. The index of the nodeset is set automatically when it is loaded.

+

Now you can compile the DI nodeset XML using the following command:

+
ua_generate_nodeset(
+    NAME "di"
+    FILE "${UA_NODESET_DIR}/DI/Opc.Ua.Di.NodeSet2.xml"
+    TYPES_ARRAY "UA_TYPES_DI"
+    INTERNAL
+    DEPENDS_TYPES "UA_TYPES"
+    DEPENDS_NS    "${UA_NODESET_DIR}/Schema/Opc.Ua.NodeSet2.xml"
+    DEPENDS_TARGET "open62541-generator-types-di"
+)
+
+
+

There are now two new arguments: INTERNAL indicates that internal headers (and non public API) should be included within the generated source code. This is currently required for nodesets which use structures as data values, and will probably be fixed in the future. +The DEPENDS_TYPES types array argument is matched with the nodesets in the same order as they appear on the DEPENDS_TARGET parameter. It tells the nodeset compiler which types array it should use: UA_TYPES for Opc.Ua.NodeSet2.xml and UA_TYPES_DI for Opc.Ua.Di.NodeSet2.xml. This is the type array generated by the generate_datatypes.py script. The rest is similar to the example in previous section: Opc.Ua.NodeSet2.xml is assumed to exist already and only needs to be loaded for consistency checks, Opc.Ua.Di.NodeSet2.xml will be generated in the output file ua_namespace_di.c/.h

+

Next we can generate the PLCopen nodeset. Since it doesn’t require any additional datatype definitions, we can immediately start with the nodeset compiler command:

+
ua_generate_nodeset(
+    NAME "plc"
+    FILE "${UA_NODESET_DIR}/PLCopen/Opc.Ua.PLCopen.NodeSet2_V1.02.xml"
+    INTERNAL
+    DEPENDS_TYPES
+        "UA_TYPES" "UA_TYPES_DI"
+    DEPENDS_NS
+        "${UA_NODESET_DIR}/Schema/Opc.Ua.NodeSet2.xml"
+        "${UA_NODESET_DIR}/DI/Opc.Ua.Di.NodeSet2.xml"
+    DEPENDS_TARGET "open62541-generator-ns-di"
+)
+
+
+

This call is quite similar to the compilation of the DI nodeset. As you can see, we do not define any specific types array for the PLCopen nodeset. Since the PLCopen nodeset depends on the NS0 and DI nodeset, we need to tell the nodeset compiler that these two nodesets should be seen as already existing. Make sure that the order is the same as in your XML file, e.g., in this case the order indicated in Opc.Ua.PLCopen.NodeSet2_V1.02.xml -> UANodeSet -> Models -> Model.

+

As a result of the previous scripts you will have multiple source files:

+
    +
  • ua_types_di_generated.c

  • +
  • ua_types_di_generated.h

  • +
  • ua_types_di_generated_encoding_binary.h

  • +
  • ua_types_di_generated_handling.h

  • +
  • ua_namespace_di.c

  • +
  • ua_namespace_di.h

  • +
  • ua_namespace_plc.c

  • +
  • ua_namespace_plc.h

  • +
+

Finally you need to include all these files in your build process and call the corresponding initialization methods for the nodesets. An example application could look like this:

+
UA_Server *server = UA_Server_new();
+UA_ServerConfig_setDefault(UA_Server_getConfig(server));
+
+/* Create nodes from nodeset */
+UA_StatusCode retval = ua_namespace_di(server);
+if(retval != UA_STATUSCODE_GOOD) {
+    UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
+                 "Adding the DI namespace failed. Please check previous error output.");
+    UA_Server_delete(server);
+    return (int)UA_STATUSCODE_BADUNEXPECTEDERROR;
+}
+
+retval |= ua_namespace_plc(server);
+if(retval != UA_STATUSCODE_GOOD) {
+    UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
+                 "Adding the PLCopen namespace failed. Please check previous error output.");
+    UA_Server_delete(server);
+    return (int)UA_STATUSCODE_BADUNEXPECTEDERROR;
+}
+
+retval = UA_Server_run(server, &running);
+
+
+
+
+

Outstanding Companion Spec Issues

+

There are some Companion Specifications that currently cannot be compiled with the Nodeset compiler. +Which Companion Specifications are affected and what causes this is described below.

+
+
Safety, Glass, DEXPI

Do not specify a BSD file or BSD blob in the XML file. The BSD file is considered deprecated. However, it is currently still required by the Nodeser compiler.

+
+
I4AAS, RSL, FDI

Attempting to load will result in a runtime error (“Type-checking failed with error code BadTypeMismatch” or “Parent node not found”).

+
+
BACnet

Defines data types whose fields have the names signed or unsigned. This leads to errors when creating C structures, because signed and unsigned are keywords in C.

+
+
+
+
+

Automatic Nodesetinjection

+

The nodesetinjector is a mechanism for automatically loading nodeset/companion specifications during server initialization. +It provides a fast and easy way to load nodesets in all applications, focusing on the official OPCFoundation/UANodeset Repository ( https://github.com/OPCFoundation/UA-Nodeset ). +Specify the required information models using CMake.

+

Which nodesets are to be loaded is determined by the Cmake flag DUA_INFORMATION_MODEL_AUTOLOAD. All nodesets that are to be loaded automatically are listed here. +The naming is based on the folder name of the Companion Specification in the ua-nodeset folder.

+

A CMake call could look like this.

+
-DCMAKE_BUILD_TYPE=Debug
+-DUA_BUILD_EXAMPLES=ON
+-DUA_INFORMATION_MODEL_AUTOLOAD=DI;POWERLINK;PROFINET;MachineVision
+-DUA_NAMESPACE_ZERO=FULL
+
+
+

The order of nodesets is important! Nodesets that build on other nodesets must be placed after them in the list. +The following nodesets are currently supported:

+

DI, CNC, ISA95-JOBCONTROL, OpenSCS, AMB, AutoID, POWERLINK, IA, Machinery, +PackML, PNEM, PLCopen, MachineTool, PROFINET, MachineVision, FDT, +CommercialKitchenEquipment, PNRIO, Scales, Weihenstephan, Pumps, CAS, TMC, IJT

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/objects.inv b/static/doc/v1.4.0/objects.inv new file mode 100644 index 0000000000..c970581230 Binary files /dev/null and b/static/doc/v1.4.0/objects.inv differ diff --git a/static/doc/v1.4.0/plugin.html b/static/doc/v1.4.0/plugin.html new file mode 100644 index 0000000000..108cccf751 --- /dev/null +++ b/static/doc/v1.4.0/plugin.html @@ -0,0 +1,185 @@ + + + + + + + Plugin API — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/plugin_accesscontrol.html b/static/doc/v1.4.0/plugin_accesscontrol.html new file mode 100644 index 0000000000..4fcf51a39c --- /dev/null +++ b/static/doc/v1.4.0/plugin_accesscontrol.html @@ -0,0 +1,241 @@ + + + + + + + Access Control Plugin API — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Access Control Plugin API

+

The access control callback is used to authenticate sessions and grant access +rights accordingly.

+

The sessionId and sessionContext can be both NULL. This is the case +when, for example, a MonitoredItem (the underlying Subscription) is detached +from its Session but continues to run.

+
struct UA_AccessControl {
+    void *context;
+    void (*clear)(UA_AccessControl *ac);
+
+    /* Supported login mechanisms. The server endpoints are created from here. */
+    size_t userTokenPoliciesSize;
+    UA_UserTokenPolicy *userTokenPolicies;
+
+    /* Authenticate a session. The session context is attached to the session
+     * and later passed into the node-based access control callbacks. The new
+     * session is rejected if a StatusCode other than UA_STATUSCODE_GOOD is
+     * returned.
+     *
+     * Note that this callback can be called several times for a Session. For
+     * example when a Session is recovered (activated) on a new
+     * SecureChannel. */
+    UA_StatusCode (*activateSession)(UA_Server *server, UA_AccessControl *ac,
+                                     const UA_EndpointDescription *endpointDescription,
+                                     const UA_ByteString *secureChannelRemoteCertificate,
+                                     const UA_NodeId *sessionId,
+                                     const UA_ExtensionObject *userIdentityToken,
+                                     void **sessionContext);
+
+    /* Deauthenticate a session and cleanup */
+    void (*closeSession)(UA_Server *server, UA_AccessControl *ac,
+                         const UA_NodeId *sessionId, void *sessionContext);
+
+    /* Access control for all nodes*/
+    UA_UInt32 (*getUserRightsMask)(UA_Server *server, UA_AccessControl *ac,
+                                   const UA_NodeId *sessionId, void *sessionContext,
+                                   const UA_NodeId *nodeId, void *nodeContext);
+
+    /* Additional access control for variable nodes */
+    UA_Byte (*getUserAccessLevel)(UA_Server *server, UA_AccessControl *ac,
+                                  const UA_NodeId *sessionId, void *sessionContext,
+                                  const UA_NodeId *nodeId, void *nodeContext);
+
+    /* Additional access control for method nodes */
+    UA_Boolean (*getUserExecutable)(UA_Server *server, UA_AccessControl *ac,
+                                    const UA_NodeId *sessionId, void *sessionContext,
+                                    const UA_NodeId *methodId, void *methodContext);
+
+    /* Additional access control for calling a method node in the context of a
+     * specific object */
+    UA_Boolean (*getUserExecutableOnObject)(UA_Server *server, UA_AccessControl *ac,
+                                            const UA_NodeId *sessionId, void *sessionContext,
+                                            const UA_NodeId *methodId, void *methodContext,
+                                            const UA_NodeId *objectId, void *objectContext);
+
+    /* Allow adding a node */
+    UA_Boolean (*allowAddNode)(UA_Server *server, UA_AccessControl *ac,
+                               const UA_NodeId *sessionId, void *sessionContext,
+                               const UA_AddNodesItem *item);
+
+    /* Allow adding a reference */
+    UA_Boolean (*allowAddReference)(UA_Server *server, UA_AccessControl *ac,
+                                    const UA_NodeId *sessionId, void *sessionContext,
+                                    const UA_AddReferencesItem *item);
+
+    /* Allow deleting a node */
+    UA_Boolean (*allowDeleteNode)(UA_Server *server, UA_AccessControl *ac,
+                                  const UA_NodeId *sessionId, void *sessionContext,
+                                  const UA_DeleteNodesItem *item);
+
+    /* Allow deleting a reference */
+    UA_Boolean (*allowDeleteReference)(UA_Server *server, UA_AccessControl *ac,
+                                       const UA_NodeId *sessionId, void *sessionContext,
+                                       const UA_DeleteReferencesItem *item);
+
+    /* Allow browsing a node */
+    UA_Boolean (*allowBrowseNode)(UA_Server *server, UA_AccessControl *ac,
+                                  const UA_NodeId *sessionId, void *sessionContext,
+                                  const UA_NodeId *nodeId, void *nodeContext);
+
+#ifdef UA_ENABLE_SUBSCRIPTIONS
+    /* Allow transfer of a subscription to another session. The Server shall
+     * validate that the Client of that Session is operating on behalf of the
+     * same user */
+    UA_Boolean (*allowTransferSubscription)(UA_Server *server, UA_AccessControl *ac,
+                                            const UA_NodeId *oldSessionId, void *oldSessionContext,
+                                            const UA_NodeId *newSessionId, void *newSessionContext);
+#endif
+
+#ifdef UA_ENABLE_HISTORIZING
+    /* Allow insert,replace,update of historical data */
+    UA_Boolean (*allowHistoryUpdateUpdateData)(UA_Server *server, UA_AccessControl *ac,
+                                               const UA_NodeId *sessionId, void *sessionContext,
+                                               const UA_NodeId *nodeId,
+                                               UA_PerformUpdateType performInsertReplace,
+                                               const UA_DataValue *value);
+
+    /* Allow delete of historical data */
+    UA_Boolean (*allowHistoryUpdateDeleteRawModified)(UA_Server *server, UA_AccessControl *ac,
+                                                      const UA_NodeId *sessionId, void *sessionContext,
+                                                      const UA_NodeId *nodeId,
+                                                      UA_DateTime startTimestamp,
+                                                      UA_DateTime endTimestamp,
+                                                      bool isDeleteModified);
+#endif
+};
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/plugin_eventloop.html b/static/doc/v1.4.0/plugin_eventloop.html new file mode 100644 index 0000000000..3be08dabfd --- /dev/null +++ b/static/doc/v1.4.0/plugin_eventloop.html @@ -0,0 +1,752 @@ + + + + + + + Event Loop Subsystem — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Event Loop Subsystem

+

An OPC UA-enabled application can have several clients and servers. And +server can serve different transport-level protocols for OPC UA. The +EventLoop is a central module that provides a unified control-flow for all of +these. Hence, several applications can share an EventLoop.

+

The EventLoop and the ConnectionManager implementation is +architecture-specific. The goal is to have a single call to “poll” (epoll, +kqueue, …) in the EventLoop that covers all ConnectionManagers. Hence the +EventLoop plugin implementation must know implementation details of the +ConnectionManager implementations. So the EventLoop can extract socket +information, etc. from the ConnectionManagers.

+
+

Timer Policies

+

A timer comes with a cyclic interval in which a callback is executed. If an +application is congested the interval can be missed. Two different policies +can be used when this happens. Either schedule the next execution after the +interval has elapsed again from the current time onwards or stay within the +regular interval with respect to the original basetime.

+
typedef enum {
+    UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME,
+    UA_TIMER_HANDLE_CYCLEMISS_WITH_BASETIME
+} UA_TimerPolicy;
+
+
+
+
+

Event Loop

+

The EventLoop implementation is part of the selected architecture. For +example, “Win32/POSIX” stands for a Windows environment with an EventLoop +that uses the POSIX API. Several EventLoops can be instantiated in parallel. +But the globally defined functions are the same everywhere.

+
typedef void (*UA_Callback)(void *application, void *context);
+
+/* Delayed callbacks are executed not when they are registered, but in the
+ * following EventLoop cycle */
+typedef struct UA_DelayedCallback {
+    struct UA_DelayedCallback *next; /* Singly-linked list */
+    UA_Callback callback;
+    void *application;
+    void *context;
+} UA_DelayedCallback;
+
+typedef enum {
+    UA_EVENTLOOPSTATE_FRESH = 0,
+    UA_EVENTLOOPSTATE_STOPPED,
+    UA_EVENTLOOPSTATE_STARTED,
+    UA_EVENTLOOPSTATE_STOPPING /* Stopping in progress, needs EventLoop
+                                * cycles to finish */
+} UA_EventLoopState;
+
+struct UA_EventLoop {
+    /* Configuration
+     * ~~~~~~~~~~~~~~~
+     * The configuration should be set before the EventLoop is started */
+
+    const UA_Logger *logger;
+    UA_KeyValueMap *params; /* See the implementation-specific documentation */
+
+    /* EventLoop Lifecycle
+     * ~~~~~~~~~~~~~~~~~~~~
+     * The EventLoop state also controls the state of the configured
+     * EventSources. Stopping the EventLoop gracefully closes e.g. the open
+     * network connections. The only way to process incoming events is to call
+     * the 'run' method. Events are then triggering their respective callbacks
+     * from within that method.*/
+
+    const volatile UA_EventLoopState state; /* Only read the state from outside */
+
+    /* Start the EventLoop and start all already registered EventSources */
+    UA_StatusCode (*start)(UA_EventLoop *el);
+
+    /* Stop all EventSources. This is asynchronous and might need a few
+     * iterations of the main-loop to succeed. */
+    void (*stop)(UA_EventLoop *el);
+
+    /* Process events for at most "timeout" ms or until an unrecoverable error
+     * occurs. If timeout==0, then only already received events are
+     * processed. */
+    UA_StatusCode (*run)(UA_EventLoop *el, UA_UInt32 timeout);
+
+    /* Clean up the EventLoop and free allocated memory. Can fail if the
+     * EventLoop is not stopped. */
+    UA_StatusCode (*free)(UA_EventLoop *el);
+
+    /* EventLoop Time Domain
+     * ~~~~~~~~~~~~~~~~~~~~~
+     * Each EventLoop instance can manage its own time domain. This affects the
+     * execution of timed/cyclic callbacks and time-based sending of network
+     * packets (if this is implemented). Managing independent time domains is
+     * important when different parts of a system a synchronized to different
+     * external (network-wide) clocks.
+     *
+     * Note that the logger configured in the EventLoop generates timestamps
+     * internally as well. If the logger uses a different time domain than the
+     * EventLoop, discrepancies may appear in the logs.
+     *
+     * The time domain of the EventLoop is exposed via the following functons.
+     * See `open62541/types.h` for the documentation of their equivalent
+     * globally defined functions. */
+
+    UA_DateTime (*dateTime_now)(UA_EventLoop *el);
+    UA_DateTime (*dateTime_nowMonotonic)(UA_EventLoop *el);
+    UA_Int64    (*dateTime_localTimeUtcOffset)(UA_EventLoop *el);
+
+    /* Timed Callbacks
+     * ~~~~~~~~~~~~~~~
+     * Cyclic callbacks are executed regularly with an interval.
+     * A timed callback is executed only once. */
+
+    /* Time of the next cyclic callback. Returns the max DateTime if no cyclic
+     * callback is registered. */
+    UA_DateTime (*nextCyclicTime)(UA_EventLoop *el);
+
+    /* The execution interval is in ms. Returns the callbackId if the pointer is
+     * non-NULL. */
+    UA_StatusCode
+    (*addCyclicCallback)(UA_EventLoop *el, UA_Callback cb, void *application,
+                         void *data, UA_Double interval_ms, UA_DateTime *baseTime,
+                         UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId);
+
+    UA_StatusCode
+    (*modifyCyclicCallback)(UA_EventLoop *el, UA_UInt64 callbackId,
+                            UA_Double interval_ms, UA_DateTime *baseTime,
+                            UA_TimerPolicy timerPolicy);
+
+    void (*removeCyclicCallback)(UA_EventLoop *el, UA_UInt64 callbackId);
+
+    /* Like a cyclic callback, but executed only once */
+    UA_StatusCode
+    (*addTimedCallback)(UA_EventLoop *el, UA_Callback cb, void *application,
+                        void *data, UA_DateTime date, UA_UInt64 *callbackId);
+
+    /* Delayed Callbacks
+     * ~~~~~~~~~~~~~~~~~
+     * Delayed callbacks are executed once in the next iteration of the
+     * EventLoop and then deregistered automatically. A typical use case is to
+     * delay a resource cleanup to a point where it is known that the resource
+     * has no remaining users.
+     *
+     * The delayed callbacks are processed in each of the cycle of the EventLoop
+     * between the handling of timed cyclic callbacks and polling for (network)
+     * events. The memory for the delayed callback is *NOT* automatically freed
+     * after the execution. */
+
+    void (*addDelayedCallback)(UA_EventLoop *el, UA_DelayedCallback *dc);
+    void (*removeDelayedCallback)(UA_EventLoop *el, UA_DelayedCallback *dc);
+
+    /* EventSources
+     * ~~~~~~~~~~~~
+     * EventSources are stored in a singly-linked list for direct access. But
+     * only the below methods shall be used for adding and removing - this
+     * impacts the lifecycle of the EventSource. For example it may be
+     * auto-started if the EventLoop is already running. */
+
+    /* Linked list of EventSources */
+    UA_EventSource *eventSources;
+
+    /* Register the ES. Immediately starts the ES if the EventLoop is already
+     * started. Otherwise the ES is started together with the EventLoop. */
+    UA_StatusCode
+    (*registerEventSource)(UA_EventLoop *el, UA_EventSource *es);
+
+    /* Stops the EventSource before deregistrering it */
+    UA_StatusCode
+    (*deregisterEventSource)(UA_EventLoop *el, UA_EventSource *es);
+};
+
+
+
+
+

Event Source

+

Event Sources are attached to an EventLoop. Typically the event source and +the EventLoop are developed together and share a private API in the +background.

+
typedef enum {
+    UA_EVENTSOURCESTATE_FRESH = 0,
+    UA_EVENTSOURCESTATE_STOPPED,      /* Registered but stopped */
+    UA_EVENTSOURCESTATE_STARTING,
+    UA_EVENTSOURCESTATE_STARTED,
+    UA_EVENTSOURCESTATE_STOPPING      /* Stopping in progress, needs
+                                       * EventLoop cycles to finish */
+} UA_EventSourceState;
+
+/* Type-tag for proper casting of the difference EventSource (e.g. when they are
+ * looked up via UA_EventLoop_findEventSource). */
+typedef enum {
+    UA_EVENTSOURCETYPE_CONNECTIONMANAGER,
+    UA_EVENTSOURCETYPE_INTERRUPTMANAGER
+} UA_EventSourceType;
+
+struct UA_EventSource {
+    struct UA_EventSource *next; /* Singly-linked list for use by the
+                                  * application that registered the ES */
+
+    UA_EventSourceType eventSourceType;
+
+    /* Configuration
+     * ~~~~~~~~~~~~~ */
+    UA_String name;                 /* Unique name of the ES */
+    UA_EventLoop *eventLoop;        /* EventLoop where the ES is registered */
+    UA_KeyValueMap params;
+
+    /* Lifecycle
+     * ~~~~~~~~~ */
+    UA_EventSourceState state;
+    UA_StatusCode (*start)(UA_EventSource *es);
+    void (*stop)(UA_EventSource *es); /* Asynchronous. Iterate theven EventLoop
+                                       * until the EventSource is stopped. */
+    UA_StatusCode (*free)(UA_EventSource *es);
+};
+
+
+
+
+

Connection Manager

+

Every Connection is created by a ConnectionManager. Every ConnectionManager +belongs to just one application. A ConnectionManager can act purely as a +passive “Factory” for Connections. But it can also be stateful. For example, +it can keep a session to an MQTT broker open which is used by individual +connections that are each bound to an MQTT topic.

+
/* The ConnectionCallback is the only interface from the connection back to
+ * the application.
+ *
+ * - The connectionId is initially unknown to the target application and
+ *   "announced" to the application when first used first in this callback.
+ *
+ * - The context is attached to the connection. Initially a default context
+ *   is set. The context can be replaced within the callback (via the
+ *   double-pointer).
+ *
+ * - The state argument indicates the lifecycle of the connection. Every
+ *   connection calls the callback a last time with UA_CONNECTIONSTATE_CLOSING.
+ *   Protocols individually can forward diagnostic information relevant to the
+ *   state as part of the key-value parameters.
+ *
+ * - The parameters are a key-value list with additional information. The
+ *   possible keys and their meaning are documented for the individual
+ *   ConnectionManager implementations.
+ *
+ * - The msg ByteString is the message (or packet) received on the
+ *   connection. Can be empty. */
+typedef void
+(*UA_ConnectionManager_connectionCallback)
+     (UA_ConnectionManager *cm, uintptr_t connectionId,
+      void *application, void **connectionContext, UA_ConnectionState state,
+      const UA_KeyValueMap *params, UA_ByteString msg);
+
+struct UA_ConnectionManager {
+    /* Every ConnectionManager is treated like an EventSource from the
+     * perspective of the EventLoop. */
+    UA_EventSource eventSource;
+
+    /* Name of the protocol supported by the ConnectionManager. For example
+     * "mqtt", "udp", "mqtt". */
+    UA_String protocol;
+
+    /* Open a Connection
+     * ~~~~~~~~~~~~~~~~~
+     * Connecting is asynchronous. The connection-callback is called when the
+     * connection is open (status=GOOD) or aborted (status!=GOOD) when
+     * connecting failed.
+     *
+     * Some ConnectionManagers can also passively listen for new connections.
+     * Configuration parameters for this are passed via the key-value list. The
+     * `context` pointer of the listening connection is also set as the initial
+     * context of newly opened connections.
+     *
+     * The parameters describe the connection. For example hostname and port
+     * (for TCP). Other protocols (e.g. MQTT, AMQP, etc.) may required
+     * additional arguments to open a connection in the key-value list.
+     *
+     * The provided context is set as the initial context attached to this
+     * connection. It is already set before the first call to
+     * connectionCallback.
+     *
+     * The connection can be opened synchronously or asynchronously.
+     *
+     * - For synchronous connection, the connectionCallback is called with the
+     *   status UA_CONNECTIONSTATE_ESTABLISHED immediately from within the
+     *   openConnection operation.
+     *
+     * - In the asynchronous case the connectionCallback is called immediately
+     *   from within the openConnection operation with the status
+     *   UA_CONNECTIONSTATE_OPENING. The connectionCallback is called with the
+     *   status UA_CONNECTIONSTATE_ESTABLISHED once the connection has fully
+     *   opened.
+     *
+     * Note that a single call to openConnection might open multiple
+     * connections. For example listening on IPv4 and IPv6 for a single
+     * hostname. Each protocol implementation documents whether multiple
+     * connections might be opened at once. */
+    UA_StatusCode
+    (*openConnection)(UA_ConnectionManager *cm, const UA_KeyValueMap *params,
+                      void *application, void *context,
+                      UA_ConnectionManager_connectionCallback connectionCallback);
+
+    /* Send a message over a Connection
+     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+     * Sending is asynchronous. That is, the function returns before the message
+     * is ACKed from remote. The memory for the buffer is expected to be
+     * allocated with allocNetworkBuffer and is released internally (also if
+     * sending fails).
+     *
+     * Some ConnectionManagers can accept additional parameters for sending. For
+     * example a tx-time for sending in time-synchronized TSN settings. */
+    UA_StatusCode
+    (*sendWithConnection)(UA_ConnectionManager *cm, uintptr_t connectionId,
+                          const UA_KeyValueMap *params, UA_ByteString *buf);
+
+    /* Close a Connection
+     * ~~~~~~~~~~~~~~~~~~
+     * When a connection is closed its `connectionCallback` is called with
+     * (status=BadConnectionClosed, msg=empty). Then the connection is cleared
+     * up inside the ConnectionManager. This is the case both for connections
+     * that are actively closed and those that are closed remotely. The return
+     * code is non-good only if the connection is already closed. */
+    UA_StatusCode
+    (*closeConnection)(UA_ConnectionManager *cm, uintptr_t connectionId);
+
+    /* Buffer Management
+     * ~~~~~~~~~~~~~~~~~
+     * Each ConnectionManager allocates and frees his own memory for the network
+     * buffers. This enables, for example, zero-copy neworking mechanisms. The
+     * connectionId is part of the API to enable cases where memory is
+     * statically allocated for every connection */
+    UA_StatusCode
+    (*allocNetworkBuffer)(UA_ConnectionManager *cm, uintptr_t connectionId,
+                          UA_ByteString *buf, size_t bufSize);
+    void
+    (*freeNetworkBuffer)(UA_ConnectionManager *cm, uintptr_t connectionId,
+                         UA_ByteString *buf);
+};
+
+
+
+
+

Interrupt Manager

+

The Interrupt Manager allows to register to listen for system interrupts. +Triggering the interrupt calls the callback associated with it.

+

The implementations of the interrupt manager for the different platforms +shall be designed such that:

+
    +
  • Registered interrupts are only intercepted from within the running EventLoop

  • +
  • Processing an interrupt in the EventLoop is handled similarly to handling a +network event: all methods and also memory allocation are available from +within the interrupt callback.

  • +
+
/* Interrupts can have additional key-value 'instanceInfos' for each individual
+ * triggering. See the architecture-specific documentation. */
+typedef void
+(*UA_InterruptCallback)(UA_InterruptManager *im,
+                        uintptr_t interruptHandle, void *interruptContext,
+                        const UA_KeyValueMap *instanceInfos);
+
+struct UA_InterruptManager {
+    /* Every InterruptManager is treated like an EventSource from the
+     * perspective of the EventLoop. */
+    UA_EventSource eventSource;
+
+    /* Register an interrupt. The handle and context information is passed
+     * through to the callback.
+     *
+     * The interruptHandle is a numerical identifier of the interrupt. In some
+     * cases, such as POSIX signals, this is enough information to register
+     * callback. For other interrupt systems (architectures) additional
+     * parameters may be required and can be passed in via the parameters
+     * key-value list. See the implementation-specific documentation.
+     *
+     * The interruptContext is opaque user-defined information and passed
+     * through to the callback without modification. */
+    UA_StatusCode
+    (*registerInterrupt)(UA_InterruptManager *im, uintptr_t interruptHandle,
+                         const UA_KeyValueMap *params,
+                         UA_InterruptCallback callback, void *interruptContext);
+
+    /* Remove a registered interrupt. Returns no error code if the interrupt is
+     * already deregistered. */
+    void
+    (*deregisterInterrupt)(UA_InterruptManager *im, uintptr_t interruptHandle);
+};
+
+
+
+
+

POSIX-Specific Implementation

+

The POSIX compatibility of WIN32 is ‘close enough’. So a joint implementation +is provided.

+
#if defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32)
+
+UA_EventLoop *
+UA_EventLoop_new_POSIX(const UA_Logger *logger);
+
+
+
+

TCP Connection Manager

+

Listens on the network and manages TCP connections. This should be available +for all architectures.

+

The openConnection callback is used to create both client and server +sockets. A server socket listens and accepts incoming connections (creates an +active connection). This is distinguished by the key-value parameters passed +to openConnection. Note that a single call to openConnection for a server +connection may actually create multiple connections (one per hostname / +device).

+

The connectionCallback of the server socket and context of the server +socket is reused for each new connection. But the key-value parameters for +the first callback are different between server and client connections.

+

The following list defines the parameters and their type. Note that some +parameters are only set for the first callback when a new connection opens.

+

Configuration parameters for the entire ConnectionManager:

+
+
0:recv-bufsize [uint32]

Size of the buffer that is allocated for receiving messages (default 64kB).

+
+
+

Open Connection Parameters:

+
+
0:address [string | array of string]

Hostname or IPv4/v6 address for the connection (scalar parameter required +for active connections). For listen-connections the address contains the +local hostnames or IP addresses for listening. If undefined, listen on all +interfaces INADDR_ANY. (default: undefined)

+
+
0:port [uint16]

Port of the target host (required).

+
+
0:listen [boolean]

Listen-connection or active-connection (default: false)

+
+
0:validate [boolean]

If true, the connection setup will act as a dry-run without actually +creating any connection but solely validating the provided parameters +(default: false)

+
+
+

Active Connection Connection Callback Parameters (first callback only):

+
+
0:remote-address [string]

Address of the remote side (hostname or IP address).

+
+
+

Listen Connection Connection Callback Parameters (first callback only):

+
+
0:listen-address [string]

Local address (IP or hostname) for the new listen-connection.

+
+
0:listen-port [uint16]

Port on which the new connection listens.

+
+
+

Send Parameters:

+

No additional parameters for sending over an established TCP socket +defined.

+
UA_ConnectionManager *
+UA_ConnectionManager_new_POSIX_TCP(const UA_String eventSourceName);
+
+
+
+
+

UDP Connection Manager

+

Manages UDP connections. This should be available for all architectures. The +configuration parameters have to set before calling _start to take effect.

+

Configuration Parameters:

+
+
0:recv-bufsize [uint32]

Size of the buffer that is allocated for receiving messages (default +64kB).

+
+
+

Open Connection Parameters:

+
+
0:listen [boolean]

Use the connection for listening or for sending (default: false)

+
+
0:address [string | string array]

Hostname (or IPv4/v6 address) for sending or receiving. A scalar is +required for sending. For listening a string array for the list-hostnames +is possible as well (default: list on all hostnames).

+
+
0:port [uint16]

Port for sending or listening (required).

+
+
0:interface [string]

Network interface for listening or sending (e.g. when using multicast +addresses)

+
+
0:ttl [uint32]

Multicast time to live, (optional, default: 1 - meaning multicast is +available only to the local subnet).

+
+
0:loopback [boolean]

Whether or not to use multicast loopback, enabling local interfaces +belonging to the multicast group to receive packages. (default: enabled).

+
+
0:reuse [boolean]

Enables sharing of the same listening address on different sockets +(default: disabled).

+
+
0:sockpriority [uint32]

The socket priority (optional) - only available on linux. packets with a +higher priority may be processed first depending on the selected device +queueing discipline. Setting a priority outside the range 0 to 6 requires +the CAP_NET_ADMIN capability (on Linux).

+
+
0:validate [boolean]

If true, the connection setup will act as a dry-run without actually +creating any connection but solely validating the provided parameters +(default: false)

+
+
+

Connection Callback Paramters:

+
+
0:remote-address [string]

Contains the remote IP address.

+
+
0:remote-port [uint16]

Contains the remote port.

+
+
+

Send Parameters:

+

No additional parameters for sending over an UDP connection defined.

+
UA_ConnectionManager *
+UA_ConnectionManager_new_POSIX_UDP(const UA_String eventSourceName);
+
+
+
+
+

Ethernet Connection Manager

+

Listens on the network and manages UDP connections. This should be available +for all architectures. The configuration parameters have to set before +calling _start to take effect.

+

Open Connection Parameters:

+
+
0:listen [bool]

The connection is either for sending or for listening (default: false).

+
+
0:interface [string]

The name of the Ethernet interface to use (required).

+
+
0:address [string]

MAC target address consisting of six groups of hexadecimal digits +separated by hyphens such as 01-23-45-67-89-ab. For sending this is a +required parameter. For listening this is a multicast address that the +connections tries to register for.

+
+
0:ethertype [uint16]

EtherType for sending and receiving frames (optional). For listening +connections, this filters out all frames with different EtherTypes.

+
+
0:promiscuous [bool]

Receive frames also for different target addresses. Defined only for +listening connections (default: false).

+
+
0:vid [uint16]

12-bit VLAN identifier (optional for send connections).

+
+
0:pcp [byte]

3-bit priority code point (optional for send connections).

+
+
0:dei [bool]

1-bit drop eligible indicator (optional for seond connections).

+
+
0:validate [boolean]

If true, the connection setup will act as a dry-run without actually +creating any connection but solely validating the provided parameters +(default: false)

+
+
+

Send Parameters:

+

No additional parameters for sending over an Ethernet connection defined.

+
UA_ConnectionManager *
+UA_ConnectionManager_new_POSIX_Ethernet(const UA_String eventSourceName);
+
+
+
+
+

MQTT Connection Manager

+

The MQTT ConnectionManager reuses the TCP ConnectionManager that is +configured in the EventLoop. Hence the MQTT ConnectionManager is platform +agnostic and does not require porting. An MQTT connection is for a +combination of broker and topic. The MQTT ConnectionManager can group +connections to the same broker in the background. Hence adding multiple +connections for the same broker is “cheap”. To have individual control, +separate connections are created for each topic and for each direction +(publishing / subscribing).

+

Open Connection Parameters:

+
+
0:address [string]

Hostname or IPv4/v6 address of the MQTT broker (required).

+
+
0:port [uint16]

Port of the MQTT broker (default: 1883).

+
+
0:username [string]

Username to use (default: none)

+
+
0:password [string]

Password to use (default: none)

+
+
0:keep-alive [uint16]

Number of seconds for the keep-alive (ping) (default: 400).

+
+
0:validate [boolean]

If true, the connection setup will act as a dry-run without actually +creating any connection but solely validating the provided parameters +(default: false)

+
+
0:topic [string]

Topic to which the connection is associated (required).

+
+
0:subscribe [bool]

Subscribe to the topic (default: false). Otherwise it is only possible to +publish on the topic. Subscribed topics can also be published to.

+
+
+

Connection Callback Parameters:

+
+
0:topic [string]

The value set during connect.

+
+
0:subscribe [bool]

The value set during connect.

+
+
+

Send Parameters:

+

No additional parameters for sending over an Ethernet connection defined.

+
UA_ConnectionManager *
+UA_ConnectionManager_new_MQTT(const UA_String eventSourceName);
+
+
+
+
+

Signal Interrupt Manager

+

Create an instance of the interrupt manager that handles POSX signals. This +interrupt manager takes the numerical interrupt identifiers from <signal.h> +for the interruptHandle.

+
UA_InterruptManager *
+UA_InterruptManager_new_POSIX(const UA_String eventSourceName);
+
+#endif /* defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) */
+
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/plugin_log.html b/static/doc/v1.4.0/plugin_log.html new file mode 100644 index 0000000000..f7c55913e0 --- /dev/null +++ b/static/doc/v1.4.0/plugin_log.html @@ -0,0 +1,269 @@ + + + + + + + Logging Plugin API — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Logging Plugin API

+

Servers and clients define a logger in their configuration. The logger is a +plugin. A default plugin that logs to stdout is provided as an example. +The logger plugin is stateful and can point to custom data. So it is possible +to keep open file handlers in the logger context.

+

Every log message consists of a log level, a log category and a string +message content. The timestamp of the log message is created within the +logger.

+
typedef enum {
+    UA_LOGLEVEL_TRACE   = 100,
+    UA_LOGLEVEL_DEBUG   = 200,
+    UA_LOGLEVEL_INFO    = 300,
+    UA_LOGLEVEL_WARNING = 400,
+    UA_LOGLEVEL_ERROR   = 500,
+    UA_LOGLEVEL_FATAL   = 600
+} UA_LogLevel;
+
+#define UA_LOGCATEGORIES 10
+
+typedef enum {
+    UA_LOGCATEGORY_NETWORK = 0,
+    UA_LOGCATEGORY_SECURECHANNEL,
+    UA_LOGCATEGORY_SESSION,
+    UA_LOGCATEGORY_SERVER,
+    UA_LOGCATEGORY_CLIENT,
+    UA_LOGCATEGORY_USERLAND,
+    UA_LOGCATEGORY_SECURITYPOLICY,
+    UA_LOGCATEGORY_EVENTLOOP,
+    UA_LOGCATEGORY_PUBSUB,
+    UA_LOGCATEGORY_DISCOVERY
+} UA_LogCategory;
+
+typedef struct UA_Logger {
+    /* Log a message. The message string and following varargs are formatted
+     * according to the rules of the printf command. Use the convenience macros
+     * below that take the minimum log level defined in ua_config.h into
+     * account. */
+    void (*log)(void *logContext, UA_LogLevel level, UA_LogCategory category,
+                const char *msg, va_list args);
+
+    void *context; /* Logger state */
+
+    void (*clear)(struct UA_Logger *logger); /* Clean up the logger plugin */
+} UA_Logger;
+
+static UA_INLINE UA_FORMAT(3,4) void
+UA_LOG_TRACE(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) {
+#if UA_LOGLEVEL <= 100
+    if(!logger || !logger->log)
+        return;
+    va_list args; va_start(args, msg);
+    logger->log(logger->context, UA_LOGLEVEL_TRACE, category, msg, args);
+    va_end(args);
+#else
+    (void) logger;
+    (void) category;
+    (void) msg;
+#endif
+}
+
+static UA_INLINE UA_FORMAT(3,4) void
+UA_LOG_DEBUG(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) {
+#if UA_LOGLEVEL <= 200
+    if(!logger || !logger->log)
+        return;
+    va_list args; va_start(args, msg);
+    logger->log(logger->context, UA_LOGLEVEL_DEBUG, category, msg, args);
+    va_end(args);
+#else
+    (void) logger;
+    (void) category;
+    (void) msg;
+#endif
+}
+
+static UA_INLINE UA_FORMAT(3,4) void
+UA_LOG_INFO(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) {
+#if UA_LOGLEVEL <= 300
+    if(!logger || !logger->log)
+        return;
+    va_list args; va_start(args, msg);
+    logger->log(logger->context, UA_LOGLEVEL_INFO, category, msg, args);
+    va_end(args);
+#else
+    (void) logger;
+    (void) category;
+    (void) msg;
+#endif
+}
+
+static UA_INLINE UA_FORMAT(3,4) void
+UA_LOG_WARNING(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) {
+#if UA_LOGLEVEL <= 400
+    if(!logger || !logger->log)
+        return;
+    va_list args; va_start(args, msg);
+    logger->log(logger->context, UA_LOGLEVEL_WARNING, category, msg, args);
+    va_end(args);
+#else
+    (void) logger;
+    (void) category;
+    (void) msg;
+#endif
+}
+
+static UA_INLINE UA_FORMAT(3,4) void
+UA_LOG_ERROR(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) {
+#if UA_LOGLEVEL <= 500
+    if(!logger || !logger->log)
+        return;
+    va_list args; va_start(args, msg);
+    logger->log(logger->context, UA_LOGLEVEL_ERROR, category, msg, args);
+    va_end(args);
+#else
+    (void) logger;
+    (void) category;
+    (void) msg;
+#endif
+}
+
+static UA_INLINE UA_FORMAT(3,4) void
+UA_LOG_FATAL(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) {
+#if UA_LOGLEVEL <= 600
+    if(!logger || !logger->log)
+        return;
+    va_list args; va_start(args, msg);
+    logger->log(logger->context, UA_LOGLEVEL_FATAL, category, msg, args);
+    va_end(args);
+#else
+    (void) logger;
+    (void) category;
+    (void) msg;
+#endif
+}
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/plugin_nodestore.html b/static/doc/v1.4.0/plugin_nodestore.html new file mode 100644 index 0000000000..1fc6ce811c --- /dev/null +++ b/static/doc/v1.4.0/plugin_nodestore.html @@ -0,0 +1,976 @@ + + + + + + + Node Store Plugin API — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Node Store Plugin API

+

Warning!! The structures defined in this section are only relevant for +the developers of custom Nodestores. The interaction with the information +model is possible only via the OPC UA Services. So the following +sections are purely informational so that users may have a clear mental +model of the underlying representation.

+
+

Node Lifecycle: Constructors, Destructors and Node Contexts

+

To finalize the instantiation of a node, a (user-defined) constructor +callback is executed. There can be both a global constructor for all nodes +and node-type constructor specific to the TypeDefinition of the new node +(attached to an ObjectTypeNode or VariableTypeNode).

+

In the hierarchy of ObjectTypes and VariableTypes, only the constructor of +the (lowest) type defined for the new node is executed. Note that every +Object and Variable can have only one isTypeOf reference. But type-nodes +can technically have several hasSubType references to implement multiple +inheritance. Issues of (multiple) inheritance in the constructor need to be +solved by the user.

+

When a node is destroyed, the node-type destructor is called before the +global destructor. So the overall node lifecycle is as follows:

+
    +
  1. Global Constructor (set in the server config)

  2. +
  3. Node-Type Constructor (for VariableType or ObjectTypes)

  4. +
  5. (Usage-period of the Node)

  6. +
  7. Node-Type Destructor

  8. +
  9. Global Destructor

  10. +
+

The constructor and destructor callbacks can be set to NULL and are not +used in that case. If the node-type constructor fails, the global destructor +will be called before removing the node. The destructors are assumed to never +fail.

+

Every node carries a user-context and a constructor-context pointer. The +user-context is used to attach custom data to a node. But the (user-defined) +constructors and destructors may replace the user-context pointer if they +wish to do so. The initial value for the constructor-context is NULL. +When the AddNodes service is used over the network, the user-context +pointer of the new node is also initially set to NULL.

+
+

Global Node Lifecycle

+

Global constructor and destructor callbacks used for every node type. +To be set in the server config.

+
typedef struct {
+    /* Can be NULL. May replace the nodeContext */
+    UA_StatusCode (*constructor)(UA_Server *server,
+                                 const UA_NodeId *sessionId, void *sessionContext,
+                                 const UA_NodeId *nodeId, void **nodeContext);
+
+    /* Can be NULL. The context cannot be replaced since the node is destroyed
+     * immediately afterwards anyway. */
+    void (*destructor)(UA_Server *server,
+                       const UA_NodeId *sessionId, void *sessionContext,
+                       const UA_NodeId *nodeId, void *nodeContext);
+
+    /* Can be NULL. Called during recursive node instantiation. While mandatory
+     * child nodes are automatically created if not already present, optional child
+     * nodes are not. This callback can be used to define whether an optional child
+     * node should be created.
+     *
+     * @param server The server executing the callback
+     * @param sessionId The identifier of the session
+     * @param sessionContext Additional data attached to the session in the
+     *        access control layer
+     * @param sourceNodeId Source node from the type definition. If the new node
+     *        shall be created, it will be a copy of this node.
+     * @param targetParentNodeId Parent of the potential new child node
+     * @param referenceTypeId Identifies the reference type which that the parent
+     *        node has to the new node.
+     * @return Return UA_TRUE if the child node shall be instantiated,
+     *         UA_FALSE otherwise. */
+    UA_Boolean (*createOptionalChild)(UA_Server *server,
+                                      const UA_NodeId *sessionId,
+                                      void *sessionContext,
+                                      const UA_NodeId *sourceNodeId,
+                                      const UA_NodeId *targetParentNodeId,
+                                      const UA_NodeId *referenceTypeId);
+
+    /* Can be NULL. Called when a node is to be copied during recursive
+     * node instantiation. Allows definition of the NodeId for the new node.
+     * If the callback is set to NULL or the resulting NodeId is UA_NODEID_NUMERIC(X,0)
+     * an unused nodeid in namespace X will be used. E.g. passing UA_NODEID_NULL will
+     * result in a NodeId in namespace 0.
+     *
+     * @param server The server executing the callback
+     * @param sessionId The identifier of the session
+     * @param sessionContext Additional data attached to the session in the
+     *        access control layer
+     * @param sourceNodeId Source node of the copy operation
+     * @param targetParentNodeId Parent node of the new node
+     * @param referenceTypeId Identifies the reference type which that the parent
+     *        node has to the new node. */
+    UA_StatusCode (*generateChildNodeId)(UA_Server *server,
+                                         const UA_NodeId *sessionId, void *sessionContext,
+                                         const UA_NodeId *sourceNodeId,
+                                         const UA_NodeId *targetParentNodeId,
+                                         const UA_NodeId *referenceTypeId,
+                                         UA_NodeId *targetNodeId);
+} UA_GlobalNodeLifecycle;
+
+
+
+
+

Node Type Lifecycle

+

Constructor and destructors for specific object and variable types.

+
typedef struct {
+    /* Can be NULL. May replace the nodeContext */
+    UA_StatusCode (*constructor)(UA_Server *server,
+                                 const UA_NodeId *sessionId, void *sessionContext,
+                                 const UA_NodeId *typeNodeId, void *typeNodeContext,
+                                 const UA_NodeId *nodeId, void **nodeContext);
+
+    /* Can be NULL. May replace the nodeContext. */
+    void (*destructor)(UA_Server *server,
+                       const UA_NodeId *sessionId, void *sessionContext,
+                       const UA_NodeId *typeNodeId, void *typeNodeContext,
+                       const UA_NodeId *nodeId, void **nodeContext);
+} UA_NodeTypeLifecycle;
+
+
+
+
+
+

ReferenceType Bitfield Representation

+

ReferenceTypes have an alternative represention as an index into a bitfield +for fast comparison. The index is generated when the corresponding +ReferenceTypeNode is added. By bounding the number of ReferenceTypes that can +exist in the server, the bitfield can represent a set of an combination of +ReferenceTypes.

+

Every ReferenceTypeNode contains a bitfield with the set of all its subtypes. +This speeds up the Browse services substantially.

+

The following ReferenceTypes have a fixed index. The NS0 bootstrapping +creates these ReferenceTypes in-order.

+
#define UA_REFERENCETYPEINDEX_REFERENCES 0
+#define UA_REFERENCETYPEINDEX_HASSUBTYPE 1
+#define UA_REFERENCETYPEINDEX_AGGREGATES 2
+#define UA_REFERENCETYPEINDEX_HIERARCHICALREFERENCES 3
+#define UA_REFERENCETYPEINDEX_NONHIERARCHICALREFERENCES 4
+#define UA_REFERENCETYPEINDEX_HASCHILD 5
+#define UA_REFERENCETYPEINDEX_ORGANIZES 6
+#define UA_REFERENCETYPEINDEX_HASEVENTSOURCE 7
+#define UA_REFERENCETYPEINDEX_HASMODELLINGRULE 8
+#define UA_REFERENCETYPEINDEX_HASENCODING 9
+#define UA_REFERENCETYPEINDEX_HASDESCRIPTION 10
+#define UA_REFERENCETYPEINDEX_HASTYPEDEFINITION 11
+#define UA_REFERENCETYPEINDEX_GENERATESEVENT 12
+#define UA_REFERENCETYPEINDEX_HASPROPERTY 13
+#define UA_REFERENCETYPEINDEX_HASCOMPONENT 14
+#define UA_REFERENCETYPEINDEX_HASNOTIFIER 15
+#define UA_REFERENCETYPEINDEX_HASORDEREDCOMPONENT 16
+#define UA_REFERENCETYPEINDEX_HASINTERFACE 17
+
+/* The maximum number of ReferrenceTypes. Must be a multiple of 32. */
+#define UA_REFERENCETYPESET_MAX 128
+typedef struct {
+    UA_UInt32 bits[UA_REFERENCETYPESET_MAX / 32];
+} UA_ReferenceTypeSet;
+
+extern const UA_ReferenceTypeSet UA_REFERENCETYPESET_NONE;
+extern const UA_ReferenceTypeSet UA_REFERENCETYPESET_ALL;
+
+static UA_INLINE void
+UA_ReferenceTypeSet_init(UA_ReferenceTypeSet *set) {
+    memset(set, 0, sizeof(UA_ReferenceTypeSet));
+}
+
+static UA_INLINE UA_ReferenceTypeSet
+UA_REFTYPESET(UA_Byte index) {
+    UA_Byte i = index / 32, j = index % 32;
+    UA_ReferenceTypeSet set;
+    UA_ReferenceTypeSet_init(&set);
+    set.bits[i] |= ((UA_UInt32)1) << j;
+    return set;
+}
+
+static UA_INLINE UA_ReferenceTypeSet
+UA_ReferenceTypeSet_union(const UA_ReferenceTypeSet setA,
+                          const UA_ReferenceTypeSet setB) {
+    UA_ReferenceTypeSet set;
+    for(size_t i = 0; i < UA_REFERENCETYPESET_MAX / 32; i++)
+        set.bits[i] = setA.bits[i] | setB.bits[i];
+    return set;
+}
+
+static UA_INLINE UA_Boolean
+UA_ReferenceTypeSet_contains(const UA_ReferenceTypeSet *set, UA_Byte index) {
+    UA_Byte i = index / 32, j = index % 32;
+    return !!(set->bits[i] & (((UA_UInt32)1) << j));
+}
+
+
+
+
+

Node Pointer

+

The “native” format for reference between nodes is the ExpandedNodeId. That +is, references can also point to external servers. In practice, most +references point to local nodes using numerical NodeIds from the +standard-defined namespace zero. In order to save space (and time), +pointer-tagging is used for compressed “NodePointer” representations. +Numerical NodeIds are immediately contained in the pointer. Full NodeIds and +ExpandedNodeIds are behind a pointer indirection. If the Nodestore supports +it, a NodePointer can also be an actual pointer to the target node.

+

Depending on the processor architecture, some numerical NodeIds don’t fit +into an immediate encoding and are kept as pointers. ExpandedNodeIds may be +internally translated to “normal” NodeIds. Use the provided functions to +generate NodePointers that fit the assumptions for the local architecture.

+
/* Forward declaration. All node structures begin with the NodeHead. */
+struct UA_NodeHead;
+typedef struct UA_NodeHead UA_NodeHead;
+
+/* Tagged Pointer structure. */
+typedef union {
+    uintptr_t immediate;                 /* 00: Small numerical NodeId */
+    const UA_NodeId *id;                 /* 01: Pointer to NodeId */
+    const UA_ExpandedNodeId *expandedId; /* 10: Pointer to ExternalNodeId */
+    const UA_NodeHead *node;             /* 11: Pointer to a node */
+} UA_NodePointer;
+
+/* Sets the pointer to an immediate NodeId "ns=0;i=0" similar to a freshly
+ * initialized UA_NodeId */
+static UA_INLINE void
+UA_NodePointer_init(UA_NodePointer *np) { np->immediate = 0; }
+
+/* NodeId and ExpandedNodeId targets are freed */
+void
+UA_NodePointer_clear(UA_NodePointer *np);
+
+/* Makes a deep copy */
+UA_StatusCode
+UA_NodePointer_copy(UA_NodePointer in, UA_NodePointer *out);
+
+/* Test if an ExpandedNodeId or a local NodeId */
+UA_Boolean
+UA_NodePointer_isLocal(UA_NodePointer np);
+
+UA_Order
+UA_NodePointer_order(UA_NodePointer p1, UA_NodePointer p2);
+
+static UA_INLINE UA_Boolean
+UA_NodePointer_equal(UA_NodePointer p1, UA_NodePointer p2) {
+    return (UA_NodePointer_order(p1, p2) == UA_ORDER_EQ);
+}
+
+/* Cannot fail. The resulting NodePointer can point to the memory from the
+ * NodeId. Make a deep copy if required. */
+UA_NodePointer
+UA_NodePointer_fromNodeId(const UA_NodeId *id);
+
+/* Cannot fail. The resulting NodePointer can point to the memory from the
+ * ExpandedNodeId. Make a deep copy if required. */
+UA_NodePointer
+UA_NodePointer_fromExpandedNodeId(const UA_ExpandedNodeId *id);
+
+/* Can point to the memory from the NodePointer */
+UA_ExpandedNodeId
+UA_NodePointer_toExpandedNodeId(UA_NodePointer np);
+
+/* Can point to the memory from the NodePointer. Discards the ServerIndex and
+ * NamespaceUri of a potential ExpandedNodeId inside the NodePointer. Test
+ * before if the NodePointer is local. */
+UA_NodeId
+UA_NodePointer_toNodeId(UA_NodePointer np);
+
+
+
+
+

Base Node Attributes

+

Nodes contain attributes according to their node type. The base node +attributes are common to all node types. In the OPC UA Services, +attributes are referred to via the NodeId of the containing node and +an integer Attribute Id.

+

Internally, open62541 uses UA_Node in places where the exact node type is +not known or not important. The nodeClass attribute is used to ensure the +correctness of casting from UA_Node to a specific node type.

+
typedef struct {
+    UA_NodePointer targetId;  /* Has to be the first entry */
+    UA_UInt32 targetNameHash; /* Hash of the target's BrowseName. Set to zero
+                               * if the target is remote. */
+} UA_ReferenceTarget;
+
+typedef struct UA_ReferenceTargetTreeElem {
+    UA_ReferenceTarget target;   /* Has to be the first entry */
+    UA_UInt32 targetIdHash;      /* Hash of the targetId */
+    struct {
+        struct UA_ReferenceTargetTreeElem *left;
+        struct UA_ReferenceTargetTreeElem *right;
+    } idTreeEntry;
+    struct {
+        struct UA_ReferenceTargetTreeElem *left;
+        struct UA_ReferenceTargetTreeElem *right;
+    } nameTreeEntry;
+} UA_ReferenceTargetTreeElem;
+
+
+/* List of reference targets with the same reference type and direction. Uses
+ * either an array or a tree structure. The SDK will not change the type of
+ * reference target structure internally. The nodestore implementations may
+ * switch internally when a node is updated.
+ *
+ * The recommendation is to switch to a tree once the number of refs > 8. */
+typedef struct {
+    union {
+        /* Organize the references in an array. Uses less memory, but incurs
+         * lookups in linear time. Recommended if the number of references is
+         * known to be small. */
+        UA_ReferenceTarget *array;
+
+        /* Organize the references in a tree for fast lookup. Use
+         * UA_Node_addReference and UA_Node_deleteReference to modify the
+         * tree-structure. The binary tree implementation (and absolute ordering
+         * / duplicate browseNames are allowed) are not exposed otherwise in the
+         * public API. */
+        struct {
+            UA_ReferenceTargetTreeElem *idRoot;   /* Lookup based on target id */
+            UA_ReferenceTargetTreeElem *nameRoot; /* Lookup based on browseName*/
+        } tree;
+    } targets;
+    size_t targetsSize;
+    UA_Boolean hasRefTree; /* RefTree or RefArray? */
+    UA_Byte referenceTypeIndex;
+    UA_Boolean isInverse;
+} UA_NodeReferenceKind;
+
+/* Iterate over the references. Aborts when the first callback return a non-NULL
+ * pointer and returns that pointer. Do not modify the reference targets during
+ * the iteration. */
+typedef void *
+(*UA_NodeReferenceKind_iterateCallback)(void *context, UA_ReferenceTarget *target);
+
+void *
+UA_NodeReferenceKind_iterate(UA_NodeReferenceKind *rk,
+                             UA_NodeReferenceKind_iterateCallback callback,
+                             void *context);
+
+/* Returns the entry for the targetId or NULL if not found */
+const UA_ReferenceTarget *
+UA_NodeReferenceKind_findTarget(const UA_NodeReferenceKind *rk,
+                                const UA_ExpandedNodeId *targetId);
+
+/* Switch between array and tree representation. Does nothing upon error (e.g.
+ * out-of-memory). */
+UA_StatusCode
+UA_NodeReferenceKind_switch(UA_NodeReferenceKind *rk);
+
+/* Singly-linked LocalizedText list */
+typedef struct UA_LocalizedTextListEntry {
+    struct UA_LocalizedTextListEntry *next;
+    UA_LocalizedText localizedText;
+} UA_LocalizedTextListEntry;
+
+/* Every Node starts with these attributes */
+struct UA_NodeHead {
+    UA_NodeId nodeId;
+    UA_NodeClass nodeClass;
+    UA_QualifiedName browseName;
+
+    /* A node can have different localizations for displayName and description.
+     * The server selects a suitable localization depending on the locale ids
+     * that are set for the current session.
+     *
+     * Locales are added simply by writing a LocalizedText value with a new
+     * locale. A locale can be removed by writing a LocalizedText value of the
+     * corresponding locale with an empty text field. */
+    UA_LocalizedTextListEntry *displayName;
+    UA_LocalizedTextListEntry *description;
+
+    UA_UInt32 writeMask;
+    size_t referencesSize;
+    UA_NodeReferenceKind *references;
+
+    /* Members specific to open62541 */
+    void *context;
+    UA_Boolean constructed; /* Constructors were called */
+#ifdef UA_ENABLE_SUBSCRIPTIONS
+    UA_MonitoredItem *monitoredItems; /* MonitoredItems for Events and immediate
+                                       * DataChanges (no sampling interval). */
+#endif
+};
+
+
+
+
+

VariableNode

+
/* Indicates whether a variable contains data inline or whether it points to an
+ * external data source */
+typedef enum {
+    UA_VALUESOURCE_DATA,
+    UA_VALUESOURCE_DATASOURCE
+} UA_ValueSource;
+
+typedef struct {
+    /* Called before the value attribute is read. It is possible to write into the
+     * value attribute during onRead (using the write service). The node is
+     * re-opened afterwards so that changes are considered in the following read
+     * operation.
+     *
+     * @param handle Points to user-provided data for the callback.
+     * @param nodeid The identifier of the node.
+     * @param data Points to the current node value.
+     * @param range Points to the numeric range the client wants to read from
+     *        (or NULL). */
+    void (*onRead)(UA_Server *server, const UA_NodeId *sessionId,
+                   void *sessionContext, const UA_NodeId *nodeid,
+                   void *nodeContext, const UA_NumericRange *range,
+                   const UA_DataValue *value);
+
+    /* Called after writing the value attribute. The node is re-opened after
+     * writing so that the new value is visible in the callback.
+     *
+     * @param server The server executing the callback
+     * @sessionId The identifier of the session
+     * @sessionContext Additional data attached to the session
+     *                 in the access control layer
+     * @param nodeid The identifier of the node.
+     * @param nodeUserContext Additional data attached to the node by
+     *        the user.
+     * @param nodeConstructorContext Additional data attached to the node
+     *        by the type constructor(s).
+     * @param range Points to the numeric range the client wants to write to (or
+     *        NULL). */
+    void (*onWrite)(UA_Server *server, const UA_NodeId *sessionId,
+                    void *sessionContext, const UA_NodeId *nodeId,
+                    void *nodeContext, const UA_NumericRange *range,
+                    const UA_DataValue *data);
+} UA_ValueCallback;
+
+typedef struct {
+    /* Copies the data from the source into the provided value.
+     *
+     * !! ZERO-COPY OPERATIONS POSSIBLE !!
+     * It is not required to return a copy of the actual content data. You can
+     * return a pointer to memory owned by the user. Memory can be reused
+     * between read callbacks of a DataSource, as the result is already encoded
+     * on the network buffer between each read operation.
+     *
+     * To use zero-copy reads, set the value of the `value->value` Variant
+     * without copying, e.g. with `UA_Variant_setScalar`. Then, also set
+     * `value->value.storageType` to `UA_VARIANT_DATA_NODELETE` to prevent the
+     * memory being cleaned up. Don't forget to also set `value->hasValue` to
+     * true to indicate the presence of a value.
+     *
+     * @param server The server executing the callback
+     * @param sessionId The identifier of the session
+     * @param sessionContext Additional data attached to the session in the
+     *        access control layer
+     * @param nodeId The identifier of the node being read from
+     * @param nodeContext Additional data attached to the node by the user
+     * @param includeSourceTimeStamp If true, then the datasource is expected to
+     *        set the source timestamp in the returned value
+     * @param range If not null, then the datasource shall return only a
+     *        selection of the (nonscalar) data. Set
+     *        UA_STATUSCODE_BADINDEXRANGEINVALID in the value if this does not
+     *        apply
+     * @param value The (non-null) DataValue that is returned to the client. The
+     *        data source sets the read data, the result status and optionally a
+     *        sourcetimestamp.
+     * @return Returns a status code for logging. Error codes intended for the
+     *         original caller are set in the value. If an error is returned,
+     *         then no releasing of the value is done
+     */
+    UA_StatusCode (*read)(UA_Server *server, const UA_NodeId *sessionId,
+                          void *sessionContext, const UA_NodeId *nodeId,
+                          void *nodeContext, UA_Boolean includeSourceTimeStamp,
+                          const UA_NumericRange *range, UA_DataValue *value);
+
+    /* Write into a data source. This method pointer can be NULL if the
+     * operation is unsupported.
+     *
+     * @param server The server executing the callback
+     * @param sessionId The identifier of the session
+     * @param sessionContext Additional data attached to the session in the
+     *        access control layer
+     * @param nodeId The identifier of the node being written to
+     * @param nodeContext Additional data attached to the node by the user
+     * @param range If not NULL, then the datasource shall return only a
+     *        selection of the (nonscalar) data. Set
+     *        UA_STATUSCODE_BADINDEXRANGEINVALID in the value if this does not
+     *        apply
+     * @param value The (non-NULL) DataValue that has been written by the client.
+     *        The data source contains the written data, the result status and
+     *        optionally a sourcetimestamp
+     * @return Returns a status code for logging. Error codes intended for the
+     *         original caller are set in the value. If an error is returned,
+     *         then no releasing of the value is done
+     */
+    UA_StatusCode (*write)(UA_Server *server, const UA_NodeId *sessionId,
+                           void *sessionContext, const UA_NodeId *nodeId,
+                           void *nodeContext, const UA_NumericRange *range,
+                           const UA_DataValue *value);
+} UA_DataSource;
+
+
+
+

Value Callback

+

Value Callbacks can be attached to variable and variable type nodes. If +not NULL, they are called before reading and after writing respectively.

+
typedef struct {
+    /* Called before the value attribute is read. The external value source can be
+     * be updated and/or locked during this notification call. After this function returns
+     * to the core, the external value source is readed immediately.
+    */
+    UA_StatusCode (*notificationRead)(UA_Server *server, const UA_NodeId *sessionId,
+                                      void *sessionContext, const UA_NodeId *nodeid,
+                                      void *nodeContext, const UA_NumericRange *range);
+
+    /* Called after writing the value attribute. The node is re-opened after
+     * writing so that the new value is visible in the callback.
+     *
+     * @param server The server executing the callback
+     * @sessionId The identifier of the session
+     * @sessionContext Additional data attached to the session
+     *                 in the access control layer
+     * @param nodeid The identifier of the node.
+     * @param nodeUserContext Additional data attached to the node by
+     *        the user.
+     * @param nodeConstructorContext Additional data attached to the node
+     *        by the type constructor(s).
+     * @param range Points to the numeric range the client wants to write to (or
+     *        NULL). */
+    UA_StatusCode (*userWrite)(UA_Server *server, const UA_NodeId *sessionId,
+                               void *sessionContext, const UA_NodeId *nodeId,
+                               void *nodeContext, const UA_NumericRange *range,
+                               const UA_DataValue *data);
+} UA_ExternalValueCallback;
+
+typedef enum {
+    UA_VALUEBACKENDTYPE_NONE,
+    UA_VALUEBACKENDTYPE_INTERNAL,
+    UA_VALUEBACKENDTYPE_DATA_SOURCE_CALLBACK,
+    UA_VALUEBACKENDTYPE_EXTERNAL
+} UA_ValueBackendType;
+
+typedef struct {
+    UA_ValueBackendType backendType;
+    union {
+        struct {
+            UA_DataValue value;
+            UA_ValueCallback callback;
+        } internal;
+        UA_DataSource dataSource;
+        struct {
+            UA_DataValue **value;
+            UA_ExternalValueCallback callback;
+        } external;
+    } backend;
+} UA_ValueBackend;
+
+#define UA_NODE_VARIABLEATTRIBUTES                                      \
+    /* Constraints on possible values */                                \
+    UA_NodeId dataType;                                                 \
+    UA_Int32 valueRank;                                                 \
+    size_t arrayDimensionsSize;                                         \
+    UA_UInt32 *arrayDimensions;                                         \
+                                                                        \
+    UA_ValueBackend valueBackend;                                       \
+                                                                        \
+    /* The current value */                                             \
+    UA_ValueSource valueSource;                                         \
+    union {                                                             \
+        struct {                                                        \
+            UA_DataValue value;                                         \
+            UA_ValueCallback callback;                                  \
+        } data;                                                         \
+        UA_DataSource dataSource;                                       \
+    } value;
+
+typedef struct {
+    UA_NodeHead head;
+    UA_NODE_VARIABLEATTRIBUTES
+    UA_Byte accessLevel;
+    UA_Double minimumSamplingInterval;
+    UA_Boolean historizing;
+
+    /* Members specific to open62541 */
+    UA_Boolean isDynamic; /* Some variables are "static" in the sense that they
+                           * are not attached to a dynamic process in the
+                           * background. Only dynamic variables conserve source
+                           * and server timestamp for the value attribute.
+                           * Static variables have timestamps of "now". */
+} UA_VariableNode;
+
+
+
+
+
+

VariableTypeNode

+
typedef struct {
+    UA_NodeHead head;
+    UA_NODE_VARIABLEATTRIBUTES
+    UA_Boolean isAbstract;
+
+    /* Members specific to open62541 */
+    UA_NodeTypeLifecycle lifecycle;
+} UA_VariableTypeNode;
+
+
+
+
+

MethodNode

+
typedef UA_StatusCode
+(*UA_MethodCallback)(UA_Server *server, const UA_NodeId *sessionId,
+                     void *sessionContext, const UA_NodeId *methodId,
+                     void *methodContext, const UA_NodeId *objectId,
+                     void *objectContext, size_t inputSize,
+                     const UA_Variant *input, size_t outputSize,
+                     UA_Variant *output);
+
+typedef struct {
+    UA_NodeHead head;
+    UA_Boolean executable;
+
+    /* Members specific to open62541 */
+    UA_MethodCallback method;
+#if UA_MULTITHREADING >= 100
+    UA_Boolean async; /* Indicates an async method call */
+#endif
+} UA_MethodNode;
+
+
+
+
+

ObjectNode

+
typedef struct {
+    UA_NodeHead head;
+    UA_Byte eventNotifier;
+} UA_ObjectNode;
+
+
+
+
+

ObjectTypeNode

+
typedef struct {
+    UA_NodeHead head;
+    UA_Boolean isAbstract;
+
+    /* Members specific to open62541 */
+    UA_NodeTypeLifecycle lifecycle;
+} UA_ObjectTypeNode;
+
+
+
+
+

ReferenceTypeNode

+
typedef struct {
+    UA_NodeHead head;
+    UA_Boolean isAbstract;
+    UA_Boolean symmetric;
+    UA_LocalizedText inverseName;
+
+    /* Members specific to open62541 */
+    UA_Byte referenceTypeIndex;
+    UA_ReferenceTypeSet subTypes; /* contains the type itself as well */
+} UA_ReferenceTypeNode;
+
+
+
+
+

DataTypeNode

+
typedef struct {
+    UA_NodeHead head;
+    UA_Boolean isAbstract;
+} UA_DataTypeNode;
+
+
+
+
+

ViewNode

+
typedef struct {
+    UA_NodeHead head;
+    UA_Byte eventNotifier;
+    UA_Boolean containsNoLoops;
+} UA_ViewNode;
+
+
+
+
+

Node Union

+

A union that represents any kind of node. The node head can always be used. +Check the NodeClass before accessing specific content.

+
typedef union {
+    UA_NodeHead head;
+    UA_VariableNode variableNode;
+    UA_VariableTypeNode variableTypeNode;
+    UA_MethodNode methodNode;
+    UA_ObjectNode objectNode;
+    UA_ObjectTypeNode objectTypeNode;
+    UA_ReferenceTypeNode referenceTypeNode;
+    UA_DataTypeNode dataTypeNode;
+    UA_ViewNode viewNode;
+} UA_Node;
+
+
+
+
+

Nodestore

+

The following definitions are used for implementing custom node storage +backends. Most users will want to use the default nodestore and don’t need +to work with the nodestore API.

+

Outside of custom nodestore implementations, users should not manually edit +nodes. Please use the OPC UA services for that. Otherwise, all consistency +checks are omitted. This can crash the application eventually.

+
typedef void (*UA_NodestoreVisitor)(void *visitorCtx, const UA_Node *node);
+
+typedef struct {
+    /* Nodestore context and lifecycle */
+    void *context;
+    void (*clear)(void *nsCtx);
+
+    /* The following definitions are used to create empty nodes of the different
+     * node types. The memory is managed by the nodestore. Therefore, the node
+     * has to be removed via a special deleteNode function. (If the new node is
+     * not added to the nodestore.) */
+    UA_Node * (*newNode)(void *nsCtx, UA_NodeClass nodeClass);
+
+    void (*deleteNode)(void *nsCtx, UA_Node *node);
+
+    /* ``Get`` returns a pointer to an immutable node. Call ``releaseNode`` to
+     * indicate when the pointer is no longer accessed.
+     *
+     * It can be indicated if only a subset of the attributes and referencs need
+     * to be accessed. That is relevant when the nodestore accesses a slow
+     * storage backend for the attributes. The attribute mask is a bitfield with
+     * ORed entries from UA_NodeAttributesMask.
+     *
+     * The returned node always contains the context-pointer and other fields
+     * specific to open626541 (not official attributes).
+     *
+     * The NodeStore does not complain if attributes and references that don't
+     * exist (for that node) are requested. Attributes and references in
+     * addition to those specified can be returned. For example, if the full
+     * node already is kept in memory by the Nodestore. */
+    const UA_Node * (*getNode)(void *nsCtx, const UA_NodeId *nodeId,
+                               UA_UInt32 attributeMask,
+                               UA_ReferenceTypeSet references,
+                               UA_BrowseDirection referenceDirections);
+
+    /* Similar to the normal ``getNode``. But it can take advantage of the
+     * NodePointer structure, e.g. if it contains a direct pointer. */
+    const UA_Node * (*getNodeFromPtr)(void *nsCtx, UA_NodePointer ptr,
+                                      UA_UInt32 attributeMask,
+                                      UA_ReferenceTypeSet references,
+                                      UA_BrowseDirection referenceDirections);
+
+    /* Release a node that has been retrieved with ``getNode`` or
+     * ``getNodeFromPtr``. */
+    void (*releaseNode)(void *nsCtx, const UA_Node *node);
+
+    /* Returns an editable copy of a node (needs to be deleted with the
+     * deleteNode function or inserted / replaced into the nodestore). */
+    UA_StatusCode (*getNodeCopy)(void *nsCtx, const UA_NodeId *nodeId,
+                                 UA_Node **outNode);
+
+    /* Inserts a new node into the nodestore. If the NodeId is zero, then a
+     * fresh numeric NodeId is assigned. If insertion fails, the node is
+     * deleted. */
+    UA_StatusCode (*insertNode)(void *nsCtx, UA_Node *node,
+                                UA_NodeId *addedNodeId);
+
+    /* To replace a node, get an editable copy of the node, edit and replace
+     * with this function. If the node was already replaced since the copy was
+     * made, UA_STATUSCODE_BADINTERNALERROR is returned. If the NodeId is not
+     * found, UA_STATUSCODE_BADNODEIDUNKNOWN is returned. In both error cases,
+     * the editable node is deleted. */
+    UA_StatusCode (*replaceNode)(void *nsCtx, UA_Node *node);
+
+    /* Removes a node from the nodestore. */
+    UA_StatusCode (*removeNode)(void *nsCtx, const UA_NodeId *nodeId);
+
+    /* Maps the ReferenceTypeIndex used for the references to the NodeId of the
+     * ReferenceType. The returned pointer is stable until the Nodestore is
+     * deleted. */
+    const UA_NodeId * (*getReferenceTypeId)(void *nsCtx, UA_Byte refTypeIndex);
+
+    /* Execute a callback for every node in the nodestore. */
+    void (*iterate)(void *nsCtx, UA_NodestoreVisitor visitor,
+                    void *visitorCtx);
+} UA_Nodestore;
+
+/* Attributes must be of a matching type (VariableAttributes, ObjectAttributes,
+ * and so on). The attributes are copied. Note that the attributes structs do
+ * not contain NodeId, NodeClass and BrowseName. The NodeClass of the node needs
+ * to be correctly set before calling this method. UA_Node_clear is called on
+ * the node when an error occurs internally. */
+UA_StatusCode
+UA_Node_setAttributes(UA_Node *node, const void *attributes,
+                      const UA_DataType *attributeType);
+
+/* Reset the destination node and copy the content of the source */
+UA_StatusCode
+UA_Node_copy(const UA_Node *src, UA_Node *dst);
+
+/* Allocate new node and copy the values from src */
+UA_Node *
+UA_Node_copy_alloc(const UA_Node *src);
+
+/* Add a single reference to the node */
+UA_StatusCode
+UA_Node_addReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward,
+                     const UA_ExpandedNodeId *targetNodeId,
+                     UA_UInt32 targetBrowseNameHash);
+
+/* Delete a single reference from the node */
+UA_StatusCode
+UA_Node_deleteReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward,
+                        const UA_ExpandedNodeId *targetNodeId);
+
+/* Deletes references from the node which are not matching any type in the given
+ * array. Could be used to e.g. delete all the references, except
+ * 'HASMODELINGRULE' */
+void
+UA_Node_deleteReferencesSubset(UA_Node *node, const UA_ReferenceTypeSet *keepSet);
+
+/* Delete all references of the node */
+void
+UA_Node_deleteReferences(UA_Node *node);
+
+/* Remove all malloc'ed members of the node and reset */
+void
+UA_Node_clear(UA_Node *node);
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/plugin_pki.html b/static/doc/v1.4.0/plugin_pki.html new file mode 100644 index 0000000000..c2d4ca7cb0 --- /dev/null +++ b/static/doc/v1.4.0/plugin_pki.html @@ -0,0 +1,191 @@ + + + + + + + Public Key Infrastructure Integration — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Public Key Infrastructure Integration

+

This file contains interface definitions for integration in a Public Key +Infrastructure (PKI). Currently only one plugin interface is defined.

+
+

Certificate Verification

+

This plugin verifies that the origin of the certificate is trusted. It does +not assign any access rights/roles to the holder of the certificate.

+

Usually, implementations of the certificate verification plugin provide an +initialization method that takes a trust-list and a revocation-list as input. +The lifecycle of the plugin is attached to a server or client config. The +clear method is called automatically when the config is destroyed.

+
struct UA_CertificateVerification;
+typedef struct UA_CertificateVerification UA_CertificateVerification;
+
+struct UA_CertificateVerification {
+    void *context;
+
+    /* Verify the certificate against the configured policies and trust chain. */
+    UA_StatusCode (*verifyCertificate)(const UA_CertificateVerification *cv,
+                                       const UA_ByteString *certificate);
+
+    /* Verify that the certificate has the applicationURI in the subject name. */
+    UA_StatusCode (*verifyApplicationURI)(const UA_CertificateVerification *cv,
+                                          const UA_ByteString *certificate,
+                                          const UA_String *applicationURI);
+
+    /* Get the expire date from certificate */
+    UA_StatusCode (*getExpirationDate)(UA_DateTime *expiryDateTime,
+                                       UA_ByteString *certificate);
+
+    UA_StatusCode (*getSubjectName)(UA_String *subjectName,
+                                    UA_ByteString *certificate);
+
+    /* Delete the certificate verification context */
+    void (*clear)(UA_CertificateVerification *cv);
+
+    /* Pointer to logging pointer in the server/client configuration. If the
+     * logging pointer is changed outside of the plugin, the new logger is used
+     * automatically*/
+    const UA_Logger *logging;
+};
+
+/* Decrypt a private key in PEM format using a password. The output is the key
+ * in the binary DER format. Also succeeds if the PEM private key does not
+ * require a password or is already in the DER format. The outDerKey memory is
+ * allocated internally.
+ *
+ * Returns UA_STATUSCODE_BADSECURITYCHECKSFAILED if the password is wrong. */
+UA_StatusCode
+UA_PKI_decryptPrivateKey(const UA_ByteString privateKey,
+                         const UA_ByteString password,
+                         UA_ByteString *outDerKey);
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/plugin_securitypolicy.html b/static/doc/v1.4.0/plugin_securitypolicy.html new file mode 100644 index 0000000000..afe44fc8fb --- /dev/null +++ b/static/doc/v1.4.0/plugin_securitypolicy.html @@ -0,0 +1,483 @@ + + + + + + + SecurityPolicy — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

SecurityPolicy

+
typedef struct {
+    UA_String uri;
+
+    /* Verifies the signature of the message using the provided keys in the context.
+     *
+     * @param channelContext the channelContext that contains the key to verify
+     *                       the supplied message with.
+     * @param message the message to which the signature is supposed to belong.
+     * @param signature the signature of the message, that should be verified. */
+    UA_StatusCode (*verify)(void *channelContext, const UA_ByteString *message,
+                            const UA_ByteString *signature);
+
+    /* Signs the given message using this policys signing algorithm and the
+     * provided keys in the context.
+     *
+     * @param channelContext the channelContext that contains the key to sign
+     *                       the supplied message with.
+     * @param message the message to sign.
+     * @param signature an output buffer to which the signature is written. The
+     *                  buffer needs to be allocated by the caller. The
+     *                  necessary size can be acquired with the signatureSize
+     *                  attribute of this module. */
+    UA_StatusCode (*sign)(void *channelContext, const UA_ByteString *message,
+                          UA_ByteString *signature);
+
+    /* Gets the signature size that depends on the local (private) key.
+     *
+     * @param channelContext the channelContext that contains the
+     *                       certificate/key.
+     * @return the size of the local signature. Returns 0 if no local
+     *         certificate was set. */
+    size_t (*getLocalSignatureSize)(const void *channelContext);
+
+    /* Gets the signature size that depends on the remote (public) key.
+     *
+     * @param channelContext the context to retrieve data from.
+     * @return the size of the remote signature. Returns 0 if no
+     *         remote certificate was set previousely. */
+    size_t (*getRemoteSignatureSize)(const void *channelContext);
+
+    /* Gets the local signing key length.
+     *
+     * @param channelContext the context to retrieve data from.
+     * @return the length of the signing key in bytes. Returns 0 if no length can be found.
+     */
+    size_t (*getLocalKeyLength)(const void *channelContext);
+
+    /* Gets the local signing key length.
+     *
+     * @param channelContext the context to retrieve data from.
+     * @return the length of the signing key in bytes. Returns 0 if no length can be found.
+     */
+    size_t (*getRemoteKeyLength)(const void *channelContext);
+} UA_SecurityPolicySignatureAlgorithm;
+
+typedef struct {
+    UA_String uri;
+
+    /* Encrypt the given data in place. For asymmetric encryption, the block
+     * size for plaintext and cypher depend on the remote key (certificate).
+     *
+     * @param channelContext the channelContext which contains information about
+     *                       the keys to encrypt data.
+     * @param data the data that is encrypted. The encrypted data will overwrite
+     *             the data that was supplied. */
+    UA_StatusCode (*encrypt)(void *channelContext,
+                             UA_ByteString *data);
+
+    /* Decrypts the given ciphertext in place. For asymmetric encryption, the
+     * block size for plaintext and cypher depend on the local private key.
+     *
+     * @param channelContext the channelContext which contains information about
+     *                       the keys needed to decrypt the message.
+     * @param data the data to decrypt. The decryption is done in place. */
+    UA_StatusCode (*decrypt)(void *channelContext,
+                             UA_ByteString *data);
+
+    /* Returns the length of the key used to encrypt messages in bits. For
+     * asymmetric encryption the key length is for the local private key.
+     *
+     * @param channelContext the context to retrieve data from.
+     * @return the length of the local key. Returns 0 if no
+     *         key length is known. */
+    size_t (*getLocalKeyLength)(const void *channelContext);
+
+    /* Returns the length of the key to encrypt messages in bits. Depends on the
+     * key (certificate) from the remote side.
+     *
+     * @param channelContext the context to retrieve data from.
+     * @return the length of the remote key. Returns 0 if no
+     *         key length is known. */
+    size_t (*getRemoteKeyLength)(const void *channelContext);
+
+    /* Returns the size of encrypted blocks for sending. For asymmetric
+     * encryption this depends on the remote key (certificate). For symmetric
+     * encryption the local and remote encrypted block size are identical.
+     *
+     * @param channelContext the context to retrieve data from.
+     * @return the size of encrypted blocks in bytes. Returns 0 if no key length is known.
+     */
+    size_t (*getRemoteBlockSize)(const void *channelContext);
+
+    /* Returns the size of plaintext blocks for sending. For asymmetric
+     * encryption this depends on the remote key (certificate). For symmetric
+     * encryption the local and remote plaintext block size are identical.
+     *
+     * @param channelContext the context to retrieve data from.
+     * @return the size of plaintext blocks in bytes. Returns 0 if no key length is known.
+     */
+    size_t (*getRemotePlainTextBlockSize)(const void *channelContext);
+} UA_SecurityPolicyEncryptionAlgorithm;
+
+typedef struct {
+    /* The algorithm used to sign and verify certificates. */
+    UA_SecurityPolicySignatureAlgorithm signatureAlgorithm;
+
+    /* The algorithm used to encrypt and decrypt messages. */
+    UA_SecurityPolicyEncryptionAlgorithm encryptionAlgorithm;
+
+} UA_SecurityPolicyCryptoModule;
+
+typedef struct {
+    /* Generates a thumbprint for the specified certificate.
+     *
+     * @param certificate the certificate to make a thumbprint of.
+     * @param thumbprint an output buffer for the resulting thumbprint. Always
+     *                   has the length specified in the thumbprintLength in the
+     *                   asymmetricModule. */
+    UA_StatusCode (*makeCertificateThumbprint)(const UA_SecurityPolicy *securityPolicy,
+                                               const UA_ByteString *certificate,
+                                               UA_ByteString *thumbprint)
+   ;
+
+    /* Compares the supplied certificate with the certificate in the endpoint context.
+     *
+     * @param securityPolicy the policy data that contains the certificate
+     *                       to compare to.
+     * @param certificateThumbprint the certificate thumbprint to compare to the
+     *                              one stored in the context.
+     * @return if the thumbprints match UA_STATUSCODE_GOOD is returned. If they
+     *         don't match or an error occurred an error code is returned. */
+    UA_StatusCode (*compareCertificateThumbprint)(const UA_SecurityPolicy *securityPolicy,
+                                                  const UA_ByteString *certificateThumbprint)
+   ;
+
+    UA_SecurityPolicyCryptoModule cryptoModule;
+} UA_SecurityPolicyAsymmetricModule;
+
+typedef struct {
+    /* Pseudo random function that is used to generate the symmetric keys.
+     *
+     * For information on what parameters this function receives in what situation,
+     * refer to the OPC UA specification 1.03 Part6 Table 33
+     *
+     * @param policyContext The context of the policy instance
+     * @param secret
+     * @param seed
+     * @param out an output to write the data to. The length defines the maximum
+     *            number of output bytes that are produced. */
+    UA_StatusCode (*generateKey)(void *policyContext, const UA_ByteString *secret,
+                                 const UA_ByteString *seed, UA_ByteString *out)
+   ;
+
+    /* Random generator for generating nonces.
+     *
+     * @param policyContext The context of the policy instance
+     * @param out pointer to a buffer to store the nonce in. Needs to be
+     *            allocated by the caller. The buffer is filled with random
+     *            data. */
+    UA_StatusCode (*generateNonce)(void *policyContext, UA_ByteString *out)
+   ;
+
+    /*
+     * The length of the nonce used in the SecureChannel as specified in the standard.
+     */
+    size_t secureChannelNonceLength;
+
+    UA_SecurityPolicyCryptoModule cryptoModule;
+} UA_SecurityPolicySymmetricModule;
+
+typedef struct {
+    /* This method creates a new context data object.
+     *
+     * The caller needs to call delete on the received object to free allocated
+     * memory. Memory is only allocated if the function succeeds so there is no
+     * need to manually free the memory pointed to by *channelContext or to
+     * call delete in case of failure.
+     *
+     * @param securityPolicy the policy context of the endpoint that is connected
+     *                       to. It will be stored in the channelContext for
+     *                       further access by the policy.
+     * @param remoteCertificate the remote certificate contains the remote
+     *                          asymmetric key. The certificate will be verified
+     *                          and then stored in the context so that its
+     *                          details may be accessed.
+     * @param channelContext the initialized channelContext that is passed to
+     *                       functions that work on a context. */
+    UA_StatusCode (*newContext)(const UA_SecurityPolicy *securityPolicy,
+                                const UA_ByteString *remoteCertificate,
+                                void **channelContext)
+   ;
+
+    /* Deletes the the security context. */
+    void (*deleteContext)(void *channelContext);
+
+    /* Sets the local encrypting key in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param key the local encrypting key to store in the context. */
+    UA_StatusCode (*setLocalSymEncryptingKey)(void *channelContext,
+                                              const UA_ByteString *key)
+   ;
+
+    /* Sets the local signing key in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param key the local signing key to store in the context. */
+    UA_StatusCode (*setLocalSymSigningKey)(void *channelContext,
+                                           const UA_ByteString *key)
+   ;
+
+    /* Sets the local initialization vector in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param iv the local initialization vector to store in the context. */
+    UA_StatusCode (*setLocalSymIv)(void *channelContext,
+                                   const UA_ByteString *iv)
+   ;
+
+    /* Sets the remote encrypting key in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param key the remote encrypting key to store in the context. */
+    UA_StatusCode (*setRemoteSymEncryptingKey)(void *channelContext,
+                                               const UA_ByteString *key)
+   ;
+
+    /* Sets the remote signing key in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param key the remote signing key to store in the context. */
+    UA_StatusCode (*setRemoteSymSigningKey)(void *channelContext,
+                                            const UA_ByteString *key)
+   ;
+
+    /* Sets the remote initialization vector in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param iv the remote initialization vector to store in the context. */
+    UA_StatusCode (*setRemoteSymIv)(void *channelContext,
+                                    const UA_ByteString *iv)
+   ;
+
+    /* Compares the supplied certificate with the certificate in the channel
+     * context.
+     *
+     * @param channelContext the channel context data that contains the
+     *                       certificate to compare to.
+     * @param certificate the certificate to compare to the one stored in the context.
+     * @return if the certificates match UA_STATUSCODE_GOOD is returned. If they
+     *         don't match or an errror occurred an error code is returned. */
+    UA_StatusCode (*compareCertificate)(const void *channelContext,
+                                        const UA_ByteString *certificate)
+   ;
+} UA_SecurityPolicyChannelModule;
+
+struct UA_SecurityPolicy {
+    /* Additional data */
+    void *policyContext;
+
+    /* The policy uri that identifies the implemented algorithms */
+    UA_String policyUri;
+
+    /* The local certificate is specific for each SecurityPolicy since it
+     * depends on the used key length. */
+    UA_ByteString localCertificate;
+
+    /* Function pointers grouped into modules */
+    UA_SecurityPolicyAsymmetricModule asymmetricModule;
+    UA_SecurityPolicySymmetricModule symmetricModule;
+    UA_SecurityPolicySignatureAlgorithm certificateSigningAlgorithm;
+    UA_SecurityPolicyChannelModule channelModule;
+
+    const UA_Logger *logger;
+
+    /* Updates the ApplicationInstanceCertificate and the corresponding private
+     * key at runtime. */
+    UA_StatusCode (*updateCertificateAndPrivateKey)(UA_SecurityPolicy *policy,
+                                                    const UA_ByteString newCertificate,
+                                                    const UA_ByteString newPrivateKey);
+
+    /* Deletes the dynamic content of the policy */
+    void (*clear)(UA_SecurityPolicy *policy);
+};
+
+
+
+
+

PubSub SecurityPolicy

+

For PubSub encryption, the message nonce is part of the (unencrypted) +SecurityHeader. The nonce is required for the de- and encryption and has to +be set in the channel context before de/encrypting.

+
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
+struct UA_PubSubSecurityPolicy;
+typedef struct UA_PubSubSecurityPolicy UA_PubSubSecurityPolicy;
+
+struct UA_PubSubSecurityPolicy {
+    UA_String policyUri; /* The policy uri that identifies the implemented
+                          * algorithms */
+    UA_SecurityPolicySymmetricModule symmetricModule;
+
+    /* Create the context for the WriterGroup. The keys and nonce can be NULL
+     * here. Then they have to be set before the first encryption or signing
+     * operation. */
+    UA_StatusCode
+    (*newContext)(void *policyContext,
+                  const UA_ByteString *signingKey,
+                  const UA_ByteString *encryptingKey,
+                  const UA_ByteString *keyNonce,
+                  void **wgContext);
+
+    /* Delete the WriterGroup SecurityPolicy context */
+    void (*deleteContext)(void *wgContext);
+
+    /* Set the keys and nonce for the WriterGroup. This is returned from the
+     * GetSecurityKeys method of a Security Key Service (SKS). Otherwise, set
+     * manually via out-of-band transmission of the keys. */
+    UA_StatusCode
+    (*setSecurityKeys)(void *wgContext,
+                       const UA_ByteString *signingKey,
+                       const UA_ByteString *encryptingKey,
+                       const UA_ByteString *keyNonce)
+   ;
+
+    /* The nonce is contained in the NetworkMessage SecurityHeader. Set before
+     * each en-/decryption step. */
+    UA_StatusCode
+    (*setMessageNonce)(void *wgContext,
+                       const UA_ByteString *nonce)
+   ;
+
+    const UA_Logger *logger;
+
+    /* Deletes the dynamic content of the policy */
+    void (*clear)(UA_PubSubSecurityPolicy *policy);
+    void *policyContext;
+};
+
+#endif
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/pubsub.html b/static/doc/v1.4.0/pubsub.html new file mode 100644 index 0000000000..474826c1ea --- /dev/null +++ b/static/doc/v1.4.0/pubsub.html @@ -0,0 +1,1060 @@ + + + + + + + PubSub — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

PubSub

+

In PubSub the participating OPC UA Applications take their roles as +Publishers and Subscribers. Publishers are the sources of data, while +Subscribers consume that data. Communication in PubSub is message-based. +Publishers send messages to a Message Oriented Middleware, without knowledge +of what, if any, Subscribers there may be. Similarly, Subscribers express +interest in specific types of data, and process messages that contain this +data, without knowledge of what Publishers there are.

+

Message Oriented Middleware is software or hardware infrastructure that +supports sending and receiving messages between distributed systems. OPC UA +PubSub supports two different Message Oriented Middleware variants, namely +the broker-less form and broker-based form. A broker-less form is where the +Message Oriented Middleware is the network infrastructure that is able to +route datagram-based messages. Subscribers and Publishers use datagram +protocols like UDP. In a broker-based form, the core component of the Message +Oriented Middleware is a message Broker. Subscribers and Publishers use +standard messaging protocols like AMQP or MQTT to communicate with the +Broker.

+

This makes PubSub suitable for applications where location independence +and/or scalability are required.

+

The Publish/Subscribe (PubSub) extension for OPC UA enables fast and +efficient 1:m communication. The PubSub extension is protocol agnostic and +can be used with broker based protocols like MQTT and AMQP or brokerless +implementations like UDP-Multicasting.

+

The configuration model for PubSub uses the following components:

+
typedef enum  {
+    UA_PUBSUB_COMPONENT_CONNECTION,
+    UA_PUBSUB_COMPONENT_WRITERGROUP,
+    UA_PUBSUB_COMPONENT_DATASETWRITER,
+    UA_PUBSUB_COMPONENT_READERGROUP,
+    UA_PUBSUB_COMPONENT_DATASETREADER
+} UA_PubSubComponentEnumType;
+
+
+

The open62541 PubSub API uses the following scheme:

+
    +
  1. Create a configuration for the needed PubSub element.

  2. +
  3. Call the add[element] function and pass in the configuration.

  4. +
  5. The add[element] function returns the unique nodeId of the internally created element.

  6. +
+

Take a look on the PubSub Tutorials for more details about the API usage:

+
+-----------+
+| UA_Server |
++-----------+
+ |    |
+ |    |
+ |    |
+ |    |  +----------------------+
+ |    +--> UA_PubSubConnection  |  UA_Server_addPubSubConnection
+ |       +----------------------+
+ |        |    |
+ |        |    |    +----------------+
+ |        |    +----> UA_WriterGroup |  UA_PubSubConnection_addWriterGroup
+ |        |         +----------------+
+ |        |              |
+ |        |              |    +------------------+
+ |        |              +----> UA_DataSetWriter |  UA_WriterGroup_addDataSetWriter     +-+
+ |        |                   +------------------+                                        |
+ |        |                                                                               |
+ |        |         +----------------+                                                    | r
+ |        +---------> UA_ReaderGroup |    UA_PubSubConnection_addReaderGroup              | e
+ |                  +----------------+                                                    | f
+ |                       |                                                                |
+ |                       |    +------------------+                                        |
+ |                       +----> UA_DataSetReader |  UA_ReaderGroup_addDataSetReader       |
+ |                            +------------------+                                        |
+ |                                 |                                                      |
+ |                                 |    +----------------------+                          |
+ |                                 +----> UA_SubscribedDataSet |                          |
+ |                                      +----------------------+                          |
+ |                                           |                                            |
+ |                                           |    +----------------------------+          |
+ |                                           +----> UA_TargetVariablesDataType |          |
+ |                                           |    +----------------------------+          |
+ |                                           |                                            |
+ |                                           |    +------------------------------------+  |
+ |                                           +----> UA_SubscribedDataSetMirrorDataType |  |
+ |                                                +------------------------------------+  |
+ |                                                                                        |
+ |       +---------------------------+                                                    |
+ +-------> UA_PubSubPublishedDataSet |  UA_Server_addPublishedDataSet                   <-+
+         +---------------------------+
+               |
+               |    +-----------------+
+               +----> UA_DataSetField |  UA_PublishedDataSet_addDataSetField
+                    +-----------------+
+
+
+
+

PubSub Information Model Representation

+

The complete PubSub configuration is available inside the information model. +The entry point is the node ‘PublishSubscribe’, located under the Server +node. +The standard defines for PubSub no new Service set. The configuration can +optionally be done over methods inside the information model. +The information model representation of the current PubSub configuration is +generated automatically. This feature can be enabled/disabled by changing the +UA_ENABLE_PUBSUB_INFORMATIONMODEL option.

+
+
+

Connections

+

The PubSub connections are the abstraction between the concrete transport protocol +and the PubSub functionality. It is possible to create multiple connections with +different transport protocols at runtime.

+
/* Valid PublisherId types from Part 14 */
+typedef enum {
+    UA_PUBLISHERIDTYPE_BYTE   = 0,
+    UA_PUBLISHERIDTYPE_UINT16 = 1,
+    UA_PUBLISHERIDTYPE_UINT32 = 2,
+    UA_PUBLISHERIDTYPE_UINT64 = 3,
+    UA_PUBLISHERIDTYPE_STRING = 4
+} UA_PublisherIdType;
+
+/* Publisher Id
+    Valid types are defined in Part 14, 7.2.2.2.2 NetworkMessage Layout:
+
+    Bit range 0-2: PublisherId Type
+    000 The PublisherId is of DataType Byte This is the default value if ExtendedFlags1 is omitted
+    001 The PublisherId is of DataType UInt16
+    010 The PublisherId is of DataType UInt32
+    011 The PublisherId is of DataType UInt64
+    100 The PublisherId is of DataType String
+*/
+typedef union {
+    UA_Byte byte;
+    UA_UInt16 uint16;
+    UA_UInt32 uint32;
+    UA_UInt64 uint64;
+    UA_String string;
+} UA_PublisherId;
+
+typedef struct {
+    UA_String name;
+    UA_Boolean enabled;
+    UA_PublisherIdType publisherIdType;
+    UA_PublisherId publisherId;
+    UA_String transportProfileUri;
+    UA_Variant address;
+    UA_KeyValueMap connectionProperties;
+    UA_Variant connectionTransportSettings;
+
+    UA_EventLoop *eventLoop; /* Use an external EventLoop (use the EventLoop of
+                              * the server if this is NULL). Propagates to the
+                              * ReaderGroup/WriterGroup attached to the
+                              * Connection. */
+} UA_PubSubConnectionConfig;
+
+#ifdef UA_ENABLE_PUBSUB_MONITORING
+
+typedef enum {
+    UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT
+    // extend as needed
+} UA_PubSubMonitoringType;
+
+/* PubSub monitoring interface */
+typedef struct {
+    UA_StatusCode (*createMonitoring)(UA_Server *server, UA_NodeId Id,
+                                      UA_PubSubComponentEnumType eComponentType,
+                                      UA_PubSubMonitoringType eMonitoringType,
+                                      void *data, UA_ServerCallback callback);
+    UA_StatusCode (*startMonitoring)(UA_Server *server, UA_NodeId Id,
+                                     UA_PubSubComponentEnumType eComponentType,
+                                     UA_PubSubMonitoringType eMonitoringType, void *data);
+    UA_StatusCode (*stopMonitoring)(UA_Server *server, UA_NodeId Id,
+                                    UA_PubSubComponentEnumType eComponentType,
+                                    UA_PubSubMonitoringType eMonitoringType, void *data);
+    UA_StatusCode (*updateMonitoringInterval)(UA_Server *server, UA_NodeId Id,
+                                              UA_PubSubComponentEnumType eComponentType,
+                                              UA_PubSubMonitoringType eMonitoringType,
+                                              void *data);
+    UA_StatusCode (*deleteMonitoring)(UA_Server *server, UA_NodeId Id,
+                                      UA_PubSubComponentEnumType eComponentType,
+                                      UA_PubSubMonitoringType eMonitoringType, void *data);
+} UA_PubSubMonitoringInterface;
+
+#endif /* UA_ENABLE_PUBSUB_MONITORING */
+
+/* General PubSub configuration */
+struct UA_PubSubConfiguration {
+    /* Callback for PubSub component state changes: If provided this callback
+     * informs the application about PubSub component state changes. E.g. state
+     * change from operational to error in case of a DataSetReader
+     * MessageReceiveTimeout. The status code provides additional
+     * information. */
+    void (*stateChangeCallback)(UA_Server *server, UA_NodeId *id,
+                                UA_PubSubState state, UA_StatusCode status);
+
+    UA_Boolean enableDeltaFrames;
+
+#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
+    UA_Boolean enableInformationModelMethods;
+#endif
+
+#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
+    /* PubSub security policies */
+    size_t securityPoliciesSize;
+    UA_PubSubSecurityPolicy *securityPolicies;
+#endif
+
+#ifdef UA_ENABLE_PUBSUB_MONITORING
+    UA_PubSubMonitoringInterface monitoringInterface;
+#endif
+};
+
+/* Add a new PubSub connection to the given server and open it.
+ * @param server The server to add the connection to.
+ * @param connectionConfig The configuration for the newly added connection.
+ * @param connectionIdentifier If not NULL will be set to the identifier of the
+ *        newly added connection.
+ * @return UA_STATUSCODE_GOOD if connection was successfully added, otherwise an
+ *         error code. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_addPubSubConnection(UA_Server *server,
+                              const UA_PubSubConnectionConfig *connectionConfig,
+                              UA_NodeId *connectionIdentifier);
+
+/* Returns a deep copy of the config */
+UA_StatusCode UA_THREADSAFE
+UA_Server_getPubSubConnectionConfig(UA_Server *server,
+                                    const UA_NodeId connection,
+                                    UA_PubSubConnectionConfig *config);
+
+/* Remove Connection, identified by the NodeId. Deletion of Connection
+ * removes all contained WriterGroups and Writers. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_removePubSubConnection(UA_Server *server, const UA_NodeId connection);
+
+
+
+
+

PublishedDataSets

+

The PublishedDataSets (PDS) are containers for the published information. The +PDS contain the published variables and meta information. The metadata is +commonly autogenerated or given as constant argument as part of the template +functions. The template functions are standard defined and intended for +configuration tools. You should normally create an empty PDS and call the +functions to add new fields.

+
/* The UA_PUBSUB_DATASET_PUBLISHEDITEMS has currently no additional members and
+ * thus no dedicated config structure. */
+
+typedef enum {
+    UA_PUBSUB_DATASET_PUBLISHEDITEMS,
+    UA_PUBSUB_DATASET_PUBLISHEDEVENTS,
+    UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE,
+    UA_PUBSUB_DATASET_PUBLISHEDEVENTS_TEMPLATE,
+} UA_PublishedDataSetType;
+
+typedef struct {
+    UA_DataSetMetaDataType metaData;
+    size_t variablesToAddSize;
+    UA_PublishedVariableDataType *variablesToAdd;
+} UA_PublishedDataItemsTemplateConfig;
+
+typedef struct {
+    UA_NodeId eventNotfier;
+    UA_ContentFilter filter;
+} UA_PublishedEventConfig;
+
+typedef struct {
+    UA_DataSetMetaDataType metaData;
+    UA_NodeId eventNotfier;
+    size_t selectedFieldsSize;
+    UA_SimpleAttributeOperand *selectedFields;
+    UA_ContentFilter filter;
+} UA_PublishedEventTemplateConfig;
+
+/* Configuration structure for PublishedDataSet */
+typedef struct {
+    UA_String name;
+    UA_PublishedDataSetType publishedDataSetType;
+    union {
+        /* The UA_PUBSUB_DATASET_PUBLISHEDITEMS has currently no additional members
+         * and thus no dedicated config structure.*/
+        UA_PublishedDataItemsTemplateConfig itemsTemplate;
+        UA_PublishedEventConfig event;
+        UA_PublishedEventTemplateConfig eventTemplate;
+    } config;
+} UA_PublishedDataSetConfig;
+
+void
+UA_PublishedDataSetConfig_clear(UA_PublishedDataSetConfig *pdsConfig);
+
+typedef struct {
+    UA_StatusCode addResult;
+    size_t fieldAddResultsSize;
+    UA_StatusCode *fieldAddResults;
+    UA_ConfigurationVersionDataType configurationVersion;
+} UA_AddPublishedDataSetResult;
+
+UA_AddPublishedDataSetResult UA_THREADSAFE
+UA_Server_addPublishedDataSet(UA_Server *server,
+                              const UA_PublishedDataSetConfig *publishedDataSetConfig,
+                              UA_NodeId *pdsIdentifier);
+
+/* Returns a deep copy of the config */
+UA_StatusCode UA_THREADSAFE
+UA_Server_getPublishedDataSetConfig(UA_Server *server, const UA_NodeId pds,
+                                    UA_PublishedDataSetConfig *config);
+
+/* Returns a deep copy of the DataSetMetaData for an specific PDS */
+UA_StatusCode UA_THREADSAFE
+UA_Server_getPublishedDataSetMetaData(UA_Server *server, const UA_NodeId pds,
+                                      UA_DataSetMetaDataType *metaData);
+
+/* Remove PublishedDataSet, identified by the NodeId. Deletion of PDS removes
+ * all contained and linked PDS Fields. Connected WriterGroups will be also
+ * removed. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_removePublishedDataSet(UA_Server *server, const UA_NodeId pds);
+
+
+
+
+

DataSetFields

+

The description of published variables is named DataSetField. Each +DataSetField contains the selection of one information model node. The +DataSetField has additional parameters for the publishing, sampling and error +handling process.

+
typedef struct{
+    UA_ConfigurationVersionDataType configurationVersion;
+    UA_String fieldNameAlias;
+    UA_Boolean promotedField;
+    UA_PublishedVariableDataType publishParameters;
+
+    /* non std. field */
+    struct {
+        UA_Boolean rtFieldSourceEnabled;
+        /* If the rtInformationModelNode is set, the nodeid in publishParameter must point
+         * to a node with external data source backend defined
+         * */
+        UA_Boolean rtInformationModelNode;
+        //TODO -> decide if suppress C++ warnings and use 'UA_DataValue * * const staticValueSource;'
+        UA_DataValue ** staticValueSource;
+    } rtValueSource;
+    UA_UInt32 maxStringLength;
+
+} UA_DataSetVariableConfig;
+
+typedef enum {
+    UA_PUBSUB_DATASETFIELD_VARIABLE,
+    UA_PUBSUB_DATASETFIELD_EVENT
+} UA_DataSetFieldType;
+
+typedef struct {
+    UA_DataSetFieldType dataSetFieldType;
+    union {
+        /* events need other config later */
+        UA_DataSetVariableConfig variable;
+    } field;
+} UA_DataSetFieldConfig;
+
+void
+UA_DataSetFieldConfig_clear(UA_DataSetFieldConfig *dataSetFieldConfig);
+
+typedef struct {
+    UA_StatusCode result;
+    UA_ConfigurationVersionDataType configurationVersion;
+} UA_DataSetFieldResult;
+
+UA_DataSetFieldResult UA_THREADSAFE
+UA_Server_addDataSetField(UA_Server *server,
+                          const UA_NodeId publishedDataSet,
+                          const UA_DataSetFieldConfig *fieldConfig,
+                          UA_NodeId *fieldIdentifier);
+
+/* Returns a deep copy of the config */
+UA_StatusCode UA_THREADSAFE
+UA_Server_getDataSetFieldConfig(UA_Server *server, const UA_NodeId dsf,
+                                UA_DataSetFieldConfig *config);
+
+UA_DataSetFieldResult UA_THREADSAFE
+UA_Server_removeDataSetField(UA_Server *server, const UA_NodeId dsf);
+
+
+
+
+

Custom Callback Implementation

+

The user can use his own callback implementation for publishing +and subscribing. The user must take care of the callback to call for +every publishing or subscibing interval

+
typedef struct {
+    /* User's callback implementation. The user configured base time and timer policy
+     * will be provided as an argument to this callback so that the user can
+     * implement his callback (thread) considering base time and timer policies */
+    UA_StatusCode (*addCustomCallback)(UA_Server *server, UA_NodeId identifier,
+                                       UA_ServerCallback callback,
+                                       void *data, UA_Double interval_ms,
+                                       UA_DateTime *baseTime, UA_TimerPolicy timerPolicy,
+                                       UA_UInt64 *callbackId);
+
+    UA_StatusCode (*changeCustomCallback)(UA_Server *server, UA_NodeId identifier,
+                                          UA_UInt64 callbackId, UA_Double interval_ms,
+                                          UA_DateTime *baseTime, UA_TimerPolicy timerPolicy);
+
+    void (*removeCustomCallback)(UA_Server *server, UA_NodeId identifier, UA_UInt64 callbackId);
+
+} UA_PubSub_CallbackLifecycle;
+
+
+
+
+

WriterGroup

+

All WriterGroups are created within a PubSubConnection and automatically +deleted if the connection is removed. The WriterGroup is primary used as +container for DataSetWriter and network message settings. The WriterGroup can be +imagined as producer of the network messages. The creation of network +messages is controlled by parameters like the publish interval, which is e.g. +contained in the WriterGroup.

+
typedef enum {
+    UA_PUBSUB_ENCODING_UADP = 0,
+    UA_PUBSUB_ENCODING_JSON = 1,
+    UA_PUBSUB_ENCODING_BINARY = 2
+} UA_PubSubEncodingType;
+
+
+
+
+

WriterGroup

+

The message publishing can be configured for realtime requirements. The RT-levels +go along with different requirements. The below listed levels can be configured:

+

UA_PUBSUB_RT_NONE - +—> Description: Default “none-RT” Mode +—> Requirements: - +—> Restrictions: - +UA_PUBSUB_RT_DIRECT_VALUE_ACCESS (Preview - not implemented) +—> Description: Normally, the latest value for each DataSetField is read out of the information model. Within this RT-mode, the +value source of each field configured as static pointer to an DataValue. The publish cycle won’t use call the server read function. +—> Requirements: All fields must be configured with a ‘staticValueSource’. +—> Restrictions: - +UA_PUBSUB_RT_FIXED_LENGTH (Preview - not implemented) +—> Description: All DataSetFields have a known, non-changing length. The server will pre-generate some +buffers and use only memcopy operations to generate requested PubSub packages. +—> Requirements: DataSetFields with variable size cannot be used within this mode. +—> Restrictions: The configuration must be frozen and changes are not allowed while the WriterGroup is ‘Operational’. +UA_PUBSUB_RT_DETERMINISTIC (Preview - not implemented) +—> Description: - +—> Requirements: - +—> Restrictions: -

+

WARNING! For hard real time requirements the underlying system must be rt-capable.

+
typedef enum {
+    UA_PUBSUB_RT_NONE = 0,
+    UA_PUBSUB_RT_DIRECT_VALUE_ACCESS = 1,
+    UA_PUBSUB_RT_FIXED_SIZE = 2,
+    UA_PUBSUB_RT_DETERMINISTIC = 4,
+} UA_PubSubRTLevel;
+
+typedef struct {
+    UA_String name;
+    UA_Boolean enabled;
+    UA_UInt16 writerGroupId;
+    UA_Duration publishingInterval;
+    UA_Double keepAliveTime;
+    UA_Byte priority;
+    UA_ExtensionObject transportSettings;
+    UA_ExtensionObject messageSettings;
+    UA_KeyValueMap groupProperties;
+    UA_PubSubEncodingType encodingMimeType;
+    /* PubSub Manager Callback */
+    UA_PubSub_CallbackLifecycle pubsubManagerCallback;
+    /* non std. config parameter. maximum count of embedded DataSetMessage in
+     * one NetworkMessage */
+    UA_UInt16 maxEncapsulatedDataSetMessageCount;
+    /* non std. field */
+    UA_PubSubRTLevel rtLevel;
+
+    /* Message are encrypted if a SecurityPolicy is configured and the
+     * securityMode set accordingly. The symmetric key is a runtime information
+     * and has to be set via UA_Server_setWriterGroupEncryptionKey. */
+    UA_MessageSecurityMode securityMode; /* via the UA_WriterGroupDataType */
+#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
+    UA_PubSubSecurityPolicy *securityPolicy;
+    UA_String securityGroupId;
+#endif
+} UA_WriterGroupConfig;
+
+void
+UA_WriterGroupConfig_clear(UA_WriterGroupConfig *writerGroupConfig);
+
+/* Add a new WriterGroup to an existing Connection */
+UA_StatusCode UA_THREADSAFE
+UA_Server_addWriterGroup(UA_Server *server, const UA_NodeId connection,
+                         const UA_WriterGroupConfig *writerGroupConfig,
+                         UA_NodeId *writerGroupIdentifier);
+
+/* Returns a deep copy of the config */
+UA_StatusCode UA_THREADSAFE
+UA_Server_getWriterGroupConfig(UA_Server *server, const UA_NodeId writerGroup,
+                               UA_WriterGroupConfig *config);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_updateWriterGroupConfig(UA_Server *server, UA_NodeId writerGroupIdentifier,
+                                  const UA_WriterGroupConfig *config);
+
+/* Get state of WriterGroup */
+UA_StatusCode UA_THREADSAFE
+UA_Server_WriterGroup_getState(UA_Server *server, UA_NodeId writerGroupIdentifier,
+                               UA_PubSubState *state);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_WriterGroup_publish(UA_Server *server, const UA_NodeId writerGroupIdentifier);
+
+UA_StatusCode UA_THREADSAFE
+UA_WriterGroup_lastPublishTimestamp(UA_Server *server, const UA_NodeId writerGroupId,
+                                    UA_DateTime *timestamp);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_removeWriterGroup(UA_Server *server, const UA_NodeId writerGroup);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_freezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writerGroup);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_unfreezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writerGroup);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_setWriterGroupOperational(UA_Server *server, const UA_NodeId writerGroup);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_setWriterGroupDisabled(UA_Server *server, const UA_NodeId writerGroup);
+
+#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
+/* Set the group key for the message encryption */
+UA_StatusCode UA_THREADSAFE
+UA_Server_setWriterGroupEncryptionKeys(UA_Server *server, const UA_NodeId writerGroup,
+                                       UA_UInt32 securityTokenId,
+                                       const UA_ByteString signingKey,
+                                       const UA_ByteString encryptingKey,
+                                       const UA_ByteString keyNonce);
+#endif
+
+
+
+
+

DataSetWriter

+

The DataSetWriters are the glue between the WriterGroups and the +PublishedDataSets. The DataSetWriter contain configuration parameters and +flags which influence the creation of DataSet messages. These messages are +encapsulated inside the network message. The DataSetWriter must be linked +with an existing PublishedDataSet and be contained within a WriterGroup.

+
typedef struct {
+    UA_String name;
+    UA_UInt16 dataSetWriterId;
+    UA_DataSetFieldContentMask dataSetFieldContentMask;
+    UA_UInt32 keyFrameCount;
+    UA_ExtensionObject messageSettings;
+    UA_ExtensionObject transportSettings;
+    UA_String dataSetName;
+    UA_KeyValueMap dataSetWriterProperties;
+} UA_DataSetWriterConfig;
+
+void
+UA_DataSetWriterConfig_clear(UA_DataSetWriterConfig *pdsConfig);
+
+/* Add a new DataSetWriter to an existing WriterGroup. The DataSetWriter must be
+ * coupled with a PublishedDataSet on creation.
+ *
+ * Part 14, 7.1.5.2.1 defines: The link between the PublishedDataSet and
+ * DataSetWriter shall be created when an instance of the DataSetWriterType is
+ * created. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_addDataSetWriter(UA_Server *server,
+                           const UA_NodeId writerGroup, const UA_NodeId dataSet,
+                           const UA_DataSetWriterConfig *dataSetWriterConfig,
+                           UA_NodeId *writerIdentifier);
+
+/* Returns a deep copy of the config */
+UA_StatusCode UA_THREADSAFE
+UA_Server_getDataSetWriterConfig(UA_Server *server, const UA_NodeId dsw,
+                                 UA_DataSetWriterConfig *config);
+
+/* Get state of DataSetWriter */
+UA_StatusCode UA_THREADSAFE
+UA_Server_DataSetWriter_getState(UA_Server *server, UA_NodeId dataSetWriterIdentifier,
+                                 UA_PubSubState *state);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_removeDataSetWriter(UA_Server *server, const UA_NodeId dsw);
+
+
+
+
+

SubscribedDataSet

+

SubscribedDataSet describes the processing of the received DataSet. +SubscribedDataSet defines which field in the DataSet is mapped to which +Variable in the OPC UA Application. SubscribedDataSet has two sub-types +called the TargetVariablesType and SubscribedDataSetMirrorType. +SubscribedDataSetMirrorType is currently not supported. SubscribedDataSet is +set to TargetVariablesType and then the list of target Variables are created +in the Subscriber AddressSpace. TargetVariables are a list of variables that +are to be added in the Subscriber AddressSpace. It defines a list of Variable +mappings between received DataSet fields and added Variables in the +Subscriber AddressSpace.

+
/* SubscribedDataSetDataType Definition */
+typedef enum {
+    UA_PUBSUB_SDS_TARGET,
+    UA_PUBSUB_SDS_MIRROR
+} UA_SubscribedDataSetEnumType;
+
+typedef struct {
+    /* Standard-defined FieldTargetDataType */
+    UA_FieldTargetDataType targetVariable;
+
+    /* If realtime-handling is required, set this pointer non-NULL and it will be used
+     * to memcpy the value instead of using the Write service.
+     * If the beforeWrite method pointer is set, it will be called before a memcpy update
+     * to the value. But param externalDataValue already contains the new value.
+     * If the afterWrite method pointer is set, it will be called after a memcpy update
+     * to the value. */
+    UA_DataValue **externalDataValue;
+    void *targetVariableContext; /* user-defined pointer */
+    void (*beforeWrite)(UA_Server *server,
+                        const UA_NodeId *readerIdentifier,
+                        const UA_NodeId *readerGroupIdentifier,
+                        const UA_NodeId *targetVariableIdentifier,
+                        void *targetVariableContext,
+                        UA_DataValue **externalDataValue);
+    void (*afterWrite)(UA_Server *server,
+                       const UA_NodeId *readerIdentifier,
+                       const UA_NodeId *readerGroupIdentifier,
+                       const UA_NodeId *targetVariableIdentifier,
+                       void *targetVariableContext,
+                       UA_DataValue **externalDataValue);
+} UA_FieldTargetVariable;
+
+typedef struct {
+    size_t targetVariablesSize;
+    UA_FieldTargetVariable *targetVariables;
+} UA_TargetVariables;
+
+/* Return Status Code after creating TargetVariables in Subscriber AddressSpace */
+UA_StatusCode UA_THREADSAFE
+UA_Server_DataSetReader_createTargetVariables(UA_Server *server,
+                                              UA_NodeId dataSetReaderIdentifier,
+                                              size_t targetVariablesSize,
+                                              const UA_FieldTargetVariable *targetVariables);
+
+/* To Do:Implementation of SubscribedDataSetMirrorType
+ * UA_StatusCode
+ * A_PubSubDataSetReader_createDataSetMirror(UA_Server *server, UA_NodeId dataSetReaderIdentifier,
+ * UA_SubscribedDataSetMirrorDataType* mirror) */
+
+
+
+
+

DataSetReader

+

DataSetReader can receive NetworkMessages with the DataSetMessage +of interest sent by the Publisher. DataSetReaders represent +the configuration necessary to receive and process DataSetMessages +on the Subscriber side. DataSetReader must be linked with a +SubscribedDataSet and be contained within a ReaderGroup.

+
typedef enum {
+    UA_PUBSUB_RT_UNKNOWN = 0,
+    UA_PUBSUB_RT_VARIANT = 1,
+    UA_PUBSUB_RT_DATA_VALUE = 2,
+    UA_PUBSUB_RT_RAW = 4,
+} UA_PubSubRtEncoding;
+
+/* Parameters for PubSub DataSetReader Configuration */
+typedef struct {
+    UA_String name;
+    UA_Variant publisherId;
+    UA_UInt16 writerGroupId;
+    UA_UInt16 dataSetWriterId;
+    UA_DataSetMetaDataType dataSetMetaData;
+    UA_DataSetFieldContentMask dataSetFieldContentMask;
+    UA_Double messageReceiveTimeout;
+    UA_ExtensionObject messageSettings;
+    UA_ExtensionObject transportSettings;
+    UA_SubscribedDataSetEnumType subscribedDataSetType;
+    /* TODO UA_SubscribedDataSetMirrorDataType subscribedDataSetMirror */
+    union {
+        UA_TargetVariables subscribedDataSetTarget;
+        // UA_SubscribedDataSetMirrorDataType subscribedDataSetMirror;
+    } subscribedDataSet;
+    /* non std. fields */
+    UA_String linkedStandaloneSubscribedDataSetName;
+    UA_PubSubRtEncoding expectedEncoding;
+} UA_DataSetReaderConfig;
+
+/* Copy the configuration of DataSetReader */
+UA_StatusCode
+UA_DataSetReaderConfig_copy(const UA_DataSetReaderConfig *src,
+                            UA_DataSetReaderConfig *dst);
+
+/* Clear the configuration of a DataSetReader */
+void
+UA_DataSetReaderConfig_clear(UA_DataSetReaderConfig *cfg);
+
+/* Update configuration to the DataSetReader */
+UA_StatusCode UA_THREADSAFE
+UA_Server_DataSetReader_updateConfig(UA_Server *server, UA_NodeId dataSetReaderIdentifier,
+                                     UA_NodeId readerGroupIdentifier,
+                                     const UA_DataSetReaderConfig *config);
+
+/* Get the configuration (copy) of the DataSetReader */
+UA_StatusCode UA_THREADSAFE
+UA_Server_DataSetReader_getConfig(UA_Server *server, UA_NodeId dataSetReaderIdentifier,
+                                  UA_DataSetReaderConfig *config);
+
+/* Get state of DataSetReader */
+UA_StatusCode UA_THREADSAFE
+UA_Server_DataSetReader_getState(UA_Server *server, UA_NodeId dataSetReaderIdentifier,
+                                 UA_PubSubState *state);
+
+typedef struct {
+    UA_String name;
+    UA_SubscribedDataSetEnumType subscribedDataSetType;
+    union {
+        /* datasetmirror is currently not implemented */
+        UA_TargetVariablesDataType target;
+    } subscribedDataSet;
+    UA_DataSetMetaDataType dataSetMetaData;
+    UA_Boolean isConnected;
+} UA_StandaloneSubscribedDataSetConfig;
+
+void
+UA_StandaloneSubscribedDataSetConfig_clear(UA_StandaloneSubscribedDataSetConfig *sdsConfig);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_addStandaloneSubscribedDataSet(UA_Server *server,
+                               const UA_StandaloneSubscribedDataSetConfig *subscribedDataSetConfig,
+                               UA_NodeId *sdsIdentifier);
+
+/* Remove StandaloneSubscribedDataSet, identified by the NodeId. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_removeStandaloneSubscribedDataSet(UA_Server *server, const UA_NodeId sds);
+
+
+
+
+

ReaderGroup

+

ReaderGroup is used to group a list of DataSetReaders. All ReaderGroups are +created within a PubSubConnection and automatically deleted if the connection +is removed. All network message related filters are only available in the +DataSetReader.

+

The RT-levels go along with different requirements. The below listed levels +can be configured for a ReaderGroup.

+
    +
  • UA_PUBSUB_RT_NONE: RT applied to this level

  • +
  • PUBSUB_CONFIG_FASTPATH_FIXED_OFFSETS: Extends PubSub RT functionality and +implements fast path message decoding in the Subscriber. Uses a buffered +network message and only decodes the necessary offsets stored in an offset +buffer.

  • +
+
/* ReaderGroup configuration */
+typedef struct {
+    UA_String name;
+
+    /* non std. field */
+    UA_PubSubRTLevel rtLevel;
+    UA_KeyValueMap groupProperties;
+    UA_PubSubEncodingType encodingMimeType;
+    UA_ExtensionObject transportSettings;
+
+    /* Messages are decrypted if a SecurityPolicy is configured and the
+     * securityMode set accordingly. The symmetric key is a runtime information
+     * and has to be set via UA_Server_setReaderGroupEncryptionKey. */
+    UA_MessageSecurityMode securityMode;
+#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
+    UA_PubSubSecurityPolicy *securityPolicy;
+    UA_String securityGroupId;
+#endif
+} UA_ReaderGroupConfig;
+
+void
+UA_ReaderGroupConfig_clear(UA_ReaderGroupConfig *readerGroupConfig);
+
+/* Add DataSetReader to the ReaderGroup */
+UA_StatusCode UA_THREADSAFE
+UA_Server_addDataSetReader(UA_Server *server, UA_NodeId readerGroupIdentifier,
+                           const UA_DataSetReaderConfig *dataSetReaderConfig,
+                           UA_NodeId *readerIdentifier);
+
+/* Remove DataSetReader from ReaderGroup */
+UA_StatusCode UA_THREADSAFE
+UA_Server_removeDataSetReader(UA_Server *server, UA_NodeId readerIdentifier);
+
+/* To Do: Update Configuration of ReaderGroup
+ * UA_StatusCode
+ * UA_Server_ReaderGroup_updateConfig(UA_Server *server, UA_NodeId readerGroupIdentifier,
+ *                                    const UA_ReaderGroupConfig *config);
+ */
+
+/* Get configuraiton of ReaderGroup */
+UA_StatusCode UA_THREADSAFE
+UA_Server_ReaderGroup_getConfig(UA_Server *server, UA_NodeId readerGroupIdentifier,
+                                UA_ReaderGroupConfig *config);
+
+/* Get state of ReaderGroup */
+UA_StatusCode UA_THREADSAFE
+UA_Server_ReaderGroup_getState(UA_Server *server, UA_NodeId readerGroupIdentifier,
+                               UA_PubSubState *state);
+
+/* Add ReaderGroup to the created connection */
+UA_StatusCode UA_THREADSAFE
+UA_Server_addReaderGroup(UA_Server *server, UA_NodeId connectionIdentifier,
+                         const UA_ReaderGroupConfig *readerGroupConfig,
+                         UA_NodeId *readerGroupIdentifier);
+
+/* Remove ReaderGroup from connection */
+UA_StatusCode UA_THREADSAFE
+UA_Server_removeReaderGroup(UA_Server *server, UA_NodeId groupIdentifier);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_freezeReaderGroupConfiguration(UA_Server *server, const UA_NodeId readerGroupId);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_unfreezeReaderGroupConfiguration(UA_Server *server, const UA_NodeId readerGroupId);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_setReaderGroupOperational(UA_Server *server, const UA_NodeId readerGroupId);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_setReaderGroupDisabled(UA_Server *server, const UA_NodeId readerGroupId);
+
+#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
+/* Set the group key for the message encryption */
+UA_StatusCode UA_THREADSAFE
+UA_Server_setReaderGroupEncryptionKeys(UA_Server *server, UA_NodeId readerGroup,
+                                       UA_UInt32 securityTokenId,
+                                       UA_ByteString signingKey,
+                                       UA_ByteString encryptingKey,
+                                       UA_ByteString keyNonce);
+#endif
+
+#ifdef UA_ENABLE_PUBSUB_SKS
+
+
+
+
+

SecurityGroup

+

A SecurityGroup is an abstraction that represents the message security settings and +security keys for a subset of NetworkMessages exchanged between Publishers and +Subscribers. The SecurityGroup objects are created on a Security Key Service (SKS). The +SKS manages the access to the keys based on the role permission for a user assigned to +a SecurityGroup Object. A SecurityGroup is identified with a unique identifier called +the SecurityGroupId. It is unique within the SKS.

+
+

Note

+

The access to the SecurityGroup and therefore the securitykeys managed by SKS +requires management of Roles and Permissions in the SKS. The Role Permission +model is not supported at the time of writing. However, the access control plugin can +be used to create and manage role permission on SecurityGroup object.

+
+
typedef struct {
+    UA_String securityGroupName;
+    UA_Duration keyLifeTime;
+    UA_String securityPolicyUri;
+    UA_UInt32 maxFutureKeyCount;
+    UA_UInt32 maxPastKeyCount;
+} UA_SecurityGroupConfig;
+
+
+

@brief Creates a SecurityGroup object and add it to the list in PubSub Manager. If the +information model is enabled then the SecurityGroup object Node is also created in the +server. A keyStorage with initial list of keys is created with a SecurityGroup. A +callback is added to new SecurityGroup which updates the keys periodically at each +KeyLifeTime expire.

+

@param server The server instance +@param securityGroupFolderNodeId The parent node of the SecurityGroup. It must be of +SecurityGroupFolderType +@param securityGroupConfig The security settings of a SecurityGroup +@param securityGroupNodeId The output nodeId of the new SecurityGroup +@return UA_StatusCode The return status code

+
UA_StatusCode UA_THREADSAFE
+UA_Server_addSecurityGroup(UA_Server *server, UA_NodeId securityGroupFolderNodeId,
+                           const UA_SecurityGroupConfig *securityGroupConfig,
+                           UA_NodeId *securityGroupNodeId);
+
+
+

@brief Removes the SecurityGroup from PubSub Manager. It removes the KeyStorage +associated with the SecurityGroup from the server.

+

@param server The server instance +@param securityGroup The nodeId of the securityGroup to be removed +@return UA_StatusCode The returned status code.

+
UA_StatusCode UA_THREADSAFE
+UA_Server_removeSecurityGroup(UA_Server *server, const UA_NodeId securityGroup);
+
+
+

@brief This is a repeated callback which is triggered on each iteration of SKS Pull request. +The server uses this callback to notify user about the status of current Pull request iteration. +The period is calculated based on the KeylifeTime of specified in the SecurityGroup object node on +the SKS server.

+

@param server The server instance managing the publisher/subscriber. +@param sksPullRequestStatus The current status of sks pull request. +@param context The pointer to user defined data passed to this callback.

+
typedef void
+(*UA_Server_sksPullRequestCallback)(UA_Server *server, UA_StatusCode sksPullRequestStatus, void* context);
+
+
+

@brief Sets the SKS client config used to call the GetSecurityKeys Method on SKS and get the +initial set of keys for a SecurityGroupId and adds timedCallback for the next GetSecurityKeys +method Call. This uses async Client API for SKS Pull request. The SKS Client instance is created and destroyed at +runtime on each iteration of SKS Pull request by the server. The key Rollover mechanism will check if the new +keys are needed then it will call the getSecurityKeys Method on SKS Server. At the end of SKS Pull request +iteration, the sks client will be deleted by a delayed callback (in next server iteration).

+

@note It is be called before setting Reader/Writer Group into Operational because this also allocates +a channel context for the pubsub security policy.

+

@note the stateCallback of sksClientConfig will be overwritten by an internal callback.

+

@param server the server instance +@param clientConfig holds the required configuration to make encrypted connection with +SKS Server. The input client config takes the lifecycle as long as SKS request are made. +It is deleted with its plugins when the server is deleted or the last Reader/Writer +Group of the securityGroupId is deleted. The input config is copied to an internal +config object and the content of input config object will be reset to zero. +@param endpointUrl holds the endpointUrl of the SKS server +@param securityGroupId the SecurityGroupId of the securityGroup on SKS and +reader/writergroups +@param callback the user defined callback to notify the user about the status of SKS +Pull request. +@param context passed to the callback function +@return UA_StatusCode the retuned status

+
UA_StatusCode
+UA_Server_setSksClient(UA_Server *server, UA_String securityGroupId,
+                       UA_ClientConfig *clientConfig, const char *endpointUrl,
+                       UA_Server_sksPullRequestCallback callback, void *context);
+
+#endif /* UA_ENABLE_PUBSUB_SKS */
+
+#endif /* UA_ENABLE_PUBSUB */
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/search.html b/static/doc/v1.4.0/search.html new file mode 100644 index 0000000000..0d535d2966 --- /dev/null +++ b/static/doc/v1.4.0/search.html @@ -0,0 +1,135 @@ + + + + + + Search — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/searchindex.js b/static/doc/v1.4.0/searchindex.js new file mode 100644 index 0000000000..ced7be03a6 --- /dev/null +++ b/static/doc/v1.4.0/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["building", "client", "client_highlevel", "client_highlevel_async", "client_subscriptions", "common", "core_concepts", "index", "nodeset_compiler", "plugin", "plugin_accesscontrol", "plugin_eventloop", "plugin_log", "plugin_nodestore", "plugin_pki", "plugin_securitypolicy", "pubsub", "server", "statuscodes", "toc", "tutorial_client_firststeps", "tutorial_datatypes", "tutorial_pubsub_publish", "tutorial_pubsub_subscribe", "tutorial_server_alarms_conditions", "tutorial_server_datasource", "tutorial_server_events", "tutorial_server_firststeps", "tutorial_server_method", "tutorial_server_monitoreditems", "tutorial_server_object", "tutorial_server_variable", "tutorial_server_variabletype", "tutorials", "types", "types_generated", "util"], "filenames": ["building.rst", "client.rst", "client_highlevel.rst", "client_highlevel_async.rst", "client_subscriptions.rst", "common.rst", "core_concepts.rst", "index.rst", "nodeset_compiler.rst", "plugin.rst", "plugin_accesscontrol.rst", "plugin_eventloop.rst", "plugin_log.rst", "plugin_nodestore.rst", "plugin_pki.rst", "plugin_securitypolicy.rst", "pubsub.rst", "server.rst", "statuscodes.rst", "toc.rst", "tutorial_client_firststeps.rst", "tutorial_datatypes.rst", "tutorial_pubsub_publish.rst", "tutorial_pubsub_subscribe.rst", "tutorial_server_alarms_conditions.rst", "tutorial_server_datasource.rst", "tutorial_server_events.rst", "tutorial_server_firststeps.rst", "tutorial_server_method.rst", "tutorial_server_monitoreditems.rst", "tutorial_server_object.rst", "tutorial_server_variable.rst", "tutorial_server_variabletype.rst", "tutorials.rst", "types.rst", "types_generated.rst", "util.rst"], "titles": ["Building open62541", "Client", "Highlevel Client Functionality", "Async Services", "Subscriptions", "Common Definitions", "Core Concepts of OPC UA", "Introduction", "XML Nodeset Compiler", "Plugin API", "Access Control Plugin API", "Event Loop Subsystem", "Logging Plugin API", "Node Store Plugin API", "Public Key Infrastructure Integration", "SecurityPolicy", "PubSub", "Server", "StatusCodes", "open62541 Documentation", "Building a Simple Client", "Working with Data Types", "Working with Publish/Subscribe", "Subscribing Fields", "Using Alarms and Conditions Server", "Connecting a Variable with a Physical Process", "Generating events", "Building a Simple Server", "Adding Methods to Objects", "Observing Attributes with Local MonitoredItems", "Working with Objects and Object Types", "Adding Variables to a Server", "Working with Variable Types", "Tutorials", "Data Types", "NamingRuleType", "Range Definition"], "terms": {"us": [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 31, 32, 33, 34, 36], "gener": [0, 1, 4, 6, 7, 8, 11, 13, 15, 16, 17, 18, 19, 21, 22, 24, 27, 32, 33], "makefil": 0, "visual": [0, 27], "studio": [0, 27], "project": [0, 7, 8], "thi": [0, 1, 2, 4, 5, 6, 7, 8, 10, 11, 13, 14, 15, 16, 17, 18, 21, 22, 24, 25, 26, 27, 30, 31, 32, 34, 36], "i": [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 36], "perform": [0, 1, 5, 17, 18, 31, 34], "actual": [0, 6, 11, 13, 17, 24, 34], "sudo": 0, "apt": 0, "get": [0, 1, 2, 4, 13, 14, 15, 16, 17, 19, 25, 27, 30], "instal": [0, 27], "git": [0, 8], "essenti": 0, "gcc": [0, 17, 20, 27], "pkg": 0, "config": [0, 1, 13, 14, 16, 17, 19], "python": [0, 8], "enabl": [0, 6, 11, 16, 17, 18, 22, 23, 24, 27, 32, 34], "addit": [0, 1, 5, 7, 8, 10, 11, 13, 15, 16, 19, 21, 22, 26, 34], "curs": 0, "gui": [0, 8, 27], "ccmake": 0, "graphic": [0, 22, 27, 30], "interfac": [0, 6, 11, 14, 16, 17, 22, 23, 32, 34], "libmbedtl": 0, "dev": 0, "encrypt": [0, 6, 7, 15, 16, 19], "support": [0, 1, 5, 6, 7, 8, 10, 11, 13, 16, 17, 18, 27, 36], "check": [0, 1, 4, 6, 8, 13, 16, 17, 28, 31, 34], "libsubunit": 0, "unit": [0, 18], "test": [0, 6, 13, 21, 31, 34], "sphinx": 0, "graphviz": 0, "document": [0, 7, 11, 27, 34], "rtd": 0, "theme": 0, "style": 0, "cd": 0, "mkdir": 0, "make": [0, 1, 2, 6, 8, 13, 15, 16, 17, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 34], "doc": [0, 34], "html": 0, "doc_pdf": 0, "pdf": 0, "requir": [0, 1, 6, 8, 11, 13, 14, 15, 16, 17, 18, 26, 27, 30, 32, 34], "latex": 0, "you": [0, 1, 2, 6, 7, 8, 13, 16, 17, 20, 22, 26, 27, 34], "can": [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 34, 36], "well": [0, 1, 5, 6, 7, 8, 11, 13, 29], "known": [0, 1, 3, 6, 11, 13, 15, 16, 21, 27, 34], "command": [0, 8, 12, 27], "allow": [0, 1, 6, 7, 8, 10, 11, 13, 16, 17, 18, 25, 32, 34], "pre": [0, 6, 16, 34], "built": [0, 7, 20, 21, 34], "header": [0, 1, 6, 8, 17, 18], "your": [0, 8, 27], "own": [0, 1, 8, 11, 13, 16, 25, 26, 27, 34], "In": [0, 6, 8, 11, 13, 16, 17, 20, 24, 25, 26, 27, 30, 32, 34], "order": [0, 1, 6, 8, 13, 17, 19, 26, 27, 34], "dll": 0, "so": [0, 1, 5, 6, 8, 11, 12, 13, 15, 16, 17, 18, 20, 24, 25, 26, 28, 29, 30, 32, 34, 36], "sure": [0, 8, 17, 21, 24], "activ": [0, 1, 6, 10, 11, 17, 18, 24], "build_shared_lib": 0, "To": [0, 5, 8, 11, 13, 16, 17, 24, 26, 27, 34, 36], "overrid": [0, 17], "default": [0, 1, 2, 4, 6, 8, 11, 12, 13, 16, 17, 19, 27, 31, 32, 34], "directori": 0, "dcmake_install_prefix": 0, "some": [0, 1, 6, 7, 8, 11, 13, 16, 17, 20, 21, 30, 34], "path": [0, 5, 6, 8, 16, 17, 18, 36], "base": [0, 1, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 32, 36], "describ": [0, 6, 8, 11, 16, 22, 23, 34], "also": [0, 1, 5, 6, 7, 8, 11, 13, 14, 16, 17, 24, 27, 31, 34, 36], "includ": [0, 1, 2, 5, 7, 8, 17, 20, 21, 22, 23, 25, 27, 28, 29, 31, 32, 34, 36], "thu": [0, 8, 16, 17, 24], "we": [0, 1, 6, 7, 8, 17, 22, 24, 25, 26, 27, 28, 30, 31, 32, 34], "recommend": [0, 8, 13], "mani": [0, 2, 3, 4, 6, 8, 18, 26, 34], "non": [0, 1, 3, 5, 8, 11, 13, 16, 17, 18, 34, 36], "experiment": [0, 19], "possibl": [0, 1, 5, 6, 8, 11, 12, 13, 16, 17, 18, 32], "specifi": [0, 1, 6, 8, 13, 15, 16, 17, 18, 26, 34], "specif": [0, 1, 5, 6, 7, 8, 9, 10, 13, 15, 16, 17, 19, 24, 26, 27, 31, 34], "version": [0, 1, 2, 5, 6, 8, 17, 18], "e": [0, 1, 5, 6, 7, 8, 11, 13, 16, 17, 18, 20, 21, 22, 34, 36], "g": [0, 1, 5, 6, 7, 8, 11, 13, 16, 17, 21, 22, 34, 36], "find_packag": 0, "1": [0, 4, 5, 6, 8, 11, 13, 15, 16, 20, 21, 22, 23, 24, 25, 26, 28, 30, 31, 32, 34, 35, 36], "0": [0, 1, 4, 5, 6, 7, 8, 11, 12, 13, 15, 16, 17, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36], "compon": [0, 6, 7, 16, 24], "event": [0, 1, 4, 5, 6, 7, 9, 13, 16, 18, 19, 29, 33, 34, 35], "fullnamespac": 0, "add_execut": 0, "cpp": 0, "target_link_librari": 0, "A": [0, 1, 5, 6, 8, 11, 12, 13, 16, 17, 18, 21, 22, 24, 28, 29, 34, 36], "full": [0, 1, 6, 8, 13, 17, 21], "list": [0, 1, 6, 7, 8, 11, 13, 14, 16, 17, 18, 23, 31, 34], "dure": [0, 1, 4, 6, 8, 11, 13, 17, 22, 32], "time": [0, 2, 3, 5, 6, 8, 10, 11, 13, 16, 18, 19, 20, 24, 25, 26, 34, 36], "store": [0, 4, 5, 6, 8, 9, 11, 15, 16, 17, 19, 25, 28, 34, 36], "variabl": [0, 5, 6, 7, 8, 10, 13, 16, 17, 18, 19, 20, 22, 23, 24, 28, 29, 30, 33, 34, 36], "open62541_components_al": 0, "here": [0, 1, 6, 8, 10, 15, 17, 22], "explain": [0, 1], "process": [0, 1, 4, 6, 8, 11, 13, 16, 18, 19, 22, 23, 30, 33, 34], "2013": 0, "newer": [0, 27], "mingw": [0, 20, 27], "just": [0, 6, 8, 11, 17, 25, 30, 34], "replac": [0, 4, 6, 10, 11, 13, 17, 18, 30], "compil": [0, 5, 7, 19, 20, 25, 27, 34, 36], "call": [0, 1, 4, 5, 6, 7, 8, 10, 11, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 27, 28, 29, 33, 34, 36], "download": [0, 7, 8], "2": [0, 5, 6, 8, 13, 16, 21, 22, 23, 24, 28, 31, 32, 34, 35, 36], "7": [0, 5, 6, 8, 13, 16, 17, 21, 34, 35, 36], "3": [0, 5, 6, 7, 8, 11, 12, 13, 16, 17, 21, 22, 23, 24, 34, 35, 36], "work": [0, 1, 5, 7, 8, 13, 15, 17, 19, 27, 31, 33, 34, 36], "http": [0, 6, 7, 8, 22, 23, 27, 34], "org": [0, 6, 7, 8, 22, 23, 27, 34], "www": [0, 8], "resourc": [0, 7, 11, 18, 25], "softwar": [0, 6, 7, 16, 18], "microsoft": 0, "visualstudio": 0, "com": [0, 8], "product": 0, "commun": [0, 6, 7, 16, 17, 18], "v": [0, 8, 17, 21, 34], "sourc": [0, 1, 6, 7, 8, 9, 13, 16, 18, 19, 24, 27, 33, 34], "zipfil": 0, "from": [0, 1, 3, 4, 5, 6, 7, 8, 10, 11, 13, 14, 15, 16, 17, 18, 20, 22, 23, 24, 25, 26, 27, 28, 30, 32, 34, 36], "github": [0, 8], "open": [0, 1, 5, 6, 7, 11, 12, 13, 16, 17, 22], "shell": 0, "cmd": 0, "run": [0, 1, 8, 10, 11, 17, 22, 23, 27, 30], "ex": [0, 20, 27], "14": [0, 5, 6, 13, 16, 34, 35], "2015": [0, 27], "user": [0, 1, 4, 5, 6, 8, 10, 11, 13, 16, 17, 18, 24, 27, 29, 34], "Then": [0, 5, 6, 11, 13, 15, 17, 34, 36], "buildopen62541": 0, "sln": 0, "usual": [0, 1, 6, 14, 17, 24, 34], "xcode": 0, "itun": 0, "appl": 0, "u": [0, 8, 20, 23, 25, 26, 28, 30, 31, 32], "app": 0, "id497799835": 0, "l": 0, "mt": 0, "12": [0, 5, 8, 11, 13, 34, 35], "homebrew": 0, "brew": 0, "sh": 0, "pip": 0, "manag": [0, 1, 5, 6, 7, 9, 13, 16, 19, 25, 27], "mai": [0, 1, 4, 5, 6, 8, 11, 13, 15, 16, 17, 18, 28, 34, 36], "preinstal": 0, "easy_instal": 0, "follow": [0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 36], "sphinx_rtd_them": 0, "instruct": [0, 27], "without": [0, 1, 6, 11, 13, 16, 17, 18, 34], "ar": [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 15, 16, 17, 18, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 36], "taken": [0, 17, 25], "care": [0, 8, 16, 17], "abov": [0, 8, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32], "The": [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 36], "procedur": 0, "below": [0, 1, 5, 6, 8, 11, 12, 16, 17, 31, 36], "5": [0, 5, 13, 16, 17, 21, 28, 34, 35, 36], "8": [0, 5, 13, 21, 34, 35], "4": [0, 5, 6, 8, 12, 13, 16, 17, 21, 23, 31, 34, 35, 36], "10": [0, 4, 5, 12, 13, 17, 22, 23, 34, 35], "recent": 0, "pkg_add": 0, "tell": [0, 8], "system": [0, 5, 6, 7, 11, 16, 18, 21, 22, 25, 34, 36], "egcc": 0, "export": [0, 8], "cc": [0, 1, 17], "cxx": 0, "eg": 0, "now": [0, 1, 5, 8, 13, 17, 22, 25, 26, 27, 30, 31, 32, 36], "proced": 0, "an": [0, 1, 2, 3, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32, 33, 34, 36], "howto": 0, "engin": 0, "linux": [0, 11], "ce": 0, "deb": 0, "builder": 0, "tsaarni": 0, "util": [0, 19], "imag": 0, "need": [0, 1, 2, 6, 7, 8, 11, 13, 15, 16, 17, 18, 20, 21, 22, 23, 25, 26, 27, 29, 31, 34], "relas": 0, "goto": 0, "local": [0, 1, 5, 6, 8, 11, 13, 15, 19, 23, 33, 34, 36], "develop": [0, 6, 7, 11, 13, 27], "clone": [0, 8], "chang": [0, 1, 4, 6, 7, 13, 14, 16, 17, 18, 19, 20, 22, 25, 26, 29, 31, 33, 34], "18": [0, 5, 34], "04": [0, 5, 36], "17": [0, 5, 13, 34, 35], "t": [0, 1, 2, 4, 5, 8, 13, 15, 16, 17, 24, 27, 28, 34, 36], "f": [0, 16], "dockerfil": 0, "copi": [0, 1, 5, 7, 8, 11, 13, 16, 17, 20, 21, 25, 28, 30, 32, 34, 36], "repo": 0, "checkout": 0, "pack": 0, "branch": [0, 18], "home": 0, "": [0, 1, 5, 6, 8, 13, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 30, 31, 32, 34, 36], "all": [0, 1, 2, 3, 5, 6, 7, 8, 10, 11, 13, 16, 17, 18, 22, 23, 24, 26, 27, 28, 30, 31, 32, 34, 36], "set": [0, 1, 4, 5, 7, 8, 11, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 27, 30, 31, 32, 33, 34, 36], "developmet": 0, "output": [0, 1, 2, 3, 5, 6, 8, 13, 14, 15, 16, 17, 26, 28, 34, 36], "where": [0, 1, 6, 8, 11, 13, 16, 17, 30, 34], "place": [0, 2, 8, 13, 15, 17], "after": [0, 1, 5, 6, 8, 11, 13, 16, 17, 25, 34, 36], "successful": 0, "found": [0, 1, 5, 8, 13, 15, 17, 18, 20, 22, 34, 36], "If": [0, 1, 2, 3, 5, 6, 8, 11, 13, 14, 15, 16, 17, 22, 24, 32, 34, 36], "master": 0, "alter": 0, "ad": [0, 1, 6, 7, 8, 10, 11, 13, 16, 17, 19, 20, 24, 26, 27, 29, 32, 33, 34], "should": [0, 1, 8, 11, 13, 15, 16, 17, 18, 20, 24, 26, 27, 30, 34], "done": [0, 1, 5, 8, 13, 15, 16], "rule": [0, 12, 18, 19, 30], "file": [0, 8, 12, 14, 17, 18, 20, 25, 27, 34], "respect": [0, 6, 11, 13, 23, 24, 28], "templat": [0, 16], "section": [0, 1, 2, 6, 8, 13, 17, 21, 27, 34], "defin": [0, 1, 2, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 25, 26, 28, 29, 30, 31, 34, 36], "override_dh_auto_configur": 0, "dh_auto_configur": 0, "dbuild_shared_lib": 0, "ON": [0, 8], "dcmake_build_typ": [0, 8], "relwithdebinfo": 0, "dua_namespace_zero": [0, 8], "dua_enable_amalgam": 0, "off": 0, "dua_pack_debian": 0, "pass": [0, 1, 8, 10, 11, 13, 15, 16, 17, 18, 26], "line": [0, 6, 8, 21], "code": [0, 1, 2, 5, 7, 8, 11, 13, 15, 16, 17, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 36], "differ": [0, 1, 4, 8, 11, 13, 16, 17, 23, 25, 31, 34], "id": [0, 1, 6, 8, 13, 16, 17, 18, 19, 24, 26, 34, 36], "tool": [0, 6, 7, 8, 16, 22], "most": [0, 1, 3, 5, 6, 8, 11, 13, 17, 27, 34], "manual": [0, 1, 8, 13, 15, 17, 18, 19, 24, 27, 30, 33, 34], "ua_config": [0, 12], "h": [0, 1, 8, 11, 12, 17, 20, 21, 22, 23, 25, 27, 28, 29, 31, 32], "singl": [0, 2, 3, 4, 5, 6, 8, 11, 13, 17, 27, 34, 36], "releas": [0, 7, 11, 13, 22, 27, 34], "But": [0, 1, 4, 5, 6, 11, 13, 16, 27, 30, 34], "adjust": [0, 1, 4, 17, 27, 34], "them": [0, 1, 6, 8, 17, 34], "cmake_build_typ": 0, "o2": 0, "optim": [0, 5, 26, 36], "symbol": 0, "o0": 0, "minsizerel": 0, "ua_loglevel": [0, 12], "log": [0, 1, 5, 6, 9, 11, 13, 14, 17, 19], "level": [0, 1, 6, 11, 12, 16, 18, 19], "onli": [0, 1, 3, 4, 5, 6, 7, 8, 11, 13, 14, 15, 16, 17, 18, 23, 24, 26, 27, 31, 34, 36], "600": [0, 12], "fatal": 0, "500": [0, 4, 12], "error": [0, 1, 2, 5, 6, 8, 11, 13, 15, 16, 17, 18, 22, 23, 31, 34, 36], "400": [0, 11, 12], "warn": [0, 13, 16, 17], "300": [0, 12], "info": [0, 8], "200": [0, 12], "100": [0, 1, 12, 13, 16, 17, 22, 23, 24, 26, 29, 34], "trace": [0, 5, 36], "flag": [0, 8, 16, 17, 22, 34], "which": [0, 1, 6, 8, 11, 13, 15, 16, 17, 18, 20, 22, 23, 24, 26, 28, 29, 34], "implement": [0, 1, 2, 5, 6, 7, 9, 13, 14, 15, 17, 18, 19, 25, 27, 31, 34, 36], "plugin": [0, 1, 5, 7, 11, 14, 16, 17, 19, 20, 21, 22, 23, 25, 28, 29, 31, 32, 33, 36], "api": [0, 1, 6, 7, 8, 11, 16, 17, 18, 19, 20, 22, 23], "filter": [0, 1, 2, 6, 11, 16, 17, 18, 23, 26, 34, 35], "runtim": [0, 1, 6, 7, 8, 15, 16, 19, 22, 25, 30], "configur": [0, 5, 6, 11, 12, 14, 16, 18, 19, 22, 23, 33, 34, 36], "recompil": [0, 8], "ua_multithread": [0, 5, 13, 17, 36], "multi": [0, 1, 6, 17, 28], "thread": [0, 1, 5, 16, 17, 27, 36], "current": [0, 1, 4, 5, 6, 7, 8, 11, 13, 14, 16, 17, 18, 20, 23, 25, 27, 29, 34, 36], "99": 0, "multithread": 0, "disabl": [0, 1, 6, 11, 16, 17, 18, 24, 34], "function": [0, 5, 6, 7, 8, 11, 13, 15, 16, 19, 20, 21, 22, 24, 25, 30, 31, 32, 34, 36], "mark": [0, 7, 17, 30], "ua_threadsaf": [0, 1, 3, 16, 17], "macro": [0, 6, 12, 19], "protect": [0, 1, 8, 17], "intern": [0, 1, 5, 6, 8, 11, 13, 14, 16, 17, 18, 20, 24, 25, 26, 27, 28, 34, 36], "mutex": 0, "multipl": [0, 11, 13, 16, 17, 18, 19, 34], "same": [0, 1, 2, 5, 6, 8, 10, 11, 13, 17, 18, 26, 28, 30, 31, 34, 36], "caus": [0, 6, 8, 17, 34], "race": 0, "condit": [0, 18, 19, 29, 33, 34], "furthermor": [0, 1, 6, 7, 17, 30], "handl": [0, 1, 2, 6, 8, 11, 13, 16, 19, 22, 33], "asynchron": [0, 4, 5, 6, 7, 11, 17, 18, 19], "method": [0, 1, 5, 7, 8, 10, 11, 13, 14, 15, 16, 18, 19, 21, 24, 29, 33, 34, 36], "extern": [0, 1, 5, 6, 8, 11, 13, 16, 17, 25, 34, 36], "worker": [0, 17], "By": [0, 13, 24], "object": [0, 1, 6, 7, 10, 13, 15, 16, 18, 19, 22, 24, 26, 33, 34], "libopen62541": 0, "static": [0, 1, 2, 3, 4, 8, 11, 12, 13, 16, 17, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 34], "link": [0, 1, 6, 8, 11, 13, 16, 17, 22, 23, 34], "archiv": 0, "lib": [0, 8], "artifact": 0, "ua_build_exampl": 0, "server": [0, 2, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 16, 18, 19, 20, 21, 22, 23, 25, 26, 28, 29, 30, 32, 33, 34, 35, 36], "client": [0, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 16, 17, 18, 19, 24, 25, 26, 27, 29, 30, 31, 33, 34, 36], "c": [0, 7, 8, 16, 17, 20, 22, 23, 24, 27, 34], "ua_build_unit_test": 0, "execut": [0, 1, 3, 5, 6, 11, 13, 17, 18, 25, 26, 27, 28, 34, 35, 36], "individu": [0, 1, 6, 7, 11, 17, 29], "arg": [0, 12], "r": [0, 16], "test_nam": 0, "avail": [0, 1, 5, 6, 11, 16, 17, 18, 20, 21, 23, 34], "displai": [0, 6], "n": [0, 6, 8, 13, 20, 21, 22, 23, 25, 31, 34], "ua_build_selfsigned_certif": 0, "self": [0, 18], "sign": [0, 1, 6, 8, 15, 34], "certif": [0, 1, 6, 7, 9, 15, 18, 19], "openssl": 0, "ua_enable_subscript": [0, 10, 13, 17], "subscript": [0, 1, 7, 10, 18, 19, 29], "ua_enable_subscriptions_ev": [0, 17], "new": [0, 1, 4, 6, 7, 8, 10, 11, 13, 14, 15, 16, 17, 22, 23, 25, 26, 27, 30, 31, 32, 34], "ua_enable_subscriptions_alarms_condit": [0, 17], "upon": [0, 1, 7, 13, 17, 24, 25, 34], "ua_enable_methodcal": [0, 17], "servic": [0, 2, 4, 5, 7, 13, 15, 16, 17, 18, 19, 20, 30, 31, 36], "ua_enable_pars": [0, 5, 34, 36], "pars": [0, 8, 17, 19, 34], "human": [0, 34], "readabl": [0, 34], "format": [0, 1, 5, 12, 13, 14, 17, 18, 34, 36], "builtin": [0, 19], "data": [0, 2, 5, 7, 8, 10, 11, 12, 13, 15, 16, 18, 19, 20, 22, 23, 24, 26, 28, 31, 32, 33, 36], "type": [0, 2, 7, 8, 9, 11, 16, 18, 19, 20, 22, 23, 25, 26, 28, 31, 33], "guid": [0, 5, 19, 21, 27, 36], "nodeid": [0, 1, 2, 3, 4, 6, 8, 10, 13, 16, 17, 18, 19, 20, 24, 25, 29, 30, 31, 33, 35], "etc": [0, 11, 17], "ua_enable_nodemanag": 0, "dynam": [0, 13, 15, 17, 21, 34], "remov": [0, 1, 5, 6, 7, 8, 11, 13, 16, 17, 23, 34, 36], "node": [0, 1, 4, 7, 8, 9, 10, 16, 18, 19, 20, 21, 25, 26, 28, 29, 30, 31, 32, 34], "ua_enable_amalgam": 0, "Not": [0, 17, 18, 34], "ua_enable_immutable_nod": 0, "inform": [0, 1, 5, 7, 8, 11, 13, 15, 19, 21, 22, 23, 25, 26, 27, 28, 31, 33, 34], "model": [0, 5, 7, 8, 13, 18, 19, 21, 22, 23, 24, 25, 27, 28, 31, 33], "edit": [0, 13, 18], "atom": [0, 34], "oper": [0, 1, 2, 4, 5, 6, 7, 10, 11, 13, 15, 16, 18, 19, 25, 34, 36], "alwai": [0, 1, 2, 6, 8, 13, 15, 17, 28, 34], "consist": [0, 1, 5, 6, 8, 11, 12, 13, 17, 18, 31, 36], "access": [0, 1, 6, 7, 9, 11, 13, 14, 15, 16, 18, 19, 31, 34], "interrupt": [0, 9, 17, 18, 19], "parallel": [0, 11], "depend": [0, 1, 5, 6, 7, 8, 11, 13, 15, 17, 18, 24], "storag": [0, 5, 6, 13, 36], "ua_enable_coverag": 0, "measur": [0, 25, 34], "coverag": 0, "ua_enable_discoveri": [0, 17], "discoveri": [0, 19], "ld": [0, 1], "ua_enable_discovery_multicast": [0, 17], "multicast": [0, 6, 11, 16, 22], "me": 0, "ua_enable_discovery_semaphor": 0, "semaphor": [0, 17, 18], "ua_enable_encrypt": [0, 1, 17], "backend": [0, 13, 16, 25], "No": [0, 11, 18, 24, 34], "mbedtl": 0, "mbed": 0, "tl": 0, "libressl": 0, "ua_enable_encryption_tpm2": 0, "tpm": 0, "hardwar": [0, 16], "ua_namespace_zero": [0, 8], "namespac": [0, 2, 5, 8, 13, 17, 21, 34, 36], "zero": [0, 1, 5, 6, 8, 11, 13, 16, 17, 21, 31, 32, 34, 36], "standard": [0, 1, 2, 5, 6, 7, 8, 13, 15, 16, 17, 18, 22, 24, 34, 36], "applic": [0, 1, 2, 6, 7, 8, 11, 13, 16, 17, 18, 24, 25, 27, 32], "barebon": 0, "compat": [0, 11, 17, 18, 34], "small": [0, 5, 13, 34, 36], "doe": [0, 1, 4, 5, 6, 8, 11, 13, 14, 17, 18, 26, 27, 29, 32, 34, 36], "ctt": 0, "conform": [0, 6, 7, 17], "opc": [0, 1, 2, 3, 4, 5, 8, 11, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 28, 30, 31, 34, 36], "foundat": [0, 7], "reduc": [0, 1, 6], "offici": [0, 8, 13, 34], "xml": [0, 7, 19], "definit": [0, 2, 6, 7, 8, 13, 14, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32], "advanc": [0, 19], "ua_file_ns0": [0, 8], "toggl": 0, "visibl": [0, 6, 13], "ua_enable_typedescript": [0, 34], "add": [0, 1, 6, 8, 13, 16, 17, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34], "member": [0, 13, 16, 21, 30, 34], "name": [0, 1, 5, 8, 11, 14, 16, 17, 18, 22, 23, 28, 30, 34, 35, 36], "ua_datatyp": [0, 1, 2, 3, 5, 6, 13, 17, 34, 36], "structur": [0, 1, 3, 5, 8, 13, 16, 17, 18, 19, 21, 31, 33, 34, 36], "ua_enable_statuscode_descript": [0, 34], "statuscod": [0, 1, 3, 10, 17, 19, 24, 26, 30, 31, 35], "ua_enable_full_ns0": 0, "ns0": [0, 8, 13], "instead": [0, 1, 6, 8, 16, 17, 28, 29, 34], "nodeset": [0, 7, 19], "namespace0": 0, "folder": [0, 1, 8, 17, 27], "valu": [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19, 20, 21, 23, 24, 29, 30, 31, 32, 33, 34, 35], "ua": [0, 1, 2, 3, 4, 5, 7, 8, 11, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 28, 30, 31, 34], "nodeset2": [0, 8], "ua_enable_pubsub": [0, 16, 17], "udp": [0, 6, 9, 16, 19, 22, 23], "ua_enable_pubsub_deltafram": 0, "messag": [0, 1, 5, 7, 8, 11, 12, 15, 16, 17, 18, 19, 21, 22, 23, 24, 26, 27, 34], "differenti": [0, 6, 34], "between": [0, 4, 5, 6, 8, 11, 13, 16, 17, 18, 21, 22, 23, 27, 34], "keyfram": 0, "publish": [0, 6, 7, 11, 16, 18, 19, 23, 33], "deltafram": 0, "creation": [0, 4, 6, 16, 22, 23, 32], "consum": [0, 16, 25], "ua_enable_pubsub_file_config": 0, "load": [0, 8], "bytestr": [0, 11, 19, 21], "informationmodel": 0, "subscrib": [0, 5, 6, 11, 16, 18, 19, 33], "ua_enable_pubsub_informationmodel": [0, 16], "represent": [0, 5, 8, 9, 17, 19, 25, 26, 30, 34, 36], "For": [0, 1, 3, 5, 6, 7, 8, 10, 11, 13, 15, 16, 17, 23, 25, 27, 30, 34, 36], "more": [0, 1, 2, 4, 6, 7, 8, 16, 17, 18, 20, 22, 30, 34], "take": [0, 1, 5, 6, 8, 11, 12, 13, 14, 16, 17, 22, 25, 27, 28, 31, 34], "look": [0, 8, 11, 16, 22, 31, 34], "ua_enable_pubsub_monitor": [0, 16], "monitor": [0, 4, 6, 7, 16, 17, 18, 24, 26, 29], "provid": [0, 1, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 17, 18, 20, 23, 25, 27, 31, 32, 34, 36], "basic": [0, 1, 6, 19, 20, 26, 27, 30, 33], "framework": [0, 6, 27], "timeout": [0, 1, 11, 17, 18, 27], "initi": [0, 1, 5, 6, 7, 8, 11, 13, 14, 15, 16, 17, 18, 23, 31, 34, 36], "messagereceivetimeout": [0, 16], "datasetread": [0, 19, 23], "It": [0, 1, 6, 7, 8, 11, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34], "callback": [0, 2, 3, 4, 6, 8, 9, 10, 11, 19, 24, 26, 28, 29, 33], "satisfi": 0, "realtim": [0, 16], "group": [0, 5, 11, 15, 16, 22, 23, 36], "mainli": [0, 8], "itself": [0, 7, 8, 13, 34], "ua_debug": 0, "assert": 0, "intend": [0, 13, 16, 34], "ua_debug_dump_pkg": 0, "dump": 0, "everi": [0, 1, 4, 5, 6, 11, 12, 13, 16, 17, 21, 25, 28, 30, 31, 34, 36], "receiv": [0, 1, 8, 11, 15, 16, 17, 18, 23, 24, 26, 29, 34], "hexdump": 0, "enough": [0, 4, 11, 18, 26], "want": [0, 1, 6, 13, 17, 22, 26, 29, 30], "program": [0, 18, 28, 30], "note": [0, 1, 3, 4, 5, 6, 8, 10, 11, 13, 16, 17, 28, 31, 34, 36], "modifi": [0, 1, 5, 6, 13, 17, 36], "distribut": [0, 7, 16], "consider": 0, "With": [0, 6, 25, 27], "less": [0, 2, 5, 6, 13, 16, 17, 18], "than": [0, 1, 5, 6, 8, 10, 11, 17, 18, 30, 34], "100kb": [0, 7], "ram": 0, "rom": [0, 1, 17, 34], "influenc": [0, 16], "first": [0, 1, 6, 7, 8, 11, 13, 15, 17, 26, 27, 31, 34], "strip": 0, "out": [0, 2, 5, 6, 8, 11, 13, 15, 16, 17, 18, 21, 22, 24, 27, 34, 36], "second": [0, 6, 11, 17, 26, 34], "via": [0, 1, 6, 7, 11, 13, 15, 16, 17, 27, 29, 34], "half": 0, "case": [0, 2, 5, 8, 10, 11, 13, 15, 16, 17, 24, 26, 27, 34], "third": 0, "might": [0, 5, 6, 11, 18, 30, 34], "footprint": 0, "last": [0, 3, 8, 11, 16, 17, 18, 26, 34], "up": [0, 1, 5, 6, 8, 11, 12, 13, 17, 19, 20, 21, 23, 25, 27, 30, 33, 34, 36], "lot": [0, 25, 26, 30], "space": [0, 6, 13, 17, 18, 24, 32, 34], "embed": [0, 7, 16, 34], "scenario": 0, "mostli": [0, 17], "due": [0, 18, 34], "number": [0, 1, 6, 11, 13, 15, 17, 18, 19, 23, 34], "connect": [0, 2, 6, 7, 9, 15, 18, 19, 20, 22, 23, 33], "maximum": [0, 6, 8, 13, 15, 16, 18], "prealloc": 0, "our": [0, 7, 8, 25, 26, 34], "ppa": 0, "daili": 0, "launchpad": 0, "net": 0, "team": 0, "start": [0, 1, 5, 6, 7, 11, 13, 17, 18, 19, 25, 27, 34, 36], "repositori": [0, 6, 8], "updat": [0, 1, 6, 8, 10, 13, 15, 16, 18, 19, 23, 24, 33], "aur": 0, "stabl": [0, 13], "archlinux": 0, "unstabl": 0, "custom": [0, 6, 7, 8, 12, 13, 19, 28, 34], "environ": [0, 11, 20, 27], "open62541_cmake_flag": 0, "6": [0, 5, 6, 11, 13, 17, 21, 34, 35, 36], "port": [0, 1, 5, 6, 11, 17, 27, 36], "misc": [0, 1, 19], "mirror": [0, 16], "have": [0, 1, 2, 3, 5, 6, 7, 8, 11, 13, 15, 16, 17, 18, 20, 26, 27, 28, 29, 30, 31, 32, 34, 36], "previou": [0, 5, 8, 17, 18, 20, 21, 22, 25, 36], "step": [0, 15, 17, 25, 27], "automat": [0, 1, 4, 6, 11, 13, 14, 16, 17, 19, 23, 24, 26, 30], "find": [0, 8, 17, 30], "cp": 0, "tutorial_server_firststep": 0, "std": [0, 16, 20, 27], "c99": [0, 7, 20, 27, 34], "lopen62541": [0, 20, 27], "remot": [1, 6, 11, 13, 15, 17, 18], "conveni": [1, 2, 3, 8, 12, 17, 19, 34], "ha": [1, 4, 5, 6, 7, 8, 11, 13, 14, 15, 16, 17, 18, 21, 23, 25, 26, 30, 34], "been": [1, 4, 5, 6, 7, 8, 13, 17, 18, 25, 26], "wrap": [1, 34], "high": [1, 17, 34, 35], "abstract": [1, 6, 8, 16, 26], "howev": [1, 6, 8, 16, 17, 24, 34], "At": [1, 6, 7, 16, 30], "yet": [1, 8, 17, 18], "contain": [1, 3, 4, 5, 6, 7, 8, 11, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 28, 30, 34, 36], "its": [1, 5, 6, 7, 8, 10, 11, 13, 15, 16, 17, 18, 25, 27, 30, 32, 34, 36], "driven": 1, "main": [1, 6, 8, 11, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32], "loop": [1, 6, 7, 9, 17, 19, 25], "mean": [1, 5, 6, 8, 11, 17, 22, 26, 34, 36], "ani": [1, 4, 6, 7, 8, 11, 13, 14, 16, 17, 18, 20, 21, 26, 27, 28, 34], "action": [1, 6, 18], "background": [1, 2, 4, 7, 11, 13, 17], "especi": [1, 6, 8, 17, 30], "relev": [1, 11, 13, 17, 34], "session": [1, 5, 6, 7, 10, 11, 13, 18, 19], "period": [1, 13, 16, 17], "ua_client_run_iter": [1, 4], "ensur": [1, 5, 6, 13, 17, 34, 36], "keep": [1, 4, 6, 11, 12, 17, 34], "secur": [1, 6, 7, 15, 16, 18, 19], "establish": [1, 5, 6, 7, 11, 17, 18], "see": [1, 2, 4, 5, 6, 7, 8, 11, 17, 21, 27, 31, 34, 36], "about": [1, 4, 15, 16, 17, 22, 29, 34], "paramet": [1, 4, 6, 8, 11, 15, 16, 17, 18, 19, 22, 23], "one": [1, 4, 5, 6, 8, 11, 13, 14, 15, 16, 17, 18, 22, 25, 27, 34, 36], "exampl": [1, 3, 6, 7, 8, 10, 11, 12, 13, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 30, 32, 33, 34], "usag": [1, 8, 13, 16, 17, 22, 23, 24], "creat": [1, 5, 6, 7, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 29, 30, 32, 34, 36], "point": [1, 5, 6, 7, 8, 11, 12, 13, 15, 16, 17, 18, 25, 30, 32, 34, 36], "modifii": [1, 17], "instanti": [1, 6, 7, 8, 11, 13, 17, 19, 28, 32, 33], "shutdown": [1, 5, 17], "clean": [1, 11, 12, 13, 17, 20, 30, 34], "free": [1, 7, 11, 15, 17, 34], "memori": [1, 5, 11, 13, 14, 15, 17, 18, 21, 25, 34, 36], "tutori": [1, 8, 16, 17, 19, 20, 21, 22, 24, 25, 26, 27, 30, 31, 32, 34], "good": [1, 3, 7, 11, 17, 18, 23, 26, 31, 34], "struct": [1, 2, 5, 10, 11, 12, 13, 14, 15, 16, 17, 34, 35, 36], "ua_clientconfig": [1, 16, 17], "void": [1, 2, 3, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 36], "clientcontext": 1, "pointer": [1, 3, 5, 8, 9, 11, 14, 15, 16, 17, 19, 28, 29, 34, 36], "attach": [1, 4, 8, 10, 11, 13, 14, 16, 17, 25, 28], "ua_logg": [1, 11, 12, 14, 15, 17], "respons": [1, 3, 4, 6, 7, 17, 18, 24], "m": [1, 4, 6, 11, 16, 17, 27, 29], "answer": [1, 20, 31], "request": [1, 3, 4, 6, 7, 8, 13, 16, 17, 18, 20, 25, 34], "within": [1, 6, 8, 11, 12, 16, 17, 18, 22, 23, 34], "ua_statuscode_badtimeout": [1, 18], "return": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 36], "overridden": [1, 18], "null": [1, 3, 5, 6, 8, 10, 11, 13, 15, 16, 17, 18, 23, 24, 25, 26, 28, 29, 30, 31, 32, 34, 36], "timeouthint": [1, 34, 35], "ua_uint32": [1, 2, 3, 4, 5, 10, 11, 13, 16, 17, 21, 23, 28, 29, 31, 32, 34, 35, 36], "descript": [1, 3, 6, 8, 13, 16, 19, 23, 26, 28, 31, 34, 35], "must": [1, 5, 6, 8, 11, 13, 16, 17, 20, 22, 23, 27, 34, 36], "applicationuri": [1, 14, 17, 34, 35], "applicationdescript": [1, 17, 18, 19], "match": [1, 5, 6, 8, 13, 15, 17, 18, 23, 32, 34], "uri": [1, 2, 8, 15, 17, 18, 22, 23, 34], "ua_applicationdescript": [1, 17, 34, 35], "clientdescript": [1, 17, 34, 35], "endpoint": [1, 6, 10, 15, 17, 19, 34, 35], "Such": 1, "tcp": [1, 5, 6, 7, 9, 17, 19, 20, 27, 36], "host": [1, 5, 6, 11, 36], "ua_str": [1, 2, 5, 11, 14, 15, 16, 17, 21, 22, 23, 26, 28, 30, 31, 32, 34, 35, 36], "endpointurl": [1, 5, 16, 34, 35, 36], "element": [1, 5, 6, 16, 18, 22, 28, 30, 34, 35], "degre": 1, "freedom": 1, "when": [1, 4, 6, 7, 8, 10, 11, 13, 14, 16, 17, 18, 24, 25, 28, 30, 32, 34], "made": [1, 13, 16, 21], "under": [1, 6, 7, 8, 16, 17, 29], "restrict": [1, 16], "abort": [1, 5, 11, 13], "ua_extensionobject": [1, 2, 10, 16, 34, 35], "useridentitytoken": [1, 10, 17, 19], "ident": [1, 6, 8, 15, 18, 34], "token": [1, 18], "ua_messagesecuritymod": [1, 16, 34, 35], "securitymod": [1, 6, 16, 17, 34, 35], "none": [1, 6, 11, 16, 17], "signandencrypt": [1, 6], "invalid": [1, 5, 18, 36], "indic": [1, 2, 3, 4, 5, 6, 8, 11, 13, 17, 30, 34, 36], "select": [1, 6, 11, 13, 16, 17, 19, 22], "securitypolicyuri": [1, 16, 34, 35], "securitypolici": [1, 6, 9, 16, 17, 19], "securechannel": [1, 5, 10, 15, 17, 19], "empti": [1, 5, 8, 11, 13, 16, 17, 32, 34, 36], "string": [1, 5, 8, 11, 12, 16, 17, 19, 21, 28, 31, 32, 36], "ua_boolean": [1, 2, 3, 5, 8, 10, 13, 16, 17, 21, 24, 25, 30, 34, 35, 36], "nosess": 1, "noreconnect": 1, "don": [1, 2, 4, 5, 13, 15, 17, 27, 28, 34, 36], "reconnect": 1, "lost": [1, 18], "explicitli": [1, 17, 28], "close": [1, 5, 6, 11, 17, 18], "nonewsess": 1, "intial": 1, "either": [1, 5, 6, 11, 13, 17, 18, 34, 36], "usertokenpolici": [1, 10, 17, 19], "least": [1, 18], "byte": [1, 5, 6, 11, 15, 16, 19, 36], "overwrit": [1, 15, 17], "arrai": [1, 3, 5, 8, 11, 13, 17, 19, 20, 21, 31, 32, 33, 36], "endpointdescript": [1, 10, 19], "ignor": [1, 8], "dedic": [1, 7, 16], "field": [1, 8, 13, 16, 17, 18, 19, 24, 26, 33, 34, 35], "write": [1, 6, 8, 13, 15, 16, 18, 19, 24, 25, 30, 31, 32], "getendpoint": [1, 6], "wa": [1, 5, 6, 8, 13, 15, 16, 17, 18, 25, 28, 30, 34, 36], "broken": [1, 5], "ua_endpointdescript": [1, 10, 17, 34, 35], "ua_usertokenpolici": [1, 10, 34, 35], "constrain": [1, 6, 32], "consid": [1, 2, 6, 8, 13, 16, 17, 34], "findserv": [1, 6], "decod": [1, 8, 16, 17, 18, 19, 22, 23], "togeth": [1, 5, 6, 11, 17, 25, 30, 34, 36], "alloc": [1, 5, 11, 13, 14, 15, 16, 17, 18, 21, 34, 36], "custom_datatyp": [1, 17], "const": [1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15, 16, 17, 20, 24, 25, 26, 28, 29, 30, 34, 36], "ua_datatypearrai": [1, 17, 34], "customdatatyp": [1, 17], "securechannellifetim": 1, "lifetim": 1, "channel": [1, 6, 7, 15, 16, 17, 18], "renew": [1, 6], "requestedsessiontimeout": [1, 34, 35], "ua_connectionconfig": [1, 5, 36], "localconnectionconfig": 1, "connectivitycheckinterv": 1, "interv": [1, 11, 13, 16, 17, 29, 34], "task": [1, 7, 19, 27, 33], "eventloop": [1, 11, 16, 19], "ua_eventloop": [1, 11, 16, 17], "externaleventloop": [1, 17], "delet": [1, 4, 5, 6, 10, 13, 14, 15, 16, 18, 19, 22, 23, 26, 27, 34, 36], "size_t": [1, 2, 3, 4, 5, 10, 11, 13, 15, 16, 17, 23, 26, 28, 34, 35, 36], "securitypoliciess": [1, 16, 17], "ua_securitypolici": [1, 15, 17], "verif": [1, 9, 19], "ua_certificateverif": [1, 14, 17], "certificateverif": 1, "authent": [1, 6, 10], "polici": [1, 7, 9, 14, 15, 16, 18, 19], "accesscontrol": [1, 17], "authsecuritypoliciess": 1, "authsecuritypolici": 1, "authsecuritypolicyuri": 1, "state": [1, 6, 11, 12, 16, 17, 18, 19, 26, 28, 30, 33, 34, 35], "different": 1, "connectstatu": 1, "fail": [1, 5, 8, 11, 13, 17, 18, 20, 24, 26, 32, 34, 36], "give": [1, 6, 8, 26], "still": [1, 3, 6, 8, 17, 18, 25, 34], "hope": 1, "recov": [1, 10], "statecallback": [1, 16, 17], "ua_client": [1, 2, 3, 4, 5, 20], "ua_securechannelst": [1, 5, 17], "channelst": 1, "ua_sessionst": [1, 5], "sessionst": 1, "ua_statuscod": [1, 2, 3, 4, 5, 8, 10, 11, 13, 14, 15, 16, 17, 20, 22, 23, 24, 25, 26, 28, 30, 31, 32, 34, 35, 36], "greater": 1, "async": [1, 13, 16, 19], "read": [1, 5, 6, 11, 13, 16, 18, 19, 20, 25, 31, 34, 36], "inactivitycallback": 1, "attempt": [1, 6, 8, 17, 34], "recreat": 1, "healthi": 1, "publishrespons": [1, 4, 19], "queu": [1, 18], "ua_uint16": [1, 2, 5, 16, 17, 23, 24, 26, 34, 36], "outstandingpublishrequest": 1, "delai": [1, 6, 11, 16, 17], "sub": [1, 16, 18], "publishinginterv": [1, 16, 22, 34, 35], "maxkeepalivecount": [1, 34, 35], "subscriptioninactivitycallback": 1, "subscriptionid": [1, 4, 34, 35], "subcontext": [1, 4], "sessionnam": [1, 17, 34, 35], "ua_localeid": [1, 34, 35], "sessionlocaleid": 1, "sessionlocaleidss": 1, "ifdef": [1, 5, 10, 13, 15, 16, 17, 21, 34, 36], "privat": [1, 6, 11, 14, 15, 17], "kei": [1, 6, 8, 9, 11, 15, 16, 17, 19, 34, 35], "pem": [1, 14, 17], "password": [1, 6, 11, 14, 19, 34, 35], "decrypt": [1, 14, 15, 16, 17], "freed": [1, 5, 11, 13, 17, 34, 36], "earli": [1, 17], "other": [1, 6, 8, 10, 11, 13, 16, 17, 18, 20, 21, 22, 34], "part": [1, 3, 5, 6, 8, 11, 15, 16, 17, 18, 22, 27, 34, 36], "setup": [1, 11, 17, 26], "privatekeypasswordcallback": [1, 17], "ua_bytestr": [1, 5, 10, 11, 14, 15, 16, 17, 34, 35, 36], "endif": [1, 2, 5, 10, 11, 12, 13, 15, 16, 17, 18, 21, 34, 36], "brief": [1, 16], "partial": 1, "deep": [1, 5, 13, 16, 17, 34, 36], "clientconfig": [1, 16], "shallow": [1, 17, 34], "logger": [1, 11, 12, 14, 15], "destin": [1, 13, 34], "therefor": [1, 13, 16, 17, 28], "_clear": [1, 17], "dst": [1, 5, 13, 16, 34, 36], "src": [1, 5, 13, 16, 34, 36], "ua_clientconfig_copi": 1, "ua_clientconfig_delet": 1, "wherea": 1, "_copi": 1, "ua_clientconfig_clear": 1, "usernam": [1, 6, 11, 17, 34, 35], "ua_clientconfig_setauthenticationcert": 1, "x509": [1, 6], "crypto": 1, "librari": [1, 7, 19, 20, 27], "ua_inlin": [1, 2, 3, 4, 12, 13, 17, 34], "ua_clientconfig_setauthenticationusernam": 1, "char": [1, 5, 8, 12, 16, 17, 21, 22, 23, 30, 34, 36], "ua_usernameidentitytoken": [1, 34, 35], "identitytoken": 1, "ua_usernameidentitytoken_new": 1, "ua_statuscode_badoutofmemori": [1, 18, 34], "ua_string_alloc": [1, 21, 28, 34], "ua_extensionobject_clear": 1, "ua_extensionobject_setvalu": [1, 34], "ua_typ": [1, 2, 3, 4, 8, 17, 20, 21, 22, 23, 24, 25, 26, 28, 30, 31, 32, 34], "ua_types_usernameidentitytoken": 1, "ua_statuscode_good": [1, 8, 10, 15, 16, 17, 18, 20, 22, 23, 24, 25, 26, 28, 30, 34], "network": [1, 5, 6, 7, 11, 13, 16, 18, 19, 23, 27, 31, 34, 36], "client_config_default": [1, 20, 28], "detail": [1, 2, 6, 7, 8, 11, 15, 16, 17, 18, 19, 22, 27, 34], "option": [1, 3, 5, 6, 8, 11, 13, 16, 17, 19, 23, 27, 34, 36], "ua_client_new": [1, 20], "cc0": [1, 7, 17], "licens": [1, 7, 8, 17, 18], "confiugr": [1, 17], "public": [1, 6, 7, 8, 9, 13, 15, 17, 19, 22], "occur": [1, 5, 11, 13, 15, 17, 18, 34, 36], "move": [1, 17, 18, 34], "content": [1, 12, 13, 15, 16, 17, 18, 21, 22, 23, 27, 34], "clear": [1, 10, 11, 12, 13, 14, 15, 16, 17, 34], "ua_client_newwithconfig": 1, "argument": [1, 3, 5, 6, 8, 11, 16, 17, 18, 19, 26, 28, 36], "except": [1, 13, 21], "ua_client_getst": 1, "ua_client_getconfig": [1, 20], "context": [1, 4, 6, 9, 10, 11, 12, 14, 15, 16, 17, 19, 25, 28, 29, 30], "ua_client_getcontext": 1, "cannot": [1, 4, 6, 8, 13, 16, 17, 18, 24, 30, 34], "disconnect": [1, 6, 18, 20], "ua_client_delet": [1, 20], "besid": [1, 7, 17, 24], "attribut": [1, 4, 8, 9, 15, 18, 19, 20, 26, 31, 32, 33], "choic": 1, "applicationdescripton": 1, "serverdescript": 1, "_delet": [1, 17], "variant": [1, 3, 6, 13, 16, 17, 19, 20, 28, 33], "control": [1, 7, 9, 11, 13, 16, 17, 19], "flow": [1, 11], "ua_client_getconnectionattribut": 1, "ua_qualifiednam": [1, 2, 3, 5, 8, 13, 17, 23, 24, 25, 26, 28, 30, 31, 32, 34, 35, 36], "ua_vari": [1, 2, 3, 4, 5, 13, 16, 17, 20, 21, 24, 25, 26, 28, 30, 31, 34, 35, 36], "outvalu": [1, 2, 17], "ua_client_getconnectionattributecopi": 1, "scalar": [1, 5, 6, 11, 17, 20, 21, 23, 28, 32, 34, 36], "right": [1, 5, 6, 8, 10, 13, 14, 17, 29, 36], "datatyp": [1, 3, 5, 6, 8, 13, 16, 17, 21, 23, 28, 31, 32, 34, 35, 36], "otherwis": [1, 8, 11, 13, 15, 16, 17, 34], "target": [1, 5, 6, 7, 8, 11, 13, 16, 17, 18, 23, 30, 34, 35, 36], "locat": [1, 16, 17, 22, 34], "henc": [1, 11, 17], "ua_client_getconnectionattribute_scalar": 1, "onc": [1, 2, 11, 13, 17, 26, 27], "switch": [1, 5, 6, 13, 36], "anoth": [1, 6, 10, 17, 18, 24], "necessari": [1, 6, 7, 8, 15, 16, 18, 22, 23, 26], "unrecover": [1, 11], "longer": [1, 6, 8, 13, 17, 18, 34], "usabl": [1, 7, 34], "finish": [1, 11, 17, 18], "__ua_client_connect": 1, "param": [1, 2, 5, 11, 13, 15, 16, 17, 34, 36], "localhost": [1, 17, 20, 27], "4840": [1, 17, 20, 22, 23, 27], "whether": [1, 2, 6, 11, 13, 17, 26, 34], "succeed": [1, 2, 18, 34], "ua_client_connect": [1, 20], "fals": [1, 8, 11, 17, 24, 30, 31, 34], "ua_string_clear": [1, 21, 28], "block": [1, 5, 15, 17, 18, 36], "repeatedli": [1, 6, 17], "until": [1, 6, 11, 13, 17], "fulli": [1, 11], "notifi": [1, 16, 17, 29], "statu": [1, 2, 3, 11, 13, 16, 17, 18, 20, 23, 30, 31, 32, 34, 35], "Or": 1, "ua_client_connectasync": 1, "true": [1, 4, 5, 8, 11, 13, 17, 21, 24, 25, 26, 28, 30, 31, 34, 36], "ua_client_connectsecurechannel": 1, "ua_client_connectsecurechannelasync": 1, "given": [1, 5, 6, 8, 13, 15, 16, 17, 27, 32, 34, 36], "regular": [1, 2, 11, 17, 27], "ua_client_connectusernam": 1, "re": [1, 13, 17, 22], "listen": [1, 11, 17, 27], "socket": [1, 5, 11, 17], "incom": [1, 6, 11, 27], "revers": [1, 5, 6, 19, 36], "could": [1, 6, 8, 13, 17, 18, 30, 34], "issu": [1, 6, 7, 13, 19], "ua_client_startlisteningforreverseconnect": 1, "while": [1, 3, 6, 8, 13, 16, 17, 18], "like": [1, 5, 8, 11, 16, 17, 24, 34, 36], "normal": [1, 4, 13, 16, 18, 24], "listenhostnam": 1, "listenhostnameslength": 1, "ua_client_disconnect": 1, "ua_client_disconnectasync": 1, "intact": 1, "exist": [1, 5, 6, 7, 8, 13, 16, 17, 18, 22, 34, 36], "ua_client_disconnectsecurechannel": 1, "iter": [1, 2, 11, 13, 16, 17], "ua_client_disconnectsecurechannelasync": 1, "authenticationtoken": [1, 6, 34, 35], "servernonc": [1, 34, 35], "ua_client_getsessionauthenticationtoken": 1, "ua_nodeid": [1, 2, 3, 4, 8, 10, 13, 16, 17, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 34, 35], "prefer": [1, 17], "ua_client_activatecurrentsess": 1, "ua_client_activatecurrentsessionasync": 1, "alreadi": [1, 5, 8, 11, 13, 14, 16, 17, 18, 20, 22, 30, 34, 36], "transfer": [1, 6, 10, 18], "instanc": [1, 6, 11, 15, 16, 17, 19, 24, 30, 32, 34], "both": [1, 5, 6, 10, 11, 13, 17, 20, 34, 36], "retriev": [1, 2, 6, 13, 15, 17, 18, 34], "origin": [1, 5, 6, 11, 13, 14, 17, 34, 36], "ua_client_activatesess": 1, "ua_client_activatesessionasync": 1, "serverurl": [1, 17], "url": [1, 17, 19, 22, 23], "endpointdescriptionss": 1, "size": [1, 5, 6, 7, 11, 15, 16, 17, 18, 19, 21, 23, 34, 36], "ua_client_getendpoint": 1, "regist": [1, 5, 6, 7, 11, 19, 36], "serveruri": [1, 18, 34, 35], "addition": [1, 6, 8, 17, 21], "serveruriss": [1, 34, 35], "localeidss": [1, 34, 35], "localeid": [1, 17, 19], "registeredserverss": 1, "registeredserv": [1, 17, 19], "ua_client_findserv": 1, "startingrecordid": [1, 34, 35], "record": [1, 6, 17], "higher": [1, 5, 11, 34], "equal": [1, 5, 6, 34, 36], "pagin": 1, "subset": [1, 6, 7, 8, 13, 16, 34], "maxrecordstoreturn": [1, 34, 35], "servercapabilityfilters": [1, 34, 35], "capabl": [1, 6, 11, 16, 17], "servercapabilityfilt": [1, 34, 35], "serveronnetworks": 1, "serveronnetwork": [1, 17, 19], "ua_client_findserversonnetwork": 1, "ua_serveronnetwork": [1, 17, 34, 35], "raw": [1, 2, 6, 7, 20, 31], "expos": [1, 6, 11, 13, 17, 24], "better": 1, "ua_client_highlevel": 1, "__ua_client_servic": [1, 4], "requesttyp": [1, 34, 35], "responsetyp": 1, "ua_readrespons": [1, 3, 21, 34, 35], "ua_client_service_read": [1, 20], "ua_readrequest": [1, 3, 21, 34, 35], "ua_types_readrequest": [1, 3, 21], "ua_types_readrespons": [1, 3, 21], "ua_writerespons": [1, 3, 34, 35], "ua_client_service_writ": 1, "ua_writerequest": [1, 3, 34, 35], "ua_types_writerequest": [1, 3], "ua_types_writerespons": [1, 3], "histor": [1, 3, 5, 6, 10, 13, 18, 19, 34, 35], "ua_historyreadrespons": [1, 34, 35], "ua_client_service_historyread": 1, "ua_historyreadrequest": [1, 34, 35], "ua_types_historyreadrequest": 1, "ua_types_historyreadrespons": 1, "ua_historyupdaterespons": [1, 34, 35], "ua_client_service_historyupd": 1, "ua_historyupdaterequest": [1, 34, 35], "ua_types_historyupdaterequest": 1, "ua_types_historyupdaterespons": 1, "ua_callrespons": [1, 3, 34, 35], "ua_client_service_cal": 1, "ua_callrequest": [1, 34, 35], "ua_types_callrequest": 1, "ua_types_callrespons": 1, "nodemanag": [1, 19], "ua_addnodesrespons": [1, 3, 34, 35], "ua_client_service_addnod": 1, "ua_addnodesrequest": [1, 34, 35], "ua_types_addnodesrequest": 1, "ua_types_addnodesrespons": 1, "ua_addreferencesrespons": [1, 34, 35], "ua_client_service_addrefer": 1, "ua_addreferencesrequest": [1, 34, 35], "ua_types_addreferencesrequest": 1, "ua_types_addreferencesrespons": 1, "ua_deletenodesrespons": [1, 34, 35], "ua_client_service_deletenod": 1, "ua_deletenodesrequest": [1, 34, 35], "ua_types_deletenodesrequest": 1, "ua_types_deletenodesrespons": 1, "ua_deletereferencesrespons": [1, 34, 35], "ua_client_service_deleterefer": 1, "ua_deletereferencesrequest": [1, 34, 35], "ua_types_deletereferencesrequest": 1, "ua_types_deletereferencesrespons": 1, "view": [1, 18, 19, 34, 35], "ua_browserespons": [1, 3, 34, 35], "ua_client_service_brows": 1, "ua_browserequest": [1, 3, 34, 35], "ua_types_browserequest": [1, 3], "ua_types_browserespons": [1, 3], "ua_browsenextrespons": [1, 3, 34, 35], "ua_client_service_browsenext": 1, "ua_browsenextrequest": [1, 3, 34, 35], "ua_types_browsenextrequest": [1, 3], "ua_types_browsenextrespons": [1, 3], "ua_translatebrowsepathstonodeidsrespons": [1, 34, 35], "ua_client_service_translatebrowsepathstonodeid": 1, "ua_translatebrowsepathstonodeidsrequest": [1, 34, 35], "ua_types_translatebrowsepathstonodeidsrequest": 1, "ua_types_translatebrowsepathstonodeidsrespons": 1, "ua_registernodesrespons": [1, 34, 35], "ua_client_service_registernod": 1, "ua_registernodesrequest": [1, 34, 35], "ua_types_registernodesrequest": 1, "ua_types_registernodesrespons": 1, "ua_unregisternodesrespons": [1, 34, 35], "ua_client_service_unregisternod": 1, "ua_unregisternodesrequest": [1, 34, 35], "ua_types_unregisternodesrequest": 1, "ua_types_unregisternodesrespons": 1, "queri": [1, 19, 20], "ua_enable_queri": 1, "ua_queryfirstrespons": 1, "ua_client_service_queryfirst": 1, "ua_queryfirstrequest": 1, "ua_types_queryfirstrequest": 1, "ua_types_queryfirstrespons": 1, "ua_querynextrespons": 1, "ua_client_service_querynext": 1, "ua_querynextrequest": 1, "natur": [1, 34], "sever": [1, 2, 4, 6, 10, 11, 13, 17, 24, 26, 28, 34], "wait": [1, 4, 17, 18], "prioriti": [1, 4, 5, 11, 16, 34, 35, 36], "come": [1, 6, 11, 17, 18, 34], "sent": [1, 6, 16, 17, 18, 23, 29, 34], "wrapper": [1, 3, 20], "__ua_client_asyncservic": [1, 3, 4], "directli": [1, 4, 17, 22, 34], "mechan": [1, 6, 8, 10, 11, 16, 17, 29], "how": [1, 5, 6, 8, 17, 25, 31, 34], "appropri": [1, 6, 17, 18, 20], "do": [1, 6, 7, 8, 13, 16, 17, 18, 26, 29], "securitytoken": [1, 34, 35], "design": [1, 11], "limit": [1, 6, 18, 19], "sai": [1, 28, 34], "dispatch": [1, 34], "accordingli": [1, 10, 16], "shut": [1, 17, 18], "down": [1, 5, 6, 17, 18, 36], "ua_statuscode_badshutdown": [1, 18], "doesn": [1, 8, 17], "userdata": [1, 3, 4], "requestid": [1, 3, 4], "cancel": [1, 3, 6, 17, 18], "pend": [1, 3], "uniqu": [1, 6, 11, 16, 17, 18, 21, 26, 34], "each": [1, 2, 3, 6, 7, 8, 11, 13, 15, 16, 17, 18, 23, 25, 28, 29, 30, 34], "altern": [1, 13, 27], "requesthandl": [1, 34, 35], "necessarili": [1, 34], "outstand": [1, 6, 19], "auto": [1, 6, 11, 17, 34], "000": [1, 16], "avoid": [1, 17], "requethandl": 1, "requesthead": [1, 19, 21], "clash": 1, "typedef": [1, 2, 3, 4, 5, 11, 12, 13, 14, 15, 16, 17, 34, 35, 36], "ua_clientasyncservicecallback": [1, 3, 4], "cancelcount": [1, 34, 35], "ua_client_cancelbyrequesthandl": 1, "map": [1, 8, 13, 16, 19, 23], "ua_client_cancelbyrequestid": 1, "befor": [1, 4, 6, 8, 11, 13, 15, 16, 17, 18, 24, 25, 34], "success": [1, 3, 17, 18, 34], "ua_statuscode_badnotfound": [1, 18], "ua_client_modifyasynccallback": 1, "arriv": [1, 17, 25], "housekeep": 1, "forc": 1, "downtim": 1, "critic": [1, 18], "trigger": [1, 6, 11, 16, 17, 19, 25, 33, 34, 35], "opn": 1, "complet": [1, 16, 18], "synchron": [1, 4, 11, 25], "ua_statuscode_goodcallagain": [1, 18], "elaps": [1, 11], "75": 1, "ua_client_renewsecurechannel": 1, "repeat": [1, 16, 17], "ua_clientcallback": 1, "li": [1, 17], "past": [1, 17], "next": [1, 6, 8, 11, 13, 16, 17, 22, 34], "shall": [1, 5, 6, 8, 10, 11, 13, 16, 17, 30], "forward": [1, 4, 11, 13, 17, 19, 34], "date": [1, 11, 14, 17, 20, 34], "timestamp": [1, 2, 11, 12, 13, 16, 17, 18, 21, 34, 35], "callbackid": [1, 11, 16, 17], "identifi": [1, 6, 8, 11, 13, 15, 16, 17, 21, 22, 24, 25, 26, 28, 30, 34], "later": [1, 5, 6, 8, 10, 16, 17, 22, 30, 34], "ua_client_addtimedcallback": 1, "ua_datetim": [1, 2, 10, 11, 14, 16, 17, 20, 25, 26, 34, 35], "ua_uint64": [1, 5, 11, 16, 17, 34, 36], "cyclic": [1, 11, 17], "repetit": [1, 17], "interval_m": [1, 11, 16, 17], "posit": [1, 5, 6, 8, 17, 36], "latest": [1, 16, 17], "ua_client_addrepeatedcallback": 1, "ua_doubl": [1, 2, 3, 11, 13, 16, 17, 21, 30, 31, 32, 34, 35], "ua_client_changerepeatedcallbackinterv": 1, "ua_client_removecallback": 1, "ua_client_removerepeatedcallback": 1, "lookup": [1, 5, 13, 17, 36], "account": [1, 12, 17], "ua_client_finddatatyp": 1, "typeid": [1, 8, 17, 23, 28, 30, 31, 32, 34], "highlevel": [1, 19], "monitoreditem": [1, 7, 10, 13, 19, 33, 34, 35], "flexibl": [2, 27], "wai": [2, 5, 8, 11, 17, 22, 23, 24, 25, 26, 30, 34, 36], "stack": [2, 5, 7, 8, 17, 18], "becaus": [2, 8, 16, 17, 18, 32, 34], "sensibl": [2, 6, 27, 32], "presum": 2, "easiest": 2, "go": [2, 4, 16, 25, 26, 27, 29], "achiev": 2, "__ua_client_readattribut": 2, "ua_attributeid": [2, 3, 5, 17], "attributeid": [2, 3, 4, 17, 22, 23, 29, 31, 34, 35], "outdatatyp": [2, 17], "ua_client_readnodeidattribut": 2, "outnodeid": [2, 17, 24], "ua_attributeid_nodeid": [2, 3, 5, 17], "ua_types_nodeid": [2, 3, 17], "ua_client_readnodeclassattribut": 2, "ua_nodeclass": [2, 3, 13, 17, 21, 34, 35], "outnodeclass": [2, 17], "ua_attributeid_nodeclass": [2, 3, 5, 17], "ua_types_nodeclass": [2, 3], "ua_client_readbrowsenameattribut": 2, "outbrowsenam": [2, 17], "ua_attributeid_browsenam": [2, 3, 5, 17], "ua_types_qualifiednam": [2, 3, 17], "ua_client_readdisplaynameattribut": 2, "ua_localizedtext": [2, 3, 8, 13, 17, 23, 24, 25, 26, 28, 30, 31, 32, 34, 35], "outdisplaynam": [2, 17], "ua_attributeid_displaynam": [2, 3, 5, 17], "ua_types_localizedtext": [2, 3, 17, 24, 26], "ua_client_readdescriptionattribut": 2, "outdescript": [2, 17], "ua_attributeid_descript": [2, 3, 5, 17], "ua_client_readwritemaskattribut": 2, "outwritemask": [2, 17], "ua_attributeid_writemask": [2, 3, 5, 17], "ua_types_uint32": [2, 3, 17, 21], "ua_client_readuserwritemaskattribut": 2, "outuserwritemask": 2, "ua_attributeid_userwritemask": [2, 3, 5], "ua_client_readisabstractattribut": 2, "outisabstract": [2, 17], "ua_attributeid_isabstract": [2, 3, 5, 17], "ua_types_boolean": [2, 3, 17, 23, 24, 30], "ua_client_readsymmetricattribut": 2, "outsymmetr": [2, 17], "ua_attributeid_symmetr": [2, 3, 5, 17], "ua_client_readinversenameattribut": 2, "outinversenam": [2, 17], "ua_attributeid_inversenam": [2, 3, 5, 17], "ua_client_readcontainsnoloopsattribut": 2, "outcontainsnoloop": [2, 17], "ua_attributeid_containsnoloop": [2, 3, 5, 17], "ua_client_readeventnotifierattribut": 2, "ua_byt": [2, 3, 5, 10, 13, 16, 17, 21, 28, 34, 35, 36], "outeventnotifi": [2, 17], "ua_attributeid_eventnotifi": [2, 3, 5, 17], "ua_types_byt": [2, 3, 17], "ua_client_readvalueattribut": [2, 20], "ua_attributeid_valu": [2, 3, 4, 5, 17, 22, 23, 31], "ua_types_vari": [2, 3, 17], "ua_client_readdatatypeattribut": 2, "ua_attributeid_datatyp": [2, 3, 5, 17], "ua_client_readvaluerankattribut": 2, "ua_int32": [2, 3, 13, 17, 21, 28, 31, 34, 35], "outvaluerank": [2, 17], "ua_attributeid_valuerank": [2, 3, 5, 17], "ua_types_int32": [2, 3, 17, 21, 23, 28, 31], "ua_client_readarraydimensionsattribut": 2, "outarraydimensionss": 2, "outarraydimens": [2, 17], "ua_client_readaccesslevelattribut": 2, "outaccesslevel": [2, 17], "ua_attributeid_accesslevel": [2, 3, 5, 17], "ua_client_readaccesslevelexattribut": 2, "outaccesslevelex": [2, 17], "ua_attributeid_accesslevelex": [2, 3, 5, 17], "ua_client_readuseraccesslevelattribut": 2, "outuseraccesslevel": 2, "ua_attributeid_useraccesslevel": [2, 3, 5], "ua_client_readminimumsamplingintervalattribut": 2, "outminsamplinginterv": 2, "ua_attributeid_minimumsamplinginterv": [2, 3, 5, 17], "ua_types_doubl": [2, 3, 17, 21, 30, 31, 32], "ua_client_readhistorizingattribut": 2, "outhistor": [2, 17], "ua_attributeid_histor": [2, 3, 5, 17], "ua_client_readexecutableattribut": 2, "outexecut": [2, 17], "ua_attributeid_execut": [2, 3, 5, 17], "ua_client_readuserexecutableattribut": 2, "outuserexecut": 2, "ua_attributeid_userexecut": [2, 3, 5], "ua_historicaliteratorcallback": 2, "moredataavail": 2, "callbackcontext": [2, 17], "ua_client_historyread_ev": 2, "starttim": [2, 34, 35], "endtim": [2, 34, 35], "indexrang": [2, 34, 35], "ua_eventfilt": [2, 34, 35], "numvaluespernod": [2, 34, 35], "ua_timestampstoreturn": [2, 3, 4, 17, 34, 35], "timestampstoreturn": [2, 3, 4, 17, 19], "ua_client_historyread_raw": 2, "returnbound": [2, 34, 35], "ua_client_historyread_modifi": 2, "ua_client_historyupdate_insert": 2, "ua_datavalu": [2, 3, 4, 10, 13, 16, 17, 21, 24, 25, 29, 34, 35], "ua_client_historyupdate_replac": 2, "ua_client_historyupdate_upd": 2, "ua_client_historyupdate_deleteraw": 2, "starttimestamp": [2, 10], "endtimestamp": [2, 10], "__ua_client_writeattribut": 2, "indatatyp": [2, 3], "ua_client_writenodeidattribut": 2, "newnodeid": 2, "ua_client_writenodeclassattribut": 2, "newnodeclass": 2, "ua_client_writebrowsenameattribut": 2, "newbrowsenam": 2, "ua_client_writedisplaynameattribut": 2, "newdisplaynam": 2, "ua_client_writedescriptionattribut": 2, "newdescript": 2, "ua_client_writewritemaskattribut": 2, "newwritemask": 2, "ua_client_writeuserwritemaskattribut": 2, "newuserwritemask": 2, "ua_client_writeisabstractattribut": 2, "newisabstract": 2, "ua_client_writesymmetricattribut": 2, "newsymmetr": 2, "ua_client_writeinversenameattribut": 2, "newinversenam": 2, "ua_client_writecontainsnoloopsattribut": 2, "newcontainsnoloop": 2, "ua_client_writeeventnotifierattribut": 2, "neweventnotifi": 2, "ua_client_writevalueattribut": 2, "newvalu": 2, "ua_client_writevalueattribute_scalar": 2, "valuetyp": 2, "datavalu": [2, 6, 13, 16, 17, 19, 25, 35], "ua_client_writevalueattributeex": 2, "ua_types_datavalu": [2, 17, 21], "ua_client_writedatatypeattribut": 2, "newdatatyp": 2, "ua_client_writevaluerankattribut": 2, "newvaluerank": 2, "ua_client_writearraydimensionsattribut": 2, "newarraydimensionss": 2, "newarraydimens": 2, "ua_client_writeaccesslevelattribut": 2, "newaccesslevel": 2, "ua_client_writeaccesslevelexattribut": 2, "newaccesslevelex": 2, "ua_client_writeuseraccesslevelattribut": 2, "newuseraccesslevel": 2, "ua_client_writeminimumsamplingintervalattribut": 2, "newmininterv": 2, "ua_client_writehistorizingattribut": 2, "newhistor": 2, "ua_client_writeexecutableattribut": 2, "newexecut": 2, "ua_client_writeuserexecutableattribut": 2, "newuserexecut": 2, "ua_client_cal": 2, "objectid": [2, 3, 8, 10, 13, 17, 26, 28, 34, 35], "methodid": [2, 3, 10, 13, 26, 28, 34, 35], "inputs": [2, 3, 13, 26, 28], "input": [2, 3, 6, 13, 14, 16, 17, 18, 26, 28, 34], "outputs": [2, 13, 26, 28], "side": [2, 5, 7, 11, 15, 16, 22, 23, 36], "ua_client_addrefer": 2, "sourcenodeid": [2, 13, 17, 34, 35], "referencetypeid": [2, 3, 13, 17, 30, 34, 35], "isforward": [2, 8, 13, 17, 34, 35], "targetserveruri": [2, 34, 35], "ua_expandednodeid": [2, 13, 17, 34, 35], "targetnodeid": [2, 13, 17, 23, 34, 35], "targetnodeclass": [2, 34, 35], "ua_client_deleterefer": 2, "deletebidirect": [2, 17, 34, 35], "ua_client_deletenod": 2, "deletetargetrefer": [2, 34, 35], "__ua_client_addnod": 2, "nodeclass": [2, 3, 13, 17, 19, 21], "requestednewnodeid": [2, 3, 17, 34, 35], "parentnodeid": [2, 3, 8, 17, 24, 25, 31, 34, 35], "browsenam": [2, 3, 5, 6, 8, 13, 17, 28, 34, 35, 36], "typedefinit": [2, 3, 8, 13, 17, 34, 35], "ua_nodeattribut": [2, 3, 17, 34, 35], "attr": [2, 3, 17, 24, 25, 26, 31], "attributetyp": [2, 3, 13, 17], "outnewnodeid": [2, 3, 17], "ua_client_addvariablenod": 2, "ua_variableattribut": [2, 3, 5, 17, 23, 24, 25, 30, 31, 32, 34, 35, 36], "ua_nodeclass_vari": [2, 3, 17, 34, 35], "ua_types_variableattribut": [2, 3, 17], "ua_client_addvariabletypenod": 2, "ua_variabletypeattribut": [2, 3, 5, 17, 32, 34, 35, 36], "ua_nodeclass_variabletyp": [2, 3, 17, 34, 35], "ua_nodeid_nul": [2, 3, 13, 17, 23, 24, 26, 30, 32, 34], "ua_types_variabletypeattribut": [2, 3, 17], "ua_client_addobjectnod": 2, "ua_objectattribut": [2, 3, 5, 8, 17, 23, 24, 30, 34, 35, 36], "ua_nodeclass_object": [2, 3, 17, 34, 35], "ua_types_objectattribut": [2, 3, 17], "ua_client_addobjecttypenod": 2, "ua_objecttypeattribut": [2, 3, 5, 17, 26, 30, 34, 35, 36], "ua_nodeclass_objecttyp": [2, 3, 17, 34, 35], "ua_types_objecttypeattribut": [2, 3, 17], "ua_client_addviewnod": 2, "ua_viewattribut": [2, 3, 5, 17, 34, 35, 36], "ua_nodeclass_view": [2, 3, 17, 34, 35], "ua_types_viewattribut": [2, 3, 17], "ua_client_addreferencetypenod": 2, "ua_referencetypeattribut": [2, 3, 5, 17, 34, 35, 36], "ua_nodeclass_referencetyp": [2, 3, 17, 34, 35], "ua_types_referencetypeattribut": [2, 3, 17], "ua_client_adddatatypenod": 2, "ua_datatypeattribut": [2, 3, 5, 17, 34, 35, 36], "ua_nodeclass_datatyp": [2, 3, 17, 34, 35], "ua_types_datatypeattribut": [2, 3, 17], "ua_client_addmethodnod": 2, "ua_methodattribut": [2, 3, 5, 17, 26, 28, 34, 35, 36], "ua_nodeclass_method": [2, 3, 34, 35], "ua_types_methodattribut": [2, 3], "index": [2, 6, 8, 13, 17, 18, 34, 35], "namespaceuri": [2, 8, 13, 17, 34, 35], "interest": [2, 6, 16, 23, 24, 26, 29], "namespaceindex": [2, 5, 17, 21, 23, 24, 34, 36], "unchang": [2, 5, 36], "ua_client_namespacegetindex": 2, "ifndef": [2, 5, 17, 18, 36], "have_nodeiter_callback": [2, 17], "over": [2, 6, 11, 13, 16, 17, 18, 22, 23, 30, 31, 34], "referenc": [2, 6, 13, 17, 18, 32], "child": [2, 6, 7, 13, 17, 28, 30], "ua_nodeiteratorcallback": [2, 17], "childid": [2, 17], "isinvers": [2, 13, 17, 30, 34, 35], "ua_client_foreachchildnodecal": 2, "ua_clientasyncreadcallback": 3, "rr": [3, 21], "ua_client_sendasyncreadrequest": 3, "readcallback": 3, "reqid": 3, "ua_clientasyncwritecallback": 3, "wr": 3, "ua_client_sendasyncwriterequest": 3, "writecallback": 3, "ua_clientasyncbrowsecallback": 3, "ua_client_sendasyncbrowserequest": 3, "browsecallback": 3, "ua_clientasyncbrowsenextcallback": 3, "ua_client_sendasyncbrowsenextrequest": 3, "browsenextcallback": 3, "readvalueid": [3, 17, 19], "correspond": [3, 6, 8, 13, 15, 17, 22, 32, 34], "common": [3, 6, 7, 8, 13, 19, 30], "split": [3, 5, 6, 7, 17, 36], "two": [3, 6, 8, 11, 16, 17, 23, 28, 34], "overal": [3, 5, 13], "result": [3, 5, 6, 8, 13, 15, 16, 17, 18, 30, 34, 35], "ua_clientasyncoperationcallback": 3, "unpack": 3, "ahead": [3, 17, 27], "ua_clientasyncreadattributecallback": 3, "ua_client_readattribute_async": 3, "ua_readvalueid": [3, 17, 21, 34, 35], "rvi": [3, 21], "ua_clientasyncreadvalueattributecallback": 3, "ua_client_readvalueattribute_async": 3, "ua_clientasyncreaddatatypeattributecallback": 3, "ua_client_readdatatypeattribute_async": 3, "arraydimens": [3, 6, 8, 13, 17, 21, 28, 31, 32, 34, 35], "carri": [3, 6, 13, 17], "uint32": [3, 6, 8, 11, 16, 19, 23], "ua_clientreadarraydimensionsattributecallback": 3, "ua_client_readarraydimensionsattribute_async": 3, "ua_clientasyncreadnodeclassattributecallback": 3, "ua_client_readnodeclassattribute_async": 3, "ua_clientasyncreadbrowsenameattributecallback": 3, "ua_client_readbrowsenameattribute_async": 3, "displaynam": [3, 6, 8, 13, 17, 23, 24, 25, 26, 28, 30, 31, 32, 34, 35], "ua_clientasyncreaddisplaynameattributecallback": 3, "ua_client_readdisplaynameattribute_async": 3, "ua_clientasyncreaddescriptionattributecallback": 3, "ua_client_readdescriptionattribute_async": 3, "writemask": [3, 6, 13, 17, 34, 35], "ua_clientasyncreadwritemaskattributecallback": 3, "ua_client_readwritemaskattribute_async": 3, "userwritemask": [3, 6, 17, 34, 35], "ua_clientasyncreaduserwritemaskattributecallback": 3, "ua_client_readuserwritemaskattribute_async": 3, "isabstract": [3, 6, 8, 13, 17, 34, 35], "ua_clientasyncreadisabstractattributecallback": 3, "ua_client_readisabstractattribute_async": 3, "symmetr": [3, 6, 13, 15, 16, 17, 34, 35], "ua_clientasyncreadsymmetricattributecallback": 3, "ua_client_readsymmetricattribute_async": 3, "inversenam": [3, 6, 8, 13, 17, 34, 35], "ua_clientasyncreadinversenameattributecallback": 3, "ua_client_readinversenameattribute_async": 3, "containsnoloop": [3, 6, 13, 17, 34, 35], "ua_clientasyncreadcontainsnoloopsattributecallback": 3, "ua_client_readcontainsnoloopsattribute_async": 3, "eventnotifi": [3, 4, 6, 13, 17, 19, 24, 34, 35], "ua_clientasyncreadeventnotifierattributecallback": 3, "ua_client_readeventnotifierattribute_async": 3, "valuerank": [3, 8, 13, 17, 19, 23, 28, 30, 31, 32, 34, 35, 36], "ua_clientasyncreadvaluerankattributecallback": 3, "ua_client_readvaluerankattribute_async": 3, "accesslevel": [3, 5, 6, 8, 13, 17, 24, 25, 31, 32, 34, 35, 36], "ua_clientasyncreadaccesslevelattributecallback": 3, "ua_client_readaccesslevelattribute_async": 3, "accesslevelex": [3, 6, 17], "ua_clientasyncreadaccesslevelexattributecallback": 3, "ua_client_readaccesslevelexattribute_async": 3, "useraccesslevel": [3, 6, 8, 17, 34, 35], "ua_clientasyncreaduseraccesslevelattributecallback": 3, "ua_client_readuseraccesslevelattribute_async": 3, "minimumsamplinginterv": [3, 6, 13, 34, 35], "ua_clientasyncreadminimumsamplingintervalattributecallback": 3, "ua_client_readminimumsamplingintervalattribute_async": 3, "ua_clientasyncreadhistorizingattributecallback": 3, "ua_client_readhistorizingattribute_async": 3, "ua_clientasyncreadexecutableattributecallback": 3, "ua_client_readexecutableattribute_async": 3, "userexecut": [3, 6, 17, 26, 28, 34, 35], "ua_clientasyncreaduserexecutableattributecallback": 3, "ua_client_readuserexecutableattribute_async": 3, "__ua_client_writeattribute_async": 3, "ua_client_writevalueattribute_async": 3, "ua_client_writenodeidattribute_async": 3, "ua_client_writenodeclassattribute_async": 3, "ua_client_writebrowsenameattribute_async": 3, "ua_client_writedisplaynameattribute_async": 3, "ua_client_writedescriptionattribute_async": 3, "ua_client_writewritemaskattribute_async": 3, "ua_client_writeuserwritemaskattribute_async": 3, "ua_client_writeisabstractattribute_async": 3, "ua_client_writesymmetricattribute_async": 3, "ua_client_writeinversenameattribute_async": 3, "ua_client_writecontainsnoloopsattribute_async": 3, "ua_client_writeeventnotifierattribute_async": 3, "ua_client_writedatatypeattribute_async": 3, "ua_client_writevaluerankattribute_async": 3, "ua_client_writeaccesslevelattribute_async": 3, "ua_client_writeaccesslevelexattribute_async": 3, "ua_client_writeuseraccesslevelattribute_async": 3, "ua_client_writeminimumsamplingintervalattribute_async": 3, "ua_client_writehistorizingattribute_async": 3, "ua_client_writeexecutableattribute_async": 3, "ua_client_writeuserexecutableattribute_async": 3, "__ua_client_call_async": 3, "ua_clientasynccallcallback": 3, "cr": 3, "ua_client_call_async": 3, "ua_clientasyncaddnodescallback": 3, "__ua_client_addnode_async": 3, "ua_client_addvariablenode_async": 3, "ua_client_addvariabletypenode_async": 3, "ua_client_addobjectnode_async": 3, "ua_client_addobjecttypenode_async": 3, "ua_client_addviewnode_async": 3, "ua_client_addreferencetypenode_async": 3, "ua_client_adddatatypenode_async": 3, "ua_client_addmethodnode_async": 3, "That": [4, 8, 11, 13, 22, 27, 34], "send": [4, 6, 11, 15, 16, 17, 22, 23, 34], "publishrequest": [4, 17, 19], "notif": [4, 6, 7, 13, 17, 18, 24, 29], "continu": [4, 5, 6, 7, 10, 18, 22, 25], "report": [4, 6, 7], "back": [4, 11, 17], "exactli": [4, 22, 30], "And": [4, 6, 8, 11, 30], "transit": [4, 17], "reciev": 4, "ua_client_deletesubscriptioncallback": 4, "subid": 4, "ua_client_statuschangenotificationcallback": 4, "ua_statuschangenotif": [4, 34, 35], "requestedpublishinginterv": [4, 34, 35], "requestedlifetimecount": [4, 34, 35], "10000": 4, "requestedmaxkeepalivecount": [4, 34, 35], "maxnotificationsperpublish": [4, 17, 34, 35], "unlimit": [4, 17], "publishingen": [4, 34, 35], "ua_createsubscriptionrequest": [4, 34, 35], "ua_createsubscriptionrequest_default": 4, "ua_createsubscriptionrequest_init": 4, "ua_createsubscriptionrespons": [4, 34, 35], "ua_client_subscriptions_cr": 4, "subscriptioncontext": 4, "statuschangecallback": 4, "deletecallback": 4, "ua_client_subscriptions_create_async": 4, "ua_modifysubscriptionrespons": [4, 34, 35], "ua_client_subscriptions_modifi": 4, "ua_modifysubscriptionrequest": [4, 34, 35], "ua_client_subscriptions_modify_async": 4, "ua_deletesubscriptionsrespons": [4, 34, 35], "ua_client_subscriptions_delet": 4, "ua_deletesubscriptionsrequest": [4, 34, 35], "ua_client_subscriptions_delete_async": 4, "ua_client_subscriptions_deletesingl": 4, "ua_setpublishingmoderespons": [4, 34, 35], "ua_client_subscriptions_setpublishingmod": 4, "ua_setpublishingmoderequest": [4, 34, 35], "ua_types_setpublishingmoderequest": 4, "ua_types_setpublishingmoderespons": 4, "ua_createmonitoreditemsrespons": [4, 34, 35], "item": [4, 6, 10, 17, 18, 24, 26], "ua_monitoreditemcreaterequest": [4, 17, 29, 34, 35], "ua_monitoreditemcreaterequest_default": [4, 29], "ua_monitoreditemcreaterequest_init": 4, "itemtomonitor": [4, 34, 35], "monitoringmod": [4, 19], "ua_monitoringmode_report": [4, 34, 35], "requestedparamet": [4, 29, 34, 35], "samplinginterv": [4, 29, 34, 35], "250": 4, "discardoldest": [4, 34, 35], "queuesiz": [4, 34, 35], "clienthandl": [4, 34, 35], "ua_client_deletemonitoreditemcallback": 4, "monid": [4, 17], "moncontext": [4, 17], "datachang": [4, 13], "ua_client_datachangenotificationcallback": 4, "ua_client_eventnotificationcallback": 4, "neventfield": [4, 17], "eventfield": [4, 17, 34, 35], "ua_client_monitoreditems_createdatachang": 4, "ua_createmonitoreditemsrequest": [4, 34, 35], "ua_client_monitoreditems_createdatachanges_async": 4, "createcallback": 4, "ua_monitoreditemcreateresult": [4, 17, 34, 35], "ua_client_monitoreditems_createev": 4, "ua_client_monitoreditems_createevents_async": 4, "ua_deletemonitoreditemsrespons": [4, 34, 35], "ua_client_monitoreditems_delet": 4, "ua_deletemonitoreditemsrequest": [4, 34, 35], "ua_client_monitoreditems_delete_async": 4, "ua_client_monitoreditems_deletesingl": 4, "monitoreditemid": [4, 17, 29, 34, 35], "fill": [4, 15, 17], "ua_modifymonitoreditemsrespons": [4, 34, 35], "ua_client_monitoreditems_modifi": 4, "ua_modifymonitoreditemsrequest": [4, 34, 35], "ua_client_monitoreditems_modify_async": 4, "ua_setmonitoringmoderespons": [4, 34, 35], "ua_client_monitoreditems_setmonitoringmod": 4, "ua_setmonitoringmoderequest": [4, 34, 35], "ua_types_setmonitoringmoderequest": 4, "ua_types_setmonitoringmoderespons": 4, "ua_client_monitoreditems_setmonitoringmode_async": 4, "ua_settriggeringrespons": [4, 34, 35], "ua_client_monitoreditems_settrigg": 4, "ua_settriggeringrequest": [4, 34, 35], "ua_types_settriggeringrequest": 4, "ua_types_settriggeringrespons": 4, "ua_client_monitoreditems_settriggering_async": 4, "pubsub": [5, 6, 9, 19, 22, 23], "enum": [5, 11, 12, 13, 16, 17, 34, 35], "9": [5, 6, 13, 21, 34, 35, 36], "11": [5, 13, 34, 35], "13": [5, 13, 34, 35], "15": [5, 13, 34, 35], "ua_attributeid_arraydimens": [5, 17], "16": [5, 13, 34, 35], "19": [5, 34], "20": [5, 34], "21": [5, 34], "22": [5, 22, 23, 34], "ua_attributeid_datatypedefinit": 5, "23": [5, 11, 34, 36], "ua_attributeid_rolepermiss": 5, "24": [5, 34], "ua_attributeid_userrolepermiss": 5, "25": [5, 34], "ua_attributeid_accessrestrict": 5, "26": [5, 34], "27": [5, 34], "constant": [5, 16, 36], "ANDed": 5, "ua_accesslevelmask_read": [5, 24, 25, 31, 32], "0x01u": 5, "0u": 5, "ua_accesslevelmask_writ": [5, 24, 25, 31, 32], "1u": 5, "ua_accesslevelmask_historyread": 5, "2u": 5, "ua_accesslevelmask_historywrit": 5, "3u": 5, "ua_accesslevelmask_semanticchang": 5, "4u": 5, "ua_accesslevelmask_statuswrit": 5, "5u": 5, "ua_accesslevelmask_timestampwrit": 5, "6u": 5, "tabl": [5, 6, 15], "ua_writemask_accesslevel": 5, "ua_writemask_arrraydimens": 5, "ua_writemask_browsenam": 5, "ua_writemask_containsnoloop": 5, "ua_writemask_datatyp": 5, "ua_writemask_descript": 5, "ua_writemask_displaynam": 5, "ua_writemask_eventnotifi": 5, "7u": 5, "ua_writemask_execut": 5, "8u": 5, "ua_writemask_histor": 5, "9u": 5, "ua_writemask_inversenam": 5, "10u": 5, "ua_writemask_isabstract": 5, "11u": 5, "ua_writemask_minimumsamplinginterv": 5, "12u": 5, "ua_writemask_nodeclass": 5, "13u": 5, "ua_writemask_nodeid": 5, "14u": 5, "ua_writemask_symmetr": 5, "15u": 5, "ua_writemask_useraccesslevel": 5, "16u": 5, "ua_writemask_userexecut": 5, "17u": 5, "ua_writemask_userwritemask": 5, "18u": 5, "ua_writemask_valuerank": 5, "19u": 5, "ua_writemask_writemask": 5, "20u": 5, "ua_writemask_valueforvariabletyp": 5, "21u": 5, "ua_writemask_accesslevelex": 5, "25u": 5, "variabletyp": [5, 6, 13, 17], "valid": [5, 6, 7, 8, 10, 11, 16, 18, 34, 36], "ua_valuerank_scalar_or_one_dimens": 5, "ua_valuerank_ani": 5, "ua_valuerank_scalar": [5, 28, 30, 32], "ua_valuerank_one_or_more_dimens": [5, 32], "ua_valuerank_one_dimens": [5, 28, 32], "ua_valuerank_two_dimens": [5, 31], "ua_valuerank_three_dimens": 5, "ua_eventnotifier_subscribe_to_ev": 5, "ua_eventnotifier_history_read": 5, "ua_eventnotifier_history_writ": 5, "rulehand": 5, "soften": 5, "workaround": 5, "misbehav": 5, "mitig": [5, 36], "impact": [5, 11], "introduc": [5, 6], "ua_rulehandling_default": 5, "ua_rulehandling_abort": 5, "ua_rulehandling_warn": 5, "print": [5, 8, 34], "ua_rulehandling_accept": 5, "disregard": [5, 34], "ua_rulehandl": [5, 17], "absolut": [5, 13, 34], "ua_order_less": 5, "ua_order_eq": [5, 13, 34], "ua_order_mor": 5, "ua_ord": [5, 13, 34], "ua_connectionstate_clos": [5, 11], "ua_connectionstate_open": [5, 11], "hel": [5, 6], "ack": [5, 6, 11, 24], "handshak": [5, 6], "ua_connectionstate_establish": [5, 11], "ua_connectionst": [5, 11], "ua_securechannelstate_clos": 5, "ua_securechannelstate_reverse_listen": 5, "ua_securechannelstate_connect": [5, 17], "ua_securechannelstate_reverse_connect": 5, "ua_securechannelstate_rhe_s": 5, "ua_securechannelstate_hel_s": 5, "ua_securechannelstate_hel_receiv": 5, "ua_securechannelstate_ack_s": 5, "ua_securechannelstate_ack_receiv": 5, "ua_securechannelstate_opn_s": 5, "ua_securechannelstate_open": 5, "ua_sessionstate_clos": 5, "ua_sessionstate_create_request": 5, "ua_sessionstate_cr": 5, "ua_sessionstate_activate_request": 5, "ua_sessionstate_activ": 5, "layer": [5, 6, 7, 13, 17, 18, 23, 27, 34, 36], "serverdiagnosticssummarydatatyp": [5, 19], "spec": [5, 19], "harmon": 5, "ua_shutdownreason_clos": 5, "ua_shutdownreason_reject": 5, "ua_shutdownreason_securityreject": 5, "ua_shutdownreason_timeout": 5, "ua_shutdownreason_abort": 5, "ua_shutdownreason_purg": 5, "ua_shutdownreason": 5, "currentchannelcount": 5, "cumulatedchannelcount": 5, "rejectedchannelcount": 5, "channeltimeoutcount": 5, "channelabortcount": 5, "channelpurgecount": 5, "ua_securechannelstatist": [5, 17], "currentsessioncount": [5, 34, 35], "cumulatedsessioncount": [5, 34, 35], "securityrejectedsessioncount": [5, 34, 35], "rejectedsessioncount": [5, 34, 35], "sessiontimeoutcount": [5, 34, 35], "sessionabortcount": [5, 34, 35], "ua_sessionstatist": [5, 17], "stop": [5, 8, 11, 17, 18, 27, 34, 36], "being": [5, 6, 8, 13, 18, 23, 25], "termin": [5, 6, 34], "grace": 5, "ua_lifecyclestate_stop": 5, "ua_lifecyclestate_start": 5, "ua_lifecyclest": [5, 17], "opaqu": [5, 11], "ua_serv": [5, 8, 10, 13, 16, 17, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32], "ua_serverconfig": [5, 17], "ua_servercallback": [5, 16, 17], "min": [5, 20, 34, 36], "max": [5, 8, 11, 17, 18, 34, 36], "ua_uint32rang": [5, 17, 36], "ua_dur": [5, 16, 34, 35, 36], "ua_durationrang": [5, 17, 36], "seed": [5, 15, 36], "ua_random_se": [5, 36], "ua_uint32_random": [5, 23, 36], "cryptograph": [5, 34, 36], "entropi": [5, 36], "ua_guid": [5, 34, 36], "ua_guid_random": [5, 36], "ua_keyvaluepair": [5, 34, 35, 36], "linear": [5, 13, 36], "accept": [5, 11, 17, 18, 36], "ua_keyvaluemap": [5, 11, 16, 36], "treat": [5, 11, 36], "mapsiz": [5, 36], "ua_keyvaluemap_nul": [5, 36], "ua_keyvaluemap_new": [5, 36], "ua_keyvaluemap_clear": [5, 36], "ua_keyvaluemap_delet": [5, 36], "ua_keyvaluemap_isempti": [5, 36], "entri": [5, 13, 16, 18, 28, 34, 36], "ua_keyvaluemap_contain": [5, 36], "insert": [5, 6, 10, 13, 17, 18, 34, 36], "realloc": [5, 34, 36], "underli": [5, 6, 10, 13, 16, 18, 25, 30, 36], "overwritten": [5, 16, 17, 18, 34, 36], "upsert": [5, 36], "semant": [5, 6, 7, 32, 36], "ua_keyvaluemap_set": [5, 36], "ua_keyvaluemap_setscalar": [5, 36], "p": [5, 34, 36], "ua_keyvaluemap_get": [5, 36], "ua_keyvaluemap_getscalar": [5, 36], "entir": [5, 6, 11, 21, 34, 36], "ua_keyvaluemap_remov": [5, 36], "keyvaluemap": [5, 36], "ua_keyvaluemap_copi": [5, 36], "hand": [5, 36], "left": [5, 6, 13, 26, 32, 34, 36], "untouch": [5, 34, 36], "ua_keyvaluemap_merg": [5, 36], "lh": [5, 36], "rh": [5, 36], "protocolvers": [5, 36], "recvbuffers": [5, 36], "sendbuffers": [5, 36], "localmaxmessages": [5, 36], "unbound": [5, 17, 36], "remotemaxmessages": [5, 36], "localmaxchunkcount": [5, 36], "remotemaxchunkcount": [5, 36], "simplifi": [5, 8, 17, 34, 36], "addnod": [5, 6, 13, 17, 30, 36], "often": [5, 6, 30, 36], "unintend": [5, 36], "lead": [5, 8, 17, 34, 36], "hard": [5, 8, 16, 17, 36], "track": [5, 8, 17, 36], "basedatatyp": [5, 17, 34, 35, 36], "ua_variableattributes_default": [5, 23, 24, 25, 30, 31, 32, 36], "ua_variabletypeattributes_default": [5, 32, 36], "ua_methodattributes_default": [5, 26, 28, 36], "remain": [5, 11, 17, 36], "ua_objectattributes_default": [5, 8, 23, 24, 30, 36], "ua_objecttypeattributes_default": [5, 26, 30, 36], "ua_referencetypeattributes_default": [5, 36], "ua_datatypeattributes_default": [5, 36], "ua_viewattributes_default": [5, 36], "hostnam": [5, 6, 11, 17, 18, 36], "form": [5, 6, 16, 36], "omit": [5, 8, 13, 16, 30, 34, 36], "prefix": [5, 36], "colon": [5, 34, 36], "slash": [5, 36], "outhostnam": [5, 36], "ipv6": [5, 11, 36], "address": [5, 6, 11, 16, 17, 18, 20, 22, 23, 24, 34, 36], "2001": [5, 8, 36], "0db8": [5, 36], "85a3": [5, 36], "8a2e": [5, 36], "0370": [5, 36], "7334": [5, 36], "outport": [5, 36], "outpath": [5, 36], "present": [5, 8, 13, 17, 36], "trail": [5, 34, 36], "NOT": [5, 11, 36], "ua_statuscode_badtcpendpointurlinvalid": [5, 18, 36], "ua_parseendpointurl": [5, 36], "vid": [5, 11, 36], "pcp": [5, 11, 36], "eth": [5, 22, 23, 36], "mac": [5, 11, 36], "ip": [5, 11, 21, 36], "six": [5, 11, 36], "hexadecim": [5, 11, 36], "digit": [5, 11, 36], "separ": [5, 11, 34, 36], "hyphen": [5, 11, 36], "01": [5, 11, 13, 36], "45": [5, 8, 11, 36], "67": [5, 11, 36], "89": [5, 11, 36], "ab": [5, 11, 36], "resolv": [5, 17, 36], "dn": [5, 36], "arp": [5, 36], "vlan": [5, 11, 36], "ua_statuscode_badinternalerror": [5, 13, 18, 23, 25, 36], "ua_parseendpointurlethernet": [5, 36], "convert": [5, 34, 36], "ua_readnumb": [5, 36], "buf": [5, 11, 36], "buflen": [5, 36], "ua_readnumberwithbas": [5, 36], "ua_min": [5, 36], "b": [5, 8, 34, 36], "ua_max": [5, 36], "accord": [5, 6, 8, 12, 13, 17, 27, 36], "a2": [5, 36], "browsepath": [5, 17, 19, 36], "referencetyp": [5, 6, 8, 9, 17, 19, 36], "recogn": [5, 18, 36], "hierarchicalrefer": [5, 17, 36], "subtyp": [5, 6, 13, 17, 36], "aggreg": [5, 18, 36], "referencetypesand": [5, 36], "qualifiednam": [5, 6, 19, 36], "invers": [5, 36], "refer": [5, 6, 7, 8, 10, 13, 15, 18, 19, 21, 24, 28, 30, 34, 35, 36], "exclud": [5, 36], "nameitself": [5, 36], "escap": [5, 36], "charact": [5, 34, 36], "truck": [5, 36], "nodevers": [5, 36], "hasproperti": [5, 6, 8, 17, 36], "boiler": [5, 36], "heatsensor": [5, 36], "haschild": [5, 36], "wheel": [5, 36], "ua_relativepath_pars": [5, 36], "ua_relativepath": [5, 34, 35, 36], "rp": [5, 36], "str": [5, 34, 36], "ua_printf_guid_format": [5, 36], "08": [5, 36], "prix32": [5, 36], "prix16": [5, 36], "02": [5, 8, 36], "prix8": [5, 36], "ua_printf_guid_data": [5, 36], "data1": [5, 34, 36], "data2": [5, 34, 36], "data3": [5, 34, 36], "data4": [5, 34, 36], "ua_printf_string_format": [5, 36], "ua_printf_string_data": [5, 36], "int": [5, 8, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 36], "length": [5, 6, 8, 15, 16, 17, 18, 21, 23, 28, 34, 36], "compar": [5, 15, 21, 34, 36], "attack": [5, 36], "ptr1": [5, 36], "ptr2": [5, 36], "ua_constanttimeequ": [5, 36], "secret": [5, 6, 15, 36], "leav": [5, 36], "ua_bytestring_memzero": [5, 36], "sentenc": 6, "iso": 6, "62541": [6, 7, 22, 23, 26, 28], "orient": [6, 7, 16, 30], "typic": [6, 11, 25], "repres": [6, 13, 16, 17, 18, 24, 26, 28, 30, 32, 34], "physic": [6, 19, 33], "devic": [6, 7, 11, 18, 22, 23, 30], "live": [6, 11], "interact": [6, 7, 13, 19, 21, 34], "opcfound": [6, 7, 8, 22, 23, 34], "focu": [6, 30], "binari": [6, 7, 8, 13, 14, 19], "sinc": [6, 8, 13, 15, 17, 26, 34], "far": 6, "transport": [6, 11, 16, 17, 22, 23], "translat": [6, 7, 13, 25], "soap": [6, 7], "best": [6, 8], "understood": 6, "principl": [6, 24], "pattern": [6, 21], "sensor": [6, 17, 18], "machin": [6, 18], "immedi": [6, 8, 11, 13], "respond": 6, "push": 6, "special": [6, 13, 17, 34], "extens": [6, 8, 16, 18, 22, 34], "integr": [6, 7, 9, 19, 27, 30], "rather": [6, 34], "broker": [6, 11, 16], "mqtt": [6, 9, 16, 19], "ethernet": [6, 9, 19, 23], "featur": [6, 16, 17, 19, 34], "three": [6, 17, 27, 32, 34], "nest": 6, "top": [6, 7, 34], "opensecurechannel": 6, "pair": [6, 17], "attent": [6, 17, 34], "even": [6, 8, 27, 34], "though": [6, 26], "mandatori": [6, 13, 17, 18, 30], "As": [6, 7, 8, 25, 34], "open62541": [6, 8, 11, 13, 16, 18, 20, 21, 22, 23, 25, 27, 28, 29, 31, 32, 34], "ongo": 6, "asymmetr": [6, 15], "algorithm": [6, 15, 34, 35], "cryptographi": [6, 19], "unsecur": 6, "subsequ": 6, "advantag": [6, 13], "much": [6, 8, 34], "faster": 6, "hash": [6, 8, 13, 34], "transmiss": [6, 15], "cleartext": 6, "basic256sha256": [6, 7], "mandat": [6, 34], "rsa": 6, "sha256": 6, "aes256": 6, "jointli": [6, 7], "discuss": [6, 7], "certain": [6, 17], "invok": [6, 17], "unencrypt": [6, 15], "discov": 6, "credenti": 6, "anonym": 6, "login": [6, 10], "kerbero": 6, "latter": 6, "accompani": 6, "signatur": [6, 7, 15, 18, 34, 35], "prove": 6, "sender": 6, "possess": 6, "There": [6, 8, 13, 17, 18], "exchang": [6, 7, 16, 27], "createsess": 6, "acticatesess": 6, "activatesess": [6, 10, 18], "import": [6, 8, 11, 13, 24], "broke": 6, "reus": [6, 7, 11, 13, 34], "entail": 6, "author": 6, "verifi": [6, 8, 14, 15, 17, 18, 28], "against": [6, 14, 32], "convers": [6, 34], "figur": [6, 22], "fig": [6, 8], "wireshark": [6, 22], "window": [6, 11, 17, 19], "show": [6, 8, 21, 23, 25, 26, 27, 31], "green": 6, "appli": [6, 8, 13, 16, 17, 18], "packet": [6, 11, 17, 22], "49": 6, "56": 6, "63": [6, 8, 34, 35], "On": [6, 17, 34], "readrequest": [6, 19], "cover": [6, 11, 30], "bottom": 6, "purpos": 6, "bodi": [6, 7, 8, 34], "relat": [6, 7, 16, 18, 23, 24, 30], "chunk": [6, 7, 17, 18], "reassembl": 6, "These": [6, 16, 17, 18, 22, 30, 34], "begin": [6, 13, 34], "payload": 6, "highlight": 6, "light": 6, "grei": 6, "blue": 6, "encod": [6, 7, 8, 13, 18, 19, 21, 22, 35], "thei": [6, 7, 8, 11, 13, 15, 17, 18, 25, 34], "pleas": [6, 8, 13, 17, 24], "end": [6, 16, 17, 18, 34], "authorit": 6, "behaviour": [6, 17, 18], "those": [6, 8, 11, 13, 17, 34], "criteria": [6, 18], "findserversonnetwork": 6, "unlik": 6, "detect": [6, 17, 30], "through": [6, 11, 17, 24, 27], "registerserv": [6, 17], "registerserver2": 6, "discoveryurl": [6, 18, 34, 35], "extend": [6, 16, 22, 34], "registr": 6, "confidenti": 6, "closesecurechannel": [6, 17], "sessionid": [6, 10, 13, 17, 24, 25, 26, 28, 30, 34, 35], "audit": 6, "associ": [6, 11, 16, 17, 34], "submit": [6, 17], "softwarecertif": 6, "failur": [6, 15, 18, 34], "closesess": [6, 10, 17], "successfulli": [6, 8, 16, 17, 18], "bad_requestcancelledbycli": 6, "addressspac": [6, 16, 23], "hierarchi": [6, 13, 17, 19, 32, 33], "supertyp": 6, "hasinterfac": 6, "10001": 6, "amend": 6, "addrefer": 6, "deletenod": [6, 13], "deleterefer": [6, 17], "brows": [6, 10, 13, 18, 19, 27], "navig": 6, "further": [6, 15, 19, 25, 33, 34], "primit": 6, "browsenext": 6, "too": [6, 18, 34], "larg": [6, 7, 18], "abl": [6, 8, 16, 17, 18], "larger": 6, "exce": [6, 18], "translatebrowsepathstonodeid": [6, 17], "textual": 6, "registernod": 6, "know": [6, 11], "anyth": 6, "effici": [6, 16], "unregisternod": 6, "unregist": [6, 17], "obtain": [6, 18], "independ": [6, 7, 11, 16, 17], "wide": [6, 11], "varieti": 6, "permit": [6, 17, 18, 34], "maintain": 6, "knowledg": [6, 16], "logic": [6, 17, 24, 34], "schema": [6, 8, 18, 34], "suffici": 6, "queryfirst": 6, "querynext": 6, "construct": [6, 13], "whose": [6, 8], "composit": 6, "rang": [6, 11, 13, 16, 17, 18, 19, 24, 25], "historyread": 6, "although": [6, 8, 24], "themselv": 6, "historyupd": 6, "discard": [6, 13], "createmonitoreditem": 6, "effect": [6, 8, 11], "deletemonitoreditem": 6, "modifymonitoreditem": 6, "soon": 6, "practic": [6, 8, 13], "twice": 6, "revisedsamplinginterv": [6, 34, 35], "illeg": 6, "revis": 6, "choos": 6, "setmonitoringmod": 6, "mode": [6, 16, 18], "settrigg": 6, "createsubscript": 6, "modifysubscript": 6, "setpublishingmod": 6, "acknowledg": [6, 18, 24], "receipt": 6, "notificationmessag": [6, 19], "aliv": [6, 11], "republish": 6, "retransmiss": [6, 18], "queue": [6, 11, 17, 18, 29], "deletesubscript": [6, 34, 35], "belong": [6, 8, 11, 15, 21], "transfersubscript": 6, "reopen": 6, "combin": [6, 7, 11, 13, 17, 18, 19, 34], "graph": 6, "eight": 6, "objecttyp": [6, 8, 13, 17, 26, 30], "direct": [6, 11, 13, 18], "part3": 6, "sometim": 6, "written": [6, 7, 13, 15, 17, 18, 32], "tripl": [6, 7], "expandednodeid": [6, 13, 19], "hastypedefinit": [6, 8, 30], "hierarch": [6, 17], "adapt": [6, 27], "o": [6, 19, 20, 27], "localizedtext": [6, 13, 19], "mask": [6, 13, 19], "boolean": [6, 8, 11, 19, 23, 26], "int32": [6, 17, 19, 20, 21, 23, 28, 31], "doubl": [6, 11, 19, 31, 32], "datatypedefinit": 6, "numer": [6, 11, 13, 17, 18, 24, 34], "bitfield": [6, 9, 19, 34], "particular": [6, 17], "unsupport": [6, 13], "rolepermiss": 6, "userrolepermiss": 6, "accessrestrict": 6, "metadata": [6, 8, 16, 23], "introspect": 6, "notabl": [6, 17], "rank": [6, 28, 32, 34], "flavour": 6, "properti": [6, 17, 18], "datavari": 6, "parent": [6, 8, 13, 16, 17, 18, 30], "hascompon": [6, 8, 24], "children": [6, 8, 17, 24, 30], "exact": [6, 13, 34], "float": [6, 19], "dimension": [6, 21, 28, 34], "helper": [6, 19], "wildcard": 6, "undefin": [6, 11, 34], "implicit": 6, "motortemperaturevariabletyp": 6, "meaning": 6, "basedatavari": 6, "real": [6, 16, 18, 34, 35], "world": [6, 19, 33, 34], "lifecycl": [6, 9, 11, 14, 16, 19, 30, 33, 34], "constructor": [6, 7, 9, 17, 19, 30], "destructor": [6, 7, 9, 17, 19, 30], "perspect": [6, 11], "arrow": 6, "hassubtyp": [6, 8, 13], "companion": [6, 7, 19], "domain": [6, 7, 11], "technic": [6, 13], "subsystem": [6, 9, 19], "rise": 6, "tree": [6, 8, 13], "motor": 6, "car": 6, "crankshaft": 6, "connectedto": 6, "gear": 6, "box": [6, 27], "induc": 6, "electr": 6, "learn": 6, "layout": [6, 16, 30, 34], "understand": [6, 8, 24], "simpl": [6, 8, 19, 26, 33, 34], "callabl": 6, "inputargu": [6, 17, 28, 34, 35], "outputargu": [6, 8, 17, 28, 34, 35], "ua_argu": [6, 17, 28, 34, 35], "98": 7, "languag": [7, 8, 17, 28], "major": 7, "platform": [7, 11, 17, 27], "mozilla": 7, "v2": [7, 21], "mplv2": 7, "proprietari": 7, "sampl": [7, 13, 16, 17, 18], "server_ctt": 7, "v1": 7, "micro": 7, "profil": [7, 18, 22, 23], "basic128rsa15": 7, "basic256": 7, "facet": 7, "certifi": 7, "sdk": [7, 13, 19, 28, 34], "protocol": [7, 11, 16, 17, 18, 19, 21, 34], "industri": [7, 25], "iec": 7, "seri": [7, 27], "core": [7, 13, 16, 19, 27], "scheme": [7, 16], "meta": [7, 16, 17, 23], "37": [7, 8, 34], "purchas": 7, "websit": 7, "email": 7, "drive": [7, 27], "improv": 7, "concept": [7, 19], "reusabl": 7, "council": 7, "organ": [7, 13], "dissemin": 7, "infrastructur": [7, 9, 16, 19], "complianc": 7, "plu": 7, "inherit": [7, 8, 13, 30], "veri": [7, 26, 27], "low": [7, 18, 34, 35], "consumpt": 7, "roadmap": 7, "miss": [7, 11, 17, 18], "v0": 7, "emit": [7, 19, 33], "reach": [7, 17, 18, 31], "mail": 7, "irc": 7, "bugtrack": 7, "invit": 7, "contributor": 7, "bugfix": 7, "welcom": [7, 8], "bug": 7, "comfort": 8, "transform": 8, "nodeset_compil": 8, "subfold": 8, "correct": [8, 13, 18, 34], "snippet": [8, 25], "blog": 8, "post": [8, 18], "opcua": 8, "rock": 8, "uanodeset": 8, "xmln": 8, "xsi": 8, "w3": 8, "xmlschema": 8, "uax": 8, "2008": 8, "xsd": 8, "2011": 8, "03": [8, 15], "s1": [8, 34], "yourorganis": 8, "example_nodeset": 8, "alias": 8, "alia": [8, 34, 35], "hasmodellingrul": [8, 17, 30], "40": 8, "46": 8, "47": 8, "296": 8, "modelinfo": 8, "uamodel": 8, "zs8w1aqi71w8p": 8, "gok3k": 8, "xq": 8, "uareferencetyp": 8, "4001": 8, "providesinputto": 8, "33": [8, 15], "en": [8, 15, 19, 23, 24, 25, 26, 28, 30, 31, 32], "inputprocidedbi": 8, "uaobjecttyp": 8, "1001": [8, 30], "fielddevic": 8, "58": 8, "6001": 8, "6002": 8, "uavari": 8, "manufacturernam": [8, 30, 34, 35], "78": 8, "modelnam": [8, 30], "1002": 8, "pump": [8, 30], "6003": 8, "6004": 8, "7001": 8, "7002": 8, "ison": 8, "motorrpm": [8, 30], "uamethod": 8, "startpump": 8, "6005": 8, "68": 8, "listofextensionobject": 8, "extensionobject": [8, 19], "297": 8, "stoppump": 8, "6006": 8, "save": [8, 13, 18, 26], "myn": 8, "help": [8, 19, 27], "py": 8, "existingnodesetxml": 8, "x": [8, 13, 17, 19, 34, 35], "nodesetxml": 8, "blacklistfil": 8, "ignorefil": 8, "typesarrai": 8, "outputfil": 8, "basenam": 8, "exit": 8, "amalgam": [8, 27], "blacklist": 8, "per": [8, 11, 17, 32], "encount": [8, 17], "prior": 8, "kept": [8, 13, 34], "nodestor": [8, 9, 17, 19], "mutlipl": 8, "max_string_length": 8, "liter": [8, 18], "verbos": 8, "script": 8, "dep": 8, "__main__": 8, "preprocess": 8, "global": [8, 9, 11, 17, 19, 34], "assum": [8, 13, 25, 27, 30, 34], "beforehand": 8, "submodul": 8, "init": 8, "syntax": [8, 17, 18], "highli": 8, "discourag": 8, "examin": [8, 27], "cmakelist": 8, "txt": [8, 17], "server_nodeset": 8, "ua_generate_nodeset": 8, "project_source_dir": 8, "depends_typ": 8, "depends_n": 8, "ua_server_new": [8, 17, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32], "weren": 8, "cmake": [8, 19], "simpler": 8, "ua_generate_datatyp": 8, "ua_generate_nodeset_and_datatyp": 8, "csv": [8, 18], "bsd": [8, 34], "noteset": 8, "skip": 8, "di": 8, "plcopen": 8, "file_csv": 8, "ua_nodeset_dir": 8, "file_bsd": 8, "file_n": 8, "plc": 8, "nodeset2_v1": 8, "One": [8, 18, 28], "benefit": 8, "fairli": 8, "easili": 8, "along": [8, 16], "datasourc": [8, 13, 17, 25], "paradigm": [8, 30], "piec": 8, "likewis": 8, "methodcallback": [8, 17], "methodnod": [8, 9, 17, 19, 28], "job": 8, "deref": 8, "moment": 8, "let": 8, "newli": [8, 11, 16, 17], "creativ": 8, "cczero": 8, "univers": 8, "creativecommon": 8, "publicdomain": 8, "signal": [8, 9, 17, 19], "stdio": [8, 21, 22, 23, 31], "stophandl": 8, "ua_log_info": [8, 12, 20, 25, 26, 28, 29, 30, 32], "ua_log_stdout": [8, 20, 24, 25, 26, 28, 29, 30, 32], "ua_logcategory_serv": [8, 12, 26, 28], "ctrl": [8, 17, 27], "argc": [8, 22, 23], "argv": [8, 22, 23], "sigint": [8, 17], "sigterm": 8, "ua_serverconfig_setdefault": 8, "ua_server_getconfig": [8, 17], "retval": [8, 20, 22, 23, 24, 26, 28, 31, 32], "ua_log_error": [8, 12, 24], "ua_statuscode_badunexpectederror": [8, 18], "els": [8, 12, 17, 20, 22, 23, 24, 26], "creatednodeid": 8, "object_attr": [8, 24], "pump1": 8, "ua_server_addnamespac": [8, 17], "what": [8, 15, 16, 17], "ua_server_addobjectnod": [8, 17, 23, 24, 30], "ua_nodeid_numer": [8, 13, 17, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 34], "ua_ns0id_objectsfold": [8, 23, 24, 25, 26, 28, 30, 31, 32], "ua_ns0id_organ": [8, 23, 24, 25, 30, 31], "ua_server_run": [8, 17, 27], "ua_server_delet": [8, 17, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32], "inspect": [8, 22], "expert": 8, "contrast": [8, 17], "never": [8, 13], "reason": [8, 34], "quit": [8, 17], "propabl": 8, "central": [8, 11], "associatedserv": 8, "servertyp": [8, 34, 35], "would": [8, 17, 18, 25, 26], "recurs": [8, 13, 17], "infinit": 8, "ascend": 8, "redescend": 8, "seen": 8, "shown": [8, 17], "generate_datatyp": 8, "ua_types_di": 8, "target_suffix": 8, "files_bsd": 8, "namespace_map": 8, "reli": 8, "final": [8, 13], "infer": 8, "pull": [8, 16], "warmli": 8, "deprec": 8, "types_arrai": 8, "depends_target": 8, "probabl": 8, "fix": [8, 13, 34], "futur": [8, 34], "appear": [8, 11, 18], "rest": 8, "similar": [8, 13, 17, 20, 28, 30], "ua_namespace_di": 8, "ua_types_di_gener": 8, "ua_types_di_generated_encoding_binari": 8, "ua_types_di_generated_handl": 8, "ua_namespace_plc": 8, "build": [8, 19, 30, 33, 34], "affect": [8, 11, 18], "safeti": 8, "glass": 8, "dexpi": 8, "blob": 8, "nodes": 8, "i4aa": 8, "rsl": 8, "fdi": 8, "badtypemismatch": 8, "bacnet": 8, "unsign": 8, "keyword": 8, "nodesetinjector": 8, "fast": [8, 13, 16], "easi": [8, 20], "focus": 8, "determin": [8, 17, 18, 34], "dua_information_model_autoload": 8, "debug": [8, 19], "dua_build_exampl": 8, "powerlink": 8, "profinet": 8, "machinevis": 8, "cnc": 8, "isa95": 8, "jobcontrol": 8, "opensc": 8, "amb": 8, "autoid": 8, "ia": 8, "machineri": 8, "packml": 8, "pnem": 8, "machinetool": 8, "fdt": 8, "commercialkitchenequip": 8, "pnrio": 8, "scale": 8, "weihenstephan": 8, "ca": 8, "tmc": 8, "ijt": 8, "variablenod": [9, 17, 19, 28, 31], "variabletypenod": [9, 19, 32], "objectnod": [9, 17, 19, 26], "objecttypenod": [9, 19], "referencetypenod": [9, 19], "datatypenod": [9, 19], "viewnod": [9, 19], "union": [9, 16, 17, 19, 34], "timer": [9, 16, 19], "posix": [9, 17, 19, 27], "grant": 10, "sessioncontext": [10, 13, 17, 24, 25, 28, 30], "detach": 10, "ua_accesscontrol": [10, 17], "ac": 10, "usertokenpoliciess": 10, "reject": [10, 18], "securechannelremotecertif": 10, "deauthent": 10, "cleanup": [10, 11, 17, 34], "getuserrightsmask": 10, "nodecontext": [10, 13, 17, 24, 25, 29, 30], "getuseraccesslevel": 10, "getuserexecut": 10, "methodcontext": [10, 13, 26, 28], "getuserexecutableonobject": 10, "objectcontext": [10, 13, 26, 28], "allowaddnod": 10, "ua_addnodesitem": [10, 34, 35], "allowaddrefer": 10, "ua_addreferencesitem": [10, 34, 35], "allowdeletenod": 10, "ua_deletenodesitem": [10, 34, 35], "allowdeleterefer": 10, "ua_deletereferencesitem": [10, 34, 35], "allowbrowsenod": 10, "behalf": 10, "allowtransfersubscript": 10, "oldsessionid": 10, "oldsessioncontext": 10, "newsessionid": 10, "newsessioncontext": 10, "ua_enable_histor": [10, 17], "allowhistoryupdateupdatedata": 10, "ua_performupdatetyp": [10, 34, 35], "performinsertreplac": [10, 34, 35], "allowhistoryupdatedeleterawmodifi": 10, "bool": [10, 11, 34], "isdeletemodifi": [10, 34, 35], "serv": 11, "modul": [11, 15], "unifi": [11, 19, 27], "share": [11, 18, 19, 30], "connectionmanag": 11, "architectur": [11, 13, 19, 25, 34], "goal": [11, 27], "poll": [11, 29], "epol": 11, "kqueue": 11, "extract": [11, 34], "congest": 11, "happen": [11, 17], "schedul": [11, 17, 27], "again": [11, 18, 24, 34], "onward": 11, "stai": 11, "basetim": [11, 16], "ua_timer_handle_cyclemiss_with_currenttim": 11, "ua_timer_handle_cyclemiss_with_basetim": 11, "ua_timerpolici": [11, 16], "win32": [11, 17], "stand": 11, "everywher": 11, "ua_callback": 11, "cycl": [11, 16], "ua_delayedcallback": 11, "singli": [11, 13], "ua_eventloopstate_fresh": 11, "ua_eventloopstate_stop": 11, "ua_eventloopstate_start": 11, "progress": [11, 22], "ua_eventloopst": 11, "eventsourc": 11, "gracefulli": 11, "volatil": [11, 17], "outsid": [11, 13, 14, 18], "el": 11, "few": 11, "succe": [11, 14, 15, 17], "clock": [11, 25, 34], "discrep": 11, "functon": 11, "equival": [11, 17, 18], "datetime_now": 11, "datetime_nowmonoton": 11, "ua_int64": [11, 34, 35], "datetime_localtimeutcoffset": 11, "regularli": [11, 29], "datetim": [11, 19, 23, 25], "nextcyclictim": 11, "addcycliccallback": 11, "cb": [11, 17], "timerpolici": [11, 16], "modifycycliccallback": 11, "removecycliccallback": 11, "addtimedcallback": 11, "deregist": [11, 17], "adddelayedcallback": 11, "dc": 11, "removedelayedcallback": 11, "ua_eventsourc": 11, "registereventsourc": 11, "deregistr": 11, "deregistereventsourc": 11, "ua_eventsourcestate_fresh": 11, "ua_eventsourcestate_stop": 11, "ua_eventsourcestate_start": 11, "ua_eventsourcest": 11, "tag": [11, 13], "proper": 11, "cast": [11, 13], "ua_eventloop_findeventsourc": 11, "ua_eventsourcetype_connectionmanag": 11, "ua_eventsourcetype_interruptmanag": 11, "ua_eventsourcetyp": 11, "eventsourcetyp": 11, "theven": 11, "act": 11, "pure": [11, 13], "passiv": 11, "factori": 11, "bound": [11, 13, 18], "topic": 11, "connectioncallback": 11, "connectionid": [11, 22], "unknown": [11, 18, 22, 23, 34], "announc": [11, 17], "diagnost": [11, 34], "msg": [11, 12], "ua_connectionmanager_connectioncallback": 11, "ua_connectionmanag": 11, "cm": 11, "uintptr_t": [11, 13, 34], "connectioncontext": 11, "amqp": [11, 16], "openconnect": 11, "ipv4": 11, "buffer": [11, 13, 15, 16, 34], "expect": [11, 13, 17, 18], "allocnetworkbuff": 11, "tx": 11, "tsn": 11, "sendwithconnect": 11, "badconnectionclos": 11, "insid": [11, 13, 16, 19, 22, 24], "closeconnect": 11, "hi": [11, 16], "nework": 11, "bufsiz": 11, "freenetworkbuff": 11, "intercept": 11, "similarli": [11, 16], "instanceinfo": 11, "ua_interruptcallback": 11, "ua_interruptmanag": 11, "im": 11, "interrupthandl": 11, "interruptcontext": 11, "interruptmanag": 11, "modif": [11, 20], "registerinterrupt": 11, "deregisterinterrupt": 11, "joint": 11, "ua_architecture_posix": 11, "ua_architecture_win32": 11, "ua_eventloop_new_posix": 11, "distinguish": 11, "recv": 11, "64kb": [11, 17], "v6": 11, "inaddr_ani": 11, "uint16": [11, 16, 19, 22], "dry": 11, "sole": 11, "ua_connectionmanager_new_posix_tcp": 11, "eventsourcenam": [11, 26], "_start": 11, "ttl": 11, "subnet": 11, "loopback": 11, "packag": [11, 16, 19, 22], "sockprior": 11, "disciplin": 11, "cap_net_admin": 11, "paramt": 11, "ua_connectionmanager_new_posix_udp": 11, "tri": [11, 34], "ethertyp": 11, "frame": [11, 17], "promiscu": 11, "bit": [11, 13, 15, 16, 34], "dei": 11, "drop": 11, "elig": 11, "seond": 11, "ua_connectionmanager_new_posix_ethernet": 11, "agnost": [11, 16], "cheap": 11, "1883": 11, "ping": 11, "ua_connectionmanager_new_mqtt": 11, "posx": 11, "ua_interruptmanager_new_posix": 11, "stdout": 12, "handler": 12, "categori": 12, "ua_loglevel_trac": 12, "ua_loglevel_debug": 12, "ua_loglevel_info": 12, "ua_loglevel_warn": 12, "ua_loglevel_error": 12, "ua_loglevel_fat": 12, "ua_logcategori": 12, "ua_logcategory_network": 12, "ua_logcategory_securechannel": 12, "ua_logcategory_sess": 12, "ua_logcategory_cli": 12, "ua_logcategory_userland": [12, 20, 24, 25, 26, 29, 30, 32], "ua_logcategory_securitypolici": 12, "ua_logcategory_eventloop": 12, "ua_logcategory_pubsub": 12, "ua_logcategory_discoveri": 12, "vararg": 12, "printf": [12, 21, 22, 23, 31], "minimum": 12, "logcontext": 12, "va_list": 12, "ua_format": 12, "ua_log_trac": 12, "va_start": 12, "va_end": 12, "ua_log_debug": 12, "ua_log_warn": [12, 24, 26], "ua_log_fat": 12, "mental": 13, "lowest": 13, "istypeof": 13, "solv": 13, "destroi": [13, 14, 16, 17], "wish": 13, "afterward": [13, 34], "anywai": 13, "targetparentnodeid": 13, "potenti": 13, "ua_tru": [13, 17, 22, 23, 24, 26, 34], "ua_fals": [13, 22, 24, 34], "createoptionalchild": 13, "unus": [13, 17, 34], "generatechildnodeid": 13, "ua_globalnodelifecycl": [13, 17], "typenodeid": 13, "typenodecontext": 13, "ua_nodetypelifecycl": [13, 17, 30], "comparison": 13, "speed": 13, "substanti": 13, "bootstrap": 13, "ua_referencetypeindex_refer": 13, "ua_referencetypeindex_hassubtyp": 13, "ua_referencetypeindex_aggreg": 13, "ua_referencetypeindex_hierarchicalrefer": 13, "ua_referencetypeindex_nonhierarchicalrefer": 13, "ua_referencetypeindex_haschild": 13, "ua_referencetypeindex_organ": 13, "ua_referencetypeindex_haseventsourc": 13, "ua_referencetypeindex_hasmodellingrul": 13, "ua_referencetypeindex_hasencod": 13, "ua_referencetypeindex_hasdescript": 13, "ua_referencetypeindex_hastypedefinit": 13, "ua_referencetypeindex_generatesev": 13, "ua_referencetypeindex_hasproperti": 13, "ua_referencetypeindex_hascompon": 13, "ua_referencetypeindex_hasnotifi": 13, "ua_referencetypeindex_hasorderedcompon": 13, "ua_referencetypeindex_hasinterfac": 13, "referrencetyp": 13, "32": [13, 34, 35], "ua_referencetypeset_max": 13, "128": [13, 34, 35], "ua_referencetypeset": 13, "ua_referencetypeset_non": 13, "ua_referencetypeset_al": 13, "ua_referencetypeset_init": 13, "memset": [13, 22, 23, 34], "sizeof": [13, 22, 23, 34], "ua_reftypeset": 13, "j": [13, 21], "ua_referencetypeset_union": 13, "seta": 13, "setb": 13, "ua_referencetypeset_contain": 13, "nativ": 13, "compress": 13, "nodepoint": 13, "behind": 13, "indirect": 13, "processor": 13, "fit": [13, 27, 34], "assumpt": 13, "declar": [13, 19, 34], "nodehead": 13, "ua_nodehead": 13, "00": [13, 34], "expandedid": 13, "externalnodeid": 13, "ua_nodepoint": 13, "freshli": 13, "ua_nodepointer_init": 13, "np": 13, "ua_nodepointer_clear": 13, "ua_nodepointer_copi": 13, "ua_nodepointer_isloc": 13, "ua_nodepointer_ord": 13, "p1": [13, 34], "p2": [13, 34], "ua_nodepointer_equ": 13, "ua_nodepointer_fromnodeid": 13, "ua_nodepointer_fromexpandednodeid": 13, "ua_nodepointer_toexpandednodeid": 13, "serverindex": [13, 34], "ua_nodepointer_tonodeid": 13, "integ": [13, 21, 28, 31, 34], "ua_nod": 13, "targetid": [13, 17, 30, 34, 35], "targetnamehash": 13, "ua_referencetarget": 13, "ua_referencetargettreeelem": 13, "targetidhash": 13, "idtreeentri": 13, "nametreeentri": 13, "ref": 13, "incur": 13, "ua_node_addrefer": 13, "ua_node_deleterefer": 13, "duplic": 13, "idroot": 13, "nameroot": 13, "targetss": [13, 30, 34, 35], "hasreftre": 13, "reftre": 13, "refarrai": 13, "referencetypeindex": 13, "ua_nodereferencekind": 13, "ua_nodereferencekind_iteratecallback": 13, "ua_nodereferencekind_iter": 13, "rk": 13, "ua_nodereferencekind_findtarget": 13, "noth": [13, 17, 18], "ua_nodereferencekind_switch": 13, "ua_localizedtextlistentri": 13, "suitabl": [13, 16], "simpli": [13, 27, 30], "text": [13, 17, 23, 34], "referencess": [13, 34, 35], "were": [13, 18, 34], "ua_monitoreditem": 13, "inlin": [13, 17, 34], "ua_valuesource_data": 13, "ua_valuesource_datasourc": 13, "ua_valuesourc": 13, "onread": [13, 24, 25], "ua_numericrang": [13, 24, 25, 34], "nodeusercontext": 13, "nodeconstructorcontext": 13, "onwrit": [13, 24, 25], "ua_valuecallback": [13, 17, 24, 25], "ua_variant_setscalar": [13, 21, 22, 23, 24, 25, 30, 31, 32, 34], "storagetyp": [13, 34], "ua_variant_data_nodelet": [13, 34], "prevent": [13, 34], "forget": [13, 17], "hasvalu": [13, 21, 25, 31, 34], "presenc": 13, "includesourcetimestamp": 13, "nonscalar": 13, "ua_statuscode_badindexrangeinvalid": [13, 18], "sourcetimestamp": [13, 17, 18, 24, 25, 34], "caller": [13, 15, 18], "ua_datasourc": [13, 17, 25], "lock": 13, "notificationread": 13, "userwrit": 13, "ua_externalvaluecallback": 13, "ua_valuebackendtype_non": 13, "ua_valuebackendtype_intern": 13, "ua_valuebackendtype_data_source_callback": 13, "ua_valuebackendtype_extern": [13, 25], "ua_valuebackendtyp": 13, "backendtyp": [13, 25], "ua_valuebackend": [13, 17, 25], "ua_node_variableattribut": 13, "constraint": [13, 18, 28, 30, 31, 32], "arraydimensionss": [13, 21, 28, 31, 32, 34, 35], "valuebackend": [13, 17, 25], "valuesourc": 13, "head": 13, "isdynam": [13, 17], "sens": [13, 26], "conserv": [13, 17], "ua_variablenod": 13, "ua_variabletypenod": 13, "ua_methodcallback": [13, 17], "ua_methodnod": 13, "ua_objectnod": 13, "ua_objecttypenod": 13, "ua_referencetypenod": 13, "ua_datatypenod": 13, "ua_viewnod": 13, "kind": [13, 34], "crash": 13, "eventu": [13, 17], "ua_nodestorevisitor": 13, "visitorctx": 13, "nsctx": 13, "newnod": [13, 23], "immut": 13, "releasenod": 13, "slow": [13, 18], "ORed": 13, "ua_nodeattributesmask": [13, 34, 35], "open626541": 13, "complain": 13, "getnod": 13, "attributemask": 13, "ua_browsedirect": [13, 34, 35], "referencedirect": 13, "getnodefromptr": 13, "ptr": [13, 34], "getnodecopi": 13, "outnod": 13, "fresh": [13, 34], "assign": [13, 14, 16, 17, 18, 30], "insertnod": 13, "addednodeid": [13, 34, 35], "ua_statuscode_badnodeidunknown": [13, 18], "replacenod": 13, "removenod": 13, "getreferencetypeid": 13, "reftypeindex": 13, "visitor": 13, "ua_nodestor": [13, 17], "variableattribut": [13, 17, 19], "objectattribut": [13, 17, 19], "correctli": 13, "ua_node_clear": 13, "ua_node_setattribut": 13, "reset": [13, 16, 31, 34], "ua_node_copi": 13, "ua_node_copy_alloc": 13, "targetbrowsenamehash": 13, "hasmodelingrul": 13, "ua_node_deletereferencessubset": 13, "keepset": 13, "malloc": [13, 34], "ed": [13, 34], "pki": 14, "trust": [14, 17, 18, 22], "role": [14, 16], "holder": 14, "revoc": 14, "chain": [14, 18], "verifycertif": 14, "cv": 14, "subject": 14, "verifyapplicationuri": 14, "expir": [14, 16, 17, 18], "getexpirationd": 14, "expirydatetim": 14, "getsubjectnam": 14, "subjectnam": 14, "der": 14, "outderkei": 14, "ua_statuscode_badsecuritychecksfail": [14, 18], "wrong": 14, "ua_pki_decryptprivatekei": 14, "privatekei": 14, "channelcontext": 15, "suppli": [15, 17, 18], "suppos": 15, "acquir": 15, "signatures": 15, "getlocalsignatures": 15, "previous": 15, "getremotesignatures": 15, "getlocalkeylength": 15, "getremotekeylength": 15, "ua_securitypolicysignaturealgorithm": 15, "plaintext": 15, "cypher": 15, "ciphertext": 15, "getremoteblocks": 15, "getremoteplaintextblocks": 15, "ua_securitypolicyencryptionalgorithm": 15, "signaturealgorithm": 15, "encryptionalgorithm": [15, 34, 35], "ua_securitypolicycryptomodul": 15, "thumbprint": 15, "thumbprintlength": 15, "asymmetricmodul": 15, "makecertificatethumbprint": 15, "certificatethumbprint": 15, "comparecertificatethumbprint": 15, "cryptomodul": 15, "ua_securitypolicyasymmetricmodul": 15, "pseudo": [15, 17], "random": [15, 17, 18, 19, 22, 26], "situat": [15, 25, 30], "part6": 15, "policycontext": 15, "produc": [15, 16, 27], "generatekei": 15, "nonc": [15, 18], "generatenonc": 15, "securechannelnoncelength": 15, "ua_securitypolicysymmetricmodul": 15, "remotecertif": 15, "newcontext": 15, "deletecontext": 15, "setlocalsymencryptingkei": 15, "setlocalsymsigningkei": 15, "vector": 15, "iv": 15, "setlocalsymiv": 15, "setremotesymencryptingkei": 15, "setremotesymsigningkei": 15, "setremotesymiv": 15, "errror": 15, "comparecertif": 15, "ua_securitypolicychannelmodul": 15, "policyuri": 15, "localcertif": 15, "symmetricmodul": 15, "certificatesigningalgorithm": 15, "channelmodul": 15, "applicationinstancecertif": 15, "updatecertificateandprivatekei": 15, "newcertif": [15, 17], "newprivatekei": [15, 17], "securityhead": 15, "de": [15, 18], "ua_enable_pubsub_encrypt": [15, 16], "ua_pubsubsecuritypolici": [15, 16], "writergroup": [15, 19, 22], "signingkei": [15, 16], "encryptingkei": [15, 16], "keynonc": [15, 16], "wgcontext": 15, "getsecuritykei": [15, 16], "sk": [15, 16], "band": 15, "setsecuritykei": 15, "networkmessag": [15, 16, 22, 23], "setmessagenonc": 15, "particip": 16, "middlewar": 16, "express": [16, 19, 34], "rout": 16, "datagram": [16, 22], "scalabl": 16, "brokerless": 16, "ua_pubsub_component_connect": 16, "ua_pubsub_component_writergroup": 16, "ua_pubsub_component_datasetwrit": 16, "ua_pubsub_component_readergroup": 16, "ua_pubsub_component_datasetread": 16, "ua_pubsubcomponentenumtyp": 16, "ua_pubsubconnect": 16, "ua_server_addpubsubconnect": [16, 22, 23], "ua_writergroup": 16, "ua_pubsubconnection_addwritergroup": 16, "ua_datasetwrit": 16, "ua_writergroup_adddatasetwrit": 16, "ua_readergroup": 16, "ua_pubsubconnection_addreadergroup": 16, "ua_datasetread": 16, "ua_readergroup_adddatasetread": 16, "ua_subscribeddataset": 16, "ua_targetvariablesdatatyp": 16, "ua_subscribeddatasetmirrordatatyp": 16, "ua_pubsubpublisheddataset": 16, "ua_server_addpublisheddataset": [16, 22], "ua_datasetfield": 16, "ua_publisheddataset_adddatasetfield": 16, "publishsubscrib": 16, "concret": 16, "publisherid": [16, 22, 23], "ua_publisheridtype_byt": 16, "ua_publisheridtype_uint16": [16, 22], "ua_publisheridtype_uint32": [16, 23], "ua_publisheridtype_uint64": 16, "ua_publisheridtype_str": 16, "ua_publisheridtyp": 16, "extendedflags1": 16, "001": 16, "010": 16, "011": 16, "uint64": [16, 19], "ua_publisherid": 16, "publisheridtyp": [16, 22, 23], "transportprofileuri": [16, 22, 23, 34, 35], "connectionproperti": 16, "connectiontransportset": 16, "propag": 16, "ua_pubsubconnectionconfig": [16, 22, 23], "ua_pubsub_monitoring_message_receive_timeout": 16, "ua_pubsubmonitoringtyp": 16, "createmonitor": 16, "ecomponenttyp": 16, "emonitoringtyp": 16, "startmonitor": 16, "stopmonitor": 16, "updatemonitoringinterv": 16, "deletemonitor": 16, "ua_pubsubmonitoringinterfac": 16, "ua_pubsubconfigur": [16, 17], "statechangecallback": 16, "ua_pubsubst": 16, "enabledeltafram": 16, "enableinformationmodelmethod": 16, "monitoringinterfac": 16, "connectionconfig": [16, 22, 23], "connectionidentifi": [16, 23], "ua_server_getpubsubconnectionconfig": 16, "writer": 16, "ua_server_removepubsubconnect": 16, "pd": [16, 22], "commonli": 16, "autogener": [16, 18], "ua_pubsub_dataset_publisheditem": [16, 22], "ua_pubsub_dataset_publishedev": 16, "ua_pubsub_dataset_publisheditems_templ": 16, "ua_pubsub_dataset_publishedevents_templ": 16, "ua_publisheddatasettyp": 16, "ua_datasetmetadatatyp": [16, 23], "variablestoadds": 16, "ua_publishedvariabledatatyp": 16, "variablestoadd": 16, "ua_publisheddataitemstemplateconfig": 16, "eventnotfi": 16, "ua_contentfilt": [16, 34, 35], "ua_publishedeventconfig": 16, "selectedfieldss": 16, "ua_simpleattributeoperand": [16, 34, 35], "selectedfield": 16, "ua_publishedeventtemplateconfig": 16, "publisheddatasettyp": [16, 22], "itemstempl": 16, "eventtempl": 16, "ua_publisheddatasetconfig": [16, 22], "ua_publisheddatasetconfig_clear": 16, "pdsconfig": 16, "addresult": [16, 34, 35], "fieldaddresultss": 16, "fieldaddresult": 16, "ua_configurationversiondatatyp": 16, "configurationvers": 16, "ua_addpublisheddatasetresult": 16, "publisheddatasetconfig": [16, 22], "pdsidentifi": 16, "ua_server_getpublisheddatasetconfig": 16, "datasetmetadata": [16, 23], "ua_server_getpublisheddatasetmetadata": 16, "ua_server_removepublisheddataset": 16, "fieldnamealia": [16, 22], "promotedfield": [16, 22], "publishparamet": [16, 22], "rtfieldsourceen": 16, "rtinformationmodelnod": 16, "todo": [16, 17], "decid": 16, "suppress": 16, "staticvaluesourc": 16, "rtvaluesourc": 16, "maxstringlength": [16, 34, 35], "ua_datasetvariableconfig": 16, "ua_pubsub_datasetfield_vari": [16, 22], "ua_pubsub_datasetfield_ev": 16, "ua_datasetfieldtyp": 16, "datasetfieldtyp": [16, 22], "ua_datasetfieldconfig": [16, 22], "ua_datasetfieldconfig_clear": 16, "datasetfieldconfig": [16, 22], "ua_datasetfieldresult": 16, "ua_server_adddatasetfield": [16, 22], "fieldconfig": 16, "fieldidentifi": 16, "ua_server_getdatasetfieldconfig": 16, "dsf": [16, 22], "ua_server_removedatasetfield": 16, "subscib": 16, "addcustomcallback": 16, "changecustomcallback": 16, "removecustomcallback": 16, "ua_pubsub_callbacklifecycl": 16, "pubsubconnect": [16, 22, 23], "primari": [16, 22], "imagin": 16, "ua_pubsub_encoding_uadp": [16, 22], "ua_pubsub_encoding_json": 16, "ua_pubsub_encoding_binari": 16, "ua_pubsubencodingtyp": 16, "rt": 16, "ua_pubsub_rt_non": 16, "ua_pubsub_rt_direct_value_access": 16, "preview": 16, "won": [16, 24], "ua_pubsub_rt_fixed_length": 16, "memcopi": 16, "frozen": 16, "ua_pubsub_rt_determinist": 16, "ua_pubsub_rt_fixed_s": 16, "ua_pubsubrtlevel": 16, "writergroupid": [16, 22, 23], "keepalivetim": 16, "transportset": 16, "messageset": [16, 22], "groupproperti": 16, "encodingmimetyp": [16, 22], "pubsubmanagercallback": 16, "count": [16, 34], "datasetmessag": [16, 23], "maxencapsulateddatasetmessagecount": 16, "rtlevel": 16, "ua_server_setwritergroupencryptionkei": 16, "ua_writergroupdatatyp": 16, "securitygroupid": 16, "ua_writergroupconfig": [16, 22], "ua_writergroupconfig_clear": 16, "writergroupconfig": [16, 22], "ua_server_addwritergroup": [16, 22], "writergroupidentifi": 16, "ua_server_getwritergroupconfig": 16, "ua_server_updatewritergroupconfig": 16, "ua_server_writergroup_getst": 16, "ua_server_writergroup_publish": 16, "ua_writergroup_lastpublishtimestamp": 16, "ua_server_removewritergroup": 16, "ua_server_freezewritergroupconfigur": 16, "ua_server_unfreezewritergroupconfigur": 16, "ua_server_setwritergroupoper": [16, 22], "ua_server_setwritergroupdis": 16, "securitytokenid": 16, "glue": [16, 22], "dataset": [16, 23], "encapsul": [16, 22], "datasetwriterid": [16, 22, 23], "ua_datasetfieldcontentmask": 16, "datasetfieldcontentmask": 16, "keyframecount": [16, 22], "datasetnam": 16, "datasetwriterproperti": 16, "ua_datasetwriterconfig": [16, 22], "ua_datasetwriterconfig_clear": 16, "coupl": 16, "datasetwritertyp": 16, "ua_server_adddatasetwrit": [16, 22], "datasetwriterconfig": [16, 22], "writeridentifi": 16, "ua_server_getdatasetwriterconfig": 16, "dsw": [16, 22], "ua_server_datasetwriter_getst": 16, "datasetwriteridentifi": 16, "ua_server_removedatasetwrit": 16, "targetvariablestyp": 16, "subscribeddatasetmirrortyp": 16, "targetvari": [16, 23], "subscribeddatasetdatatyp": 16, "ua_pubsub_sds_target": 16, "ua_pubsub_sds_mirror": 16, "ua_subscribeddatasetenumtyp": 16, "fieldtargetdatatyp": 16, "ua_fieldtargetdatatyp": 16, "memcpi": [16, 28], "beforewrit": 16, "externaldatavalu": 16, "afterwrit": 16, "targetvariablecontext": 16, "readeridentifi": [16, 23], "readergroupidentifi": [16, 23], "targetvariableidentifi": 16, "ua_fieldtargetvari": [16, 23], "targetvariabless": 16, "ua_targetvari": 16, "ua_server_datasetreader_createtargetvari": [16, 23], "datasetreaderidentifi": 16, "a_pubsubdatasetreader_createdatasetmirror": 16, "ua_pubsub_rt_unknown": 16, "ua_pubsub_rt_vari": 16, "ua_pubsub_rt_data_valu": 16, "ua_pubsub_rt_raw": 16, "ua_pubsubrtencod": 16, "subscribeddatasettyp": 16, "subscribeddatasetmirror": 16, "subscribeddatasettarget": 16, "linkedstandalonesubscribeddatasetnam": 16, "expectedencod": 16, "ua_datasetreaderconfig": [16, 23], "ua_datasetreaderconfig_copi": 16, "ua_datasetreaderconfig_clear": 16, "cfg": 16, "ua_server_datasetreader_updateconfig": 16, "ua_server_datasetreader_getconfig": 16, "ua_server_datasetreader_getst": 16, "datasetmirror": 16, "isconnect": 16, "ua_standalonesubscribeddatasetconfig": 16, "ua_standalonesubscribeddatasetconfig_clear": 16, "sdsconfig": 16, "ua_server_addstandalonesubscribeddataset": 16, "subscribeddatasetconfig": 16, "sdsidentifi": 16, "standalonesubscribeddataset": 16, "ua_server_removestandalonesubscribeddataset": 16, "sd": 16, "pubsub_config_fastpath_fixed_offset": 16, "offset": [16, 34, 35], "ua_server_setreadergroupencryptionkei": 16, "ua_readergroupconfig": [16, 23], "ua_readergroupconfig_clear": 16, "readergroupconfig": [16, 23], "ua_server_adddatasetread": [16, 23], "datasetreaderconfig": 16, "ua_server_removedatasetread": 16, "ua_server_readergroup_updateconfig": 16, "configuraiton": 16, "ua_server_readergroup_getconfig": 16, "ua_server_readergroup_getst": 16, "ua_server_addreadergroup": [16, 23], "ua_server_removereadergroup": 16, "groupidentifi": 16, "ua_server_freezereadergroupconfigur": 16, "readergroupid": 16, "ua_server_unfreezereadergroupconfigur": 16, "ua_server_setreadergroupoper": [16, 23], "ua_server_setreadergroupdis": 16, "ua_enable_pubsub_sk": 16, "permiss": [16, 18], "securitykei": 16, "securitygroupnam": 16, "keylifetim": 16, "maxfuturekeycount": 16, "maxpastkeycount": 16, "ua_securitygroupconfig": 16, "keystorag": 16, "securitygroupfoldernodeid": 16, "securitygroupfoldertyp": 16, "securitygroupconfig": 16, "securitygroupnodeid": 16, "ua_server_addsecuritygroup": 16, "ua_server_removesecuritygroup": 16, "calcul": 16, "skspullrequeststatu": 16, "ua_server_skspullrequestcallback": 16, "timedcallback": 16, "rollov": 16, "reader": [16, 23], "sksclientconfig": 16, "hold": [16, 20, 21, 26], "long": [16, 17], "retun": 16, "ua_server_setskscli": 16, "applicationtyp": [17, 19], "discoveryserv": 17, "shutdowndelai": 17, "notifylifecyclest": 17, "behavior": 17, "balanc": 17, "contradict": 17, "strict": [17, 34], "interoper": 17, "old": [17, 34], "wild": 17, "largest": 17, "vendor": 17, "cf": 17, "postel": 17, "law": 17, "liber": 17, "verifyrequesttimestamp": 17, "allowemptyvari": 17, "plug": 17, "severurl": 17, "my": 17, "wss": 17, "443": 17, "serverurlss": 17, "tcpenabl": 17, "tcpbufsiz": 17, "tcpmaxmsgsiz": 17, "tcpmaxchunk": 17, "tcpreuseaddr": 17, "endpointss": [17, 34, 35], "securitypolicynon": 17, "getendpointsrequest": [17, 19], "findserversrequest": [17, 19], "findserversonnetworkrequest": [17, 19], "securitypolicynonediscoveryonli": 17, "transmit": [17, 34], "plain": 17, "why": 17, "realli": 17, "allownonepolicypassword": 17, "securechannelpki": 17, "sessionpki": 17, "nodelifecycl": 17, "ua_server_addvariablenod": [17, 23, 24, 25, 30, 31, 32], "instancedeclar": 17, "modellingrul": 17, "modellingrulesoninst": 17, "maxsecurechannel": 17, "maxsecuritytokenlifetim": 17, "maxsess": 17, "maxsessiontimeout": 17, "maxnodesperread": 17, "maxnodesperwrit": 17, "maxnodespermethodcal": 17, "maxnodesperbrows": 17, "maxnodesperregisternod": 17, "maxnodespertranslatebrowsepathstonodeid": 17, "maxnodespernodemanag": 17, "maxmonitoreditemspercal": 17, "maxreferencespernod": 17, "asyncoperationtimeout": 17, "maxasyncoperationqueues": 17, "enqueu": 17, "ua_server_asyncoperationnotifycallback": 17, "asyncoperationnotifycallback": 17, "60": [17, 34, 35], "minut": 17, "bigger": 17, "approxim": 17, "discoverycleanuptimeout": 17, "mdnsenabl": 17, "ua_mdnsdiscoveryconfigur": [17, 34, 35], "mdnsconfig": 17, "mdnsinterfaceip": 17, "ua_has_getifaddr": 17, "mdnsipaddresslists": 17, "mdnsipaddresslist": 17, "subscriptionsen": 17, "maxsubscript": 17, "maxsubscriptionspersess": 17, "publishingintervallimit": 17, "lifetimecountlimit": 17, "keepalivecountlimit": 17, "enableretransmissionqueu": 17, "maxretransmissionqueues": 17, "maxeventspernod": 17, "maxmonitoreditem": 17, "maxmonitoreditemspersubscript": 17, "samplingintervallimit": 17, "queuesizelimit": 17, "negoti": 17, "maxpublishreqpersess": 17, "userland": 17, "question": [17, 34], "nodeidcontext": 17, "monitoreditemregistercallback": 17, "attibuteid": 17, "pubsuben": 17, "pubsubconfig": 17, "historizingen": 17, "ua_historydatabas": 17, "historydatabas": 17, "accesshistorydatacap": 17, "maxreturndatavalu": 17, "accesshistoryeventscap": 17, "maxreturneventvalu": 17, "insertdatacap": 17, "inserteventcap": 17, "insertannotationscap": 17, "replacedatacap": 17, "replaceeventcap": 17, "updatedatacap": 17, "updateeventcap": 17, "deleterawcap": 17, "deleteeventcap": 17, "deleteattimedatacap": 17, "reversereconnectinterv": 17, "15000": 17, "sc": 17, "ua_serverconfig_clean": 17, "server_config_default": [17, 21], "ua_server_newwithconfig": 17, "simplfi": 17, "ua_server_getlifecyclest": 17, "unix": [17, 34], "sequenc": [17, 18, 34], "ua_server_run_startup": 17, "ua_server_run_iter": 17, "ua_server_run_shutdown": 17, "bad": [17, 18, 34], "ua_config_default": 17, "ua_server_rununtilinterrupt": [17, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32], "prologu": 17, "waitintern": 17, "networklay": 17, "timout": 17, "200m": 17, "epilogu": 17, "ua_server_addtimedcallback": 17, "ua_server_addrepeatedcallback": 17, "ua_server_changerepeatedcallbackinterv": 17, "ua_server_removecallback": 17, "ua_server_removerepeatedcallback": 17, "ua_server_closesess": 17, "clientuserid": 17, "ua_server_getsessionattribut": 17, "ua_server_getsessionattributecopi": 17, "ua_server_getsessionattribute_scalar": 17, "ua_server_setsessionattribut": 17, "ua_server_deletesessionattribut": 17, "admin": 17, "concis": 17, "numericrang": [17, 19], "ua_server_read": 17, "__ua_server_read": 17, "ua_server_readnodeid": 17, "ua_server_readnodeclass": 17, "ua_server_readbrowsenam": 17, "ua_server_readdisplaynam": 17, "ua_server_readdescript": 17, "ua_server_readwritemask": 17, "ua_server_readisabstract": 17, "ua_server_readsymmetr": 17, "ua_server_readinversenam": 17, "ua_server_readcontainsnoloop": 17, "ua_server_readeventnotifi": 17, "ua_server_readvalu": 17, "ua_server_readdatatyp": 17, "ua_server_readvaluerank": 17, "ua_server_readarraydimens": 17, "ua_server_readaccesslevel": 17, "ua_server_readaccesslevelex": 17, "ua_server_readminimumsamplinginterv": 17, "outminimumsamplinginterv": 17, "ua_server_readhistor": 17, "ua_server_readexecut": 17, "writevalu": [17, 19], "ua_server_writ": [17, 31], "ua_writevalu": [17, 31, 34, 35], "overhead": 17, "__ua_server_writ": 17, "attr_typ": 17, "ua_server_writebrowsenam": 17, "ua_server_writedisplaynam": 17, "ua_server_writedescript": 17, "ua_server_writewritemask": 17, "ua_server_writeisabstract": 17, "ua_server_writeinversenam": 17, "ua_server_writeeventnotifi": 17, "ua_server_writevalu": [17, 25, 30, 31], "servertimestamp": [17, 18, 24, 34], "ua_server_writedatavalu": 17, "ua_server_writedatatyp": 17, "ua_server_writevaluerank": [17, 32], "ua_server_writearraydimens": 17, "ua_server_writeaccesslevel": 17, "ua_server_writeaccesslevelex": 17, "ua_server_writeminimumsamplinginterv": 17, "miniumsamplinginterv": 17, "ua_server_writehistor": 17, "ua_server_writeexecut": 17, "browsedescript": [17, 19], "ua_browseresult": [17, 34, 35], "ua_server_brows": 17, "maxrefer": 17, "ua_browsedescript": [17, 34, 35], "bd": 17, "ua_server_browsenext": 17, "releasecontinuationpoint": [17, 34, 35], "continuationpoint": [17, 34, 35], "nodeclassmask": [17, 34, 35], "ua_server_browserecurs": 17, "resultss": [17, 34, 35], "ua_browsepathresult": [17, 30, 34, 35], "ua_server_translatebrowsepathtonodeid": [17, 30], "ua_browsepath": [17, 30, 34, 35], "simpleattributeoperand": [17, 19], "rel": [17, 18], "relativepath": [17, 19, 30], "ua_server_browsesimplifiedbrowsepath": 17, "browsepaths": [17, 34, 35], "clang": [17, 27], "ua_server_foreachchildnodecal": 17, "_unregisterdiscoveri": 17, "outdat": 17, "ua_server_registerdiscoveri": 17, "discoveryserverurl": 17, "semaphorefilepath": [17, 34, 35], "ua_server_deregisterdiscoveri": 17, "ua_server_registerservercallback": 17, "ua_registeredserv": [17, 34, 35], "register": 17, "ua_statuscode_success": 17, "ua_server_setregisterservercallback": 17, "mdn": 17, "isserverannounc": 17, "istxtreceiv": 17, "cap": 17, "ua_server_serveronnetworkcallback": 17, "srv": 17, "ua_server_setserveronnetworkcallback": 17, "ua_server_setadminsessioncontext": 17, "ua_server_setnodetypelifecycl": [17, 30], "ua_server_getnodecontext": 17, "ua_server_setnodecontext": 17, "deal": 17, "whenev": 17, "ask": 17, "ua_server_setvariablenode_datasourc": 17, "ua_server_setvariablenode_valuecallback": [17, 24, 25], "ua_server_setvariablenode_valuebackend": [17, 25], "ua_server_datachangenotificationcallback": 17, "monitoreditemcontext": [17, 29], "ua_server_eventnotificationcallback": 17, "ua_server_createdatachangemonitoreditem": [17, 29], "ua_server_createeventmonitoreditem": 17, "ua_server_deletemonitoreditem": 17, "theori": 17, "ua_server_setmethodnode_callback": 17, "ua_server_setmethodnodecallback": 17, "methodnodeid": 17, "backward": 17, "ua_server_getmethodnodecallback": 17, "outmethodcallback": 17, "ua_callmethodresult": [17, 34, 35], "ua_server_cal": 17, "ua_callmethodrequest": [17, 34, 35], "propertynam": 17, "ua_server_writeobjectproperti": 17, "ua_server_writeobjectproperty_scalar": [17, 24, 26], "ua_server_readobjectproperti": 17, "chanc": 17, "evalu": 17, "unassign": 17, "likelihood": 17, "thing": [17, 26], "manifest": 17, "__ua_server_addnod": 17, "ua_server_addvariabletypenod": [17, 32], "ua_server_addobjecttypenod": [17, 26, 30], "ua_server_addviewnod": 17, "ua_server_addreferencetypenod": 17, "ua_server_adddatatypenod": 17, "ua_server_adddatasourcevariablenod": [17, 25], "ua_server_setvariablenodedynam": 17, "ua_server_addmethodnodeex": 17, "inputargumentss": [17, 34, 35], "inputargumentsrequestednewnodeid": 17, "inputargumentsoutnewnodeid": 17, "outputargumentss": [17, 34, 35], "outputargumentsrequestednewnodeid": 17, "outputargumentsoutnewnodeid": 17, "ua_server_addmethodnod": [17, 26, 28], "ua_server_addnode_begin": 17, "_finish": 17, "_begin": 17, "prepar": [17, 32], "ua_node_id_nul": 17, "hastypedef": 17, "yourself": 17, "ua_server_addmethodnode_finish": 17, "specifii": 17, "ua_server_addnode_finish": 17, "ua_server_deletenod": 17, "ua_server_addrefer": [17, 24, 30], "sourceid": 17, "reftypeid": 17, "ua_server_deleterefer": 17, "ua_server_createev": [17, 26], "eventid": [17, 26], "uaexpert": [17, 24, 26, 27], "ua_server_triggerev": [17, 26], "outeventid": 17, "deleteeventnod": 17, "frequent": 17, "eventtyp": [17, 18, 26], "eventfilt": [17, 19], "eventnodeid": [17, 26], "outev": 17, "originid": 17, "ua_twostatevariablecallbacktyp": 17, "ua_entering_enabledst": [17, 24], "ua_entering_ackedst": [17, 24], "ua_entering_confirmedst": [17, 24], "ua_entering_activest": 17, "prototyp": 17, "ua_twostatevariablechangecallback": [17, 24], "conditiontyp": 17, "haseventsourc": [17, 24], "conditionid": 17, "conditionnam": 17, "conditionsourc": [17, 24], "hierarchialreferencetyp": 17, "outconditionid": 17, "ua_server_createcondit": [17, 24], "ua_server_addcondition_begin": 17, "ua_server_createcondt": 17, "similiar": 17, "ua_server_addcondition_finish": 17, "unfinish": 17, "fieldnam": 17, "ua_server_setconditionfield": [17, 24], "variablefieldnam": 17, "variablepropertynam": 17, "ua_server_setconditionvariablefieldproperti": [17, 24], "ua_server_triggerconditionev": [17, 24], "outoptionalvari": 17, "ua_server_addconditionoptionalfield": 17, "twostatevari": 17, "enabledst": [17, 24], "ackedst": [17, 24], "confirmedst": [17, 24], "activest": [17, 24], "removebranch": 17, "callbacktyp": 17, "ua_server_setconditiontwostatevariablecallback": [17, 24], "ua_server_deletecondit": 17, "limitst": 17, "limitalarmtyp": 17, "limitvalu": 17, "ua_server_setlimitst": 17, "certifc": 17, "cert": 17, "ua_server_setexpirationd": 17, "ua_server_updatecertif": 17, "oldcertif": 17, "ua_server_finddatatyp": 17, "ua_server_getnamespacebynam": 17, "foundindex": 17, "ua_server_getnamespacebyindex": 17, "founduri": 17, "warm": 17, "outsourc": 17, "callrequest": [17, 19], "put": [17, 24], "readi": 17, "tutorial_server_method_async": 17, "ua_server_setmethodnodeasync": 17, "isasync": 17, "ua_asyncoperationtype_invalid": 17, "ua_asyncoperationtype_cal": 17, "ua_asyncoperationtype_read": 17, "ua_asyncoperationtype_writ": 17, "ua_asyncoperationtyp": 17, "callmethodrequest": [17, 19], "ua_asyncoperationrequest": 17, "callmethodresult": [17, 19], "readresult": 17, "writeresult": 17, "ua_asyncoperationrespons": 17, "ua_server_setasyncoperationresult": 17, "ua_server_getasyncoperationnonblock": 17, "ua_server_getasyncoperationblock": 17, "counter": [17, 19], "ss": 17, "ua_serverstatist": 17, "ua_server_getstatist": 17, "loss": 17, "reflect": 17, "ua_server_reverseconnectstatecallback": 17, "break": 17, "ua_server_addreverseconnect": 17, "ua_server_removereverseconnect": 17, "ua_statuscode_infotype_datavalu": 18, "0x00000400": 18, "ua_statuscode_infobits_overflow": 18, "0x00000080": 18, "0x00000000": 18, "uncertain": [18, 34], "ua_statuscode_uncertain": 18, "0x40000000": 18, "ua_statuscode_bad": 18, "0x80000000": 18, "unexpect": 18, "0x80010000": 18, "0x80020000": 18, "0x80030000": 18, "ua_statuscode_badresourceunavail": 18, "0x80040000": 18, "ua_statuscode_badcommunicationerror": 18, "0x80050000": 18, "halt": 18, "serial": [18, 34], "ua_statuscode_badencodingerror": 18, "0x80060000": 18, "stream": [18, 34], "ua_statuscode_baddecodingerror": 18, "0x80070000": 18, "impos": 18, "exceed": 18, "ua_statuscode_badencodinglimitsexceed": 18, "0x80080000": 18, "ua_statuscode_badrequesttoolarg": 18, "0x80b80000": 18, "ua_statuscode_badresponsetoolarg": 18, "0x80b90000": 18, "unrecogn": 18, "ua_statuscode_badunknownrespons": 18, "0x80090000": 18, "0x800a0000": 18, "ua_statuscode_badserviceunsupport": 18, "0x800b0000": 18, "0x800c0000": 18, "ua_statuscode_badservernotconnect": 18, "0x800d0000": 18, "ua_statuscode_badserverhalt": 18, "0x800e0000": 18, "ua_statuscode_badnothingtodo": 18, "0x800f0000": 18, "ua_statuscode_badtoomanyoper": 18, "0x80100000": 18, "ua_statuscode_badtoomanymonitoreditem": 18, "0x80db0000": 18, "ua_statuscode_baddatatypeidunknown": 18, "0x80110000": 18, "ua_statuscode_badcertificateinvalid": 18, "0x80120000": 18, "0x80130000": 18, "meet": 18, "ua_statuscode_badcertificatepolicycheckfail": 18, "0x81140000": 18, "ua_statuscode_badcertificatetimeinvalid": 18, "0x80140000": 18, "issuer": 18, "ua_statuscode_badcertificateissuertimeinvalid": 18, "0x80150000": 18, "ua_statuscode_badcertificatehostnameinvalid": 18, "0x80160000": 18, "ua_statuscode_badcertificateuriinvalid": 18, "0x80170000": 18, "ua_statuscode_badcertificateusenotallow": 18, "0x80180000": 18, "ua_statuscode_badcertificateissuerusenotallow": 18, "0x80190000": 18, "ua_statuscode_badcertificateuntrust": 18, "0x801a0000": 18, "revok": 18, "ua_statuscode_badcertificaterevocationunknown": 18, "0x801b0000": 18, "ua_statuscode_badcertificateissuerrevocationunknown": 18, "0x801c0000": 18, "ua_statuscode_badcertificaterevok": 18, "0x801d0000": 18, "ua_statuscode_badcertificateissuerrevok": 18, "0x801e0000": 18, "incomplet": 18, "ua_statuscode_badcertificatechainincomplet": 18, "0x810d0000": 18, "ua_statuscode_baduseraccessdeni": 18, "0x801f0000": 18, "ua_statuscode_badidentitytokeninvalid": 18, "0x80200000": 18, "ua_statuscode_badidentitytokenreject": 18, "0x80210000": 18, "ua_statuscode_badsecurechannelidinvalid": 18, "0x80220000": 18, "ua_statuscode_badinvalidtimestamp": 18, "0x80230000": 18, "ua_statuscode_badnonceinvalid": 18, "0x80240000": 18, "ua_statuscode_badsessionidinvalid": 18, "0x80250000": 18, "ua_statuscode_badsessionclos": 18, "0x80260000": 18, "ua_statuscode_badsessionnotactiv": 18, "0x80270000": 18, "ua_statuscode_badsubscriptionidinvalid": 18, "0x80280000": 18, "ua_statuscode_badrequestheaderinvalid": 18, "0x802a0000": 18, "ua_statuscode_badtimestampstoreturninvalid": 18, "0x802b0000": 18, "ua_statuscode_badrequestcancelledbycli": 18, "0x802c0000": 18, "ua_statuscode_badtoomanyargu": 18, "0x80e50000": 18, "operatio": 18, "ua_statuscode_badlicenseexpir": 18, "0x810e0000": 18, "ua_statuscode_badlicenselimitsexceed": 18, "0x810f0000": 18, "ua_statuscode_badlicensenotavail": 18, "0x81100000": 18, "ua_statuscode_goodsubscriptiontransf": 18, "0x002d0000": 18, "ua_statuscode_goodcompletesasynchron": 18, "0x002e0000": 18, "ua_statuscode_goodoverload": 18, "0x002f0000": 18, "clamp": 18, "ua_statuscode_goodclamp": 18, "0x00300000": 18, "ua_statuscode_badnocommun": 18, "0x80310000": 18, "ua_statuscode_badwaitingforinitialdata": 18, "0x80320000": 18, "ua_statuscode_badnodeidinvalid": 18, "0x80330000": 18, "0x80340000": 18, "ua_statuscode_badattributeidinvalid": 18, "0x80350000": 18, "0x80360000": 18, "ua_statuscode_badindexrangenodata": 18, "0x80370000": 18, "ua_statuscode_baddataencodinginvalid": 18, "0x80380000": 18, "ua_statuscode_baddataencodingunsupport": 18, "0x80390000": 18, "ua_statuscode_badnotread": 18, "0x803a0000": 18, "ua_statuscode_badnotwrit": 18, "0x803b0000": 18, "ua_statuscode_badoutofrang": 18, "0x803c0000": 18, "ua_statuscode_badnotsupport": 18, "0x803d0000": 18, "search": [18, 34], "0x803e0000": 18, "ua_statuscode_badobjectdelet": 18, "0x803f0000": 18, "ua_statuscode_badnotimpl": 18, "0x80400000": 18, "ua_statuscode_badmonitoringmodeinvalid": 18, "0x80410000": 18, "ua_statuscode_badmonitoreditemidinvalid": 18, "0x80420000": 18, "ua_statuscode_badmonitoreditemfilterinvalid": 18, "0x80430000": 18, "ua_statuscode_badmonitoreditemfilterunsupport": 18, "0x80440000": 18, "ua_statuscode_badfilternotallow": 18, "0x80450000": 18, "ua_statuscode_badstructuremiss": 18, "0x80460000": 18, "ua_statuscode_badeventfilterinvalid": 18, "0x80470000": 18, "ua_statuscode_badcontentfilterinvalid": 18, "0x80480000": 18, "ua_statuscode_badfilteroperatorinvalid": 18, "0x80c10000": 18, "ua_statuscode_badfilteroperatorunsupport": 18, "0x80c20000": 18, "operand": 18, "ua_statuscode_badfilteroperandcountmismatch": 18, "0x80c30000": 18, "ua_statuscode_badfilteroperandinvalid": 18, "0x80490000": 18, "ua_statuscode_badfilterelementinvalid": 18, "0x80c40000": 18, "ua_statuscode_badfilterliteralinvalid": 18, "0x80c50000": 18, "ua_statuscode_badcontinuationpointinvalid": 18, "0x804a0000": 18, "ua_statuscode_badnocontinuationpoint": 18, "0x804b0000": 18, "ua_statuscode_badreferencetypeidinvalid": 18, "0x804c0000": 18, "ua_statuscode_badbrowsedirectioninvalid": 18, "0x804d0000": 18, "ua_statuscode_badnodenotinview": 18, "0x804e0000": 18, "overflow": 18, "ua_statuscode_badnumericoverflow": 18, "0x81120000": 18, "ua_statuscode_badserveruriinvalid": 18, "0x804f0000": 18, "servernam": [18, 34, 35], "ua_statuscode_badservernamemiss": 18, "0x80500000": 18, "ua_statuscode_baddiscoveryurlmiss": 18, "0x80510000": 18, "ua_statuscode_badsempahorefilemiss": 18, "0x80520000": 18, "ua_statuscode_badrequesttypeinvalid": 18, "0x80530000": 18, "ua_statuscode_badsecuritymodereject": 18, "0x80540000": 18, "ua_statuscode_badsecuritypolicyreject": 18, "0x80550000": 18, "ua_statuscode_badtoomanysess": 18, "0x80560000": 18, "ua_statuscode_badusersignatureinvalid": 18, "0x80570000": 18, "ua_statuscode_badapplicationsignatureinvalid": 18, "0x80580000": 18, "did": 18, "ua_statuscode_badnovalidcertif": 18, "0x80590000": 18, "ua_statuscode_badidentitychangenotsupport": 18, "0x80c60000": 18, "ua_statuscode_badrequestcancelledbyrequest": 18, "0x805a0000": 18, "ua_statuscode_badparentnodeidinvalid": 18, "0x805b0000": 18, "violat": 18, "ua_statuscode_badreferencenotallow": 18, "0x805c0000": 18, "ua_statuscode_badnodeidreject": 18, "0x805d0000": 18, "ua_statuscode_badnodeidexist": 18, "0x805e0000": 18, "class": 18, "ua_statuscode_badnodeclassinvalid": 18, "0x805f0000": 18, "ua_statuscode_badbrowsenameinvalid": 18, "0x80600000": 18, "among": 18, "relationship": 18, "ua_statuscode_badbrowsenamedupl": 18, "0x80610000": 18, "ua_statuscode_badnodeattributesinvalid": 18, "0x80620000": 18, "ua_statuscode_badtypedefinitioninvalid": 18, "0x80630000": 18, "ua_statuscode_badsourcenodeidinvalid": 18, "0x80640000": 18, "ua_statuscode_badtargetnodeidinvalid": 18, "0x80650000": 18, "ua_statuscode_badduplicatereferencenotallow": 18, "0x80660000": 18, "ua_statuscode_badinvalidselfrefer": 18, "0x80670000": 18, "ua_statuscode_badreferencelocalonli": 18, "0x80680000": 18, "ua_statuscode_badnodeleteright": 18, "0x80690000": 18, "ua_statuscode_uncertainreferencenotdelet": 18, "0x40bc0000": 18, "ua_statuscode_badserverindexinvalid": 18, "0x806a0000": 18, "ua_statuscode_badviewidunknown": 18, "0x806b0000": 18, "ua_statuscode_badviewtimestampinvalid": 18, "0x80c90000": 18, "ua_statuscode_badviewparametermismatch": 18, "0x80ca0000": 18, "ua_statuscode_badviewversioninvalid": 18, "0x80cb0000": 18, "ua_statuscode_uncertainnotallnodesavail": 18, "0x40c00000": 18, "ua_statuscode_goodresultsmaybeincomplet": 18, "0x00ba0000": 18, "ua_statuscode_badnottypedefinit": 18, "0x80c80000": 18, "ua_statuscode_uncertainreferenceoutofserv": 18, "0x406c0000": 18, "ua_statuscode_badtoomanymatch": 18, "0x806d0000": 18, "ua_statuscode_badquerytoocomplex": 18, "0x806e0000": 18, "ua_statuscode_badnomatch": 18, "0x806f0000": 18, "ag": 18, "ua_statuscode_badmaxageinvalid": 18, "0x80700000": 18, "ua_statuscode_badsecuritymodeinsuffici": 18, "0x80e60000": 18, "histori": 18, "ua_statuscode_badhistoryoperationinvalid": 18, "0x80710000": 18, "ua_statuscode_badhistoryoperationunsupport": 18, "0x80720000": 18, "ua_statuscode_badinvalidtimestampargu": 18, "0x80bd0000": 18, "ua_statuscode_badwritenotsupport": 18, "0x80730000": 18, "ua_statuscode_badtypemismatch": [18, 32], "0x80740000": 18, "ua_statuscode_badmethodinvalid": 18, "0x80750000": 18, "ua_statuscode_badargumentsmiss": 18, "0x80760000": 18, "ua_statuscode_badnotexecut": 18, "0x81110000": 18, "ua_statuscode_badtoomanysubscript": 18, "0x80770000": 18, "ua_statuscode_badtoomanypublishrequest": 18, "0x80780000": 18, "ua_statuscode_badnosubscript": 18, "0x80790000": 18, "ua_statuscode_badsequencenumberunknown": 18, "0x807a0000": 18, "ua_statuscode_goodretransmissionqueuenotsupport": 18, "0x00df0000": 18, "ua_statuscode_badmessagenotavail": 18, "0x807b0000": 18, "ua_statuscode_badinsufficientclientprofil": 18, "0x807c0000": 18, "ua_statuscode_badstatenotact": 18, "0x80bf0000": 18, "ua_statuscode_badalreadyexist": 18, "0x81150000": 18, "busi": 18, "ua_statuscode_badtcpservertoobusi": 18, "0x807d0000": 18, "ua_statuscode_badtcpmessagetypeinvalid": 18, "0x807e0000": 18, "securechannelid": 18, "tokenid": [18, 34, 35], "ua_statuscode_badtcpsecurechannelunknown": 18, "0x807f0000": 18, "ua_statuscode_badtcpmessagetoolarg": 18, "0x80800000": 18, "ua_statuscode_badtcpnotenoughresourc": 18, "0x80810000": 18, "ua_statuscode_badtcpinternalerror": 18, "0x80820000": 18, "querystr": 18, "0x80830000": 18, "ua_statuscode_badrequestinterrupt": 18, "0x80840000": 18, "ua_statuscode_badrequesttimeout": 18, "0x80850000": 18, "ua_statuscode_badsecurechannelclos": 18, "0x80860000": 18, "ua_statuscode_badsecurechanneltokenunknown": 18, "0x80870000": 18, "ua_statuscode_badsequencenumberinvalid": 18, "0x80880000": 18, "ua_statuscode_badprotocolversionunsupport": 18, "0x80be0000": 18, "problem": 18, "ua_statuscode_badconfigurationerror": 18, "0x80890000": 18, "ua_statuscode_badnotconnect": [18, 31], "0x808a0000": 18, "ua_statuscode_baddevicefailur": 18, "0x808b0000": 18, "deriv": [18, 30, 34], "ua_statuscode_badsensorfailur": 18, "0x808c0000": 18, "ua_statuscode_badoutofservic": 18, "0x808d0000": 18, "deadband": 18, "ua_statuscode_baddeadbandfilterinvalid": 18, "0x808e0000": 18, "had": 18, "qualiti": [18, 34], "ua_statuscode_uncertainnocommunicationlastusablevalu": 18, "0x408f0000": 18, "whatev": 18, "ua_statuscode_uncertainlastusablevalu": 18, "0x40900000": 18, "ua_statuscode_uncertainsubstitutevalu": 18, "0x40910000": 18, "ua_statuscode_uncertaininitialvalu": 18, "0x40920000": 18, "ua_statuscode_uncertainsensornotaccur": 18, "0x40930000": 18, "ua_statuscode_uncertainengineeringunitsexceed": 18, "0x40940000": 18, "ua_statuscode_uncertainsubnorm": 18, "0x40950000": 18, "ua_statuscode_goodlocaloverrid": 18, "0x00960000": 18, "refresh": 18, "ua_statuscode_badrefreshinprogress": 18, "0x80970000": 18, "ua_statuscode_badconditionalreadydis": 18, "0x80980000": 18, "ua_statuscode_badconditionalreadyen": 18, "0x80cc0000": 18, "availabl": 18, "ua_statuscode_badconditiondis": 18, "0x80990000": 18, "ua_statuscode_badeventidunknown": 18, "0x809a0000": 18, "ua_statuscode_badeventnotacknowledg": 18, "0x80bb0000": 18, "dialog": 18, "ua_statuscode_baddialognotact": 18, "0x80cd0000": 18, "ua_statuscode_baddialogresponseinvalid": 18, "0x80ce0000": 18, "ua_statuscode_badconditionbranchalreadyack": 18, "0x80cf0000": 18, "confirm": [18, 24], "ua_statuscode_badconditionbranchalreadyconfirm": 18, "0x80d00000": 18, "shelv": 18, "ua_statuscode_badconditionalreadyshelv": 18, "0x80d10000": 18, "ua_statuscode_badconditionnotshelv": 18, "0x80d20000": 18, "ua_statuscode_badshelvingtimeoutofrang": 18, "0x80d30000": 18, "ua_statuscode_badnodata": 18, "0x809b0000": 18, "upper": 18, "lower": [18, 34], "ua_statuscode_badboundnotfound": 18, "0x80d70000": 18, "ua_statuscode_badboundnotsupport": 18, "0x80d80000": 18, "collect": [18, 22], "ua_statuscode_baddatalost": 18, "0x809d0000": 18, "unavail": 18, "un": 18, "mount": 18, "volum": 18, "ua_statuscode_baddataunavail": 18, "0x809e0000": 18, "ua_statuscode_badentryexist": 18, "0x809f0000": 18, "ua_statuscode_badnoentryexist": 18, "0x80a00000": 18, "ua_statuscode_badtimestampnotsupport": 18, "0x80a10000": 18, "databas": 18, "ua_statuscode_goodentryinsert": 18, "0x00a20000": 18, "ua_statuscode_goodentryreplac": 18, "0x00a30000": 18, "ua_statuscode_uncertaindatasubnorm": 18, "0x40a40000": 18, "ua_statuscode_goodnodata": 18, "0x00a50000": 18, "ua_statuscode_goodmoredata": 18, "0x00a60000": 18, "ua_statuscode_badaggregatelistmismatch": 18, "0x80d40000": 18, "ua_statuscode_badaggregatenotsupport": 18, "0x80d50000": 18, "ua_statuscode_badaggregateinvalidinput": 18, "0x80d60000": 18, "ua_statuscode_badaggregateconfigurationreject": 18, "0x80da0000": 18, "historian": 18, "ua_statuscode_gooddataignor": 18, "0x00d90000": 18, "ua_statuscode_badrequestnotallow": 18, "0x80e40000": 18, "ua_statuscode_badrequestnotcomplet": 18, "0x81130000": 18, "ticket": 18, "ua_statuscode_badticketrequir": 18, "0x811f0000": 18, "ua_statuscode_badticketinvalid": 18, "0x81200000": 18, "ua_statuscode_goodedit": 18, "0x00dc0000": 18, "ua_statuscode_goodpostactionfail": 18, "0x00dd0000": 18, "engineeringunit": [18, 34, 35], "ua_statuscode_uncertaindominantvaluechang": 18, "0x40de0000": 18, "ua_statuscode_gooddependentvaluechang": 18, "0x00e00000": 18, "ua_statuscode_baddominantvaluechang": 18, "0x80e10000": 18, "domin": 18, "ua_statuscode_uncertaindependentvaluechang": 18, "0x40e20000": 18, "ua_statuscode_baddependentvaluechang": 18, "0x80e30000": 18, "deliv": 18, "ua_statuscode_goodedited_dependentvaluechang": 18, "0x01160000": 18, "ua_statuscode_goodedited_dominantvaluechang": 18, "0x01170000": 18, "ua_statuscode_goodedited_dominantvaluechanged_dependentvaluechang": 18, "0x01180000": 18, "legal": 18, "ua_statuscode_badedited_outofrang": 18, "0x81190000": 18, "ua_statuscode_badinitialvalue_outofrang": 18, "0x811a0000": 18, "ua_statuscode_badoutofrange_dominantvaluechang": 18, "0x811b0000": 18, "ua_statuscode_badedited_outofrange_dominantvaluechang": 18, "0x811c0000": 18, "ua_statuscode_badoutofrange_dominantvaluechanged_dependentvaluechang": 18, "0x811d0000": 18, "ua_statuscode_badedited_outofrange_dominantvaluechanged_dependentvaluechang": 18, "0x811e0000": 18, "rais": 18, "ua_statuscode_goodcommunicationev": 18, "0x00a70000": 18, "ua_statuscode_goodshutdownev": 18, "0x00a80000": 18, "0x00a90000": 18, "ua_statuscode_goodnoncriticaltimeout": 18, "0x00aa0000": 18, "ua_statuscode_badinvalidargu": 18, "0x80ab0000": 18, "ua_statuscode_badconnectionreject": 18, "0x80ac0000": 18, "ua_statuscode_baddisconnect": 18, "0x80ad0000": 18, "ua_statuscode_badconnectionclos": 18, "0x80ae0000": 18, "ua_statuscode_badinvalidst": 18, "0x80af0000": 18, "beyond": 18, "ua_statuscode_badendofstream": 18, "0x80b00000": 18, "ua_statuscode_badnodataavail": 18, "0x80b10000": 18, "ua_statuscode_badwaitingforrespons": 18, "0x80b20000": 18, "abandon": 18, "ua_statuscode_badoperationabandon": 18, "0x80b30000": 18, "possibli": 18, "ua_statuscode_badexpectedstreamtoblock": 18, "0x80b40000": 18, "ua_statuscode_badwouldblock": 18, "0x80b50000": 18, "ua_statuscode_badsyntaxerror": 18, "0x80b60000": 18, "ua_statuscode_badmaxconnectionsreach": 18, "0x80b70000": 18, "introduct": 19, "contribut": 19, "dimens": [19, 21, 28, 31, 32, 34], "ubuntu": 19, "debian": 19, "openbsd": 19, "docker": 19, "artefact": 19, "minim": 19, "prebuilt": 19, "arch": 19, "sbyte": 19, "int16": 19, "int64": [19, 23], "xmlelement": 19, "diagnosticinfo": [19, 35], "json": 19, "namingruletyp": 19, "keyvaluepair": 19, "structuretyp": 19, "structurefield": 19, "structuredefinit": 19, "enumvaluetyp": 19, "enumfield": 19, "durat": 19, "utctim": 19, "timezonedatatyp": 19, "responsehead": 19, "servicefault": 19, "findserversrespons": 19, "findserversonnetworkrespons": 19, "messagesecuritymod": 19, "usertokentyp": 19, "getendpointsrespons": 19, "registerserverrequest": 19, "registerserverrespons": 19, "mdnsdiscoveryconfigur": 19, "registerserver2request": 19, "registerserver2respons": 19, "securitytokenrequesttyp": 19, "channelsecuritytoken": 19, "opensecurechannelrequest": 19, "opensecurechannelrespons": 19, "closesecurechannelrequest": 19, "closesecurechannelrespons": 19, "signedsoftwarecertif": 19, "signaturedata": 19, "createsessionrequest": 19, "createsessionrespons": 19, "anonymousidentitytoken": 19, "usernameidentitytoken": 19, "x509identitytoken": 19, "issuedidentitytoken": 19, "activatesessionrequest": 19, "activatesessionrespons": 19, "closesessionrequest": 19, "closesessionrespons": 19, "cancelrequest": 19, "cancelrespons": 19, "nodeattributesmask": 19, "nodeattribut": 19, "methodattribut": 19, "objecttypeattribut": 19, "variabletypeattribut": 19, "referencetypeattribut": 19, "datatypeattribut": 19, "viewattribut": 19, "addnodesitem": 19, "addnodesresult": 19, "addnodesrequest": 19, "addnodesrespons": 19, "addreferencesitem": 19, "addreferencesrequest": 19, "addreferencesrespons": 19, "deletenodesitem": 19, "deletenodesrequest": 19, "deletenodesrespons": 19, "deletereferencesitem": 19, "deletereferencesrequest": 19, "deletereferencesrespons": 19, "browsedirect": 19, "viewdescript": 19, "browseresultmask": 19, "referencedescript": 19, "browseresult": 19, "browserequest": 19, "browserespons": 19, "browsenextrequest": 19, "browsenextrespons": 19, "relativepathel": 19, "browsepathtarget": 19, "browsepathresult": 19, "translatebrowsepathstonodeidsrequest": 19, "translatebrowsepathstonodeidsrespons": 19, "registernodesrequest": 19, "registernodesrespons": 19, "unregisternodesrequest": 19, "unregisternodesrespons": 19, "filteroper": 19, "contentfilterel": 19, "contentfilt": 19, "elementoperand": 19, "literaloperand": 19, "attributeoperand": 19, "contentfilterelementresult": 19, "contentfilterresult": 19, "readrespons": 19, "historyreadvalueid": 19, "historyreadresult": 19, "readrawmodifieddetail": 19, "readattimedetail": 19, "historydata": 19, "historyreadrequest": 19, "historyreadrespons": 19, "writerequest": 19, "writerespons": 19, "historyupdatetyp": 19, "performupdatetyp": 19, "updatedatadetail": 19, "deleterawmodifieddetail": 19, "historyupdateresult": 19, "historyupdaterequest": 19, "historyupdaterespons": 19, "callrespons": 19, "datachangetrigg": 19, "deadbandtyp": 19, "datachangefilt": 19, "aggregateconfigur": 19, "aggregatefilt": 19, "eventfilterresult": 19, "monitoringparamet": 19, "monitoreditemcreaterequest": 19, "monitoreditemcreateresult": 19, "createmonitoreditemsrequest": 19, "createmonitoreditemsrespons": 19, "monitoreditemmodifyrequest": 19, "monitoreditemmodifyresult": 19, "modifymonitoreditemsrequest": 19, "modifymonitoreditemsrespons": 19, "setmonitoringmoderequest": 19, "setmonitoringmoderespons": 19, "settriggeringrequest": 19, "settriggeringrespons": 19, "deletemonitoreditemsrequest": 19, "deletemonitoreditemsrespons": 19, "createsubscriptionrequest": 19, "createsubscriptionrespons": 19, "modifysubscriptionrequest": 19, "modifysubscriptionrespons": 19, "setpublishingmoderequest": 19, "setpublishingmoderespons": 19, "monitoreditemnotif": 19, "eventfieldlist": 19, "historyeventfieldlist": 19, "statuschangenotif": 19, "subscriptionacknowledg": 19, "republishrequest": 19, "republishrespons": 19, "transferresult": 19, "transfersubscriptionsrequest": 19, "transfersubscriptionsrespons": 19, "deletesubscriptionsrequest": 19, "deletesubscriptionsrespons": 19, "buildinfo": 19, "redundancysupport": 19, "serverst": 19, "serverstatusdatatyp": 19, "sessionsecuritydiagnosticsdatatyp": 19, "servicecounterdatatyp": 19, "subscriptiondiagnosticsdatatyp": 19, "euinform": 19, "axisscaleenumer": 19, "complexnumbertyp": 19, "doublecomplexnumbertyp": 19, "axisinform": 19, "xvtype": 19, "enumdefinit": 19, "readeventdetail": 19, "readprocesseddetail": 19, "modificationinfo": 19, "historymodifieddata": 19, "historyev": 19, "datachangenotif": 19, "eventnotificationlist": 19, "sessiondiagnosticsdatatyp": 19, "alarm": [19, 33], "statist": 19, "attrbiut": 19, "publisheddataset": [19, 22], "datasetfield": [19, 22], "datasetwrit": [19, 22], "subscribeddataset": [19, 23], "readergroup": [19, 23], "securitygroup": 19, "hello": [19, 33, 34], "increas": [19, 33, 34], "observ": [19, 24, 33], "parser": 19, "complex": 19, "nodesetinject": 19, "clientsid": 20, "myclient": 20, "client_highlevel": 20, "log_stdout": [20, 21, 22, 23, 25, 28, 29, 31, 32], "ua_clientconfig_setdefault": 20, "ua_statuscode_nam": [20, 24, 26, 31, 32, 34], "ua_variant_init": [20, 31], "ua_ns0id_server_serverstatus_currenttim": [20, 22, 29], "ua_variant_hasscalartyp": [20, 34], "ua_types_datetim": [20, 23, 24, 25, 26], "raw_dat": 20, "ua_datetimestruct": [20, 34], "dt": 20, "ua_datetime_tostruct": [20, 34], "03u": 20, "dai": [20, 34], "month": [20, 34], "year": [20, 34], "hour": [20, 34], "sec": [20, 34], "millisec": [20, 34], "ua_variant_clear": [20, 21], "winsock": [20, 27], "lws2_32": [20, 27], "try": [20, 34], "rememb": 20, "ua_client_writ": 20, "stdlib": [21, 22, 23], "variables_bas": 21, "ua_int32_copi": 21, "ua_int32_new": [21, 34], "ua_int32_delet": 21, "ua_string_init": 21, "_init": [21, 34], "strlen": [21, 34], "s2": [21, 34], "ua_string_copi": 21, "heap": [21, 34], "s3": 21, "test2": 21, "s4": 21, "eq": 21, "ua_string_equ": 21, "ua_init": [21, 34], "ua_readrequest_init": 21, "shorthand": [21, 34], "ua_datetime_now": [21, 25, 26, 34], "nodestoread": [21, 34, 35], "ua_array_new": [21, 23, 34], "ua_types_readvalueid": 21, "nodestoreads": [21, 34, 35], "rr2": 21, "ua_readrequest_new": 21, "ua_copi": [21, 34], "ua_readrequest_clear": 21, "ua_readrequest_delet": 21, "variables_nodeid": 21, "id1": 21, "1234": 21, "id2": 21, "ua_nodeid_str": [21, 25, 28, 31, 34], "testid": 21, "ua_nodeid_equ": 21, "id3": 21, "ua_nodeid_copi": [21, 23], "ua_nodeid_clear": 21, "id4": 21, "ua_nodeid_string_alloc": [21, 34], "denot": 21, "2x3": 21, "matrix": [21, 31, 34], "variables_vari": 21, "42": [21, 31, 34], "ua_variant_copi": 21, "v3": 21, "d": 21, "ua_variant_setarraycopi": [21, 28, 34], "ua_enable_json_encod": [21, 34], "prettyprint": [21, 34], "ua_readvalueid_init": 21, "ua_string_nul": [21, 22, 23, 34], "ua_print": [21, 34], "resp": 21, "ua_readresponse_init": 21, "ua_referencedescript": [21, 34, 35], "br": 21, "ua_referencedescription_init": 21, "ua_types_referencedescript": 21, "ua_float": [21, 34, 35], "matrix_dim": 21, "dv": 21, "ua_datavalue_init": 21, "ua_variant_setarrai": [21, 31, 32, 34], "ua_types_float": 21, "hasstatu": [21, 31, 34], "hasservertimestamp": [21, 34], "hassourcepicosecond": [21, 34], "batch": 22, "demonstr": [22, 23], "simplest": [22, 23, 34], "uadp": [22, 23], "preconfigur": 22, "tutorial_pubsub_connect": 22, "server_pubsub": [22, 23], "publisheddatasetid": 22, "addpubsubconnect": [22, 23], "transportprofil": [22, 23], "ua_networkaddressurldatatyp": [22, 23], "networkaddressurl": [22, 23], "ua_types_networkaddressurldatatyp": [22, 23], "2234": [22, 23], "toplevel": 22, "entiti": 22, "alon": 22, "indirectli": 22, "addpublisheddataset": 22, "demo": 22, "adddatasetfield": 22, "datasetfieldid": 22, "localtim": 22, "publishedvari": 22, "wg": 22, "addwritergroup": 22, "ua_extensionobject_decod": [22, 34], "ua_types_uadpwritergroupmessagedatatyp": 22, "uadpwritergroupmessagedatatyp": 22, "ua_uadpwritergroupmessagedatatyp": 22, "writergroupmessag": 22, "ua_uadpwritergroupmessagedatatype_new": 22, "grouphead": 22, "payloadhead": 22, "networkmessagecontentmask": 22, "ua_uadpnetworkmessagecontentmask": 22, "ua_uadpnetworkmessagecontentmask_publisherid": 22, "ua_uadpnetworkmessagecontentmask_grouphead": 22, "ua_uadpnetworkmessagecontentmask_writergroupid": 22, "ua_uadpnetworkmessagecontentmask_payloadhead": 22, "ua_uadpwritergroupmessagedatatype_delet": 22, "adddatasetwrit": 22, "outgo": 22, "ua_network_pubsub_networkmessag": 22, "exit_success": [22, 23], "exit_failur": [22, 23], "prognam": [22, 23], "224": [22, 23], "strcmp": [22, 23], "strncmp": [22, 23], "networkinterfac": [22, 23], "tutorial_pubsub_publish": 23, "readerconfig": 23, "filltestdatasetmetadata": 23, "pmetadata": 23, "udpmc": 23, "addreadergroup": 23, "readergroup1": 23, "adddatasetread": 23, "publisheridentifi": 23, "ua_types_uint16": [23, 24, 26], "subscribedvari": 23, "addsubscribedvari": 23, "datasetreaderid": 23, "folderid": 23, "foldernam": 23, "oattr": [23, 30], "folderbrowsenam": 23, "ua_ns0id_baseobjecttyp": [23, 24, 30], "targetvar": 23, "ua_calloc": 23, "fieldssiz": [23, 34, 35], "vattr": [23, 32], "ua_localizedtext_copi": 23, "50000": 23, "ua_ns0id_hascompon": [23, 24, 26, 28, 30, 32], "ua_ns0id_basedatavariabletyp": [23, 24, 25, 30, 31, 32], "ua_fieldtargetdatatype_init": 23, "ua_fieldtargetdatatype_clear": 23, "ua_fre": 23, "publisheddatasetfield": 23, "ua_datasetmetadatatype_init": 23, "four": [23, 34], "distinct": 23, "ua_fieldmetadata": 23, "ua_types_fieldmetadata": 23, "ua_fieldmetadata_init": 23, "builtintyp": 23, "ua_ns0id_datetim": 23, "ua_ns0id_int32": 23, "ua_types_int64": 23, "ua_ns0id_int64": 23, "ua_ns0id_boolean": 23, "booltoggl": 23, "proceed": 24, "conditioninstance_1": 24, "conditioninstance_2": 24, "addconditionsourceobject": 24, "conditionsourceobject": 24, "ua_ns0id_serv": [24, 26], "ua_ns0id_hasnotifi": 24, "ua_expandednodeid_numer": [24, 30, 34], "offnormalalarmtyp": 24, "addcondition_1": 24, "ua_ns0id_offnormalalarmtyp": 24, "addcondition_2": 24, "addvariable_1_triggeralarmofcondition_1": 24, "tboolvalu": 24, "callbacktestvariablenam": 24, "parentreferencenodeid": [24, 25, 31], "variabletypenodeid": [24, 25], "addvariable_2_changeseverityofcondition_2": 24, "severityvalu": 24, "addvariable_3_returncondition_1_tonormalst": 24, "rtn": 24, "afterwritecallbackvariable_1": 24, "activestatefield": 24, "activestateidfield": 24, "activestateid": 24, "inact": 24, "conditionrefresh": 24, "conditionvariabletyp": 24, "afterwritecallbackvariable_2": 24, "retain": 24, "afterwritecallbackvariable_3": 24, "enabledstatefield": 24, "ackedstatefield": 24, "confirmedstatefield": 24, "severityfield": 24, "messagefield": 24, "commentfield": 24, "comment": [24, 34], "retainfield": 24, "idfield": 24, "idvalu": 24, "messagevalu": 24, "commentvalu": 24, "retainvalu": 24, "enteringenabledstatecallback": 24, "enteringackedstatecallback": 24, "deactiv": 24, "enteringconfirmedstatecallback": 24, "setupenviron": 24, "variable_1": 24, "variable_2": 24, "variable_3": 24, "enter": 24, "userspecificcallback": 24, "unexpos": 24, "behav": 24, "manner": 24, "soft": 24, "enabledstateid": 24, "enabledstateidfield": 24, "saw": 25, "simplic": 25, "concern": 25, "updatecurrenttim": 25, "currentnodeid": 25, "addcurrenttimevari": 25, "currentnam": 25, "tight": 25, "beforereadtim": 25, "afterwritetim": 25, "addvaluecallbacktocurrenttimevari": 25, "redirect": 25, "readcurrenttim": 25, "ua_variant_setscalarcopi": [25, 28, 34], "writecurrenttim": 25, "addcurrenttimedatasourcevari": 25, "timedatasourc": 25, "externalvalu": 25, "addcurrenttimeexternaldatasourc": 25, "convei": 26, "solut": [26, 30], "baseeventtyp": 26, "addneweventtyp": 26, "simpleeventtyp": 26, "ua_ns0id_baseeventtyp": 26, "ua_ns0id_hassubtyp": [26, 30, 32], "receivetim": 26, "sourcenod": 26, "compliant": 26, "setupev": 26, "outid": 26, "createev": 26, "eventtim": 26, "eventsever": 26, "eventmessag": 26, "sourcenam": 26, "ua_types_str": [26, 28, 30, 31, 32], "onto": 26, "said": 26, "generateeventmethodcallback": 26, "sessionhandl": [26, 28], "triggerev": 26, "addgenerateeventmethod": 26, "generateattr": 26, "mingw32": 27, "straightforward": 27, "frontend": 27, "autom": 27, "downdload": 27, "myserv": 27, "accommod": 27, "lowlevel": 27, "worri": 27, "listern": 27, "trivial": 27, "mainloop": 27, "toolkit": 27, "turn": [28, 32], "term": 28, "prepend": 28, "helloworldmethodcallback": 28, "inputstr": 28, "tmp": 28, "ua_realloc": 28, "addhelloworldmethod": 28, "ua_argument_init": 28, "myinput": 28, "myoutput": 28, "helloattr": 28, "incint32arraymethodcallback": 28, "inputarrai": 28, "delta": 28, "increat": 28, "outputarrai": 28, "arraylength": [28, 34], "addincint32arraymethod": 28, "pinputdimens": 28, "increment": 28, "poutputdimens": 28, "incattr": 28, "incint32arrayvalu": 28, "client_subscript": 29, "datachangenotificationcallback": 29, "addmonitoreditemtocurrenttimevari": 29, "currenttimenodeid": 29, "monrequest": 29, "ua_timestampstoreturn_sourc": [29, 34, 35], "Of": 30, "cours": 30, "scada": 30, "visualis": 30, "resuabl": 30, "manuallydefinepump": 30, "pumpid": 30, "mnattr": 30, "king": 30, "ltd": 30, "modelattr": 30, "mega": 30, "3000": 30, "statusattr": 30, "rpmattr": 30, "rpm": 30, "50": 30, "convent": [30, 34], "predefin": 30, "pumptypeid": 30, "ua_nodeidtype_numer": [30, 34], "defineobjecttyp": 30, "devicetypeid": 30, "dtattr": 30, "devicetyp": 30, "manufacturernameid": 30, "manufactur": 30, "ua_ns0id_hasmodellingrul": 30, "ua_ns0id_modellingrule_mandatori": 30, "ptattr": 30, "pumptyp": 30, "statusid": 30, "addpumpobjectinst": 30, "pumptypeconstructor": 30, "typecontext": 30, "ua_relativepathel": [30, 34, 35], "rpe": 30, "ua_relativepathelement_init": 30, "includesubtyp": [30, 34, 35], "targetnam": [30, 34, 35], "bp": 30, "ua_browsepath_init": 30, "startingnod": [30, 34, 35], "elementss": [30, 34, 35], "bpr": 30, "ua_browsepathresult_clear": 30, "addpumptypeconstructor": 30, "pump2": 30, "pump3": 30, "pump4": 30, "pump5": 30, "writabl": 31, "addvari": [31, 32], "myinteg": 31, "myintegernodeid": 31, "myintegernam": 31, "addmatrixvari": 31, "arraydim": [31, 32], "writevari": [31, 32], "43": 31, "myvar": 31, "syntact": 31, "sugar": 31, "wv": 31, "ua_writevalue_init": 31, "forbid": 31, "writewrongvari": 31, "mystr": 31, "interpret": 32, "2d": 32, "pointtypeid": 32, "addvariabletype2dpoint": 32, "vtattr": 32, "2dpoint": 32, "pointvariableid": 32, "enforc": 32, "addvariablefail": 32, "Their": 34, "dive": 34, "ua_internal_deprec": 34, "127": 34, "int8_t": 34, "ua_sbyt": 34, "ua_sbyte_min": 34, "ua_sbyte_max": 34, "255": 34, "uint8_t": 34, "ua_byte_min": 34, "ua_byte_max": 34, "768": 34, "767": 34, "int16_t": 34, "ua_int16": [34, 35], "ua_int16_min": 34, "32768": [34, 35], "ua_int16_max": 34, "32767": 34, "65": 34, "535": 34, "uint16_t": 34, "ua_uint16_min": 34, "ua_uint16_max": 34, "65535": 34, "147": 34, "483": 34, "648": 34, "647": 34, "int32_t": 34, "ua_int32_min": 34, "2147483648ll": 34, "ua_int32_max": 34, "2147483647l": 34, "294": 34, "967": 34, "295": 34, "uint32_t": 34, "ua_uint32_min": 34, "ua_uint32_max": 34, "4294967295ul": 34, "223": 34, "372": 34, "036": 34, "854": 34, "775": 34, "808": 34, "807": 34, "int64_t": 34, "ua_int64_max": 34, "9223372036854775807ll": 34, "ua_int64_min": 34, "1ll": 34, "446": 34, "744": 34, "073": 34, "709": 34, "551": 34, "615": 34, "uint64_t": 34, "ua_uint64_min": 34, "ua_uint64_max": 34, "18446744073709551615ull": 34, "ieee": 34, "precis": 34, "ua_float_min": 34, "flt_min": 34, "ua_float_max": 34, "flt_max": 34, "64": [34, 35], "ua_double_min": 34, "dbl_min": 34, "ua_double_max": 34, "dbl_max": 34, "subcod": 34, "smaller": 34, "34": 34, "ua_statuscode_isbad": 34, "30": 34, "0x02": 34, "ua_statuscode_isuncertain": 34, "0x01": 34, "ua_statuscode_isgood": 34, "0x00": 34, "ua_statuscode_isequaltop": 34, "0xffff0000": 34, "unicod": 34, "ua_string_fromchar": 34, "ua_string_isempti": 34, "ua_string_stat": 34, "nanosecond": 34, "januari": 34, "1601": 34, "utc": 34, "leap": 34, "tai": 34, "unusu": 34, "2019": 34, "apart": 34, "ua_datetime_usec": 34, "10ll": 34, "ua_datetime_msec": 34, "1000ll": 34, "ua_datetime_sec": 34, "ua_datetime_localtimeutcoffset": 34, "cpu": 34, "invari": 34, "ua_datetime_nowmonoton": 34, "nanosec": 34, "microsec": 34, "31": 34, "neg": 34, "bc": 34, "ua_datetime_fromstruct": 34, "clock_t": 34, "time_t": 34, "epoch": 34, "jan": 34, "1970": 34, "ua_datetime_unix_epoch": 34, "11644473600ll": 34, "ua_datetime_tounixtim": 34, "ua_datetime_fromunixtim": 34, "unixd": 34, "ua_guid_nul": 34, "c496578a": 34, "0dfe": 34, "4b8f": 34, "870a": 34, "745238c6aeae": 34, "36": 34, "ua_guid_print": 34, "humand": 34, "ua_guid_pars": 34, "octet": 34, "ua_bytestring_nul": 34, "ua_bytestring_allocbuff": 34, "base64": 34, "ua_bytestring_tobase64": 34, "ua_bytestring_frombase64": 34, "ua_bytestring_alloc": 34, "ua_bytestring_hash": 34, "initialhashvalu": 34, "ua_xmlel": 34, "ua_nodeidtyp": 34, "becom": 34, "ua_nodeidtype_str": 34, "ua_nodeidtype_guid": 34, "ua_nodeidtype_bytestr": 34, "identifiertyp": 34, "ua_nodeid_isnul": 34, "09087e75": 34, "8e5e": 34, "499b": 34, "954f": 34, "f2a9603db28a": 34, "b3blbjyyntqxiq": 34, "ua_nodeid_print": 34, "ua_nodeid_pars": 34, "nsindex": 34, "ua_nodeid_guid": 34, "ua_nodeid_bytestr": 34, "ua_nodeid_bytestring_alloc": 34, "total": 34, "ua_nodeid_ord": 34, "n1": 34, "n2": 34, "ua_nodeid_hash": 34, "ua_expandednodeid_nul": 34, "svr": 34, "nsu": 34, "ua_expandednodeid_print": 34, "ua_expandednodeid_pars": 34, "ua_expandednodeid_str": 34, "ua_expandednodeid_string_alloc": 34, "ua_expandednodeid_string_guid": 34, "ua_expandednodeid_bytestr": 34, "ua_expandednodeid_bytestring_alloc": 34, "ua_expandednodeid_nodeid": 34, "ua_expandednodeid_isloc": 34, "ua_expandednodeid_ord": 34, "ua_expandednodeid_hash": 34, "qualifi": 34, "ua_qualifiedname_isnul": 34, "q": 34, "ua_qualifiedname_hash": 34, "qn": 34, "ua_qualifiedname_alloc": 34, "lt": 34, "ua_localizedtext_alloc": 34, "multidimension": 34, "comma": 34, "ua_numericrangedimens": 34, "dimensionss": 34, "ua_numericrange_pars": 34, "nr": 34, "hide": 34, "transpar": 34, "tensor": 34, "who": 34, "mind": 34, "highest": 34, "stride": 34, "ua_variant_isscalar": 34, "ua_empty_array_sentinel": 34, "ua_variant_data": 34, "borrow": 34, "ua_variantstoragetyp": 34, "neither": 34, "nor": 34, "ua_variant_isempti": 34, "ua_variant_hasarraytyp": 34, "resid": 34, "arrays": 34, "ua_variant_copyrang": 34, "dataarrai": 34, "dataarrays": 34, "ua_variant_setrang": 34, "ua_variant_setrangecopi": 34, "ua_extensionobject_encoded_nobodi": 34, "ua_extensionobject_encoded_bytestr": 34, "ua_extensionobject_encoded_xml": 34, "ua_extensionobject_decoded_nodelet": 34, "ua_extensionobjectencod": 34, "eo": 34, "ua_extensionobject_setvaluenodelet": 34, "ua_extensionobject_setvaluecopi": 34, "sourcepicosecond": 34, "serverpicosecond": 34, "hassourcetimestamp": 34, "hasserverpicosecond": 34, "ua_datavalue_copyvariantrang": 34, "ua_diagnosticinfo": [34, 35], "hassymbolicid": 34, "hasnamespaceuri": 34, "haslocalizedtext": 34, "haslocal": 34, "hasadditionalinfo": 34, "hasinnerstatuscod": 34, "hasinnerdiagnosticinfo": 34, "symbolicid": 34, "additionalinfo": 34, "innerstatuscod": 34, "innerdiagnosticinfo": 34, "t_init": 34, "synonym": 34, "t_new": 34, "t_copi": 34, "t_clear": 34, "t_delet": 34, "t_equal": 34, "membernam": 34, "membertyp": 34, "pad": 34, "switchfield": 34, "isarrai": 34, "isopt": [34, 35], "ua_datatypememb": 34, "classif": 34, "routin": 34, "ua_datatypekind": 34, "ua_datatypekind_boolean": 34, "ua_datatypekind_sbyt": 34, "ua_datatypekind_byt": 34, "ua_datatypekind_int16": 34, "ua_datatypekind_uint16": 34, "ua_datatypekind_int32": 34, "ua_datatypekind_uint32": 34, "ua_datatypekind_int64": 34, "ua_datatypekind_uint64": 34, "ua_datatypekind_float": 34, "ua_datatypekind_doubl": 34, "ua_datatypekind_str": 34, "ua_datatypekind_datetim": 34, "ua_datatypekind_guid": 34, "ua_datatypekind_bytestr": 34, "ua_datatypekind_xmlel": 34, "ua_datatypekind_nodeid": 34, "ua_datatypekind_expandednodeid": 34, "ua_datatypekind_statuscod": 34, "ua_datatypekind_qualifiednam": 34, "ua_datatypekind_localizedtext": 34, "ua_datatypekind_extensionobject": 34, "ua_datatypekind_datavalu": 34, "ua_datatypekind_vari": 34, "ua_datatypekind_diagnosticinfo": 34, "ua_datatypekind_decim": 34, "ua_datatypekind_enum": 34, "ua_datatypekind_structur": 34, "ua_datatypekind_optstruct": 34, "28": 34, "ua_datatypekind_union": 34, "29": 34, "ua_datatypekind_bitfieldclust": 34, "typenam": 34, "binaryencodingid": 34, "xmlencodingid": 34, "memsiz": 34, "typekind": 34, "pointerfre": 34, "overlay": 34, "memberss": 34, "typess": 34, "ua_datatype_getstructmemb": 34, "outoffset": 34, "outmembertyp": 34, "outisarrai": 34, "ua_datatype_isnumer": 34, "ua_types_xxx": 34, "xxx": 34, "ua_finddatatyp": 34, "scope": 34, "ua_finddatatypewithcustom": 34, "customtyp": 34, "ua_new": 34, "leak": 34, "safe": 34, "ua_clear": 34, "ua_deletememb": 34, "ua_delet": 34, "pretti": 34, "json5": 34, "nan": 34, "smallest": 34, "shortlex": 34, "shorter": 34, "ua_equ": 34, "ua_calcsizebinari": 34, "outbuf": 34, "ua_encodebinari": 34, "ua_decodebinaryopt": 34, "ua_decodebinari": 34, "inbuf": 34, "relax": 34, "namespacess": 34, "userevers": 34, "newlin": 34, "legibl": 34, "unquotedkei": 34, "quot": 34, "around": 34, "stringnodeid": 34, "ua_encodejsonopt": 34, "ua_calcsizejson": 34, "ua_encodejson": 34, "ua_decodejsonopt": 34, "ua_decodejson": 34, "ua_enable_xml_encod": 34, "ua_encodexmlopt": 34, "ua_calcsizexml": 34, "ua_encodexml": 34, "ua_decodexmlopt": 34, "ua_decodexml": 34, "ua_array_copi": 34, "resiz": 34, "decreas": 34, "newsiz": 34, "ua_array_res": 34, "append": 34, "newelem": 34, "ua_array_append": 34, "ua_array_appendcopi": 34, "ua_array_delet": 34, "ua_namingruletype_mandatori": [34, 35], "ua_namingruletype_opt": [34, 35], "ua_namingruletype_constraint": [34, 35], "ua_namingruletyp": [34, 35], "ua_nodeclass_unspecifi": [34, 35], "ua_structuretype_structur": [34, 35], "ua_structuretype_structurewithoptionalfield": [34, 35], "ua_structuretype_union": [34, 35], "ua_structuretype_structurewithsubtypedvalu": [34, 35], "ua_structuretype_unionwithsubtypedvalu": [34, 35], "ua_structuretyp": [34, 35], "ua_structurefield": [34, 35], "defaultencodingid": [34, 35], "ua_structuredefinit": [34, 35], "ua_enumvaluetyp": [34, 35], "ua_enumfield": [34, 35], "ua_utctim": [34, 35], "daylightsavinginoffset": [34, 35], "ua_timezonedatatyp": [34, 35], "ua_applicationtype_serv": [34, 35], "ua_applicationtype_cli": [34, 35], "ua_applicationtype_clientandserv": [34, 35], "ua_applicationtype_discoveryserv": [34, 35], "ua_applicationtyp": [34, 35], "producturi": [34, 35], "applicationnam": [34, 35], "gatewayserveruri": [34, 35], "discoveryprofileuri": [34, 35], "discoveryurlss": [34, 35], "returndiagnost": [34, 35], "auditentryid": [34, 35], "additionalhead": [34, 35], "ua_requesthead": [34, 35], "serviceresult": [34, 35], "servicediagnost": [34, 35], "stringtables": [34, 35], "stringtabl": [34, 35], "ua_responsehead": [34, 35], "ua_servicefault": [34, 35], "ua_findserversrequest": [34, 35], "serverss": [34, 35], "ua_findserversrespons": [34, 35], "recordid": [34, 35], "servercapabilitiess": [34, 35], "servercap": [34, 35], "ua_findserversonnetworkrequest": [34, 35], "lastcounterresettim": [34, 35], "ua_findserversonnetworkrespons": [34, 35], "ua_messagesecuritymode_invalid": [34, 35], "ua_messagesecuritymode_non": [34, 35], "ua_messagesecuritymode_sign": [34, 35], "ua_messagesecuritymode_signandencrypt": [34, 35], "ua_usertokentype_anonym": [34, 35], "ua_usertokentype_usernam": [34, 35], "ua_usertokentype_certif": [34, 35], "ua_usertokentype_issuedtoken": [34, 35], "ua_usertokentyp": [34, 35], "policyid": [34, 35], "tokentyp": [34, 35], "issuedtokentyp": [34, 35], "issuerendpointurl": [34, 35], "servercertif": [34, 35], "useridentitytokenss": [34, 35], "securitylevel": [34, 35], "profileuriss": [34, 35], "profileuri": [34, 35], "ua_getendpointsrequest": [34, 35], "ua_getendpointsrespons": [34, 35], "servernamess": [34, 35], "isonlin": [34, 35], "ua_registerserverrequest": [34, 35], "ua_registerserverrespons": [34, 35], "mdnsservernam": [34, 35], "discoveryconfigurations": [34, 35], "discoveryconfigur": [34, 35], "ua_registerserver2request": [34, 35], "configurationresultss": [34, 35], "configurationresult": [34, 35], "diagnosticinfoss": [34, 35], "ua_registerserver2respons": [34, 35], "ua_securitytokenrequesttype_issu": [34, 35], "ua_securitytokenrequesttype_renew": [34, 35], "ua_securitytokenrequesttyp": [34, 35], "channelid": [34, 35], "createdat": [34, 35], "revisedlifetim": [34, 35], "ua_channelsecuritytoken": [34, 35], "clientprotocolvers": [34, 35], "clientnonc": [34, 35], "requestedlifetim": [34, 35], "ua_opensecurechannelrequest": [34, 35], "serverprotocolvers": [34, 35], "ua_opensecurechannelrespons": [34, 35], "ua_closesecurechannelrequest": [34, 35], "ua_closesecurechannelrespons": [34, 35], "certificatedata": [34, 35], "ua_signedsoftwarecertif": [34, 35], "ua_signaturedata": [34, 35], "clientcertif": [34, 35], "maxresponsemessages": [34, 35], "ua_createsessionrequest": [34, 35], "revisedsessiontimeout": [34, 35], "serverendpointss": [34, 35], "serverendpoint": [34, 35], "serversoftwarecertificatess": [34, 35], "serversoftwarecertif": [34, 35], "serversignatur": [34, 35], "maxrequestmessages": [34, 35], "ua_createsessionrespons": [34, 35], "ua_useridentitytoken": [34, 35], "ua_anonymousidentitytoken": [34, 35], "ua_x509identitytoken": [34, 35], "tokendata": [34, 35], "ua_issuedidentitytoken": [34, 35], "clientsignatur": [34, 35], "clientsoftwarecertificatess": [34, 35], "clientsoftwarecertif": [34, 35], "usertokensignatur": [34, 35], "ua_activatesessionrequest": [34, 35], "ua_activatesessionrespons": [34, 35], "ua_closesessionrequest": [34, 35], "ua_closesessionrespons": [34, 35], "ua_cancelrequest": [34, 35], "ua_cancelrespons": [34, 35], "ua_nodeattributesmask_non": [34, 35], "ua_nodeattributesmask_accesslevel": [34, 35], "ua_nodeattributesmask_arraydimens": [34, 35], "ua_nodeattributesmask_browsenam": [34, 35], "ua_nodeattributesmask_containsnoloop": [34, 35], "ua_nodeattributesmask_datatyp": [34, 35], "ua_nodeattributesmask_descript": [34, 35], "ua_nodeattributesmask_displaynam": [34, 35], "ua_nodeattributesmask_eventnotifi": [34, 35], "ua_nodeattributesmask_execut": [34, 35], "256": [34, 35], "ua_nodeattributesmask_histor": [34, 35], "512": [34, 35], "ua_nodeattributesmask_inversenam": [34, 35], "1024": [34, 35], "ua_nodeattributesmask_isabstract": [34, 35], "2048": [34, 35], "ua_nodeattributesmask_minimumsamplinginterv": [34, 35], "4096": [34, 35], "ua_nodeattributesmask_nodeclass": [34, 35], "8192": [34, 35], "ua_nodeattributesmask_nodeid": [34, 35], "16384": [34, 35], "ua_nodeattributesmask_symmetr": [34, 35], "ua_nodeattributesmask_useraccesslevel": [34, 35], "65536": [34, 35], "ua_nodeattributesmask_userexecut": [34, 35], "131072": [34, 35], "ua_nodeattributesmask_userwritemask": [34, 35], "262144": [34, 35], "ua_nodeattributesmask_valuerank": [34, 35], "524288": [34, 35], "ua_nodeattributesmask_writemask": [34, 35], "1048576": [34, 35], "ua_nodeattributesmask_valu": [34, 35], "2097152": [34, 35], "ua_nodeattributesmask_datatypedefinit": [34, 35], "4194304": [34, 35], "ua_nodeattributesmask_rolepermiss": [34, 35], "8388608": [34, 35], "ua_nodeattributesmask_accessrestrict": [34, 35], "16777216": [34, 35], "ua_nodeattributesmask_al": [34, 35], "33554431": [34, 35], "ua_nodeattributesmask_basenod": [34, 35], "26501220": [34, 35], "ua_nodeattributesmask_object": [34, 35], "26501348": [34, 35], "ua_nodeattributesmask_objecttyp": [34, 35], "26503268": [34, 35], "ua_nodeattributesmask_vari": [34, 35], "26571383": [34, 35], "ua_nodeattributesmask_variabletyp": [34, 35], "28600438": [34, 35], "ua_nodeattributesmask_method": [34, 35], "26632548": [34, 35], "ua_nodeattributesmask_referencetyp": [34, 35], "26537060": [34, 35], "ua_nodeattributesmask_view": [34, 35], "26501356": [34, 35], "specifiedattribut": [34, 35], "ua_addnodesresult": [34, 35], "nodestoadds": [34, 35], "nodestoadd": [34, 35], "referencestoadds": [34, 35], "referencestoadd": [34, 35], "nodestodeletes": [34, 35], "nodestodelet": [34, 35], "referencestodeletes": [34, 35], "referencestodelet": [34, 35], "ua_browsedirection_forward": [34, 35], "ua_browsedirection_invers": [34, 35], "ua_browsedirection_both": [34, 35], "ua_browsedirection_invalid": [34, 35], "viewid": [34, 35], "viewvers": [34, 35], "ua_viewdescript": [34, 35], "resultmask": [34, 35], "ua_browseresultmask_non": [34, 35], "ua_browseresultmask_referencetypeid": [34, 35], "ua_browseresultmask_isforward": [34, 35], "ua_browseresultmask_nodeclass": [34, 35], "ua_browseresultmask_browsenam": [34, 35], "ua_browseresultmask_displaynam": [34, 35], "ua_browseresultmask_typedefinit": [34, 35], "ua_browseresultmask_al": [34, 35], "ua_browseresultmask_referencetypeinfo": [34, 35], "ua_browseresultmask_targetinfo": [34, 35], "ua_browseresultmask": [34, 35], "requestedmaxreferencespernod": [34, 35], "nodestobrowses": [34, 35], "nodestobrows": [34, 35], "continuationpointss": [34, 35], "remainingpathindex": [34, 35], "ua_browsepathtarget": [34, 35], "browsepathss": [34, 35], "nodestoregisters": [34, 35], "nodestoregist": [34, 35], "registerednodeidss": [34, 35], "registerednodeid": [34, 35], "nodestounregisters": [34, 35], "nodestounregist": [34, 35], "ua_filteroperator_equ": [34, 35], "ua_filteroperator_isnul": [34, 35], "ua_filteroperator_greaterthan": [34, 35], "ua_filteroperator_lessthan": [34, 35], "ua_filteroperator_greaterthanorequ": [34, 35], "ua_filteroperator_lessthanorequ": [34, 35], "ua_filteroperator_lik": [34, 35], "ua_filteroperator_not": [34, 35], "ua_filteroperator_between": [34, 35], "ua_filteroperator_inlist": [34, 35], "ua_filteroperator_and": [34, 35], "ua_filteroperator_or": [34, 35], "ua_filteroperator_cast": [34, 35], "ua_filteroperator_inview": [34, 35], "ua_filteroperator_oftyp": [34, 35], "ua_filteroperator_relatedto": [34, 35], "ua_filteroperator_bitwiseand": [34, 35], "ua_filteroperator_bitwiseor": [34, 35], "ua_filteroper": [34, 35], "filteroperandss": [34, 35], "filteroperand": [34, 35], "ua_contentfilterel": [34, 35], "ua_elementoperand": [34, 35], "ua_literaloperand": [34, 35], "ua_attributeoperand": [34, 35], "typedefinitionid": [34, 35], "operandstatuscodess": [34, 35], "operandstatuscod": [34, 35], "operanddiagnosticinfoss": [34, 35], "operanddiagnosticinfo": [34, 35], "ua_contentfilterelementresult": [34, 35], "elementresultss": [34, 35], "elementresult": [34, 35], "elementdiagnosticinfoss": [34, 35], "elementdiagnosticinfo": [34, 35], "ua_contentfilterresult": [34, 35], "ua_timestampstoreturn_serv": [34, 35], "ua_timestampstoreturn_both": [34, 35], "ua_timestampstoreturn_neith": [34, 35], "ua_timestampstoreturn_invalid": [34, 35], "dataencod": [34, 35], "maxag": [34, 35], "ua_historyreadvalueid": [34, 35], "ua_historyreadresult": [34, 35], "isreadmodifi": [34, 35], "ua_readrawmodifieddetail": [34, 35], "reqtimess": [34, 35], "reqtim": [34, 35], "usesimplebound": [34, 35], "ua_readattimedetail": [34, 35], "datavaluess": [34, 35], "ua_historydata": [34, 35], "historyreaddetail": [34, 35], "nodestowrites": [34, 35], "nodestowrit": [34, 35], "ua_historyupdatetype_insert": [34, 35], "ua_historyupdatetype_replac": [34, 35], "ua_historyupdatetype_upd": [34, 35], "ua_historyupdatetype_delet": [34, 35], "ua_historyupdatetyp": [34, 35], "ua_performupdatetype_insert": [34, 35], "ua_performupdatetype_replac": [34, 35], "ua_performupdatetype_upd": [34, 35], "ua_performupdatetype_remov": [34, 35], "updatevaluess": [34, 35], "updatevalu": [34, 35], "ua_updatedatadetail": [34, 35], "ua_deleterawmodifieddetail": [34, 35], "operationresultss": [34, 35], "operationresult": [34, 35], "ua_historyupdateresult": [34, 35], "historyupdatedetailss": [34, 35], "historyupdatedetail": [34, 35], "inputargumentresultss": [34, 35], "inputargumentresult": [34, 35], "inputargumentdiagnosticinfoss": [34, 35], "inputargumentdiagnosticinfo": [34, 35], "methodstocalls": [34, 35], "methodstocal": [34, 35], "ua_monitoringmode_dis": [34, 35], "ua_monitoringmode_sampl": [34, 35], "ua_monitoringmod": [34, 35], "ua_datachangetrigger_statu": [34, 35], "ua_datachangetrigger_statusvalu": [34, 35], "ua_datachangetrigger_statusvaluetimestamp": [34, 35], "ua_datachangetrigg": [34, 35], "ua_deadbandtype_non": [34, 35], "ua_deadbandtype_absolut": [34, 35], "ua_deadbandtype_perc": [34, 35], "ua_deadbandtyp": [34, 35], "deadbandvalu": [34, 35], "ua_datachangefilt": [34, 35], "selectclausess": [34, 35], "selectclaus": [34, 35], "whereclaus": [34, 35], "useservercapabilitiesdefault": [34, 35], "treatuncertainasbad": [34, 35], "percentdatabad": [34, 35], "percentdatagood": [34, 35], "useslopedextrapol": [34, 35], "ua_aggregateconfigur": [34, 35], "aggregatetyp": [34, 35], "processinginterv": [34, 35], "ua_aggregatefilt": [34, 35], "selectclauseresultss": [34, 35], "selectclauseresult": [34, 35], "selectclausediagnosticinfoss": [34, 35], "selectclausediagnosticinfo": [34, 35], "whereclauseresult": [34, 35], "ua_eventfilterresult": [34, 35], "ua_monitoringparamet": [34, 35], "revisedqueues": [34, 35], "filterresult": [34, 35], "itemstocreates": [34, 35], "itemstocr": [34, 35], "ua_monitoreditemmodifyrequest": [34, 35], "ua_monitoreditemmodifyresult": [34, 35], "itemstomodifys": [34, 35], "itemstomodifi": [34, 35], "monitoreditemidss": [34, 35], "triggeringitemid": [34, 35], "linkstoadds": [34, 35], "linkstoadd": [34, 35], "linkstoremoves": [34, 35], "linkstoremov": [34, 35], "addresultss": [34, 35], "adddiagnosticinfoss": [34, 35], "adddiagnosticinfo": [34, 35], "removeresultss": [34, 35], "removeresult": [34, 35], "removediagnosticinfoss": [34, 35], "removediagnosticinfo": [34, 35], "revisedpublishinginterv": [34, 35], "revisedlifetimecount": [34, 35], "revisedmaxkeepalivecount": [34, 35], "subscriptionidss": [34, 35], "sequencenumb": [34, 35], "publishtim": [34, 35], "notificationdatas": [34, 35], "notificationdata": [34, 35], "ua_notificationmessag": [34, 35], "ua_monitoreditemnotif": [34, 35], "eventfieldss": [34, 35], "ua_eventfieldlist": [34, 35], "ua_historyeventfieldlist": [34, 35], "ua_subscriptionacknowledg": [34, 35], "subscriptionacknowledgementss": [34, 35], "ua_publishrequest": [34, 35], "availablesequencenumberss": [34, 35], "availablesequencenumb": [34, 35], "morenotif": [34, 35], "ua_publishrespons": [34, 35], "retransmitsequencenumb": [34, 35], "ua_republishrequest": [34, 35], "ua_republishrespons": [34, 35], "ua_transferresult": [34, 35], "sendinitialvalu": [34, 35], "ua_transfersubscriptionsrequest": [34, 35], "ua_transfersubscriptionsrespons": [34, 35], "productnam": [34, 35], "softwarevers": [34, 35], "buildnumb": [34, 35], "builddat": [34, 35], "ua_buildinfo": [34, 35], "ua_redundancysupport_non": [34, 35], "ua_redundancysupport_cold": [34, 35], "ua_redundancysupport_warm": [34, 35], "ua_redundancysupport_hot": [34, 35], "ua_redundancysupport_transpar": [34, 35], "ua_redundancysupport_hotandmirror": [34, 35], "ua_redundancysupport": [34, 35], "ua_serverstate_run": [34, 35], "ua_serverstate_fail": [34, 35], "ua_serverstate_noconfigur": [34, 35], "ua_serverstate_suspend": [34, 35], "ua_serverstate_shutdown": [34, 35], "ua_serverstate_test": [34, 35], "ua_serverstate_communicationfault": [34, 35], "ua_serverstate_unknown": [34, 35], "ua_serverst": [34, 35], "serverviewcount": [34, 35], "currentsubscriptioncount": [34, 35], "cumulatedsubscriptioncount": [34, 35], "publishingintervalcount": [34, 35], "securityrejectedrequestscount": [34, 35], "rejectedrequestscount": [34, 35], "ua_serverdiagnosticssummarydatatyp": [34, 35], "currenttim": [34, 35], "secondstillshutdown": [34, 35], "shutdownreason": [34, 35], "ua_serverstatusdatatyp": [34, 35], "clientuseridofsess": [34, 35], "clientuseridhistorys": [34, 35], "clientuseridhistori": [34, 35], "authenticationmechan": [34, 35], "transportprotocol": [34, 35], "ua_sessionsecuritydiagnosticsdatatyp": [34, 35], "totalcount": [34, 35], "errorcount": [34, 35], "ua_servicecounterdatatyp": [34, 35], "maxlifetimecount": [34, 35], "modifycount": [34, 35], "enablecount": [34, 35], "disablecount": [34, 35], "republishrequestcount": [34, 35], "republishmessagerequestcount": [34, 35], "republishmessagecount": [34, 35], "transferrequestcount": [34, 35], "transferredtoaltclientcount": [34, 35], "transferredtosameclientcount": [34, 35], "publishrequestcount": [34, 35], "datachangenotificationscount": [34, 35], "eventnotificationscount": [34, 35], "notificationscount": [34, 35], "latepublishrequestcount": [34, 35], "currentkeepalivecount": [34, 35], "currentlifetimecount": [34, 35], "unacknowledgedmessagecount": [34, 35], "discardedmessagecount": [34, 35], "monitoreditemcount": [34, 35], "disabledmonitoreditemcount": [34, 35], "monitoringqueueoverflowcount": [34, 35], "nextsequencenumb": [34, 35], "eventqueueoverflowcount": [34, 35], "ua_subscriptiondiagnosticsdatatyp": [34, 35], "ua_rang": [34, 35], "unitid": [34, 35], "ua_euinform": [34, 35], "ua_axisscaleenumeration_linear": [34, 35], "ua_axisscaleenumeration_log": [34, 35], "ua_axisscaleenumeration_ln": [34, 35], "ua_axisscaleenumer": [34, 35], "imaginari": [34, 35], "ua_complexnumbertyp": [34, 35], "ua_doublecomplexnumbertyp": [34, 35], "eurang": [34, 35], "titl": [34, 35], "axisscaletyp": [34, 35], "axisstepss": [34, 35], "axisstep": [34, 35], "ua_axisinform": [34, 35], "ua_xvtyp": [34, 35], "ua_enumdefinit": [34, 35], "ua_readeventdetail": [34, 35], "aggregatetypes": [34, 35], "ua_readprocesseddetail": [34, 35], "modificationtim": [34, 35], "updatetyp": [34, 35], "ua_modificationinfo": [34, 35], "modificationinfoss": [34, 35], "ua_historymodifieddata": [34, 35], "eventss": [34, 35], "ua_historyev": [34, 35], "monitoreditemss": [34, 35], "ua_datachangenotif": [34, 35], "ua_eventnotificationlist": [34, 35], "actualsessiontimeout": [34, 35], "clientconnectiontim": [34, 35], "clientlastcontacttim": [34, 35], "currentsubscriptionscount": [34, 35], "currentmonitoreditemscount": [34, 35], "currentpublishrequestsinqueu": [34, 35], "totalrequestcount": [34, 35], "unauthorizedrequestcount": [34, 35], "readcount": [34, 35], "historyreadcount": [34, 35], "writecount": [34, 35], "historyupdatecount": [34, 35], "callcount": [34, 35], "createmonitoreditemscount": [34, 35], "modifymonitoreditemscount": [34, 35], "setmonitoringmodecount": [34, 35], "settriggeringcount": [34, 35], "deletemonitoreditemscount": [34, 35], "createsubscriptioncount": [34, 35], "modifysubscriptioncount": [34, 35], "setpublishingmodecount": [34, 35], "publishcount": [34, 35], "republishcount": [34, 35], "transfersubscriptionscount": [34, 35], "deletesubscriptionscount": [34, 35], "addnodescount": [34, 35], "addreferencescount": [34, 35], "deletenodescount": [34, 35], "deletereferencescount": [34, 35], "browsecount": [34, 35], "browsenextcount": [34, 35], "translatebrowsepathstonodeidscount": [34, 35], "queryfirstcount": [34, 35], "querynextcount": [34, 35], "registernodescount": [34, 35], "unregisternodescount": [34, 35], "ua_sessiondiagnosticsdatatyp": [34, 35]}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"build": [0, 20, 27], "open62541": [0, 7, 19], "librari": 0, "cmake": 0, "ubuntu": 0, "debian": 0, "window": 0, "o": 0, "x": 0, "openbsd": 0, "packag": 0, "insid": 0, "docker": 0, "contain": 0, "option": 0, "main": 0, "select": 0, "artefact": 0, "detail": 0, "sdk": 0, "featur": [0, 7], "pubsub": [0, 15, 16, 17], "debug": 0, "share": 0, "minim": 0, "binari": [0, 5, 34, 36], "size": 0, "prebuilt": 0, "arch": 0, "exampl": [0, 5, 28, 36], "client": [1, 2, 20], "configur": [1, 17, 27], "connect": [1, 5, 11, 16, 17, 25, 36], "custom": [1, 16, 17], "data": [1, 6, 17, 21, 25, 34], "type": [1, 5, 6, 13, 17, 21, 30, 32, 34, 36], "advanc": 1, "lifecycl": [1, 5, 13, 17, 27], "attrbiut": 1, "server": [1, 17, 24, 27, 31], "discoveri": [1, 6, 17], "servic": [1, 3, 6], "asynchron": [1, 3], "time": [1, 17], "callback": [1, 13, 16, 17, 25], "util": [1, 17], "function": [1, 2, 17], "highlevel": 2, "read": [2, 3, 17], "attribut": [2, 3, 5, 6, 13, 17, 29, 36], "histor": [2, 17], "access": [2, 5, 10, 17], "write": [2, 3, 5, 17], "method": [2, 3, 6, 17, 26, 28], "call": [2, 3, 26], "node": [2, 3, 5, 6, 13, 17, 36], "manag": [2, 3, 11, 17], "misc": 2, "async": [3, 17], "oper": [3, 17], "subscript": [4, 6, 17], "monitoreditem": [4, 6, 17, 29], "common": 5, "definit": [5, 34, 36], "id": 5, "level": 5, "mask": 5, "valuerank": [5, 6], "eventnotifi": 5, "rule": [5, 17], "handl": [5, 17, 21, 34], "order": 5, "state": [5, 24], "statist": [5, 17], "counter": 5, "forward": 5, "declar": 5, "rang": [5, 34, 35, 36], "random": [5, 36], "number": [5, 36], "gener": [5, 26, 34, 36], "kei": [5, 14, 36], "valu": [5, 13, 25, 28, 36], "map": [5, 36], "config": [5, 36], "paramet": [5, 36], "default": [5, 36], "endpoint": [5, 36], "url": [5, 36], "parser": [5, 36], "pars": [5, 36], "relativepath": [5, 34, 35, 36], "express": [5, 36], "conveni": [5, 36], "macro": [5, 36], "complex": [5, 36], "cryptographi": [5, 36], "helper": [5, 36], "core": 6, "concept": 6, "opc": [6, 7], "ua": 6, "protocol": 6, "structur": [6, 30], "messag": 6, "set": [6, 26], "securechannel": 6, "nodemanag": 6, "view": 6, "queri": 6, "inform": [6, 16, 17, 30], "model": [6, 16, 17, 30], "differ": 6, "nodeclass": [6, 34, 35], "variablenod": [6, 13], "arrai": [6, 28, 34], "dimens": 6, "variabletypenod": [6, 13], "objectnod": [6, 13], "objecttypenod": [6, 13], "referencetypenod": [6, 13], "datatypenod": [6, 13], "methodnod": [6, 13], "viewnod": [6, 13], "introduct": 7, "unifi": 7, "architectur": 7, "get": [7, 8], "help": 7, "contribut": 7, "xml": [8, 34], "nodeset": 8, "compil": 8, "start": 8, "creat": 8, "object": [8, 17, 28, 30], "instanc": 8, "combin": 8, "multipl": 8, "outstand": 8, "companion": 8, "spec": 8, "issu": 8, "automat": 8, "nodesetinject": 8, "plugin": [9, 10, 12, 13, 27], "api": [9, 10, 12, 13], "control": 10, "event": [11, 17, 24, 26], "loop": 11, "subsystem": 11, "timer": 11, "polici": 11, "sourc": [11, 17, 25], "interrupt": 11, "posix": 11, "specif": 11, "implement": [11, 16], "tcp": 11, "udp": 11, "ethernet": 11, "mqtt": 11, "signal": 11, "log": 12, "store": 13, "constructor": 13, "destructor": 13, "context": 13, "global": 13, "referencetyp": 13, "bitfield": 13, "represent": [13, 16], "pointer": 13, "base": 13, "union": 13, "nodestor": 13, "public": 14, "infrastructur": 14, "integr": 14, "certif": [14, 17], "verif": 14, "securitypolici": 15, "publisheddataset": 16, "datasetfield": 16, "writergroup": 16, "datasetwrit": 16, "subscribeddataset": 16, "datasetread": 16, "readergroup": 16, "securitygroup": 16, "descript": 17, "eventloop": 17, "network": 17, "secur": 17, "encrypt": 17, "limit": 17, "revers": 17, "password": 17, "session": 17, "brows": 17, "regist": 17, "local": [17, 29], "interact": 17, "addit": 17, "delet": 17, "refer": 17, "alarm": [17, 24], "condit": [17, 24], "experiment": 17, "updat": [17, 25], "runtim": 17, "statuscod": [18, 34], "document": 19, "simpl": [20, 27], "further": 20, "task": 20, "work": [21, 22, 30, 32], "basic": 21, "nodeid": [21, 34], "variant": [21, 34], "publish": 22, "subscrib": [22, 23], "field": [22, 23], "us": [24, 30], "trigger": [24, 26], "chang": 24, "variabl": [25, 31, 32], "physic": 25, "process": 25, "manual": 25, "emit": 26, "up": 26, "an": 26, "ad": [28, 31], "hello": 28, "world": 28, "increas": 28, "observ": 29, "hierarchi": 30, "instanti": 30, "tutori": 33, "builtin": 34, "boolean": 34, "sbyte": 34, "byte": 34, "int16": 34, "uint16": 34, "int32": 34, "uint32": 34, "int64": 34, "uint64": 34, "float": 34, "doubl": 34, "string": 34, "datetim": 34, "guid": 34, "bytestr": 34, "xmlelement": 34, "expandednodeid": 34, "qualifiednam": 34, "localizedtext": 34, "numericrang": 34, "extensionobject": 34, "datavalu": 34, "diagnosticinfo": 34, "encod": 34, "decod": 34, "json": 34, "en": 34, "namingruletyp": [34, 35], "keyvaluepair": [34, 35], "structuretyp": [34, 35], "structurefield": [34, 35], "structuredefinit": [34, 35], "argument": [34, 35], "enumvaluetyp": [34, 35], "enumfield": [34, 35], "durat": [34, 35], "utctim": [34, 35], "localeid": [34, 35], "timezonedatatyp": [34, 35], "applicationtyp": [34, 35], "applicationdescript": [34, 35], "requesthead": [34, 35], "responsehead": [34, 35], "servicefault": [34, 35], "findserversrequest": [34, 35], "findserversrespons": [34, 35], "serveronnetwork": [34, 35], "findserversonnetworkrequest": [34, 35], "findserversonnetworkrespons": [34, 35], "messagesecuritymod": [34, 35], "usertokentyp": [34, 35], "usertokenpolici": [34, 35], "endpointdescript": [34, 35], "getendpointsrequest": [34, 35], "getendpointsrespons": [34, 35], "registeredserv": [34, 35], "registerserverrequest": [34, 35], "registerserverrespons": [34, 35], "mdnsdiscoveryconfigur": [34, 35], "registerserver2request": [34, 35], "registerserver2respons": [34, 35], "securitytokenrequesttyp": [34, 35], "channelsecuritytoken": [34, 35], "opensecurechannelrequest": [34, 35], "opensecurechannelrespons": [34, 35], "closesecurechannelrequest": [34, 35], "closesecurechannelrespons": [34, 35], "signedsoftwarecertif": [34, 35], "signaturedata": [34, 35], "createsessionrequest": [34, 35], "createsessionrespons": [34, 35], "useridentitytoken": [34, 35], "anonymousidentitytoken": [34, 35], "usernameidentitytoken": [34, 35], "x509identitytoken": [34, 35], "issuedidentitytoken": [34, 35], "activatesessionrequest": [34, 35], "activatesessionrespons": [34, 35], "closesessionrequest": [34, 35], "closesessionrespons": [34, 35], "cancelrequest": [34, 35], "cancelrespons": [34, 35], "nodeattributesmask": [34, 35], "nodeattribut": [34, 35], "objectattribut": [34, 35], "variableattribut": [34, 35], "methodattribut": [34, 35], "objecttypeattribut": [34, 35], "variabletypeattribut": [34, 35], "referencetypeattribut": [34, 35], "datatypeattribut": [34, 35], "viewattribut": [34, 35], "addnodesitem": [34, 35], "addnodesresult": [34, 35], "addnodesrequest": [34, 35], "addnodesrespons": [34, 35], "addreferencesitem": [34, 35], "addreferencesrequest": [34, 35], "addreferencesrespons": [34, 35], "deletenodesitem": [34, 35], "deletenodesrequest": [34, 35], "deletenodesrespons": [34, 35], "deletereferencesitem": [34, 35], "deletereferencesrequest": [34, 35], "deletereferencesrespons": [34, 35], "browsedirect": [34, 35], "viewdescript": [34, 35], "browsedescript": [34, 35], "browseresultmask": [34, 35], "referencedescript": [34, 35], "browseresult": [34, 35], "browserequest": [34, 35], "browserespons": [34, 35], "browsenextrequest": [34, 35], "browsenextrespons": [34, 35], "relativepathel": [34, 35], "browsepath": [34, 35], "browsepathtarget": [34, 35], "browsepathresult": [34, 35], "translatebrowsepathstonodeidsrequest": [34, 35], "translatebrowsepathstonodeidsrespons": [34, 35], "registernodesrequest": [34, 35], "registernodesrespons": [34, 35], "unregisternodesrequest": [34, 35], "unregisternodesrespons": [34, 35], "filteroper": [34, 35], "contentfilterel": [34, 35], "contentfilt": [34, 35], "elementoperand": [34, 35], "literaloperand": [34, 35], "attributeoperand": [34, 35], "simpleattributeoperand": [34, 35], "contentfilterelementresult": [34, 35], "contentfilterresult": [34, 35], "timestampstoreturn": [34, 35], "readvalueid": [34, 35], "readrequest": [34, 35], "readrespons": [34, 35], "historyreadvalueid": [34, 35], "historyreadresult": [34, 35], "readrawmodifieddetail": [34, 35], "readattimedetail": [34, 35], "historydata": [34, 35], "historyreadrequest": [34, 35], "historyreadrespons": [34, 35], "writevalu": [34, 35], "writerequest": [34, 35], "writerespons": [34, 35], "historyupdatetyp": [34, 35], "performupdatetyp": [34, 35], "updatedatadetail": [34, 35], "deleterawmodifieddetail": [34, 35], "historyupdateresult": [34, 35], "historyupdaterequest": [34, 35], "historyupdaterespons": [34, 35], "callmethodrequest": [34, 35], "callmethodresult": [34, 35], "callrequest": [34, 35], "callrespons": [34, 35], "monitoringmod": [34, 35], "datachangetrigg": [34, 35], "deadbandtyp": [34, 35], "datachangefilt": [34, 35], "eventfilt": [34, 35], "aggregateconfigur": [34, 35], "aggregatefilt": [34, 35], "eventfilterresult": [34, 35], "monitoringparamet": [34, 35], "monitoreditemcreaterequest": [34, 35], "monitoreditemcreateresult": [34, 35], "createmonitoreditemsrequest": [34, 35], "createmonitoreditemsrespons": [34, 35], "monitoreditemmodifyrequest": [34, 35], "monitoreditemmodifyresult": [34, 35], "modifymonitoreditemsrequest": [34, 35], "modifymonitoreditemsrespons": [34, 35], "setmonitoringmoderequest": [34, 35], "setmonitoringmoderespons": [34, 35], "settriggeringrequest": [34, 35], "settriggeringrespons": [34, 35], "deletemonitoreditemsrequest": [34, 35], "deletemonitoreditemsrespons": [34, 35], "createsubscriptionrequest": [34, 35], "createsubscriptionrespons": [34, 35], "modifysubscriptionrequest": [34, 35], "modifysubscriptionrespons": [34, 35], "setpublishingmoderequest": [34, 35], "setpublishingmoderespons": [34, 35], "notificationmessag": [34, 35], "monitoreditemnotif": [34, 35], "eventfieldlist": [34, 35], "historyeventfieldlist": [34, 35], "statuschangenotif": [34, 35], "subscriptionacknowledg": [34, 35], "publishrequest": [34, 35], "publishrespons": [34, 35], "republishrequest": [34, 35], "republishrespons": [34, 35], "transferresult": [34, 35], "transfersubscriptionsrequest": [34, 35], "transfersubscriptionsrespons": [34, 35], "deletesubscriptionsrequest": [34, 35], "deletesubscriptionsrespons": [34, 35], "buildinfo": [34, 35], "redundancysupport": [34, 35], "serverst": [34, 35], "serverdiagnosticssummarydatatyp": [34, 35], "serverstatusdatatyp": [34, 35], "sessionsecuritydiagnosticsdatatyp": [34, 35], "servicecounterdatatyp": [34, 35], "subscriptiondiagnosticsdatatyp": [34, 35], "euinform": [34, 35], "axisscaleenumer": [34, 35], "complexnumbertyp": [34, 35], "doublecomplexnumbertyp": [34, 35], "axisinform": [34, 35], "xvtype": [34, 35], "enumdefinit": [34, 35], "readeventdetail": [34, 35], "readprocesseddetail": [34, 35], "modificationinfo": [34, 35], "historymodifieddata": [34, 35], "historyev": [34, 35], "datachangenotif": [34, 35], "eventnotificationlist": [34, 35], "sessiondiagnosticsdatatyp": [34, 35]}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 60}, "alltitles": {"Building open62541": [[0, "building-open62541"]], "Building the Library": [[0, "building-the-library"]], "Building with CMake on Ubuntu or Debian": [[0, "building-with-cmake-on-ubuntu-or-debian"]], "Building with CMake on Windows": [[0, "building-with-cmake-on-windows"]], "Building on OS X": [[0, "building-on-os-x"]], "Building on OpenBSD": [[0, "building-on-openbsd"]], "Building Debian Packages inside Docker Container with CMake on Ubuntu or Debian": [[0, "building-debian-packages-inside-docker-container-with-cmake-on-ubuntu-or-debian"]], "CMake Build Options and Debian Packaging": [[0, "cmake-build-options-and-debian-packaging"]], "Build Options": [[0, "build-options"]], "Main Build Options": [[0, "main-build-options"]], "Select build artefacts": [[0, "select-build-artefacts"]], "Detailed SDK Features": [[0, "detailed-sdk-features"]], "PubSub Build Options": [[0, "pubsub-build-options"]], "Debug Build Options": [[0, "debug-build-options"]], "Building a shared library": [[0, "building-a-shared-library"]], "Minimizing the binary size": [[0, "minimizing-the-binary-size"]], "Prebuilt packages": [[0, "prebuilt-packages"]], "Debian": [[0, "debian"]], "Arch": [[0, "arch"]], "OpenBSD": [[0, "openbsd"]], "Building the Examples": [[0, "building-the-examples"]], "Client": [[1, "client"]], "Client Configuration": [[1, "client-configuration"]], "Connection configuration": [[1, "connection-configuration"]], "Custom Data Types": [[1, "custom-data-types"], [17, "custom-data-types"]], "Advanced Client Configuration": [[1, "advanced-client-configuration"]], "Client Lifecycle": [[1, "client-lifecycle"]], "Connection Attrbiutes": [[1, "connection-attrbiutes"]], "Connect to a Server": [[1, "connect-to-a-server"]], "Discovery": [[1, "discovery"], [17, "discovery"], [17, "id5"]], "Services": [[1, "services"], [6, "services"]], "Asynchronous Services": [[1, "asynchronous-services"]], "Timed Callbacks": [[1, "timed-callbacks"], [17, "timed-callbacks"]], "Client Utility Functions": [[1, "client-utility-functions"]], "Highlevel Client Functionality": [[2, "highlevel-client-functionality"]], "Read Attributes": [[2, "read-attributes"]], "Historical Access": [[2, "historical-access"], [17, "historical-access"]], "Write Attributes": [[2, "write-attributes"]], "Method Calling": [[2, "method-calling"], [3, "method-calling"]], "Node Management": [[2, "node-management"], [3, "node-management"]], "Misc Highlevel Functionality": [[2, "misc-highlevel-functionality"]], "Async Services": [[3, "async-services"]], "Asynchronous Operations": [[3, "asynchronous-operations"]], "Read Attribute": [[3, "read-attribute"]], "Write Attribute": [[3, "write-attribute"]], "Subscriptions": [[4, "subscriptions"], [17, "subscriptions"]], "MonitoredItems": [[4, "monitoreditems"]], "Common Definitions": [[5, "common-definitions"]], "Attribute Id": [[5, "attribute-id"]], "Access Level Masks": [[5, "access-level-masks"]], "Write Masks": [[5, "write-masks"]], "ValueRank": [[5, "valuerank"], [6, "valuerank"]], "EventNotifier": [[5, "eventnotifier"]], "Rule Handling": [[5, "rule-handling"], [17, "rule-handling"]], "Order": [[5, "order"]], "Connection State": [[5, "connection-state"]], "Statistic Counters": [[5, "statistic-counters"]], "Lifecycle States": [[5, "lifecycle-states"]], "Forward Declarations": [[5, "forward-declarations"]], "Range Definition": [[5, "range-definition"], [36, "range-definition"]], "Random Number Generator": [[5, "random-number-generator"], [36, "random-number-generator"]], "Key Value Map": [[5, "key-value-map"], [36, "key-value-map"]], "Binary Connection Config Parameters": [[5, "binary-connection-config-parameters"], [36, "binary-connection-config-parameters"]], "Default Node Attributes": [[5, "default-node-attributes"], [36, "default-node-attributes"]], "Endpoint URL Parser": [[5, "endpoint-url-parser"], [36, "endpoint-url-parser"]], "Parse RelativePath Expressions": [[5, "parse-relativepath-expressions"], [36, "parse-relativepath-expressions"]], "Example RelativePaths": [[5, "example-relativepaths"], [36, "example-relativepaths"]], "Convenience macros for complex types": [[5, "convenience-macros-for-complex-types"], [36, "convenience-macros-for-complex-types"]], "Cryptography Helpers": [[5, "cryptography-helpers"], [36, "cryptography-helpers"]], "Core Concepts of OPC UA": [[6, "core-concepts-of-opc-ua"]], "Protocol": [[6, "protocol"]], "Structure of a protocol message": [[6, "structure-of-a-protocol-message"]], "Discovery Service Set": [[6, "discovery-service-set"]], "SecureChannel Service Set": [[6, "securechannel-service-set"]], "NodeManagement Service Set": [[6, "nodemanagement-service-set"]], "View Service Set": [[6, "view-service-set"]], "Query Service Set": [[6, "query-service-set"]], "Attribute Service Set": [[6, "attribute-service-set"]], "Method Service Set": [[6, "method-service-set"]], "MonitoredItem Service Set": [[6, "monitoreditem-service-set"]], "Subscription Service Set": [[6, "subscription-service-set"]], "Information Modelling": [[6, "information-modelling"]], "Node attributes for the different NodeClasses": [[6, "id11"]], "VariableNode": [[6, "variablenode"], [13, "variablenode"]], "Data Type": [[6, "data-type"]], "Array Dimensions": [[6, "array-dimensions"]], "VariableTypeNode": [[6, "variabletypenode"], [13, "variabletypenode"]], "ObjectNode": [[6, "objectnode"], [13, "objectnode"]], "ObjectTypeNode": [[6, "objecttypenode"], [13, "objecttypenode"]], "ReferenceTypeNode": [[6, "referencetypenode"], [13, "referencetypenode"]], "DataTypeNode": [[6, "datatypenode"], [13, "datatypenode"]], "MethodNode": [[6, "methodnode"], [13, "methodnode"]], "ViewNode": [[6, "viewnode"], [13, "viewnode"]], "Introduction": [[7, "introduction"]], "OPC Unified Architecture": [[7, "opc-unified-architecture"]], "open62541 Features": [[7, "open62541-features"]], "Getting Help": [[7, "getting-help"]], "Contributing": [[7, "contributing"]], "XML Nodeset Compiler": [[8, "xml-nodeset-compiler"]], "Getting started": [[8, "getting-started"]], "Creating object instances": [[8, "creating-object-instances"]], "Combination of multiple nodesets": [[8, "combination-of-multiple-nodesets"]], "Outstanding Companion Spec Issues": [[8, "outstanding-companion-spec-issues"]], "Automatic Nodesetinjection": [[8, "automatic-nodesetinjection"]], "Plugin API": [[9, "plugin-api"]], "Access Control Plugin API": [[10, "access-control-plugin-api"]], "Event Loop Subsystem": [[11, "event-loop-subsystem"]], "Timer Policies": [[11, "timer-policies"]], "Event Loop": [[11, "event-loop"]], "Event Source": [[11, "event-source"]], "Connection Manager": [[11, "connection-manager"]], "Interrupt Manager": [[11, "interrupt-manager"]], "POSIX-Specific Implementation": [[11, "posix-specific-implementation"]], "TCP Connection Manager": [[11, "tcp-connection-manager"]], "UDP Connection Manager": [[11, "udp-connection-manager"]], "Ethernet Connection Manager": [[11, "ethernet-connection-manager"]], "MQTT Connection Manager": [[11, "mqtt-connection-manager"]], "Signal Interrupt Manager": [[11, "signal-interrupt-manager"]], "Logging Plugin API": [[12, "logging-plugin-api"]], "Node Store Plugin API": [[13, "node-store-plugin-api"]], "Node Lifecycle: Constructors, Destructors and Node Contexts": [[13, "node-lifecycle-constructors-destructors-and-node-contexts"]], "Global Node Lifecycle": [[13, "global-node-lifecycle"]], "Node Type Lifecycle": [[13, "node-type-lifecycle"]], "ReferenceType Bitfield Representation": [[13, "referencetype-bitfield-representation"]], "Node Pointer": [[13, "node-pointer"]], "Base Node Attributes": [[13, "base-node-attributes"]], "Value Callback": [[13, "value-callback"]], "Node Union": [[13, "node-union"]], "Nodestore": [[13, "nodestore"]], "Public Key Infrastructure Integration": [[14, "public-key-infrastructure-integration"]], "Certificate Verification": [[14, "certificate-verification"]], "SecurityPolicy": [[15, "securitypolicy"]], "PubSub SecurityPolicy": [[15, "pubsub-securitypolicy"]], "PubSub": [[16, "pubsub"], [17, "pubsub"]], "PubSub Information Model Representation": [[16, "pubsub-information-model-representation"]], "Connections": [[16, "connections"]], "PublishedDataSets": [[16, "publisheddatasets"]], "DataSetFields": [[16, "datasetfields"]], "Custom Callback Implementation": [[16, "custom-callback-implementation"]], "WriterGroup": [[16, "writergroup"], [16, "id2"]], "DataSetWriter": [[16, "datasetwriter"]], "SubscribedDataSet": [[16, "subscribeddataset"]], "DataSetReader": [[16, "datasetreader"]], "ReaderGroup": [[16, "readergroup"]], "SecurityGroup": [[16, "securitygroup"]], "Server": [[17, "server"]], "Server Configuration": [[17, "server-configuration"]], "Server Description": [[17, "server-description"]], "Server Lifecycle": [[17, "server-lifecycle"], [17, "id3"], [27, "server-lifecycle"]], "EventLoop": [[17, "eventloop"]], "Networking": [[17, "networking"]], "Security and Encryption": [[17, "security-and-encryption"]], "Nodes and Node Lifecycle": [[17, "nodes-and-node-lifecycle"]], "Limits": [[17, "limits"]], "Async Operations": [[17, "async-operations"], [17, "id8"]], "Reverse Connect": [[17, "reverse-connect"], [17, "id10"]], "Certificate Password Callback": [[17, "certificate-password-callback"]], "Session Handling": [[17, "session-handling"]], "Reading and Writing Node Attributes": [[17, "reading-and-writing-node-attributes"]], "Browsing": [[17, "browsing"]], "Registering at a Discovery Server": [[17, "registering-at-a-discovery-server"]], "Operating a Discovery Server": [[17, "operating-a-discovery-server"]], "Information Model Callbacks": [[17, "information-model-callbacks"]], "Data Source Callback": [[17, "data-source-callback"]], "Local MonitoredItems": [[17, "local-monitoreditems"]], "Method Callbacks": [[17, "method-callbacks"]], "Interacting with Objects": [[17, "interacting-with-objects"]], "Node Addition and Deletion": [[17, "node-addition-and-deletion"]], "Reference Management": [[17, "reference-management"]], "Events": [[17, "events"]], "Alarms & Conditions (Experimental)": [[17, "alarms-conditions-experimental"]], "Update the Server Certificate at Runtime": [[17, "update-the-server-certificate-at-runtime"]], "Utility Functions": [[17, "utility-functions"]], "Statistics": [[17, "statistics"]], "StatusCodes": [[18, "statuscodes"]], "open62541 Documentation": [[19, "open62541-documentation"]], "Building a Simple Client": [[20, "building-a-simple-client"]], "Further tasks": [[20, "further-tasks"]], "Working with Data Types": [[21, "working-with-data-types"]], "Basic Data Handling": [[21, "basic-data-handling"]], "NodeIds": [[21, "nodeids"]], "Variants": [[21, "variants"]], "Working with Publish/Subscribe": [[22, "working-with-publish-subscribe"]], "Publishing Fields": [[22, "publishing-fields"]], "Subscribing Fields": [[23, "subscribing-fields"]], "Using Alarms and Conditions Server": [[24, "using-alarms-and-conditions-server"]], "Trigger Alarm events by changing States": [[24, "trigger-alarm-events-by-changing-states"]], "Connecting a Variable with a Physical Process": [[25, "connecting-a-variable-with-a-physical-process"]], "Updating variables manually": [[25, "updating-variables-manually"]], "Variable Value Callback": [[25, "variable-value-callback"]], "Variable Data Sources": [[25, "variable-data-sources"]], "Generating events": [[26, "generating-events"]], "Emitting events by calling methods": [[26, "emitting-events-by-calling-methods"]], "Setting up an event": [[26, "setting-up-an-event"]], "Triggering an event": [[26, "triggering-an-event"]], "Building a Simple Server": [[27, "building-a-simple-server"]], "Server Configuration and Plugins": [[27, "server-configuration-and-plugins"]], "Adding Methods to Objects": [[28, "adding-methods-to-objects"]], "Example: Hello World Method": [[28, "example-hello-world-method"]], "Increase Array Values Method": [[28, "increase-array-values-method"]], "Observing Attributes with Local MonitoredItems": [[29, "observing-attributes-with-local-monitoreditems"]], "Working with Objects and Object Types": [[30, "working-with-objects-and-object-types"]], "Using objects to structure information models": [[30, "using-objects-to-structure-information-models"]], "Object types, type hierarchies and instantiation": [[30, "object-types-type-hierarchies-and-instantiation"]], "Adding Variables to a Server": [[31, "adding-variables-to-a-server"]], "Working with Variable Types": [[32, "working-with-variable-types"]], "Tutorials": [[33, "tutorials"]], "Data Types": [[34, "data-types"]], "Builtin Types": [[34, "builtin-types"]], "Boolean": [[34, "boolean"]], "SByte": [[34, "sbyte"]], "Byte": [[34, "byte"]], "Int16": [[34, "int16"]], "UInt16": [[34, "uint16"]], "Int32": [[34, "int32"]], "UInt32": [[34, "uint32"]], "Int64": [[34, "int64"]], "UInt64": [[34, "uint64"]], "Float": [[34, "float"]], "Double": [[34, "double"]], "StatusCode": [[34, "statuscode"]], "String": [[34, "string"]], "DateTime": [[34, "datetime"]], "Guid": [[34, "guid"]], "ByteString": [[34, "bytestring"]], "XmlElement": [[34, "xmlelement"]], "NodeId": [[34, "nodeid"]], "ExpandedNodeId": [[34, "expandednodeid"]], "QualifiedName": [[34, "qualifiedname"]], "LocalizedText": [[34, "localizedtext"]], "NumericRange": [[34, "numericrange"]], "Variant": [[34, "variant"]], "ExtensionObject": [[34, "extensionobject"]], "DataValue": [[34, "datavalue"]], "DiagnosticInfo": [[34, "diagnosticinfo"]], "Generic Type Handling": [[34, "generic-type-handling"]], "Binary Encoding/Decoding": [[34, "binary-encoding-decoding"]], "JSON En/Decoding": [[34, "json-en-decoding"]], "XML En/Decoding": [[34, "xml-en-decoding"]], "Array handling": [[34, "array-handling"]], "Generated Data Type Definitions": [[34, "generated-data-type-definitions"]], "NamingRuleType": [[34, "namingruletype"], [35, "namingruletype"]], "KeyValuePair": [[34, "keyvaluepair"], [35, "keyvaluepair"]], "NodeClass": [[34, "nodeclass"], [35, "nodeclass"]], "StructureType": [[34, "structuretype"], [35, "structuretype"]], "StructureField": [[34, "structurefield"], [35, "structurefield"]], "StructureDefinition": [[34, "structuredefinition"], [35, "structuredefinition"]], "Argument": [[34, "argument"], [35, "argument"]], "EnumValueType": [[34, "enumvaluetype"], [35, "enumvaluetype"]], "EnumField": [[34, "enumfield"], [35, "enumfield"]], "Duration": [[34, "duration"], [35, "duration"]], "UtcTime": [[34, "utctime"], [35, "utctime"]], "LocaleId": [[34, "localeid"], [35, "localeid"]], "TimeZoneDataType": [[34, "timezonedatatype"], [35, "timezonedatatype"]], "ApplicationType": [[34, "applicationtype"], [35, "applicationtype"]], "ApplicationDescription": [[34, "applicationdescription"], [35, "applicationdescription"]], "RequestHeader": [[34, "requestheader"], [35, "requestheader"]], "ResponseHeader": [[34, "responseheader"], [35, "responseheader"]], "ServiceFault": [[34, "servicefault"], [35, "servicefault"]], "FindServersRequest": [[34, "findserversrequest"], [35, "findserversrequest"]], "FindServersResponse": [[34, "findserversresponse"], [35, "findserversresponse"]], "ServerOnNetwork": [[34, "serveronnetwork"], [35, "serveronnetwork"]], "FindServersOnNetworkRequest": [[34, "findserversonnetworkrequest"], [35, "findserversonnetworkrequest"]], "FindServersOnNetworkResponse": [[34, "findserversonnetworkresponse"], [35, "findserversonnetworkresponse"]], "MessageSecurityMode": [[34, "messagesecuritymode"], [35, "messagesecuritymode"]], "UserTokenType": [[34, "usertokentype"], [35, "usertokentype"]], "UserTokenPolicy": [[34, "usertokenpolicy"], [35, "usertokenpolicy"]], "EndpointDescription": [[34, "endpointdescription"], [35, "endpointdescription"]], "GetEndpointsRequest": [[34, "getendpointsrequest"], [35, "getendpointsrequest"]], "GetEndpointsResponse": [[34, "getendpointsresponse"], [35, "getendpointsresponse"]], "RegisteredServer": [[34, "registeredserver"], [35, "registeredserver"]], "RegisterServerRequest": [[34, "registerserverrequest"], [35, "registerserverrequest"]], "RegisterServerResponse": [[34, "registerserverresponse"], [35, "registerserverresponse"]], "MdnsDiscoveryConfiguration": [[34, "mdnsdiscoveryconfiguration"], [35, "mdnsdiscoveryconfiguration"]], "RegisterServer2Request": [[34, "registerserver2request"], [35, "registerserver2request"]], "RegisterServer2Response": [[34, "registerserver2response"], [35, "registerserver2response"]], "SecurityTokenRequestType": [[34, "securitytokenrequesttype"], [35, "securitytokenrequesttype"]], "ChannelSecurityToken": [[34, "channelsecuritytoken"], [35, "channelsecuritytoken"]], "OpenSecureChannelRequest": [[34, "opensecurechannelrequest"], [35, "opensecurechannelrequest"]], "OpenSecureChannelResponse": [[34, "opensecurechannelresponse"], [35, "opensecurechannelresponse"]], "CloseSecureChannelRequest": [[34, "closesecurechannelrequest"], [35, "closesecurechannelrequest"]], "CloseSecureChannelResponse": [[34, "closesecurechannelresponse"], [35, "closesecurechannelresponse"]], "SignedSoftwareCertificate": [[34, "signedsoftwarecertificate"], [35, "signedsoftwarecertificate"]], "SignatureData": [[34, "signaturedata"], [35, "signaturedata"]], "CreateSessionRequest": [[34, "createsessionrequest"], [35, "createsessionrequest"]], "CreateSessionResponse": [[34, "createsessionresponse"], [35, "createsessionresponse"]], "UserIdentityToken": [[34, "useridentitytoken"], [35, "useridentitytoken"]], "AnonymousIdentityToken": [[34, "anonymousidentitytoken"], [35, "anonymousidentitytoken"]], "UserNameIdentityToken": [[34, "usernameidentitytoken"], [35, "usernameidentitytoken"]], "X509IdentityToken": [[34, "x509identitytoken"], [35, "x509identitytoken"]], "IssuedIdentityToken": [[34, "issuedidentitytoken"], [35, "issuedidentitytoken"]], "ActivateSessionRequest": [[34, "activatesessionrequest"], [35, "activatesessionrequest"]], "ActivateSessionResponse": [[34, "activatesessionresponse"], [35, "activatesessionresponse"]], "CloseSessionRequest": [[34, "closesessionrequest"], [35, "closesessionrequest"]], "CloseSessionResponse": [[34, "closesessionresponse"], [35, "closesessionresponse"]], "CancelRequest": [[34, "cancelrequest"], [35, "cancelrequest"]], "CancelResponse": [[34, "cancelresponse"], [35, "cancelresponse"]], "NodeAttributesMask": [[34, "nodeattributesmask"], [35, "nodeattributesmask"]], "NodeAttributes": [[34, "nodeattributes"], [35, "nodeattributes"]], "ObjectAttributes": [[34, "objectattributes"], [35, "objectattributes"]], "VariableAttributes": [[34, "variableattributes"], [35, "variableattributes"]], "MethodAttributes": [[34, "methodattributes"], [35, "methodattributes"]], "ObjectTypeAttributes": [[34, "objecttypeattributes"], [35, "objecttypeattributes"]], "VariableTypeAttributes": [[34, "variabletypeattributes"], [35, "variabletypeattributes"]], "ReferenceTypeAttributes": [[34, "referencetypeattributes"], [35, "referencetypeattributes"]], "DataTypeAttributes": [[34, "datatypeattributes"], [35, "datatypeattributes"]], "ViewAttributes": [[34, "viewattributes"], [35, "viewattributes"]], "AddNodesItem": [[34, "addnodesitem"], [35, "addnodesitem"]], "AddNodesResult": [[34, "addnodesresult"], [35, "addnodesresult"]], "AddNodesRequest": [[34, "addnodesrequest"], [35, "addnodesrequest"]], "AddNodesResponse": [[34, "addnodesresponse"], [35, "addnodesresponse"]], "AddReferencesItem": [[34, "addreferencesitem"], [35, "addreferencesitem"]], "AddReferencesRequest": [[34, "addreferencesrequest"], [35, "addreferencesrequest"]], "AddReferencesResponse": [[34, "addreferencesresponse"], [35, "addreferencesresponse"]], "DeleteNodesItem": [[34, "deletenodesitem"], [35, "deletenodesitem"]], "DeleteNodesRequest": [[34, "deletenodesrequest"], [35, "deletenodesrequest"]], "DeleteNodesResponse": [[34, "deletenodesresponse"], [35, "deletenodesresponse"]], "DeleteReferencesItem": [[34, "deletereferencesitem"], [35, "deletereferencesitem"]], "DeleteReferencesRequest": [[34, "deletereferencesrequest"], [35, "deletereferencesrequest"]], "DeleteReferencesResponse": [[34, "deletereferencesresponse"], [35, "deletereferencesresponse"]], "BrowseDirection": [[34, "browsedirection"], [35, "browsedirection"]], "ViewDescription": [[34, "viewdescription"], [35, "viewdescription"]], "BrowseDescription": [[34, "browsedescription"], [35, "browsedescription"]], "BrowseResultMask": [[34, "browseresultmask"], [35, "browseresultmask"]], "ReferenceDescription": [[34, "referencedescription"], [35, "referencedescription"]], "BrowseResult": [[34, "browseresult"], [35, "browseresult"]], "BrowseRequest": [[34, "browserequest"], [35, "browserequest"]], "BrowseResponse": [[34, "browseresponse"], [35, "browseresponse"]], "BrowseNextRequest": [[34, "browsenextrequest"], [35, "browsenextrequest"]], "BrowseNextResponse": [[34, "browsenextresponse"], [35, "browsenextresponse"]], "RelativePathElement": [[34, "relativepathelement"], [35, "relativepathelement"]], "RelativePath": [[34, "relativepath"], [35, "relativepath"]], "BrowsePath": [[34, "browsepath"], [35, "browsepath"]], "BrowsePathTarget": [[34, "browsepathtarget"], [35, "browsepathtarget"]], "BrowsePathResult": [[34, "browsepathresult"], [35, "browsepathresult"]], "TranslateBrowsePathsToNodeIdsRequest": [[34, "translatebrowsepathstonodeidsrequest"], [35, "translatebrowsepathstonodeidsrequest"]], "TranslateBrowsePathsToNodeIdsResponse": [[34, "translatebrowsepathstonodeidsresponse"], [35, "translatebrowsepathstonodeidsresponse"]], "RegisterNodesRequest": [[34, "registernodesrequest"], [35, "registernodesrequest"]], "RegisterNodesResponse": [[34, "registernodesresponse"], [35, "registernodesresponse"]], "UnregisterNodesRequest": [[34, "unregisternodesrequest"], [35, "unregisternodesrequest"]], "UnregisterNodesResponse": [[34, "unregisternodesresponse"], [35, "unregisternodesresponse"]], "FilterOperator": [[34, "filteroperator"], [35, "filteroperator"]], "ContentFilterElement": [[34, "contentfilterelement"], [35, "contentfilterelement"]], "ContentFilter": [[34, "contentfilter"], [35, "contentfilter"]], "ElementOperand": [[34, "elementoperand"], [35, "elementoperand"]], "LiteralOperand": [[34, "literaloperand"], [35, "literaloperand"]], "AttributeOperand": [[34, "attributeoperand"], [35, "attributeoperand"]], "SimpleAttributeOperand": [[34, "simpleattributeoperand"], [35, "simpleattributeoperand"]], "ContentFilterElementResult": [[34, "contentfilterelementresult"], [35, "contentfilterelementresult"]], "ContentFilterResult": [[34, "contentfilterresult"], [35, "contentfilterresult"]], "TimestampsToReturn": [[34, "timestampstoreturn"], [35, "timestampstoreturn"]], "ReadValueId": [[34, "readvalueid"], [35, "readvalueid"]], "ReadRequest": [[34, "readrequest"], [35, "readrequest"]], "ReadResponse": [[34, "readresponse"], [35, "readresponse"]], "HistoryReadValueId": [[34, "historyreadvalueid"], [35, "historyreadvalueid"]], "HistoryReadResult": [[34, "historyreadresult"], [35, "historyreadresult"]], "ReadRawModifiedDetails": [[34, "readrawmodifieddetails"], [35, "readrawmodifieddetails"]], "ReadAtTimeDetails": [[34, "readattimedetails"], [35, "readattimedetails"]], "HistoryData": [[34, "historydata"], [35, "historydata"]], "HistoryReadRequest": [[34, "historyreadrequest"], [35, "historyreadrequest"]], "HistoryReadResponse": [[34, "historyreadresponse"], [35, "historyreadresponse"]], "WriteValue": [[34, "writevalue"], [35, "writevalue"]], "WriteRequest": [[34, "writerequest"], [35, "writerequest"]], "WriteResponse": [[34, "writeresponse"], [35, "writeresponse"]], "HistoryUpdateType": [[34, "historyupdatetype"], [35, "historyupdatetype"]], "PerformUpdateType": [[34, "performupdatetype"], [35, "performupdatetype"]], "UpdateDataDetails": [[34, "updatedatadetails"], [35, "updatedatadetails"]], "DeleteRawModifiedDetails": [[34, "deleterawmodifieddetails"], [35, "deleterawmodifieddetails"]], "HistoryUpdateResult": [[34, "historyupdateresult"], [35, "historyupdateresult"]], "HistoryUpdateRequest": [[34, "historyupdaterequest"], [35, "historyupdaterequest"]], "HistoryUpdateResponse": [[34, "historyupdateresponse"], [35, "historyupdateresponse"]], "CallMethodRequest": [[34, "callmethodrequest"], [35, "callmethodrequest"]], "CallMethodResult": [[34, "callmethodresult"], [35, "callmethodresult"]], "CallRequest": [[34, "callrequest"], [35, "callrequest"]], "CallResponse": [[34, "callresponse"], [35, "callresponse"]], "MonitoringMode": [[34, "monitoringmode"], [35, "monitoringmode"]], "DataChangeTrigger": [[34, "datachangetrigger"], [35, "datachangetrigger"]], "DeadbandType": [[34, "deadbandtype"], [35, "deadbandtype"]], "DataChangeFilter": [[34, "datachangefilter"], [35, "datachangefilter"]], "EventFilter": [[34, "eventfilter"], [35, "eventfilter"]], "AggregateConfiguration": [[34, "aggregateconfiguration"], [35, "aggregateconfiguration"]], "AggregateFilter": [[34, "aggregatefilter"], [35, "aggregatefilter"]], "EventFilterResult": [[34, "eventfilterresult"], [35, "eventfilterresult"]], "MonitoringParameters": [[34, "monitoringparameters"], [35, "monitoringparameters"]], "MonitoredItemCreateRequest": [[34, "monitoreditemcreaterequest"], [35, "monitoreditemcreaterequest"]], "MonitoredItemCreateResult": [[34, "monitoreditemcreateresult"], [35, "monitoreditemcreateresult"]], "CreateMonitoredItemsRequest": [[34, "createmonitoreditemsrequest"], [35, "createmonitoreditemsrequest"]], "CreateMonitoredItemsResponse": [[34, "createmonitoreditemsresponse"], [35, "createmonitoreditemsresponse"]], "MonitoredItemModifyRequest": [[34, "monitoreditemmodifyrequest"], [35, "monitoreditemmodifyrequest"]], "MonitoredItemModifyResult": [[34, "monitoreditemmodifyresult"], [35, "monitoreditemmodifyresult"]], "ModifyMonitoredItemsRequest": [[34, "modifymonitoreditemsrequest"], [35, "modifymonitoreditemsrequest"]], "ModifyMonitoredItemsResponse": [[34, "modifymonitoreditemsresponse"], [35, "modifymonitoreditemsresponse"]], "SetMonitoringModeRequest": [[34, "setmonitoringmoderequest"], [35, "setmonitoringmoderequest"]], "SetMonitoringModeResponse": [[34, "setmonitoringmoderesponse"], [35, "setmonitoringmoderesponse"]], "SetTriggeringRequest": [[34, "settriggeringrequest"], [35, "settriggeringrequest"]], "SetTriggeringResponse": [[34, "settriggeringresponse"], [35, "settriggeringresponse"]], "DeleteMonitoredItemsRequest": [[34, "deletemonitoreditemsrequest"], [35, "deletemonitoreditemsrequest"]], "DeleteMonitoredItemsResponse": [[34, "deletemonitoreditemsresponse"], [35, "deletemonitoreditemsresponse"]], "CreateSubscriptionRequest": [[34, "createsubscriptionrequest"], [35, "createsubscriptionrequest"]], "CreateSubscriptionResponse": [[34, "createsubscriptionresponse"], [35, "createsubscriptionresponse"]], "ModifySubscriptionRequest": [[34, "modifysubscriptionrequest"], [35, "modifysubscriptionrequest"]], "ModifySubscriptionResponse": [[34, "modifysubscriptionresponse"], [35, "modifysubscriptionresponse"]], "SetPublishingModeRequest": [[34, "setpublishingmoderequest"], [35, "setpublishingmoderequest"]], "SetPublishingModeResponse": [[34, "setpublishingmoderesponse"], [35, "setpublishingmoderesponse"]], "NotificationMessage": [[34, "notificationmessage"], [35, "notificationmessage"]], "MonitoredItemNotification": [[34, "monitoreditemnotification"], [35, "monitoreditemnotification"]], "EventFieldList": [[34, "eventfieldlist"], [35, "eventfieldlist"]], "HistoryEventFieldList": [[34, "historyeventfieldlist"], [35, "historyeventfieldlist"]], "StatusChangeNotification": [[34, "statuschangenotification"], [35, "statuschangenotification"]], "SubscriptionAcknowledgement": [[34, "subscriptionacknowledgement"], [35, "subscriptionacknowledgement"]], "PublishRequest": [[34, "publishrequest"], [35, "publishrequest"]], "PublishResponse": [[34, "publishresponse"], [35, "publishresponse"]], "RepublishRequest": [[34, "republishrequest"], [35, "republishrequest"]], "RepublishResponse": [[34, "republishresponse"], [35, "republishresponse"]], "TransferResult": [[34, "transferresult"], [35, "transferresult"]], "TransferSubscriptionsRequest": [[34, "transfersubscriptionsrequest"], [35, "transfersubscriptionsrequest"]], "TransferSubscriptionsResponse": [[34, "transfersubscriptionsresponse"], [35, "transfersubscriptionsresponse"]], "DeleteSubscriptionsRequest": [[34, "deletesubscriptionsrequest"], [35, "deletesubscriptionsrequest"]], "DeleteSubscriptionsResponse": [[34, "deletesubscriptionsresponse"], [35, "deletesubscriptionsresponse"]], "BuildInfo": [[34, "buildinfo"], [35, "buildinfo"]], "RedundancySupport": [[34, "redundancysupport"], [35, "redundancysupport"]], "ServerState": [[34, "serverstate"], [35, "serverstate"]], "ServerDiagnosticsSummaryDataType": [[34, "serverdiagnosticssummarydatatype"], [35, "serverdiagnosticssummarydatatype"]], "ServerStatusDataType": [[34, "serverstatusdatatype"], [35, "serverstatusdatatype"]], "SessionSecurityDiagnosticsDataType": [[34, "sessionsecuritydiagnosticsdatatype"], [35, "sessionsecuritydiagnosticsdatatype"]], "ServiceCounterDataType": [[34, "servicecounterdatatype"], [35, "servicecounterdatatype"]], "SubscriptionDiagnosticsDataType": [[34, "subscriptiondiagnosticsdatatype"], [35, "subscriptiondiagnosticsdatatype"]], "Range": [[34, "range"], [35, "range"]], "EUInformation": [[34, "euinformation"], [35, "euinformation"]], "AxisScaleEnumeration": [[34, "axisscaleenumeration"], [35, "axisscaleenumeration"]], "ComplexNumberType": [[34, "complexnumbertype"], [35, "complexnumbertype"]], "DoubleComplexNumberType": [[34, "doublecomplexnumbertype"], [35, "doublecomplexnumbertype"]], "AxisInformation": [[34, "axisinformation"], [35, "axisinformation"]], "XVType": [[34, "xvtype"], [35, "xvtype"]], "EnumDefinition": [[34, "enumdefinition"], [35, "enumdefinition"]], "ReadEventDetails": [[34, "readeventdetails"], [35, "readeventdetails"]], "ReadProcessedDetails": [[34, "readprocesseddetails"], [35, "readprocesseddetails"]], "ModificationInfo": [[34, "modificationinfo"], [35, "modificationinfo"]], "HistoryModifiedData": [[34, "historymodifieddata"], [35, "historymodifieddata"]], "HistoryEvent": [[34, "historyevent"], [35, "historyevent"]], "DataChangeNotification": [[34, "datachangenotification"], [35, "datachangenotification"]], "EventNotificationList": [[34, "eventnotificationlist"], [35, "eventnotificationlist"]], "SessionDiagnosticsDataType": [[34, "sessiondiagnosticsdatatype"], [35, "sessiondiagnosticsdatatype"]]}, "indexentries": {}}) \ No newline at end of file diff --git a/static/doc/v1.4.0/server.html b/static/doc/v1.4.0/server.html new file mode 100644 index 0000000000..577bab1e4b --- /dev/null +++ b/static/doc/v1.4.0/server.html @@ -0,0 +1,2078 @@ + + + + + + + Server — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Server

+
+

Server Configuration

+

The configuration structure is passed to the server during initialization. +The server expects that the configuration is not modified during runtime. +Currently, only one server can use a configuration at a time. During +shutdown, the server will clean up the parts of the configuration that are +modified at runtime through the provided API.

+

Examples for configurations are provided in the /plugins folder. +The usual usage is as follows:

+
    +
  1. Create a server configuration with default settings as a starting point

  2. +
  3. Modifiy the configuration, e.g. by adding a server certificate

  4. +
  5. Instantiate a server with it

  6. +
  7. After shutdown of the server, clean up the configuration (free memory)

  8. +
+

The Tutorials provide a good starting point for this.

+
struct UA_ServerConfig {
+    void *context; /* Used to attach custom data to a server config. This can
+                    * then be retrieved e.g. in a callback that forwards a
+                    * pointer to the server. */
+    UA_Logger *logging; /* Plugin for log output */
+
+
+
+

Server Description

+

The description must be internally consistent. The ApplicationUri set in +the ApplicationDescription must match the URI set in the server +certificate. +The applicationType is not just descriptive, it changes the actual +functionality of the server. The RegisterServer service is available only +if the server is a DiscoveryServer and the applicationType is set to the +appropriate value.*/

+
+
+

Server Lifecycle

+
/* Delay in ms from the shutdown signal (ctrl-c) until the actual shutdown.
+ * Clients need to be able to get a notification ahead of time. */
+UA_Double shutdownDelay;
+
+/* If an asynchronous server shutdown is used, this callback notifies about
+ * the current lifecycle state (notably the STOPPING -> STOPPED
+ * transition). */
+void (*notifyLifecycleState)(UA_Server *server, UA_LifecycleState state);
+
+
+
+
+

Rule Handling

+

Override the handling of standard-defined behavior. These settings are +used to balance the following contradicting requirements:

+
    +
  • Strict conformance with the standard (for certification).

  • +
  • Ensure interoperability with old/non-conforming implementations +encountered in the wild.

  • +
+

The defaults are set for compatibility with the largest number of OPC UA +vendors (with log warnings activated). Cf. Postel’s Law “be conservative +in what you send, be liberal in what you accept”.

+

See the section Rule Handling for the possible settings.

+
/* Verify that the server sends a timestamp in the request header */
+UA_RuleHandling verifyRequestTimestamp;
+
+/* Variables (that don't have a DataType of BaseDataType) must not have an
+ * empty variant value. The default behaviour is to auto-create a matching
+ * zeroed-out value for empty VariableNodes when they are added. */
+UA_RuleHandling allowEmptyVariables;
+
+
+
+
+

Custom Data Types

+

The following is a linked list of arrays with custom data types. All data +types that are accessible from here are automatically considered for the +decoding of received messages. Custom data types are not cleaned up +together with the configuration. So it is possible to allocate them on +ROM.

+

See the section on Generic Type Handling. Examples for working with custom +data types are provided in /examples/custom_datatype/.

+
const UA_DataTypeArray *customDataTypes;
+
+
+
+

Note

+

See the section on Generic Type Handling. Examples for working +with custom data types are provided in +/examples/custom_datatype/.

+
+

+
+
+
+
+

EventLoop

+

The sever can be plugged into an external EventLoop. Otherwise the +EventLoop is considered to be attached to the server’s lifecycle and will +be destroyed when the config is cleaned up.

+
UA_EventLoop *eventLoop;
+UA_Boolean externalEventLoop; /* The EventLoop is not deleted with the config */
+
+
+
+
+

Networking

+

The severUrls array contains the server URLs like +opc.tcp://my-server:4840 or opc.wss://localhost:443. The URLs are +used both for discovery and to set up the server sockets based on the +defined hostnames (and ports).

+
    +
  • If the list is empty: Listen on all network interfaces with TCP port 4840.

  • +
  • If the hostname of a URL is empty: Use the define protocol and port and +listen on all interfaces.

  • +
+
UA_String *serverUrls;
+size_t serverUrlsSize;
+
+
+

The following settings are specific to OPC UA with TCP transport.

+
UA_Boolean tcpEnabled;
+UA_UInt32 tcpBufSize;    /* Max length of sent and received chunks (packets)
+                          * (default: 64kB) */
+UA_UInt32 tcpMaxMsgSize; /* Max length of messages
+                          * (default: 0 -> unbounded) */
+UA_UInt32 tcpMaxChunks;  /* Max number of chunks per message
+                          * (default: 0 -> unbounded) */
+UA_Boolean tcpReuseAddr;
+
+
+
+
+

Security and Encryption

+
size_t securityPoliciesSize;
+UA_SecurityPolicy* securityPolicies;
+
+/* Endpoints with combinations of SecurityPolicy and SecurityMode. If the
+ * UserIdentityToken array of the Endpoint is not set, then it will be
+ * filled by the server for all UserTokenPolicies that are configured in the
+ * AccessControl plugin. */
+size_t endpointsSize;
+UA_EndpointDescription *endpoints;
+
+/* Only allow the following discovery services to be executed on a
+ * SecureChannel with SecurityPolicyNone: GetEndpointsRequest,
+ * FindServersRequest and FindServersOnNetworkRequest.
+ *
+ * Only enable this option if there is no endpoint with SecurityPolicy#None
+ * in the endpoints list. The SecurityPolicy#None must be present in the
+ * securityPolicies list. */
+UA_Boolean securityPolicyNoneDiscoveryOnly;
+
+/* Allow clients without encryption support to connect with username and password.
+ * This requires to transmit the password in plain text over the network which is
+ * why this option is disabled by default.
+ * Make sure you really need this before enabling plain text passwords. */
+UA_Boolean allowNonePolicyPassword;
+
+/* Different sets of certificates are trusted for SecureChannel / Session */
+UA_CertificateVerification secureChannelPKI;
+UA_CertificateVerification sessionPKI;
+
+
+

See the section for access-control +handling.

+
UA_AccessControl accessControl;
+
+
+
+
+

Nodes and Node Lifecycle

+

See the section for node lifecycle handling.

+
UA_Nodestore nodestore;
+UA_GlobalNodeLifecycle nodeLifecycle;
+
+
+

Copy the HasModellingRule reference in instances from the type +definition in UA_Server_addObjectNode and UA_Server_addVariableNode.

+

Part 3 - 6.4.4: […] it is not required that newly created or referenced +instances based on InstanceDeclarations have a ModellingRule, however, it +is allowed that they have any ModellingRule independent of the +ModellingRule of their InstanceDeclaration

+
UA_Boolean modellingRulesOnInstances;
+
+
+
+
+

Limits

+
/* Limits for SecureChannels */
+UA_UInt16 maxSecureChannels;
+UA_UInt32 maxSecurityTokenLifetime; /* in ms */
+
+/* Limits for Sessions */
+UA_UInt16 maxSessions;
+UA_Double maxSessionTimeout; /* in ms */
+
+/* Operation limits */
+UA_UInt32 maxNodesPerRead;
+UA_UInt32 maxNodesPerWrite;
+UA_UInt32 maxNodesPerMethodCall;
+UA_UInt32 maxNodesPerBrowse;
+UA_UInt32 maxNodesPerRegisterNodes;
+UA_UInt32 maxNodesPerTranslateBrowsePathsToNodeIds;
+UA_UInt32 maxNodesPerNodeManagement;
+UA_UInt32 maxMonitoredItemsPerCall;
+
+/* Limits for Requests */
+UA_UInt32 maxReferencesPerNode;
+
+
+
+
+

Async Operations

+

See the section for async operations.

+
#if UA_MULTITHREADING >= 100
+    UA_Double asyncOperationTimeout; /* in ms, 0 => unlimited */
+    size_t maxAsyncOperationQueueSize; /* 0 => unlimited */
+    /* Notify workers when an async operation was enqueued */
+    UA_Server_AsyncOperationNotifyCallback asyncOperationNotifyCallback;
+#endif
+
+
+
+
+

Discovery

+
#ifdef UA_ENABLE_DISCOVERY
+    /* Timeout in seconds when to automatically remove a registered server from
+     * the list, if it doesn't re-register within the given time frame. A value
+     * of 0 disables automatic removal. Default is 60 Minutes (60*60). Must be
+     * bigger than 10 seconds, because cleanup is only triggered approximately
+     * every 10 seconds. The server will still be removed depending on the
+     * state of the semaphore file. */
+    UA_UInt32 discoveryCleanupTimeout;
+
+# ifdef UA_ENABLE_DISCOVERY_MULTICAST
+    UA_Boolean mdnsEnabled;
+    UA_MdnsDiscoveryConfiguration mdnsConfig;
+    UA_String mdnsInterfaceIP;
+#  if !defined(UA_HAS_GETIFADDR)
+    size_t mdnsIpAddressListSize;
+    UA_UInt32 *mdnsIpAddressList;
+#  endif
+# endif
+#endif
+
+
+
+
+

Subscriptions

+
    UA_Boolean subscriptionsEnabled;
+#ifdef UA_ENABLE_SUBSCRIPTIONS
+    /* Limits for Subscriptions */
+    UA_UInt32 maxSubscriptions;
+    UA_UInt32 maxSubscriptionsPerSession;
+    UA_DurationRange publishingIntervalLimits; /* in ms (must not be less than 5) */
+    UA_UInt32Range lifeTimeCountLimits;
+    UA_UInt32Range keepAliveCountLimits;
+    UA_UInt32 maxNotificationsPerPublish;
+    UA_Boolean enableRetransmissionQueue;
+    UA_UInt32 maxRetransmissionQueueSize; /* 0 -> unlimited size */
+# ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
+    UA_UInt32 maxEventsPerNode; /* 0 -> unlimited size */
+# endif
+
+    /* Limits for MonitoredItems */
+    UA_UInt32 maxMonitoredItems;
+    UA_UInt32 maxMonitoredItemsPerSubscription;
+    UA_DurationRange samplingIntervalLimits; /* in ms (must not be less than 5) */
+    UA_UInt32Range queueSizeLimits; /* Negotiated with the client */
+
+    /* Limits for PublishRequests */
+    UA_UInt32 maxPublishReqPerSession;
+
+    /* Register MonitoredItem in Userland
+     *
+     * @param server Allows the access to the server object
+     * @param sessionId The session id, represented as an node id
+     * @param sessionContext An optional pointer to user-defined data for the
+     *        specific data source
+     * @param nodeid Id of the node in question
+     * @param nodeidContext An optional pointer to user-defined data, associated
+     *        with the node in the nodestore. Note that, if the node has already
+     *        been removed, this value contains a NULL pointer.
+     * @param attributeId Identifies which attribute (value, data type etc.) is
+     *        monitored
+     * @param removed Determines if the MonitoredItem was removed or created. */
+    void (*monitoredItemRegisterCallback)(UA_Server *server,
+                                          const UA_NodeId *sessionId,
+                                          void *sessionContext,
+                                          const UA_NodeId *nodeId,
+                                          void *nodeContext,
+                                          UA_UInt32 attibuteId,
+                                          UA_Boolean removed);
+#endif
+
+
+
+
+

PubSub

+
    UA_Boolean pubsubEnabled;
+#ifdef UA_ENABLE_PUBSUB
+    UA_PubSubConfiguration pubSubConfig;
+#endif
+
+
+
+
+

Historical Access

+
    UA_Boolean historizingEnabled;
+#ifdef UA_ENABLE_HISTORIZING
+    UA_HistoryDatabase historyDatabase;
+
+    UA_Boolean accessHistoryDataCapability;
+    UA_UInt32  maxReturnDataValues; /* 0 -> unlimited size */
+
+    UA_Boolean accessHistoryEventsCapability;
+    UA_UInt32  maxReturnEventValues; /* 0 -> unlimited size */
+
+    UA_Boolean insertDataCapability;
+    UA_Boolean insertEventCapability;
+    UA_Boolean insertAnnotationsCapability;
+
+    UA_Boolean replaceDataCapability;
+    UA_Boolean replaceEventCapability;
+
+    UA_Boolean updateDataCapability;
+    UA_Boolean updateEventCapability;
+
+    UA_Boolean deleteRawCapability;
+    UA_Boolean deleteEventCapability;
+    UA_Boolean deleteAtTimeDataCapability;
+#endif
+
+
+
+
+

Reverse Connect

+
UA_UInt32 reverseReconnectInterval; /* Default is 15000 ms */
+
+
+
+
+

Certificate Password Callback

+
#ifdef UA_ENABLE_ENCRYPTION
+    /* If the private key is in PEM format and password protected, this callback
+     * is called during initialization to get the password to decrypt the
+     * private key. The memory containing the password is freed by the client
+     * after use. The callback should be set early, other parts of the client
+     * config setup may depend on it. */
+    UA_StatusCode (*privateKeyPasswordCallback)(UA_ServerConfig *sc,
+                                                UA_ByteString *password);
+#endif
+};
+
+void
+UA_ServerConfig_clean(UA_ServerConfig *config);
+
+
+
+
+
+

Server Lifecycle

+
/* Create a new server with a default configuration that adds plugins for
+ * networking, security, logging and so on. See `server_config_default.h` for
+ * more detailed options.
+ *
+ * The default configuration can be used as the starting point to adjust the
+ * server configuration to individual needs. UA_Server_new is implemented in the
+ * /plugins folder under the CC0 license. Furthermore the server confiugration
+ * only uses the public server API.
+ *
+ * @return Returns the configured server or NULL if an error occurs. */
+UA_Server *
+UA_Server_new(void);
+
+/* Creates a new server. Moves the config into the server with a shallow copy.
+ * The config content is cleared together with the server. */
+UA_Server *
+UA_Server_newWithConfig(UA_ServerConfig *config);
+
+/* Delete the server. */
+UA_StatusCode
+UA_Server_delete(UA_Server *server);
+
+/* Get the configuration. Always succeeds as this simplfy resolves a pointer.
+ * Attention! Do not adjust the configuration while the server is running! */
+UA_ServerConfig *
+UA_Server_getConfig(UA_Server *server);
+
+/* Get the current server lifecycle state */
+UA_LifecycleState
+UA_Server_getLifecycleState(UA_Server *server);
+
+/* Runs the server until interrupted. On Unix/Windows this registers an
+ * interrupt for SIGINT (ctrl-c). The method only returns after having received
+ * the interrupt. The logical sequence is as follows:
+ *
+ * - UA_Server_run_startup
+ * - Loop until interrupt: UA_Server_run_iterate
+ * - UA_Server_run_shutdown
+ *
+ * @param server The server object.
+ * @return Returns a bad statuscode if an error occurred internally. */
+UA_StatusCode
+UA_Server_run(UA_Server *server, const volatile UA_Boolean *running);
+
+/* Runs the server until interrupted. On Unix/Windows this registers an
+ * interrupt for SIGINT (ctrl-c). The method only returns after having received
+ * the interrupt or upon an error condition. The logical sequence is as follows:
+ *
+ * - Register the interrupt
+ * - UA_Server_run_startup
+ * - Loop until interrupt: UA_Server_run_iterate
+ * - UA_Server_run_shutdown
+ * - Deregister the interrupt
+ *
+ * Attention! This method is implemented individually for the different
+ * platforms (POSIX/Win32/etc.). The default implementation is in
+ * /plugins/ua_config_default.c under the CC0 license. Adjust as needed.
+ *
+ * @param server The server object.
+ * @return Returns a bad statuscode if an error occurred internally. */
+UA_StatusCode
+UA_Server_runUntilInterrupt(UA_Server *server);
+
+/* The prologue part of UA_Server_run (no need to use if you call
+ * UA_Server_run or UA_Server_runUntilInterrupt) */
+UA_StatusCode
+UA_Server_run_startup(UA_Server *server);
+
+/* Executes a single iteration of the server's main loop.
+ *
+ * @param server The server object.
+ * @param waitInternal Should we wait for messages in the networklayer?
+ *        Otherwise, the timouts for the networklayers are set to zero.
+ *        The default max wait time is 200ms.
+ * @return Returns how long we can wait until the next scheduled
+ *         callback (in ms) */
+UA_UInt16
+UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal);
+
+/* The epilogue part of UA_Server_run (no need to use if you call
+ * UA_Server_run or UA_Server_runUntilInterrupt) */
+UA_StatusCode
+UA_Server_run_shutdown(UA_Server *server);
+
+
+
+
+

Timed Callbacks

+

Add a callback to the server that is executed at a defined time. +The callback can also be registered with a cyclic interval.

+
/* Add a callback for execution at a specified time. If the indicated time lies
+ * in the past, then the callback is executed at the next iteration of the
+ * server's main loop.
+ *
+ * @param server The server object.
+ * @param callback The callback that shall be added.
+ * @param data Data that is forwarded to the callback.
+ * @param date The timestamp for the execution time.
+ * @param callbackId Set to the identifier of the repeated callback . This can
+ *        be used to cancel the callback later on. If the pointer is null, the
+ *        identifier is not set.
+ * @return Upon success, ``UA_STATUSCODE_GOOD`` is returned. An error code
+ *         otherwise. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_addTimedCallback(UA_Server *server, UA_ServerCallback callback,
+                           void *data, UA_DateTime date, UA_UInt64 *callbackId);
+
+/* Add a callback for cyclic repetition to the server.
+ *
+ * @param server The server object.
+ * @param callback The callback that shall be added.
+ * @param data Data that is forwarded to the callback.
+ * @param interval_ms The callback shall be repeatedly executed with the given
+ *        interval (in ms). The interval must be positive. The first execution
+ *        occurs at now() + interval at the latest.
+ * @param callbackId Set to the identifier of the repeated callback . This can
+ *        be used to cancel the callback later on. If the pointer is null, the
+ *        identifier is not set.
+ * @return Upon success, ``UA_STATUSCODE_GOOD`` is returned. An error code
+ *         otherwise. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
+                              void *data, UA_Double interval_ms,
+                              UA_UInt64 *callbackId);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
+                                         UA_Double interval_ms);
+
+/* Remove a repeated callback. Does nothing if the callback is not found.
+ *
+ * @param server The server object.
+ * @param callbackId The id of the callback */
+void UA_THREADSAFE
+UA_Server_removeCallback(UA_Server *server, UA_UInt64 callbackId);
+
+#define UA_Server_removeRepeatedCallback(server, callbackId) \
+    UA_Server_removeCallback(server, callbackId);
+
+
+
+
+

Session Handling

+

A new session is announced via the AccessControl plugin. The session +identifier is forwarded to the relevant callbacks back into userland. The +following methods enable an interaction with a particular session.

+
/* Manually close a session */
+UA_StatusCode UA_THREADSAFE
+UA_Server_closeSession(UA_Server *server, const UA_NodeId *sessionId);
+
+
+

Session attributes: Besides the user-definable session context pointer (set +by the AccessControl plugin when the Session is created), a session carries +attributes in a key-value list. Some attributes are present in every session +and shown in the list below. Additional attributes can be manually set as +meta-data.

+

Always present as session attributes are:

+
    +
  • 0:localeIds [UA_String]: List of preferred languages (read-only)

  • +
  • 0:clientDescription [UA_ApplicationDescription]: Client description (read-only)

  • +
  • 0:sessionName [String] Client-defined name of the session (read-only)

  • +
  • 0:clientUserId [String] User identifier used to activate the session (read-only)

  • +
+
/* Returns a shallow copy of the attribute. Don't _clear or _delete the value
+ * variant. Don't use the value once the Session could be already closed in the
+ * background or the attribute of the session replaced. Hence don't use this in a
+ * multi-threaded application. */
+UA_StatusCode
+UA_Server_getSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
+                              const UA_QualifiedName key, UA_Variant *outValue);
+
+/* Return a deep copy of the attribute */
+UA_StatusCode UA_THREADSAFE
+UA_Server_getSessionAttributeCopy(UA_Server *server, const UA_NodeId *sessionId,
+                                  const UA_QualifiedName key, UA_Variant *outValue);
+
+/* Returns NULL if the attribute is not defined or not a scalar or not of the
+ * right datatype. Otherwise a shallow copy of the scalar value is created at
+ * the target location of the void pointer. Hence don't use this in a
+ * multi-threaded application. */
+UA_StatusCode
+UA_Server_getSessionAttribute_scalar(UA_Server *server,
+                                     const UA_NodeId *sessionId,
+                                     const UA_QualifiedName key,
+                                     const UA_DataType *type,
+                                     void *outValue);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_setSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
+                              const UA_QualifiedName key,
+                              const UA_Variant *value);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_deleteSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
+                                 const UA_QualifiedName key);
+
+
+
+
+

Reading and Writing Node Attributes

+

The functions for reading and writing node attributes call the regular read +and write service in the background that are also used over the network.

+

The following attributes cannot be read, since the local “admin” user always +has full rights.

+
    +
  • UserWriteMask

  • +
  • UserAccessLevel

  • +
  • UserExecutable

  • +
+
/* Read an attribute of a node. The specialized functions below provide a more
+ * concise syntax.
+ *
+ * @param server The server object.
+ * @param item ReadValueIds contain the NodeId of the target node, the id of the
+ *             attribute to read and (optionally) an index range to read parts
+ *             of an array only. See the section on NumericRange for the format
+ *             used for array ranges.
+ * @param timestamps Which timestamps to return for the attribute.
+ * @return Returns a DataValue that contains either an error code, or a variant
+ *         with the attribute value and the timestamps. */
+UA_DataValue UA_THREADSAFE
+UA_Server_read(UA_Server *server, const UA_ReadValueId *item,
+               UA_TimestampsToReturn timestamps);
+
+/* Don't use this function. There are typed versions for every supported
+ * attribute. */
+UA_StatusCode UA_THREADSAFE
+__UA_Server_read(UA_Server *server, const UA_NodeId *nodeId,
+                 UA_AttributeId attributeId, void *v);
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readNodeId(UA_Server *server, const UA_NodeId nodeId,
+                     UA_NodeId *outNodeId) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_NODEID, outNodeId);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readNodeClass(UA_Server *server, const UA_NodeId nodeId,
+                        UA_NodeClass *outNodeClass) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_NODECLASS,
+                            outNodeClass);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readBrowseName(UA_Server *server, const UA_NodeId nodeId,
+                         UA_QualifiedName *outBrowseName) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_BROWSENAME,
+                            outBrowseName);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readDisplayName(UA_Server *server, const UA_NodeId nodeId,
+                          UA_LocalizedText *outDisplayName) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME,
+                            outDisplayName);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readDescription(UA_Server *server, const UA_NodeId nodeId,
+                          UA_LocalizedText *outDescription) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DESCRIPTION,
+                            outDescription);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readWriteMask(UA_Server *server, const UA_NodeId nodeId,
+                        UA_UInt32 *outWriteMask) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_WRITEMASK,
+                            outWriteMask);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readIsAbstract(UA_Server *server, const UA_NodeId nodeId,
+                         UA_Boolean *outIsAbstract) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ISABSTRACT,
+                            outIsAbstract);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readSymmetric(UA_Server *server, const UA_NodeId nodeId,
+                        UA_Boolean *outSymmetric) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_SYMMETRIC,
+                            outSymmetric);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readInverseName(UA_Server *server, const UA_NodeId nodeId,
+                          UA_LocalizedText *outInverseName) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_INVERSENAME,
+                            outInverseName);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readContainsNoLoops(UA_Server *server, const UA_NodeId nodeId,
+                              UA_Boolean *outContainsNoLoops) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS,
+                            outContainsNoLoops);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readEventNotifier(UA_Server *server, const UA_NodeId nodeId,
+                            UA_Byte *outEventNotifier) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER,
+                            outEventNotifier);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readValue(UA_Server *server, const UA_NodeId nodeId,
+                    UA_Variant *outValue) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_VALUE, outValue);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readDataType(UA_Server *server, const UA_NodeId nodeId,
+                       UA_NodeId *outDataType) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DATATYPE,
+                            outDataType);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readValueRank(UA_Server *server, const UA_NodeId nodeId,
+                        UA_Int32 *outValueRank) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_VALUERANK,
+                            outValueRank);
+}
+
+/* Returns a variant with an int32 array */
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readArrayDimensions(UA_Server *server, const UA_NodeId nodeId,
+                              UA_Variant *outArrayDimensions) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS,
+                            outArrayDimensions);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readAccessLevel(UA_Server *server, const UA_NodeId nodeId,
+                          UA_Byte *outAccessLevel) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL,
+                            outAccessLevel);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readAccessLevelEx(UA_Server *server, const UA_NodeId nodeId,
+                            UA_UInt32 *outAccessLevelEx) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX,
+                            outAccessLevelEx);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readMinimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId,
+                                      UA_Double *outMinimumSamplingInterval) {
+    return __UA_Server_read(server, &nodeId,
+                            UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
+                            outMinimumSamplingInterval);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readHistorizing(UA_Server *server, const UA_NodeId nodeId,
+                          UA_Boolean *outHistorizing) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_HISTORIZING,
+                            outHistorizing);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_readExecutable(UA_Server *server, const UA_NodeId nodeId,
+                         UA_Boolean *outExecutable) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_EXECUTABLE,
+                            outExecutable);
+}
+
+
+

The following node attributes cannot be changed once a node has been created:

+
    +
  • NodeClass

  • +
  • NodeId

  • +
  • Symmetric

  • +
  • ContainsNoLoops

  • +
+

The following attributes cannot be written from the server, as they are +specific to the different users and set by the access control callback:

+
    +
  • UserWriteMask

  • +
  • UserAccessLevel

  • +
  • UserExecutable

  • +
+
/* Overwrite an attribute of a node. The specialized functions below provide a
+ * more concise syntax.
+ *
+ * @param server The server object.
+ * @param value WriteValues contain the NodeId of the target node, the id of the
+ *              attribute to overwritten, the actual value and (optionally) an
+ *              index range to replace parts of an array only. of an array only.
+ *              See the section on NumericRange for the format used for array
+ *              ranges.
+ * @return Returns a status code. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_write(UA_Server *server, const UA_WriteValue *value);
+
+/* Don't use this function. There are typed versions with no additional
+ * overhead. */
+UA_StatusCode UA_THREADSAFE
+__UA_Server_write(UA_Server *server, const UA_NodeId *nodeId,
+                  const UA_AttributeId attributeId,
+                  const UA_DataType *attr_type, const void *attr);
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeBrowseName(UA_Server *server, const UA_NodeId nodeId,
+                          const UA_QualifiedName browseName) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_BROWSENAME,
+                             &UA_TYPES[UA_TYPES_QUALIFIEDNAME], &browseName);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeDisplayName(UA_Server *server, const UA_NodeId nodeId,
+                           const UA_LocalizedText displayName) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME,
+                             &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &displayName);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeDescription(UA_Server *server, const UA_NodeId nodeId,
+                           const UA_LocalizedText description) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DESCRIPTION,
+                             &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &description);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeWriteMask(UA_Server *server, const UA_NodeId nodeId,
+                         const UA_UInt32 writeMask) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_WRITEMASK,
+                             &UA_TYPES[UA_TYPES_UINT32], &writeMask);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeIsAbstract(UA_Server *server, const UA_NodeId nodeId,
+                          const UA_Boolean isAbstract) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ISABSTRACT,
+                             &UA_TYPES[UA_TYPES_BOOLEAN], &isAbstract);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeInverseName(UA_Server *server, const UA_NodeId nodeId,
+                           const UA_LocalizedText inverseName) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_INVERSENAME,
+                             &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &inverseName);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeEventNotifier(UA_Server *server, const UA_NodeId nodeId,
+                             const UA_Byte eventNotifier) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER,
+                             &UA_TYPES[UA_TYPES_BYTE], &eventNotifier);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeValue(UA_Server *server, const UA_NodeId nodeId,
+                     const UA_Variant value) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUE,
+                             &UA_TYPES[UA_TYPES_VARIANT], &value);
+}
+
+/* Writes an UA_DataValue to a variable/variableType node. In contrast to
+ * UA_Server_writeValue, this functions can also write SourceTimestamp,
+ * ServerTimestamp and StatusCode. */
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeDataValue(UA_Server *server, const UA_NodeId nodeId,
+                         const UA_DataValue value) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUE,
+                             &UA_TYPES[UA_TYPES_DATAVALUE], &value);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeDataType(UA_Server *server, const UA_NodeId nodeId,
+                        const UA_NodeId dataType) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DATATYPE,
+                             &UA_TYPES[UA_TYPES_NODEID], &dataType);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeValueRank(UA_Server *server, const UA_NodeId nodeId,
+                         const UA_Int32 valueRank) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUERANK,
+                             &UA_TYPES[UA_TYPES_INT32], &valueRank);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeArrayDimensions(UA_Server *server, const UA_NodeId nodeId,
+                               const UA_Variant arrayDimensions) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS,
+                             &UA_TYPES[UA_TYPES_VARIANT], &arrayDimensions);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeAccessLevel(UA_Server *server, const UA_NodeId nodeId,
+                           const UA_Byte accessLevel) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL,
+                             &UA_TYPES[UA_TYPES_BYTE], &accessLevel);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeAccessLevelEx(UA_Server *server, const UA_NodeId nodeId,
+                             const UA_UInt32 accessLevelEx) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX,
+                             &UA_TYPES[UA_TYPES_UINT32], &accessLevelEx);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeMinimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId,
+                                       const UA_Double miniumSamplingInterval) {
+    return __UA_Server_write(server, &nodeId,
+                             UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
+                             &UA_TYPES[UA_TYPES_DOUBLE],
+                             &miniumSamplingInterval);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeHistorizing(UA_Server *server, const UA_NodeId nodeId,
+                          const UA_Boolean historizing) {
+    return __UA_Server_write(server, &nodeId,
+                             UA_ATTRIBUTEID_HISTORIZING,
+                             &UA_TYPES[UA_TYPES_BOOLEAN],
+                             &historizing);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_writeExecutable(UA_Server *server, const UA_NodeId nodeId,
+                          const UA_Boolean executable) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_EXECUTABLE,
+                             &UA_TYPES[UA_TYPES_BOOLEAN], &executable); }
+
+
+
+
+

Browsing

+
/* Browse the references of a particular node. See the definition of
+ * BrowseDescription structure for details. */
+UA_BrowseResult UA_THREADSAFE
+UA_Server_browse(UA_Server *server, UA_UInt32 maxReferences,
+                 const UA_BrowseDescription *bd);
+
+UA_BrowseResult UA_THREADSAFE
+UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint,
+                     const UA_ByteString *continuationPoint);
+
+/* Non-standard version of the Browse service that recurses into child nodes.
+ *
+ * Possible loops (that can occur for non-hierarchical references) are handled
+ * internally. Every node is added at most once to the results array.
+ *
+ * Nodes are only added if they match the NodeClassMask in the
+ * BrowseDescription. However, child nodes are still recursed into if the
+ * NodeClass does not match. So it is possible, for example, to get all
+ * VariableNodes below a certain ObjectNode, with additional objects in the
+ * hierarchy below. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_browseRecursive(UA_Server *server, const UA_BrowseDescription *bd,
+                          size_t *resultsSize, UA_ExpandedNodeId **results);
+
+UA_BrowsePathResult UA_THREADSAFE
+UA_Server_translateBrowsePathToNodeIds(UA_Server *server,
+                                       const UA_BrowsePath *browsePath);
+
+/* A simplified TranslateBrowsePathsToNodeIds based on the
+ * SimpleAttributeOperand type (Part 4, 7.4.4.5).
+ *
+ * This specifies a relative path using a list of BrowseNames instead of the
+ * RelativePath structure. The list of BrowseNames is equivalent to a
+ * RelativePath that specifies forward references which are subtypes of the
+ * HierarchicalReferences ReferenceType. All Nodes followed by the browsePath
+ * shall be of the NodeClass Object or Variable. */
+UA_BrowsePathResult UA_THREADSAFE
+UA_Server_browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
+                                     size_t browsePathSize,
+                                     const UA_QualifiedName *browsePath);
+
+#ifndef HAVE_NODEITER_CALLBACK
+#define HAVE_NODEITER_CALLBACK
+/* Iterate over all nodes referenced by parentNodeId by calling the callback
+ * function for each child node (in ifdef because GCC/CLANG handle include order
+ * differently) */
+typedef UA_StatusCode
+(*UA_NodeIteratorCallback)(UA_NodeId childId, UA_Boolean isInverse,
+                           UA_NodeId referenceTypeId, void *handle);
+#endif
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
+                               UA_NodeIteratorCallback callback, void *handle);
+
+#ifdef UA_ENABLE_DISCOVERY
+
+
+
+
+

Discovery

+
+

Registering at a Discovery Server

+
/* Register the given server instance at the discovery server. This should be
+ * called periodically, for example every 10 minutes, depending on the
+ * configuration of the discovery server. You should also call
+ * _unregisterDiscovery when the server shuts down.
+ *
+ * The supplied client configuration is used to create a new client to connect
+ * to the discovery server. The client configuration is moved over to the server
+ * and eventually cleaned up internally. The structure pointed at by `cc` is
+ * zeroed to avoid accessing outdated information.
+ *
+ * The eventloop and logging plugins in the client configuration are replaced by
+ * those configured in the server. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_registerDiscovery(UA_Server *server, UA_ClientConfig *cc,
+                            const UA_String discoveryServerUrl,
+                            const UA_String semaphoreFilePath);
+
+/* Deregister the given server instance from the discovery server.
+ * This should be called when the server is shutting down. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_deregisterDiscovery(UA_Server *server, UA_ClientConfig *cc,
+                              const UA_String discoveryServerUrl);
+
+
+
+
+

Operating a Discovery Server

+
/* Callback for RegisterServer. Data is passed from the register call */
+typedef void
+(*UA_Server_registerServerCallback)(const UA_RegisteredServer *registeredServer,
+                                    void* data);
+
+/* Set the callback which is called if another server registeres or unregisters
+ * with this instance. This callback is called every time the server gets a
+ * register call. This especially means that for every periodic server register
+ * the callback will be called.
+ *
+ * @param server
+ * @param cb the callback
+ * @param data data passed to the callback
+ * @return ``UA_STATUSCODE_SUCCESS`` on success */
+void UA_THREADSAFE
+UA_Server_setRegisterServerCallback(UA_Server *server,
+                                    UA_Server_registerServerCallback cb, void* data);
+
+#ifdef UA_ENABLE_DISCOVERY_MULTICAST
+
+/* Callback for server detected through mDNS. Data is passed from the register
+ * call
+ *
+ * @param isServerAnnounce indicates if the server has just been detected. If
+ *        set to false, this means the server is shutting down.
+ * @param isTxtReceived indicates if we already received the corresponding TXT
+ *        record with the path and caps data */
+typedef void
+(*UA_Server_serverOnNetworkCallback)(const UA_ServerOnNetwork *serverOnNetwork,
+                                     UA_Boolean isServerAnnounce,
+                                     UA_Boolean isTxtReceived, void* data);
+
+/* Set the callback which is called if another server is found through mDNS or
+ * deleted. It will be called for any mDNS message from the remote server, thus
+ * it may be called multiple times for the same instance. Also the SRV and TXT
+ * records may arrive later, therefore for the first call the server
+ * capabilities may not be set yet. If called multiple times, previous data will
+ * be overwritten.
+ *
+ * @param server
+ * @param cb the callback
+ * @param data data passed to the callback
+ * @return ``UA_STATUSCODE_SUCCESS`` on success */
+void UA_THREADSAFE
+UA_Server_setServerOnNetworkCallback(UA_Server *server,
+                                     UA_Server_serverOnNetworkCallback cb,
+                                     void* data);
+
+#endif /* UA_ENABLE_DISCOVERY_MULTICAST */
+
+#endif /* UA_ENABLE_DISCOVERY */
+
+
+
+
+
+

Information Model Callbacks

+

There are three places where a callback from an information model to +user-defined code can happen.

+
    +
  • Custom node constructors and destructors

  • +
  • Linking VariableNodes with an external data source

  • +
  • MethodNode callbacks

  • +
+
void
+UA_Server_setAdminSessionContext(UA_Server *server,
+                                 void *context);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
+                               UA_NodeTypeLifecycle lifecycle);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId,
+                         void **nodeContext);
+
+/* Careful! The user has to ensure that the destructor callbacks still work. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId,
+                         void *nodeContext);
+
+
+
+

Data Source Callback

+

The server has a unique way of dealing with the content of variables. Instead +of storing a variant attached to the variable node, the node can point to a +function with a local data provider. Whenever the value attribute is read, +the function will be called and asked to provide a UA_DataValue return value +that contains the value content and additional timestamps.

+

It is expected that the read callback is implemented. The write callback can +be set to a null-pointer.

+
UA_StatusCode UA_THREADSAFE
+UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
+                                     const UA_DataSource dataSource);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_setVariableNode_valueCallback(UA_Server *server,
+                                        const UA_NodeId nodeId,
+                                        const UA_ValueCallback callback);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_setVariableNode_valueBackend(UA_Server *server,
+                                       const UA_NodeId nodeId,
+                                       const UA_ValueBackend valueBackend);
+
+
+
+
+

Local MonitoredItems

+

MonitoredItems are used with the Subscription mechanism of OPC UA to +transported notifications for data changes and events. MonitoredItems can +also be registered locally. Notifications are then forwarded to a +user-defined callback instead of a remote client.

+
#ifdef UA_ENABLE_SUBSCRIPTIONS
+
+typedef void (*UA_Server_DataChangeNotificationCallback)
+    (UA_Server *server, UA_UInt32 monitoredItemId, void *monitoredItemContext,
+     const UA_NodeId *nodeId, void *nodeContext, UA_UInt32 attributeId,
+     const UA_DataValue *value);
+
+typedef void (*UA_Server_EventNotificationCallback)
+    (UA_Server *server, UA_UInt32 monId, void *monContext,
+     size_t nEventFields, const UA_Variant *eventFields);
+
+/* Create a local MonitoredItem with a sampling interval that detects data
+ * changes.
+ *
+ * @param server The server executing the MonitoredItem
+ * @timestampsToReturn Shall timestamps be added to the value for the callback?
+ * @item The parameters of the new MonitoredItem. Note that the attribute of the
+ *       ReadValueId (the node that is monitored) can not be
+ *       ``UA_ATTRIBUTEID_EVENTNOTIFIER``. A different callback type needs to be
+ *       registered for event notifications.
+ * @monitoredItemContext A pointer that is forwarded with the callback
+ * @callback The callback that is executed on detected data changes
+ *
+ * @return Returns a description of the created MonitoredItem. The structure
+ * also contains a StatusCode (in case of an error) and the identifier of the
+ * new MonitoredItem. */
+UA_MonitoredItemCreateResult UA_THREADSAFE
+UA_Server_createDataChangeMonitoredItem(UA_Server *server,
+          UA_TimestampsToReturn timestampsToReturn,
+          const UA_MonitoredItemCreateRequest item,
+          void *monitoredItemContext,
+          UA_Server_DataChangeNotificationCallback callback);
+
+/* UA_MonitoredItemCreateResult */
+/* UA_Server_createEventMonitoredItem(UA_Server *server, */
+/*           UA_TimestampsToReturn timestampsToReturn, */
+/*           const UA_MonitoredItemCreateRequest item, void *context, */
+/*           UA_Server_EventNotificationCallback callback); */
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_deleteMonitoredItem(UA_Server *server, UA_UInt32 monitoredItemId);
+
+#endif
+
+
+
+
+

Method Callbacks

+

Method callbacks are set to NULL (not executable) when a method node is +added over the network. In theory, it is possible to add a callback via +UA_Server_setMethodNode_callback within the global constructor when +adding methods over the network is really wanted. See the Section +Interacting with Objects for calling methods on an object.

+
#ifdef UA_ENABLE_METHODCALLS
+UA_StatusCode UA_THREADSAFE
+UA_Server_setMethodNodeCallback(UA_Server *server,
+                                const UA_NodeId methodNodeId,
+                                UA_MethodCallback methodCallback);
+
+/* Backwards compatibility definition */
+#define UA_Server_setMethodNode_callback(server, methodNodeId, methodCallback) \
+    UA_Server_setMethodNodeCallback(server, methodNodeId, methodCallback)
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_getMethodNodeCallback(UA_Server *server,
+                                const UA_NodeId methodNodeId,
+                                UA_MethodCallback *outMethodCallback);
+
+UA_CallMethodResult UA_THREADSAFE
+UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request);
+#endif
+
+
+
+
+
+

Interacting with Objects

+

Objects in the information model are represented as ObjectNodes. Some +convenience functions are provided to simplify the interaction with objects.

+
/* Write an object property. The property is represented as a VariableNode with
+ * a ``HasProperty`` reference from the ObjectNode. The VariableNode is
+ * identified by its BrowseName. Writing the property sets the value attribute
+ * of the VariableNode.
+ *
+ * @param server The server object
+ * @param objectId The identifier of the object (node)
+ * @param propertyName The name of the property
+ * @param value The value to be set for the event attribute
+ * @return The StatusCode for setting the event attribute */
+UA_StatusCode UA_THREADSAFE
+UA_Server_writeObjectProperty(UA_Server *server, const UA_NodeId objectId,
+                              const UA_QualifiedName propertyName,
+                              const UA_Variant value);
+
+/* Directly point to the scalar value instead of a variant */
+UA_StatusCode UA_THREADSAFE
+UA_Server_writeObjectProperty_scalar(UA_Server *server, const UA_NodeId objectId,
+                                     const UA_QualifiedName propertyName,
+                                     const void *value, const UA_DataType *type);
+
+/* Read an object property.
+ *
+ * @param server The server object
+ * @param objectId The identifier of the object (node)
+ * @param propertyName The name of the property
+ * @param value Contains the property value after reading. Must not be NULL.
+ * @return The StatusCode for setting the event attribute */
+UA_StatusCode UA_THREADSAFE
+UA_Server_readObjectProperty(UA_Server *server, const UA_NodeId objectId,
+                             const UA_QualifiedName propertyName,
+                             UA_Variant *value);
+
+
+
+
+

Node Addition and Deletion

+

When creating dynamic node instances at runtime, chances are that you will +not care about the specific NodeId of the new node, as long as you can +reference it later. When passing numeric NodeIds with a numeric identifier 0, +the stack evaluates this as “select a random unassigned numeric NodeId in +that namespace”. To find out which NodeId was actually assigned to the new +node, you may pass a pointer outNewNodeId, which will (after a successful +node insertion) contain the nodeId of the new node. You may also pass a +NULL pointer if this result is not needed.

+

See the Section Node Lifecycle: Constructors, Destructors and Node Contexts on constructors and on attaching +user-defined data to nodes.

+

The Section Default Node Attributes contains useful starting points +for defining node attributes. Forgetting to set the ValueRank or the +AccessLevel leads to errors that can be hard to track down for new users. The +default attributes have a high likelihood to “do the right thing”.

+

The methods for node addition and deletion take mostly const arguments that +are not modified. When creating a node, a deep copy of the node identifier, +node attributes, etc. is created. Therefore, it is possible to call for +example UA_Server_addVariablenode with a value attribute (a +Variant) pointing to a memory location on the stack. If you need +changes to a variable value to manifest at a specific memory location, please +use a Data Source Callback or a Value Callback.

+
/* Don't use this function. There are typed versions as inline functions. */
+UA_StatusCode UA_THREADSAFE
+__UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
+                    const UA_NodeId *requestedNewNodeId,
+                    const UA_NodeId *parentNodeId,
+                    const UA_NodeId *referenceTypeId,
+                    const UA_QualifiedName browseName,
+                    const UA_NodeId *typeDefinition,
+                    const UA_NodeAttributes *attr,
+                    const UA_DataType *attributeType,
+                    void *nodeContext, UA_NodeId *outNewNodeId);
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_addVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
+                          const UA_NodeId parentNodeId,
+                          const UA_NodeId referenceTypeId,
+                          const UA_QualifiedName browseName,
+                          const UA_NodeId typeDefinition,
+                          const UA_VariableAttributes attr,
+                          void *nodeContext, UA_NodeId *outNewNodeId) {
+    return __UA_Server_addNode(server, UA_NODECLASS_VARIABLE, &requestedNewNodeId,
+                               &parentNodeId, &referenceTypeId, browseName,
+                               &typeDefinition, (const UA_NodeAttributes*)&attr,
+                               &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
+                               nodeContext, outNewNodeId);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_addVariableTypeNode(UA_Server *server,
+                              const UA_NodeId requestedNewNodeId,
+                              const UA_NodeId parentNodeId,
+                              const UA_NodeId referenceTypeId,
+                              const UA_QualifiedName browseName,
+                              const UA_NodeId typeDefinition,
+                              const UA_VariableTypeAttributes attr,
+                              void *nodeContext, UA_NodeId *outNewNodeId) {
+    return __UA_Server_addNode(server, UA_NODECLASS_VARIABLETYPE,
+                               &requestedNewNodeId, &parentNodeId, &referenceTypeId,
+                               browseName, &typeDefinition,
+                               (const UA_NodeAttributes*)&attr,
+                               &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],
+                               nodeContext, outNewNodeId);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_addObjectNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
+                        const UA_NodeId parentNodeId,
+                        const UA_NodeId referenceTypeId,
+                        const UA_QualifiedName browseName,
+                        const UA_NodeId typeDefinition,
+                        const UA_ObjectAttributes attr,
+                        void *nodeContext, UA_NodeId *outNewNodeId) {
+    return __UA_Server_addNode(server, UA_NODECLASS_OBJECT, &requestedNewNodeId,
+                               &parentNodeId, &referenceTypeId, browseName,
+                               &typeDefinition, (const UA_NodeAttributes*)&attr,
+                               &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
+                               nodeContext, outNewNodeId);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_addObjectTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
+                            const UA_NodeId parentNodeId,
+                            const UA_NodeId referenceTypeId,
+                            const UA_QualifiedName browseName,
+                            const UA_ObjectTypeAttributes attr,
+                            void *nodeContext, UA_NodeId *outNewNodeId) {
+    return __UA_Server_addNode(server, UA_NODECLASS_OBJECTTYPE, &requestedNewNodeId,
+                               &parentNodeId, &referenceTypeId, browseName,
+                               &UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                               &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],
+                               nodeContext, outNewNodeId);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_addViewNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
+                      const UA_NodeId parentNodeId,
+                      const UA_NodeId referenceTypeId,
+                      const UA_QualifiedName browseName,
+                      const UA_ViewAttributes attr,
+                      void *nodeContext, UA_NodeId *outNewNodeId) {
+    return __UA_Server_addNode(server, UA_NODECLASS_VIEW, &requestedNewNodeId,
+                               &parentNodeId, &referenceTypeId, browseName,
+                               &UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                               &UA_TYPES[UA_TYPES_VIEWATTRIBUTES],
+                               nodeContext, outNewNodeId);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_addReferenceTypeNode(UA_Server *server,
+                               const UA_NodeId requestedNewNodeId,
+                               const UA_NodeId parentNodeId,
+                               const UA_NodeId referenceTypeId,
+                               const UA_QualifiedName browseName,
+                               const UA_ReferenceTypeAttributes attr,
+                               void *nodeContext, UA_NodeId *outNewNodeId) {
+    return __UA_Server_addNode(server, UA_NODECLASS_REFERENCETYPE,
+                               &requestedNewNodeId, &parentNodeId, &referenceTypeId,
+                               browseName, &UA_NODEID_NULL,
+                               (const UA_NodeAttributes*)&attr,
+                               &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],
+                               nodeContext, outNewNodeId);
+}
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_addDataTypeNode(UA_Server *server,
+                          const UA_NodeId requestedNewNodeId,
+                          const UA_NodeId parentNodeId,
+                          const UA_NodeId referenceTypeId,
+                          const UA_QualifiedName browseName,
+                          const UA_DataTypeAttributes attr,
+                          void *nodeContext, UA_NodeId *outNewNodeId) {
+    return __UA_Server_addNode(server, UA_NODECLASS_DATATYPE, &requestedNewNodeId,
+                               &parentNodeId, &referenceTypeId, browseName,
+                               &UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                               &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],
+                               nodeContext, outNewNodeId);
+}
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_addDataSourceVariableNode(UA_Server *server,
+                                    const UA_NodeId requestedNewNodeId,
+                                    const UA_NodeId parentNodeId,
+                                    const UA_NodeId referenceTypeId,
+                                    const UA_QualifiedName browseName,
+                                    const UA_NodeId typeDefinition,
+                                    const UA_VariableAttributes attr,
+                                    const UA_DataSource dataSource,
+                                    void *nodeContext, UA_NodeId *outNewNodeId);
+
+/* VariableNodes that are "dynamic" (default for user-created variables) receive
+ * and store a SourceTimestamp. For non-dynamic VariableNodes the current time
+ * is used for the SourceTimestamp. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_setVariableNodeDynamic(UA_Server *server, const UA_NodeId nodeId,
+                                 UA_Boolean isDynamic);
+
+#ifdef UA_ENABLE_METHODCALLS
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_addMethodNodeEx(UA_Server *server, const UA_NodeId requestedNewNodeId,
+                          const UA_NodeId parentNodeId,
+                          const UA_NodeId referenceTypeId,
+                          const UA_QualifiedName browseName,
+                          const UA_MethodAttributes attr, UA_MethodCallback method,
+                          size_t inputArgumentsSize, const UA_Argument *inputArguments,
+                          const UA_NodeId inputArgumentsRequestedNewNodeId,
+                          UA_NodeId *inputArgumentsOutNewNodeId,
+                          size_t outputArgumentsSize, const UA_Argument *outputArguments,
+                          const UA_NodeId outputArgumentsRequestedNewNodeId,
+                          UA_NodeId *outputArgumentsOutNewNodeId,
+                          void *nodeContext, UA_NodeId *outNewNodeId);
+
+static UA_INLINE UA_THREADSAFE UA_StatusCode
+UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
+                        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                        const UA_QualifiedName browseName, const UA_MethodAttributes attr,
+                        UA_MethodCallback method,
+                        size_t inputArgumentsSize, const UA_Argument *inputArguments,
+                        size_t outputArgumentsSize, const UA_Argument *outputArguments,
+                        void *nodeContext, UA_NodeId *outNewNodeId) {
+    return UA_Server_addMethodNodeEx(server, requestedNewNodeId,  parentNodeId,
+                                     referenceTypeId, browseName, attr, method,
+                                     inputArgumentsSize, inputArguments,
+                                     UA_NODEID_NULL, NULL,
+                                     outputArgumentsSize, outputArguments,
+                                     UA_NODEID_NULL, NULL,
+                                     nodeContext, outNewNodeId);
+}
+
+#endif
+
+
+

The method pair UA_Server_addNode_begin and _finish splits the AddNodes +service in two parts. This is useful if the node shall be modified before +finish the instantiation. For example to add children with specific NodeIds. +Otherwise, mandatory children (e.g. of an ObjectType) are added with +pseudo-random unique NodeIds. Existing children are detected during the +_finish part via their matching BrowseName.

+
+
The _begin method:
    +
  • prepares the node and adds it to the nodestore

  • +
  • copies some unassigned attributes from the TypeDefinition node internally

  • +
  • adds the references to the parent (and the TypeDefinition if applicable)

  • +
  • performs type-checking of variables.

  • +
+
+
+

You can add an object node without a parent if you set the parentNodeId and +referenceTypeId to UA_NODE_ID_NULL. Then you need to add the parent reference +and hasTypeDef reference yourself before calling the _finish method. +Not that this is only allowed for object nodes.

+
+
The _finish method:
    +
  • copies mandatory children

  • +
  • calls the node constructor(s) at the end

  • +
  • may remove the node if it encounters an error.

  • +
+
+
+

The special UA_Server_addMethodNode_finish method needs to be used for method +nodes, since there you need to explicitly specifiy the input and output +arguments which are added in the finish step (if not yet already there)

+
/* The ``attr`` argument must have a type according to the NodeClass.
+ * ``VariableAttributes`` for variables, ``ObjectAttributes`` for objects, and
+ * so on. Missing attributes are taken from the TypeDefinition node if
+ * applicable. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
+                        const UA_NodeId requestedNewNodeId,
+                        const UA_NodeId parentNodeId,
+                        const UA_NodeId referenceTypeId,
+                        const UA_QualifiedName browseName,
+                        const UA_NodeId typeDefinition,
+                        const void *attr, const UA_DataType *attributeType,
+                        void *nodeContext, UA_NodeId *outNewNodeId);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId);
+
+#ifdef UA_ENABLE_METHODCALLS
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId,
+                         UA_MethodCallback method,
+                         size_t inputArgumentsSize, const UA_Argument *inputArguments,
+                         size_t outputArgumentsSize, const UA_Argument *outputArguments);
+
+#endif
+
+/* Deletes a node and optionally all references leading to the node. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
+                     UA_Boolean deleteReferences);
+
+
+
+
+

Reference Management

+
UA_StatusCode UA_THREADSAFE
+UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId,
+                       const UA_NodeId refTypeId,
+                       const UA_ExpandedNodeId targetId, UA_Boolean isForward);
+
+UA_StatusCode UA_THREADSAFE
+UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
+                          const UA_NodeId referenceTypeId, UA_Boolean isForward,
+                          const UA_ExpandedNodeId targetNodeId,
+                          UA_Boolean deleteBidirectional);
+
+
+
+
+

Events

+

The method UA_Server_createEvent creates an event and represents it as +node. The node receives a unique EventId which is automatically added to +the node. The method returns a NodeId to the object node which represents +the event through outNodeId. The NodeId can be used to set the +attributes of the event. The generated NodeId is always numeric. +outNodeId cannot be NULL.

+

Note: In order to see an event in UAExpert, the field Time must be given a +value!

+

The method UA_Server_triggerEvent “triggers” an event by adding it to all +monitored items of the specified origin node and those of all its parents. +Any filters specified by the monitored items are automatically applied. Using +this method deletes the node generated by UA_Server_createEvent. The +EventId for the new event is generated automatically and is returned +through outEventId. NULL can be passed if the EventId is not +needed. deleteEventNode specifies whether the node representation of the +event should be deleted after invoking the method. This can be useful if +events with the similar attributes are triggered frequently. UA_TRUE +would cause the node to be deleted.

+
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
+
+/* Creates a node representation of an event
+ *
+ * @param server The server object
+ * @param eventType The type of the event for which a node should be created
+ * @param outNodeId The NodeId of the newly created node for the event
+ * @return The StatusCode of the UA_Server_createEvent method */
+UA_StatusCode UA_THREADSAFE
+UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType,
+                      UA_NodeId *outNodeId);
+
+/* Triggers a node representation of an event by applying EventFilters and
+ * adding the event to the appropriate queues.
+ *
+ * @param server The server object
+ * @param eventNodeId The NodeId of the node representation of the event which
+ *        should be triggered
+ * @param outEvent the EventId of the new event
+ * @param deleteEventNode Specifies whether the node representation of the event
+ *        should be deleted
+ * @return The StatusCode of the UA_Server_triggerEvent method */
+UA_StatusCode UA_THREADSAFE
+UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId,
+                       const UA_NodeId originId, UA_ByteString *outEventId,
+                       const UA_Boolean deleteEventNode);
+
+#endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */
+
+
+
+
+

Alarms & Conditions (Experimental)

+
#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS
+typedef enum UA_TwoStateVariableCallbackType {
+  UA_ENTERING_ENABLEDSTATE,
+  UA_ENTERING_ACKEDSTATE,
+  UA_ENTERING_CONFIRMEDSTATE,
+  UA_ENTERING_ACTIVESTATE
+} UA_TwoStateVariableCallbackType;
+
+/* Callback prototype to set user specific callbacks */
+typedef UA_StatusCode
+(*UA_TwoStateVariableChangeCallback)(UA_Server *server, const UA_NodeId *condition);
+
+/* Create condition instance. The function checks first whether the passed
+ * conditionType is a subType of ConditionType. Then checks whether the
+ * condition source has HasEventSource reference to its parent. If not, a
+ * HasEventSource reference will be created between condition source and server
+ * object. To expose the condition in address space, a hierarchical
+ * ReferenceType should be passed to create the reference to condition source.
+ * Otherwise, UA_NODEID_NULL should be passed to make the condition not exposed.
+ *
+ * @param server The server object
+ * @param conditionId The NodeId of the requested Condition Object. When passing
+ *        UA_NODEID_NUMERIC(X,0) an unused nodeid in namespace X will be used.
+ *        E.g. passing UA_NODEID_NULL will result in a NodeId in namespace 0.
+ * @param conditionType The NodeId of the node representation of the ConditionType
+ * @param conditionName The name of the condition to be created
+ * @param conditionSource The NodeId of the Condition Source (Parent of the Condition)
+ * @param hierarchialReferenceType The NodeId of Hierarchical ReferenceType
+ *                                 between Condition and its source
+ * @param outConditionId The NodeId of the created Condition
+ * @return The StatusCode of the UA_Server_createCondition method */
+UA_StatusCode
+UA_Server_createCondition(UA_Server *server,
+                          const UA_NodeId conditionId,
+                          const UA_NodeId conditionType,
+                          const UA_QualifiedName conditionName,
+                          const UA_NodeId conditionSource,
+                          const UA_NodeId hierarchialReferenceType,
+                          UA_NodeId *outConditionId);
+
+/* The method pair UA_Server_addCondition_begin and _finish splits the
+ * UA_Server_createCondtion in two parts similiar to the
+ * UA_Server_addNode_begin / _finish pair. This is useful if the node shall be
+ * modified before finish the instantiation. For example to add children with
+ * specific NodeIds.
+ * For details refer to the UA_Server_addNode_begin / _finish methods.
+ *
+ * Additionally to UA_Server_addNode_begin UA_Server_addCondition_begin checks
+ * if the passed condition type is a subtype of the OPC UA ConditionType.
+ *
+ * @param server The server object
+ * @param conditionId The NodeId of the requested Condition Object. When passing
+ *        UA_NODEID_NUMERIC(X,0) an unused nodeid in namespace X will be used.
+ *        E.g. passing UA_NODEID_NULL will result in a NodeId in namespace 0.
+ * @param conditionType The NodeId of the node representation of the ConditionType
+ * @param conditionName The name of the condition to be added
+ * @param outConditionId The NodeId of the added Condition
+ * @return The StatusCode of the UA_Server_addCondition_begin method */
+UA_StatusCode
+UA_Server_addCondition_begin(UA_Server *server,
+                             const UA_NodeId conditionId,
+                             const UA_NodeId conditionType,
+                             const UA_QualifiedName conditionName,
+                             UA_NodeId *outConditionId);
+
+/* Second call of the UA_Server_addCondition_begin and _finish pair.
+ * Additionally to UA_Server_addNode_finish UA_Server_addCondition_finish:
+ *  - checks whether the condition source has HasEventSource reference to its
+ *    parent. If not, a HasEventSource reference will be created between
+ *    condition source and server object
+ *  - exposes the condition in the address space if hierarchialReferenceType is
+ *    not UA_NODEID_NULL by adding a reference of this type from the condition
+ *    source to the condition instance
+ *  - initializes the standard condition fields and callbacks
+ *
+ * @param server The server object
+ * @param conditionId The NodeId of the unfinished Condition Object
+ * @param conditionSource The NodeId of the Condition Source (Parent of the Condition)
+ * @param hierarchialReferenceType The NodeId of Hierarchical ReferenceType
+ *                                 between Condition and its source
+ * @return The StatusCode of the UA_Server_addCondition_finish method */
+
+UA_StatusCode
+UA_Server_addCondition_finish(UA_Server *server,
+                              const UA_NodeId conditionId,
+                              const UA_NodeId conditionSource,
+                              const UA_NodeId hierarchialReferenceType);
+
+/* Set the value of condition field.
+ *
+ * @param server The server object
+ * @param condition The NodeId of the node representation of the Condition Instance
+ * @param value Variant Value to be written to the Field
+ * @param fieldName Name of the Field in which the value should be written
+ * @return The StatusCode of the UA_Server_setConditionField method*/
+UA_StatusCode UA_THREADSAFE
+UA_Server_setConditionField(UA_Server *server,
+                            const UA_NodeId condition,
+                            const UA_Variant *value,
+                            const UA_QualifiedName fieldName);
+
+/* Set the value of property of condition field.
+ *
+ * @param server The server object
+ * @param condition The NodeId of the node representation of the Condition
+ *        Instance
+ * @param value Variant Value to be written to the Field
+ * @param variableFieldName Name of the Field which has a property
+ * @param variablePropertyName Name of the Field Property in which the value
+ *        should be written
+ * @return The StatusCode of the UA_Server_setConditionVariableFieldProperty*/
+UA_StatusCode
+UA_Server_setConditionVariableFieldProperty(UA_Server *server,
+                                            const UA_NodeId condition,
+                                            const UA_Variant *value,
+                                            const UA_QualifiedName variableFieldName,
+                                            const UA_QualifiedName variablePropertyName);
+
+/* Triggers an event only for an enabled condition. The condition list is
+ * updated then with the last generated EventId.
+ *
+ * @param server The server object
+ * @param condition The NodeId of the node representation of the Condition Instance
+ * @param conditionSource The NodeId of the node representation of the Condition Source
+ * @param outEventId last generated EventId
+ * @return The StatusCode of the UA_Server_triggerConditionEvent method */
+UA_StatusCode
+UA_Server_triggerConditionEvent(UA_Server *server,
+                                const UA_NodeId condition,
+                                const UA_NodeId conditionSource,
+                                UA_ByteString *outEventId);
+
+/* Add an optional condition field using its name. (TODO Adding optional methods
+ * is not implemented yet)
+ *
+ * @param server The server object
+ * @param condition The NodeId of the node representation of the Condition Instance
+ * @param conditionType The NodeId of the node representation of the Condition Type
+ * from which the optional field comes
+ * @param fieldName Name of the optional field
+ * @param outOptionalVariable The NodeId of the created field (Variable Node)
+ * @return The StatusCode of the UA_Server_addConditionOptionalField method */
+UA_StatusCode
+UA_Server_addConditionOptionalField(UA_Server *server,
+                                    const UA_NodeId condition,
+                                    const UA_NodeId conditionType,
+                                    const UA_QualifiedName fieldName,
+                                    UA_NodeId *outOptionalVariable);
+
+/* Function used to set a user specific callback to TwoStateVariable Fields of a
+ * condition. The callbacks will be called before triggering the events when
+ * transition to true State of EnabledState/Id, AckedState/Id, ConfirmedState/Id
+ * and ActiveState/Id occurs.
+ *
+ * @param server The server object
+ * @param condition The NodeId of the node representation of the Condition Instance
+ * @param conditionSource The NodeId of the node representation of the Condition Source
+ * @param removeBranch (Not Implemented yet)
+ * @param callback User specific callback function
+ * @param callbackType Callback function type, indicates where it should be called
+ * @return The StatusCode of the UA_Server_setConditionTwoStateVariableCallback method */
+UA_StatusCode
+UA_Server_setConditionTwoStateVariableCallback(UA_Server *server,
+                                               const UA_NodeId condition,
+                                               const UA_NodeId conditionSource,
+                                               UA_Boolean removeBranch,
+                                               UA_TwoStateVariableChangeCallback callback,
+                                               UA_TwoStateVariableCallbackType callbackType);
+
+/* Delete a condition from the address space and the internal lists.
+ *
+ * @param server The server object
+ * @param condition The NodeId of the node representation of the Condition Instance
+ * @param conditionSource The NodeId of the node representation of the Condition Source
+ * @return ``UA_STATUSCODE_GOOD`` on success */
+UA_StatusCode
+UA_Server_deleteCondition(UA_Server *server,
+                          const UA_NodeId condition,
+                          const UA_NodeId conditionSource);
+
+/* Set the LimitState of the LimitAlarmType
+ *
+ * @param server The server object
+ * @param conditionId NodeId of the node representation of the Condition Instance
+ * @param limitValue The value from the trigger node */
+UA_StatusCode
+UA_Server_setLimitState(UA_Server *server, const UA_NodeId conditionId,
+                        UA_Double limitValue);
+
+/* Parse the certifcate and set Expiration date
+ *
+ * @param server The server object
+ * @param conditionId NodeId of the node representation of the Condition Instance
+ * @param cert The certificate for parsing */
+UA_StatusCode
+UA_Server_setExpirationDate(UA_Server *server, const UA_NodeId conditionId,
+                            UA_ByteString  cert);
+
+#endif /* UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */
+
+
+
+
+

Update the Server Certificate at Runtime

+
UA_StatusCode
+UA_Server_updateCertificate(UA_Server *server,
+                            const UA_ByteString *oldCertificate,
+                            const UA_ByteString *newCertificate,
+                            const UA_ByteString *newPrivateKey,
+                            UA_Boolean closeSessions,
+                            UA_Boolean closeSecureChannels);
+
+
+
+
+

Utility Functions

+
/* Lookup a datatype by its NodeId. Takes the custom types in the server
+ * configuration into account. Return NULL if none found. */
+const UA_DataType *
+UA_Server_findDataType(UA_Server *server, const UA_NodeId *typeId);
+
+/* Add a new namespace to the server. Returns the index of the new namespace */
+UA_UInt16 UA_THREADSAFE
+UA_Server_addNamespace(UA_Server *server, const char* name);
+
+/* Get namespace by name from the server. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_getNamespaceByName(UA_Server *server, const UA_String namespaceUri,
+                             size_t* foundIndex);
+
+/* Get namespace by id from the server. */
+UA_StatusCode UA_THREADSAFE
+UA_Server_getNamespaceByIndex(UA_Server *server, const size_t namespaceIndex,
+                              UA_String *foundUri);
+
+
+
+
+

Async Operations

+

Some operations (such as reading out a sensor that needs to warm up) can take +quite some time. In order not to block the server during such an operation, it +can be “outsourced” to a worker thread.

+

Take the example of a CallRequest. It is split into the individual method call +operations. If the method is marked as async, then the operation is put into a +queue where it is be retrieved by a worker. The worker returns the result when +ready. See the examples in /examples/tutorial_server_method_async.c for +the usage.

+

Note that the operation can time out (see the asyncOperationTimeout setting in +the server config) also when it has been retrieved by the worker.

+
#if UA_MULTITHREADING >= 100
+
+/* Set the async flag in a method node */
+UA_StatusCode
+UA_Server_setMethodNodeAsync(UA_Server *server, const UA_NodeId id,
+                             UA_Boolean isAsync);
+
+typedef enum {
+    UA_ASYNCOPERATIONTYPE_INVALID, /* 0, the default */
+    UA_ASYNCOPERATIONTYPE_CALL
+    /* UA_ASYNCOPERATIONTYPE_READ, */
+    /* UA_ASYNCOPERATIONTYPE_WRITE, */
+} UA_AsyncOperationType;
+
+typedef union {
+    UA_CallMethodRequest callMethodRequest;
+    /* UA_ReadValueId readValueId; */
+    /* UA_WriteValue writeValue; */
+} UA_AsyncOperationRequest;
+
+typedef union {
+    UA_CallMethodResult callMethodResult;
+    /* UA_DataValue readResult; */
+    /* UA_StatusCode writeResult; */
+} UA_AsyncOperationResponse;
+
+/* Get the next async operation without blocking
+ *
+ * @param server The server object
+ * @param type The type of the async operation
+ * @param request Receives pointer to the operation
+ * @param context Receives the pointer to the operation context
+ * @param timeout The timestamp when the operation times out and can
+ *        no longer be returned to the client. The response has to
+ *        be set in UA_Server_setAsyncOperationResult in any case.
+ * @return false if queue is empty, true else */
+UA_Boolean
+UA_Server_getAsyncOperationNonBlocking(UA_Server *server,
+                                       UA_AsyncOperationType *type,
+                                       const UA_AsyncOperationRequest **request,
+                                       void **context, UA_DateTime *timeout);
+
+/* UA_Boolean */
+/* UA_Server_getAsyncOperationBlocking(UA_Server *server, */
+/*                                     UA_AsyncOperationType *type, */
+/*                                     const UA_AsyncOperationRequest **request, */
+/*                                     void **context, UA_DateTime *timeout); */
+
+/* Submit an async operation result
+ *
+ * @param server The server object
+ * @param response Pointer to the operation result
+ * @param context Pointer to the operation context */
+void
+UA_Server_setAsyncOperationResult(UA_Server *server,
+                                  const UA_AsyncOperationResponse *response,
+                                  void *context);
+
+#endif /* !UA_MULTITHREADING >= 100 */
+
+
+
+
+

Statistics

+

Statistic counters keeping track of the current state of the stack. Counters +are structured per OPC UA communication layer.

+
typedef struct {
+   UA_SecureChannelStatistics scs;
+   UA_SessionStatistics ss;
+} UA_ServerStatistics;
+
+UA_ServerStatistics
+UA_Server_getStatistics(UA_Server *server);
+
+
+
+
+

Reverse Connect

+

The reverse connect feature of OPC UA permits the server instead of the +client to establish the connection. The client must expose the listening port +so the server is able to reach it.

+
/* The reverse connect state change callback is called whenever the state of a
+ * reverse connect is changed by a connection attempt, a successful connection
+ * or a connection loss.
+ *
+ * The reverse connect states reflect the state of the secure channel currently
+ * associated with a reverse connect. The state will remain
+ * UA_SECURECHANNELSTATE_CONNECTING while the server attempts repeatedly to
+ * establish a connection. */
+typedef void (*UA_Server_ReverseConnectStateCallback)(UA_Server *server,
+                                                      UA_UInt64 handle,
+                                                      UA_SecureChannelState state,
+                                                      void *context);
+
+/* Registers a reverse connect in the server. The server periodically attempts
+ * to establish a connection if the initial connect fails or if the connection
+ * breaks.
+ *
+ * @param server The server object
+ * @param url The URL of the remote client
+ * @param stateCallback The callback which will be called on state changes
+ * @param callbackContext The context for the state callback
+ * @param handle Is set to the handle of the reverse connect if not NULL
+ * @return Returns UA_STATUSCODE_GOOD if the reverse connect has been registered */
+UA_StatusCode
+UA_Server_addReverseConnect(UA_Server *server, UA_String url,
+                            UA_Server_ReverseConnectStateCallback stateCallback,
+                            void *callbackContext, UA_UInt64 *handle);
+
+/* Removes a reverse connect from the server and closes the connection if it is
+ * currently open.
+ *
+ * @param server The server object
+ * @param handle The handle of the reverse connect to remove
+ * @return Returns UA_STATUSCODE_GOOD if the reverse connect has been
+ *         successfully removed */
+UA_StatusCode
+UA_Server_removeReverseConnect(UA_Server *server, UA_UInt64 handle);
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/statuscodes.html b/static/doc/v1.4.0/statuscodes.html new file mode 100644 index 0000000000..1678b2f6c7 --- /dev/null +++ b/static/doc/v1.4.0/statuscodes.html @@ -0,0 +1,894 @@ + + + + + + + StatusCodes — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

StatusCodes

+

StatusCodes are extensively used in the OPC UA protocol and in the open62541 +API. They are represented by the StatusCode data type. The following +definitions are autogenerated from the Opc.Ua.StatusCodes.csv file provided +with the OPC UA standard.

+
/* These StatusCodes are manually generated. */
+#define UA_STATUSCODE_INFOTYPE_DATAVALUE 0x00000400
+#define UA_STATUSCODE_INFOBITS_OVERFLOW 0x00000080
+
+/* The operation succeeded. */
+#define UA_STATUSCODE_GOOD 0x00000000
+
+/* The operation was uncertain. */
+#define UA_STATUSCODE_UNCERTAIN 0x40000000
+
+/* The operation failed. */
+#define UA_STATUSCODE_BAD 0x80000000
+
+/* An unexpected error occurred. */
+#define UA_STATUSCODE_BADUNEXPECTEDERROR 0x80010000
+
+/* An internal error occurred as a result of a programming or configuration error. */
+#define UA_STATUSCODE_BADINTERNALERROR 0x80020000
+
+/* Not enough memory to complete the operation. */
+#define UA_STATUSCODE_BADOUTOFMEMORY 0x80030000
+
+/* An operating system resource is not available. */
+#define UA_STATUSCODE_BADRESOURCEUNAVAILABLE 0x80040000
+
+/* A low level communication error occurred. */
+#define UA_STATUSCODE_BADCOMMUNICATIONERROR 0x80050000
+
+/* Encoding halted because of invalid data in the objects being serialized. */
+#define UA_STATUSCODE_BADENCODINGERROR 0x80060000
+
+/* Decoding halted because of invalid data in the stream. */
+#define UA_STATUSCODE_BADDECODINGERROR 0x80070000
+
+/* The message encoding/decoding limits imposed by the stack have been exceeded. */
+#define UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED 0x80080000
+
+/* The request message size exceeds limits set by the server. */
+#define UA_STATUSCODE_BADREQUESTTOOLARGE 0x80B80000
+
+/* The response message size exceeds limits set by the client. */
+#define UA_STATUSCODE_BADRESPONSETOOLARGE 0x80B90000
+
+/* An unrecognized response was received from the server. */
+#define UA_STATUSCODE_BADUNKNOWNRESPONSE 0x80090000
+
+/* The operation timed out. */
+#define UA_STATUSCODE_BADTIMEOUT 0x800A0000
+
+/* The server does not support the requested service. */
+#define UA_STATUSCODE_BADSERVICEUNSUPPORTED 0x800B0000
+
+/* The operation was cancelled because the application is shutting down. */
+#define UA_STATUSCODE_BADSHUTDOWN 0x800C0000
+
+/* The operation could not complete because the client is not connected to the server. */
+#define UA_STATUSCODE_BADSERVERNOTCONNECTED 0x800D0000
+
+/* The server has stopped and cannot process any requests. */
+#define UA_STATUSCODE_BADSERVERHALTED 0x800E0000
+
+/* There was nothing to do because the client passed a list of operations with no elements. */
+#define UA_STATUSCODE_BADNOTHINGTODO 0x800F0000
+
+/* The request could not be processed because it specified too many operations. */
+#define UA_STATUSCODE_BADTOOMANYOPERATIONS 0x80100000
+
+/* The request could not be processed because there are too many monitored items in the subscription. */
+#define UA_STATUSCODE_BADTOOMANYMONITOREDITEMS 0x80DB0000
+
+/* The extension object cannot be (de)serialized because the data type id is not recognized. */
+#define UA_STATUSCODE_BADDATATYPEIDUNKNOWN 0x80110000
+
+/* The certificate provided as a parameter is not valid. */
+#define UA_STATUSCODE_BADCERTIFICATEINVALID 0x80120000
+
+/* An error occurred verifying security. */
+#define UA_STATUSCODE_BADSECURITYCHECKSFAILED 0x80130000
+
+/* The certificate does not meet the requirements of the security policy. */
+#define UA_STATUSCODE_BADCERTIFICATEPOLICYCHECKFAILED 0x81140000
+
+/* The certificate has expired or is not yet valid. */
+#define UA_STATUSCODE_BADCERTIFICATETIMEINVALID 0x80140000
+
+/* An issuer certificate has expired or is not yet valid. */
+#define UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID 0x80150000
+
+/* The HostName used to connect to a server does not match a HostName in the certificate. */
+#define UA_STATUSCODE_BADCERTIFICATEHOSTNAMEINVALID 0x80160000
+
+/* The URI specified in the ApplicationDescription does not match the URI in the certificate. */
+#define UA_STATUSCODE_BADCERTIFICATEURIINVALID 0x80170000
+
+/* The certificate may not be used for the requested operation. */
+#define UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED 0x80180000
+
+/* The issuer certificate may not be used for the requested operation. */
+#define UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED 0x80190000
+
+/* The certificate is not trusted. */
+#define UA_STATUSCODE_BADCERTIFICATEUNTRUSTED 0x801A0000
+
+/* It was not possible to determine if the certificate has been revoked. */
+#define UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN 0x801B0000
+
+/* It was not possible to determine if the issuer certificate has been revoked. */
+#define UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN 0x801C0000
+
+/* The certificate has been revoked. */
+#define UA_STATUSCODE_BADCERTIFICATEREVOKED 0x801D0000
+
+/* The issuer certificate has been revoked. */
+#define UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED 0x801E0000
+
+/* The certificate chain is incomplete. */
+#define UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE 0x810D0000
+
+/* User does not have permission to perform the requested operation. */
+#define UA_STATUSCODE_BADUSERACCESSDENIED 0x801F0000
+
+/* The user identity token is not valid. */
+#define UA_STATUSCODE_BADIDENTITYTOKENINVALID 0x80200000
+
+/* The user identity token is valid but the server has rejected it. */
+#define UA_STATUSCODE_BADIDENTITYTOKENREJECTED 0x80210000
+
+/* The specified secure channel is no longer valid. */
+#define UA_STATUSCODE_BADSECURECHANNELIDINVALID 0x80220000
+
+/* The timestamp is outside the range allowed by the server. */
+#define UA_STATUSCODE_BADINVALIDTIMESTAMP 0x80230000
+
+/* The nonce does appear to be not a random value or it is not the correct length. */
+#define UA_STATUSCODE_BADNONCEINVALID 0x80240000
+
+/* The session id is not valid. */
+#define UA_STATUSCODE_BADSESSIONIDINVALID 0x80250000
+
+/* The session was closed by the client. */
+#define UA_STATUSCODE_BADSESSIONCLOSED 0x80260000
+
+/* The session cannot be used because ActivateSession has not been called. */
+#define UA_STATUSCODE_BADSESSIONNOTACTIVATED 0x80270000
+
+/* The subscription id is not valid. */
+#define UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID 0x80280000
+
+/* The header for the request is missing or invalid. */
+#define UA_STATUSCODE_BADREQUESTHEADERINVALID 0x802A0000
+
+/* The timestamps to return parameter is invalid. */
+#define UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID 0x802B0000
+
+/* The request was cancelled by the client. */
+#define UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT 0x802C0000
+
+/* Too many arguments were provided. */
+#define UA_STATUSCODE_BADTOOMANYARGUMENTS 0x80E50000
+
+/* The server requires a license to operate in general or to perform a service or operatio */
+#define UA_STATUSCODE_BADLICENSEEXPIRED 0x810E0000
+
+/* The server has limits on number of allowed operations / object */
+#define UA_STATUSCODE_BADLICENSELIMITSEXCEEDED 0x810F0000
+
+/* The server does not have a license which is required to operate in general or to perform a service or operation. */
+#define UA_STATUSCODE_BADLICENSENOTAVAILABLE 0x81100000
+
+/* The subscription was transferred to another session. */
+#define UA_STATUSCODE_GOODSUBSCRIPTIONTRANSFERRED 0x002D0000
+
+/* The processing will complete asynchronously. */
+#define UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY 0x002E0000
+
+/* Sampling has slowed down due to resource limitations. */
+#define UA_STATUSCODE_GOODOVERLOAD 0x002F0000
+
+/* The value written was accepted but was clamped. */
+#define UA_STATUSCODE_GOODCLAMPED 0x00300000
+
+/* Communication with the data source is define */
+#define UA_STATUSCODE_BADNOCOMMUNICATION 0x80310000
+
+/* Waiting for the server to obtain values from the underlying data source. */
+#define UA_STATUSCODE_BADWAITINGFORINITIALDATA 0x80320000
+
+/* The syntax of the node id is not valid. */
+#define UA_STATUSCODE_BADNODEIDINVALID 0x80330000
+
+/* The node id refers to a node that does not exist in the server address space. */
+#define UA_STATUSCODE_BADNODEIDUNKNOWN 0x80340000
+
+/* The attribute is not supported for the specified Node. */
+#define UA_STATUSCODE_BADATTRIBUTEIDINVALID 0x80350000
+
+/* The syntax of the index range parameter is invalid. */
+#define UA_STATUSCODE_BADINDEXRANGEINVALID 0x80360000
+
+/* No data exists within the range of indexes specified. */
+#define UA_STATUSCODE_BADINDEXRANGENODATA 0x80370000
+
+/* The data encoding is invalid. */
+#define UA_STATUSCODE_BADDATAENCODINGINVALID 0x80380000
+
+/* The server does not support the requested data encoding for the node. */
+#define UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED 0x80390000
+
+/* The access level does not allow reading or subscribing to the Node. */
+#define UA_STATUSCODE_BADNOTREADABLE 0x803A0000
+
+/* The access level does not allow writing to the Node. */
+#define UA_STATUSCODE_BADNOTWRITABLE 0x803B0000
+
+/* The value was out of range. */
+#define UA_STATUSCODE_BADOUTOFRANGE 0x803C0000
+
+/* The requested operation is not supported. */
+#define UA_STATUSCODE_BADNOTSUPPORTED 0x803D0000
+
+/* A requested item was not found or a search operation ended without success. */
+#define UA_STATUSCODE_BADNOTFOUND 0x803E0000
+
+/* The object cannot be used because it has been deleted. */
+#define UA_STATUSCODE_BADOBJECTDELETED 0x803F0000
+
+/* Requested operation is not implemented. */
+#define UA_STATUSCODE_BADNOTIMPLEMENTED 0x80400000
+
+/* The monitoring mode is invalid. */
+#define UA_STATUSCODE_BADMONITORINGMODEINVALID 0x80410000
+
+/* The monitoring item id does not refer to a valid monitored item. */
+#define UA_STATUSCODE_BADMONITOREDITEMIDINVALID 0x80420000
+
+/* The monitored item filter parameter is not valid. */
+#define UA_STATUSCODE_BADMONITOREDITEMFILTERINVALID 0x80430000
+
+/* The server does not support the requested monitored item filter. */
+#define UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED 0x80440000
+
+/* A monitoring filter cannot be used in combination with the attribute specified. */
+#define UA_STATUSCODE_BADFILTERNOTALLOWED 0x80450000
+
+/* A mandatory structured parameter was missing or null. */
+#define UA_STATUSCODE_BADSTRUCTUREMISSING 0x80460000
+
+/* The event filter is not valid. */
+#define UA_STATUSCODE_BADEVENTFILTERINVALID 0x80470000
+
+/* The content filter is not valid. */
+#define UA_STATUSCODE_BADCONTENTFILTERINVALID 0x80480000
+
+/* An unrecognized operator was provided in a filter. */
+#define UA_STATUSCODE_BADFILTEROPERATORINVALID 0x80C10000
+
+/* A valid operator was provide */
+#define UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED 0x80C20000
+
+/* The number of operands provided for the filter operator was less then expected for the operand provided. */
+#define UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH 0x80C30000
+
+/* The operand used in a content filter is not valid. */
+#define UA_STATUSCODE_BADFILTEROPERANDINVALID 0x80490000
+
+/* The referenced element is not a valid element in the content filter. */
+#define UA_STATUSCODE_BADFILTERELEMENTINVALID 0x80C40000
+
+/* The referenced literal is not a valid value. */
+#define UA_STATUSCODE_BADFILTERLITERALINVALID 0x80C50000
+
+/* The continuation point provide is longer valid. */
+#define UA_STATUSCODE_BADCONTINUATIONPOINTINVALID 0x804A0000
+
+/* The operation could not be processed because all continuation points have been allocated. */
+#define UA_STATUSCODE_BADNOCONTINUATIONPOINTS 0x804B0000
+
+/* The reference type id does not refer to a valid reference type node. */
+#define UA_STATUSCODE_BADREFERENCETYPEIDINVALID 0x804C0000
+
+/* The browse direction is not valid. */
+#define UA_STATUSCODE_BADBROWSEDIRECTIONINVALID 0x804D0000
+
+/* The node is not part of the view. */
+#define UA_STATUSCODE_BADNODENOTINVIEW 0x804E0000
+
+/* The number was not accepted because of a numeric overflow. */
+#define UA_STATUSCODE_BADNUMERICOVERFLOW 0x81120000
+
+/* The ServerUri is not a valid URI. */
+#define UA_STATUSCODE_BADSERVERURIINVALID 0x804F0000
+
+/* No ServerName was specified. */
+#define UA_STATUSCODE_BADSERVERNAMEMISSING 0x80500000
+
+/* No DiscoveryUrl was specified. */
+#define UA_STATUSCODE_BADDISCOVERYURLMISSING 0x80510000
+
+/* The semaphore file specified by the client is not valid. */
+#define UA_STATUSCODE_BADSEMPAHOREFILEMISSING 0x80520000
+
+/* The security token request type is not valid. */
+#define UA_STATUSCODE_BADREQUESTTYPEINVALID 0x80530000
+
+/* The security mode does not meet the requirements set by the server. */
+#define UA_STATUSCODE_BADSECURITYMODEREJECTED 0x80540000
+
+/* The security policy does not meet the requirements set by the server. */
+#define UA_STATUSCODE_BADSECURITYPOLICYREJECTED 0x80550000
+
+/* The server has reached its maximum number of sessions. */
+#define UA_STATUSCODE_BADTOOMANYSESSIONS 0x80560000
+
+/* The user token signature is missing or invalid. */
+#define UA_STATUSCODE_BADUSERSIGNATUREINVALID 0x80570000
+
+/* The signature generated with the client certificate is missing or invalid. */
+#define UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID 0x80580000
+
+/* The client did not provide at least one software certificate that is valid and meets the profile requirements for the server. */
+#define UA_STATUSCODE_BADNOVALIDCERTIFICATES 0x80590000
+
+/* The server does not support changing the user identity assigned to the session. */
+#define UA_STATUSCODE_BADIDENTITYCHANGENOTSUPPORTED 0x80C60000
+
+/* The request was cancelled by the client with the Cancel service. */
+#define UA_STATUSCODE_BADREQUESTCANCELLEDBYREQUEST 0x805A0000
+
+/* The parent node id does not to refer to a valid node. */
+#define UA_STATUSCODE_BADPARENTNODEIDINVALID 0x805B0000
+
+/* The reference could not be created because it violates constraints imposed by the data model. */
+#define UA_STATUSCODE_BADREFERENCENOTALLOWED 0x805C0000
+
+/* The requested node id was reject because it was either invalid or server does not allow node ids to be specified by the client. */
+#define UA_STATUSCODE_BADNODEIDREJECTED 0x805D0000
+
+/* The requested node id is already used by another node. */
+#define UA_STATUSCODE_BADNODEIDEXISTS 0x805E0000
+
+/* The node class is not valid. */
+#define UA_STATUSCODE_BADNODECLASSINVALID 0x805F0000
+
+/* The browse name is invalid. */
+#define UA_STATUSCODE_BADBROWSENAMEINVALID 0x80600000
+
+/* The browse name is not unique among nodes that share the same relationship with the parent. */
+#define UA_STATUSCODE_BADBROWSENAMEDUPLICATED 0x80610000
+
+/* The node attributes are not valid for the node class. */
+#define UA_STATUSCODE_BADNODEATTRIBUTESINVALID 0x80620000
+
+/* The type definition node id does not reference an appropriate type node. */
+#define UA_STATUSCODE_BADTYPEDEFINITIONINVALID 0x80630000
+
+/* The source node id does not reference a valid node. */
+#define UA_STATUSCODE_BADSOURCENODEIDINVALID 0x80640000
+
+/* The target node id does not reference a valid node. */
+#define UA_STATUSCODE_BADTARGETNODEIDINVALID 0x80650000
+
+/* The reference type between the nodes is already defined. */
+#define UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED 0x80660000
+
+/* The server does not allow this type of self reference on this node. */
+#define UA_STATUSCODE_BADINVALIDSELFREFERENCE 0x80670000
+
+/* The reference type is not valid for a reference to a remote server. */
+#define UA_STATUSCODE_BADREFERENCELOCALONLY 0x80680000
+
+/* The server will not allow the node to be deleted. */
+#define UA_STATUSCODE_BADNODELETERIGHTS 0x80690000
+
+/* The server was not able to delete all target references. */
+#define UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED 0x40BC0000
+
+/* The server index is not valid. */
+#define UA_STATUSCODE_BADSERVERINDEXINVALID 0x806A0000
+
+/* The view id does not refer to a valid view node. */
+#define UA_STATUSCODE_BADVIEWIDUNKNOWN 0x806B0000
+
+/* The view timestamp is not available or not supported. */
+#define UA_STATUSCODE_BADVIEWTIMESTAMPINVALID 0x80C90000
+
+/* The view parameters are not consistent with each other. */
+#define UA_STATUSCODE_BADVIEWPARAMETERMISMATCH 0x80CA0000
+
+/* The view version is not available or not supported. */
+#define UA_STATUSCODE_BADVIEWVERSIONINVALID 0x80CB0000
+
+/* The list of references may not be complete because the underlying system is not available. */
+#define UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE 0x40C00000
+
+/* The server should have followed a reference to a node in a remote server but did not. The result set may be incomplete. */
+#define UA_STATUSCODE_GOODRESULTSMAYBEINCOMPLETE 0x00BA0000
+
+/* The provided Nodeid was not a type definition nodeid. */
+#define UA_STATUSCODE_BADNOTTYPEDEFINITION 0x80C80000
+
+/* One of the references to follow in the relative path references to a node in the address space in another server. */
+#define UA_STATUSCODE_UNCERTAINREFERENCEOUTOFSERVER 0x406C0000
+
+/* The requested operation has too many matches to return. */
+#define UA_STATUSCODE_BADTOOMANYMATCHES 0x806D0000
+
+/* The requested operation requires too many resources in the server. */
+#define UA_STATUSCODE_BADQUERYTOOCOMPLEX 0x806E0000
+
+/* The requested operation has no match to return. */
+#define UA_STATUSCODE_BADNOMATCH 0x806F0000
+
+/* The max age parameter is invalid. */
+#define UA_STATUSCODE_BADMAXAGEINVALID 0x80700000
+
+/* The operation is not permitted over the current secure channel. */
+#define UA_STATUSCODE_BADSECURITYMODEINSUFFICIENT 0x80E60000
+
+/* The history details parameter is not valid. */
+#define UA_STATUSCODE_BADHISTORYOPERATIONINVALID 0x80710000
+
+/* The server does not support the requested operation. */
+#define UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED 0x80720000
+
+/* The defined timestamp to return was invalid. */
+#define UA_STATUSCODE_BADINVALIDTIMESTAMPARGUMENT 0x80BD0000
+
+/* The server does not support writing the combination of valu */
+#define UA_STATUSCODE_BADWRITENOTSUPPORTED 0x80730000
+
+/* The value supplied for the attribute is not of the same type as the attribute's value. */
+#define UA_STATUSCODE_BADTYPEMISMATCH 0x80740000
+
+/* The method id does not refer to a method for the specified object. */
+#define UA_STATUSCODE_BADMETHODINVALID 0x80750000
+
+/* The client did not specify all of the input arguments for the method. */
+#define UA_STATUSCODE_BADARGUMENTSMISSING 0x80760000
+
+/* The executable attribute does not allow the execution of the method. */
+#define UA_STATUSCODE_BADNOTEXECUTABLE 0x81110000
+
+/* The server has reached its maximum number of subscriptions. */
+#define UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS 0x80770000
+
+/* The server has reached the maximum number of queued publish requests. */
+#define UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS 0x80780000
+
+/* There is no subscription available for this session. */
+#define UA_STATUSCODE_BADNOSUBSCRIPTION 0x80790000
+
+/* The sequence number is unknown to the server. */
+#define UA_STATUSCODE_BADSEQUENCENUMBERUNKNOWN 0x807A0000
+
+/* The Server does not support retransmission queue and acknowledgement of sequence numbers is not available. */
+#define UA_STATUSCODE_GOODRETRANSMISSIONQUEUENOTSUPPORTED 0x00DF0000
+
+/* The requested notification message is no longer available. */
+#define UA_STATUSCODE_BADMESSAGENOTAVAILABLE 0x807B0000
+
+/* The client of the current session does not support one or more Profiles that are necessary for the subscription. */
+#define UA_STATUSCODE_BADINSUFFICIENTCLIENTPROFILE 0x807C0000
+
+/* The sub-state machine is not currently active. */
+#define UA_STATUSCODE_BADSTATENOTACTIVE 0x80BF0000
+
+/* An equivalent rule already exists. */
+#define UA_STATUSCODE_BADALREADYEXISTS 0x81150000
+
+/* The server cannot process the request because it is too busy. */
+#define UA_STATUSCODE_BADTCPSERVERTOOBUSY 0x807D0000
+
+/* The type of the message specified in the header invalid. */
+#define UA_STATUSCODE_BADTCPMESSAGETYPEINVALID 0x807E0000
+
+/* The SecureChannelId and/or TokenId are not currently in use. */
+#define UA_STATUSCODE_BADTCPSECURECHANNELUNKNOWN 0x807F0000
+
+/* The size of the message chunk specified in the header is too large. */
+#define UA_STATUSCODE_BADTCPMESSAGETOOLARGE 0x80800000
+
+/* There are not enough resources to process the request. */
+#define UA_STATUSCODE_BADTCPNOTENOUGHRESOURCES 0x80810000
+
+/* An internal error occurred. */
+#define UA_STATUSCODE_BADTCPINTERNALERROR 0x80820000
+
+/* The server does not recognize the QueryString specified. */
+#define UA_STATUSCODE_BADTCPENDPOINTURLINVALID 0x80830000
+
+/* The request could not be sent because of a network interruption. */
+#define UA_STATUSCODE_BADREQUESTINTERRUPTED 0x80840000
+
+/* Timeout occurred while processing the request. */
+#define UA_STATUSCODE_BADREQUESTTIMEOUT 0x80850000
+
+/* The secure channel has been closed. */
+#define UA_STATUSCODE_BADSECURECHANNELCLOSED 0x80860000
+
+/* The token has expired or is not recognized. */
+#define UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN 0x80870000
+
+/* The sequence number is not valid. */
+#define UA_STATUSCODE_BADSEQUENCENUMBERINVALID 0x80880000
+
+/* The applications do not have compatible protocol versions. */
+#define UA_STATUSCODE_BADPROTOCOLVERSIONUNSUPPORTED 0x80BE0000
+
+/* There is a problem with the configuration that affects the usefulness of the value. */
+#define UA_STATUSCODE_BADCONFIGURATIONERROR 0x80890000
+
+/* The variable should receive its value from another variabl */
+#define UA_STATUSCODE_BADNOTCONNECTED 0x808A0000
+
+/* There has been a failure in the device/data source that generates the value that has affected the value. */
+#define UA_STATUSCODE_BADDEVICEFAILURE 0x808B0000
+
+/* There has been a failure in the sensor from which the value is derived by the device/data source. */
+#define UA_STATUSCODE_BADSENSORFAILURE 0x808C0000
+
+/* The source of the data is not operational. */
+#define UA_STATUSCODE_BADOUTOFSERVICE 0x808D0000
+
+/* The deadband filter is not valid. */
+#define UA_STATUSCODE_BADDEADBANDFILTERINVALID 0x808E0000
+
+/* Communication to the data source has failed. The variable value is the last value that had a good quality. */
+#define UA_STATUSCODE_UNCERTAINNOCOMMUNICATIONLASTUSABLEVALUE 0x408F0000
+
+/* Whatever was updating this value has stopped doing so. */
+#define UA_STATUSCODE_UNCERTAINLASTUSABLEVALUE 0x40900000
+
+/* The value is an operational value that was manually overwritten. */
+#define UA_STATUSCODE_UNCERTAINSUBSTITUTEVALUE 0x40910000
+
+/* The value is an initial value for a variable that normally receives its value from another variable. */
+#define UA_STATUSCODE_UNCERTAININITIALVALUE 0x40920000
+
+/* The value is at one of the sensor limits. */
+#define UA_STATUSCODE_UNCERTAINSENSORNOTACCURATE 0x40930000
+
+/* The value is outside of the range of values defined for this parameter. */
+#define UA_STATUSCODE_UNCERTAINENGINEERINGUNITSEXCEEDED 0x40940000
+
+/* The value is derived from multiple sources and has less than the required number of Good sources. */
+#define UA_STATUSCODE_UNCERTAINSUBNORMAL 0x40950000
+
+/* The value has been overridden. */
+#define UA_STATUSCODE_GOODLOCALOVERRIDE 0x00960000
+
+/* This Condition refresh faile */
+#define UA_STATUSCODE_BADREFRESHINPROGRESS 0x80970000
+
+/* This condition has already been disabled. */
+#define UA_STATUSCODE_BADCONDITIONALREADYDISABLED 0x80980000
+
+/* This condition has already been enabled. */
+#define UA_STATUSCODE_BADCONDITIONALREADYENABLED 0x80CC0000
+
+/* Property not availabl */
+#define UA_STATUSCODE_BADCONDITIONDISABLED 0x80990000
+
+/* The specified event id is not recognized. */
+#define UA_STATUSCODE_BADEVENTIDUNKNOWN 0x809A0000
+
+/* The event cannot be acknowledged. */
+#define UA_STATUSCODE_BADEVENTNOTACKNOWLEDGEABLE 0x80BB0000
+
+/* The dialog condition is not active. */
+#define UA_STATUSCODE_BADDIALOGNOTACTIVE 0x80CD0000
+
+/* The response is not valid for the dialog. */
+#define UA_STATUSCODE_BADDIALOGRESPONSEINVALID 0x80CE0000
+
+/* The condition branch has already been acknowledged. */
+#define UA_STATUSCODE_BADCONDITIONBRANCHALREADYACKED 0x80CF0000
+
+/* The condition branch has already been confirmed. */
+#define UA_STATUSCODE_BADCONDITIONBRANCHALREADYCONFIRMED 0x80D00000
+
+/* The condition has already been shelved. */
+#define UA_STATUSCODE_BADCONDITIONALREADYSHELVED 0x80D10000
+
+/* The condition is not currently shelved. */
+#define UA_STATUSCODE_BADCONDITIONNOTSHELVED 0x80D20000
+
+/* The shelving time not within an acceptable range. */
+#define UA_STATUSCODE_BADSHELVINGTIMEOUTOFRANGE 0x80D30000
+
+/* No data exists for the requested time range or event filter. */
+#define UA_STATUSCODE_BADNODATA 0x809B0000
+
+/* No data found to provide upper or lower bound value. */
+#define UA_STATUSCODE_BADBOUNDNOTFOUND 0x80D70000
+
+/* The server cannot retrieve a bound for the variable. */
+#define UA_STATUSCODE_BADBOUNDNOTSUPPORTED 0x80D80000
+
+/* Data is missing due to collection started/stopped/lost. */
+#define UA_STATUSCODE_BADDATALOST 0x809D0000
+
+/* Expected data is unavailable for the requested time range due to an un-mounted volum */
+#define UA_STATUSCODE_BADDATAUNAVAILABLE 0x809E0000
+
+/* The data or event was not successfully inserted because a matching entry exists. */
+#define UA_STATUSCODE_BADENTRYEXISTS 0x809F0000
+
+/* The data or event was not successfully updated because no matching entry exists. */
+#define UA_STATUSCODE_BADNOENTRYEXISTS 0x80A00000
+
+/* The client requested history using a timestamp format the server does not support (i.e requested ServerTimestamp when server only supports SourceTimestamp). */
+#define UA_STATUSCODE_BADTIMESTAMPNOTSUPPORTED 0x80A10000
+
+/* The data or event was successfully inserted into the historical database. */
+#define UA_STATUSCODE_GOODENTRYINSERTED 0x00A20000
+
+/* The data or event field was successfully replaced in the historical database. */
+#define UA_STATUSCODE_GOODENTRYREPLACED 0x00A30000
+
+/* The value is derived from multiple values and has less than the required number of Good values. */
+#define UA_STATUSCODE_UNCERTAINDATASUBNORMAL 0x40A40000
+
+/* No data exists for the requested time range or event filter. */
+#define UA_STATUSCODE_GOODNODATA 0x00A50000
+
+/* The data or event field was successfully replaced in the historical database. */
+#define UA_STATUSCODE_GOODMOREDATA 0x00A60000
+
+/* The requested number of Aggregates does not match the requested number of NodeIds. */
+#define UA_STATUSCODE_BADAGGREGATELISTMISMATCH 0x80D40000
+
+/* The requested Aggregate is not support by the server. */
+#define UA_STATUSCODE_BADAGGREGATENOTSUPPORTED 0x80D50000
+
+/* The aggregate value could not be derived due to invalid data inputs. */
+#define UA_STATUSCODE_BADAGGREGATEINVALIDINPUTS 0x80D60000
+
+/* The aggregate configuration is not valid for specified node. */
+#define UA_STATUSCODE_BADAGGREGATECONFIGURATIONREJECTED 0x80DA0000
+
+/* The request specifies fields which are not valid for the EventType or cannot be saved by the historian. */
+#define UA_STATUSCODE_GOODDATAIGNORED 0x00D90000
+
+/* The request was rejected by the server because it did not meet the criteria set by the server. */
+#define UA_STATUSCODE_BADREQUESTNOTALLOWED 0x80E40000
+
+/* The request has not been processed by the server yet. */
+#define UA_STATUSCODE_BADREQUESTNOTCOMPLETE 0x81130000
+
+/* The device identity needs a ticket before it can be accepted. */
+#define UA_STATUSCODE_BADTICKETREQUIRED 0x811F0000
+
+/* The device identity needs a ticket before it can be accepted. */
+#define UA_STATUSCODE_BADTICKETINVALID 0x81200000
+
+/* The value does not come from the real source and has been edited by the server. */
+#define UA_STATUSCODE_GOODEDITED 0x00DC0000
+
+/* There was an error in execution of these post-actions. */
+#define UA_STATUSCODE_GOODPOSTACTIONFAILED 0x00DD0000
+
+/* The related EngineeringUnit has been changed but the Variable Value is still provided based on the previous unit. */
+#define UA_STATUSCODE_UNCERTAINDOMINANTVALUECHANGED 0x40DE0000
+
+/* A dependent value has been changed but the change has not been applied to the device. */
+#define UA_STATUSCODE_GOODDEPENDENTVALUECHANGED 0x00E00000
+
+/* 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. */
+#define UA_STATUSCODE_BADDOMINANTVALUECHANGED 0x80E10000
+
+/* A dependent value has been changed but the change has not been applied to the device. The quality of the dominant variable is uncertain. */
+#define UA_STATUSCODE_UNCERTAINDEPENDENTVALUECHANGED 0x40E20000
+
+/* A dependent value has been changed but the change has not been applied to the device. The quality of the dominant variable is Bad. */
+#define UA_STATUSCODE_BADDEPENDENTVALUECHANGED 0x80E30000
+
+/* It is delivered with a dominant Variable value when a dependent Variable has changed but the change has not been applied. */
+#define UA_STATUSCODE_GOODEDITED_DEPENDENTVALUECHANGED 0x01160000
+
+/* It is delivered with a dependent Variable value when a dominant Variable has changed but the change has not been applied. */
+#define UA_STATUSCODE_GOODEDITED_DOMINANTVALUECHANGED 0x01170000
+
+/* It is delivered with a dependent Variable value when a dominant or dependent Variable has changed but change has not been applied. */
+#define UA_STATUSCODE_GOODEDITED_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED 0x01180000
+
+/* It is delivered with a Variable value when Variable has changed but the value is not legal. */
+#define UA_STATUSCODE_BADEDITED_OUTOFRANGE 0x81190000
+
+/* It is delivered with a Variable value when a source Variable has changed but the value is not legal. */
+#define UA_STATUSCODE_BADINITIALVALUE_OUTOFRANGE 0x811A0000
+
+/* It is delivered with a dependent Variable value when a dominant Variable has changed and the value is not legal. */
+#define UA_STATUSCODE_BADOUTOFRANGE_DOMINANTVALUECHANGED 0x811B0000
+
+/* It is delivered with a dependent Variable value when a dominant Variable has change */
+#define UA_STATUSCODE_BADEDITED_OUTOFRANGE_DOMINANTVALUECHANGED 0x811C0000
+
+/* It is delivered with a dependent Variable value when a dominant or dependent Variable has changed and the value is not legal. */
+#define UA_STATUSCODE_BADOUTOFRANGE_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED 0x811D0000
+
+/* It is delivered with a dependent Variable value when a dominant or dependent Variable has change */
+#define UA_STATUSCODE_BADEDITED_OUTOFRANGE_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED 0x811E0000
+
+/* The communication layer has raised an event. */
+#define UA_STATUSCODE_GOODCOMMUNICATIONEVENT 0x00A70000
+
+/* The system is shutting down. */
+#define UA_STATUSCODE_GOODSHUTDOWNEVENT 0x00A80000
+
+/* The operation is not finished and needs to be called again. */
+#define UA_STATUSCODE_GOODCALLAGAIN 0x00A90000
+
+/* A non-critical timeout occurred. */
+#define UA_STATUSCODE_GOODNONCRITICALTIMEOUT 0x00AA0000
+
+/* One or more arguments are invalid. */
+#define UA_STATUSCODE_BADINVALIDARGUMENT 0x80AB0000
+
+/* Could not establish a network connection to remote server. */
+#define UA_STATUSCODE_BADCONNECTIONREJECTED 0x80AC0000
+
+/* The server has disconnected from the client. */
+#define UA_STATUSCODE_BADDISCONNECT 0x80AD0000
+
+/* The network connection has been closed. */
+#define UA_STATUSCODE_BADCONNECTIONCLOSED 0x80AE0000
+
+/* The operation cannot be completed because the object is close */
+#define UA_STATUSCODE_BADINVALIDSTATE 0x80AF0000
+
+/* Cannot move beyond end of the stream. */
+#define UA_STATUSCODE_BADENDOFSTREAM 0x80B00000
+
+/* No data is currently available for reading from a non-blocking stream. */
+#define UA_STATUSCODE_BADNODATAAVAILABLE 0x80B10000
+
+/* The asynchronous operation is waiting for a response. */
+#define UA_STATUSCODE_BADWAITINGFORRESPONSE 0x80B20000
+
+/* The asynchronous operation was abandoned by the caller. */
+#define UA_STATUSCODE_BADOPERATIONABANDONED 0x80B30000
+
+/* The stream did not return all data requested (possibly because it is a non-blocking stream). */
+#define UA_STATUSCODE_BADEXPECTEDSTREAMTOBLOCK 0x80B40000
+
+/* Non blocking behaviour is required and the operation would block. */
+#define UA_STATUSCODE_BADWOULDBLOCK 0x80B50000
+
+/* A value had an invalid syntax. */
+#define UA_STATUSCODE_BADSYNTAXERROR 0x80B60000
+
+/* The operation could not be finished because all available connections are in use. */
+#define UA_STATUSCODE_BADMAXCONNECTIONSREACHED 0x80B70000
+
+/* Depending on the version of the schema, the following might be already defined: */
+#ifndef UA_STATUSCODE_GOOD
+# define UA_STATUSCODE_GOOD 0x00000000
+#endif
+#ifndef UA_STATUSCODE_UNCERTAIN
+# define UA_STATUSCODE_UNCERTAIN 0x40000000
+#endif
+#ifndef UA_STATUSCODE_BAD
+# define UA_STATUSCODE_BAD 0x80000000
+#endif
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/toc.html b/static/doc/v1.4.0/toc.html new file mode 100644 index 0000000000..1896f03ea2 --- /dev/null +++ b/static/doc/v1.4.0/toc.html @@ -0,0 +1,676 @@ + + + + + + + open62541 Documentation — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

open62541 Documentation

+
+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/tutorial_client_firststeps.html b/static/doc/v1.4.0/tutorial_client_firststeps.html new file mode 100644 index 0000000000..705f4cc35b --- /dev/null +++ b/static/doc/v1.4.0/tutorial_client_firststeps.html @@ -0,0 +1,214 @@ + + + + + + + Building a Simple Client — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Building a Simple Client

+

You should already have a basic server from the previous tutorials. open62541 +provides both a server- and clientside API, so creating a client is as easy as +creating a server. Copy the following into a file myClient.c:

+
#include <open62541/client_config_default.h>
+#include <open62541/client_highlevel.h>
+#include <open62541/plugin/log_stdout.h>
+
+int main(void) {
+    UA_Client *client = UA_Client_new();
+    UA_ClientConfig_setDefault(UA_Client_getConfig(client));
+    UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                    "The connection failed with status code %s",
+                    UA_StatusCode_name(retval));
+        UA_Client_delete(client);
+        return 0;
+    }
+
+    /* Read the value attribute of the node. UA_Client_readValueAttribute is a
+     * wrapper for the raw read service available as UA_Client_Service_read. */
+    UA_Variant value; /* Variants can hold scalar values and arrays of any type */
+    UA_Variant_init(&value);
+
+    /* NodeId of the variable holding the current time */
+    const UA_NodeId nodeId =
+        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
+    retval = UA_Client_readValueAttribute(client, nodeId, &value);
+
+    if(retval == UA_STATUSCODE_GOOD &&
+       UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME])) {
+        UA_DateTime raw_date = *(UA_DateTime *) value.data;
+        UA_DateTimeStruct dts = UA_DateTime_toStruct(raw_date);
+        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                    "date is: %u-%u-%u %u:%u:%u.%03u",
+                    dts.day, dts.month, dts.year, dts.hour,
+                    dts.min, dts.sec, dts.milliSec);
+    } else {
+        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                    "Reading the value failed with status code %s",
+                    UA_StatusCode_name(retval));
+    }
+
+    /* Clean up */
+    UA_Variant_clear(&value);
+    UA_Client_delete(client); /* Disconnects the client internally */
+    return 0;
+}
+
+
+

Compilation is similar to the server example.

+
$ gcc -std=c99 myClient.c -lopen62541 -o myClient
+
+
+

In a MinGW environment, the Winsock library must be added.

+
$ gcc -std=c99 myClient.c -lopen62541 -lws2_32 -o myClient.exe
+
+
+
+

Further tasks

+
    +
  • Try to connect to some other OPC UA server by changing +opc.tcp://localhost:4840 to an appropriate address (remember that the +queried node is contained in any OPC UA server).

  • +
  • Try to set the value of the variable node (ns=1,i=”the.answer”) containing +an Int32 from the example server (which is built in +Building a Simple Server) using “UA_Client_write” function. The +example server needs some more modifications, i.e., changing request types. +The answer can be found in examples/client.c.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/tutorial_datatypes.html b/static/doc/v1.4.0/tutorial_datatypes.html new file mode 100644 index 0000000000..1c99a314da --- /dev/null +++ b/static/doc/v1.4.0/tutorial_datatypes.html @@ -0,0 +1,323 @@ + + + + + + + Working with Data Types — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Working with Data Types

+

OPC UA defines a type system for values that can be encoded in the protocol +messages. This tutorial shows some examples for available data types and +their use. See the section on Data Types for the full definitions.

+
+

Basic Data Handling

+

This section shows the basic interaction patterns for data types. Make +sure to compare with the type definitions in types.h.

+
#include <open62541/plugin/log_stdout.h>
+#include <open62541/server.h>
+#include <open62541/server_config_default.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+static void
+variables_basic(void) {
+    /* Int32 */
+    UA_Int32 i = 5;
+    UA_Int32 j;
+    UA_Int32_copy(&i, &j);
+
+    UA_Int32 *ip = UA_Int32_new();
+    UA_Int32_copy(&i, ip);
+    UA_Int32_delete(ip);
+
+    /* String */
+    UA_String s;
+    UA_String_init(&s); /* _init zeroes out the entire memory of the datatype */
+    char *test = "test";
+    s.length = strlen(test);
+    s.data = (UA_Byte*)test;
+
+    UA_String s2;
+    UA_String_copy(&s, &s2);
+    UA_String_clear(&s2); /* Copying heap-allocated the dynamic content */
+
+    UA_String s3 = UA_STRING("test2");
+    UA_String s4 = UA_STRING_ALLOC("test2"); /* Copies the content to the heap */
+    UA_Boolean eq = UA_String_equal(&s3, &s4);
+    UA_String_clear(&s4);
+    if(!eq)
+        return;
+
+    /* Structured Type */
+    UA_ReadRequest rr;
+    UA_init(&rr, &UA_TYPES[UA_TYPES_READREQUEST]); /* Generic method */
+    UA_ReadRequest_init(&rr); /* Shorthand for the previous line */
+
+    rr.requestHeader.timestamp = UA_DateTime_now(); /* Members of a structure */
+
+    rr.nodesToRead = (UA_ReadValueId *)UA_Array_new(5, &UA_TYPES[UA_TYPES_READVALUEID]);
+    rr.nodesToReadSize = 5; /* Array size needs to be made known */
+
+    UA_ReadRequest *rr2 = UA_ReadRequest_new();
+    UA_copy(&rr, rr2, &UA_TYPES[UA_TYPES_READREQUEST]);
+    UA_ReadRequest_clear(&rr);
+    UA_ReadRequest_delete(rr2);
+}
+
+
+
+
+

NodeIds

+

An OPC UA information model is made up of nodes and references between nodes. +Every node has a unique NodeId. NodeIds refer to a namespace with an +additional identifier value that can be an integer, a string, a guid or a +bytestring.

+
static void
+variables_nodeids(void) {
+    UA_NodeId id1 = UA_NODEID_NUMERIC(1, 1234);
+    id1.namespaceIndex = 3;
+
+    UA_NodeId id2 = UA_NODEID_STRING(1, "testid"); /* the string is static */
+    UA_Boolean eq = UA_NodeId_equal(&id1, &id2);
+    if(eq)
+        return;
+
+    UA_NodeId id3;
+    UA_NodeId_copy(&id2, &id3);
+    UA_NodeId_clear(&id3);
+
+    UA_NodeId id4 = UA_NODEID_STRING_ALLOC(1, "testid"); /* the string is copied
+                                                            to the heap */
+    UA_NodeId_clear(&id4);
+}
+
+
+
+
+

Variants

+

The datatype Variant belongs to the built-in datatypes of OPC UA and +is used as a container type. A variant can hold any other datatype as a +scalar (except variant) or as an array. Array variants can additionally +denote the dimensionality of the data (e.g. a 2x3 matrix) in an additional +integer array.

+
static void
+variables_variants(void) {
+    /* Set a scalar value */
+    UA_Variant v;
+    UA_Int32 i = 42;
+    UA_Variant_setScalar(&v, &i, &UA_TYPES[UA_TYPES_INT32]);
+
+    /* Make a copy */
+    UA_Variant v2;
+    UA_Variant_copy(&v, &v2);
+    UA_Variant_clear(&v2);
+
+    /* Set an array value */
+    UA_Variant v3;
+    UA_Double d[9] = {1.0, 2.0, 3.0,
+                      4.0, 5.0, 6.0,
+                      7.0, 8.0, 9.0};
+    UA_Variant_setArrayCopy(&v3, d, 9, &UA_TYPES[UA_TYPES_DOUBLE]);
+
+    /* Set array dimensions */
+    v3.arrayDimensions = (UA_UInt32 *)UA_Array_new(2, &UA_TYPES[UA_TYPES_UINT32]);
+    v3.arrayDimensionsSize = 2;
+    v3.arrayDimensions[0] = 3;
+    v3.arrayDimensions[1] = 3;
+    UA_Variant_clear(&v3);
+}
+
+#ifdef UA_ENABLE_JSON_ENCODING
+static void
+prettyprint(void) {
+    UA_ReadRequest rr;
+    UA_ReadRequest_init(&rr);
+    UA_ReadValueId rvi[2];
+    UA_ReadValueId_init(rvi);
+    UA_ReadValueId_init(&rvi[1]);
+    rr.nodesToRead = rvi;
+    rr.nodesToReadSize = 2;
+    UA_String out = UA_STRING_NULL;
+    UA_print(&rr, &UA_TYPES[UA_TYPES_READREQUEST], &out);
+
+    printf("%.*s\n", (int)out.length, out.data);
+    UA_String_clear(&out);
+
+    UA_ReadResponse resp;
+    UA_ReadResponse_init(&resp);
+    UA_print(&resp, &UA_TYPES[UA_TYPES_READRESPONSE], &out);
+
+    printf("%.*s\n", (int)out.length, out.data);
+    UA_String_clear(&out);
+
+    UA_ReferenceDescription br;
+    UA_ReferenceDescription_init(&br);
+    br.nodeClass = (UA_NodeClass)5;
+    UA_print(&br, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], &out);
+    printf("%.*s\n", (int)out.length, out.data);
+    UA_String_clear(&out);
+
+    UA_Float matrix[4] = {1.0, 2.0, 3.0, 4.0};
+    UA_UInt32 matrix_dims[2] = {2, 2};
+    UA_DataValue dv;
+    UA_DataValue_init(&dv);
+    UA_Variant_setArray(&dv.value, &matrix, 4, &UA_TYPES[UA_TYPES_FLOAT]);
+    dv.value.arrayDimensions = matrix_dims;
+    dv.value.arrayDimensionsSize = 2;
+    dv.hasValue = true;
+    dv.hasStatus = true;
+    dv.hasServerTimestamp = true;
+    dv.hasSourcePicoseconds = true;
+    UA_print(&dv, &UA_TYPES[UA_TYPES_DATAVALUE], &out);
+    printf("%.*s\n", (int)out.length, out.data);
+    UA_String_clear(&out);
+}
+#endif
+
+
+

It follows the main function, making use of the above definitions.

+
int main(void) {
+    variables_basic();
+    variables_nodeids();
+    variables_variants();
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/tutorial_pubsub_publish.html b/static/doc/v1.4.0/tutorial_pubsub_publish.html new file mode 100644 index 0000000000..bc2a086a21 --- /dev/null +++ b/static/doc/v1.4.0/tutorial_pubsub_publish.html @@ -0,0 +1,340 @@ + + + + + + + Working with Publish/Subscribe — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Working with Publish/Subscribe

+

Work in progress: This Tutorial will be continuously extended during the next +PubSub batches. More details about the PubSub extension and corresponding +open62541 API are located here: PubSub.

+
+

Publishing Fields

+

The PubSub publish example demonstrates the simplest way to publish +information from the information model over UDP multicast using the UADP +encoding.

+

Connection handling

+

PubSubConnections can be created and deleted on runtime. More details about +the system preconfiguration and connection can be found in +tutorial_pubsub_connection.c.

+
#include <open62541/plugin/log_stdout.h>
+#include <open62541/server.h>
+#include <open62541/server_pubsub.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+UA_NodeId connectionIdent, publishedDataSetIdent, writerGroupIdent;
+
+static void
+addPubSubConnection(UA_Server *server, UA_String *transportProfile,
+                    UA_NetworkAddressUrlDataType *networkAddressUrl){
+    /* Details about the connection configuration and handling are located
+     * in the pubsub connection tutorial */
+    UA_PubSubConnectionConfig connectionConfig;
+    memset(&connectionConfig, 0, sizeof(connectionConfig));
+    connectionConfig.name = UA_STRING("UADP Connection 1");
+    connectionConfig.transportProfileUri = *transportProfile;
+    connectionConfig.enabled = UA_TRUE;
+    UA_Variant_setScalar(&connectionConfig.address, networkAddressUrl,
+                         &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);
+    /* Changed to static publisherId from random generation to identify
+     * the publisher on Subscriber side */
+    connectionConfig.publisherIdType = UA_PUBLISHERIDTYPE_UINT16;
+    connectionConfig.publisherId.uint16 = 2234;
+    UA_Server_addPubSubConnection(server, &connectionConfig, &connectionIdent);
+}
+
+
+

PublishedDataSet handling

+

The PublishedDataSet (PDS) and PubSubConnection are the toplevel entities and +can exist alone. The PDS contains the collection of the published fields. All +other PubSub elements are directly or indirectly linked with the PDS or +connection.

+
static void
+addPublishedDataSet(UA_Server *server) {
+    /* The PublishedDataSetConfig contains all necessary public
+    * information for the creation of a new PublishedDataSet */
+    UA_PublishedDataSetConfig publishedDataSetConfig;
+    memset(&publishedDataSetConfig, 0, sizeof(UA_PublishedDataSetConfig));
+    publishedDataSetConfig.publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDITEMS;
+    publishedDataSetConfig.name = UA_STRING("Demo PDS");
+    /* Create new PublishedDataSet based on the PublishedDataSetConfig. */
+    UA_Server_addPublishedDataSet(server, &publishedDataSetConfig, &publishedDataSetIdent);
+}
+
+
+

DataSetField handling

+

The DataSetField (DSF) is part of the PDS and describes exactly one published +field.

+
static void
+addDataSetField(UA_Server *server) {
+    /* Add a field to the previous created PublishedDataSet */
+    UA_NodeId dataSetFieldIdent;
+    UA_DataSetFieldConfig dataSetFieldConfig;
+    memset(&dataSetFieldConfig, 0, sizeof(UA_DataSetFieldConfig));
+    dataSetFieldConfig.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE;
+    dataSetFieldConfig.field.variable.fieldNameAlias = UA_STRING("Server localtime");
+    dataSetFieldConfig.field.variable.promotedField = UA_FALSE;
+    dataSetFieldConfig.field.variable.publishParameters.publishedVariable =
+    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
+    dataSetFieldConfig.field.variable.publishParameters.attributeId = UA_ATTRIBUTEID_VALUE;
+    UA_Server_addDataSetField(server, publishedDataSetIdent,
+                              &dataSetFieldConfig, &dataSetFieldIdent);
+}
+
+
+

WriterGroup handling

+

The WriterGroup (WG) is part of the connection and contains the primary +configuration parameters for the message creation.

+
static void
+addWriterGroup(UA_Server *server) {
+    /* Now we create a new WriterGroupConfig and add the group to the existing
+     * PubSubConnection. */
+    UA_WriterGroupConfig writerGroupConfig;
+    memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
+    writerGroupConfig.name = UA_STRING("Demo WriterGroup");
+    writerGroupConfig.publishingInterval = 100;
+    writerGroupConfig.enabled = UA_FALSE;
+    writerGroupConfig.writerGroupId = 100;
+    writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
+    writerGroupConfig.messageSettings.encoding             = UA_EXTENSIONOBJECT_DECODED;
+    writerGroupConfig.messageSettings.content.decoded.type = &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE];
+    /* The configuration flags for the messages are encapsulated inside the
+     * message- and transport settings extension objects. These extension
+     * objects are defined by the standard. e.g.
+     * UadpWriterGroupMessageDataType */
+    UA_UadpWriterGroupMessageDataType *writerGroupMessage  = UA_UadpWriterGroupMessageDataType_new();
+    /* Change message settings of writerGroup to send PublisherId,
+     * WriterGroupId in GroupHeader and DataSetWriterId in PayloadHeader
+     * of NetworkMessage */
+    writerGroupMessage->networkMessageContentMask          = (UA_UadpNetworkMessageContentMask)(UA_UADPNETWORKMESSAGECONTENTMASK_PUBLISHERID |
+                                                              (UA_UadpNetworkMessageContentMask)UA_UADPNETWORKMESSAGECONTENTMASK_GROUPHEADER |
+                                                              (UA_UadpNetworkMessageContentMask)UA_UADPNETWORKMESSAGECONTENTMASK_WRITERGROUPID |
+                                                              (UA_UadpNetworkMessageContentMask)UA_UADPNETWORKMESSAGECONTENTMASK_PAYLOADHEADER);
+    writerGroupConfig.messageSettings.content.decoded.data = writerGroupMessage;
+    UA_Server_addWriterGroup(server, connectionIdent, &writerGroupConfig, &writerGroupIdent);
+    UA_Server_setWriterGroupOperational(server, writerGroupIdent);
+    UA_UadpWriterGroupMessageDataType_delete(writerGroupMessage);
+}
+
+
+

DataSetWriter handling

+

A DataSetWriter (DSW) is the glue between the WG and the PDS. The DSW is +linked to exactly one PDS and contains additional information for the +message generation.

+
static void
+addDataSetWriter(UA_Server *server) {
+    /* We need now a DataSetWriter within the WriterGroup. This means we must
+     * create a new DataSetWriterConfig and add call the addWriterGroup function. */
+    UA_NodeId dataSetWriterIdent;
+    UA_DataSetWriterConfig dataSetWriterConfig;
+    memset(&dataSetWriterConfig, 0, sizeof(UA_DataSetWriterConfig));
+    dataSetWriterConfig.name = UA_STRING("Demo DataSetWriter");
+    dataSetWriterConfig.dataSetWriterId = 62541;
+    dataSetWriterConfig.keyFrameCount = 10;
+    UA_Server_addDataSetWriter(server, writerGroupIdent, publishedDataSetIdent,
+                               &dataSetWriterConfig, &dataSetWriterIdent);
+}
+
+
+

That’s it! You’re now publishing the selected fields. Open a packet +inspection tool of trust e.g. wireshark and take a look on the outgoing +packages. The following graphic figures out the packages created by this +tutorial.

+
+OPC UA PubSub communication in wireshark +
+

The open62541 subscriber API will be released later. If you want to process +the the datagrams, take a look on the ua_network_pubsub_networkmessage.c +which already contains the decoding code for UADP messages.

+

It follows the main server code, making use of the above definitions.

+
static int run(UA_String *transportProfile,
+               UA_NetworkAddressUrlDataType *networkAddressUrl) {
+    UA_Server *server = UA_Server_new();
+
+    addPubSubConnection(server, transportProfile, networkAddressUrl);
+    addPublishedDataSet(server);
+    addDataSetField(server);
+    addWriterGroup(server);
+    addDataSetWriter(server);
+
+    UA_StatusCode retval = UA_Server_runUntilInterrupt(server);
+
+    UA_Server_delete(server);
+    return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static void
+usage(char *progname) {
+    printf("usage: %s <uri> [device]\n", progname);
+}
+
+int main(int argc, char **argv) {
+    UA_String transportProfile =
+        UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
+    UA_NetworkAddressUrlDataType networkAddressUrl =
+        {UA_STRING_NULL , UA_STRING("opc.udp://224.0.0.22:4840/")};
+
+    if (argc > 1) {
+        if (strcmp(argv[1], "-h") == 0) {
+            usage(argv[0]);
+            return EXIT_SUCCESS;
+        } else if (strncmp(argv[1], "opc.udp://", 10) == 0) {
+            networkAddressUrl.url = UA_STRING(argv[1]);
+        } else if (strncmp(argv[1], "opc.eth://", 10) == 0) {
+            transportProfile =
+                UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp");
+            if (argc < 3) {
+                printf("Error: UADP/ETH needs an interface name\n");
+                return EXIT_FAILURE;
+            }
+            networkAddressUrl.networkInterface = UA_STRING(argv[2]);
+            networkAddressUrl.url = UA_STRING(argv[1]);
+        } else {
+            printf("Error: unknown URI\n");
+            return EXIT_FAILURE;
+        }
+    }
+
+    return run(&transportProfile, &networkAddressUrl);
+}
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/tutorial_pubsub_subscribe.html b/static/doc/v1.4.0/tutorial_pubsub_subscribe.html new file mode 100644 index 0000000000..3c750ccfc3 --- /dev/null +++ b/static/doc/v1.4.0/tutorial_pubsub_subscribe.html @@ -0,0 +1,443 @@ + + + + + + + Subscribing Fields — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Subscribing Fields

+

The PubSub subscribe example demonstrates the simplest way to receive +information over two transport layers such as UDP and Ethernet, that are +published by tutorial_pubsub_publish example and update values in the +TargetVariables of Subscriber Information Model.

+
#include <open62541/plugin/log_stdout.h>
+#include <open62541/server.h>
+#include <open62541/server_pubsub.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+UA_NodeId connectionIdentifier;
+UA_NodeId readerGroupIdentifier;
+UA_NodeId readerIdentifier;
+
+UA_DataSetReaderConfig readerConfig;
+
+static void fillTestDataSetMetaData(UA_DataSetMetaDataType *pMetaData);
+
+/* Add new connection to the server */
+static UA_StatusCode
+addPubSubConnection(UA_Server *server, UA_String *transportProfile,
+                    UA_NetworkAddressUrlDataType *networkAddressUrl) {
+    if((server == NULL) || (transportProfile == NULL) ||
+        (networkAddressUrl == NULL)) {
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    /* Configuration creation for the connection */
+    UA_PubSubConnectionConfig connectionConfig;
+    memset (&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig));
+    connectionConfig.name = UA_STRING("UDPMC Connection 1");
+    connectionConfig.transportProfileUri = *transportProfile;
+    connectionConfig.enabled = UA_TRUE;
+    UA_Variant_setScalar(&connectionConfig.address, networkAddressUrl,
+                         &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);
+    connectionConfig.publisherIdType = UA_PUBLISHERIDTYPE_UINT32;
+    connectionConfig.publisherId.uint32 = UA_UInt32_random();
+    retval |= UA_Server_addPubSubConnection (server, &connectionConfig, &connectionIdentifier);
+    if (retval != UA_STATUSCODE_GOOD) {
+        return retval;
+    }
+
+    return retval;
+}
+
+
+

ReaderGroup

+

ReaderGroup is used to group a list of DataSetReaders. All ReaderGroups are +created within a PubSubConnection and automatically deleted if the connection +is removed. All network message related filters are only available in the DataSetReader.

+
/* Add ReaderGroup to the created connection */
+static UA_StatusCode
+addReaderGroup(UA_Server *server) {
+    if(server == NULL) {
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    UA_ReaderGroupConfig readerGroupConfig;
+    memset (&readerGroupConfig, 0, sizeof(UA_ReaderGroupConfig));
+    readerGroupConfig.name = UA_STRING("ReaderGroup1");
+    retval |= UA_Server_addReaderGroup(server, connectionIdentifier, &readerGroupConfig,
+                                       &readerGroupIdentifier);
+    UA_Server_setReaderGroupOperational(server, readerGroupIdentifier);
+    return retval;
+}
+
+
+

DataSetReader

+

DataSetReader can receive NetworkMessages with the DataSetMessage +of interest sent by the Publisher. DataSetReader provides +the configuration necessary to receive and process DataSetMessages +on the Subscriber side. DataSetReader must be linked with a +SubscribedDataSet and be contained within a ReaderGroup.

+
/* Add DataSetReader to the ReaderGroup */
+static UA_StatusCode
+addDataSetReader(UA_Server *server) {
+    if(server == NULL) {
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    memset (&readerConfig, 0, sizeof(UA_DataSetReaderConfig));
+    readerConfig.name = UA_STRING("DataSet Reader 1");
+    /* Parameters to filter which DataSetMessage has to be processed
+     * by the DataSetReader */
+    /* The following parameters are used to show that the data published by
+     * tutorial_pubsub_publish.c is being subscribed and is being updated in
+     * the information model */
+    UA_UInt16 publisherIdentifier = 2234;
+    readerConfig.publisherId.type = &UA_TYPES[UA_TYPES_UINT16];
+    readerConfig.publisherId.data = &publisherIdentifier;
+    readerConfig.writerGroupId    = 100;
+    readerConfig.dataSetWriterId  = 62541;
+
+    /* Setting up Meta data configuration in DataSetReader */
+    fillTestDataSetMetaData(&readerConfig.dataSetMetaData);
+
+    retval |= UA_Server_addDataSetReader(server, readerGroupIdentifier, &readerConfig,
+                                         &readerIdentifier);
+    return retval;
+}
+
+
+

SubscribedDataSet

+

Set SubscribedDataSet type to TargetVariables data type. +Add subscribedvariables to the DataSetReader

+
static UA_StatusCode
+addSubscribedVariables (UA_Server *server, UA_NodeId dataSetReaderId) {
+    if(server == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    UA_NodeId folderId;
+    UA_String folderName = readerConfig.dataSetMetaData.name;
+    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
+    UA_QualifiedName folderBrowseName;
+    if(folderName.length > 0) {
+        oAttr.displayName.locale = UA_STRING ("en-US");
+        oAttr.displayName.text = folderName;
+        folderBrowseName.namespaceIndex = 1;
+        folderBrowseName.name = folderName;
+    }
+    else {
+        oAttr.displayName = UA_LOCALIZEDTEXT ("en-US", "Subscribed Variables");
+        folderBrowseName = UA_QUALIFIEDNAME (1, "Subscribed Variables");
+    }
+
+    UA_Server_addObjectNode (server, UA_NODEID_NULL,
+                             UA_NODEID_NUMERIC (0, UA_NS0ID_OBJECTSFOLDER),
+                             UA_NODEID_NUMERIC (0, UA_NS0ID_ORGANIZES),
+                             folderBrowseName, UA_NODEID_NUMERIC (0,
+                             UA_NS0ID_BASEOBJECTTYPE), oAttr, NULL, &folderId);
+
+
+

TargetVariables

+

The SubscribedDataSet option TargetVariables defines a list of Variable mappings between +received DataSet fields and target Variables in the Subscriber AddressSpace. +The values subscribed from the Publisher are updated in the value field of these variables

+
    /* Create the TargetVariables with respect to DataSetMetaData fields */
+    UA_FieldTargetVariable *targetVars = (UA_FieldTargetVariable *)
+            UA_calloc(readerConfig.dataSetMetaData.fieldsSize, sizeof(UA_FieldTargetVariable));
+    for(size_t i = 0; i < readerConfig.dataSetMetaData.fieldsSize; i++) {
+        /* Variable to subscribe data */
+        UA_VariableAttributes vAttr = UA_VariableAttributes_default;
+        UA_LocalizedText_copy(&readerConfig.dataSetMetaData.fields[i].description,
+                              &vAttr.description);
+        vAttr.displayName.locale = UA_STRING("en-US");
+        vAttr.displayName.text = readerConfig.dataSetMetaData.fields[i].name;
+        vAttr.dataType = readerConfig.dataSetMetaData.fields[i].dataType;
+
+        UA_NodeId newNode;
+        retval |= UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, (UA_UInt32)i + 50000),
+                                           folderId,
+                                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                                           UA_QUALIFIEDNAME(1, (char *)readerConfig.dataSetMetaData.fields[i].name.data),
+                                           UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                           vAttr, NULL, &newNode);
+
+        /* For creating Targetvariables */
+        UA_FieldTargetDataType_init(&targetVars[i].targetVariable);
+        targetVars[i].targetVariable.attributeId  = UA_ATTRIBUTEID_VALUE;
+        targetVars[i].targetVariable.targetNodeId = newNode;
+    }
+
+    retval = UA_Server_DataSetReader_createTargetVariables(server, dataSetReaderId,
+                                                           readerConfig.dataSetMetaData.fieldsSize, targetVars);
+    for(size_t i = 0; i < readerConfig.dataSetMetaData.fieldsSize; i++)
+        UA_FieldTargetDataType_clear(&targetVars[i].targetVariable);
+
+    UA_free(targetVars);
+    UA_free(readerConfig.dataSetMetaData.fields);
+    return retval;
+}
+
+
+

DataSetMetaData

+

The DataSetMetaData describes the content of a DataSet. It provides the information necessary to decode +DataSetMessages on the Subscriber side. DataSetMessages received from the Publisher are decoded into +DataSet and each field is updated in the Subscriber based on datatype match of TargetVariable fields of Subscriber +and PublishedDataSetFields of Publisher

+
/* Define MetaData for TargetVariables */
+static void fillTestDataSetMetaData(UA_DataSetMetaDataType *pMetaData) {
+    if(pMetaData == NULL) {
+        return;
+    }
+
+    UA_DataSetMetaDataType_init (pMetaData);
+    pMetaData->name = UA_STRING ("DataSet 1");
+
+    /* Static definition of number of fields size to 4 to create four different
+     * targetVariables of distinct datatype
+     * Currently the publisher sends only DateTime data type */
+    pMetaData->fieldsSize = 4;
+    pMetaData->fields = (UA_FieldMetaData*)UA_Array_new (pMetaData->fieldsSize,
+                         &UA_TYPES[UA_TYPES_FIELDMETADATA]);
+
+    /* DateTime DataType */
+    UA_FieldMetaData_init (&pMetaData->fields[0]);
+    UA_NodeId_copy (&UA_TYPES[UA_TYPES_DATETIME].typeId,
+                    &pMetaData->fields[0].dataType);
+    pMetaData->fields[0].builtInType = UA_NS0ID_DATETIME;
+    pMetaData->fields[0].name =  UA_STRING ("DateTime");
+    pMetaData->fields[0].valueRank = -1; /* scalar */
+
+    /* Int32 DataType */
+    UA_FieldMetaData_init (&pMetaData->fields[1]);
+    UA_NodeId_copy(&UA_TYPES[UA_TYPES_INT32].typeId,
+                   &pMetaData->fields[1].dataType);
+    pMetaData->fields[1].builtInType = UA_NS0ID_INT32;
+    pMetaData->fields[1].name =  UA_STRING ("Int32");
+    pMetaData->fields[1].valueRank = -1; /* scalar */
+
+    /* Int64 DataType */
+    UA_FieldMetaData_init (&pMetaData->fields[2]);
+    UA_NodeId_copy(&UA_TYPES[UA_TYPES_INT64].typeId,
+                   &pMetaData->fields[2].dataType);
+    pMetaData->fields[2].builtInType = UA_NS0ID_INT64;
+    pMetaData->fields[2].name =  UA_STRING ("Int64");
+    pMetaData->fields[2].valueRank = -1; /* scalar */
+
+    /* Boolean DataType */
+    UA_FieldMetaData_init (&pMetaData->fields[3]);
+    UA_NodeId_copy (&UA_TYPES[UA_TYPES_BOOLEAN].typeId,
+                    &pMetaData->fields[3].dataType);
+    pMetaData->fields[3].builtInType = UA_NS0ID_BOOLEAN;
+    pMetaData->fields[3].name =  UA_STRING ("BoolToggle");
+    pMetaData->fields[3].valueRank = -1; /* scalar */
+}
+
+
+

Followed by the main server code, making use of the above definitions

+
static int
+run(UA_String *transportProfile, UA_NetworkAddressUrlDataType *networkAddressUrl) {
+    /* Return value initialized to Status Good */
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    UA_Server *server = UA_Server_new();
+
+    /* API calls */
+    /* Add PubSubConnection */
+    retval |= addPubSubConnection(server, transportProfile, networkAddressUrl);
+    if (retval != UA_STATUSCODE_GOOD)
+        return EXIT_FAILURE;
+
+    /* Add ReaderGroup to the created PubSubConnection */
+    retval |= addReaderGroup(server);
+    if (retval != UA_STATUSCODE_GOOD)
+        return EXIT_FAILURE;
+
+    /* Add DataSetReader to the created ReaderGroup */
+    retval |= addDataSetReader(server);
+    if (retval != UA_STATUSCODE_GOOD)
+        return EXIT_FAILURE;
+
+    /* Add SubscribedVariables to the created DataSetReader */
+    retval |= addSubscribedVariables(server, readerIdentifier);
+    if (retval != UA_STATUSCODE_GOOD)
+        return EXIT_FAILURE;
+
+    retval = UA_Server_runUntilInterrupt(server);
+
+    UA_Server_delete(server);
+    return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static void
+usage(char *progname) {
+    printf("usage: %s <uri> [device]\n", progname);
+}
+
+int main(int argc, char **argv) {
+    UA_String transportProfile =
+        UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
+    UA_NetworkAddressUrlDataType networkAddressUrl =
+        {UA_STRING_NULL , UA_STRING("opc.udp://224.0.0.22:4840/")};
+    if(argc > 1) {
+        if(strcmp(argv[1], "-h") == 0) {
+            usage(argv[0]);
+            return EXIT_SUCCESS;
+        } else if(strncmp(argv[1], "opc.udp://", 10) == 0) {
+            networkAddressUrl.url = UA_STRING(argv[1]);
+        } else if(strncmp(argv[1], "opc.eth://", 10) == 0) {
+            transportProfile =
+                UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp");
+            if(argc < 3) {
+                printf("Error: UADP/ETH needs an interface name\n");
+                return EXIT_FAILURE;
+            }
+
+            networkAddressUrl.networkInterface = UA_STRING(argv[2]);
+            networkAddressUrl.url = UA_STRING(argv[1]);
+        } else {
+            printf ("Error: unknown URI\n");
+            return EXIT_FAILURE;
+        }
+    }
+
+    return run(&transportProfile, &networkAddressUrl);
+}
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/tutorial_server_alarms_conditions.html b/static/doc/v1.4.0/tutorial_server_alarms_conditions.html new file mode 100644 index 0000000000..7e5a2172bf --- /dev/null +++ b/static/doc/v1.4.0/tutorial_server_alarms_conditions.html @@ -0,0 +1,687 @@ + + + + + + + Using Alarms and Conditions Server — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Using Alarms and Conditions Server

+

Besides the usage of monitored items and events to observe the changes in the +server, it is also important to make use of the Alarms and Conditions Server +Model. Alarms are events which are triggered automatically by the server +dependent on internal server logic or user specific logic when the states of +server components change. The state of a component is represented through a +condition. So the values of all the condition children (Fields) are the +actual state of the component.

+
+

Trigger Alarm events by changing States

+

The following example will be based on the server events tutorial. Please +make sure to understand the principle of normal events before proceeding with +this example!

+
static UA_NodeId conditionSource;
+static UA_NodeId conditionInstance_1;
+static UA_NodeId conditionInstance_2;
+
+static UA_StatusCode
+addConditionSourceObject(UA_Server *server) {
+    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
+    object_attr.eventNotifier = 1;
+
+    object_attr.displayName = UA_LOCALIZEDTEXT("en", "ConditionSourceObject");
+    UA_StatusCode retval =  UA_Server_addObjectNode(server, UA_NODEID_NULL,
+                                      UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                      UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                      UA_QUALIFIEDNAME(0, "ConditionSourceObject"),
+                                      UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
+                                      object_attr, NULL, &conditionSource);
+
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Creating Condition Source failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+    }
+
+    /* ConditionSource should be EventNotifier of another Object (usually the
+     * Server Object). If this Reference is not created by user then the A&C
+     * Server will create "HasEventSource" reference to the Server Object
+     * automatically when the condition is created*/
+    retval = UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
+                                     UA_NODEID_NUMERIC(0, UA_NS0ID_HASNOTIFIER),
+                                     UA_EXPANDEDNODEID_NUMERIC(conditionSource.namespaceIndex,
+                                                               conditionSource.identifier.numeric),
+                                     UA_TRUE);
+
+    return retval;
+}
+
+
+

Create a condition instance from OffNormalAlarmType. The condition source is +the Object created in addConditionSourceObject(). The condition will be +exposed in Address Space through the HasComponent reference to the condition +source.

+
static UA_StatusCode
+addCondition_1(UA_Server *server) {
+    UA_StatusCode retval = addConditionSourceObject(server);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "creating Condition Source failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+    }
+
+    retval = UA_Server_createCondition(server,
+                                       UA_NODEID_NULL,
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_OFFNORMALALARMTYPE),
+                                       UA_QUALIFIEDNAME(0, "Condition 1"), conditionSource,
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                                       &conditionInstance_1);
+
+    return retval;
+}
+
+
+

Create a condition instance from OffNormalAlarmType. The condition source is +the server Object. The condition won’t be exposed in Address Space.

+
static UA_StatusCode
+addCondition_2(UA_Server *server) {
+    UA_StatusCode retval =
+        UA_Server_createCondition(server, UA_NODEID_NULL,
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_OFFNORMALALARMTYPE),
+                                  UA_QUALIFIEDNAME(0, "Condition 2"),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
+                                  UA_NODEID_NULL, &conditionInstance_2);
+
+    return retval;
+}
+
+static void
+addVariable_1_triggerAlarmOfCondition_1(UA_Server *server, UA_NodeId* outNodeId) {
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
+    attr.displayName = UA_LOCALIZEDTEXT("en", "Activate Condition 1");
+    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
+    UA_Boolean tboolValue = UA_FALSE;
+    UA_Variant_setScalar(&attr.value, &tboolValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
+
+    UA_QualifiedName CallbackTestVariableName = UA_QUALIFIEDNAME(0, "Activate Condition 1");
+    UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+    UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+    UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
+    UA_Server_addVariableNode(server, UA_NODEID_NULL, parentNodeId,
+                              parentReferenceNodeId, CallbackTestVariableName,
+                              variableTypeNodeId, attr, NULL, outNodeId);
+}
+
+static void
+addVariable_2_changeSeverityOfCondition_2(UA_Server *server,
+                                          UA_NodeId* outNodeId) {
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
+    attr.displayName = UA_LOCALIZEDTEXT("en", "Change Severity Condition 2");
+    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
+    UA_UInt16 severityValue = 0;
+    UA_Variant_setScalar(&attr.value, &severityValue, &UA_TYPES[UA_TYPES_UINT16]);
+
+    UA_QualifiedName CallbackTestVariableName =
+        UA_QUALIFIEDNAME(0, "Change Severity Condition 2");
+    UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+    UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+    UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
+    UA_Server_addVariableNode(server, UA_NODEID_NULL, parentNodeId,
+                              parentReferenceNodeId, CallbackTestVariableName,
+                              variableTypeNodeId, attr, NULL, outNodeId);
+}
+
+static void
+addVariable_3_returnCondition_1_toNormalState(UA_Server *server,
+                                              UA_NodeId* outNodeId) {
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
+    attr.displayName = UA_LOCALIZEDTEXT("en", "Return to Normal Condition 1");
+    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
+    UA_Boolean rtn = 0;
+    UA_Variant_setScalar(&attr.value, &rtn, &UA_TYPES[UA_TYPES_BOOLEAN]);
+
+    UA_QualifiedName CallbackTestVariableName =
+        UA_QUALIFIEDNAME(0, "Return to Normal Condition 1");
+    UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+    UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+    UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
+    UA_Server_addVariableNode(server, UA_NODEID_NULL, parentNodeId,
+                              parentReferenceNodeId, CallbackTestVariableName,
+                              variableTypeNodeId, attr, NULL, outNodeId);
+}
+
+static void
+afterWriteCallbackVariable_1(UA_Server *server, const UA_NodeId *sessionId,
+                             void *sessionContext, const UA_NodeId *nodeId,
+                             void *nodeContext, const UA_NumericRange *range,
+                             const UA_DataValue *data) {
+    UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState");
+    UA_QualifiedName activeStateIdField = UA_QUALIFIEDNAME(0,"Id");
+    UA_Variant value;
+
+    UA_StatusCode retval =
+        UA_Server_writeObjectProperty_scalar(server, conditionInstance_1,
+                                             UA_QUALIFIEDNAME(0, "Time"),
+                                             &data->sourceTimestamp,
+                                             &UA_TYPES[UA_TYPES_DATETIME]);
+
+    if(*(UA_Boolean *)(data->value.data) == true) {
+        /* By writing "true" in ActiveState/Id, the A&C server will set the
+         * related fields automatically and then will trigger event
+         * notification. */
+        UA_Boolean activeStateId = true;
+        UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]);
+        retval |= UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1,
+                                                              &value, activeStateField,
+                                                              activeStateIdField);
+        if(retval != UA_STATUSCODE_GOOD) {
+            UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                         "Setting ActiveState/Id Field failed. StatusCode %s",
+                         UA_StatusCode_name(retval));
+            return;
+        }
+    } else {
+        /* By writing "false" in ActiveState/Id, the A&C server will set only
+         * the ActiveState field automatically to the value "Inactive". The user
+         * should trigger the event manually by calling
+         * UA_Server_triggerConditionEvent inside the application or call
+         * ConditionRefresh method with client to update the event notification. */
+        UA_Boolean activeStateId = false;
+        UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]);
+        retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1,
+                                                             &value, activeStateField,
+                                                             activeStateIdField);
+        if(retval != UA_STATUSCODE_GOOD) {
+            UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                         "Setting ActiveState/Id Field failed. StatusCode %s",
+                         UA_StatusCode_name(retval));
+            return;
+        }
+
+        retval = UA_Server_triggerConditionEvent(server, conditionInstance_1,
+                                                 conditionSource, NULL);
+        if(retval != UA_STATUSCODE_GOOD) {
+            UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                           "Triggering condition event failed. StatusCode %s",
+                           UA_StatusCode_name(retval));
+            return;
+        }
+    }
+}
+
+
+

The callback only changes the severity field of the condition 2. The severity +field is of ConditionVariableType, so changes in it triggers an event +notification automatically by the server.

+
static void
+afterWriteCallbackVariable_2(UA_Server *server, const UA_NodeId *sessionId,
+                             void *sessionContext, const UA_NodeId *nodeId,
+                             void *nodeContext, const UA_NumericRange *range,
+                             const UA_DataValue *data) {
+   /* Another way to set fields of conditions */
+    UA_Server_writeObjectProperty_scalar(server, conditionInstance_2,
+                                         UA_QUALIFIEDNAME(0, "Severity"),
+                                         (UA_UInt16 *)data->value.data,
+                                         &UA_TYPES[UA_TYPES_UINT16]);
+}
+
+
+

RTN = return to normal.

+

Retain will be set to false, thus no events will be generated for condition 1 +(although EnabledState/=true). To set Retain to true again, the disable and +enable methods should be called respectively.

+
static void
+afterWriteCallbackVariable_3(UA_Server *server,
+               const UA_NodeId *sessionId, void *sessionContext,
+               const UA_NodeId *nodeId, void *nodeContext,
+               const UA_NumericRange *range, const UA_DataValue *data) {
+
+    //UA_QualifiedName enabledStateField = UA_QUALIFIEDNAME(0,"EnabledState");
+    UA_QualifiedName ackedStateField = UA_QUALIFIEDNAME(0,"AckedState");
+    UA_QualifiedName confirmedStateField = UA_QUALIFIEDNAME(0,"ConfirmedState");
+    UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState");
+    UA_QualifiedName severityField = UA_QUALIFIEDNAME(0,"Severity");
+    UA_QualifiedName messageField = UA_QUALIFIEDNAME(0,"Message");
+    UA_QualifiedName commentField = UA_QUALIFIEDNAME(0,"Comment");
+    UA_QualifiedName retainField = UA_QUALIFIEDNAME(0,"Retain");
+    UA_QualifiedName idField = UA_QUALIFIEDNAME(0,"Id");
+
+    UA_StatusCode retval =
+        UA_Server_writeObjectProperty_scalar(server, conditionInstance_1,
+                                             UA_QUALIFIEDNAME(0, "Time"),
+                                             &data->serverTimestamp,
+                                             &UA_TYPES[UA_TYPES_DATETIME]);
+    UA_Variant value;
+    UA_Boolean idValue = false;
+    UA_Variant_setScalar(&value, &idValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    retval |= UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1,
+                                                          &value, activeStateField,
+                                                          idField);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Setting ActiveState/Id Field failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return;
+    }
+
+    retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1,
+                                                         &value, ackedStateField,
+                                                         idField);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Setting AckedState/Id Field failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return;
+    }
+
+    retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1,
+                                                         &value, confirmedStateField,
+                                                         idField);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Setting ConfirmedState/Id Field failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return;
+    }
+
+    UA_UInt16 severityValue = 100;
+    UA_Variant_setScalar(&value, &severityValue, &UA_TYPES[UA_TYPES_UINT16]);
+    retval = UA_Server_setConditionField(server, conditionInstance_1,
+                                         &value, severityField);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Setting Severity Field failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return;
+    }
+
+    UA_LocalizedText messageValue =
+        UA_LOCALIZEDTEXT("en", "Condition returned to normal state");
+    UA_Variant_setScalar(&value, &messageValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+    retval = UA_Server_setConditionField(server, conditionInstance_1,
+                                         &value, messageField);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Setting Message Field failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return;
+    }
+
+    UA_LocalizedText commentValue = UA_LOCALIZEDTEXT("en", "Normal State");
+    UA_Variant_setScalar(&value, &commentValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+    retval = UA_Server_setConditionField(server, conditionInstance_1,
+                                         &value, commentField);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Setting Comment Field failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return;
+    }
+
+    UA_Boolean retainValue = false;
+    UA_Variant_setScalar(&value, &retainValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    retval = UA_Server_setConditionField(server, conditionInstance_1,
+                                         &value, retainField);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Setting Retain Field failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return;
+    }
+
+    retval = UA_Server_triggerConditionEvent(server, conditionInstance_1,
+                                             conditionSource, NULL);
+    if (retval != UA_STATUSCODE_GOOD) {
+     UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                    "Triggering condition event failed. StatusCode %s",
+                    UA_StatusCode_name(retval));
+     return;
+    }
+}
+
+static UA_StatusCode
+enteringEnabledStateCallback(UA_Server *server, const UA_NodeId *condition) {
+    UA_Boolean retain = true;
+    return UA_Server_writeObjectProperty_scalar(server, *condition,
+                                                UA_QUALIFIEDNAME(0, "Retain"),
+                                                &retain,
+                                                &UA_TYPES[UA_TYPES_BOOLEAN]);
+}
+
+
+

This is user specific function which will be called upon acknowledging an +alarm notification. In this example we will set the Alarm to Inactive state. +The server is responsible of setting standard fields related to Acknowledge +Method and triggering the alarm notification.

+
static UA_StatusCode
+enteringAckedStateCallback(UA_Server *server, const UA_NodeId *condition) {
+    /* deactivate Alarm when acknowledging*/
+    UA_Boolean activeStateId = false;
+    UA_Variant value;
+    UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState");
+    UA_QualifiedName activeStateIdField = UA_QUALIFIEDNAME(0,"Id");
+
+    UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    UA_StatusCode retval =
+        UA_Server_setConditionVariableFieldProperty(server, *condition,
+                                                    &value, activeStateField,
+                                                    activeStateIdField);
+
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Setting ActiveState/Id Field failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+    }
+
+    return retval;
+}
+
+static UA_StatusCode
+enteringConfirmedStateCallback(UA_Server *server, const UA_NodeId *condition) {
+     /* Deactivate Alarm and put it out of the interesting state (by writing
+     * false to Retain field) when confirming*/
+    UA_Boolean activeStateId = false;
+    UA_Boolean retain = false;
+    UA_Variant value;
+    UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState");
+    UA_QualifiedName activeStateIdField = UA_QUALIFIEDNAME(0,"Id");
+    UA_QualifiedName retainField = UA_QUALIFIEDNAME(0,"Retain");
+
+    UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    UA_StatusCode retval =
+        UA_Server_setConditionVariableFieldProperty(server, *condition,
+                                                    &value, activeStateField,
+                                                    activeStateIdField);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Setting ActiveState/Id Field failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return retval;
+    }
+
+    UA_Variant_setScalar(&value, &retain, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    retval = UA_Server_setConditionField(server, *condition,
+                                         &value, retainField);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Setting ActiveState/Id Field failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+    }
+
+    return retval;
+}
+
+static UA_StatusCode
+setUpEnvironment(UA_Server *server) {
+    UA_NodeId variable_1;
+    UA_NodeId variable_2;
+    UA_NodeId variable_3;
+    UA_ValueCallback callback;
+    callback.onRead = NULL;
+
+    /* Exposed condition 1. We will add to it user specific callbacks when
+     * entering enabled state, when acknowledging and when confirming. */
+    UA_StatusCode retval = addCondition_1(server);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "adding condition 1 failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return retval;
+    }
+
+    UA_TwoStateVariableChangeCallback userSpecificCallback = enteringEnabledStateCallback;
+    retval = UA_Server_setConditionTwoStateVariableCallback(server, conditionInstance_1,
+                                                            conditionSource, false,
+                                                            userSpecificCallback,
+                                                            UA_ENTERING_ENABLEDSTATE);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "adding entering enabled state callback failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return retval;
+    }
+
+    userSpecificCallback = enteringAckedStateCallback;
+    retval = UA_Server_setConditionTwoStateVariableCallback(server, conditionInstance_1,
+                                                            conditionSource, false,
+                                                            userSpecificCallback,
+                                                            UA_ENTERING_ACKEDSTATE);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "adding entering acked state callback failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return retval;
+    }
+
+    userSpecificCallback = enteringConfirmedStateCallback;
+    retval = UA_Server_setConditionTwoStateVariableCallback(server, conditionInstance_1,
+                                                            conditionSource, false,
+                                                            userSpecificCallback,
+                                                            UA_ENTERING_CONFIRMEDSTATE);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "adding entering confirmed state callback failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return retval;
+    }
+
+    /* Unexposed condition 2. No user specific callbacks, so the server will
+     * behave in a standard manner upon entering enabled state, acknowledging
+     * and confirming. We will set Retain field to true and enable the condition
+     * so we can receive event notifications (we cannot call enable method on
+     * unexposed condition using a client like UaExpert or Softing). */
+    retval = addCondition_2(server);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "adding condition 2 failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return retval;
+    }
+
+    UA_Boolean retain = UA_TRUE;
+    UA_Server_writeObjectProperty_scalar(server, conditionInstance_2,
+                                         UA_QUALIFIEDNAME(0, "Retain"),
+                                         &retain, &UA_TYPES[UA_TYPES_BOOLEAN]);
+
+    UA_Variant value;
+    UA_Boolean enabledStateId = true;
+    UA_QualifiedName enabledStateField = UA_QUALIFIEDNAME(0,"EnabledState");
+    UA_QualifiedName enabledStateIdField = UA_QUALIFIEDNAME(0,"Id");
+    UA_Variant_setScalar(&value, &enabledStateId, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_2,
+                                                         &value, enabledStateField,
+                                                         enabledStateIdField);
+
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Setting EnabledState/Id Field failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return retval;
+    }
+
+
+    /* Add 3 variables to trigger condition events */
+    addVariable_1_triggerAlarmOfCondition_1(server, &variable_1);
+
+    callback.onWrite = afterWriteCallbackVariable_1;
+    retval = UA_Server_setVariableNode_valueCallback(server, variable_1, callback);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Setting variable 1 Callback failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return retval;
+    }
+
+    /* Severity can change internally also when the condition disabled and
+     * retain is false. However, in this case no events will be generated. */
+    addVariable_2_changeSeverityOfCondition_2(server, &variable_2);
+
+    callback.onWrite = afterWriteCallbackVariable_2;
+    retval = UA_Server_setVariableNode_valueCallback(server, variable_2, callback);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Setting variable 2 Callback failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        return retval;
+    }
+
+    addVariable_3_returnCondition_1_toNormalState(server, &variable_3);
+
+    callback.onWrite = afterWriteCallbackVariable_3;
+    retval = UA_Server_setVariableNode_valueCallback(server, variable_3, callback);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                     "Setting variable 3 Callback failed. StatusCode %s",
+                     UA_StatusCode_name(retval));
+    }
+
+    return retval;
+}
+
+
+

It follows the main server code, making use of the above definitions.

+
int main (void) {
+    UA_Server *server = UA_Server_new();
+
+    setUpEnvironment(server);
+
+    UA_Server_runUntilInterrupt(server);
+    UA_Server_delete(server);
+    return 0;
+}
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/tutorial_server_datasource.html b/static/doc/v1.4.0/tutorial_server_datasource.html new file mode 100644 index 0000000000..dc8cde6d64 --- /dev/null +++ b/static/doc/v1.4.0/tutorial_server_datasource.html @@ -0,0 +1,312 @@ + + + + + + + Connecting a Variable with a Physical Process — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Connecting a Variable with a Physical Process

+

In OPC UA-based architectures, servers are typically situated near the source +of information. In an industrial context, this translates into servers being +near the physical process and clients consuming the data at runtime. In the +previous tutorial, we saw how to add variables to an OPC UA information +model. This tutorial shows how to connect a variable to runtime information, +for example from measurements of a physical process. For simplicity, we take +the system clock as the underlying “process”.

+

The following code snippets are each concerned with a different way of +updating variable values at runtime. Taken together, the code snippets define +a compilable source file.

+
+

Updating variables manually

+

As a starting point, assume that a variable for a value of type +DateTime has been created in the server with the identifier +“ns=1,s=current-time”. Assuming that our application gets triggered when a +new value arrives from the underlying process, we can just write into the +variable.

+
#include <open62541/plugin/log_stdout.h>
+#include <open62541/server.h>
+
+static void
+updateCurrentTime(UA_Server *server) {
+    UA_DateTime now = UA_DateTime_now();
+    UA_Variant value;
+    UA_Variant_setScalar(&value, &now, &UA_TYPES[UA_TYPES_DATETIME]);
+    UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback");
+    UA_Server_writeValue(server, currentNodeId, value);
+}
+
+static void
+addCurrentTimeVariable(UA_Server *server) {
+    UA_DateTime now = 0;
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
+    attr.displayName = UA_LOCALIZEDTEXT("en-US", "Current time - value callback");
+    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
+    UA_Variant_setScalar(&attr.value, &now, &UA_TYPES[UA_TYPES_DATETIME]);
+
+    UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback");
+    UA_QualifiedName currentName = UA_QUALIFIEDNAME(1, "current-time-value-callback");
+    UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+    UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+    UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
+    UA_Server_addVariableNode(server, currentNodeId, parentNodeId,
+                              parentReferenceNodeId, currentName,
+                              variableTypeNodeId, attr, NULL, NULL);
+
+    updateCurrentTime(server);
+}
+
+
+
+
+

Variable Value Callback

+

When a value changes continuously, such as the system time, updating the +value in a tight loop would take up a lot of resources. Value callbacks allow +to synchronize a variable value with an external representation. They attach +callbacks to the variable that are executed before every read and after every +write operation.

+
static void
+beforeReadTime(UA_Server *server,
+               const UA_NodeId *sessionId, void *sessionContext,
+               const UA_NodeId *nodeid, void *nodeContext,
+               const UA_NumericRange *range, const UA_DataValue *data) {
+    updateCurrentTime(server);
+}
+
+static void
+afterWriteTime(UA_Server *server,
+               const UA_NodeId *sessionId, void *sessionContext,
+               const UA_NodeId *nodeId, void *nodeContext,
+               const UA_NumericRange *range, const UA_DataValue *data) {
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                "The variable was updated");
+}
+
+static void
+addValueCallbackToCurrentTimeVariable(UA_Server *server) {
+    UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback");
+    UA_ValueCallback callback ;
+    callback.onRead = beforeReadTime;
+    callback.onWrite = afterWriteTime;
+    UA_Server_setVariableNode_valueCallback(server, currentNodeId, callback);
+}
+
+
+
+
+

Variable Data Sources

+

With value callbacks, the value is still stored in the variable node. +So-called data sources go one step further. The server redirects every read +and write request to a callback function. Upon reading, the callback provides +a copy of the current value. Internally, the data source needs to implement +its own memory management.

+
static UA_StatusCode
+readCurrentTime(UA_Server *server,
+                const UA_NodeId *sessionId, void *sessionContext,
+                const UA_NodeId *nodeId, void *nodeContext,
+                UA_Boolean sourceTimeStamp, const UA_NumericRange *range,
+                UA_DataValue *dataValue) {
+    UA_DateTime now = UA_DateTime_now();
+    UA_Variant_setScalarCopy(&dataValue->value, &now,
+                             &UA_TYPES[UA_TYPES_DATETIME]);
+    dataValue->hasValue = true;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+writeCurrentTime(UA_Server *server,
+                 const UA_NodeId *sessionId, void *sessionContext,
+                 const UA_NodeId *nodeId, void *nodeContext,
+                 const UA_NumericRange *range, const UA_DataValue *data) {
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                "Changing the system time is not implemented");
+    return UA_STATUSCODE_BADINTERNALERROR;
+}
+
+static void
+addCurrentTimeDataSourceVariable(UA_Server *server) {
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
+    attr.displayName = UA_LOCALIZEDTEXT("en-US", "Current time - data source");
+    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
+
+    UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-datasource");
+    UA_QualifiedName currentName = UA_QUALIFIEDNAME(1, "current-time-datasource");
+    UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+    UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+    UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
+
+    UA_DataSource timeDataSource;
+    timeDataSource.read = readCurrentTime;
+    timeDataSource.write = writeCurrentTime;
+    UA_Server_addDataSourceVariableNode(server, currentNodeId, parentNodeId,
+                                        parentReferenceNodeId, currentName,
+                                        variableTypeNodeId, attr,
+                                        timeDataSource, NULL, NULL);
+}
+
+static UA_DataValue *externalValue;
+
+static void
+addCurrentTimeExternalDataSource(UA_Server *server) {
+    UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-external-source");
+
+    UA_ValueBackend valueBackend;
+    valueBackend.backendType = UA_VALUEBACKENDTYPE_EXTERNAL;
+    valueBackend.backend.external.value = &externalValue;
+
+    UA_Server_setVariableNode_valueBackend(server, currentNodeId, valueBackend);
+}
+
+
+

It follows the main server code, making use of the above definitions.

+
int main(void) {
+    UA_Server *server = UA_Server_new();
+
+    addCurrentTimeVariable(server);
+    addValueCallbackToCurrentTimeVariable(server);
+    addCurrentTimeDataSourceVariable(server);
+    addCurrentTimeExternalDataSource(server);
+
+    UA_Server_runUntilInterrupt(server);
+    UA_Server_delete(server);
+    return 0;
+}
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/tutorial_server_events.html b/static/doc/v1.4.0/tutorial_server_events.html new file mode 100644 index 0000000000..acb2ae5087 --- /dev/null +++ b/static/doc/v1.4.0/tutorial_server_events.html @@ -0,0 +1,290 @@ + + + + + + + Generating events — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Generating events

+

To make sense of the many things going on in a server, monitoring items can +be useful. Though in many cases, data change does not convey enough +information to be the optimal solution. Events can be generated at any time, +hold a lot of information and can be filtered so the client only receives the +specific attributes of interest.

+
+

Emitting events by calling methods

+

The following example will be based on the server method tutorial. We will be +creating a method node which generates an event from the server node.

+

The event we want to generate should be very simple. Since the BaseEventType is abstract, +we will have to create our own event type. EventTypes are saved internally as ObjectTypes, +so add the type as you would a new ObjectType.

+
static UA_NodeId eventType;
+
+static UA_StatusCode
+addNewEventType(UA_Server *server) {
+    UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
+    attr.displayName = UA_LOCALIZEDTEXT("en-US", "SimpleEventType");
+    attr.description = UA_LOCALIZEDTEXT("en-US", "The simple event type we created");
+    return UA_Server_addObjectTypeNode(server, UA_NODEID_NULL,
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE),
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                                       UA_QUALIFIEDNAME(0, "SimpleEventType"),
+                                       attr, NULL, &eventType);
+}
+
+
+
+
+

Setting up an event

+

In order to set up the event, we can first use UA_Server_createEvent to +give us a node representation of the event. All we need for this is our +EventType. Once we have our event node, which is saved internally as an +ObjectNode, we can define the attributes the event has the same way we +would define the attributes of an object node. It is not necessary to define +the attributes EventId, ReceiveTime, SourceNode or EventType since +these are set automatically by the server. In this example, we will be +setting the fields ‘Message’ and ‘Severity’ in addition to Time which is +needed to make the example UaExpert compliant.

+
static UA_StatusCode
+setUpEvent(UA_Server *server, UA_NodeId *outId) {
+    UA_StatusCode retval = UA_Server_createEvent(server, eventType, outId);
+    if (retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
+                       "createEvent failed. StatusCode %s", UA_StatusCode_name(retval));
+        return retval;
+    }
+
+    /* Set the Event Attributes */
+    /* Setting the Time is required or else the event will not show up in UAExpert! */
+    UA_DateTime eventTime = UA_DateTime_now();
+    UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "Time"),
+                                         &eventTime, &UA_TYPES[UA_TYPES_DATETIME]);
+
+    UA_UInt16 eventSeverity = 100;
+    UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "Severity"),
+                                         &eventSeverity, &UA_TYPES[UA_TYPES_UINT16]);
+
+    UA_LocalizedText eventMessage = UA_LOCALIZEDTEXT("en-US", "An event has been generated.");
+    UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "Message"),
+                                         &eventMessage, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+
+    UA_String eventSourceName = UA_STRING("Server");
+    UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "SourceName"),
+                                         &eventSourceName, &UA_TYPES[UA_TYPES_STRING]);
+
+    return UA_STATUSCODE_GOOD;
+}
+
+
+
+
+

Triggering an event

+

First a node representing an event is generated using setUpEvent. Once +our event is good to go, we specify a node which emits the event - in this +case the server node. We can use UA_Server_triggerEvent to trigger our +event onto said node. Passing NULL as the second-last argument means we +will not receive the EventId. The last boolean argument states whether the +node should be deleted.

+
static UA_StatusCode
+generateEventMethodCallback(UA_Server *server,
+                         const UA_NodeId *sessionId, void *sessionHandle,
+                         const UA_NodeId *methodId, void *methodContext,
+                         const UA_NodeId *objectId, void *objectContext,
+                         size_t inputSize, const UA_Variant *input,
+                         size_t outputSize, UA_Variant *output) {
+
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Creating event");
+
+    /* set up event */
+    UA_NodeId eventNodeId;
+    UA_StatusCode retval = setUpEvent(server, &eventNodeId);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                       "Creating event failed. StatusCode %s", UA_StatusCode_name(retval));
+        return retval;
+    }
+
+    retval = UA_Server_triggerEvent(server, eventNodeId,
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
+                                    NULL, UA_TRUE);
+    if(retval != UA_STATUSCODE_GOOD)
+        UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                       "Triggering event failed. StatusCode %s", UA_StatusCode_name(retval));
+
+    return retval;
+}
+
+
+

Now, all that is left to do is to create a method node which uses our +callback. We do not require any input and as output we will be using the +EventId we receive from triggerEvent. The EventId is generated by the +server internally and is a random unique ID which identifies that specific +event.

+

This method node will be added to a basic server setup.

+
static void
+addGenerateEventMethod(UA_Server *server) {
+    UA_MethodAttributes generateAttr = UA_MethodAttributes_default;
+    generateAttr.description = UA_LOCALIZEDTEXT("en-US","Generate an event.");
+    generateAttr.displayName = UA_LOCALIZEDTEXT("en-US","Generate Event");
+    generateAttr.executable = true;
+    generateAttr.userExecutable = true;
+    UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, 62541),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                            UA_QUALIFIEDNAME(1, "Generate Event"),
+                            generateAttr, &generateEventMethodCallback,
+                            0, NULL, 0, NULL, NULL, NULL);
+}
+
+
+

It follows the main server code, making use of the above definitions.

+
int main(void) {
+    UA_Server *server = UA_Server_new();
+
+    addNewEventType(server);
+    addGenerateEventMethod(server);
+
+    UA_Server_runUntilInterrupt(server);
+    UA_Server_delete(server);
+    return 0;
+}
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/tutorial_server_firststeps.html b/static/doc/v1.4.0/tutorial_server_firststeps.html new file mode 100644 index 0000000000..bc4086fdb3 --- /dev/null +++ b/static/doc/v1.4.0/tutorial_server_firststeps.html @@ -0,0 +1,208 @@ + + + + + + + Building a Simple Server — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Building a Simple Server

+

This series of tutorial guide you through your first steps with open62541. +For compiling the examples, you need a compiler (MS Visual Studio 2015 or +newer, GCC, Clang and MinGW32 are all known to be working). The compilation +instructions are given for GCC but should be straightforward to adapt.

+

It will also be very helpful to install an OPC UA Client with a graphical +frontend, such as UAExpert by Unified Automation. That will enable you to +examine the information model of any OPC UA server.

+

To get started, downdload the open62541 single-file release from +http://open62541.org or generate it according to the build instructions with the “amalgamation” option enabled. From now on, we assume +you have the open62541.c/.h files in the current folder. Now create a new +C source-file called myServer.c with the following content:

+
#include <open62541/server.h>
+
+int main(void) {
+    UA_Server *server = UA_Server_new();
+    UA_Server_runUntilInterrupt(server);
+    UA_Server_delete(server);
+    return 0;
+}
+
+
+

This is all that is needed for a simple OPC UA server. With the GCC compiler, +the following command produces an executable:

+
$ gcc -std=c99 myServer.c -lopen62541 -o myServer
+
+
+

In a MinGW environment, the Winsock library must be added.

+
$ gcc -std=c99 myServer.c -lopen62541 -lws2_32 -o myServer.exe
+
+
+

Now start the server (stop with ctrl-c):

+
$ ./myServer
+
+
+

You have now compiled and run your first OPC UA server. You can go ahead and +browse the information model with client. The server is listening on +opc.tcp://localhost:4840.

+
+

Server Configuration and Plugins

+

open62541 provides a flexible framework for building OPC UA servers and +clients. The goals is to have a core library that accommodates for all use +cases and runs on all platforms. Users can then adjust the library to fit +their use case via configuration and by developing (platform-specific) +plugins. The core library is based on C99 only and does not even require +basic POSIX support. For example, the lowlevel networking code is implemented +as an exchangeable plugin. But don’t worry. open62541 provides plugin +implementations for most platforms and sensible default configurations +out-of-the-box.

+

In the above server code, we simply take the default server configuration and +add a single TCP network layer that is listerning on port 4840.

+
+
+

Server Lifecycle

+

The code in this example shows the three parts for server lifecycle +management: Creating a server, running the server, and deleting the server. +Creating and deleting a server is trivial once the configuration is set up. +The server is started with UA_Server_run. Internally, the server +schedules regular tasks. Between the timeouts, the server listens on the +network layer for incoming messages.

+

In order to integrate OPC UA in a single-threaded application with its own +mainloop (for example provided by a GUI toolkit), one can alternatively drive +the server manually. See the section of the server documentation on +Server Lifecycle for details.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/tutorial_server_method.html b/static/doc/v1.4.0/tutorial_server_method.html new file mode 100644 index 0000000000..139698c519 --- /dev/null +++ b/static/doc/v1.4.0/tutorial_server_method.html @@ -0,0 +1,308 @@ + + + + + + + Adding Methods to Objects — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Adding Methods to Objects

+

An object in an OPC UA information model may contain methods similar to +objects in a programming language. Methods are represented by a MethodNode. +Note that several objects may reference the same MethodNode. When an object +type is instantiated, a reference to the method is added instead of copying +the MethodNode. Therefore, the identifier of the context object is always +explicitly stated when a method is called.

+

The method callback takes as input a custom data pointer attached to the +method node, the identifier of the object from which the method is called, +and two arrays for the input and output arguments. The input and output +arguments are all of type Variant. Each variant may in turn contain a +(multi-dimensional) array or scalar of any data type.

+

Constraints for the method arguments are defined in terms of data type, value +rank and array dimension (similar to variable definitions). The argument +definitions are stored in child VariableNodes of the MethodNode with the +respective BrowseNames (0, "InputArguments") and (0, +"OutputArguments").

+
+

Example: Hello World Method

+

The method takes a string scalar and returns a string scalar with “Hello ” +prepended. The type and length of the input arguments is checked internally +by the SDK, so that we don’t have to verify the arguments in the callback.

+
#include <open62541/client_config_default.h>
+#include <open62541/plugin/log_stdout.h>
+#include <open62541/server.h>
+
+static UA_StatusCode
+helloWorldMethodCallback(UA_Server *server,
+                         const UA_NodeId *sessionId, void *sessionHandle,
+                         const UA_NodeId *methodId, void *methodContext,
+                         const UA_NodeId *objectId, void *objectContext,
+                         size_t inputSize, const UA_Variant *input,
+                         size_t outputSize, UA_Variant *output) {
+    UA_String *inputStr = (UA_String*)input->data;
+    UA_String tmp = UA_STRING_ALLOC("Hello ");
+    if(inputStr->length > 0) {
+        tmp.data = (UA_Byte *)UA_realloc(tmp.data, tmp.length + inputStr->length);
+        memcpy(&tmp.data[tmp.length], inputStr->data, inputStr->length);
+        tmp.length += inputStr->length;
+    }
+    UA_Variant_setScalarCopy(output, &tmp, &UA_TYPES[UA_TYPES_STRING]);
+    UA_String_clear(&tmp);
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Hello World was called");
+    return UA_STATUSCODE_GOOD;
+}
+
+static void
+addHelloWorldMethod(UA_Server *server) {
+    UA_Argument inputArgument;
+    UA_Argument_init(&inputArgument);
+    inputArgument.description = UA_LOCALIZEDTEXT("en-US", "A String");
+    inputArgument.name = UA_STRING("MyInput");
+    inputArgument.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
+    inputArgument.valueRank = UA_VALUERANK_SCALAR;
+
+    UA_Argument outputArgument;
+    UA_Argument_init(&outputArgument);
+    outputArgument.description = UA_LOCALIZEDTEXT("en-US", "A String");
+    outputArgument.name = UA_STRING("MyOutput");
+    outputArgument.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
+    outputArgument.valueRank = UA_VALUERANK_SCALAR;
+
+    UA_MethodAttributes helloAttr = UA_MethodAttributes_default;
+    helloAttr.description = UA_LOCALIZEDTEXT("en-US","Say `Hello World`");
+    helloAttr.displayName = UA_LOCALIZEDTEXT("en-US","Hello World");
+    helloAttr.executable = true;
+    helloAttr.userExecutable = true;
+    UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1,62541),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                            UA_QUALIFIEDNAME(1, "hello world"),
+                            helloAttr, &helloWorldMethodCallback,
+                            1, &inputArgument, 1, &outputArgument, NULL, NULL);
+}
+
+
+
+
+

Increase Array Values Method

+

The method takes an array of 5 integers and a scalar as input. It returns a +copy of the array with every entry increased by the scalar.

+
static UA_StatusCode
+IncInt32ArrayMethodCallback(UA_Server *server,
+                            const UA_NodeId *sessionId, void *sessionContext,
+                            const UA_NodeId *methodId, void *methodContext,
+                            const UA_NodeId *objectId, void *objectContext,
+                            size_t inputSize, const UA_Variant *input,
+                            size_t outputSize, UA_Variant *output) {
+    UA_Int32 *inputArray = (UA_Int32*)input[0].data;
+    UA_Int32 delta = *(UA_Int32*)input[1].data;
+
+    /* Copy the input array */
+    UA_StatusCode retval = UA_Variant_setArrayCopy(output, inputArray, 5,
+                                                   &UA_TYPES[UA_TYPES_INT32]);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    /* Increate the elements */
+    UA_Int32 *outputArray = (UA_Int32*)output->data;
+    for(size_t i = 0; i < input->arrayLength; i++)
+        outputArray[i] = inputArray[i] + delta;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+static void
+addIncInt32ArrayMethod(UA_Server *server) {
+    /* Two input arguments */
+    UA_Argument inputArguments[2];
+    UA_Argument_init(&inputArguments[0]);
+    inputArguments[0].description = UA_LOCALIZEDTEXT("en-US", "int32[5] array");
+    inputArguments[0].name = UA_STRING("int32 array");
+    inputArguments[0].dataType = UA_TYPES[UA_TYPES_INT32].typeId;
+    inputArguments[0].valueRank = UA_VALUERANK_ONE_DIMENSION;
+    UA_UInt32 pInputDimension = 5;
+    inputArguments[0].arrayDimensionsSize = 1;
+    inputArguments[0].arrayDimensions = &pInputDimension;
+
+    UA_Argument_init(&inputArguments[1]);
+    inputArguments[1].description = UA_LOCALIZEDTEXT("en-US", "int32 delta");
+    inputArguments[1].name = UA_STRING("int32 delta");
+    inputArguments[1].dataType = UA_TYPES[UA_TYPES_INT32].typeId;
+    inputArguments[1].valueRank = UA_VALUERANK_SCALAR;
+
+    /* One output argument */
+    UA_Argument outputArgument;
+    UA_Argument_init(&outputArgument);
+    outputArgument.description = UA_LOCALIZEDTEXT("en-US", "int32[5] array");
+    outputArgument.name = UA_STRING("each entry is incremented by the delta");
+    outputArgument.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
+    outputArgument.valueRank = UA_VALUERANK_ONE_DIMENSION;
+    UA_UInt32 pOutputDimension = 5;
+    outputArgument.arrayDimensionsSize = 1;
+    outputArgument.arrayDimensions = &pOutputDimension;
+
+    /* Add the method node */
+    UA_MethodAttributes incAttr = UA_MethodAttributes_default;
+    incAttr.description = UA_LOCALIZEDTEXT("en-US", "IncInt32ArrayValues");
+    incAttr.displayName = UA_LOCALIZEDTEXT("en-US", "IncInt32ArrayValues");
+    incAttr.executable = true;
+    incAttr.userExecutable = true;
+    UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "IncInt32ArrayValues"),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                            UA_QUALIFIEDNAME(1, "IncInt32ArrayValues"),
+                            incAttr, &IncInt32ArrayMethodCallback,
+                            2, inputArguments, 1, &outputArgument,
+                            NULL, NULL);
+}
+
+
+

It follows the main server code, making use of the above definitions.

+
int main(void) {
+    UA_Server *server = UA_Server_new();
+
+    addHelloWorldMethod(server);
+    addIncInt32ArrayMethod(server);
+
+    UA_Server_runUntilInterrupt(server);
+    UA_Server_delete(server);
+    return 0;
+}
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/tutorial_server_monitoreditems.html b/static/doc/v1.4.0/tutorial_server_monitoreditems.html new file mode 100644 index 0000000000..cdd9aafbb5 --- /dev/null +++ b/static/doc/v1.4.0/tutorial_server_monitoreditems.html @@ -0,0 +1,187 @@ + + + + + + + Observing Attributes with Local MonitoredItems — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Observing Attributes with Local MonitoredItems

+

A client that is interested in the current value of a variable does not need +to regularly poll the variable. Instead, the client can use the Subscription +mechanism to be notified about changes.

+

So-called MonitoredItems define which values (node attributes) and events the +client wants to monitor. Under the right conditions, a notification is +created and added to the Subscription. The notifications currently in the +queue are regularly sent to the client.

+

The local user can add MonitoredItems as well. Locally, the MonitoredItems do +not go via a Subscription and each have an individual callback method and a +context pointer.

+
#include <open62541/client_subscriptions.h>
+#include <open62541/server.h>
+#include <open62541/plugin/log_stdout.h>
+
+static void
+dataChangeNotificationCallback(UA_Server *server, UA_UInt32 monitoredItemId,
+                               void *monitoredItemContext, const UA_NodeId *nodeId,
+                               void *nodeContext, UA_UInt32 attributeId,
+                               const UA_DataValue *value) {
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Received Notification");
+}
+
+static void
+addMonitoredItemToCurrentTimeVariable(UA_Server *server) {
+    UA_NodeId currentTimeNodeId =
+        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
+    UA_MonitoredItemCreateRequest monRequest =
+        UA_MonitoredItemCreateRequest_default(currentTimeNodeId);
+    monRequest.requestedParameters.samplingInterval = 100.0; /* 100 ms interval */
+    UA_Server_createDataChangeMonitoredItem(server, UA_TIMESTAMPSTORETURN_SOURCE,
+                                            monRequest, NULL,
+                                            dataChangeNotificationCallback);
+}
+
+
+

It follows the main server code, making use of the above definitions.

+
int main(void) {
+    UA_Server *server = UA_Server_new();
+
+    addMonitoredItemToCurrentTimeVariable(server);
+
+    UA_Server_runUntilInterrupt(server);
+    UA_Server_delete(server);
+    return 0;
+}
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/tutorial_server_object.html b/static/doc/v1.4.0/tutorial_server_object.html new file mode 100644 index 0000000000..38928643ed --- /dev/null +++ b/static/doc/v1.4.0/tutorial_server_object.html @@ -0,0 +1,454 @@ + + + + + + + Working with Objects and Object Types — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Working with Objects and Object Types

+
+

Using objects to structure information models

+

Assume a situation where we want to model a set of pumps and their runtime +state in an OPC UA information model. Of course, all pump representations +should follow the same basic structure, For example, we might have graphical +representation of pumps in a SCADA visualisation that shall be resuable for +all pumps.

+

Following the object-oriented programming paradigm, every pump is represented +by an object with the following layout:

+
digraph tree {
+
+fixedsize=true;
+node [width=2, height=0, shape=box, fillcolor="#E5E5E5", concentrate=true]
+
+node_root [label=< <I>ObjectNode</I><BR/>Pump >]
+
+{ rank=same
+  point_1 [shape=point]
+  node_1 [label=< <I>VariableNode</I><BR/>ManufacturerName >] }
+node_root -> point_1 [arrowhead=none]
+point_1 -> node_1 [label="hasComponent"]
+
+{ rank=same
+  point_2 [shape=point]
+  node_2 [label=< <I>VariableNode</I><BR/>ModelName >] }
+point_1 -> point_2 [arrowhead=none]
+point_2 -> node_2 [label="hasComponent"]
+
+{  rank=same
+   point_4 [shape=point]
+   node_4 [label=< <I>VariableNode</I><BR/>Status >] }
+point_2 -> point_4 [arrowhead=none]
+point_4 -> node_4 [label="hasComponent"]
+
+{  rank=same
+   point_5 [shape=point]
+   node_5 [label=< <I>VariableNode</I><BR/>MotorRPM >] }
+point_4 -> point_5 [arrowhead=none]
+point_5 -> node_5 [label="hasComponent"]
+
+}
+

The following code manually defines a pump and its member variables. We omit +setting constraints on the variable values as this is not the focus of this +tutorial and was already covered.

+
static void
+manuallyDefinePump(UA_Server *server) {
+    UA_NodeId pumpId; /* get the nodeid assigned by the server */
+    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
+    oAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Pump (Manual)");
+    UA_Server_addObjectNode(server, UA_NODEID_NULL,
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                            UA_QUALIFIEDNAME(1, "Pump (Manual)"),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
+                            oAttr, NULL, &pumpId);
+
+    UA_VariableAttributes mnAttr = UA_VariableAttributes_default;
+    UA_String manufacturerName = UA_STRING("Pump King Ltd.");
+    UA_Variant_setScalar(&mnAttr.value, &manufacturerName, &UA_TYPES[UA_TYPES_STRING]);
+    mnAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ManufacturerName");
+    UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId,
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                              UA_QUALIFIEDNAME(1, "ManufacturerName"),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                              mnAttr, NULL, NULL);
+
+    UA_VariableAttributes modelAttr = UA_VariableAttributes_default;
+    UA_String modelName = UA_STRING("Mega Pump 3000");
+    UA_Variant_setScalar(&modelAttr.value, &modelName, &UA_TYPES[UA_TYPES_STRING]);
+    modelAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ModelName");
+    UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId,
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                              UA_QUALIFIEDNAME(1, "ModelName"),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                              modelAttr, NULL, NULL);
+
+    UA_VariableAttributes statusAttr = UA_VariableAttributes_default;
+    UA_Boolean status = true;
+    UA_Variant_setScalar(&statusAttr.value, &status, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    statusAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Status");
+    UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId,
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                              UA_QUALIFIEDNAME(1, "Status"),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                              statusAttr, NULL, NULL);
+
+    UA_VariableAttributes rpmAttr = UA_VariableAttributes_default;
+    UA_Double rpm = 50.0;
+    UA_Variant_setScalar(&rpmAttr.value, &rpm, &UA_TYPES[UA_TYPES_DOUBLE]);
+    rpmAttr.displayName = UA_LOCALIZEDTEXT("en-US", "MotorRPM");
+    UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId,
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                              UA_QUALIFIEDNAME(1, "MotorRPMs"),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                              rpmAttr, NULL, NULL);
+}
+
+
+
+
+

Object types, type hierarchies and instantiation

+

Building up each object manually requires us to write a lot of code. +Furthermore, there is no way for clients to detect that an object represents +a pump. (We might use naming conventions or similar to detect pumps. But +that’s not exactly a clean solution.) Furthermore, we might have more devices +than just pumps. And we require all devices to share some common structure. +The solution is to define ObjectTypes in a hierarchy with inheritance +relations.

+
digraph tree {
+
+fixedsize=true;
+node [width=2, height=0, shape=box, fillcolor="#E5E5E5", concentrate=true]
+
+node_root [label=< <I>ObjectTypeNode</I><BR/>Device >]
+
+{ rank=same
+  point_1 [shape=point]
+  node_1 [label=< <I>VariableNode</I><BR/>ManufacturerName<BR/>(mandatory) >] }
+node_root -> point_1 [arrowhead=none]
+point_1 -> node_1 [label="hasComponent"]
+
+{ rank=same
+  point_2 [shape=point]
+  node_2 [label=< <I>VariableNode</I><BR/>ModelName >] }
+point_1 -> point_2 [arrowhead=none]
+point_2 -> node_2 [label="hasComponent"]
+
+{  rank=same
+   point_3 [shape=point]
+   node_3 [label=< <I>ObjectTypeNode</I><BR/>Pump >] }
+point_2 -> point_3 [arrowhead=none]
+point_3 -> node_3 [label="hasSubtype"]
+
+{  rank=same
+   point_4 [shape=point]
+   node_4 [label=< <I>VariableNode</I><BR/>Status<BR/>(mandatory) >] }
+node_3 -> point_4 [arrowhead=none]
+point_4 -> node_4 [label="hasComponent"]
+
+{  rank=same
+   point_5 [shape=point]
+   node_5 [label=< <I>VariableNode</I><BR/>MotorRPM >] }
+point_4 -> point_5 [arrowhead=none]
+point_5 -> node_5 [label="hasComponent"]
+
+}
+

Children that are marked mandatory are automatically instantiated together +with the parent object. This is indicated by a hasModellingRule reference +to an object that representes the mandatory modelling rule.

+
/* predefined identifier for later use */
+UA_NodeId pumpTypeId = {1, UA_NODEIDTYPE_NUMERIC, {1001}};
+
+static void
+defineObjectTypes(UA_Server *server) {
+    /* Define the object type for "Device" */
+    UA_NodeId deviceTypeId; /* get the nodeid assigned by the server */
+    UA_ObjectTypeAttributes dtAttr = UA_ObjectTypeAttributes_default;
+    dtAttr.displayName = UA_LOCALIZEDTEXT("en-US", "DeviceType");
+    UA_Server_addObjectTypeNode(server, UA_NODEID_NULL,
+                                UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
+                                UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                                UA_QUALIFIEDNAME(1, "DeviceType"), dtAttr,
+                                NULL, &deviceTypeId);
+
+    UA_VariableAttributes mnAttr = UA_VariableAttributes_default;
+    mnAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ManufacturerName");
+    UA_NodeId manufacturerNameId;
+    UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId,
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                              UA_QUALIFIEDNAME(1, "ManufacturerName"),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                              mnAttr, NULL, &manufacturerNameId);
+    /* Make the manufacturer name mandatory */
+    UA_Server_addReference(server, manufacturerNameId,
+                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
+                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);
+
+
+    UA_VariableAttributes modelAttr = UA_VariableAttributes_default;
+    modelAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ModelName");
+    UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId,
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                              UA_QUALIFIEDNAME(1, "ModelName"),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                              modelAttr, NULL, NULL);
+
+    /* Define the object type for "Pump" */
+    UA_ObjectTypeAttributes ptAttr = UA_ObjectTypeAttributes_default;
+    ptAttr.displayName = UA_LOCALIZEDTEXT("en-US", "PumpType");
+    UA_Server_addObjectTypeNode(server, pumpTypeId,
+                                deviceTypeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                                UA_QUALIFIEDNAME(1, "PumpType"), ptAttr,
+                                NULL, NULL);
+
+    UA_VariableAttributes statusAttr = UA_VariableAttributes_default;
+    statusAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Status");
+    statusAttr.valueRank = UA_VALUERANK_SCALAR;
+    UA_NodeId statusId;
+    UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId,
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                              UA_QUALIFIEDNAME(1, "Status"),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                              statusAttr, NULL, &statusId);
+    /* Make the status variable mandatory */
+    UA_Server_addReference(server, statusId,
+                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
+                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);
+
+    UA_VariableAttributes rpmAttr = UA_VariableAttributes_default;
+    rpmAttr.displayName = UA_LOCALIZEDTEXT("en-US", "MotorRPM");
+    rpmAttr.valueRank = UA_VALUERANK_SCALAR;
+    UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId,
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                              UA_QUALIFIEDNAME(1, "MotorRPMs"),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                              rpmAttr, NULL, NULL);
+}
+
+
+

Now we add the derived ObjectType for the pump that inherits from the device +object type. The resulting object contains all mandatory child variables. +These are simply copied over from the object type. The object has a reference +of type hasTypeDefinition to the object type, so that clients can detect +the type-instance relation at runtime.

+
static void
+addPumpObjectInstance(UA_Server *server, char *name) {
+    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
+    oAttr.displayName = UA_LOCALIZEDTEXT("en-US", name);
+    UA_Server_addObjectNode(server, UA_NODEID_NULL,
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                            UA_QUALIFIEDNAME(1, name),
+                            pumpTypeId, /* this refers to the object type
+                                           identifier */
+                            oAttr, NULL, NULL);
+}
+
+
+

Often we want to run a constructor function on a new object. This is +especially useful when an object is instantiated at runtime (with the +AddNodes service) and the integration with an underlying process cannot be +manually defined. In the following constructor example, we simply set the +pump status to on.

+
static UA_StatusCode
+pumpTypeConstructor(UA_Server *server,
+                    const UA_NodeId *sessionId, void *sessionContext,
+                    const UA_NodeId *typeId, void *typeContext,
+                    const UA_NodeId *nodeId, void **nodeContext) {
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "New pump created");
+
+    /* Find the NodeId of the status child variable */
+    UA_RelativePathElement rpe;
+    UA_RelativePathElement_init(&rpe);
+    rpe.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT);
+    rpe.isInverse = false;
+    rpe.includeSubtypes = false;
+    rpe.targetName = UA_QUALIFIEDNAME(1, "Status");
+
+    UA_BrowsePath bp;
+    UA_BrowsePath_init(&bp);
+    bp.startingNode = *nodeId;
+    bp.relativePath.elementsSize = 1;
+    bp.relativePath.elements = &rpe;
+
+    UA_BrowsePathResult bpr =
+        UA_Server_translateBrowsePathToNodeIds(server, &bp);
+    if(bpr.statusCode != UA_STATUSCODE_GOOD ||
+       bpr.targetsSize < 1)
+        return bpr.statusCode;
+
+    /* Set the status value */
+    UA_Boolean status = true;
+    UA_Variant value;
+    UA_Variant_setScalar(&value, &status, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    UA_Server_writeValue(server, bpr.targets[0].targetId.nodeId, value);
+    UA_BrowsePathResult_clear(&bpr);
+
+    /* At this point we could replace the node context .. */
+
+    return UA_STATUSCODE_GOOD;
+}
+
+static void
+addPumpTypeConstructor(UA_Server *server) {
+    UA_NodeTypeLifecycle lifecycle;
+    lifecycle.constructor = pumpTypeConstructor;
+    lifecycle.destructor = NULL;
+    UA_Server_setNodeTypeLifecycle(server, pumpTypeId, lifecycle);
+}
+
+
+

It follows the main server code, making use of the above definitions.

+
int main(void) {
+    UA_Server *server = UA_Server_new();
+
+    manuallyDefinePump(server);
+    defineObjectTypes(server);
+    addPumpObjectInstance(server, "pump2");
+    addPumpObjectInstance(server, "pump3");
+    addPumpTypeConstructor(server);
+    addPumpObjectInstance(server, "pump4");
+    addPumpObjectInstance(server, "pump5");
+
+    UA_Server_runUntilInterrupt(server);
+    UA_Server_delete(server);
+    return 0;
+}
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/tutorial_server_variable.html b/static/doc/v1.4.0/tutorial_server_variable.html new file mode 100644 index 0000000000..d90fc05d6c --- /dev/null +++ b/static/doc/v1.4.0/tutorial_server_variable.html @@ -0,0 +1,267 @@ + + + + + + + Adding Variables to a Server — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Adding Variables to a Server

+

This tutorial shows how to work with data types and how to add variable nodes +to a server. First, we add a new variable to the server. Take a look at the +definition of the UA_VariableAttributes structure to see the list of all +attributes defined for VariableNodes.

+

Note that the default settings have the AccessLevel of the variable value as +read only. See below for making the variable writable.

+
#include <open62541/plugin/log_stdout.h>
+#include <open62541/server.h>
+#include <stdio.h>
+
+static void
+addVariable(UA_Server *server) {
+    /* Define the attribute of the myInteger variable node */
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
+    UA_Int32 myInteger = 42;
+    UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    attr.description = UA_LOCALIZEDTEXT("en-US","the answer");
+    attr.displayName = UA_LOCALIZEDTEXT("en-US","the answer");
+    attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
+    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
+
+    /* Add the variable node to the information model */
+    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
+    UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
+    UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+    UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+    UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
+                              parentReferenceNodeId, myIntegerName,
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), attr, NULL, NULL);
+}
+
+static void
+addMatrixVariable(UA_Server *server) {
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
+    attr.displayName = UA_LOCALIZEDTEXT("en-US", "Double Matrix");
+    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
+
+    /* Set the variable value constraints */
+    attr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
+    attr.valueRank = UA_VALUERANK_TWO_DIMENSIONS;
+    UA_UInt32 arrayDims[2] = {2,2};
+    attr.arrayDimensions = arrayDims;
+    attr.arrayDimensionsSize = 2;
+
+    /* Set the value. The array dimensions need to be the same for the value. */
+    UA_Double zero[4] = {0.0, 0.0, 0.0, 0.0};
+    UA_Variant_setArray(&attr.value, zero, 4, &UA_TYPES[UA_TYPES_DOUBLE]);
+    attr.value.arrayDimensions = arrayDims;
+    attr.value.arrayDimensionsSize = 2;
+
+    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "double.matrix");
+    UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "double matrix");
+    UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+    UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+    UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
+                              parentReferenceNodeId, myIntegerName,
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                              attr, NULL, NULL);
+}
+
+
+

Now we change the value with the write service. This uses the same service +implementation that can also be reached over the network by an OPC UA client.

+
static void
+writeVariable(UA_Server *server) {
+    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
+
+    /* Write a different integer value */
+    UA_Int32 myInteger = 43;
+    UA_Variant myVar;
+    UA_Variant_init(&myVar);
+    UA_Variant_setScalar(&myVar, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    UA_Server_writeValue(server, myIntegerNodeId, myVar);
+
+    /* Set the status code of the value to an error code. The function
+     * UA_Server_write provides access to the raw service. The above
+     * UA_Server_writeValue is syntactic sugar for writing a specific node
+     * attribute with the write service. */
+    UA_WriteValue wv;
+    UA_WriteValue_init(&wv);
+    wv.nodeId = myIntegerNodeId;
+    wv.attributeId = UA_ATTRIBUTEID_VALUE;
+    wv.value.status = UA_STATUSCODE_BADNOTCONNECTED;
+    wv.value.hasStatus = true;
+    UA_Server_write(server, &wv);
+
+    /* Reset the variable to a good statuscode with a value */
+    wv.value.hasStatus = false;
+    wv.value.value = myVar;
+    wv.value.hasValue = true;
+    UA_Server_write(server, &wv);
+}
+
+
+

Note how we initially set the DataType attribute of the variable node to the +NodeId of the Int32 data type. This forbids writing values that are not an +Int32. The following code shows how this consistency check is performed for +every write.

+
static void
+writeWrongVariable(UA_Server *server) {
+    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
+
+    /* Write a string */
+    UA_String myString = UA_STRING("test");
+    UA_Variant myVar;
+    UA_Variant_init(&myVar);
+    UA_Variant_setScalar(&myVar, &myString, &UA_TYPES[UA_TYPES_STRING]);
+    UA_StatusCode retval = UA_Server_writeValue(server, myIntegerNodeId, myVar);
+    printf("Writing a string returned statuscode %s\n", UA_StatusCode_name(retval));
+}
+
+
+

It follows the main server code, making use of the above definitions.

+
int main(void) {
+    UA_Server *server = UA_Server_new();
+
+    addVariable(server);
+    addMatrixVariable(server);
+    writeVariable(server);
+    writeWrongVariable(server);
+
+    UA_Server_runUntilInterrupt(server);
+    UA_Server_delete(server);
+    return 0;
+}
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/tutorial_server_variabletype.html b/static/doc/v1.4.0/tutorial_server_variabletype.html new file mode 100644 index 0000000000..9c1ce08538 --- /dev/null +++ b/static/doc/v1.4.0/tutorial_server_variabletype.html @@ -0,0 +1,256 @@ + + + + + + + Working with Variable Types — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Working with Variable Types

+

Variable types have three functions:

+
    +
  • Constrain the possible data type, value rank and array dimensions of the +variables of that type. This allows interface code to be written against +the generic type definition, so it is applicable for all instances.

  • +
  • Provide a sensible default value

  • +
  • Enable a semantic interpretation of the variable based on its type

  • +
+

In the example of this tutorial, we represent a point in 2D space by an array +of double values. The following function adds the corresponding +VariableTypeNode to the hierarchy of variable types.

+
#include <open62541/plugin/log_stdout.h>
+#include <open62541/server.h>
+
+static UA_NodeId pointTypeId;
+
+static void
+addVariableType2DPoint(UA_Server *server) {
+    UA_VariableTypeAttributes vtAttr = UA_VariableTypeAttributes_default;
+    vtAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
+    vtAttr.valueRank = UA_VALUERANK_ONE_DIMENSION;
+    UA_UInt32 arrayDims[1] = {2};
+    vtAttr.arrayDimensions = arrayDims;
+    vtAttr.arrayDimensionsSize = 1;
+    vtAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Type");
+
+    /* a matching default value is required */
+    UA_Double zero[2] = {0.0, 0.0};
+    UA_Variant_setArray(&vtAttr.value, zero, 2, &UA_TYPES[UA_TYPES_DOUBLE]);
+
+    UA_Server_addVariableTypeNode(server, UA_NODEID_NULL,
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                                  UA_QUALIFIEDNAME(1, "2DPoint Type"), UA_NODEID_NULL,
+                                  vtAttr, NULL, &pointTypeId);
+}
+
+
+

Now the new variable type for 2DPoint can be referenced during the creation +of a new variable. If no value is given, the default from the variable type +is copied during instantiation.

+
static UA_NodeId pointVariableId;
+
+static void
+addVariable(UA_Server *server) {
+    /* Prepare the node attributes */
+    UA_VariableAttributes vAttr = UA_VariableAttributes_default;
+    vAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
+    vAttr.valueRank = UA_VALUERANK_ONE_DIMENSION;
+    UA_UInt32 arrayDims[1] = {2};
+    vAttr.arrayDimensions = arrayDims;
+    vAttr.arrayDimensionsSize = 1;
+    vAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Variable");
+    vAttr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
+    /* vAttr.value is left empty, the server instantiates with the default value */
+
+    /* Add the node */
+    UA_Server_addVariableNode(server, UA_NODEID_NULL,
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                              UA_QUALIFIEDNAME(1, "2DPoint Type"), pointTypeId,
+                              vAttr, NULL, &pointVariableId);
+}
+
+
+

The constraints of the variable type are enforced when creating new variable +instances of the type. In the following function, adding a variable of +2DPoint type with a string value fails because the value does not match the +variable type constraints.

+
static void
+addVariableFail(UA_Server *server) {
+    /* Prepare the node attributes */
+    UA_VariableAttributes vAttr = UA_VariableAttributes_default;
+    vAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
+    vAttr.valueRank = UA_VALUERANK_SCALAR; /* a scalar. this is not allowed per
+                                            * the variable type */
+    vAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Variable (fail)");
+    UA_String s = UA_STRING("2dpoint?");
+    UA_Variant_setScalar(&vAttr.value, &s, &UA_TYPES[UA_TYPES_STRING]);
+
+    /* Add the node will return UA_STATUSCODE_BADTYPEMISMATCH*/
+    UA_Server_addVariableNode(server, UA_NODEID_NULL,
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                              UA_QUALIFIEDNAME(1, "2DPoint Type (fail)"), pointTypeId,
+                              vAttr, NULL, NULL);
+}
+
+
+

The constraints of the variable type are enforced when writing the datatype, +valuerank and arraydimensions attributes of the variable. This, in turn, +constrains the value attribute of the variable.

+
static void
+writeVariable(UA_Server *server) {
+    UA_StatusCode retval =
+        UA_Server_writeValueRank(server, pointVariableId,
+                                 UA_VALUERANK_ONE_OR_MORE_DIMENSIONS);
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                "Setting the Value Rank failed with Status Code %s",
+                UA_StatusCode_name(retval));
+}
+
+
+

It follows the main server code, making use of the above definitions.

+
int main(void) {
+    UA_Server *server = UA_Server_new();
+    addVariableType2DPoint(server);
+    addVariable(server);
+    addVariableFail(server);
+    writeVariable(server);
+    UA_Server_runUntilInterrupt(server);
+    UA_Server_delete(server);
+    return 0;
+}
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/tutorials.html b/static/doc/v1.4.0/tutorials.html new file mode 100644 index 0000000000..fcae6a71cb --- /dev/null +++ b/static/doc/v1.4.0/tutorials.html @@ -0,0 +1,192 @@ + + + + + + + Tutorials — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/types.html b/static/doc/v1.4.0/types.html new file mode 100644 index 0000000000..04f79e66ef --- /dev/null +++ b/static/doc/v1.4.0/types.html @@ -0,0 +1,4208 @@ + + + + + + + Data Types — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Data Types

+

The OPC UA protocol defines 25 builtin data types and three ways of combining +them into higher-order types: arrays, structures and unions. In open62541, +only the builtin data types are defined manually. All other data types are +generated from standard XML definitions. Their exact definitions can be +looked up at https://opcfoundation.org/UA/schemas/Opc.Ua.Types.bsd.

+

For users that are new to open62541, take a look at the tutorial for +working with data types before diving into the +implementation details.

+
+

Builtin Types

+
+

Boolean

+

A two-state logical value (true or false).

+
typedef bool UA_Boolean;
+#define UA_TRUE true UA_INTERNAL_DEPRECATED
+#define UA_FALSE false UA_INTERNAL_DEPRECATED
+
+
+
+
+

SByte

+

An integer value between -128 and 127.

+
typedef int8_t UA_SByte;
+#define UA_SBYTE_MIN (-128)
+#define UA_SBYTE_MAX 127
+
+
+
+
+

Byte

+

An integer value between 0 and 255.

+
typedef uint8_t UA_Byte;
+#define UA_BYTE_MIN 0
+#define UA_BYTE_MAX 255
+
+
+
+
+

Int16

+

An integer value between -32 768 and 32 767.

+
typedef int16_t UA_Int16;
+#define UA_INT16_MIN (-32768)
+#define UA_INT16_MAX 32767
+
+
+
+
+

UInt16

+

An integer value between 0 and 65 535.

+
typedef uint16_t UA_UInt16;
+#define UA_UINT16_MIN 0
+#define UA_UINT16_MAX 65535
+
+
+
+
+

Int32

+

An integer value between -2 147 483 648 and 2 147 483 647.

+
typedef int32_t UA_Int32;
+#define UA_INT32_MIN ((int32_t)-2147483648LL)
+#define UA_INT32_MAX 2147483647L
+
+
+
+
+

UInt32

+

An integer value between 0 and 4 294 967 295.

+
typedef uint32_t UA_UInt32;
+#define UA_UINT32_MIN 0
+#define UA_UINT32_MAX 4294967295UL
+
+
+
+
+

Int64

+

An integer value between -9 223 372 036 854 775 808 and +9 223 372 036 854 775 807.

+
typedef int64_t UA_Int64;
+#define UA_INT64_MAX (int64_t)9223372036854775807LL
+#define UA_INT64_MIN ((int64_t)-UA_INT64_MAX-1LL)
+
+
+
+
+

UInt64

+

An integer value between 0 and 18 446 744 073 709 551 615.

+
typedef uint64_t UA_UInt64;
+#define UA_UINT64_MIN 0
+#define UA_UINT64_MAX (uint64_t)18446744073709551615ULL
+
+
+
+
+

Float

+

An IEEE single precision (32 bit) floating point value.

+
typedef float UA_Float;
+#define UA_FLOAT_MIN FLT_MIN;
+#define UA_FLOAT_MAX FLT_MAX;
+
+
+
+
+

Double

+

An IEEE double precision (64 bit) floating point value.

+
typedef double UA_Double;
+#define UA_DOUBLE_MIN DBL_MIN;
+#define UA_DOUBLE_MAX DBL_MAX;
+
+
+
+
+

StatusCode

+

A numeric identifier for an error or condition that is associated with a +value or an operation. See the section StatusCodes for the meaning of +a specific code.

+

Each StatusCode has one of three “severity” bit-flags: +Good, Uncertain, Bad. An additional reason is indicated by the SubCode +bitfield.

+
    +
  • A StatusCode with severity Good means that the value is of good quality.

  • +
  • A StatusCode with severity Uncertain means that the quality of the value is +uncertain for reasons indicated by the SubCode.

  • +
  • A StatusCode with severity Bad means that the value is not usable for +reasons indicated by the SubCode.

  • +
+
typedef uint32_t UA_StatusCode;
+
+/* Returns the human-readable name of the StatusCode. If no matching StatusCode
+ * is found, a default string for "Unknown" is returned. This feature might be
+ * disabled to create a smaller binary with the
+ * UA_ENABLE_STATUSCODE_DESCRIPTIONS build-flag. Then the function returns an
+ * empty string for every StatusCode. */
+const char *
+UA_StatusCode_name(UA_StatusCode code);
+
+/* Extracts the severity from a StatusCode. See Part 4, Section 7.34 for
+ * details. */
+UA_INLINABLE(UA_Boolean
+             UA_StatusCode_isBad(UA_StatusCode code), {
+    return ((code >> 30) >= 0x02);
+})
+
+UA_INLINABLE(UA_Boolean
+             UA_StatusCode_isUncertain(UA_StatusCode code), {
+    return ((code >> 30) == 0x01);
+})
+
+UA_INLINABLE(UA_Boolean
+             UA_StatusCode_isGood(UA_StatusCode code), {
+    return ((code >> 30) == 0x00);
+})
+
+/* Compares the top 16 bits of two StatusCodes for equality. This should only
+ * be used when processing user-defined StatusCodes e.g when processing a ReadResponse.
+ * As a convention, the lower bits of StatusCodes should not be used internally, meaning
+ * can compare them without the use of this function. */
+UA_INLINABLE(UA_Boolean
+             UA_StatusCode_isEqualTop(UA_StatusCode s1, UA_StatusCode s2), {
+    return ((s1 & 0xFFFF0000) == (s2 & 0xFFFF0000));
+})
+
+
+
+
+

String

+

A sequence of Unicode characters. Strings are just an array of UA_Byte.

+
typedef struct {
+    size_t length; /* The length of the string */
+    UA_Byte *data; /* The content (not null-terminated) */
+} UA_String;
+
+/* Copies the content on the heap. Returns a null-string when alloc fails */
+UA_String
+UA_String_fromChars(const char *src);
+
+UA_Boolean
+UA_String_isEmpty(const UA_String *s);
+
+extern const UA_String UA_STRING_NULL;
+
+
+

UA_STRING returns a string pointing to the original char-array. +UA_STRING_ALLOC is shorthand for UA_String_fromChars and makes a copy +of the char-array.

+
UA_INLINABLE(UA_String
+             UA_STRING(char *chars), {
+    UA_String s;
+    memset(&s, 0, sizeof(s));
+    if(!chars)
+        return s;
+    s.length = strlen(chars); s.data = (UA_Byte*)chars;
+    return s;
+})
+
+#define UA_STRING_ALLOC(CHARS) UA_String_fromChars(CHARS)
+
+/* Define strings at compile time (in ROM) */
+#define UA_STRING_STATIC(CHARS) {sizeof(CHARS)-1, (UA_Byte*)CHARS}
+
+
+
+
+

DateTime

+

An instance in time. A DateTime value is encoded as a 64-bit signed integer +which represents the number of 100 nanosecond intervals since January 1, 1601 +(UTC).

+

The methods providing an interface to the system clock are architecture- +specific. Usually, they provide a UTC clock that includes leap seconds. The +OPC UA standard allows the use of International Atomic Time (TAI) for the +DateTime instead. But this is still unusual and not implemented for most +SDKs. Currently (2019), UTC and TAI are 37 seconds apart due to leap +seconds.

+
typedef int64_t UA_DateTime;
+
+/* Multiples to convert durations to DateTime */
+#define UA_DATETIME_USEC 10LL
+#define UA_DATETIME_MSEC (UA_DATETIME_USEC * 1000LL)
+#define UA_DATETIME_SEC (UA_DATETIME_MSEC * 1000LL)
+
+/* The current time in UTC time */
+UA_DateTime UA_DateTime_now(void);
+
+/* Offset between local time and UTC time */
+UA_Int64 UA_DateTime_localTimeUtcOffset(void);
+
+/* CPU clock invariant to system time changes. Use only to measure durations,
+ * not absolute time. */
+UA_DateTime UA_DateTime_nowMonotonic(void);
+
+/* Represents a Datetime as a structure */
+typedef struct UA_DateTimeStruct {
+    UA_UInt16 nanoSec;
+    UA_UInt16 microSec;
+    UA_UInt16 milliSec;
+    UA_UInt16 sec;
+    UA_UInt16 min;
+    UA_UInt16 hour;
+    UA_UInt16 day;   /* From 1 to 31 */
+    UA_UInt16 month; /* From 1 to 12 */
+    UA_Int16 year;   /* Can be negative (BC) */
+} UA_DateTimeStruct;
+
+UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime t);
+UA_DateTime UA_DateTime_fromStruct(UA_DateTimeStruct ts);
+
+/* The C99 standard (7.23.1) says: "The range and precision of times
+ * representable in clock_t and time_t are implementation-defined." On most
+ * systems, time_t is a 4 or 8 byte integer counting seconds since the UTC Unix
+ * epoch. The following methods are used for conversion. */
+
+/* Datetime of 1 Jan 1970 00:00 */
+#define UA_DATETIME_UNIX_EPOCH (11644473600LL * UA_DATETIME_SEC)
+
+UA_INLINABLE(UA_Int64
+             UA_DateTime_toUnixTime(UA_DateTime date), {
+    return (date - UA_DATETIME_UNIX_EPOCH) / UA_DATETIME_SEC;
+})
+
+UA_INLINABLE(UA_DateTime
+             UA_DateTime_fromUnixTime(UA_Int64 unixDate), {
+    return (unixDate * UA_DATETIME_SEC) + UA_DATETIME_UNIX_EPOCH;
+})
+
+
+
+
+

Guid

+

A 16 byte value that can be used as a globally unique identifier.

+
typedef struct {
+    UA_UInt32 data1;
+    UA_UInt16 data2;
+    UA_UInt16 data3;
+    UA_Byte   data4[8];
+} UA_Guid;
+
+extern const UA_Guid UA_GUID_NULL;
+
+/* Print a Guid in the human-readable format defined in Part 6, 5.1.3
+ *
+ * Format: C496578A-0DFE-4B8F-870A-745238C6AEAE
+ *         |       |    |    |    |            |
+ *         0       8    13   18   23           36
+ *
+ * This allocates memory if the output argument is an empty string. Tries to use
+ * the given buffer otherwise. */
+UA_StatusCode
+UA_Guid_print(const UA_Guid *guid, UA_String *output);
+
+/* Parse the humand-readable Guid format */
+#ifdef UA_ENABLE_PARSING
+UA_StatusCode
+UA_Guid_parse(UA_Guid *guid, const UA_String str);
+
+UA_INLINABLE(UA_Guid
+             UA_GUID(const char *chars), {
+    UA_Guid guid;
+    UA_Guid_parse(&guid, UA_STRING((char*)(uintptr_t)chars));
+    return guid;
+})
+#endif
+
+
+
+
+

ByteString

+

A sequence of octets.

+
typedef UA_String UA_ByteString;
+
+extern const UA_ByteString UA_BYTESTRING_NULL;
+
+/* Allocates memory of size length for the bytestring.
+ * The content is not set to zero. */
+UA_StatusCode
+UA_ByteString_allocBuffer(UA_ByteString *bs, size_t length);
+
+/* Converts a ByteString to the corresponding
+ * base64 representation */
+UA_StatusCode
+UA_ByteString_toBase64(const UA_ByteString *bs, UA_String *output);
+
+/* Parse a ByteString from a base64 representation */
+UA_StatusCode
+UA_ByteString_fromBase64(UA_ByteString *bs,
+                         const UA_String *input);
+
+#define UA_BYTESTRING(chars) UA_STRING(chars)
+#define UA_BYTESTRING_ALLOC(chars) UA_STRING_ALLOC(chars)
+
+/* Returns a non-cryptographic hash of a bytestring */
+UA_UInt32
+UA_ByteString_hash(UA_UInt32 initialHashValue,
+                   const UA_Byte *data, size_t size);
+
+
+
+
+

XmlElement

+

An XML element.

+
typedef UA_String UA_XmlElement;
+
+
+
+
+

NodeId

+

An identifier for a node in the address space of an OPC UA Server.

+
enum UA_NodeIdType {
+    UA_NODEIDTYPE_NUMERIC    = 0, /* In the binary encoding, this can also
+                                   * become 1 or 2 (two-byte and four-byte
+                                   * encoding of small numeric nodeids) */
+    UA_NODEIDTYPE_STRING     = 3,
+    UA_NODEIDTYPE_GUID       = 4,
+    UA_NODEIDTYPE_BYTESTRING = 5
+};
+
+typedef struct {
+    UA_UInt16 namespaceIndex;
+    enum UA_NodeIdType identifierType;
+    union {
+        UA_UInt32     numeric;
+        UA_String     string;
+        UA_Guid       guid;
+        UA_ByteString byteString;
+    } identifier;
+} UA_NodeId;
+
+extern const UA_NodeId UA_NODEID_NULL;
+
+UA_Boolean UA_NodeId_isNull(const UA_NodeId *p);
+
+/* Print the NodeId in the human-readable format defined in Part 6,
+ * 5.3.1.10.
+ *
+ * Examples:
+ *   UA_NODEID("i=13")
+ *   UA_NODEID("ns=10;i=1")
+ *   UA_NODEID("ns=10;s=Hello:World")
+ *   UA_NODEID("g=09087e75-8e5e-499b-954f-f2a9603db28a")
+ *   UA_NODEID("ns=1;b=b3BlbjYyNTQxIQ==") // base64
+ *
+ * The method can either use a pre-allocated string buffer or allocates memory
+ * internally if called with an empty output string. */
+UA_StatusCode
+UA_NodeId_print(const UA_NodeId *id, UA_String *output);
+
+/* Parse the human-readable NodeId format. Attention! String and
+ * ByteString NodeIds have their identifier malloc'ed and need to be
+ * cleaned up. */
+#ifdef UA_ENABLE_PARSING
+UA_StatusCode
+UA_NodeId_parse(UA_NodeId *id, const UA_String str);
+
+UA_INLINABLE(UA_NodeId
+             UA_NODEID(const char *chars), {
+    UA_NodeId id;
+    UA_NodeId_parse(&id, UA_STRING((char*)(uintptr_t)chars));
+    return id;
+})
+#endif
+
+
+

The following methods are a shorthand for creating NodeIds.

+
UA_INLINABLE(UA_NodeId
+             UA_NODEID_NUMERIC(UA_UInt16 nsIndex,
+                               UA_UInt32 identifier), {
+    UA_NodeId id;
+    memset(&id, 0, sizeof(UA_NodeId));
+    id.namespaceIndex = nsIndex;
+    id.identifierType = UA_NODEIDTYPE_NUMERIC;
+    id.identifier.numeric = identifier;
+    return id;
+})
+
+UA_INLINABLE(UA_NodeId
+             UA_NODEID_STRING(UA_UInt16 nsIndex, char *chars), {
+    UA_NodeId id;
+    memset(&id, 0, sizeof(UA_NodeId));
+    id.namespaceIndex = nsIndex;
+    id.identifierType = UA_NODEIDTYPE_STRING;
+    id.identifier.string = UA_STRING(chars);
+    return id;
+})
+
+UA_INLINABLE(UA_NodeId
+             UA_NODEID_STRING_ALLOC(UA_UInt16 nsIndex,
+                                    const char *chars), {
+    UA_NodeId id;
+    memset(&id, 0, sizeof(UA_NodeId));
+    id.namespaceIndex = nsIndex;
+    id.identifierType = UA_NODEIDTYPE_STRING;
+    id.identifier.string = UA_STRING_ALLOC(chars);
+    return id;
+})
+
+UA_INLINABLE(UA_NodeId
+             UA_NODEID_GUID(UA_UInt16 nsIndex, UA_Guid guid), {
+    UA_NodeId id;
+    memset(&id, 0, sizeof(UA_NodeId));
+    id.namespaceIndex = nsIndex;
+    id.identifierType = UA_NODEIDTYPE_GUID;
+    id.identifier.guid = guid;
+    return id;
+})
+
+UA_INLINABLE(UA_NodeId
+             UA_NODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars), {
+    UA_NodeId id;
+    memset(&id, 0, sizeof(UA_NodeId));
+    id.namespaceIndex = nsIndex;
+    id.identifierType = UA_NODEIDTYPE_BYTESTRING;
+    id.identifier.byteString = UA_BYTESTRING(chars);
+    return id;
+})
+
+UA_INLINABLE(UA_NodeId
+             UA_NODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex,
+                                        const char *chars), {
+    UA_NodeId id;
+    memset(&id, 0, sizeof(UA_NodeId));
+    id.namespaceIndex = nsIndex;
+    id.identifierType = UA_NODEIDTYPE_BYTESTRING;
+    id.identifier.byteString = UA_BYTESTRING_ALLOC(chars);
+    return id;
+})
+
+/* Total ordering of NodeId */
+UA_Order
+UA_NodeId_order(const UA_NodeId *n1, const UA_NodeId *n2);
+
+/* Returns a non-cryptographic hash for NodeId */
+UA_UInt32 UA_NodeId_hash(const UA_NodeId *n);
+
+
+
+
+

ExpandedNodeId

+

A NodeId that allows the namespace URI to be specified instead of an index.

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_String namespaceUri;
+    UA_UInt32 serverIndex;
+} UA_ExpandedNodeId;
+
+extern const UA_ExpandedNodeId UA_EXPANDEDNODEID_NULL;
+
+/* Print the ExpandedNodeId in the humand-readable format defined in Part 6,
+ * 5.3.1.11:
+ *
+ *   svr=<serverindex>;ns=<namespaceindex>;<type>=<value>
+ *     or
+ *   svr=<serverindex>;nsu=<uri>;<type>=<value>
+ *
+ * The definitions for svr, ns and nsu is omitted if zero / the empty string.
+ *
+ * The method can either use a pre-allocated string buffer or allocates memory
+ * internally if called with an empty output string. */
+UA_StatusCode
+UA_ExpandedNodeId_print(const UA_ExpandedNodeId *id, UA_String *output);
+
+/* Parse the human-readable NodeId format. Attention! String and
+ * ByteString NodeIds have their identifier malloc'ed and need to be
+ * cleaned up. */
+#ifdef UA_ENABLE_PARSING
+UA_StatusCode
+UA_ExpandedNodeId_parse(UA_ExpandedNodeId *id, const UA_String str);
+
+UA_INLINABLE(UA_ExpandedNodeId
+             UA_EXPANDEDNODEID(const char *chars), {
+    UA_ExpandedNodeId id;
+    UA_ExpandedNodeId_parse(&id, UA_STRING((char*)(uintptr_t)chars));
+    return id;
+})
+#endif
+
+
+

The following functions are shorthand for creating ExpandedNodeIds.

+
UA_INLINABLE(UA_ExpandedNodeId
+             UA_EXPANDEDNODEID_NUMERIC(UA_UInt16 nsIndex, UA_UInt32 identifier), {
+    UA_ExpandedNodeId id; id.nodeId = UA_NODEID_NUMERIC(nsIndex, identifier);
+    id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id;
+})
+
+UA_INLINABLE(UA_ExpandedNodeId
+             UA_EXPANDEDNODEID_STRING(UA_UInt16 nsIndex, char *chars), {
+    UA_ExpandedNodeId id; id.nodeId = UA_NODEID_STRING(nsIndex, chars);
+    id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id;
+})
+
+UA_INLINABLE(UA_ExpandedNodeId
+             UA_EXPANDEDNODEID_STRING_ALLOC(UA_UInt16 nsIndex, const char *chars), {
+    UA_ExpandedNodeId id; id.nodeId = UA_NODEID_STRING_ALLOC(nsIndex, chars);
+    id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id;
+})
+
+UA_INLINABLE(UA_ExpandedNodeId
+             UA_EXPANDEDNODEID_STRING_GUID(UA_UInt16 nsIndex, UA_Guid guid), {
+    UA_ExpandedNodeId id; id.nodeId = UA_NODEID_GUID(nsIndex, guid);
+    id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id;
+})
+
+UA_INLINABLE(UA_ExpandedNodeId
+             UA_EXPANDEDNODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars), {
+    UA_ExpandedNodeId id; id.nodeId = UA_NODEID_BYTESTRING(nsIndex, chars);
+    id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id;
+})
+
+UA_INLINABLE(UA_ExpandedNodeId
+             UA_EXPANDEDNODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex, const char *chars), {
+    UA_ExpandedNodeId id; id.nodeId = UA_NODEID_BYTESTRING_ALLOC(nsIndex, chars);
+    id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id;
+})
+
+UA_INLINABLE(UA_ExpandedNodeId
+             UA_EXPANDEDNODEID_NODEID(UA_NodeId nodeId), {
+    UA_ExpandedNodeId id; memset(&id, 0, sizeof(UA_ExpandedNodeId));
+    id.nodeId = nodeId; return id;
+})
+
+/* Does the ExpandedNodeId point to a local node? That is, are namespaceUri and
+ * serverIndex empty? */
+UA_Boolean
+UA_ExpandedNodeId_isLocal(const UA_ExpandedNodeId *n);
+
+/* Total ordering of ExpandedNodeId */
+UA_Order
+UA_ExpandedNodeId_order(const UA_ExpandedNodeId *n1,
+                        const UA_ExpandedNodeId *n2);
+
+/* Returns a non-cryptographic hash for ExpandedNodeId. The hash of an
+ * ExpandedNodeId is identical to the hash of the embedded (simple) NodeId if
+ * the ServerIndex is zero and no NamespaceUri is set. */
+UA_UInt32
+UA_ExpandedNodeId_hash(const UA_ExpandedNodeId *n);
+
+
+
+
+

QualifiedName

+

A name qualified by a namespace.

+
typedef struct {
+    UA_UInt16 namespaceIndex;
+    UA_String name;
+} UA_QualifiedName;
+
+UA_INLINABLE(UA_Boolean
+             UA_QualifiedName_isNull(const UA_QualifiedName *q), {
+    return (q->namespaceIndex == 0 && q->name.length == 0);
+})
+
+/* Returns a non-cryptographic hash for QualifiedName */
+UA_UInt32
+UA_QualifiedName_hash(const UA_QualifiedName *q);
+
+UA_INLINABLE(UA_QualifiedName
+             UA_QUALIFIEDNAME(UA_UInt16 nsIndex, char *chars), {
+    UA_QualifiedName qn;
+    qn.namespaceIndex = nsIndex;
+    qn.name = UA_STRING(chars);
+    return qn;
+})
+
+UA_INLINABLE(UA_QualifiedName
+             UA_QUALIFIEDNAME_ALLOC(UA_UInt16 nsIndex, const char *chars), {
+    UA_QualifiedName qn;
+    qn.namespaceIndex = nsIndex;
+    qn.name = UA_STRING_ALLOC(chars);
+    return qn;
+})
+
+
+
+
+

LocalizedText

+

Human readable text with an optional locale identifier.

+
typedef struct {
+    UA_String locale;
+    UA_String text;
+} UA_LocalizedText;
+
+UA_INLINABLE(UA_LocalizedText
+             UA_LOCALIZEDTEXT(char *locale, char *text), {
+    UA_LocalizedText lt;
+    lt.locale = UA_STRING(locale);
+    lt.text = UA_STRING(text);
+    return lt;
+})
+
+UA_INLINABLE(UA_LocalizedText
+             UA_LOCALIZEDTEXT_ALLOC(const char *locale, const char *text), {
+    UA_LocalizedText lt;
+    lt.locale = UA_STRING_ALLOC(locale);
+    lt.text = UA_STRING_ALLOC(text);
+    return lt;
+})
+
+
+
+
+

NumericRange

+

NumericRanges are used to indicate subsets of a (multidimensional) array. +They no official data type in the OPC UA standard and are transmitted only +with a string encoding, such as “1:2,0:3,5”. The colon separates min/max +index and the comma separates dimensions. A single value indicates a range +with a single element (min==max).

+
typedef struct {
+    UA_UInt32 min;
+    UA_UInt32 max;
+} UA_NumericRangeDimension;
+
+typedef struct  {
+    size_t dimensionsSize;
+    UA_NumericRangeDimension *dimensions;
+} UA_NumericRange;
+
+UA_StatusCode
+UA_NumericRange_parse(UA_NumericRange *range, const UA_String str);
+
+UA_INLINABLE(UA_NumericRange
+             UA_NUMERICRANGE(const char *s), {
+    UA_NumericRange nr;
+    memset(&nr, 0, sizeof(nr));
+    UA_NumericRange_parse(&nr, UA_STRING((char*)(uintptr_t)s));
+    return nr;
+})
+
+
+
+
+

Variant

+

Variants may contain values of any type together with a description of the +content. See the section on Generic Type Handling on how types are described. +The standard mandates that variants contain built-in data types only. If the +value is not of a builtin type, it is wrapped into an ExtensionObject. +open62541 hides this wrapping transparently in the encoding layer. If the +data type is unknown to the receiver, the variant contains the original +ExtensionObject in binary or XML encoding.

+

Variants may contain a scalar value or an array. For details on the handling +of arrays, see the section on Array handling. Array variants can have +an additional dimensionality (matrix, 3-tensor, …) defined in an array of +dimension lengths. The actual values are kept in an array of dimensions one. +For users who work with higher-dimensions arrays directly, keep in mind that +dimensions of higher rank are serialized first (the highest rank dimension +has stride 1 and elements follow each other directly). Usually it is simplest +to interact with higher-dimensional arrays via UA_NumericRange +descriptions (see Array handling).

+

To differentiate between scalar / array variants, the following definition is +used. UA_Variant_isScalar provides simplified access to these checks.

+
    +
  • arrayLength == 0 && data == NULL: undefined array of length -1

  • +
  • arrayLength == 0 && data == UA_EMPTY_ARRAY_SENTINEL: array of length 0

  • +
  • arrayLength == 0 && data > UA_EMPTY_ARRAY_SENTINEL: scalar value

  • +
  • arrayLength > 0: array of the given length

  • +
+

Variants can also be empty. Then, the pointer to the type description is +NULL.

+
/* Forward declaration. See the section on Generic Type Handling */
+struct UA_DataType;
+typedef struct UA_DataType UA_DataType;
+
+#define UA_EMPTY_ARRAY_SENTINEL ((void*)0x01)
+
+typedef enum {
+    UA_VARIANT_DATA,         /* The data has the same lifecycle as the variant */
+    UA_VARIANT_DATA_NODELETE /* The data is "borrowed" by the variant and is
+                              * not deleted when the variant is cleared up.
+                              * The array dimensions also borrowed. */
+} UA_VariantStorageType;
+
+typedef struct {
+    const UA_DataType *type;      /* The data type description */
+    UA_VariantStorageType storageType;
+    size_t arrayLength;           /* The number of elements in the data array */
+    void *data;                   /* Points to the scalar or array data */
+    size_t arrayDimensionsSize;   /* The number of dimensions */
+    UA_UInt32 *arrayDimensions;   /* The length of each dimension */
+} UA_Variant;
+
+/* Returns true if the variant has no value defined (contains neither an array
+ * nor a scalar value).
+ *
+ * @param v The variant
+ * @return Is the variant empty */
+UA_INLINABLE(UA_Boolean
+             UA_Variant_isEmpty(const UA_Variant *v), {
+    return v->type == NULL;
+})
+
+/* Returns true if the variant contains a scalar value. Note that empty variants
+ * contain an array of length -1 (undefined).
+ *
+ * @param v The variant
+ * @return Does the variant contain a scalar value */
+UA_INLINABLE(UA_Boolean
+             UA_Variant_isScalar(const UA_Variant *v), {
+    return (v->arrayLength == 0 && v->data > UA_EMPTY_ARRAY_SENTINEL);
+})
+
+/* Returns true if the variant contains a scalar value of the given type.
+ *
+ * @param v The variant
+ * @param type The data type
+ * @return Does the variant contain a scalar value of the given type */
+UA_INLINABLE(UA_Boolean
+             UA_Variant_hasScalarType(const UA_Variant *v,
+                                      const UA_DataType *type), {
+    return UA_Variant_isScalar(v) && type == v->type;
+})
+
+/* Returns true if the variant contains an array of the given type.
+ *
+ * @param v The variant
+ * @param type The data type
+ * @return Does the variant contain an array of the given type */
+UA_INLINABLE(UA_Boolean
+             UA_Variant_hasArrayType(const UA_Variant *v,
+                                     const UA_DataType *type), {
+    return (!UA_Variant_isScalar(v)) && type == v->type;
+})
+
+/* Set the variant to a scalar value that already resides in memory. The value
+ * takes on the lifecycle of the variant and is deleted with it.
+ *
+ * @param v The variant
+ * @param p A pointer to the value data
+ * @param type The datatype of the value in question */
+void
+UA_Variant_setScalar(UA_Variant *v, void *p,
+                     const UA_DataType *type);
+
+/* Set the variant to a scalar value that is copied from an existing variable.
+ * @param v The variant
+ * @param p A pointer to the value data
+ * @param type The datatype of the value
+ * @return Indicates whether the operation succeeded or returns an error code */
+UA_StatusCode
+UA_Variant_setScalarCopy(UA_Variant *v, const void *p,
+                         const UA_DataType *type);
+
+/* Set the variant to an array that already resides in memory. The array takes
+ * on the lifecycle of the variant and is deleted with it.
+ *
+ * @param v The variant
+ * @param array A pointer to the array data
+ * @param arraySize The size of the array
+ * @param type The datatype of the array */
+void
+UA_Variant_setArray(UA_Variant *v, void *array,
+                    size_t arraySize, const UA_DataType *type);
+
+/* Set the variant to an array that is copied from an existing array.
+ *
+ * @param v The variant
+ * @param array A pointer to the array data
+ * @param arraySize The size of the array
+ * @param type The datatype of the array
+ * @return Indicates whether the operation succeeded or returns an error code */
+UA_StatusCode
+UA_Variant_setArrayCopy(UA_Variant *v, const void *array,
+                        size_t arraySize, const UA_DataType *type);
+
+/* Copy the variant, but use only a subset of the (multidimensional) array into
+ * a variant. Returns an error code if the variant is not an array or if the
+ * indicated range does not fit.
+ *
+ * @param src The source variant
+ * @param dst The target variant
+ * @param range The range of the copied data
+ * @return Returns UA_STATUSCODE_GOOD or an error code */
+UA_StatusCode
+UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst,
+                     const UA_NumericRange range);
+
+/* Insert a range of data into an existing variant. The data array cannot be
+ * reused afterwards if it contains types without a fixed size (e.g. strings)
+ * since the members are moved into the variant and take on its lifecycle.
+ *
+ * @param v The variant
+ * @param dataArray The data array. The type must match the variant
+ * @param dataArraySize The length of the data array. This is checked to match
+ *        the range size.
+ * @param range The range of where the new data is inserted
+ * @return Returns UA_STATUSCODE_GOOD or an error code */
+UA_StatusCode
+UA_Variant_setRange(UA_Variant *v, void *array,
+                    size_t arraySize, const UA_NumericRange range);
+
+/* Deep-copy a range of data into an existing variant.
+ *
+ * @param v The variant
+ * @param dataArray The data array. The type must match the variant
+ * @param dataArraySize The length of the data array. This is checked to match
+ *        the range size.
+ * @param range The range of where the new data is inserted
+ * @return Returns UA_STATUSCODE_GOOD or an error code */
+UA_StatusCode
+UA_Variant_setRangeCopy(UA_Variant *v, const void *array,
+                        size_t arraySize, const UA_NumericRange range);
+
+
+
+
+

ExtensionObject

+

ExtensionObjects may contain scalars of any data type. Even those that are +unknown to the receiver. See the section on Generic Type Handling on how types +are described. If the received data type is unknown, the encoded string and +target NodeId is stored instead of the decoded value.

+
typedef enum {
+    UA_EXTENSIONOBJECT_ENCODED_NOBODY     = 0,
+    UA_EXTENSIONOBJECT_ENCODED_BYTESTRING = 1,
+    UA_EXTENSIONOBJECT_ENCODED_XML        = 2,
+    UA_EXTENSIONOBJECT_DECODED            = 3,
+    UA_EXTENSIONOBJECT_DECODED_NODELETE   = 4 /* Don't delete the content
+                                                 together with the
+                                                 ExtensionObject */
+} UA_ExtensionObjectEncoding;
+
+typedef struct {
+    UA_ExtensionObjectEncoding encoding;
+    union {
+        struct {
+            UA_NodeId typeId;   /* The nodeid of the datatype */
+            UA_ByteString body; /* The bytestring of the encoded data */
+        } encoded;
+        struct {
+            const UA_DataType *type;
+            void *data;
+        } decoded;
+    } content;
+} UA_ExtensionObject;
+
+/* Initialize the ExtensionObject and set the "decoded" value to the given
+ * pointer. The value will be deleted when the ExtensionObject is cleared. */
+void
+UA_ExtensionObject_setValue(UA_ExtensionObject *eo,
+                            void *p,
+                            const UA_DataType *type);
+
+/* Initialize the ExtensionObject and set the "decoded" value to the given
+ * pointer. The value will *not* be deleted when the ExtensionObject is
+ * cleared. */
+void
+UA_ExtensionObject_setValueNoDelete(UA_ExtensionObject *eo,
+                                    void *p,
+                                    const UA_DataType *type);
+
+/* Initialize the ExtensionObject and set the "decoded" value to a fresh copy of
+ * the given value pointer. The value will be deleted when the ExtensionObject
+ * is cleared. */
+UA_StatusCode
+UA_ExtensionObject_setValueCopy(UA_ExtensionObject *eo,
+                                void *p,
+                                const UA_DataType *type);
+
+
+
+
+

DataValue

+

A data value with an associated status code and timestamps.

+
typedef struct {
+    UA_Variant    value;
+    UA_DateTime   sourceTimestamp;
+    UA_DateTime   serverTimestamp;
+    UA_UInt16     sourcePicoseconds;
+    UA_UInt16     serverPicoseconds;
+    UA_StatusCode status;
+    UA_Boolean    hasValue             : 1;
+    UA_Boolean    hasStatus            : 1;
+    UA_Boolean    hasSourceTimestamp   : 1;
+    UA_Boolean    hasServerTimestamp   : 1;
+    UA_Boolean    hasSourcePicoseconds : 1;
+    UA_Boolean    hasServerPicoseconds : 1;
+} UA_DataValue;
+
+/* Copy the DataValue, but use only a subset of the (multidimensional) array of
+ * of the variant of the source DataValue. Returns an error code if the variant
+ * of the DataValue is not an array or if the indicated range does not fit.
+ *
+ * @param src The source DataValue
+ * @param dst The target DataValue
+ * @param range The range of the variant of the DataValue to copy
+ * @return Returns UA_STATUSCODE_GOOD or an error code */
+UA_StatusCode
+UA_DataValue_copyVariantRange(const UA_DataValue *src, UA_DataValue *dst,
+                              const UA_NumericRange range);
+
+
+
+
+

DiagnosticInfo

+

A structure that contains detailed error and diagnostic information +associated with a StatusCode.

+
typedef struct UA_DiagnosticInfo {
+    UA_Boolean    hasSymbolicId          : 1;
+    UA_Boolean    hasNamespaceUri        : 1;
+    UA_Boolean    hasLocalizedText       : 1;
+    UA_Boolean    hasLocale              : 1;
+    UA_Boolean    hasAdditionalInfo      : 1;
+    UA_Boolean    hasInnerStatusCode     : 1;
+    UA_Boolean    hasInnerDiagnosticInfo : 1;
+    UA_Int32      symbolicId;
+    UA_Int32      namespaceUri;
+    UA_Int32      localizedText;
+    UA_Int32      locale;
+    UA_String     additionalInfo;
+    UA_StatusCode innerStatusCode;
+    struct UA_DiagnosticInfo *innerDiagnosticInfo;
+} UA_DiagnosticInfo;
+
+
+
+
+
+

Generic Type Handling

+

All information about a (builtin/structured) data type is stored in a +UA_DataType. The array UA_TYPES contains the description of all +standard-defined types. This type description is used for the following +generic operations that work on all types:

+
    +
  • void T_init(T *ptr): Initialize the data type. This is synonymous with +zeroing out the memory, i.e. memset(ptr, 0, sizeof(T)).

  • +
  • T* T_new(): Allocate and return the memory for the data type. The +value is already initialized.

  • +
  • UA_StatusCode T_copy(const T *src, T *dst): Copy the content of the +data type. Returns UA_STATUSCODE_GOOD or +UA_STATUSCODE_BADOUTOFMEMORY.

  • +
  • void T_clear(T *ptr): Delete the dynamically allocated content +of the data type and perform a T_init to reset the type.

  • +
  • void T_delete(T *ptr): Delete the content of the data type and the +memory for the data type itself.

  • +
  • void T_equal(T *p1, T *p2): Compare whether p1 and p2 have +identical content. You can use UA_order if an absolute ordering +is required.

  • +
+

Specializations, such as UA_Int32_new() are derived from the generic +type operations as static inline functions.

+
typedef struct {
+#ifdef UA_ENABLE_TYPEDESCRIPTION
+    const char *memberName;       /* Human-readable member name */
+#endif
+    const UA_DataType *memberType;/* The member data type description */
+    UA_Byte padding    : 6;       /* How much padding is there before this
+                                     member element? For arrays this is the
+                                     padding before the size_t length member.
+                                     (No padding between size_t and the
+                                     following ptr.) For unions, the padding
+                                     includes the size of the switchfield (the
+                                     offset from the start of the union
+                                     type). */
+    UA_Byte isArray    : 1;       /* The member is an array */
+    UA_Byte isOptional : 1;       /* The member is an optional field */
+} UA_DataTypeMember;
+
+/* The DataType "kind" is an internal type classification. It is used to
+ * dispatch handling to the correct routines. */
+#define UA_DATATYPEKINDS 31
+typedef enum {
+    UA_DATATYPEKIND_BOOLEAN = 0,
+    UA_DATATYPEKIND_SBYTE = 1,
+    UA_DATATYPEKIND_BYTE = 2,
+    UA_DATATYPEKIND_INT16 = 3,
+    UA_DATATYPEKIND_UINT16 = 4,
+    UA_DATATYPEKIND_INT32 = 5,
+    UA_DATATYPEKIND_UINT32 = 6,
+    UA_DATATYPEKIND_INT64 = 7,
+    UA_DATATYPEKIND_UINT64 = 8,
+    UA_DATATYPEKIND_FLOAT = 9,
+    UA_DATATYPEKIND_DOUBLE = 10,
+    UA_DATATYPEKIND_STRING = 11,
+    UA_DATATYPEKIND_DATETIME = 12,
+    UA_DATATYPEKIND_GUID = 13,
+    UA_DATATYPEKIND_BYTESTRING = 14,
+    UA_DATATYPEKIND_XMLELEMENT = 15,
+    UA_DATATYPEKIND_NODEID = 16,
+    UA_DATATYPEKIND_EXPANDEDNODEID = 17,
+    UA_DATATYPEKIND_STATUSCODE = 18,
+    UA_DATATYPEKIND_QUALIFIEDNAME = 19,
+    UA_DATATYPEKIND_LOCALIZEDTEXT = 20,
+    UA_DATATYPEKIND_EXTENSIONOBJECT = 21,
+    UA_DATATYPEKIND_DATAVALUE = 22,
+    UA_DATATYPEKIND_VARIANT = 23,
+    UA_DATATYPEKIND_DIAGNOSTICINFO = 24,
+    UA_DATATYPEKIND_DECIMAL = 25,
+    UA_DATATYPEKIND_ENUM = 26,
+    UA_DATATYPEKIND_STRUCTURE = 27,
+    UA_DATATYPEKIND_OPTSTRUCT = 28, /* struct with optional fields */
+    UA_DATATYPEKIND_UNION = 29,
+    UA_DATATYPEKIND_BITFIELDCLUSTER = 30 /* bitfields + padding */
+} UA_DataTypeKind;
+
+struct UA_DataType {
+#ifdef UA_ENABLE_TYPEDESCRIPTION
+    const char *typeName;
+#endif
+    UA_NodeId typeId;           /* The nodeid of the type */
+    UA_NodeId binaryEncodingId; /* NodeId of datatype when encoded as binary */
+    //UA_NodeId xmlEncodingId;  /* NodeId of datatype when encoded as XML */
+    UA_UInt32 memSize     : 16; /* Size of the struct in memory */
+    UA_UInt32 typeKind    : 6;  /* Dispatch index for the handling routines */
+    UA_UInt32 pointerFree : 1;  /* The type (and its members) contains no
+                                 * pointers that need to be freed */
+    UA_UInt32 overlayable : 1;  /* The type has the identical memory layout
+                                 * in memory and on the binary stream. */
+    UA_UInt32 membersSize : 8;  /* How many members does the type have? */
+    UA_DataTypeMember *members;
+};
+
+/* Datatype arrays with custom type definitions can be added in a linked list to
+ * the client or server configuration. */
+typedef struct UA_DataTypeArray {
+    const struct UA_DataTypeArray *next;
+    const size_t typesSize;
+    const UA_DataType *types;
+    UA_Boolean cleanup; /* Free the array structure and its content
+                           when the client or server configuration
+                           containing it is cleaned up */
+} UA_DataTypeArray;
+
+/* Returns the offset and type of a structure member. The return value is false
+ * if the member was not found.
+ *
+ * If the member is an array, the offset points to the (size_t) length field.
+ * (The array pointer comes after the length field without any padding.) */
+#ifdef UA_ENABLE_TYPEDESCRIPTION
+UA_Boolean
+UA_DataType_getStructMember(const UA_DataType *type,
+                            const char *memberName,
+                            size_t *outOffset,
+                            const UA_DataType **outMemberType,
+                            UA_Boolean *outIsArray);
+#endif
+
+/* Test if the data type is a numeric builtin data type (via the typeKind field
+ * of UA_DataType). This includes integers and floating point numbers. Not
+ * included are Boolean, DateTime, StatusCode and Enums. */
+UA_Boolean
+UA_DataType_isNumeric(const UA_DataType *type);
+
+
+

Builtin data types can be accessed as UA_TYPES[UA_TYPES_XXX], where XXX is +the name of the data type. If only the NodeId of a type is known, use the +following method to retrieve the data type description.

+
/* Returns the data type description for the type's identifier or NULL if no
+ * matching data type was found. */
+const UA_DataType *
+UA_findDataType(const UA_NodeId *typeId);
+
+/*
+ * Add custom data types to the search scope of UA_findDataType. */
+
+const UA_DataType *
+UA_findDataTypeWithCustom(const UA_NodeId *typeId,
+                          const UA_DataTypeArray *customTypes);
+
+
+

The following functions are used for generic handling of data types.

+
/* Allocates and initializes a variable of type dataType
+ *
+ * @param type The datatype description
+ * @return Returns the memory location of the variable or NULL if no
+ *         memory could be allocated */
+void * UA_new(const UA_DataType *type);
+
+/* Initializes a variable to default values
+ *
+ * @param p The memory location of the variable
+ * @param type The datatype description */
+UA_INLINABLE(void
+             UA_init(void *p, const UA_DataType *type), {
+    memset(p, 0, type->memSize);
+})
+
+/* Copies the content of two variables. If copying fails (e.g. because no memory
+ * was available for an array), then dst is emptied and initialized to prevent
+ * memory leaks.
+ *
+ * @param src The memory location of the source variable
+ * @param dst The memory location of the destination variable
+ * @param type The datatype description
+ * @return Indicates whether the operation succeeded or returns an error code */
+UA_StatusCode
+UA_copy(const void *src, void *dst, const UA_DataType *type);
+
+/* Deletes the dynamically allocated content of a variable (e.g. resets all
+ * arrays to undefined arrays). Afterwards, the variable can be safely deleted
+ * without causing memory leaks. But the variable is not initialized and may
+ * contain old data that is not memory-relevant.
+ *
+ * @param p The memory location of the variable
+ * @param type The datatype description of the variable */
+void UA_clear(void *p, const UA_DataType *type);
+
+#define UA_deleteMembers(p, type) UA_clear(p, type)
+
+/* Frees a variable and all of its content.
+ *
+ * @param p The memory location of the variable
+ * @param type The datatype description of the variable */
+void UA_delete(void *p, const UA_DataType *type);
+
+/* Pretty-print the value from the datatype. The output is pretty-printed JSON5.
+ * Note that this format is non-standard and should not be sent over the
+ * network. It can however be read by our own JSON decoding.
+ *
+ * @param p The memory location of the variable
+ * @param type The datatype description of the variable
+ * @param output A string that is used for the pretty-printed output. If the
+ *        memory for string is already allocated, we try to use the existing
+ *        string (the length is adjusted). If the string is empty, memory
+ *        is allocated for it.
+ * @return Indicates whether the operation succeeded */
+#ifdef UA_ENABLE_JSON_ENCODING
+UA_StatusCode
+UA_print(const void *p, const UA_DataType *type, UA_String *output);
+#endif
+
+/* Compare two values and return their order.
+ *
+ * For numerical types (including StatusCodes and Enums), their natural order is
+ * used. NaN is the "smallest" value for floating point values. Different bit
+ * representations of NaN are considered identical.
+ *
+ * All other types have *some* absolute ordering so that a < b, b < c -> a < c.
+ *
+ * The ordering of arrays (also strings) is in "shortlex": A shorter array is
+ * always smaller than a longer array. Otherwise the first different element
+ * defines the order.
+ *
+ * When members of different types are permitted (in Variants and
+ * ExtensionObjects), the memory address in the "UA_DataType*" pointer
+ * determines which variable is smaller.
+ *
+ * @param p1 The memory location of the first value
+ * @param p2 The memory location of the first value
+ * @param type The datatype description of both values */
+UA_Order
+UA_order(const void *p1, const void *p2, const UA_DataType *type);
+
+/* Compare if two values have identical content. */
+UA_INLINABLE(UA_Boolean
+             UA_equal(const void *p1, const void *p2, const UA_DataType *type), {
+    return (UA_order(p1, p2, type) == UA_ORDER_EQ);
+})
+
+
+
+
+

Binary Encoding/Decoding

+

Encoding and decoding routines for the binary format. For the binary decoding +additional data types can be forwarded.

+
/* Returns the number of bytes the value p takes in binary encoding. Returns
+ * zero if an error occurs. */
+size_t
+UA_calcSizeBinary(const void *p, const UA_DataType *type);
+
+/* Encodes a data-structure in the binary format. If outBuf has a length of
+ * zero, a buffer of the required size is allocated. Otherwise, encoding into
+ * the existing outBuf is attempted (and may fail if the buffer is too
+ * small). */
+UA_StatusCode
+UA_encodeBinary(const void *p, const UA_DataType *type,
+                UA_ByteString *outBuf);
+
+/* The structure with the decoding options may be extended in the future.
+ * Zero-out the entire structure initially to ensure code-compatibility when
+ * more fields are added in a later release. */
+typedef struct {
+    const UA_DataTypeArray *customTypes; /* Begin of a linked list with custom
+                                          * datatype definitions */
+} UA_DecodeBinaryOptions;
+
+/* Decodes a data structure from the input buffer in the binary format. It is
+ * assumed that `p` points to valid memory (not necessarily zeroed out). The
+ * options can be NULL and will be disregarded in that case. */
+UA_StatusCode
+UA_decodeBinary(const UA_ByteString *inBuf,
+                void *p, const UA_DataType *type,
+                const UA_DecodeBinaryOptions *options);
+
+
+
+
+

JSON En/Decoding

+

The JSON decoding can parse the official encoding from the OPC UA +specification. It further allows the following extensions:

+
    +
  • The strict JSON format is relaxed to also allow the JSON5 extensions +(https://json5.org/). This allows for more human-readable encoding and adds +convenience features such as trailing commas in arrays and comments within +JSON documents.

  • +
  • Int64/UInt64 don’t necessarily have to be wrapped into a string.

  • +
  • If UA_ENABLE_PARSING is set, NodeIds and ExpandedNodeIds can be given in +the string encoding (e.g. “ns=1;i=42”, see UA_NodeId_parse). The standard +encoding is to express NodeIds as JSON objects.

  • +
+

These extensions are not intended to be used for the OPC UA protocol on the +network. They were rather added to allow more convenient configuration file +formats that also include data in the OPC UA type system.

+
#ifdef UA_ENABLE_JSON_ENCODING
+
+typedef struct {
+    const UA_String *namespaces;
+    size_t namespacesSize;
+    const UA_String *serverUris;
+    size_t serverUrisSize;
+    UA_Boolean useReversible;
+
+    UA_Boolean prettyPrint;   /* Add newlines and spaces for legibility */
+
+    /* Enabling the following options leads to non-standard compatible JSON5
+     * encoding! Use it for pretty-printing, but not for sending messages over
+     * the network. (Our own decoding can still parse it.) */
+
+    UA_Boolean unquotedKeys;  /* Don't print quotes around object element keys */
+    UA_Boolean stringNodeIds; /* String encoding for NodeIds, like "ns=1;i=42" */
+} UA_EncodeJsonOptions;
+
+/* Returns the number of bytes the value src takes in json encoding. Returns
+ * zero if an error occurs. */
+size_t
+UA_calcSizeJson(const void *src, const UA_DataType *type,
+                const UA_EncodeJsonOptions *options);
+
+/* Encodes the scalar value described by type to json encoding.
+ *
+ * @param src The value. Must not be NULL.
+ * @param type The value type. Must not be NULL.
+ * @param outBuf Pointer to ByteString containing the result if the encoding
+ *        was successful
+ * @return Returns a statuscode whether encoding succeeded. */
+UA_StatusCode
+UA_encodeJson(const void *src, const UA_DataType *type, UA_ByteString *outBuf,
+              const UA_EncodeJsonOptions *options);
+
+/* The structure with the decoding options may be extended in the future.
+ * Zero-out the entire structure initially to ensure code-compatibility when
+ * more fields are added in a later release. */
+typedef struct {
+    const UA_String *namespaces;
+    size_t namespacesSize;
+    const UA_String *serverUris;
+    size_t serverUrisSize;
+    const UA_DataTypeArray *customTypes; /* Begin of a linked list with custom
+                                          * datatype definitions */
+} UA_DecodeJsonOptions;
+
+/* Decodes a scalar value described by type from json encoding.
+ *
+ * @param src The buffer with the json encoded value. Must not be NULL.
+ * @param dst The target value. Must not be NULL. The target is assumed to have
+ *        size type->memSize. The value is reset to zero before decoding. If
+ *        decoding fails, members are deleted and the value is reset (zeroed)
+ *        again.
+ * @param type The value type. Must not be NULL.
+ * @param options The options struct for decoding, currently unused
+ * @return Returns a statuscode whether decoding succeeded. */
+UA_StatusCode
+UA_decodeJson(const UA_ByteString *src, void *dst, const UA_DataType *type,
+              const UA_DecodeJsonOptions *options);
+
+#endif /* UA_ENABLE_JSON_ENCODING */
+
+
+
+
+

XML En/Decoding

+

The XML decoding can parse the official encoding from the OPC UA +specification.

+

These extensions are not intended to be used for the OPC UA protocol on the +network. They were rather added to allow more convenient configuration file +formats that also include data in the OPC UA type system.

+
#ifdef UA_ENABLE_XML_ENCODING
+
+typedef struct {
+    UA_Boolean prettyPrint;   /* Add newlines and spaces for legibility */
+} UA_EncodeXmlOptions;
+
+/* Returns the number of bytes the value src takes in xml encoding. Returns
+ * zero if an error occurs. */
+size_t
+UA_calcSizeXml(const void *src, const UA_DataType *type,
+               const UA_EncodeXmlOptions *options);
+
+/* Encodes the scalar value described by type to xml encoding.
+ *
+ * @param src The value. Must not be NULL.
+ * @param type The value type. Must not be NULL.
+ * @param outBuf Pointer to ByteString containing the result if the encoding
+ *        was successful
+ * @return Returns a statuscode whether encoding succeeded. */
+UA_StatusCode
+UA_encodeXml(const void *src, const UA_DataType *type, UA_ByteString *outBuf,
+             const UA_EncodeXmlOptions *options);
+
+/* The structure with the decoding options may be extended in the future.
+ * Zero-out the entire structure initially to ensure code-compatibility when
+ * more fields are added in a later release. */
+typedef struct {
+    const UA_DataTypeArray *customTypes; /* Begin of a linked list with custom
+                                          * datatype definitions */
+} UA_DecodeXmlOptions;
+
+/* Decodes a scalar value described by type from xml encoding.
+ *
+ * @param src The buffer with the xml encoded value. Must not be NULL.
+ * @param dst The target value. Must not be NULL. The target is assumed to have
+ *        size type->memSize. The value is reset to zero before decoding. If
+ *        decoding fails, members are deleted and the value is reset (zeroed)
+ *        again.
+ * @param type The value type. Must not be NULL.
+ * @param options The options struct for decoding, currently unused
+ * @return Returns a statuscode whether decoding succeeded. */
+UA_StatusCode
+UA_decodeXml(const UA_ByteString *src, void *dst, const UA_DataType *type,
+             const UA_DecodeXmlOptions *options);
+
+#endif /* UA_ENABLE_XML_ENCODING */
+
+
+
+
+

Array handling

+

In OPC UA, arrays can have a length of zero or more with the usual meaning. +In addition, arrays can be undefined. Then, they don’t even have a length. In +the binary encoding, this is indicated by an array of length -1.

+

In open62541 however, we use size_t for array lengths. An undefined array +has length 0 and the data pointer is NULL. An array of length 0 also has +length 0 but a data pointer UA_EMPTY_ARRAY_SENTINEL.

+
/* Allocates and initializes an array of variables of a specific type
+ *
+ * @param size The requested array length
+ * @param type The datatype description
+ * @return Returns the memory location of the variable or NULL if no memory
+ *         could be allocated */
+void *
+UA_Array_new(size_t size, const UA_DataType *type);
+
+/* Allocates and copies an array
+ *
+ * @param src The memory location of the source array
+ * @param size The size of the array
+ * @param dst The location of the pointer to the new array
+ * @param type The datatype of the array members
+ * @return Returns UA_STATUSCODE_GOOD or UA_STATUSCODE_BADOUTOFMEMORY */
+UA_StatusCode
+UA_Array_copy(const void *src, size_t size, void **dst,
+              const UA_DataType *type);
+
+/* Resizes (and reallocates) an array. The last entries are initialized to zero
+ * if the array length is increased. If the array length is decreased, the last
+ * entries are removed if the size is decreased.
+ *
+ * @param p Double pointer to the array memory. Can be overwritten by the result
+ *          of a realloc.
+ * @param size The current size of the array. Overwritten in case of success.
+ * @param newSize The new size of the array
+ * @param type The datatype of the array members
+ * @return Returns UA_STATUSCODE_GOOD or UA_STATUSCODE_BADOUTOFMEMORY. The
+ *         original array is left untouched in the failure case. */
+UA_StatusCode
+UA_Array_resize(void **p, size_t *size, size_t newSize,
+                const UA_DataType *type);
+
+/* Append the given element at the end of the array. The content is moved
+ * (shallow copy) and the original memory is _init'ed if appending is
+ * successful.
+ *
+ * @param p Double pointer to the array memory. Can be overwritten by the result
+ *          of a realloc.
+ * @param size The current size of the array. Overwritten in case of success.
+ * @param newElem The element to be appended. The memory is reset upon success.
+ * @param type The datatype of the array members
+ * @return Returns UA_STATUSCODE_GOOD or UA_STATUSCODE_BADOUTOFMEMORY. The
+ *         original array is left untouched in the failure case. */
+UA_StatusCode
+UA_Array_append(void **p, size_t *size, void *newElem,
+                const UA_DataType *type);
+
+/* Append a copy of the given element at the end of the array.
+ *
+ * @param p Double pointer to the array memory. Can be overwritten by the result
+ *          of a realloc.
+ * @param size The current size of the array. Overwritten in case of success.
+ * @param newElem The element to be appended.
+ * @param type The datatype of the array members
+ * @return Returns UA_STATUSCODE_GOOD or UA_STATUSCODE_BADOUTOFMEMORY. The
+ *         original array is left untouched in the failure case. */
+
+UA_StatusCode
+UA_Array_appendCopy(void **p, size_t *size, const void *newElem,
+                    const UA_DataType *type);
+
+/* Deletes an array.
+ *
+ * @param p The memory location of the array
+ * @param size The size of the array
+ * @param type The datatype of the array members */
+void
+UA_Array_delete(void *p, size_t size, const UA_DataType *type);
+
+
+
+
+

Generated Data Type Definitions

+

The following standard-defined datatypes are auto-generated from XML files +that are part of the OPC UA standard. All datatypes are built up from the 25 +builtin-in datatypes from the Data Types section.

+
+

NamingRuleType

+
typedef enum {
+    UA_NAMINGRULETYPE_MANDATORY = 1,
+    UA_NAMINGRULETYPE_OPTIONAL = 2,
+    UA_NAMINGRULETYPE_CONSTRAINT = 3
+} UA_NamingRuleType;
+
+
+
+
+

KeyValuePair

+
typedef struct {
+    UA_QualifiedName key;
+    UA_Variant value;
+} UA_KeyValuePair;
+
+
+
+
+

NodeClass

+
typedef enum {
+    UA_NODECLASS_UNSPECIFIED = 0,
+    UA_NODECLASS_OBJECT = 1,
+    UA_NODECLASS_VARIABLE = 2,
+    UA_NODECLASS_METHOD = 4,
+    UA_NODECLASS_OBJECTTYPE = 8,
+    UA_NODECLASS_VARIABLETYPE = 16,
+    UA_NODECLASS_REFERENCETYPE = 32,
+    UA_NODECLASS_DATATYPE = 64,
+    UA_NODECLASS_VIEW = 128
+} UA_NodeClass;
+
+
+
+
+

StructureType

+
typedef enum {
+    UA_STRUCTURETYPE_STRUCTURE = 0,
+    UA_STRUCTURETYPE_STRUCTUREWITHOPTIONALFIELDS = 1,
+    UA_STRUCTURETYPE_UNION = 2,
+    UA_STRUCTURETYPE_STRUCTUREWITHSUBTYPEDVALUES = 3,
+    UA_STRUCTURETYPE_UNIONWITHSUBTYPEDVALUES = 4
+} UA_StructureType;
+
+
+
+
+

StructureField

+
typedef struct {
+    UA_String name;
+    UA_LocalizedText description;
+    UA_NodeId dataType;
+    UA_Int32 valueRank;
+    size_t arrayDimensionsSize;
+    UA_UInt32 *arrayDimensions;
+    UA_UInt32 maxStringLength;
+    UA_Boolean isOptional;
+} UA_StructureField;
+
+
+
+
+

StructureDefinition

+
typedef struct {
+    UA_NodeId defaultEncodingId;
+    UA_NodeId baseDataType;
+    UA_StructureType structureType;
+    size_t fieldsSize;
+    UA_StructureField *fields;
+} UA_StructureDefinition;
+
+
+
+
+

Argument

+
typedef struct {
+    UA_String name;
+    UA_NodeId dataType;
+    UA_Int32 valueRank;
+    size_t arrayDimensionsSize;
+    UA_UInt32 *arrayDimensions;
+    UA_LocalizedText description;
+} UA_Argument;
+
+
+
+
+

EnumValueType

+
typedef struct {
+    UA_Int64 value;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+} UA_EnumValueType;
+
+
+
+
+

EnumField

+
typedef struct {
+    UA_Int64 value;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_String name;
+} UA_EnumField;
+
+
+
+
+

Duration

+
typedef UA_Double UA_Duration;
+
+
+
+
+

UtcTime

+
typedef UA_DateTime UA_UtcTime;
+
+
+
+
+

LocaleId

+
typedef UA_String UA_LocaleId;
+
+
+
+
+

TimeZoneDataType

+
typedef struct {
+    UA_Int16 offset;
+    UA_Boolean daylightSavingInOffset;
+} UA_TimeZoneDataType;
+
+
+
+
+

ApplicationType

+
typedef enum {
+    UA_APPLICATIONTYPE_SERVER = 0,
+    UA_APPLICATIONTYPE_CLIENT = 1,
+    UA_APPLICATIONTYPE_CLIENTANDSERVER = 2,
+    UA_APPLICATIONTYPE_DISCOVERYSERVER = 3
+} UA_ApplicationType;
+
+
+
+
+

ApplicationDescription

+
typedef struct {
+    UA_String applicationUri;
+    UA_String productUri;
+    UA_LocalizedText applicationName;
+    UA_ApplicationType applicationType;
+    UA_String gatewayServerUri;
+    UA_String discoveryProfileUri;
+    size_t discoveryUrlsSize;
+    UA_String *discoveryUrls;
+} UA_ApplicationDescription;
+
+
+
+
+

RequestHeader

+
typedef struct {
+    UA_NodeId authenticationToken;
+    UA_DateTime timestamp;
+    UA_UInt32 requestHandle;
+    UA_UInt32 returnDiagnostics;
+    UA_String auditEntryId;
+    UA_UInt32 timeoutHint;
+    UA_ExtensionObject additionalHeader;
+} UA_RequestHeader;
+
+
+
+
+

ResponseHeader

+
typedef struct {
+    UA_DateTime timestamp;
+    UA_UInt32 requestHandle;
+    UA_StatusCode serviceResult;
+    UA_DiagnosticInfo serviceDiagnostics;
+    size_t stringTableSize;
+    UA_String *stringTable;
+    UA_ExtensionObject additionalHeader;
+} UA_ResponseHeader;
+
+
+
+
+

ServiceFault

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+} UA_ServiceFault;
+
+
+
+
+

FindServersRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_String endpointUrl;
+    size_t localeIdsSize;
+    UA_String *localeIds;
+    size_t serverUrisSize;
+    UA_String *serverUris;
+} UA_FindServersRequest;
+
+
+
+
+

FindServersResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t serversSize;
+    UA_ApplicationDescription *servers;
+} UA_FindServersResponse;
+
+
+
+
+

ServerOnNetwork

+
typedef struct {
+    UA_UInt32 recordId;
+    UA_String serverName;
+    UA_String discoveryUrl;
+    size_t serverCapabilitiesSize;
+    UA_String *serverCapabilities;
+} UA_ServerOnNetwork;
+
+
+
+
+

FindServersOnNetworkRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 startingRecordId;
+    UA_UInt32 maxRecordsToReturn;
+    size_t serverCapabilityFilterSize;
+    UA_String *serverCapabilityFilter;
+} UA_FindServersOnNetworkRequest;
+
+
+
+
+

FindServersOnNetworkResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_DateTime lastCounterResetTime;
+    size_t serversSize;
+    UA_ServerOnNetwork *servers;
+} UA_FindServersOnNetworkResponse;
+
+
+
+
+

MessageSecurityMode

+
typedef enum {
+    UA_MESSAGESECURITYMODE_INVALID = 0,
+    UA_MESSAGESECURITYMODE_NONE = 1,
+    UA_MESSAGESECURITYMODE_SIGN = 2,
+    UA_MESSAGESECURITYMODE_SIGNANDENCRYPT = 3
+} UA_MessageSecurityMode;
+
+
+
+
+

UserTokenType

+
typedef enum {
+    UA_USERTOKENTYPE_ANONYMOUS = 0,
+    UA_USERTOKENTYPE_USERNAME = 1,
+    UA_USERTOKENTYPE_CERTIFICATE = 2,
+    UA_USERTOKENTYPE_ISSUEDTOKEN = 3
+} UA_UserTokenType;
+
+
+
+
+

UserTokenPolicy

+
typedef struct {
+    UA_String policyId;
+    UA_UserTokenType tokenType;
+    UA_String issuedTokenType;
+    UA_String issuerEndpointUrl;
+    UA_String securityPolicyUri;
+} UA_UserTokenPolicy;
+
+
+
+
+

EndpointDescription

+
typedef struct {
+    UA_String endpointUrl;
+    UA_ApplicationDescription server;
+    UA_ByteString serverCertificate;
+    UA_MessageSecurityMode securityMode;
+    UA_String securityPolicyUri;
+    size_t userIdentityTokensSize;
+    UA_UserTokenPolicy *userIdentityTokens;
+    UA_String transportProfileUri;
+    UA_Byte securityLevel;
+} UA_EndpointDescription;
+
+
+
+
+

GetEndpointsRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_String endpointUrl;
+    size_t localeIdsSize;
+    UA_String *localeIds;
+    size_t profileUrisSize;
+    UA_String *profileUris;
+} UA_GetEndpointsRequest;
+
+
+
+
+

GetEndpointsResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t endpointsSize;
+    UA_EndpointDescription *endpoints;
+} UA_GetEndpointsResponse;
+
+
+
+
+

RegisteredServer

+
typedef struct {
+    UA_String serverUri;
+    UA_String productUri;
+    size_t serverNamesSize;
+    UA_LocalizedText *serverNames;
+    UA_ApplicationType serverType;
+    UA_String gatewayServerUri;
+    size_t discoveryUrlsSize;
+    UA_String *discoveryUrls;
+    UA_String semaphoreFilePath;
+    UA_Boolean isOnline;
+} UA_RegisteredServer;
+
+
+
+
+

RegisterServerRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_RegisteredServer server;
+} UA_RegisterServerRequest;
+
+
+
+
+

RegisterServerResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+} UA_RegisterServerResponse;
+
+
+
+
+

MdnsDiscoveryConfiguration

+
typedef struct {
+    UA_String mdnsServerName;
+    size_t serverCapabilitiesSize;
+    UA_String *serverCapabilities;
+} UA_MdnsDiscoveryConfiguration;
+
+
+
+
+

RegisterServer2Request

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_RegisteredServer server;
+    size_t discoveryConfigurationSize;
+    UA_ExtensionObject *discoveryConfiguration;
+} UA_RegisterServer2Request;
+
+
+
+
+

RegisterServer2Response

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t configurationResultsSize;
+    UA_StatusCode *configurationResults;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_RegisterServer2Response;
+
+
+
+
+

SecurityTokenRequestType

+
typedef enum {
+    UA_SECURITYTOKENREQUESTTYPE_ISSUE = 0,
+    UA_SECURITYTOKENREQUESTTYPE_RENEW = 1
+} UA_SecurityTokenRequestType;
+
+
+
+
+

ChannelSecurityToken

+
typedef struct {
+    UA_UInt32 channelId;
+    UA_UInt32 tokenId;
+    UA_DateTime createdAt;
+    UA_UInt32 revisedLifetime;
+} UA_ChannelSecurityToken;
+
+
+
+
+

OpenSecureChannelRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 clientProtocolVersion;
+    UA_SecurityTokenRequestType requestType;
+    UA_MessageSecurityMode securityMode;
+    UA_ByteString clientNonce;
+    UA_UInt32 requestedLifetime;
+} UA_OpenSecureChannelRequest;
+
+
+
+
+

OpenSecureChannelResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_UInt32 serverProtocolVersion;
+    UA_ChannelSecurityToken securityToken;
+    UA_ByteString serverNonce;
+} UA_OpenSecureChannelResponse;
+
+
+
+
+

CloseSecureChannelRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+} UA_CloseSecureChannelRequest;
+
+
+
+
+

CloseSecureChannelResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+} UA_CloseSecureChannelResponse;
+
+
+
+
+

SignedSoftwareCertificate

+
typedef struct {
+    UA_ByteString certificateData;
+    UA_ByteString signature;
+} UA_SignedSoftwareCertificate;
+
+
+
+
+

SignatureData

+
typedef struct {
+    UA_String algorithm;
+    UA_ByteString signature;
+} UA_SignatureData;
+
+
+
+
+

CreateSessionRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_ApplicationDescription clientDescription;
+    UA_String serverUri;
+    UA_String endpointUrl;
+    UA_String sessionName;
+    UA_ByteString clientNonce;
+    UA_ByteString clientCertificate;
+    UA_Double requestedSessionTimeout;
+    UA_UInt32 maxResponseMessageSize;
+} UA_CreateSessionRequest;
+
+
+
+
+

CreateSessionResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_NodeId sessionId;
+    UA_NodeId authenticationToken;
+    UA_Double revisedSessionTimeout;
+    UA_ByteString serverNonce;
+    UA_ByteString serverCertificate;
+    size_t serverEndpointsSize;
+    UA_EndpointDescription *serverEndpoints;
+    size_t serverSoftwareCertificatesSize;
+    UA_SignedSoftwareCertificate *serverSoftwareCertificates;
+    UA_SignatureData serverSignature;
+    UA_UInt32 maxRequestMessageSize;
+} UA_CreateSessionResponse;
+
+
+
+
+

UserIdentityToken

+
typedef struct {
+    UA_String policyId;
+} UA_UserIdentityToken;
+
+
+
+
+

AnonymousIdentityToken

+
typedef struct {
+    UA_String policyId;
+} UA_AnonymousIdentityToken;
+
+
+
+
+

UserNameIdentityToken

+
typedef struct {
+    UA_String policyId;
+    UA_String userName;
+    UA_ByteString password;
+    UA_String encryptionAlgorithm;
+} UA_UserNameIdentityToken;
+
+
+
+
+

X509IdentityToken

+
typedef struct {
+    UA_String policyId;
+    UA_ByteString certificateData;
+} UA_X509IdentityToken;
+
+
+
+
+

IssuedIdentityToken

+
typedef struct {
+    UA_String policyId;
+    UA_ByteString tokenData;
+    UA_String encryptionAlgorithm;
+} UA_IssuedIdentityToken;
+
+
+
+
+

ActivateSessionRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_SignatureData clientSignature;
+    size_t clientSoftwareCertificatesSize;
+    UA_SignedSoftwareCertificate *clientSoftwareCertificates;
+    size_t localeIdsSize;
+    UA_String *localeIds;
+    UA_ExtensionObject userIdentityToken;
+    UA_SignatureData userTokenSignature;
+} UA_ActivateSessionRequest;
+
+
+
+
+

ActivateSessionResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_ByteString serverNonce;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_ActivateSessionResponse;
+
+
+
+
+

CloseSessionRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_Boolean deleteSubscriptions;
+} UA_CloseSessionRequest;
+
+
+
+
+

CloseSessionResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+} UA_CloseSessionResponse;
+
+
+
+
+

CancelRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 requestHandle;
+} UA_CancelRequest;
+
+
+
+
+

CancelResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_UInt32 cancelCount;
+} UA_CancelResponse;
+
+
+
+
+

NodeAttributesMask

+
typedef enum {
+    UA_NODEATTRIBUTESMASK_NONE = 0,
+    UA_NODEATTRIBUTESMASK_ACCESSLEVEL = 1,
+    UA_NODEATTRIBUTESMASK_ARRAYDIMENSIONS = 2,
+    UA_NODEATTRIBUTESMASK_BROWSENAME = 4,
+    UA_NODEATTRIBUTESMASK_CONTAINSNOLOOPS = 8,
+    UA_NODEATTRIBUTESMASK_DATATYPE = 16,
+    UA_NODEATTRIBUTESMASK_DESCRIPTION = 32,
+    UA_NODEATTRIBUTESMASK_DISPLAYNAME = 64,
+    UA_NODEATTRIBUTESMASK_EVENTNOTIFIER = 128,
+    UA_NODEATTRIBUTESMASK_EXECUTABLE = 256,
+    UA_NODEATTRIBUTESMASK_HISTORIZING = 512,
+    UA_NODEATTRIBUTESMASK_INVERSENAME = 1024,
+    UA_NODEATTRIBUTESMASK_ISABSTRACT = 2048,
+    UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL = 4096,
+    UA_NODEATTRIBUTESMASK_NODECLASS = 8192,
+    UA_NODEATTRIBUTESMASK_NODEID = 16384,
+    UA_NODEATTRIBUTESMASK_SYMMETRIC = 32768,
+    UA_NODEATTRIBUTESMASK_USERACCESSLEVEL = 65536,
+    UA_NODEATTRIBUTESMASK_USEREXECUTABLE = 131072,
+    UA_NODEATTRIBUTESMASK_USERWRITEMASK = 262144,
+    UA_NODEATTRIBUTESMASK_VALUERANK = 524288,
+    UA_NODEATTRIBUTESMASK_WRITEMASK = 1048576,
+    UA_NODEATTRIBUTESMASK_VALUE = 2097152,
+    UA_NODEATTRIBUTESMASK_DATATYPEDEFINITION = 4194304,
+    UA_NODEATTRIBUTESMASK_ROLEPERMISSIONS = 8388608,
+    UA_NODEATTRIBUTESMASK_ACCESSRESTRICTIONS = 16777216,
+    UA_NODEATTRIBUTESMASK_ALL = 33554431,
+    UA_NODEATTRIBUTESMASK_BASENODE = 26501220,
+    UA_NODEATTRIBUTESMASK_OBJECT = 26501348,
+    UA_NODEATTRIBUTESMASK_OBJECTTYPE = 26503268,
+    UA_NODEATTRIBUTESMASK_VARIABLE = 26571383,
+    UA_NODEATTRIBUTESMASK_VARIABLETYPE = 28600438,
+    UA_NODEATTRIBUTESMASK_METHOD = 26632548,
+    UA_NODEATTRIBUTESMASK_REFERENCETYPE = 26537060,
+    UA_NODEATTRIBUTESMASK_VIEW = 26501356
+} UA_NodeAttributesMask;
+
+
+
+
+

NodeAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+} UA_NodeAttributes;
+
+
+
+
+

ObjectAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Byte eventNotifier;
+} UA_ObjectAttributes;
+
+
+
+
+

VariableAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Variant value;
+    UA_NodeId dataType;
+    UA_Int32 valueRank;
+    size_t arrayDimensionsSize;
+    UA_UInt32 *arrayDimensions;
+    UA_Byte accessLevel;
+    UA_Byte userAccessLevel;
+    UA_Double minimumSamplingInterval;
+    UA_Boolean historizing;
+} UA_VariableAttributes;
+
+
+
+
+

MethodAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Boolean executable;
+    UA_Boolean userExecutable;
+} UA_MethodAttributes;
+
+
+
+
+

ObjectTypeAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Boolean isAbstract;
+} UA_ObjectTypeAttributes;
+
+
+
+
+

VariableTypeAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Variant value;
+    UA_NodeId dataType;
+    UA_Int32 valueRank;
+    size_t arrayDimensionsSize;
+    UA_UInt32 *arrayDimensions;
+    UA_Boolean isAbstract;
+} UA_VariableTypeAttributes;
+
+
+
+
+

ReferenceTypeAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Boolean isAbstract;
+    UA_Boolean symmetric;
+    UA_LocalizedText inverseName;
+} UA_ReferenceTypeAttributes;
+
+
+
+
+

DataTypeAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Boolean isAbstract;
+} UA_DataTypeAttributes;
+
+
+
+
+

ViewAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Boolean containsNoLoops;
+    UA_Byte eventNotifier;
+} UA_ViewAttributes;
+
+
+
+
+

AddNodesItem

+
typedef struct {
+    UA_ExpandedNodeId parentNodeId;
+    UA_NodeId referenceTypeId;
+    UA_ExpandedNodeId requestedNewNodeId;
+    UA_QualifiedName browseName;
+    UA_NodeClass nodeClass;
+    UA_ExtensionObject nodeAttributes;
+    UA_ExpandedNodeId typeDefinition;
+} UA_AddNodesItem;
+
+
+
+
+

AddNodesResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    UA_NodeId addedNodeId;
+} UA_AddNodesResult;
+
+
+
+
+

AddNodesRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t nodesToAddSize;
+    UA_AddNodesItem *nodesToAdd;
+} UA_AddNodesRequest;
+
+
+
+
+

AddNodesResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_AddNodesResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_AddNodesResponse;
+
+
+
+
+

AddReferencesItem

+
typedef struct {
+    UA_NodeId sourceNodeId;
+    UA_NodeId referenceTypeId;
+    UA_Boolean isForward;
+    UA_String targetServerUri;
+    UA_ExpandedNodeId targetNodeId;
+    UA_NodeClass targetNodeClass;
+} UA_AddReferencesItem;
+
+
+
+
+

AddReferencesRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t referencesToAddSize;
+    UA_AddReferencesItem *referencesToAdd;
+} UA_AddReferencesRequest;
+
+
+
+
+

AddReferencesResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_AddReferencesResponse;
+
+
+
+
+

DeleteNodesItem

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_Boolean deleteTargetReferences;
+} UA_DeleteNodesItem;
+
+
+
+
+

DeleteNodesRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t nodesToDeleteSize;
+    UA_DeleteNodesItem *nodesToDelete;
+} UA_DeleteNodesRequest;
+
+
+
+
+

DeleteNodesResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_DeleteNodesResponse;
+
+
+
+
+

DeleteReferencesItem

+
typedef struct {
+    UA_NodeId sourceNodeId;
+    UA_NodeId referenceTypeId;
+    UA_Boolean isForward;
+    UA_ExpandedNodeId targetNodeId;
+    UA_Boolean deleteBidirectional;
+} UA_DeleteReferencesItem;
+
+
+
+
+

DeleteReferencesRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t referencesToDeleteSize;
+    UA_DeleteReferencesItem *referencesToDelete;
+} UA_DeleteReferencesRequest;
+
+
+
+
+

DeleteReferencesResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_DeleteReferencesResponse;
+
+
+
+
+

BrowseDirection

+
typedef enum {
+    UA_BROWSEDIRECTION_FORWARD = 0,
+    UA_BROWSEDIRECTION_INVERSE = 1,
+    UA_BROWSEDIRECTION_BOTH = 2,
+    UA_BROWSEDIRECTION_INVALID = 3
+} UA_BrowseDirection;
+
+
+
+
+

ViewDescription

+
typedef struct {
+    UA_NodeId viewId;
+    UA_DateTime timestamp;
+    UA_UInt32 viewVersion;
+} UA_ViewDescription;
+
+
+
+
+

BrowseDescription

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_BrowseDirection browseDirection;
+    UA_NodeId referenceTypeId;
+    UA_Boolean includeSubtypes;
+    UA_UInt32 nodeClassMask;
+    UA_UInt32 resultMask;
+} UA_BrowseDescription;
+
+
+
+
+

BrowseResultMask

+
typedef enum {
+    UA_BROWSERESULTMASK_NONE = 0,
+    UA_BROWSERESULTMASK_REFERENCETYPEID = 1,
+    UA_BROWSERESULTMASK_ISFORWARD = 2,
+    UA_BROWSERESULTMASK_NODECLASS = 4,
+    UA_BROWSERESULTMASK_BROWSENAME = 8,
+    UA_BROWSERESULTMASK_DISPLAYNAME = 16,
+    UA_BROWSERESULTMASK_TYPEDEFINITION = 32,
+    UA_BROWSERESULTMASK_ALL = 63,
+    UA_BROWSERESULTMASK_REFERENCETYPEINFO = 3,
+    UA_BROWSERESULTMASK_TARGETINFO = 60
+} UA_BrowseResultMask;
+
+
+
+
+

ReferenceDescription

+
typedef struct {
+    UA_NodeId referenceTypeId;
+    UA_Boolean isForward;
+    UA_ExpandedNodeId nodeId;
+    UA_QualifiedName browseName;
+    UA_LocalizedText displayName;
+    UA_NodeClass nodeClass;
+    UA_ExpandedNodeId typeDefinition;
+} UA_ReferenceDescription;
+
+
+
+
+

BrowseResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    UA_ByteString continuationPoint;
+    size_t referencesSize;
+    UA_ReferenceDescription *references;
+} UA_BrowseResult;
+
+
+
+
+

BrowseRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_ViewDescription view;
+    UA_UInt32 requestedMaxReferencesPerNode;
+    size_t nodesToBrowseSize;
+    UA_BrowseDescription *nodesToBrowse;
+} UA_BrowseRequest;
+
+
+
+
+

BrowseResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_BrowseResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_BrowseResponse;
+
+
+
+
+

BrowseNextRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_Boolean releaseContinuationPoints;
+    size_t continuationPointsSize;
+    UA_ByteString *continuationPoints;
+} UA_BrowseNextRequest;
+
+
+
+
+

BrowseNextResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_BrowseResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_BrowseNextResponse;
+
+
+
+
+

RelativePathElement

+
typedef struct {
+    UA_NodeId referenceTypeId;
+    UA_Boolean isInverse;
+    UA_Boolean includeSubtypes;
+    UA_QualifiedName targetName;
+} UA_RelativePathElement;
+
+
+
+
+

RelativePath

+
typedef struct {
+    size_t elementsSize;
+    UA_RelativePathElement *elements;
+} UA_RelativePath;
+
+
+
+
+

BrowsePath

+
typedef struct {
+    UA_NodeId startingNode;
+    UA_RelativePath relativePath;
+} UA_BrowsePath;
+
+
+
+
+

BrowsePathTarget

+
typedef struct {
+    UA_ExpandedNodeId targetId;
+    UA_UInt32 remainingPathIndex;
+} UA_BrowsePathTarget;
+
+
+
+
+

BrowsePathResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    size_t targetsSize;
+    UA_BrowsePathTarget *targets;
+} UA_BrowsePathResult;
+
+
+
+
+

TranslateBrowsePathsToNodeIdsRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t browsePathsSize;
+    UA_BrowsePath *browsePaths;
+} UA_TranslateBrowsePathsToNodeIdsRequest;
+
+
+
+
+

TranslateBrowsePathsToNodeIdsResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_BrowsePathResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_TranslateBrowsePathsToNodeIdsResponse;
+
+
+
+
+

RegisterNodesRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t nodesToRegisterSize;
+    UA_NodeId *nodesToRegister;
+} UA_RegisterNodesRequest;
+
+
+
+
+

RegisterNodesResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t registeredNodeIdsSize;
+    UA_NodeId *registeredNodeIds;
+} UA_RegisterNodesResponse;
+
+
+
+
+

UnregisterNodesRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t nodesToUnregisterSize;
+    UA_NodeId *nodesToUnregister;
+} UA_UnregisterNodesRequest;
+
+
+
+
+

UnregisterNodesResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+} UA_UnregisterNodesResponse;
+
+
+
+
+

FilterOperator

+
typedef enum {
+    UA_FILTEROPERATOR_EQUALS = 0,
+    UA_FILTEROPERATOR_ISNULL = 1,
+    UA_FILTEROPERATOR_GREATERTHAN = 2,
+    UA_FILTEROPERATOR_LESSTHAN = 3,
+    UA_FILTEROPERATOR_GREATERTHANOREQUAL = 4,
+    UA_FILTEROPERATOR_LESSTHANOREQUAL = 5,
+    UA_FILTEROPERATOR_LIKE = 6,
+    UA_FILTEROPERATOR_NOT = 7,
+    UA_FILTEROPERATOR_BETWEEN = 8,
+    UA_FILTEROPERATOR_INLIST = 9,
+    UA_FILTEROPERATOR_AND = 10,
+    UA_FILTEROPERATOR_OR = 11,
+    UA_FILTEROPERATOR_CAST = 12,
+    UA_FILTEROPERATOR_INVIEW = 13,
+    UA_FILTEROPERATOR_OFTYPE = 14,
+    UA_FILTEROPERATOR_RELATEDTO = 15,
+    UA_FILTEROPERATOR_BITWISEAND = 16,
+    UA_FILTEROPERATOR_BITWISEOR = 17
+} UA_FilterOperator;
+
+
+
+
+

ContentFilterElement

+
typedef struct {
+    UA_FilterOperator filterOperator;
+    size_t filterOperandsSize;
+    UA_ExtensionObject *filterOperands;
+} UA_ContentFilterElement;
+
+
+
+
+

ContentFilter

+
typedef struct {
+    size_t elementsSize;
+    UA_ContentFilterElement *elements;
+} UA_ContentFilter;
+
+
+
+
+

ElementOperand

+
typedef struct {
+    UA_UInt32 index;
+} UA_ElementOperand;
+
+
+
+
+

LiteralOperand

+
typedef struct {
+    UA_Variant value;
+} UA_LiteralOperand;
+
+
+
+
+

AttributeOperand

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_String alias;
+    UA_RelativePath browsePath;
+    UA_UInt32 attributeId;
+    UA_String indexRange;
+} UA_AttributeOperand;
+
+
+
+
+

SimpleAttributeOperand

+
typedef struct {
+    UA_NodeId typeDefinitionId;
+    size_t browsePathSize;
+    UA_QualifiedName *browsePath;
+    UA_UInt32 attributeId;
+    UA_String indexRange;
+} UA_SimpleAttributeOperand;
+
+
+
+
+

ContentFilterElementResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    size_t operandStatusCodesSize;
+    UA_StatusCode *operandStatusCodes;
+    size_t operandDiagnosticInfosSize;
+    UA_DiagnosticInfo *operandDiagnosticInfos;
+} UA_ContentFilterElementResult;
+
+
+
+
+

ContentFilterResult

+
typedef struct {
+    size_t elementResultsSize;
+    UA_ContentFilterElementResult *elementResults;
+    size_t elementDiagnosticInfosSize;
+    UA_DiagnosticInfo *elementDiagnosticInfos;
+} UA_ContentFilterResult;
+
+
+
+
+

TimestampsToReturn

+
typedef enum {
+    UA_TIMESTAMPSTORETURN_SOURCE = 0,
+    UA_TIMESTAMPSTORETURN_SERVER = 1,
+    UA_TIMESTAMPSTORETURN_BOTH = 2,
+    UA_TIMESTAMPSTORETURN_NEITHER = 3,
+    UA_TIMESTAMPSTORETURN_INVALID = 4
+} UA_TimestampsToReturn;
+
+
+
+
+

ReadValueId

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_UInt32 attributeId;
+    UA_String indexRange;
+    UA_QualifiedName dataEncoding;
+} UA_ReadValueId;
+
+
+
+
+

ReadRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_Double maxAge;
+    UA_TimestampsToReturn timestampsToReturn;
+    size_t nodesToReadSize;
+    UA_ReadValueId *nodesToRead;
+} UA_ReadRequest;
+
+
+
+
+

ReadResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_DataValue *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_ReadResponse;
+
+
+
+
+

HistoryReadValueId

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_String indexRange;
+    UA_QualifiedName dataEncoding;
+    UA_ByteString continuationPoint;
+} UA_HistoryReadValueId;
+
+
+
+
+

HistoryReadResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    UA_ByteString continuationPoint;
+    UA_ExtensionObject historyData;
+} UA_HistoryReadResult;
+
+
+
+
+

ReadRawModifiedDetails

+
typedef struct {
+    UA_Boolean isReadModified;
+    UA_DateTime startTime;
+    UA_DateTime endTime;
+    UA_UInt32 numValuesPerNode;
+    UA_Boolean returnBounds;
+} UA_ReadRawModifiedDetails;
+
+
+
+
+

ReadAtTimeDetails

+
typedef struct {
+    size_t reqTimesSize;
+    UA_DateTime *reqTimes;
+    UA_Boolean useSimpleBounds;
+} UA_ReadAtTimeDetails;
+
+
+
+
+

HistoryData

+
typedef struct {
+    size_t dataValuesSize;
+    UA_DataValue *dataValues;
+} UA_HistoryData;
+
+
+
+
+

HistoryReadRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_ExtensionObject historyReadDetails;
+    UA_TimestampsToReturn timestampsToReturn;
+    UA_Boolean releaseContinuationPoints;
+    size_t nodesToReadSize;
+    UA_HistoryReadValueId *nodesToRead;
+} UA_HistoryReadRequest;
+
+
+
+
+

HistoryReadResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_HistoryReadResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_HistoryReadResponse;
+
+
+
+
+

WriteValue

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_UInt32 attributeId;
+    UA_String indexRange;
+    UA_DataValue value;
+} UA_WriteValue;
+
+
+
+
+

WriteRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t nodesToWriteSize;
+    UA_WriteValue *nodesToWrite;
+} UA_WriteRequest;
+
+
+
+
+

WriteResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_WriteResponse;
+
+
+
+
+

HistoryUpdateType

+
typedef enum {
+    UA_HISTORYUPDATETYPE_INSERT = 1,
+    UA_HISTORYUPDATETYPE_REPLACE = 2,
+    UA_HISTORYUPDATETYPE_UPDATE = 3,
+    UA_HISTORYUPDATETYPE_DELETE = 4
+} UA_HistoryUpdateType;
+
+
+
+
+

PerformUpdateType

+
typedef enum {
+    UA_PERFORMUPDATETYPE_INSERT = 1,
+    UA_PERFORMUPDATETYPE_REPLACE = 2,
+    UA_PERFORMUPDATETYPE_UPDATE = 3,
+    UA_PERFORMUPDATETYPE_REMOVE = 4
+} UA_PerformUpdateType;
+
+
+
+
+

UpdateDataDetails

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_PerformUpdateType performInsertReplace;
+    size_t updateValuesSize;
+    UA_DataValue *updateValues;
+} UA_UpdateDataDetails;
+
+
+
+
+

DeleteRawModifiedDetails

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_Boolean isDeleteModified;
+    UA_DateTime startTime;
+    UA_DateTime endTime;
+} UA_DeleteRawModifiedDetails;
+
+
+
+
+

HistoryUpdateResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    size_t operationResultsSize;
+    UA_StatusCode *operationResults;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_HistoryUpdateResult;
+
+
+
+
+

HistoryUpdateRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t historyUpdateDetailsSize;
+    UA_ExtensionObject *historyUpdateDetails;
+} UA_HistoryUpdateRequest;
+
+
+
+
+

HistoryUpdateResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_HistoryUpdateResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_HistoryUpdateResponse;
+
+
+
+
+

CallMethodRequest

+
typedef struct {
+    UA_NodeId objectId;
+    UA_NodeId methodId;
+    size_t inputArgumentsSize;
+    UA_Variant *inputArguments;
+} UA_CallMethodRequest;
+
+
+
+
+

CallMethodResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    size_t inputArgumentResultsSize;
+    UA_StatusCode *inputArgumentResults;
+    size_t inputArgumentDiagnosticInfosSize;
+    UA_DiagnosticInfo *inputArgumentDiagnosticInfos;
+    size_t outputArgumentsSize;
+    UA_Variant *outputArguments;
+} UA_CallMethodResult;
+
+
+
+
+

CallRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t methodsToCallSize;
+    UA_CallMethodRequest *methodsToCall;
+} UA_CallRequest;
+
+
+
+
+

CallResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_CallMethodResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_CallResponse;
+
+
+
+
+

MonitoringMode

+
typedef enum {
+    UA_MONITORINGMODE_DISABLED = 0,
+    UA_MONITORINGMODE_SAMPLING = 1,
+    UA_MONITORINGMODE_REPORTING = 2
+} UA_MonitoringMode;
+
+
+
+
+

DataChangeTrigger

+
typedef enum {
+    UA_DATACHANGETRIGGER_STATUS = 0,
+    UA_DATACHANGETRIGGER_STATUSVALUE = 1,
+    UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP = 2
+} UA_DataChangeTrigger;
+
+
+
+
+

DeadbandType

+
typedef enum {
+    UA_DEADBANDTYPE_NONE = 0,
+    UA_DEADBANDTYPE_ABSOLUTE = 1,
+    UA_DEADBANDTYPE_PERCENT = 2
+} UA_DeadbandType;
+
+
+
+
+

DataChangeFilter

+
typedef struct {
+    UA_DataChangeTrigger trigger;
+    UA_UInt32 deadbandType;
+    UA_Double deadbandValue;
+} UA_DataChangeFilter;
+
+
+
+
+

EventFilter

+
typedef struct {
+    size_t selectClausesSize;
+    UA_SimpleAttributeOperand *selectClauses;
+    UA_ContentFilter whereClause;
+} UA_EventFilter;
+
+
+
+
+

AggregateConfiguration

+
typedef struct {
+    UA_Boolean useServerCapabilitiesDefaults;
+    UA_Boolean treatUncertainAsBad;
+    UA_Byte percentDataBad;
+    UA_Byte percentDataGood;
+    UA_Boolean useSlopedExtrapolation;
+} UA_AggregateConfiguration;
+
+
+
+
+

AggregateFilter

+
typedef struct {
+    UA_DateTime startTime;
+    UA_NodeId aggregateType;
+    UA_Double processingInterval;
+    UA_AggregateConfiguration aggregateConfiguration;
+} UA_AggregateFilter;
+
+
+
+
+

EventFilterResult

+
typedef struct {
+    size_t selectClauseResultsSize;
+    UA_StatusCode *selectClauseResults;
+    size_t selectClauseDiagnosticInfosSize;
+    UA_DiagnosticInfo *selectClauseDiagnosticInfos;
+    UA_ContentFilterResult whereClauseResult;
+} UA_EventFilterResult;
+
+
+
+
+

MonitoringParameters

+
typedef struct {
+    UA_UInt32 clientHandle;
+    UA_Double samplingInterval;
+    UA_ExtensionObject filter;
+    UA_UInt32 queueSize;
+    UA_Boolean discardOldest;
+} UA_MonitoringParameters;
+
+
+
+
+

MonitoredItemCreateRequest

+
typedef struct {
+    UA_ReadValueId itemToMonitor;
+    UA_MonitoringMode monitoringMode;
+    UA_MonitoringParameters requestedParameters;
+} UA_MonitoredItemCreateRequest;
+
+
+
+
+

MonitoredItemCreateResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    UA_UInt32 monitoredItemId;
+    UA_Double revisedSamplingInterval;
+    UA_UInt32 revisedQueueSize;
+    UA_ExtensionObject filterResult;
+} UA_MonitoredItemCreateResult;
+
+
+
+
+

CreateMonitoredItemsRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 subscriptionId;
+    UA_TimestampsToReturn timestampsToReturn;
+    size_t itemsToCreateSize;
+    UA_MonitoredItemCreateRequest *itemsToCreate;
+} UA_CreateMonitoredItemsRequest;
+
+
+
+
+

CreateMonitoredItemsResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_MonitoredItemCreateResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_CreateMonitoredItemsResponse;
+
+
+
+
+

MonitoredItemModifyRequest

+
typedef struct {
+    UA_UInt32 monitoredItemId;
+    UA_MonitoringParameters requestedParameters;
+} UA_MonitoredItemModifyRequest;
+
+
+
+
+

MonitoredItemModifyResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    UA_Double revisedSamplingInterval;
+    UA_UInt32 revisedQueueSize;
+    UA_ExtensionObject filterResult;
+} UA_MonitoredItemModifyResult;
+
+
+
+
+

ModifyMonitoredItemsRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 subscriptionId;
+    UA_TimestampsToReturn timestampsToReturn;
+    size_t itemsToModifySize;
+    UA_MonitoredItemModifyRequest *itemsToModify;
+} UA_ModifyMonitoredItemsRequest;
+
+
+
+
+

ModifyMonitoredItemsResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_MonitoredItemModifyResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_ModifyMonitoredItemsResponse;
+
+
+
+
+

SetMonitoringModeRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 subscriptionId;
+    UA_MonitoringMode monitoringMode;
+    size_t monitoredItemIdsSize;
+    UA_UInt32 *monitoredItemIds;
+} UA_SetMonitoringModeRequest;
+
+
+
+
+

SetMonitoringModeResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_SetMonitoringModeResponse;
+
+
+
+
+

SetTriggeringRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 subscriptionId;
+    UA_UInt32 triggeringItemId;
+    size_t linksToAddSize;
+    UA_UInt32 *linksToAdd;
+    size_t linksToRemoveSize;
+    UA_UInt32 *linksToRemove;
+} UA_SetTriggeringRequest;
+
+
+
+
+

SetTriggeringResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t addResultsSize;
+    UA_StatusCode *addResults;
+    size_t addDiagnosticInfosSize;
+    UA_DiagnosticInfo *addDiagnosticInfos;
+    size_t removeResultsSize;
+    UA_StatusCode *removeResults;
+    size_t removeDiagnosticInfosSize;
+    UA_DiagnosticInfo *removeDiagnosticInfos;
+} UA_SetTriggeringResponse;
+
+
+
+
+

DeleteMonitoredItemsRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 subscriptionId;
+    size_t monitoredItemIdsSize;
+    UA_UInt32 *monitoredItemIds;
+} UA_DeleteMonitoredItemsRequest;
+
+
+
+
+

DeleteMonitoredItemsResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_DeleteMonitoredItemsResponse;
+
+
+
+
+

CreateSubscriptionRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_Double requestedPublishingInterval;
+    UA_UInt32 requestedLifetimeCount;
+    UA_UInt32 requestedMaxKeepAliveCount;
+    UA_UInt32 maxNotificationsPerPublish;
+    UA_Boolean publishingEnabled;
+    UA_Byte priority;
+} UA_CreateSubscriptionRequest;
+
+
+
+
+

CreateSubscriptionResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_UInt32 subscriptionId;
+    UA_Double revisedPublishingInterval;
+    UA_UInt32 revisedLifetimeCount;
+    UA_UInt32 revisedMaxKeepAliveCount;
+} UA_CreateSubscriptionResponse;
+
+
+
+
+

ModifySubscriptionRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 subscriptionId;
+    UA_Double requestedPublishingInterval;
+    UA_UInt32 requestedLifetimeCount;
+    UA_UInt32 requestedMaxKeepAliveCount;
+    UA_UInt32 maxNotificationsPerPublish;
+    UA_Byte priority;
+} UA_ModifySubscriptionRequest;
+
+
+
+
+

ModifySubscriptionResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_Double revisedPublishingInterval;
+    UA_UInt32 revisedLifetimeCount;
+    UA_UInt32 revisedMaxKeepAliveCount;
+} UA_ModifySubscriptionResponse;
+
+
+
+
+

SetPublishingModeRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_Boolean publishingEnabled;
+    size_t subscriptionIdsSize;
+    UA_UInt32 *subscriptionIds;
+} UA_SetPublishingModeRequest;
+
+
+
+
+

SetPublishingModeResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_SetPublishingModeResponse;
+
+
+
+
+

NotificationMessage

+
typedef struct {
+    UA_UInt32 sequenceNumber;
+    UA_DateTime publishTime;
+    size_t notificationDataSize;
+    UA_ExtensionObject *notificationData;
+} UA_NotificationMessage;
+
+
+
+
+

MonitoredItemNotification

+
typedef struct {
+    UA_UInt32 clientHandle;
+    UA_DataValue value;
+} UA_MonitoredItemNotification;
+
+
+
+
+

EventFieldList

+
typedef struct {
+    UA_UInt32 clientHandle;
+    size_t eventFieldsSize;
+    UA_Variant *eventFields;
+} UA_EventFieldList;
+
+
+
+
+

HistoryEventFieldList

+
typedef struct {
+    size_t eventFieldsSize;
+    UA_Variant *eventFields;
+} UA_HistoryEventFieldList;
+
+
+
+
+

StatusChangeNotification

+
typedef struct {
+    UA_StatusCode status;
+    UA_DiagnosticInfo diagnosticInfo;
+} UA_StatusChangeNotification;
+
+
+
+
+

SubscriptionAcknowledgement

+
typedef struct {
+    UA_UInt32 subscriptionId;
+    UA_UInt32 sequenceNumber;
+} UA_SubscriptionAcknowledgement;
+
+
+
+
+

PublishRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t subscriptionAcknowledgementsSize;
+    UA_SubscriptionAcknowledgement *subscriptionAcknowledgements;
+} UA_PublishRequest;
+
+
+
+
+

PublishResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_UInt32 subscriptionId;
+    size_t availableSequenceNumbersSize;
+    UA_UInt32 *availableSequenceNumbers;
+    UA_Boolean moreNotifications;
+    UA_NotificationMessage notificationMessage;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_PublishResponse;
+
+
+
+
+

RepublishRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 subscriptionId;
+    UA_UInt32 retransmitSequenceNumber;
+} UA_RepublishRequest;
+
+
+
+
+

RepublishResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_NotificationMessage notificationMessage;
+} UA_RepublishResponse;
+
+
+
+
+

TransferResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    size_t availableSequenceNumbersSize;
+    UA_UInt32 *availableSequenceNumbers;
+} UA_TransferResult;
+
+
+
+
+

TransferSubscriptionsRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t subscriptionIdsSize;
+    UA_UInt32 *subscriptionIds;
+    UA_Boolean sendInitialValues;
+} UA_TransferSubscriptionsRequest;
+
+
+
+
+

TransferSubscriptionsResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_TransferResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_TransferSubscriptionsResponse;
+
+
+
+
+

DeleteSubscriptionsRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t subscriptionIdsSize;
+    UA_UInt32 *subscriptionIds;
+} UA_DeleteSubscriptionsRequest;
+
+
+
+
+

DeleteSubscriptionsResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_DeleteSubscriptionsResponse;
+
+
+
+
+

BuildInfo

+
typedef struct {
+    UA_String productUri;
+    UA_String manufacturerName;
+    UA_String productName;
+    UA_String softwareVersion;
+    UA_String buildNumber;
+    UA_DateTime buildDate;
+} UA_BuildInfo;
+
+
+
+
+

RedundancySupport

+
typedef enum {
+    UA_REDUNDANCYSUPPORT_NONE = 0,
+    UA_REDUNDANCYSUPPORT_COLD = 1,
+    UA_REDUNDANCYSUPPORT_WARM = 2,
+    UA_REDUNDANCYSUPPORT_HOT = 3,
+    UA_REDUNDANCYSUPPORT_TRANSPARENT = 4,
+    UA_REDUNDANCYSUPPORT_HOTANDMIRRORED = 5
+} UA_RedundancySupport;
+
+
+
+
+

ServerState

+
typedef enum {
+    UA_SERVERSTATE_RUNNING = 0,
+    UA_SERVERSTATE_FAILED = 1,
+    UA_SERVERSTATE_NOCONFIGURATION = 2,
+    UA_SERVERSTATE_SUSPENDED = 3,
+    UA_SERVERSTATE_SHUTDOWN = 4,
+    UA_SERVERSTATE_TEST = 5,
+    UA_SERVERSTATE_COMMUNICATIONFAULT = 6,
+    UA_SERVERSTATE_UNKNOWN = 7
+} UA_ServerState;
+
+
+
+
+

ServerDiagnosticsSummaryDataType

+
typedef struct {
+    UA_UInt32 serverViewCount;
+    UA_UInt32 currentSessionCount;
+    UA_UInt32 cumulatedSessionCount;
+    UA_UInt32 securityRejectedSessionCount;
+    UA_UInt32 rejectedSessionCount;
+    UA_UInt32 sessionTimeoutCount;
+    UA_UInt32 sessionAbortCount;
+    UA_UInt32 currentSubscriptionCount;
+    UA_UInt32 cumulatedSubscriptionCount;
+    UA_UInt32 publishingIntervalCount;
+    UA_UInt32 securityRejectedRequestsCount;
+    UA_UInt32 rejectedRequestsCount;
+} UA_ServerDiagnosticsSummaryDataType;
+
+
+
+
+

ServerStatusDataType

+
typedef struct {
+    UA_DateTime startTime;
+    UA_DateTime currentTime;
+    UA_ServerState state;
+    UA_BuildInfo buildInfo;
+    UA_UInt32 secondsTillShutdown;
+    UA_LocalizedText shutdownReason;
+} UA_ServerStatusDataType;
+
+
+
+
+

SessionSecurityDiagnosticsDataType

+
typedef struct {
+    UA_NodeId sessionId;
+    UA_String clientUserIdOfSession;
+    size_t clientUserIdHistorySize;
+    UA_String *clientUserIdHistory;
+    UA_String authenticationMechanism;
+    UA_String encoding;
+    UA_String transportProtocol;
+    UA_MessageSecurityMode securityMode;
+    UA_String securityPolicyUri;
+    UA_ByteString clientCertificate;
+} UA_SessionSecurityDiagnosticsDataType;
+
+
+
+
+

ServiceCounterDataType

+
typedef struct {
+    UA_UInt32 totalCount;
+    UA_UInt32 errorCount;
+} UA_ServiceCounterDataType;
+
+
+
+
+

SubscriptionDiagnosticsDataType

+
typedef struct {
+    UA_NodeId sessionId;
+    UA_UInt32 subscriptionId;
+    UA_Byte priority;
+    UA_Double publishingInterval;
+    UA_UInt32 maxKeepAliveCount;
+    UA_UInt32 maxLifetimeCount;
+    UA_UInt32 maxNotificationsPerPublish;
+    UA_Boolean publishingEnabled;
+    UA_UInt32 modifyCount;
+    UA_UInt32 enableCount;
+    UA_UInt32 disableCount;
+    UA_UInt32 republishRequestCount;
+    UA_UInt32 republishMessageRequestCount;
+    UA_UInt32 republishMessageCount;
+    UA_UInt32 transferRequestCount;
+    UA_UInt32 transferredToAltClientCount;
+    UA_UInt32 transferredToSameClientCount;
+    UA_UInt32 publishRequestCount;
+    UA_UInt32 dataChangeNotificationsCount;
+    UA_UInt32 eventNotificationsCount;
+    UA_UInt32 notificationsCount;
+    UA_UInt32 latePublishRequestCount;
+    UA_UInt32 currentKeepAliveCount;
+    UA_UInt32 currentLifetimeCount;
+    UA_UInt32 unacknowledgedMessageCount;
+    UA_UInt32 discardedMessageCount;
+    UA_UInt32 monitoredItemCount;
+    UA_UInt32 disabledMonitoredItemCount;
+    UA_UInt32 monitoringQueueOverflowCount;
+    UA_UInt32 nextSequenceNumber;
+    UA_UInt32 eventQueueOverFlowCount;
+} UA_SubscriptionDiagnosticsDataType;
+
+
+
+
+

Range

+
typedef struct {
+    UA_Double low;
+    UA_Double high;
+} UA_Range;
+
+
+
+
+

EUInformation

+
typedef struct {
+    UA_String namespaceUri;
+    UA_Int32 unitId;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+} UA_EUInformation;
+
+
+
+
+

AxisScaleEnumeration

+
typedef enum {
+    UA_AXISSCALEENUMERATION_LINEAR = 0,
+    UA_AXISSCALEENUMERATION_LOG = 1,
+    UA_AXISSCALEENUMERATION_LN = 2
+} UA_AxisScaleEnumeration;
+
+
+
+
+

ComplexNumberType

+
typedef struct {
+    UA_Float real;
+    UA_Float imaginary;
+} UA_ComplexNumberType;
+
+
+
+
+

DoubleComplexNumberType

+
typedef struct {
+    UA_Double real;
+    UA_Double imaginary;
+} UA_DoubleComplexNumberType;
+
+
+
+
+

AxisInformation

+
typedef struct {
+    UA_EUInformation engineeringUnits;
+    UA_Range eURange;
+    UA_LocalizedText title;
+    UA_AxisScaleEnumeration axisScaleType;
+    size_t axisStepsSize;
+    UA_Double *axisSteps;
+} UA_AxisInformation;
+
+
+
+
+

XVType

+
typedef struct {
+    UA_Double x;
+    UA_Float value;
+} UA_XVType;
+
+
+
+
+

EnumDefinition

+
typedef struct {
+    size_t fieldsSize;
+    UA_EnumField *fields;
+} UA_EnumDefinition;
+
+
+
+
+

ReadEventDetails

+
typedef struct {
+    UA_UInt32 numValuesPerNode;
+    UA_DateTime startTime;
+    UA_DateTime endTime;
+    UA_EventFilter filter;
+} UA_ReadEventDetails;
+
+
+
+
+

ReadProcessedDetails

+
typedef struct {
+    UA_DateTime startTime;
+    UA_DateTime endTime;
+    UA_Double processingInterval;
+    size_t aggregateTypeSize;
+    UA_NodeId *aggregateType;
+    UA_AggregateConfiguration aggregateConfiguration;
+} UA_ReadProcessedDetails;
+
+
+
+
+

ModificationInfo

+
typedef struct {
+    UA_DateTime modificationTime;
+    UA_HistoryUpdateType updateType;
+    UA_String userName;
+} UA_ModificationInfo;
+
+
+
+
+

HistoryModifiedData

+
typedef struct {
+    size_t dataValuesSize;
+    UA_DataValue *dataValues;
+    size_t modificationInfosSize;
+    UA_ModificationInfo *modificationInfos;
+} UA_HistoryModifiedData;
+
+
+
+
+

HistoryEvent

+
typedef struct {
+    size_t eventsSize;
+    UA_HistoryEventFieldList *events;
+} UA_HistoryEvent;
+
+
+
+
+

DataChangeNotification

+
typedef struct {
+    size_t monitoredItemsSize;
+    UA_MonitoredItemNotification *monitoredItems;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_DataChangeNotification;
+
+
+
+
+

EventNotificationList

+
typedef struct {
+    size_t eventsSize;
+    UA_EventFieldList *events;
+} UA_EventNotificationList;
+
+
+
+
+

SessionDiagnosticsDataType

+
typedef struct {
+    UA_NodeId sessionId;
+    UA_String sessionName;
+    UA_ApplicationDescription clientDescription;
+    UA_String serverUri;
+    UA_String endpointUrl;
+    size_t localeIdsSize;
+    UA_String *localeIds;
+    UA_Double actualSessionTimeout;
+    UA_UInt32 maxResponseMessageSize;
+    UA_DateTime clientConnectionTime;
+    UA_DateTime clientLastContactTime;
+    UA_UInt32 currentSubscriptionsCount;
+    UA_UInt32 currentMonitoredItemsCount;
+    UA_UInt32 currentPublishRequestsInQueue;
+    UA_ServiceCounterDataType totalRequestCount;
+    UA_UInt32 unauthorizedRequestCount;
+    UA_ServiceCounterDataType readCount;
+    UA_ServiceCounterDataType historyReadCount;
+    UA_ServiceCounterDataType writeCount;
+    UA_ServiceCounterDataType historyUpdateCount;
+    UA_ServiceCounterDataType callCount;
+    UA_ServiceCounterDataType createMonitoredItemsCount;
+    UA_ServiceCounterDataType modifyMonitoredItemsCount;
+    UA_ServiceCounterDataType setMonitoringModeCount;
+    UA_ServiceCounterDataType setTriggeringCount;
+    UA_ServiceCounterDataType deleteMonitoredItemsCount;
+    UA_ServiceCounterDataType createSubscriptionCount;
+    UA_ServiceCounterDataType modifySubscriptionCount;
+    UA_ServiceCounterDataType setPublishingModeCount;
+    UA_ServiceCounterDataType publishCount;
+    UA_ServiceCounterDataType republishCount;
+    UA_ServiceCounterDataType transferSubscriptionsCount;
+    UA_ServiceCounterDataType deleteSubscriptionsCount;
+    UA_ServiceCounterDataType addNodesCount;
+    UA_ServiceCounterDataType addReferencesCount;
+    UA_ServiceCounterDataType deleteNodesCount;
+    UA_ServiceCounterDataType deleteReferencesCount;
+    UA_ServiceCounterDataType browseCount;
+    UA_ServiceCounterDataType browseNextCount;
+    UA_ServiceCounterDataType translateBrowsePathsToNodeIdsCount;
+    UA_ServiceCounterDataType queryFirstCount;
+    UA_ServiceCounterDataType queryNextCount;
+    UA_ServiceCounterDataType registerNodesCount;
+    UA_ServiceCounterDataType unregisterNodesCount;
+} UA_SessionDiagnosticsDataType;
+
+
+
/* stop-doc-generation */
+
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/types_generated.html b/static/doc/v1.4.0/types_generated.html new file mode 100644 index 0000000000..6a0343119a --- /dev/null +++ b/static/doc/v1.4.0/types_generated.html @@ -0,0 +1,2510 @@ + + + + + + + NamingRuleType — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

NamingRuleType

+
typedef enum {
+    UA_NAMINGRULETYPE_MANDATORY = 1,
+    UA_NAMINGRULETYPE_OPTIONAL = 2,
+    UA_NAMINGRULETYPE_CONSTRAINT = 3
+} UA_NamingRuleType;
+
+
+
+
+

KeyValuePair

+
typedef struct {
+    UA_QualifiedName key;
+    UA_Variant value;
+} UA_KeyValuePair;
+
+
+
+
+

NodeClass

+
typedef enum {
+    UA_NODECLASS_UNSPECIFIED = 0,
+    UA_NODECLASS_OBJECT = 1,
+    UA_NODECLASS_VARIABLE = 2,
+    UA_NODECLASS_METHOD = 4,
+    UA_NODECLASS_OBJECTTYPE = 8,
+    UA_NODECLASS_VARIABLETYPE = 16,
+    UA_NODECLASS_REFERENCETYPE = 32,
+    UA_NODECLASS_DATATYPE = 64,
+    UA_NODECLASS_VIEW = 128
+} UA_NodeClass;
+
+
+
+
+

StructureType

+
typedef enum {
+    UA_STRUCTURETYPE_STRUCTURE = 0,
+    UA_STRUCTURETYPE_STRUCTUREWITHOPTIONALFIELDS = 1,
+    UA_STRUCTURETYPE_UNION = 2,
+    UA_STRUCTURETYPE_STRUCTUREWITHSUBTYPEDVALUES = 3,
+    UA_STRUCTURETYPE_UNIONWITHSUBTYPEDVALUES = 4
+} UA_StructureType;
+
+
+
+
+

StructureField

+
typedef struct {
+    UA_String name;
+    UA_LocalizedText description;
+    UA_NodeId dataType;
+    UA_Int32 valueRank;
+    size_t arrayDimensionsSize;
+    UA_UInt32 *arrayDimensions;
+    UA_UInt32 maxStringLength;
+    UA_Boolean isOptional;
+} UA_StructureField;
+
+
+
+
+

StructureDefinition

+
typedef struct {
+    UA_NodeId defaultEncodingId;
+    UA_NodeId baseDataType;
+    UA_StructureType structureType;
+    size_t fieldsSize;
+    UA_StructureField *fields;
+} UA_StructureDefinition;
+
+
+
+
+

Argument

+
typedef struct {
+    UA_String name;
+    UA_NodeId dataType;
+    UA_Int32 valueRank;
+    size_t arrayDimensionsSize;
+    UA_UInt32 *arrayDimensions;
+    UA_LocalizedText description;
+} UA_Argument;
+
+
+
+
+

EnumValueType

+
typedef struct {
+    UA_Int64 value;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+} UA_EnumValueType;
+
+
+
+
+

EnumField

+
typedef struct {
+    UA_Int64 value;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_String name;
+} UA_EnumField;
+
+
+
+
+

Duration

+
typedef UA_Double UA_Duration;
+
+
+
+
+

UtcTime

+
typedef UA_DateTime UA_UtcTime;
+
+
+
+
+

LocaleId

+
typedef UA_String UA_LocaleId;
+
+
+
+
+

TimeZoneDataType

+
typedef struct {
+    UA_Int16 offset;
+    UA_Boolean daylightSavingInOffset;
+} UA_TimeZoneDataType;
+
+
+
+
+

ApplicationType

+
typedef enum {
+    UA_APPLICATIONTYPE_SERVER = 0,
+    UA_APPLICATIONTYPE_CLIENT = 1,
+    UA_APPLICATIONTYPE_CLIENTANDSERVER = 2,
+    UA_APPLICATIONTYPE_DISCOVERYSERVER = 3
+} UA_ApplicationType;
+
+
+
+
+

ApplicationDescription

+
typedef struct {
+    UA_String applicationUri;
+    UA_String productUri;
+    UA_LocalizedText applicationName;
+    UA_ApplicationType applicationType;
+    UA_String gatewayServerUri;
+    UA_String discoveryProfileUri;
+    size_t discoveryUrlsSize;
+    UA_String *discoveryUrls;
+} UA_ApplicationDescription;
+
+
+
+
+

RequestHeader

+
typedef struct {
+    UA_NodeId authenticationToken;
+    UA_DateTime timestamp;
+    UA_UInt32 requestHandle;
+    UA_UInt32 returnDiagnostics;
+    UA_String auditEntryId;
+    UA_UInt32 timeoutHint;
+    UA_ExtensionObject additionalHeader;
+} UA_RequestHeader;
+
+
+
+
+

ResponseHeader

+
typedef struct {
+    UA_DateTime timestamp;
+    UA_UInt32 requestHandle;
+    UA_StatusCode serviceResult;
+    UA_DiagnosticInfo serviceDiagnostics;
+    size_t stringTableSize;
+    UA_String *stringTable;
+    UA_ExtensionObject additionalHeader;
+} UA_ResponseHeader;
+
+
+
+
+

ServiceFault

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+} UA_ServiceFault;
+
+
+
+
+

FindServersRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_String endpointUrl;
+    size_t localeIdsSize;
+    UA_String *localeIds;
+    size_t serverUrisSize;
+    UA_String *serverUris;
+} UA_FindServersRequest;
+
+
+
+
+

FindServersResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t serversSize;
+    UA_ApplicationDescription *servers;
+} UA_FindServersResponse;
+
+
+
+
+

ServerOnNetwork

+
typedef struct {
+    UA_UInt32 recordId;
+    UA_String serverName;
+    UA_String discoveryUrl;
+    size_t serverCapabilitiesSize;
+    UA_String *serverCapabilities;
+} UA_ServerOnNetwork;
+
+
+
+
+

FindServersOnNetworkRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 startingRecordId;
+    UA_UInt32 maxRecordsToReturn;
+    size_t serverCapabilityFilterSize;
+    UA_String *serverCapabilityFilter;
+} UA_FindServersOnNetworkRequest;
+
+
+
+
+

FindServersOnNetworkResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_DateTime lastCounterResetTime;
+    size_t serversSize;
+    UA_ServerOnNetwork *servers;
+} UA_FindServersOnNetworkResponse;
+
+
+
+
+

MessageSecurityMode

+
typedef enum {
+    UA_MESSAGESECURITYMODE_INVALID = 0,
+    UA_MESSAGESECURITYMODE_NONE = 1,
+    UA_MESSAGESECURITYMODE_SIGN = 2,
+    UA_MESSAGESECURITYMODE_SIGNANDENCRYPT = 3
+} UA_MessageSecurityMode;
+
+
+
+
+

UserTokenType

+
typedef enum {
+    UA_USERTOKENTYPE_ANONYMOUS = 0,
+    UA_USERTOKENTYPE_USERNAME = 1,
+    UA_USERTOKENTYPE_CERTIFICATE = 2,
+    UA_USERTOKENTYPE_ISSUEDTOKEN = 3
+} UA_UserTokenType;
+
+
+
+
+

UserTokenPolicy

+
typedef struct {
+    UA_String policyId;
+    UA_UserTokenType tokenType;
+    UA_String issuedTokenType;
+    UA_String issuerEndpointUrl;
+    UA_String securityPolicyUri;
+} UA_UserTokenPolicy;
+
+
+
+
+

EndpointDescription

+
typedef struct {
+    UA_String endpointUrl;
+    UA_ApplicationDescription server;
+    UA_ByteString serverCertificate;
+    UA_MessageSecurityMode securityMode;
+    UA_String securityPolicyUri;
+    size_t userIdentityTokensSize;
+    UA_UserTokenPolicy *userIdentityTokens;
+    UA_String transportProfileUri;
+    UA_Byte securityLevel;
+} UA_EndpointDescription;
+
+
+
+
+

GetEndpointsRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_String endpointUrl;
+    size_t localeIdsSize;
+    UA_String *localeIds;
+    size_t profileUrisSize;
+    UA_String *profileUris;
+} UA_GetEndpointsRequest;
+
+
+
+
+

GetEndpointsResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t endpointsSize;
+    UA_EndpointDescription *endpoints;
+} UA_GetEndpointsResponse;
+
+
+
+
+

RegisteredServer

+
typedef struct {
+    UA_String serverUri;
+    UA_String productUri;
+    size_t serverNamesSize;
+    UA_LocalizedText *serverNames;
+    UA_ApplicationType serverType;
+    UA_String gatewayServerUri;
+    size_t discoveryUrlsSize;
+    UA_String *discoveryUrls;
+    UA_String semaphoreFilePath;
+    UA_Boolean isOnline;
+} UA_RegisteredServer;
+
+
+
+
+

RegisterServerRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_RegisteredServer server;
+} UA_RegisterServerRequest;
+
+
+
+
+

RegisterServerResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+} UA_RegisterServerResponse;
+
+
+
+
+

MdnsDiscoveryConfiguration

+
typedef struct {
+    UA_String mdnsServerName;
+    size_t serverCapabilitiesSize;
+    UA_String *serverCapabilities;
+} UA_MdnsDiscoveryConfiguration;
+
+
+
+
+

RegisterServer2Request

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_RegisteredServer server;
+    size_t discoveryConfigurationSize;
+    UA_ExtensionObject *discoveryConfiguration;
+} UA_RegisterServer2Request;
+
+
+
+
+

RegisterServer2Response

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t configurationResultsSize;
+    UA_StatusCode *configurationResults;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_RegisterServer2Response;
+
+
+
+
+

SecurityTokenRequestType

+
typedef enum {
+    UA_SECURITYTOKENREQUESTTYPE_ISSUE = 0,
+    UA_SECURITYTOKENREQUESTTYPE_RENEW = 1
+} UA_SecurityTokenRequestType;
+
+
+
+
+

ChannelSecurityToken

+
typedef struct {
+    UA_UInt32 channelId;
+    UA_UInt32 tokenId;
+    UA_DateTime createdAt;
+    UA_UInt32 revisedLifetime;
+} UA_ChannelSecurityToken;
+
+
+
+
+

OpenSecureChannelRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 clientProtocolVersion;
+    UA_SecurityTokenRequestType requestType;
+    UA_MessageSecurityMode securityMode;
+    UA_ByteString clientNonce;
+    UA_UInt32 requestedLifetime;
+} UA_OpenSecureChannelRequest;
+
+
+
+
+

OpenSecureChannelResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_UInt32 serverProtocolVersion;
+    UA_ChannelSecurityToken securityToken;
+    UA_ByteString serverNonce;
+} UA_OpenSecureChannelResponse;
+
+
+
+
+

CloseSecureChannelRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+} UA_CloseSecureChannelRequest;
+
+
+
+
+

CloseSecureChannelResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+} UA_CloseSecureChannelResponse;
+
+
+
+
+

SignedSoftwareCertificate

+
typedef struct {
+    UA_ByteString certificateData;
+    UA_ByteString signature;
+} UA_SignedSoftwareCertificate;
+
+
+
+
+

SignatureData

+
typedef struct {
+    UA_String algorithm;
+    UA_ByteString signature;
+} UA_SignatureData;
+
+
+
+
+

CreateSessionRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_ApplicationDescription clientDescription;
+    UA_String serverUri;
+    UA_String endpointUrl;
+    UA_String sessionName;
+    UA_ByteString clientNonce;
+    UA_ByteString clientCertificate;
+    UA_Double requestedSessionTimeout;
+    UA_UInt32 maxResponseMessageSize;
+} UA_CreateSessionRequest;
+
+
+
+
+

CreateSessionResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_NodeId sessionId;
+    UA_NodeId authenticationToken;
+    UA_Double revisedSessionTimeout;
+    UA_ByteString serverNonce;
+    UA_ByteString serverCertificate;
+    size_t serverEndpointsSize;
+    UA_EndpointDescription *serverEndpoints;
+    size_t serverSoftwareCertificatesSize;
+    UA_SignedSoftwareCertificate *serverSoftwareCertificates;
+    UA_SignatureData serverSignature;
+    UA_UInt32 maxRequestMessageSize;
+} UA_CreateSessionResponse;
+
+
+
+
+

UserIdentityToken

+
typedef struct {
+    UA_String policyId;
+} UA_UserIdentityToken;
+
+
+
+
+

AnonymousIdentityToken

+
typedef struct {
+    UA_String policyId;
+} UA_AnonymousIdentityToken;
+
+
+
+
+

UserNameIdentityToken

+
typedef struct {
+    UA_String policyId;
+    UA_String userName;
+    UA_ByteString password;
+    UA_String encryptionAlgorithm;
+} UA_UserNameIdentityToken;
+
+
+
+
+

X509IdentityToken

+
typedef struct {
+    UA_String policyId;
+    UA_ByteString certificateData;
+} UA_X509IdentityToken;
+
+
+
+
+

IssuedIdentityToken

+
typedef struct {
+    UA_String policyId;
+    UA_ByteString tokenData;
+    UA_String encryptionAlgorithm;
+} UA_IssuedIdentityToken;
+
+
+
+
+

ActivateSessionRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_SignatureData clientSignature;
+    size_t clientSoftwareCertificatesSize;
+    UA_SignedSoftwareCertificate *clientSoftwareCertificates;
+    size_t localeIdsSize;
+    UA_String *localeIds;
+    UA_ExtensionObject userIdentityToken;
+    UA_SignatureData userTokenSignature;
+} UA_ActivateSessionRequest;
+
+
+
+
+

ActivateSessionResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_ByteString serverNonce;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_ActivateSessionResponse;
+
+
+
+
+

CloseSessionRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_Boolean deleteSubscriptions;
+} UA_CloseSessionRequest;
+
+
+
+
+

CloseSessionResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+} UA_CloseSessionResponse;
+
+
+
+
+

CancelRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 requestHandle;
+} UA_CancelRequest;
+
+
+
+
+

CancelResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_UInt32 cancelCount;
+} UA_CancelResponse;
+
+
+
+
+

NodeAttributesMask

+
typedef enum {
+    UA_NODEATTRIBUTESMASK_NONE = 0,
+    UA_NODEATTRIBUTESMASK_ACCESSLEVEL = 1,
+    UA_NODEATTRIBUTESMASK_ARRAYDIMENSIONS = 2,
+    UA_NODEATTRIBUTESMASK_BROWSENAME = 4,
+    UA_NODEATTRIBUTESMASK_CONTAINSNOLOOPS = 8,
+    UA_NODEATTRIBUTESMASK_DATATYPE = 16,
+    UA_NODEATTRIBUTESMASK_DESCRIPTION = 32,
+    UA_NODEATTRIBUTESMASK_DISPLAYNAME = 64,
+    UA_NODEATTRIBUTESMASK_EVENTNOTIFIER = 128,
+    UA_NODEATTRIBUTESMASK_EXECUTABLE = 256,
+    UA_NODEATTRIBUTESMASK_HISTORIZING = 512,
+    UA_NODEATTRIBUTESMASK_INVERSENAME = 1024,
+    UA_NODEATTRIBUTESMASK_ISABSTRACT = 2048,
+    UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL = 4096,
+    UA_NODEATTRIBUTESMASK_NODECLASS = 8192,
+    UA_NODEATTRIBUTESMASK_NODEID = 16384,
+    UA_NODEATTRIBUTESMASK_SYMMETRIC = 32768,
+    UA_NODEATTRIBUTESMASK_USERACCESSLEVEL = 65536,
+    UA_NODEATTRIBUTESMASK_USEREXECUTABLE = 131072,
+    UA_NODEATTRIBUTESMASK_USERWRITEMASK = 262144,
+    UA_NODEATTRIBUTESMASK_VALUERANK = 524288,
+    UA_NODEATTRIBUTESMASK_WRITEMASK = 1048576,
+    UA_NODEATTRIBUTESMASK_VALUE = 2097152,
+    UA_NODEATTRIBUTESMASK_DATATYPEDEFINITION = 4194304,
+    UA_NODEATTRIBUTESMASK_ROLEPERMISSIONS = 8388608,
+    UA_NODEATTRIBUTESMASK_ACCESSRESTRICTIONS = 16777216,
+    UA_NODEATTRIBUTESMASK_ALL = 33554431,
+    UA_NODEATTRIBUTESMASK_BASENODE = 26501220,
+    UA_NODEATTRIBUTESMASK_OBJECT = 26501348,
+    UA_NODEATTRIBUTESMASK_OBJECTTYPE = 26503268,
+    UA_NODEATTRIBUTESMASK_VARIABLE = 26571383,
+    UA_NODEATTRIBUTESMASK_VARIABLETYPE = 28600438,
+    UA_NODEATTRIBUTESMASK_METHOD = 26632548,
+    UA_NODEATTRIBUTESMASK_REFERENCETYPE = 26537060,
+    UA_NODEATTRIBUTESMASK_VIEW = 26501356
+} UA_NodeAttributesMask;
+
+
+
+
+

NodeAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+} UA_NodeAttributes;
+
+
+
+
+

ObjectAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Byte eventNotifier;
+} UA_ObjectAttributes;
+
+
+
+
+

VariableAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Variant value;
+    UA_NodeId dataType;
+    UA_Int32 valueRank;
+    size_t arrayDimensionsSize;
+    UA_UInt32 *arrayDimensions;
+    UA_Byte accessLevel;
+    UA_Byte userAccessLevel;
+    UA_Double minimumSamplingInterval;
+    UA_Boolean historizing;
+} UA_VariableAttributes;
+
+
+
+
+

MethodAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Boolean executable;
+    UA_Boolean userExecutable;
+} UA_MethodAttributes;
+
+
+
+
+

ObjectTypeAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Boolean isAbstract;
+} UA_ObjectTypeAttributes;
+
+
+
+
+

VariableTypeAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Variant value;
+    UA_NodeId dataType;
+    UA_Int32 valueRank;
+    size_t arrayDimensionsSize;
+    UA_UInt32 *arrayDimensions;
+    UA_Boolean isAbstract;
+} UA_VariableTypeAttributes;
+
+
+
+
+

ReferenceTypeAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Boolean isAbstract;
+    UA_Boolean symmetric;
+    UA_LocalizedText inverseName;
+} UA_ReferenceTypeAttributes;
+
+
+
+
+

DataTypeAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Boolean isAbstract;
+} UA_DataTypeAttributes;
+
+
+
+
+

ViewAttributes

+
typedef struct {
+    UA_UInt32 specifiedAttributes;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+    UA_UInt32 writeMask;
+    UA_UInt32 userWriteMask;
+    UA_Boolean containsNoLoops;
+    UA_Byte eventNotifier;
+} UA_ViewAttributes;
+
+
+
+
+

AddNodesItem

+
typedef struct {
+    UA_ExpandedNodeId parentNodeId;
+    UA_NodeId referenceTypeId;
+    UA_ExpandedNodeId requestedNewNodeId;
+    UA_QualifiedName browseName;
+    UA_NodeClass nodeClass;
+    UA_ExtensionObject nodeAttributes;
+    UA_ExpandedNodeId typeDefinition;
+} UA_AddNodesItem;
+
+
+
+
+

AddNodesResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    UA_NodeId addedNodeId;
+} UA_AddNodesResult;
+
+
+
+
+

AddNodesRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t nodesToAddSize;
+    UA_AddNodesItem *nodesToAdd;
+} UA_AddNodesRequest;
+
+
+
+
+

AddNodesResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_AddNodesResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_AddNodesResponse;
+
+
+
+
+

AddReferencesItem

+
typedef struct {
+    UA_NodeId sourceNodeId;
+    UA_NodeId referenceTypeId;
+    UA_Boolean isForward;
+    UA_String targetServerUri;
+    UA_ExpandedNodeId targetNodeId;
+    UA_NodeClass targetNodeClass;
+} UA_AddReferencesItem;
+
+
+
+
+

AddReferencesRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t referencesToAddSize;
+    UA_AddReferencesItem *referencesToAdd;
+} UA_AddReferencesRequest;
+
+
+
+
+

AddReferencesResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_AddReferencesResponse;
+
+
+
+
+

DeleteNodesItem

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_Boolean deleteTargetReferences;
+} UA_DeleteNodesItem;
+
+
+
+
+

DeleteNodesRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t nodesToDeleteSize;
+    UA_DeleteNodesItem *nodesToDelete;
+} UA_DeleteNodesRequest;
+
+
+
+
+

DeleteNodesResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_DeleteNodesResponse;
+
+
+
+
+

DeleteReferencesItem

+
typedef struct {
+    UA_NodeId sourceNodeId;
+    UA_NodeId referenceTypeId;
+    UA_Boolean isForward;
+    UA_ExpandedNodeId targetNodeId;
+    UA_Boolean deleteBidirectional;
+} UA_DeleteReferencesItem;
+
+
+
+
+

DeleteReferencesRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t referencesToDeleteSize;
+    UA_DeleteReferencesItem *referencesToDelete;
+} UA_DeleteReferencesRequest;
+
+
+
+
+

DeleteReferencesResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_DeleteReferencesResponse;
+
+
+
+
+

BrowseDirection

+
typedef enum {
+    UA_BROWSEDIRECTION_FORWARD = 0,
+    UA_BROWSEDIRECTION_INVERSE = 1,
+    UA_BROWSEDIRECTION_BOTH = 2,
+    UA_BROWSEDIRECTION_INVALID = 3
+} UA_BrowseDirection;
+
+
+
+
+

ViewDescription

+
typedef struct {
+    UA_NodeId viewId;
+    UA_DateTime timestamp;
+    UA_UInt32 viewVersion;
+} UA_ViewDescription;
+
+
+
+
+

BrowseDescription

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_BrowseDirection browseDirection;
+    UA_NodeId referenceTypeId;
+    UA_Boolean includeSubtypes;
+    UA_UInt32 nodeClassMask;
+    UA_UInt32 resultMask;
+} UA_BrowseDescription;
+
+
+
+
+

BrowseResultMask

+
typedef enum {
+    UA_BROWSERESULTMASK_NONE = 0,
+    UA_BROWSERESULTMASK_REFERENCETYPEID = 1,
+    UA_BROWSERESULTMASK_ISFORWARD = 2,
+    UA_BROWSERESULTMASK_NODECLASS = 4,
+    UA_BROWSERESULTMASK_BROWSENAME = 8,
+    UA_BROWSERESULTMASK_DISPLAYNAME = 16,
+    UA_BROWSERESULTMASK_TYPEDEFINITION = 32,
+    UA_BROWSERESULTMASK_ALL = 63,
+    UA_BROWSERESULTMASK_REFERENCETYPEINFO = 3,
+    UA_BROWSERESULTMASK_TARGETINFO = 60
+} UA_BrowseResultMask;
+
+
+
+
+

ReferenceDescription

+
typedef struct {
+    UA_NodeId referenceTypeId;
+    UA_Boolean isForward;
+    UA_ExpandedNodeId nodeId;
+    UA_QualifiedName browseName;
+    UA_LocalizedText displayName;
+    UA_NodeClass nodeClass;
+    UA_ExpandedNodeId typeDefinition;
+} UA_ReferenceDescription;
+
+
+
+
+

BrowseResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    UA_ByteString continuationPoint;
+    size_t referencesSize;
+    UA_ReferenceDescription *references;
+} UA_BrowseResult;
+
+
+
+
+

BrowseRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_ViewDescription view;
+    UA_UInt32 requestedMaxReferencesPerNode;
+    size_t nodesToBrowseSize;
+    UA_BrowseDescription *nodesToBrowse;
+} UA_BrowseRequest;
+
+
+
+
+

BrowseResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_BrowseResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_BrowseResponse;
+
+
+
+
+

BrowseNextRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_Boolean releaseContinuationPoints;
+    size_t continuationPointsSize;
+    UA_ByteString *continuationPoints;
+} UA_BrowseNextRequest;
+
+
+
+
+

BrowseNextResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_BrowseResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_BrowseNextResponse;
+
+
+
+
+

RelativePathElement

+
typedef struct {
+    UA_NodeId referenceTypeId;
+    UA_Boolean isInverse;
+    UA_Boolean includeSubtypes;
+    UA_QualifiedName targetName;
+} UA_RelativePathElement;
+
+
+
+
+

RelativePath

+
typedef struct {
+    size_t elementsSize;
+    UA_RelativePathElement *elements;
+} UA_RelativePath;
+
+
+
+
+

BrowsePath

+
typedef struct {
+    UA_NodeId startingNode;
+    UA_RelativePath relativePath;
+} UA_BrowsePath;
+
+
+
+
+

BrowsePathTarget

+
typedef struct {
+    UA_ExpandedNodeId targetId;
+    UA_UInt32 remainingPathIndex;
+} UA_BrowsePathTarget;
+
+
+
+
+

BrowsePathResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    size_t targetsSize;
+    UA_BrowsePathTarget *targets;
+} UA_BrowsePathResult;
+
+
+
+
+

TranslateBrowsePathsToNodeIdsRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t browsePathsSize;
+    UA_BrowsePath *browsePaths;
+} UA_TranslateBrowsePathsToNodeIdsRequest;
+
+
+
+
+

TranslateBrowsePathsToNodeIdsResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_BrowsePathResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_TranslateBrowsePathsToNodeIdsResponse;
+
+
+
+
+

RegisterNodesRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t nodesToRegisterSize;
+    UA_NodeId *nodesToRegister;
+} UA_RegisterNodesRequest;
+
+
+
+
+

RegisterNodesResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t registeredNodeIdsSize;
+    UA_NodeId *registeredNodeIds;
+} UA_RegisterNodesResponse;
+
+
+
+
+

UnregisterNodesRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t nodesToUnregisterSize;
+    UA_NodeId *nodesToUnregister;
+} UA_UnregisterNodesRequest;
+
+
+
+
+

UnregisterNodesResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+} UA_UnregisterNodesResponse;
+
+
+
+
+

FilterOperator

+
typedef enum {
+    UA_FILTEROPERATOR_EQUALS = 0,
+    UA_FILTEROPERATOR_ISNULL = 1,
+    UA_FILTEROPERATOR_GREATERTHAN = 2,
+    UA_FILTEROPERATOR_LESSTHAN = 3,
+    UA_FILTEROPERATOR_GREATERTHANOREQUAL = 4,
+    UA_FILTEROPERATOR_LESSTHANOREQUAL = 5,
+    UA_FILTEROPERATOR_LIKE = 6,
+    UA_FILTEROPERATOR_NOT = 7,
+    UA_FILTEROPERATOR_BETWEEN = 8,
+    UA_FILTEROPERATOR_INLIST = 9,
+    UA_FILTEROPERATOR_AND = 10,
+    UA_FILTEROPERATOR_OR = 11,
+    UA_FILTEROPERATOR_CAST = 12,
+    UA_FILTEROPERATOR_INVIEW = 13,
+    UA_FILTEROPERATOR_OFTYPE = 14,
+    UA_FILTEROPERATOR_RELATEDTO = 15,
+    UA_FILTEROPERATOR_BITWISEAND = 16,
+    UA_FILTEROPERATOR_BITWISEOR = 17
+} UA_FilterOperator;
+
+
+
+
+

ContentFilterElement

+
typedef struct {
+    UA_FilterOperator filterOperator;
+    size_t filterOperandsSize;
+    UA_ExtensionObject *filterOperands;
+} UA_ContentFilterElement;
+
+
+
+
+

ContentFilter

+
typedef struct {
+    size_t elementsSize;
+    UA_ContentFilterElement *elements;
+} UA_ContentFilter;
+
+
+
+
+

ElementOperand

+
typedef struct {
+    UA_UInt32 index;
+} UA_ElementOperand;
+
+
+
+
+

LiteralOperand

+
typedef struct {
+    UA_Variant value;
+} UA_LiteralOperand;
+
+
+
+
+

AttributeOperand

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_String alias;
+    UA_RelativePath browsePath;
+    UA_UInt32 attributeId;
+    UA_String indexRange;
+} UA_AttributeOperand;
+
+
+
+
+

SimpleAttributeOperand

+
typedef struct {
+    UA_NodeId typeDefinitionId;
+    size_t browsePathSize;
+    UA_QualifiedName *browsePath;
+    UA_UInt32 attributeId;
+    UA_String indexRange;
+} UA_SimpleAttributeOperand;
+
+
+
+
+

ContentFilterElementResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    size_t operandStatusCodesSize;
+    UA_StatusCode *operandStatusCodes;
+    size_t operandDiagnosticInfosSize;
+    UA_DiagnosticInfo *operandDiagnosticInfos;
+} UA_ContentFilterElementResult;
+
+
+
+
+

ContentFilterResult

+
typedef struct {
+    size_t elementResultsSize;
+    UA_ContentFilterElementResult *elementResults;
+    size_t elementDiagnosticInfosSize;
+    UA_DiagnosticInfo *elementDiagnosticInfos;
+} UA_ContentFilterResult;
+
+
+
+
+

TimestampsToReturn

+
typedef enum {
+    UA_TIMESTAMPSTORETURN_SOURCE = 0,
+    UA_TIMESTAMPSTORETURN_SERVER = 1,
+    UA_TIMESTAMPSTORETURN_BOTH = 2,
+    UA_TIMESTAMPSTORETURN_NEITHER = 3,
+    UA_TIMESTAMPSTORETURN_INVALID = 4
+} UA_TimestampsToReturn;
+
+
+
+
+

ReadValueId

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_UInt32 attributeId;
+    UA_String indexRange;
+    UA_QualifiedName dataEncoding;
+} UA_ReadValueId;
+
+
+
+
+

ReadRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_Double maxAge;
+    UA_TimestampsToReturn timestampsToReturn;
+    size_t nodesToReadSize;
+    UA_ReadValueId *nodesToRead;
+} UA_ReadRequest;
+
+
+
+
+

ReadResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_DataValue *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_ReadResponse;
+
+
+
+
+

HistoryReadValueId

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_String indexRange;
+    UA_QualifiedName dataEncoding;
+    UA_ByteString continuationPoint;
+} UA_HistoryReadValueId;
+
+
+
+
+

HistoryReadResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    UA_ByteString continuationPoint;
+    UA_ExtensionObject historyData;
+} UA_HistoryReadResult;
+
+
+
+
+

ReadRawModifiedDetails

+
typedef struct {
+    UA_Boolean isReadModified;
+    UA_DateTime startTime;
+    UA_DateTime endTime;
+    UA_UInt32 numValuesPerNode;
+    UA_Boolean returnBounds;
+} UA_ReadRawModifiedDetails;
+
+
+
+
+

ReadAtTimeDetails

+
typedef struct {
+    size_t reqTimesSize;
+    UA_DateTime *reqTimes;
+    UA_Boolean useSimpleBounds;
+} UA_ReadAtTimeDetails;
+
+
+
+
+

HistoryData

+
typedef struct {
+    size_t dataValuesSize;
+    UA_DataValue *dataValues;
+} UA_HistoryData;
+
+
+
+
+

HistoryReadRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_ExtensionObject historyReadDetails;
+    UA_TimestampsToReturn timestampsToReturn;
+    UA_Boolean releaseContinuationPoints;
+    size_t nodesToReadSize;
+    UA_HistoryReadValueId *nodesToRead;
+} UA_HistoryReadRequest;
+
+
+
+
+

HistoryReadResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_HistoryReadResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_HistoryReadResponse;
+
+
+
+
+

WriteValue

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_UInt32 attributeId;
+    UA_String indexRange;
+    UA_DataValue value;
+} UA_WriteValue;
+
+
+
+
+

WriteRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t nodesToWriteSize;
+    UA_WriteValue *nodesToWrite;
+} UA_WriteRequest;
+
+
+
+
+

WriteResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_WriteResponse;
+
+
+
+
+

HistoryUpdateType

+
typedef enum {
+    UA_HISTORYUPDATETYPE_INSERT = 1,
+    UA_HISTORYUPDATETYPE_REPLACE = 2,
+    UA_HISTORYUPDATETYPE_UPDATE = 3,
+    UA_HISTORYUPDATETYPE_DELETE = 4
+} UA_HistoryUpdateType;
+
+
+
+
+

PerformUpdateType

+
typedef enum {
+    UA_PERFORMUPDATETYPE_INSERT = 1,
+    UA_PERFORMUPDATETYPE_REPLACE = 2,
+    UA_PERFORMUPDATETYPE_UPDATE = 3,
+    UA_PERFORMUPDATETYPE_REMOVE = 4
+} UA_PerformUpdateType;
+
+
+
+
+

UpdateDataDetails

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_PerformUpdateType performInsertReplace;
+    size_t updateValuesSize;
+    UA_DataValue *updateValues;
+} UA_UpdateDataDetails;
+
+
+
+
+

DeleteRawModifiedDetails

+
typedef struct {
+    UA_NodeId nodeId;
+    UA_Boolean isDeleteModified;
+    UA_DateTime startTime;
+    UA_DateTime endTime;
+} UA_DeleteRawModifiedDetails;
+
+
+
+
+

HistoryUpdateResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    size_t operationResultsSize;
+    UA_StatusCode *operationResults;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_HistoryUpdateResult;
+
+
+
+
+

HistoryUpdateRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t historyUpdateDetailsSize;
+    UA_ExtensionObject *historyUpdateDetails;
+} UA_HistoryUpdateRequest;
+
+
+
+
+

HistoryUpdateResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_HistoryUpdateResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_HistoryUpdateResponse;
+
+
+
+
+

CallMethodRequest

+
typedef struct {
+    UA_NodeId objectId;
+    UA_NodeId methodId;
+    size_t inputArgumentsSize;
+    UA_Variant *inputArguments;
+} UA_CallMethodRequest;
+
+
+
+
+

CallMethodResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    size_t inputArgumentResultsSize;
+    UA_StatusCode *inputArgumentResults;
+    size_t inputArgumentDiagnosticInfosSize;
+    UA_DiagnosticInfo *inputArgumentDiagnosticInfos;
+    size_t outputArgumentsSize;
+    UA_Variant *outputArguments;
+} UA_CallMethodResult;
+
+
+
+
+

CallRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t methodsToCallSize;
+    UA_CallMethodRequest *methodsToCall;
+} UA_CallRequest;
+
+
+
+
+

CallResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_CallMethodResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_CallResponse;
+
+
+
+
+

MonitoringMode

+
typedef enum {
+    UA_MONITORINGMODE_DISABLED = 0,
+    UA_MONITORINGMODE_SAMPLING = 1,
+    UA_MONITORINGMODE_REPORTING = 2
+} UA_MonitoringMode;
+
+
+
+
+

DataChangeTrigger

+
typedef enum {
+    UA_DATACHANGETRIGGER_STATUS = 0,
+    UA_DATACHANGETRIGGER_STATUSVALUE = 1,
+    UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP = 2
+} UA_DataChangeTrigger;
+
+
+
+
+

DeadbandType

+
typedef enum {
+    UA_DEADBANDTYPE_NONE = 0,
+    UA_DEADBANDTYPE_ABSOLUTE = 1,
+    UA_DEADBANDTYPE_PERCENT = 2
+} UA_DeadbandType;
+
+
+
+
+

DataChangeFilter

+
typedef struct {
+    UA_DataChangeTrigger trigger;
+    UA_UInt32 deadbandType;
+    UA_Double deadbandValue;
+} UA_DataChangeFilter;
+
+
+
+
+

EventFilter

+
typedef struct {
+    size_t selectClausesSize;
+    UA_SimpleAttributeOperand *selectClauses;
+    UA_ContentFilter whereClause;
+} UA_EventFilter;
+
+
+
+
+

AggregateConfiguration

+
typedef struct {
+    UA_Boolean useServerCapabilitiesDefaults;
+    UA_Boolean treatUncertainAsBad;
+    UA_Byte percentDataBad;
+    UA_Byte percentDataGood;
+    UA_Boolean useSlopedExtrapolation;
+} UA_AggregateConfiguration;
+
+
+
+
+

AggregateFilter

+
typedef struct {
+    UA_DateTime startTime;
+    UA_NodeId aggregateType;
+    UA_Double processingInterval;
+    UA_AggregateConfiguration aggregateConfiguration;
+} UA_AggregateFilter;
+
+
+
+
+

EventFilterResult

+
typedef struct {
+    size_t selectClauseResultsSize;
+    UA_StatusCode *selectClauseResults;
+    size_t selectClauseDiagnosticInfosSize;
+    UA_DiagnosticInfo *selectClauseDiagnosticInfos;
+    UA_ContentFilterResult whereClauseResult;
+} UA_EventFilterResult;
+
+
+
+
+

MonitoringParameters

+
typedef struct {
+    UA_UInt32 clientHandle;
+    UA_Double samplingInterval;
+    UA_ExtensionObject filter;
+    UA_UInt32 queueSize;
+    UA_Boolean discardOldest;
+} UA_MonitoringParameters;
+
+
+
+
+

MonitoredItemCreateRequest

+
typedef struct {
+    UA_ReadValueId itemToMonitor;
+    UA_MonitoringMode monitoringMode;
+    UA_MonitoringParameters requestedParameters;
+} UA_MonitoredItemCreateRequest;
+
+
+
+
+

MonitoredItemCreateResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    UA_UInt32 monitoredItemId;
+    UA_Double revisedSamplingInterval;
+    UA_UInt32 revisedQueueSize;
+    UA_ExtensionObject filterResult;
+} UA_MonitoredItemCreateResult;
+
+
+
+
+

CreateMonitoredItemsRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 subscriptionId;
+    UA_TimestampsToReturn timestampsToReturn;
+    size_t itemsToCreateSize;
+    UA_MonitoredItemCreateRequest *itemsToCreate;
+} UA_CreateMonitoredItemsRequest;
+
+
+
+
+

CreateMonitoredItemsResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_MonitoredItemCreateResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_CreateMonitoredItemsResponse;
+
+
+
+
+

MonitoredItemModifyRequest

+
typedef struct {
+    UA_UInt32 monitoredItemId;
+    UA_MonitoringParameters requestedParameters;
+} UA_MonitoredItemModifyRequest;
+
+
+
+
+

MonitoredItemModifyResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    UA_Double revisedSamplingInterval;
+    UA_UInt32 revisedQueueSize;
+    UA_ExtensionObject filterResult;
+} UA_MonitoredItemModifyResult;
+
+
+
+
+

ModifyMonitoredItemsRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 subscriptionId;
+    UA_TimestampsToReturn timestampsToReturn;
+    size_t itemsToModifySize;
+    UA_MonitoredItemModifyRequest *itemsToModify;
+} UA_ModifyMonitoredItemsRequest;
+
+
+
+
+

ModifyMonitoredItemsResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_MonitoredItemModifyResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_ModifyMonitoredItemsResponse;
+
+
+
+
+

SetMonitoringModeRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 subscriptionId;
+    UA_MonitoringMode monitoringMode;
+    size_t monitoredItemIdsSize;
+    UA_UInt32 *monitoredItemIds;
+} UA_SetMonitoringModeRequest;
+
+
+
+
+

SetMonitoringModeResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_SetMonitoringModeResponse;
+
+
+
+
+

SetTriggeringRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 subscriptionId;
+    UA_UInt32 triggeringItemId;
+    size_t linksToAddSize;
+    UA_UInt32 *linksToAdd;
+    size_t linksToRemoveSize;
+    UA_UInt32 *linksToRemove;
+} UA_SetTriggeringRequest;
+
+
+
+
+

SetTriggeringResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t addResultsSize;
+    UA_StatusCode *addResults;
+    size_t addDiagnosticInfosSize;
+    UA_DiagnosticInfo *addDiagnosticInfos;
+    size_t removeResultsSize;
+    UA_StatusCode *removeResults;
+    size_t removeDiagnosticInfosSize;
+    UA_DiagnosticInfo *removeDiagnosticInfos;
+} UA_SetTriggeringResponse;
+
+
+
+
+

DeleteMonitoredItemsRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 subscriptionId;
+    size_t monitoredItemIdsSize;
+    UA_UInt32 *monitoredItemIds;
+} UA_DeleteMonitoredItemsRequest;
+
+
+
+
+

DeleteMonitoredItemsResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_DeleteMonitoredItemsResponse;
+
+
+
+
+

CreateSubscriptionRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_Double requestedPublishingInterval;
+    UA_UInt32 requestedLifetimeCount;
+    UA_UInt32 requestedMaxKeepAliveCount;
+    UA_UInt32 maxNotificationsPerPublish;
+    UA_Boolean publishingEnabled;
+    UA_Byte priority;
+} UA_CreateSubscriptionRequest;
+
+
+
+
+

CreateSubscriptionResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_UInt32 subscriptionId;
+    UA_Double revisedPublishingInterval;
+    UA_UInt32 revisedLifetimeCount;
+    UA_UInt32 revisedMaxKeepAliveCount;
+} UA_CreateSubscriptionResponse;
+
+
+
+
+

ModifySubscriptionRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 subscriptionId;
+    UA_Double requestedPublishingInterval;
+    UA_UInt32 requestedLifetimeCount;
+    UA_UInt32 requestedMaxKeepAliveCount;
+    UA_UInt32 maxNotificationsPerPublish;
+    UA_Byte priority;
+} UA_ModifySubscriptionRequest;
+
+
+
+
+

ModifySubscriptionResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_Double revisedPublishingInterval;
+    UA_UInt32 revisedLifetimeCount;
+    UA_UInt32 revisedMaxKeepAliveCount;
+} UA_ModifySubscriptionResponse;
+
+
+
+
+

SetPublishingModeRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_Boolean publishingEnabled;
+    size_t subscriptionIdsSize;
+    UA_UInt32 *subscriptionIds;
+} UA_SetPublishingModeRequest;
+
+
+
+
+

SetPublishingModeResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_SetPublishingModeResponse;
+
+
+
+
+

NotificationMessage

+
typedef struct {
+    UA_UInt32 sequenceNumber;
+    UA_DateTime publishTime;
+    size_t notificationDataSize;
+    UA_ExtensionObject *notificationData;
+} UA_NotificationMessage;
+
+
+
+
+

MonitoredItemNotification

+
typedef struct {
+    UA_UInt32 clientHandle;
+    UA_DataValue value;
+} UA_MonitoredItemNotification;
+
+
+
+
+

EventFieldList

+
typedef struct {
+    UA_UInt32 clientHandle;
+    size_t eventFieldsSize;
+    UA_Variant *eventFields;
+} UA_EventFieldList;
+
+
+
+
+

HistoryEventFieldList

+
typedef struct {
+    size_t eventFieldsSize;
+    UA_Variant *eventFields;
+} UA_HistoryEventFieldList;
+
+
+
+
+

StatusChangeNotification

+
typedef struct {
+    UA_StatusCode status;
+    UA_DiagnosticInfo diagnosticInfo;
+} UA_StatusChangeNotification;
+
+
+
+
+

SubscriptionAcknowledgement

+
typedef struct {
+    UA_UInt32 subscriptionId;
+    UA_UInt32 sequenceNumber;
+} UA_SubscriptionAcknowledgement;
+
+
+
+
+

PublishRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t subscriptionAcknowledgementsSize;
+    UA_SubscriptionAcknowledgement *subscriptionAcknowledgements;
+} UA_PublishRequest;
+
+
+
+
+

PublishResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_UInt32 subscriptionId;
+    size_t availableSequenceNumbersSize;
+    UA_UInt32 *availableSequenceNumbers;
+    UA_Boolean moreNotifications;
+    UA_NotificationMessage notificationMessage;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_PublishResponse;
+
+
+
+
+

RepublishRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    UA_UInt32 subscriptionId;
+    UA_UInt32 retransmitSequenceNumber;
+} UA_RepublishRequest;
+
+
+
+
+

RepublishResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    UA_NotificationMessage notificationMessage;
+} UA_RepublishResponse;
+
+
+
+
+

TransferResult

+
typedef struct {
+    UA_StatusCode statusCode;
+    size_t availableSequenceNumbersSize;
+    UA_UInt32 *availableSequenceNumbers;
+} UA_TransferResult;
+
+
+
+
+

TransferSubscriptionsRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t subscriptionIdsSize;
+    UA_UInt32 *subscriptionIds;
+    UA_Boolean sendInitialValues;
+} UA_TransferSubscriptionsRequest;
+
+
+
+
+

TransferSubscriptionsResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_TransferResult *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_TransferSubscriptionsResponse;
+
+
+
+
+

DeleteSubscriptionsRequest

+
typedef struct {
+    UA_RequestHeader requestHeader;
+    size_t subscriptionIdsSize;
+    UA_UInt32 *subscriptionIds;
+} UA_DeleteSubscriptionsRequest;
+
+
+
+
+

DeleteSubscriptionsResponse

+
typedef struct {
+    UA_ResponseHeader responseHeader;
+    size_t resultsSize;
+    UA_StatusCode *results;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_DeleteSubscriptionsResponse;
+
+
+
+
+

BuildInfo

+
typedef struct {
+    UA_String productUri;
+    UA_String manufacturerName;
+    UA_String productName;
+    UA_String softwareVersion;
+    UA_String buildNumber;
+    UA_DateTime buildDate;
+} UA_BuildInfo;
+
+
+
+
+

RedundancySupport

+
typedef enum {
+    UA_REDUNDANCYSUPPORT_NONE = 0,
+    UA_REDUNDANCYSUPPORT_COLD = 1,
+    UA_REDUNDANCYSUPPORT_WARM = 2,
+    UA_REDUNDANCYSUPPORT_HOT = 3,
+    UA_REDUNDANCYSUPPORT_TRANSPARENT = 4,
+    UA_REDUNDANCYSUPPORT_HOTANDMIRRORED = 5
+} UA_RedundancySupport;
+
+
+
+
+

ServerState

+
typedef enum {
+    UA_SERVERSTATE_RUNNING = 0,
+    UA_SERVERSTATE_FAILED = 1,
+    UA_SERVERSTATE_NOCONFIGURATION = 2,
+    UA_SERVERSTATE_SUSPENDED = 3,
+    UA_SERVERSTATE_SHUTDOWN = 4,
+    UA_SERVERSTATE_TEST = 5,
+    UA_SERVERSTATE_COMMUNICATIONFAULT = 6,
+    UA_SERVERSTATE_UNKNOWN = 7
+} UA_ServerState;
+
+
+
+
+

ServerDiagnosticsSummaryDataType

+
typedef struct {
+    UA_UInt32 serverViewCount;
+    UA_UInt32 currentSessionCount;
+    UA_UInt32 cumulatedSessionCount;
+    UA_UInt32 securityRejectedSessionCount;
+    UA_UInt32 rejectedSessionCount;
+    UA_UInt32 sessionTimeoutCount;
+    UA_UInt32 sessionAbortCount;
+    UA_UInt32 currentSubscriptionCount;
+    UA_UInt32 cumulatedSubscriptionCount;
+    UA_UInt32 publishingIntervalCount;
+    UA_UInt32 securityRejectedRequestsCount;
+    UA_UInt32 rejectedRequestsCount;
+} UA_ServerDiagnosticsSummaryDataType;
+
+
+
+
+

ServerStatusDataType

+
typedef struct {
+    UA_DateTime startTime;
+    UA_DateTime currentTime;
+    UA_ServerState state;
+    UA_BuildInfo buildInfo;
+    UA_UInt32 secondsTillShutdown;
+    UA_LocalizedText shutdownReason;
+} UA_ServerStatusDataType;
+
+
+
+
+

SessionSecurityDiagnosticsDataType

+
typedef struct {
+    UA_NodeId sessionId;
+    UA_String clientUserIdOfSession;
+    size_t clientUserIdHistorySize;
+    UA_String *clientUserIdHistory;
+    UA_String authenticationMechanism;
+    UA_String encoding;
+    UA_String transportProtocol;
+    UA_MessageSecurityMode securityMode;
+    UA_String securityPolicyUri;
+    UA_ByteString clientCertificate;
+} UA_SessionSecurityDiagnosticsDataType;
+
+
+
+
+

ServiceCounterDataType

+
typedef struct {
+    UA_UInt32 totalCount;
+    UA_UInt32 errorCount;
+} UA_ServiceCounterDataType;
+
+
+
+
+

SubscriptionDiagnosticsDataType

+
typedef struct {
+    UA_NodeId sessionId;
+    UA_UInt32 subscriptionId;
+    UA_Byte priority;
+    UA_Double publishingInterval;
+    UA_UInt32 maxKeepAliveCount;
+    UA_UInt32 maxLifetimeCount;
+    UA_UInt32 maxNotificationsPerPublish;
+    UA_Boolean publishingEnabled;
+    UA_UInt32 modifyCount;
+    UA_UInt32 enableCount;
+    UA_UInt32 disableCount;
+    UA_UInt32 republishRequestCount;
+    UA_UInt32 republishMessageRequestCount;
+    UA_UInt32 republishMessageCount;
+    UA_UInt32 transferRequestCount;
+    UA_UInt32 transferredToAltClientCount;
+    UA_UInt32 transferredToSameClientCount;
+    UA_UInt32 publishRequestCount;
+    UA_UInt32 dataChangeNotificationsCount;
+    UA_UInt32 eventNotificationsCount;
+    UA_UInt32 notificationsCount;
+    UA_UInt32 latePublishRequestCount;
+    UA_UInt32 currentKeepAliveCount;
+    UA_UInt32 currentLifetimeCount;
+    UA_UInt32 unacknowledgedMessageCount;
+    UA_UInt32 discardedMessageCount;
+    UA_UInt32 monitoredItemCount;
+    UA_UInt32 disabledMonitoredItemCount;
+    UA_UInt32 monitoringQueueOverflowCount;
+    UA_UInt32 nextSequenceNumber;
+    UA_UInt32 eventQueueOverFlowCount;
+} UA_SubscriptionDiagnosticsDataType;
+
+
+
+
+

Range

+
typedef struct {
+    UA_Double low;
+    UA_Double high;
+} UA_Range;
+
+
+
+
+

EUInformation

+
typedef struct {
+    UA_String namespaceUri;
+    UA_Int32 unitId;
+    UA_LocalizedText displayName;
+    UA_LocalizedText description;
+} UA_EUInformation;
+
+
+
+
+

AxisScaleEnumeration

+
typedef enum {
+    UA_AXISSCALEENUMERATION_LINEAR = 0,
+    UA_AXISSCALEENUMERATION_LOG = 1,
+    UA_AXISSCALEENUMERATION_LN = 2
+} UA_AxisScaleEnumeration;
+
+
+
+
+

ComplexNumberType

+
typedef struct {
+    UA_Float real;
+    UA_Float imaginary;
+} UA_ComplexNumberType;
+
+
+
+
+

DoubleComplexNumberType

+
typedef struct {
+    UA_Double real;
+    UA_Double imaginary;
+} UA_DoubleComplexNumberType;
+
+
+
+
+

AxisInformation

+
typedef struct {
+    UA_EUInformation engineeringUnits;
+    UA_Range eURange;
+    UA_LocalizedText title;
+    UA_AxisScaleEnumeration axisScaleType;
+    size_t axisStepsSize;
+    UA_Double *axisSteps;
+} UA_AxisInformation;
+
+
+
+
+

XVType

+
typedef struct {
+    UA_Double x;
+    UA_Float value;
+} UA_XVType;
+
+
+
+
+

EnumDefinition

+
typedef struct {
+    size_t fieldsSize;
+    UA_EnumField *fields;
+} UA_EnumDefinition;
+
+
+
+
+

ReadEventDetails

+
typedef struct {
+    UA_UInt32 numValuesPerNode;
+    UA_DateTime startTime;
+    UA_DateTime endTime;
+    UA_EventFilter filter;
+} UA_ReadEventDetails;
+
+
+
+
+

ReadProcessedDetails

+
typedef struct {
+    UA_DateTime startTime;
+    UA_DateTime endTime;
+    UA_Double processingInterval;
+    size_t aggregateTypeSize;
+    UA_NodeId *aggregateType;
+    UA_AggregateConfiguration aggregateConfiguration;
+} UA_ReadProcessedDetails;
+
+
+
+
+

ModificationInfo

+
typedef struct {
+    UA_DateTime modificationTime;
+    UA_HistoryUpdateType updateType;
+    UA_String userName;
+} UA_ModificationInfo;
+
+
+
+
+

HistoryModifiedData

+
typedef struct {
+    size_t dataValuesSize;
+    UA_DataValue *dataValues;
+    size_t modificationInfosSize;
+    UA_ModificationInfo *modificationInfos;
+} UA_HistoryModifiedData;
+
+
+
+
+

HistoryEvent

+
typedef struct {
+    size_t eventsSize;
+    UA_HistoryEventFieldList *events;
+} UA_HistoryEvent;
+
+
+
+
+

DataChangeNotification

+
typedef struct {
+    size_t monitoredItemsSize;
+    UA_MonitoredItemNotification *monitoredItems;
+    size_t diagnosticInfosSize;
+    UA_DiagnosticInfo *diagnosticInfos;
+} UA_DataChangeNotification;
+
+
+
+
+

EventNotificationList

+
typedef struct {
+    size_t eventsSize;
+    UA_EventFieldList *events;
+} UA_EventNotificationList;
+
+
+
+
+

SessionDiagnosticsDataType

+
typedef struct {
+    UA_NodeId sessionId;
+    UA_String sessionName;
+    UA_ApplicationDescription clientDescription;
+    UA_String serverUri;
+    UA_String endpointUrl;
+    size_t localeIdsSize;
+    UA_String *localeIds;
+    UA_Double actualSessionTimeout;
+    UA_UInt32 maxResponseMessageSize;
+    UA_DateTime clientConnectionTime;
+    UA_DateTime clientLastContactTime;
+    UA_UInt32 currentSubscriptionsCount;
+    UA_UInt32 currentMonitoredItemsCount;
+    UA_UInt32 currentPublishRequestsInQueue;
+    UA_ServiceCounterDataType totalRequestCount;
+    UA_UInt32 unauthorizedRequestCount;
+    UA_ServiceCounterDataType readCount;
+    UA_ServiceCounterDataType historyReadCount;
+    UA_ServiceCounterDataType writeCount;
+    UA_ServiceCounterDataType historyUpdateCount;
+    UA_ServiceCounterDataType callCount;
+    UA_ServiceCounterDataType createMonitoredItemsCount;
+    UA_ServiceCounterDataType modifyMonitoredItemsCount;
+    UA_ServiceCounterDataType setMonitoringModeCount;
+    UA_ServiceCounterDataType setTriggeringCount;
+    UA_ServiceCounterDataType deleteMonitoredItemsCount;
+    UA_ServiceCounterDataType createSubscriptionCount;
+    UA_ServiceCounterDataType modifySubscriptionCount;
+    UA_ServiceCounterDataType setPublishingModeCount;
+    UA_ServiceCounterDataType publishCount;
+    UA_ServiceCounterDataType republishCount;
+    UA_ServiceCounterDataType transferSubscriptionsCount;
+    UA_ServiceCounterDataType deleteSubscriptionsCount;
+    UA_ServiceCounterDataType addNodesCount;
+    UA_ServiceCounterDataType addReferencesCount;
+    UA_ServiceCounterDataType deleteNodesCount;
+    UA_ServiceCounterDataType deleteReferencesCount;
+    UA_ServiceCounterDataType browseCount;
+    UA_ServiceCounterDataType browseNextCount;
+    UA_ServiceCounterDataType translateBrowsePathsToNodeIdsCount;
+    UA_ServiceCounterDataType queryFirstCount;
+    UA_ServiceCounterDataType queryNextCount;
+    UA_ServiceCounterDataType registerNodesCount;
+    UA_ServiceCounterDataType unregisterNodesCount;
+} UA_SessionDiagnosticsDataType;
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/doc/v1.4.0/util.html b/static/doc/v1.4.0/util.html new file mode 100644 index 0000000000..08494ac306 --- /dev/null +++ b/static/doc/v1.4.0/util.html @@ -0,0 +1,388 @@ + + + + + + + Range Definition — open62541 1.4.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Range Definition

+
typedef struct {
+    UA_UInt32 min;
+    UA_UInt32 max;
+} UA_UInt32Range;
+
+typedef struct {
+    UA_Duration min;
+    UA_Duration max;
+} UA_DurationRange;
+
+
+
+
+

Random Number Generator

+

If UA_MULTITHREADING is defined, then the seed is stored in thread +local storage. The seed is initialized for every thread in the +server/client.

+
void
+UA_random_seed(UA_UInt64 seed);
+
+UA_UInt32
+UA_UInt32_random(void); /* no cryptographic entropy */
+
+UA_Guid
+UA_Guid_random(void);   /* no cryptographic entropy */
+
+
+
+
+

Key Value Map

+

Helper functions to work with configuration parameters in an array of +UA_KeyValuePair. Lookup is linear. So this is for small numbers of keys. The +methods below that accept a const UA_KeyValueMap as an argument also accept +NULL for that argument and treat it as an empty map.

+
typedef struct {
+    size_t mapSize;
+    UA_KeyValuePair *map;
+} UA_KeyValueMap;
+
+extern const UA_KeyValueMap UA_KEYVALUEMAP_NULL;
+
+UA_KeyValueMap *
+UA_KeyValueMap_new(void);
+
+void
+UA_KeyValueMap_clear(UA_KeyValueMap *map);
+
+void
+UA_KeyValueMap_delete(UA_KeyValueMap *map);
+
+/* Is the map empty (or NULL)? */
+UA_Boolean
+UA_KeyValueMap_isEmpty(const UA_KeyValueMap *map);
+
+/* Does the map contain an entry for the key? */
+UA_Boolean
+UA_KeyValueMap_contains(const UA_KeyValueMap *map, const UA_QualifiedName key);
+
+/* Insert a copy of the value. Can reallocate the underlying array. This
+ * invalidates pointers into the previous array. If the key exists already, the
+ * value is overwritten (upsert semantics). */
+UA_StatusCode
+UA_KeyValueMap_set(UA_KeyValueMap *map,
+                   const UA_QualifiedName key,
+                   const UA_Variant *value);
+
+/* Helper function for scalar insertion that internally calls
+ * `UA_KeyValueMap_set` */
+UA_StatusCode
+UA_KeyValueMap_setScalar(UA_KeyValueMap *map,
+                         const UA_QualifiedName key,
+                         void *p,
+                         const UA_DataType *type);
+
+/* Returns a pointer to the value or NULL if the key is not found */
+const UA_Variant *
+UA_KeyValueMap_get(const UA_KeyValueMap *map,
+                   const UA_QualifiedName key);
+
+/* Returns NULL if the value for the key is not defined, not of the right
+ * datatype or not a scalar */
+const void *
+UA_KeyValueMap_getScalar(const UA_KeyValueMap *map,
+                         const UA_QualifiedName key,
+                         const UA_DataType *type);
+
+/* Remove a single entry. To delete the entire map, use `UA_KeyValueMap_clear`. */
+UA_StatusCode
+UA_KeyValueMap_remove(UA_KeyValueMap *map,
+                      const UA_QualifiedName key);
+
+/* Create a deep copy of the given KeyValueMap */
+UA_StatusCode
+UA_KeyValueMap_copy(const UA_KeyValueMap *src, UA_KeyValueMap *dst);
+
+/* Copy entries from the right-hand-side into the left-hand-size. Reallocates
+ * previous memory in the left-hand-side. If the operation fails, both maps are
+ * left untouched. */
+UA_StatusCode
+UA_KeyValueMap_merge(UA_KeyValueMap *lhs, const UA_KeyValueMap *rhs);
+
+
+
+
+

Binary Connection Config Parameters

+
typedef struct {
+    UA_UInt32 protocolVersion;
+    UA_UInt32 recvBufferSize;
+    UA_UInt32 sendBufferSize;
+    UA_UInt32 localMaxMessageSize;  /* (0 = unbounded) */
+    UA_UInt32 remoteMaxMessageSize; /* (0 = unbounded) */
+    UA_UInt32 localMaxChunkCount;   /* (0 = unbounded) */
+    UA_UInt32 remoteMaxChunkCount;  /* (0 = unbounded) */
+} UA_ConnectionConfig;
+
+
+
+
+

Default Node Attributes

+

Default node attributes to simplify the use of the AddNodes services. For +example, Setting the ValueRank and AccessLevel to zero is often an unintended +setting and leads to errors that are hard to track down.

+
/* The default for variables is "BaseDataType" for the datatype, -2 for the
+ * valuerank and a read-accesslevel. */
+extern const UA_VariableAttributes UA_VariableAttributes_default;
+extern const UA_VariableTypeAttributes UA_VariableTypeAttributes_default;
+
+/* Methods are executable by default */
+extern const UA_MethodAttributes UA_MethodAttributes_default;
+
+/* The remaining attribute definitions are currently all zeroed out */
+extern const UA_ObjectAttributes UA_ObjectAttributes_default;
+extern const UA_ObjectTypeAttributes UA_ObjectTypeAttributes_default;
+extern const UA_ReferenceTypeAttributes UA_ReferenceTypeAttributes_default;
+extern const UA_DataTypeAttributes UA_DataTypeAttributes_default;
+extern const UA_ViewAttributes UA_ViewAttributes_default;
+
+
+
+
+

Endpoint URL Parser

+

The endpoint URL parser is generally useful for the implementation of network +layer plugins.

+
/* Split the given endpoint url into hostname, port and path. All arguments must
+ * be non-NULL. EndpointUrls have the form "opc.tcp://hostname:port/path", port
+ * and path may be omitted (together with the prefix colon and slash).
+ *
+ * @param endpointUrl The endpoint URL.
+ * @param outHostname Set to the parsed hostname. The string points into the
+ *        original endpointUrl, so no memory is allocated. If an IPv6 address is
+ *        given, hostname contains e.g. '[2001:0db8:85a3::8a2e:0370:7334]'
+ * @param outPort Set to the port of the url or left unchanged.
+ * @param outPath Set to the path if one is present in the endpointUrl. Can be
+ *        NULL. Then not path is returned. Starting or trailing '/' are NOT
+ *        included in the path. The string points into the original endpointUrl,
+ *        so no memory is allocated.
+ * @return Returns UA_STATUSCODE_BADTCPENDPOINTURLINVALID if parsing failed. */
+UA_StatusCode
+UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname,
+                    UA_UInt16 *outPort, UA_String *outPath);
+
+/* Split the given endpoint url into hostname, vid and pcp. All arguments must
+ * be non-NULL. EndpointUrls have the form "opc.eth://<host>[:<VID>[.PCP]]".
+ * The host is a MAC address, an IP address or a registered name like a
+ * hostname. The format of a MAC address is six groups of hexadecimal digits,
+ * separated by hyphens (e.g. 01-23-45-67-89-ab). A system may also accept
+ * hostnames and/or IP addresses if it provides means to resolve it to a MAC
+ * address (e.g. DNS and Reverse-ARP).
+ *
+ * Note: currently only parsing MAC address is supported.
+ *
+ * @param endpointUrl The endpoint URL.
+ * @param vid Set to VLAN ID.
+ * @param pcp Set to Priority Code Point.
+ * @return Returns UA_STATUSCODE_BADINTERNALERROR if parsing failed. */
+UA_StatusCode
+UA_parseEndpointUrlEthernet(const UA_String *endpointUrl, UA_String *target,
+                            UA_UInt16 *vid, UA_Byte *pcp);
+
+/* Convert given byte string to a positive number. Returns the number of valid
+ * digits. Stops if a non-digit char is found and returns the number of digits
+ * up to that point. */
+size_t
+UA_readNumber(const UA_Byte *buf, size_t buflen, UA_UInt32 *number);
+
+/* Same as UA_ReadNumber but with a base parameter */
+size_t
+UA_readNumberWithBase(const UA_Byte *buf, size_t buflen,
+                      UA_UInt32 *number, UA_Byte base);
+
+#ifndef UA_MIN
+#define UA_MIN(A, B) ((A) > (B) ? (B) : (A))
+#endif
+
+#ifndef UA_MAX
+#define UA_MAX(A, B) ((A) > (B) ? (A) : (B))
+#endif
+
+
+
+
+

Parse RelativePath Expressions

+

Parse a RelativePath according to the format defined in Part 4, A2. This is +used e.g. for the BrowsePath structure. For now, only the standard +ReferenceTypes from Namespace 0 are recognized (see Part 3).

+
+

RelativePath := ( ReferenceType [BrowseName]? )*

+
+

The ReferenceTypes have either of the following formats:

+
    +
  • /: HierarchicalReferences and subtypes

  • +
  • .: Aggregates ReferenceTypesand subtypes

  • +
  • < [!#]* BrowseName >: The ReferenceType is indicated by its BrowseName +(a QualifiedName). Prefixed modifiers can be as follows: ! switches to +inverse References. # excludes subtypes of the ReferenceType.

  • +
+

QualifiedNames consist of an optional NamespaceIndex and the nameitself:

+
+

QualifiedName := ([0-9]+ ":")? Name

+
+

The QualifiedName representation for RelativePaths uses & as the escape +character. Occurences of the characters /.<>:#!& in a QualifiedName have +to be escaped (prefixed with &).

+
+

Example RelativePaths

+
    +
  • /2:Block&.Output

  • +
  • /3:Truck.0:NodeVersion

  • +
  • <0:HasProperty>1:Boiler/1:HeatSensor

  • +
  • <0:HasChild>2:Wheel

  • +
  • <#Aggregates>1:Boiler/

  • +
  • <!HasChild>Truck

  • +
  • <HasChild>

  • +
+
#ifdef UA_ENABLE_PARSING
+UA_StatusCode
+UA_RelativePath_parse(UA_RelativePath *rp, const UA_String str);
+#endif
+
+
+
+
+
+

Convenience macros for complex types

+
#define UA_PRINTF_GUID_FORMAT "%08" PRIx32 "-%04" PRIx16 "-%04" PRIx16 \
+    "-%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8
+#define UA_PRINTF_GUID_DATA(GUID) (GUID).data1, (GUID).data2, (GUID).data3, \
+        (GUID).data4[0], (GUID).data4[1], (GUID).data4[2], (GUID).data4[3], \
+        (GUID).data4[4], (GUID).data4[5], (GUID).data4[6], (GUID).data4[7]
+
+#define UA_PRINTF_STRING_FORMAT "\"%.*s\""
+#define UA_PRINTF_STRING_DATA(STRING) (int)(STRING).length, (STRING).data
+
+
+
+
+

Cryptography Helpers

+
/* Compare memory in constant time to mitigate timing attacks.
+ * Returns true if ptr1 and ptr2 are equal for length bytes. */
+UA_Boolean
+UA_constantTimeEqual(const void *ptr1, const void *ptr2, size_t length);
+
+/* Zero-out memory in a way that is not removed by compiler-optimizations. Use
+ * this to ensure cryptographic secrets don't leave traces after the memory was
+ * freed. */
+void
+UA_ByteString_memZero(UA_ByteString *bs);
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file