/// <summary>
 /// Convert to monitored item notifications
 /// </summary>
 /// <param name="notification"></param>
 /// <param name="monitoredItems"></param>
 /// <returns></returns>
 public static IEnumerable <MonitoredItemNotificationModel> ToMonitoredItemNotifications(
     this DataChangeNotification notification, IEnumerable <MonitoredItem> monitoredItems)
 {
     for (var i = 0; i < notification.MonitoredItems.Count; i++)
     {
         var monitoredItem = monitoredItems.SingleOrDefault(
             m => m.ClientHandle == notification.MonitoredItems[i].ClientHandle);
         if (monitoredItem == null)
         {
             continue;
         }
         var message = notification.MonitoredItems[i].ToMonitoredItemNotification(
             monitoredItem);
         if (message == null)
         {
             continue;
         }
         if (message.DiagnosticInfo == null && notification.DiagnosticInfos != null &&
             i < notification.DiagnosticInfos.Count)
         {
             message.DiagnosticInfo = notification.DiagnosticInfos[i];
         }
         yield return(message);
     }
 }
Exemple #2
0
 private void OnDataChangeCallback(Subscription subscription, DataChangeNotification notification, IList <string> stringTable)
 {
     _context.Send(o =>
     {
         var state = (Tuple <UaSubscription, DataChangeNotification>)o;
         foreach (var itemNotification in state.Item2.MonitoredItems)
         {
             var item = state.Item1.FindItemByClientHandle(itemNotification.ClientHandle) as UaItem;
             if (item != null)
             {
                 var cacheQueue = item.CacheQueue;
                 if (cacheQueue != null)
                 {
                     cacheQueue.Enqueue(itemNotification.Value);
                     while (cacheQueue.Count > item.CacheQueueSize)
                     {
                         cacheQueue.Dequeue();
                     }
                     continue;
                 }
                 item.CacheValue = itemNotification.Value;
                 state.Item1.NotifyPropertyChanged(item.DisplayName);
             }
         }
     }, Tuple.Create(this, notification));
 }
Exemple #3
0
 /// <summary>
 /// callback to report session's notifications
 /// </summary>
 /// <param name="session"></param>
 /// <param name="e"></param>
 private void Session_Notification(Session session, NotificationEventArgs e)
 {
     try {
         _logger.Debug("Notification for session '{id}', subscription '{displayName}' - sequence# {sequence}-{publishTime}",
                       session?.Handle is SessionWrapper wrapper ? wrapper?.Id : session?.SessionName,
                       e.Subscription?.DisplayName, e?.NotificationMessage?.SequenceNumber,
                       e.NotificationMessage?.PublishTime);
         if (e.NotificationMessage.IsEmpty || e.NotificationMessage.NotificationData.Count() == 0)
         {
             var keepAlive = new DataChangeNotification()
             {
                 MonitoredItems = new MonitoredItemNotificationCollection()
                 {
                     new MonitoredItemNotification()
                     {
                         ClientHandle = 0,
                         Value        = null,
                         Message      = e.NotificationMessage
                     }
                 }
             };
             e.Subscription.FastDataChangeCallback.Invoke(e.Subscription, keepAlive, e.StringTable);
         }
     }
     catch (Exception ex) {
         _logger.Error(ex, "Failed to process notifications for session '{name}'", session.SessionName);
     }
 }
Exemple #4
0
        /// <summary>
        /// Returns the data changes contained in the notification message.
        /// </summary>
        public IList <MonitoredItemNotification> GetDataChanges(bool reverse)
        {
            List <MonitoredItemNotification> datachanges = new List <MonitoredItemNotification>();

            for (int jj = 0; jj < m_notificationData.Count; jj++)
            {
                ExtensionObject extension = m_notificationData[jj];

                if (ExtensionObject.IsNull(extension))
                {
                    continue;
                }

                DataChangeNotification notification = extension.Body as DataChangeNotification;

                if (notification == null)
                {
                    continue;
                }

                if (reverse)
                {
                    for (int ii = notification.MonitoredItems.Count - 1; ii >= 0; ii--)
                    {
                        MonitoredItemNotification datachange = notification.MonitoredItems[ii];

                        if (datachange != null)
                        {
                            datachange.Message = this;
                            datachanges.Add(datachange);
                        }
                    }
                }
                else
                {
                    for (int ii = 0; ii < notification.MonitoredItems.Count; ii++)
                    {
                        MonitoredItemNotification datachange = notification.MonitoredItems[ii];

                        if (datachange != null)
                        {
                            datachange.Message = this;
                            datachanges.Add(datachange);
                        }
                    }
                }
            }

            return(datachanges);
        }
Exemple #5
0
        /// <see cref="BaseListCtrl.UpdateItem" />
        protected override void UpdateItem(ListViewItem listItem, object item)
        {
            ItemData itemData = item as ItemData;

            if (itemData == null)
            {
                base.UpdateItem(listItem, item);
                return;
            }

            listItem.SubItems[0].Text = String.Format("{0}", itemData.Subscription.DisplayName);
            listItem.SubItems[1].Text = String.Format("{0}", itemData.NotificationMessage.SequenceNumber);
            listItem.SubItems[2].Text =
                String.Format("{0:HH:mm:ss.fff}", itemData.NotificationMessage.PublishTime.ToLocalTime());

            int events        = 0;
            int datachanges   = 0;
            int notifications = 0;

            foreach (ExtensionObject notification in itemData.NotificationMessage.NotificationData)
            {
                notifications++;

                if (ExtensionObject.IsNull(notification))
                {
                    continue;
                }

                DataChangeNotification datachangeNotification = notification.Body as DataChangeNotification;

                if (datachangeNotification != null)
                {
                    datachanges += datachangeNotification.MonitoredItems.Count;
                }

                EventNotificationList EventNotification = notification.Body as EventNotificationList;

                if (EventNotification != null)
                {
                    events += EventNotification.Events.Count;
                }
            }

            listItem.SubItems[3].Text = String.Format("{0}", notifications);
            listItem.SubItems[4].Text = String.Format("{0}", datachanges);
            listItem.SubItems[5].Text = String.Format("{0}", events);

            listItem.Tag = item;
        }
