Parcourir la source

added missing files

FlorianPalm il y a 10 ans
Parent
commit
9ba0818789

+ 17 - 0
src/server/nodestore/open62541_nodestore.c

@@ -0,0 +1,17 @@
+/*
+ * open62541_nodestore.c
+ *
+ *  Created on: Oct 27, 2014
+ *      Author: opcua
+ */
+
+#include "open62541_nodestore.h"
+static UA_NodeStoreExample *open62541_nodestore;
+
+void Nodestore_set(UA_NodeStoreExample *nodestore){
+	open62541_nodestore = nodestore;
+}
+
+UA_NodeStoreExample *Nodestore_get(){
+	return open62541_nodestore;
+}

+ 28 - 0
src/server/nodestore/open62541_nodestore.h

@@ -0,0 +1,28 @@
+/*
+ * open62541_nodestore.h
+ *
+ *  Created on: Oct 27, 2014
+ *      Author: opcua
+ */
+
+#ifndef OPEN62541_NODESTORE_H_
+#define OPEN62541_NODESTORE_H_
+
+
+
+
+#include "ua_server.h"
+
+
+void UA_EXPORT Nodestore_set(UA_NodeStoreExample *nodestore);
+UA_NodeStoreExample UA_EXPORT *Nodestore_get();
+
+
+UA_Int32 UA_EXPORT open62541NodeStore_ReadNodes(UA_ReadValueId *readValueIds,UA_UInt32 *indices,UA_UInt32 indicesSize,UA_DataValue *readNodesResults, UA_Boolean timeStampToReturn, UA_DiagnosticInfo *diagnosticInfos);
+UA_Int32 UA_EXPORT open62541NodeStore_BrowseNodes(UA_BrowseDescription *browseDescriptions,UA_UInt32 *indices,UA_UInt32 indicesSize, UA_UInt32 requestedMaxReferencesPerNode,
+		UA_BrowseResult *browseResults,
+		UA_DiagnosticInfo *diagnosticInfos);
+UA_Int32 UA_EXPORT open62541Nodestore_addNodes(UA_AddNodesItem *nodesToAdd,UA_UInt32 *indices,
+		UA_UInt32 indicesSize, UA_AddNodesResult* addNodesResults,
+		UA_DiagnosticInfo *diagnosticInfos);
+#endif /* OPEN62541_NODESTORE_H_ */

+ 349 - 0
src/server/nodestore/open62541_nodestore_attribute.c

