浏览代码

refactor the open62541 code generation backend into a separate module

Julius Pfrommer 8 年之前
父节点
当前提交
a097b30f1f

+ 7 - 9
tools/pyUANamespace/README.md

@@ -3,8 +3,6 @@ pyUANamespace
 
 pyUANamespace is a collection of python 2 scripts that can parse OPC UA XML Namespace definition files and transform them into a class representation. This facilitates both reprinting the namespace in a different non-XML format (such as C-Code or DOT) and analysis of the namespace structure.
 
-
-
 ### Documentation
 
 The pyUANamespace implementation has been contributed by a research project of the chair for Process Control Systems Engineering of the TU Dresden. It was not strictly speaking created as a C generator, but could be easily modified to fullfill this role for open62541.
@@ -80,7 +78,7 @@ Further attributes may be added at a later point depending on demand.
 
 OPC UA node types, base data types and references are described in ua_node_types.py and ua_builtin_types.py. These classes are primarily intended to act as part of an AST to parse OPC UA Namespace description files. They implement a hierarchic/rekursive parsing of XML DOM objects, supplementing their respective properties from the XML description.
 
-A manager class called ua_namespace is included in the respective source file. This class does _not_ correspond to a OPC UA Namespace. It is an aggregator and manager for nodes and references which may belong to any number of namespaces. This class includes extensive parsing/validation to ensure that a complete and consistent namespace is generated.
+A manager class called NodeSet is included in the respective source file. This class does _not_ correspond to a OPC UA Namespace. It is an aggregator and manager for nodes and references which may belong to any number of namespaces. This class includes extensive parsing/validation to ensure that a complete and consistent namespace is generated.
 
 ## Namespace compilation internals
 
@@ -92,15 +90,15 @@ Compiling a namespace consists of the following steps:
 - Parse/Allocate variable values according to their dataType definitions
 
 
-Reading and parsing XML files is handled by ua_namespace.parseXML(/path/to/file.xml). It is the first part of a multipass compiler that will create all nodes contained in the XML description.
+Reading and parsing XML files is handled by NodeSet.parseXML(/path/to/file.xml). It is the first part of a multipass compiler that will create all nodes contained in the XML description.
 
 During the reading of XML files, nodes will attempt to parse any attributes they own, but not refer to any other nodes. References will be kept as XML descriptions. Any number of XML files can be read in this phase. __NOTE__: In the open62541 (this) implementation, duplicate nodes (same NodeId) are allowed. The last definition encountered will be kept. This allows overwriting specific nodes of a much larger XML file to with implementation specific nodes.
 
-The next phase of the compilation is to link all references. The phase is called by ua_namespace.linkOpenPointers(). All references will attempt to locate their target() node in the namespace and point to it.
+The next phase of the compilation is to link all references. The phase is called by NodeSet.linkOpenPointers(). All references will attempt to locate their target() node in the namespace and point to it.
 
-During the sanitation phase called by ua_namespace.sanitize(), nodes check themselves for invalid attributes. Most notably any references that could not be resolved to a node will be removed from the nodes.
+During the sanitation phase called by NodeSet.sanitize(), nodes check themselves for invalid attributes. Most notably any references that could not be resolved to a node will be removed from the nodes.
 
-When calling ua_namespace.buildEncodingRules(), dataType nodes are examined to determine if and how the can be encoded as a serialization of OPC UA builtin types as well as their aliases.
+When calling NodeSet.buildEncodingRules(), dataType nodes are examined to determine if and how the can be encoded as a serialization of OPC UA builtin types as well as their aliases.
 
 The following fragment of a variable value can illustrate the necessity for determining encoding rules:
 ```xml
@@ -123,7 +121,7 @@ LastMethodOutputArguments : Argument -> i=296
 
 DataTypes that cannot be encoded as a definite serial object (e.g. by having a member of NumericType, but not a specific one), will have their isEncodable() attribute disabled. All dataTypes that complete this node can be used to effectively determine the size and serialization properties of any variables.
 
-Having encoding rules means that data can now be parsed when a <Value> tag is encountered in a description. Calling ua_namespace.allocateVariables() will do just that for any variable node that holds XML Values.
+Having encoding rules means that data can now be parsed when a <Value> tag is encountered in a description. Calling NodeSet.allocateVariables() will do just that for any variable node that holds XML Values.
 
 The result of this compilation is a completely linked and instantiated OPC UA namespace.
 
@@ -131,7 +129,7 @@ An example compiler can be built as follows:
 ```python
 class testing:
   def __init__(self):
-    self.namespace = opcua_namespace("testing")
+    self.namespace = NodeSet("testing")
 
     log(self, "Phase 1: Reading XML file nodessets")
     self.namespace.parseXML("Opc.Ua.NodeSet2.xml")

+ 9 - 9
tools/pyUANamespace/generate_open62541CCode.py

@@ -24,8 +24,9 @@ from __future__ import print_function
 import logging
 import argparse
 from os.path import basename
-from ua_namespace import *
+from ua_nodeset import *
 from open62541_XMLPreprocessor import open62541_XMLPreprocessor