Exemple #6
0
 private void CheckNotifications(DataChangeNotification dcn)
 {
     foreach (var min in dcn.MonitoredItems)
     {
         if (this.monitoredItems.TryGetValueByClientId(min.ClientHandle, out MonitoredItemBase item))
         {
             try
             {
                 item.Publish(min.Value);
             }
             catch (Exception ex)
             {
                 logger?.LogError($"Error publishing value for NodeId {item.NodeId}. {ex.Message}");
             }
         }
     }
 }
Exemple #7
0
        private void OnDataChange(Subscription subscription, DataChangeNotification notification,
                                  IList <string> stringTable)
        {
            if (!Object.ReferenceEquals(subscription, m_subscription))
            {
                return;
            }

            if (this.InvokeRequired)
            {
                this.BeginInvoke(new FastDataChangeNotificationEventHandler(OnDataChange), subscription, notification,
                                 stringTable);
                return;
            }

            try {
                foreach (MonitoredItemNotification itemNotification in notification.MonitoredItems)
                {
                    MonitoredItem monitoredItem = subscription.FindItemByClientHandle(itemNotification.ClientHandle);

                    if (monitoredItem == null)
                    {
                        continue;
                    }

                    DataRow row = (DataRow)monitoredItem.Handle;

                    if (row.RowState == DataRowState.Detached)
                    {
                        continue;
                    }

                    UpdateRow(row, itemNotification);

                    if (m_EditComplexValueDlg != null &&
                        Object.ReferenceEquals(m_EditComplexValueDlg.Tag, monitoredItem))
                    {
                        m_EditComplexValueDlg.UpdateValue(monitoredItem.ResolvedNodeId, monitoredItem.AttributeId, null,
                                                          itemNotification.Value.Value);
                    }
                }
            } catch (Exception exception) {
                ClientUtils.HandleException(this.Text, exception);
            }
        }
