|
@@ -21,8 +21,61 @@
|
|
|
|
|
|
#ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */
|
|
|
|
|
|
+#ifdef UA_ENABLE_DA
|
|
|
+
|
|
|
+/* Translate a percentage deadband into an absolute deadband based on the
|
|
|
+ * UARange property of the variable */
|
|
|
+static UA_StatusCode
|
|
|
+setAbsoluteFromPercentageDeadband(UA_Server *server, UA_Session *session,
|
|
|
+ UA_MonitoredItem *mon, UA_DataChangeFilter *filter) {
|
|
|
+ /* A valid deadband? */
|
|
|
+ if(filter->deadbandValue < 0.0 || filter->deadbandValue > 100.0)
|
|
|
+ return UA_STATUSCODE_BADDEADBANDFILTERINVALID;
|
|
|
+
|
|
|
+ /* Browse for the percent range */
|
|
|
+ UA_QualifiedName qn = UA_QUALIFIEDNAME(0, "EURange");
|
|
|
+ UA_BrowsePathResult bpr =
|
|
|
+ browseSimplifiedBrowsePath(server, mon->monitoredNodeId, 1, &qn);
|
|
|
+ if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
|
|
|
+ UA_BrowsePathResult_clear(&bpr);
|
|
|
+ return UA_STATUSCODE_BADFILTERNOTALLOWED;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Read the range */
|
|
|
+ UA_ReadValueId rvi;
|
|
|
+ UA_ReadValueId_init(&rvi);
|
|
|
+ rvi.nodeId = bpr.targets->targetId.nodeId;
|
|
|
+ rvi.attributeId = UA_ATTRIBUTEID_VALUE;
|
|
|
+ UA_DataValue rangeVal = UA_Server_readWithSession(server, session, &rvi,
|
|
|
+ UA_TIMESTAMPSTORETURN_NEITHER);
|
|
|
+ UA_BrowsePathResult_clear(&bpr);
|
|
|
+ if(!UA_Variant_isScalar(&rangeVal.value) ||
|
|
|
+ rangeVal.value.type != &UA_TYPES[UA_TYPES_RANGE]) {
|
|
|
+ UA_DataValue_clear(&rangeVal);
|
|
|
+ return UA_STATUSCODE_BADFILTERNOTALLOWED;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Compute the abs deadband */
|
|
|
+ UA_Range* euRange = (UA_Range*)rangeVal.value.data;
|
|
|
+ UA_Double absDeadband =
|
|
|
+ (filter->deadbandValue/100.0) * (euRange->high - euRange->low);
|
|
|
+
|
|
|
+ /* EURange invalid or NaN? */
|
|
|
+ if(absDeadband < 0.0 || absDeadband != absDeadband) {
|
|
|
+ UA_DataValue_clear(&rangeVal);
|
|
|
+ return UA_STATUSCODE_BADFILTERNOTALLOWED;
|
|
|
+ }
|
|
|
+
|
|
|
+ mon->filter.dataChangeFilter.trigger = filter->trigger;
|
|
|
+ mon->filter.dataChangeFilter.deadbandType = UA_DEADBANDTYPE_ABSOLUTE;
|
|
|
+ mon->filter.dataChangeFilter.deadbandValue = absDeadband;
|
|
|
+ return UA_STATUSCODE_GOOD;
|
|
|
+}
|
|
|
+
|
|
|
+#endif /* UA_ENABLE_DA */
|
|
|
+
|
|
|
static UA_StatusCode
|
|
|
-setMonitoredItemSettings(UA_Server *server, UA_MonitoredItem *mon,
|
|
|
+setMonitoredItemSettings(UA_Server *server, UA_Session *session, UA_MonitoredItem *mon,
|
|
|
UA_MonitoringMode monitoringMode,
|
|
|
const UA_MonitoringParameters *params,
|
|
|
const UA_DataType* dataType) {
|
|
@@ -53,20 +106,27 @@ setMonitoredItemSettings(UA_Server *server, UA_MonitoredItem *mon,
|
|
|
mon->filter.dataChangeFilter.trigger = UA_DATACHANGETRIGGER_STATUSVALUE;
|
|
|
} 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
|
|
|
switch(filter->deadbandType) {
|
|
|
case UA_DEADBANDTYPE_NONE:
|
|
|
+ mon->filter.dataChangeFilter = *filter;
|
|
|
break;
|
|
|
case UA_DEADBANDTYPE_ABSOLUTE:
|
|
|
if(!dataType || !UA_DataType_isNumeric(dataType))
|
|
|
return UA_STATUSCODE_BADFILTERNOTALLOWED;
|
|
|
+ mon->filter.dataChangeFilter = *filter;
|
|
|
break;
|
|
|
case UA_DEADBANDTYPE_PERCENT:
|
|
|
+#ifdef UA_ENABLE_DA
|
|
|
+ if(!dataType || !UA_DataType_isNumeric(dataType))
|
|
|
+ return UA_STATUSCODE_BADFILTERNOTALLOWED;
|
|
|
+ retval = setAbsoluteFromPercentageDeadband(server, session, mon, filter);
|
|
|
+ break;
|
|
|
+#else
|
|
|
return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
|
|
|
+#endif
|
|
|
default:
|
|
|
return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
|
|
|
}
|
|
|
- retval = UA_DataChangeFilter_copy(filter, &mon->filter.dataChangeFilter);
|
|
|
} else {
|
|
|
return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
|
|
|
}
|
|
@@ -214,7 +274,7 @@ Operation_CreateMonitoredItem(UA_Server *server, UA_Session *session, struct cre
|
|
|
UA_StatusCode retval = UA_STATUSCODE_GOOD;
|
|
|
retval |= UA_NodeId_copy(&request->itemToMonitor.nodeId, &newMon->monitoredNodeId);
|
|
|
retval |= UA_String_copy(&request->itemToMonitor.indexRange, &newMon->indexRange);
|
|
|
- retval |= setMonitoredItemSettings(server, newMon, request->monitoringMode,
|
|
|
+ retval |= setMonitoredItemSettings(server, session, newMon, request->monitoringMode,
|
|
|
&request->requestedParameters, v.value.type);
|
|
|
UA_DataValue_clear(&v);
|
|
|
if(retval != UA_STATUSCODE_GOOD) {
|
|
@@ -353,7 +413,7 @@ Operation_ModifyMonitoredItem(UA_Server *server, UA_Session *session, UA_Subscri
|
|
|
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,
|
|
|
+ UA_StatusCode retval = setMonitoredItemSettings(server, session, mon, mon->monitoringMode,
|
|
|
&request->requestedParameters,
|
|
|
v.value.type);
|
|
|
UA_DataValue_clear(&v);
|