Procházet zdrojové kódy

finish basic read service

Julius Pfrommer před 11 roky
rodič
revize
91c4f810ee
3 změnil soubory, kde provedl 147 přidání a 84 odebrání
  1. 5 0
      include/ua_basictypes.h
  2. 38 1
      src/ua_basictypes.c
  3. 104 83
      src/ua_services_attribute.c

+ 5 - 0
include/ua_basictypes.h

@@ -240,6 +240,11 @@ typedef struct UA_Variant {
 } UA_Variant;
 UA_TYPE_METHOD_PROTOTYPES (UA_Variant)
 
+UA_Int32 UA_Variant_setValue(UA_Variant *v, UA_Int32 type, const void* data); // Take care! Data is freed together with the Variant
+UA_Int32 UA_Variant_copySetValue(UA_Variant *v, UA_Int32 type, const void* data);
+UA_Int32 UA_Variant_setArray(UA_Variant *v, UA_Int32 type, UA_Int32 arrayLength, const void* data); // Take care! Data is freed together with the Variant
+UA_Int32 UA_Variant_copySetArray(UA_Variant *v, UA_Int32 type_id, UA_Int32 arrayLength, UA_UInt32 elementSize, const void* array);
+
 /* String - Part: 6, Chapter: 5.2.2.4, Page: 16 */
 typedef struct UA_String
 {

+ 38 - 1
src/ua_basictypes.c

@@ -8,7 +8,7 @@
 
 static inline UA_Int32 UA_VTable_isValidType(UA_Int32 type) {
 	if(type < 0 /* UA_BOOLEAN */ || type > 271 /* UA_INVALID */)
-		return UA_ERROR;
+		return UA_INVALIDTYPE;
 	return UA_SUCCESS;
 }
 
@@ -1529,6 +1529,43 @@ UA_Int32 UA_Variant_copy(UA_Variant const *src, UA_Variant *dst)
 	return retval;
 }
 
