/// <summary> /// Establishes a subscription for the current set of items. /// </summary> private ItemValueResultList Subscribe(ArrayList items) { lock (this) { // cancel any current subscription. Unsubscribe(); // check if there is nothing to do. if (items == null || items.Count == 0) { return(new ItemValueResultList()); } // create a single item list and use the subscription state to set list level parameters. ItemList itemList = new ItemList(); itemList.ClientHandle = Guid.NewGuid().ToString(); itemList.ItemPath = null; itemList.ReqType = null; itemList.Deadband = m_state.Deadband; itemList.DeadbandSpecified = true; itemList.SamplingRate = m_state.UpdateRate; itemList.SamplingRateSpecified = true; itemList.EnableBuffering = false; itemList.EnableBufferingSpecified = false; // set the ping rate based on the keep alive (if specified) or five times update rate. m_pingRate = (m_state.KeepAlive != 0)?m_state.KeepAlive:m_state.UpdateRate * 5; // stop any existing timer. if (m_pollTimer != null) { m_pollTimer.Dispose(); m_pollTimer = null; } // create copies of each and replace the client handle with the server handle. foreach (Item item in items) { Item clone = (Item)item.Clone(); clone.ClientHandle = clone.ServerHandle; itemList.Add(clone); } string subscription = null; // establish the subscription on the server. OpcXml.Da10.RequestOptions options = OpcXml.Da10.Request.GetRequestOptions(m_state.Locale, m_filters); OpcXml.Da10.SubscribeReplyItemList replyList = null; OpcXml.Da10.OPCError[] errors = null; OpcXml.Da10.ReplyBase reply = m_proxy.Subscribe( options, OpcXml.Da10.Request.GetSubscribeList(itemList), true, m_pingRate * 2, out replyList, out errors, out subscription); // cache results with the server object. m_server.CacheResponse(m_state.Locale, reply, errors); // save subscription handle. m_state.ServerHandle = subscription; // check for valid response. if (replyList == null) { throw new InvalidResponseException(); } // save the revised update rate. if (replyList.RevisedSamplingRateSpecified) { m_state.UpdateRate = (int)replyList.RevisedSamplingRate; } // update items. ItemValueResultList resultList = OpcXml.Da10.Request.GetSubscribeResultList(replyList); for (int ii = 0; ii < itemList.Count; ii++) { SubscribeItemValueResult resultItem = (SubscribeItemValueResult)resultList[ii]; // restore the client/server handles in the result. resultItem.ServerHandle = resultItem.ClientHandle; resultItem.ClientHandle = ((Item)items[ii]).ClientHandle; // check if the requested sampling rate was accepted. if (!resultItem.SamplingRateSpecified) { resultItem.SamplingRate = itemList[ii].SamplingRate; resultItem.SamplingRateSpecified = itemList[ii].SamplingRateSpecified; } } // schedule polling. SchedulePoll(); // return result list. return(resultList); } }
/// <summary> /// Removes items from the subscription. /// </summary> /// <param name="items">The identifiers (i.e. server handles) for the items being removed.</param> /// <returns>The results of the remove item operation for each item.</returns> public IdentifiedResult[] RemoveItems(ItemIdentifier[] items) { if (items == null) { throw new ArgumentNullException("items"); } // check if nothing to do. if (items.Length == 0) { return(new IdentifiedResult[0]); } lock (this) { if (m_proxy == null) { throw new NotConnectedException(); } // initialize results list. IdentifiedResult[] results = new IdentifiedResult[items.Length]; // build the remaining list of items. ArrayList itemList = new ArrayList(items.Length); foreach (Item item in m_items) { // search the list of items to remove for a matching server handle. bool found = false; for (int ii = 0; ii < items.Length; ii++) { if (item.ServerHandle.Equals(items[ii].ServerHandle)) { results[ii] = new IdentifiedResult(items[ii]); found = true; break; } } // add copy to the item list. if (!found) { itemList.Add(item); } } // create a new subscription. ItemValueResultList resultList = Subscribe(itemList); // update remaining items. for (int ii = 0; ii < resultList.Count; ii++) { // the current item value result object. SubscribeItemValueResult result = (SubscribeItemValueResult)resultList[ii]; // the matching item object. Item item = (Item)itemList[ii]; // save revised sampling rates. item.SamplingRate = result.SamplingRate; item.SamplingRateSpecified = result.SamplingRateSpecified; } // look for uninitialized results - must have an invalid or duplicate server handles. for (int ii = 0; ii < results.Length; ii++) { if (results[ii] == null) { results[ii] = new IdentifiedResult(items[ii]); results[ii].ResultID = ResultID.Da.E_INVALIDHANDLE; results[ii].DiagnosticInfo = null; } } // save modified list of items. m_items = itemList; // send data change notifications. OnDataChange(resultList); // return results. return(results); } }
//====================================================================== // Item Management /// <summary> /// Adds items to the subscription. /// </summary> /// <param name="items">The set of items to add to the subscription.</param> /// <returns>The results of the add item operation for each item.</returns> public ItemResult[] AddItems(Item[] items) { if (items == null) { throw new ArgumentNullException("items"); } // check if nothing to do. if (items.Length == 0) { return(new ItemResult[0]); } lock (this) { if (m_proxy == null) { throw new NotConnectedException(); } // create complete item list. ItemList itemList = new ItemList(); if (m_items != null) { itemList.AddRange(m_items); } // add new items. for (int ii = 0; ii < items.Length; ii++) { Item clone = (Item)items[ii].Clone(); // generate a unique item handle. clone.ServerHandle = Guid.NewGuid().ToString(); // items must be active when first added. clone.Active = true; clone.ActiveSpecified = true; itemList.Add(clone); } // save the index of the first new item. int start = (m_items != null)?m_items.Count:0; // (re)establishes a subscription. ItemValueResultList resultList = Subscribe(itemList); if (resultList == null || resultList.Count != itemList.Count) { throw new InvalidResponseException(); } // clear existing item list. m_items.Clear(); // process results. ItemResult[] results = new ItemResult[items.Length]; for (int ii = 0; ii < resultList.Count; ii++) { // the current item value result object. SubscribeItemValueResult result = (SubscribeItemValueResult)resultList[ii]; // the matching item object. Item item = itemList[ii]; // save revised sampling rates. item.SamplingRate = result.SamplingRate; item.SamplingRateSpecified = result.SamplingRateSpecified; // create item result object for new items. if (ii >= start) { results[ii - start] = new ItemResult(item); results[ii - start].ResultID = result.ResultID; results[ii - start].DiagnosticInfo = result.DiagnosticInfo; } // existing items stay in the list; only add new items if successful. if (ii < start || result.ResultID.Succeeded()) { m_items.Add(item); } } // cancel subscription if subscription is not active. if (!m_state.Active) { Unsubscribe(); } // send data change notifications if subscription is active. else { OnDataChange(resultList); } // return the results for the new items. return(results); } }
/// <summary> /// Modifies the state of items in the subscription /// </summary> /// <param name="masks">Specifies which item state parameters are being modified.</param> /// <param name="items">The new state for each item.</param> /// <returns>The results of the modify item operation for each item.</returns> public ItemResult[] ModifyItems(int masks, Item[] items) { if (items == null) { throw new ArgumentNullException("items"); } // check if nothing to do. if (items.Length == 0) { return(new ItemResult[0]); } lock (this) { if (m_proxy == null) { throw new NotConnectedException(); } // build the modified list of items. ArrayList itemList = new ArrayList(items.Length); foreach (Item item in m_items) { // search the list of masks for a matching server handle. bool found = false; foreach (Item changes in items) { // apply the updates to an item copy. if (item.ServerHandle.Equals(changes.ServerHandle)) { Item clone = (Item)item.Clone(); // change requested data type. if ((masks & (int)StateMask.ReqType) != 0) { clone.ReqType = changes.ReqType; } // deactivating items not supported at ths time. if ((masks & (int)StateMask.Active) != 0) { clone.Active = true; clone.ActiveSpecified = true; } // change deadband. if ((masks & (int)StateMask.Deadband) != 0) { clone.Deadband = changes.Deadband; clone.DeadbandSpecified = changes.DeadbandSpecified; } // change sampling rate if ((masks & (int)StateMask.SamplingRate) != 0) { clone.SamplingRate = changes.SamplingRate; clone.SamplingRateSpecified = changes.SamplingRateSpecified; } // change buffering. if ((masks & (int)StateMask.SamplingRate) != 0) { clone.EnableBuffering = changes.EnableBuffering; clone.EnableBufferingSpecified = changes.EnableBufferingSpecified; } itemList.Add(clone); found = true; break; } } // original to the item list. if (!found) { itemList.Add(item); } } // create a new subscription. ItemValueResultList resultList = Subscribe(itemList); // construct result for each mask provided. ItemResult[] results = new ItemResult[items.Length]; for (int ii = 0; ii < resultList.Count; ii++) { // the current item value result object. SubscribeItemValueResult result = (SubscribeItemValueResult)resultList[ii]; // the matching item object. Item item = (Item)itemList[ii]; // save revised sampling rates. item.SamplingRate = result.SamplingRate; item.SamplingRateSpecified = result.SamplingRateSpecified; // search list of masks for a matching server handle. for (int jj = 0; jj < items.Length; jj++) { if (result.ServerHandle.Equals(items[jj].ServerHandle)) { results[jj] = new ItemResult(item); results[jj].ResultID = result.ResultID; results[jj].DiagnosticInfo = result.DiagnosticInfo; break; } } } // look for masks without a result - must have an invalid or duplicate server handles. for (int ii = 0; ii < results.Length; ii++) { if (results[ii] == null) { results[ii] = new ItemResult(items[ii]); results[ii].ResultID = ResultID.Da.E_INVALIDHANDLE; results[ii].DiagnosticInfo = null; } } // save modified list of items. m_items = itemList; // send data change notifications. OnDataChange(resultList); // return results. return(results); } }
/// <summary> /// Called when a poll completes. /// </summary> private void OnPollCompleted(IAsyncResult handle) { // restore async state parameters. string[] args = (string[])handle.AsyncState; try { lock (this) { // check if object has been disposed. if (m_proxy == null) { return; } // fetch the poll results. string[] invalidHandles = null; bool bufferOverflow = false; OpcXml.Da10.SubscribePolledRefreshReplyItemList[] replyLists = null; OpcXml.Da10.OPCError[] errors = null; OpcXml.Da10.ReplyBase reply = null; reply = m_proxy.EndSubscriptionPolledRefresh( handle, out invalidHandles, out replyLists, out errors, out bufferOverflow); // cache results with the server object. m_server.PollCompleted((string)args[1], reply, errors); // check if the server handle has changed - ignore results in this case. if (!args[0].Equals(m_state.ServerHandle)) { return; } ItemValueResultList resultList = null; // restore subscription if it has been dropped by the server for some reason. if (invalidHandles != null && invalidHandles.Length > 0) { resultList = Subscribe(m_items); if (resultList != null && resultList.Count == m_items.Count) { // replace the client handles. for (int ii = 0; ii < m_items.Count; ii++) { SubscribeItemValueResult result = (SubscribeItemValueResult)resultList[ii]; if (result.ResultID.Succeeded()) { Item item = (Item)m_items[ii]; // save revised sampling rate. item.SamplingRate = result.SamplingRate; item.SamplingRateSpecified = result.SamplingRateSpecified; } } } } // get the list of changed items. else { ItemValueResultList[] resultLists = OpcXml.Da10.Request.GetSubscribeRefreshLists(replyLists); // validate items and replace the client handles. resultList = new ItemValueResultList(); if (resultLists != null && resultLists.Length == 1) { foreach (ItemValueResult result in resultLists[0]) { foreach (Item item in m_items) { if (item.ServerHandle.Equals(result.ClientHandle)) { result.ServerHandle = item.ServerHandle; result.ClientHandle = item.ClientHandle; resultList.Add(result); break; } } } } } // send the data change notifications. OnDataChange(resultList); // check if a new poll should be scheduled. if (args[2] != null) { SchedulePoll(); } } } catch (Exception e) { string message = e.Message; // schedule a new poll on exception. if (args[2] != null) { SchedulePoll(); } } }