//======================================================================
        // GetStatus

        /// <summary>
        /// Returns the current server status.
        /// </summary>
        /// <returns>The current server status.</returns>
        public ServerStatus GetStatus()
        {
            lock (this)
            {
                if (m_proxy == null)
                {
                    throw new NotConnectedException();
                }

                OpcXml.Da10.RequestOptions options      = OpcXml.Da10.Request.GetRequestOptions(m_options.Locale, m_options.Filters);
                OpcXml.Da10.ServerStatus   remoteStatus = null;

                OpcXml.Da10.ReplyBase reply = m_proxy.GetStatus(
                    options.LocaleID,
                    options.ClientRequestHandle,
                    out remoteStatus);

                CacheResponse(m_options.Locale, reply, null);

                // fill in the last update time.
                ServerStatus status = OpcXml.Da10.Request.GetServerStatus(reply, remoteStatus);

                status.LastUpdateTime = m_lastUpdateTime;

                return(status);
            }
        }
        /// <summary>
        /// Returns the locales supported by the server
        /// </summary>
        /// <remarks>The first element in the array must be the default locale for the server.</remarks>
        /// <returns>An array of locales with the format "[languagecode]-[country/regioncode]".</returns>
        public string[] GetSupportedLocales()
        {
            lock (this)
            {
                if (m_proxy == null)
                {
                    throw new NotConnectedException();
                }

                OpcXml.Da10.ServerStatus status = null;

                OpcXml.Da10.ReplyBase reply = m_proxy.GetStatus(
                    m_options.Locale,
                    null,
                    out status);

                if (status != null && status.SupportedLocaleIDs != null)
                {
                    ArrayList locales = new ArrayList();

                    foreach (string locale in status.SupportedLocaleIDs)
                    {
                        if (locale != null)
                        {
                            locales.Add(locale);
                        }
                    }

                    return((string[])locales.ToArray(typeof(string)));
                }

                return(null);
            }
        }
        //======================================================================
        // Write

        /// <summary>
        /// Writes the value, quality and timestamp for a set of items.
        /// </summary>
        /// <param name="items">The set of item values to write.</param>
        /// <returns>The results of the write operation for each item.</returns>
        public IdentifiedResult[] Write(ItemValue[] items)
        {
            if (items == null)
            {
                throw new ArgumentNullException("items");
            }

            if (items.Length == 0)
            {
                return(new Opc.IdentifiedResult[0]);
            }

            lock (this)
            {
                if (m_proxy == null)
                {
                    throw new NotConnectedException();
                }

                ItemValueList list = new ItemValueList();
                list.AddRange(items);

                OpcXml.Da10.RequestOptions       options     = OpcXml.Da10.Request.GetRequestOptions(m_options.Locale, m_options.Filters);
                OpcXml.Da10.WriteRequestItemList requestList = OpcXml.Da10.Request.GetItemValueList(list);
                OpcXml.Da10.ReplyItemList        replyList   = null;
                OpcXml.Da10.OPCError[]           errors      = null;

                OpcXml.Da10.ReplyBase reply = m_proxy.Write(
                    options,
                    requestList,
                    false,
                    out replyList,
                    out errors);

                CacheResponse(m_options.Locale, reply, errors);

                ItemValueResultList valueList = OpcXml.Da10.Request.GetResultList(replyList);

                if (valueList == null)
                {
                    throw new InvalidResponseException();
                }

                IdentifiedResult[] results = new IdentifiedResult[valueList.Count];

                for (int ii = 0; ii < valueList.Count; ii++)
                {
                    ItemValueResult valueResult = valueList[ii];

                    results[ii]                = new IdentifiedResult(valueResult);
                    results[ii].ResultID       = valueResult.ResultID;
                    results[ii].DiagnosticInfo = valueResult.DiagnosticInfo;
                }

                return(results);
            }
        }
 /// <summary>
 /// Called when a subscription receives a polled refresh response.
 /// </summary>
 internal void PollCompleted(
     string localeID,
     OpcXml.Da10.ReplyBase reply,
     OpcXml.Da10.OPCError[] errors)
 {
     lock (this)
     {
         CacheResponse(localeID, reply, errors);
         m_lastUpdateTime = reply.ReplyTime;
     }
 }
        //======================================================================
        // BrowseNext

        /// <summary>
        /// Continues a browse operation with previously specified search criteria.
        /// </summary>
        /// <param name="position">An object containing the browse operation state information.</param>
        /// <returns>The set of elements found.</returns>
        public BrowseElement[] BrowseNext(ref Opc.Da.BrowsePosition position)
        {
            if (position == null)
            {
                throw new ArgumentNullException("position");
            }
            if (m_proxy == null)
            {
                throw new NotConnectedException();
            }

            lock (this)
            {
                BrowsePosition pos = (BrowsePosition)position;

                if (pos.ContinuationPoint == null || pos.ContinuationPoint == "")
                {
                    throw new BrowseCannotContinueException();
                }

                OpcXml.Da10.BrowseElement[] elements = null;
                OpcXml.Da10.OPCError[]      errors   = null;

                OpcXml.Da10.ReplyBase reply = m_proxy.Browse(
                    OpcXml.Da10.Request.GetPropertyNames(pos.Filters.PropertyIDs),
                    pos.Locale,
                    "",
                    (pos.ItemID != null)?pos.ItemID.ItemPath:null,
                    (pos.ItemID != null)?pos.ItemID.ItemName:null,
                    ref pos.ContinuationPoint,
                    pos.Filters.MaxElementsReturned,
                    OpcXml.Da10.Request.GetBrowseFilter(pos.Filters.BrowseFilter),
                    pos.Filters.ElementNameFilter,
                    pos.Filters.VendorFilter,
                    pos.Filters.ReturnAllProperties,
                    pos.Filters.ReturnPropertyValues,
                    pos.ReturnErrorText,
                    out elements,
                    out errors,
                    out pos.MoreElements);

                CacheResponse(pos.Locale, reply, errors);

                position = null;

                if (pos.MoreElements || (pos.ContinuationPoint != null && pos.ContinuationPoint != ""))
                {
                    position = pos;
                }

                return(OpcXml.Da10.Request.GetBrowseElements(elements));
            }
        }
        //======================================================================
        // Browse

        /// <summary>
        /// Fetches the children of a branch that meet the filter criteria.
        /// </summary>
        /// <param name="itemID">The identifier of branch which is the target of the search.</param>
        /// <param name="filters">The filters to use to limit the set of child elements returned.</param>
        /// <param name="position">An object used to continue a browse that could not be completed.</param>
        /// <returns>The set of elements found.</returns>
        public BrowseElement[] Browse(
            ItemIdentifier itemID,
            BrowseFilters filters,
            out Opc.Da.BrowsePosition position)
        {
            position = null;

            lock (this)
            {
                if (m_proxy == null)
                {
                    throw new NotConnectedException();
                }

                // use default filters if none specified.
                if (filters == null)
                {
                    filters = new BrowseFilters();
                }

                BrowsePosition pos = new BrowsePosition(itemID, filters, m_options.Locale, ((m_options.Filters & (int)ResultFilter.ErrorText) != 0));

                OpcXml.Da10.BrowseElement[] elements = null;
                OpcXml.Da10.OPCError[]      errors   = null;

                OpcXml.Da10.ReplyBase reply = m_proxy.Browse(
                    OpcXml.Da10.Request.GetPropertyNames(filters.PropertyIDs),
                    pos.Locale,
                    "",
                    (itemID != null)?itemID.ItemPath:null,
                    (itemID != null)?itemID.ItemName:null,
                    ref pos.ContinuationPoint,
                    filters.MaxElementsReturned,
                    OpcXml.Da10.Request.GetBrowseFilter(filters.BrowseFilter),
                    filters.ElementNameFilter,
                    filters.VendorFilter,
                    filters.ReturnAllProperties,
                    filters.ReturnPropertyValues,
                    pos.ReturnErrorText,
                    out elements,
                    out errors,
                    out pos.MoreElements);

                CacheResponse(pos.Locale, reply, errors);

                if (pos.MoreElements || (pos.ContinuationPoint != null && pos.ContinuationPoint != ""))
                {
                    position = pos;
                }

                return(OpcXml.Da10.Request.GetBrowseElements(elements));
            }
        }
        //======================================================================
        // Read

        /// <summary>
        /// Reads the current values for a set of items.
        /// </summary>
        /// <param name="items">The set of items to read.</param>
        /// <returns>The results of the read operation for each item.</returns>
        public Opc.Da.ItemValueResult[] Read(Item[] items)
        {
            if (items == null)
            {
                throw new ArgumentNullException("items");
            }

            if (items.Length == 0)
            {
                return(new Opc.Da.ItemValueResult[0]);
            }

            lock (this)
            {
                if (m_proxy == null)
                {
                    throw new NotConnectedException();
                }

                ItemList list = new ItemList();
                list.AddRange(items);

                OpcXml.Da10.RequestOptions      options     = OpcXml.Da10.Request.GetRequestOptions(m_options.Locale, m_options.Filters);
                OpcXml.Da10.ReadRequestItemList requestList = OpcXml.Da10.Request.GetItemList(list);
                OpcXml.Da10.ReplyItemList       replyList   = null;
                OpcXml.Da10.OPCError[]          errors      = null;

                OpcXml.Da10.ReplyBase reply = m_proxy.Read(
                    options,
                    requestList,
                    out replyList,
                    out errors);

                CacheResponse(m_options.Locale, reply, errors);

                ItemValueResultList valueList = OpcXml.Da10.Request.GetResultList(replyList);

                if (valueList == null)
                {
                    throw new InvalidResponseException();
                }

                return((ItemValueResult[])valueList.ToArray(typeof(ItemValueResult)));
            }
        }
        //======================================================================
        // Private Methods

        /// <summary>
        /// Caches error messages and request statistics after each request.
        /// </summary>
        internal void CacheResponse(
            string locale,
            OpcXml.Da10.ReplyBase reply,
            OpcXml.Da10.OPCError[] errors)
        {
            lock (this)
            {
                if (reply != null)
                {
                    // check for revised locale id.
                    if (reply.RevisedLocaleID != null)
                    {
                        locale = reply.RevisedLocaleID;
                    }

                    // calculate the bias to use when calculating request timeouts.
                    m_timebias = reply.ReplyTime.Subtract(DateTime.Now);
                }

                if (errors != null && errors.Length > 0)
                {
                    // check for null locale.
                    if (locale == null)
                    {
                        locale = "";
                    }

                    // find the message table for the locale.
                    Hashtable messageTable = (Hashtable)m_messageTables[locale];

                    if (messageTable == null)
                    {
                        m_messageTables[locale] = messageTable = new Hashtable();
                    }

                    // index message texts by message id.
                    foreach (OpcXml.Da10.OPCError error in errors)
                    {
                        messageTable[OpcXml.Da10.Request.GetResultID(error.ID)] = error.Text;
                    }
                }
            }
        }
        //======================================================================
        // GetProperties

        /// <summary>
        /// Returns the item properties for a set of items.
        /// </summary>
        /// <param name="itemIDs">A list of item identifiers.</param>
        /// <param name="propertyIDs">A list of properties to fetch for each item.</param>
        /// <param name="returnValues">Whether the property values should be returned with the properties.</param>
        /// <returns>A list of properties for each item.</returns>
        public ItemPropertyCollection[] GetProperties(
            ItemIdentifier[] itemIDs,
            PropertyID[]     propertyIDs,
            bool returnValues)
        {
            if (itemIDs == null)
            {
                throw new ArgumentNullException("itemIDs");
            }
            if (m_proxy == null)
            {
                throw new NotConnectedException();
            }

            lock (this)
            {
                OpcXml.Da10.RequestOptions      options    = OpcXml.Da10.Request.GetRequestOptions(m_options.Locale, m_options.Filters);
                OpcXml.Da10.PropertyReplyList[] properties = null;
                OpcXml.Da10.OPCError[]          errors     = null;

                OpcXml.Da10.ReplyBase reply = m_proxy.GetProperties(
                    OpcXml.Da10.Request.GetItemIdentifiers(itemIDs),
                    OpcXml.Da10.Request.GetPropertyNames(propertyIDs),
                    options.LocaleID,
                    options.ClientRequestHandle,
                    null,
                    (propertyIDs == null),
                    returnValues,
                    options.ReturnErrorText,
                    out properties,
                    out errors);

                CacheResponse(options.LocaleID, reply, errors);

                return(OpcXml.Da10.Request.GetItemPropertyCollections(properties));
            }
        }
Beispiel #10
0
        /// <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);
            }
        }
Beispiel #11
0
        /// <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();
                }
            }
        }