Forráskód Böngészése

Merge branch 'automation' of https://github.com/acplt/open62541 into automation

Stasik0 10 éve
szülő
commit
26d88f143e
2 módosított fájl, 115 hozzáadás és 36 törlés
  1. 13 16
      src/ua_application.c
  2. 102 20
      src/ua_services_view.c

+ 13 - 16
src/ua_application.c

@@ -224,7 +224,7 @@ void appMockup_init() {
 	aggregates->isAbstract = UA_TRUE;
 	aggregates->symmetric = UA_FALSE;
 	AddReference((UA_Node*)aggregates, &(UA_ReferenceNode){RefTypeId_HasSubtype, UA_TRUE,
-				(UA_ExpandedNodeId){RefTypeId_HierarchicalReferences, UA_STRING_NULL, 0}}, ns0);
+				(UA_ExpandedNodeId){RefTypeId_HasChild, UA_STRING_NULL, 0}}, ns0);
 	Namespace_insert(ns0,(UA_Node*)aggregates);
 	
 	UA_ReferenceTypeNode *hassubtype;
@@ -251,7 +251,7 @@ void appMockup_init() {
 	hasproperty->isAbstract = UA_FALSE;
 	hasproperty->symmetric = UA_FALSE;
 	generatesevent->inverseName = UA_LOCALIZEDTEXT_STATIC("PropertyOf");
-	AddReference((UA_Node*)hasproperty, &(UA_ReferenceNode){RefTypeId_HasProperty, UA_TRUE,
+	AddReference((UA_Node*)hasproperty, &(UA_ReferenceNode){RefTypeId_HasSubtype, UA_TRUE,
 				(UA_ExpandedNodeId){RefTypeId_Aggregates, UA_STRING_NULL, 0}}, ns0);
 	Namespace_insert(ns0,(UA_Node*)hasproperty);
 
@@ -265,7 +265,7 @@ void appMockup_init() {
 	hascomponent->isAbstract = UA_FALSE;
 	hascomponent->symmetric = UA_FALSE;
 	generatesevent->inverseName = UA_LOCALIZEDTEXT_STATIC("ComponentOf");
-	AddReference((UA_Node*)hascomponent, &(UA_ReferenceNode){RefTypeId_HasComponent, UA_TRUE,
+	AddReference((UA_Node*)hascomponent, &(UA_ReferenceNode){RefTypeId_HasSubtype, UA_TRUE,
 				(UA_ExpandedNodeId){RefTypeId_Aggregates, UA_STRING_NULL, 0}}, ns0);
 	Namespace_insert(ns0,(UA_Node*)hascomponent);
 
@@ -279,7 +279,7 @@ void appMockup_init() {
 	hasnotifier->isAbstract = UA_FALSE;
 	hasnotifier->symmetric = UA_FALSE;
 	generatesevent->inverseName = UA_LOCALIZEDTEXT_STATIC("NotifierOf");
-	AddReference((UA_Node*)hasnotifier, &(UA_ReferenceNode){RefTypeId_HasNotifier, UA_TRUE,
+	AddReference((UA_Node*)hasnotifier, &(UA_ReferenceNode){RefTypeId_HasSubtype, UA_TRUE,
 				(UA_ExpandedNodeId){RefTypeId_HasEventSource, UA_STRING_NULL, 0}}, ns0);
 	Namespace_insert(ns0,(UA_Node*)hasnotifier);
 
@@ -293,7 +293,7 @@ void appMockup_init() {
 	hasorderedcomponent->isAbstract = UA_FALSE;
 	hasorderedcomponent->symmetric = UA_FALSE;
 	generatesevent->inverseName = UA_LOCALIZEDTEXT_STATIC("OrderedComponentOf");
-	AddReference((UA_Node*)hasorderedcomponent, &(UA_ReferenceNode){RefTypeId_HasOrderedComponent, UA_TRUE,
+	AddReference((UA_Node*)hasorderedcomponent, &(UA_ReferenceNode){RefTypeId_HasSubtype, UA_TRUE,
 				(UA_ExpandedNodeId){RefTypeId_HasComponent, UA_STRING_NULL, 0}}, ns0);
 	Namespace_insert(ns0,(UA_Node*)hasorderedcomponent);
 
@@ -307,7 +307,7 @@ void appMockup_init() {
 	hasmodelparent->isAbstract = UA_FALSE;
 	hasmodelparent->symmetric = UA_FALSE;
 	generatesevent->inverseName = UA_LOCALIZEDTEXT_STATIC("ModelParentOf");
-	AddReference((UA_Node*)hasmodelparent, &(UA_ReferenceNode){RefTypeId_HasModelParent, UA_TRUE,
+	AddReference((UA_Node*)hasmodelparent, &(UA_ReferenceNode){RefTypeId_HasSubtype, UA_TRUE,
 				(UA_ExpandedNodeId){RefTypeId_NonHierarchicalReferences, UA_STRING_NULL, 0}}, ns0);
 	Namespace_insert(ns0,(UA_Node*)hasmodelparent);
 
@@ -321,7 +321,7 @@ void appMockup_init() {
 	fromstate->isAbstract = UA_FALSE;
 	fromstate->symmetric = UA_FALSE;
 	generatesevent->inverseName = UA_LOCALIZEDTEXT_STATIC("ToTransition");
-	AddReference((UA_Node*)fromstate, &(UA_ReferenceNode){RefTypeId_FromState, UA_TRUE,
+	AddReference((UA_Node*)fromstate, &(UA_ReferenceNode){RefTypeId_HasSubtype, UA_TRUE,
 				(UA_ExpandedNodeId){RefTypeId_NonHierarchicalReferences, UA_STRING_NULL, 0}}, ns0);
 	Namespace_insert(ns0,(UA_Node*)fromstate);
 
@@ -335,7 +335,7 @@ void appMockup_init() {
 	tostate->isAbstract = UA_FALSE;
 	tostate->symmetric = UA_FALSE;
 	generatesevent->inverseName = UA_LOCALIZEDTEXT_STATIC("FromTransition");
-	AddReference((UA_Node*)tostate, &(UA_ReferenceNode){RefTypeId_ToState, UA_TRUE,
+	AddReference((UA_Node*)tostate, &(UA_ReferenceNode){RefTypeId_HasSubtype, UA_TRUE,
 				(UA_ExpandedNodeId){RefTypeId_NonHierarchicalReferences, UA_STRING_NULL, 0}}, ns0);
 	Namespace_insert(ns0,(UA_Node*)tostate);
 
@@ -349,7 +349,7 @@ void appMockup_init() {
 	hascause->isAbstract = UA_FALSE;
 	hascause->symmetric = UA_FALSE;
 	generatesevent->inverseName = UA_LOCALIZEDTEXT_STATIC("MayBeCausedBy");
-	AddReference((UA_Node*)hascause, &(UA_ReferenceNode){RefTypeId_HasCause, UA_TRUE,
+	AddReference((UA_Node*)hascause, &(UA_ReferenceNode){RefTypeId_HasSubtype, UA_TRUE,
 				(UA_ExpandedNodeId){RefTypeId_NonHierarchicalReferences, UA_STRING_NULL, 0}}, ns0);
 	Namespace_insert(ns0,(UA_Node*)hascause);
 
@@ -363,7 +363,7 @@ void appMockup_init() {
 	haseffect->isAbstract = UA_FALSE;
 	haseffect->symmetric = UA_FALSE;
 	generatesevent->inverseName = UA_LOCALIZEDTEXT_STATIC("MayBeEffectedBy");
-	AddReference((UA_Node*)haseffect, &(UA_ReferenceNode){RefTypeId_HasEffect, UA_TRUE,
+	AddReference((UA_Node*)haseffect, &(UA_ReferenceNode){RefTypeId_HasSubtype, UA_TRUE,
 				(UA_ExpandedNodeId){RefTypeId_NonHierarchicalReferences, UA_STRING_NULL, 0}}, ns0);
 	Namespace_insert(ns0,(UA_Node*)haseffect);
 
@@ -377,8 +377,8 @@ void appMockup_init() {
 	hashistoricalconfiguration->isAbstract = UA_FALSE;
 	hashistoricalconfiguration->symmetric = UA_FALSE;
 	generatesevent->inverseName = UA_LOCALIZEDTEXT_STATIC("HistoricalConfigurationOf");
-	AddReference((UA_Node*)hashistoricalconfiguration, &(UA_ReferenceNode){RefTypeId_HasHistoricalConfiguration, UA_TRUE,
-				(UA_ExpandedNodeId){RefTypeId_Aggregates, UA_STRING_NULL, 0}}, ns0);
+	AddReference((UA_Node*)hashistoricalconfiguration, &(UA_ReferenceNode){RefTypeId_HasSubtype,
+				UA_TRUE, (UA_ExpandedNodeId){RefTypeId_Aggregates, UA_STRING_NULL, 0}}, ns0);
 	Namespace_insert(ns0,(UA_Node*)hashistoricalconfiguration);
 
 
@@ -400,7 +400,7 @@ void appMockup_init() {
 	UA_ObjectNode *folderType;
 	UA_ObjectNode_new(&folderType);
 	folderType->nodeId = NS0NODEID(61);
-	folderType->nodeClass = UA_NODECLASS_OBJECT; // I should not have to set this manually
+	folderType->nodeClass = UA_NODECLASS_OBJECTTYPE; // I should not have to set this manually
 	folderType->browseName = UA_QUALIFIEDNAME_STATIC("FolderType");
 	folderType->displayName = UA_LOCALIZEDTEXT_STATIC("FolderType");
 	folderType->description = UA_LOCALIZEDTEXT_STATIC("FolderType");
@@ -415,7 +415,6 @@ void appMockup_init() {
 	root->displayName = UA_LOCALIZEDTEXT_STATIC("Root");
 	root->description = UA_LOCALIZEDTEXT_STATIC("Root");
 	AddReference((UA_Node*)root, &(UA_ReferenceNode){RefTypeId_HasTypeDefinition, UA_FALSE, ObjTypeId_FolderType}, ns0);
-	AddReference((UA_Node*)root, &(UA_ReferenceNode){RefTypeId_Organizes, UA_FALSE, ObjTypeId_FolderType}, ns0);
 	AddReference((UA_Node*)root, &(UA_ReferenceNode){RefTypeId_Organizes, UA_FALSE, ObjId_ObjectsFolder}, ns0);
 	AddReference((UA_Node*)root, &(UA_ReferenceNode){RefTypeId_Organizes, UA_FALSE, ObjId_TypesFolder}, ns0);
 	AddReference((UA_Node*)root, &(UA_ReferenceNode){RefTypeId_Organizes, UA_FALSE, ObjId_ViewsFolder}, ns0);
@@ -542,8 +541,6 @@ void appMockup_init() {
     /* Namespace local */
     /*******************/
 
-
-
 #if defined(DEBUG) && defined(VERBOSE)
 	uint32_t i;
 	for (i=0;i < ns0->size;i++) {

+ 102 - 20
src/ua_services_view.c

@@ -8,6 +8,11 @@ UA_Int32 Service_Browse_getReferenceDescription(Namespace *ns, UA_ReferenceNode*
 	if(Namespace_get(ns,&reference->targetId.nodeId,&foundNode, &lock) != UA_SUCCESS)
 		return UA_ERROR;
 
+	UA_NodeId_copy(&foundNode->nodeId, &referenceDescription->nodeId.nodeId);
+	//TODO ExpandedNodeId is a mockup
+	referenceDescription->nodeId.serverIndex = 0;
+	referenceDescription->nodeId.namespaceUri.length = -1;
+
 	UA_UInt32 mask = 0;
 	for (mask = 0x01; mask <= 0x40; mask *= 2) {
 		switch (mask & (resultMask)) {
@@ -27,12 +32,16 @@ UA_Int32 Service_Browse_getReferenceDescription(Namespace *ns, UA_ReferenceNode*
 			UA_LocalizedText_copy(&foundNode->displayName, &referenceDescription->displayName);
 			break;
 		case UA_BROWSERESULTMASK_TYPEDEFINITION:
-			if (referenceDescription->nodeClass == UA_NODECLASS_OBJECT ||
-				referenceDescription->nodeClass == UA_NODECLASS_VARIABLE) {
-				UA_NodeId_copy(&foundNode->nodeId, &referenceDescription->typeDefinition.nodeId);
-				//TODO mockup
-				referenceDescription->typeDefinition.serverIndex = 0;
-				referenceDescription->typeDefinition.namespaceUri.length = 0;
+			if (foundNode->nodeClass != UA_NODECLASS_OBJECT &&
+				foundNode->nodeClass != UA_NODECLASS_VARIABLE)
+				break;
+
+			for(UA_Int32 i = 0;i<foundNode->referencesSize;i++) {
+				UA_ReferenceNode *ref = &foundNode->references[i];
+				if(ref->referenceTypeId.identifier.numeric == 40 /* hastypedefinition */) {
+					UA_ExpandedNodeId_copy(&ref->targetId, &referenceDescription->typeDefinition);
+					break;
+				}
 			}
 			break;
 		}
@@ -42,19 +51,81 @@ UA_Int32 Service_Browse_getReferenceDescription(Namespace *ns, UA_ReferenceNode*
 	return UA_SUCCESS;
 }
 
-static inline UA_Boolean Service_Browse_returnReference(UA_BrowseDescription *browseDescription, UA_ReferenceNode* reference) {
-	UA_Boolean c = UA_FALSE;
+/* singly-linked list */
+struct SubRefTypeId {
+	UA_NodeId id;
+	UA_SLIST_ENTRY(SubRefTypeId) next;
+};
+UA_SLIST_HEAD(SubRefTypeIdList, SubRefTypeId);
+
+UA_UInt32 walkReferenceTree(Namespace *ns, UA_ReferenceTypeNode *current, struct SubRefTypeIdList *list) {
+	// insert the current referencetype
+	struct SubRefTypeId *element;
+	UA_alloc((void**)&element, sizeof(struct SubRefTypeId));
+	element->id = current->nodeId;
+	UA_SLIST_INSERT_HEAD(list, element, next);
+
+	UA_UInt32 count = 1; // the current element
+
+	// walk the tree
+	for(UA_Int32 i = 0;i < current->referencesSize;i++) {
+		if(current->references[i].referenceTypeId.identifier.numeric == 45 /* HasSubtype */ &&
+		   current->references[i].isInverse == UA_FALSE) {
+			const UA_Node *node;
+			Namespace_Entry_Lock *lock;
+			if(Namespace_get(ns, &current->references[i].targetId.nodeId, &node, &lock) == UA_SUCCESS &&
+			   node->nodeClass == UA_NODECLASS_REFERENCETYPE) {
+				count += walkReferenceTree(ns,(UA_ReferenceTypeNode*)node, list);
+				Namespace_Entry_Lock_release(lock);
+			}
+		}
+	}
+	return count;
+}
+
+/* We do not search across namespaces so far. The id of the father-referencetype is returned in the array also. */
+static UA_Int32 findSubReferenceTypes(Namespace *ns, UA_NodeId *rootReferenceType, UA_NodeId **ids, UA_UInt32 *idcount) {
+	struct SubRefTypeIdList list;
+	UA_SLIST_INIT(&list);
+
+	// walk the tree
+	UA_ReferenceTypeNode *root;
+	Namespace_Entry_Lock *lock;
+	if(Namespace_get(ns, rootReferenceType, (const UA_Node**)&root, &lock) != UA_SUCCESS ||
+	   root->nodeClass != UA_NODECLASS_REFERENCETYPE)
+		return UA_ERROR;
+	UA_UInt32 count = walkReferenceTree(ns, root, &list);
+	Namespace_Entry_Lock_release(lock);
+
+	// copy results into an array
+	UA_alloc((void**) ids, sizeof(UA_NodeId)*count);
+	for(UA_UInt32 i = 0; i < count;i++) {
+		struct SubRefTypeId *element = UA_SLIST_FIRST(&list);
+		UA_NodeId_copy(&element->id, &(*ids)[i]);
+		UA_SLIST_REMOVE_HEAD(&list, next);
+		UA_free(element);
+	}
+	*idcount = count;
 
-	c = c || ((reference->isInverse == UA_TRUE) && (browseDescription->browseDirection == UA_BROWSEDIRECTION_INVERSE));
-	c = c || ((reference->isInverse == UA_FALSE) && (browseDescription->browseDirection == UA_BROWSEDIRECTION_FORWARD));
-	c = c || (browseDescription->browseDirection == UA_BROWSEDIRECTION_BOTH);
-	c = c && &browseDescription->referenceTypeId == UA_NULL;
-	c = c || UA_NodeId_equal(&browseDescription->referenceTypeId, &reference->referenceTypeId);
-	//TODO subtypes
-	return c;
+	return UA_SUCCESS;
 }
 
-static void Service_Browse_getBrowseResult(Namespace *ns,UA_BrowseDescription *browseDescription,
+/* is this a relevant reference? */
+static inline UA_Boolean Service_Browse_returnReference(UA_BrowseDescription *browseDescription, UA_ReferenceNode* reference,
+														UA_NodeId *relevantRefTypes, UA_UInt32 relevantRefTypesCount) {
+	if (reference->isInverse == UA_TRUE && browseDescription->browseDirection == UA_BROWSEDIRECTION_FORWARD)
+		return UA_FALSE;
+	else if (reference->isInverse == UA_FALSE && browseDescription->browseDirection == UA_BROWSEDIRECTION_INVERSE)
+		return UA_FALSE;
+	for(UA_UInt32 i = 0; i<relevantRefTypesCount;i++) {
+		if(UA_NodeId_equal(&browseDescription->referenceTypeId, &relevantRefTypes[i]) == UA_EQUAL)
+			return UA_TRUE;
+	}
+	return UA_FALSE;
+}
+
+/* Return results to a single browsedescription. */
+static void Service_Browse_getBrowseResult(Namespace *ns, UA_BrowseDescription *browseDescription,
 										   UA_UInt32 maxReferences, UA_BrowseResult *browseResult) {
 	const UA_Node* node;
 	Namespace_Entry_Lock *lock;
@@ -68,18 +139,28 @@ static void Service_Browse_getBrowseResult(Namespace *ns,UA_BrowseDescription *b
 	if(maxReferences == 0)
 		maxReferences = node->referencesSize;
 
+	// discover the relevant subtypes
+	UA_NodeId *relevantReferenceTypes;
+	UA_UInt32 relevantReferenceTypesCount;
+	if(!browseDescription->includeSubtypes ||
+	   findSubReferenceTypes(ns, &browseDescription->referenceTypeId, &relevantReferenceTypes, &relevantReferenceTypesCount) != UA_SUCCESS) {
+		UA_alloc((void**)&relevantReferenceTypes, sizeof(UA_NodeId));
+		UA_NodeId_copy(&browseDescription->referenceTypeId, relevantReferenceTypes);
+		relevantReferenceTypesCount = 1;
+	}
+
 	/* We do not use a linked list but traverse the nodes references list twice
 	 * (once for counting, once for generating the referencedescriptions). That
 	 * is much faster than using a linked list, since the references are
 	 * allocated in a continuous blob and RAM access is predictible/does not
-	 * miss cache lines so often. */
+	 * miss cache lines so often. TODO: measure with some huge objects! */
 	UA_UInt32 refs = 0;
 	for(UA_Int32 i=0;i < node->referencesSize && refs <= maxReferences;i++) {
-		if(Service_Browse_returnReference(browseDescription, &node->references[i]))
+		if(Service_Browse_returnReference(browseDescription, &node->references[i], relevantReferenceTypes, relevantReferenceTypesCount))
 			refs++;
 	}
 
-	// can we return all relevant references in one go?
+	// can we return all relevant references at once?
 	UA_Boolean finished = UA_TRUE;
 	if(refs > maxReferences) {
 		refs--;
@@ -90,7 +171,7 @@ static void Service_Browse_getBrowseResult(Namespace *ns,UA_BrowseDescription *b
 	UA_Array_new((void**) &browseResult->references, refs, &UA_.types[UA_REFERENCEDESCRIPTION]);
 	
 	for(UA_UInt32 i = 0, j=0; j < refs; i++) {
-		if(!Service_Browse_returnReference(browseDescription, &node->references[i]))
+		if(!Service_Browse_returnReference(browseDescription, &node->references[i], relevantReferenceTypes, relevantReferenceTypesCount))
 			continue;
 		
 		if(Service_Browse_getReferenceDescription(ns, &node->references[i], browseDescription->nodeClassMask,
@@ -104,6 +185,7 @@ static void Service_Browse_getBrowseResult(Namespace *ns,UA_BrowseDescription *b
 	}
 	
 	Namespace_Entry_Lock_release(lock);
+	UA_Array_delete(relevantReferenceTypes, relevantReferenceTypesCount, &UA_.types[UA_NODEID]);
 }
 
 UA_Int32 Service_Browse(SL_Channel *channel, const UA_BrowseRequest *request, UA_BrowseResponse *response) {