A class that implements a COM DA group.
Inheritance: IDisposable
Esempio n. 1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ComDaGroupItem"/> class.
        /// </summary>
        public ComDaGroupItem(ComDaGroup group, string itemId)
		{
            m_group = group;
            m_itemId = itemId;
            m_serverHandle = 0;
            m_active = true;
            m_euType = -1;
            m_samplingRate = -1;
            m_bufferEnabled = false;
            m_deadband = -1;
        }
Esempio n. 2
0
 /// <summary>
 /// Removes the group.
 /// </summary>
 /// <param name="group">The group.</param>
 public void RemoveGroup(ComDaGroup group)
 {
     m_groupManager.RemoveGroup(group);
 }
Esempio n. 3
0
        /// <summary>
        /// Recovers the session context.
        /// </summary>
        /// <param name="group">The group.</param>
        public void RecoverSessionContext(ComDaGroup group)
        {
            // create a new subscription and copy existing one.
            Subscription discardSubscription = group.Subscription;
            Subscription subscription = new Subscription();
            subscription.DisplayName = discardSubscription.DisplayName;
            subscription.PublishingInterval = discardSubscription.PublishingInterval;
            subscription.KeepAliveCount = discardSubscription.KeepAliveCount;
            subscription.LifetimeCount = discardSubscription.LifetimeCount;
            subscription.MaxNotificationsPerPublish = discardSubscription.MaxNotificationsPerPublish;
            subscription.Priority = discardSubscription.Priority;
            subscription.PublishingEnabled = discardSubscription.PublishingEnabled;
            subscription.DisableMonitoredItemCache = discardSubscription.DisableMonitoredItemCache;

            try
            {
                discardSubscription.Dispose();
            }
            catch (Exception)
            {
            }

            m_session.AddSubscription(subscription);
            
            try
            {
                // create the initial subscription.
                subscription.Create();

                // set the keep alive interval to 30 seconds and the the lifetime interval to 5 minutes.
                subscription.KeepAliveCount = (uint)((30000 / (int)subscription.CurrentPublishingInterval) + 1);
                subscription.LifetimeCount = (uint)((600000 / (int)subscription.CurrentPublishingInterval) + 1);

                // update the subscription.
                subscription.Modify();
            }
            catch (Exception e)
            {
                m_session.RemoveSubscription(subscription);
                throw ComUtils.CreateComException(e, ResultIds.E_FAIL);
            }

            // update the group.
            group.ActualUpdateRate = (int)(subscription.CurrentPublishingInterval * 2);
            group.Subscription = subscription;
            group.RecreateItems();
        }
