Browse Source

be more compliant fix #1362 (fix NS Compiler for opaque type) (#1405)

* be more compliant

* Generates the correct dataType for nodes with an opaque dataType

* don't generate dataType for opaque dataType

* fix UA_TYPES_COUNT

* force valueRank = -1 for scalar VariableNode

* new implementation

* remove iter_opaque_types

* force rebuild
StalderT 6 years ago
parent
commit
4330edc8f4

+ 4 - 0
examples/server.c

@@ -191,6 +191,8 @@ main(int argc, char **argv) {
     myVar.description = UA_LOCALIZEDTEXT("en-US", "the answer");
     myVar.displayName = UA_LOCALIZEDTEXT("en-US", "the answer");
     myVar.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
+    myVar.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
+    myVar.valueRank = -1;
     UA_Int32 myInteger = 42;
     UA_Variant_setScalarCopy(&myVar.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
     const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
@@ -209,6 +211,8 @@ main(int argc, char **argv) {
     v_attr.description = UA_LOCALIZEDTEXT("en-US", "current time");
     v_attr.displayName = UA_LOCALIZEDTEXT("en-US", "current time");
     v_attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
+    v_attr.dataType = UA_TYPES[UA_TYPES_DATETIME].typeId;
+    v_attr.valueRank = -1;
     const UA_QualifiedName dateName = UA_QUALIFIEDNAME(1, "current time");
     UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), dateName,

+ 22 - 5
tools/generate_datatypes.py

@@ -14,7 +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
+from nodeset_compiler.opaque_type_mapping import opaque_type_mapping, get_base_type_for_opaque
 
 types = OrderedDict() # contains types that were already parsed
 typedescriptions = {} # contains type nodeids
@@ -416,7 +416,6 @@ outname = args.outfile.split("/")[-1]
 inname = ', '.join(list(map(lambda x:x.name.split("/")[-1], args.type_bsd)))
 
 
-
 ################
 # Create Types #
 ################
@@ -455,7 +454,7 @@ def printe(string):
 def printc(string):
     print(string, end='\n', file=fc)
 
-def iter_types(v):
+def iter_types(v, opaqueType):
     l = None
     if sys.version_info[0] < 3:
         l = list(v.itervalues())
@@ -465,8 +464,13 @@ def iter_types(v):
         l = list(filter(lambda t: t.name in selected_types, l))
     if args.no_builtin:
         l = list(filter(lambda t: type(t) != BuiltinType, l))
+    if opaqueType:
+        # only opaque type
+        l = list(filter(lambda t: t.name in opaque_type_mapping, l))
+    else:
+        # remove opaque type
+        l = list(filter(lambda t: t.name not in opaque_type_mapping, l))
     return l
-
 ################
 # Print Header #
 ################
@@ -485,7 +489,8 @@ extern "C" {
 #include "ua_types.h"
 ''' + ('#include "ua_types_generated.h"\n' if outname != "ua_types" else ''))
 
-filtered_types = iter_types(types)
+filtered_types = iter_types(types, False)
+filtered_opaque_types = iter_types(types, True)
 
 printh('''/**
  * Every type is assigned an index in an array containing the type descriptions.
@@ -507,6 +512,18 @@ for t in filtered_types:
     printh("#define " + outname.upper() + "_" + t.name.upper() + " " + str(i))
     i += 1
 
+# Generate alias for opaque types
+for t in filtered_opaque_types:
+    printh("\n/**\n * " +  t.name)
+    printh(" * " + "^" * len(t.name))
+    if t.description == "":
+        printh(" */")
+    else:
+        printh(" * " + t.description + " */")
+    if type(t) != BuiltinType:
+        printh(t.typedef_h() + "\n")
+    printh("#define " + outname.upper() + "_" + t.name.upper() + " " + outname.upper() + "_" + get_base_type_for_opaque(t.name)['name'].upper())
+
 printh('''
 #ifdef __cplusplus
 } // extern "C"

+ 7 - 1
tools/nodeset_compiler/backend_open62541_nodes.py

@@ -115,6 +115,10 @@ def generateVariableNodeCode(node, nodeset, max_string_length):
     code.append("attr.minimumSamplingInterval = %f;" % node.minimumSamplingInterval)
     code.append("attr.userAccessLevel = %d;" % node.userAccessLevel)
     code.append("attr.accessLevel = %d;" % node.accessLevel)
+    # in order to be compatible with mostly OPC UA client
+    # force valueRank = -1 for scalar VariableNode
+    if node.valueRank == -2:
+        node.valueRank = -1
     code.append("attr.valueRank = %d;" % node.valueRank)
     if node.valueRank > 0:
         code.append("attr.arrayDimensionsSize = %d;" % node.valueRank)
@@ -127,11 +131,13 @@ def generateVariableNodeCode(node, nodeset, max_string_length):
         if isinstance(node.dataType, NodeId) and node.dataType.ns == 0 and node.dataType.i == 0:
             #BaseDataType
             dataTypeNode = nodeset.nodes[NodeId("i=24")]
+            dataTypeNodeOpaque = nodeset.nodes[NodeId("i=24")]
         else:
+            dataTypeNodeOpaque = nodeset.getDataTypeNode(node.dataType)
             dataTypeNode = nodeset.getBaseDataType(nodeset.getDataTypeNode(node.dataType))
 
         if dataTypeNode is not None:
-            code.append("attr.dataType = %s;" % generateNodeIdCode(dataTypeNode.id))
+            code.append("attr.dataType = %s;" % generateNodeIdCode(dataTypeNodeOpaque.id))
 
             if dataTypeNode.isEncodable():
                 if node.value is not None: