/// <summary> /// Initializes a new instance of the <see cref="ComAeSubscriptionClient"/> class. /// </summary> /// <param name="context">The context.</param> /// <param name="configuration">The configuration.</param> /// <param name="cache">The cache for known types.</param> /// <param name="namespaceIndex">The namespace index for the event types.</param> /// <param name="manager">The manager.</param> /// <param name="monitoredItem">The monitored item.</param> public ComAeSubscriptionClient( ServerSystemContext context, ComAeClientConfiguration configuration, AeTypeCache cache, ushort namespaceIndex, ComAeClientManager manager, MonitoredItem monitoredItem) { m_defaultContext = context; m_separators = configuration.SeperatorChars; m_cache = cache; m_namespaceIndex = namespaceIndex; m_manager = manager; m_refreshComplete = new ManualResetEvent(false); m_monitoredItems = new List<MonitoredItem>(); m_monitoredItems.Add(monitoredItem); m_qualifiedName = null; m_isSource = false; NodeHandle handle = monitoredItem.ManagerHandle as NodeHandle; AeAreaState area = handle.Node as AeAreaState; if (area != null) { m_qualifiedName = area.QualifiedName; m_isSource = false; } else { AeSourceState source = handle.Node as AeSourceState; if (source != null) { m_qualifiedName = source.QualifiedName; m_isSource = true; } } }
/// <summary> /// Queues the value to the monitored item. /// </summary> /// <param name="context">The context.</param> /// <param name="request">The request.</param> /// <param name="monitoredItem">The monitored item.</param> public void QueueValue(ServerSystemContext context, ReadRequest request, MonitoredItem monitoredItem) { NodeHandle handle = monitoredItem.ManagerHandle as NodeHandle; if (handle == null) { return; } ReadValueId nodeToRead = monitoredItem.GetReadValueId(); DataValue value = new DataValue(); ServiceResult error = null; // read item value. DaItemState item = handle.Node as DaItemState; DaPropertyState daProperty = handle.Node as DaPropertyState; PropertyState uaProperty = handle.Node as PropertyState; if (item != null) { error = request.GetResult(context, item, nodeToRead, value, monitoredItem.DiagnosticsMasks); } // read vendor defined property value. else if (daProperty != null) { error = request.GetResult(context, daProperty, nodeToRead, value, monitoredItem.DiagnosticsMasks); } // read UA defined property value. else if (uaProperty != null) { error = request.GetResult(context, uaProperty, nodeToRead, value, monitoredItem.DiagnosticsMasks); } value.ServerTimestamp = DateTime.UtcNow; if (value.StatusCode != StatusCodes.BadNotFound) { monitoredItem.QueueValue(value, error); } else { monitoredItem.QueueValue(value, StatusCodes.BadNodeIdUnknown); } }
/// <summary> /// Creates a new sampled item. /// </summary> private void CreateSampledItem(double samplingInterval, MonitoredItem monitoredItem) { m_sampledItems.Add(monitoredItem); if (m_samplingTimer == null) { m_samplingTimer = new Timer(DoSample, null, (int)m_minimumSamplingInterval, (int)m_minimumSamplingInterval); } }
/// <summary> /// Called after deleting a MonitoredItem. /// </summary> /// <param name="context">The context.</param> /// <param name="handle">The handle for the node.</param> /// <param name="monitoredItem">The monitored item.</param> protected override void OnMonitoredItemDeleted( ServerSystemContext context, NodeHandle handle, MonitoredItem monitoredItem) { // check if diagnostics collection needs to be turned off. if (IsDiagnosticsNode(handle.Node)) { if (monitoredItem.MonitoringMode != MonitoringMode.Disabled) { m_diagnosticsMonitoringCount--; if (m_diagnosticsMonitoringCount == 0 && m_diagnosticsScanTimer != null) { m_diagnosticsScanTimer.Dispose(); m_diagnosticsScanTimer = null; } if (m_diagnosticsScanTimer != null) { DoScan(true); } } } // check if sampling needs to be turned off. if (monitoredItem.AttributeId == Attributes.Value) { BaseVariableState variable = handle.Node as BaseVariableState; if (variable != null && variable.MinimumSamplingInterval > 0) { DeleteSampledItem(monitoredItem); } } }
/// <summary> /// Called after changing the MonitoringMode for a MonitoredItem. /// </summary> /// <param name="context">The context.</param> /// <param name="handle">The handle for the node.</param> /// <param name="monitoredItem">The monitored item.</param> /// <param name="previousMode">The previous monitoring mode.</param> /// <param name="monitoringMode">The current monitoring mode.</param> protected virtual void OnMonitoringModeChanged( ServerSystemContext context, NodeHandle handle, MonitoredItem monitoredItem, MonitoringMode previousMode, MonitoringMode monitoringMode) { // overridden by the sub-class. }
/// <summary> /// Reads the initial value for a monitored item. /// </summary> /// <param name="context">The context.</param> /// <param name="handle">The item handle.</param> /// <param name="monitoredItem">The monitored item.</param> protected virtual void ReadInitialValue( ServerSystemContext context, NodeHandle handle, MonitoredItem monitoredItem) { DataValue initialValue = new DataValue(); initialValue.Value = null; initialValue.ServerTimestamp = DateTime.UtcNow; initialValue.SourceTimestamp = DateTime.MinValue; initialValue.StatusCode = StatusCodes.BadWaitingForInitialData; ServiceResult error = handle.Node.ReadAttribute( context, monitoredItem.AttributeId, monitoredItem.IndexRange, monitoredItem.DataEncoding, initialValue); monitoredItem.QueueValue(initialValue, error); }
/// <summary> /// Called after changing the MonitoringMode for a MonitoredItem. /// </summary> /// <param name="context">The context.</param> /// <param name="handle">The handle for the node.</param> /// <param name="monitoredItem">The monitored item.</param> /// <param name="previousMode">The previous monitoring mode.</param> /// <param name="monitoringMode">The current monitoring mode.</param> protected override void OnMonitoringModeChanged( ServerSystemContext context, NodeHandle handle, MonitoredItem monitoredItem, MonitoringMode previousMode, MonitoringMode monitoringMode) { if (SystemScanRequired(handle.MonitoredNode, monitoredItem)) { BaseVariableState source = handle.Node as BaseVariableState; if (previousMode != MonitoringMode.Disabled && monitoredItem.MonitoringMode == MonitoringMode.Disabled) { m_system.StopMonitoringValue(monitoredItem.Id); } if (previousMode == MonitoringMode.Disabled && monitoredItem.MonitoringMode != MonitoringMode.Disabled) { m_system.StartMonitoringValue(monitoredItem.Id, monitoredItem.SamplingInterval, source); } } }
/// <summary> /// Called after creating a MonitoredItem. /// </summary> /// <param name="context">The context.</param> /// <param name="handle">The handle for the node.</param> /// <param name="monitoredItem">The monitored item.</param> protected override void OnMonitoredItemCreated( ServerSystemContext context, NodeHandle handle, MonitoredItem monitoredItem) { if (SystemScanRequired(handle.MonitoredNode, monitoredItem)) { if (monitoredItem.MonitoringMode != MonitoringMode.Disabled) { m_system.StartMonitoringValue( monitoredItem.Id, monitoredItem.SamplingInterval, handle.Node as BaseVariableState); } } }
/// <summary> /// Modifies the request after the specified item changes. /// </summary> /// <param name="context">The context.</param> /// <param name="monitoredItem">The monitored item.</param> public void Modify(ServerSystemContext context, MonitoredItem monitoredItem) { // nothing to do. }
/// <summary> /// Adds the specified monitored item. /// </summary> /// <param name="context">The context.</param> /// <param name="monitoredItem">The monitored item.</param> public void Add(ServerSystemContext context, MonitoredItem monitoredItem) { if (monitoredItem == null) { return; } // save the monitored item. if (m_monitoredItems == null) { m_monitoredItems = new List<MonitoredItem>(); } m_monitoredItems.Add(monitoredItem); }
/// <summary> /// Removes an item from the subscription. /// </summary> public int RemoveItem(MonitoredItem monitoredItem) { lock (m_monitoredItems) { for (int ii = 0; ii < m_monitoredItems.Count; ii++) { if (m_monitoredItems[ii].Id == monitoredItem.Id) { m_monitoredItems.RemoveAt(ii); break; } } return m_monitoredItems.Count; } }
/// <summary> /// Adds an item to a subscription. /// </summary> public void AddItem(MonitoredItem monitoredItem) { lock (m_monitoredItems) { m_monitoredItems.Add(monitoredItem); } }
/// <summary> /// Modifies the request after the specified item changes. /// </summary> /// <param name="context">The context.</param> /// <param name="monitoredItem">The monitored item.</param> public void Modify(ServerSystemContext context, MonitoredItem monitoredItem) { // re-queue the last value. if (m_lastRequest != null) { QueueValue(context, m_lastRequest, monitoredItem); } }
/// <summary> /// Adds the specified monitored item. /// </summary> /// <param name="context">The context.</param> /// <param name="monitoredItem">The monitored item.</param> public void Add(ServerSystemContext context, MonitoredItem monitoredItem) { if (monitoredItem == null) { return; } // save the monitored item. if (m_monitoredItems == null) { m_monitoredItems = new List<MonitoredItem>(); } m_monitoredItems.Add(monitoredItem); // queue the initial value. if (m_lastRequest != null) { QueueValue(context, m_lastRequest, monitoredItem); } }
/// <summary> /// Creates a set of monitored items. /// </summary> public MonitoredItem CreateMonitoredItem( OperationContext context, INodeManager nodeManager, object handle, uint subscriptionId, uint monitoredItemId, TimestampsToReturn timestampsToReturn, double publishingInterval, MonitoredItemCreateRequest itemToCreate, EventFilter filter) { lock (m_lock) { // calculate sampling interval. double samplingInterval = itemToCreate.RequestedParameters.SamplingInterval; if (samplingInterval < 0) { samplingInterval = publishingInterval; } // limit the queue size. uint queueSize = itemToCreate.RequestedParameters.QueueSize; if (queueSize > m_maxEventQueueSize) { queueSize = m_maxEventQueueSize; } // create the monitored item. MonitoredItem monitoredItem = new MonitoredItem( m_server, nodeManager, handle, subscriptionId, monitoredItemId, context.Session, itemToCreate.ItemToMonitor, context.DiagnosticsMask, timestampsToReturn, itemToCreate.MonitoringMode, itemToCreate.RequestedParameters.ClientHandle, filter, filter, null, samplingInterval, queueSize, itemToCreate.RequestedParameters.DiscardOldest, MinimumSamplingIntervals.Continuous); // save the monitored item. m_monitoredItems.Add(monitoredItemId, monitoredItem); return monitoredItem; } }
/// <summary> /// Removes the specified monitored item. /// </summary> /// <param name="context">The context.</param> /// <param name="monitoredItem">The monitored item.</param> public void Remove(ServerSystemContext context, MonitoredItem monitoredItem) { // remove the monitored item. if (monitoredItem != null && m_monitoredItems != null) { for (int ii = 0; ii < m_monitoredItems.Count; ii++) { if (Object.ReferenceEquals(m_monitoredItems[ii], monitoredItem)) { m_monitoredItems.RemoveAt(ii); break; } } } }
/// <summary> /// Sets the monitored items associated with the item. /// </summary> /// <param name="item">The item.</param> /// <param name="monitoredItems">The monitored items.</param> public void SetMonitoredItems(GroupItem item, MonitoredItem[] monitoredItems) { // check if callbacks are enabled. if (item == null || m_monitoredItems == null) { return; } // save the monitored items. lock (m_monitoredItems) { DataChangeInfo info = null; if (!m_monitoredItems.TryGetValue(item.ClientHandle, out info)) { m_monitoredItems[item.ClientHandle] = info = new DataChangeInfo(); } info.MonitoredItems = monitoredItems; // resend the last cached value. if (info.LastError != null || info.LastValue != null) { for (int ii = 0; ii < monitoredItems.Length; ii++) { monitoredItems[ii].QueueValue(info.LastValue, info.LastError); } } } }
/// <summary> /// Queues the value to the monitored item. /// </summary> /// <param name="context">The context.</param> /// <param name="request">The request.</param> /// <param name="monitoredItem">The monitored item.</param> private void QueueValue(ServerSystemContext context, HdaReadRequest request, MonitoredItem monitoredItem) { NodeHandle handle = monitoredItem.ManagerHandle as NodeHandle; if (handle == null) { return; } ReadValueId nodeToRead = monitoredItem.GetReadValueId(); DataValue value = new DataValue(); ServiceResult error = null; HdaItemState item = handle.Node as HdaItemState; HdaAttributeState attribute = handle.Node as HdaAttributeState; if (item != null) { error = request.GetResult(context, item, nodeToRead, value, monitoredItem.DiagnosticsMasks); } else if (attribute != null) { error = request.GetResult(context, attribute, nodeToRead, value, monitoredItem.DiagnosticsMasks); } value.ServerTimestamp = DateTime.UtcNow; if (value.StatusCode != StatusCodes.BadNotFound) { monitoredItem.QueueValue(value, error); } }
/// <summary> /// Called after deleting a MonitoredItem. /// </summary> /// <param name="context">The context.</param> /// <param name="handle">The handle for the node.</param> /// <param name="monitoredItem">The monitored item.</param> protected override void OnMonitoredItemDeleted( ServerSystemContext context, NodeHandle handle, MonitoredItem monitoredItem) { // check for variables that need to be scanned. if (SystemScanRequired(handle.MonitoredNode, monitoredItem)) { m_system.StopMonitoringValue(monitoredItem.Id); } }
/// <summary> /// Adds the monitored item to the collection. /// </summary> /// <param name="source">The source.</param> /// <param name="monitoredItem">The monitored item.</param> private HdaSubscribeAttributeRequest Add(NodeState source, MonitoredItem monitoredItem) { lock (m_lock) { m_monitoredItems.Add(monitoredItem.Id, monitoredItem); // get the HDA item id. string itemId = GetItemId(source); // create/update the subscribe request for the HDA item. if (itemId != null) { HdaSubscribeAttributeRequest request = FindAttributeRequest(itemId, true); if (request != null) { request.Add(m_context, monitoredItem); return request; } } return null; } }
/// <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 virtual 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; } // check if the node is already being monitored. MonitoredNode monitoredNode = null; if (!m_monitoredNodes.TryGetValue(handle.Node.NodeId, out monitoredNode)) { NodeState cachedNode = AddNodeToComponentCache(context, handle, handle.Node); m_monitoredNodes[handle.Node.NodeId] = monitoredNode = new MonitoredNode(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 > m_maxQueueSize) { queueSize = m_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 MonitoredItem( 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. m_monitoredItems.Add(monitoredItemId, datachangeItem); monitoredNode.Add(datachangeItem); // report change. OnMonitoredItemCreated(context, handle, datachangeItem); return error; }
/// <summary> /// Removes the monitored item from the collection. /// </summary> /// <param name="source">The source.</param> /// <param name="monitoredItem">The monitored item.</param> private HdaSubscribeAttributeRequest Remove(NodeState source, MonitoredItem monitoredItem) { lock (m_lock) { m_monitoredItems.Remove(monitoredItem.Id); // get the HDA item id. string itemId = GetItemId(source); // delete the subscribe request for the HDA item. if (itemId != null) { HdaSubscribeAttributeRequest request = FindAttributeRequest(itemId, false); if (request != null) { request.Remove(m_context, monitoredItem); return request; } } return null; } }
/// <summary> /// Called after deleting a MonitoredItem. /// </summary> /// <param name="context">The context.</param> /// <param name="handle">The handle for the node.</param> /// <param name="monitoredItem">The monitored item.</param> protected virtual void OnMonitoredItemDeleted( ServerSystemContext context, NodeHandle handle, MonitoredItem monitoredItem) { // overridden by the sub-class. }
/// <summary> /// Adds the specified data change monitored item. /// </summary> /// <param name="datachangeItem">The monitored item.</param> public void Add(MonitoredItem datachangeItem) { if (DataChangeMonitoredItems == null) { DataChangeMonitoredItems = new List<MonitoredItem>(); Node.OnStateChanged = OnMonitoredNodeChanged; } DataChangeMonitoredItems.Add(datachangeItem); }
/// <summary> /// Called after creating a MonitoredItem. /// </summary> /// <param name="context">The context.</param> /// <param name="handle">The handle for the node.</param> /// <param name="monitoredItem">The monitored item.</param> protected override void OnMonitoredItemCreated( ServerSystemContext context, NodeHandle handle, MonitoredItem monitoredItem) { // check if the variable needs to be sampled. if (monitoredItem.AttributeId == Attributes.Value) { BaseVariableState variable = handle.Node as BaseVariableState; if (variable != null && variable.MinimumSamplingInterval > 0) { CreateSampledItem(monitoredItem.SamplingInterval, monitoredItem); } } // check if diagnostics collection needs to be turned one. if (IsDiagnosticsNode(handle.Node)) { monitoredItem.AlwaysReportUpdates = IsDiagnosticsStructureNode(handle.Node); if (monitoredItem.MonitoringMode != MonitoringMode.Disabled) { m_diagnosticsMonitoringCount++; if (m_diagnosticsScanTimer == null) { m_diagnosticsScanTimer = new Timer(DoScan, null, 1000, 1000); } DoScan(true); } } }
/// <summary> /// Removes the specified data change monitored item. /// </summary> /// <param name="datachangeItem">The monitored item.</param> public void Remove(MonitoredItem datachangeItem) { for (int ii = 0; ii < DataChangeMonitoredItems.Count; ii++) { if (Object.ReferenceEquals(DataChangeMonitoredItems[ii], datachangeItem)) { DataChangeMonitoredItems.RemoveAt(ii); break; } } if (DataChangeMonitoredItems.Count == 0) { DataChangeMonitoredItems = null; Node.OnStateChanged = null; } }
/// <summary> /// Called after changing the MonitoringMode for a MonitoredItem. /// </summary> /// <param name="context">The context.</param> /// <param name="handle">The handle for the node.</param> /// <param name="monitoredItem">The monitored item.</param> /// <param name="previousMode">The previous monitoring mode.</param> /// <param name="monitoringMode">The current monitoring mode.</param> protected override void OnMonitoringModeChanged( ServerSystemContext context, NodeHandle handle, MonitoredItem monitoredItem, MonitoringMode previousMode, MonitoringMode monitoringMode) { if (previousMode != MonitoringMode.Disabled) { m_diagnosticsMonitoringCount--; } if (monitoringMode != MonitoringMode.Disabled) { m_diagnosticsMonitoringCount++; } if (m_diagnosticsMonitoringCount == 0 && m_diagnosticsScanTimer != null) { if (m_diagnosticsScanTimer != null) { m_diagnosticsScanTimer.Dispose(); m_diagnosticsScanTimer = null; } } else { if (m_diagnosticsScanTimer != null) { m_diagnosticsScanTimer = new Timer(DoScan, null, 1000, 1000); } } }
/// <summary> /// Reads the value of an attribute and reports it to the MonitoredItem. /// </summary> public void QueueValue( ISystemContext context, NodeState node, MonitoredItem monitoredItem) { DataValue value = new DataValue(); value.Value = null; value.ServerTimestamp = DateTime.UtcNow; value.SourceTimestamp = DateTime.MinValue; value.StatusCode = StatusCodes.Good; ServiceResult error = node.ReadAttribute( context, monitoredItem.AttributeId, monitoredItem.IndexRange, monitoredItem.DataEncoding, value); if (ServiceResult.IsBad(error)) { value = null; } monitoredItem.QueueValue(value, error); }
/// <summary> /// Deletes a sampled item. /// </summary> private void DeleteSampledItem(MonitoredItem monitoredItem) { for (int ii = 0; ii < m_sampledItems.Count; ii++) { if (Object.ReferenceEquals(monitoredItem, m_sampledItems[ii])) { m_sampledItems.RemoveAt(ii); break; } } if (m_sampledItems.Count == 0) { if (m_samplingTimer != null) { m_samplingTimer.Dispose(); m_samplingTimer = null; } } }
/// <summary> /// Removes a request for the specified UA property. /// </summary> /// <param name="property">The property.</param> /// <param name="monitoredItem">The monitored item.</param> private void Remove(PropertyState property, MonitoredItem monitoredItem) { if (monitoredItem.AttributeId != Attributes.Value) { return; } DaItemState item = property.Parent as DaItemState; if (item == null) { return; } int[] propertyIds = SubscribePropertyRequest.UaPropertyToDaProperty(property.SymbolicName); if (propertyIds == null) { return; } SubscribePropertyRequest request = FindPropertyRequest(item.ItemId, false); if (request != null) { request.Remove(m_context, monitoredItem); if (request.MonitoredItems.Count == 0) { m_subscribedProperties.Remove(item.ItemId); } } }