@@ -0,0 +1,349 @@
+/*
+ * nodestore_attribute.c
+ *
+ *  Created on: Oct 27, 2014
+ *      Author: opcua
+ */
+#include "ua_nodestoreExample.h"
+#include "../ua_services.h"
+#include "open62541_nodestore.h"
+#include "ua_namespace_0.h"
+
+
+#define CHECK_NODECLASS(CLASS)                                 \
+    if(!(node->nodeClass & (CLASS))) {                         \
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE; \
+        v.status       = UA_STATUSCODE_BADNOTREADABLE;         \
+        break;                                                 \
+    }                                                          \
+
+static UA_DataValue service_read_node(UA_Server *server, const UA_ReadValueId *id) {
+    UA_DataValue v;
+    UA_DataValue_init(&v);
+
+    UA_Node const *node   = UA_NULL;
+    UA_NodeStoreExample *ns =  Nodestore_get();
+    UA_Int32       result = UA_NodeStoreExample_get(ns, &(id->nodeId), &node);
+    if(result != UA_STATUSCODE_GOOD || node == UA_NULL) {
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
+        v.status       = UA_STATUSCODE_BADNODEIDUNKNOWN;
+        return v;
+    }
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+
+    switch(id->attributeId) {
+    case UA_ATTRIBUTEID_NODEID:
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_NODEID], &node->nodeId);
+        break;
+
+    case UA_ATTRIBUTEID_NODECLASS:
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_INT32], &node->nodeClass);
+        break;
+
+    case UA_ATTRIBUTEID_BROWSENAME:
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_QUALIFIEDNAME], &node->browseName);
+        break;
+
+    case UA_ATTRIBUTEID_DISPLAYNAME:
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_LOCALIZEDTEXT],
+                                          &node->displayName);
+        break;
+
+    case UA_ATTRIBUTEID_DESCRIPTION:
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_LOCALIZEDTEXT],
+                                          &node->description);
+        break;
+
+    case UA_ATTRIBUTEID_WRITEMASK:
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_UINT32], &node->writeMask);
+        break;
+
+    case UA_ATTRIBUTEID_USERWRITEMASK:
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_UINT32], &node->userWriteMask);
+        break;
+
+    case UA_ATTRIBUTEID_ISABSTRACT:
+        CHECK_NODECLASS(
+            UA_NODECLASS_REFERENCETYPE | UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE |
+            UA_NODECLASS_DATATYPE);
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |=
+            UA_Variant_copySetValue(&v.value, &UA_[UA_BOOLEAN],
+                                    &((UA_ReferenceTypeNode *)node)->isAbstract);
+        break;
+
+    case UA_ATTRIBUTEID_SYMMETRIC:
+        CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_BOOLEAN],
+                                          &((UA_ReferenceTypeNode *)node)->symmetric);
+        break;
+
+    case UA_ATTRIBUTEID_INVERSENAME:
+        CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_LOCALIZEDTEXT],
+                                          &((UA_ReferenceTypeNode *)node)->inverseName);
+        break;
+
+    case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
+        CHECK_NODECLASS(UA_NODECLASS_VIEW);
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_BOOLEAN],
+                                          &((UA_ViewNode *)node)->containsNoLoops);
+        break;
+
+    case UA_ATTRIBUTEID_EVENTNOTIFIER:
+        CHECK_NODECLASS(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_BYTE],
+                                          &((UA_ViewNode *)node)->eventNotifier);
+        break;
+
+    case UA_ATTRIBUTEID_VALUE:
+        CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copy(&((UA_VariableNode *)node)->value, &v.value); // todo: zero-copy
+        break;
+
+    case UA_ATTRIBUTEID_DATATYPE:
+        CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_NODEID],
+                                          &((UA_VariableTypeNode *)node)->dataType);
+        break;
+
+    case UA_ATTRIBUTEID_VALUERANK:
+        CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_INT32],
+                                          &((UA_VariableTypeNode *)node)->valueRank);
+        break;
+
+    case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
+        CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        UA_Variant_copySetArray(&v.value, &UA_[UA_UINT32],
+                                ((UA_VariableTypeNode *)node)->arrayDimensionsSize,
+                                &((UA_VariableTypeNode *)node)->arrayDimensions);
+        break;
+
+    case UA_ATTRIBUTEID_ACCESSLEVEL:
+        CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_BYTE],
+                                          &((UA_VariableNode *)node)->accessLevel);
+        break;
+
+    case UA_ATTRIBUTEID_USERACCESSLEVEL:
+        CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_BYTE],
+                                          &((UA_VariableNode *)node)->userAccessLevel);
+        break;
+
+    case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
+        CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_DOUBLE],
+                                          &((UA_VariableNode *)node)->minimumSamplingInterval);
+        break;
+
+    case UA_ATTRIBUTEID_HISTORIZING:
+        CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_BOOLEAN],
+                                          &((UA_VariableNode *)node)->historizing);
+        break;
+
+    case UA_ATTRIBUTEID_EXECUTABLE:
+        CHECK_NODECLASS(UA_NODECLASS_METHOD);
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_BOOLEAN],
+                                          &((UA_MethodNode *)node)->executable);
+        break;
+
+    case UA_ATTRIBUTEID_USEREXECUTABLE:
+        CHECK_NODECLASS(UA_NODECLASS_METHOD);
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+        retval |= UA_Variant_copySetValue(&v.value, &UA_[UA_BOOLEAN],
+                                          &((UA_MethodNode *)node)->userExecutable);
+        break;
+
+    default:
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
+        v.status       = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
+        break;
+    }
+
+    UA_NodeStoreExample_releaseManagedNode(node);
+
+    if(retval != UA_STATUSCODE_GOOD) {
+        v.encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
+        v.status       = UA_STATUSCODE_BADNOTREADABLE;
+    }
+
+
+    return v;
+}
+
+UA_Int32 open62541NodeStore_ReadNodes(UA_ReadValueId *readValueIds,UA_UInt32 *indices,UA_UInt32 indicesSize,UA_DataValue *readNodesResults, UA_Boolean timeStampToReturn, UA_DiagnosticInfo *diagnosticInfos)
+{
+	for(UA_UInt32 i = 0; i< indicesSize; i++){
+			service_read_node(UA_NULL,&readValueIds[indices[i]]);
+	}
+	return UA_STATUSCODE_GOOD;
+}
+
+
+static UA_StatusCode Service_Write_writeNode(UA_NodeStoreExample *nodestore, UA_WriteValue *writeValue) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    const UA_Node *node;
+    retval = UA_NodeStoreExample_get(nodestore, &writeValue->nodeId, &node);
+    if(retval)
+        return retval;
+
+    switch(writeValue->attributeId) {
+    case UA_ATTRIBUTEID_NODEID:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){ } */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_NODECLASS:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){ } */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_BROWSENAME:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_DISPLAYNAME:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_DESCRIPTION:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_WRITEMASK:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_USERWRITEMASK:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_ISABSTRACT:
+
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_SYMMETRIC:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_INVERSENAME:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_EVENTNOTIFIER:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_VALUE:
+        if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT) {
+            retval |= UA_Variant_copy(&writeValue->value.value, &((UA_VariableNode *)node)->value); // todo: zero-copy
+        }
+        break;
+
+
+    case UA_ATTRIBUTEID_DATATYPE:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_VALUERANK:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_ACCESSLEVEL:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_USERACCESSLEVEL:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_HISTORIZING:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_EXECUTABLE:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    case UA_ATTRIBUTEID_USEREXECUTABLE:
+        /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
+        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        break;
+
+    default:
+        retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
+        break;
+    }
+
+    UA_NodeStoreExample_releaseManagedNode(node);
+    return retval;
+
+}
+
+//void Service_Write(UA_Server *server, UA_Session *session,
+//                   const UA_WriteRequest *request, UA_WriteResponse *response) {
+ //   UA_assert(server != UA_NULL && session != UA_NULL && request != UA_NULL && response != UA_NULL);
+//
+    //if(UA_Array_new((void **)&response->results, request->nodesToWriteSize, &UA_[UA_STATUSCODE])) {
+    //    response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
+    //    return;
+    //}
+
+   // response->resultsSize = request->nodesToWriteSize;
+   // for(UA_Int32 i = 0;i < request->nodesToWriteSize;i++)
+     //   response->results[i] = Service_Write_writeNode(server, &request->nodesToWrite[i]);
+//}

