Browse Source

update to type layout generation

Julius Pfrommer 10 years ago
parent
commit
c881dfa173
2 changed files with 69 additions and 43 deletions
  1. 4 3
      include/ua_types.h
  2. 65 40
      tools/generate_datatypes.py

+ 4 - 3
include/ua_types.h

@@ -420,9 +420,10 @@ typedef struct {
 } UA_DataTypeMember;
     
 typedef struct {
-    UA_UInt16 memSize : 15; ///< Size of the struct in memory
-    UA_Boolean zeroCopyable; ///< Can the type be copied directly off the stream?
-    UA_Byte membersSize; ///< How many members does the struct have?
+    UA_UInt16 memSize; ///< Size of the struct in memory
+    UA_Boolean fixedSize : 1; ///< The type contains no pointers
+    UA_Boolean zeroCopyable : 1; ///< Can the type be copied directly off the stream?
+    UA_Byte membersSize : 6; ///< How many members does the struct have?
     UA_DataTypeMember members[UA_MAX_MEMBERS];
 } UA_DataTypeLayout;
 

+ 65 - 40
tools/generate_datatypes.py

@@ -12,6 +12,9 @@ fixed_size = {"UA_Boolean": 1, "UA_SByte": 1, "UA_Byte": 1, "UA_Int16": 2, "UA_U
               "UA_Int32": 4, "UA_UInt32": 4, "UA_Int64": 8, "UA_UInt64": 8, "UA_Float": 4,
               "UA_Double": 8, "UA_DateTime": 8, "UA_Guid": 16, "UA_StatusCode": 4}
 
