Bläddra i källkod

write datatype

Julius Pfrommer 8 år sedan
förälder
incheckning
84b587caa6
1 ändrade filer med 95 tillägg och 49 borttagningar
  1. 95 49
      src/server/ua_services_attribute.c

+ 95 - 49
src/server/ua_services_attribute.c

@@ -500,38 +500,67 @@ UA_Server_editNode(UA_Server *server, UA_Session *session,
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode
-writeToDataSource(UA_Server *server, UA_Session *session,
-                  const UA_VariableNode *node, const UA_WriteValue *wvalue) {
-    if(!node->value.dataSource.write)
-        return UA_STATUSCODE_BADWRITENOTSUPPORTED;
+enum type_equivalence {
+    TYPE_EQUIVALENCE_NONE,
+    TYPE_EQUIVALENCE_ENUM,
+    TYPE_EQUIVALENCE_OPAQUE
+};
 
-    UA_NumericRange *rangeptr = NULL;
-    UA_NumericRange range;
-    UA_StatusCode retval;
+static const UA_VariableTypeNode *
+getVariableType(UA_Server *server, const UA_VariableNode *node) {
+    /* The reference to the parent is different for variable and variabletype */ 
+    UA_NodeId parentRef;
+    UA_Boolean inverse;
+    if(node->nodeClass == UA_NODECLASS_VARIABLE) {
+        parentRef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
+        inverse = false;
+    } else {
+        parentRef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
+        inverse = true;
+    }
 
-    /* Parse the range */
-    if(wvalue->indexRange.length > 0) {
-        retval = parse_numericrange(&wvalue->indexRange, &range);
-        if(retval != UA_STATUSCODE_GOOD)
-            return retval;
-        rangeptr = ⦥
+    /* stop at the first matching candidate */
+    UA_NodeId *parentId = NULL;
+    for(size_t i = 0; i < node->referencesSize; i++) {
+        if(node->references[i].isInverse == inverse &&
+           UA_NodeId_equal(&node->references[i].referenceTypeId, &parentRef)) {
+            parentId = &node->references[i].targetId.nodeId;
+            break;
+        }
     }
 
-    /* Write into the datasource */
-    retval = node->value.dataSource.write(node->value.dataSource.handle,
-                                          node->nodeId, &wvalue->value.value,
-                                          rangeptr);
-    if(rangeptr)
-        UA_free(range.dimensions);
-    return retval;
+    const UA_Node *parent = UA_NodeStore_get(server->nodestore, parentId);
+    if(!parent || parent->nodeClass != UA_NODECLASS_VARIABLETYPE)
+        return NULL;
+    return (const UA_VariableTypeNode*)parent;
 }
 
-enum type_equivalence {
-    TYPE_EQUIVALENCE_NONE,
-    TYPE_EQUIVALENCE_ENUM,
-    TYPE_EQUIVALENCE_OPAQUE
-};
+static UA_StatusCode
+writeDataTypeAttribute(UA_Server *server, UA_VariableNode *node,
+                       const UA_NodeId *dataType) {
+    const UA_VariableNode *vt = (const UA_VariableNode*)getVariableType(server, node);
+    if(!vt)
+        return UA_STATUSCODE_BADINTERNALERROR; /* should never happen */
+
+    const UA_NodeId *vtDataType = &vt->dataType;
+    UA_NodeId subtypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
+    UA_Boolean found = false;
+    UA_StatusCode retval = isNodeInTree(server->nodestore, dataType,
+                                        vtDataType, &subtypeId,
+                                        1, 10, &found);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    if(!found)
+        retval = UA_STATUSCODE_BADTYPEMISMATCH;
+    UA_NodeId dtCopy = node->dataType;
+    retval = UA_NodeId_copy(dataType, &node->dataType);
+    if(!retval) {
+        node->dataType = dtCopy;
+        return retval;
+    }
+    UA_NodeId_deleteMembers(&dtCopy);
+    return UA_STATUSCODE_GOOD; 
+}
 
 const UA_DataType *
 findDataType(const UA_NodeId *typeId) {
@@ -558,7 +587,7 @@ static enum type_equivalence typeEquivalence(const UA_DataType *t) {
  * contains the correct definition (NODELETE, pointing to the members of the
  * original value, so do not delete) */
 static UA_StatusCode
-matchValueWithNodeDefinition(UA_Server *server, UA_VariableNode *node,
+matchValueWithNodeDefinition(UA_Server *server, const UA_VariableNode *node,
                              const UA_Variant *value, const UA_NumericRange *range,
                              UA_Variant *equivalent) {
     /* Prepare the output variant */
@@ -608,7 +637,7 @@ matchValueWithNodeDefinition(UA_Server *server, UA_VariableNode *node,
         }
 
         /* An enum was sent as an int32, or an opaque type as a bytestring. This
-         * is detected with the typeIndex indicated the "true" datatype. */
+         * is detected with the typeIndex indicating the "true" datatype. */
         enum type_equivalence te1 = typeEquivalence(nodeDataType);
         enum type_equivalence te2 = typeEquivalence(valueDataType);
         if(te1 != TYPE_EQUIVALENCE_NONE && te1 == te2) {
@@ -688,19 +717,27 @@ writeValueAttribute(UA_Server *server, UA_VariableNode *node,
     }
 
     /* write the value */
-    if(!rangeptr)
-        retval = UA_DataValue_copy(value, &node->value.data.value);
-    else
-        retval = UA_Variant_setRangeCopy(&node->value.data.value.value,
-                                         value->value.data, value->value.arrayLength, range);
+    if(node->valueSource == UA_VALUESOURCE_DATA) {
+        if(!rangeptr)
+            retval = UA_DataValue_copy(value, &node->value.data.value);
+        else
+            retval = UA_Variant_setRangeCopy(&node->value.data.value.value,
+                                             value->value.data,
+                                             value->value.arrayLength, range);
+        /* post-write callback */
+        if(retval == UA_STATUSCODE_GOOD && node->value.data.callback.onWrite)
+            node->value.data.callback.onWrite(node->value.data.callback.handle, node->nodeId,
+                                              &node->value.data.value.value, rangeptr);
+    } else {
+        /* TODO: Don't make a copy of the node in the multithreaded case */
+        retval = node->value.dataSource.write(node->value.dataSource.handle, node->nodeId,
+                                              &value->value, rangeptr);
+    }
 
-    /* post-write callback */
-    if(retval == UA_STATUSCODE_GOOD && node->value.data.callback.onWrite)
-        node->value.data.callback.onWrite(node->value.data.callback.handle, node->nodeId,
-                                          &node->value.data.value.value, rangeptr);
  cleanup:
     if(rangeptr)
         UA_free(range.dimensions);
+
     return retval;
 }
 
@@ -751,8 +788,7 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
     switch(wvalue->attributeId) {
     case UA_ATTRIBUTEID_NODEID:
     case UA_ATTRIBUTEID_NODECLASS:
-    case UA_ATTRIBUTEID_DATATYPE:
-        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+        retval = UA_STATUSCODE_BADNOTWRITABLE;
         break;
     case UA_ATTRIBUTEID_BROWSENAME:
         CHECK_DATATYPE(QUALIFIEDNAME);
@@ -804,14 +840,24 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
         break;
     case UA_ATTRIBUTEID_VALUE:
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        if(((const UA_VariableNode*)node)->valueSource == UA_VALUESOURCE_DATA)
-            retval = writeValueAttribute(server, (UA_VariableNode*)node,
-                                         &wvalue->value, &wvalue->indexRange);
-        else
-            /* TODO: Don't make a copy of the node in the multithreaded case */
-            /* TODO: Check if the type matches also for data sources */
-            retval = writeToDataSource(server, session,
-                                       (const UA_VariableNode*)node, wvalue);
+        retval = writeValueAttribute(server, (UA_VariableNode*)node, &wvalue->value, &wvalue->indexRange);
+        break;
+    case UA_ATTRIBUTEID_DATATYPE:
+        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+        CHECK_DATATYPE(NODEID);
+        /* TODO: Check if the current value remains valid */
+        retval = writeDataTypeAttribute(server, (UA_VariableNode*)node, (const UA_NodeId*)value);
+        break;
+    case UA_ATTRIBUTEID_VALUERANK:
+        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+        CHECK_DATATYPE(INT32);
+        /* TODO */
+        retval = UA_STATUSCODE_BADNOTWRITABLE;
+        break;
+    case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
+        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+        /* TODO */
+        retval = UA_STATUSCODE_BADNOTWRITABLE;
         break;
     case UA_ATTRIBUTEID_ACCESSLEVEL:
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
@@ -848,8 +894,8 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
         break;
     }
     if(retval != UA_STATUSCODE_GOOD)
-        UA_LOG_DEBUG_SESSION(server->config.logger, session,
-                             "WriteRequest returned status code 0x%08x", retval);
+        UA_LOG_INFO_SESSION(server->config.logger, session,
+                            "WriteRequest returned status code 0x%08x", retval);
     return retval;
 }