Kaynağa Gözat

Subscriptions: Improve ModifyMonitoredItem for switching filters on/off

Julius Pfrommer 6 yıl önce
ebeveyn
işleme
eea27e5733
1 değiştirilmiş dosya ile 28 ekleme ve 16 silme
  1. 28 16
      src/server/ua_services_subscription.c

+ 28 - 16
src/server/ua_services_subscription.c

@@ -159,11 +159,7 @@ static UA_StatusCode
 setMonitoredItemSettings(UA_Server *server, UA_MonitoredItem *mon,
                          UA_MonitoringMode monitoringMode,
                          const UA_MonitoringParameters *params,
-                         // This parameter is optional and used only if mon->lastValue is not set yet.
-                         // Then numeric type will be detected from this value. Set null as defaut.
                          const UA_DataType* dataType) {
-
-
     /* Filter */
     if(params->filter.encoding != UA_EXTENSIONOBJECT_DECODED) {
         UA_DataChangeFilter_init(&(mon->filter.dataChangeFilter));
@@ -171,17 +167,19 @@ setMonitoredItemSettings(UA_Server *server, UA_MonitoredItem *mon,
     } else if(params->filter.content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGEFILTER]) {
         UA_DataChangeFilter *filter = (UA_DataChangeFilter *)params->filter.content.decoded.data;
         // TODO implement EURange to support UA_DEADBANDTYPE_PERCENT
-        if (filter->deadbandType == UA_DEADBANDTYPE_PERCENT) {
-            return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
-        }
-        if (UA_Variant_isEmpty(&mon->lastValue)) {
-            if (!dataType || !isDataTypeNumeric(dataType))
+        switch(filter->deadbandType) {
+        case UA_DEADBANDTYPE_NONE:
+            break;
+        case UA_DEADBANDTYPE_ABSOLUTE:
+            if(!dataType || !isDataTypeNumeric(dataType))
                 return UA_STATUSCODE_BADFILTERNOTALLOWED;
-        } else
-        if (!isDataTypeNumeric(mon->lastValue.type)) {
-            return UA_STATUSCODE_BADFILTERNOTALLOWED;
+            break;
+        case UA_DEADBANDTYPE_PERCENT:
+            return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
+        default:
+            return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
         }
-        UA_DataChangeFilter_copy(filter, &(mon->filter.dataChangeFilter));
+        UA_DataChangeFilter_copy(filter, &mon->filter.dataChangeFilter);
 #ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
     } else if (params->filter.content.decoded.type == &UA_TYPES[UA_TYPES_EVENTFILTER]) {
         UA_EventFilter_copy((UA_EventFilter *)params->filter.content.decoded.data,
@@ -191,8 +189,10 @@ setMonitoredItemSettings(UA_Server *server, UA_MonitoredItem *mon,
         return UA_STATUSCODE_BADMONITOREDITEMFILTERINVALID;
     }
 
+    /* <-- The point of no return --> */
+
+    /* Unregister the callback */
     UA_MonitoredItem_unregisterSampleCallback(server, mon);
-    mon->monitoringMode = monitoringMode;
 
     /* Remove the old samples */
     UA_ByteString_deleteMembers(&mon->lastSampledValue);
@@ -234,6 +234,7 @@ setMonitoredItemSettings(UA_Server *server, UA_MonitoredItem *mon,
     mon->discardOldest = params->discardOldest;
 
     /* Register sample callback if reporting is enabled */
+    mon->monitoringMode = monitoringMode;
     if(monitoringMode == UA_MONITORINGMODE_REPORTING)
         UA_MonitoredItem_registerSampleCallback(server, mon);
     return UA_STATUSCODE_GOOD;
@@ -442,8 +443,19 @@ Operation_ModifyMonitoredItem(UA_Server *server, UA_Session *session, UA_Subscri
         result->statusCode = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
         return;
     }
-    UA_StatusCode retval;
-    retval = setMonitoredItemSettings(server, mon, mon->monitoringMode, &request->requestedParameters, NULL);
+
+    /* Read the current value to test if filters are possible.
+     * Can return an empty value (v.value.type == NULL). */
+    UA_ReadValueId rvid;
+    UA_ReadValueId_init(&rvid);
+    rvid.nodeId = mon->monitoredNodeId;
+    rvid.attributeId = mon->attributeId;
+    rvid.indexRange = mon->indexRange;
+    UA_DataValue v = UA_Server_readWithSession(server, session, &rvid, mon->timestampsToReturn);
+    UA_StatusCode retval = setMonitoredItemSettings(server, mon, mon->monitoringMode,
+                                                    &request->requestedParameters,
+                                                    v.value.type);
+    UA_DataValue_deleteMembers(&v);
     if(retval != UA_STATUSCODE_GOOD) {
         result->statusCode = retval;
         return;