Esempio n. 4
0
        /// <summary>
        /// Validates the items by reading the attributes required to add them to the group.
        /// </summary>
        /// <param name="session">The session.</param>
        /// <param name="group">The group.</param>
        /// <param name="requests">The requests.</param>
        /// <param name="items">The items.</param>
        /// <param name="start">The start index.</param>
        /// <param name="count">The number of items to process.</param>
        private void ValidateItems(
            Session session,
            ComDaGroup group,
            ComDaCreateItemRequest[] requests,
            ComDaGroupItem[] items,
            int start,
            int count)
        {
            // build list of the UA attributes that need to be read.
            ReadValueIdCollection attributesToRead = new ReadValueIdCollection();

            for (int ii = start; ii < start + count && ii < requests.Length; ii++)
            {
                // create the group item.
                ComDaCreateItemRequest request = requests[ii];
                ComDaGroupItem item = items[ii] = new ComDaGroupItem(group, request.ItemId);

                item.NodeId = m_mapper.GetRemoteNodeId(request.ItemId);
                item.Active = request.Active;
                item.ClientHandle = request.ClientHandle;
                item.RequestedDataType = request.RequestedDataType;
                item.SamplingRate = -1;
                item.Deadband = -1;

                // add attributes.
                ReadValueId attributeToRead;

                attributeToRead = new ReadValueId();
                attributeToRead.NodeId = item.NodeId;
                attributeToRead.AttributeId = Attributes.NodeClass;
                attributesToRead.Add(attributeToRead);

                attributeToRead = new ReadValueId();
                attributeToRead.NodeId = item.NodeId;
                attributeToRead.AttributeId = Attributes.DataType;
                attributesToRead.Add(attributeToRead);

                attributeToRead = new ReadValueId();
                attributeToRead.NodeId = item.NodeId;
                attributeToRead.AttributeId = Attributes.ValueRank;
                attributesToRead.Add(attributeToRead);

                attributeToRead = new ReadValueId();
                attributeToRead.NodeId = item.NodeId;
                attributeToRead.AttributeId = Attributes.UserAccessLevel;
                attributesToRead.Add(attributeToRead);
            }

            // read attribute values from the server.
            DataValueCollection results = null;
            DiagnosticInfoCollection diagnosticInfos = null;

            try
            {
                session.Read(
                    null,
                    0,
                    TimestampsToReturn.Neither,
                    attributesToRead,
                    out results,
                    out diagnosticInfos);

                ClientBase.ValidateResponse(results, attributesToRead);
                ClientBase.ValidateDiagnosticInfos(diagnosticInfos, attributesToRead);
            }
            catch (Exception e)
            {
                Utils.Trace(e, "Unexpected error reading attributes for items.");

                // set default values on error.
                for (int ii = start; ii < start + count && ii < requests.Length; ii++)
                {
                    requests[ii].Error = ResultIds.E_INVALIDITEMID;
                }

                return;
            }

            // process results.
            int first = 0;

            for (int ii = start; ii < start + count && ii < requests.Length; ii++, first += 4)
            {
                ComDaGroupItem item = items[ii];

                // verify node class.
                NodeClass nodeClass = (NodeClass)results[first].GetValue<int>((int)NodeClass.Unspecified);

                if (nodeClass != NodeClass.Variable)
                {
                    requests[ii].Error = ResultIds.E_INVALIDITEMID;
                    continue;
                }

                // verify data type.
                NodeId dataTypeId = results[first+1].GetValue<NodeId>(null);

                if (dataTypeId == null)
                {
                    requests[ii].Error = ResultIds.E_INVALIDITEMID;
                    continue;
                }

                // get value rank.
                int valueRank = results[first+2].GetValue<int>(ValueRanks.Scalar);

                // update datatypes.
                BuiltInType builtInType = DataTypes.GetBuiltInType(dataTypeId, session.TypeTree);
                item.RemoteDataType = new TypeInfo(builtInType, valueRank);
                item.CanonicalDataType = (short)ComUtils.GetVarType(item.RemoteDataType);

                // update access rights.
                byte userAccessLevel = results[first+3].GetValue<byte>(0);

                if ((userAccessLevel & AccessLevels.CurrentRead) != 0)
                {
                    item.AccessRights |= OpcRcw.Da.Constants.OPC_READABLE;
                }

                if ((userAccessLevel & AccessLevels.CurrentWrite) != 0)
                {
                    item.AccessRights |= OpcRcw.Da.Constants.OPC_WRITEABLE;
                }
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Validates the items.
        /// </summary>
        /// <param name="group">The group.</param>
        /// <param name="requests">The requests.</param>
        /// <returns>The items. May contain null is validation failed.</returns>
        public ComDaGroupItem[] ValidateItems(ComDaGroup group, ComDaCreateItemRequest[] requests)
        {
            TraceState("ValidateItems", group.Name);

            // get the session to use for the operation.
            Session session = m_session;

            if (session == null)
            {
                throw ComUtils.CreateComException(ResultIds.E_FAIL);
            }

            // validate items.
            ComDaGroupItem[] items = new ComDaGroupItem[requests.Length];

            for (int ii = 0; ii < requests.Length; ii += 10000)
            {
                ValidateItems(session, group, requests, items, ii, 10000);
            }

            // process results.
            for (int ii = 0; ii < requests.Length; ii++)
            {
                // check for the results.
                ComDaCreateItemRequest request = requests[ii];

                if (request.Error < 0)
                {
                    items[ii] = null;
                    continue;
                }

                // check access path.
                if (!String.IsNullOrEmpty(request.AccessPath))
                {
                    items[ii] = null;
                    request.Error = ResultIds.E_UNKNOWNPATH;
                    continue;
                }

                ComDaGroupItem item = items[ii];

                // validate the datatype.
                if (request.RequestedDataType != 0)
                {
                    NodeId dataTypeId = ComUtils.GetDataTypeId(request.RequestedDataType);

                    if (NodeId.IsNull(dataTypeId))
                    {
                        items[ii] = null;
                        request.Error = ResultIds.E_BADTYPE;
                        continue;
                    }

                    bool reqTypeIsArray = (request.RequestedDataType & (short)VarEnum.VT_ARRAY) != 0;
                    bool actualTypeIsArray = (item.CanonicalDataType & (short)VarEnum.VT_ARRAY) != 0;

                    if (reqTypeIsArray != actualTypeIsArray)
                    {
                        items[ii] = null;
                        request.Error = ResultIds.E_BADTYPE;
                        continue;
                    }
                }

                // create a new monitored item.
                MonitoredItem monitoredItem = new MonitoredItem();

                monitoredItem.StartNodeId = item.NodeId;
                monitoredItem.RelativePath = null;
                monitoredItem.AttributeId = Attributes.Value;
                monitoredItem.MonitoringMode = (request.Active)?MonitoringMode.Reporting:MonitoringMode.Disabled;
                monitoredItem.SamplingInterval = group.UpdateRate/2;
                monitoredItem.QueueSize = 0;
                monitoredItem.DiscardOldest = true;
                monitoredItem.Filter = null;

                // update item.
                item.ServerHandle = (int)monitoredItem.ClientHandle;
                item.MonitoredItem = monitoredItem;

                // link the monitored item back to the group item.
                monitoredItem.Handle = item;
                
                // update return parameters.
                request.ServerHandle = item.ServerHandle;
                request.CanonicalDataType = item.CanonicalDataType;
                request.AccessRights = item.AccessRights;
                request.Error = ResultIds.S_OK;
            }

            return items;
        }
Esempio n. 6
0
        /// <summary>
        /// Updates the EUInfo for the items.
        /// </summary>
        /// <param name="group">The group.</param>
        /// <param name="items">The items. Null entries are ignored.</param>
        public void UpdateItemEuInfo(
            ComDaGroup group,
            IList<ComDaGroupItem> items)
        {
            // get the session to use for the operation.
            Session session = m_session;

            if (session == null)
            {
                throw ComUtils.CreateComException(ResultIds.E_FAIL);
            }

            // build list of properties that need to be read.
            BrowsePathCollection browsePaths = new BrowsePathCollection();

            for (int ii = 0; ii < items.Count; ii++)
            {
                ComDaGroupItem item = (ComDaGroupItem)items[ii];

                // ignore invalid items or items which have already checked their EU type.
                if (item == null || item.EuType >= 0)
                {
                    continue;
                }

                BrowsePath browsePath = new BrowsePath();
                browsePath.StartingNode = item.NodeId;
                RelativePathElement element = new RelativePathElement();
                element.ReferenceTypeId = ReferenceTypeIds.HasProperty;
                element.IsInverse = false;
                element.IncludeSubtypes = false;
                element.TargetName = Opc.Ua.BrowseNames.EURange;
                browsePath.RelativePath.Elements.Add(element);
                browsePath.Handle = item;
                browsePaths.Add(browsePath);

                browsePath = new BrowsePath();
                browsePath.StartingNode = item.NodeId;
                element = new RelativePathElement();
                element.ReferenceTypeId = ReferenceTypeIds.HasProperty;
                element.IsInverse = false;
                element.IncludeSubtypes = false;
                element.TargetName = Opc.Ua.BrowseNames.EnumStrings;
                browsePath.RelativePath.Elements.Add(element);
                browsePath.Handle = item;
                browsePaths.Add(browsePath);
            }

            // check if nothing to do.
            if (browsePaths.Count == 0)
            {
                return;
            }

            // translate browse paths.
            BrowsePathResultCollection results = null;
            DiagnosticInfoCollection diagnosticInfos = null;

            try
            {
                session.TranslateBrowsePathsToNodeIds(
                    null,
                    browsePaths,
                    out results,
                    out diagnosticInfos);

                ClientBase.ValidateResponse(results, browsePaths);
                ClientBase.ValidateDiagnosticInfos(diagnosticInfos, browsePaths);
            }
            catch (Exception)
            {
                for (int ii = 0; ii < browsePaths.Count; ii++)
                {
                    ComDaGroupItem item = (ComDaGroupItem)browsePaths[ii].Handle;
                    item.EuType = 0;
                }

                return;
            }

            // build list of properties that need to be read.
            ReadValueIdCollection propertiesToRead = new ReadValueIdCollection();

            for (int ii = 0; ii < results.Count; ii++)
            {
                ComDaGroupItem item = (ComDaGroupItem)browsePaths[ii].Handle;
                BrowsePathResult result = results[ii];

                if (StatusCode.IsBad(result.StatusCode))
                {
                    if (item.EuType < 0 && result.StatusCode == StatusCodes.BadNoMatch)
                    {
                        item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_NOENUM;
                    }

                    continue;
                }

                if (result.Targets.Count == 0 || result.Targets[0].TargetId.IsAbsolute)
                {
                    if (item.EuType < 0)
                    {
                        item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_NOENUM;
                    }

                    continue;
                }

                ReadValueId propertyToRead = new ReadValueId();
                propertyToRead.NodeId = (NodeId)result.Targets[0].TargetId;
                propertyToRead.AttributeId = Attributes.Value;
                propertyToRead.Handle = item;
                propertiesToRead.Add(propertyToRead);

                if (browsePaths[ii].RelativePath.Elements[0].TargetName.Name == Opc.Ua.BrowseNames.EURange)
                {
                    item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_ANALOG;
                }
                else
                {
                    item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_ENUMERATED;
                }
            }

            // check if nothing to do.
            if (propertiesToRead.Count == 0)
            {
                return;
            }

            // read attribute values from the server.
            DataValueCollection values = null;

            try
            {
                session.Read(
                    null,
                    0,
                    TimestampsToReturn.Neither,
                    propertiesToRead,
                    out values,
                    out diagnosticInfos);

                ClientBase.ValidateResponse(values, propertiesToRead);
                ClientBase.ValidateDiagnosticInfos(diagnosticInfos, propertiesToRead);
            }
            catch (Exception)
            {
                for (int ii = 0; ii < propertiesToRead.Count; ii++)
                {
                    ComDaGroupItem item = (ComDaGroupItem)propertiesToRead[ii].Handle;
                    item.EuType = 0;
                }

                return;
            }

            // process results.
            for (int ii = 0; ii < values.Count; ii++)
            {
                ComDaGroupItem item = (ComDaGroupItem)propertiesToRead[ii].Handle;

                if (StatusCode.IsBad(values[ii].StatusCode))
                {
                    item.EuType = 0;
                    continue;
                }

                if (item.EuType == (int)OpcRcw.Da.OPCEUTYPE.OPC_ANALOG)
                {
                    Range range = (Range)values[ii].GetValue<Range>(null);

                    if (range == null)
                    {
                        item.EuType = 0;
                        continue;
                    }

                    item.EuInfo = new double[] { range.Low, range.High };
                    continue;
                }

                if (item.EuType == (int)OpcRcw.Da.OPCEUTYPE.OPC_ENUMERATED)
                {
                    LocalizedText[] texts = (LocalizedText[])values[ii].GetValue<LocalizedText[]>(null);

                    if (texts == null)
                    {
                        item.EuType = 0;
                        continue;
                    }

                    string[] strings = new string[texts.Length];

                    for (int jj = 0; jj < strings.Length; jj++)
                    {
                        if (!LocalizedText.IsNullOrEmpty(texts[jj]))
                        {
                            strings[jj] = texts[jj].Text;
                        }
                    }

                    item.EuInfo = strings;
                    continue;
                }
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Returns the current set of groups.
        /// </summary>
        /// <returns>The list of groups.</returns>
        public ComDaGroup[] GetGroups()
        {
            TraceState("GetGroups");

            lock (m_lock)
            {
                ComDaGroup[] groups = new ComDaGroup[m_groups.Count];

                for (int ii = 0; ii < m_groups.Count; ii++)
                {
                    groups[ii] = m_groups[ii];
                }

                return groups;
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Removes the group.
        /// </summary>
        /// <param name="group">The group.</param>
        public void RemoveGroup(ComDaGroup group)
        {
            TraceState("RemoveGroup", group.Name);

            lock (m_lock)
            {
                for (int ii = 0; ii < m_groups.Count; ii++)
                {
                    if (Object.ReferenceEquals(group, m_groups[ii]))
                    {
                        m_groups.RemoveAt(ii);

                        if (group.Subscription != null && group.Subscription.Session != null)
                        {
                            group.Subscription.Session.RemoveSubscription(group.Subscription);
                        }
                    }
                }

                group.Dispose();
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Adds the group.
        /// </summary>
        /// <param name="groupName">The group name.</param>
        /// <param name="active">if set to <c>true</c> the group is active.</param>
        /// <param name="updateRate">The update rate.</param>
        /// <param name="clientHandle">The client handle.</param>
        /// <param name="timeBias">The time bias.</param>
        /// <param name="deadband">The deadband.</param>
        /// <param name="lcid">The lcid.</param>
        /// <returns>The new group.</returns>
        public ComDaGroup AddGroup(
            string groupName,
            bool active,
            int updateRate,
            int clientHandle,
            int timeBias,
            float deadband,
            int lcid)
        {
            TraceState("AddGroup", groupName, active, updateRate, clientHandle, timeBias, deadband, lcid);

            // check for valid session.
            Session session = m_session;

            if (session == null)
            {
                throw ComUtils.CreateComException(ResultIds.E_FAIL);
            }

            ComDaGroup group = null;

            // check for duplicate name.
            lock (m_lock)
            {
                // ensure the name is unique.
                if (!String.IsNullOrEmpty(groupName))
                {
                    if (GetGroupByName(groupName) != null)
                    {
                        throw ComUtils.CreateComException(ResultIds.E_DUPLICATENAME);
                    }
                }

                // assign a unique name.
                else
                {
                    groupName = Utils.Format("Group{0}", m_groupCounter+1);
                }

                // validate the deadband.
                if (deadband < 0 || deadband > 100)
                {
                    throw ComUtils.CreateComException(ResultIds.E_INVALIDARG);
                }

                // create the group.
                group = new ComDaGroup(this, groupName, ++m_groupCounter);
                m_groups.Add(group);

                group.ClientHandle = clientHandle;
                group.Active = active;
                group.UpdateRate = updateRate;
                group.TimeBias = timeBias;
                group.Deadband = deadband;
                group.Lcid = lcid;

                if (updateRate < 100)
                {
                    updateRate = 100;
                }

                // create a new subscription.
                Subscription subscription = new Subscription();
                subscription.DisplayName = groupName;
                subscription.PublishingInterval = updateRate/2;
                subscription.KeepAliveCount = 30;
                subscription.LifetimeCount = 600;
                subscription.MaxNotificationsPerPublish = 10000;
                subscription.Priority = 1;
                subscription.PublishingEnabled = active;
                subscription.DisableMonitoredItemCache = true;
                
                // create the subscription on the server.
                session.AddSubscription(subscription);

                try
                {
                    // create the initial subscription.
                    subscription.Create();

                    // set the keep alive interval to 30 seconds and the the lifetime interval to 5 minutes.
                    subscription.KeepAliveCount = (uint)((30000/(int)subscription.CurrentPublishingInterval)+1);
                    subscription.LifetimeCount = (uint)((600000/(int)subscription.CurrentPublishingInterval)+1);

                    // update the subscription.
                    subscription.Modify();
                }
                catch (Exception e)
                {
                    session.RemoveSubscription(subscription);
                    Utils.Trace((int)Utils.TraceMasks.Error, "Create subscription failed: {0}", e.Message);
                    throw ComUtils.CreateComException(e, ResultIds.E_FAIL);
                }

                // update the group.
                group.ActualUpdateRate = (int)(subscription.CurrentPublishingInterval*2);
                group.Subscription = subscription;
            }

            return group;
        }
Esempio n. 10
0
        /// <summary>
        /// Sets the name.
        /// </summary>
        /// <param name="group">The group.</param>
        /// <param name="groupName">Name of the group.</param>
        public void SetGroupName(ComDaGroup group, string groupName)
        {
            TraceState("SetGroupName", group.Name, groupName);

            if (String.IsNullOrEmpty(groupName))
            {
                throw ComUtils.CreateComException(ResultIds.E_INVALIDARG);
            }

            lock (m_lock)
            {
                for (int ii = 0; ii < m_groups.Count; ii++)
                {
                    ComDaGroup target = m_groups[ii];

                    if (target.ServerHandle != group.ServerHandle && target.Name == groupName)
                    {
                        throw ComUtils.CreateComException(ResultIds.E_DUPLICATENAME);
                    }

                    group.Name = groupName;
                }
            }
        }
Esempio n. 11
0
        /// <summary>
        /// Clones the item.
        /// </summary>
        /// <param name="group">The group.</param>
        /// <returns>The new item.</returns>
        public ComDaGroupItem CloneItem(ComDaGroup group)
        {
            ComDaGroupItem copy = new ComDaGroupItem(group, this.ItemId);

            copy.m_nodeId = this.m_nodeId;
            copy.m_serverHandle = this.m_serverHandle;
            copy.m_clientHandle = this.m_clientHandle;
            copy.m_active = this.m_active;
            copy.m_requestedDataType = this.m_requestedDataType;
            copy.m_canonicalDataType = this.m_canonicalDataType;
            copy.m_accessRights = this.m_accessRights;
            copy.m_euType = this.m_euType;
            copy.m_euInfo = this.m_euInfo;
            copy.m_samplingRate = this.m_samplingRate;
            copy.m_bufferEnabled = this.m_bufferEnabled;
            copy.m_actualSamplingRate = this.m_actualSamplingRate;
            copy.m_deadband = this.m_deadband;

            // create new monitored item and use its client handle as the server handle.
            copy.m_monitoredItem = new MonitoredItem(this.MonitoredItem);

            return copy;
        }