+UA_Int32 UA_Variant_setValue(UA_Variant *v, UA_Int32 type_id, const void* value) {
+	v->encodingMask = type_id & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK;
+	if(UA_VTable_isValidType(type_id) != UA_SUCCESS) return UA_INVALIDTYPE;
+	v->vt = &UA_[type_id];
+	v->data = (void*) value;
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_Variant_copySetValue(UA_Variant *v, UA_Int32 type_id, const void* value) {
+	v->encodingMask = type_id & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK;
+	if(UA_VTable_isValidType(type_id) != UA_SUCCESS) return UA_INVALIDTYPE;
+	v->vt = &UA_[type_id];
+	return v->vt->copy(value, v->data);
+}
+
+UA_Int32 UA_Variant_setArray(UA_Variant *v, UA_Int32 type_id, UA_Int32 arrayLength, const void* array) {
+	v->encodingMask = (type_id & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK) | UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
+	if(UA_VTable_isValidType(type_id) != UA_SUCCESS) return UA_INVALIDTYPE;
+	v->vt = &UA_[type_id];
+	v->arrayLength = arrayLength;
+	v->data = (void*) array;
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_Variant_copySetArray(UA_Variant *v, UA_Int32 type_id, UA_Int32 arrayLength, UA_UInt32 elementSize, const void* array) {
+	v->encodingMask = (type_id & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK) | UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
+	if(UA_VTable_isValidType(type_id) != UA_SUCCESS) return UA_INVALIDTYPE;
+	v->vt = &UA_[type_id];
+	v->arrayLength = arrayLength;
+	void *new_arr;
+	UA_Int32 retval = UA_SUCCESS;
+	retval |= UA_alloc(&new_arr, arrayLength * elementSize);
+	retval |= UA_memcpy(new_arr, array, arrayLength * elementSize);
+	v->data = new_arr;
+	return UA_SUCCESS;
+}
+
 //TODO: place this define at the server configuration
 #define MAX_PICO_SECONDS 1000
 UA_Int32 UA_DataValue_decodeBinary(UA_ByteString const * src, UA_Int32* pos, UA_DataValue* dst) {

+ 104 - 83
src/ua_services_attribute.c

@@ -26,163 +26,184 @@ enum UA_AttributeId {
 	UA_ATTRIBUTEID_USEREXECUTABLE = 22
 };
 
-static UA_DataValue * service_read_node(Application *app, const UA_ReadValueId *id) {
-	UA_DataValue *v; UA_DataValue_new(&v);
-	
-	DBG(printf("service_read_node - entered with ns=%d,id=%d,attr=%i\n",id->nodeId.namespace, id->nodeId.identifier.numeric, id->attributeId));
+#define CHECK_NODECLASS(CLASS) do {									\
+		if((node->nodeClass & (CLASS)) != 0x00) {					\
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;		\
+			v->status = UA_STATUSCODE_BADNOTREADABLE;				\
+		}															\
+		break;														\
+	} while(0)
+
+static UA_DataValue *service_read_node(Application * app, const UA_ReadValueId * id) {
+	UA_DataValue *v;
+	UA_DataValue_new(&v);
+
+	DBG(printf("service_read_node - entered with ns=%d,id=%d,attr=%i\n", id->nodeId.namespace, id->nodeId.identifier.numeric, id->attributeId));
 	Namespace *ns = UA_indexedList_findValue(app->namespaces, id->nodeId.namespace);
 
-	if (ns == UA_NULL) {
-		DBG_VERBOSE(printf("service_read_node - unknown namespace %d\n",id->nodeId.namespace));
+	if(ns == UA_NULL) {
+		DBG_VERBOSE(printf("service_read_node - unknown namespace %d\n", id->nodeId.namespace));
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
 		return v;
 	}
-	DBG_VERBOSE(UA_String_printf(",namespaceUri=",&(ns->namespaceUri)));
-	
+	DBG_VERBOSE(UA_String_printf(",namespaceUri=", &(ns->namespaceUri)));
+
 	UA_Node const *node = UA_NULL;
 	Namespace_Lock *lock = UA_NULL;
-	DBG_VERBOSE(UA_NodeId_printf("service_read_node - search for ",&(id->nodeId)));
+
+	DBG_VERBOSE(UA_NodeId_printf("service_read_node - search for ", &(id->nodeId)));
 	UA_Int32 result = Namespace_get(ns, &(id->nodeId), &node, &lock);
 	if(result != UA_SUCCESS || node == UA_NULL) {
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
 		return v;
 	}
-	DBG_VERBOSE(UA_NodeId_printf("service_read_node - found node=",&(node->nodeId)));
+	DBG_VERBOSE(UA_NodeId_printf("service_read_node - found node=", &(node->nodeId)));
 
-	switch(id->attributeId) {
+	UA_Int32 retval = UA_SUCCESS;
+
+	switch (id->attributeId) {
 	case UA_ATTRIBUTEID_NODEID:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_NODEID, &node->nodeId);
 		break;
 	case UA_ATTRIBUTEID_NODECLASS:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_UINT32, &node->nodeClass);
 		break;
 	case UA_ATTRIBUTEID_BROWSENAME:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_QUALIFIEDNAME, &node->browseName);
 		break;
 	case UA_ATTRIBUTEID_DISPLAYNAME:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_LOCALIZEDTEXT, &node->displayName);
 		break;
 	case UA_ATTRIBUTEID_DESCRIPTION:
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADNOTREADABLE;
 		break;
 	case UA_ATTRIBUTEID_WRITEMASK:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_UINT32, &node->writeMask);
 		break;
 	case UA_ATTRIBUTEID_USERWRITEMASK:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_UINT32, &node->userWriteMask);
 		break;
 	case UA_ATTRIBUTEID_ISABSTRACT:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_ReferenceTypeNode *) node)->isAbstract);
 		break;
 	case UA_ATTRIBUTEID_SYMMETRIC:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_ReferenceTypeNode *) node)->symmetric);
 		break;
 	case UA_ATTRIBUTEID_INVERSENAME:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_LOCALIZEDTEXT, &((UA_ReferenceTypeNode *) node)->inverseName);
 		break;
 	case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VIEW);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_ViewNode *) node)->containsNoLoops);
 		break;
 	case UA_ATTRIBUTEID_EVENTNOTIFIER:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VIEW);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BYTE, &((UA_ViewNode *) node)->eventNotifier);
 		break;
 	case UA_ATTRIBUTEID_VALUE:
