private bool VerifyInitialDataChange(
Subscription subscription,
DataChangeNotification notification,
DateTime receiveTime,
IList<MonitoredItem> monitoredItems,
ref int totalCount,
Dictionary<uint,MonitoredItem> updatedItems)
{
bool success = true;
bool errorReported = false;
// determine the maximum requested diagnostics.
uint diagnosticsMask = 0;
DiagnosticInfoCollection diagnosticInfos = notification.DiagnosticInfos;
for (int ii = 0; ii < notification.MonitoredItems.Count; ii++)
{
totalCount++;
MonitoredItemNotification update = notification.MonitoredItems[ii];
// find matching item.
MonitoredItem monitoredItem = null;
for (int jj = 0; jj < monitoredItems.Count; jj++)
{
monitoredItem = monitoredItems[jj];
if (update.ClientHandle == monitoredItem.ClientHandle)
{
MonitoredItem existingItem = null;
if (updatedItems.TryGetValue(update.ClientHandle, out existingItem))
{
Log(
"Unexpected notification returned from server for MonitoredItem. ClientHandle = {0}, Node = {1}, Attribute = {2}, NewValue = {3}, OldValue={4}",
update.ClientHandle,
monitoredItem.Node,
Attributes.GetBrowseName(monitoredItem.AttributeId),
update.Value.WrappedValue,
existingItem.Value.Value);
}
updatedItems[update.ClientHandle] = monitoredItem;
break;
}
monitoredItem = null;
}
if (monitoredItem == null)
{
Log(
"Unexpected notification returned from server for Node. ClientHandle = {0}, Value = {1}",
update.ClientHandle,
update.Value.WrappedValue);
success = false;
break;
}
if (monitoredItem.Value != null)
{
Log(
"Duplicate notification for MonitoredItem for Node {0}. NodeId = {1}, AttributeId = {2}",
monitoredItem.Node,
monitoredItem.Node.NodeId,
Attributes.GetBrowseName(monitoredItem.AttributeId));
success = false;
break;
}
double initialDelay = CalculateInterval(monitoredItem.UpdateTime, receiveTime);
if (initialDelay > subscription.PublishingInterval + m_idealTimingError)
{
bool fatal = initialDelay > subscription.PublishingInterval*2;
if (!errorReported)
{
Log(
"{0}: Late notification for MonitoredItem for Node {1}. NodeId = {2}, AttributeId = {3}, Delay = {4}ms, MaxDelay = {5}ms",
"TIMING ERROR",
monitoredItem.Node,
monitoredItem.Node.NodeId,
Attributes.GetBrowseName(monitoredItem.AttributeId),
initialDelay,
subscription.PublishingInterval);
errorReported = true;
}
if (fatal)
{
success = false;
break;
}
}
monitoredItem.Value = update.Value;
// verify timestamps.
if (!VerifyTimestamps(monitoredItem.Node, monitoredItem.AttributeId, monitoredItem.TimestampsToReturn, update.Value))
{
success = false;
break;
}
// check if diagnostics could exist.
if (update.Value.StatusCode != StatusCodes.Good)
{
diagnosticsMask |= monitoredItem.DiagnosticsMasks;
if ((monitoredItem.DiagnosticsMasks & (uint)DiagnosticsMasks.OperationAll) != 0)
{
if (diagnosticInfos == null || diagnosticInfos.Count < ii || diagnosticInfos[ii] == null)
{
Log(
"Missing DiagnosticInfo for MonitoredItem for Node {0}. NodeId = {1}, AttributeId = {2}",
monitoredItem.Node,
monitoredItem.Node.NodeId,
Attributes.GetBrowseName(monitoredItem.AttributeId));
success = false;
break;
}
}
}
// verify error.
if (StatusCode.IsBad(update.Value.StatusCode))
{
if (!VerifyBadAttribute(monitoredItem.Node, monitoredItem.AttributeId, update.Value.StatusCode))
{
success = false;
break;
}
continue;
}
// verify success.
if (!VerifyGoodAttribute(monitoredItem.Node, monitoredItem.AttributeId, update.Value))
{
success = false;
break;
}
}
// check for unnecessary diagnostics.
if ((diagnosticsMask & (uint)DiagnosticsMasks.OperationAll) == 0)
{
if (diagnosticInfos != null && diagnosticInfos.Count > 0)
{
Log("Returned non-empty DiagnosticInfos array during Publish.");
return false;
}
}
return success;
}