Selaa lähdekoodia

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 vuotta sitten
vanhempi
commit
9a795903c6

+ 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")