+ 223 - 0
src/server/nodestore/open62541_nodestore_nodemanagement.c

@@ -0,0 +1,223 @@
+/*
+ * open62541_nodestore_nodemanagement.c
+ *
+ *  Created on: Oct 27, 2014
+ *      Author: opcua
+ */
+#include "ua_nodestoreExample.h"
+#include "../ua_services.h"
+#include "open62541_nodestore.h"
+#include "ua_namespace_0.h"
+#include "ua_util.h"
+/*
+
+    // ReferenceType Ids
+    UA_ExpandedNodeId RefTypeId_References; NS0EXPANDEDNODEID(RefTypeId_References, 31);
+    UA_ExpandedNodeId RefTypeId_NonHierarchicalReferences; NS0EXPANDEDNODEID(RefTypeId_NonHierarchicalReferences, 32);
+    UA_ExpandedNodeId RefTypeId_HierarchicalReferences; NS0EXPANDEDNODEID(RefTypeId_HierarchicalReferences, 33);
+    UA_ExpandedNodeId RefTypeId_HasChild; NS0EXPANDEDNODEID(RefTypeId_HasChild, 34);
+    UA_ExpandedNodeId RefTypeId_Organizes; NS0EXPANDEDNODEID(RefTypeId_Organizes, 35);
+    UA_ExpandedNodeId RefTypeId_HasEventSource; NS0EXPANDEDNODEID(RefTypeId_HasEventSource, 36);
+    UA_ExpandedNodeId RefTypeId_HasModellingRule; NS0EXPANDEDNODEID(RefTypeId_HasModellingRule, 37);
+    UA_ExpandedNodeId RefTypeId_HasEncoding; NS0EXPANDEDNODEID(RefTypeId_HasEncoding, 38);
+    UA_ExpandedNodeId RefTypeId_HasDescription; NS0EXPANDEDNODEID(RefTypeId_HasDescription, 39);
+    UA_ExpandedNodeId RefTypeId_HasTypeDefinition; NS0EXPANDEDNODEID(RefTypeId_HasTypeDefinition, 40);
+    UA_ExpandedNodeId RefTypeId_GeneratesEvent; NS0EXPANDEDNODEID(RefTypeId_GeneratesEvent, 41);
+    UA_ExpandedNodeId RefTypeId_Aggregates; NS0EXPANDEDNODEID(RefTypeId_Aggregates, 44);
+    UA_ExpandedNodeId RefTypeId_HasSubtype; NS0EXPANDEDNODEID(RefTypeId_HasSubtype, 45);
+    UA_ExpandedNodeId RefTypeId_HasProperty; NS0EXPANDEDNODEID(RefTypeId_HasProperty, 46);
+    UA_ExpandedNodeId RefTypeId_HasComponent; NS0EXPANDEDNODEID(RefTypeId_HasComponent, 47);
+    UA_ExpandedNodeId RefTypeId_HasNotifier; NS0EXPANDEDNODEID(RefTypeId_HasNotifier, 48);
+    UA_ExpandedNodeId RefTypeId_HasOrderedComponent; NS0EXPANDEDNODEID(RefTypeId_HasOrderedComponent, 49);
+    UA_ExpandedNodeId RefTypeId_HasModelParent; NS0EXPANDEDNODEID(RefTypeId_HasModelParent, 50);
+    UA_ExpandedNodeId RefTypeId_FromState; NS0EXPANDEDNODEID(RefTypeId_FromState, 51);
+    UA_ExpandedNodeId RefTypeId_ToState; NS0EXPANDEDNODEID(RefTypeId_ToState, 52);
+    UA_ExpandedNodeId RefTypeId_HasCause; NS0EXPANDEDNODEID(RefTypeId_HasCause, 53);
+    UA_ExpandedNodeId RefTypeId_HasEffect; NS0EXPANDEDNODEID(RefTypeId_HasEffect, 54);
+    UA_ExpandedNodeId RefTypeId_HasHistoricalConfiguration; NS0EXPANDEDNODEID(RefTypeId_HasHistoricalConfiguration, 56);
+
+*/
+UA_Int32 open62541NodeStore_addReferences(UA_AddReferencesItem* referencesToAdd,
+		UA_UInt32 *indices,UA_UInt32 indicesSize, UA_StatusCode *addReferencesResults,
+		UA_DiagnosticInfo *diagnosticInfos)
+{
+
+	for(UA_UInt32 i = 0;i<indicesSize;i++){
+		UA_Node *node = UA_NULL;
+		UA_NodeStoreExample *ns = Nodestore_get();
+		UA_NodeStoreExample_get((const UA_NodeStoreExample*)ns,(const UA_NodeId*)&referencesToAdd[indices[i]].sourceNodeId, (const UA_Node**)&node);
+		if(node == UA_NULL){
+			addReferencesResults[indices[i]] = UA_STATUSCODE_BADSOURCENODEIDINVALID;
+			continue;
+		}
+	    // TODO: Check if reference already exists
+	    UA_Int32 count = node->referencesSize;
+	    UA_ReferenceNode *old_refs = node->references;
+	    UA_ReferenceNode *new_refs;
+	    if(count < 0) count = 0;
+
+	    if(!(new_refs = UA_alloc(sizeof(UA_ReferenceNode)*(count+1))))
+	        return UA_STATUSCODE_BADOUTOFMEMORY;
+
+	    UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
+
+	    UA_ReferenceNode *reference;
+	    UA_ReferenceNode_new(&reference);
+
+	    reference->isInverse = !referencesToAdd[indices[i]].isForward;
+	    UA_NodeId_copy(&referencesToAdd[indices[i]].referenceTypeId,&reference->referenceTypeId);
+	    UA_ExpandedNodeId_copy(&referencesToAdd[indices[i]].targetNodeId,&reference->targetId);
+
+	    if(UA_ReferenceNode_copy(reference, &new_refs[count]) != UA_STATUSCODE_GOOD) {
+	        UA_free(new_refs);
+	        addReferencesResults[indices[i]] = UA_STATUSCODE_BADOUTOFMEMORY;
+	    }
+	    node->references     = new_refs;
+	    node->referencesSize = count+1;
+	    UA_free(old_refs);
+	    addReferencesResults[indices[i]] =  UA_STATUSCODE_GOOD;
+	    UA_ReferenceNode_delete(reference); //FIXME to be removed
+	    //TODO fill diagnostic info if needed
+	}
+
+	return UA_STATUSCODE_GOOD;
+}
+
+UA_Int32 open62541Nodestore_addNodes(UA_AddNodesItem *nodesToAdd,UA_UInt32 *indices,
+		UA_UInt32 indicesSize, UA_AddNodesResult* addNodesResults,
+		UA_DiagnosticInfo *diagnosticInfos){
+
+	UA_Node *node = UA_NULL;
+	for(UA_UInt32 i=0;i<indicesSize;i++){
+		UA_NodeStoreExample *ns = Nodestore_get();
+		UA_NodeStoreExample_get((const UA_NodeStoreExample*)ns, (const UA_NodeId*)&nodesToAdd[indices[i]].requestedNewNodeId.nodeId , (const UA_Node**)&node);
+		if(node==UA_NULL){
+			switch(nodesToAdd[indices[i]].nodeClass){
+				case UA_NODECLASS_DATATYPE:
+				{
+					break;
+				}
+				case UA_NODECLASS_METHOD:
+				{
+
+					break;
+				}
+				case UA_NODECLASS_OBJECT:
+				{
+					UA_ObjectNode *newNode;
+					UA_ObjectNode_new(&newNode);
+					newNode->nodeId    = nodesToAdd[indices[i]].requestedNewNodeId.nodeId;
+					newNode->nodeClass = nodesToAdd[indices[i]].nodeClass;
+					UA_QualifiedName_copy(&nodesToAdd[indices[i]].browseName, &newNode->browseName);
+
+					UA_UInt32 offset = 0;
+					UA_ObjectAttributes objType;
+
+					UA_ObjectAttributes_decodeBinary(&nodesToAdd[indices[i]].nodeAttributes.body,&offset,&objType);
+					if(objType.specifiedAttributes & UA_ATTRIBUTEID_DISPLAYNAME){
+						UA_LocalizedText_copy(&objType.displayName, &newNode->displayName);
+					}
+
+					if(objType.specifiedAttributes & UA_ATTRIBUTEID_DESCRIPTION){
+						UA_LocalizedText_copy(&objType.description, &newNode->description);
+					}
+					if(objType.specifiedAttributes & UA_ATTRIBUTEID_EVENTNOTIFIER){
+						newNode->eventNotifier =  objType.eventNotifier;
+					}
+					if(objType.specifiedAttributes & UA_ATTRIBUTEID_WRITEMASK){
+						newNode->writeMask = objType.writeMask;
+					}
+
+					UA_AddReferencesItem addRefItem;
+					addRefItem.isForward = UA_TRUE;
+
+					addRefItem.referenceTypeId = nodesToAdd[indices[i]].referenceTypeId;
+					addRefItem.sourceNodeId =  nodesToAdd[indices[i]].parentNodeId.nodeId;
+					addRefItem.targetNodeId.nodeId = newNode->nodeId;
+					addRefItem.targetNodeId.namespaceUri.length = 0;
+					addRefItem.targetServerUri.length = 0;
+					addRefItem.targetNodeClass = newNode->nodeClass;
+
+					UA_UInt32 ind = 0;
+					UA_UInt32 indSize = 1;
+					UA_StatusCode result;
+					UA_DiagnosticInfo diagnosticInfo;
+					UA_NodeStoreExample_insert(ns, (UA_Node**)&newNode, UA_NODESTORE_INSERT_UNIQUE);
+					if(!(
+							nodesToAdd[indices[i]].requestedNewNodeId.nodeId.identifier.numeric == 84 &&
+							nodesToAdd[indices[i]].requestedNewNodeId.nodeId.namespaceIndex ==  0)){
+						open62541NodeStore_addReferences(&addRefItem, &ind, indSize, &result, &diagnosticInfo);
+					}
+					break;
+				}
+				case UA_NODECLASS_OBJECTTYPE:
+				{
+
+					break;
+				}
+				case UA_NODECLASS_REFERENCETYPE:
+				{
+					UA_ReferenceTypeNode *newNode;
+					UA_ReferenceTypeNode_new(&newNode);
+					newNode->nodeId    = nodesToAdd[indices[i]].requestedNewNodeId.nodeId;
+					newNode->nodeClass = nodesToAdd[indices[i]].nodeClass;
+					UA_QualifiedName_copy(&nodesToAdd[indices[i]].browseName, &newNode->browseName);
+					UA_UInt32 offset = 0;
+					UA_ReferenceTypeAttributes refType;
+					UA_ReferenceTypeAttributes_decodeBinary(&nodesToAdd[indices[i]].nodeAttributes.body,&offset,&refType);
+					if(refType.specifiedAttributes & UA_ATTRIBUTEID_DISPLAYNAME){
+						UA_LocalizedText_copy(&refType.displayName, &newNode->displayName);
+					}
+
+					if(refType.specifiedAttributes & UA_ATTRIBUTEID_DESCRIPTION){
+						UA_LocalizedText_copy(&refType.description, &newNode->description);
+					}
+
+					if(refType.specifiedAttributes & UA_ATTRIBUTEID_ISABSTRACT){
+						newNode->isAbstract = refType.isAbstract;
+					}
+
+					if(refType.specifiedAttributes & UA_ATTRIBUTEID_SYMMETRIC){
+						newNode->symmetric = refType.symmetric;
+					}
+					//ADDREFERENCE(haschild, RefTypeId_HasSubtype, UA_TRUE, RefTypeId_HierarchicalReferences);
+
+					UA_AddReferencesItem addRefItem;
+					addRefItem.isForward = UA_TRUE;
+
+					addRefItem.referenceTypeId = nodesToAdd[indices[i]].referenceTypeId;
+					addRefItem.sourceNodeId =  nodesToAdd[indices[i]].parentNodeId.nodeId;
+					addRefItem.targetNodeId.nodeId = newNode->nodeId;
+					addRefItem.targetNodeId.namespaceUri.length = 0;
+					addRefItem.targetServerUri.length = 0;
+					addRefItem.targetNodeClass = newNode->nodeClass;
+
+					UA_UInt32 ind = 0;
+					UA_UInt32 indSize = 1;
+					UA_StatusCode result;
+					UA_DiagnosticInfo diagnosticInfo;
+					UA_NodeStoreExample_insert(ns, (UA_Node**)&newNode, UA_NODESTORE_INSERT_UNIQUE);
+					open62541NodeStore_addReferences(&addRefItem, &ind, indSize, &result, &diagnosticInfo);
+
+
+					break;
+				}
+				case UA_NODECLASS_VARIABLE:
+				{
+
+					break;
+				}
+				case UA_NODECLASS_VARIABLETYPE:
+				{
+
+					break;
+				}
+				default:
+				{
+					break;
+				}
+			}
+		}
+	}
+	return UA_STATUSCODE_GOOD;
+}

