/// <summary> /// Initializes the node manager. /// </summary> public ComHdaClientNodeManager(IServerInternal server, string namespaceUri, ComHdaClientConfiguration configuration, bool ownsTypeModel) : base(server, namespaceUri, ownsTypeModel) { SystemContext.SystemHandle = m_system = new ComHdaClientManager(); SystemContext.NodeIdFactory = this; // save the configuration for the node manager. m_configuration = configuration; // set the alias root. AliasRoot = m_configuration.ServerName; if (String.IsNullOrEmpty(AliasRoot)) { AliasRoot = "HDA"; } // set the default parser if none provided. if (configuration.ItemIdParser == null) { configuration.ItemIdParser = new ComItemIdParser(); } // set default parameters. if (m_configuration.AttributeSamplingInterval == 0) { m_configuration.AttributeSamplingInterval = 1000; } // create the list of subscriptions. m_subscriptionManagers = new Dictionary<int, HdaSubscribeRequestManager>(); m_subscriptionManagers[ComUtils.LOCALE_SYSTEM_DEFAULT] = new HdaSubscribeRequestManager(SystemContext, ComUtils.LOCALE_SYSTEM_DEFAULT, m_configuration); m_monitoredItems = new Dictionary<uint, HdaSubscribeRequestManager>(); }
/// <summary> /// Applies any changes to the subscriptions. /// </summary> private void ApplyChanges(Dictionary <string, HdaSubscribeAttributeRequest> requests, bool initialUpdateRequired) { List <HdaSubscribeAttributeRequest> requestsToRemove = null; lock (m_lock) { // update existing requests. foreach (KeyValuePair <string, HdaSubscribeAttributeRequest> entry in requests) { HdaSubscribeAttributeRequest request = entry.Value; // remove unused requests. if (request.MonitoredItems == null || request.MonitoredItems.Count == 0) { if (requestsToRemove == null) { requestsToRemove = new List <HdaSubscribeAttributeRequest>(); } requestsToRemove.Add(entry.Value); continue; } request.ChangesComplete(m_configuration.AttributeSamplingInterval); } // remove deleted requests from dictionary. if (requestsToRemove != null) { for (int ii = 0; ii < requestsToRemove.Count; ii++) { m_requests.Remove(requestsToRemove[ii].ItemId); } } // check if the attribute scanner needs to be stopped/started. if (m_attributeScanTimer == null) { if (m_requests.Count > 0) { m_attributeScanTimer = new Timer(OnScanAttributes, null, m_configuration.AttributeSamplingInterval, m_configuration.AttributeSamplingInterval); } } else { if (m_requests.Count == 0) { m_attributeScanTimer.Dispose(); m_attributeScanTimer = null; } } } // release any unused handles. if (requestsToRemove != null) { ComHdaClientManager system = (ComHdaClientManager)m_context.SystemHandle; ComHdaClient client = (ComHdaClient)system.SelectClient(m_context, false); ReleaseHandles(client, requestsToRemove); } // send initial update. if (initialUpdateRequired) { DoScan(requests, true); } }
/// <summary> /// Called when the scan attributes timer expires. /// </summary> private void DoScan(Dictionary <string, HdaSubscribeAttributeRequest> requests, bool initialUpdate) { try { ComHdaClientManager system = (ComHdaClientManager)m_context.SystemHandle; ComHdaClient client = (ComHdaClient)system.SelectClient(m_context, false); // ensure all requests have valid handles. AssignHandles(client, requests); // collect the list of attributes that need reading. HdaReadRequestCollection itemsToRead = new HdaReadRequestCollection(); List <HdaSubscribeAttributeRequest> subscribeRequests = new List <HdaSubscribeAttributeRequest>(); List <HdaReadRequest> readRequestsForSubscribeRequests = new List <HdaReadRequest>(); lock (m_lock) { DateTime now = DateTime.UtcNow; foreach (KeyValuePair <string, HdaSubscribeAttributeRequest> entry in requests) { // check if it is time for an update. if (!initialUpdate && entry.Value.NextUpdateTime > now) { continue; } // create a read request for each monitored item. bool somethingToDo = false; for (int ii = 0; ii < entry.Value.MonitoredItems.Count; ii++) { MonitoredItem monitoredItem = entry.Value.MonitoredItems[ii]; NodeHandle handle = monitoredItem.ManagerHandle as NodeHandle; if (handle == null) { continue; } // check if item is not valid. if (entry.Value.ServerHandle == null) { monitoredItem.QueueValue(null, StatusCodes.BadNodeIdUnknown); continue; } ReadValueId valueToRead = monitoredItem.GetReadValueId(); bool queued = false; StatusCode error = itemsToRead.Add(handle.Node, valueToRead, out queued); if (StatusCode.IsBad(error)) { monitoredItem.QueueValue(null, error); continue; } if (!somethingToDo && queued) { // add server handle to read request. HdaReadRequest request = (HdaReadRequest)valueToRead.Handle; request.ServerHandle = entry.Value.ServerHandle.Value; // save mapping between subscribe request and read requests. subscribeRequests.Add(entry.Value); readRequestsForSubscribeRequests.Add(request); somethingToDo = true; } } } // check if nothing to do. if (requests.Count == 0) { return; } } // read the attributes from the server. client.Read(itemsToRead, true); // update the monitored items. lock (m_lock) { for (int ii = 0; ii < subscribeRequests.Count; ii++) { subscribeRequests[ii].QueueValues(m_context, readRequestsForSubscribeRequests[ii], initialUpdate); } } } catch (Exception e) { Utils.Trace(e, "Unexpected error scanning attributes in HDA COM server."); } }
/// <summary> /// Initializes the next stage of browsing. /// </summary> private void NextStage() { ComHdaClientManager system = (ComHdaClientManager)this.SystemContext.SystemHandle; ComHdaClient client = (ComHdaClient)system.SelectClient((ServerSystemContext)SystemContext, false); // determine which stage is next based on the reference types requested. for (Stage next = m_stage + 1; next <= Stage.Done; next++) { if (next == Stage.Browse) { if (IsRequired(ReferenceTypeIds.Organizes, false)) { m_stage = next; break; } } else if (next == Stage.Children) { if (IsRequired(ReferenceTypeIds.HasProperty, false) || IsRequired(ReferenceTypeIds.HasHistoricalConfiguration, false)) { m_stage = next; break; } } else if (next == Stage.Parents) { if (IsRequired(ReferenceTypeIds.Organizes, true) || IsRequired(ReferenceTypeIds.HasHistoricalConfiguration, true)) { m_stage = next; break; } } else if (next == Stage.Done) { m_stage = next; break; } } // start enumerating areas. if (m_stage == Stage.Browse) { m_browser = null; if (m_sourceTypeDefinitionId == Opc.Ua.ObjectTypeIds.FolderType) { m_browser = new ComHdaBrowserClient(client, m_itemId); } return; } // start enumerating attributes. if (m_stage == Stage.Children) { m_position = 0; m_children = null; if (m_sourceTypeDefinitionId == Opc.Ua.ObjectTypeIds.FolderType) { return; } List <BaseInstanceState> children = new List <BaseInstanceState>(); // check if browsing aggregate functions. if (m_sourceBrowseName == Opc.Ua.BrowseNames.AggregateFunctions) { if (IsRequired(ReferenceTypeIds.HasComponent, false)) { BaseObjectState[] aggregates = client.GetSupportedAggregates(m_namespaceIndex); if (aggregates != null) { children.AddRange(aggregates); } m_children = children.ToArray(); } return; } // must be browsing children of an item. HdaItem[] items = client.GetItems(m_itemId); if (items[0].Error < 0) { return; } try { HdaAttributeValue[] attributes = client.ReadAvailableAttributes(items[0]); if (m_sourceTypeDefinitionId == Opc.Ua.VariableTypeIds.DataItemType) { FindChildrenForHdaItem(client, children, attributes); } if (m_sourceTypeDefinitionId == Opc.Ua.ObjectTypeIds.HistoricalDataConfigurationType) { FindChildrenForHdaItemConfiguration(client, children, attributes); } } finally { client.ReleaseItemHandles(items); } m_children = children.ToArray(); return; } // start enumerating parents. if (m_stage == Stage.Parents) { return; } // all done. }