瀏覽代碼

Dynamic topological sorting of nodes enabled; fixed duplicate referencing of dataType and subType definitions.

ichrispa 9 年之前
父節點
當前提交
09f8df55d8
共有 2 個文件被更改,包括 141 次插入42 次删除
  1. 89 3
      tools/pyUANamespace/ua_namespace.py
  2. 52 39
      tools/pyUANamespace/ua_node_types.py

+ 89 - 3
tools/pyUANamespace/ua_namespace.py

@@ -516,16 +516,101 @@ class opcua_namespace():
     file.write("}\n")
     file.close()
 
+  def __reorder_getMinWeightNode__(self, nmatrix):
+    rcind = -1
+    rind = -1
+    minweight = -1
+    minweightnd = None
+    for row in nmatrix:
+      rcind += 1
+      if row[0] == None:
+        continue
+      w = sum(row[1:])
+      if minweight < 0:
+        rind = rcind
+        minweight = w
+        minweightnd = row[0]
+      elif w < minweight:
+        rind = rcind
+        minweight = w
+        minweightnd = row[0]
+    return (rind, minweightnd, minweight)
+  
+  def reorderNodesMinDependencies(self):
+    # create a matrix represtantion of all node
+    #
+    nmatrix = []
+    for n in range(0,len(self.nodes)):
+      nmatrix.append([None] + [0]*len(self.nodes))
+    
+    typeRefs = []
+    tn = self.getNodeByBrowseName("HasTypeDefinition")
+    if tn != None:
+      typeRefs.append(tn)
+      typeRefs = typeRefs + self.getSubTypesOf(currentNode=tn)
+    subTypeRefs = []
+    tn = self.getNodeByBrowseName("HasSubtype")
+    if tn  != None:
+      subTypeRefs.append(tn)
+      subTypeRefs = subTypeRefs + self.getSubTypesOf(currentNode=tn)
+    
+    log(self, "Building connectivity matrix for node order optimization.")
+    # Set column 0 to contain the node
+    for node in self.nodes:
+      nind = self.nodes.index(node)
+      nmatrix[nind][0] = node
+      
+    # Determine the dependencies of all nodes
+    for node in self.nodes:
+      nind = self.nodes.index(node)
+      #print "Examining node " + str(nind) + " " + str(node)
+      for ref in node.getReferences():
+        if isinstance(ref.target(), opcua_node_t):
+          tind = self.nodes.index(ref.target())
+          # Typedefinition of this node has precedence over this node
+          if ref.referenceType() in typeRefs and ref.isForward():
+            nmatrix[nind][tind+1] += 1
+          # isSubTypeOf/typeDefinition of this node has precedence over this node
+          elif ref.referenceType() in subTypeRefs and not ref.isForward():
+            nmatrix[nind][tind+1] += 1
+          # Else the target depends on us
+          elif ref.isForward():
+            nmatrix[tind][nind+1] += 1
+    
+    log(self, "Using Djikstra topological sorting to determine printing order.")
+    reorder = []
+    while len(reorder) < len(self.nodes):
+      (nind, node, w) = self.__reorder_getMinWeightNode__(nmatrix)
+      #print  str(100*float(len(reorder))/len(self.nodes)) + "% " + str(w) + " " + str(node) + " " + str(node.browseName())
+      reorder.append(node)
+      for ref in node.getReferences():
+        if isinstance(ref.target(), opcua_node_t):
+          tind = self.nodes.index(ref.target())
+          if ref.referenceType() in typeRefs and ref.isForward():
+            nmatrix[nind][tind+1] -= 1
+          elif ref.referenceType() in subTypeRefs and not ref.isForward():
+            nmatrix[nind][tind+1] -= 1
+          elif ref.isForward():
+            nmatrix[tind][nind+1] -= 1
+      nmatrix[nind][0] = None
+    self.nodes = reorder
+    log(self, "Nodes reordered.")
+    return
+  
   def printOpen62541Header(self, printedExternally=[], supressGenerationOfAttribute=[], outfilename=""):
     unPrintedNodes = []
     unPrintedRefs  = []
     code = []
     header = []
-
+    
+    # Reorder our nodes to produce a bare minimum of bootstrapping dependencies
+    log(self, "Reordering nodes for minimal dependencies during printing.")
+    self.reorderNodesMinDependencies()
+    
     # 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.
