Sfoglia il codice sorgente

Merge pull request #1202 from open62541/feature/minor_fixes_nodeset

New Datatype generator arguments and code cleanup
Stefan Profanter 6 anni fa
parent
commit
c565ec095c

+ 41 - 24
CMakeLists.txt

@@ -90,6 +90,8 @@ mark_as_advanced(UA_ENABLE_DETERMINISTIC_RNG)
 
 option(UA_ENABLE_GENERATE_NAMESPACE0 "Generate and load UA XML Namespace 0 definition (experimental)" OFF)
 mark_as_advanced(UA_ENABLE_GENERATE_NAMESPACE0)
+set(UA_DATATYPES_FILE ${PROJECT_SOURCE_DIR}/tools/schema/datatypes_minimal.txt CACHE FILEPATH "File containing the list of datatypes added to the server")
+mark_as_advanced(UA_DATATYPES_FILE)
 
 option(UA_ENABLE_VALGRIND_UNIT_TESTS "Use Valgrind to detect memory leaks when running the unit tests" OFF)
 mark_as_advanced(UA_ENABLE_VALGRIND_UNIT_TESTS)
@@ -380,26 +382,32 @@ endif()
 # Generate source files #
 #########################
 
-# standard data types
+if (UA_DATATYPES_FILE STREQUAL "")
+    set(SELECTED_TYPES_TMP "")
+else()
+    set(SELECTED_TYPES_TMP "--selected-types=${UA_DATATYPES_FILE}")
+endif()
+
 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_handling.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
-                           --selected_types=${PROJECT_SOURCE_DIR}/tools/schema/datatypes_minimal.txt
-                           ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_types
+                           --type-csv=${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv
+                           ${SELECTED_TYPES_TMP}
+                           --type-bsd=${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
-                           ${PROJECT_SOURCE_DIR}/tools/schema/datatypes_minimal.txt
-                           ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
-                           ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/NodeIds.csv)
+                           ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv
+                           ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
+                           ${SELECTED_TYPES})
 # we need a custom target to avoid that the generator is called concurrently and thus overwriting files while the other thread is compiling
 add_custom_target(open62541-generator-types DEPENDS
-        ${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_handling.h
-        ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h)
+                  ${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_handling.h
+                  ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h)
 
 # transport data types
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.c
@@ -408,13 +416,16 @@ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_transport_gener
                           ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated_encoding_binary.h
                    PRE_BUILD
                    COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py
-                           --namespace=1 --selected_types=${PROJECT_SOURCE_DIR}/tools/schema/datatypes_transport.txt
-                           ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
-                           ${PROJECT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd
+                           --namespace=1
+                           --selected-types=${PROJECT_SOURCE_DIR}/tools/schema/datatypes_transport.txt
+                           --type-bsd=${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
+                           --type-bsd=${PROJECT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd
+                           --no-builtin
                            ${PROJECT_BINARY_DIR}/src_generated/ua_transport
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
                            ${PROJECT_SOURCE_DIR}/tools/schema/datatypes_transport.txt
-                           ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd)
+                           ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
+                           ${PROJECT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd)
 # we need a custom target to avoid that the generator is called concurrently and thus overwriting files while the other thread is compiling
 add_custom_target(open62541-generator-transport DEPENDS
         ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.c
@@ -446,13 +457,15 @@ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.c
                    COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py
                            ${OPEN62541_VER_COMMIT} ${CMAKE_CURRENT_BINARY_DIR}/open62541.c
                            ${internal_headers} ${lib_sources} ${default_plugin_sources}
-                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${internal_headers} ${lib_sources})
+                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${internal_headers}
+                           ${lib_sources})
 
 add_custom_target(open62541-amalgamation-source DEPENDS ${PROJECT_BINARY_DIR}/open62541.c)
 add_custom_target(open62541-amalgamation-header DEPENDS ${PROJECT_BINARY_DIR}/open62541.h)
 
-add_dependencies(open62541-amalgamation-source open62541-generator-types open62541-generator-transport open62541-generator-statuscode)
 add_dependencies(open62541-amalgamation-header open62541-generator-types)
+add_dependencies(open62541-amalgamation-source open62541-generator-types
+                 open62541-generator-transport open62541-generator-statuscode)
 
 # generated namespace 0
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated.c
@@ -492,8 +505,12 @@ if(UA_ENABLE_AMALGAMATION)
     # and thus may overwrite the amalgamation result during multiprocessor compilation
     # the header is already a dependency of open62541 target itself
     add_dependencies(open62541-object
-            open62541-amalgamation-header
-            open62541-amalgamation-source)
+                     open62541-amalgamation-header
+                     open62541-generator-types
+                     open62541-generator-transport
+                     open62541-generator-statuscode
+                     open62541-amalgamation-source
+                     )
 
     add_library(open62541 $<TARGET_OBJECTS:open62541-object>)
 
@@ -504,14 +521,14 @@ else()
     add_definitions(-DUA_NO_AMALGAMATION)
     add_library(open62541-object OBJECT ${lib_sources} ${internal_headers} ${exported_headers})
     add_dependencies(open62541-object
-            open62541-amalgamation-header
-            open62541-generator-types
-            open62541-generator-transport
-            open62541-generator-statuscode)
+                     open62541-amalgamation-header
+                     open62541-generator-types
+                     open62541-generator-transport
+                     open62541-generator-statuscode)
     target_include_directories(open62541-object PRIVATE ${PROJECT_SOURCE_DIR}/src)
 
     add_library(open62541-plugins OBJECT ${default_plugin_sources} ${exported_headers})
