ソースを参照

update to type layout generation

Julius Pfrommer 10 年 前
コミット
c881dfa173
共有2 個のファイルを変更した69 個の追加43 個の削除を含む
  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;
 } UA_DataTypeMember;
     
     
 typedef struct {
 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_DataTypeMember members[UA_MAX_MEMBERS];
 } UA_DataTypeLayout;
 } 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_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}
               "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",
 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_Int64", "UA_UInt64", "UA_Float", "UA_Double", "UA_String", "UA_DateTime",
                  "UA_Guid", "UA_ByteString", "UA_XmlElement", "UA_NodeId", "UA_ExpandedNodeId",
                  "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_SamplingIntervalDiagnosticsDataType", "UA_SessionSecurityDiagnosticsDataType",
                   "UA_SubscriptionDiagnosticsDataType", "UA_SessionDiagnosticsDataType"]
                   "UA_SubscriptionDiagnosticsDataType", "UA_SessionDiagnosticsDataType"]
 
 
-class Type(object):
+class BuiltinType(object):
+    "Generic type without members. Used for builtin types."
     def __init__(self, name, description = ""):
     def __init__(self, name, description = ""):
         self.name = name
         self.name = name
         self.description = description
         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):
     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()):
     def __init__(self, name, description = "", elements = OrderedDict()):
         self.name = name
         self.name = name
         self.description = description
         self.description = description
@@ -60,25 +63,38 @@ class EnumerationType(Type):
     def fixed_size(self):
     def fixed_size(self):
         return True
         return True
 
 
+    def mem_size(self):
+        return 4
+
+    def zero_copy(self):
+        return True
+
     def typedef_c(self):
     def typedef_c(self):
         return "typedef enum { \n    " + \
         return "typedef enum { \n    " + \
             ",\n    ".join(map(lambda (key,value) : key.upper() + " = " + value,self.elements.iteritems())) + \
             ",\n    ".join(map(lambda (key,value) : key.upper() + " = " + value,self.elements.iteritems())) + \
             "\n} " + self.name + ";"
             "\n} " + self.name + ";"
 
 
     def typelayout_c(self):
     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," + \
             ".membersSize = 1,\n\t.members[0] = {.memberTypeIndex = UA_INT32," + \
             ".nameSpaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE } }"
             ".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):
     def fixed_size(self):
         return False
         return False
 
 
+    def zero_copy(self):
+        return False
+
     def typedef_c(self):
     def typedef_c(self):
         return "typedef UA_ByteString " + self.name + ";"
         return "typedef UA_ByteString " + self.name + ";"
 
 
     def typelayout_c(self):
     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," + \
             ".membersSize = 1,\n\t.members[0] = {.memberTypeIndex = UA_BYTE," + \
             ".nameSpaceZero = UA_TRUE, .padding = offsetof(UA_String, data), .isArray = UA_TRUE } }"
             ".nameSpaceZero = UA_TRUE, .padding = offsetof(UA_String, data), .isArray = UA_TRUE } }"
 
 
@@ -88,20 +104,33 @@ class StructMember(object):
         self.memberType = memberType
         self.memberType = memberType
         self.isArray = isArray
         self.isArray = isArray
 
 
-class StructType(Type):
+class StructType(object):
     def __init__(self, name, description, members = OrderedDict()):
     def __init__(self, name, description, members = OrderedDict()):
         self.name = name
         self.name = name
         self.description = description
         self.description = description
         self.members = members # maps a name to a member definition
         self.members = members # maps a name to a member definition
 
 
     def fixed_size(self):
     def fixed_size(self):
-        if self.name in fixed_size:
-            return True
         for m in self.members.values():
         for m in self.members.values():
             if m.isArray or not m.memberType.fixed_size():
             if m.isArray or not m.memberType.fixed_size():
                 return False
                 return False
         return True
         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):
     def typedef_c(self):
         if len(self.members) == 0:
         if len(self.members) == 0:
             return "typedef void * " + self.name + ";"
             return "typedef void * " + self.name + ";"
@@ -115,9 +144,11 @@ class StructType(Type):
         return returnstr + "} " + self.name + ";"
         return returnstr + "} " + self.name + ";"
 
 
     def typelayout_c(self):
     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()):
         for index, member in enumerate(self.members.values()):
             layout += "\n\t.members["+ str(index)+ "] = {" + \
             layout += "\n\t.members["+ str(index)+ "] = {" + \
                       ".memberTypeIndex = UA_" + member.memberType.name.upper()[3:] + ", " + \
                       ".memberTypeIndex = UA_" + member.memberType.name.upper()[3:] + ", " + \