@@ -562,7 +647,8 @@ class opcua_namespace():
     refsUsed = []
     for n in self.nodes:
       for r in n.getReferences():
-        if not r.referenceType() in refsUsed:
+        # Only print valid refernces 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())
     log(self, str(len(refsUsed)) + " reference types are used in the namespace, which will now get bootstrapped.", LOG_LEVEL_DEBUG)
     for r in refsUsed:

+ 52 - 39
tools/pyUANamespace/ua_node_types.py

@@ -631,7 +631,7 @@ class opcua_node_t:
     """
     return []
   
-  def printOpen62541CCode_Subtype(self, bootstrapping = True):
+  def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
     """ printOpen62541CCode_Subtype
 
         Appends node type specific information to the nodes  UA_Server_addNode 
@@ -788,29 +788,32 @@ class opcua_node_referenceType_t(opcua_node_t):
         else:
           log(self,  "Unprocessable XML Element: " + x.tagName, LOG_LEVEL_INFO)
 
-  def printOpen62541CCode_Subtype(self, bootstrapping = True):
+  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
-      myType = None
+      myTypeRef = None
       for ref in self.getReferences():
         if ref.referenceType() in typeDefs:
-          myType = ref.target()
+          myTypeRef = ref
           break
-      if myType==None:
+      if myTypeRef==None:
         for ref in self.getReferences():
           if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
-            myType = ref.target()
+            myTypeRef = ref
             break
-      if myType==None:
+      if myTypeRef==None:
         log(self, str(self) + " failed to locate a type definition, assuming BaseDataType.", LOG_LEVEL_WARN)
         code.append("       // No valid typeDefinition found; assuming BaseDataType")
         code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE),")
       else:
-        code.append("       " + codegen.getCreateExpandedNodeIDMacro(myType) + ",")
+        code.append("       " + codegen.getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
+        if myTypeRef in unPrintedReferences:
+          unPrintedReferences.remove(myTypeRef)
+          
       code.append("       UA_LOCALIZEDTEXT(\"\",\"" + str(self.inverseName()) + "\"),");
       code.append("       // FIXME: Missing, isAbstract")
       code.append("       // FIXME: Missing, symmetric")
@@ -852,29 +855,31 @@ class opcua_node_object_t(opcua_node_t):
       if x.nodeType == x.ELEMENT_NODE:
         log(self,  "Unprocessable XML Element: " + x.tagName, LOG_LEVEL_INFO)
 
-  def printOpen62541CCode_Subtype(self, bootstrapping = True):
+  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
-      myType = None
+      myTypeRef = None
       for ref in self.getReferences():
         if ref.referenceType() in typeDefs:
-          myType = ref.target()
+          myTypeRef = ref
           break
-      if myType==None:
+      if myTypeRef==None:
         for ref in self.getReferences():
           if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
-            myType = ref.target()
+            myTypeRef = ref
             break
-      if myType==None:
+      if myTypeRef==None:
         log(self, str(self) + " failed to locate a type definition, assuming BaseObjectType.", LOG_LEVEL_WARN)
         code.append("       // No valid typeDefinition found; assuming BaseObjectType")
         code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),")
       else:
-        code.append("       " + codegen.getCreateExpandedNodeIDMacro(myType) + ",")
+        code.append("       " + codegen.getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
+        if myTypeRef in unPrintedReferences:
+          unPrintedReferences.remove(myTypeRef)
       
       #FIXME: No event notifier in UA_Server_addNode call!
       return code
@@ -1053,7 +1058,7 @@ class opcua_node_variable_t(opcua_node_t):
     code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_Variant_new();")
     return code
   
-  def printOpen62541CCode_Subtype(self, bootstrapping = True):
+  def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
     code = []
     codegen = open62541_MacroHelper()
     
@@ -1124,7 +1129,7 @@ class opcua_node_method_t(opcua_node_t):
       if x.nodeType == x.ELEMENT_NODE:
         log(self,  "Unprocessable XML Element: " + x.tagName, LOG_LEVEL_INFO)
 
-  def printOpen62541CCode_Subtype(self, bootstrapping = True):
+  def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
     code = []
     
     # Detect if this is bootstrapping or if we are attempting to use userspace...
@@ -1171,29 +1176,32 @@ class opcua_node_objectType_t(opcua_node_t):
       if x.nodeType == x.ELEMENT_NODE:
         log(self,  "Unprocessable XML Element: " + x.tagName, LOG_LEVEL_INFO)
 
-  def printOpen62541CCode_Subtype(self, bootstrapping = True):
+  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
-      myType = None
+      myTypeRef = None
       for ref in self.getReferences():
         if ref.referenceType() in typeDefs:
-          myType = ref.target()
+          myTypeRef = ref
           break
-      if myType==None:
+      if myTypeRef==None:
         for ref in self.getReferences():
           if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
-            myType = ref.target()
+            myTypeRef = ref
             break
-      if myType==None:
+      if myTypeRef==None:
         log(self, str(self) + " failed to locate a type definition, assuming BaseObjectType.", LOG_LEVEL_WARN)
         code.append("       // No valid typeDefinition found; assuming BaseObjectType")
         code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),")
       else:
