Parcourir la source

Merge branch 'master' into inline_setattribute

Conflicts:
	examples/CMakeLists.txt
	include/ua_config.h.in
Julius Pfrommer il y a 9 ans
Parent
commit
3c2869f8a5

+ 3 - 2
.travis.yml

@@ -28,6 +28,7 @@ before_install:
 - sudo dpkg -i liburcu2_0.8.5-1ubuntu1_amd64.deb
 - sudo dpkg -i liburcu-dev_0.8.5-1ubuntu1_amd64.deb
 - sudo pip install cpp-coveralls
+- sudo pip install Pygments
 - sudo pip install sphinx
 - sudo pip install breathe
 - sudo pip install sphinx_rtd_theme
@@ -100,8 +101,8 @@ script:
   fi
 - cd .. 
 after_success:
-- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc") ]]; then ./tools/.deployGH.sh; fi
-- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc") ]]; then ./tools/.coverity.sh; fi
+- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" && ${TRAVIS_BRANCH} == "master") ]]; then ./tools/.deployGH.sh; fi
+- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" && ${TRAVIS_BRANCH} == "master") ]]; then ./tools/.coverity.sh; fi
 before_deploy:
 - rm build -rf && mkdir -p build && cd build
 - echo "Cross compile release build for Raspberry Pi"

+ 77 - 15
CMakeLists.txt

