backend_open62541.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #!/usr/bin/env/python
  2. # -*- coding: utf-8 -*-
  3. ###
  4. ### Author: Chris Iatrou (ichrispa@core-vector.net)
  5. ### Version: rev 13
  6. ###
  7. ### This program was created for educational purposes and has been
  8. ### contributed to the open62541 project by the author. All licensing
  9. ### terms for this source is inherited by the terms and conditions
  10. ### specified for by the open62541 project (see the projects readme
  11. ### file for more information on the LGPL terms and restrictions).
  12. ###
  13. ### This program is not meant to be used in a production environment. The
  14. ### author is not liable for any complications arising due to the use of
  15. ### this program.
  16. ###
  17. from __future__ import print_function
  18. import string
  19. from collections import deque
  20. from os.path import basename
  21. import logging; logger = logging.getLogger(__name__)
  22. from constants import *
  23. from nodes import *
  24. from nodeset import *
  25. from backend_open62541_nodes import generateNodeCode, generateReferenceCode
  26. ##############
  27. # Sort Nodes #
  28. ##############
  29. # Select the references that shall be generated after this node in the ordering
  30. def selectPrintRefs(nodeset, L, node):
  31. printRefs = []
  32. for ref in node.references:
  33. if ref.hidden:
  34. continue
  35. targetnode = nodeset.nodes[ref.target]
  36. if not targetnode in L:
  37. continue
  38. printRefs.append(ref)
  39. for ref in node.inverseReferences:
  40. if ref.hidden:
  41. continue
  42. targetnode = nodeset.nodes[ref.target]
  43. if not targetnode in L:
  44. continue
  45. printRefs.append(ref)
  46. return printRefs
  47. def reorderNodesMinDependencies(nodeset):
  48. #Kahn's algorithm
  49. #https://algocoding.wordpress.com/2015/04/05/topological-sorting-python/
  50. relevant_types = getSubTypesOf(nodeset,
  51. nodeset.getNodeByBrowseName("HierarchicalReferences"))
  52. relevant_types = map(lambda x: x.id, relevant_types)
  53. # determine in-degree
  54. in_degree = { u.id : 0 for u in nodeset.nodes.values() }
  55. for u in nodeset.nodes.values(): # of each node
  56. for ref in u.references:
  57. if(ref.referenceType in relevant_types and ref.isForward):
  58. in_degree[ref.target] += 1
  59. # collect nodes with zero in-degree
  60. Q = deque()
  61. for id in in_degree:
  62. if in_degree[id] == 0:
  63. # print referencetypenodes first
  64. n = nodeset.nodes[id]
  65. if isinstance(n, ReferenceTypeNode):
  66. Q.append(nodeset.nodes[id])
  67. else:
  68. Q.appendleft(nodeset.nodes[id])
  69. L = [] # list for order of nodes
  70. while Q:
  71. u = Q.pop() # choose node of zero in-degree
  72. # decide which references to print now based on the ordering
  73. u.printRefs = selectPrintRefs(nodeset, L, u)
  74. L.append(u) # and 'remove' it from graph
  75. for ref in u.references:
  76. if(ref.referenceType in relevant_types and ref.isForward):
  77. in_degree[ref.target] -= 1
  78. if in_degree[ref.target] == 0:
  79. Q.append(nodeset.nodes[ref.target])
  80. if len(L) != len(nodeset.nodes.values()):
  81. raise Exception("Node graph is circular on the specified references")
  82. return L
  83. ###################
  84. # Generate C Code #
  85. ###################
  86. def generateOpen62541Code(nodeset, outfilename, supressGenerationOfAttribute = [], generate_ns0 = False):
  87. outfilebase = basename(outfilename)
  88. # Printing functions
  89. outfileh = open(outfilename + ".h", r"w+")
  90. outfilec = open(outfilename + ".c", r"w+")
  91. def writeh(line):
  92. print(unicode(line).encode('utf8'), end='\n', file=outfileh)
  93. def writec(line):
  94. print(unicode(line).encode('utf8'), end='\n', file=outfilec)
  95. # Print the preamble of the generated code
  96. writeh("""/* WARNING: This is a generated file.
  97. * Any manual changes will be overwritten. */
  98. #ifndef %s_H_
  99. #define %s_H_
  100. #ifdef UA_NO_AMALGAMATION
  101. #include "ua_types.h"
  102. #include "ua_job.h"
  103. #include "ua_server.h"
  104. #else
  105. #include "open62541.h"
  106. #define NULL ((void *)0)
  107. #endif
  108. extern void %s(UA_Server *server);
  109. #endif /* %s_H_ */""" % \
  110. (outfilebase.upper(), outfilebase.upper(), \
  111. outfilebase, outfilebase.upper()))
  112. writec("""/* WARNING: This is a generated file.
  113. * Any manual changes will be overwritten. */
  114. #include "%s.h"
  115. void %s(UA_Server *server) {""" % (outfilebase, outfilebase))
  116. parentrefs = getSubTypesOf(nodeset, nodeset.getNodeByBrowseName("HierarchicalReferences"))
  117. parentrefs = map(lambda x: x.id, parentrefs)
  118. # Generate namespaces (don't worry about duplicates)
  119. writec("/* Use namespace ids generated by the server */")
  120. for i,nsid in enumerate(nodeset.namespaces):
  121. nsid = nsid.replace("\"","\\\"")
  122. writec("UA_UInt16 ns" + str(i) + " = UA_Server_addNamespace(server, \"" + nsid + "\");")
  123. # Loop over the sorted nodes
  124. logger.info("Reordering nodes for minimal dependencies during printing")
  125. sorted_nodes = reorderNodesMinDependencies(nodeset)
  126. logger.info("Writing code for nodes and references")
  127. for node in sorted_nodes:
  128. # Print node
  129. if not node.hidden:
  130. writec("\n/* " + str(node.displayName) + " - " + str(node.id) + " */")
  131. writec(generateNodeCode(node, supressGenerationOfAttribute, generate_ns0, parentrefs))
  132. # Print inverse references leading to this node
  133. for ref in node.printRefs:
  134. writec(generateReferenceCode(ref))
  135. # Finalize the generated source
  136. writec("} // closing nodeset()")
  137. outfileh.close()
  138. outfilec.close()