-        code.append("       " + codegen.getCreateExpandedNodeIDMacro(myType) + ",")
+        code.append("       " + codegen.getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
+        if myTypeRef in unPrintedReferences:
+          code.append("       // removed " + str(myTypeRef))
+          unPrintedReferences.remove(myTypeRef)
       
       if (self.isAbstract()):
         code.append("       UA_TRUE,")
@@ -1303,7 +1311,7 @@ class opcua_node_variableType_t(opcua_node_t):
     code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_Variant_new();")
     return code
   
-  def printOpen62541CCode_Subtype(self, bootstrapping = True):
+  def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
     code = []
     codegen = open62541_MacroHelper()
     
@@ -1632,29 +1640,31 @@ class opcua_node_dataType_t(opcua_node_t):
           else:
             return opcua_value_t(None).getTypeByString(enc[0]).getNumericRepresentation()
 
-  def printOpen62541CCode_Subtype(self, bootstrapping = True):
+  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
-      myType = None
+      myTypeRef = None
       for ref in self.getReferences():
         if ref.referenceType() in typeDefs:
-          myType = ref.target()
+          myTypeRef = ref
           break
-      if myType==None:
+      if myTypeRef==None:
         for ref in self.getReferences():
           if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
-            myType = ref.target()
+            myTypeRef = ref
             break
-      if myType==None:
+      if myTypeRef==None:
         log(self, str(self) + " failed to locate a type definition, assuming BaseDataType.", LOG_LEVEL_WARN)
         code.append("       // No valid typeDefinition found; assuming BaseDataType")
         code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE),")
       else:
-        code.append("       " + codegen.getCreateExpandedNodeIDMacro(myType) + ",")
+        code.append("       " + codegen.getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
+        if myTypeRef in unPrintedReferences:
+          unPrintedReferences.remove(myTypeRef)
       
       if (self.isAbstract()):
         code.append("       UA_TRUE,")
@@ -1695,29 +1705,32 @@ class opcua_node_view_t(opcua_node_t):
       if x.nodeType == x.ELEMENT_NODE:
         log(self,  "Unprocessable XML Element: " + x.tagName, LOG_LEVEL_INFO)
 
-  def printOpen62541CCode_Subtype(self, bootstrapping = True):
+  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
-      myType = None
+      myTypeRef = None
       for ref in self.getReferences():
         if ref.referenceType() in typeDefs:
-          myType = ref.target()
+          myTypeRef = ref
           break
-      if myType==None:
+      if myTypeRef==None:
         for ref in self.getReferences():
           if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
-            myType = ref.target()
+            myTypeRef = ref
             break
-      if myType==None:
+      if myTypeRef==None:
         log(self, str(self) + " failed to locate a type definition, assuming BaseViewType.", LOG_LEVEL_WARN)
         code.append("       // No valid typeDefinition found; assuming BaseViewType")
         code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEViewTYPE),")
       else:
-        code.append("       " + codegen.getCreateExpandedNodeIDMacro(myType) + ",")
+        code.append("       " + codegen.getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
+        if myTypeRef in unPrintedReferences:
+          unPrintedReferences.remove(myTypeRef)
+          
       code.append("       // FIXME: Missing eventNotifier")
       code.append("       // FIXME: Missing containsNoLoops")
       return code