@@ -48,7 +48,7 @@ if(CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang")
     # binary size reduction settings
     add_definitions(-ffunction-sections -fdata-sections -fno-stack-protector -fno-unwind-tables
                     -fno-asynchronous-unwind-tables -fno-math-errno -fmerge-all-constants -fno-ident)
-  if (APPLE)
+  if(APPLE)
       set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-dead_strip")
       set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-dead_strip")
   else()
@@ -56,19 +56,18 @@ if(CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang")
       set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections")
   endif()
   set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # cmake sets -rdynamic by default
-	if(NOT WIN32)
-     if(NOT CYGWIN)
+	if(NOT WIN32 AND NOT CYGWIN)
 	    add_definitions(-fvisibility=hidden -fPIC)
-      if (NOT APPLE)
-          set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,--build-id=none")
-      endif()
+      if(NOT APPLE)
+        # these settings reduce the binary size by ~2kb
+        set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,--build-id=none")
       endif()
 	endif()
     if(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release")
         set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -s")
         set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -s")
     endif()
-    if (APPLE)
+    if(APPLE)
         set(CMAKE_MACOSX_RPATH 1)
         set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_DARWIN_C_SOURCE=1")
     endif()
@@ -91,8 +90,10 @@ set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
                      ${PROJECT_SOURCE_DIR}/examples/logger_stdout.h)
 set(internal_headers ${PROJECT_SOURCE_DIR}/src/ua_util.h
                      ${PROJECT_SOURCE_DIR}/deps/queue.h
-                     ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.h
                      ${PROJECT_SOURCE_DIR}/src/ua_types_encoding_binary.h
+                     ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
+                     ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.h
+                     ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated_encoding_binary.h
                      ${PROJECT_SOURCE_DIR}/src/ua_securechannel.h
                      ${PROJECT_SOURCE_DIR}/src/server/ua_nodes.h
                      ${PROJECT_SOURCE_DIR}/src/ua_session.h
@@ -143,6 +144,7 @@ if(ENABLE_SUBSCRIPTIONS)
 
   add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.c
                             ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h
+                            ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
                      PRE_BUILD
                      COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py --enable-subscription-types=1 --typedescriptions ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv 0 ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_types
                      DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
@@ -151,6 +153,7 @@ if(ENABLE_SUBSCRIPTIONS)
 else()
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.c
                           ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h
+                          ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
                    PRE_BUILD
                    COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py --typedescriptions ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv 0 ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_types
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
@@ -160,6 +163,7 @@ endif()
 
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.c
                           ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.h
+                          ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated_encoding_binary.h
                    PRE_BUILD
                    COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py --ns0-types-xml ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd 1 ${PROJECT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_transport
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
@@ -250,16 +254,12 @@ option(ENABLE_AMALGAMATION "Concatenate the library to a single file open62541.h
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.h
                PRE_BUILD
                COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${GIT_COMMIT_ID} ${CMAKE_CURRENT_BINARY_DIR}/open62541.h ${exported_headers}
-
-
                DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${exported_headers} ${internal_headers})
 
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.c
                PRE_BUILD
-
                COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${GIT_COMMIT_ID} ${CMAKE_CURRENT_BINARY_DIR}/open62541.c
                                             ${internal_headers} ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc ${lib_sources}
-
                DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${internal_headers} ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc ${lib_sources})
 
 if(ENABLE_AMALGAMATION)
@@ -272,16 +272,22 @@ else()
     include_directories(${PROJECT_SOURCE_DIR}/include)
     include_directories(${PROJECT_SOURCE_DIR}/deps)
     include_directories(${PROJECT_SOURCE_DIR}/src)
-    include_directories(${PROJECT_BINARY_DIR}/src_generated)
 endif()
+include_directories(${PROJECT_BINARY_DIR}/src_generated) #needed to locate an include of examples/server_nodeset.c
 target_compile_definitions(open62541-object PRIVATE -DUA_DYNAMIC_LINKING)
+
 add_library(open62541 SHARED $<TARGET_OBJECTS:open62541-object>)
+add_library(open62541-static STATIC $<TARGET_OBJECTS:open62541-object>)
 target_compile_definitions(open62541 PRIVATE -DUA_DYNAMIC_LINKING)
+target_compile_definitions(open62541-static PRIVATE -DUA_DYNAMIC_LINKING)
 if(WIN32)
-    target_link_libraries(open62541 ws2_32) #since networklayer_tcp is linked into the amalgate
+    # since networklayer_tcp is linked into the amalgate
+    target_link_libraries(open62541 ws2_32)
+    target_link_libraries(open62541-static ws2_32)
 endif()
 if(ENABLE_MULTITHREADING)
   target_link_libraries(open62541 urcu-cds urcu urcu-common pthread)
+  target_link_libraries(open62541-static urcu-cds urcu urcu-common pthread)
 endif()
 
 # build language bindings for the library
@@ -377,7 +383,57 @@ endif()
 
 option(BUILD_EXAMPLES "Build example servers and clients" OFF)
 if(BUILD_EXAMPLES)
-    add_subdirectory(examples)
+    #add_subdirectory(examples)
+    #FIXME: we had problem with static linking for msvs, here a quick and dirty workaround
+    #http://stackoverflow.com/questions/3704374/linking-error-lnk2019-in-msvc-unresolved-symbols-with-imp-prefix-but-shoul
+    #http://stackoverflow.com/questions/1089828/same-header-file-for-both-dll-and-static-library
+    if(NOT WIN32)
+		list(APPEND LIBS pthread)
+		if (NOT APPLE)
+		    list(APPEND LIBS rt)
+		endif()
+	else()
+		list(APPEND LIBS ws2_32)
+	endif()
+	if(ENABLE_MULTITHREADING)
+		list(APPEND LIBS urcu-cds urcu urcu-common)
+	endif(ENABLE_MULTITHREADING)
+
+    add_executable(server_variable ${PROJECT_SOURCE_DIR}/examples/server_variable.c $<TARGET_OBJECTS:open62541-object>)
+	target_link_libraries(server_variable ${LIBS})
+
+	add_executable(server_datasource ${PROJECT_SOURCE_DIR}/examples/server_datasource.c $<TARGET_OBJECTS:open62541-object>)
+	target_link_libraries(server_datasource ${LIBS})
+
+	add_executable(server_firstSteps ${PROJECT_SOURCE_DIR}/examples/server_firstSteps.c $<TARGET_OBJECTS:open62541-object>)
+	target_link_libraries(server_firstSteps ${LIBS})
+
+	add_executable(client_firstSteps ${PROJECT_SOURCE_DIR}/examples/client_firstSteps.c $<TARGET_OBJECTS:open62541-object>)
+	target_link_libraries(client_firstSteps ${LIBS})
+
+	add_executable(server_repeated_job ${PROJECT_SOURCE_DIR}/examples/server_repeated_job.c $<TARGET_OBJECTS:open62541-object>)
+	target_link_libraries(server_repeated_job ${LIBS})
+
+	add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/nodeset.h ${PROJECT_BINARY_DIR}/src_generated/nodeset.c
+					   PRE_BUILD
+					   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py -i ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_Blacklist_FullNS0.txt ${PROJECT_SOURCE_DIR}/tools/schema/namespace0/Opc.Ua.NodeSet2.xml ${PROJECT_SOURCE_DIR}/examples/server_nodeset.xml ${PROJECT_BINARY_DIR}/src_generated/nodeset
+					   DEPENDS ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py
+					           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/logger.py
+					           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/open62541_MacroHelper.py
+					           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_builtin_types.py
+					           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_constants.py
+					           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_namespace.py
+					           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_node_types.py
+					           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_Blacklist_FullNS0.txt
+					           ${PROJECT_SOURCE_DIR}/examples/server_nodeset.xml)
+					   
+	add_executable(server_nodeset ${PROJECT_SOURCE_DIR}/examples/server_nodeset.c ${PROJECT_BINARY_DIR}/src_generated/nodeset.c $<TARGET_OBJECTS:open62541-object>)
+	target_link_libraries(server_nodeset ${LIBS})
+
+	if(ENABLE_METHODCALLS)
+	  add_executable(server_method ${PROJECT_SOURCE_DIR}/examples/server_method.c $<TARGET_OBJECTS:open62541-object>)
+	  target_link_libraries(server_method ${LIBS})
+	endif()
 endif()
 
 # build documentation
@@ -391,9 +447,15 @@ if(BUILD_DOCUMENTATION)
                       ${DOXYGEN_EXECUTABLE} ${PROJECT_BINARY_DIR}/Doxyfile
                       WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
                       COMMENT "Generating API documentation with Doxygen")
+    add_custom_target(latex ${SPHINX_EXECUTABLE}
+      -b latex -c "${PROJECT_BINARY_DIR}"
+      "${PROJECT_SOURCE_DIR}/doc" "${PROJECT_BINARY_DIR}/doc/sphinx"
+      DEPENDS doxygen
+      COMMENT "Building LaTeX sources for documentation with Sphinx")
     add_custom_target(doc ${SPHINX_EXECUTABLE}
       -b html -c "${PROJECT_BINARY_DIR}"
       "${PROJECT_SOURCE_DIR}/doc" "${PROJECT_BINARY_DIR}/doc/sphinx"
+      COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/doc/open62541_html.png" "${PROJECT_BINARY_DIR}/doc/sphinx/_static/"
       DEPENDS doxygen
       COMMENT "Building HTML documentation with Sphinx")
 endif()

+ 1 - 1
README.md

@@ -26,7 +26,7 @@ Automatically compiled MSVC binaries are available [here](https://ci.appveyor.co
 ### Contribute to open62541
 As an open source project, we invite new contributors to help improving open62541. If you are a developer, your bugfixes and new features are very welcome. Note that there are ways to contribute even without deep knowledge of the project or the UA standard:
 - [Report bugs](https://github.com/acplt/open62541/issues)
-- Improve the [documentation](http://open62541.org/doc)
+- Improve the [documentation for 0.1](http://open62541.org/doc) and [documentation for 0.2](http://open62541.org/doc/sphinx)
 - Work on issues marked as "[easy hacks](https://github.com/acplt/open62541/labels/easy%20hack)"
 
 ### Example Server Implementation

+ 3 - 3
appveyor.yml

@@ -7,14 +7,14 @@ build_script:
 - cd c:\projects\open62541
 - md build
 - cd build
-- cmake -DBUILD_EXAMPLESERVER:BOOL=ON -DBUILD_EXAMPLECLIENT:BOOL=ON -G"Visual Studio 12 2013" ..
+- cmake -DBUILD_EXAMPLESERVER:BOOL=ON -DBUILD_EXAMPLECLIENT:BOOL=ON -DBUILD_EXAMPLES:BOOL=ON -G"Visual Studio 12 2013" ..
 - msbuild open62541.sln
 - echo "Testing amalgamation"
 - cd ..
 - rd /s /q build
 - md build
 - cd build
-- cmake -DBUILD_EXAMPLESERVER:BOOL=ON -DBUILD_EXAMPLECLIENT:BOOL=ON -DENABLE_AMALGAMATION:BOOL=ON -G"Visual Studio 12 2013" ..
+- cmake -DBUILD_EXAMPLESERVER:BOOL=ON -DBUILD_EXAMPLECLIENT:BOOL=ON -DBUILD_EXAMPLES:BOOL=ON -DENABLE_AMALGAMATION:BOOL=ON -G"Visual Studio 12 2013" ..
 - msbuild open62541.sln 
 - cp C:\projects\open62541\build\open62541.c C:\projects\open62541\build\Debug\open62541.c
 - cp C:\projects\open62541\build\open62541.h C:\projects\open62541\build\Debug\open62541.h
@@ -22,7 +22,7 @@ build_script:
 - echo "Win 64 build"
 - md build64
 - cd build64
-- cmake -DBUILD_EXAMPLESERVER:BOOL=ON -DBUILD_EXAMPLECLIENT:BOOL=ON -DENABLE_AMALGAMATION:BOOL=ON -G"Visual Studio 12 2013 Win64" ..
+- cmake -DBUILD_EXAMPLESERVER:BOOL=ON -DBUILD_EXAMPLECLIENT:BOOL=ON -DBUILD_EXAMPLES:BOOL=ON -DENABLE_AMALGAMATION:BOOL=ON -G"Visual Studio 12 2013 Win64" ..
 - msbuild open62541.sln 
 - cp C:\projects\open62541\build64\open62541.c C:\projects\open62541\build64\Debug\open62541.c
 - cp C:\projects\open62541\build64\open62541.h C:\projects\open62541\build64\Debug\open62541.h

+ 4 - 4
doc/conf.py

@@ -131,7 +131,7 @@ html_theme = 'sphinx_rtd_theme'
 
 # The name of an image file (relative to this directory) to place at the top
 # of the sidebar.
-#html_logo = None
+html_logo = "doc/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
@@ -204,13 +204,13 @@ html_static_path = ['_static']
 #html_search_scorer = 'scorer.js'
 
 # Output file base name for HTML help builder.
-htmlhelp_basename = 'open62541doc'
+htmlhelp_basename = 'doc/open62541doc'
 
 # -- Options for LaTeX output ---------------------------------------------
 
 latex_elements = {
 # The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
+'papersize': 'a4paper',
 
 # The font size ('10pt', '11pt' or '12pt').
 #'pointsize': '10pt',
@@ -232,7 +232,7 @@ latex_documents = [
 
 # The name of an image file (relative to this directory) to place at the top of
 # the title page.
-#latex_logo = None
+latex_logo = "doc/open62541.png"
 
 # For "manual" documents, if this is true, then toplevel headings are parts,
 # not chapters.

+ 107 - 0
doc/in_a_nutshell.rst

@@ -0,0 +1,107 @@
+OPC UA in a nutshell
+====================
+
+OPC UA, a collection of services
+--------------------------------
+
+In OPC-UA, all communication is based on service calls, each consisting of a request and a response
+message. Be careful to note the difference between services and methods. Services are pre-defined in
+the standard and cannot be changed. But you can use the *Call* service to invoke user-defined
+methods on the server.
+
+For completeness, the following tables contain all services defined in the standard. Do not bother
+with their details yet. We will introduce the different services later in the text. In open62541,
+each service is implemented in a single function. See the \ref services section for details.
+
+**Establishing communication**
+
++-----------------------------+-----------------------------+------------------------------+
+| Discovery Service Set       | SecureChannel Service Set   | Session Service Set          |
++=============================+=============================+==============================+
+| FindServers                 | OpenSecureChannel           | CreateSession                |
++-----------------------------+-----------------------------+------------------------------+
+| GetEndpoints                | CloseSecureChannel          | ActivateSession              |
++-----------------------------+-----------------------------+------------------------------+
+| RegisterServer              | CloseSession                |                              |
++-----------------------------+-----------------------------+------------------------------+
+| Cancel                      |                             |                              |
++-----------------------------+-----------------------------+------------------------------+
+
+**Interaction with the information model**
+
++-----------------------------+-------------------------------+------------------------------+------------------------------+----------------------+
+| Attribute Service Set       | View Service Set              | Method Service Set           | NodeManagement Service Set   | Query Service Set    |
++=============================+===============================+==============================+==============================+======================+
+| Read                        | Browse                        | Call                         | AddNodes                     | QueryFirst           |
++-----------------------------+-------------------------------+------------------------------+------------------------------+----------------------+
+| HistoryRead                 | BrowseNext                    |                              | AddReferences                | QueryNext            |
++-----------------------------+-------------------------------+------------------------------+------------------------------+----------------------+
+| Write                       | TranslateBrowsePathsToNodeids |                              | DeleteNodes                  |                      |
++-----------------------------+-------------------------------+------------------------------+------------------------------+----------------------+
+| HistoryUpdate               | RegisterNodes                 |                              | DeleteReferences             |                      |
++-----------------------------+-------------------------------+------------------------------+------------------------------+----------------------+
+|                             | UnregisterNodes               |                              |                              |                      |
++-----------------------------+-------------------------------+------------------------------+------------------------------+----------------------+
+
+**Notifications**
+
++-----------------------------+-------------------------------+
+| MonitoredItem Service Set   | Subscription Service Set      |
++=============================+===============================+
+| CreateMonitoredItems        | CreateSubscription            |
++-----------------------------+-------------------------------+
+| ModifyMonitoreditems        | ModifySubscription            |
++-----------------------------+-------------------------------+
+| SetMonitoringMode           | SetPublishingMode             |
++-----------------------------+-------------------------------+
+| SetTriggering               | Publish                       |
++-----------------------------+-------------------------------+
+| DeleteMonitoredItems        | Republish                     |
++-----------------------------+-------------------------------+
+|                             | TransferSubscription          |
++-----------------------------+-------------------------------+
+|                             | DeleteSubscription            |
++-----------------------------+-------------------------------+
+
+OPC UA, a web of nodes
+----------------------
+
+The information model in each OPC UA server is a web of interconnected nodes.
+There are eight different types of nodes. Depending on its type, every node
+contains different attributes. Some attributes, such as the *NodeId* (unique
+identifier) and the *BrowseName*, are contained in all node types.
+
++-----------------------+-------------------+
+| ReferenceTypeNode     | MethodNode        |
++-----------------------+-------------------+
+| DataTypeNode          | ObjectTypeNode    |
++-----------------------+-------------------+
+| VariableTypeNode      | ObjectNode        |
++-----------------------+-------------------+
+| VariableNode          | ViewNode          |
++-----------------------+-------------------+
+                                                                                                            
+Nodes are interconnected by directed reference-triples of the form ``(nodeid,
+referencetype, target-nodeid)``. Therefore an OPC UA information model is
+easiest imagined as a *web of nodes*. Reference types can be
+
+- standard- or user-defined and
+- either non-hierarchical (e.g., indicating the type of a variable-node) or
+  hierarchical (e.g., indicating a parent-child relationship).
+
+OPC UA, a protocol
+------------------
+
+The OPC UA protocol (both binary and XML-based) is based on 25 *built-in*
+datatypes. In open62541, these are defined in ua_types.h.
+
+The builtin datatypes are combined to more complex structures. When the structure contains an array,
+then the size of the array is stored in an Int32 value just before the array itself. A size of -1
+indicates an undefined array. Positive sizes (and zero) have the usual semantics.
+
+Most importantly, every service has a request and a response message defined as such a data
+structure. The entire OPC UA protocol revolves around the exchange of these request and response
+messages. Their exact definitions can be looked up here:
+https://opcfoundation.org/UA/schemas/Opc.Ua.Types.bsd.xml. In open62541, we autogenerate the
+C-structs to handle the standard-defined structures automatically. See ua_types_generated.h for
+comparison.

+ 7 - 111
doc/index.rst

@@ -1,14 +1,6 @@
 Welcome to open62541's documentation!
 =====================================
 
-.. toctree::
-   :maxdepth: 3
-   :hidden:
-
-   building
-   datatypes
-   tutorials
-
 `OPC UA <http://en.wikipedia.org/wiki/OPC_Unified_Architecture>`_ (short for OPC
 Unified Architecture) is a protocol for industrial communication and has been
 standardized in the IEC62541. At its core, OPC UA defines a set of services to
@@ -25,111 +17,15 @@ understanding, we go on explaining how these principles are realized in detail.
 Examples are given based on the *open62541* implementation of the
 standard.
 
-OPC UA, a collection of services
---------------------------------
-
-In OPC-UA, all communication is based on service calls, each consisting of a request and a response
-message. Be careful to note the difference between services and methods. Services are pre-defined in
-the standard and cannot be changed. But you can use the *Call* service to invoke user-defined
-methods on the server.
-
-For completeness, the following tables contain all services defined in the standard. Do not bother
-with their details yet. We will introduce the different services later in the text. In open62541,
-each service is implemented in a single function. See the \ref services section for details.
-
-**Establishing communication**
-
-+-----------------------------+-----------------------------+------------------------------+
-| Discovery Service Set       | SecureChannel Service Set   | Session Service Set          |
-+=============================+=============================+==============================+
-| FindServers                 | OpenSecureChannel           | CreateSession                |
-+-----------------------------+-----------------------------+------------------------------+
-| GetEndpoints                | CloseSecureChannel          | ActivateSession              |
-+-----------------------------+-----------------------------+------------------------------+
-| RegisterServer              | CloseSession                |                              |
-+-----------------------------+-----------------------------+------------------------------+
-| Cancel                      |                             |                              |
-+-----------------------------+-----------------------------+------------------------------+
-
-**Interaction with the information model**
-
-+-----------------------------+-------------------------------+------------------------------+------------------------------+----------------------+
-| Attribute Service Set       | View Service Set              | Method Service Set           | NodeManagement Service Set   | Query Service Set    |
-+=============================+===============================+==============================+==============================+======================+
-| Read                        | Browse                        | Call                         | AddNodes                     | QueryFirst           |
-+-----------------------------+-------------------------------+------------------------------+------------------------------+----------------------+
-| HistoryRead                 | BrowseNext                    |                              | AddReferences                | QueryNext            |
-+-----------------------------+-------------------------------+------------------------------+------------------------------+----------------------+
-| Write                       | TranslateBrowsePathsToNodeids |                              | DeleteNodes                  |                      |
-+-----------------------------+-------------------------------+------------------------------+------------------------------+----------------------+
-| HistoryUpdate               | RegisterNodes                 |                              | DeleteReferences             |                      |
-+-----------------------------+-------------------------------+------------------------------+------------------------------+----------------------+
-|                             | UnregisterNodes               |                              |                              |                      |
-+-----------------------------+-------------------------------+------------------------------+------------------------------+----------------------+
-
-**Notifications**
-
-+-----------------------------+-------------------------------+
-| MonitoredItem Service Set   | Subscription Service Set      |
-+=============================+===============================+
-| CreateMonitoredItems        | CreateSubscription            |
-+-----------------------------+-------------------------------+
-| ModifyMonitoreditems        | ModifySubscription            |
-+-----------------------------+-------------------------------+
-| SetMonitoringMode           | SetPublishingMode             |
-+-----------------------------+-------------------------------+
-| SetTriggering               | Publish                       |
-+-----------------------------+-------------------------------+
-| DeleteMonitoredItems        | Republish                     |
-+-----------------------------+-------------------------------+
-|                             | TransferSubscription          |
-+-----------------------------+-------------------------------+
-|                             | DeleteSubscription            |
-+-----------------------------+-------------------------------+
-
-OPC UA, a web of nodes
-----------------------
-
-The information model in each OPC UA server is a web of interconnected nodes.
-There are eight different types of nodes. Depending on its type, every node
-contains different attributes. Some attributes, such as the *NodeId* (unique
-identifier) and the *BrowseName*, are contained in all node types.
-
-+-----------------------+-------------------+
-| ReferenceTypeNode     | MethodNode        |
-+-----------------------+-------------------+
-| DataTypeNode          | ObjectTypeNode    |
-+-----------------------+-------------------+
-| VariableTypeNode      | ObjectNode        |
-+-----------------------+-------------------+
-| VariableNode          | ViewNode          |
-+-----------------------+-------------------+
-                                                                                                            
-Nodes are interconnected by directed reference-triples of the form ``(nodeid,
-referencetype, target-nodeid)``. Therefore an OPC UA information model is
-easiest imagined as a *web of nodes*. Reference types can be
-
-- standard- or user-defined and
-- either non-hierarchical (e.g., indicating the type of a variable-node) or
-  hierarchical (e.g., indicating a parent-child relationship).
-
-OPC UA, a protocol
-------------------
-
-The OPC UA protocol (both binary and XML-based) is based on 25 *built-in*
-datatypes. In open62541, these are defined in ua_types.h.
-
-The builtin datatypes are combined to more complex structures. When the structure contains an array,
-then the size of the array is stored in an Int32 value just before the array itself. A size of -1
-indicates an undefined array. Positive sizes (and zero) have the usual semantics.
+.. toctree::
+   :maxdepth: 3
 
-Most importantly, every service has a request and a response message defined as such a data
-structure. The entire OPC UA protocol revolves around the exchange of these request and response
-messages. Their exact definitions can be looked up here:
-https://opcfoundation.org/UA/schemas/Opc.Ua.Types.bsd.xml. In open62541, we autogenerate the
-C-structs to handle the standard-defined structures automatically. See ua_types_generated.h for
-comparison.
+   in_a_nutshell
+   building
+   tutorials
+   datatypes
 
+   
 Indices and tables
 ==================
 

BIN
doc/open62541.png


BIN
doc/open62541_html.png


+ 38 - 78
doc/tutorial_firstStepsClient.rst

@@ -1,9 +1,7 @@
 First steps with open62541-client
-===================================
+=================================
 
-In the previous :doc:`tutorial_firstStepsServer` tutorial, you should have gotten your build environment verified and created a first OPC UA server using the open62541 stack. The created server however doesn't do much yet and there is no client to interact with the server. We are going to remedy that in this tutorial by creating some nodes and variables.
-
-----------------------
+In the previous :doc:`tutorial_server_firstSteps` tutorial, you should have gotten your build environment verified and created a first OPC UA server using the open62541 stack. The created server however doesn't do much yet and there is no client to interact with the server. We are going to remedy that in this tutorial by creating some nodes and variables.
 
 You should already have a basic server from the previous tutorial. open62541 provides both a server- and clientside API, so creating a client is equally as easy as creating a server. We are going to use dynamic linking (libopen62541.so) from now on, because our client and server will share a lot of code. Reusing the shared library will considerably reduce the overhead. To avoid confusion, remove the amalgated open62541.c/h files from your example directory.
 
@@ -13,29 +11,31 @@ As a recap, your directory structure should now look like this::
   :myApp> ln -s ../open62541/build/*so ./
   :myApp> tree
   .
-  ── include
-  │   ── logger_stdout.h
-  │   ── networklayer_tcp.h
-  │   ── networklayer_udp.h
-  │   ── open62541.h
-  │   ── ua_client.h
-  │   ── ua_config.h
-  │   ── ua_config.h.in
-  │   ── ua_connection.h
-  │   ── ua_log.h
-  │   ── ua_nodeids.h
-  │   ── ua_server.h
-  │   ── ua_statuscodes.h
-  │   ── ua_transport_generated.h
-  │   ── ua_types_generated.h
-  │   ── ua_types.h
-  ── libopen62541.so -> ../../open62541/build/libopen62541.so
-  ── myServer
-  ── myServer.c
+  +── include
+  │   +── logger_stdout.h
+  │   +── networklayer_tcp.h
+  │   +── networklayer_udp.h
+  │   +── open62541.h
+  │   +── ua_client.h
+  │   +── ua_config.h
+  │   +── ua_config.h.in
+  │   +── ua_connection.h
+  │   +── ua_log.h
+  │   +── ua_nodeids.h
+  │   +── ua_server.h
+  │   +── ua_statuscodes.h
+  │   +── ua_transport_generated.h
+  │   +── ua_types_generated.h
+  │   +── ua_types.h
+  +── libopen62541.so -> ../../open62541/build/libopen62541.so
+  +── myServer
+  +── myServer.c
 
 Note that I have linked the library into the folder to spare me the trouble of copying it every time I change/rebuild the stack.
 
-To create a really basic client, navigate back into the myApp folder from the previous tutorial and create a client::
+To create a really basic client, navigate back into the myApp folder from the previous tutorial and create a client:
+
+.. code-block:: c
 
     #include <stdio.h>
 
@@ -61,53 +61,6 @@ Let's recompile both server and client - if you feel up to it, you can create a
 
     :myApp> gcc -Wl,-rpath=./ -L./ -I ./include -o myClient myClient.c  -lopen62541
 
-We will also make a slight change to our server: We want it to exit cleanly when pressing ``CTRL+C``. We will add signal handler for SIGINT and SIGTERM to accomplish that to the server::
-
-    #include <stdio.h>
-    #include <signal.h>
-
-    # include "ua_types.h"
-    # include "ua_server.h"
-    # include "logger_stdout.h"
-    # include "networklayer_tcp.h"
-
-    UA_Boolean running;
-    UA_Logger logger;
-
-    void stopHandler(int signal) {
-      running = 0;
-    }
-
-    int main(void) {
-      signal(SIGINT,  stopHandler);
-      signal(SIGTERM, stopHandler);
-      
-      UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
-      logger = Logger_Stdout_new();
-      UA_Server_setLogger(server, logger);
-      UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
-      running = UA_TRUE;
-      UA_Server_run(server, 1, &running);
-      UA_Server_delete(server);
-      
-      printf("Terminated\n");
-      return 0;
-    }
-And then of course, recompile it::
-
-    :myApp> gcc -Wl,-rpath=./ -L./ -I ./include -o myServer myServer.c  -lopen62541
-
-You can now start and background the server, run the client, and then terminate the server like so::
-
-    :myApp> ./myServer &
-    [xx/yy/zz aa:bb:cc.dd.ee] info/communication	Listening on opc.tcp://localhost:16664
-    [1] 2114
-    :myApp> ./myClient && killall myServer
-    Terminated
-    [1]+  Done                    ./myServer
-    :myApp> 
-
-Notice how the server received the SIGTERM signal from kill and exited cleany? We also used the return value of our client by inserting the ``&&``, so kill is only called after a clean client exit (``return 0``).
 
 Asserting success/failure
 -------------------------
@@ -115,7 +68,8 @@ Asserting success/failure
 Almost all functions of the open62541 API will return a ``UA_StatusCode``, which in the C world would be represented by a ``unsigned int``. OPC UA defines large number of good and bad return codes represented by this number. The constant UA_STATUSCODE_GOOD is defined as 0 in ``include/ua_statuscodes.h`` along with many other return codes. It pays off to check the return code of your function calls, as we already did implicitly in the client.
 
 Minimalistic introduction to OPC UA nodes and node IDs
------------------------
+------------------------------------------------------
+
 OPC UA nodespace model defines 9 standard attribute for every node:
 
 +---------------+----------------+
@@ -166,7 +120,9 @@ Reading variable's node value
 
 In this example we are going to read node (n=0,i=2258), i.e. a node in namespace 0 with a numerical id 2258. This node is present in every server (since it is located in namespace 0) and contains server current time (encoded as UInt64).
 
-Let us extend the client with with an action reading node's value::
+Let us extend the client with with an action reading node's value:
+
+.. code-block:: c
 
     #include <stdio.h>
 
@@ -199,7 +155,7 @@ Let us extend the client with with an action reading node's value::
          UA_Variant_isScalar(&rResp.results[0].value) &&
          rResp.results[0].value.type == &UA_TYPES[UA_TYPES_DATETIME]) {
              raw_date = *(UA_DateTime*)rResp.results[0].value.data;
-             printf("raw date is: %llu\n", raw_date);
+             printf("raw date is: %" PRId64 "\n", raw_date);
       }
       
       UA_ReadRequest_deleteMembers(&rReq);
@@ -214,10 +170,12 @@ You should see raw time in milliseconds since January 1, 1601 UTC midnight::
 
     :myApp> ./myClient
     :myApp> raw date is: 130856974061125520
-    
+
 Firstly we constructed a read request "rReq", it contains 1 node's attribute we want to query for. The attribute is filled with the numeric id "UA_NODEID_NUMERIC(0, 2258)" and the attribute we are reading "UA_ATTRIBUTEID_VALUE". After the read request was sent, we can find the actual read value in the read response.
 
-As the last step for this tutorial, we are going to convert the raw date value into a well formatted string::
+As the last step for this tutorial, we are going to convert the raw date value into a well formatted string:
+
+.. code-block:: c
 
     #include <stdio.h>
     
@@ -264,6 +222,8 @@ As the last step for this tutorial, we are going to convert the raw date value i
       UA_Client_delete(client);
       return 0;
     }
+
+Note that this file can be found as "examples/client_firstSteps.c" in the repository.
     
 Now you should see raw time and a formatted date::
 
@@ -274,5 +234,5 @@ Now you should see raw time and a formatted date::
 Further tasks
 -------------
 * Try to connect to some other OPC UA server by changing "opc.tcp://localhost:16664" to an appropriate address (remember that the queried node is contained in any OPC UA server).
-* Display the value of the variable node (ns=1,i="the.answer") containing an "Int32" from the example server (which is built in :doc:`tutorial_firstStepsServer`). Note that the identifier of this node is a string type: use "UA_NODEID_STRING_ALLOC". The answer can be found in "examples/exampleClient.c".
-* 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_firstStepsServer`) using "UA_Client_write" function. The example server needs some more modifications, i.e., changing request types. The answer can be found in "examples/exampleClient.c".
+* Display 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`). Note that the identifier of this node is a string type: use "UA_NODEID_STRING_ALLOC". The answer can be found in "examples/exampleClient.c".
+* 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/exampleClient.c".

+ 23 - 13
doc/tutorial_noderelations.rst

@@ -1,7 +1,7 @@
 Examining and interacting with node relations
 =============================================
 
-In the past tutorials you learned to compile the stack in various configurations, create/delete nodes and manage variables. The core of OPC UA are it's data modelling capabilities, and you will invariably find yourself confronted to investigate these relations during runtime. This tutorial will show you how to interact with object and types hierarchies and how to create your own.
+In the past tutorials you have learned to compile the stack in various configurations, create/delete nodes and manage variables. The core of OPC UA is its data modelling capabilities, and you will invariably find yourself confronted to investigate these relations during runtime. This tutorial will show you how to interact with object and type hierarchies and how to create your own.
 
 Compile XML Namespaces
 ----------------------
@@ -10,7 +10,9 @@ So far we have made due with the hardcoded mini-namespace in the server stack. W
 
 Note beforehand that the pyUANamespace compiler you can find in the *tools* subfolder is *not* a XML transformation tool but a compiler. That means that it will create an internal representation (dAST) when parsing the XML files and attempt to understand this representation in order to generate C Code. In consequence, the compiler will refuse to print any inconsistencies or invalid nodes.
 
-As an example, we will create a simple object model using UA Modeller and embed this into the servers nodeset, which is exported to the following XML file::
+As an example, we will create a simple object model using UA Modeller and embed this into the servers nodeset, which is exported to the following XML file:
+
+.. code-block:: xml
 
     <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>
@@ -282,7 +284,9 @@ And at this point, you are going to see the compiler hanging again. If you speci
   Linking C shared library libopen62541.so
   [100%] Built target open62541
 
-If you open the header ``src_generated/ua_namespaceinit_generated.h`` and take a short look at the generated defines, you will notice the following definitions have been created::
+If you open the header ``src_generated/ua_namespaceinit_generated.h`` and take a short look at the generated defines, you will notice the following definitions have been created:
+
+.. code-block:: c
   
   #define UA_NS1ID_PROVIDESINPUTTO
   #define UA_NS1ID_FIELDDEVICE
@@ -310,16 +314,18 @@ A minor list of some of the miriad things that can go wrong:
 Creating object instances
 -------------------------
 
-Defining an object type is only usefull if it ends up making our lives easier in some way (though it is always the proper thing to do). One of the key benefits of defining object types is being able to create object instances fairly easily. As an example, we will modify the server to create 2 pump instances::
+Defining an object type is only usefull if it ends up making our lives easier in some way (though it is always the proper thing to do). One of the key benefits of defining object types is being able to create object instances fairly easily. As an example, we will modify the server to create 2 pump instances:
+
+.. code-block:: c
 
     #include <stdio.h>
     #include <signal.h>
 
-    # include "ua_types.h"
-    # include "ua_server.h"
-    # include "ua_namespaceinit_generated.h"
-    # include "logger_stdout.h"
-    # include "networklayer_tcp.h"
+    #include "ua_types.h"
+    #include "ua_server.h"
+    #include "ua_namespaceinit_generated.h"
+    #include "logger_stdout.h"
+    #include "networklayer_tcp.h"
 
     UA_Boolean running;
     UA_Int32 global_accessCounter = 0;
@@ -418,7 +424,9 @@ Iterating over Child nodes
 
 A common usecase is wanting to perform something akin to ``for each node referenced by X, call ...``; you may for example be searching for a specific browseName or instance which was created with a dynamic nodeId. There is no way of telling what you are searching for beforehand (inverse hasComponents, typedefinitions, etc.), but all usescases of "searching for" basically means iterating over each reference of a node.
 
-Since searching in nodes is a common operation, the high-level branch provides a function to help you perform this operation:  ``UA_(Server|Client)_forEachChildNodeCall();``. These functions will iterate over all references of a given node, invoking a callback (with a handle) for every found reference. Since in our last tutorial we created a server that instantiates two pumps, we are now going to build a client that will search for pumps in all object instances on the server.::
+Since searching in nodes is a common operation, the high-level branch provides a function to help you perform this operation:  ``UA_(Server|Client)_forEachChildNodeCall();``. These functions will iterate over all references of a given node, invoking a callback (with a handle) for every found reference. Since in our last tutorial we created a server that instantiates two pumps, we are now going to build a client that will search for pumps in all object instances on the server.
+
+.. code-block:: c
 
     #include <stdio.h>
 
@@ -502,16 +510,18 @@ You can use the handle to contain a pointer to a struct, which can hold multiple
 Examining node copies
 ---------------------
 
-So far we have always used the getAttribute() functions to inspect node contents. There may be isolated cases where these are insuficient because you want to examine the properties of a node "in bulk". As mentioned in the first tutorials, the user can not directly interact with the servers nodestore; but the userspace may request a copy of a node, including all its attributes and references. The following functions server the purpose of getting and getting rid of node copies::
+So far we have always used the getAttribute() functions to inspect node contents. There may be isolated cases where these are insuficient because you want to examine the properties of a node "in bulk". As mentioned in the first tutorials, the user can not directly interact with the servers nodestore; but the userspace may request a copy of a node, including all its attributes and references. The following functions server the purpose of getting and getting rid of node copies.
+
+.. code-block:: c
   
     UA_(Server|Client)_getNodeCopy()
     UA_(Server|Client)_destroyNodeCopy()
 
-
 Since you are trying to see a struct (node types) that are usually hidden from userspace, you will have to include ``include/ua_nodes.h``, ``src/ua_types_encoding_binary.h`` and ``deps/queue.h`` in addition to the previous includes (link them into the includes folder).
 
-Let's suppose we wanted to do something elaborate with our pump instance that was returned by the iterator of the previous example, or simply "print" all its fields. We could modify the above client's main function like so::
+Let's suppose we wanted to do something elaborate with our pump instance that was returned by the iterator of the previous example, or simply "print" all its fields. We could modify the above client's main function like so:
 
+.. code-block:: c
 
     int main(void) {
       UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout_new());

+ 60 - 4
doc/tutorial_firstStepsServer.rst

@@ -124,7 +124,9 @@ Let's build a very rudimentary server. Create a separate folder for your applica
    `-- myServer.c
    :myServerApp> touch myServer.c
 
-Open myServer.c and write/paste your minimal server application::
+Open myServer.c and write/paste your minimal server application:
+
+.. code-block:: c
 
    #include <stdio.h>
 
@@ -156,6 +158,59 @@ Now execute the server::
 
 You have now compiled and started your first OPC UA Server. Though quite unspectacular and only terminatable with ``CTRL+C`` (SIGTERM) at the moment, you can already launch it and browse around with UA Expert. The Server will be listening on localhost:16664 - go ahead and give it a try.
 
+We will also make a slight change to our server: We want it to exit cleanly when pressing ``CTRL+C``. We will add signal handler for SIGINT and SIGTERM to accomplish that to the server:
+
+.. code-block:: c
+
+    #include <stdio.h>
+    #include <signal.h>
+
+    #include "ua_types.h"
+    #include "ua_server.h"
+    #include "logger_stdout.h"
+    #include "networklayer_tcp.h"
+
+    UA_Boolean running;
+    UA_Logger logger;
+
+    static void stopHandler(int signal) {
+      running = UA_FALSE;
+    }
+
+    int main(void) {
+      signal(SIGINT,  stopHandler);
+      signal(SIGTERM, stopHandler);
+      
+      UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
+      logger = Logger_Stdout_new();
+      UA_Server_setLogger(server, logger);
+      UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+      running = UA_TRUE;
+      UA_Server_run(server, 1, &running);
+      UA_Server_delete(server);
+      
+      printf("Terminated\n");
+      return 0;
+    }
+
+Note that this file can be found as "examples/server_firstSteps.c" in the repository.
+    
+And then of course, recompile it::
+
+    :myApp> gcc -Wl,-rpath=./ -L./ -I ./include -o myServer myServer.c  -lopen62541
+
+You can now start and background the server, run the client, and then terminate the server like so::
+
+    :myApp> ./myServer &
+    [xx/yy/zz aa:bb:cc.dd.ee] info/communication	Listening on opc.tcp://localhost:16664
+    [1] 2114
+    :myApp> ./myClient && killall myServer
+    Terminated
+    [1]+  Done                    ./myServer
+    :myApp> 
+
+Notice how the server received the SIGTERM signal from kill and exited cleany? We also used the return value of our client by inserting the ``&&``, so kill is only called after a clean client exit (``return 0``).
+
 Introduction to Configuration options (Amalgamation)
 ----------------------------------------------------
 
@@ -205,11 +260,12 @@ You can now start the server and browse around as before. As you might have noti
 
 The next step is to simplify the header dependencies. Instead of picking header files one-by-one, we can use the copied amalgamated header including all the public headers dependencies.
 
-Open myServer.c and simplify it to::
+Open myServer.c and simplify it to:
 
-   #include <stdio.h>
+.. code-block:: c
 
-   # include "open62541.h"
+   #include <stdio.h>
+   #include "open62541.h"
 
    UA_Boolean running;
    int main(void) {

+ 8 - 0
doc/tutorial_server_method.rst

@@ -0,0 +1,8 @@
+Adding server-side methods
+======================
+
+This tutorial demonstrates how to add method nodes to the server.
+
+Consider 'examples/server_method.c' in the repository. The examples are compiled if the Cmake option BUILD_EXAMPLE is turned on.
+
+Use an UA client, e.g., UaExpert to call the method (right-click on the method node -> call).

+ 59 - 0
doc/tutorial_server_variables.rst

@@ -0,0 +1,59 @@
+Adding nodes to a server and connecting nodes to user-defined values
+====================================================================
+
+This tutorial shows how to add variable nodes to a server and how these can be connected to user-defined values and callbacks.
+
+Firstly, we need to introduce a concept of Variants. This is a data structure able to hold any datatype.
+
+Variants
+--------
+The datatype UA_Variant a belongs to the built-in datatypes of OPC UA and is used as a container type. A Variant can hold any other built-in scalar datatype (except Variants) or array built-in datatype (array of variants too). The variant is structured like this in open62541:
+
+.. code-block:: c
+
+	typedef struct {
+		const UA_DataType *type; ///< The nodeid of the datatype
+		enum {
+		    UA_VARIANT_DATA, ///< The data is "owned" by this variant (copied and deleted together)
+		    UA_VARIANT_DATA_NODELETE, /**< The data is "borrowed" by the variant and shall not be
+		                                   deleted at the end of this variant's lifecycle. It is not
+		                                   possible to overwrite borrowed data due to concurrent access.
+		                                   Use a custom datasource with a mutex. */
+		} storageType; ///< Shall the data be deleted together with the variant
+		UA_Int32  arrayLength;  ///< the number of elements in the data-pointer
+		void     *data; ///< points to the scalar or array data
+		UA_Int32  arrayDimensionsSize; ///< the number of dimensions the data-array has
+		UA_Int32 *arrayDimensions; ///< the length of each dimension of the data-array
+	} UA_Variant;
+
+The members of the struct are
+
+* type: a pointer to the vtable entry. It points onto the functions which handles the stored data i.e. encode/decode etc.
+
+* storageType:  used to declare who the owner of data is and to which lifecycle it belongs. Three different cases are possible:
+
+ * UA_VARIANT_DATA: this is the simplest case. The data belongs to the variant, which means if the variant is deleted so does the data which is kept inside
+ 
+ * UA_VARIANT_DATASOURCE: in this case user-defined functions are called to access the data. The signature of the functions is defined by UA_VariantDataSource structure. A use-case could be to access a sensor only when the data is asked by some client
+
+* arrayLength: length of the array (-1 if a scalar is saved)
+
+* data: raw pointer to the saved vale or callback
+
+* arrayDimensionsSize: size of arrayDimensions array
+
+* arrayDimensions: dimensinos array in case the array is interpreted as a multi-dimensional construction, e.g., [5,5] for a 5x5 matrix
+
+Adding a variable node to the server that contains a user-defined variable
+--------------------------------------------------------------------------
+
+This simple case allows to 'inject' a pre-defined variable into a variable node. The variable is wrapped by a "UA_Variant" before being insterted into the node.
+
+Consider 'examples/server_variable.c' in the repository. The examples are compiled if the Cmake option BUILD_EXAMPLE is turned on.
+
+Adding a variable node to the server that contains a user-defined callback
+--------------------------------------------------------------------------
+
+The latter case allows to define callback functions that are executed on read or write of the node. In this case an "UA_DataSource" containing the respective callback pointer is intserted into the node.
+
+Consider 'examples/server_datasource.c' in the repository. The examples are compiled if the Cmake option BUILD_EXAMPLE is turned on.

+ 43 - 7
doc/tutorials.rst

@@ -1,10 +1,11 @@
 Tutorials
 =========
 
-Tutorial 1: First steps with open62541-server
-------------------------------
+This section contains structured tutorials
+   
+**Tutorial 1: First steps with open62541-server**
 
-:doc:`tutorial_firstStepsServer`
+:doc:`tutorial_server_firstSteps`
 
 Contents:
 
@@ -16,10 +17,9 @@ Contents:
 
 * Compiling built-in server and client examples
 
-Tutorial 2: First steps with open62541-client
-------------------------------
+**Tutorial 2: First steps with open62541-client**
 
-:doc:`tutorial_firstStepsClient`
+:doc:`tutorial_client_firstSteps`
 
 Contents:
 
@@ -31,4 +31,40 @@ Contents:
 
 * Reading a variable
 
-* Introduction to stings
+* Introduction to strings
+
+**Tutorial 3: Adding nodes to a server and connecting nodes to user-defined values**
+
+:doc:`tutorial_server_variables`
+
+Contents:
+
+* Introduction to Variants
+
+* Adding user-defined nodes to a server
+
+* Connecting a node to a variable
+
+* Connecting a node to a callback function
+
+**Tutorial 4: Adding server-side methods**
+
+:doc:`tutorial_server_method`
+
+Contents:
+
+* Defining server-side method nodes
+
+**Tutorial 5: Nodeset handling**
+
+:doc:`tutorial_noderelations`
+
+.. toctree::
+   :maxdepth: 2
+   :hidden:
+
+   tutorial_server_firstSteps
+   tutorial_client_firstSteps
+   tutorial_server_variables
+   tutorial_server_method
+   tutorial_noderelations

+ 26 - 20
examples/CMakeLists.txt

@@ -1,7 +1,7 @@
 include_directories(${PROJECT_SOURCE_DIR}/include)
 include_directories(${PROJECT_BINARY_DIR}/src_generated)
 
-set(LIBS open62541)
+set(LIBS open62541-static)
 if(NOT WIN32)
     list(APPEND LIBS pthread)
     if (NOT APPLE)
@@ -14,31 +14,37 @@ if(ENABLE_MULTITHREADING)
     list(APPEND LIBS urcu-cds urcu urcu-common)
 endif(ENABLE_MULTITHREADING)
 
+add_executable(server_readspeed server_readspeed.c)
+target_link_libraries(server_readspeed ${LIBS})
+
 add_executable(server_variable server_variable.c)
 target_link_libraries(server_variable ${LIBS})
 
 add_executable(server_datasource server_datasource.c)
 target_link_libraries(server_datasource ${LIBS})
 
-add_executable(server_repeated_job server_repeated_job.c)
-target_link_libraries(server_repeated_job ${LIBS})
-
-add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/nodeset.h ${PROJECT_BINARY_DIR}/src_generated/nodeset.c
-               PRE_BUILD
-               COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py -i ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_Blacklist_FullNS0.txt ${PROJECT_SOURCE_DIR}/tools/schema/namespace0/Opc.Ua.NodeSet2.xml ${PROJECT_SOURCE_DIR}/examples/server_nodeset.xml ${PROJECT_BINARY_DIR}/src_generated/nodeset
-               DEPENDS ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py
-                       ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/logger.py
-                       ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/open62541_MacroHelper.py
-                       ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_builtin_types.py
-                       ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_constants.py
-                       ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_namespace.py
-                       ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_node_types.py
-                       ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_Blacklist_FullNS0.txt
-                       ${PROJECT_SOURCE_DIR}/examples/server_nodeset.xml)
-               
-if(ENABLE_GENERATE_NAMESPACE0)
-  add_executable(server_nodeset server_nodeset.c ${PROJECT_BINARY_DIR}/src_generated/nodeset.c)
-  target_link_libraries(server_nodeset ${LIBS})
+add_executable(server_firstSteps server_firstSteps.c)
+target_link_libraries(server_firstSteps ${LIBS})
+
+add_executable(client_firstSteps client_firstSteps.c)
+target_link_libraries(client_firstSteps ${LIBS})
+
+if(NOT ENABLE_AMALGAMATION)
+	add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/nodeset.h ${PROJECT_BINARY_DIR}/src_generated/nodeset.c
+		           PRE_BUILD
+		           COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py -i ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_Blacklist_FullNS0.txt ${PROJECT_SOURCE_DIR}/tools/schema/namespace0/Opc.Ua.NodeSet2.xml ${PROJECT_SOURCE_DIR}/examples/server_nodeset.xml ${PROJECT_BINARY_DIR}/src_generated/nodeset
+		           DEPENDS ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py
+		                   ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/logger.py
+		                   ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/open62541_MacroHelper.py
+		                   ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_builtin_types.py
+		                   ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_constants.py
+		                   ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_namespace.py
+		                   ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_node_types.py
+		                   ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_Blacklist_FullNS0.txt
+		                   ${PROJECT_SOURCE_DIR}/examples/server_nodeset.xml)
+		           
+	add_executable(server_nodeset server_nodeset.c ${PROJECT_BINARY_DIR}/src_generated/nodeset.c)
+	target_link_libraries(server_nodeset ${LIBS})
 endif()
 
 if(ENABLE_METHODCALLS)

+ 52 - 0
examples/client_firstSteps.c

@@ -0,0 +1,52 @@
+//This file contains source-code that is discussed in a tutorial located here:
+//http://open62541.org/doc/sphinx/tutorial_firstStepsClient.html
+
+#include <stdio.h>
+
+#ifdef UA_NO_AMALGAMATION
+# include "ua_types.h"
+# include "ua_server.h"
+# include "logger_stdout.h"
+# include "networklayer_tcp.h"
+#else
+# include "open62541.h"
+#endif
+
+int main(void) {
+    UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout_new());
+    UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect, "opc.tcp://localhost:16664");
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Client_delete(client);
+        return retval;
+    }
+
+    //variables to store data
+    UA_DateTime raw_date = 0;
+    UA_String* string_date = UA_String_new();
+
+    UA_ReadRequest rReq;
+    UA_ReadRequest_init(&rReq);
+    rReq.nodesToRead = UA_Array_new(&UA_TYPES[UA_TYPES_READVALUEID], 1);
+    rReq.nodesToReadSize = 1;
+    rReq.nodesToRead[0].nodeId = UA_NODEID_NUMERIC(0, 2258);
+    rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
+
+    UA_ReadResponse rResp = UA_Client_read(client, &rReq);
+    if(rResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD &&
+            rResp.resultsSize > 0 && rResp.results[0].hasValue &&
+            UA_Variant_isScalar(&rResp.results[0].value) &&
+            rResp.results[0].value.type == &UA_TYPES[UA_TYPES_DATETIME]) {
+        raw_date = *(UA_DateTime*)rResp.results[0].value.data;
+        printf("raw date is: %" PRId64 "\n", raw_date);
+        UA_DateTime_toString(raw_date, string_date);
+        printf("string date is: %.*s\n", string_date->length, string_date->data);
+    }
+
+    UA_ReadRequest_deleteMembers(&rReq);
+    UA_ReadResponse_deleteMembers(&rResp);
+    UA_String_delete(string_date);
+
+    UA_Client_disconnect(client);
+    UA_Client_delete(client);
+    return 0;
+}

