open62541_MacroHelper.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # This Source Code Form is subject to the terms of the Mozilla Public
  4. # License, v. 2.0. If a copy of the MPL was not distributed with this
  5. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. ###
  7. ### Author: Chris Iatrou (ichrispa@core-vector.net)
  8. ### Version: rev 13
  9. ###
  10. ### This program was created for educational purposes and has been
  11. ### contributed to the open62541 project by the author. All licensing
  12. ### terms for this source is inherited by the terms and conditions
  13. ### specified for by the open62541 project (see the projects readme
  14. ### file for more information on the MPLv2 terms and restrictions).
  15. ###
  16. ### This program is not meant to be used in a production environment. The
  17. ### author is not liable for any complications arising due to the use of
  18. ### this program.
  19. ###
  20. import logging
  21. from ua_constants import *
  22. import string
  23. logger = logging.getLogger(__name__)
  24. __unique_item_id = 0
  25. defined_typealiases = []
  26. class open62541_MacroHelper():
  27. def __init__(self, supressGenerationOfAttribute=[]):
  28. self.supressGenerationOfAttribute = supressGenerationOfAttribute
  29. def getCreateExpandedNodeIDMacro(self, node):
  30. if node.id().i != None:
  31. return "UA_EXPANDEDNODEID_NUMERIC(%s, %s)" % (str(node.id().ns),str(node.id().i))
  32. elif node.id().s != None:
  33. return "UA_EXPANDEDNODEID_STRING(%s, %s)" % (str(node.id().ns), node.id().s)
  34. elif node.id().b != None:
  35. logger.debug("NodeID Generation macro for bytestrings has not been implemented.")
  36. return ""
  37. elif node.id().g != None:
  38. logger.debug("NodeID Generation macro for guids has not been implemented.")
  39. return ""
  40. else:
  41. return ""
  42. def substitutePunctuationCharacters(self, input):
  43. ''' substitutePunctuationCharacters
  44. Replace punctuation characters in input. Part of this class because it is used by
  45. ua_namespace on occasion.
  46. returns: C-printable string representation of input
  47. '''
  48. # No punctuation characters <>!$
  49. for illegal_char in list(string.punctuation):
  50. if illegal_char == '_': # underscore is allowed
  51. continue
  52. input = input.replace(illegal_char, "_") # map to underscore
  53. return input
  54. def getNodeIdDefineString(self, node):
  55. extrNs = node.browseName().split(":")
  56. symbolic_name = ""
  57. # strip all characters that would be illegal in C-Code
  58. if len(extrNs) > 1:
  59. nodename = extrNs[1]
  60. else:
  61. nodename = extrNs[0]
  62. symbolic_name = self.substitutePunctuationCharacters(nodename)
  63. if symbolic_name != nodename :
  64. logger.warn("Substituted characters in browsename for nodeid " + str(node.id().i) + " while generating C-Code ")
  65. if symbolic_name in defined_typealiases:
  66. logger.warn(self, "Typealias definition of " + str(node.id().i) + " is non unique!")
  67. extendedN = 1
  68. while (symbolic_name+"_"+str(extendedN) in defined_typealiases):
  69. logger.warn("Typealias definition of " + str(node.id().i) + " is non unique!")
  70. extendedN+=1
  71. symbolic_name = symbolic_name+"_"+str(extendedN)
  72. defined_typealiases.append(symbolic_name)
  73. code.append("#define UA_NS%sID_%s %s" % (str(node.id().ns), symbolic_name.upper(),str(node.id().i)))
  74. return code
  75. def getCreateNodeIDMacro(self, node):
  76. if node.id().i != None:
  77. return "UA_NODEID_NUMERIC(%s, %s)" % (str(node.id().ns),str(node.id().i))
  78. elif node.id().s != None:
  79. return "UA_NODEID_STRING(%s, %s)" % (str(node.id().ns), node.id().s)
  80. elif node.id().b != None:
  81. logger.debug("NodeID Generation macro for bytestrings has not been implemented.")
  82. return ""
  83. elif node.id().g != None:
  84. logger.debug("NodeID Generation macro for guids has not been implemented.")
  85. return ""
  86. else:
  87. return ""
  88. def getCreateStandaloneReference(self, sourcenode, reference):
  89. code = []
  90. if reference.isForward():
  91. code.append("UA_Server_addReference(server, %s, %s, %s, true);" % (self.getCreateNodeIDMacro(sourcenode), self.getCreateNodeIDMacro(reference.referenceType()), self.getCreateExpandedNodeIDMacro(reference.target())))
  92. else:
  93. code.append("UA_Server_addReference(server, %s, %s, %s, false);" % (self.getCreateNodeIDMacro(sourcenode), self.getCreateNodeIDMacro(reference.referenceType()), self.getCreateExpandedNodeIDMacro(reference.target())))
  94. return code
  95. def getCreateNodeNoBootstrap(self, node, parentNode, parentReference, unprintedNodes=[]):
  96. code = []
  97. code.append("// Node: %s, %s" % (str(node), str(node.browseName())))
  98. if node.nodeClass() == NODE_CLASS_OBJECT:
  99. nodetype = "Object"
  100. elif node.nodeClass() == NODE_CLASS_VARIABLE:
  101. nodetype = "Variable"
  102. elif node.nodeClass() == NODE_CLASS_METHOD:
  103. nodetype = "Method"
  104. elif node.nodeClass() == NODE_CLASS_OBJECTTYPE:
  105. nodetype = "ObjectType"
  106. elif node.nodeClass() == NODE_CLASS_REFERENCETYPE:
  107. nodetype = "ReferenceType"
  108. elif node.nodeClass() == NODE_CLASS_VARIABLETYPE:
  109. nodetype = "VariableType"
  110. elif node.nodeClass() == NODE_CLASS_DATATYPE:
  111. nodetype = "DataType"
  112. elif node.nodeClass() == NODE_CLASS_VIEW:
  113. nodetype = "View"
  114. else:
  115. code.append("/* undefined nodeclass */")
  116. return code;
  117. # If this is a method, construct in/outargs for addMethod
  118. #inputArguments.arrayDimensionsSize = 0;
  119. #inputArguments.arrayDimensions = NULL;
  120. #inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
  121. # Node ordering should have made sure that arguments, if they exist, have not been printed yet
  122. if node.nodeClass() == NODE_CLASS_METHOD:
  123. inArgVal = []
  124. outArgVal = []
  125. code.append("UA_Argument *inputArguments = NULL;")
  126. code.append("UA_Argument *outputArguments = NULL;")
  127. for r in node.getReferences():
  128. if r.isForward():
  129. if r.target() != None and r.target().nodeClass() == NODE_CLASS_VARIABLE and r.target().browseName() == 'InputArguments':
  130. while r.target() in unprintedNodes:
  131. unprintedNodes.remove(r.target())
  132. if r.target().value() != None:
  133. inArgVal = r.target().value().value
  134. elif r.target() != None and r.target().nodeClass() == NODE_CLASS_VARIABLE and r.target().browseName() == 'OutputArguments':
  135. while r.target() in unprintedNodes:
  136. unprintedNodes.remove(r.target())
  137. if r.target().value() != None:
  138. outArgVal = r.target().value().value
  139. if len(inArgVal)>0:
  140. code.append("")
  141. code.append("inputArguments = (UA_Argument *) UA_malloc(sizeof(UA_Argument) * " + str(len(inArgVal)) + ");")
  142. code.append("int inputArgumentCnt;")
  143. code.append("for (inputArgumentCnt=0; inputArgumentCnt<" + str(len(inArgVal)) + "; ++inputArgumentCnt) UA_Argument_init(&inputArguments[inputArgumentCnt]); ")
  144. argumentCnt = 0
  145. for inArg in inArgVal:
  146. if inArg.getValueFieldByAlias("Description") != None:
  147. code.append("inputArguments[" + str(argumentCnt) + "].description = UA_LOCALIZEDTEXT(\"" + str(inArg.getValueFieldByAlias("Description")[0]) + "\",\"" + str(inArg.getValueFieldByAlias("Description")[1]) + "\");")
  148. if inArg.getValueFieldByAlias("Name") != None:
  149. code.append("inputArguments[" + str(argumentCnt) + "].name = UA_STRING(\"" + str(inArg.getValueFieldByAlias("Name")) + "\");")
  150. if inArg.getValueFieldByAlias("ValueRank") != None:
  151. code.append("inputArguments[" + str(argumentCnt) + "].valueRank = " + str(inArg.getValueFieldByAlias("ValueRank")) + ";")
  152. if inArg.getValueFieldByAlias("DataType") != None:
  153. code.append("inputArguments[" + str(argumentCnt) + "].dataType = " + str(self.getCreateNodeIDMacro(inArg.getValueFieldByAlias("DataType"))) + ";")
  154. #if inArg.getValueFieldByAlias("ArrayDimensions") != None:
  155. # code.append("inputArguments[" + str(argumentCnt) + "].arrayDimensions = " + str(inArg.getValueFieldByAlias("ArrayDimensions")) + ";")
  156. argumentCnt += 1
  157. if len(outArgVal)>0:
  158. code.append("")
  159. code.append("outputArguments = (UA_Argument *) UA_malloc(sizeof(UA_Argument) * " + str(len(outArgVal)) + ");")
  160. code.append("int outputArgumentCnt;")
  161. code.append("for (outputArgumentCnt=0; outputArgumentCnt<" + str(len(outArgVal)) + "; ++outputArgumentCnt) UA_Argument_init(&outputArguments[outputArgumentCnt]); ")
  162. argumentCnt = 0
  163. for outArg in outArgVal:
  164. if outArg.getValueFieldByAlias("Description") != None:
  165. code.append("outputArguments[" + str(argumentCnt) + "].description = UA_LOCALIZEDTEXT(\"" + str(outArg.getValueFieldByAlias("Description")[0]) + "\",\"" + str(outArg.getValueFieldByAlias("Description")[1]) + "\");")
  166. if outArg.getValueFieldByAlias("Name") != None:
  167. code.append("outputArguments[" + str(argumentCnt) + "].name = UA_STRING(\"" + str(outArg.getValueFieldByAlias("Name")) + "\");")
  168. if outArg.getValueFieldByAlias("ValueRank") != None:
  169. code.append("outputArguments[" + str(argumentCnt) + "].valueRank = " + str(outArg.getValueFieldByAlias("ValueRank")) + ";")
  170. if outArg.getValueFieldByAlias("DataType") != None:
  171. code.append("outputArguments[" + str(argumentCnt) + "].dataType = " + str(self.getCreateNodeIDMacro(outArg.getValueFieldByAlias("DataType"))) + ";")
  172. #if outArg.getValueFieldByAlias("ArrayDimensions") != None:
  173. # code.append("outputArguments[" + str(argumentCnt) + "].arrayDimensions = " + str(outArg.getValueFieldByAlias("ArrayDimensions")) + ";")
  174. argumentCnt += 1
  175. # print the attributes struct
  176. code.append("UA_%sAttributes attr = UA_%sAttributes_default;" % (nodetype, nodetype))
  177. code.append("attr.displayName = UA_LOCALIZEDTEXT(\"\", \"" + str(node.displayName()) + "\");")
  178. code.append("attr.description = UA_LOCALIZEDTEXT(\"\", \"" + str(node.description()) + "\");")
  179. if nodetype == "Variable":
  180. code.append("attr.accessLevel = %s;" % str(node.accessLevel()))
  181. code.append("attr.userAccessLevel = %s;" % str(node.userAccessLevel()))
  182. if nodetype in ["Variable", "VariableType"]:
  183. code.append("attr.valueRank = %s;" % str(node.valueRank()))
  184. if nodetype in ["Variable", "VariableType"]:
  185. code.extend(node.printOpen62541CCode_SubtypeEarly(bootstrapping = False))
  186. elif nodetype == "Method":
  187. if node.executable():
  188. code.append("attr.executable = true;")
  189. if node.userExecutable():
  190. code.append("attr.userExecutable = true;")
  191. code.append("UA_NodeId nodeId = %s;" % str(self.getCreateNodeIDMacro(node)))
  192. if nodetype in ["Object", "Variable", "VariableType"]:
  193. typeDefinition = None
  194. for r in node.getReferences():
  195. if r.isForward() and r.referenceType().id().ns == 0 and r.referenceType().id().i == 40:
  196. typeDefinition = r.target()
  197. if typeDefinition == None:
  198. # FIXME: We might want to resort to BaseXYTTypes here?
  199. code.append("UA_NodeId typeDefinition = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);")
  200. else:
  201. code.append("UA_NodeId typeDefinition = " + str(self.getCreateNodeIDMacro(typeDefinition)) + ";")
  202. code.append("UA_NodeId parentNodeId = %s;" % str(self.getCreateNodeIDMacro(parentNode)))
  203. code.append("UA_NodeId parentReferenceNodeId = %s;" % str(self.getCreateNodeIDMacro(parentReference.referenceType())))
  204. extrNs = node.browseName().split(":")
  205. if len(extrNs) > 1:
  206. code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(%s, \"%s\");" % (str(extrNs[0]), extrNs[1]))
  207. else:
  208. code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(0, \"%s\");" % str(node.browseName()))
  209. # In case of a MethodNode: Add in|outArg struct generation here. Mandates that namespace reordering was done using
  210. # Djikstra (check that arguments have not been printed). (@ichrispa)
  211. code.append("UA_Server_add%sNode(server, nodeId, parentNodeId, parentReferenceNodeId, nodeName" % nodetype)
  212. if nodetype in ["Object", "Variable", "VariableType"]:
  213. code.append(" , typeDefinition")
  214. if nodetype != "Method":
  215. code.append(" , attr, NULL, NULL);")
  216. else:
  217. code.append(" , attr, (UA_MethodCallback) NULL, NULL, %s, inputArguments, %s, outputArguments, NULL);" % (str(len(inArgVal)), str(len(outArgVal))))
  218. #Adding a Node with typeDefinition = UA_NODEID_NULL will create a HasTypeDefinition reference to BaseDataType - remove it since
  219. #a real Reference will be add in a later step (a single HasTypeDefinition reference is assumed here)
  220. #The current API does not let us specify IDs of Object's subelements.
  221. if nodetype is "Object":
  222. 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");
  223. if nodetype is "Variable":
  224. 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");
  225. return code