Exemple #8
0
        /// <summary>
        /// Sends publish requests in the background for the currently active subscription.
        /// </summary>
        public void Publish(object state)
        {
            try
            {
                uint                 subscriptionId;
                ListOfUInt32         availableSequenceNumbers;
                bool                 moreNotifications;
                NotificationMessage  notificationMessage;
                ListOfStatusCode     results;
                ListOfDiagnosticInfo diagnosticInfos;

                m_client.Publish(
                    m_client.CreateRequestHeader(),
                    new ListOfSubscriptionAcknowledgement(),
                    out subscriptionId,
                    out availableSequenceNumbers,
                    out moreNotifications,
                    out notificationMessage,
                    out results,
                    out diagnosticInfos);

                LastMessageTimeTB.Text = String.Format("{0:HH:mm:ss}", notificationMessage.PublishTime.ToLocalTime());

                foreach (ExtensionObject extension in notificationMessage.NotificationData)
                {
                    if (extension.TypeId == new ExpandedNodeId(Objects.DataChangeNotification_Encoding_DefaultXml))
                    {
                        DataChangeNotification body = (DataChangeNotification)extension.ParseBody(typeof(DataChangeNotification));

                        foreach (MonitoredItemNotification notification in body.MonitoredItems)
                        {
                            UpdateValue(notification);
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message);
            }

            ThreadPool.QueueUserWorkItem(Publish);
        }
Exemple #9
0
        void Session_Notification(Session session, NotificationEventArgs e)
        {
            lock (m_lock)
            {
                if (m_messageCount == 0)
                {
                    m_firstMessageTime     = DateTime.UtcNow;
                    m_totalItemUpdateCount = 0;
                    m_itemUpdateCounts     = new int[m_itemCount];
                }

                m_messageCount++;
                m_lastMessageTime = DateTime.UtcNow;

                int count = 0;

                for (int ii = 0; ii < e.NotificationMessage.NotificationData.Count; ii++)
                {
                    DataChangeNotification notification = e.NotificationMessage.NotificationData[ii].Body as DataChangeNotification;

                    if (notification == null)
                    {
                        continue;
                    }

                    for (int jj = 0; jj < notification.MonitoredItems.Count; jj++)
                    {
                        count++;
                        int clientHandle = (int)notification.MonitoredItems[jj].ClientHandle;

                        m_totalItemUpdateCount++;

                        if (clientHandle >= 0 && clientHandle < m_itemUpdateCounts.Length)
                        {
                            m_itemUpdateCounts[clientHandle]++;
                        }
                    }
                }

                // ReportMessage("OnDataChange. Time={0} ({3}), Count={1}/{2}", DateTime.UtcNow.ToString("mm:ss.fff"), count, m_totalItemUpdateCount, (m_lastMessageTime - m_firstMessageTime).TotalMilliseconds);
            }
        }
Exemple #10
0
        public void Setup()
        {
            _notification = new DataChangeNotification();

            for (int i = 0; i < _numberOfElements; i++)
            {
                _notification.MonitoredItems.Add(new MonitoredItemNotification()
                {
                    Message      = new NotificationMessage(),
                    Value        = new DataValue(new Variant(i)),
                    ClientHandle = (uint)i
                });
            }

            _monitoredItems = new List <MonitoredItem>(_numberOfElements);
            for (uint i = 0; i < _numberOfElements; i++)
            {
                _monitoredItems.Add(new MonitoredItem(i));
            }
        }
Exemple #11
0
 public static IEnumerable <MonitoredItemNotificationModel> ToMonitoredItemNotifications(
     DataChangeNotification notification, IEnumerable <MonitoredItem> monitoredItems)
 {
     for (var i = 0; i < notification.MonitoredItems.Count; i++)
     {
         var monitoredItem = monitoredItems.SingleOrDefault(
             m => m.ClientHandle == notification?.MonitoredItems[i]?.ClientHandle);
         if (monitoredItem == null)
         {
             continue;
         }
         var message = notification?.MonitoredItems[i]?
                       .ToMonitoredItemNotification(monitoredItem);
         if (message == null)
         {
             continue;
         }
         yield return(message);
     }
 }
        /// <summary>
        /// Handles a datachange notifications.
        /// </summary>
        private void MonitoredItem_Notification(Subscription subscription, DataChangeNotification notification, IList <string> stringTable)
        {
            if (!Object.ReferenceEquals(subscription, m_subscription))
            {
                return;
            }

            lock (m_lock)
            {
                for (int ii = 0; ii < notification.MonitoredItems.Count; ii++)
                {
                    MonitoredItem monitoredItem = m_subscription.FindItemByClientHandle(notification.MonitoredItems[ii].ClientHandle);

                    if (monitoredItem != null)
                    {
                        Opc.Ua.Server.MonitoredItem localItem = (Opc.Ua.Server.MonitoredItem)monitoredItem.Handle;
                        localItem.QueueValue(notification.MonitoredItems[ii].Value, null);
                    }
                }
            }
        }
Exemple #13
0
        /// <see cref="BaseListCtrl.UpdateItem" />
        protected override void UpdateItem(ListViewItem listItem, object item)
        {
            ItemData itemData = item as ItemData;

            if (itemData == null)
            {
                base.UpdateItem(listItem, item);
                return;
            }

            int events        = 0;
            int datachanges   = 0;
            int notifications = 0;

            foreach (ExtensionObject notification in itemData.NotificationMessage.NotificationData)
            {
                notifications++;

                if (ExtensionObject.IsNull(notification))
                {
                    continue;
                }

                DataChangeNotification datachangeNotification = notification.Body as DataChangeNotification;

                if (datachangeNotification != null)
                {
                    datachanges += datachangeNotification.MonitoredItems.Count;
                }

                EventNotificationList EventNotification = notification.Body as EventNotificationList;

                if (EventNotification != null)
                {
                    events += EventNotification.Events.Count;
                }
            }

            listItem.Tag = item;
        }
Exemple #14
0
 /// <summary>
 /// callback to report session's notifications
 /// </summary>
 /// <param name="session"></param>
 /// <param name="e"></param>
 private void Session_Notification(Session session, NotificationEventArgs e)
 {
     _logger.Debug("Notification for session: {Session}, subscription {Subscription} -sequence# {Sequence}-{PublishTime}",
                   session.SessionName, e.Subscription?.DisplayName, e.NotificationMessage?.SequenceNumber,
                   e.NotificationMessage.PublishTime);
     if (e.NotificationMessage.IsEmpty || e.NotificationMessage.NotificationData.Count() == 0)
     {
         var keepAlive = new DataChangeNotification()
         {
             MonitoredItems = new MonitoredItemNotificationCollection()
             {
                 new MonitoredItemNotification()
                 {
                     ClientHandle = 0,
                     Value        = null,
                     Message      = e.NotificationMessage
                 }
             }
         };
         e.Subscription.FastDataChangeCallback.Invoke(e.Subscription, keepAlive, e.StringTable);
     }
 }
 /// <summary>
 /// Subscription data changed
 /// </summary>
 /// <param name="subscription"></param>
 /// <param name="notification"></param>
 /// <param name="stringTable"></param>
 private void OnSubscriptionDataChanged(Subscription subscription,
                                        DataChangeNotification notification, IList <string> stringTable)
 {
     try {
         if (OnSubscriptionChange == null)
         {
             return;
         }
         var message = new SubscriptionNotificationModel {
             ServiceMessageContext = subscription.Session.MessageContext,
             ApplicationUri        = subscription.Session.Endpoint.Server.ApplicationUri,
             EndpointUrl           = subscription.Session.Endpoint.EndpointUrl,
             SubscriptionId        = Id,
             Notifications         = notification
                                     .ToMonitoredItemNotifications(subscription.MonitoredItems)
                                     .ToList()
         };
         OnSubscriptionChange?.Invoke(this, message);
     }
     catch (Exception ex) {
         _logger.Debug(ex, "Exception processing subscription notification");
     }
 }
Exemple #16
0
        /// <summary>
        /// Convert to monitored item notifications
        /// </summary>
        /// <param name="notification"></param>
        /// <param name="monitoredItems"></param>
        /// <returns></returns>
        public static IEnumerable <MonitoredItemNotificationModel> ToMonitoredItemNotifications(
            this DataChangeNotification notification, IEnumerable <MonitoredItem> monitoredItems)
        {
            var handles = new Dictionary <uint, MonitoredItem>(1024);

            foreach (var monitoredItem in monitoredItems)
            {
                handles.Add(monitoredItem.ClientHandle, monitoredItem);
            }

            foreach (var monitoredItemWithNotification in notification.MonitoredItems)
            {
                if (handles.TryGetValue(monitoredItemWithNotification.ClientHandle, out var monitoredItem))
                {
                    var message = monitoredItemWithNotification.ToMonitoredItemNotification(monitoredItem);
                    if (message == null)
                    {
                        continue;
                    }
                    yield return(message);
                }
            }
        }
Exemple #17
0
        private void OnFastDataChange(Subscription subscription, DataChangeNotification notification, IList <string> stringTable)
        {
            OpcUaDeviceOutParamEntity opcUaDeviceOutParamEntity = new OpcUaDeviceOutParamEntity();

            opcUaDeviceOutParamEntity.StatusCode            = (uint)DeviceStatusCode.SubscriptionOK;
            opcUaDeviceOutParamEntity.SubScriptionValueList = new List <Tuple <string, object> >();

            foreach (MonitoredItemNotification itemNotification in notification.MonitoredItems)
            {
                MonitoredItem item = subscription.FindItemByClientHandle(itemNotification.ClientHandle);
                if (item == null)
                {
                    continue;
                }
                foreach (var value in item.DequeueValues())
                {
                    opcUaDeviceOutParamEntity.SubScriptionValueList.Add(Tuple.Create(item.ResolvedNodeId.ToString(), value.Value));
                }
            }

            DeviceEventArgs <DeviceParamEntityBase> args = new DeviceEventArgs <DeviceParamEntityBase>(opcUaDeviceOutParamEntity);

            Notification.Invoke(this, args);
        }
Exemple #18
0
        /// <summary>
        /// Construct a message from the queues.
        /// </summary>
        private NotificationMessage ConstructMessage(
            Queue<EventFieldList> events,
            Queue<MonitoredItemNotification> datachanges,
            Queue<DiagnosticInfo> datachangeDiagnostics,
            out int notificationCount)
        {
            notificationCount = 0;

            NotificationMessage message = new NotificationMessage();

            message.SequenceNumber = (uint)m_sequenceNumber; 
            message.PublishTime    = DateTime.UtcNow;

            Utils.IncrementIdentifier(ref m_sequenceNumber);

            lock (m_diagnostics)
            {
                m_diagnostics.NextSequenceNumber = (uint)m_sequenceNumber;
            }
             
            // add events.
            if (events.Count > 0 && notificationCount < m_maxNotificationsPerPublish)
            {
                EventNotificationList notification = new EventNotificationList();

                while (events.Count > 0 && notificationCount < m_maxNotificationsPerPublish)
                {
                    notification.Events.Add(events.Dequeue());
                    notificationCount++;
                }

                message.NotificationData.Add(new ExtensionObject(notification));
            }

            // add datachanges (space permitting).
            if (datachanges.Count > 0 && notificationCount < m_maxNotificationsPerPublish)
            {
                bool diagnosticsExist = false;
                DataChangeNotification notification = new DataChangeNotification();

                notification.MonitoredItems  = new MonitoredItemNotificationCollection(datachanges.Count);
                notification.DiagnosticInfos = new DiagnosticInfoCollection(datachanges.Count);

                while (datachanges.Count > 0 && notificationCount < m_maxNotificationsPerPublish)
                {
                    MonitoredItemNotification datachange = datachanges.Dequeue();
                    notification.MonitoredItems.Add(datachange);

                    DiagnosticInfo diagnosticInfo = datachangeDiagnostics.Dequeue();

                    if (diagnosticInfo != null)
                    {
                        diagnosticsExist = true;
                    }
                    
                    notification.DiagnosticInfos.Add(diagnosticInfo);

                    notificationCount++;
                }

                // clear diagnostics if not used.
                if (!diagnosticsExist)
                {
                    notification.DiagnosticInfos.Clear();
                }

                message.NotificationData.Add(new ExtensionObject(notification));
            }

            return message;
        }
Exemple #19
0
        /// <summary>
        /// Called when a data change arrives.
        /// </summary>
        /// <param name="subscription">The subscription.</param>
        /// <param name="notification">The notification.</param>
        /// <param name="stringTable">The string table.</param>
        void OnDataChange(Subscription subscription, DataChangeNotification notification, IList<string> stringTable)
        {
            try
            {
                lock (m_lock)
                {
                    for (int jj = 0; jj < notification.MonitoredItems.Count; jj++)
                    {
                        uint clientHandle = notification.MonitoredItems[jj].ClientHandle;

                        // find item.
                        ComDaGroupItem item = null;

                        if (!m_itemsByMonitoredItem.TryGetValue(clientHandle, out item))
                        {
                            continue;
                        }

                        // convert data change.
                        DaValue result = m_manager.Mapper.GetLocalDataValue(notification.MonitoredItems[jj].Value);

                        // update cache.
                        UpdateCache(item, result, false);
                    }
                }
            }
            catch (Exception exception)
            {
                Utils.Trace("Unexpected error during CacheUpdate. {0}", exception.Message);
            }
        }
Exemple #20
0
        /// <summary>
        /// Handles a datachange notifications.
        /// </summary>
        private void MonitoredItem_Notification(Subscription subscription, DataChangeNotification notification, IList<string> stringTable)
        {
            if (!Object.ReferenceEquals(subscription, m_subscription))
            {
                return;
            }

            lock (m_lock)
            {
                for (int ii = 0; ii < notification.MonitoredItems.Count; ii++)
                {
                    MonitoredItem monitoredItem = m_subscription.FindItemByClientHandle(notification.MonitoredItems[ii].ClientHandle);

                    if (monitoredItem != null)
                    {
                        Opc.Ua.Server.MonitoredItem localItem = (Opc.Ua.Server.MonitoredItem)monitoredItem.Handle;
                        localItem.QueueValue(notification.MonitoredItems[ii].Value, null);
                    }
                }
            }
        }
Exemple #21
0
        /// <summary>
        /// Raised when a publish response arrives from the server.
        /// </summary>
        static void Session_Notification(Session session, NotificationEventArgs e)
        {
            NotificationMessage message = e.NotificationMessage;

            // check for keep alive.
            if (message.NotificationData.Count == 0)
            {
                Console.WriteLine(
                    "===>>> Subscription KeepAlive: SubscriptionId={0} MessageId={1} Time={2:HH:mm:ss.fff}",
                    e.Subscription.Id,
                    message.SequenceNumber,
                    message.PublishTime.ToLocalTime());

                return;
            }

            DataChangeNotification dcn = (DataChangeNotification)ExtensionObject.ToEncodeable(message.NotificationData[0]);
            // Console.WriteLine("{0:mm:ss.fff} - SeqNo={1}, Items={2}", message.PublishTime, message.SequenceNumber, dcn.MonitoredItems.Count);

            int count = 0;

            // get the data changes (oldest to newest).
            foreach (MonitoredItemNotification datachange in message.GetDataChanges(false))
            {
                // lookup the monitored item.
                MonitoredItem monitoredItem = e.Subscription.FindItemByClientHandle(datachange.ClientHandle);

                if (monitoredItem == null)
                {
                    Console.WriteLine("MonitoredItem ClientHandle not known: {0}", datachange.ClientHandle);
                    continue;
                }

                // this is called on another thread so we need to synchronize before accessing the node.
                lock (m_lock)
                {
                    NodeOfInterest node = monitoredItem.Handle as NodeOfInterest;

                    //Console.WriteLine(
                    //    "Update for {0}: {1} Status={2} Timestamp={3:HH:mm:ss.fff}",
                    //    node.DisplayName,
                    //    datachange.Value.WrappedValue,
                    //    datachange.Value.StatusCode,
                    //    datachange.Value.SourceTimestamp.ToLocalTime());

                    node.Value = datachange.Value;
                    Save(datachange.ClientHandle, node.Value);
                    count++;
                }
            }

            if (count > NotificationsPerPublish)
            {
                Console.WriteLine("Too many notifications in Publish: {0}/{1}", count, NotificationsPerPublish);
            }

            lock (m_publishes)
            {
                m_notifications++;

                if (m_lastDump.AddSeconds(1) > DateTime.UtcNow)
                {
                    return;
                }

                int sampleCount = 0;
                int itemCount   = 0;

                DateTime timestamp = DateTime.MinValue;

                while (m_publishes.Count > 0)
                {
                    DataValue value1 = m_publishes.Dequeue();

                    if (timestamp < value1.SourceTimestamp)
                    {
                        if (timestamp != DateTime.MinValue)
                        {
                            //Console.WriteLine(
                            //    "Items = {1}, Timestamp = {0:mm:ss.fff}",
                            //    timestamp,
                            //    itemCount);
                        }

                        timestamp = value1.SourceTimestamp;
                        itemCount = 0;
                    }

                    sampleCount++;
                    itemCount++;
                }

                //Console.WriteLine(
                //    "Items = {1}, Timestamp = {0:mm:ss.fff}",
                //    timestamp,
                //    itemCount);

                uint expectedSamples       = 10000; // (uint)((1000.0/SamplingInterval)*ItemsToMonitor);
                uint expectedNotifications = 50;

                Console.WriteLine(
                    "{0:mm:ss.fff}-{1:mm:ss.fff}, Messages = {2}/{3}, Samples = {4}/{5}, MissedSamples = {6}",
                    m_lastDump,
                    m_lastDump.AddSeconds(1),
                    m_notifications,
                    expectedNotifications,
                    sampleCount,
                    expectedSamples,
                    (int)m_expectedSamples - (int)m_actualSamples);

                m_lastDump    = m_lastDump.AddSeconds(1);
                m_lastMessage = message.SequenceNumber;
                m_dumpCount++;
                m_notifications = 0;

                m_actualSamples   += (uint)sampleCount;
                m_expectedSamples += expectedSamples;

                if (m_dumpCount == 10)
                {
                    m_actualSamples   = 0;
                    m_expectedSamples = 0;
                }
            }
        }
Exemple #22
0
        /// <summary>
        /// Checks if the subscription is ready to publish and returns a notification message.
        /// </summary>
        public NotificationMessage Publish()
        {
            lock (m_lock)
            {
                long currentTime = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;

                // check of it is time for a publish.
                if (m_lastPublishTime + m_publishingInterval < currentTime)
                {
                    ListOfMonitoredItemNotification notifications   = new ListOfMonitoredItemNotification();
                    ListOfDiagnosticInfo            diagnosticInfos = new ListOfDiagnosticInfo();

                    // check each monitored item for data changes to send.
                    foreach (MonitoredItem monitoredItem in m_monitoredItems.Values)
                    {
                        while (monitoredItem.Values.Count > 0)
                        {
                            MonitoredItemNotification notification = new MonitoredItemNotification();

                            notification.ClientHandle = monitoredItem.Parameters.ClientHandle;
                            notification.Value        = monitoredItem.Values.Dequeue();

                            notifications.Add(notification);
                            diagnosticInfos.Add(monitoredItem.DiagnosticInfos.Dequeue());
                        }
                    }

                    // check if any notifications were found.
                    if (notifications.Count > 0)
                    {
                        // subscriptions can produce different types of notifications so the notification parameter
                        // is an extensible parameter. This means the object must be manually serialized and wrapped in
                        // an ExtensionObject which specifies the type of data contained in the Body. The complete
                        // UA SDK takes care this housekeeping and will serialize extensible parameters automatically.

                        DataChangeNotification body = new DataChangeNotification();

                        body.MonitoredItems  = notifications;
                        body.DiagnosticInfos = diagnosticInfos;

                        ExtensionObject extension = new ExtensionObject(
                            new ExpandedNodeId(Objects.DataChangeNotification_Encoding_DefaultXml),
                            body);

                        // construct the message and assign a new sequence number.
                        NotificationMessage message = new NotificationMessage();

                        message.SequenceNumber   = ++m_nextSequenceNumber;
                        message.PublishTime      = DateTime.UtcNow;
                        message.NotificationData = new ListOfExtensionObject();

                        message.NotificationData.Add(extension);

                        m_lastPublishTime   = currentTime;
                        m_nextKeepAliveTime = (long)(currentTime + m_publishingInterval * m_keepAliveCount);

                        return(message);
                    }
                }

                // check if it is time for a keep alive.
                if (m_nextKeepAliveTime < currentTime)
                {
                    NotificationMessage message = new NotificationMessage();

                    message.SequenceNumber   = m_nextSequenceNumber;
                    message.PublishTime      = DateTime.UtcNow;
                    message.NotificationData = new ListOfExtensionObject();

                    m_nextKeepAliveTime = (long)(currentTime + m_publishingInterval * m_keepAliveCount);

                    return(message);
                }

                return(null);
            }
        }
            /// <summary>
            /// Subscription data changed
            /// </summary>
            /// <param name="subscription"></param>
            /// <param name="notification"></param>
            /// <param name="stringTable"></param>
            private void OnSubscriptionDataChanged(Subscription subscription,
                                                   DataChangeNotification notification, IList <string> stringTable)
            {
                try {
                    if (OnSubscriptionChange == null)
                    {
                        return;
                    }
                    if (notification == null)
                    {
                        _logger.Warning("DataChange for subscription: {Subscription} having empty notification",
                                        subscription.DisplayName);
                        return;
                    }

                    if (_currentlyMonitored == null)
                    {
                        _logger.Information("DataChange for subscription: {Subscription} having no monitored items yet",
                                            subscription.DisplayName);
                        return;
                    }

                    // check if notification is a keep alive
                    var isKeepAlive = notification?.MonitoredItems?.Count == 1 &&
                                      notification?.MonitoredItems?.First().ClientHandle == 0 &&
                                      notification?.MonitoredItems?.First().Message?.NotificationData?.Count == 0;
                    var sequenceNumber = notification?.MonitoredItems?.First().Message?.SequenceNumber;
                    var publishTime    = (notification?.MonitoredItems?.First().Message?.PublishTime).
                                         GetValueOrDefault(DateTime.MinValue);

                    _logger.Debug("DataChange for subscription: {Subscription}, sequence#: " +
                                  "{Sequence} isKeepAlive{KeepAlive}, publishTime: {PublishTime}",
                                  subscription.DisplayName, sequenceNumber, isKeepAlive, publishTime);

                    var message = new SubscriptionNotificationModel {
                        ServiceMessageContext = subscription.Session.MessageContext,
                        ApplicationUri        = subscription.Session.Endpoint.Server.ApplicationUri,
                        EndpointUrl           = subscription.Session.Endpoint.EndpointUrl,
                        SubscriptionId        = Id,
                        Notifications         = (!isKeepAlive)
                            ? notification.ToMonitoredItemNotifications(
                            subscription.MonitoredItems).ToList()
                            : new List <MonitoredItemNotificationModel>()
                    };
                    message.IsKeyMessage = true;

                    // add the heartbeat for monitored items that did not receive a a datachange notification
                    // Try access lock if we cannot continue...
                    List <MonitoredItemWrapper> currentlyMonitored = null;
                    if (_lock.Wait(0))
                    {
                        try {
                            currentlyMonitored = _currentlyMonitored;
                        }
                        finally {
                            _lock.Release();
                        }
                    }
                    if (currentlyMonitored != null)
                    {
                        // add the heartbeat for monitored items that did not receive a
                        // a datachange notification
                        foreach (var item in currentlyMonitored)
                        {
                            if (isKeepAlive ||
                                !notification.MonitoredItems.Exists(m => m.ClientHandle == item.Item.ClientHandle))
                            {
                                if (item.TriggerHeartbeat(publishTime))
                                {
                                    var heartbeatValue = item.Item.LastValue.ToMonitoredItemNotification(item.Item);
                                    if (heartbeatValue != null)
                                    {
                                        heartbeatValue.SequenceNumber = sequenceNumber;
                                        heartbeatValue.IsHeartbeat    = true;
                                        heartbeatValue.PublishTime    = publishTime;
                                        message.Notifications.Add(heartbeatValue);
                                    }
                                }
                                else
                                {
                                    // just reset the heartbeat for the items already processed
                                    item.TriggerHeartbeat(publishTime);
                                }
                            }
                        }
                    }
                    OnSubscriptionChange?.Invoke(this, message);
                }
                catch (Exception ex) {
                    _logger.Debug(ex, "Exception processing subscription notification");
                }
            }
        private void OnDataChange(Subscription subscription, DataChangeNotification notification, IList<string> stringTable)
        {
            if (!Object.ReferenceEquals(subscription, m_subscription))
            {
                return;
            }

            if (this.InvokeRequired)
            {
                this.BeginInvoke(new FastDataChangeNotificationEventHandler(OnDataChange), subscription, notification, stringTable);
                return;
            }

            try
            {
                foreach (MonitoredItemNotification itemNotification in notification.MonitoredItems)
                {
                    MonitoredItem monitoredItem = subscription.FindItemByClientHandle(itemNotification.ClientHandle);

                    if (monitoredItem == null)
                    {
                        continue;
                    }

                    DataRow row = (DataRow)monitoredItem.Handle;

                    if (row.RowState == DataRowState.Detached)
                    {
                        continue;
                    }

                    UpdateRow(row, itemNotification);

                    if (m_EditComplexValueDlg != null && Object.ReferenceEquals(m_EditComplexValueDlg.Tag, monitoredItem))
                    {
                        m_EditComplexValueDlg.UpdateValue(monitoredItem.ResolvedNodeId, monitoredItem.AttributeId, null, itemNotification.Value.Value);
                    }
                }
            }
            catch (Exception exception)
            {
                ClientUtils.HandleException(this.Text, exception);
            }
        }
Exemple #25
0
        /// <summary>
        /// Checks if the subscription is ready to publish and returns a notification message.
        /// </summary>
        public NotificationMessage Publish()
        {
            lock (m_lock)
            {
                long currentTime = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;

                // check of it is time for a publish.
                if (m_lastPublishTime + m_publishingInterval < currentTime)
                {
                    ListOfMonitoredItemNotification notifications = new ListOfMonitoredItemNotification();
                    ListOfDiagnosticInfo diagnosticInfos = new ListOfDiagnosticInfo();

                    // check each monitored item for data changes to send.
                    foreach (MonitoredItem monitoredItem in m_monitoredItems.Values)
                    {
                        while (monitoredItem.Values.Count > 0)
                        {
                            MonitoredItemNotification notification = new MonitoredItemNotification();

                            notification.ClientHandle = monitoredItem.Parameters.ClientHandle;
                            notification.Value = monitoredItem.Values.Dequeue();

                            notifications.Add(notification);
                            diagnosticInfos.Add(monitoredItem.DiagnosticInfos.Dequeue());
                        }
                    }

                    // check if any notifications were found.
                    if (notifications.Count > 0)
                    {
                        // subscriptions can produce different types of notifications so the notification parameter 
                        // is an extensible parameter. This means the object must be manually serialized and wrapped in
                        // an ExtensionObject which specifies the type of data contained in the Body. The complete
                        // UA SDK takes care this housekeeping and will serialize extensible parameters automatically.

                        DataChangeNotification body = new DataChangeNotification();

                        body.MonitoredItems = notifications;
                        body.DiagnosticInfos = diagnosticInfos;
                        
                        ExtensionObject extension = new ExtensionObject(
                            new ExpandedNodeId(Objects.DataChangeNotification_Encoding_DefaultXml),
                            body);

                        // construct the message and assign a new sequence number.
                        NotificationMessage message = new NotificationMessage();

                        message.SequenceNumber = ++m_nextSequenceNumber;
                        message.PublishTime = DateTime.UtcNow;
                        message.NotificationData = new ListOfExtensionObject();

                        message.NotificationData.Add(extension);

                        m_lastPublishTime = currentTime;
                        m_nextKeepAliveTime = (long)(currentTime + m_publishingInterval * m_keepAliveCount);

                        return message;
                    }
                }

                // check if it is time for a keep alive.
                if (m_nextKeepAliveTime < currentTime)
                {
                    NotificationMessage message = new NotificationMessage();

                    message.SequenceNumber = m_nextSequenceNumber;
                    message.PublishTime = DateTime.UtcNow;
                    message.NotificationData = new ListOfExtensionObject();

                    m_nextKeepAliveTime = (long)(currentTime + m_publishingInterval * m_keepAliveCount);

                    return message;
                }

                return null;
            }
        }
        /// <summary>
        /// Verifies that the initial data change was received.
        /// </summary>
        private bool VerifyInitialDataChange(
            Subscription subscription,
            DataChangeNotification notification,
            DateTime receiveTime,
            IList<MonitoredItem> monitoredItems,
            ref int totalCount,
            Dictionary<uint,MonitoredItem> updatedItems)
        {
            bool success = true;
            bool errorReported = false;

            // determine the maximum requested diagnostics.
            uint diagnosticsMask = 0;
            DiagnosticInfoCollection diagnosticInfos = notification.DiagnosticInfos;
       
            for (int ii = 0; ii < notification.MonitoredItems.Count; ii++)
            {
                totalCount++;

                MonitoredItemNotification update = notification.MonitoredItems[ii];

                // find matching item.
                MonitoredItem monitoredItem = null;

                for (int jj = 0; jj < monitoredItems.Count; jj++)
                {
                    monitoredItem =  monitoredItems[jj];

                    if (update.ClientHandle == monitoredItem.ClientHandle)
                    {
                        MonitoredItem existingItem = null;

                        if (updatedItems.TryGetValue(update.ClientHandle, out existingItem))
                        {
                            Log(
                                "Unexpected notification returned from server for MonitoredItem. ClientHandle = {0}, Node = {1}, Attribute = {2}, NewValue = {3}, OldValue={4}",
                                update.ClientHandle,
                                monitoredItem.Node,
                                Attributes.GetBrowseName(monitoredItem.AttributeId),
                                update.Value.WrappedValue,
                                existingItem.Value.Value);
                        }

                        updatedItems[update.ClientHandle] = monitoredItem;
                        break;
                    }

                    monitoredItem = null;
                }

                if (monitoredItem == null)
                {
                    Log(
                        "Unexpected notification returned from server for Node. ClientHandle = {0}, Value = {1}",
                        update.ClientHandle,
                        update.Value.WrappedValue);

                    success = false;
                    break;
                }
                
                if (monitoredItem.Value != null)
                {
                    Log(
                        "Duplicate notification for MonitoredItem for Node {0}. NodeId = {1}, AttributeId = {2}",
                        monitoredItem.Node,
                        monitoredItem.Node.NodeId,
                        Attributes.GetBrowseName(monitoredItem.AttributeId));

                    success = false;
                    break;
                }

                double initialDelay = CalculateInterval(monitoredItem.UpdateTime, receiveTime);

                if (initialDelay > subscription.PublishingInterval + m_idealTimingError)
                {
                    bool fatal = initialDelay > subscription.PublishingInterval*2;

                    if (!errorReported)
                    {
                        Log(
                            "{0}: Late notification for MonitoredItem for Node {1}. NodeId = {2}, AttributeId = {3}, Delay = {4}ms, MaxDelay = {5}ms",
                            "TIMING ERROR",
                            monitoredItem.Node,
                            monitoredItem.Node.NodeId,
                            Attributes.GetBrowseName(monitoredItem.AttributeId),
                            initialDelay,
                            subscription.PublishingInterval);

                        errorReported = true;
                    }

                    if (fatal)
                    {
                        success = false;
                        break;
                    }
                }
                
                monitoredItem.Value = update.Value;
                
                // verify timestamps.
                if (!VerifyTimestamps(monitoredItem.Node, monitoredItem.AttributeId, monitoredItem.TimestampsToReturn, update.Value))
                {
                    success = false;
                    break;
                }
                    
                // check if diagnostics could exist.
                if (update.Value.StatusCode != StatusCodes.Good)
                {
                    diagnosticsMask |= monitoredItem.DiagnosticsMasks;

                    if ((monitoredItem.DiagnosticsMasks & (uint)DiagnosticsMasks.OperationAll) != 0)
                    {
                        if (diagnosticInfos == null || diagnosticInfos.Count < ii || diagnosticInfos[ii] == null)
                        {
                            Log(
                                "Missing DiagnosticInfo for MonitoredItem for Node {0}. NodeId = {1}, AttributeId = {2}",
                                monitoredItem.Node,
                                monitoredItem.Node.NodeId,
                                Attributes.GetBrowseName(monitoredItem.AttributeId));

                            success = false;
                            break;
                        }
                    }
                }

                // verify error.
                if (StatusCode.IsBad(update.Value.StatusCode))
                {
                    if (!VerifyBadAttribute(monitoredItem.Node, monitoredItem.AttributeId, update.Value.StatusCode))
                    {
                        success = false;
                        break;                   
                    }

                    continue;
                }
                    
                // verify success.
                if (!VerifyGoodAttribute(monitoredItem.Node, monitoredItem.AttributeId, update.Value))
                {
                    success = false;
                    break;                 
                }
            }

            // check for unnecessary diagnostics.
            if ((diagnosticsMask & (uint)DiagnosticsMasks.OperationAll) == 0)
            {
                if (diagnosticInfos != null && diagnosticInfos.Count > 0)
                {
                    Log("Returned non-empty DiagnosticInfos array during Publish.");
                    return false;
                }
            }

            return success;
        }
        /// <summary>
        /// The delegate used to receive data change notifications via a direct function call instead of a .NET Event.
        /// </summary>
        public void OnDataChangeNotification(Opc.Ua.Client.Subscription subscription, DataChangeNotification notification, IList<string> stringTable)
        {
            for (int ii = 0; ii < notification.MonitoredItems.Count; ii++)
            {
                MonitoredItem localItem = null;
                DataValue value = null;
                ServiceResult error = null;

                lock (subscription.Session)
                {
                    Opc.Ua.Client.MonitoredItem monitoredItem = subscription.FindItemByClientHandle(notification.MonitoredItems[ii].ClientHandle);

                    if (monitoredItem != null)
                    {
                        MonitoredItemNotification value2 = notification.MonitoredItems[ii];

                        if (value2.Value.StatusCode != StatusCodes.Good)
                        {
                            error = new ServiceResult(value2.Value.StatusCode, value2.DiagnosticInfo, stringTable);
                        }

                        value = value2.Value;
                        value.WrappedValue = m_mapper.ToLocalVariant(value2.Value.WrappedValue);
                        value.ServerTimestamp = DateTime.UtcNow;

                        localItem = (MonitoredItem)monitoredItem.Handle;
                    }
                }

                localItem.QueueValue(value, error);
            }
        }