/// <summary> /// Releases the handles. /// </summary> /// <param name="client">The client.</param> /// <param name="requests">The requests.</param> private void ReleaseHandles(ComHdaClient client, List <HdaSubscribeAttributeRequest> requests) { List <int> serverHandles = null; lock (m_lock) { for (int ii = 0; ii < requests.Count; ii++) { if (requests[ii].ServerHandle != null) { if (serverHandles == null) { serverHandles = new List <int>(); } serverHandles.Add(requests[ii].ServerHandle.Value); requests[ii].ServerHandle = null; } } } if (serverHandles == null) { return; } client.ReleaseItemHandles(serverHandles.ToArray()); }
/// <summary> /// Initializes a new instance of the <see cref="ComHdaBrowserClient"/> class. /// </summary> /// <param name="client">The client.</param> /// <param name="itemId">The qualified area name.</param> public ComHdaBrowserClient( ComHdaClient client, string itemId) { m_client = client; m_itemId = itemId; }
/// <summary> /// Initializes the object with the containing subscription object. /// </summary> public ComHdaDataCallback(ComHdaClient server) { // save group. m_server = server; // create connection point. m_connectionPoint = new ConnectionPoint(server.Unknown, typeof(OpcRcw.Hda.IOPCHDA_DataCallback).GUID); // advise. m_connectionPoint.Advise(this); }
/// <summary> /// Assigns the handles to the requests. /// </summary> /// <param name="client">The client.</param> /// <param name="requests">The requests.</param> private void AssignHandles(ComHdaClient client, Dictionary <string, HdaSubscribeAttributeRequest> requests) { List <string> itemIds = null; lock (m_lock) { foreach (KeyValuePair <string, HdaSubscribeAttributeRequest> entry in requests) { if (entry.Value.ServerHandle == null) { if (itemIds == null) { itemIds = new List <string>(); } itemIds.Add(entry.Key); } } } if (itemIds == null) { return; } HdaItem[] items = client.GetItems(itemIds.ToArray()); lock (m_lock) { for (int ii = 0; ii < items.Length; ii++) { HdaSubscribeAttributeRequest request = null; if (!requests.TryGetValue(itemIds[ii], out request)) { continue; } if (items[ii].Error < 0) { request.ServerHandle = null; continue; } request.ServerHandle = items[ii].ServerHandle; } } }
/// <summary> /// Updates the status node. /// </summary> protected override bool UpdateStatus() { // get the status from the server. ComHdaClient client = DefaultClient; ComHdaClient.ServerStatus?status = client.GetStatus(); // check the client has been abandoned. if (!Object.ReferenceEquals(client, DefaultClient)) { return(false); } // update the server status. lock (StatusNodeLock) { StatusNode.ServerUrl.Value = Configuration.ServerUrl; if (status != null) { StatusNode.SetStatusCode(DefaultSystemContext, StatusCodes.Good, DateTime.UtcNow); if (String.IsNullOrEmpty(status.Value.szStatusString)) { StatusNode.ServerState.Value = Utils.Format("{0}", status.Value.wStatus); } else { StatusNode.ServerState.Value = Utils.Format("{0} '{1}'", status.Value.wStatus, status.Value.szStatusString); } StatusNode.CurrentTime.Value = status.Value.ftCurrentTime; StatusNode.LastUpdateTime.Value = DateTime.MinValue; StatusNode.StartTime.Value = status.Value.ftStartTime; StatusNode.VendorInfo.Value = status.Value.szVendorInfo; StatusNode.SoftwareVersion.Value = Utils.Format("{0}.{1}.{2}", status.Value.wMajorVersion, status.Value.wMinorVersion, status.Value.wBuildNumber); } else { StatusNode.SetStatusCode(DefaultSystemContext, StatusCodes.BadOutOfService, DateTime.UtcNow); } StatusNode.ClearChangeMasks(DefaultSystemContext, true); return(status != null); } }
/// <summary> /// Finds the children for hda item configuration. /// </summary> /// <param name="client">The client.</param> /// <param name="children">The children.</param> /// <param name="attributes">The attribute values.</param> private void FindChildrenForHdaItemConfiguration(ComHdaClient client, List <BaseInstanceState> children, HdaAttributeValue[] attributes) { BaseInstanceState child = null; if (IsRequired(ReferenceTypeIds.HasProperty, false)) { for (int ii = 0; ii < attributes.Length; ii++) { if (attributes[ii].Error < 0 || attributes[ii].Error == ResultIds.S_NODATA) { continue; } bool skip = true; switch (attributes[ii].AttributeId) { case Constants.OPCHDA_DERIVE_EQUATION: case Constants.OPCHDA_STEPPED: case Constants.OPCHDA_MAX_TIME_INT: case Constants.OPCHDA_MIN_TIME_INT: case Constants.OPCHDA_EXCEPTION_DEV: case Constants.OPCHDA_EXCEPTION_DEV_TYPE: { skip = false; break; } } if (skip) { continue; } child = client.FindItemAttribute(m_itemId, attributes[ii].AttributeId, m_namespaceIndex); if (child != null) { children.Add(child); } } } }
/// <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> /// 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> /// 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. }