+ 14 - 12
examples/server.c

@@ -119,7 +119,9 @@ static UA_StatusCode readLedStatus(void *handle, UA_Boolean sourceTimeStamp, con
   if(range)
     return UA_STATUSCODE_BADINDEXRANGEINVALID;
 
+  value->hasValue = UA_TRUE;
   UA_StatusCode retval = UA_Variant_setScalarCopy(&value->value, &ledStatus, &UA_TYPES[UA_TYPES_BOOLEAN]);
+
   if(retval != UA_STATUSCODE_GOOD)
     return retval;
   
@@ -197,11 +199,11 @@ static UA_ByteString loadCertificate(void) {
 
 UA_StatusCode nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, void *handle);
 UA_StatusCode nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, void *handle) {  
-  printf("References ns=%d;i=%d using i=%d ", childId.namespaceIndex, childId.identifier.numeric, referenceTypeId.identifier.numeric);
+  /*printf("References ns=%d;i=%d using i=%d ", childId.namespaceIndex, childId.identifier.numeric, referenceTypeId.identifier.numeric);
   if (isInverse == UA_TRUE) {
     printf(" (inverse)");
   }
-  printf("\n");
+  printf("\n");*/
   
   return UA_STATUSCODE_GOOD;
 }
@@ -300,18 +302,18 @@ int main(int argc, char** argv) {
                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), NULL);
 
 #define SCALARID 50001
