|
@@ -75,6 +75,39 @@ def generateObjectNodeCode(node):
|
|
|
code.append("attr.eventNotifier = true;")
|
|
|
return code
|
|
|
|
|
|
+def setNodeDatatypeRecursive(node, nodeset):
|
|
|
+
|
|
|
+ if not isinstance(node, VariableNode) and not isinstance(node, VariableTypeNode):
|
|
|
+ raise RuntimeError("DataType can only be set for VariableNode and VariableTypeNode")
|
|
|
+
|
|
|
+ if node.dataType is not None:
|
|
|
+ return
|
|
|
+
|
|
|
+ # If BaseVariableType
|
|
|
+ if node.id == NodeId("ns=0;i=62"):
|
|
|
+ if node.dataType is None:
|
|
|
+ # Set to default BaseDataType
|
|
|
+ node.dataType = NodeId("ns=0;i=24")
|
|
|
+ return
|
|
|
+
|
|
|
+ if isinstance(node, VariableNode) and not isinstance(node, VariableTypeNode):
|
|
|
+ typeDefNode = nodeset.getNodeTypeDefinition(node)
|
|
|
+ if typeDefNode is None:
|
|
|
+ # Use the parent type.
|
|
|
+ raise RuntimeError("Cannot get node for HasTypeDefinition of VariableNode " + node.browseName.name + " " + str(node.id))
|
|
|
+
|
|
|
+ setNodeDatatypeRecursive(typeDefNode, nodeset)
|
|
|
+
|
|
|
+ node.dataType = typeDefNode.dataType
|
|
|
+ else:
|
|
|
+ # Use the parent type.
|
|
|
+ if node.parent is None:
|
|
|
+ raise RuntimeError("Parent node not defined for " + node.browseName.name + " " + str(node.id))
|
|
|
+
|
|
|
+ setNodeDatatypeRecursive(node.parent, nodeset)
|
|
|
+ node.dataType = node.parent.dataType
|
|
|
+
|
|
|
+
|
|
|
def generateCommonVariableCode(node, nodeset):
|
|
|
code = []
|
|
|
codeCleanup = []
|
|
@@ -92,41 +125,49 @@ def generateCommonVariableCode(node, nodeset):
|
|
|
for dim in range(0, node.valueRank):
|
|
|
code.append("arrayDimensions[{}] = 0;".format(dim))
|
|
|
code.append("attr.arrayDimensions = &arrayDimensions[0];")
|
|
|
-
|
|
|
- if node.dataType is not None:
|
|
|
- dataTypeNode = nodeset.getBaseDataType(nodeset.getDataTypeNode(node.dataType))
|
|
|
-
|
|
|
- if dataTypeNode is None:
|
|
|
- raise RuntimeError("Cannot get BaseDataType for dataType : " + str(node.dataType) + " of node " + node.browseName.name + " " + str(node.id))
|
|
|
-
|
|
|
- code.append("attr.dataType = %s;" % generateNodeIdCode(node.dataType))
|
|
|
-
|
|
|
- if dataTypeNode.isEncodable():
|
|
|
- if node.value is not None:
|
|
|
- [code1, codeCleanup1, codeGlobal1] = generateValueCode(node.value, nodeset.nodes[node.id], nodeset)
|
|
|
- code += code1
|
|
|
- codeCleanup += codeCleanup1
|
|
|
- codeGlobal += codeGlobal1
|
|
|
- if node.valueRank is not None and node.valueRank > 0 and len(node.arrayDimensions) == node.valueRank and len(node.value.value) > 0:
|
|
|
- numElements = 1
|
|
|
- hasZero = False
|
|
|
- for v in node.arrayDimensions:
|
|
|
- dim = int(unicode(v))
|
|
|
- if dim > 0:
|
|
|
- numElements = numElements * dim
|
|
|
- else:
|
|
|
- hasZero = True
|
|
|
- if hasZero == False and len(node.value.value) == numElements:
|
|
|
- code.append("attr.value.arrayDimensionsSize = attr.arrayDimensionsSize;")
|
|
|
- code.append("attr.value.arrayDimensions = attr.arrayDimensions;")
|
|
|
- logger.warning("printing arrayDimensions")
|
|
|
+ else:
|
|
|
+ # Default value for the value rank as defined in the NodeSet2 xsd file
|
|
|
+ code.append("attr.valueRank = -1;")
|
|
|
+
|
|
|
+ if node.dataType is None:
|
|
|
+ # Inherit the datatype from the HasTypeDefinition reference, as stated in the OPC UA Spec:
|
|
|
+ # 6.4.2
|
|
|
+ # "Instances inherit the initial values for the Attributes that they have in common with the
|
|
|
+ # TypeDefinitionNode from which they are instantiated, with the exceptions of the NodeClass and
|
|
|
+ # NodeId."
|
|
|
+ setNodeDatatypeRecursive(node, nodeset)
|
|
|
+ code.append("/* DataType inherited */")
|
|
|
+
|
|
|
+ dataTypeNode = nodeset.getBaseDataType(nodeset.getDataTypeNode(node.dataType))
|
|
|
+
|
|
|
+ if dataTypeNode is None:
|
|
|
+ raise RuntimeError("Cannot get BaseDataType for dataType : " + str(node.dataType) + " of node " + node.browseName.name + " " + str(node.id))
|
|
|
+
|
|
|
+ code.append("attr.dataType = %s;" % generateNodeIdCode(node.dataType))
|
|
|
+
|
|
|
+ if dataTypeNode.isEncodable():
|
|
|
+ if node.value is not None:
|
|
|
+ [code1, codeCleanup1, codeGlobal1] = generateValueCode(node.value, nodeset.nodes[node.id], nodeset)
|
|
|
+ code += code1
|
|
|
+ codeCleanup += codeCleanup1
|
|
|
+ codeGlobal += codeGlobal1
|
|
|
+ if node.valueRank is not None and node.valueRank > 0 and len(node.arrayDimensions) == node.valueRank and len(node.value.value) > 0:
|
|
|
+ numElements = 1
|
|
|
+ hasZero = False
|
|
|
+ for v in node.arrayDimensions:
|
|
|
+ dim = int(unicode(v))
|
|
|
+ if dim > 0:
|
|
|
+ numElements = numElements * dim
|
|
|
else:
|
|
|
- logger.error("Dimension with size 0 or value count mismatch detected, ArrayDimensions won't be copied to the Value attribute.")
|
|
|
- elif not isinstance(node, VariableTypeNode): # Don't generate a dummy value for VariableType nodes
|
|
|
- code += generateValueCodeDummy(dataTypeNode, nodeset.nodes[node.id], nodeset)
|
|
|
- elif node.value is not None:
|
|
|
- raise RuntimeError("Cannot encode dataTypeNode: " + dataTypeNode.browseName.name + " for value of node " + node.browseName.name + " " + str(node.id))
|
|
|
-
|
|
|
+ hasZero = True
|
|
|
+ if hasZero == False and len(node.value.value) == numElements:
|
|
|
+ code.append("attr.value.arrayDimensionsSize = attr.arrayDimensionsSize;")
|
|
|
+ code.append("attr.value.arrayDimensions = attr.arrayDimensions;")
|
|
|
+ logger.warning("printing arrayDimensions")
|
|
|
+ else:
|
|
|
+ logger.error("Dimension with size 0 or value count mismatch detected, ArrayDimensions won't be copied to the Value attribute.")
|
|
|
+ elif node.value is not None:
|
|
|
+ raise RuntimeError("Cannot encode dataTypeNode: " + dataTypeNode.browseName.name + " for value of node " + node.browseName.name + " " + str(node.id))
|
|
|
|
|
|
return [code, codeCleanup, codeGlobal]
|
|
|
|
|
@@ -145,6 +186,19 @@ def generateVariableNodeCode(node, nodeset):
|
|
|
if node.valueRank == -2 and node.value is not None and len(node.value.value) == 1:
|
|
|
node.valueRank = -1
|
|
|
|
|
|
+ if node.valueRank is None:
|
|
|
+ # If the VariableNode does not have any valueRank, use the one from the VariableType
|
|
|
+ # The type may define the valueRank to e.g. 1 which is not the default value for the variable itself.
|
|
|
+ # This is e.g. the case for 'ActiveBackground1' of the Adi.NodeSet2.xml
|
|
|
+ variableTypeNode = nodeset.getNodeTypeDefinition(node)
|
|
|
+
|
|
|
+ if variableTypeNode is None:
|
|
|
+ raise RuntimeError("Cannot get node for HasTypeDefinition of VariableNode " + node.browseName.name + " " + str(node.id))
|
|
|
+
|
|
|
+ if variableTypeNode.valueRank is not None and variableTypeNode.valueRank > -2:
|
|
|
+ code.append("attr.valueRank = %d; /* From VariableType */" % variableTypeNode.valueRank)
|
|
|
+
|
|
|
+
|
|
|
[code1, codeCleanup1, codeGlobal1] = generateCommonVariableCode(node, nodeset)
|
|
|
code += code1
|
|
|
codeCleanup += codeCleanup1
|
|
@@ -251,22 +305,6 @@ def getTypeBrowseName(dataTypeNode):
|
|
|
typeBrowseName = "String"
|
|
|
return typeBrowseName
|
|
|
|
|
|
-def generateValueCodeDummy(dataTypeNode, parentNode, nodeset):
|
|
|
- code = []
|
|
|
- valueName = generateNodeIdPrintable(parentNode) + "_variant_DataContents"
|
|
|
- typeBrowseName = getTypeBrowseName(dataTypeNode)
|
|
|
- typeArr = dataTypeNode.typesArray + "[" + dataTypeNode.typesArray + "_" + typeBrowseName.upper() + "]"
|
|
|
- typeStr = "UA_" + typeBrowseName
|
|
|
-
|
|
|
- if parentNode.valueRank is not None and parentNode.valueRank > 0:
|
|
|
- for i in range(0, parentNode.valueRank):
|
|
|
- code.append("UA_Variant_setArray(&attr.value, NULL, (UA_Int32) " + "0, &" + typeArr + ");")
|
|
|
- elif not dataTypeNode.isAbstract:
|
|
|
- code.append("UA_STACKARRAY(" + typeStr + ", " + valueName + ", 1);")
|
|
|
- code.append("UA_init(" + valueName + ", &" + typeArr + ");")
|
|
|
- code.append("UA_Variant_setScalar(&attr.value, " + valueName + ", &" + typeArr + ");")
|
|
|
- return code
|
|
|
-
|
|
|
def getTypesArrayForValue(nodeset, value):
|
|
|
typeNode = nodeset.getNodeByBrowseName(value.__class__.__name__)
|
|
|
if typeNode is None or value.isInternal:
|
|
@@ -397,13 +435,6 @@ def generateViewNodeCode(node):
|
|
|
code.append("attr.eventNotifier = (UA_Byte)%s;" % str(node.eventNotifier))
|
|
|
return code
|
|
|
|
|
|
-def getNodeTypeDefinition(node):
|
|
|
- for ref in node.references:
|
|
|
- # 40 = HasTypeDefinition
|
|
|
- if ref.referenceType.i == 40:
|
|
|
- return ref.target
|
|
|
- return None
|
|
|
-
|
|
|
def generateSubtypeOfDefinitionCode(node):
|
|
|
for ref in node.inverseReferences:
|
|
|
# 45 = HasSubtype
|
|
@@ -411,7 +442,7 @@ def generateSubtypeOfDefinitionCode(node):
|
|
|
return generateNodeIdCode(ref.target)
|
|
|
return "UA_NODEID_NULL"
|
|
|
|
|
|
-def generateNodeCode_begin(node, nodeset, parentref, code_global):
|
|
|
+def generateNodeCode_begin(node, nodeset, code_global):
|
|
|
code = []
|
|
|
codeCleanup = []
|
|
|
code.append("UA_StatusCode retVal = UA_STATUSCODE_GOOD;")
|
|
@@ -454,8 +485,8 @@ def generateNodeCode_begin(node, nodeset, parentref, code_global):
|
|
|
code.append("retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_{},".
|
|
|
format(makeCIdentifier(node.__class__.__name__.upper().replace("NODE" ,""))))
|
|
|
code.append(generateNodeIdCode(node.id) + ",")
|
|
|
- code.append(generateNodeIdCode(parentref.target) + ",")
|
|
|
- code.append(generateNodeIdCode(parentref.referenceType) + ",")
|
|
|
+ code.append(generateNodeIdCode(node.parent.id if node.parent else NodeId()) + ",")
|
|
|
+ code.append(generateNodeIdCode(node.parentReference.id if node.parent else NodeId()) + ",")
|
|
|
code.append(generateQualifiedNameCode(node.browseName) + ",")
|
|
|
if isinstance(node, VariableNode) or isinstance(node, ObjectNode):
|
|
|
typeDefRef = node.popTypeDef()
|