-		if (node->nodeClass != UA_NODECLASS_VARIABLE) {
-			v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-			v->status = UA_STATUSCODE_BADNOTREADABLE;
-			break;
-		}
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE | UA_DATAVALUE_ENCODINGMASK_VARIANT;
-		v->status = UA_STATUSCODE_GOOD;
-
-		// be careful not to release the node before encoding the message
-
-		UA_VariableNode * vn = (UA_VariableNode*) node;
-		// FIXME: delete will be called later on on on all the members of v, so essentially
-		// the item's data will be removed from the namespace-object. We would need
-		// something like a deep copy function just as we have it for the strings
-		// UA_Variant_copy(UA_Variant* src, UA_Variant* dst);
-
-		// FIXME: mockup code - we know that for 2255 we simply need to copy the array
-		if (node->nodeId.identifier.numeric == 2255) {
-			v->value = vn->value;
-			UA_Array_copy((void const*const*)vn->value.data,vn->value.arrayLength,UA_ns0ToVTableIndex(vn->value.vt->ns0Id),(void***)&v->value.data);
-		} else {
-			v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-			v->status = UA_STATUSCODE_BADNOTREADABLE;
-		}
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copy(&((UA_VariableNode *) node)->value, &v->value);
 		break;
 	case UA_ATTRIBUTEID_DATATYPE:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_NODEID, &((UA_VariableTypeNode *) node)->dataType);
 		break;
 	case UA_ATTRIBUTEID_VALUERANK:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_INT32, &((UA_VariableTypeNode *) node)->valueRank);
 		break;
 	case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		UA_Variant_copySetArray(&v->value, UA_UINT32, ((UA_VariableTypeNode *) node)->arrayDimensionsSize, sizeof(UA_UInt32),
+								&((UA_VariableTypeNode *) node)->arrayDimensions);
 		break;
 	case UA_ATTRIBUTEID_ACCESSLEVEL:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BYTE, &((UA_VariableNode *) node)->accessLevel);
 		break;
 	case UA_ATTRIBUTEID_USERACCESSLEVEL:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BYTE, &((UA_VariableNode *) node)->userAccessLevel);
 		break;
 	case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_DOUBLE, &((UA_VariableNode *) node)->minimumSamplingInterval);
 		break;
 	case UA_ATTRIBUTEID_HISTORIZING:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_VariableNode *) node)->historizing);
 		break;
 	case UA_ATTRIBUTEID_EXECUTABLE:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_METHOD);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_MethodNode *) node)->executable);
 		break;
 	case UA_ATTRIBUTEID_USEREXECUTABLE:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_METHOD);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_MethodNode *) node)->userExecutable);
 		break;
 	default:
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
 		break;
 	}
+
 	Namespace_Lock_release(lock);
+
+	if(retval != UA_SUCCESS) {
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
+		v->status = UA_STATUSCODE_BADNOTREADABLE;
+	}
+
 	return v;
 }
 
-UA_Int32 Service_Read(SL_Channel *channel, const UA_ReadRequest *request, UA_ReadResponse *response ) {
-	if(channel->session == UA_NULL || channel->session->application == UA_NULL) return UA_ERROR; // TODO: Return error message
+UA_Int32 Service_Read(SL_Channel * channel, const UA_ReadRequest * request, UA_ReadResponse * response) {
+	if(channel->session == UA_NULL || channel->session->application == UA_NULL)
+		return UA_ERROR;	// TODO: Return error message
+
+	int readsize = request->nodesToReadSize;
+	/* NothingTodo */
+	if(readsize <= 0) {
+		response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
+		response->resultsSize = 0;
+		return UA_SUCCESS;
+	}
 
-	int readsize = request->nodesToReadSize > 0 ? request->nodesToReadSize : 0;
 	response->resultsSize = readsize;
-	UA_alloc((void **)&response->results, sizeof(void *)*readsize);
-	for(int i=0;i<readsize;i++) {
-		DBG_VERBOSE(printf("service_read - attributeId=%d\n",request->nodesToRead[i]->attributeId));
-		DBG_VERBOSE(UA_NodeId_printf("service_read - nodeId=",&(request->nodesToRead[i]->nodeId)));
+	UA_alloc((void **)&response->results, sizeof(void *) * readsize);
+	for(int i = 0; i < readsize; i++) {
+		DBG_VERBOSE(printf("service_read - attributeId=%d\n", request->nodesToRead[i]->attributeId));
+		DBG_VERBOSE(UA_NodeId_printf("service_read - nodeId=", &(request->nodesToRead[i]->nodeId)));
 		response->results[i] = service_read_node(channel->session->application, request->nodesToRead[i]);
 	}
+	response->responseHeader.serviceResult = UA_STATUSCODE_GOOD;
 	response->diagnosticInfosSize = -1;
 	return UA_SUCCESS;
 }
-