Bladeren bron

NodesetCompiler: Add support for OptionSet

Fixes #2300
Stefan Profanter 5 jaren geleden
bovenliggende
commit
064cf25800

+ 9 - 7
tools/nodeset_compiler/backend_open62541_datatypes.py

@@ -44,15 +44,17 @@ def generateXmlElementCode(value, alloc=False):
     value = makeCLiteral(value)
     return u"UA_XMLELEMENT{}({})".format("_ALLOC" if alloc else "", splitStringLiterals(value))
 
-def generateByteStringCode(value, valueName, global_var_code):
-    asciiarray = [ord(c) for c in value.strip()]
+def generateByteStringCode(value, valueName, global_var_code, isPointer):
+    asciiarray = list(value)
     asciiarraystr = str(asciiarray).rstrip(']').lstrip('[')
-    global_var_code.append("static const UA_Byte {instance}_byteArray[{len}] = {{{data}}};".format(
-        len=len(asciiarray), data=asciiarraystr, instance=valueName
+    cleanValueName = re.sub(r"->", "__", re.sub(r"\.", "_", valueName))
+    global_var_code.append("static const UA_Byte {cleanValueName}_byteArray[{len}] = {{{data}}};".format(
+        len=len(asciiarray), data=asciiarraystr, cleanValueName=cleanValueName
     ))
     # Cast away const with '(UA_Byte *)(void*)(uintptr_t)' since we know that UA_Server_addNode_begin will copy the content
-    return "{instance}->length = {len};\n{instance}->data = (UA_Byte *)(void*)(uintptr_t){instance}_byteArray;"\
-                                                .format(len=len(asciiarray), instance=valueName)
+    return "{instance}{accessor}length = {len};\n{instance}{accessor}data = (UA_Byte *)(void*)(uintptr_t){cleanValueName}_byteArray;"\
+                                                .format(len=len(asciiarray), instance=valueName, cleanValueName=cleanValueName,
+                                                        accessor='->' if isPointer else '.')
 
 def generateLocalizedTextCode(value, alloc=False):
     vt = makeCLiteral(value.text)
@@ -97,7 +99,7 @@ def generateNodeValueCode(prepend , node, instanceName, valueName, global_var_co
     elif type(node) == ByteString:
         # replace whitespaces between tags and remove newlines
         return prepend + "UA_BYTESTRING_NULL;" if not node.value else generateByteStringCode(
-            re.sub(r">\s*<", "><", re.sub(r"[\r\n]+", "", node.value)), valueName, global_var_code)
+            node.value, valueName, global_var_code, isPointer=asIndirect)
         # the replacements done here is just for the array form can be workable in C code. It doesn't couses any problem
         # because the core data used here is already in byte form. So, there is no way we disturb it.
     elif type(node) == LocalizedText:

+ 2 - 2
tools/nodeset_compiler/datatypes.py

@@ -263,7 +263,7 @@ class Value(object):
                 logger.error(str(parent.id) + ": Expected ExtensionObject to hold a variable of type " + str(parentDataTypeNode.browseName) + " but found nothing.")
                 return None
 
-            if not ebodypart.localName == parentDataTypeNode.browseName.name:
+            if not ebodypart.localName == "OptionSet" and not ebodypart.localName == parentDataTypeNode.browseName.name:
                 logger.error(str(parent.id) + ": Expected ExtensionObject to hold a variable of type " + str(parentDataTypeNode.browseName) + " but found " +
                              str(ebodypart.localName) + " instead.")
                 return None
@@ -449,7 +449,7 @@ class ByteString(Value):
         if xmlvalue.firstChild is None:
             self.value = []  # Catch XML <ByteString /> by setting the value to a default
         else:
-            self.value = b64decode(xmlvalue.firstChild.data).decode("utf-8")
+            self.value = b64decode(xmlvalue.firstChild.data)
 
 class ExtensionObject(Value):
     def __init__(self, xmlelement=None):

+ 32 - 15
tools/nodeset_compiler/nodes.py

@@ -389,6 +389,7 @@ class DataTypeNode(Node):
         self.__encodingBuilt__ = False
         self.__definition__ = []
         self.__isEnum__     = False
+        self.__isOptionSet__ = False
         if xmlelement:
             DataTypeNode.parseXML(self, xmlelement)
 
@@ -491,22 +492,27 @@ class DataTypeNode(Node):
             logger.debug("")
             return self.__baseTypeEncoding__
 
-        if self.__xmlDefinition__ is None:
-            # Check if there is a supertype available
-            for ref in self.references:
-                if ref.isForward:
-                    continue
+
+        # Check if there is a supertype available
+        parentType = None
+        for ref in self.references:
+            if ref.isForward:
+                continue
                 # hasSubtype
-                if ref.referenceType.i == 45:
-                    targetNode = nodeset.nodes[ref.target]
-                    if targetNode is not None and isinstance(targetNode, DataTypeNode):
-                        logger.debug( prefix + "Attempting definition using supertype " + str(targetNode.browseName) + " for DataType " + " " + str(self.browseName))
-                        subenc = targetNode.buildEncoding(nodeset=nodeset, indent=indent+1)
-                        if not targetNode.isEncodable():
-                            self.__encodable__ = False
-                            break
-                        else:
-                            self.__baseTypeEncoding__ = self.__baseTypeEncoding__ + [self.browseName.name, subenc, None]
+            if ref.referenceType.i == 45:
+                targetNode = nodeset.nodes[ref.target]
+                if targetNode is not None and isinstance(targetNode, DataTypeNode):
+                    parentType = targetNode
+                    break
+
+        if self.__xmlDefinition__ is None:
+            if parentType is not None:
+                logger.debug( prefix + "Attempting definition using supertype " + str(targetNode.browseName) + " for DataType " + " " + str(self.browseName))
+                subenc = targetNode.buildEncoding(nodeset=nodeset, indent=indent+1)
+                if not targetNode.isEncodable():
+                    self.__encodable__ = False
+                else:
+                    self.__baseTypeEncoding__ = self.__baseTypeEncoding__ + [self.browseName.name, subenc, None]
             if len(self.__baseTypeEncoding__) == 0:
                 logger.debug(prefix + "No viable definition for " + str(self.browseName) + " " + str(self.id) + " found.")
                 self.__encodable__ = False
@@ -522,6 +528,7 @@ class DataTypeNode(Node):
 
         isEnum = True
         isSubType = True
+        isOptionSet = parentType is not None and parentType.id.ns == 0 and parentType.id.i==12755
 
         # We need to store the definition as ordered data, but can't use orderedDict
         # for backward compatibility with Python 2.6 and 3.4
@@ -593,6 +600,16 @@ class DataTypeNode(Node):
         while len(self.__baseTypeEncoding__) == 1 and isinstance(self.__baseTypeEncoding__[0], list):
             self.__baseTypeEncoding__ = self.__baseTypeEncoding__[0]
 
+        if isOptionSet == True:
+            self.__isOptionSet__ = True
+            subenc = parentType.getEncoding()
+            if not parentType.isEncodable():
+                self.__encodable__ = False
+            else:
+                self.__baseTypeEncoding__ = self.__baseTypeEncoding__ + [self.browseName.name, subenc, None]
+                self.__definition__ = enumDict
+            return self.__baseTypeEncoding__
+
         if isEnum == True:
             self.__baseTypeEncoding__ = self.__baseTypeEncoding__ + ['Int32']
             self.__definition__ = enumDict