-  UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, SCALARID), UA_QUALIFIEDNAME(1, "Scalar"), UA_LOCALIZEDTEXT("en_US","Demo"), 
-                          UA_LOCALIZEDTEXT("en_US","Demo"), 0, 0, UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+  UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, SCALARID), UA_QUALIFIEDNAME(1, "Scalar"), UA_LOCALIZEDTEXT("en_US","Scalar"),
+                          UA_LOCALIZEDTEXT("en_US","Scalar"), 0, 0, UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), NULL);
 
 #define ARRAYID 50002
-  UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, ARRAYID), UA_QUALIFIEDNAME(1, "Array"), UA_LOCALIZEDTEXT("en_US","Demo"), 
-                          UA_LOCALIZEDTEXT("en_US","Demo"), 0, 0, UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+  UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, ARRAYID), UA_QUALIFIEDNAME(1, "Array"), UA_LOCALIZEDTEXT("en_US","Array"),
+                          UA_LOCALIZEDTEXT("en_US","Array"), 0, 0, UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), NULL);
 
 #define MATRIXID 50003
-  UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, MATRIXID), UA_QUALIFIEDNAME(1, "Matrix"), UA_LOCALIZEDTEXT("en_US","Demo"), 
-                          UA_LOCALIZEDTEXT("en_US","Demo"), 0, 0, UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+  UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, MATRIXID), UA_QUALIFIEDNAME(1, "Matrix"), UA_LOCALIZEDTEXT("en_US","Matrix"),
+                          UA_LOCALIZEDTEXT("en_US","Matrix"), 0, 0, UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), NULL);
 
   UA_UInt32 id = 51000; //running id in namespace 0