+from open62541_backend import generateCCode
 
 parser = argparse.ArgumentParser(
   description="""Parse OPC UA NodeSetXML file(s) and create C code for generating nodes in open62541
@@ -95,7 +96,7 @@ outfileh = open(args.outputFile+".h", r"w+")
 outfilec = open(args.outputFile+".c", r"w+")
 
 # Create a new nodeset. The nodeset name is not significant.
-ns = opcua_namespace("open62541")
+ns = NodeSet("open62541")
 
 # Clean up the XML files by removing duplicate namespaces and unwanted prefixes
 preProc = open62541_XMLPreprocessor()
@@ -163,14 +164,13 @@ for ignore in args.ignoreFiles:
       ignoreNodes.append(ns.getNodeByIDString(id))
   ignore.close()
 
-# Create the C Code
-logger.info("Generating Header")
-# Returns a tuple of (["Header","lines"],["Code","lines","generated"])
-
-generatedCode = ns.printOpen62541Header(ignoreNodes, args.suppressedAttributes, outfilename=basename(args.outputFile))
-for line in generatedCode[0]:
+# Create the C code with the open62541 backend of the compiler
+logger.info("Generating Code")
+(header, code) = generateCCode( ns,ignoreNodes, args.suppressedAttributes,
+                                        outfilename=basename(args.outputFile))
+for line in header:
   print(line, end='\n', file=outfileh)
-for line in generatedCode[1]:
+for line in code:
   print(line, end='\n', file=outfilec)
 
 outfilec.close()

+ 0 - 256
tools/pyUANamespace/open62541_MacroHelper.py

@@ -1,256 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-###
-### Author:  Chris Iatrou (ichrispa@core-vector.net)
-### Version: rev 13
-###
-### This program was created for educational purposes and has been
-### contributed to the open62541 project by the author. All licensing
-### terms for this source is inherited by the terms and conditions
-### specified for by the open62541 project (see the projects readme
-### file for more information on the MPLv2 terms and restrictions).
-###
-### This program is not meant to be used in a production environment. The
-### author is not liable for any complications arising due to the use of
-### this program.
-###
-
-import logging
-from ua_constants import *
-import string
-
-
-logger = logging.getLogger(__name__)
-
-__unique_item_id = 0
-
-defined_typealiases = []
-
-class open62541_MacroHelper():
-  def __init__(self, supressGenerationOfAttribute=[]):
-    self.supressGenerationOfAttribute = supressGenerationOfAttribute
-
-  def getCreateExpandedNodeIDMacro(self, node):
-    if node.id().i != None:
-      return "UA_EXPANDEDNODEID_NUMERIC(%s, %s)" % (str(node.id().ns),str(node.id().i))
-    elif node.id().s != None:
-      return "UA_EXPANDEDNODEID_STRING(%s, %s)" % (str(node.id().ns), node.id().s)
-    elif node.id().b != None:
-      logger.debug("NodeID Generation macro for bytestrings has not been implemented.")
-      return ""
-    elif node.id().g != None:
-      logger.debug("NodeID Generation macro for guids has not been implemented.")
-      return ""
-    else:
-      return ""
-
-  def substitutePunctuationCharacters(self, input):
-    ''' substitutePunctuationCharacters
-
-        Replace punctuation characters in input. Part of this class because it is used by
-        ua_namespace on occasion.
-
-        returns: C-printable string representation of input
-    '''
-    # No punctuation characters <>!$
-    for illegal_char in list(string.punctuation):
-        if illegal_char == '_': # underscore is allowed
-            continue
-        input = input.replace(illegal_char, "_") # map to underscore
-    return input
-
-  def getNodeIdDefineString(self, node):
-    extrNs = node.browseName().split(":")
-    symbolic_name = ""
-    # strip all characters that would be illegal in C-Code
-    if len(extrNs) > 1:
-        nodename = extrNs[1]
-    else:
-        nodename = extrNs[0]
-
-    symbolic_name = self.substitutePunctuationCharacters(nodename)
-    if symbolic_name != nodename :
-        logger.warn("Substituted characters in browsename for nodeid " + str(node.id().i) + " while generating C-Code ")
-
-    if symbolic_name in defined_typealiases:
-      logger.warn(self, "Typealias definition of " + str(node.id().i) + " is non unique!")
-      extendedN = 1
-      while (symbolic_name+"_"+str(extendedN) in defined_typealiases):
-        logger.warn("Typealias definition of " + str(node.id().i) + " is non unique!")
-        extendedN+=1
-      symbolic_name = symbolic_name+"_"+str(extendedN)
-
-    defined_typealiases.append(symbolic_name)
-
-    code.append("#define UA_NS%sID_%s %s" % (str(node.id().ns), symbolic_name.upper(),str(node.id().i)))
-    return code
-
-  def getCreateNodeIDMacro(self, node):
-    if node.id().i != None:
-      return "UA_NODEID_NUMERIC(%s, %s)" % (str(node.id().ns),str(node.id().i))
-    elif node.id().s != None:
-      return "UA_NODEID_STRING(%s, %s)" % (str(node.id().ns), node.id().s)
-    elif node.id().b != None:
-      logger.debug("NodeID Generation macro for bytestrings has not been implemented.")
-      return ""
-    elif node.id().g != None:
-      logger.debug("NodeID Generation macro for guids has not been implemented.")
-      return ""
-    else:
-      return ""
-
-  def getCreateStandaloneReference(self, sourcenode, reference):
-    code = []
-
-    if reference.isForward():
-      code.append("UA_Server_addReference(server, %s, %s, %s, true);" % (self.getCreateNodeIDMacro(sourcenode), self.getCreateNodeIDMacro(reference.referenceType()), self.getCreateExpandedNodeIDMacro(reference.target())))
-    else:
-      code.append("UA_Server_addReference(server, %s, %s, %s, false);" % (self.getCreateNodeIDMacro(sourcenode), self.getCreateNodeIDMacro(reference.referenceType()), self.getCreateExpandedNodeIDMacro(reference.target())))
-    return code
-
-  def getCreateNodeNoBootstrap(self, node, parentNode, parentReference, unprintedNodes=[]):
-    code = []
-    code.append("// Node: %s, %s" % (str(node), str(node.browseName())))
-
-    if node.nodeClass() == NODE_CLASS_OBJECT:
-      nodetype = "Object"
-    elif node.nodeClass() == NODE_CLASS_VARIABLE:
-      nodetype = "Variable"
-    elif node.nodeClass() == NODE_CLASS_METHOD:
-      nodetype = "Method"
-    elif node.nodeClass() == NODE_CLASS_OBJECTTYPE:
-      nodetype = "ObjectType"
-    elif node.nodeClass() == NODE_CLASS_REFERENCETYPE:
-      nodetype = "ReferenceType"
-    elif node.nodeClass() == NODE_CLASS_VARIABLETYPE:
-      nodetype = "VariableType"
-    elif node.nodeClass() == NODE_CLASS_DATATYPE:
-      nodetype = "DataType"
-    elif node.nodeClass() == NODE_CLASS_VIEW:
-      nodetype = "View"
-    else:
-      code.append("/* undefined nodeclass */")
-      return code;
-
-    # If this is a method, construct in/outargs for addMethod
-    #inputArguments.arrayDimensionsSize = 0;
-    #inputArguments.arrayDimensions = NULL;
-    #inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
-
-    # Node ordering should have made sure that arguments, if they exist, have not been printed yet
-    if node.nodeClass() == NODE_CLASS_METHOD:
-        inArgVal = []
-        outArgVal = []
-        code.append("UA_Argument *inputArguments = NULL;")
-        code.append("UA_Argument *outputArguments = NULL;")
-        for r in node.getReferences():
-            if r.isForward():
-                if r.target() != None and r.target().nodeClass() == NODE_CLASS_VARIABLE and r.target().browseName() == 'InputArguments':
-                    while r.target() in unprintedNodes:
-                        unprintedNodes.remove(r.target())
-                    if r.target().value() != None:
-                        inArgVal = r.target().value().value
-                elif r.target() != None and r.target().nodeClass() == NODE_CLASS_VARIABLE and r.target().browseName() == 'OutputArguments':
-                    while r.target() in unprintedNodes:
-                        unprintedNodes.remove(r.target())
-                    if r.target().value() != None:
-                        outArgVal = r.target().value().value
-        if len(inArgVal)>0:
-            code.append("")
-            code.append("inputArguments = (UA_Argument *) UA_malloc(sizeof(UA_Argument) * " + str(len(inArgVal)) + ");")
-            code.append("int inputArgumentCnt;")
-            code.append("for (inputArgumentCnt=0; inputArgumentCnt<" + str(len(inArgVal)) + "; ++inputArgumentCnt) UA_Argument_init(&inputArguments[inputArgumentCnt]); ")
-            argumentCnt = 0
-            for inArg in inArgVal:
-                if inArg.getValueFieldByAlias("Description") != None:
-                    code.append("inputArguments[" + str(argumentCnt) + "].description = UA_LOCALIZEDTEXT(\"" + str(inArg.getValueFieldByAlias("Description")[0]) + "\",\"" + str(inArg.getValueFieldByAlias("Description")[1]) + "\");")
-                if inArg.getValueFieldByAlias("Name") != None:
-                    code.append("inputArguments[" + str(argumentCnt) + "].name = UA_STRING(\"" + str(inArg.getValueFieldByAlias("Name")) + "\");")
-                if inArg.getValueFieldByAlias("ValueRank") != None:
-                    code.append("inputArguments[" + str(argumentCnt) + "].valueRank = " + str(inArg.getValueFieldByAlias("ValueRank")) + ";")
-                if inArg.getValueFieldByAlias("DataType") != None:
-                    code.append("inputArguments[" + str(argumentCnt) + "].dataType = " + str(self.getCreateNodeIDMacro(inArg.getValueFieldByAlias("DataType"))) + ";")
-                #if inArg.getValueFieldByAlias("ArrayDimensions") != None:
-                #  code.append("inputArguments[" + str(argumentCnt) + "].arrayDimensions = " + str(inArg.getValueFieldByAlias("ArrayDimensions")) + ";")
-                argumentCnt += 1
-        if len(outArgVal)>0:
-            code.append("")
-            code.append("outputArguments = (UA_Argument *) UA_malloc(sizeof(UA_Argument) * " + str(len(outArgVal)) + ");")
-            code.append("int outputArgumentCnt;")
-            code.append("for (outputArgumentCnt=0; outputArgumentCnt<" + str(len(outArgVal)) + "; ++outputArgumentCnt) UA_Argument_init(&outputArguments[outputArgumentCnt]); ")
-            argumentCnt = 0
-            for outArg in outArgVal:
-                if outArg.getValueFieldByAlias("Description") != None:
-                    code.append("outputArguments[" + str(argumentCnt) + "].description = UA_LOCALIZEDTEXT(\"" + str(outArg.getValueFieldByAlias("Description")[0]) + "\",\"" + str(outArg.getValueFieldByAlias("Description")[1]) + "\");")
-                if outArg.getValueFieldByAlias("Name") != None:
-                    code.append("outputArguments[" + str(argumentCnt) + "].name = UA_STRING(\"" + str(outArg.getValueFieldByAlias("Name")) + "\");")
-                if outArg.getValueFieldByAlias("ValueRank") != None:
-                    code.append("outputArguments[" + str(argumentCnt) + "].valueRank = " + str(outArg.getValueFieldByAlias("ValueRank")) + ";")
-                if outArg.getValueFieldByAlias("DataType") != None:
-                    code.append("outputArguments[" + str(argumentCnt) + "].dataType = " + str(self.getCreateNodeIDMacro(outArg.getValueFieldByAlias("DataType"))) + ";")
-                #if outArg.getValueFieldByAlias("ArrayDimensions") != None:
-                #  code.append("outputArguments[" + str(argumentCnt) + "].arrayDimensions = " + str(outArg.getValueFieldByAlias("ArrayDimensions")) + ";")
-                argumentCnt += 1
-
-    # print the attributes struct
-    code.append("UA_%sAttributes attr = UA_%sAttributes_default;" % (nodetype, nodetype))
-    code.append("attr.displayName = UA_LOCALIZEDTEXT(\"\", \"" + str(node.displayName()) + "\");")
-    code.append("attr.description = UA_LOCALIZEDTEXT(\"\", \"" + str(node.description()) + "\");")
-    
-    if nodetype == "Variable":
-      code.append("attr.accessLevel = %s;"     % str(node.accessLevel()))
-      code.append("attr.userAccessLevel = %s;" % str(node.userAccessLevel()))
-    if nodetype in ["Variable", "VariableType"]:
-      code.append("attr.valueRank = %s;"       % str(node.valueRank()))
-
-    if nodetype in ["Variable", "VariableType"]:
-      code.extend(node.printOpen62541CCode_SubtypeEarly(bootstrapping = False))
-    elif nodetype == "Method":
-      if node.executable():
-        code.append("attr.executable = true;")
-      if node.userExecutable():
-        code.append("attr.userExecutable = true;")
-
-    code.append("UA_NodeId nodeId = %s;" % str(self.getCreateNodeIDMacro(node)))
-    if nodetype in ["Object", "Variable", "VariableType"]:
-      typeDefinition = None
-      for r in node.getReferences():
-        if r.isForward() and r.referenceType().id().ns == 0 and r.referenceType().id().i == 40:
-          typeDefinition = r.target()
-      if typeDefinition == None:
-        # FIXME: We might want to resort to BaseXYTTypes here?
-        code.append("UA_NodeId typeDefinition = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);")
-      else:
-        code.append("UA_NodeId typeDefinition = " + str(self.getCreateNodeIDMacro(typeDefinition)) + ";")
-    code.append("UA_NodeId parentNodeId = %s;" % str(self.getCreateNodeIDMacro(parentNode)))
-    code.append("UA_NodeId parentReferenceNodeId = %s;" % str(self.getCreateNodeIDMacro(parentReference.referenceType())))
-    extrNs = node.browseName().split(":")
-    if len(extrNs) > 1:
-      code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(%s, \"%s\");" % (str(extrNs[0]), extrNs[1]))
-    else:
-      code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(0, \"%s\");" % str(node.browseName()))
-
-    # In case of a MethodNode: Add in|outArg struct generation here. Mandates that namespace reordering was done using
-    # Djikstra (check that arguments have not been printed). (@ichrispa)
-    code.append("UA_Server_add%sNode(server, nodeId, parentNodeId, parentReferenceNodeId, nodeName" % nodetype)
-
-    if nodetype in ["Object", "Variable", "VariableType"]:
-      code.append("       , typeDefinition")
-    if nodetype != "Method":
-      code.append("       , attr, NULL, NULL);")
-    else:
-      code.append("       , attr, (UA_MethodCallback) NULL, NULL, %s, inputArguments,  %s, outputArguments, NULL);" % (str(len(inArgVal)), str(len(outArgVal))))
-
-    #Adding a Node with typeDefinition = UA_NODEID_NULL will create a HasTypeDefinition reference to BaseDataType - remove it since
-    #a real Reference will be add in a later step (a single HasTypeDefinition reference is assumed here)
-    #The current API does not let us specify IDs of Object's subelements.
-    if nodetype is "Object":
-      code.append("UA_Server_deleteReference(server, nodeId, UA_NODEID_NUMERIC(0, 40), true, UA_EXPANDEDNODEID_NUMERIC(0, 58), true); //remove HasTypeDefinition refs generated by addObjectNode");
-    if nodetype is "Variable":
-      code.append("UA_Server_deleteReference(server, nodeId, UA_NODEID_NUMERIC(0, 40), true, UA_EXPANDEDNODEID_NUMERIC(0, 62), true); //remove HasTypeDefinition refs generated by addVariableNode");
-    return code

+ 7 - 10
tools/pyUANamespace/open62541_XMLPreprocessor.py

@@ -185,11 +185,9 @@ class preProcessDocument:
     os.close(outfile)
 
   def reassignReferencedNamespaceId(self, currentNsId, newNsId):
-    """ Iterates over all references in this document, find references to currentNsId and changes them to newNsId.
-        NodeIds themselves are not altered.
-
-        returns: nothing
-    """
+    """Iterates over all references in this document, find references to
+       currentNsId and changes them to newNsId. NodeIds themselves are not
+       altered."""
     for refNd in self.referencedNodes:
       if refNd[0].ns == currentNsId:
         refNd[1].firstChild.data = refNd[1].firstChild.data.replace("ns="+str(currentNsId), "ns="+str(newNsId))
@@ -197,10 +195,8 @@ class preProcessDocument:
         refNd[0].toString()
 
   def reassignNamespaceId(self, currentNsId, newNsId):
-    """ Iterates over all nodes in this document, find those in namespace currentNsId and changes them to newNsId.
-
-        returns: nothing
-    """
+    """Iterates over all nodes in this document, find those in namespace
+       currentNsId and changes them to newNsId."""
 
     #change ids in aliases
     ns = self.nodeset.getElementsByTagName("Alias")
@@ -218,7 +214,8 @@ class preProcessDocument:
             refNd[1].firstChild.data = refNd[1].firstChild.data.replace("ns="+str(currentNsId), "ns="+str(newNsId))
             refNd[0].ns = newNsId
             refNd[0].toString()
-        nd[1].setAttribute(u'NodeId', nd[1].getAttribute(u'NodeId').replace("ns="+str(currentNsId), "ns="+str(newNsId)))
+        nd[1].setAttribute(u'NodeId', nd[1].getAttribute(u'NodeId').replace("ns="+str(currentNsId),
+                                                                            "ns="+str(newNsId)))
         nd[0].ns = newNsId
         nd[0].toString()
 

+ 205 - 0
tools/pyUANamespace/open62541_backend.py

@@ -0,0 +1,205 @@
+#!/usr/bin/env/python
+# -*- coding: utf-8 -*-
+
+###
+### Author:  Chris Iatrou (ichrispa@core-vector.net)
+### Version: rev 13
+###
+### This program was created for educational purposes and has been
+### contributed to the open62541 project by the author. All licensing
+### terms for this source is inherited by the terms and conditions
+### specified for by the open62541 project (see the projects readme
+### file for more information on the LGPL terms and restrictions).
+###
+### This program is not meant to be used in a production environment. The
+### author is not liable for any complications arising due to the use of
+### this program.
+###
+
+import string
+import logging; logger = logging.getLogger(__name__)
+
+from ua_constants import *
+from open62541_backend_nodes import Node_printOpen62541CCode, getCreateStandaloneReference
+
+####################
+# Helper Functions #
+####################
+
+def substitutePunctuationCharacters(input):
+    # No punctuation characters <>!$
+    for illegal_char in list(string.punctuation):
+        if illegal_char == '_': # underscore is allowed
+            continue
+        input = input.replace(illegal_char, "_") # map to underscore
+    return input
+
+defined_typealiases = []
+def getNodeIdDefineString(node):
+    extrNs = node.browseName().split(":")
+    symbolic_name = ""
+    # strip all characters that would be illegal in C-Code
+    if len(extrNs) > 1:
+        nodename = extrNs[1]
+    else:
+        nodename = extrNs[0]
+
+    symbolic_name = substitutePunctuationCharacters(nodename)
+    if symbolic_name != nodename :
+        logger.warn("Substituted characters in browsename for nodeid " + \
+                    str(node.id().i) + " while generating C-Code ")
+    if symbolic_name in defined_typealiases:
+      logger.warn("Typealias definition of " + str(node.id().i) + " is non unique!")
+      extendedN = 1
+      while (symbolic_name+"_"+str(extendedN) in defined_typealiases):
+        logger.warn("Typealias definition of " + str(node.id().i) + " is non unique!")
+        extendedN+=1
+      symbolic_name = symbolic_name+"_"+str(extendedN)
+    defined_typealiases.append(symbolic_name)
+    return "#define UA_NS%sID_%s %s" % (node.id().ns, symbolic_name.upper(), node.id().i)
+
+###################
+# Generate C Code #
+###################
+
+def generateCCode(nodeset, printedExternally=[], supressGenerationOfAttribute=[],
+                  outfilename="", high_level_api=False):
+    unPrintedNodes = []
+    unPrintedRefs  = []
+    code = []
+    header = []
+
+    # Reorder our nodes to produce a bare minimum of bootstrapping dependencies
+    logger.debug("Reordering nodes for minimal dependencies during printing.")
+    nodeset.reorderNodesMinDependencies(printedExternally)
+
+    # Populate the unPrinted-Lists with everything we have. Every Time a nodes
+    # printfunction is called, it will pop itself and all printed references
+    # from these lists.
+    for n in nodeset.nodes:
+      if not n in printedExternally:
+        unPrintedNodes.append(n)
+      else:
+        logger.debug("Node " + str(n.id()) + " is being ignored.")
+    for n in unPrintedNodes:
+      for r in n.getReferences():
+        if (r.target() != None) and (r.target().id() != None) and (r.parent() != None):
+          unPrintedRefs.append(r)
+    logger.debug("%d nodes and %d references need to get printed.", len(unPrintedNodes), len(unPrintedRefs))
+
+    # Print the preamble of the generated code
+    header.append("/* WARNING: This is a generated file.\n * Any manual changes will be overwritten.\n\n */")
+    code.append("/* WARNING: This is a generated file.\n * Any manual changes will be overwritten.\n\n */")
+    header.append('#ifndef '+outfilename.upper()+'_H_')
+    header.append('#define '+outfilename.upper()+'_H_')
+    header.append('#ifdef UA_NO_AMALGAMATION')
+    header.append('#include "ua_types.h"')
+    if high_level_api:
+        header.append('#include "ua_job.h"')
+        header.append('#include "ua_server.h"')
+    if not high_level_api:
+        header.append('#include "server/ua_server_internal.h"')
+        header.append('#include "server/ua_nodes.h"')
+        header.append('#include "ua_util.h"')
+        header.append('#include "ua_types_encoding_binary.h"')
+        header.append('#include "ua_types_generated_encoding_binary.h"')
+        header.append('#include "ua_transport_generated_encoding_binary.h"')
+    header.append('#else')
+    header.append('#include "open62541.h"')
+    header.append('#define NULL ((void *)0)')
+    header.append('#endif')
+    code.append('#include "'+outfilename+'.h"')
+    code.append("UA_INLINE void "+outfilename+"(UA_Server *server) {")
+
+    # Before printing nodes, we need to request additional namespace arrays from the server
+    for nsid in nodeset.namespaceIdentifiers:
+      if nsid == 0 or nsid==1:
+        continue
+      else:
+        name =  nodeset.namespaceIdentifiers[nsid]
+        name = name.replace("\"","\\\"")
+        code.append("UA_Server_addNamespace(server, \"" + name + "\");")
+
+    # Find all references necessary to create the namespace and
+    # "Bootstrap" them so all other nodes can safely use these referencetypes whenever
+    # they can locate both source and target of the reference.
+    logger.debug("Collecting all references used in the namespace.")
+    refsUsed = []
+    for n in nodeset.nodes:
+      # Since we are already looping over all nodes, use this chance to print NodeId defines
+      if n.id().ns != 0:
+        nc = n.nodeClass()
+        if nc != NODE_CLASS_OBJECT and nc != NODE_CLASS_VARIABLE and nc != NODE_CLASS_VIEW:
+          header.append(getNodeIdDefineString(n))
+
+      # Now for the actual references...
+      for r in n.getReferences():
+        # Only print valid references in namespace 0 (users will not want their refs bootstrapped)
+        if not r.referenceType() in refsUsed and r.referenceType() != None and r.referenceType().id().ns == 0:
+          refsUsed.append(r.referenceType())
+    logger.debug("%d reference types are used in the namespace, which will now get bootstrapped.", len(refsUsed))
+    for r in refsUsed:
+      code.extend(Node_printOpen62541CCode(r, unPrintedNodes, unPrintedRefs, supressGenerationOfAttribute))
+
+    logger.debug("%d Nodes, %d References need to get printed.", len(unPrintedNodes), len(unPrintedRefs))
+
+    if not high_level_api:
+        # Note to self: do NOT - NOT! - try to iterate over unPrintedNodes!
+        #               Nodes remove themselves from this list when printed.
+        logger.debug("Printing all other nodes.")
+        for n in nodeset.nodes:
+          code.extend(Node_printOpen62541CCode(n, unPrintedNodes, unPrintedRefs, supressGenerationOfAttribute))
+
+        if len(unPrintedNodes) != 0:
+          logger.warn("%d nodes could not be translated to code.", len(unPrintedNodes))
+        else:
+          logger.debug("Printing suceeded for all nodes")
+
+        if len(unPrintedRefs) != 0:
+          logger.debug("Attempting to print " + str(len(unPrintedRefs)) + " unprinted references.")
+          tmprefs = []
+          for r in unPrintedRefs:
+            if  not (r.target() not in unPrintedNodes) and not (r.parent() in unPrintedNodes):
+              if not isinstance(r.parent(), opcua_node_t):
+                logger.debug("Reference has no parent!")
+              elif not isinstance(r.parent().id(), opcua_node_id_t):
+                logger.debug("Parents nodeid is not a nodeID!")
+              else:
+                if (len(tmprefs) == 0):
+                  code.append("//  Creating leftover references:")
+                code.extend(getCreateStandaloneReference(r.parent(), r))
+                code.append("")
+                tmprefs.append(r)
+          # Remove printed refs from list
+          for r in tmprefs:
+            unPrintedRefs.remove(r)
+          if len(unPrintedRefs) != 0:
+            logger.warn("" + str(len(unPrintedRefs)) + " references could not be translated to code.")
+        else:
+          logger.debug("Printing succeeded for all references")
+    else:  # Using only High Level API
+        already_printed = list(printedExternally)
+        while unPrintedNodes:
+            node_found = False
+            for node in unPrintedNodes:
+                for ref in node.getReferences():
+                    if ref.referenceType() in already_printed and ref.target() in already_printed:
+                        node_found = True
+                        code.extend(Node_printOpen62541CCode_HL_API(node, ref, supressGenerationOfAttribute))
+                        unPrintedRefs.remove(ref)
+                        unPrintedNodes.remove(node)
+                        already_printed.append(node)
+                        break
+            if not node_found:
+                logger.critical("no complete code generation with high level API possible; not all nodes will be created")
+                code.append("CRITICAL: no complete code generation with high level API possible; not all nodes will be created")
+                break
+        code.append("// creating references")
+        for r in unPrintedRefs:
+            code.extend(getCreateStandaloneReference(r.parent(), r))
+
+    # finalizing source and header
+    header.append("extern void "+outfilename+"(UA_Server *server);\n")
+    header.append("#endif /* "+outfilename.upper()+"_H_ */")
+    code.append("} // closing nodeset()")
+    return (header,code)

+ 716 - 0
tools/pyUANamespace/open62541_backend_nodes.py

@@ -0,0 +1,716 @@
+#!/usr/bin/env/python
+# -*- coding: utf-8 -*-
+
+###
+### Author:  Chris Iatrou (ichrispa@core-vector.net)
+### Version: rev 13
+###
+### This program was created for educational purposes and has been
+### contributed to the open62541 project by the author. All licensing
+### terms for this source is inherited by the terms and conditions
+### specified for by the open62541 project (see the projects readme
+### file for more information on the LGPL terms and restrictions).
+###
+### This program is not meant to be used in a production environment. The
+### author is not liable for any complications arising due to the use of
+### this program.
+###
+
+from ua_node_types import *
+
+####################
+# Helper Functions #
+####################
+
+def getCreateNodeIDMacro(node):
+    if node.id().i != None:
+      return "UA_NODEID_NUMERIC(%s, %s)" % (node.id().ns, node.id().i)
+    elif node.id().s != None:
+      return "UA_NODEID_STRING(%s, %s)" % (node.id().ns, node.id().s)
+    elif node.id().b != None:
+      logger.debug("NodeID Generation macro for bytestrings has not been implemented.")
+      return ""
+    elif node.id().g != None:
+      logger.debug("NodeID Generation macro for guids has not been implemented.")
+      return ""
+    else:
+      return ""
+
+def getCreateExpandedNodeIDMacro(node):
+    if node.id().i != None:
+      return "UA_EXPANDEDNODEID_NUMERIC(%s, %s)" % (str(node.id().ns),str(node.id().i))
+    elif node.id().s != None:
+      return "UA_EXPANDEDNODEID_STRING(%s, %s)" % (str(node.id().ns), node.id().s)
+    elif node.id().b != None:
+      logger.debug("NodeID Generation macro for bytestrings has not been implemented.")
+      return ""
+    elif node.id().g != None:
+      logger.debug("NodeID Generation macro for guids has not been implemented.")
+      return ""
+    else:
+      return ""
+
+def getCreateStandaloneReference(sourcenode, reference):
+    code = []
+    if reference.isForward():
+      code.append("UA_Server_addReference(server, %s, %s, %s, true);" % \
+                  (getCreateNodeIDMacro(sourcenode), getCreateNodeIDMacro(reference.referenceType()), \
+                   getCreateExpandedNodeIDMacro(reference.target())))
+    else:
+      code.append("UA_Server_addReference(server, %s, %s, %s, false);" % \
+                  (getCreateNodeIDMacro(sourcenode), getCreateNodeIDMacro(reference.referenceType()), \
+                   getCreateExpandedNodeIDMacro(reference.target())))
+    return code
+
+
+#################
+# Subtype Early #
+#################
+
+def Node_printOpen62541CCode_SubtypeEarly(node, bootstrapping = True):
+    """ Initiate code segments for the nodes instantiotion that preceed
+        the actual UA_Server_addNode or UA_NodeStore_insert calls.
+    """
+    code = []
+    if isinstance(node, opcua_node_variable_t) or isinstance(node, opcua_node_variableType_t):
+        # If we have an encodable value, try to encode that
+        if node.dataType() != None and isinstance(node.dataType().target(), opcua_node_dataType_t):
+          # Delegate the encoding of the datavalue to the helper if we have
+          # determined a valid encoding
+          if node.dataType().target().isEncodable():
+            if node.value() != None:
+              code.extend(node.value().printOpen62541CCode(bootstrapping))
+              return code
+        if(bootstrapping):
+          code.append("UA_Variant *" + node.getCodePrintableID() + "_variant = UA_alloca(sizeof(UA_Variant));")
+          code.append("UA_Variant_init(" + node.getCodePrintableID() + "_variant);")
+
+    return code
+
+###########
+# Subtype #
+###########
+
+def ReferenceTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
+    code = []
+
+    # Detect if this is bootstrapping or if we are attempting to use userspace...
+    if bootstrapping == False:
+        typeDefs = node.getNamespace().getSubTypesOf() # defaults to TypeDefinition
+        myTypeRef = None
+        for ref in node.getReferences():
+          if ref.referenceType() in typeDefs:
+            myTypeRef = ref
+            break
+        if myTypeRef==None:
+          for ref in node.getReferences():
+            if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
+              myTypeRef = ref
+              break
+        if myTypeRef==None:
+          logger.warn(str(self) + " failed to locate a type definition, assuming BaseDataType.")
+          code.append("       // No valid typeDefinition found; assuming BaseDataType")
+          code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE),")
+        else:
+          code.append("       " + getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
+          while myTypeRef in unPrintedReferences:
+            unPrintedReferences.remove(myTypeRef)
+
+        code.append("       UA_LOCALIZEDTEXT(\"\",\"" + str(node.inverseName()) + "\"),");
+        code.append("       // FIXME: Missing, isAbstract")
+        code.append("       // FIXME: Missing, symmetric")
+        return code
+
+    if node.isAbstract():
+        code.append(node.getCodePrintableID() + "->isAbstract = true;")
+    if node.symmetric():
+        code.append(node.getCodePrintableID() + "->symmetric  = true;")
+    if node.__reference_inverseName__ != "":
+        code.append(node.getCodePrintableID() + "->inverseName  = UA_LOCALIZEDTEXT_ALLOC(\"en_US\", \"" + \
+                    node.__reference_inverseName__ + "\");")
+    return code;
+
+def ObjectNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
+    code = []
+
+    # Detect if this is bootstrapping or if we are attempting to use userspace...
+    if bootstrapping == False:
+      typeDefs = self.getNamespace().getSubTypesOf() # defaults to TypeDefinition
+      myTypeRef = None
+      for ref in self.getReferences():
+        if ref.referenceType() in typeDefs:
+          myTypeRef = ref
+          break
+      if myTypeRef==None:
+        for ref in self.getReferences():
+          if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
+            myTypeRef = ref
+            break
+      if myTypeRef==None:
+        logger.warn(str(self) + " failed to locate a type definition, assuming BaseObjectType.")
+        code.append("       // No valid typeDefinition found; assuming BaseObjectType")
+        code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),")
+      else:
+        code.append("       " + getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
+        while myTypeRef in unPrintedReferences:
+          unPrintedReferences.remove(myTypeRef)
+
+      #FIXME: No event notifier in UA_Server_addNode call!
+      return code
+
+    # We are being bootstrapped! Add the raw attributes to the node.
+    code.append(node.getCodePrintableID() + "->eventNotifier = (UA_Byte) " + str(node.eventNotifier()) + ";")
+    return code
+
+
+def ObjectTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
+    code = []
+
+    # Detect if this is bootstrapping or if we are attempting to use userspace...
+    if bootstrapping == False:
+      typeDefs = node.getNamespace().getSubTypesOf() # defaults to TypeDefinition
+      myTypeRef = None
+      for ref in node.getReferences():
+        if ref.referenceType() in typeDefs:
+          myTypeRef = ref
+          break
+      if myTypeRef==None:
+        for ref in node.getReferences():
+          if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
+            myTypeRef = ref
+            break
+      if myTypeRef==None:
+        logger.warn(str(node) + " failed to locate a type definition, assuming BaseObjectType.")
+        code.append("       // No valid typeDefinition found; assuming BaseObjectType")
+        code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),")
+      else:
+        code.append("       " + getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
+        while myTypeRef in unPrintedReferences:
+          code.append("       // removed " + str(myTypeRef))
+          unPrintedReferences.remove(myTypeRef)
+
+      if (node.isAbstract()):
+        code.append("       true,")
+      else:
+        code.append("       false,")
+
+    # Fallback mode for bootstrapping
+    if (node.isAbstract()):
+      code.append(node.getCodePrintableID() + "->isAbstract = true;")
+
+    return code
+
+def VariableNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
+    code = []
+
+    # Detect if this is bootstrapping or if we are attempting to use userspace...
+    if bootstrapping == False:
+      code.append("       " + node.getCodePrintableID() + "_variant, ")
+      code.append("       // FIXME: missing minimumSamplingInterval")
+      code.append("       // FIXME: missing accessLevel")
+      code.append("       // FIXME: missing userAccessLevel")
+      code.append("       // FIXME: missing valueRank")
+      return code
+
+    if node.historizing():
+      code.append(node.getCodePrintableID() + "->historizing = true;")
+
+    code.append(node.getCodePrintableID() + "->minimumSamplingInterval = (UA_Double) " + \
+                str(node.minimumSamplingInterval()) + ";")
+    code.append(node.getCodePrintableID() + "->userAccessLevel = (UA_Int32) " + str(node.userAccessLevel()) + ";")
+    code.append(node.getCodePrintableID() + "->accessLevel = (UA_Int32) " + str(node.accessLevel()) + ";")
+    code.append(node.getCodePrintableID() + "->valueRank = (UA_Int32) " + str(node.valueRank()) + ";")
+    # The variant is guaranteed to exist by SubtypeEarly()
+    code.append(node.getCodePrintableID() + "->value.variant.value = *" + node.getCodePrintableID() + "_variant;")
+    code.append(node.getCodePrintableID() + "->valueSource = UA_VALUESOURCE_VARIANT;")
+    return code
+
+def VariableTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
+    code = []
+    if bootstrapping == False:
+      code.append("       " + node.getCodePrintableID() + "_variant, ")
+      code.append("       " + str(node.valueRank()) + ",")
+      if node.isAbstract():
+        code.append("       true,")
+      else:
+        code.append("       false,")
+      return code
+
+    if (node.isAbstract()):
+      code.append(node.getCodePrintableID() + "->isAbstract = true;")
+    else:
+      code.append(node.getCodePrintableID() + "->isAbstract = false;")
+
+    # The variant is guaranteed to exist by SubtypeEarly()
+    code.append(node.getCodePrintableID() + "->value.variant.value = *" + node.getCodePrintableID() + "_variant;")
+    code.append(node.getCodePrintableID() + "->valueSource = UA_VALUESOURCE_VARIANT;")
+    return code
+
+def MethodNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
+    code = []
+
+    # Detect if this is bootstrapping or if we are attempting to use userspace...
+    if bootstrapping == False:
+      code.append("       // Note: in/outputArguments are added by attaching the variable nodes,")
+      code.append("       //       not by including the in the addMethodNode() call.")
+      code.append("       NULL,")
+      code.append("       NULL,")
+      code.append("       0, NULL,")
+      code.append("       0, NULL,")
+      code.append("       // FIXME: Missing executable")
+      code.append("       // FIXME: Missing userExecutable")
+      return code
+
+    # UA_False is default for booleans on _init()
+    if node.executable():
+      code.append(node.getCodePrintableID() + "->executable = true;")
+    if node.userExecutable():
+      code.append(node.getCodePrintableID() + "->userExecutable = true;")
+    return code
+
+def DataTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
+    code = []
+
+    # Detect if this is bootstrapping or if we are attempting to use userspace...
+    if bootstrapping == False:
+      typeDefs = node.getNamespace().getSubTypesOf() # defaults to TypeDefinition
+      myTypeRef = None
+      for ref in node.getReferences():
+        if ref.referenceType() in typeDefs:
+          myTypeRef = ref
+          break
+      if myTypeRef==None:
+        for ref in node.getReferences():
+          if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
+            myTypeRef = ref
+            break
+      if myTypeRef==None:
+        logger.warn(str(node) + " failed to locate a type definition, assuming BaseDataType.")
+        code.append("       // No valid typeDefinition found; assuming BaseDataType")
+        code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE),")
+      else:
+        code.append("       " + getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
+        while myTypeRef in unPrintedReferences:
+          unPrintedReferences.remove(myTypeRef)
+
+      if (node.isAbstract()):
+        code.append("       true,")
+      else:
+        code.append("       false,")
+      return code
+
+    if (node.isAbstract()):
+      code.append(node.getCodePrintableID() + "->isAbstract = true;")
+    else:
+      code.append(node.getCodePrintableID() + "->isAbstract = false;")
+    return code
+
+def ViewNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
+    code = []
+
+    # Detect if this is bootstrapping or if we are attempting to use userspace...
+    if bootstrapping == False:
+      typeDefs = node.getNamespace().getSubTypesOf() # defaults to TypeDefinition
+      myTypeRef = None
+      for ref in node.getReferences():
+        if ref.referenceType() in typeDefs:
+          myTypeRef = ref
+          break
+      if myTypeRef==None:
+        for ref in node.getReferences():
+          if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
+            myTypeRef = ref
+            break
+      if myTypeRef==None:
+        logger.warn(str(node) + " failed to locate a type definition, assuming BaseViewType.")
+        code.append("       // No valid typeDefinition found; assuming BaseViewType")
+        code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEViewTYPE),")
+      else:
+        code.append("       " + getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
+        while myTypeRef in unPrintedReferences:
+          unPrintedReferences.remove(myTypeRef)
+
+      code.append("       // FIXME: Missing eventNotifier")
+      code.append("       // FIXME: Missing containsNoLoops")
+      return code
+
+    if node.containsNoLoops():
+      code.append(node.getCodePrintableID() + "->containsNoLoops = true;")
+    else:
+      code.append(node.getCodePrintableID() + "->containsNoLoops = false;")
+    code.append(node.getCodePrintableID() + "->eventNotifier = (UA_Byte) " + str(node.eventNotifier()) + ";")
+    return code
+
+def Node_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
+    """ Appends node type specific information to the nodes  UA_Server_addNode
+        or UA_NodeStore_insert calls.
+    """
+
+    if isinstance(node, opcua_node_referenceType_t):
+      return ReferenceTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
+    elif isinstance(node, opcua_node_object_t):
+      return ObjectNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
+    elif isinstance(node, opcua_node_objectType_t):
+      return ObjectTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
+    elif isinstance(node, opcua_node_variable_t):
+      return VariableNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
+    elif isinstance(node, opcua_node_variableType_t):
+      return VariableTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
+    elif isinstance(node, opcua_node_method_t):
+      return MethodNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
+    elif isinstance(node, opcua_node_dataType_t):
+      return DataTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
+    elif isinstance(node, opcua_node_view_t):
+      return ViewNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
+    
+    raise Exception('Unknown node type', node)
+
+###############
+# Entry Point #
+###############
+
+def getCreateNodeNoBootstrap(node, parentNode, parentReference, unprintedNodes=[]):
+    code = []
+    code.append("// Node: %s, %s" % (str(node), str(node.browseName())))
+
+    if node.nodeClass() == NODE_CLASS_OBJECT:
+      nodetype = "Object"
+    elif node.nodeClass() == NODE_CLASS_VARIABLE:
+      nodetype = "Variable"
+    elif node.nodeClass() == NODE_CLASS_METHOD:
+      nodetype = "Method"
+    elif node.nodeClass() == NODE_CLASS_OBJECTTYPE:
+      nodetype = "ObjectType"
+    elif node.nodeClass() == NODE_CLASS_REFERENCETYPE:
+      nodetype = "ReferenceType"
+    elif node.nodeClass() == NODE_CLASS_VARIABLETYPE:
+      nodetype = "VariableType"
+    elif node.nodeClass() == NODE_CLASS_DATATYPE:
+      nodetype = "DataType"
+    elif node.nodeClass() == NODE_CLASS_VIEW:
+      nodetype = "View"
+    else:
+      code.append("/* undefined nodeclass */")
+      return code;
+
+    # If this is a method, construct in/outargs for addMethod
+    #inputArguments.arrayDimensionsSize = 0;
+    #inputArguments.arrayDimensions = NULL;
+    #inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
+
+    # Node ordering should have made sure that arguments, if they exist, have not been printed yet
+    if node.nodeClass() == NODE_CLASS_METHOD:
+        inArgVal = []
+        outArgVal = []
+        code.append("UA_Argument *inputArguments = NULL;")
+        code.append("UA_Argument *outputArguments = NULL;")
+        for r in node.getReferences():
+            if r.isForward():
+                if r.target() != None and r.target().nodeClass() == NODE_CLASS_VARIABLE and \
+                   r.target().browseName() == 'InputArguments':
+                    while r.target() in unprintedNodes:
+                        unprintedNodes.remove(r.target())
+                    if r.target().value() != None:
+                        inArgVal = r.target().value().value
+                elif r.target() != None and r.target().nodeClass() == NODE_CLASS_VARIABLE and \
+                     r.target().browseName() == 'OutputArguments':
+                    while r.target() in unprintedNodes:
+                        unprintedNodes.remove(r.target())
+                    if r.target().value() != None:
+                        outArgVal = r.target().value().value
+        if len(inArgVal)>0:
+            code.append("")
+            code.append("inputArguments = (UA_Argument *) malloc(sizeof(UA_Argument) * " + \
+                        str(len(inArgVal)) + ");")
+            code.append("int inputArgumentCnt;")
+            code.append("for (inputArgumentCnt=0; inputArgumentCnt<" + str(len(inArgVal)) + \
+                        "; inputArgumentCnt++) UA_Argument_init(&inputArguments[inputArgumentCnt]); ")
+            argumentCnt = 0
+            for inArg in inArgVal:
+                if inArg.getValueFieldByAlias("Description") != None:
+                    code.append("inputArguments[" + str(argumentCnt) + "].description = UA_LOCALIZEDTEXT(\"" + \
+                                str(inArg.getValueFieldByAlias("Description")[0]) + "\",\"" + \
+                                str(inArg.getValueFieldByAlias("Description")[1]) + "\");")
+                if inArg.getValueFieldByAlias("Name") != None:
+                    code.append("inputArguments[" + str(argumentCnt) + "].name = UA_STRING(\"" + \
+                                str(inArg.getValueFieldByAlias("Name")) + "\");")
+                if inArg.getValueFieldByAlias("ValueRank") != None:
+                    code.append("inputArguments[" + str(argumentCnt) + "].valueRank = " + \
+                                str(inArg.getValueFieldByAlias("ValueRank")) + ";")
+                if inArg.getValueFieldByAlias("DataType") != None:
+                    code.append("inputArguments[" + str(argumentCnt) + "].dataType = " + \
+                                str(getCreateNodeIDMacro(inArg.getValueFieldByAlias("DataType"))) + ";")
+                #if inArg.getValueFieldByAlias("ArrayDimensions") != None:
+                #  code.append("inputArguments[" + str(argumentCnt) + "].arrayDimensions = " + \
+                #                  str(inArg.getValueFieldByAlias("ArrayDimensions")) + ";")
+                argumentCnt += 1
+        if len(outArgVal)>0:
+            code.append("")
+            code.append("outputArguments = (UA_Argument *) malloc(sizeof(UA_Argument) * " + \
+                        str(len(outArgVal)) + ");")
+            code.append("int outputArgumentCnt;")
+            code.append("for (outputArgumentCnt=0; outputArgumentCnt<" + str(len(outArgVal)) + \
+                        "; outputArgumentCnt++) UA_Argument_init(&outputArguments[outputArgumentCnt]); ")
+            argumentCnt = 0
+            for outArg in outArgVal:
+                if outArg.getValueFieldByAlias("Description") != None:
+                    code.append("outputArguments[" + str(argumentCnt) + "].description = UA_LOCALIZEDTEXT(\"" + \
+                                str(outArg.getValueFieldByAlias("Description")[0]) + "\",\"" + \
+                                str(outArg.getValueFieldByAlias("Description")[1]) + "\");")
+                if outArg.getValueFieldByAlias("Name") != None:
+                    code.append("outputArguments[" + str(argumentCnt) + "].name = UA_STRING(\"" + \
+                                str(outArg.getValueFieldByAlias("Name")) + "\");")
+                if outArg.getValueFieldByAlias("ValueRank") != None:
+                    code.append("outputArguments[" + str(argumentCnt) + "].valueRank = " + \
+                                str(outArg.getValueFieldByAlias("ValueRank")) + ";")
+                if outArg.getValueFieldByAlias("DataType") != None:
+                    code.append("outputArguments[" + str(argumentCnt) + "].dataType = " + \
+                                str(getCreateNodeIDMacro(outArg.getValueFieldByAlias("DataType"))) + ";")
+                #if outArg.getValueFieldByAlias("ArrayDimensions") != None:
+                #  code.append("outputArguments[" + str(argumentCnt) + "].arrayDimensions = " + \
+                #              str(outArg.getValueFieldByAlias("ArrayDimensions")) + ";")
+                argumentCnt += 1
+
+    # print the attributes struct
+    code.append("UA_%sAttributes attr;" % nodetype)
+    code.append("UA_%sAttributes_init(&attr);" %  nodetype);
+    code.append("attr.displayName = UA_LOCALIZEDTEXT(\"\", \"%s\");" % node.displayName().replace("\"", "\\\""))
+    code.append("attr.description = UA_LOCALIZEDTEXT(\"\", \"%s\");" % node.description().replace("\"", "\\\""))
+
+    if nodetype == "Variable":
+      code.append("attr.accessLevel = %s;"     % str(node.accessLevel()))
+      code.append("attr.userAccessLevel = %s;" % str(node.userAccessLevel()))
+
+    if nodetype in ["Variable", "VariableType"]:
+      code.extend(Node_printOpen62541CCode_SubtypeEarly(node, bootstrapping = False))
+    elif nodetype == "Method":
+      if node.executable():
+        code.append("attr.executable = true;")
+      if node.userExecutable():
+        code.append("attr.userExecutable = true;")
+
+    code.append("UA_NodeId nodeId = %s;" % str(getCreateNodeIDMacro(node)))
+    if nodetype in ["Object", "Variable"]:
+      #due to the current API we cannot set types here since the API will
+      #generate nodes with random IDs
+      code.append("UA_NodeId typeDefinition = UA_NODEID_NULL;")
+    code.append("UA_NodeId parentNodeId = %s;" % str(getCreateNodeIDMacro(parentNode)))
+    code.append("UA_NodeId parentReferenceNodeId = %s;" % \
+                str(getCreateNodeIDMacro(parentReference.referenceType())))
+    extrNs = node.browseName().split(":")
+    if len(extrNs) > 1:
+      code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(%s, \"%s\");" % (str(extrNs[0]), extrNs[1]))
+    else:
+      code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(0, \"%s\");" % str(node.browseName()))
+
+    # In case of a MethodNode: Add in|outArg struct generation here. Mandates
+    # that namespace reordering was done using Djikstra (check that arguments
+    # have not been printed). (@ichrispa)
+    code.append("UA_Server_add%sNode(server, nodeId, parentNodeId, parentReferenceNodeId, nodeName" % nodetype)
+
+    if nodetype in ["Object", "Variable"]:
+      code.append("       , typeDefinition")
+    if nodetype != "Method":
+      code.append("       , attr, NULL, NULL);")
+    else:
+      code.append("       , attr, (UA_MethodCallback) NULL, NULL, %s, inputArguments,  %s, outputArguments, NULL);" % (str(len(inArgVal)), str(len(outArgVal))))
+
+    #Adding a Node with typeDefinition = UA_NODEID_NULL will create a
+    #HasTypeDefinition reference to BaseDataType - remove it since a real
+    #Reference will be add in a later step (a single HasTypeDefinition reference
+    #is assumed here) The current API does not let us specify IDs of Object's
+    #subelements.
+    if nodetype is "Object":
+      code.append("UA_Server_deleteReference(server, nodeId, UA_NODEID_NUMERIC(0, 40), true, UA_EXPANDEDNODEID_NUMERIC(0, 58), true); //remove HasTypeDefinition refs generated by addObjectNode");
+    if nodetype is "Variable":
+      code.append("UA_Server_deleteReference(server, nodeId, UA_NODEID_NUMERIC(0, 40), true, UA_EXPANDEDNODEID_NUMERIC(0, 62), true); //remove HasTypeDefinition refs generated by addVariableNode");
+    return code
+
+##################
+# Node Bootstrap #
+##################
+
+def getCreateNodeBootstrap(node, supressGenerationOfAttribute=[]):
+    nodetype = ""
+    code = []
+
+    code.append("// Node: " + str(node) + ", " + str(node.browseName()))
+
+    if node.nodeClass() == NODE_CLASS_OBJECT:
+      nodetype = "Object"
+    elif node.nodeClass() == NODE_CLASS_VARIABLE:
+      nodetype = "Variable"
+    elif node.nodeClass() == NODE_CLASS_METHOD:
+      nodetype = "Method"
+    elif node.nodeClass() == NODE_CLASS_OBJECTTYPE:
+      nodetype = "ObjectType"
+    elif node.nodeClass() == NODE_CLASS_REFERENCETYPE:
+      nodetype = "ReferenceType"
+    elif node.nodeClass() == NODE_CLASS_VARIABLETYPE:
+      nodetype = "VariableType"
+    elif node.nodeClass() == NODE_CLASS_DATATYPE:
+      nodetype = "DataType"
+    elif node.nodeClass() == NODE_CLASS_VIEW:
+      nodetype = "View"
+    else:
+      raise Exception('Undefined NodeClass')
+
+    code.append("UA_" + nodetype + "Node *" + node.getCodePrintableID() + \
+                " = UA_NodeStore_new" + nodetype + "Node();")
+    if not "browsename" in supressGenerationOfAttribute:
+      extrNs = node.browseName().split(":")
+      if len(extrNs) > 1:
+        code.append(node.getCodePrintableID() + "->browseName = UA_QUALIFIEDNAME_ALLOC(" + \
+                    str(extrNs[0]) + ", \"" + extrNs[1] + "\");")
+      else:
+        code.append(node.getCodePrintableID() + "->browseName = UA_QUALIFIEDNAME_ALLOC(0, \"" + \
+                    node.browseName() + "\");")
+    if not "displayname" in supressGenerationOfAttribute:
+      code.append(node.getCodePrintableID() + "->displayName = UA_LOCALIZEDTEXT_ALLOC(\"en_US\", \"" + \
+                  node.displayName() + "\");")
+    if not "description" in supressGenerationOfAttribute:
+      code.append(node.getCodePrintableID() + "->description = UA_LOCALIZEDTEXT_ALLOC(\"en_US\", \"" + \
+                  node.description() + "\");")
+
+    if not "writemask" in supressGenerationOfAttribute:
+        if node.__node_writeMask__ != 0:
+          code.append(node.getCodePrintableID() + "->writeMask = (UA_Int32) " + \
+                      str(node.__node_writeMask__) + ";")
+    if not "userwritemask" in supressGenerationOfAttribute:
+        if node.__node_userWriteMask__ != 0:
+          code.append(node.getCodePrintableID() + "->userWriteMask = (UA_Int32) " + \
+                      str(node.__node_userWriteMask__) + ";")
+    if not "nodeid" in supressGenerationOfAttribute:
+      if node.id().ns != 0:
+        code.append(node.getCodePrintableID() + "->nodeId.namespaceIndex = " + str(node.id().ns) + ";")
+      if node.id().i != None:
+        code.append(node.getCodePrintableID() + "->nodeId.identifier.numeric = " + str(node.id().i) + ";")
+      elif node.id().b != None:
+        code.append(node.getCodePrintableID() + "->nodeId.identifierType = UA_NODEIDTYPE_BYTESTRING;")
+        logger.error("ByteString IDs for nodes has not been implemented yet.")
+        return []
+      elif node.id().g != None:
+        #<jpfr> the string is sth like { .length = 111, .data = <ptr> }
+        #<jpfr> there you _may_ alloc the <ptr> on the heap
+        #<jpfr> for the guid, just set it to {.data1 = 111, .data2 = 2222, ....
+        code.append(node.getCodePrintableID() + "->nodeId.identifierType = UA_NODEIDTYPE_GUID;")
+        logger.error("GUIDs for nodes has not been implemented yet.")
+        return []
+      elif node.id().s != None:
+        code.append(node.getCodePrintableID() + "->nodeId.identifierType = UA_NODEIDTYPE_STRING;")
+        code.append(node.getCodePrintableID() + "->nodeId.identifier.numeric = UA_STRING_ALLOC(\"" + str(node.id().i) + "\");")
+      else:
+        logger.error("Node ID is not numeric, bytestring, guid or string. I do not know how to create c code for that...")
+        return []
+    return code
+
+def Node_printOpen62541CCode(node, unPrintedNodes=[], unPrintedReferences=[],
+                             supressGenerationOfAttribute=[]):
+    """ Returns a list of strings containing the C-code necessary to intialize
+        this node for the open62541 OPC-UA Stack.
+
+        Note that this function will fail if the nodeid is non-numeric, as
+        there is no UA_EXPANDEDNNODEID_[STRING|GUID|BYTESTRING] macro.
+    """
+    code = []
+    code.append("")
+    code.append("do {")
+
+    # Just to be sure...
+    if not (node in unPrintedNodes):
+      logger.warn(str(node) + " attempted to reprint already printed node " + str(node)+ ".")
+      return []
+
+    # If we are being passed a parent node by the namespace, use that for registering ourselves in the namespace
+    # Note: getFirstParentNode will return [parentNode, referenceToChild]
+    (parentNode, parentRef) = node.getFirstParentNode()
+    if not (parentNode in unPrintedNodes) and (parentNode != None) and (parentRef.referenceType() != None):
+      code.append("// Referencing node found and declared as parent: " + str(parentNode .id()) + "/" +
+                  str(parentNode .__node_browseName__) + " using " + str(parentRef.referenceType().id()) +
+                  "/" + str(parentRef.referenceType().__node_browseName__))
+      code.extend(getCreateNodeNoBootstrap(node, parentNode, parentRef, unPrintedNodes))
+      # Parent to child reference is added by the server, do not reprint that reference
+      if parentRef in unPrintedReferences:
+        unPrintedReferences.remove(parentRef)
+      # the UA_Server_addNode function will use addReference which creates a
+      # bidirectional reference; remove any inverse references to our parent to
+      # avoid duplicate refs
+      for ref in node.getReferences():
+        if ref.target() == parentNode and ref.referenceType() == parentRef.referenceType() and \
+           ref.isForward() == False:
+          while ref in unPrintedReferences:
+            unPrintedReferences.remove(ref)
+    # Otherwise use the "Bootstrapping" method and we will get registered with other nodes later.
+    else:
+      code.extend(Node_printOpen62541CCode_SubtypeEarly(node, bootstrapping = True))
+      code.extend(getCreateNodeBootstrap(node, supressGenerationOfAttribute))
+      code.extend(Node_printOpen62541CCode_Subtype(node, unPrintedReferences = unPrintedReferences,
+                                                   bootstrapping = True))
+      code.append("// Parent node does not exist yet. This node will be bootstrapped and linked later.")
+      code.append("UA_RCU_LOCK();")
+      code.append("UA_NodeStore_insert(server->nodestore, (UA_Node*) " + node.getCodePrintableID() + ");")
+      code.append("UA_RCU_UNLOCK();")
+
+    # Try to print all references to nodes that already exist
+    # Note: we know the reference types exist, because the namespace class made sure they were
+    #       the first ones being printed
+    tmprefs = []
+    for r in node.getReferences():
+      #logger.debug("Checking if reference from " + str(r.parent()) + "can be created...")
+      if not (r.target() in unPrintedNodes):
+        if r in unPrintedReferences:
+          if (len(tmprefs) == 0):
+            code.append("// This node has the following references that can be created:")
+          code.extend(getCreateStandaloneReference(node, r))
+          tmprefs.append(r)
+    # Remove printed refs from list
+    for r in tmprefs:
+      unPrintedReferences.remove(r)
+
+    # Again, but this time check if other nodes deffered their node creation
+    # because this node did not exist...
+    tmprefs = []
+    for r in unPrintedReferences:
+      #logger.debug("Checking if another reference " + str(r.target()) + "can be created...")
+      if (r.target() == node) and not (r.parent() in unPrintedNodes):
+        if not isinstance(r.parent(), opcua_node_t):
+          logger.debug("Reference has no parent!")
+        elif not isinstance(r.parent().id(), opcua_node_id_t):
+          logger.debug("Parents nodeid is not a nodeID!")
+        else:
+          if (len(tmprefs) == 0):
+            code.append("//  Creating this node has resolved the following open references:")
+          code.extend(getCreateStandaloneReference(r.parent(), r))
+          tmprefs.append(r)
+    # Remove printed refs from list
+    for r in tmprefs:
+      unPrintedReferences.remove(r)
+
+    # Again, just to be sure...
+    if node in unPrintedNodes:
+      # This is necessery to make printing work at all!
+      unPrintedNodes.remove(node)
+
+    code.append("} while(0);")
+    return code
+
+def Node_printOpen62541CCode_HL_API(node, reference, supressGenerationOfAttribute=[]):
+    """ Returns a list of strings containing the C-code necessary to intialize
+        this node for the open62541 OPC-UA Stack using only the high level API
+
+        Note that this function will fail if the nodeid is non-numeric, as
+        there is no UA_EXPANDEDNNODEID_[STRING|GUID|BYTESTRING] macro.
+    """
+    code = []
+    code.append("")
+    code.append("do {")
+    # If we are being passed a parent node by the namespace, use that for registering ourselves in the namespace
+    # Note: getFirstParentNode will return [parentNode, referenceToChild]
+    parentNode = reference.target()
+    parentRefType = reference.referenceType()
+    code.append("// Referencing node found and declared as parent: " + str(parentNode .id()) + "/" +
+                  str(parentNode .__node_browseName__) + " using " + str(parentRefType.id()) +
+                  "/" + str(parentRefType.__node_browseName__))
+    code.extend(getCreateNodeNoBootstrap(node, parentNode, reference))
+    code.append("} while(0);")
+    return code

+ 317 - 0
tools/pyUANamespace/open62541_backend_types.py

@@ -0,0 +1,317 @@
+import * from ua_builtin_types
+import open62541Backend from open62541_MacroHelper
+
+class opcua_value_t_open62541(opcua_value_t):
+  def printOpen62541CCode(self, bootstrapping = True):
+    codegen = open62541Backend()
+    code = []
+    valueName = self.parent.getCodePrintableID() + "_variant_DataContents"
+
+    # self.value either contains a list of multiple identical BUILTINTYPES, or it
+    # contains a single builtintype (which may be a container); choose if we need
+    # to create an array or a single variable.
+    # Note that some genious defined that there are arrays of size 1, which are
+    # distinctly different then a single value, so we need to check that as well
+    # Semantics:
+    # -3: Scalar or 1-dim
+    # -2: Scalar or x-dim | x>0
+    # -1: Scalar
+    #  0: x-dim | x>0
+    #  n: n-dim | n>0
+    if (len(self.value) == 0):
+      return code
+    if not isinstance(self.value[0], opcua_value_t):
+      return code
+
+    if self.parent.valueRank() != -1 and \
+       (self.parent.valueRank() >=0 or (len(self.value) > 1 and \
+                                        (self.parent.valueRank() != -2 or self.parent.valueRank() != -3))):
+      # User the following strategy for all directly mappable values a la 'UA_Type MyInt = (UA_Type) 23;'
+      if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_GUID:
+        logger.warn("Don't know how to print array of GUID in node " + str(self.parent.id()))
+      elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_DATETIME:
+        logger.warn("Don't know how to print array of DateTime in node " + str(self.parent.id()))
+      elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_DIAGNOSTICINFO:
+        logger.warn("Don't know how to print array of DiagnosticInfo in node " + str(self.parent.id()))
+      elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_STATUSCODE:
+        logger.warn("Don't know how to print array of StatusCode in node " + str(self.parent.id()))
+      else:
+        if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
+          for v in self.value:
+            logger.debug("Building extObj array index " + str(self.value.index(v)))
+            code.extend(v.printOpen62541CCode_SubType_build(arrayIndex=self.value.index(v)))
+        #code.append("attr.value.type = &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "];")
+        code.append("UA_" + self.value[0].stringRepresentation + " " + valueName + \
+                    "[" + str(len(self.value)) + "];")
+        if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
+          for v in self.value:
+            logger.debug("Printing extObj array index " + str(self.value.index(v)))
+            code.append(valueName + "[" + str(self.value.index(v)) + "] = " + \
+                        v.printOpen62541CCode_SubType(asIndirect=False) + ";")
+            code.append("UA_free(" + v.printOpen62541CCode_SubType() + ");")
+        else:
+          for v in self.value:
+            code.append(valueName + "[" + str(self.value.index(v)) + "] = " + \
+                        v.printOpen62541CCode_SubType() + ";")
+        code.append("UA_Variant_setArray( &attr.value, &" + valueName +
+                    ", (UA_Int32) " + str(len(self.value)) + ", &UA_TYPES[UA_TYPES_" + \
+                    self.value[0].stringRepresentation.upper() + "]);")
+    else:
+      # User the following strategy for all directly mappable values a la 'UA_Type MyInt = (UA_Type) 23;'
+      if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_GUID:
+        logger.warn("Don't know how to print scalar GUID in node " + str(self.parent.id()))
+      elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_DATETIME:
+        logger.warn("Don't know how to print scalar DateTime in node " + str(self.parent.id()))
+      elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_DIAGNOSTICINFO:
+        logger.warn("Don't know how to print scalar DiagnosticInfo in node " + str(self.parent.id()))
+      elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_STATUSCODE:
+        logger.warn("Don't know how to print scalar StatusCode in node " + str(self.parent.id()))
+      else:
+        # The following strategy applies to all other types, in particular strings and numerics.
+        if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
+          code.extend(self.value[0].printOpen62541CCode_SubType_build())
+        #code.append("attr.value.type = &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "];")
+        if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
+          code.append("UA_" + self.value[0].stringRepresentation + " *" + valueName + " = " + \
+                      self.value[0].printOpen62541CCode_SubType() + ";")
+          code.append("UA_Variant_setScalar( &attr.value, " + valueName + ", &UA_TYPES[UA_TYPES_" + \
+                      self.value[0].stringRepresentation.upper() + "]);")
+
+          #FIXME: There is no membership definition for extensionObjects generated in this function.
+          #code.append("UA_" + self.value[0].stringRepresentation + "_deleteMembers(" + valueName + ");")
+        else:
+          if bootstrapping == True:
+              code.append("UA_Variant* " + self.parent.getCodePrintableID() + "_variant = UA_Variant_new();" )
+          code.append("UA_" + self.value[0].stringRepresentation + " *" + valueName + " =  UA_" + \
+                      self.value[0].stringRepresentation + "_new();")
+          code.append("*" + valueName + " = " + self.value[0].printOpen62541CCode_SubType() + ";")
+          if bootstrapping == False:
+            code.append("UA_Variant_setScalar( &attr.value, " + valueName + ", &UA_TYPES[UA_TYPES_" + \
+                        self.value[0].stringRepresentation.upper() + "]);")
+          else:
+            code.append("UA_Variant_setScalar( "+self.parent.getCodePrintableID()+"_variant, " + \
+                        valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
+          #code.append("UA_" + self.value[0].stringRepresentation + "_deleteMembers(" + valueName + ");")
+    return code
+
+class opcua_BuiltinType_boolean_t_open62541(opcua_BuiltinType_boolean_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
+
+class opcua_BuiltinType_byte_t_open62541(opcua_BuiltinType_byte_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
+
+class opcua_BuiltinType_sbyte_t_open62541(opcua_BuiltinType_sbyte_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
+
+class opcua_BuiltinType_int16_t_open62541(opcua_BuiltinType_int16_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
+
+class opcua_BuiltinType_uint16_t_open62541(opcua_BuiltinType_uint16_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
+
+class opcua_BuiltinType_int32_t_open62541(opcua_BuiltinType_int32_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
+
+class opcua_BuiltinType_uint32_t_open62541(opcua_BuiltinType_uint32_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
+
+class opcua_BuiltinType_int64_t_open62541(opcua_BuiltinType_int64_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
+
+class opcua_BuiltinType_uint64_t_open62541(opcua_BuiltinType_uint64_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
+
+class opcua_BuiltinType_float_t_open62541(opcua_BuiltinType_float_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
+
+class opcua_BuiltinType_double_t_open62541(opcua_BuiltinType_double_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
+
+class opcua_BuiltinType_string_t_open62541(opcua_BuiltinType_string_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+      code = "UA_STRING_ALLOC(\"" + self.value.encode('utf-8') + "\")"
+      return code
+
+class opcua_BuiltinType_xmlelement_t_open62541(opcua_BuiltinType_xmlelement_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+      code = "UA_XMLELEMENT_ALLOC(\"" + self.value.encode('utf-8') + "\")"
+      return code
+
+class opcua_BuiltinType_bytestring_t_open62541(opcua_BuiltinType_bytestring_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+      bs = ""
+      for line in self.value:
+        bs = bs + str(line).replace("\n","");
+      outs = bs
+      logger.debug("Encoded Bytestring: " + outs)
+#      bs = bs.decode('base64')
+#      outs = ""
+#      for s in bs:
+#        outs = outs + hex(ord(s)).upper().replace("0X", "\\x")
+      code = "UA_STRING_ALLOC(\"" + outs + "\")"
+      return code
+
+class opcua_BuiltinType_localizedtext_open62541(opcua_BuiltinType_localizedtext_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+      if asIndirect==True:
+        return "UA_LOCALIZEDTEXT_ALLOC(\"" + str(self.value[0]) + "\", \"" + \
+            str(self.value[1].encode('utf-8')) + "\")"
+      else:
+        return "UA_LOCALIZEDTEXT(\"" + str(self.value[0]) + "\", \"" + \
+            str(self.value[1].encode('utf-8')) + "\")"
+
+class opcua_BuiltinType_qualifiedname_t_open62541(opcua_BuiltinType_qualifiedname_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+      code = "UA_QUALIFIEDNAME_ALLOC(" + str(self.value[0]) + ", \"" + self.value[1].encode('utf-8') + "\")"
+      return code
+
+class opcua_BuiltinType_nodeid_t_open62541(opcua_BuiltinType_nodeid_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+    if self.value == None:
+      return "UA_NODEID_NUMERIC(0,0)"
+    nodeId = self.value.id()
+    if nodeId.i != None:
+      return "UA_NODEID_NUMERIC(" + str(nodeId.ns) + ", " + str(nodeId.i) + ")"
+    elif nodeId.s != None:
+      return "UA_NODEID_STRING("  + str(nodeId.ns) + ", " + str(nodeId.s) + ")"
+    elif nodeId.b != None:
+      logger.debug("NodeID Generation macro for bytestrings has not been implemented.")
+      return "UA_NODEID_NUMERIC(0,0)"
+    elif nodeId.g != None:
+      logger.debug("NodeID Generation macro for guids has not been implemented.")
+      return "UA_NODEID_NUMERIC(0,0)"
+    return "UA_NODEID_NUMERIC(0,0)"
+
+class opcua_BuiltinType_expandednodeid_t_open62541(opcua_BuiltinType_expandednodeid_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+    #FIXME! This one is definetely broken!
+    code = ""
+    return code
+
+class opcua_BuiltinType_extensionObject_open62541(opcua_BuiltinType_extensionObject_t):
+  def printOpen62541CCode_SubType(self, asIndirect=True):
+    if asIndirect == False:
+      return "*" + str(self.getCodeInstanceName())
+    return str(self.getCodeInstanceName())
+
+  def printOpen62541CCode_SubType_build(self, recursionDepth=0, arrayIndex=0):
+    code = [""]
+    codegen = open62541_MacroHelper();
+
+    logger.debug("Building extensionObject for " + str(self.parent.id()))
+    logger.debug("Value    " + str(self.value))
+    logger.debug("Encoding " + str(self.getEncodingRule()))
+
+    self.setCodeInstanceName(recursionDepth, arrayIndex)
+    # If there are any ExtensionObjects instide this ExtensionObject, we need to
+    # generate one-time-structs for them too before we can proceed;
+    for subv in self.value:
+      if isinstance(subv, list):
+        logger.debug("ExtensionObject contains an ExtensionObject, which is currently not encodable!",
+                     LOG_LEVEL_ERR)
+
+    code.append("struct {")
+    for field in self.getEncodingRule():
+      ptrSym = ""
+      # If this is an Array, this is pointer to its contents with a AliasOfFieldSize entry
+      if field[2] != 0:
+        code.append("  UA_Int32 " + str(field[0]) + "Size;")
+        ptrSym = "*"
+      if len(field[1]) == 1:
+        code.append("  UA_" + str(field[1][0]) + " " + ptrSym + str(field[0]) + ";")
+      else:
+        code.append("  UA_ExtensionObject " + " " + ptrSym + str(field[0]) + ";")
+    code.append("} " + self.getCodeInstanceName() + "_struct;")
+
+    # Assign data to the struct contents
+    # Track the encoding rule definition to detect arrays and/or ExtensionObjects
+    encFieldIdx = 0
+    for subv in self.value:
+      encField = self.getEncodingRule()[encFieldIdx]
+      encFieldIdx = encFieldIdx + 1;
+      logger.debug("Encoding of field " + subv.alias() + " is " + str(subv.getEncodingRule()) + \
+                   "defined by " + str(encField))
+      # Check if this is an array
+      if encField[2] == 0:
+        code.append(self.getCodeInstanceName()+"_struct."+subv.alias() + " = " + \
+                    subv.printOpen62541CCode_SubType(asIndirect=False) + ";")
+      else:
+        if isinstance(subv, list):
+          # this is an array
+          code.append(self.getCodeInstanceName()+"_struct."+subv.alias() + "Size = " + str(len(subv)) + ";")
+          code.append(self.getCodeInstanceName()+"_struct."+subv.alias()+" = (UA_" + \
+                      subv.stringRepresentation + " *) UA_malloc(sizeof(UA_" + subv.stringRepresentation + \
+                      ")*"+ str(len(subv))+");")
+          logger.debug("Encoding included array of " + str(len(subv)) + " values.")
+          for subvidx in range(0,len(subv)):
+            subvv = subv[subvidx]
+            logger.debug("  " + str(subvix) + " " + str(subvv))
+            code.append(self.getCodeInstanceName()+"_struct."+subv.alias() + "[" + str(subvidx) + \
+                        "] = " + subvv.printOpen62541CCode_SubType(asIndirect=True) + ";")
+          code.append("}")
+        else:
+          code.append(self.getCodeInstanceName()+"_struct."+subv.alias() + "Size = 1;")
+          code.append(self.getCodeInstanceName()+"_struct."+subv.alias()+" = (UA_" + \
+                      subv.stringRepresentation + " *) UA_malloc(sizeof(UA_" + subv.stringRepresentation + "));")
+          code.append(self.getCodeInstanceName()+"_struct."+subv.alias() + "[0]  = " + \
+                      subv.printOpen62541CCode_SubType(asIndirect=True) + ";")
+
+
+    # Allocate some memory
+    code.append("UA_ExtensionObject *" + self.getCodeInstanceName() + " =  UA_ExtensionObject_new();")
+    code.append(self.getCodeInstanceName() + "->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;")
+    code.append(self.getCodeInstanceName() + "->content.encoded.typeId = UA_NODEID_NUMERIC(" + \
+                str(self.parent.dataType().target().id().ns) + ", " + \
+                str(self.parent.dataType().target().id().i) + "+ UA_ENCODINGOFFSET_BINARY);")
+    code.append("if(UA_ByteString_allocBuffer(&" + self.getCodeInstanceName() + \
+                "->content.encoded.body, 65000) != UA_STATUSCODE_GOOD) {}" )
+
+    # Encode each value as a bytestring seperately.
+    code.append("size_t " + self.getCodeInstanceName() + "_encOffset = 0;" )
+    encFieldIdx = 0;
+    for subv in self.value:
+      encField = self.getEncodingRule()[encFieldIdx]
+      encFieldIdx = encFieldIdx + 1;
+      if encField[2] == 0:
+        code.append("UA_" + subv.stringRepresentation + "_encodeBinary(&" + \
+                    self.getCodeInstanceName()+"_struct."+subv.alias() + ", &" + \
+                    self.getCodeInstanceName() + "->content.encoded.body, &" + \
+                    self.getCodeInstanceName() + "_encOffset);" )
+      else:
+        if isinstance(subv, list):
+          for subvidx in range(0,len(subv)):
+            code.append("UA_" + subv.stringRepresentation + "_encodeBinary(&" + \
+                        self.getCodeInstanceName()+"_struct."+subv.alias() + \
+                        "[" + str(subvidx) + "], &" + self.getCodeInstanceName() + \
+                        "->content.encoded.body, &" + self.getCodeInstanceName() + "_encOffset);" )
+        else:
+          code.append("UA_" + subv.stringRepresentation + "_encodeBinary(&" + \
+                      self.getCodeInstanceName()+"_struct."+subv.alias() + "[0], &" + \
+                      self.getCodeInstanceName() + "->content.encoded.body, &" + \
+                      self.getCodeInstanceName() + "_encOffset);" )
+
+    # Reallocate the memory by swapping the 65k Bytestring for a new one
+    code.append(self.getCodeInstanceName() + "->content.encoded.body.length = " + \
+                self.getCodeInstanceName() + "_encOffset;");
+    code.append("UA_Byte *" + self.getCodeInstanceName() + "_newBody = (UA_Byte *) UA_malloc(" + \
+                self.getCodeInstanceName() + "_encOffset );" )
+    code.append("memcpy(" + self.getCodeInstanceName() + "_newBody, " + self.getCodeInstanceName() + \
+                "->content.encoded.body.data, " + self.getCodeInstanceName() + "_encOffset);" )
+    code.append("UA_Byte *" + self.getCodeInstanceName() + "_oldBody = " + \
+                self.getCodeInstanceName() + "->content.encoded.body.data;");
+    code.append(self.getCodeInstanceName() + "->content.encoded.body.data = " + \
+                self.getCodeInstanceName() + "_newBody;")
+    code.append("UA_free(" + self.getCodeInstanceName() + "_oldBody);")
+    code.append("")
+    return code

+ 1 - 281
tools/pyUANamespace/ua_builtin_types.py

@@ -24,7 +24,6 @@ import xml.dom.minidom as dom
 from ua_constants import *
 import logging
 from time import strftime, strptime
-from open62541_MacroHelper import open62541_MacroHelper
 
 logger = logging.getLogger(__name__)
 
@@ -330,93 +329,8 @@ class opcua_value_t():
   def __repr__(self):
     return self.__str__()
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-    return ""
-
-  def printOpen62541CCode(self, bootstrapping = True):
-    codegen = open62541_MacroHelper()
-    code = []
-    valueName = self.parent.getCodePrintableID() + "_variant_DataContents"
-
-    # self.value either contains a list of multiple identical BUILTINTYPES, or it
-    # contains a single builtintype (which may be a container); choose if we need
-    # to create an array or a single variable.
-    # Note that some genious defined that there are arrays of size 1, which are
-    # distinctly different then a single value, so we need to check that as well
-    # Semantics:
-    # -3: Scalar or 1-dim
-    # -2: Scalar or x-dim | x>0
-    # -1: Scalar
-    #  0: x-dim | x>0
-    #  n: n-dim | n>0
-    if (len(self.value) == 0):
-      return code
-    if not isinstance(self.value[0], opcua_value_t):
-      return code
-
-    if self.parent.valueRank() != -1 and (self.parent.valueRank() >=0 or (len(self.value) > 1 and (self.parent.valueRank() != -2 or self.parent.valueRank() != -3))):
-      # User the following strategy for all directly mappable values a la 'UA_Type MyInt = (UA_Type) 23;'
-      if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_GUID:
-        logger.warn("Don't know how to print array of GUID in node " + str(self.parent.id()))
-      elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_DATETIME:
-        logger.warn("Don't know how to print array of DateTime in node " + str(self.parent.id()))
-      elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_DIAGNOSTICINFO:
-        logger.warn("Don't know how to print array of DiagnosticInfo in node " + str(self.parent.id()))
-      elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_STATUSCODE:
-        logger.warn("Don't know how to print array of StatusCode in node " + str(self.parent.id()))
-      else:
-        if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
-          for v in self.value:
-            logger.debug("Building extObj array index " + str(self.value.index(v)))
-            code.extend(v.printOpen62541CCode_SubType_build(arrayIndex=self.value.index(v)))
-        #code.append("attr.value.type = &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "];")
-        code.append("UA_" + self.value[0].stringRepresentation + " " + valueName + "[" + str(len(self.value)) + "];")
-        if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
-          for v in self.value:
-            logger.debug("Printing extObj array index " + str(self.value.index(v)))
-            code.append(valueName + "[" + str(self.value.index(v)) + "] = " + v.printOpen62541CCode_SubType(asIndirect=False) + ";")
-            code.append("UA_free(" + v.printOpen62541CCode_SubType() + ");")
-        else:
-          for v in self.value:
-            code.append(valueName + "[" + str(self.value.index(v)) + "] = " + v.printOpen62541CCode_SubType() + ";")
-        code.append("UA_Variant_setArray( &attr.value, &" + valueName +
-                    ", (UA_Int32) " + str(len(self.value)) + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
-    else:
-      # User the following strategy for all directly mappable values a la 'UA_Type MyInt = (UA_Type) 23;'
-      if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_GUID:
-        logger.warn("Don't know how to print scalar GUID in node " + str(self.parent.id()))
-      elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_DATETIME:
-        logger.warn("Don't know how to print scalar DateTime in node " + str(self.parent.id()))
-      elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_DIAGNOSTICINFO:
-        logger.warn("Don't know how to print scalar DiagnosticInfo in node " + str(self.parent.id()))
-      elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_STATUSCODE:
-        logger.warn("Don't know how to print scalar StatusCode in node " + str(self.parent.id()))
-      else:
-        # The following strategy applies to all other types, in particular strings and numerics.
-        if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
-          code.extend(self.value[0].printOpen62541CCode_SubType_build())
-        #code.append("attr.value.type = &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "];")
-        if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
-          code.append("UA_" + self.value[0].stringRepresentation + " *" + valueName + " = " + self.value[0].printOpen62541CCode_SubType() + ";")
-          code.append("UA_Variant_setScalar( &attr.value, " + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
-
-          #FIXME: There is no membership definition for extensionObjects generated in this function.
-          #code.append("UA_" + self.value[0].stringRepresentation + "_deleteMembers(" + valueName + ");")
-        else:
-          if bootstrapping == True:
-              code.append("UA_Variant* " + self.parent.getCodePrintableID() + "_variant = UA_Variant_new();" )
-          code.append("UA_" + self.value[0].stringRepresentation + " *" + valueName + " =  UA_" + self.value[0].stringRepresentation + "_new();")
-          code.append("*" + valueName + " = " + self.value[0].printOpen62541CCode_SubType() + ";")
-          if bootstrapping == False:
-            code.append("UA_Variant_setScalar( &attr.value, " + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
-          else:
-            code.append("UA_Variant_setScalar( "+self.parent.getCodePrintableID()+"_variant, " + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
-          #code.append("UA_" + self.value[0].stringRepresentation + "_deleteMembers(" + valueName + ");")
-    return code
-
-
 ###
-### Actual buitlin types
+### Actual builtin types
 ###
 
 class opcua_BuiltinType_extensionObject_t(opcua_value_t):
@@ -441,95 +355,6 @@ class opcua_BuiltinType_extensionObject_t(opcua_value_t):
     self.__codeInstanceName__ = self.parent.getCodePrintableID() + "_" + str(self.alias()) + "_" + str(arrayIndex) + "_" + str(recursionDepth)
     return self.__codeInstanceName__
 
-  def printOpen62541CCode_SubType_build(self, recursionDepth=0, arrayIndex=0):
-    code = [""]
-    codegen = open62541_MacroHelper();
-
-    logger.debug("Building extensionObject for " + str(self.parent.id()))
-    logger.debug("Value    " + str(self.value))
-    logger.debug("Encoding " + str(self.getEncodingRule()))
-
-    self.setCodeInstanceName(recursionDepth, arrayIndex)
-    # If there are any ExtensionObjects instide this ExtensionObject, we need to
-    # generate one-time-structs for them too before we can proceed;
-    for subv in self.value:
-      if isinstance(subv, list):
-        logger.debug("ExtensionObject contains an ExtensionObject, which is currently not encodable!", LOG_LEVEL_ERR)
-
-    code.append("struct {")
-    for field in self.getEncodingRule():
-      ptrSym = ""
-      # If this is an Array, this is pointer to its contents with a AliasOfFieldSize entry
-      if field[2] != 0:
-        code.append("  UA_Int32 " + str(field[0]) + "Size;")
-        ptrSym = "*"
-      if len(field[1]) == 1:
-        code.append("  UA_" + str(field[1][0]) + " " + ptrSym + str(field[0]) + ";")
-      else:
-        code.append("  UA_ExtensionObject " + " " + ptrSym + str(field[0]) + ";")
-    code.append("} " + self.getCodeInstanceName() + "_struct;")
-
-    # Assign data to the struct contents
-    # Track the encoding rule definition to detect arrays and/or ExtensionObjects
-    encFieldIdx = 0
-    for subv in self.value:
-      encField = self.getEncodingRule()[encFieldIdx]
-      encFieldIdx = encFieldIdx + 1;
-      logger.debug("Encoding of field " + subv.alias() + " is " + str(subv.getEncodingRule()) + "defined by " + str(encField))
-      # Check if this is an array
-      if encField[2] == 0:
-        code.append(self.getCodeInstanceName()+"_struct."+subv.alias() + " = " + subv.printOpen62541CCode_SubType(asIndirect=False) + ";")
-      else:
-        if isinstance(subv, list):
-          # this is an array
-          code.append(self.getCodeInstanceName()+"_struct."+subv.alias() + "Size = " + str(len(subv)) + ";")
-          code.append(self.getCodeInstanceName()+"_struct."+subv.alias()+" = (UA_" + subv.stringRepresentation + " *) UA_malloc(sizeof(UA_" + subv.stringRepresentation + ")*"+ str(len(subv))+");")
-          logger.debug("Encoding included array of " + str(len(subv)) + " values.")
-          for subvidx in range(0,len(subv)):
-            subvv = subv[subvidx]
-            logger.debug("  " + str(subvix) + " " + str(subvv))
-            code.append(self.getCodeInstanceName()+"_struct."+subv.alias() + "[" + str(subvidx) + "] = " + subvv.printOpen62541CCode_SubType(asIndirect=True) + ";")
-          code.append("}")
-        else:
-          code.append(self.getCodeInstanceName()+"_struct."+subv.alias() + "Size = 1;")
-          code.append(self.getCodeInstanceName()+"_struct."+subv.alias()+" = (UA_" + subv.stringRepresentation + " *) UA_malloc(sizeof(UA_" + subv.stringRepresentation + "));")
-          code.append(self.getCodeInstanceName()+"_struct."+subv.alias() + "[0]  = " + subv.printOpen62541CCode_SubType(asIndirect=True) + ";")
-
-
-    # Allocate some memory
-    code.append("UA_ExtensionObject *" + self.getCodeInstanceName() + " =  UA_ExtensionObject_new();")
-    code.append(self.getCodeInstanceName() + "->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;")
-    code.append(self.getCodeInstanceName() + "->content.encoded.typeId = UA_NODEID_NUMERIC(" + str(self.parent.dataType().target().id().ns) + ", " + str(self.parent.dataType().target().id().i) + "+ UA_ENCODINGOFFSET_BINARY);")
-    code.append("if(UA_ByteString_allocBuffer(&" + self.getCodeInstanceName() + "->content.encoded.body, 65000) != UA_STATUSCODE_GOOD) {}" )
-
-    # Encode each value as a bytestring seperately.
-    code.append("UA_Byte *pos" + self.getCodeInstanceName() + " = " + self.getCodeInstanceName() + "->content.encoded.body.data;")
-    code.append("const UA_Byte *end" + self.getCodeInstanceName() + " = &" + self.getCodeInstanceName() + "->content.encoded.body.data[65000];")
-    encFieldIdx = 0;
-    for subv in self.value:
-      encField = self.getEncodingRule()[encFieldIdx]
-      encFieldIdx = encFieldIdx + 1;
-      if encField[2] == 0:
-        code.append("retval |= UA_encodeBinary(&" + self.getCodeInstanceName()+"_struct."+subv.alias() + ", &UA_TYPES[UA_TYPES_" + subv.stringRepresentation.upper() + "], &pos" + self.getCodeInstanceName() + ", &end" + self.getCodeInstanceName() + ", NULL, NULL);" )
-      else:
-        if isinstance(subv, list):
-          for subvidx in range(0,len(subv)):
-            code.append("retval |= UA_encodeBinary(&" + self.getCodeInstanceName()+"_struct."+subv.alias() + "[" + str(subvidx) + "], &UA_TYPES[UA_TYPES_"  + subv.stringRepresentation.upper() + "], &pos" + self.getCodeInstanceName() + ", &end" + self.getCodeInstanceName() + ", NULL, NULL);" )
-        else:
-          code.append("retval |= UA_encodeBinary(&" + self.getCodeInstanceName()+"_struct."+subv.alias() + "[0], &UA_TYPES[UA_TYPES_"  + subv.stringRepresentation.upper() + "], &pos" + self.getCodeInstanceName() + ", &end" + self.getCodeInstanceName() + ", NULL, NULL);" )
-
-    # Reallocate the memory by swapping the 65k Bytestring for a new one
-    code.append("size_t " + self.getCodeInstanceName() + "_encOffset = (uintptr_t)(" +
-                "pos" + self.getCodeInstanceName() + "-" + self.getCodeInstanceName() + "->content.encoded.body.data);")
-    code.append(self.getCodeInstanceName() + "->content.encoded.body.length = " + self.getCodeInstanceName() + "_encOffset;");
-    code.append("UA_Byte *" + self.getCodeInstanceName() + "_newBody = (UA_Byte *) UA_malloc(" + self.getCodeInstanceName() + "_encOffset );" )
-    code.append("memcpy(" + self.getCodeInstanceName() + "_newBody, " + self.getCodeInstanceName() + "->content.encoded.body.data, " + self.getCodeInstanceName() + "_encOffset);" )
-    code.append("UA_Byte *" + self.getCodeInstanceName() + "_oldBody = " + self.getCodeInstanceName() + "->content.encoded.body.data;");
-    code.append(self.getCodeInstanceName() + "->content.encoded.body.data = " +self.getCodeInstanceName() + "_newBody;")
-    code.append("UA_free(" + self.getCodeInstanceName() + "_oldBody);")
-    code.append("")
-    return code
-
   def printOpen62541CCode_SubType(self, asIndirect=True):
     if asIndirect == False:
       return "*" + str(self.getCodeInstanceName())
@@ -598,13 +423,6 @@ class opcua_BuiltinType_localizedtext_t(opcua_value_t):
       else:
         self.value.append(tmp[0].firstChild.data)
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-      if asIndirect==True:
-        code = "UA_LOCALIZEDTEXT_ALLOC(\"" + str(self.value[0]) + "\", \"" + str(self.value[1].encode('utf-8')) + "\")"
-      else:
-        code = "UA_LOCALIZEDTEXT(\"" + str(self.value[0]) + "\", \"" + str(self.value[1].encode('utf-8')) + "\")"
-      return code
-
 class opcua_BuiltinType_expandednodeid_t(opcua_value_t):
   def setStringRepresentation(self):
     self.stringRepresentation = "ExpandedNodeId"
@@ -619,47 +437,7 @@ class opcua_BuiltinType_expandednodeid_t(opcua_value_t):
 
     logger.debug("Not implemented", LOG_LEVEL_ERR)
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-    #FIXME! This one is definetely broken!
-    code = ""
-    return code
-
 class opcua_BuiltinType_nodeid_t(opcua_value_t):
-  def setStringRepresentation(self):
-    self.stringRepresentation = "NodeId"
-
-  def setNumericRepresentation(self):
-    self.__binTypeId__ = BUILTINTYPE_TYPEID_NODEID
-
-  def parseXML(self, xmlvalue):
-    # Expect <NodeId> or <Alias>
-    #           <Identifier> # It is unclear whether or not this is manditory. Identifier tags are used in Namespace 0.
-    #                ns=x;i=y or similar string representation of id()
-    #           </Identifier>
-    #        </NodeId> or </Alias>
-    if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      logger.error("Expected XML Element, but got junk...")
-      return
-
-    if self.alias() != None:
-      if not self.alias() == xmlvalue.tagName:
-        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
-    else:
-      if not self.stringRepresentation == xmlvalue.tagName:
-        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
-
-    # Catch XML <NodeId />
-    if xmlvalue.firstChild == None :
-      logger.error("No value is given, which is illegal for Node Types...")
-      self.value = None
-    else:
-      # Check if there is an <Identifier> tag
-      if len(xmlvalue.getElementsByTagName("Identifier")) != 0:
-        xmlvalue = xmlvalue.getElementsByTagName("Identifier")[0]
-      self.value = self.parent.getNamespace().getNodeByIDString(unicode(xmlvalue.firstChild.data))
-      if self.value == None:
-        logger.error("Node with id " + str(unicode(xmlvalue.firstChild.data)) + " was not found in namespace.")
-
   def printOpen62541CCode_SubType(self, asIndirect=True):
     if self.value == None:
       return "UA_NODEID_NUMERIC(0,0)"
@@ -759,10 +537,6 @@ class opcua_BuiltinType_qualifiedname_t(opcua_value_t):
         self.value = [0]
         self.value.append(unicode(xmlvalue.firstChild.data))
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-      code = "UA_QUALIFIEDNAME_ALLOC(" + str(self.value[0]) + ", \"" + self.value[1].encode('utf-8') + "\")"
-      return code
-
 class opcua_BuiltinType_statuscode_t(opcua_value_t):
   def setStringRepresentation(self):
     self.stringRepresentation = "StatusCode"
@@ -863,9 +637,6 @@ class opcua_BuiltinType_boolean_t(opcua_value_t):
       else:
         self.value = "true"
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
-
 class opcua_BuiltinType_byte_t(opcua_value_t):
   def setStringRepresentation(self):
     self.stringRepresentation = "Byte"
@@ -897,9 +668,6 @@ class opcua_BuiltinType_byte_t(opcua_value_t):
       except:
         logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
-
 class opcua_BuiltinType_sbyte_t(opcua_value_t):
   def setStringRepresentation(self):
     self.stringRepresentation = "SByte"
@@ -931,9 +699,6 @@ class opcua_BuiltinType_sbyte_t(opcua_value_t):
       except:
         logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
-
 class opcua_BuiltinType_int16_t(opcua_value_t):
   def setStringRepresentation(self):
     self.stringRepresentation = "Int16"
@@ -965,9 +730,6 @@ class opcua_BuiltinType_int16_t(opcua_value_t):
       except:
         logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
-
 class opcua_BuiltinType_uint16_t(opcua_value_t):
   def setStringRepresentation(self):
     self.stringRepresentation = "UInt16"
@@ -999,9 +761,6 @@ class opcua_BuiltinType_uint16_t(opcua_value_t):
       except:
         logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
-
 class opcua_BuiltinType_int32_t(opcua_value_t):
   def setStringRepresentation(self):
     self.stringRepresentation = "Int32"
@@ -1033,9 +792,6 @@ class opcua_BuiltinType_int32_t(opcua_value_t):
       except:
         logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
-
 class opcua_BuiltinType_uint32_t(opcua_value_t):
   def setStringRepresentation(self):
     self.stringRepresentation = "UInt32"
@@ -1067,9 +823,6 @@ class opcua_BuiltinType_uint32_t(opcua_value_t):
       except:
         logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
-
 class opcua_BuiltinType_int64_t(opcua_value_t):
   def setStringRepresentation(self):
     self.stringRepresentation = "Int64"
@@ -1097,9 +850,6 @@ class opcua_BuiltinType_int64_t(opcua_value_t):
       except:
         logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
-
 class opcua_BuiltinType_uint64_t(opcua_value_t):
   def setStringRepresentation(self):
     self.stringRepresentation = "UInt64"
@@ -1131,9 +881,6 @@ class opcua_BuiltinType_uint64_t(opcua_value_t):
       except:
         logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
-
 class opcua_BuiltinType_float_t(opcua_value_t):
   def setStringRepresentation(self):
     self.stringRepresentation = "Float"
@@ -1165,9 +912,6 @@ class opcua_BuiltinType_float_t(opcua_value_t):
       except:
         logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
-
 class opcua_BuiltinType_double_t(opcua_value_t):
   def setStringRepresentation(self):
     self.stringRepresentation = "Double"
@@ -1199,9 +943,6 @@ class opcua_BuiltinType_double_t(opcua_value_t):
       except:
         logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-    return "(UA_" + self.stringRepresentation + ") " + str(self.value)
-
 class opcua_BuiltinType_string_t(opcua_value_t):
   def setStringRepresentation(self):
     self.stringRepresentation = "String"
@@ -1235,10 +976,6 @@ class opcua_BuiltinType_string_t(opcua_value_t):
     else:
       self.value = str(unicode(xmlvalue.firstChild.data))
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-      code = "UA_STRING_ALLOC(\"" + self.value.encode('utf-8') + "\")"
-      return code
-
 class opcua_BuiltinType_xmlelement_t(opcua_BuiltinType_string_t):
   def setStringRepresentation(self):
     self.stringRepresentation = "XmlElement"
@@ -1246,10 +983,6 @@ class opcua_BuiltinType_xmlelement_t(opcua_BuiltinType_string_t):
   def setNumericRepresentation(self):
     self.__binTypeId__ = BUILTINTYPE_TYPEID_XMLELEMENT
 
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-      code = "UA_XMLELEMENT_ALLOC(\"" + self.value.encode('utf-8') + "\")"
-      return code
-
 class opcua_BuiltinType_bytestring_t(opcua_value_t):
   def setStringRepresentation(self):
     self.stringRepresentation = "ByteString"
@@ -1277,16 +1010,3 @@ class opcua_BuiltinType_bytestring_t(opcua_value_t):
       self.value = ""
     else:
       self.value = str(unicode(xmlvalue.firstChild.data))
-
-  def printOpen62541CCode_SubType(self, asIndirect=True):
-      bs = ""
-      for line in self.value:
-        bs = bs + str(line).replace("\n","");
-      outs = bs
-      logger.debug("Encoded Bytestring: " + outs)
-#      bs = bs.decode('base64')
-#      outs = ""
-#      for s in bs:
-#        outs = outs + hex(ord(s)).upper().replace("0X", "\\x")
-      code = "UA_STRING_ALLOC(\"" + outs + "\")"
-      return code

+ 6 - 418
tools/pyUANamespace/ua_node_types.py

@@ -23,11 +23,15 @@
 import sys
 import logging
 from ua_builtin_types import *;
-from open62541_MacroHelper import open62541_MacroHelper
 from ua_constants import *
 
 logger = logging.getLogger(__name__)
 
+if sys.version_info[0] >= 3:
+  # strings are already parsed to unicode
+  def unicode(s):
+    return s
+
 def getNextElementNode(xmlvalue):
   if xmlvalue == None:
     return None
@@ -639,130 +643,6 @@ class opcua_node_t:
   def printXML(self):
     pass
 
-  def printOpen62541CCode_SubtypeEarly(self, bootstrapping = True):
-    """ printOpen62541CCode_SubtypeEarly
-
-        Initiate code segments for the nodes instantiotion that preceed
-        the actual UA_Server_addNode or UA_NodeStore_insert calls.
-    """
-    return []
-
-  def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
-    """ printOpen62541CCode_Subtype
-
-        Appends node type specific information to the nodes  UA_Server_addNode
-        or UA_NodeStore_insert calls.
-    """
-    return []
-
-  def printOpen62541CCode_HL_API(self, reference, supressGenerationOfAttribute=[]):
-    """ printOpen62541CCode_HL_API
-
-        Returns a list of strings containing the C-code necessary to intialize
-        this node for the open62541 OPC-UA Stack using only the high level API
-
-        Note that this function will fail if the nodeid is non-numeric, as
-        there is no UA_EXPANDEDNNODEID_[STRING|GUID|BYTESTRING] macro.
-    """
-    codegen = open62541_MacroHelper(supressGenerationOfAttribute=supressGenerationOfAttribute)
-    code = []
-    code.append("")
-    code.append("do {")
-    # If we are being passed a parent node by the namespace, use that for registering ourselves in the namespace
-    # Note: getFirstParentNode will return [parentNode, referenceToChild]
-    parentNode = reference.target()
-    parentRefType = reference.referenceType()
-    code.append("// Referencing node found and declared as parent: " + str(parentNode .id()) + "/" +
-                  str(parentNode .__node_browseName__) + " using " + str(parentRefType.id()) +
-                  "/" + str(parentRefType.__node_browseName__))
-    code.extend(codegen.getCreateNodeNoBootstrap(self, parentNode, reference))
-    code.append("} while(0);")
-    return code
-
-
-  def printOpen62541CCode(self, unPrintedNodes=[], unPrintedReferences=[], supressGenerationOfAttribute=[]):
-    """ printOpen62541CCode
-
-        Returns a list of strings containing the C-code necessary to intialize
-        this node for the open62541 OPC-UA Stack.
-
-        Note that this function will fail if the nodeid is non-numeric, as
-        there is no UA_EXPANDEDNNODEID_[STRING|GUID|BYTESTRING] macro.
-    """
-    codegen = open62541_MacroHelper(supressGenerationOfAttribute=supressGenerationOfAttribute)
-    code = []
-    code.append("")
-    code.append("do {")
-
-    # Just to be sure...
-    if not (self in unPrintedNodes):
-      logger.warn(str(self) + " attempted to reprint already printed node " + str(self)+ ".")
-      return []
-
-    # If we are being passed a parent node by the namespace, use that for registering ourselves in the namespace
-    # Note: getFirstParentNode will return [parentNode, referenceToChild]
-    (parentNode, parentRef) = self.getFirstParentNode()
-    if not (parentNode in unPrintedNodes) and (parentNode != None) and (parentRef.referenceType() != None):
-      code.append("// Referencing node found and declared as parent: " + str(parentNode .id()) + "/" +
-                  str(parentNode .__node_browseName__) + " using " + str(parentRef.referenceType().id()) +
-                  "/" + str(parentRef.referenceType().__node_browseName__))
-      code.extend(codegen.getCreateNodeNoBootstrap(self, parentNode, parentRef, unPrintedNodes))
-      # Parent to child reference is added by the server, do not reprint that reference
-      if parentRef in unPrintedReferences:
-        unPrintedReferences.remove(parentRef)
-      # the UA_Server_addNode function will use addReference which creates a bidirectional reference; remove any inverse
-      # references to our parent to avoid duplicate refs
-      for ref in self.getReferences():
-        if ref.target() == parentNode and ref.referenceType() == parentRef.referenceType() and ref.isForward() == False:
-          while ref in unPrintedReferences:
-            unPrintedReferences.remove(ref)
-    # Otherwise use the "Bootstrapping" method and we will get registered with other nodes later.
-    else:
-      code.append("/* Omit bootstrapping the node %s */" % str(self.id()))
-
-    # Try to print all references to nodes that already exist
-    # Note: we know the reference types exist, because the namespace class made sure they were
-    #       the first ones being printed
-    tmprefs = []
-    for r in self.getReferences():
-      #logger.debug("Checking if reference from " + str(r.parent()) + "can be created...")
-      if not (r.target() in unPrintedNodes):
-        if r in unPrintedReferences:
-          if (len(tmprefs) == 0):
-            code.append("// This node has the following references that can be created:")
-          code.extend(codegen.getCreateStandaloneReference(self, r))
-          tmprefs.append(r)
-    # Remove printed refs from list
-    for r in tmprefs:
-      unPrintedReferences.remove(r)
-
-    # Again, but this time check if other nodes deffered their node creation because this node did
-    # not exist...
-    tmprefs = []
-    for r in unPrintedReferences:
-      #logger.debug("Checking if another reference " + str(r.target()) + "can be created...")
-      if (r.target() == self) and not (r.parent() in unPrintedNodes):
-        if not isinstance(r.parent(), opcua_node_t):
-          logger.debug("Reference has no parent!")
-        elif not isinstance(r.parent().id(), opcua_node_id_t):
-          logger.debug("Parents nodeid is not a nodeID!")
-        else:
-          if (len(tmprefs) == 0):
-            code.append("//  Creating this node has resolved the following open references:")
-          code.extend(codegen.getCreateStandaloneReference(r.parent(), r))
-          tmprefs.append(r)
-    # Remove printed refs from list
-    for r in tmprefs:
-      unPrintedReferences.remove(r)
-
-    # Again, just to be sure...
-    if self in unPrintedNodes:
-      # This is necessery to make printing work at all!
-      unPrintedNodes.remove(self)
-
-    code.append("} while(0);")
-    return code
-
 class opcua_node_referenceType_t(opcua_node_t):
   __isAbstract__    = False
   __symmetric__     = False
@@ -830,46 +710,6 @@ class opcua_node_referenceType_t(opcua_node_t):
         else:
           logger.warn( "Unprocessable XML Element: " + x.tagName)
 
-  def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
-    code = []
-    codegen = open62541_MacroHelper()
-
-    # Detect if this is bootstrapping or if we are attempting to use userspace...
-    if bootstrapping == False:
-      typeDefs = self.getNamespace().getSubTypesOf() # defaults to TypeDefinition
-      myTypeRef = None
-      for ref in self.getReferences():
-        if ref.referenceType() in typeDefs:
-          myTypeRef = ref
-          break
-      if myTypeRef==None:
-        for ref in self.getReferences():
-          if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
-            myTypeRef = ref
-            break
-      if myTypeRef==None:
-        logger.warn(str(self) + " failed to locate a type definition, assuming BaseDataType.")
-        code.append("       // No valid typeDefinition found; assuming BaseDataType")
-        code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE),")
-      else:
-        code.append("       " + codegen.getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
-        while myTypeRef in unPrintedReferences:
-          unPrintedReferences.remove(myTypeRef)
-
-      code.append("       UA_LOCALIZEDTEXT(\"\",\"" + str(self.inverseName()) + "\"),");
-      code.append("       // FIXME: Missing, isAbstract")
-      code.append("       // FIXME: Missing, symmetric")
-      return code
-
-    if self.isAbstract():
-      code.append(self.getCodePrintableID() + "->isAbstract = true;")
-    if self.symmetric():
-      code.append(self.getCodePrintableID() + "->symmetric  = true;")
-    if self.__reference_inverseName__ != "":
-      code.append(self.getCodePrintableID() + "->inverseName  = UA_LOCALIZEDTEXT_ALLOC(\"\", \"" + self.__reference_inverseName__ + "\");")
-    return code;
-
-
 class opcua_node_object_t(opcua_node_t):
   __object_eventNotifier__ = 0
 
@@ -897,44 +737,6 @@ class opcua_node_object_t(opcua_node_t):
       if x.nodeType == x.ELEMENT_NODE:
         logger.info( "Unprocessable XML Element: " + x.tagName)
 
-  def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
-    code = []
-    codegen = open62541_MacroHelper()
-
-    # Detect if this is bootstrapping or if we are attempting to use userspace...
-    if bootstrapping == False:
-      typeDefs = self.getNamespace().getSubTypesOf() # defaults to TypeDefinition
-      myTypeRef = None
-      for ref in self.getReferences():
-        if ref.referenceType() in typeDefs:
-          myTypeRef = ref
-          break
-      if myTypeRef==None:
-        for ref in self.getReferences():
-          if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
-            myTypeRef = ref
-            break
-      if myTypeRef==None:
-        logger.warn(str(self) + " failed to locate a type definition, assuming BaseObjectType.")
-        code.append("       // No valid typeDefinition found; assuming BaseObjectType")
-        code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),")
-      else:
-        code.append("       " + codegen.getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
-        while myTypeRef in unPrintedReferences:
-          unPrintedReferences.remove(myTypeRef)
-
-      #FIXME: No event notifier in UA_Server_addNode call!
-      return code
-
-    # We are being bootstrapped! Add the raw attributes to the node.
-    code.append(self.getCodePrintableID() + "->eventNotifier = (UA_Byte) " + str(self.eventNotifier()) + ";")
-    return code
-
-if sys.version_info[0] >= 3:
-  # strings are already parsed to unicode
-  def unicode(s):
-    return s
-
 class opcua_node_variable_t(opcua_node_t):
   __value__               = 0
   __dataType__            = None
@@ -1092,45 +894,6 @@ class opcua_node_variable_t(opcua_node_t):
         else:
           logger.info( "Unprocessable XML Element: " + x.tagName)
 
-  def printOpen62541CCode_SubtypeEarly(self, bootstrapping = True):
-    code = []
-    # If we have an encodable value, try to encode that
-    if self.dataType() != None and isinstance(self.dataType().target(), opcua_node_dataType_t):
-      # Delegate the encoding of the datavalue to the helper if we have
-      # determined a valid encoding
-      if self.dataType().target().isEncodable():
-        if self.value() != None:
-          code.extend(self.value().printOpen62541CCode(bootstrapping))
-          return code
-    if(bootstrapping):
-      code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = (UA_Variant*)UA_alloca(sizeof(UA_Variant));")
-      code.append("UA_Variant_init(" + self.getCodePrintableID() + "_variant);")
-    return code
-
-  def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
-    code = []
-    codegen = open62541_MacroHelper()
-
-    # Detect if this is bootstrapping or if we are attempting to use userspace...
-    if bootstrapping == False:
-      code.append("       " + self.getCodePrintableID() + "_variant, ")
-      code.append("       // FIXME: missing minimumSamplingInterval")
-      code.append("       // FIXME: missing accessLevel")
-      code.append("       // FIXME: missing userAccessLevel")
-      code.append("       // FIXME: missing valueRank")
-      return code
-
-    if self.historizing():
-      code.append(self.getCodePrintableID() + "->historizing = true;")
-
-    code.append(self.getCodePrintableID() + "->minimumSamplingInterval = (UA_Double) " + str(self.minimumSamplingInterval()) + ";")
-    code.append(self.getCodePrintableID() + "->accessLevel = (UA_Int32) " + str(self.accessLevel()) + ";")
-    code.append(self.getCodePrintableID() + "->valueRank = (UA_Int32) " + str(self.valueRank()) + ";")
-    # The variant is guaranteed to exist by SubtypeEarly()
-    code.append("UA_Variant_copy(" + self.getCodePrintableID() + "_variant, &" + self.getCodePrintableID() + "->value.data.value.value );")
-    code.append(self.getCodePrintableID() + "->valueSource = UA_VALUESOURCE_DATA;")
-    return code
-
 class opcua_node_method_t(opcua_node_t):
   __executable__     = True
   __userExecutable__ = True
@@ -1178,27 +941,6 @@ class opcua_node_method_t(opcua_node_t):
       if x.nodeType == x.ELEMENT_NODE:
         logger.info( "Unprocessable XML Element: " + x.tagName)
 
-  def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
-    code = []
-
-    # Detect if this is bootstrapping or if we are attempting to use userspace...
-    if bootstrapping == False:
-      code.append("       // Note: in/outputArguments are added by attaching the variable nodes,")
-      code.append("       //       not by including the in the addMethodNode() call.")
-      code.append("       NULL,")
-      code.append("       NULL,")
-      code.append("       0, NULL,")
-      code.append("       0, NULL,")
-      code.append("       // FIXME: Missing executable")
-      code.append("       // FIXME: Missing userExecutable")
-      return code
-
-    # UA_False is default for booleans on _init()
-    if self.executable():
-      code.append(self.getCodePrintableID() + "->executable = true;")
-
-    return code
-
 class opcua_node_objectType_t(opcua_node_t):
   __isAbstract__ = False
 
@@ -1224,44 +966,6 @@ class opcua_node_objectType_t(opcua_node_t):
       if x.nodeType == x.ELEMENT_NODE:
         logger.info( "Unprocessable XML Element: " + x.tagName)
 
-  def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
-    code = []
-    codegen = open62541_MacroHelper();
-
-    # Detect if this is bootstrapping or if we are attempting to use userspace...
-    if bootstrapping == False:
-      typeDefs = self.getNamespace().getSubTypesOf() # defaults to TypeDefinition
-      myTypeRef = None
-      for ref in self.getReferences():
-        if ref.referenceType() in typeDefs:
-          myTypeRef = ref
-          break
-      if myTypeRef==None:
-        for ref in self.getReferences():
-          if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
-            myTypeRef = ref
-            break
-      if myTypeRef==None:
-        logger.warn(str(self) + " failed to locate a type definition, assuming BaseObjectType.")
-        code.append("       // No valid typeDefinition found; assuming BaseObjectType")
-        code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),")
-      else:
-        code.append("       " + codegen.getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
-        while myTypeRef in unPrintedReferences:
-          code.append("       // removed " + str(myTypeRef))
-          unPrintedReferences.remove(myTypeRef)
-
-      if (self.isAbstract()):
-        code.append("       true,")
-      else:
-        code.append("       false,")
-
-    # Fallback mode for bootstrapping
-    if (self.isAbstract()):
-      code.append(self.getCodePrintableID() + "->isAbstract = true;")
-
-    return code
-
 class opcua_node_variableType_t(opcua_node_t):
   __value__ = 0
   __dataType__ = None
@@ -1346,44 +1050,6 @@ class opcua_node_variableType_t(opcua_node_t):
         else:
           logger.info( "Unprocessable XML Element: " + x.tagName)
 
-  def printOpen62541CCode_SubtypeEarly(self, bootstrapping = True):
-    code = []
-    # If we have an encodable value, try to encode that
-    if self.dataType() != None and isinstance(self.dataType().target(), opcua_node_dataType_t):
-      # Delegate the encoding of the datavalue to the helper if we have
-      # determined a valid encoding
-      if self.dataType().target().isEncodable():
-        if self.value() != None:
-          code.extend(self.value().printOpen62541CCode(bootstrapping))
-          return code
-    if(bootstrapping):
-      code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = (UA_Variant*)UA_alloca(sizeof(UA_Variant));")
-      code.append("UA_Variant_init(" + self.getCodePrintableID() + "_variant);")
-    return code
-
-  def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
-    code = []
-    codegen = open62541_MacroHelper()
-
-    if bootstrapping == False:
-      code.append("       " + self.getCodePrintableID() + "_variant, ")
-      code.append("       " + str(self.valueRank()) + ",")
-      if self.isAbstract():
-        code.append("       true,")
-      else:
-        code.append("       false,")
-      return code
-
-    if (self.isAbstract()):
-      code.append(self.getCodePrintableID() + "->isAbstract = true;")
-    else:
-      code.append(self.getCodePrintableID() + "->isAbstract = false;")
-
-    # The variant is guaranteed to exist by SubtypeEarly()
-    code.append("UA_Variant_copy(" + self.getCodePrintableID() + "_variant, &" + self.getCodePrintableID() + "->value.data.value.value );")
-    code.append(self.getCodePrintableID() + "->valueSource = UA_VALUESOURCE_DATA;")
-    return code
-
 class opcua_node_dataType_t(opcua_node_t):
   """ opcua_node_dataType_t is a subtype of opcua_note_t describing DataType nodes.
 
@@ -1668,8 +1334,7 @@ class opcua_node_dataType_t(opcua_node_t):
         to represent this datatype.
     """
     if self.isEncodable() != True or len(self.getEncoding()) == 0:
-      # Encoding is []
-      return 0
+      return 0 # Encoding is []
     else:
       enc = self.getEncoding()
       if len(enc) > 1 and isinstance(enc[0], list):
@@ -1691,44 +1356,6 @@ class opcua_node_dataType_t(opcua_node_t):
           else:
             return opcua_value_t(None).getTypeByString(enc[0]).getNumericRepresentation()
 
-  def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
-    code = []
-    codegen = open62541_MacroHelper()
-
-    # Detect if this is bootstrapping or if we are attempting to use userspace...
-    if bootstrapping == False:
-      typeDefs = self.getNamespace().getSubTypesOf() # defaults to TypeDefinition
-      myTypeRef = None
-      for ref in self.getReferences():
-        if ref.referenceType() in typeDefs:
-          myTypeRef = ref
-          break
-      if myTypeRef==None:
-        for ref in self.getReferences():
-          if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
-            myTypeRef = ref
-            break
-      if myTypeRef==None:
-        logger.warn(str(self) + " failed to locate a type definition, assuming BaseDataType.")
-        code.append("       // No valid typeDefinition found; assuming BaseDataType")
-        code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE),")
-      else:
-        code.append("       " + codegen.getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
-        while myTypeRef in unPrintedReferences:
-          unPrintedReferences.remove(myTypeRef)
-
-      if (self.isAbstract()):
-        code.append("       true,")
-      else:
-        code.append("       false,")
-      return code
-
-    if (self.isAbstract()):
-      code.append(self.getCodePrintableID() + "->isAbstract = true;")
-    else:
-      code.append(self.getCodePrintableID() + "->isAbstract = false;")
-    return code
-
 class opcua_node_view_t(opcua_node_t):
   __containsNoLoops__ = True
   __eventNotifier__   = 0
@@ -1755,42 +1382,3 @@ class opcua_node_view_t(opcua_node_t):
     for x in xmlelement.childNodes:
       if x.nodeType == x.ELEMENT_NODE:
         logger.info( "Unprocessable XML Element: " + x.tagName)
-
-  def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
-    code = []
-    codegen = open62541_MacroHelper()
-
-    # Detect if this is bootstrapping or if we are attempting to use userspace...
-    if bootstrapping == False:
-      typeDefs = self.getNamespace().getSubTypesOf() # defaults to TypeDefinition
-      myTypeRef = None
-      for ref in self.getReferences():
-        if ref.referenceType() in typeDefs:
-          myTypeRef = ref
-          break
-      if myTypeRef==None:
-        for ref in self.getReferences():
-          if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
-            myTypeRef = ref
-            break
-      if myTypeRef==None:
-        logger.warn(str(self) + " failed to locate a type definition, assuming BaseViewType.")
-        code.append("       // No valid typeDefinition found; assuming BaseViewType")
-        code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEViewTYPE),")
-      else:
-        code.append("       " + codegen.getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
-        while myTypeRef in unPrintedReferences:
-          unPrintedReferences.remove(myTypeRef)
-
-      code.append("       // FIXME: Missing eventNotifier")
-      code.append("       // FIXME: Missing containsNoLoops")
-      return code
-
-    if self.containsNoLoops():
-      code.append(self.getCodePrintableID() + "->containsNoLoops = true;")
-    else:
-      code.append(self.getCodePrintableID() + "->containsNoLoops = false;")
-
-    code.append(self.getCodePrintableID() + "->eventNotifier = (UA_Byte) " + str(self.eventNotifier()) + ";")
-
-    return code

+ 7 - 243
tools/pyUANamespace/ua_namespace.py

@@ -22,19 +22,14 @@
 
 from __future__ import print_function
 import sys
-from time import struct_time, strftime, strptime, mktime
 from struct import pack as structpack
-
 from collections import deque
+from time import struct_time, strftime, strptime, mktime
+import logging; logger = logging.getLogger(__name__)
 
-import logging
 from ua_builtin_types import *;
 from ua_node_types import *;
 from ua_constants import *;
-from open62541_MacroHelper import open62541_MacroHelper
-
-
-logger = logging.getLogger(__name__)
 
 def getNextElementNode(xmlvalue):
   if xmlvalue == None:
@@ -44,11 +39,7 @@ def getNextElementNode(xmlvalue):
     xmlvalue = xmlvalue.nextSibling
   return xmlvalue
 
-###
-### Namespace Organizer
-###
-
-class opcua_namespace():
+class NodeSet():
   """ Class holding and managing a set of OPCUA nodes.
 
       This class handles parsing XML description of namespaces, instantiating
@@ -365,7 +356,8 @@ class opcua_namespace():
       if referenceLinked == True and targetLinked == True:
         linked.append(l)
 
-    # References marked as "not forward" must be inverted (removed from source node, assigned to target node and relinked)
+    # References marked as "not forward" must be inverted (removed from source
+    # node, assigned to target node and relinked)
     logger.warn("Inverting reference direction for all references with isForward==False attribute (is this correct!?)")
     for n in self.nodes:
       for r in n.getReferences():
@@ -421,7 +413,6 @@ class opcua_namespace():
       if isinstance(n, opcua_node_variable_t):
         n.allocateValue()
 
-
   def getSubTypesOf(self, tdNodes = None, currentNode = None, hasSubtypeRefNode = None):
     # If this is a toplevel call, collect the following information as defaults
     if tdNodes == None:
@@ -445,7 +436,8 @@ class opcua_namespace():
     return tdNodes
 
 
-  def printDotGraphWalk(self, depth=1, filename="out.dot", rootNode=None, followInverse = False, excludeNodeIds=[]):
+  def printDotGraphWalk(self, depth=1, filename="out.dot", rootNode=None,
+                        followInverse = False, excludeNodeIds=[]):
     """ Outputs a graphiz/dot description the nodes centered around rootNode.
 
         References beginning from rootNode will be followed for depth steps. If
@@ -548,231 +540,3 @@ class opcua_namespace():
         logger.error("Node graph is circular on the specified references")
         self.nodes = L + [x for x in self.nodes if x not in L]
     return
-
-  def printOpen62541Header(self, printedExternally=[], supressGenerationOfAttribute=[], outfilename=""):
-    unPrintedNodes = []
-    unPrintedRefs  = []
-    code = []
-    header = []
-
-    # Reorder our nodes to produce a bare minimum of bootstrapping dependencies
-    logger.debug("Reordering nodes for minimal dependencies during printing.")
-    self.reorderNodesMinDependencies(printedExternally)
-
-    # Some macros (UA_EXPANDEDNODEID_MACRO()...) are easily created, but
-    # bulky. This class will help to offload some code.
-    codegen = open62541_MacroHelper(supressGenerationOfAttribute=supressGenerationOfAttribute)
-    # Populate the unPrinted-Lists with everything we have.
-    # Every Time a nodes printfunction is called, it will pop itself and
-    #   all printed references from these lists.
-    for n in self.nodes:
-      if not n in printedExternally:
-        unPrintedNodes.append(n)
-      else:
-        logger.debug("Node " + str(n.id()) + " is being ignored.")
-    for n in unPrintedNodes:
-      for r in n.getReferences():
-        if (r.target() != None) and (r.target().id() != None) and (r.parent() != None):
-          unPrintedRefs.append(r)
-
-    logger.debug("%d nodes and %d references need to get printed.", len(unPrintedNodes), len(unPrintedRefs))
-    header.append("/* WARNING: This is a generated file.\n * Any manual changes will be overwritten.\n\n */")
-    code.append("/* WARNING: This is a generated file.\n * Any manual changes will be overwritten.\n\n */")
-
-    header.append('#ifndef '+outfilename.upper()+'_H_')
-    header.append('#define '+outfilename.upper()+'_H_')
-    header.append('')
-    header.append('#include "ua_server.h"')
-    header.append('#include "ua_plugin_nodestore.h"')
-    header.append('#include "ua_types_encoding_binary.h"')
-    header.append('#include "ua_types_generated_encoding_binary.h"')
-    header.append('')
-    header.append('/* Definition that (in userspace models) may be ')
-    header.append(' * - not included in the amalgamated header or')
-    header.append(' * - not part of public headers or')
-    header.append(' * - not exported in the shared object in combination with any of the above')
-    header.append(' * but are required for value encoding.')
-    header.append(' * NOTE: Userspace UA_(decode|encode)Binary /wo amalgamations requires UA_EXPORT to be appended to the appropriate definitions. */')
-    header.append('#ifndef UA_ENCODINGOFFSET_BINARY')
-    header.append('#  define UA_ENCODINGOFFSET_BINARY 2')
-    header.append('#endif')
-    
-    code.append('#include "'+outfilename+'.h"')
-    code.append("UA_INLINE UA_StatusCode "+outfilename+"(UA_Server *server) {\n")
-    code.append('UA_StatusCode retval = UA_STATUSCODE_GOOD; ')
-    code.append('if(retval == UA_STATUSCODE_GOOD){retval = UA_STATUSCODE_GOOD;} //ensure that retval is used');
-
-    # Before printing nodes, we need to request additional namespace arrays from the server
-    for nsid in self.namespaceIdentifiers:
-      if nsid == 0 or nsid==1:
-        continue
-      else:
-        name =  self.namespaceIdentifiers[nsid]
-        name = name.replace("\"","\\\"")
-        code.append("if (UA_Server_addNamespace(server, \"{0}\") != {1})\n    return UA_STATUSCODE_BADUNEXPECTEDERROR;".format(name, nsid))
-
-    # Find all references necessary to create the namespace and
-    # "Bootstrap" them so all other nodes can safely use these referencetypes whenever
-    # they can locate both source and target of the reference.
-    logger.debug("Collecting all references used in the namespace.")
-    refsUsed = []
-    for n in self.nodes:
-      # Since we are already looping over all nodes, use this chance to print NodeId defines
-      if n.id().ns != 0:
-        nc = n.nodeClass()
-        if nc != NODE_CLASS_OBJECT and nc != NODE_CLASS_VARIABLE and nc != NODE_CLASS_VIEW:
-          header.append(codegen.getNodeIdDefineString(n))
-
-      # Now for the actual references...
-      for r in n.getReferences():
-        # Only print valid references in namespace 0 (users will not want their refs bootstrapped)
-        if not r.referenceType() in refsUsed and r.referenceType() != None and r.referenceType().id().ns == 0:
-          refsUsed.append(r.referenceType())
-    logger.debug("%d reference types are used in the namespace, which will now get bootstrapped.", len(refsUsed))
-    for r in refsUsed:
-      code.extend(r.printOpen62541CCode(unPrintedNodes, unPrintedRefs))
-
-    logger.debug("%d Nodes, %d References need to get printed.", len(unPrintedNodes), len(unPrintedRefs))
-
-    if not high_level_api:
-        # Note to self: do NOT - NOT! - try to iterate over unPrintedNodes!
-        #               Nodes remove themselves from this list when printed.
-        logger.debug("Printing all other nodes.")
-        for n in self.nodes:
-          code.extend(n.printOpen62541CCode(unPrintedNodes, unPrintedRefs, supressGenerationOfAttribute=supressGenerationOfAttribute))
-
-        if len(unPrintedNodes) != 0:
-          logger.warn("%d nodes could not be translated to code.", len(unPrintedNodes))
-        else:
-          logger.debug("Printing suceeded for all nodes")
-
-        if len(unPrintedRefs) != 0:
-          logger.debug("Attempting to print " + str(len(unPrintedRefs)) + " unprinted references.")
-          tmprefs = []
-          for r in unPrintedRefs:
-            if  not (r.target() not in unPrintedNodes) and not (r.parent() in unPrintedNodes):
-              if not isinstance(r.parent(), opcua_node_t):
-                logger.debug("Reference has no parent!")
-              elif not isinstance(r.parent().id(), opcua_node_id_t):
-                logger.debug("Parents nodeid is not a nodeID!")
-              else:
-                if (len(tmprefs) == 0):
-                  code.append("//  Creating leftover references:")
-                code.extend(codegen.getCreateStandaloneReference(r.parent(), r))
-                code.append("")
-                tmprefs.append(r)
-          # Remove printed refs from list
-          for r in tmprefs:
-            unPrintedRefs.remove(r)
-          if len(unPrintedRefs) != 0:
-            logger.warn("" + str(len(unPrintedRefs)) + " references could not be translated to code.")
-        else:
-          logger.debug("Printing succeeded for all references")
-    else:  # Using only High Level API
-        already_printed = list(printedExternally)
-        while unPrintedNodes:
-            node_found = False
-            for node in unPrintedNodes:
-                for ref in node.getReferences():
-                    if ref.referenceType() in already_printed and ref.target() in already_printed:
-                        node_found = True
-                        code.extend(node.printOpen62541CCode_HL_API(ref, supressGenerationOfAttribute))
-                        unPrintedRefs.remove(ref)
-                        unPrintedNodes.remove(node)
-                        already_printed.append(node)
-                        break
-            if not node_found:
-                logger.critical("no complete code generation with high level API possible; not all nodes will be created")
-                code.append("CRITICAL: no complete code generation with high level API possible; not all nodes will be created")
-                break
-        code.append("// creating references")
-        for r in unPrintedRefs:
-            code.extend(codegen.getCreateStandaloneReference(r.parent(), r))
-
-    # finalizing source and header
-    header.append("extern void "+outfilename+"(UA_Server *server);\n")
-    header.append("#endif /* "+outfilename.upper()+"_H_ */")
-    code.append("return UA_STATUSCODE_GOOD;")
-    code.append("} // closing nodeset()")
-    return (header,code)
-
-###
-### Testing
-###
-
-class testing:
-  def __init__(self):
-    self.namespace = opcua_namespace("testing")
-
-    logger.debug("Phase 1: Reading XML file nodessets")
-    self.namespace.parseXML("Opc.Ua.NodeSet2.xml")
-    #self.namespace.parseXML("Opc.Ua.NodeSet2.Part4.xml")
-    #self.namespace.parseXML("Opc.Ua.NodeSet2.Part5.xml")
-    #self.namespace.parseXML("Opc.Ua.SimulationNodeSet2.xml")
-
-    logger.debug("Phase 2: Linking address space references and datatypes")
-    self.namespace.linkOpenPointers()
-    self.namespace.sanitize()
-
-    logger.debug("Phase 3: Comprehending DataType encoding rules")
-    self.namespace.buildEncodingRules()
-
-    logger.debug("Phase 4: Allocating variable value data")
-    self.namespace.allocateVariables()
-
-    bin = self.namespace.buildBinary()
-    f = open("binary.base64","w+")
-    f.write(bin.encode("base64"))
-    f.close()
-
-    allnodes = self.namespace.nodes;
-    ns = [self.namespace.getRoot()]
-
-    i = 0
-    #print "Starting depth search on " + str(len(allnodes)) + " nodes starting with from " + str(ns)
-    while (len(ns) < len(allnodes)):
-      i = i + 1;
-      tmp = [];
-      print("Iteration: " + str(i))
-      for n in ns:
-        tmp.append(n)
-        for r in n.getReferences():
-          if (not r.target() in tmp):
-           tmp.append(r.target())
-      print("...tmp, " + str(len(tmp)) + " nodes discovered")
-      ns = []
-      for n in tmp:
-        ns.append(n)
-      print("...done, " + str(len(ns)) + " nodes discovered")
-
-
-class testing_open62541_header:
-  def __init__(self):
-    self.namespace = opcua_namespace("testing")
-
-    logger.debug("Phase 1: Reading XML file nodessets")
-    self.namespace.parseXML("Opc.Ua.NodeSet2.xml")
-    #self.namespace.parseXML("Opc.Ua.NodeSet2.Part4.xml")
-    #self.namespace.parseXML("Opc.Ua.NodeSet2.Part5.xml")
-    #self.namespace.parseXML("Opc.Ua.SimulationNodeSet2.xml")
-
-    logger.debug("Phase 2: Linking address space references and datatypes")
-    self.namespace.linkOpenPointers()
-    self.namespace.sanitize()
-
-    logger.debug("Phase 3: Calling C Printers")
-    code = self.namespace.printOpen62541Header()
-
-    codeout = open("./open62541_namespace.c", "w+")
-    for line in code:
-      codeout.write(line + "\n")
-    codeout.close()
-    return
-
-# Call testing routine if invoked standalone.
-# For better debugging, it is advised to import this file using an interactive
-# python shell and instantiating a namespace.
-#
-# import ua_types.py as ua; ns=ua.testing().namespace
-if __name__ == '__main__':
-  tst = testing_open62541_header()

+ 77 - 0
tools/pyUANamespace/ua_nodeset_testing.py

@@ -0,0 +1,77 @@
+from ua_nodeset import *
+
+class testing:
+  def __init__(self):
+    self.ns = NodeSet("testing")
+
+    logger.debug("Phase 1: Reading XML file nodessets")
+    self.ns.parseXML("Opc.Ua.NodeSet2.xml")
+    #self.ns.parseXML("Opc.Ua.NodeSet2.Part4.xml")
+    #self.ns.parseXML("Opc.Ua.NodeSet2.Part5.xml")
+    #self.ns.parseXML("Opc.Ua.SimulationNodeSet2.xml")
+
+    logger.debug("Phase 2: Linking address space references and datatypes")
+    self.ns.linkOpenPointers()
+    self.ns.sanitize()
+
+    logger.debug("Phase 3: Comprehending DataType encoding rules")
+    self.ns.buildEncodingRules()
+
+    logger.debug("Phase 4: Allocating variable value data")
+    self.ns.allocateVariables()
+
+    bin = self.ns.buildBinary()
+    f = open("binary.base64","w+")
+    f.write(bin.encode("base64"))
+    f.close()
+
+    allnodes = self.ns.nodes;
+    ns = [self.ns.getRoot()]
+
+    i = 0
+    #print "Starting depth search on " + str(len(allnodes)) + " nodes starting with from " + str(ns)
+    while (len(ns) < len(allnodes)):
+      i = i + 1;
+      tmp = [];
+      print("Iteration: " + str(i))
+      for n in ns:
+        tmp.append(n)
+        for r in n.getReferences():
+          if (not r.target() in tmp):
+           tmp.append(r.target())
+      print("...tmp, " + str(len(tmp)) + " nodes discovered")
+      ns = []
+      for n in tmp:
+        ns.append(n)
+      print("...done, " + str(len(ns)) + " nodes discovered")
+
+class testing_open62541_header:
+  def __init__(self):
+    self.ns = opcua_ns("testing")
+
+    logger.debug("Phase 1: Reading XML file nodessets")
+    self.ns.parseXML("Opc.Ua.NodeSet2.xml")
+    #self.ns.parseXML("Opc.Ua.NodeSet2.Part4.xml")
+    #self.ns.parseXML("Opc.Ua.NodeSet2.Part5.xml")
+    #self.ns.parseXML("Opc.Ua.SimulationNodeSet2.xml")
+
+    logger.debug("Phase 2: Linking address space references and datatypes")
+    self.ns.linkOpenPointers()
+    self.ns.sanitize()
+
+    logger.debug("Phase 3: Calling C Printers")
+    code = self.ns.printOpen62541Header()
+
+    codeout = open("./open62541_nodeset.c", "w+")
+    for line in code:
+      codeout.write(line + "\n")
+    codeout.close()
+    return
+
+# Call testing routine if invoked standalone.
+# For better debugging, it is advised to import this file using an interactive
+# python shell and instantiating a nodeset.
+#
+# import ua_types.py as ua; ns=ua.testing().nodeset
+if __name__ == '__main__':
+  tst = testing_open62541_header()