-    add_dependencies(open62541-plugins open62541-generator-types)
+    add_dependencies(open62541-plugins open62541-generator-types open62541-generator-transport)
     target_include_directories(open62541-plugins PRIVATE ${PROJECT_SOURCE_DIR}/plugins)
     target_include_directories(open62541-plugins PRIVATE ${PROJECT_BINARY_DIR}/src_generated)
     target_compile_definitions(open62541-plugins PRIVATE -DUA_DYNAMIC_LINKING_EXPORT)

+ 7 - 8
include/ua_config.h.in

@@ -64,19 +64,18 @@ extern "C" {
 
 #include <stddef.h>
 
-/* Include stdint.h or workaround for older Visual Studios */
+/* Include stdint.h and stdbool.h or workaround for older Visual Studios */
 #if !defined(_MSC_VER) || _MSC_VER >= 1600
 # include <stdint.h>
+# include <stdbool.h> /* C99 Boolean */
 #else
 # include "ms_stdint.h"
-#endif
-
-#ifndef __cplusplus
-# include <stdbool.h> /* C99 Boolean */
-/* Manual Boolean:
-typedef uint8_t bool;
+#if !(defined(__bool_true_false_are_defined))
+#define bool short
 #define true 1
-#define false 0 */
+#define false 0
+#define __bool_true_false_are_defined
+#endif
 #endif
 
 /**

+ 5 - 5
include/ua_server_config.h

@@ -26,9 +26,9 @@ typedef struct {
 } UA_UInt32Range;
 
 typedef struct {
-    UA_Double min;
-    UA_Double max;
-} UA_DoubleRange;
+    UA_Duration min;
+    UA_Duration max;
+} UA_DurationRange;
 
 struct UA_ServerConfig {
     UA_UInt16 nThreads; /* only if multithreading is enabled */
@@ -70,14 +70,14 @@ struct UA_ServerConfig {
     UA_Double maxSessionTimeout; /* in ms */
 
     /* Limits for Subscriptions */
-    UA_DoubleRange publishingIntervalLimits;
+    UA_DurationRange publishingIntervalLimits;
     UA_UInt32Range lifeTimeCountLimits;
     UA_UInt32Range keepAliveCountLimits;
     UA_UInt32 maxNotificationsPerPublish;
     UA_UInt32 maxRetransmissionQueueSize; /* 0 -> unlimited size */
 
     /* Limits for MonitoredItems */
-    UA_DoubleRange samplingIntervalLimits;
+    UA_DurationRange samplingIntervalLimits;
     UA_UInt32Range queueSizeLimits; /* Negotiated with the client */
 
     /* Discovery */

+ 5 - 5
plugins/ua_config_standard.c

@@ -20,9 +20,9 @@ UA_UINT32RANGE(UA_UInt32 min, UA_UInt32 max) {
     return range;
 }
 
-static UA_INLINE UA_DoubleRange
-UA_DOUBLERANGE(UA_Double min, UA_Double max) {
-    UA_DoubleRange range = {min, max};
+static UA_INLINE UA_DurationRange
+UA_DURATIONRANGE(UA_Double min, UA_Double max) {
+    UA_DurationRange range = {min, max};
     return range;
 }
 
@@ -169,14 +169,14 @@ UA_ServerConfig_new_minimal(UA_UInt16 portNumber,
     conf->maxSessionTimeout = 60.0 * 60.0 * 1000.0; /* 1h */
 
     /* Limits for Subscriptions */
-    conf->publishingIntervalLimits = UA_DOUBLERANGE(100.0, 3600.0 * 1000.0);
+    conf->publishingIntervalLimits = UA_DURATIONRANGE(100.0, 3600.0 * 1000.0);
     conf->lifeTimeCountLimits = UA_UINT32RANGE(3, 15000);
     conf->keepAliveCountLimits = UA_UINT32RANGE(1, 100);
     conf->maxNotificationsPerPublish = 1000;
     conf->maxRetransmissionQueueSize = 0; /* unlimited */
 
     /* Limits for MonitoredItems */
-    conf->samplingIntervalLimits = UA_DOUBLERANGE(50.0, 24.0 * 3600.0 * 1000.0);
+    conf->samplingIntervalLimits = UA_DURATIONRANGE(50.0, 24.0 * 3600.0 * 1000.0);
     conf->queueSizeLimits = UA_UINT32RANGE(1, 100);
 
 #ifdef UA_ENABLE_DISCOVERY

+ 6 - 6
src/server/ua_mdns.c

@@ -25,18 +25,18 @@
 #   include <netdb.h> // for recvfrom in cygwin
 #  endif
 
-#ifndef STRDUP
+#ifndef UA_STRDUP
 # if defined(__MINGW32__)
 static char *ua_strdup(const char *s) {
     char *p = UA_malloc(strlen(s) + 1);
     if(p) { strcpy(p, s); }
     return p;
 }
-# define STRDUP ua_strdup
+# define UA_STRDUP ua_strdup
 # elif defined(_WIN32)
-# define STRDUP _strdup
+# define UA_STRDUP _strdup
 # else
-# define STRDUP strdup
+# define UA_STRDUP strdup
 # endif
 #endif
 
@@ -180,7 +180,7 @@ setTxt(const struct resource *r,
         if (!entry->srvSet) {
             /* txt arrived before SRV, thus cache path entry */
             // todo: malloc in strdup may fail: return a statuscode
-            entry->pathTmp = STRDUP(path);
+            entry->pathTmp = UA_STRDUP(path);
         } else {
             /* SRV already there and discovery URL set. Add path to discovery URL */
             mdns_append_path_to_url(&entry->serverOnNetwork.discoveryUrl, path);
@@ -311,7 +311,7 @@ void mdns_create_txt(UA_Server *server, const char *fullServiceDomain, const cha
         // path does not contain slash, so add it here
         if (path[0] == '/')
             // todo: malloc in strdup may fail: return a statuscode
-            allocPath = STRDUP(path);
+            allocPath = UA_STRDUP(path);
         else {
             // todo: malloc may fail: return a statuscode
             allocPath = (char*)UA_malloc(strlen(path) + 2);

+ 4 - 6
src/server/ua_server.c

@@ -4,12 +4,6 @@
 
 #include "ua_types.h"
 #include "ua_server_internal.h"
-#include "ua_securechannel_manager.h"
-#include "ua_session_manager.h"
-#include "ua_util.h"
-#include "ua_services.h"
-#include "ua_types_generated.h"
-#include "ua_types_generated_handling.h"
 
 #ifdef UA_ENABLE_GENERATE_NAMESPACE0
 #include "ua_namespaceinit_generated.h"
@@ -165,6 +159,10 @@ UA_Server_cleanup(UA_Server *server, void *_) {
 #endif
 }
 
+/********************/
+/* Server Lifecycle */
+/********************/
+
 UA_Server *
 UA_Server_new(const UA_ServerConfig *config) {
     UA_Server *server = (UA_Server *)UA_calloc(1, sizeof(UA_Server));

+ 4 - 0
src/server/ua_services_attribute.c

@@ -83,6 +83,10 @@ compatibleDataType(UA_Server *server, const UA_NodeId *dataType,
     if(UA_NodeId_isNull(constraintDataType))
         return true;
 
+    /* Same datatypes */
+    if (UA_NodeId_equal(dataType, constraintDataType))
+        return true;
+
     /* Variant allows any subtype */
     if(UA_NodeId_equal(constraintDataType, &UA_TYPES[UA_TYPES_VARIANT].typeId))
         return true;

+ 3 - 1
tests/check_types_memory.c

@@ -106,7 +106,9 @@ END_TEST
 
 START_TEST(decodeShallFailWithTruncatedBufferButSurvive) {
     //Skip test for void*
-    if (_i == UA_TYPES_DISCOVERYCONFIGURATION || _i == UA_TYPES_FILTEROPERAND || _i == UA_TYPES_MONITORINGFILTER)
+    if (_i == UA_TYPES_DISCOVERYCONFIGURATION ||
+            _i == UA_TYPES_FILTEROPERAND ||
+            _i == UA_TYPES_MONITORINGFILTER)
         return;
     // given
     UA_ByteString msg1;

+ 94 - 44
tools/generate_datatypes.py

@@ -1,3 +1,5 @@
+#!/usr/bin/env python
+
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this 
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -12,6 +14,7 @@ import re
 import xml.etree.ElementTree as etree
 import itertools
 import argparse
+from nodeset_compiler.opaque_type_mapping import get_base_type_for_opaque
 
 types = OrderedDict() # contains types that were already parsed
 typedescriptions = {} # contains type nodeids
@@ -61,9 +64,9 @@ class StructMember(object):
         self.isArray = isArray
 
 class Type(object):
-    def __init__(self, outname, xml):
+    def __init__(self, outname, xml, namespace):
         self.name = xml.get("Name")
-        self.ns0 = ("true" if outname == "ua_types" else "false")
+        self.ns0 = ("true" if namespace == 0 else "false")
         self.typeIndex = outname.upper() + "_" + self.name.upper()
         self.outname = outname
         self.description = ""
@@ -170,8 +173,8 @@ class BuiltinType(Type):
             self.members = [StructMember("", self, False)]
 
 class EnumerationType(Type):
-    def __init__(self, outname, xml):
-        Type.__init__(self, outname, xml)
+    def __init__(self, outname, xml, namespace):
+        Type.__init__(self, outname, xml, namespace)
         self.pointerfree = "true"
         self.overlayable = "UA_BINARY_OVERLAYABLE_INTEGER"
         self.members = [StructMember("", types["Int32"], False)] # encoded as uint32
@@ -191,16 +194,17 @@ class EnumerationType(Type):
                                                             " = " + kv[1], values)) + "\n} UA_%s;" % self.name
 
 class OpaqueType(Type):
-    def __init__(self, outname, xml):
-        Type.__init__(self, outname, xml)
-        self.members = [StructMember("", types["ByteString"], False)] # encoded as string
+    def __init__(self, outname, xml, namespace, baseType):
+        Type.__init__(self, outname, xml, namespace)
+        self.baseType = baseType
+        self.members = [StructMember("", types[baseType], False)] # encoded as string
 
     def typedef_h(self):
-        return "typedef UA_ByteString UA_%s;" % self.name
+        return "typedef UA_" + self.baseType + " UA_%s;" % self.name
 
 class StructType(Type):
-    def __init__(self, outname, xml):
-        Type.__init__(self, outname, xml)
+    def __init__(self, outname, xml, namespace):
+        Type.__init__(self, outname, xml, namespace)
         self.members = []
         lengthfields = [] # lengthfields of arrays are not included as members
         for child in xml:
@@ -250,7 +254,7 @@ class StructType(Type):
 # Parse Typedefinitions #
 #########################
 
-def parseTypeDefinitions(outname, xmlDescription):
+def parseTypeDefinitions(outname, xmlDescription, namespace):
     def typeReady(element):
         "Are all member types defined?"
         for child in element:
@@ -286,11 +290,11 @@ def parseTypeDefinitions(outname, xmlDescription):
             if name in builtin_types:
                 types[name] = BuiltinType(name)
             elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
-                types[name] = EnumerationType(outname, typeXml)
+                types[name] = EnumerationType(outname, typeXml, namespace)
             elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
-                types[name] = OpaqueType(outname, typeXml)
+                types[name] = OpaqueType(outname, typeXml, namespace, get_base_type_for_opaque(name)['name'])
             elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
-                types[name] = StructType(outname, typeXml)
+                types[name] = StructType(outname, typeXml, namespace)
             else:
                 raise Exception("Type not known")
             del snippets[name]
@@ -307,10 +311,9 @@ class TypeDescription(object):
         self.xmlEncodingId = "0"
         self.binaryEncodingId = "0"
 
-def parseTypeDescriptions(filename, namespaceid):
+def parseTypeDescriptions(f, namespaceid):
     definitions = {}
-    with open(filename) as f:
-        input_str = f.read()
+    input_str = f.read()
     input_str = input_str.replace('\r','')
     rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
     for index, row in enumerate(rows):
@@ -336,27 +339,69 @@ def parseTypeDescriptions(filename, namespaceid):
             definitions["ExtensionObject"] = TypeDescription(row[0], row[1], namespaceid)
         elif row[0] not in types:
             continue
-        elif type(types[row[0]]) == EnumerationType:
-            definitions[row[0]] = TypeDescription(row[0], "6", namespaceid) # enumerations look like int32 on the wire
         else:
             definitions[row[0]] = TypeDescription(row[0], row[1], namespaceid)
     return definitions
 
+def merge_dicts(*dict_args):
+    """
+    Given any number of dicts, shallow copy and merge into a new dict,
+    precedence goes to key value pairs in latter dicts.
+    """
+    result = {}
+    for dictionary in dict_args:
+        result.update(dictionary)
+    return result
+
 ###############################
 # Parse the Command Line Input#
 ###############################
 
 parser = argparse.ArgumentParser()
-parser.add_argument('--typedescriptions', help='csv file with type descriptions')
-parser.add_argument('--namespace', type=int, default=0, help='namespace id of the generated type nodeids (defaults to 0)')
-parser.add_argument('--selected_types', help='file with list of types (among those parsed) to be generated')
-parser.add_argument('typexml_ns0', help='path/to/Opc.Ua.Types.bsd ...')
-parser.add_argument('typexml_additional', nargs='*', help='path/to/Opc.Ua.Types.bsd ...')
-parser.add_argument('outfile', help='output file w/o extension')
+parser.add_argument('-c', '--type-csv',
+                    metavar="<typeDescriptions>",
+                    type=argparse.FileType('r'),
+                    dest="type_csv",
+                    action='append',
+                    default=[],
+                    help='csv file with type descriptions')
+
+parser.add_argument('--namespace',
+                    type=int,
+                    dest="namespace",
+                    default=0,
+                    help='namespace id of the generated type nodeids (defaults to 0)')
+
+parser.add_argument('-s', '--selected-types',
+                    metavar="<selectedTypes>",
+                    type=argparse.FileType('r'),
+                    dest="selected_types",
+                    action='append',
+                    default=[],
+                    help='file with list of types (among those parsed) to be generated. If not given, all types are generated')
+
+parser.add_argument('--no-builtin',
+                    action='store_true',
+                    dest="no_builtin",
+                    help='Do not generate builtin types')
+
+parser.add_argument('-t', '--type-bsd',
+                    metavar="<typeBsds>",
+                    type=argparse.FileType('r'),
+                    dest="type_bsd",
+                    action='append',
+                    default=[],
+                    help='csv file with type descriptions')
+
+parser.add_argument('outfile',
+                    metavar='<outputFile>',
+                    help='output file w/o extension')
 args = parser.parse_args()
 
 outname = args.outfile.split("/")[-1]
-inname = ', '.join([args.typexml_ns0.split("/")[-1]] + list(map(lambda x:x.split("/")[-1], args.typexml_additional)))
+inname = ', '.join(list(map(lambda x:x.name.split("/")[-1], args.type_bsd)))
+
+
 
 ################
 # Create Types #
@@ -365,20 +410,19 @@ inname = ', '.join([args.typexml_ns0.split("/")[-1]] + list(map(lambda x:x.split
 for builtin in builtin_types:
     types[builtin] = BuiltinType(builtin)
 
-with open(args.typexml_ns0) as f:
-    parseTypeDefinitions("ua_types", f)
-for typexml in args.typexml_additional:
-    with open(typexml) as f:
-        parseTypeDefinitions(outname, f)
+for f in args.type_bsd:
+    parseTypeDefinitions(outname, f, args.namespace)
+
 
 typedescriptions = {}
-if args.typedescriptions:
-    typedescriptions = parseTypeDescriptions(args.typedescriptions, args.namespace)
+for f in args.type_csv:
+    typedescriptions = merge_dicts(typedescriptions, parseTypeDescriptions(f, args.namespace))
 
-selected_types = types.keys()
-if args.selected_types:
-    with open(args.selected_types) as f:
-        selected_types = list(filter(len, [line.strip() for line in f]))
+selected_types = []
+for f in args.selected_types:
+    selected_types = list(filter(len, [line.strip() for line in f]))
+if len(selected_types) == 0:
+    selected_types = types.keys()
 
 #############################
 # Write out the Definitions #
@@ -403,7 +447,11 @@ def iter_types(v):
         l = list(v.itervalues())
     else:
         l = list(v.values())
-    return filter(lambda t: t.name in selected_types, l)
+    if len(selected_types) > 0:
+        l = filter(lambda t: t.name in selected_types, l)
+    if args.no_builtin:
+        l = filter(lambda t: type(t) != BuiltinType, l)
+    return l
 
 ################
 # Print Header #
@@ -423,15 +471,17 @@ extern "C" {
 #include "ua_types.h"
 ''' + ('#include "ua_types_generated.h"\n' if outname != "ua_types" else ''))
 
+filtered_types = iter_types(types)
+
 printh('''/**
  * Every type is assigned an index in an array containing the type descriptions.
  * These descriptions are used during type handling (copying, deletion,
  * binary encoding, ...). */''')
-printh("#define " + outname.upper() + "_COUNT %s" % (str(len(selected_types))))
+printh("#define " + outname.upper() + "_COUNT %s" % (str(len(filtered_types))))
 printh("extern UA_EXPORT const UA_DataType " + outname.upper() + "[" + outname.upper() + "_COUNT];")
 
 i = 0
-for t in iter_types(types):
+for t in filtered_types:
     printh("\n/**\n * " +  t.name)
     printh(" * " + "^" * len(t.name))
     if t.description == "":
@@ -473,7 +523,7 @@ extern "C" {
 #endif
 ''')
 
-for t in iter_types(types):
+for t in filtered_types:
     printf("\n/* " + t.name + " */")
     printf(t.functions_c())
 
@@ -498,13 +548,13 @@ printc('''/* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '
 #include "''' + outname + '''_generated.h"
 #include "ua_util.h"''')
 
-for t in iter_types(types):
+for t in filtered_types:
     printc("")
     printc("/* " + t.name + " */")
     printc(t.members_c())
 
 printc("const UA_DataType %s[%s_COUNT] = {" % (outname.upper(), outname.upper()))
-for t in iter_types(types):
+for t in filtered_types:
     printc("")
     printc("/* " + t.name + " */")
     printc(t.datatype_c() + ",")
@@ -521,7 +571,7 @@ printe('''/* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '
 #include "ua_types_encoding_binary.h"
 #include "''' + outname + '''_generated.h"''')
 
-for t in iter_types(types):
+for t in filtered_types:
     printe("\n/* " + t.name + " */")
     printe(t.encoding_h())
 

+ 0 - 0
tools/nodeset_compiler/__init__.py


+ 137 - 0
tools/nodeset_compiler/opaque_type_mapping.py

@@ -0,0 +1,137 @@
+
+# Opaque types are in general defined as simple byte strings. For the base opaque types there is a corresponding node id definition
+# in the nodeset. E.g. Opc.Ua.Types.bsd contains the simple definition for OpaqueType LocaleId. In Opc.Ua.NodeSet2.xml the LocaleId
+# is defined as a Subtype of String(i=12) thus LocaleId is a String object.
+# TODO we can automate this mapping by loading the NodeSet2.xml and read those mappings automatically. For now we just use this map
+opaque_type_mapping = {
+    'Image': {
+        'ns': 0,
+        'id': 15,
+        'name': 'ByteString'
+    },
+    'Number': {
+        'ns': 0,
+        'id': 24,
+        'name': 'BaseDataType'
+    },
+    'UInteger': {
+        'ns': 0,
+        'id': 24,
+        'name': 'BaseDataType'
+    },
+    'ImageBMP': {
+        'ns': 0,
+        'id': 15,
+        'name': 'ByteString'
+    },
+    'ImageGIF': {
+        'ns': 0,
+        'id': 15,
+        'name': 'ByteString'
+    },
+    'ImageJPG': {
+        'ns': 0,
+        'id': 15,
+        'name': 'ByteString'
+    },
+    'ImagePNG': {
+        'ns': 0,
+        'id': 15,
+        'name': 'ByteString'
+    },
+    'BitFieldMaskDataType': {
+        'ns': 0,
+        'id': 9,
+        'name': 'UInt64'
+    },
+    'NormalizedString': {
+        'ns': 0,
+        'id': 12,
+        'name': 'String'
+    },
+    'DecimalString': {
+        'ns': 0,
+        'id': 12,
+        'name': 'String'
+    },
+    'DurationString': {
+        'ns': 0,
+        'id': 12,
+        'name': 'String'
+    },
+    'TimeString': {
+        'ns': 0,
+        'id': 12,
+        'name': 'String'
+    },
+    'DateString': {
+        'ns': 0,
+        'id': 12,
+        'name': 'String'
+    },
+    'Duration': {
+        'ns': 0,
+        'id': 11,
+        'name': 'Double'
+    },
+    'UtcTime': {
+        'ns': 0,
+        'id': 13,
+        'name': 'DateTime'
+    },
+    'LocaleId': {
+        'ns': 0,
+        'id': 12,
+        'name': 'String'
+    },
+    'IntegerId': {
+        'ns': 0,
+        'id': 7,
+        'name': 'UInt32'
+    },
+    'ApplicationInstanceCertificate': {
+        'ns': 0,
+        'id': 15,
+        'name': 'ByteString'
+    },
+    'SessionAuthenticationToken': {
+        'ns': 0,
+        'id': 17,
+        'name': 'NodeId'
+    },
+    'ContinuationPoint': {
+        'ns': 0,
+        'id': 15,
+        'name': 'ByteString'
+    },
+    'Counter': {
+        'ns': 0,
+        'id': 7,
+        'name': 'UInt32'
+    },
+    'NumericRange': {
+        'ns': 0,
+        'id': 12,
+        'name': 'String'
+    },
+    'Time': {
+        'ns': 0,
+        'id': 12,
+        'name': 'String'
+    },
+    'Date': {
+        'ns': 0,
+        'id': 13,
+        'name': 'DateTime'
+    }
+}
+
+def get_base_type_for_opaque(opaqueTypeName):
+    if opaqueTypeName in opaque_type_mapping:
+        return opaque_type_mapping[opaqueTypeName]
+    # Default if not in mapping is ByteString
+    return {
+        'ns': 0,
+        'id': 15,
+        'name': 'ByteString'
+    }

+ 15 - 18
tools/schema/Opc.Ua.StatusCodes.csv

@@ -20,15 +20,15 @@ BadTooManyMonitoredItems,0x80DB0000,The request could not be processed because t
 BadDataTypeIdUnknown,0x80110000,The extension object cannot be (de)serialized because the data type id is not recognized.
 BadCertificateInvalid,0x80120000,The certificate provided as a parameter is not valid.
 BadSecurityChecksFailed,0x80130000,An error occurred verifying security.
-BadCertificateTimeInvalid,0x80140000,The certificate has expired or is not yet valid.
-BadCertificateIssuerTimeInvalid,0x80150000,An issuer certificate has expired or is not yet valid.
-BadCertificateHostNameInvalid,0x80160000,The HostName used to connect to a server does not match a HostName in the certificate.
-BadCertificateUriInvalid,0x80170000,The URI specified in the ApplicationDescription does not match the URI in the certificate.
-BadCertificateUseNotAllowed,0x80180000,The certificate may not be used for the requested operation.
-BadCertificateIssuerUseNotAllowed,0x80190000,The issuer certificate may not be used for the requested operation.
-BadCertificateUntrusted,0x801A0000,The certificate is not trusted.
-BadCertificateRevocationUnknown,0x801B0000,It was not possible to determine if the certificate has been revoked.
-BadCertificateIssuerRevocationUnknown,0x801C0000,It was not possible to determine if the issuer certificate has been revoked.
+BadCertificateTimeInvalid,0x80140000,The Certificate has expired or is not yet valid.
+BadCertificateIssuerTimeInvalid,0x80150000,An Issuer Certificate has expired or is not yet valid.
+BadCertificateHostNameInvalid,0x80160000,The HostName used to connect to a Server does not match a HostName in the Certificate.
+BadCertificateUriInvalid,0x80170000,The URI specified in the ApplicationDescription does not match the URI in the Certificate.
+BadCertificateUseNotAllowed,0x80180000,The Certificate may not be used for the requested operation.
+BadCertificateIssuerUseNotAllowed,0x80190000,The Issuer Certificate may not be used for the requested operation.
+BadCertificateUntrusted,0x801A0000,The Certificate is not trusted.
+BadCertificateRevocationUnknown,0x801B0000,It was not possible to determine if the Certificate has been revoked.
+BadCertificateIssuerRevocationUnknown,0x801C0000,It was not possible to determine if the Issuer Certificate has been revoked.
 BadCertificateRevoked,0x801D0000,The certificate has been revoked.
 BadCertificateIssuerRevoked,0x801E0000,The issuer certificate has been revoked.
 BadCertificateChainIncomplete,0x810D0000,The certificate chain is incomplete.
@@ -46,9 +46,6 @@ BadRequestHeaderInvalid,0x802A0000,The header for the request is missing or inva
 BadTimestampsToReturnInvalid,0x802B0000,The timestamps to return parameter is invalid.
 BadRequestCancelledByClient,0x802C0000,The request was cancelled by the client.
 BadTooManyArguments,0x80E50000,Too many arguments were provided.
-BadLicenseExpired,0x810E0000,The server requires a license to operate in general or to perform a service or operation, but existing license is expired.
-BadLicenseLimitsExceeded,0x810F0000,The server has limits on number of allowed operations / objects, based on installed licenses, and these limits where exceeded.
-BadLicenseNotAvailable,0x81100000,The server does not have a license which is required to operate in general or to perform a service or operation.
 GoodSubscriptionTransferred,0x002D0000,The subscription was transferred to another session.
 GoodCompletesAsynchronously,0x002E0000,The processing will complete asynchronously.
 GoodOverload,0x002F0000,Sampling has slowed down due to resource limitations.
@@ -93,13 +90,13 @@ BadServerNameMissing,0x80500000,No ServerName was specified.
 BadDiscoveryUrlMissing,0x80510000,No DiscoveryUrl was specified.
 BadSempahoreFileMissing,0x80520000,The semaphore file specified by the client is not valid.
 BadRequestTypeInvalid,0x80530000,The security token request type is not valid.
-BadSecurityModeRejected,0x80540000,The security mode does not meet the requirements set by the server.
-BadSecurityPolicyRejected,0x80550000,The security policy does not meet the requirements set by the server.
+BadSecurityModeRejected,0x80540000,The security mode does not meet the requirements set by the Server.
+BadSecurityPolicyRejected,0x80550000,The security policy does not meet the requirements set by the Server.
 BadTooManySessions,0x80560000,The server has reached its maximum number of sessions.
 BadUserSignatureInvalid,0x80570000,The user token signature is missing or invalid.
 BadApplicationSignatureInvalid,0x80580000,The signature generated with the client certificate is missing or invalid.
 BadNoValidCertificates,0x80590000,The client did not provide at least one software certificate that is valid and meets the profile requirements for the server.
-BadIdentityChangeNotSupported,0x80C60000,The server does not support changing the user identity assigned to the session.
+BadIdentityChangeNotSupported,0x80C60000,The Server does not support changing the user identity assigned to the session.
 BadRequestCancelledByRequest,0x805A0000,The request was cancelled by the client with the Cancel service.
 BadParentNodeIdInvalid,0x805B0000,The parent node id does not to refer to a valid node.
 BadReferenceNotAllowed,0x805C0000,The reference could not be created because it violates constraints imposed by the data model.
@@ -134,7 +131,7 @@ BadSecurityModeInsufficient,0x80E60000,The operation is not permitted over the c
 BadHistoryOperationInvalid,0x80710000,The history details parameter is not valid.
 BadHistoryOperationUnsupported,0x80720000,The server does not support the requested operation.
 BadInvalidTimestampArgument,0x80BD0000,The defined timestamp to return was invalid.
-BadWriteNotSupported,0x80730000,The server does not support writing the combination of value, status and timestamps provided.
+BadWriteNotSupported,0x80730000,The server not does support writing the combination of value, status and timestamps provided.
 BadTypeMismatch,0x80740000,The value supplied for the attribute is not of the same type as the attribute's value.
 BadMethodInvalid,0x80750000,The method id does not refer to a method for the specified object.
 BadArgumentsMissing,0x80760000,The client did not specify all of the input arguments for the method.
@@ -143,7 +140,7 @@ BadTooManyPublishRequests,0x80780000,The server has reached the maximum number o
 BadNoSubscription,0x80790000,There is no subscription available for this session.
 BadSequenceNumberUnknown,0x807A0000,The sequence number is unknown to the server.
 BadMessageNotAvailable,0x807B0000,The requested notification message is no longer available.
-BadInsufficientClientProfile,0x807C0000,The client of the current session does not support one or more Profiles that are necessary for the subscription.
+BadInsufficientClientProfile,0x807C0000,The Client of the current Session does not support one or more Profiles that are necessary for the Subscription.
 BadStateNotActive,0x80BF0000,The sub-state machine is not currently active.
 BadTcpServerTooBusy,0x807D0000,The server cannot process the request because it is too busy.
 BadTcpMessageTypeInvalid,0x807E0000,The type of the message specified in the header invalid.
@@ -151,7 +148,7 @@ BadTcpSecureChannelUnknown,0x807F0000,The SecureChannelId and/or TokenId are not
 BadTcpMessageTooLarge,0x80800000,The size of the message specified in the header is too large.
 BadTcpNotEnoughResources,0x80810000,There are not enough resources to process the request.
 BadTcpInternalError,0x80820000,An internal error occurred.
-BadTcpEndpointUrlInvalid,0x80830000,The server does not recognize the QueryString specified.
+BadTcpEndpointUrlInvalid,0x80830000,The Server does not recognize the QueryString specified.
 BadRequestInterrupted,0x80840000,The request could not be sent because of a network interruption.
 BadRequestTimeout,0x80850000,Timeout occurred while processing the request.
 BadSecureChannelClosed,0x80860000,The secure channel has been closed.

+ 0 - 0
tools/schema/datatypes_full_generate.sh


+ 1 - 0
tools/schema/datatypes_minimal.txt

@@ -178,3 +178,4 @@ SimpleAttributeOperand
 EventNotificationList
 EventFieldList
 StatusChangeNotification
+Duration

+ 2 - 7
tools/travis/travis_linux_script.sh

@@ -60,6 +60,8 @@ if [ $ANALYZE = "true" ]; then
         if [ -s cppcheck.txt ]; then
             echo "====== CPPCHECK Static Analysis Errors ======"
             cat cppcheck.txt
+            # flush output
+            sleep 5
             exit 1
         fi
     fi
@@ -198,13 +200,6 @@ else
     if [ $? -ne 0 ] ; then exit 1 ; fi
     echo -en 'travis_fold:end:script.build.unit_test_valgrind\\r'
 
-    # without valgrind
-    # echo -e "\r\n== Debug build and unit tests without valgrind ==" && echo -en 'travis_fold:start:script.build.unit_test\\r'
-    # cmake -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=ON -DUA_ENABLE_DISCOVERY=ON -DUA_ENABLE_DISCOVERY_MULTICAST=ON -DUA_BUILD_UNIT_TESTS=ON -DUA_ENABLE_COVERAGE=ON -DUA_ENABLE_VALGRIND_UNIT_TESTS=OFF ..
-    # make -j && make test ARGS="-V"
-    # (./bin/examples/server & export pid=$!; sleep 2; kill -INT $pid; wait $pid);
-    # echo -en 'travis_fold:end:script.build.unit_test\\r'
-
     # only run coveralls on main repo, otherwise it fails uploading the files
     echo -e "\r\n== -> Current repo: ${TRAVIS_REPO_SLUG} =="
     if [ "$CC" = "gcc" ] && [ "${TRAVIS_REPO_SLUG}" = "open62541/open62541" ]; then