|
@@ -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;
|
|
|
}
|
|
|
-
|