open62541_MacroHelper.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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 logger import *
  18. from ua_constants import *
  19. import string
  20. __unique_item_id = 0
  21. defined_typealiases = []
  22. def substitutePunctuationCharacters(input):
  23. '''
  24. replace punctuation characters in input
  25. '''
  26. # No punctuation characters <>!$
  27. illegal_chars = list(string.punctuation)
  28. # underscore is allowed
  29. illegal_chars.remove('_')
  30. illegal = "".join(illegal_chars)
  31. substitution = ""
  32. # Map all punctuation characters to underscore
  33. for illegal_char in illegal_chars:
  34. substitution = substitution + '_'
  35. return input.translate(string.maketrans(illegal, substitution), illegal)
  36. class open62541_MacroHelper():
  37. def __init__(self, supressGenerationOfAttribute=[]):
  38. self.supressGenerationOfAttribute = supressGenerationOfAttribute
  39. def getCreateExpandedNodeIDMacro(self, node):
  40. if node.id().i != None:
  41. return "UA_EXPANDEDNODEID_NUMERIC(" + str(node.id().ns) + ", " + str(node.id().i) + ")"
  42. elif node.id().s != None:
  43. return "UA_EXPANDEDNODEID_STRING(" + str(node.id().ns) + ", " + node.id().s + ")"
  44. elif node.id().b != None:
  45. log(self, "NodeID Generation macro for bytestrings has not been implemented.")
  46. return ""
  47. elif node.id().g != None:
  48. log(self, "NodeID Generation macro for guids has not been implemented.")
  49. return ""
  50. else:
  51. return ""
  52. def getNodeIdDefineString(self, node):
  53. code = []
  54. extrNs = node.browseName().split(":")
  55. symbolic_name = ""
  56. # strip all characters that would be illegal in C-Code
  57. if len(extrNs) > 1:
  58. nodename = extrNs[1]
  59. else:
  60. nodename = extrNs[0]
  61. symbolic_name = substitutePunctuationCharacters(nodename)
  62. if symbolic_name != nodename :
  63. log(self, "Subsituted characters in browsename for nodeid " + str(node.id().i) + " while generating C-Code ", LOG_LEVEL_WARN)
  64. if symbolic_name in defined_typealiases:
  65. log(self, "Typealias definition of " + str(node.id().i) + " is non unique!", LOG_LEVEL_WARN)
  66. extendedN = 1
  67. while (symbolic_name+"_"+str(extendedN) in defined_typealiases):
  68. log(self, "Typealias definition of " + str(node.id().i) + " is non unique!", LOG_LEVEL_WARN)
  69. extendedN+=1
  70. symbolic_name = symbolic_name+"_"+str(extendedN)
  71. defined_typealiases.append(symbolic_name)
  72. code.append("#define UA_NS" + str(node.id().ns) + "ID_" + symbolic_name.upper() + " " + str(node.id().i))
  73. return code
  74. def getCreateNodeIDMacro(self, node):
  75. if node.id().i != None:
  76. return "UA_NODEID_NUMERIC(" + str(node.id().ns) + ", " + str(node.id().i) + ")"
  77. elif node.id().s != None:
  78. return "UA_NODEID_STRING(" + str(node.id().ns) + ", " + node.id().s + ")"
  79. elif node.id().b != None:
  80. log(self, "NodeID Generation macro for bytestrings has not been implemented.")
  81. return ""
  82. elif node.id().g != None:
  83. log(self, "NodeID Generation macro for guids has not been implemented.")
  84. return ""
  85. else:
  86. return ""
  87. def getCreateStandaloneReference(self, sourcenode, reference):
  88. code = []
  89. if reference.isForward():
  90. code.append("UA_Server_addReference(server, " + self.getCreateNodeIDMacro(sourcenode) + ", " + self.getCreateNodeIDMacro(reference.referenceType()) + ", " + self.getCreateExpandedNodeIDMacro(reference.target()) + ", true);")
  91. else:
  92. code.append("UA_Server_addReference(server, " + self.getCreateNodeIDMacro(sourcenode) + ", " + self.getCreateNodeIDMacro(reference.referenceType()) + ", " + self.getCreateExpandedNodeIDMacro(reference.target()) + ", false);")
  93. return code
  94. def getCreateNodeNoBootstrap(self, node, parentNode, parentReference, unprintedNodes):
  95. code = []
  96. code.append("// Node: " + str(node) + ", " + str(node.browseName()))
  97. if node.nodeClass() == NODE_CLASS_OBJECT:
  98. nodetype = "Object"
  99. elif node.nodeClass() == NODE_CLASS_VARIABLE:
  100. nodetype = "Variable"
  101. elif node.nodeClass() == NODE_CLASS_METHOD:
  102. nodetype = "Method"
  103. elif node.nodeClass() == NODE_CLASS_OBJECTTYPE:
  104. nodetype = "ObjectType"
  105. elif node.nodeClass() == NODE_CLASS_REFERENCETYPE:
  106. nodetype = "ReferenceType"
  107. elif node.nodeClass() == NODE_CLASS_VARIABLETYPE:
  108. nodetype = "VariableType"
  109. elif node.nodeClass() == NODE_CLASS_DATATYPE:
  110. nodetype = "DataType"
  111. elif node.nodeClass() == NODE_CLASS_VIEW:
  112. nodetype = "View"
  113. else:
  114. code.append("/* undefined nodeclass */")
  115. return code;
  116. # If this is a method, construct in/outargs for addMethod
  117. #inputArguments.arrayDimensionsSize = 0;
  118. #inputArguments.arrayDimensions = NULL;
  119. #inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
  120. # Node ordering should have made sure that arguments, if they exist, have not been printed yet
  121. if node.nodeClass() == NODE_CLASS_METHOD:
  122. inArgVal = []
  123. outArgVal = []
  124. code.append("UA_Argument *inputArguments = NULL;")
  125. code.append("UA_Argument *outputArguments = NULL;")
  126. for r in node.getReferences():
  127. if r.target() != None and r.target().nodeClass() == NODE_CLASS_VARIABLE and r.target().browseName() == 'InputArguments':
  128. while r.target() in unprintedNodes:
  129. unprintedNodes.remove(r.target())
  130. if r.target().value() != None:
  131. inArgVal = r.target().value().value
  132. elif r.target() != None and r.target().nodeClass() == NODE_CLASS_VARIABLE and r.target().browseName() == 'OutputArguments':
  133. while r.target() in unprintedNodes:
  134. unprintedNodes.remove(r.target())
  135. if r.target().value() != None:
  136. outArgVal = r.target().value().value
  137. if len(inArgVal)>0:
  138. code.append("")
  139. code.append("inputArguments = (UA_Argument *) malloc(sizeof(UA_Argument) * " + str(len(inArgVal)) + ");")
  140. code.append("int inputArgumentCnt;")
  141. code.append("for (inputArgumentCnt=0; inputArgumentCnt<" + str(len(inArgVal)) + "; inputArgumentCnt++) UA_Argument_init(&inputArguments[inputArgumentCnt]); ")
  142. argumentCnt = 0
  143. for inArg in inArgVal:
  144. if inArg.getValueFieldByAlias("Description") != None:
  145. code.append("inputArguments[" + str(argumentCnt) + "].description = UA_LOCALIZEDTEXT(\"" + str(inArg.getValueFieldByAlias("Description")[0]) + "\",\"" + str(inArg.getValueFieldByAlias("Description")[1]) + "\");")
  146. if inArg.getValueFieldByAlias("Name") != None:
  147. code.append("inputArguments[" + str(argumentCnt) + "].name = UA_STRING(\"" + str(inArg.getValueFieldByAlias("Name")) + "\");")
  148. if inArg.getValueFieldByAlias("ValueRank") != None:
  149. code.append("inputArguments[" + str(argumentCnt) + "].valueRank = " + str(inArg.getValueFieldByAlias("ValueRank")) + ";")
  150. if inArg.getValueFieldByAlias("DataType") != None:
  151. code.append("inputArguments[" + str(argumentCnt) + "].dataType = " + str(self.getCreateNodeIDMacro(inArg.getValueFieldByAlias("DataType"))) + ";")
  152. #if inArg.getValueFieldByAlias("ArrayDimensions") != None:
  153. # code.append("inputArguments[" + str(argumentCnt) + "].arrayDimensions = " + str(inArg.getValueFieldByAlias("ArrayDimensions")) + ";")
  154. argumentCnt += 1
  155. if len(outArgVal)>0:
  156. code.append("")
  157. code.append("outputArguments = (UA_Argument *) malloc(sizeof(UA_Argument) * " + str(len(outArgVal)) + ");")
  158. code.append("int outputArgumentCnt;")
  159. code.append("for (outputArgumentCnt=0; outputArgumentCnt<" + str(len(outArgVal)) + "; outputArgumentCnt++) UA_Argument_init(&outputArguments[outputArgumentCnt]); ")
  160. argumentCnt = 0
  161. for outArg in outArgVal:
  162. if outArg.getValueFieldByAlias("Description") != None:
  163. code.append("outputArguments[" + str(argumentCnt) + "].description = UA_LOCALIZEDTEXT(\"" + str(outArg.getValueFieldByAlias("Description")[0]) + "\",\"" + str(outArg.getValueFieldByAlias("Description")[1]) + "\");")
  164. if outArg.getValueFieldByAlias("Name") != None:
  165. code.append("outputArguments[" + str(argumentCnt) + "].name = UA_STRING(\"" + str(outArg.getValueFieldByAlias("Name")) + "\");")
  166. if outArg.getValueFieldByAlias("ValueRank") != None:
  167. code.append("outputArguments[" + str(argumentCnt) + "].valueRank = " + str(outArg.getValueFieldByAlias("ValueRank")) + ";")
  168. if outArg.getValueFieldByAlias("DataType") != None:
  169. code.append("outputArguments[" + str(argumentCnt) + "].dataType = " + str(self.getCreateNodeIDMacro(outArg.getValueFieldByAlias("DataType"))) + ";")
  170. #if outArg.getValueFieldByAlias("ArrayDimensions") != None:
  171. # code.append("outputArguments[" + str(argumentCnt) + "].arrayDimensions = " + str(outArg.getValueFieldByAlias("ArrayDimensions")) + ";")
  172. argumentCnt += 1
  173. # print the attributes struct
  174. code.append("UA_%sAttributes attr;" % nodetype)
  175. code.append("UA_%sAttributes_init(&attr);" % nodetype);
  176. code.append("attr.displayName = UA_LOCALIZEDTEXT(\"\", \"" + str(node.displayName()) + "\");")
  177. code.append("attr.description = UA_LOCALIZEDTEXT(\"\", \"" + str(node.description()) + "\");")
  178. if nodetype in ["Variable", "VariableType"]:
  179. code = code + node.printOpen62541CCode_SubtypeEarly(bootstrapping = False)
  180. elif nodetype == "Method":
  181. if node.executable():
  182. code.append("attr.executable = true;")
  183. if node.userExecutable():
  184. code.append("attr.userExecutable = true;")
  185. code.append("UA_NodeId nodeId = " + str(self.getCreateNodeIDMacro(node)) + ";")
  186. if nodetype in ["Object", "Variable"]:
  187. code.append("UA_NodeId typeDefinition = UA_NODEID_NULL;") # todo instantiation of object and variable types
  188. code.append("UA_NodeId parentNodeId = " + str(self.getCreateNodeIDMacro(parentNode)) + ";")
  189. code.append("UA_NodeId parentReferenceNodeId = " + str(self.getCreateNodeIDMacro(parentReference.referenceType())) + ";")
  190. extrNs = node.browseName().split(":")
  191. if len(extrNs) > 1:
  192. code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(" + str(extrNs[0]) + ", \"" + extrNs[1] + "\");")
  193. else:
  194. code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(0, \"" + str(node.browseName()) + "\");")
  195. # In case of a MethodNode: Add in|outArg struct generation here. Mandates that namespace reordering was done using
  196. # Djikstra (check that arguments have not been printed). (@ichrispa)
  197. code.append("UA_Server_add%sNode(server, nodeId, parentNodeId, parentReferenceNodeId, nodeName" % nodetype)
  198. if nodetype in ["Object", "Variable"]:
  199. code.append(" , typeDefinition")
  200. if nodetype != "Method":
  201. code.append(" , attr, NULL, NULL);")
  202. else:
  203. code.append(" , attr, (UA_MethodCallback) NULL, NULL, " + str(len(inArgVal)) + ", inputArguments, " + str(len(outArgVal)) + ", outputArguments, NULL);")
  204. return code
  205. def getCreateNodeBootstrap(self, node):
  206. nodetype = ""
  207. code = []
  208. code.append("// Node: " + str(node) + ", " + str(node.browseName()))
  209. if node.nodeClass() == NODE_CLASS_OBJECT:
  210. nodetype = "Object"
  211. elif node.nodeClass() == NODE_CLASS_VARIABLE:
  212. nodetype = "Variable"
  213. elif node.nodeClass() == NODE_CLASS_METHOD:
  214. nodetype = "Method"
  215. elif node.nodeClass() == NODE_CLASS_OBJECTTYPE:
  216. nodetype = "ObjectType"
  217. elif node.nodeClass() == NODE_CLASS_REFERENCETYPE:
  218. nodetype = "ReferenceType"
  219. elif node.nodeClass() == NODE_CLASS_VARIABLETYPE:
  220. nodetype = "VariableType"
  221. elif node.nodeClass() == NODE_CLASS_DATATYPE:
  222. nodetype = "DataType"
  223. elif node.nodeClass() == NODE_CLASS_VIEW:
  224. nodetype = "View"
  225. else:
  226. code.append("/* undefined nodeclass */")
  227. return;
  228. code.append("UA_" + nodetype + "Node *" + node.getCodePrintableID() + " = UA_NodeStore_new" + nodetype + "Node();")
  229. if not "browsename" in self.supressGenerationOfAttribute:
  230. extrNs = node.browseName().split(":")
  231. if len(extrNs) > 1:
  232. code.append(node.getCodePrintableID() + "->browseName = UA_QUALIFIEDNAME_ALLOC(" + str(extrNs[0]) + ", \"" + extrNs[1] + "\");")
  233. else:
  234. code.append(node.getCodePrintableID() + "->browseName = UA_QUALIFIEDNAME_ALLOC(0, \"" + node.browseName() + "\");")
  235. if not "displayname" in self.supressGenerationOfAttribute:
  236. code.append(node.getCodePrintableID() + "->displayName = UA_LOCALIZEDTEXT_ALLOC(\"en_US\", \"" + node.displayName() + "\");")
  237. if not "description" in self.supressGenerationOfAttribute:
  238. code.append(node.getCodePrintableID() + "->description = UA_LOCALIZEDTEXT_ALLOC(\"en_US\", \"" + node.description() + "\");")
  239. if not "writemask" in self.supressGenerationOfAttribute:
  240. if node.__node_writeMask__ != 0:
  241. code.append(node.getCodePrintableID() + "->writeMask = (UA_Int32) " + str(node.__node_writeMask__) + ";")
  242. if not "userwritemask" in self.supressGenerationOfAttribute:
  243. if node.__node_userWriteMask__ != 0:
  244. code.append(node.getCodePrintableID() + "->userWriteMask = (UA_Int32) " + str(node.__node_userWriteMask__) + ";")
  245. if not "nodeid" in self.supressGenerationOfAttribute:
  246. if node.id().ns != 0:
  247. code.append(node.getCodePrintableID() + "->nodeId.namespaceIndex = " + str(node.id().ns) + ";")
  248. if node.id().i != None:
  249. code.append(node.getCodePrintableID() + "->nodeId.identifier.numeric = " + str(node.id().i) + ";")
  250. elif node.id().b != None:
  251. code.append(node.getCodePrintableID() + "->nodeId.identifierType = UA_NODEIDTYPE_BYTESTRING;")
  252. log(self, "ByteString IDs for nodes has not been implemented yet.", LOG_LEVEL_ERROR)
  253. return []
  254. elif node.id().g != None:
  255. #<jpfr> the string is sth like { .length = 111, .data = <ptr> }
  256. #<jpfr> there you _may_ alloc the <ptr> on the heap
  257. #<jpfr> for the guid, just set it to {.data1 = 111, .data2 = 2222, ....
  258. code.append(node.getCodePrintableID() + "->nodeId.identifierType = UA_NODEIDTYPE_GUID;")
  259. log(self, "GUIDs for nodes has not been implemented yet.", LOG_LEVEL_ERROR)
  260. return []
  261. elif node.id().s != None:
  262. code.append(node.getCodePrintableID() + "->nodeId.identifierType = UA_NODEIDTYPE_STRING;")
  263. code.append(node.getCodePrintableID() + "->nodeId.identifier.numeric = UA_STRING_ALLOC(\"" + str(node.id().i) + "\");")
  264. else:
  265. log(self, "Node ID is not numeric, bytestring, guid or string. I do not know how to create c code for that...", LOG_LEVEL_ERROR)
  266. return []
  267. return code