public static bool ValueChanged(
DataValue value,
ServiceResult error,
DataValue lastValue,
ServiceResult lastError,
DataChangeFilter filter,
double range)
{
if (value == null) throw new ArgumentNullException("value");
// select default data change filters.
double deadband = 0.0;
DeadbandType deadbandType = DeadbandType.None;
DataChangeTrigger trigger = DataChangeTrigger.StatusValue;
// apply filter.
if (filter != null)
{
trigger = filter.Trigger;
deadbandType = (DeadbandType)(int)filter.DeadbandType;
deadband = filter.DeadbandValue;
// when deadband is used and the trigger is StatusValueTimestamp, then it should behave as if trigger is StatusValue.
if ((deadbandType != DeadbandType.None) && (trigger == DataChangeTrigger.StatusValueTimestamp))
{
trigger = DataChangeTrigger.StatusValue;
}
}
// get the current status.
uint status = StatusCodes.Good;
if (error != null)
{
status = error.StatusCode.Code;
}
else if (lastValue != null)
{
status = value.StatusCode.Code;
}
// get the last status.
uint lastStatus = StatusCodes.Good;
if (lastError != null)
{
lastStatus = lastError.StatusCode.Code;
}
else if (lastValue != null)
{
lastStatus = lastValue.StatusCode.Code;
}
// value changed if any status change occurrs.
if (status != lastStatus)
{
return true;
}
// value changed if only one is null.
if (value == null || lastValue == null)
{
return lastValue != null || value != null;
}
// check if timestamp has changed.
if (trigger == DataChangeTrigger.StatusValueTimestamp)
{
if (lastValue.SourceTimestamp != value.SourceTimestamp)
{
return true;
}
}
// check if value changes are ignored.
if (trigger == DataChangeTrigger.Status)
{
return false;
}
// check if reference to same object.
if (!Equals(lastValue.Value, value.Value, deadbandType, deadband, range))
{
return true;
}
// must be equal.
return false;
}