backend_open62541_nodes.py 25 KB

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