backend_open62541_nodes.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  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 nodes import *
  18. from backend_open62541_datatypes import *
  19. import re
  20. import datetime
  21. import logging
  22. logger = logging.getLogger(__name__)
  23. #################
  24. # Generate Code #
  25. #################
  26. def generateNodeIdPrintable(node):
  27. CodePrintable = "NODE_"
  28. if isinstance(node.id, NodeId):
  29. CodePrintable = node.__class__.__name__ + "_" + str(node.id)
  30. else:
  31. CodePrintable = node.__class__.__name__ + "_unknown_nid"
  32. return re.sub('[^0-9a-z_]+', '_', CodePrintable.lower())
  33. def generateNodeValueInstanceName(node, parent, recursionDepth, arrayIndex):
  34. return generateNodeIdPrintable(parent) + "_" + str(node.alias) + "_" + str(arrayIndex) + "_" + str(recursionDepth)
  35. def generateReferenceCode(reference):
  36. if reference.isForward:
  37. return "retVal |= UA_Server_addReference(server, %s, %s, %s, true);" % \
  38. (generateNodeIdCode(reference.source),
  39. generateNodeIdCode(reference.referenceType),
  40. generateExpandedNodeIdCode(reference.target))
  41. else:
  42. return "retVal |= UA_Server_addReference(server, %s, %s, %s, false);" % \
  43. (generateNodeIdCode(reference.source),
  44. generateNodeIdCode(reference.referenceType),
  45. generateExpandedNodeIdCode(reference.target))
  46. def generateReferenceTypeNodeCode(node):
  47. code = []
  48. code.append("UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;")
  49. if node.isAbstract:
  50. code.append("attr.isAbstract = true;")
  51. if node.symmetric:
  52. code.append("attr.symmetric = true;")
  53. if node.inverseName != "":
  54. code.append("attr.inverseName = UA_LOCALIZEDTEXT(\"\", \"%s\");" % \
  55. node.inverseName)
  56. return code
  57. def generateObjectNodeCode(node):
  58. code = []
  59. code.append("UA_ObjectAttributes attr = UA_ObjectAttributes_default;")
  60. if node.eventNotifier:
  61. code.append("attr.eventNotifier = true;")
  62. return code
  63. def generateVariableNodeCode(node, nodeset, encode_binary_size):
  64. code = []
  65. codeCleanup = []
  66. codeGlobal = []
  67. code.append("UA_VariableAttributes attr = UA_VariableAttributes_default;")
  68. if node.historizing:
  69. code.append("attr.historizing = true;")
  70. code.append("attr.minimumSamplingInterval = %f;" % node.minimumSamplingInterval)
  71. code.append("attr.userAccessLevel = %d;" % node.userAccessLevel)
  72. code.append("attr.accessLevel = %d;" % node.accessLevel)
  73. # in order to be compatible with mostly OPC UA client
  74. # force valueRank = -1 for scalar VariableNode
  75. if node.valueRank == -2:
  76. node.valueRank = -1
  77. code.append("attr.valueRank = %d;" % node.valueRank)
  78. if node.valueRank > 0:
  79. code.append("attr.arrayDimensionsSize = %d;" % node.valueRank)
  80. code.append("attr.arrayDimensions = (UA_UInt32 *)UA_Array_new({}, &UA_TYPES[UA_TYPES_UINT32]);".format(node.valueRank))
  81. code.append("if (!attr.arrayDimensions) return UA_STATUSCODE_BADOUTOFMEMORY;")
  82. codeCleanup.append("UA_Array_delete(attr.arrayDimensions, {}, &UA_TYPES[UA_TYPES_UINT32]);".format(node.valueRank))
  83. if len(node.arrayDimensions) == node.valueRank:
  84. for idx, v in enumerate(node.arrayDimensions):
  85. code.append("attr.arrayDimensions[{}] = {};".format(idx, int(unicode(v))))
  86. else:
  87. for dim in range(0, node.valueRank):
  88. code.append("attr.arrayDimensions[{}] = 0;".format(dim))
  89. if node.dataType is not None:
  90. if isinstance(node.dataType, NodeId) and node.dataType.ns == 0 and node.dataType.i == 0:
  91. #BaseDataType
  92. dataTypeNode = nodeset.nodes[NodeId("i=24")]
  93. dataTypeNodeOpaque = nodeset.nodes[NodeId("i=24")]
  94. else:
  95. dataTypeNodeOpaque = nodeset.getDataTypeNode(node.dataType)
  96. dataTypeNode = nodeset.getBaseDataType(nodeset.getDataTypeNode(node.dataType))
  97. if dataTypeNode is not None:
  98. code.append("attr.dataType = %s;" % generateNodeIdCode(dataTypeNodeOpaque.id))
  99. if dataTypeNode.isEncodable():
  100. if node.value is not None:
  101. [code1, codeCleanup1, codeGlobal1] = generateValueCode(node.value, nodeset.nodes[node.id], nodeset, encode_binary_size=encode_binary_size)
  102. code += code1
  103. codeCleanup += codeCleanup1
  104. codeGlobal += codeGlobal1
  105. # #1978 Variant arrayDimensions are only required to properly decode multidimensional arrays
  106. # (valueRank >= 2) from data stored as one-dimensional array of arrayLength elements.
  107. # One-dimensional arrays are already completely defined by arraylength attribute so setting
  108. # also arrayDimensions, even if not explicitly forbidden, can confuse clients
  109. if node.valueRank > 1 and len(node.arrayDimensions) == node.valueRank:
  110. code.append("attr.value.arrayDimensionsSize = attr.arrayDimensionsSize;")
  111. code.append("attr.value.arrayDimensions = attr.arrayDimensions;")
  112. else:
  113. code += generateValueCodeDummy(dataTypeNode, nodeset.nodes[node.id], nodeset)
  114. return [code, codeCleanup, codeGlobal]
  115. def generateVariableTypeNodeCode(node, nodeset, encode_binary_size):
  116. code = []
  117. codeCleanup = []
  118. codeGlobal = []
  119. code.append("UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;")
  120. if node.historizing:
  121. code.append("attr.historizing = true;")
  122. if node.isAbstract:
  123. code.append("attr.isAbstract = true;")
  124. code.append("attr.valueRank = (UA_Int32)%s;" % str(node.valueRank))
  125. if node.dataType is not None:
  126. if isinstance(node.dataType, NodeId) and node.dataType.ns == 0 and node.dataType.i == 0:
  127. #BaseDataType
  128. dataTypeNode = nodeset.nodes[NodeId("i=24")]
  129. else:
  130. dataTypeNode = nodeset.getBaseDataType(nodeset.getDataTypeNode(node.dataType))
  131. if dataTypeNode is not None:
  132. code.append("attr.dataType = %s;" % generateNodeIdCode(dataTypeNode.id))
  133. if dataTypeNode.isEncodable():
  134. if node.value is not None:
  135. [code1, codeCleanup1, codeGlobal1] = generateValueCode(node.value, nodeset.nodes[node.id], nodeset, encode_binary_size)
  136. code += code1
  137. codeCleanup += codeCleanup1
  138. codeGlobal += codeGlobal1
  139. else:
  140. code += generateValueCodeDummy(dataTypeNode, nodeset.nodes[node.id], nodeset)
  141. return [code, codeCleanup, codeGlobal]
  142. def generateExtensionObjectSubtypeCode(node, parent, nodeset, global_var_code, recursionDepth=0, arrayIndex=0, encode_binary_size=32000):
  143. code = [""]
  144. codeCleanup = [""]
  145. logger.debug("Building extensionObject for " + str(parent.id))
  146. logger.debug("Value " + str(node.value))
  147. logger.debug("Encoding " + str(node.encodingRule))
  148. instanceName = generateNodeValueInstanceName(node, parent, recursionDepth, arrayIndex)
  149. # If there are any ExtensionObjects instide this ExtensionObject, we need to
  150. # generate one-time-structs for them too before we can proceed;
  151. for subv in node.value:
  152. if isinstance(subv, list):
  153. logger.error("ExtensionObject contains an ExtensionObject, which is currently not encodable!")
  154. code.append("struct {")
  155. for field in node.encodingRule:
  156. ptrSym = ""
  157. # If this is an Array, this is pointer to its contents with a AliasOfFieldSize entry
  158. if field[2] != None and field[2] != 0 :
  159. code.append(" UA_Int32 " + str(field[0]) + "Size;")
  160. ptrSym = "*"
  161. if len(field[1]) == 1:
  162. code.append(" UA_" + str(field[1][0]) + " " + ptrSym + str(field[0]) + ";")
  163. else:
  164. code.append(" UA_ExtensionObject " + " " + ptrSym + str(field[0]) + ";")
  165. code.append("} " + instanceName + "_struct;")
  166. # Allocate some memory
  167. code.append("UA_ExtensionObject *" + instanceName + " = UA_ExtensionObject_new();")
  168. code.append("if (!" + instanceName + ") return UA_STATUSCODE_BADOUTOFMEMORY;")
  169. codeCleanup.append("UA_ExtensionObject_delete(" + instanceName + ");")
  170. # Assign data to the struct contents
  171. # Track the encoding rule definition to detect arrays and/or ExtensionObjects
  172. encFieldIdx = 0
  173. for subv in node.value:
  174. encField = node.encodingRule[encFieldIdx]
  175. encFieldIdx = encFieldIdx + 1
  176. logger.debug(
  177. "Encoding of field " + subv.alias + " is " + str(subv.encodingRule) + "defined by " + str(encField))
  178. # Check if this is an array
  179. if subv.valueRank is None or subv.valueRank == 0:
  180. valueName = instanceName + "_struct." + subv.alias
  181. code.append(generateNodeValueCode(valueName + " = " ,
  182. subv, instanceName,valueName, global_var_code, asIndirect=False))
  183. else:
  184. if isinstance(subv, list):
  185. # this is an array
  186. code.append(instanceName + "_struct." + subv.alias + "Size = " + str(len(subv)) + ";")
  187. code.append(
  188. "{0}_struct.{1} = (UA_{2}*) UA_malloc(sizeof(UA_{2})*{3});".format(
  189. instanceName, subv.alias, subv.__class__.__name__, str(len(subv))))
  190. code.append("if (!{0}_struct.{1}) return UA_STATUSCODE_BADOUTOFMEMORY;".format(
  191. instanceName, subv.alias))
  192. codeCleanup.append("UA_free({0}_struct.{1});".format(instanceName, subv.alias))
  193. logger.debug("Encoding included array of " + str(len(subv)) + " values.")
  194. for subvidx in range(0, len(subv)):
  195. subvv = subv[subvidx]
  196. logger.debug(" " + str(subvidx) + " " + str(subvv))
  197. valueName = instanceName + "_struct." + subv.alias + "[" + str(
  198. subvidx) + "]"
  199. code.append(generateNodeValueCode(valueName + " = ", subvv, instanceName, valueName, global_var_code))
  200. code.append("}")
  201. else:
  202. code.append(instanceName + "_struct." + subv.alias + "Size = 1;")
  203. code.append(
  204. "{0}_struct.{1} = (UA_{2}*) UA_malloc(sizeof(UA_{2}));".format(
  205. instanceName, subv.alias, subv.__class__.__name__))
  206. code.append("if (!{0}_struct.{1}) return UA_STATUSCODE_BADOUTOFMEMORY;".format(
  207. instanceName, subv.alias))
  208. codeCleanup.append("UA_free({0}_struct.{1});".format(instanceName, subv.alias))
  209. valueName = instanceName + "_struct." + subv.alias + "[0]"
  210. code.append(generateNodeValueCode(valueName + " = ",
  211. subv, instanceName, valueName, global_var_code, asIndirect=True))
  212. code.append(instanceName + "->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;")
  213. #if parent.dataType.ns == 0:
  214. binaryEncodingId = nodeset.getBinaryEncodingIdForNode(parent.dataType)
  215. code.append(
  216. instanceName + "->content.encoded.typeId = UA_NODEID_NUMERIC(" + str(binaryEncodingId.ns) + ", " +
  217. str(binaryEncodingId.i) + ");")
  218. code.append(
  219. "retVal |= UA_ByteString_allocBuffer(&" + instanceName + "->content.encoded.body, " + str(encode_binary_size) + ");")
  220. # Encode each value as a bytestring separately.
  221. code.append("UA_Byte *pos" + instanceName + " = " + instanceName + "->content.encoded.body.data;")
  222. code.append("const UA_Byte *end" + instanceName + " = &" + instanceName + "->content.encoded.body.data[" + str(encode_binary_size) + "];")
  223. encFieldIdx = 0
  224. code.append("{")
  225. for subv in node.value:
  226. encField = node.encodingRule[encFieldIdx]
  227. encFieldIdx = encFieldIdx + 1
  228. if subv.valueRank is None or subv.valueRank == 0:
  229. code.append(
  230. "retVal |= UA_encodeBinary(&" + instanceName + "_struct." + subv.alias + ", " +
  231. getTypesArrayForValue(nodeset, subv) + ", &pos" + instanceName + ", &end" + instanceName + ", NULL, NULL);")
  232. else:
  233. if isinstance(subv, list):
  234. for subvidx in range(0, len(subv)):
  235. code.append("retVal |= UA_encodeBinary(&" + instanceName + "_struct." + subv.alias + "[" +
  236. str(subvidx) + "], " + getTypesArrayForValue(nodeset, subv) + ", &pos" +
  237. instanceName + ", &end" + instanceName + ", NULL, NULL);")
  238. else:
  239. code.append(
  240. "retVal |= UA_encodeBinary(&" + instanceName + "_struct." + subv.alias + "[0], " +
  241. getTypesArrayForValue(nodeset, subv) + ", &pos" + instanceName + ", &end" + instanceName + ", NULL, NULL);")
  242. code.append("}")
  243. # Reallocate the memory by swapping the 65k Bytestring for a new one
  244. code.append("size_t " + instanceName + "_encOffset = (uintptr_t)(" +
  245. "pos" + instanceName + "-" + instanceName + "->content.encoded.body.data);")
  246. code.append(instanceName + "->content.encoded.body.length = " + instanceName + "_encOffset;")
  247. code.append("UA_Byte *" + instanceName + "_newBody = (UA_Byte *) UA_malloc(" + instanceName + "_encOffset);")
  248. code.append("if (!" + instanceName + "_newBody) return UA_STATUSCODE_BADOUTOFMEMORY;")
  249. code.append("memcpy(" + instanceName + "_newBody, " + instanceName + "->content.encoded.body.data, " +
  250. instanceName + "_encOffset);")
  251. code.append("UA_Byte *" + instanceName + "_oldBody = " + instanceName + "->content.encoded.body.data;")
  252. code.append(instanceName + "->content.encoded.body.data = " + instanceName + "_newBody;")
  253. code.append("UA_free(" + instanceName + "_oldBody);")
  254. code.append("")
  255. return [code, codeCleanup]
  256. def generateValueCodeDummy(dataTypeNode, parentNode, nodeset):
  257. code = []
  258. valueName = generateNodeIdPrintable(parentNode) + "_variant_DataContents"
  259. typeBrowseNode = makeCIdentifier(dataTypeNode.browseName.name)
  260. if typeBrowseNode == "NumericRange":
  261. # in the stack we define a separate structure for the numeric range, but
  262. # the value itself is just a string
  263. typeBrowseNode = "String"
  264. typeArr = dataTypeNode.typesArray + "[" + dataTypeNode.typesArray + "_" + typeBrowseNode.upper() + "]"
  265. typeStr = "UA_" + typeBrowseNode
  266. if parentNode.valueRank > 0:
  267. for i in range(0, parentNode.valueRank):
  268. code.append("UA_Variant_setArray(&attr.value, NULL, (UA_Int32) " + "0, &" + typeArr + ");")
  269. elif not dataTypeNode.isAbstract:
  270. code.append("UA_STACKARRAY(" + typeStr + ", " + valueName + ", 1);")
  271. code.append("UA_init(" + valueName + ", &" + typeArr + ");")
  272. code.append("UA_Variant_setScalar(&attr.value, " + valueName + ", &" + typeArr + ");")
  273. return code
  274. def getTypesArrayForValue(nodeset, value):
  275. typeNode = nodeset.getNodeByBrowseName(value.__class__.__name__)
  276. if typeNode is None or value.isInternal:
  277. typesArray = "UA_TYPES"
  278. else:
  279. typesArray = typeNode.typesArray
  280. return "&" + typesArray + "[" + typesArray + "_" + \
  281. makeCIdentifier(value.__class__.__name__.upper()) + "]"
  282. def generateValueCode(node, parentNode, nodeset, bootstrapping=True, encode_binary_size=32000):
  283. code = []
  284. codeCleanup = []
  285. codeGlobal = []
  286. valueName = generateNodeIdPrintable(parentNode) + "_variant_DataContents"
  287. # node.value either contains a list of multiple identical BUILTINTYPES, or it
  288. # contains a single builtintype (which may be a container); choose if we need
  289. # to create an array or a single variable.
  290. # Note that some genious defined that there are arrays of size 1, which are
  291. # distinctly different then a single value, so we need to check that as well
  292. # Semantics:
  293. # -3: Scalar or 1-dim
  294. # -2: Scalar or x-dim | x>0
  295. # -1: Scalar
  296. # 0: x-dim | x>0
  297. # n: n-dim | n>0
  298. if (len(node.value) == 0):
  299. return ["", ""]
  300. if not isinstance(node.value[0], Value):
  301. return ["", ""]
  302. if parentNode.valueRank != -1 and (parentNode.valueRank >= 0
  303. or (len(node.value) > 1
  304. and (parentNode.valueRank != -2 or parentNode.valueRank != -3))):
  305. # User the following strategy for all directly mappable values a la 'UA_Type MyInt = (UA_Type) 23;'
  306. if isinstance(node.value[0], Guid):
  307. logger.warn("Don't know how to print array of GUID in node " + str(parentNode.id))
  308. elif isinstance(node.value[0], DiagnosticInfo):
  309. logger.warn("Don't know how to print array of DiagnosticInfo in node " + str(parentNode.id))
  310. elif isinstance(node.value[0], StatusCode):
  311. logger.warn("Don't know how to print array of StatusCode in node " + str(parentNode.id))
  312. else:
  313. if isinstance(node.value[0], ExtensionObject):
  314. for idx, v in enumerate(node.value):
  315. logger.debug("Building extObj array index " + str(idx))
  316. [code1, codeCleanup1] = generateExtensionObjectSubtypeCode(v, parent=parentNode, nodeset=nodeset, arrayIndex=idx,
  317. encode_binary_size=encode_binary_size, global_var_code=codeGlobal)
  318. code = code + code1
  319. codeCleanup = codeCleanup + codeCleanup1
  320. code.append("UA_" + node.value[0].__class__.__name__ + " " + valueName + "[" + str(len(node.value)) + "];")
  321. if isinstance(node.value[0], ExtensionObject):
  322. for idx, v in enumerate(node.value):
  323. logger.debug("Printing extObj array index " + str(idx))
  324. instanceName = generateNodeValueInstanceName(v, parentNode, 0, idx)
  325. code.append(generateNodeValueCode(
  326. valueName + "[" + str(idx) + "] = ",
  327. v, instanceName, valueName, codeGlobal))
  328. # code.append("UA_free(&" +valueName + "[" + str(idx) + "]);")
  329. else:
  330. for idx, v in enumerate(node.value):
  331. instanceName = generateNodeValueInstanceName(v, parentNode, 0, idx)
  332. code.append(generateNodeValueCode(
  333. valueName + "[" + str(idx) + "] = " , v, instanceName, valueName, codeGlobal))
  334. code.append("UA_Variant_setArray(&attr.value, &" + valueName +
  335. ", (UA_Int32) " + str(len(node.value)) + ", " +
  336. getTypesArrayForValue(nodeset, node.value[0]) + ");")
  337. else:
  338. # User the following strategy for all directly mappable values a la 'UA_Type MyInt = (UA_Type) 23;'
  339. if isinstance(node.value[0], Guid):
  340. logger.warn("Don't know how to print scalar GUID in node " + str(parentNode.id))
  341. elif isinstance(node.value[0], DiagnosticInfo):
  342. logger.warn("Don't know how to print scalar DiagnosticInfo in node " + str(parentNode.id))
  343. elif isinstance(node.value[0], StatusCode):
  344. logger.warn("Don't know how to print scalar StatusCode in node " + str(parentNode.id))
  345. else:
  346. # The following strategy applies to all other types, in particular strings and numerics.
  347. if isinstance(node.value[0], ExtensionObject):
  348. [code1, codeCleanup1] = generateExtensionObjectSubtypeCode(node.value[0], parent=parentNode, nodeset=nodeset,
  349. encode_binary_size=encode_binary_size, global_var_code=codeGlobal)
  350. code = code + code1
  351. codeCleanup = codeCleanup + codeCleanup1
  352. instanceName = generateNodeValueInstanceName(node.value[0], parentNode, 0, 0)
  353. if isinstance(node.value[0], ExtensionObject):
  354. code.append(generateNodeValueCode("UA_" + node.value[0].__class__.__name__ + " *" + valueName + " = " ,
  355. node.value[0], instanceName, valueName, codeGlobal, asIndirect=True ))
  356. code.append(
  357. "UA_Variant_setScalar(&attr.value, " + valueName + ", " +
  358. getTypesArrayForValue(nodeset, node.value[0]) + ");")
  359. # FIXME: There is no membership definition for extensionObjects generated in this function.
  360. # code.append("UA_" + node.value[0].__class__.__name__ + "_deleteMembers(" + valueName + ");")
  361. else:
  362. code.append("UA_" + node.value[0].__class__.__name__ + " *" + valueName + " = UA_" + node.value[
  363. 0].__class__.__name__ + "_new();")
  364. code.append("if (!" + valueName + ") return UA_STATUSCODE_BADOUTOFMEMORY;")
  365. code.append(generateNodeValueCode("*" + valueName + " = " , node.value[0], instanceName, valueName, codeGlobal, asIndirect=True))
  366. code.append(
  367. "UA_Variant_setScalar(&attr.value, " + valueName + ", " +
  368. getTypesArrayForValue(nodeset, node.value[0]) + ");")
  369. if node.value[0].__class__.__name__ == "ByteString":
  370. # The data is on the stack, not heap, so we can not delete the ByteString
  371. codeCleanup.append("{}->data = NULL;".format(valueName))
  372. codeCleanup.append("{}->length = 0;".format(valueName))
  373. codeCleanup.append("UA_{0}_delete({1});".format(
  374. node.value[0].__class__.__name__, valueName))
  375. return [code, codeCleanup, codeGlobal]
  376. def generateMethodNodeCode(node):
  377. code = []
  378. code.append("UA_MethodAttributes attr = UA_MethodAttributes_default;")
  379. if node.executable:
  380. code.append("attr.executable = true;")
  381. if node.userExecutable:
  382. code.append("attr.userExecutable = true;")
  383. return code
  384. def generateObjectTypeNodeCode(node):
  385. code = []
  386. code.append("UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;")
  387. if node.isAbstract:
  388. code.append("attr.isAbstract = true;")
  389. return code
  390. def generateDataTypeNodeCode(node):
  391. code = []
  392. code.append("UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;")
  393. if node.isAbstract:
  394. code.append("attr.isAbstract = true;")
  395. return code
  396. def generateViewNodeCode(node):
  397. code = []
  398. code.append("UA_ViewAttributes attr = UA_ViewAttributes_default;")
  399. if node.containsNoLoops:
  400. code.append("attr.containsNoLoops = true;")
  401. code.append("attr.eventNotifier = (UA_Byte)%s;" % str(node.eventNotifier))
  402. return code
  403. def getNodeTypeDefinition(node):
  404. for ref in node.references:
  405. # 40 = HasTypeDefinition
  406. if ref.referenceType.i == 40:
  407. return ref.target
  408. return None
  409. def generateSubtypeOfDefinitionCode(node):
  410. for ref in node.inverseReferences:
  411. # 45 = HasSubtype
  412. if ref.referenceType.i == 45:
  413. return generateNodeIdCode(ref.target)
  414. return "UA_NODEID_NULL"
  415. def generateNodeCode_begin(node, nodeset, generate_ns0, parentref, encode_binary_size, code_global):
  416. code = []
  417. codeCleanup = []
  418. code.append("UA_StatusCode retVal = UA_STATUSCODE_GOOD;")
  419. # Attributes
  420. if isinstance(node, ReferenceTypeNode):
  421. code.extend(generateReferenceTypeNodeCode(node))
  422. elif isinstance(node, ObjectNode):
  423. code.extend(generateObjectNodeCode(node))
  424. elif isinstance(node, VariableNode) and not isinstance(node, VariableTypeNode):
  425. [code1, codeCleanup1, codeGlobal1] = generateVariableNodeCode(node, nodeset, encode_binary_size)
  426. code.extend(code1)
  427. codeCleanup.extend(codeCleanup1)
  428. code_global.extend(codeGlobal1)
  429. elif isinstance(node, VariableTypeNode):
  430. [code1, codeCleanup1, codeGlobal1] = generateVariableTypeNodeCode(node, nodeset, encode_binary_size)
  431. code.extend(code1)
  432. codeCleanup.extend(codeCleanup1)
  433. code_global.extend(codeGlobal1)
  434. elif isinstance(node, MethodNode):
  435. code.extend(generateMethodNodeCode(node))
  436. elif isinstance(node, ObjectTypeNode):
  437. code.extend(generateObjectTypeNodeCode(node))
  438. elif isinstance(node, DataTypeNode):
  439. code.extend(generateDataTypeNodeCode(node))
  440. elif isinstance(node, ViewNode):
  441. code.extend(generateViewNodeCode(node))
  442. code.append("attr.displayName = " + generateLocalizedTextCode(node.displayName, alloc=False) + ";")
  443. code.append("#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS")
  444. code.append("attr.description = " + generateLocalizedTextCode(node.description, alloc=False) + ";")
  445. code.append("#endif")
  446. code.append("attr.writeMask = %d;" % node.writeMask)
  447. code.append("attr.userWriteMask = %d;" % node.userWriteMask)
  448. # AddNodes call
  449. code.append("retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_{},".
  450. format(makeCIdentifier(node.__class__.__name__.upper().replace("NODE" ,""))))
  451. code.append(generateNodeIdCode(node.id) + ",")
  452. code.append(generateNodeIdCode(parentref.target) + ",")
  453. code.append(generateNodeIdCode(parentref.referenceType) + ",")
  454. code.append(generateQualifiedNameCode(node.browseName) + ",")
  455. if isinstance(node, VariableNode) or isinstance(node, ObjectNode):
  456. typeDefRef = node.popTypeDef()
  457. code.append(generateNodeIdCode(typeDefRef.target) + ",")
  458. else:
  459. code.append(" UA_NODEID_NULL,")
  460. code.append("(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_{}ATTRIBUTES],NULL, NULL);".
  461. format(makeCIdentifier(node.__class__.__name__.upper().replace("NODE" ,""))))
  462. code.extend(codeCleanup)
  463. return "\n".join(code)
  464. def generateNodeCode_finish(node):
  465. code = []
  466. if isinstance(node, MethodNode):
  467. code.append("UA_Server_addMethodNode_finish(server, ")
  468. else:
  469. code.append("UA_Server_addNode_finish(server, ")
  470. code.append(generateNodeIdCode(node.id))
  471. if isinstance(node, MethodNode):
  472. code.append(", NULL, 0, NULL, 0, NULL);")
  473. else:
  474. code.append(");")
  475. return "\n".join(code)