/// <summary> /// Creates a new set of monitored items for a set of variables. /// </summary> /// <remarks> /// This method only handles data change subscriptions. Event subscriptions are created by the SDK. /// </remarks> protected override ServiceResult CreateMonitoredItem(ServerSystemContext context, NodeHandle handle, uint subscriptionId, double publishingInterval, DiagnosticsMasks diagnosticsMasks, TimestampsToReturn timestampsToReturn, MonitoredItemCreateRequest itemToCreate, ref long globalIdCounter, out MonitoringFilterResult filterResult, out IMonitoredItem monitoredItem) { filterResult = null; monitoredItem = null; // validate parameters. MonitoringParameters parameters = itemToCreate.RequestedParameters; // validate attribute. if (!Attributes.IsValid(handle.Node.NodeClass, itemToCreate.ItemToMonitor.AttributeId)) { return StatusCodes.BadAttributeIdInvalid; } NodeState cachedNode = AddNodeToComponentCache(context, handle, handle.Node); // check if the node is already being monitored. MonitoredNode2 monitoredNode = null; if (!MonitoredNodes.TryGetValue(handle.Node.NodeId, out monitoredNode)) { MonitoredNodes[handle.Node.NodeId] = monitoredNode = new MonitoredNode2(this, cachedNode); } handle.Node = monitoredNode.Node; handle.MonitoredNode = monitoredNode; // create a globally unique identifier. uint monitoredItemId = Utils.IncrementIdentifier(ref globalIdCounter); // determine the sampling interval. double samplingInterval = itemToCreate.RequestedParameters.SamplingInterval; if (samplingInterval < 0) { samplingInterval = publishingInterval; } // ensure minimum sampling interval is not exceeded. if (itemToCreate.ItemToMonitor.AttributeId == Attributes.Value) { BaseVariableState variable = handle.Node as BaseVariableState; if (variable != null && samplingInterval < variable.MinimumSamplingInterval) { samplingInterval = variable.MinimumSamplingInterval; } } // put a large upper limit on sampling. if (samplingInterval == Double.MaxValue) { samplingInterval = 365 * 24 * 3600 * 1000.0; } // put an upper limit on queue size. uint queueSize = itemToCreate.RequestedParameters.QueueSize; if (queueSize > MaxQueueSize) { queueSize = MaxQueueSize; } // validate the monitoring filter. Range euRange = null; MonitoringFilter filterToUse = null; ServiceResult error = ValidateMonitoringFilter( context, handle, itemToCreate.ItemToMonitor.AttributeId, samplingInterval, queueSize, parameters.Filter, out filterToUse, out euRange, out filterResult); if (ServiceResult.IsBad(error)) { return error; } // create the item. MonitoredItem datachangeItem = new ComMonitoredItem( Server, this, handle, subscriptionId, monitoredItemId, context.OperationContext.Session, itemToCreate.ItemToMonitor, diagnosticsMasks, timestampsToReturn, itemToCreate.MonitoringMode, itemToCreate.RequestedParameters.ClientHandle, filterToUse, filterToUse, euRange, samplingInterval, queueSize, itemToCreate.RequestedParameters.DiscardOldest, 0); // report the initial value. ReadInitialValue(context, handle, datachangeItem); // update monitored item list. monitoredItem = datachangeItem; // save the monitored item. MonitoredItems.Add(monitoredItemId, datachangeItem); monitoredNode.Add(datachangeItem); // report change. OnMonitoredItemCreated(context, handle, datachangeItem); return error; }
/// <summary> /// Called after subscribing/unsubscribing to events. /// </summary> /// <param name="context">The context.</param> /// <param name="monitoredNode">The monitored node.</param> /// <param name="unsubscribe">if set to <c>true</c> unsubscribing.</param> protected virtual void OnSubscribeToEvents( ServerSystemContext context, MonitoredNode2 monitoredNode, bool unsubscribe) { // defined by the sub-class }
/// <summary> /// Returns true if the system must be scanning to provide updates for the monitored item. /// </summary> private bool SystemScanRequired(MonitoredNode2 monitoredNode, IDataChangeMonitoredItem2 monitoredItem) { // ingore other types of monitored items. if (monitoredItem == null) { return false; } // only care about variables. BaseDataVariableState source = monitoredNode.Node as BaseDataVariableState; if (source == null) { return false; } // check for variables that need to be scanned. if (monitoredItem.AttributeId == Attributes.Value) { TestDataObjectState test = source.Parent as TestDataObjectState; if (test != null && test.SimulationActive.Value) { return true; } } return false; }
/// <summary> /// Subscribes to events. /// </summary> /// <param name="context">The context.</param> /// <param name="source">The source.</param> /// <param name="monitoredItem">The monitored item.</param> /// <param name="unsubscribe">if set to <c>true</c> [unsubscribe].</param> /// <returns>Any error code.</returns> protected virtual ServiceResult SubscribeToEvents( ServerSystemContext context, NodeState source, IEventMonitoredItem monitoredItem, bool unsubscribe) { MonitoredNode2 monitoredNode = null; // handle unsubscribe. if (unsubscribe) { // check for existing monitored node. if (!MonitoredNodes.TryGetValue(source.NodeId, out monitoredNode)) { return StatusCodes.BadNodeIdUnknown; } monitoredNode.Remove(monitoredItem); // check if node is no longer being monitored. if (!monitoredNode.HasMonitoredItems) { MonitoredNodes.Remove(source.NodeId); } // update flag. source.SetAreEventsMonitored(context, !unsubscribe, true); // call subclass. OnSubscribeToEvents(context, monitoredNode, unsubscribe); // all done. return ServiceResult.Good; } // only objects or views can be subscribed to. BaseObjectState instance = source as BaseObjectState; if (instance == null || (instance.EventNotifier & EventNotifiers.SubscribeToEvents) == 0) { ViewState view = source as ViewState; if (view == null || (view.EventNotifier & EventNotifiers.SubscribeToEvents) == 0) { return StatusCodes.BadNotSupported; } } // check for existing monitored node. if (!MonitoredNodes.TryGetValue(source.NodeId, out monitoredNode)) { MonitoredNodes[source.NodeId] = monitoredNode = new MonitoredNode2(this, source); } // this links the node to specified monitored item and ensures all events // reported by the node are added to the monitored item's queue. monitoredNode.Add(monitoredItem); // This call recursively updates a reference count all nodes in the notifier // hierarchy below the area. Sources with a reference count of 0 do not have // any active subscriptions so they do not need to report events. source.SetAreEventsMonitored(context, !unsubscribe, true); // signal update. OnSubscribeToEvents(context, monitoredNode, unsubscribe); // all done. return ServiceResult.Good; }