protected virtual StatusCode ValidateMonitoringFilter(
ServerSystemContext context,
NodeHandle handle,
uint attributeId,
double samplingInterval,
uint queueSize,
ExtensionObject filter,
out MonitoringFilter filterToUse,
out Range range,
out MonitoringFilterResult result)
{
range = null;
filterToUse = null;
result = null;
// nothing to do if the filter is not specified.
if (ExtensionObject.IsNull(filter))
{
return StatusCodes.Good;
}
// extension objects wrap any data structure. must check that the client provided the correct structure.
DataChangeFilter deadbandFilter = ExtensionObject.ToEncodeable(filter) as DataChangeFilter;
if (deadbandFilter == null)
{
AggregateFilter aggregateFilter = ExtensionObject.ToEncodeable(filter) as AggregateFilter;
if (aggregateFilter == null || attributeId != Attributes.Value)
{
return StatusCodes.BadFilterNotAllowed;
}
if (!Server.AggregateManager.IsSupported(aggregateFilter.AggregateType))
{
return StatusCodes.BadAggregateNotSupported;
}
ServerAggregateFilter revisedFilter = new ServerAggregateFilter();
revisedFilter.AggregateType = aggregateFilter.AggregateType;
revisedFilter.StartTime = aggregateFilter.StartTime;
revisedFilter.ProcessingInterval = aggregateFilter.ProcessingInterval;
revisedFilter.AggregateConfiguration = aggregateFilter.AggregateConfiguration;
revisedFilter.Stepped = false;
StatusCode error = ReviseAggregateFilter(context, handle, samplingInterval, queueSize, revisedFilter);
if (StatusCode.IsBad(error))
{
return error;
}
AggregateFilterResult aggregateFilterResult = new AggregateFilterResult();
aggregateFilterResult.RevisedProcessingInterval = aggregateFilter.ProcessingInterval;
aggregateFilterResult.RevisedStartTime = aggregateFilter.StartTime;
aggregateFilterResult.RevisedAggregateConfiguration = aggregateFilter.AggregateConfiguration;
filterToUse = revisedFilter;
result = aggregateFilterResult;
return StatusCodes.Good;
}
// deadband filters only allowed for variable values.
if (attributeId != Attributes.Value)
{
return StatusCodes.BadFilterNotAllowed;
}
BaseVariableState variable = handle.Node as BaseVariableState;
if (variable == null)
{
return StatusCodes.BadFilterNotAllowed;
}
// check for status filter.
if (deadbandFilter.DeadbandType == (uint)DeadbandType.None)
{
filterToUse = deadbandFilter;
return StatusCodes.Good;
}
// deadband filters can only be used for numeric values.
if (!Server.TypeTree.IsTypeOf(variable.DataType, DataTypeIds.Number))
{
return StatusCodes.BadFilterNotAllowed;
}
// nothing more to do for absolute filters.
if (deadbandFilter.DeadbandType == (uint)DeadbandType.Absolute)
{
filterToUse = deadbandFilter;
return StatusCodes.Good;
}
// need to look up the EU range if a percent filter is requested.
if (deadbandFilter.DeadbandType == (uint)DeadbandType.Percent)
{
PropertyState property = handle.Node.FindChild(context, Opc.Ua.BrowseNames.EURange) as PropertyState;
if (property == null)
{
return StatusCodes.BadMonitoredItemFilterUnsupported;
}
range = property.Value as Range;
if (range == null)
{
return StatusCodes.BadMonitoredItemFilterUnsupported;
}
filterToUse = deadbandFilter;
return StatusCodes.Good;
}
// no other type of filter supported.
return StatusCodes.BadFilterNotAllowed;
}