@@ -138,13 +169,13 @@ class StructType(Type):
             layout += ".isArray = " + ("UA_TRUE" if member.isArray else "UA_FALSE") + " }, "
             layout += ".isArray = " + ("UA_TRUE" if member.isArray else "UA_FALSE") + " }, "
         return layout + "}"
         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
     '''Returns an ordered dict that maps names to types. The order is such that
        every type depends only on known types. '''
        every type depends only on known types. '''
     ns = {"opc": "http://opcfoundation.org/BinarySchema/"}
     ns = {"opc": "http://opcfoundation.org/BinarySchema/"}
     tree = etree.parse(xmlDescription)
     tree = etree.parse(xmlDescription)
     typeSnippets = tree.xpath("/opc:TypeDictionary/*[not(self::opc:Import)]", namespaces=ns)
     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
     # types we do not want to autogenerate
     def skipType(name):
     def skipType(name):
@@ -156,8 +187,6 @@ def parseTypeDefinitions(xmlDescription, type_selection = None):
             return True
             return True
         if re.search("NodeId$", name) != None:
         if re.search("NodeId$", name) != None:
             return True
             return True
-        if type_selection and not(name in type_selection):
-            return True
         return False
         return False
 
 
     def stripTypename(tn):
     def stripTypename(tn):
@@ -201,13 +230,11 @@ def parseTypeDefinitions(xmlDescription, type_selection = None):
         for child in typeXml:
         for child in typeXml:
             if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
             if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
                 description = child.text
                 description = child.text
-
         # ignore lengthfields, just tag the array-members as an array
         # ignore lengthfields, just tag the array-members as an array
         lengthfields = []
         lengthfields = []
         for child in typeXml:
         for child in typeXml:
             if child.get("LengthField"):
             if child.get("LengthField"):
                 lengthfields.append(child.get("LengthField"))
                 lengthfields.append(child.get("LengthField"))
-
         members = OrderedDict()
         members = OrderedDict()
         for child in typeXml:
         for child in typeXml:
             if not child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
             if not child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
@@ -221,7 +248,6 @@ def parseTypeDefinitions(xmlDescription, type_selection = None):
             memberName = camlCase2CCase(child.get("Name"))
             memberName = camlCase2CCase(child.get("Name"))
             isArray = True if child.get("LengthField") else False
             isArray = True if child.get("LengthField") else False
             members[memberName] = StructMember(memberName, memberType, isArray)
             members[memberName] = StructMember(memberName, memberType, isArray)
-
         return StructType(name, description, members)
         return StructType(name, description, members)
 
 
     finished = False
     finished = False
@@ -230,13 +256,13 @@ def parseTypeDefinitions(xmlDescription, type_selection = None):
         for typeXml in typeSnippets:
         for typeXml in typeSnippets:
             name = "UA_" + typeXml.get("Name")
             name = "UA_" + typeXml.get("Name")
             if name in types or skipType(name):
             if name in types or skipType(name):
-		continue
+                continue
             if typeXml.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
             if typeXml.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
-		t = parseEnumeration(typeXml)
+                t = parseEnumeration(typeXml)
                 types[t.name] = t
                 types[t.name] = t
             elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
             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":
             elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
                 t = parseStructured(typeXml)
                 t = parseStructured(typeXml)
                 if t == None:
                 if t == None:
@@ -253,7 +279,8 @@ parser.add_argument('outfile', help='outfile w/o extension')
 args = parser.parse_args()
 args = parser.parse_args()
 outname = args.outfile.split("/")[-1] 
 outname = args.outfile.split("/")[-1] 
 inname = args.xml.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')
 fh = open("ua_" + args.outfile + "_generated.h",'w')
 fc = open("ua_" + args.outfile + "_generated.c",'w')
 fc = open("ua_" + args.outfile + "_generated.c",'w')
@@ -298,7 +325,7 @@ for t in types.itervalues():
     if type(t) != BuiltinType:
     if type(t) != BuiltinType:
         printh("")
         printh("")
         if t.description != "":
         if t.description != "":
-            printh("/** @brief " + t.description + "*/")
+            printh("/** @brief " + t.description + " */")
         printh(t.typedef_c())
         printh(t.typedef_c())
     printh("#define UA_" + t.name[3:].upper() + " " + str(i))
     printh("#define UA_" + t.name[3:].upper() + " " + str(i))
     i += 1
     i += 1
@@ -327,10 +354,8 @@ printc('''/**
 const UA_DataTypeLayout *UA_TYPES = (const UA_DataTypeLayout[]){''')
 const UA_DataTypeLayout *UA_TYPES = (const UA_DataTypeLayout[]){''')
 
 
 for t in types.itervalues():
 for t in types.itervalues():
-    if type(t) == BuiltinType and not args.is_ns0:
-        continue
     printc("")
     printc("")
-    printc("/* " + t.name + "*/")
+    printc("/* " + t.name + " */")
     printc(t.typelayout_c() + ",")
     printc(t.typelayout_c() + ",")
 
 
 printc("};")
 printc("};")