@@ -325,13 +327,13 @@ int main(int argc, char** argv) {
     char name[15];
     sprintf(name, "%02d", type);
     UA_QualifiedName qualifiedName = UA_QUALIFIEDNAME(1, name);
-    UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), qualifiedName, UA_LOCALIZEDTEXT("en_US",""), UA_LOCALIZEDTEXT("en_US",""), 0, 0,
+    UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), qualifiedName, UA_LOCALIZEDTEXT("en_US",name), UA_LOCALIZEDTEXT("en_US",name), 0, 0,
                               UA_NODEID_NUMERIC(1, SCALARID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), variant, NULL);
 
     //add an array node for every built-in type
     UA_Variant *arrayvar = UA_Variant_new();
     UA_Variant_setArray(arrayvar, UA_Array_new(&UA_TYPES[type], 10), 10, &UA_TYPES[type]);
-    UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), qualifiedName, UA_LOCALIZEDTEXT("en_US",""), UA_LOCALIZEDTEXT("en_US",""), 0, 0,
+    UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), qualifiedName, UA_LOCALIZEDTEXT("en_US",name), UA_LOCALIZEDTEXT("en_US",name), 0, 0,
                               UA_NODEID_NUMERIC(1, ARRAYID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), arrayvar, NULL);
 
     //add an matrix node for every built-in type
