open62541_backend_nodes.py 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  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 ua_node_types import *
  18. ####################
  19. # Helper Functions #
  20. ####################
  21. def getCreateNodeIDMacro(node):
  22. if node.id().i != None:
  23. return "UA_NODEID_NUMERIC(%s, %s)" % (node.id().ns, node.id().i)
  24. elif node.id().s != None:
  25. return "UA_NODEID_STRING(%s, %s)" % (node.id().ns, node.id().s)
  26. elif node.id().b != None:
  27. logger.debug("NodeID Generation macro for bytestrings has not been implemented.")
  28. return ""
  29. elif node.id().g != None:
  30. logger.debug("NodeID Generation macro for guids has not been implemented.")
  31. return ""
  32. else:
  33. return ""
  34. def getCreateExpandedNodeIDMacro(node):
  35. if node.id().i != None:
  36. return "UA_EXPANDEDNODEID_NUMERIC(%s, %s)" % (str(node.id().ns),str(node.id().i))
  37. elif node.id().s != None:
  38. return "UA_EXPANDEDNODEID_STRING(%s, %s)" % (str(node.id().ns), node.id().s)
  39. elif node.id().b != None:
  40. logger.debug("NodeID Generation macro for bytestrings has not been implemented.")
  41. return ""
  42. elif node.id().g != None:
  43. logger.debug("NodeID Generation macro for guids has not been implemented.")
  44. return ""
  45. else:
  46. return ""
  47. def getCreateStandaloneReference(sourcenode, reference):
  48. code = []
  49. if reference.isForward():
  50. code.append("UA_Server_addReference(server, %s, %s, %s, true);" % \
  51. (getCreateNodeIDMacro(sourcenode), getCreateNodeIDMacro(reference.referenceType()), \
  52. getCreateExpandedNodeIDMacro(reference.target())))
  53. else:
  54. code.append("UA_Server_addReference(server, %s, %s, %s, false);" % \
  55. (getCreateNodeIDMacro(sourcenode), getCreateNodeIDMacro(reference.referenceType()), \
  56. getCreateExpandedNodeIDMacro(reference.target())))
  57. return code
  58. #################
  59. # Subtype Early #
  60. #################
  61. def Node_printOpen62541CCode_SubtypeEarly(node, bootstrapping = True):
  62. """ Initiate code segments for the nodes instantiotion that preceed
  63. the actual UA_Server_addNode or UA_NodeStore_insert calls.
  64. """
  65. code = []
  66. if isinstance(node, opcua_node_variable_t) or isinstance(node, opcua_node_variableType_t):
  67. # If we have an encodable value, try to encode that
  68. if node.dataType() != None and isinstance(node.dataType().target(), opcua_node_dataType_t):
  69. # Delegate the encoding of the datavalue to the helper if we have
  70. # determined a valid encoding
  71. if node.dataType().target().isEncodable():
  72. if node.value() != None:
  73. code.extend(node.value().printOpen62541CCode(bootstrapping))
  74. return code
  75. if(bootstrapping):
  76. code.append("UA_Variant *" + node.getCodePrintableID() + "_variant = UA_alloca(sizeof(UA_Variant));")
  77. code.append("UA_Variant_init(" + node.getCodePrintableID() + "_variant);")
  78. return code
  79. ###########
  80. # Subtype #
  81. ###########
  82. def ReferenceTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
  83. code = []
  84. # Detect if this is bootstrapping or if we are attempting to use userspace...
  85. if bootstrapping == False:
  86. typeDefs = node.getNamespace().getSubTypesOf() # defaults to TypeDefinition
  87. myTypeRef = None
  88. for ref in node.getReferences():
  89. if ref.referenceType() in typeDefs:
  90. myTypeRef = ref
  91. break
  92. if myTypeRef==None:
  93. for ref in node.getReferences():
  94. if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
  95. myTypeRef = ref
  96. break
  97. if myTypeRef==None:
  98. logger.warn(str(self) + " failed to locate a type definition, assuming BaseDataType.")
  99. code.append(" // No valid typeDefinition found; assuming BaseDataType")
  100. code.append(" UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE),")
  101. else:
  102. code.append(" " + getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
  103. while myTypeRef in unPrintedReferences:
  104. unPrintedReferences.remove(myTypeRef)
  105. code.append(" UA_LOCALIZEDTEXT(\"\",\"" + str(node.inverseName()) + "\"),");
  106. code.append(" // FIXME: Missing, isAbstract")
  107. code.append(" // FIXME: Missing, symmetric")
  108. return code
  109. if node.isAbstract():
  110. code.append(node.getCodePrintableID() + "->isAbstract = true;")
  111. if node.symmetric():
  112. code.append(node.getCodePrintableID() + "->symmetric = true;")
  113. if node.__reference_inverseName__ != "":
  114. code.append(node.getCodePrintableID() + "->inverseName = UA_LOCALIZEDTEXT_ALLOC(\"en_US\", \"" + \
  115. node.__reference_inverseName__ + "\");")
  116. return code;
  117. def ObjectNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
  118. code = []
  119. # Detect if this is bootstrapping or if we are attempting to use userspace...
  120. if bootstrapping == False:
  121. typeDefs = self.getNamespace().getSubTypesOf() # defaults to TypeDefinition
  122. myTypeRef = None
  123. for ref in self.getReferences():
  124. if ref.referenceType() in typeDefs:
  125. myTypeRef = ref
  126. break
  127. if myTypeRef==None:
  128. for ref in self.getReferences():
  129. if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
  130. myTypeRef = ref
  131. break
  132. if myTypeRef==None:
  133. logger.warn(str(self) + " failed to locate a type definition, assuming BaseObjectType.")
  134. code.append(" // No valid typeDefinition found; assuming BaseObjectType")
  135. code.append(" UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),")
  136. else:
  137. code.append(" " + getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
  138. while myTypeRef in unPrintedReferences:
  139. unPrintedReferences.remove(myTypeRef)
  140. #FIXME: No event notifier in UA_Server_addNode call!
  141. return code
  142. # We are being bootstrapped! Add the raw attributes to the node.
  143. code.append(node.getCodePrintableID() + "->eventNotifier = (UA_Byte) " + str(node.eventNotifier()) + ";")
  144. return code
  145. def ObjectTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
  146. code = []
  147. # Detect if this is bootstrapping or if we are attempting to use userspace...
  148. if bootstrapping == False:
  149. typeDefs = node.getNamespace().getSubTypesOf() # defaults to TypeDefinition
  150. myTypeRef = None
  151. for ref in node.getReferences():
  152. if ref.referenceType() in typeDefs:
  153. myTypeRef = ref
  154. break
  155. if myTypeRef==None:
  156. for ref in node.getReferences():
  157. if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
  158. myTypeRef = ref
  159. break
  160. if myTypeRef==None:
  161. logger.warn(str(node) + " failed to locate a type definition, assuming BaseObjectType.")
  162. code.append(" // No valid typeDefinition found; assuming BaseObjectType")
  163. code.append(" UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),")
  164. else:
  165. code.append(" " + getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
  166. while myTypeRef in unPrintedReferences:
  167. code.append(" // removed " + str(myTypeRef))
  168. unPrintedReferences.remove(myTypeRef)
  169. if (node.isAbstract()):
  170. code.append(" true,")
  171. else:
  172. code.append(" false,")
  173. # Fallback mode for bootstrapping
  174. if (node.isAbstract()):
  175. code.append(node.getCodePrintableID() + "->isAbstract = true;")
  176. return code
  177. def VariableNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
  178. code = []
  179. # Detect if this is bootstrapping or if we are attempting to use userspace...
  180. if bootstrapping == False:
  181. code.append(" " + node.getCodePrintableID() + "_variant, ")
  182. code.append(" // FIXME: missing minimumSamplingInterval")
  183. code.append(" // FIXME: missing accessLevel")
  184. code.append(" // FIXME: missing userAccessLevel")
  185. code.append(" // FIXME: missing valueRank")
  186. return code
  187. if node.historizing():
  188. code.append(node.getCodePrintableID() + "->historizing = true;")
  189. code.append(node.getCodePrintableID() + "->minimumSamplingInterval = (UA_Double) " + \
  190. str(node.minimumSamplingInterval()) + ";")
  191. code.append(node.getCodePrintableID() + "->userAccessLevel = (UA_Int32) " + str(node.userAccessLevel()) + ";")
  192. code.append(node.getCodePrintableID() + "->accessLevel = (UA_Int32) " + str(node.accessLevel()) + ";")
  193. code.append(node.getCodePrintableID() + "->valueRank = (UA_Int32) " + str(node.valueRank()) + ";")
  194. # The variant is guaranteed to exist by SubtypeEarly()
  195. code.append(node.getCodePrintableID() + "->value.variant.value = *" + node.getCodePrintableID() + "_variant;")
  196. code.append(node.getCodePrintableID() + "->valueSource = UA_VALUESOURCE_VARIANT;")
  197. return code
  198. def VariableTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
  199. code = []
  200. if bootstrapping == False:
  201. code.append(" " + node.getCodePrintableID() + "_variant, ")
  202. code.append(" " + str(node.valueRank()) + ",")
  203. if node.isAbstract():
  204. code.append(" true,")
  205. else:
  206. code.append(" false,")
  207. return code
  208. if (node.isAbstract()):
  209. code.append(node.getCodePrintableID() + "->isAbstract = true;")
  210. else:
  211. code.append(node.getCodePrintableID() + "->isAbstract = false;")
  212. # The variant is guaranteed to exist by SubtypeEarly()
  213. code.append(node.getCodePrintableID() + "->value.variant.value = *" + node.getCodePrintableID() + "_variant;")
  214. code.append(node.getCodePrintableID() + "->valueSource = UA_VALUESOURCE_VARIANT;")
  215. return code
  216. def MethodNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
  217. code = []
  218. # Detect if this is bootstrapping or if we are attempting to use userspace...
  219. if bootstrapping == False:
  220. code.append(" // Note: in/outputArguments are added by attaching the variable nodes,")
  221. code.append(" // not by including the in the addMethodNode() call.")
  222. code.append(" NULL,")
  223. code.append(" NULL,")
  224. code.append(" 0, NULL,")
  225. code.append(" 0, NULL,")
  226. code.append(" // FIXME: Missing executable")
  227. code.append(" // FIXME: Missing userExecutable")
  228. return code
  229. # UA_False is default for booleans on _init()
  230. if node.executable():
  231. code.append(node.getCodePrintableID() + "->executable = true;")
  232. if node.userExecutable():
  233. code.append(node.getCodePrintableID() + "->userExecutable = true;")
  234. return code
  235. def DataTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
  236. code = []
  237. # Detect if this is bootstrapping or if we are attempting to use userspace...
  238. if bootstrapping == False:
  239. typeDefs = node.getNamespace().getSubTypesOf() # defaults to TypeDefinition
  240. myTypeRef = None
  241. for ref in node.getReferences():
  242. if ref.referenceType() in typeDefs:
  243. myTypeRef = ref
  244. break
  245. if myTypeRef==None:
  246. for ref in node.getReferences():
  247. if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
  248. myTypeRef = ref
  249. break
  250. if myTypeRef==None:
  251. logger.warn(str(node) + " failed to locate a type definition, assuming BaseDataType.")
  252. code.append(" // No valid typeDefinition found; assuming BaseDataType")
  253. code.append(" UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE),")
  254. else:
  255. code.append(" " + getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
  256. while myTypeRef in unPrintedReferences:
  257. unPrintedReferences.remove(myTypeRef)
  258. if (node.isAbstract()):
  259. code.append(" true,")
  260. else:
  261. code.append(" false,")
  262. return code
  263. if (node.isAbstract()):
  264. code.append(node.getCodePrintableID() + "->isAbstract = true;")
  265. else:
  266. code.append(node.getCodePrintableID() + "->isAbstract = false;")
  267. return code
  268. def ViewNode_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
  269. code = []
  270. # Detect if this is bootstrapping or if we are attempting to use userspace...
  271. if bootstrapping == False:
  272. typeDefs = node.getNamespace().getSubTypesOf() # defaults to TypeDefinition
  273. myTypeRef = None
  274. for ref in node.getReferences():
  275. if ref.referenceType() in typeDefs:
  276. myTypeRef = ref
  277. break
  278. if myTypeRef==None:
  279. for ref in node.getReferences():
  280. if ref.referenceType().browseName() == "HasSubtype" and ref.isForward() == False:
  281. myTypeRef = ref
  282. break
  283. if myTypeRef==None:
  284. logger.warn(str(node) + " failed to locate a type definition, assuming BaseViewType.")
  285. code.append(" // No valid typeDefinition found; assuming BaseViewType")
  286. code.append(" UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEViewTYPE),")
  287. else:
  288. code.append(" " + getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
  289. while myTypeRef in unPrintedReferences:
  290. unPrintedReferences.remove(myTypeRef)
  291. code.append(" // FIXME: Missing eventNotifier")
  292. code.append(" // FIXME: Missing containsNoLoops")
  293. return code
  294. if node.containsNoLoops():
  295. code.append(node.getCodePrintableID() + "->containsNoLoops = true;")
  296. else:
  297. code.append(node.getCodePrintableID() + "->containsNoLoops = false;")
  298. code.append(node.getCodePrintableID() + "->eventNotifier = (UA_Byte) " + str(node.eventNotifier()) + ";")
  299. return code
  300. def Node_printOpen62541CCode_Subtype(node, unPrintedReferences=[], bootstrapping = True):
  301. """ Appends node type specific information to the nodes UA_Server_addNode
  302. or UA_NodeStore_insert calls.
  303. """
  304. if isinstance(node, opcua_node_referenceType_t):
  305. return ReferenceTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
  306. elif isinstance(node, opcua_node_object_t):
  307. return ObjectNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
  308. elif isinstance(node, opcua_node_objectType_t):
  309. return ObjectTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
  310. elif isinstance(node, opcua_node_variable_t):
  311. return VariableNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
  312. elif isinstance(node, opcua_node_variableType_t):
  313. return VariableTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
  314. elif isinstance(node, opcua_node_method_t):
  315. return MethodNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
  316. elif isinstance(node, opcua_node_dataType_t):
  317. return DataTypeNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
  318. elif isinstance(node, opcua_node_view_t):
  319. return ViewNode_printOpen62541CCode_Subtype(node, unPrintedReferences, bootstrapping)
  320. raise Exception('Unknown node type', node)
  321. ###############
  322. # Entry Point #
  323. ###############
  324. def getCreateNodeNoBootstrap(node, parentNode, parentReference, unprintedNodes=[]):
  325. code = []
  326. code.append("// Node: %s, %s" % (str(node), str(node.browseName())))
  327. if node.nodeClass() == NODE_CLASS_OBJECT:
  328. nodetype = "Object"
  329. elif node.nodeClass() == NODE_CLASS_VARIABLE:
  330. nodetype = "Variable"
  331. elif node.nodeClass() == NODE_CLASS_METHOD:
  332. nodetype = "Method"
  333. elif node.nodeClass() == NODE_CLASS_OBJECTTYPE:
  334. nodetype = "ObjectType"
  335. elif node.nodeClass() == NODE_CLASS_REFERENCETYPE:
  336. nodetype = "ReferenceType"
  337. elif node.nodeClass() == NODE_CLASS_VARIABLETYPE:
  338. nodetype = "VariableType"
  339. elif node.nodeClass() == NODE_CLASS_DATATYPE:
  340. nodetype = "DataType"
  341. elif node.nodeClass() == NODE_CLASS_VIEW:
  342. nodetype = "View"
  343. else:
  344. code.append("/* undefined nodeclass */")
  345. return code;
  346. # If this is a method, construct in/outargs for addMethod
  347. #inputArguments.arrayDimensionsSize = 0;
  348. #inputArguments.arrayDimensions = NULL;
  349. #inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
  350. # Node ordering should have made sure that arguments, if they exist, have not been printed yet
  351. if node.nodeClass() == NODE_CLASS_METHOD:
  352. inArgVal = []
  353. outArgVal = []
  354. code.append("UA_Argument *inputArguments = NULL;")
  355. code.append("UA_Argument *outputArguments = NULL;")
  356. for r in node.getReferences():
  357. if r.isForward():
  358. if r.target() != None and r.target().nodeClass() == NODE_CLASS_VARIABLE and \
  359. r.target().browseName() == 'InputArguments':
  360. while r.target() in unprintedNodes:
  361. unprintedNodes.remove(r.target())
  362. if r.target().value() != None:
  363. inArgVal = r.target().value().value
  364. elif r.target() != None and r.target().nodeClass() == NODE_CLASS_VARIABLE and \
  365. r.target().browseName() == 'OutputArguments':
  366. while r.target() in unprintedNodes:
  367. unprintedNodes.remove(r.target())
  368. if r.target().value() != None:
  369. outArgVal = r.target().value().value
  370. if len(inArgVal)>0:
  371. code.append("")
  372. code.append("inputArguments = (UA_Argument *) malloc(sizeof(UA_Argument) * " + \
  373. str(len(inArgVal)) + ");")
  374. code.append("int inputArgumentCnt;")
  375. code.append("for (inputArgumentCnt=0; inputArgumentCnt<" + str(len(inArgVal)) + \
  376. "; inputArgumentCnt++) UA_Argument_init(&inputArguments[inputArgumentCnt]); ")
  377. argumentCnt = 0
  378. for inArg in inArgVal:
  379. if inArg.getValueFieldByAlias("Description") != None:
  380. code.append("inputArguments[" + str(argumentCnt) + "].description = UA_LOCALIZEDTEXT(\"" + \
  381. str(inArg.getValueFieldByAlias("Description")[0]) + "\",\"" + \
  382. str(inArg.getValueFieldByAlias("Description")[1]) + "\");")
  383. if inArg.getValueFieldByAlias("Name") != None:
  384. code.append("inputArguments[" + str(argumentCnt) + "].name = UA_STRING(\"" + \
  385. str(inArg.getValueFieldByAlias("Name")) + "\");")
  386. if inArg.getValueFieldByAlias("ValueRank") != None:
  387. code.append("inputArguments[" + str(argumentCnt) + "].valueRank = " + \
  388. str(inArg.getValueFieldByAlias("ValueRank")) + ";")
  389. if inArg.getValueFieldByAlias("DataType") != None:
  390. code.append("inputArguments[" + str(argumentCnt) + "].dataType = " + \
  391. str(getCreateNodeIDMacro(inArg.getValueFieldByAlias("DataType"))) + ";")
  392. #if inArg.getValueFieldByAlias("ArrayDimensions") != None:
  393. # code.append("inputArguments[" + str(argumentCnt) + "].arrayDimensions = " + \
  394. # str(inArg.getValueFieldByAlias("ArrayDimensions")) + ";")
  395. argumentCnt += 1
  396. if len(outArgVal)>0:
  397. code.append("")
  398. code.append("outputArguments = (UA_Argument *) malloc(sizeof(UA_Argument) * " + \
  399. str(len(outArgVal)) + ");")
  400. code.append("int outputArgumentCnt;")
  401. code.append("for (outputArgumentCnt=0; outputArgumentCnt<" + str(len(outArgVal)) + \
  402. "; outputArgumentCnt++) UA_Argument_init(&outputArguments[outputArgumentCnt]); ")
  403. argumentCnt = 0
  404. for outArg in outArgVal:
  405. if outArg.getValueFieldByAlias("Description") != None:
  406. code.append("outputArguments[" + str(argumentCnt) + "].description = UA_LOCALIZEDTEXT(\"" + \
  407. str(outArg.getValueFieldByAlias("Description")[0]) + "\",\"" + \
  408. str(outArg.getValueFieldByAlias("Description")[1]) + "\");")
  409. if outArg.getValueFieldByAlias("Name") != None:
  410. code.append("outputArguments[" + str(argumentCnt) + "].name = UA_STRING(\"" + \
  411. str(outArg.getValueFieldByAlias("Name")) + "\");")
  412. if outArg.getValueFieldByAlias("ValueRank") != None:
  413. code.append("outputArguments[" + str(argumentCnt) + "].valueRank = " + \
  414. str(outArg.getValueFieldByAlias("ValueRank")) + ";")
  415. if outArg.getValueFieldByAlias("DataType") != None:
  416. code.append("outputArguments[" + str(argumentCnt) + "].dataType = " + \
  417. str(getCreateNodeIDMacro(outArg.getValueFieldByAlias("DataType"))) + ";")
  418. #if outArg.getValueFieldByAlias("ArrayDimensions") != None:
  419. # code.append("outputArguments[" + str(argumentCnt) + "].arrayDimensions = " + \
  420. # str(outArg.getValueFieldByAlias("ArrayDimensions")) + ";")
  421. argumentCnt += 1
  422. # print the attributes struct
  423. code.append("UA_%sAttributes attr;" % nodetype)
  424. code.append("UA_%sAttributes_init(&attr);" % nodetype);
  425. code.append("attr.displayName = UA_LOCALIZEDTEXT(\"\", \"%s\");" % node.displayName().replace("\"", "\\\""))
  426. code.append("attr.description = UA_LOCALIZEDTEXT(\"\", \"%s\");" % node.description().replace("\"", "\\\""))
  427. if nodetype == "Variable":
  428. code.append("attr.accessLevel = %s;" % str(node.accessLevel()))
  429. code.append("attr.userAccessLevel = %s;" % str(node.userAccessLevel()))
  430. if nodetype in ["Variable", "VariableType"]:
  431. code.extend(Node_printOpen62541CCode_SubtypeEarly(node, bootstrapping = False))
  432. elif nodetype == "Method":
  433. if node.executable():
  434. code.append("attr.executable = true;")
  435. if node.userExecutable():
  436. code.append("attr.userExecutable = true;")
  437. code.append("UA_NodeId nodeId = %s;" % str(getCreateNodeIDMacro(node)))
  438. if nodetype in ["Object", "Variable"]:
  439. #due to the current API we cannot set types here since the API will
  440. #generate nodes with random IDs
  441. code.append("UA_NodeId typeDefinition = UA_NODEID_NULL;")
  442. code.append("UA_NodeId parentNodeId = %s;" % str(getCreateNodeIDMacro(parentNode)))
  443. code.append("UA_NodeId parentReferenceNodeId = %s;" % \
  444. str(getCreateNodeIDMacro(parentReference.referenceType())))
  445. extrNs = node.browseName().split(":")
  446. if len(extrNs) > 1:
  447. code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(%s, \"%s\");" % (str(extrNs[0]), extrNs[1]))
  448. else:
  449. code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(0, \"%s\");" % str(node.browseName()))
  450. # In case of a MethodNode: Add in|outArg struct generation here. Mandates
  451. # that namespace reordering was done using Djikstra (check that arguments
  452. # have not been printed). (@ichrispa)
  453. code.append("UA_Server_add%sNode(server, nodeId, parentNodeId, parentReferenceNodeId, nodeName" % nodetype)
  454. if nodetype in ["Object", "Variable"]:
  455. code.append(" , typeDefinition")
  456. if nodetype != "Method":
  457. code.append(" , attr, NULL, NULL);")
  458. else:
  459. code.append(" , attr, (UA_MethodCallback) NULL, NULL, %s, inputArguments, %s, outputArguments, NULL);" % (str(len(inArgVal)), str(len(outArgVal))))
  460. #Adding a Node with typeDefinition = UA_NODEID_NULL will create a
  461. #HasTypeDefinition reference to BaseDataType - remove it since a real
  462. #Reference will be add in a later step (a single HasTypeDefinition reference
  463. #is assumed here) The current API does not let us specify IDs of Object's
  464. #subelements.
  465. if nodetype is "Object":
  466. 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");
  467. if nodetype is "Variable":
  468. 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");
  469. return code
  470. ##################
  471. # Node Bootstrap #
  472. ##################
  473. def getCreateNodeBootstrap(node, supressGenerationOfAttribute=[]):
  474. nodetype = ""
  475. code = []
  476. code.append("// Node: " + str(node) + ", " + str(node.browseName()))
  477. if node.nodeClass() == NODE_CLASS_OBJECT:
  478. nodetype = "Object"
  479. elif node.nodeClass() == NODE_CLASS_VARIABLE:
  480. nodetype = "Variable"
  481. elif node.nodeClass() == NODE_CLASS_METHOD:
  482. nodetype = "Method"
  483. elif node.nodeClass() == NODE_CLASS_OBJECTTYPE:
  484. nodetype = "ObjectType"
  485. elif node.nodeClass() == NODE_CLASS_REFERENCETYPE:
  486. nodetype = "ReferenceType"
  487. elif node.nodeClass() == NODE_CLASS_VARIABLETYPE:
  488. nodetype = "VariableType"
  489. elif node.nodeClass() == NODE_CLASS_DATATYPE:
  490. nodetype = "DataType"
  491. elif node.nodeClass() == NODE_CLASS_VIEW:
  492. nodetype = "View"
  493. else:
  494. raise Exception('Undefined NodeClass')
  495. code.append("UA_" + nodetype + "Node *" + node.getCodePrintableID() + \
  496. " = UA_NodeStore_new" + nodetype + "Node();")
  497. if not "browsename" in supressGenerationOfAttribute:
  498. extrNs = node.browseName().split(":")
  499. if len(extrNs) > 1:
  500. code.append(node.getCodePrintableID() + "->browseName = UA_QUALIFIEDNAME_ALLOC(" + \
  501. str(extrNs[0]) + ", \"" + extrNs[1] + "\");")
  502. else:
  503. code.append(node.getCodePrintableID() + "->browseName = UA_QUALIFIEDNAME_ALLOC(0, \"" + \
  504. node.browseName() + "\");")
  505. if not "displayname" in supressGenerationOfAttribute:
  506. code.append(node.getCodePrintableID() + "->displayName = UA_LOCALIZEDTEXT_ALLOC(\"en_US\", \"" + \
  507. node.displayName() + "\");")
  508. if not "description" in supressGenerationOfAttribute:
  509. code.append(node.getCodePrintableID() + "->description = UA_LOCALIZEDTEXT_ALLOC(\"en_US\", \"" + \
  510. node.description() + "\");")
  511. if not "writemask" in supressGenerationOfAttribute:
  512. if node.__node_writeMask__ != 0:
  513. code.append(node.getCodePrintableID() + "->writeMask = (UA_Int32) " + \
  514. str(node.__node_writeMask__) + ";")
  515. if not "userwritemask" in supressGenerationOfAttribute:
  516. if node.__node_userWriteMask__ != 0:
  517. code.append(node.getCodePrintableID() + "->userWriteMask = (UA_Int32) " + \
  518. str(node.__node_userWriteMask__) + ";")
  519. if not "nodeid" in supressGenerationOfAttribute:
  520. if node.id().ns != 0:
  521. code.append(node.getCodePrintableID() + "->nodeId.namespaceIndex = " + str(node.id().ns) + ";")
  522. if node.id().i != None:
  523. code.append(node.getCodePrintableID() + "->nodeId.identifier.numeric = " + str(node.id().i) + ";")
  524. elif node.id().b != None:
  525. code.append(node.getCodePrintableID() + "->nodeId.identifierType = UA_NODEIDTYPE_BYTESTRING;")
  526. logger.error("ByteString IDs for nodes has not been implemented yet.")
  527. return []
  528. elif node.id().g != None:
  529. #<jpfr> the string is sth like { .length = 111, .data = <ptr> }
  530. #<jpfr> there you _may_ alloc the <ptr> on the heap
  531. #<jpfr> for the guid, just set it to {.data1 = 111, .data2 = 2222, ....
  532. code.append(node.getCodePrintableID() + "->nodeId.identifierType = UA_NODEIDTYPE_GUID;")
  533. logger.error("GUIDs for nodes has not been implemented yet.")
  534. return []
  535. elif node.id().s != None:
  536. code.append(node.getCodePrintableID() + "->nodeId.identifierType = UA_NODEIDTYPE_STRING;")
  537. code.append(node.getCodePrintableID() + "->nodeId.identifier.numeric = UA_STRING_ALLOC(\"" + str(node.id().i) + "\");")
  538. else:
  539. logger.error("Node ID is not numeric, bytestring, guid or string. I do not know how to create c code for that...")
  540. return []
  541. return code
  542. def Node_printOpen62541CCode(node, unPrintedNodes=[], unPrintedReferences=[],
  543. supressGenerationOfAttribute=[]):
  544. """ Returns a list of strings containing the C-code necessary to intialize
  545. this node for the open62541 OPC-UA Stack.
  546. Note that this function will fail if the nodeid is non-numeric, as
  547. there is no UA_EXPANDEDNNODEID_[STRING|GUID|BYTESTRING] macro.
  548. """
  549. code = []
  550. code.append("")
  551. code.append("do {")
  552. # Just to be sure...
  553. if not (node in unPrintedNodes):
  554. logger.warn(str(node) + " attempted to reprint already printed node " + str(node)+ ".")
  555. return []
  556. # If we are being passed a parent node by the namespace, use that for registering ourselves in the namespace
  557. # Note: getFirstParentNode will return [parentNode, referenceToChild]
  558. (parentNode, parentRef) = node.getFirstParentNode()
  559. if not (parentNode in unPrintedNodes) and (parentNode != None) and (parentRef.referenceType() != None):
  560. code.append("// Referencing node found and declared as parent: " + str(parentNode .id()) + "/" +
  561. str(parentNode .__node_browseName__) + " using " + str(parentRef.referenceType().id()) +
  562. "/" + str(parentRef.referenceType().__node_browseName__))
  563. code.extend(getCreateNodeNoBootstrap(node, parentNode, parentRef, unPrintedNodes))
  564. # Parent to child reference is added by the server, do not reprint that reference
  565. if parentRef in unPrintedReferences:
  566. unPrintedReferences.remove(parentRef)
  567. # the UA_Server_addNode function will use addReference which creates a
  568. # bidirectional reference; remove any inverse references to our parent to
  569. # avoid duplicate refs
  570. for ref in node.getReferences():
  571. if ref.target() == parentNode and ref.referenceType() == parentRef.referenceType() and \
  572. ref.isForward() == False:
  573. while ref in unPrintedReferences:
  574. unPrintedReferences.remove(ref)
  575. # Otherwise use the "Bootstrapping" method and we will get registered with other nodes later.
  576. else:
  577. code.extend(Node_printOpen62541CCode_SubtypeEarly(node, bootstrapping = True))
  578. code.extend(getCreateNodeBootstrap(node, supressGenerationOfAttribute))
  579. code.extend(Node_printOpen62541CCode_Subtype(node, unPrintedReferences = unPrintedReferences,
  580. bootstrapping = True))
  581. code.append("// Parent node does not exist yet. This node will be bootstrapped and linked later.")
  582. code.append("UA_RCU_LOCK();")
  583. code.append("UA_NodeStore_insert(server->nodestore, (UA_Node*) " + node.getCodePrintableID() + ");")
  584. code.append("UA_RCU_UNLOCK();")
  585. # Try to print all references to nodes that already exist
  586. # Note: we know the reference types exist, because the namespace class made sure they were
  587. # the first ones being printed
  588. tmprefs = []
  589. for r in node.getReferences():
  590. #logger.debug("Checking if reference from " + str(r.parent()) + "can be created...")
  591. if not (r.target() in unPrintedNodes):
  592. if r in unPrintedReferences:
  593. if (len(tmprefs) == 0):
  594. code.append("// This node has the following references that can be created:")
  595. code.extend(getCreateStandaloneReference(node, r))
  596. tmprefs.append(r)
  597. # Remove printed refs from list
  598. for r in tmprefs:
  599. unPrintedReferences.remove(r)
  600. # Again, but this time check if other nodes deffered their node creation
  601. # because this node did not exist...
  602. tmprefs = []
  603. for r in unPrintedReferences:
  604. #logger.debug("Checking if another reference " + str(r.target()) + "can be created...")
  605. if (r.target() == node) and not (r.parent() in unPrintedNodes):
  606. if not isinstance(r.parent(), opcua_node_t):
  607. logger.debug("Reference has no parent!")
  608. elif not isinstance(r.parent().id(), opcua_node_id_t):
  609. logger.debug("Parents nodeid is not a nodeID!")
  610. else:
  611. if (len(tmprefs) == 0):
  612. code.append("// Creating this node has resolved the following open references:")
  613. code.extend(getCreateStandaloneReference(r.parent(), r))
  614. tmprefs.append(r)
  615. # Remove printed refs from list
  616. for r in tmprefs:
  617. unPrintedReferences.remove(r)
  618. # Again, just to be sure...
  619. if node in unPrintedNodes:
  620. # This is necessery to make printing work at all!
  621. unPrintedNodes.remove(node)
  622. code.append("} while(0);")
  623. return code
  624. def Node_printOpen62541CCode_HL_API(node, reference, supressGenerationOfAttribute=[]):
  625. """ Returns a list of strings containing the C-code necessary to intialize
  626. this node for the open62541 OPC-UA Stack using only the high level API
  627. Note that this function will fail if the nodeid is non-numeric, as
  628. there is no UA_EXPANDEDNNODEID_[STRING|GUID|BYTESTRING] macro.
  629. """
  630. code = []
  631. code.append("")
  632. code.append("do {")
  633. # If we are being passed a parent node by the namespace, use that for registering ourselves in the namespace
  634. # Note: getFirstParentNode will return [parentNode, referenceToChild]
  635. parentNode = reference.target()
  636. parentRefType = reference.referenceType()
  637. code.append("// Referencing node found and declared as parent: " + str(parentNode .id()) + "/" +
  638. str(parentNode .__node_browseName__) + " using " + str(parentRefType.id()) +
  639. "/" + str(parentRefType.__node_browseName__))
  640. code.extend(getCreateNodeNoBootstrap(node, parentNode, reference))
  641. code.append("} while(0);")
  642. return code