+ 213 - 0
src/server/nodestore/open62541_nodestore_view.c

@@ -0,0 +1,213 @@
+/*
+ * service_view_implementation.c
+ *
+ *  Created on: Oct 27, 2014
+ *      Author: opcua
+ */
+#include "ua_nodestoreExample.h"
+#include "../ua_services.h"
+#include "open62541_nodestore.h"
+#include "../ua_services.h"
+#include "ua_namespace_0.h"
+#include "ua_util.h"
+
+UA_Int32 Service_Browse_getReferenceDescription(UA_NodeStoreExample *ns, UA_ReferenceNode *reference,
+                                                UA_UInt32 nodeClassMask, UA_UInt32 resultMask,
+                                                UA_ReferenceDescription *referenceDescription) {
+    const UA_Node *foundNode;
+    if(UA_NodeStoreExample_get(ns, &reference->targetId.nodeId, &foundNode) != UA_STATUSCODE_GOOD)
+    	return UA_STATUSCODE_BADINTERNALERROR;
+
+    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)) { */
+    if(resultMask & UA_BROWSERESULTMASK_REFERENCETYPEID)
+        UA_NodeId_copy(&reference->referenceTypeId, &referenceDescription->referenceTypeId);
+    if(resultMask & UA_BROWSERESULTMASK_ISFORWARD)
+        referenceDescription->isForward = !reference->isInverse;
+    if(resultMask & UA_BROWSERESULTMASK_NODECLASS)
+        UA_NodeClass_copy(&foundNode->nodeClass, &referenceDescription->nodeClass);
+    if(resultMask & UA_BROWSERESULTMASK_BROWSENAME)
+        UA_QualifiedName_copy(&foundNode->browseName, &referenceDescription->browseName);
+    if(resultMask & UA_BROWSERESULTMASK_DISPLAYNAME)
+        UA_LocalizedText_copy(&foundNode->displayName, &referenceDescription->displayName);
+    if(resultMask & UA_BROWSERESULTMASK_TYPEDEFINITION) {
+        if(foundNode->nodeClass != UA_NODECLASS_OBJECT &&
+           foundNode->nodeClass != UA_NODECLASS_VARIABLE)
+            goto end;
+
+        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);
+                goto end;
+            }
+        }
+    }
+ end:
+    UA_NodeStoreExample_releaseManagedNode(foundNode);
+    return UA_STATUSCODE_GOOD;
+}
+
+/* singly-linked list */
+struct SubRefTypeId {
+    UA_NodeId id;
+    SLIST_ENTRY(SubRefTypeId) next;
+};
+SLIST_HEAD(SubRefTypeIdList, SubRefTypeId);
+
+static UA_UInt32 walkReferenceTree(UA_NodeStoreExample *ns, const UA_ReferenceTypeNode *current,
+                                   struct SubRefTypeIdList *list) {
+    // insert the current referencetype
+    struct SubRefTypeId *element = UA_alloc(sizeof(struct SubRefTypeId));
+    element->id = current->nodeId;
+    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;
+            if(UA_NodeStoreExample_get(ns, &current->references[i].targetId.nodeId, &node) == UA_STATUSCODE_GOOD
+               && node->nodeClass == UA_NODECLASS_REFERENCETYPE) {
+                count += walkReferenceTree(ns, (UA_ReferenceTypeNode *)node, list);
+                UA_NodeStoreExample_releaseManagedNode(node);
+            }
+        }
+    }
+    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(UA_NodeStoreExample *ns, UA_NodeId *rootReferenceType,
+                                      UA_NodeId **ids, UA_UInt32 *idcount) {
+    struct SubRefTypeIdList list;
+    UA_UInt32 count;
+    SLIST_INIT(&list);
+
+    // walk the tree
+    const UA_ReferenceTypeNode *root;
+
+    if(UA_NodeStoreExample_get(ns, rootReferenceType, (const UA_Node **)&root) != UA_STATUSCODE_GOOD ||
+       root->nodeClass != UA_NODECLASS_REFERENCETYPE)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    count = walkReferenceTree(ns, root, &list);
+    UA_NodeStoreExample_releaseManagedNode((const UA_Node *)root);
+
+    // copy results into an array
+    *ids = UA_alloc(sizeof(UA_NodeId)*count);
+    for(UA_UInt32 i = 0;i < count;i++) {
+        struct SubRefTypeId *element = SLIST_FIRST(&list);
+        UA_NodeId_copy(&element->id, &(*ids)[i]);
+        SLIST_REMOVE_HEAD(&list, next);
+        UA_free(element);
+    }
+    *idcount = count;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+/* 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 NodeStore_Browse_getBrowseResult(UA_NodeStoreExample         *ns,
+                                           UA_BrowseDescription *browseDescription,
+                                           UA_UInt32             maxReferences,
+                                           UA_BrowseResult      *browseResult) {
+    const UA_Node *node;
+    UA_NodeId     *relevantReferenceTypes = UA_NULL;
+    UA_UInt32      relevantReferenceTypesCount = 0;
+    if(UA_NodeStoreExample_get(ns, &browseDescription->nodeId, &node) != UA_STATUSCODE_GOOD) {
+        browseResult->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
+        return;
+    }
+
+    // 0 => unlimited references
+    if(maxReferences == 0)
+        maxReferences = node->referencesSize;
+
+    // discover the relevant subtypes
+    if(!browseDescription->includeSubtypes ||
+       findSubReferenceTypes(ns, &browseDescription->referenceTypeId, &relevantReferenceTypes,
+                             &relevantReferenceTypesCount) != UA_STATUSCODE_GOOD) {
+        if(!(relevantReferenceTypes = UA_alloc(sizeof(UA_NodeId)))) {
+            return;
+        }
+        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. 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], relevantReferenceTypes,
+                                          relevantReferenceTypesCount))
+            refs++;
+    }
+
+    // can we return all relevant references at once?
+    UA_Boolean finished = UA_TRUE;
+    if(refs > maxReferences) {
+        refs--;
+        finished = UA_FALSE;
+    }
+
+    browseResult->referencesSize = refs;
+    UA_Array_new((void **)&browseResult->references, refs, &UA_[UA_REFERENCEDESCRIPTION]);
+
+    for(UA_UInt32 i = 0, j = 0;j < refs;i++) {
+        if(!Service_Browse_returnReference(browseDescription, &node->references[i], relevantReferenceTypes,
+                                           relevantReferenceTypesCount))
+            continue;
+
+        if(Service_Browse_getReferenceDescription(ns, &node->references[i], browseDescription->nodeClassMask,
+                                                  browseDescription->resultMask, &browseResult->references[j]) != UA_STATUSCODE_GOOD)
+            browseResult->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
+        j++;
+    }
+
+    if(!finished) {
+        // Todo. Set the Statuscode and the continuation point.
+    }
+
+    UA_NodeStoreExample_releaseManagedNode(node);
+    UA_Array_delete(relevantReferenceTypes, relevantReferenceTypesCount, &UA_[UA_NODEID]);
+}
+
+UA_Int32 open62541NodeStore_BrowseNodes(UA_BrowseDescription *browseDescriptions,UA_UInt32 *indices,UA_UInt32 indicesSize, UA_UInt32 requestedMaxReferencesPerNode,
+		UA_BrowseResult *browseResults,
+		UA_DiagnosticInfo *diagnosticInfos){
+
+
+	for(UA_UInt32 i = 0; i < indicesSize; i++){
+		NodeStore_Browse_getBrowseResult(Nodestore_get(),&browseDescriptions[indices[i]],requestedMaxReferencesPerNode, &browseResults[indices[i]]);
+	}
+	return UA_STATUSCODE_GOOD;
+}