@@ -344,7 +346,7 @@ int main(int argc, char** argv) {
     arrayvar->arrayLength = 9;
     arrayvar->data = myMultiArray;
     arrayvar->type = &UA_TYPES[type];
-    UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), qualifiedName, UA_LOCALIZEDTEXT("en_US",""), UA_LOCALIZEDTEXT("en_US",""),
+    UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), qualifiedName, UA_LOCALIZEDTEXT("en_US",name), UA_LOCALIZEDTEXT("en_US",name),
                               0, 0, UA_NODEID_NUMERIC(1, MATRIXID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), arrayvar, NULL);
   }
 
@@ -384,7 +386,7 @@ int main(int argc, char** argv) {
 #endif
    
   // Example for iterating over all nodes referenced by "Objects":
-  printf("Nodes connected to 'Objects':\n=============================\n");
+  //printf("Nodes connected to 'Objects':\n=============================\n");
   UA_Server_forEachChildNodeCall(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), nodeIter, NULL);
   
   // Some easy localization

+ 37 - 0
examples/server_firstSteps.c

@@ -0,0 +1,37 @@
+//This file contains source-code that is discussed in a tutorial located here:
+// http://open62541.org/doc/sphinx/tutorial_firstStepsServer.html
+
+#include <stdio.h>
+#include <signal.h>
+
+#ifdef UA_NO_AMALGAMATION
+# include "ua_types.h"
+# include "ua_server.h"
+# include "logger_stdout.h"
+# include "networklayer_tcp.h"
+#else
+# include "open62541.h"
+#endif
+
+UA_Boolean running;
+UA_Logger logger;
+
+static void stopHandler(int signal) {
+    running = UA_FALSE;
+}
+
+int main(void) {
+    signal(SIGINT,  stopHandler);
+    signal(SIGTERM, stopHandler);
+
+    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
+    logger = Logger_Stdout_new();
+    UA_Server_setLogger(server, logger);
+    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+    running = UA_TRUE;
+    UA_Server_run(server, 1, &running);
+    UA_Server_delete(server);
+
+    printf("Terminated\n");
+    return 0;
+}

+ 11 - 6
examples/server_method.c

@@ -32,13 +32,13 @@ static UA_StatusCode helloWorldMethod(const UA_NodeId objectId, const UA_Variant
         return UA_STATUSCODE_GOOD;
 } 
 
-static UA_StatusCode IncInt32ArrayValues(const UA_NodeId objectId,
+static UA_StatusCode IncInt32ArrayValuesMethod(const UA_NodeId objectId,
                                          const UA_Variant *input, UA_Variant *output, void *handle) {
 
 
 	UA_Variant_setArrayCopy(output,input->data,5,&UA_TYPES[UA_TYPES_INT32]);
 	for(int i = 0; i< input->arrayLength; i++){
-		((UA_Int32*)output->data)[i] = ((UA_Int32*)input->data)[i] + 2;
+		((UA_Int32*)output->data)[i] = ((UA_Int32*)input->data)[i] + 1;
 	}
 
 	return UA_STATUSCODE_GOOD;
@@ -57,6 +57,7 @@ int main(int argc, char** argv) {
     UA_Server_setLogger(server, logger);
     UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
 
+    //EXAMPLE 1
     /* add the method node with the callback */
     UA_Argument inputArguments;
     UA_Argument_init(&inputArguments);
@@ -78,9 +79,12 @@ int main(int argc, char** argv) {
         
     UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1,62541), UA_QUALIFIEDNAME(1, "hello world"), 
                             UA_LOCALIZEDTEXT("en_US","Hello World"), UA_LOCALIZEDTEXT("en_US","Say `Hello World`"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                             0, 0, &helloWorldMethod, NULL, 1, &inputArguments, 1, &outputArguments, NULL);
 
+    //END OF EXAMPLE 1
+
+    //EXAMPLE 2
     /* add another method node: output argument as 1d Int32 array*/
     // define input arguments
     UA_Argument_init(&inputArguments);
@@ -104,18 +108,19 @@ int main(int argc, char** argv) {
     outputArguments.description = UA_LOCALIZEDTEXT("en_US",
                     "increment each array index");
     outputArguments.name = UA_STRING(
-                    "output is the array, each index is incremented");
+                    "output is the array, each index is incremented by one");
     outputArguments.valueRank = 1;
 
     UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "IncInt32ArrayValues"), UA_QUALIFIEDNAME(1, "IncInt32ArrayValues"),
                             UA_LOCALIZEDTEXT("en_US","1dArrayExample"), UA_LOCALIZEDTEXT("en_US","1dArrayExample"),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), 
-                            0, 0, &IncInt32ArrayValues, NULL, 1, &inputArguments, 1, &outputArguments, NULL);
+                            0, 0, &IncInt32ArrayValuesMethod, NULL, 1, &inputArguments, 1, &outputArguments, NULL);
+    //END OF EXAMPLE 2
 
     /* start server */
     UA_StatusCode retval = UA_Server_run(server, 1, &running); //blocks until running=false
 
-        /* ctrl-c received -> clean up */
+    /* ctrl-c received -> clean up */
     UA_UInt32_delete(pInputDimensions);
     UA_UInt32_delete(pOutputDimensions);
     UA_Server_delete(server);

+ 103 - 0
examples/server_readspeed.c

@@ -0,0 +1,103 @@
+/*
+ * 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>
+
+#ifdef UA_NO_AMALGAMATION
+# include "ua_types.h"
+# include "ua_server.h"
+# include "logger_stdout.h"
+# include "networklayer_tcp.h"
+#else
+# include "open62541.h"
+#endif
+
+#include <time.h>
+#include "ua_types_generated.h"
+#include "server/ua_services.h"
+#include "ua_types_encoding_binary.h"
+
+UA_Boolean running = 1;
+UA_Logger logger;
+
+static void stopHandler(int sign) {
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "received ctrl-c");
+    running = 0;
+}
+
+int main(int argc, char** argv) {
+    signal(SIGINT, stopHandler); /* catches ctrl-c */
+
+    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
+    logger = Logger_Stdout_new();
+    UA_Server_setLogger(server, logger);
+    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+
+    /* add a variable node to the address space */
+    UA_Variant *myIntegerVariant = UA_Variant_new();
+    UA_Int32 myInteger = 42;
+    UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    //NOTE: the link between myInteger and the value of the node is lost here, you can safely reuse myInteger
+    UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
+    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); /* UA_NODEID_NULL would assign a random free nodeid */
+    UA_LocalizedText myIntegerBrowseName = UA_LOCALIZEDTEXT("en_US","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, myIntegerName, myIntegerBrowseName, myIntegerBrowseName, 0, 0,
+                              parentNodeId, parentReferenceNodeId, myIntegerVariant, NULL);
+
+    UA_ReadRequest request;
+    UA_ReadRequest_init(&request);
+    UA_ReadValueId rvi;
+    rvi.nodeId = myIntegerNodeId;
+    rvi.attributeId = UA_ATTRIBUTEID_VALUE;
+    rvi.indexRange = UA_STRING_NULL;
+    rvi.dataEncoding = UA_QUALIFIEDNAME(0, "DefaultBinary");
+    request.timestampsToReturn = UA_TIMESTAMPSTORETURN_NEITHER;
+    request.nodesToReadSize = 1;
+    request.nodesToRead = &rvi;
+
+    UA_ByteString request_msg;
+    UA_ByteString response_msg;
+    UA_ByteString_newMembers(&request_msg, 1000);
+    UA_ByteString_newMembers(&response_msg, 1000);
+    size_t offset = 0;
+    UA_encodeBinary(&request, &UA_TYPES[UA_TYPES_READREQUEST], &request_msg, &offset);
+    
+    clock_t begin, end;
+    begin = clock();
+
+    UA_ReadRequest rq;
+    UA_ReadResponse rr;
+
+    for(int i = 0; i < 600000; i++) {
+        UA_ReadRequest_init(&rq);
+        UA_ReadResponse_init(&rr);
+
+        offset = 0;
+        UA_decodeBinary(&request_msg, &offset, &rq, &UA_TYPES[UA_TYPES_READREQUEST]);
+
+        Service_Read(server, &adminSession, &rq, &rr);
+
+        offset = 0;
+        UA_encodeBinary(&rr, &UA_TYPES[UA_TYPES_READRESPONSE], &response_msg, &offset);
+
+        UA_ReadRequest_deleteMembers(&rq);
+        UA_ReadResponse_deleteMembers(&rr);
+    }
+
+    end = clock();
+    double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
+    printf("duration was %f s\n", time_spent);
+
+    UA_ByteString_deleteMembers(&request_msg);
+    UA_ByteString_deleteMembers(&response_msg);
+
+    UA_StatusCode retval = UA_Server_run(server, 1, &running);
+    UA_Server_delete(server);
+
+    return retval;
+}