+zero_copy = ["UA_Boolean", "UA_Byte", "UA_Int16", "UA_UInt16", "UA_Int32", "UA_UInt32",
+             "UA_Int64", "UA_UInt64", "UA_Float", "UA_Double", "UA_DateTime", "UA_StatusCode"]
+
 builtin_types = ["UA_Boolean", "UA_Byte", "UA_Int16", "UA_UInt16", "UA_Int32", "UA_UInt32",
                  "UA_Int64", "UA_UInt64", "UA_Float", "UA_Double", "UA_String", "UA_DateTime",
                  "UA_Guid", "UA_ByteString", "UA_XmlElement", "UA_NodeId", "UA_ExpandedNodeId",
@@ -24,31 +27,31 @@ excluded_types = ["UA_NodeIdType", "UA_InstanceNode", "UA_TypeNode", "UA_Node",
                   "UA_SamplingIntervalDiagnosticsDataType", "UA_SessionSecurityDiagnosticsDataType",
                   "UA_SubscriptionDiagnosticsDataType", "UA_SessionDiagnosticsDataType"]
 
-class Type(object):
+class BuiltinType(object):
+    "Generic type without members. Used for builtin types."
     def __init__(self, name, description = ""):
         self.name = name
         self.description = description
 
-    def typedef_c(self):
-        pass
+    def fixed_size(self):
+        return self.name in fixed_size
 
-    def typelayout_c(self):
-        pass
+    def mem_size(self):
+        return fixed_size[self.name]
 
-class BuiltinType(Type):
-    def __init__(self, name, description = "", zeroCopyable = False):
-        self.name = name
-        self.description = description
-        self.zeroCopyable = zeroCopyable
+    def zero_copy(self):
+        return self.name in zero_copy
 
-    def fixed_size(self):
-        return self.name in fixed_size
+    def typedef_c(self):
+        pass
 
     def typelayout_c(self):
-        return "{.memSize = sizeof(" + self.name + "), .zeroCopyable = " + \
-            ("UA_TRUE" if self.zeroCopyable else "UA_FALSE") + ", .membersSize = 0 }"
+        return "{.memSize = sizeof(" + self.name + "), " + \
+            ".fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
+            ", .zeroCopyable = " + ("UA_TRUE" if self.zero_copy() else "UA_FALSE") + \
+            ", .membersSize = 0 }"
 
-class EnumerationType(Type):
+class EnumerationType(object):
     def __init__(self, name, description = "", elements = OrderedDict()):
         self.name = name
         self.description = description
@@ -60,25 +63,38 @@ class EnumerationType(Type):
     def fixed_size(self):
         return True
 
+    def mem_size(self):
+        return 4
+
+    def zero_copy(self):
+        return True
+
     def typedef_c(self):
         return "typedef enum { \n    " + \
             ",\n    ".join(map(lambda (key,value) : key.upper() + " = " + value,self.elements.iteritems())) + \
             "\n} " + self.name + ";"
 
     def typelayout_c(self):
-        return "{.memSize = sizeof(" + self.name + "), .zeroCopyable = UA_TRUE, " + \
+        return "{.memSize = sizeof(" + self.name + "), .fixedSize = UA_TRUE, .zeroCopyable = UA_TRUE, " + \
             ".membersSize = 1,\n\t.members[0] = {.memberTypeIndex = UA_INT32," + \
             ".nameSpaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE } }"
 
-class OpaqueType(Type):
+class OpaqueType(object):
+    def __init__(self, name, description = ""):
+        self.name = name
+        self.description = description
+
     def fixed_size(self):
         return False
 
+    def zero_copy(self):
+        return False
+
     def typedef_c(self):
         return "typedef UA_ByteString " + self.name + ";"
 
     def typelayout_c(self):
-        return "{.memSize = sizeof(" + self.name + "), .zeroCopyable = UA_FALSE, " + \
+        return "{.memSize = sizeof(" + self.name + "), .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
             ".membersSize = 1,\n\t.members[0] = {.memberTypeIndex = UA_BYTE," + \
             ".nameSpaceZero = UA_TRUE, .padding = offsetof(UA_String, data), .isArray = UA_TRUE } }"
 
@@ -88,20 +104,33 @@ class StructMember(object):
         self.memberType = memberType
         self.isArray = isArray
 
-class StructType(Type):
+class StructType(object):
     def __init__(self, name, description, members = OrderedDict()):
         self.name = name
         self.description = description
         self.members = members # maps a name to a member definition
 
     def fixed_size(self):
-        if self.name in fixed_size:
-            return True
         for m in self.members.values():
             if m.isArray or not m.memberType.fixed_size():
                 return False
         return True
 
+    def mem_size(self):
+        total = 0
+        for m in self.members.values():
+            if m.isArray:
+                raise Exception("Arrays have no fixed size!")
+            else:
+                total += m.memberType.mem_size()
+        return total
+
+    def zero_copy(self):
+        for m in self.members.values():
+            if m.isArray or not m.memberType.zero_copy():
+                return False
+        return True
+
     def typedef_c(self):
         if len(self.members) == 0:
             return "typedef void * " + self.name + ";"
@@ -115,9 +144,11 @@ class StructType(Type):
         return returnstr + "} " + self.name + ";"
 
     def typelayout_c(self):
-        layout = "{.memSize = sizeof(" + self.name + "), .zeroCopyable = " + \
-                 ("UA_TRUE, " if self.fixed_size() else "UA_FALSE, ") + \
-                 ".membersSize = " + str(len(self.members)) + ","
+        layout = "{.memSize = sizeof(" + self.name + "), "+ \
+                 ".fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
+                 ", .zeroCopyable = " + ("sizeof(" + self.name + ") == " + str(self.mem_size()) if self.zero_copy() \
+                                         else "UA_FALSE") + \
+                 ", .membersSize = " + str(len(self.members)) + ","
         for index, member in enumerate(self.members.values()):
             layout += "\n\t.members["+ str(index)+ "] = {" + \
                       ".memberTypeIndex = UA_" + member.memberType.name.upper()[3:] + ", " + \
@@ -138,13 +169,13 @@ class StructType(Type):
             layout += ".isArray = " + ("UA_TRUE" if member.isArray else "UA_FALSE") + " }, "
         return layout + "}"
 
-def parseTypeDefinitions(xmlDescription, type_selection = None):
+def parseTypeDefinitions(xmlDescription, existing_types = OrderedDict()):
     '''Returns an ordered dict that maps names to types. The order is such that
        every type depends only on known types. '''
     ns = {"opc": "http://opcfoundation.org/BinarySchema/"}
     tree = etree.parse(xmlDescription)
     typeSnippets = tree.xpath("/opc:TypeDictionary/*[not(self::opc:Import)]", namespaces=ns)
-    types = OrderedDict([(t, BuiltinType(t, "", t in fixed_size)) for t in builtin_types])
+    types = OrderedDict(existing_types.items())
 
     # types we do not want to autogenerate
     def skipType(name):
@@ -156,8 +187,6 @@ def parseTypeDefinitions(xmlDescription, type_selection = None):
             return True
         if re.search("NodeId$", name) != None:
             return True
-        if type_selection and not(name in type_selection):
-            return True
         return False
 
     def stripTypename(tn):
@@ -201,13 +230,11 @@ def parseTypeDefinitions(xmlDescription, type_selection = None):
         for child in typeXml:
             if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
                 description = child.text
-
         # ignore lengthfields, just tag the array-members as an array
         lengthfields = []
         for child in typeXml:
             if child.get("LengthField"):
                 lengthfields.append(child.get("LengthField"))
-
         members = OrderedDict()
         for child in typeXml:
             if not child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
@@ -221,7 +248,6 @@ def parseTypeDefinitions(xmlDescription, type_selection = None):
             memberName = camlCase2CCase(child.get("Name"))
             isArray = True if child.get("LengthField") else False
             members[memberName] = StructMember(memberName, memberType, isArray)
-
         return StructType(name, description, members)
 
     finished = False
@@ -230,13 +256,13 @@ def parseTypeDefinitions(xmlDescription, type_selection = None):
         for typeXml in typeSnippets:
             name = "UA_" + typeXml.get("Name")
             if name in types or skipType(name):
-		continue
+                continue
             if typeXml.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
-		t = parseEnumeration(typeXml)
+                t = parseEnumeration(typeXml)
                 types[t.name] = t
             elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
-		t = parseOpaque(typeXml)
-		types[t.name] = t
+                t = parseOpaque(typeXml)
+                types[t.name] = t
             elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
                 t = parseStructured(typeXml)
                 if t == None:
@@ -253,7 +279,8 @@ parser.add_argument('outfile', help='outfile w/o extension')
 args = parser.parse_args()
 outname = args.outfile.split("/")[-1] 
 inname = args.xml.split("/")[-1]
-types = OrderedDict(parseTypeDefinitions(args.xml).items())
+existing_types = OrderedDict([(t, BuiltinType(t)) for t in builtin_types])
+types = parseTypeDefinitions(args.xml, existing_types)
 
 fh = open("ua_" + args.outfile + "_generated.h",'w')
 fc = open("ua_" + args.outfile + "_generated.c",'w')
@@ -298,7 +325,7 @@ for t in types.itervalues():
     if type(t) != BuiltinType:
         printh("")
         if t.description != "":
-            printh("/** @brief " + t.description + "*/")
+            printh("/** @brief " + t.description + " */")
         printh(t.typedef_c())
     printh("#define UA_" + t.name[3:].upper() + " " + str(i))
     i += 1
@@ -327,10 +354,8 @@ printc('''/**
 const UA_DataTypeLayout *UA_TYPES = (const UA_DataTypeLayout[]){''')
 
 for t in types.itervalues():
-    if type(t) == BuiltinType and not args.is_ns0:
-        continue
     printc("")
-    printc("/* " + t.name + "*/")
+    printc("/* " + t.name + " */")
     printc(t.typelayout_c() + ",")
 
 printc("};")