浏览代码

fix(nc): Correcting code generation for OptionSet datatypes (bitmasks)

Previously all enumerations had 32 bits size, regardless of
'IsOptionSet' or 'LengthInBits' attribute of .bsd file.
This led to incorrect type sizes for OptionSets with 'LengthInBits' != 32.
Now we use an unsigned integer type for OptionSets which is large enough
to represent the indicated 'LenghtInBits' attribute.

Fixes #3149
fem 5 年之前
父节点
当前提交
9a795903c6
共有 2 个文件被更改,包括 50 次插入8 次删除
  1. 14 8
      tools/nodeset_compiler/backend_open62541_typedefinitions.py
  2. 36 0
      tools/nodeset_compiler/type_parser.py

+ 14 - 8
tools/nodeset_compiler/backend_open62541_typedefinitions.py

@@ -72,7 +72,7 @@ class CGenerator(object):
         if isinstance(datatype,  BuiltinType):
             return makeCIdentifier("UA_TYPES_" + datatype.name.upper())
         if isinstance(datatype, EnumerationType):
-            return "UA_TYPES_INT32"
+            return datatype.strTypeIndex;
 
         if datatype.name is not None:
             return "UA_" + makeCIdentifier(datatype.outname.upper() + "_" + datatype.name.upper())
@@ -83,7 +83,7 @@ class CGenerator(object):
         if isinstance(datatype, BuiltinType):
             return "UA_DATATYPEKIND_" + datatype.name.upper()
         if isinstance(datatype, EnumerationType):
-            return "UA_DATATYPEKIND_ENUM"
+            return datatype.strTypeKind
         if isinstance(datatype, OpaqueType):
             return "UA_DATATYPEKIND_" + datatype.base_type.upper()
         if isinstance(datatype, StructType):
@@ -227,12 +227,18 @@ class CGenerator(object):
             values = enum.elements.iteritems()
         else:
             values = enum.elements.items()
-        return "typedef enum {\n    " + ",\n    ".join(
-            map(lambda kv: makeCIdentifier("UA_" + enum.name.upper() + "_" + kv[0].upper()) +
-                           " = " + kv[1], values)) + \
-               ",\n    __UA_{0}_FORCE32BIT = 0x7fffffff\n".format(makeCIdentifier(enum.name.upper())) + "} " + \
-               "UA_{0};\nUA_STATIC_ASSERT(sizeof(UA_{0}) == sizeof(UA_Int32), enum_must_be_32bit);".format(
-                   makeCIdentifier(enum.name))
+
+        if enum.isOptionSet == True:
+            return "typedef " + enum.strDataType + " " + makeCIdentifier("UA_" + enum.name) + ";\n\n" + "\n".join(
+                map(lambda kv: "#define " + makeCIdentifier("UA_" + enum.name.upper() + "_" + kv[0].upper()) +
+                " " + kv[1], values))
+        else:
+            return "typedef enum {\n    " + ",\n    ".join(
+                map(lambda kv: makeCIdentifier("UA_" + enum.name.upper() + "_" + kv[0].upper()) +
+                               " = " + kv[1], values)) + \
+                   ",\n    __UA_{0}_FORCE32BIT = 0x7fffffff\n".format(makeCIdentifier(enum.name.upper())) + "} " + \
+                   "UA_{0};\nUA_STATIC_ASSERT(sizeof(UA_{0}) == sizeof(UA_Int32), enum_must_be_32bit);".format(
+                       makeCIdentifier(enum.name))
 
     @staticmethod
     def print_struct_typedef(struct):

+ 36 - 0
tools/nodeset_compiler/type_parser.py

@@ -79,6 +79,42 @@ class EnumerationType(Type):
         Type.__init__(self, outname, xml, namespace)
         self.pointerfree = True
         self.elements = OrderedDict()
+        self.isOptionSet = True if xml.get("IsOptionSet", "false") == "true" else False
+        self.lengthInBits = 0
+        try:
+            self.lengthInBits = int(xml.get("LengthInBits", "32"))
+        except ValueError as ex:
+            raise Exception("Error at EnumerationType '" + self.name + "': 'LengthInBits' XML attribute '" +
+                xml.get("LengthInBits") + "' is not convertible to integer. " +
+                "Exception: {0}".format(ex));
+
+        # default values for enumerations (encoded as int32):
+        self.strDataType = "UA_Int32"
+        self.strTypeKind = "UA_DATATYPEKIND_ENUM"
+        self.strTypeIndex = "UA_TYPES_INT32"
+
+        # special handling for OptionSet datatype (bitmask)
+        if self.isOptionSet == True:
+            if self.lengthInBits <= 8:
+                self.strDataType = "UA_Byte"
+                self.strTypeKind = "UA_DATATYPEKIND_BYTE"
+                self.strTypeIndex = "UA_TYPES_BYTE"
+            elif self.lengthInBits <= 16:
+                self.strDataType = "UA_UInt16"
+                self.strTypeKind = "UA_DATATYPEKIND_UINT16"
+                self.strTypeIndex = "UA_TYPES_UINT16"
+            elif self.lengthInBits <= 32:
+                self.strDataType = "UA_UInt32"
+                self.strTypeKind = "UA_DATATYPEKIND_UINT32"
+                self.strTypeIndex = "UA_TYPES_UINT32"
+            elif self.lengthInBits <= 64:
+                self.strDataType = "UA_UInt64"
+                self.strTypeKind = "UA_DATATYPEKIND_UINT64"
+                self.strTypeIndex = "UA_TYPES_UINT64"
+            else:
+                raise Exception("Error at EnumerationType() CTOR '" + self.name + "': 'LengthInBits' value '" +
+                    self.lengthInBits + "' is not supported");
+
         for child in xml:
             if child.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedValue":
                 self.elements[child.get("Name")] = child.get("Value")