+ 1 - 1
include/ua_config.h.in

@@ -67,11 +67,11 @@
 # define UA_ALIGNED_MEMORY_ACCESS
 #endif
 
+/* Inline Functions */
 #ifdef _MSC_VER
 # define UA_INLINE __inline
 #else
 # define UA_INLINE inline
 #endif
 
-
 #endif /* UA_CONFIG_H_ */

+ 2 - 2
include/ua_types.h

@@ -20,7 +20,7 @@
 extern "C" {
 #endif
 
-#include <stdint.h>
+#include <inttypes.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <string.h>
@@ -31,7 +31,7 @@ typedef bool UA_Boolean;
 #define UA_TRUE true
 #define UA_FALSE false
 
-/** @brief An integer value between -129 and 127. */
+/** @brief An integer value between -128 and 127. */
 typedef int8_t UA_SByte;
 #define UA_SBYTE_MAX 127
 #define UA_SBYTE_MIN -128

+ 8 - 4
src/client/ua_client.c

@@ -1,9 +1,12 @@
-#include "ua_types_generated.h"
+#include "ua_util.h"
 #include "ua_client.h"
+#include "ua_types_generated.h"
 #include "ua_nodeids.h"
 #include "ua_securechannel.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_transport_generated.h"
+#include "ua_types_generated_encoding_binary.h"
+#include "ua_transport_generated_encoding_binary.h"
 #include "ua_client_internal.h"
 
 typedef enum {
@@ -467,7 +470,7 @@ static UA_StatusCode CloseSession(UA_Client *client) {
     request.requestHeader.timeoutHint = 10000;
     request.deleteSubscriptions = UA_TRUE;
     UA_NodeId_copy(&client->authenticationToken, &request.requestHeader.authenticationToken);
-    UA_CreateSessionResponse response;
+    UA_CloseSessionResponse response;
     synchronousRequest(client, &request, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST],
                        &response, &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE]);
 
@@ -911,7 +914,7 @@ UA_Boolean UA_Client_processPublishRx(UA_Client *client, UA_PublishResponse resp
     for(int i=0; i<response.resultsSize && nxtAck != NULL; i++) {
         tmpAck = nxtAck;
         nxtAck = tmpAck->listEntry.le_next;
-        if (response.results[i] == UA_STATUSCODE_GOOD) {
+        if (response.results[i] == UA_STATUSCODE_GOOD || response.results[i] == UA_STATUSCODE_BADSEQUENCENUMBERINVALID) {
             LIST_REMOVE(tmpAck, listEntry);
             UA_free(tmpAck);
         }
@@ -969,6 +972,8 @@ UA_Boolean UA_Client_processPublishRx(UA_Client *client, UA_PublishResponse resp
         tmpAck = (UA_Client_NotificationsAckNumber *) UA_malloc(sizeof(UA_Client_NotificationsAckNumber));
         tmpAck->subAck.sequenceNumber = msg.sequenceNumber;
         tmpAck->subAck.subscriptionId = sub->SubscriptionID;
+	tmpAck->listEntry.le_next = UA_NULL;
+	tmpAck->listEntry.le_prev = UA_NULL;
         LIST_INSERT_HEAD(&(client->pendingNotificationsAcks), tmpAck, listEntry);
     }
     
@@ -994,7 +999,6 @@ void UA_Client_doPublish(UA_Client *client) {
         
         index = 0;
         LIST_FOREACH(ack, &(client->pendingNotificationsAcks), listEntry) {
-            ack = client->pendingNotificationsAcks.lh_first;
             request.subscriptionAcknowledgements[index].sequenceNumber = ack->subAck.sequenceNumber;
             request.subscriptionAcknowledgements[index].subscriptionId = ack->subAck.subscriptionId;
             index++;

+ 3 - 3
src/server/ua_server_binary.c

@@ -1,11 +1,11 @@
 #include "ua_util.h"
 #include "ua_server_internal.h"
-#include "ua_types_encoding_binary.h"
-#include "ua_transport_generated.h"
 #include "ua_services.h"
-#include "ua_statuscodes.h"
 #include "ua_securechannel_manager.h"
 #include "ua_session_manager.h"
+#include "ua_types_generated_encoding_binary.h"
+#include "ua_transport_generated.h"
+#include "ua_transport_generated_encoding_binary.h"
 
 /** Max size of messages that are allocated on the stack */
 #define MAX_STACK_MESSAGE 65536

+ 1 - 0
src/server/ua_services.h

@@ -1,6 +1,7 @@
 #ifndef UA_SERVICES_H_
 #define UA_SERVICES_H_
 
+#include "ua_util.h"
 #include "ua_types.h"
 #include "ua_types_generated.h"
 #include "ua_server.h"

+ 2 - 1
src/server/ua_services_nodemanagement.c

@@ -1,9 +1,10 @@
+#include "ua_util.h"
 #include "ua_server_internal.h"
 #include "ua_services.h"
 #include "ua_statuscodes.h"
 #include "ua_nodestore.h"
 #include "ua_session.h"
-#include "ua_util.h"
+#include "ua_types_generated_encoding_binary.h"
 
 #define COPY_STANDARDATTRIBUTES do {  \
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DISPLAYNAME) {     \

+ 1 - 2
src/server/ua_services_session.c

@@ -1,8 +1,7 @@
 #include "ua_services.h"
 #include "ua_server_internal.h"
 #include "ua_session_manager.h"
-#include "ua_statuscodes.h"
-#include "ua_util.h"
+#include "ua_types_generated_encoding_binary.h"
 
 void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel,
                            const UA_CreateSessionRequest *request,

+ 17 - 21
src/server/ua_subscription_manager.c

@@ -21,33 +21,29 @@ void SubscriptionManager_init(UA_Session *session) {
     // Counter
     // NOTE: On a 32 bit plattform, assigning 64 bit (2 regs) is allowed by the compiler, but shifting though multiple
     //       regs is usually not. To support both 32 and 64bit, the struct splits the 64Bit timestamp into two parts.
-    union {
+    typedef union {
         struct {
             UA_UInt32 ui32h;
             UA_UInt32 ui32l;
-        };
+        } individual;
         UA_UInt64 ui64;
-    } guidInitH;
+    } guidInit;
+    guidInit guidInitH;
     guidInitH.ui64 = (UA_UInt64) UA_DateTime_now();
-    manager->lastJobGuid.data1 = guidInitH.ui32h;
-    manager->lastJobGuid.data2 = (UA_UInt16) (guidInitH.ui32l >> 16);
-    manager->lastJobGuid.data3 = (UA_UInt16) (guidInitH.ui32l);
-    union {
-        struct {
-            UA_UInt32 ui32h;
-            UA_UInt32 ui32l;
-        };
-        UA_UInt64 ui64;
-    } guidInitL;
+    manager->lastJobGuid.data1 = guidInitH.individual.ui32h;
+    manager->lastJobGuid.data2 = (UA_UInt16) (guidInitH.individual.ui32l >> 16);
+    manager->lastJobGuid.data3 = (UA_UInt16) (guidInitH.individual.ui32l);
+
+    guidInit guidInitL;
     guidInitL.ui64 = (UA_UInt64) UA_DateTime_now();
-    manager->lastJobGuid.data4[0] = (UA_Byte) guidInitL.ui32l;
-    manager->lastJobGuid.data4[1] = (UA_Byte) (guidInitL.ui32l >> 8); 
-    manager->lastJobGuid.data4[2] = (UA_Byte) (guidInitL.ui32l >> 16);
-    manager->lastJobGuid.data4[3] = (UA_Byte) (guidInitL.ui32l >> 24);
-    manager->lastJobGuid.data4[4] = (UA_Byte) (manager->lastJobGuid.data4[0]) ^ (guidInitL.ui32h);
-    manager->lastJobGuid.data4[5] = (UA_Byte) (manager->lastJobGuid.data4[0]) ^ (guidInitL.ui32h >> 8);
-    manager->lastJobGuid.data4[6] = (UA_Byte) (manager->lastJobGuid.data4[1]) ^ (guidInitL.ui32h >> 16);
-    manager->lastJobGuid.data4[7] = (UA_Byte) (manager->lastJobGuid.data4[0]) ^ (guidInitL.ui32h >> 24);
+    manager->lastJobGuid.data4[0] = (UA_Byte) guidInitL.individual.ui32l;
+    manager->lastJobGuid.data4[1] = (UA_Byte) (guidInitL.individual.ui32l >> 8);
+    manager->lastJobGuid.data4[2] = (UA_Byte) (guidInitL.individual.ui32l >> 16);
+    manager->lastJobGuid.data4[3] = (UA_Byte) (guidInitL.individual.ui32l >> 24);
+    manager->lastJobGuid.data4[4] = (UA_Byte) (manager->lastJobGuid.data4[0]) ^ (guidInitL.individual.ui32h);
+    manager->lastJobGuid.data4[5] = (UA_Byte) (manager->lastJobGuid.data4[0]) ^ (guidInitL.individual.ui32h >> 8);
+    manager->lastJobGuid.data4[6] = (UA_Byte) (manager->lastJobGuid.data4[1]) ^ (guidInitL.individual.ui32h >> 16);
+    manager->lastJobGuid.data4[7] = (UA_Byte) (manager->lastJobGuid.data4[0]) ^ (guidInitL.individual.ui32h >> 24);
 }
 
 void SubscriptionManager_deleteMembers(UA_Session *session, UA_Server *server) {

+ 1 - 1
src/ua_securechannel.c

@@ -1,8 +1,8 @@
 #include "ua_util.h"
 #include "ua_securechannel.h"
 #include "ua_session.h"
-#include "ua_statuscodes.h"
 #include "ua_types_encoding_binary.h"
+#include "ua_transport_generated_encoding_binary.h"
 
 void UA_SecureChannel_init(UA_SecureChannel *channel) {
     UA_MessageSecurityMode_init(&channel->securityMode);

+ 1 - 0
src/ua_types_encoding_binary.c

@@ -741,6 +741,7 @@ UA_StatusCode UA_Variant_encodeBinary(UA_Variant const *src, UA_ByteString *dst,
     }
 
     UA_NodeId typeId;
+    UA_NodeId_init(&typeId);
     if(isBuiltin)
         /* Do an extra lookup. E.g. UA_ServerState is encoded as UA_UINT32. The
            typeindex points to the true type. */

+ 0 - 1
src/ua_util.h

@@ -81,7 +81,6 @@
 #include <stdarg.h> // va_start, va_end
 #include <time.h>
 #include <stdio.h> // printf
-#include <inttypes.h>
 
 #ifdef _WIN32
 # include <winsock2.h> //needed for amalgation

+ 1 - 1
tests/CMakeLists.txt

@@ -8,7 +8,7 @@ find_package(Threads REQUIRED)
 
 set(LIBS ${CHECK_LIBRARIES})
 if(NOT WIN32)
-  list(APPEND LIBS pthread)
+  list(APPEND LIBS pthread m subunit)
   if (NOT APPLE)
     list(APPEND LIBS rt)
   endif()

+ 1 - 0
tests/check_builtin.c

@@ -3,6 +3,7 @@
 #include "ua_types.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_types_generated.h"
+#include "ua_types_generated_encoding_binary.h"
 //#include "ua_transport.h"
 #include "ua_util.h"
 #include "check.h"

+ 6 - 1
tools/amalgamate.py

@@ -58,7 +58,12 @@ if not is_c:
 else:
     file.write(u'''#ifndef UA_DYNAMIC_LINKING
 # define UA_DYNAMIC_LINKING
-#endif\n\n''')
+#endif
+
+#ifndef UA_INTERNAL
+#define UA_INTERNAL
+#endif
+\n''')
     file.write(u"#include \"" + outname + ".h\"\n")
 
 for fname in args.inputs:

+ 53 - 23
tools/generate_datatypes.py

@@ -183,13 +183,15 @@ class EnumerationType(object):
             ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = UA_TYPES_INT32 }"
 
     def functions_c(self, typeTableName):
-        return '''#define %s_new (%s*)UA_Int32_new
-#define %s_init(p) UA_Int32_init((UA_Int32*)p)
-#define %s_delete(p) UA_Int32_delete((UA_Int32*)p)
-#define %s_deleteMembers(p) UA_Int32_deleteMembers((UA_Int32*)p)
-#define %s_copy(src, dst) UA_Int32_copy((const UA_Int32*)src, (UA_Int32*)dst)
-#define %s_encodeBinary(src, dst, offset) UA_Int32_encodeBinary((UA_Int32*)src, dst, offset)
-#define %s_decodeBinary(src, offset, dst) UA_Int32_decodeBinary(src, offset, (UA_Int32*)dst)''' % tuple(itertools.repeat(self.name, 8))
+        return '''static UA_INLINE %s * %s_new(void) { %s *v = (%s*)UA_Int32_new(); return v; }
+static UA_INLINE void %s_init(%s *p) { UA_Int32_init((UA_Int32*)p); }
+static UA_INLINE void %s_delete(%s *p) { UA_Int32_delete((UA_Int32*)p); }
+static UA_INLINE void %s_deleteMembers(%s *p) { }
+static UA_INLINE UA_StatusCode %s_copy(const %s *src, %s *dst) { return UA_Int32_copy((const UA_Int32*)src, (UA_Int32*)dst); }''' % tuple(itertools.repeat(self.name, 13))
+
+    def encoding_h(self, typeTableName):
+        return '''static UA_INLINE UA_StatusCode %s_encodeBinary(const %s *src, UA_ByteString *dst, size_t *offset) { return UA_Int32_encodeBinary((const UA_Int32*)src, dst, offset); }
+static UA_INLINE UA_StatusCode %s_decodeBinary(const UA_ByteString *src, size_t *offset, %s *dst) { return UA_Int32_decodeBinary(src, offset, (UA_Int32*)dst); }''' % tuple(itertools.repeat(self.name, 4))
 
 class OpaqueType(object):
     def __init__(self, name, description = ""):
@@ -216,13 +218,15 @@ class OpaqueType(object):
             ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = UA_TYPES_BYTESTRING }"
 
     def functions_c(self, typeTableName):
-        return '''#define %s_new UA_ByteString_new
-#define %s_init UA_ByteString_init
-#define %s_delete UA_ByteString_delete
-#define %s_deleteMembers UA_ByteString_deleteMembers
-#define %s_copy UA_ByteString_copy
-#define %s_encodeBinary UA_ByteString_encodeBinary
-#define %s_decodeBinary UA_ByteString_decodeBinary''' % tuple(itertools.repeat(self.name, 8))
+        return '''static UA_INLINE %s * %s_new(void) { %s *v = (%s*)UA_ByteString_new(); return v; }
+static UA_INLINE void %s_init(%s *p) { UA_ByteString_init((UA_ByteString*)p); }
+static UA_INLINE void %s_delete(%s *p) { UA_ByteString_delete((UA_ByteString*)p); }
+static UA_INLINE void %s_deleteMembers(%s *p) { }
+static UA_INLINE UA_StatusCode %s_copy(const %s *src, %s *dst) { return UA_ByteString_copy((const UA_ByteString*)src, (UA_ByteString*)dst); }''' % tuple(itertools.repeat(self.name, 13))
+
+    def encoding_h(self, typeTableName):
+        return '''static UA_INLINE UA_StatusCode %s_encodeBinary(const %s *src, UA_ByteString *dst, size_t *offset) { return UA_ByteString_encodeBinary((UA_ByteString*)src, dst, offset); }
+static UA_INLINE UA_StatusCode %s_decodeBinary(const UA_ByteString *src, size_t *offset, %s *dst) { return UA_ByteString_decodeBinary(src, offset, (UA_ByteString*)dst); }''' % tuple(itertools.repeat(self.name, 4))
 
 class StructMember(object):
     def __init__(self, name, memberType, isArray):
@@ -322,14 +326,18 @@ class StructType(object):
         return layout + "}"
 
     def functions_c(self, typeTableName):
-        return '''#define %s_new() (%s*)UA_new(%s)
-#define %s_init(p) UA_init(p, %s)
-#define %s_delete(p) UA_delete(p, %s)
-#define %s_deleteMembers(p) UA_deleteMembers(p, %s)
-#define %s_copy(src, dst) UA_copy(src, dst, %s)
-#define %s_encodeBinary(src, dst, offset) UA_encodeBinary(src, %s, dst, offset)
-#define %s_decodeBinary(src, offset, dst) UA_decodeBinary(src, offset, dst, %s)''' % \
-    tuple([self.name] + list(itertools.chain(*itertools.repeat([self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 7))))
+        return '''static UA_INLINE %s * %s_new(void) { return UA_new(%s); }
+static UA_INLINE void %s_init(%s *p) { UA_init(p, %s); }
+static UA_INLINE void %s_delete(%s *p) { UA_delete(p, %s); }
+static UA_INLINE void %s_deleteMembers(%s *p) { UA_deleteMembers(p, %s); }
+static UA_INLINE UA_StatusCode %s_copy(const %s *src, %s *dst) { return UA_copy(src, dst, %s); }''' % \
+    tuple(list(itertools.chain(*itertools.repeat([self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 4)))
+          + [self.name, self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"])
+
+    def encoding_h(self, typeTableName):
+        return '''static UA_INLINE UA_StatusCode %s_encodeBinary(const %s *src, UA_ByteString *dst, size_t *offset) { return UA_encodeBinary(src, %s, dst, offset); }
+static UA_INLINE UA_StatusCode %s_decodeBinary(const UA_ByteString *src, size_t *offset, %s *dst) { return UA_decodeBinary(src, offset, dst, %s); }''' % \
+    tuple(list(itertools.chain(*itertools.repeat([self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 2))))
 
 def parseTypeDefinitions(xmlDescription, existing_types = OrderedDict()):
     '''Returns an ordered dict that maps names to types. The order is such that
@@ -472,9 +480,12 @@ if args.typedescriptions:
     typedescriptions = parseTypeDescriptions(args.typedescriptions, args.namespace_id)
 
 fh = open(args.outfile + "_generated.h",'w')
+fe = open(args.outfile + "_generated_encoding_binary.h",'w')
 fc = open(args.outfile + "_generated.c",'w')
 def printh(string):
     print(string, end='\n', file=fh)
+def printe(string):
+    print(string, end='\n', file=fe)
 def printc(string):
     print(string, end='\n', file=fc)
 
@@ -494,7 +505,10 @@ printh('''/**
 extern "C" {
 #endif
 
-#include "ua_types.h" '''
+#include "ua_types.h"
+#ifdef UA_INTERNAL
+#include "ua_types_encoding_binary.h"
+#endif'''
  + ('\n#include "ua_types_generated.h"\n' if args.namespace_id != 0 else '') + '''
 
 /**
@@ -534,6 +548,17 @@ printh('''
 #endif\n
 #endif /* %s_GENERATED_H_ */''' % outname.upper())
 
+printe('''/**
+* @file ''' + outname + '''_generated_encoding_binary.h
+*
+* @brief Binary encoding for autogenerated data types
+*
+* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
+* on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + '''
+*/\n
+#include "ua_types_encoding_binary.h"
+#include "''' + outname + '''_generated.h"''')
+
 printc('''/**
 * @file ''' + outname + '''_generated.c
 *
@@ -558,6 +583,10 @@ for t in values:
     else:
         td = None
     printc(t.typelayout_c(args.namespace_id == 0, td, outname) + ",")
+    if not type(t) == BuiltinType:
+        printe("")
+        printe("/* " + t.name + " */")
+        printe(t.encoding_h(outname.upper()))
 printc("};\n")
 # if args.typedescriptions:
 #     printc('const UA_UInt32 *' + outname.upper() + '_IDS = (UA_UInt32[]){')
@@ -566,4 +595,5 @@ printc("};\n")
 #     printc("};")
 
 fh.close()
+fe.close()
 fc.close()

+ 10 - 5
tools/pyUANamespace/ua_namespace.py

@@ -633,15 +633,20 @@ class opcua_namespace():
     header.append("/* WARNING: This is a generated file.\n * Any manual changes will be overwritten.\n\n */")
     code.append("/* WARNING: This is a generated file.\n * Any manual changes will be overwritten.\n\n */")
 
-    header.append("#ifndef "+outfilename.upper()+"_H_")
-    header.append("#define "+outfilename.upper()+"_H_")
-
+    header.append('#ifndef '+outfilename.upper()+'_H_')
+    header.append('#define '+outfilename.upper()+'_H_')
+    header.append('#ifdef UA_NO_AMALGAMATION')
     header.append('#include "server/ua_server_internal.h"')
     header.append('#include "server/ua_nodes.h"')
+    header.append('#include "ua_util.h"')
     header.append('#include "ua_types.h"')
-
+    header.append('#else')
+    header.append('#include "open62541.h"')
+    header.append('#define UA_NULL ((void *)0)')
+    header.append('#endif')
+      
     code.append('#include "'+outfilename+'.h"')
-    code.append("inline void "+outfilename+"(UA_Server *server) {")
+    code.append("UA_INLINE void "+outfilename+"(UA_Server *server) {")
 
     # Find all references necessary to create the namespace and
     # "Bootstrap" them so all other nodes can safely use these referencetypes whenever