コード例 #1
0
 /// <summary>
 /// Get the Filter as per part 11 5.3.2: A Historical Event Node that
 /// has Event history available will provide the HistoricalEventFilter
 /// Property which has the filter used by the Server to determine which
 /// HistoricalEventNode fields are available in history.  It may also
 /// include a where clause that indicates the types of Events or
 /// restrictions on the Events that are available via the Historical
 /// Event Node.
 /// </summary>
 /// <param name="ct"></param>
 /// <returns></returns>
 private Task <EventFilter> ReadEventFilterAsync(CancellationToken ct)
 {
     return(_client.ExecuteServiceAsync(_endpoint, _elevation, _priority, ct,
                                        async session => {
         _encoder.Context.UpdateFromSession(session);
         var nodeId = _nodeId.ToNodeId(session.MessageContext);
         var filterNode = await session.TranslateBrowsePathsToNodeIdsAsync(null,
                                                                           new BrowsePathCollection {
             new BrowsePath {
                 StartingNode = nodeId,
                 RelativePath = new RelativePath(
                     BrowseNames.HistoricalEventFilter)
             }
         });
         if (!filterNode.Results.Any() || !filterNode.Results[0].Targets.Any())
         {
             return null;
         }
         var read = await RawNodeModel.ReadValueAsync(session, null,
                                                      (NodeId)filterNode.Results[0].Targets[0].TargetId, _diagnostics, false);
         if (ExtensionObject.ToEncodeable(read.Value.Value as ExtensionObject)
             is EventFilter eventFilter)
         {
             return eventFilter;
         }
         return null;
     }));
 }
コード例 #2
0
        /// <summary>
        /// Initialize Connection properties from connection configuration object
        /// </summary>
        private void Initialize()
        {
            PubSubConnectionDataType            pubSubConnectionConfiguration = m_udpConnection.PubSubConnectionConfiguration;
            DatagramConnectionTransportDataType transportSettings             = ExtensionObject.ToEncodeable(pubSubConnectionConfiguration.TransportSettings)
                                                                                as DatagramConnectionTransportDataType;

            if (transportSettings != null && transportSettings.DiscoveryAddress != null)
            {
                NetworkAddressUrlDataType discoveryNetworkAddressUrlState = ExtensionObject.ToEncodeable(transportSettings.DiscoveryAddress)
                                                                            as NetworkAddressUrlDataType;
                if (discoveryNetworkAddressUrlState != null)
                {
                    Utils.Trace(Utils.TraceMasks.Information, "The configuration for connection {0} has custom DiscoveryAddress configuration.",
                                pubSubConnectionConfiguration.Name);

                    DiscoveryNetworkInterfaceName   = discoveryNetworkAddressUrlState.NetworkInterface;
                    DiscoveryNetworkAddressEndPoint = UdpClientCreator.GetEndPoint(discoveryNetworkAddressUrlState.Url);
                }
            }

            if (DiscoveryNetworkAddressEndPoint == null)
            {
                Utils.Trace(Utils.TraceMasks.Information, "The configuration for connection {0} will use the default DiscoveryAddress: {1}.",
                            pubSubConnectionConfiguration.Name, kDefaultDiscoveryUrl);

                DiscoveryNetworkAddressEndPoint = UdpClientCreator.GetEndPoint(kDefaultDiscoveryUrl);
            }
        }
コード例 #3
0
        /// <summary>
        /// Atempt to Decode dataset
        /// </summary>
        /// <returns></returns>
        public void DecodePossibleDataSetReader(BinaryDecoder binaryDecoder, DataSetReaderDataType dataSetReader)
        {
            UadpDataSetReaderMessageDataType messageSettings = ExtensionObject.ToEncodeable(dataSetReader.MessageSettings)
                                                               as UadpDataSetReaderMessageDataType;

            if (messageSettings != null)
            {
                //StartPositionInStream is calculated but different from reader configuration dataset cannot be decoded
                if (StartPositionInStream != messageSettings.DataSetOffset)
                {
                    if (StartPositionInStream == 0)
                    {
                        //use configured offset from reader
                        StartPositionInStream = messageSettings.DataSetOffset;
                    }
                    else if (messageSettings.DataSetOffset != 0)
                    {
                        //configuration is different from real position in message, the dataset cannot be decoded
                        return;
                    }
                }
                else
                {
                    StartPositionInStream = (int)(binaryDecoder.BaseStream.Position);
                }
            }
            if (binaryDecoder.BaseStream.Length <= StartPositionInStream)
            {
                return;
            }
            binaryDecoder.BaseStream.Position = StartPositionInStream;
            DecodeDataSetMessageHeader(binaryDecoder);
            DataSet = DecodeFieldMessageData(binaryDecoder, dataSetReader);
        }
コード例 #4
0
        private void ShowResults()
        {
            GoBTN.Visibility   = (m_result == null || m_result.ContinuationPoint == null || m_result.ContinuationPoint.Length == 0)? Windows.UI.Xaml.Visibility.Visible : Windows.UI.Xaml.Visibility.Collapsed;
            NextBTN.Visibility = (GoBTN.Visibility == Windows.UI.Xaml.Visibility.Collapsed)? Windows.UI.Xaml.Visibility.Visible : Windows.UI.Xaml.Visibility.Collapsed;
            StopBTN.IsEnabled  = (m_result != null && m_result.ContinuationPoint != null && m_result.ContinuationPoint.Length > 0);

            if (m_result == null)
            {
                return;
            }

            HistoryData results = ExtensionObject.ToEncodeable(m_result.HistoryData) as HistoryData;

            if (results == null)
            {
                return;
            }

            for (int ii = 0; ii < results.DataValues.Count; ii++)
            {
                StatusCode status = results.DataValues[ii].StatusCode;

                string index       = Utils.Format("[{0}]", m_index++);
                string timestamp   = results.DataValues[ii].SourceTimestamp.ToLocalTime().ToString("yyyy-MM-dd hh:mm:ss");
                string value       = Utils.Format("{0}", results.DataValues[ii].WrappedValue);
                string quality     = Utils.Format("{0}", (StatusCode)status.CodeBits);
                string historyInfo = Utils.Format("{0:X2}", (int)status.AggregateBits);

                ListViewItem item = new ListViewItem();
                item.Name = index;

                ResultsLV.Items.Add(item);
            }
        }
コード例 #5
0
        public void ValidateUadpPubSubConnectionCreateNetworkMessage()
        {
            Assert.IsNotNull(m_uadpPublisherConnection, "The UADP connection from standard configuration is invalid.");

            //Arrange
            WriterGroupDataType            writerGroup0    = m_uadpPublisherConnection.PubSubConnectionConfiguration.WriterGroups[0];
            UadpWriterGroupMessageDataType messageSettings = ExtensionObject.ToEncodeable(writerGroup0.MessageSettings)
                                                             as UadpWriterGroupMessageDataType;

            //Act
            m_uadpPublisherConnection.ResetSequenceNumber();
            UadpNetworkMessage networkMessage0 = m_uadpPublisherConnection.CreateNetworkMessage(writerGroup0) as UadpNetworkMessage;

            //Assert
            Assert.IsNotNull(networkMessage0, "CreateNetworkMessage did not return an UadpNetworkMessage.");

            Assert.AreEqual(networkMessage0.DataSetClassId, Guid.Empty, "UadpNetworkMessage.DataSetClassId is invalid.");
            Assert.AreEqual(networkMessage0.WriterGroupId, writerGroup0.WriterGroupId, "UadpNetworkMessage.WriterGroupId is invalid.");
            Assert.AreEqual(networkMessage0.UADPVersion, 1, "UadpNetworkMessage.UADPVersion is invalid.");
            Assert.AreEqual(networkMessage0.SequenceNumber, 1, "UadpNetworkMessage.SequenceNumber is not 1.");
            Assert.AreEqual(networkMessage0.GroupVersion, messageSettings.GroupVersion, "UadpNetworkMessage.GroupVersion is not valid.");
            Assert.AreEqual(networkMessage0.PublisherId, m_uadpPublisherConnection.PubSubConnectionConfiguration.PublisherId.Value,
                            "UadpNetworkMessage.PublisherId is not valid.");
            Assert.IsNotNull(networkMessage0.UadpDataSetMessages, "UadpNetworkMessage.UadpDataSetMessages is null.");
            Assert.AreEqual(networkMessage0.UadpDataSetMessages.Count, 3, "UadpNetworkMessage.UadpDataSetMessages.Count is not 3.");
            //validate flags
            Assert.AreEqual((uint)networkMessage0.NetworkMessageContentMask, messageSettings.NetworkMessageContentMask,
                            "UadpNetworkMessage.messageSettings.NetworkMessageContentMask is not valid.");
        }
コード例 #6
0
        /// <summary>
        /// The service result for a field in an notification (the field must contain a Status object).
        /// </summary>
        public static ServiceResult GetServiceResult(IEncodeable notification, int index)
        {
            EventFieldList eventFields = notification as EventFieldList;

            if (eventFields == null)
            {
                return(null);
            }

            NotificationMessage message = eventFields.Message;

            if (message != null)
            {
                return(null);
            }

            if (index < 0 || index >= eventFields.EventFields.Count)
            {
                return(null);
            }

            StatusResult status =
                ExtensionObject.ToEncodeable(eventFields.EventFields[index].Value as ExtensionObject) as StatusResult;

            if (status == null)
            {
                return(null);
            }

            return(new ServiceResult(status.StatusCode, status.DiagnosticInfo, message.StringTable));
        }
コード例 #7
0
        public override void Execute(OpcSession session)
        {
            LogExecutionStart(session);
            NormalizeNodeId(session);
            HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection
            {
                new HistoryReadValueId {
                    NodeId = OpcUaNodeId
                }
            };

            Opc.Ua.Client.Session uaSession = session.OpcUaClientSession;
            Logger.Debug("About to perform a HistoryRead:");
            Logger.Debug("Details:");
            Logger.Debug($"  Start time:  {details.StartTime}");
            Logger.Debug($"  End time:  {details.EndTime}");
            Logger.Debug($"  Read modified:  {details.IsReadModified}");
            Logger.Debug($"  Values per node:  {details.NumValuesPerNode}");
            Logger.Debug($"  Return bounds:  {details.ReturnBounds}");
            Logger.Debug("Nodes to read:");
            nodesToRead.ForEach(n => Logger.Debug($"  {n}({n.NodeId})"));
            uaSession.HistoryRead(
                null,
                new ExtensionObject(details),
                TimestampsToReturn.Both,
                false,
                nodesToRead,
                out HistoryReadResultCollection results,
                out DiagnosticInfoCollection diagnostics
                );
            Logger.Debug($"HistoryRead got {results.Count} results, {diagnostics.Count} diagnostics.");
            HistoryReadResult hrr      = results[0];
            HistoryData       histData = (HistoryData)ExtensionObject.ToEncodeable(hrr.HistoryData);

            if (StatusCode.IsBad(hrr.StatusCode))
            {
                Logger.Information($"Bad result ({hrr.StatusCode}) reading {OpcNodeId}");
            }
            else
            {
                if (StatusCode.IsGood(hrr.StatusCode))
                {
                    Logger.Debug($"Good result: {histData}, {histData.DataValues.Count} values.");
                }
                if (StatusCode.IsUncertain(hrr.StatusCode))
                {
                    Logger.Information($"Uncertain result: {hrr}");
                }
            }
            foreach (DataValue dv in histData.DataValues)
            {
                Logger.Debug($"  {dv} ({dv.SourceTimestamp})");
                dataValue1 = new DataValue();                 // Acá debería asignarse algo que viene desde «results».
                if (Program.HaveToWriteCsv)
                {
                    WriteDataValueToCsvFile(dv);
                }
            }
        }
コード例 #8
0
        /// <summary>
        /// Modifies the parameters for a monitored item.
        /// </summary>
        protected override ServiceResult ModifyMonitoredItem(
            ISystemContext context,
            DiagnosticsMasks diagnosticsMasks,
            TimestampsToReturn timestampsToReturn,
            IMonitoredItem monitoredItem,
            MonitoredItemModifyRequest itemToModify,
            out MonitoringFilterResult filterError)
        {
            filterError = null;

            // check for valid handle.
            MemoryBufferState buffer = monitoredItem.ManagerHandle as MemoryBufferState;

            if (buffer == null)
            {
                return(base.ModifyMonitoredItem(
                           context,
                           diagnosticsMasks,
                           timestampsToReturn,
                           monitoredItem,
                           itemToModify,
                           out filterError));
            }

            // owned by this node manager.
            itemToModify.Processed = true;

            // get the monitored item.
            MemoryBufferMonitoredItem datachangeItem = monitoredItem as MemoryBufferMonitoredItem;

            if (datachangeItem == null)
            {
                return(StatusCodes.BadMonitoredItemIdInvalid);
            }

            // validate parameters.
            MonitoringParameters parameters = itemToModify.RequestedParameters;

            // no filters supported at this time.
            MonitoringFilter filter = (MonitoringFilter)ExtensionObject.ToEncodeable(parameters.Filter);

            if (filter != null)
            {
                return(StatusCodes.BadFilterNotAllowed);
            }

            // modify the monitored item parameters.
            ServiceResult error = datachangeItem.Modify(
                diagnosticsMasks,
                timestampsToReturn,
                itemToModify.RequestedParameters.ClientHandle,
                itemToModify.RequestedParameters.SamplingInterval);

            return(ServiceResult.Good);
        }
コード例 #9
0
            /// <summary>
            /// Create new instance of <see cref="MetaDataState"/>
            /// </summary>
            /// <param name="dataSetWriter"></param>
            public MetaDataState(DataSetWriterDataType dataSetWriter)
            {
                DataSetWriter = dataSetWriter;
                LastSendTime  = DateTime.MinValue;

                BrokerDataSetWriterTransportDataType transport =
                    ExtensionObject.ToEncodeable(DataSetWriter.TransportSettings)
                    as BrokerDataSetWriterTransportDataType;

                MetaDataUpdateTime = transport?.MetaDataUpdateTime ?? 0;
            }
コード例 #10
0
        /// <summary>
        /// read History data
        /// </summary>
        /// <param name="tag">节点的索引</param>
        /// <param name="start">开始时间</param>
        /// <param name="end">结束时间</param>
        /// <param name="count">读取的个数</param>
        /// <param name="containBound">是否包含边界</param>
        /// <returns>读取的数据列表</returns>
        public IEnumerable <DataValue> ReadHistoryRawDataValues(string tag, DateTime start, DateTime end, uint count = 1, bool containBound = false)
        {
            HistoryReadValueId m_nodeToContinue = new HistoryReadValueId()
            {
                NodeId = new NodeId(tag),
            };

            RequestHeader requestHeader = new RequestHeader();

            ReadRawModifiedDetails m_details = new ReadRawModifiedDetails
            {
                StartTime        = start.ToUniversalTime(),
                EndTime          = end.ToUniversalTime(),
                NumValuesPerNode = count,
                IsReadModified   = false,
                ReturnBounds     = containBound
            };

            HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();

            nodesToRead.Add(m_nodeToContinue);


            m_session.HistoryRead(
                requestHeader,
                new ExtensionObject(m_details),
                TimestampsToReturn.Both,
                false,
                nodesToRead,
                out HistoryReadResultCollection results,
                out DiagnosticInfoCollection diagnosticInfos);

            ClientBase.ValidateResponse(results, nodesToRead);
            ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);

            if (StatusCode.IsBad(results[0].StatusCode))
            {
                throw new ServiceResultException(results[0].StatusCode);
            }

            if (results[0].HistoryData != null)
            {
                HistoryData values = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;
                foreach (var value in values.DataValues)
                {
                    if (value.SourceTimestamp < m_details.StartTime || value.SourceTimestamp > m_details.EndTime)
                    {
                        var difference = (m_details.StartTime - value.SourceTimestamp).Hours;
                        value.SourceTimestamp = value.SourceTimestamp.AddHours(difference);
                    }
                    yield return(value);
                }
            }
        }
コード例 #11
0
        /// <summary>
        /// Continues a read operation.
        /// </summary>
        private void ReadNext(ReadEventDetails details, HistoryReadValueId nodeToRead)
        {
            HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();

            nodesToRead.Add(nodeToRead);

            HistoryReadResultCollection results         = null;
            DiagnosticInfoCollection    diagnosticInfos = null;

            ResponseHeader responseHeader = m_session.HistoryRead(
                null,
                new ExtensionObject(details),
                TimestampsToReturn.Neither,
                false,
                nodesToRead,
                out results,
                out diagnosticInfos);

            Session.ValidateResponse(results, nodesToRead);
            Session.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);

            if (StatusCode.IsBad(results[0].StatusCode))
            {
                throw ServiceResultException.Create(results[0].StatusCode, 0, diagnosticInfos, responseHeader.StringTable);
            }

            // display results.
            HistoryEvent data = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryEvent;

            ResultsLV.AddEventHistory(data);

            // check if a continuation point exists.
            if (results[0].ContinuationPoint != null && results[0].ContinuationPoint.Length > 0)
            {
                nodeToRead.ContinuationPoint = results[0].ContinuationPoint;

                NextBTN.Visible = true;
                StopBTN.Enabled = true;
                GoBTN.Visible   = false;
                m_details       = details;
                m_nodeToRead    = nodeToRead;
            }

            // all done.
            else
            {
                NextBTN.Visible = false;
                StopBTN.Enabled = false;
                GoBTN.Visible   = true;
                m_details       = null;
                m_nodeToRead    = null;
            }
        }
コード例 #12
0
        private void Notification_EventItem(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new MonitoredItemNotificationEventHandler(Notification_EventItem), monitoredItem, e);
                return;
            }

            if (!(e.NotificationValue is EventFieldList eventFieldList))
            {
                return;
            }

            // Add RfidScanResult to EnvodableFactory to decode event data
            EncodeableFactory.GlobalFactory.AddEncodeableType(typeof(RfidScanResult));
            ExtensionObject[] exObjArr = (ExtensionObject[])eventFieldList.EventFields[4].Value;

            // TBD: Event doen't contain RfidScanResult
            if (exObjArr == null)
            {
                return;
            }

            // Add event data to LV
            ListViewItem item = new ListViewItem(new[] { ((DateTime)eventFieldList.EventFields[0].Value).ToString("MM/dd/yyyy HH:mm:ss.fff", CultureInfo.InvariantCulture), eventFieldList.EventFields[3].ToString(), eventFieldList.EventFields[2].ToString() });

            EventDataLV.Items.Add(item);


            for (int i = 0; i < exObjArr.Length; i++)
            {
                RfidScanResult rfidScanResult = ExtensionObject.ToEncodeable(exObjArr[i]) as RfidScanResult;

                if (i == 0)
                {
                    EventDataLV.Items[EventDataLV.Items.Count - 1].SubItems.Add("EPCID");
                    EventDataLV.Items[EventDataLV.Items.Count - 1].SubItems.Add(rfidScanResult.ScanData.String);
                }
                else
                {
                    item = new ListViewItem(new[] { "", "", "", "EPCID", rfidScanResult.ScanData.String });
                    EventDataLV.Items.Add(item);
                }
                item = new ListViewItem(new[] { "", "", "", "RSSI", rfidScanResult.Sighting[0].Strength.ToString() });
                EventDataLV.Items.Add(item);
                item = new ListViewItem(new[] { "", "", "", "Power", rfidScanResult.Sighting[0].CurrentPowerLevel.ToString() });
                EventDataLV.Items.Add(item);
                item = new ListViewItem(new[] { "", "", "", "Antenna", rfidScanResult.Sighting[0].Antenna.ToString() });
                EventDataLV.Items.Add(item);
                item = new ListViewItem(new[] { "", "", "", "TimeStamp", rfidScanResult.Sighting[0].Timestamp.ToString("MM/dd/yyyy HH:mm:ss.fff", CultureInfo.InvariantCulture) });
                EventDataLV.Items.Add(item);
            }
        }
コード例 #13
0
        public async Task <TimeSeries> GetTimeSeriesAsync(DateTime dateTimeFrom, DateTime dateTimeTo,
                                                          double lessThen, double moreThen)
        {
            return(await Task.Run(() =>
            {
                var details = new ReadRawModifiedDetails
                {
                    StartTime = dateTimeFrom,
                    EndTime = dateTimeTo,
                    ReturnBounds = false
                };

                var nodesToRead = new HistoryReadValueIdCollection
                {
                    new HistoryReadValueId {
                        NodeId = NodeId
                    }
                };

                Client.Session.HistoryRead(
                    null,
                    new ExtensionObject(details),
                    TimestampsToReturn.Source,
                    false,
                    nodesToRead,
                    out var results,
                    out var diagnosticInfos);

                ClientBase.ValidateResponse(results, nodesToRead);
                ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);

                if (StatusCode.IsBad(results[0].StatusCode))
                {
                    throw new ServiceResultException(results[0].StatusCode);
                }

                var data = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;

                var ts = new TimeSeries();

                if (data == null)
                {
                    return ts;
                }

                foreach (var result in data.DataValues)
                {
                    ts.Add(result.SourceTimestamp.ToLocalTime(), (double)result.Value);
                }

                return ts;
            }));
        }
コード例 #14
0
        /// <summary>
        /// Perform specific Start tasks
        /// </summary>
        protected override Task InternalStart()
        {
            lock (m_lock)
            {
                //cleanup all existing UdpClient previously open
                InternalStop();

                NetworkAddressUrlDataType networkAddressUrlState = ExtensionObject.ToEncodeable(PubSubConnectionConfiguration.Address)
                                                                   as NetworkAddressUrlDataType;
                if (networkAddressUrlState == null)
                {
                    Utils.Trace(Utils.TraceMasks.Error, "The configuration for connection {0} has invalid Address configuration.",
                                this.PubSubConnectionConfiguration.Name);
                    return(Task.FromResult <object>(null));
                }
                NetworkInterfaceName   = networkAddressUrlState.NetworkInterface;
                NetworkAddressEndPoint = UdpClientCreator.GetEndPoint(networkAddressUrlState.Url);

                if (NetworkAddressEndPoint == null)
                {
                    Utils.Trace(Utils.TraceMasks.Error, "The configuration for connection {0} with Url:'{1}' resulted in an invalid endpoint.",
                                this.PubSubConnectionConfiguration.Name, networkAddressUrlState.Url);
                    return(Task.FromResult <object>(null));
                }

                //publisher initialization
                if (Publishers.Count > 0)
                {
                    m_publisherUdpClients = UdpClientCreator.GetUdpClients(UsedInContext.Publisher, networkAddressUrlState, NetworkAddressEndPoint);
                }

                //subscriber initialization
                if (GetAllDataSetReaders().Count > 0)
                {
                    m_subscriberUdpClients = UdpClientCreator.GetUdpClients(UsedInContext.Subscriber, networkAddressUrlState, NetworkAddressEndPoint);

                    foreach (UdpClient subscriberUdpClient in m_subscriberUdpClients)
                    {
                        try
                        {
                            subscriberUdpClient.BeginReceive(new AsyncCallback(OnUadpReceive), subscriberUdpClient);
                        }
                        catch (Exception ex)
                        {
                            Utils.Trace(Utils.TraceMasks.Information, "UdpClient '{0}' Cannot receive data. Exception: {1}",
                                        subscriberUdpClient.Client.LocalEndPoint, ex.Message);
                        }
                    }
                }
            }
            return(Task.FromResult <object>(null));
        }
コード例 #15
0
        public IEnumerable <DataValue> ReadHistoryProcessed(string tag, DateTime start, DateTime end, string aggregateFunction, double processingInterval, uint count = 1, bool containBound = false)
        {
            HistoryReadValueId m_nodeToContinue = new HistoryReadValueId()
            {
                NodeId = new NodeId(tag),
            };

            AggregateConfiguration aggregate      = new AggregateConfiguration();
            NodeIdCollection       aggregateTypes = new NodeIdCollection();

            aggregateTypes.Add(new NodeId(aggregateFunction));
            ReadProcessedDetails m_details = new ReadProcessedDetails
            {
                StartTime = start.ToUniversalTime(),
                EndTime   = end.ToUniversalTime(),
                AggregateConfiguration = aggregate,
                AggregateType          = aggregateTypes,
                ProcessingInterval     = processingInterval,
            };

            m_logger.Information("start {0}/end {0}", m_details.StartTime, m_details.EndTime);

            HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();

            nodesToRead.Add(m_nodeToContinue);


            m_session.HistoryRead(
                null,
                new ExtensionObject(m_details),
                TimestampsToReturn.Both,
                false,
                nodesToRead,
                out HistoryReadResultCollection results,
                out DiagnosticInfoCollection diagnosticInfos);

            ClientBase.ValidateResponse(results, nodesToRead);
            ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);

            if (StatusCode.IsBad(results[0].StatusCode))
            {
                throw new ServiceResultException(results[0].StatusCode);
            }

            HistoryData values = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;

            foreach (var value in values.DataValues)
            {
                yield return(value);
            }
        }
コード例 #16
0
        /// <summary>
        /// Fetches the recent history.
        /// </summary>
        private void ReadHistory(ReadEventDetails details, NodeId areaId)
        {
            HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();
            HistoryReadValueId           nodeToRead  = new HistoryReadValueId();

            nodeToRead.NodeId = areaId;
            nodesToRead.Add(nodeToRead);

            HistoryReadResultCollection results         = null;
            DiagnosticInfoCollection    diagnosticInfos = null;

            m_session.HistoryRead(
                null,
                new ExtensionObject(details),
                TimestampsToReturn.Neither,
                false,
                nodesToRead,
                out results,
                out diagnosticInfos);

            ClientBase.ValidateResponse(results, nodesToRead);
            ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);

            if (StatusCode.IsBad(results[0].StatusCode))
            {
                throw new ServiceResultException(results[0].StatusCode);
            }

            HistoryEvent events = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryEvent;

            foreach (HistoryEventFieldList e in events.Events)
            {
                DisplayEvent(e.EventFields);
            }

            // release continuation points.
            if (results[0].ContinuationPoint != null && results[0].ContinuationPoint.Length > 0)
            {
                nodeToRead.ContinuationPoint = results[0].ContinuationPoint;

                m_session.HistoryRead(
                    null,
                    new ExtensionObject(details),
                    TimestampsToReturn.Neither,
                    true,
                    nodesToRead,
                    out results,
                    out diagnosticInfos);
            }
        }
コード例 #17
0
        /// <summary>
        /// 读取一连串的历史数据,并将其转化成指定的类型
        /// </summary>
        /// <param name="tag">节点的索引</param>
        /// <param name="start">开始时间</param>
        /// <param name="end">结束时间</param>
        /// <param name="count">读取的个数</param>
        /// <param name="containBound">是否包含边界</param>
        /// <returns>读取的数据列表</returns>
        public IEnumerable <T> ReadHistoryRawDataValues <T>(string tag, DateTime start, DateTime end, uint count = 1, bool containBound = false)
        {
            HistoryReadValueId m_nodeToContinue = new HistoryReadValueId()
            {
                NodeId = new NodeId(tag),
            };

            ReadRawModifiedDetails m_details = new ReadRawModifiedDetails
            {
                StartTime        = start.ToUniversalTime(),
                EndTime          = end.ToUniversalTime(),
                NumValuesPerNode = count,
                IsReadModified   = false,
                ReturnBounds     = containBound
            };

            m_logger.Information("start {0}/end {0}", m_details.StartTime, m_details.EndTime);
            HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();

            nodesToRead.Add(m_nodeToContinue);


            m_session.HistoryRead(
                null,
                new ExtensionObject(m_details),
                TimestampsToReturn.Both,
                false,
                nodesToRead,
                out HistoryReadResultCollection results,
                out DiagnosticInfoCollection diagnosticInfos);

            ClientBase.ValidateResponse(results, nodesToRead);
            ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);

            if (StatusCode.IsBad(results[0].StatusCode))
            {
                throw new ServiceResultException(results[0].StatusCode);
            }

            HistoryData values = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;

            m_logger.Information("values {0}", values);
            foreach (var value in values.DataValues)
            {
                yield return((T)value.Value);
            }
        }
コード例 #18
0
        /// <summary>
        /// Atempt to Decode dataset
        /// </summary>
        /// <returns></returns>
        public void DecodePossibleDataSetReader(BinaryDecoder binaryDecoder, DataSetReaderDataType dataSetReader)
        {
            UadpDataSetReaderMessageDataType messageSettings = ExtensionObject.ToEncodeable(dataSetReader.MessageSettings)
                                                               as UadpDataSetReaderMessageDataType;

            if (messageSettings != null)
            {
                //StartPositionInStream is calculated but different from reader configuration dataset cannot be decoded
                if (StartPositionInStream != messageSettings.DataSetOffset)
                {
                    if (StartPositionInStream == 0)
                    {
                        //use configured offset from reader
                        StartPositionInStream = messageSettings.DataSetOffset;
                    }
                    else if (messageSettings.DataSetOffset != 0)
                    {
                        //configuration is different from real position in message, the dataset cannot be decoded
                        return;
                    }
                }
                else
                {
                    StartPositionInStream = (int)(binaryDecoder.BaseStream.Position);
                }
            }
            if (binaryDecoder.BaseStream.Length <= StartPositionInStream)
            {
                return;
            }
            binaryDecoder.BaseStream.Position = StartPositionInStream;
            DecodeDataSetMessageHeader(binaryDecoder);

            DecodeErrorReason = ValidateMetadataVersion(dataSetReader.DataSetMetaData.ConfigurationVersion);

            if (!IsMetadataMajorVersionChange)
            {
                if ((DataSetFlags2 & DataSetFlags2EncodingMask.DataDeltaFrame) == DataSetFlags2EncodingMask.DataDeltaFrame)
                {
                    DataSet = DecodeMessageDataDeltaFrame(binaryDecoder, dataSetReader);
                }
                else
                {
                    DataSet = DecodeMessageDataKeyFrame(binaryDecoder, dataSetReader);
                }
            }
        }
コード例 #19
0
        private void ShowResults()
        {
            GoBTN.Visible = (m_result == null || m_result.ContinuationPoint == null ||
                             m_result.ContinuationPoint.Length == 0);
            NextBTN.Visible = !GoBTN.Visible;
            StopBTN.Enabled = (m_result != null && m_result.ContinuationPoint != null &&
                               m_result.ContinuationPoint.Length > 0);

            if (m_result == null)
            {
                return;
            }

            HistoryData results = ExtensionObject.ToEncodeable(m_result.HistoryData) as HistoryData;

            if (results == null)
            {
                return;
            }

            for (int ii = 0; ii < results.DataValues.Count; ii++)
            {
                StatusCode status = results.DataValues[ii].StatusCode;

                string index       = Utils.Format("[{0}]", m_index++);
                string timestamp   = results.DataValues[ii].SourceTimestamp.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss");
                string value       = Utils.Format("{0}", results.DataValues[ii].WrappedValue);
                string quality     = Utils.Format("{0}", (StatusCode)status.CodeBits);
                string historyInfo = Utils.Format("{0:X2}", (int)status.AggregateBits);

                ListViewItem item = new ListViewItem(index);

                item.SubItems.Add(timestamp);
                item.SubItems.Add(value);
                item.SubItems.Add(quality);
                item.SubItems.Add(historyInfo);

                ResultsLV.Items.Add(item);
            }

            // adjust width of all columns.
            for (int ii = 0; ii < ResultsLV.Columns.Count; ii++)
            {
                ResultsLV.Columns[ii].Width = -2;
            }
        }
コード例 #20
0
        public override void BindNodeStateActions(NodeState nodeState)
        {
            switch (nodeState)
            {
            case MethodState methodNodeState when methodNodeState.DisplayName.Text == PLCControllerNode.MethodNameAddApplication:
                methodNodeState.OnCallMethod = AddApplication;
                break;

            case DataTypeState dataTypeState when dataTypeState.DisplayName.Text == Processor.DisplayName:
                // add the types defined in the quickstart information model library to the factory.
                ApplicationNodeManager.Server.Factory.AddEncodeableTypes(typeof(Processor).Assembly);
                ApplicationNodeManager.Server.Factory.AddEncodeableTypes(this.GetType().Assembly);
                EncodeableFactory.GlobalFactory.AddEncodeableType(typeof(Processor));
                _processor = ExtensionObject.ToEncodeable(new ExtensionObject(dataTypeState.NodeId)) as Processor;
                break;
            }
        }
コード例 #21
0
        /// <summary>
        /// Fetches the recent history.
        /// </summary>
        private void ReadProcessed()
        {
            AvailableAggregate aggregate = (AvailableAggregate)AggregateCB.SelectedItem;

            ReadProcessedDetails details = new ReadProcessedDetails();

            details.StartTime          = StartTimeDP.Value.ToUniversalTime();
            details.EndTime            = EndTimeDP.Value.ToUniversalTime();
            details.ProcessingInterval = (double)ResampleIntervalNP.Value;
            details.AggregateType.Add(aggregate.NodeId);
            details.AggregateConfiguration.UseServerCapabilitiesDefaults = true;

            HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();
            HistoryReadValueId           nodeToRead  = new HistoryReadValueId();

            nodeToRead.NodeId = m_nodeId;
            nodesToRead.Add(nodeToRead);

            HistoryReadResultCollection results         = null;
            DiagnosticInfoCollection    diagnosticInfos = null;

            m_session.HistoryRead(
                null,
                new ExtensionObject(details),
                TimestampsToReturn.Both,
                false,
                nodesToRead,
                out results,
                out diagnosticInfos);

            ClientBase.ValidateResponse(results, nodesToRead);
            ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);

            if (StatusCode.IsBad(results[0].StatusCode))
            {
                throw new ServiceResultException(results[0].StatusCode);
            }

            HistoryData values = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;

            DisplayResults(values);

            // save any continuation point.
            SaveContinuationPoint(details, nodeToRead, results[0].ContinuationPoint);
        }
コード例 #22
0
        /// <summary>
        /// Fetches the recent history.
        /// </summary>
        private void ReadAtTime()
        {
            ReadAtTimeDetails details = new ReadAtTimeDetails();

            // generate times
            DateTime startTime = StartTimeDP.Value.ToUniversalTime();

            for (int ii = 0; ii < MaxReturnValuesNP.Value; ii++)
            {
                details.ReqTimes.Add(startTime.AddMilliseconds((double)(ii * TimeStepNP.Value)));
            }

            HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();
            HistoryReadValueId           nodeToRead  = new HistoryReadValueId();

            nodeToRead.NodeId = m_nodeId;
            nodesToRead.Add(nodeToRead);

            HistoryReadResultCollection results         = null;
            DiagnosticInfoCollection    diagnosticInfos = null;

            m_session.HistoryRead(
                null,
                new ExtensionObject(details),
                TimestampsToReturn.Both,
                false,
                nodesToRead,
                out results,
                out diagnosticInfos);

            ClientBase.ValidateResponse(results, nodesToRead);
            ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);

            if (StatusCode.IsBad(results[0].StatusCode))
            {
                throw new ServiceResultException(results[0].StatusCode);
            }

            HistoryData values = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;

            DisplayResults(values);

            // save any continuation point.
            SaveContinuationPoint(details, nodeToRead, results[0].ContinuationPoint);
        }
コード例 #23
0
        /// <summary>
        /// read History data
        /// </summary>
        /// <param name="tag">节点的索引</param>
        /// <param name="start">开始时间</param>
        /// <param name="end">结束时间</param>
        /// <param name="count">读取的个数</param>
        /// <param name="containBound">是否包含边界</param>
        /// <returns>读取的数据列表</returns>
        public IEnumerable <DataValue> ReadHistoryRawDataValues(string tag, DateTime start, DateTime end, uint count = 1,
                                                                bool containBound = false)
        {
            var m_nodeToContinue = new HistoryReadValueId()
            {
                NodeId = new NodeId(tag),
            };

            var m_details = new ReadRawModifiedDetails {
                StartTime        = start,
                EndTime          = end,
                NumValuesPerNode = count,
                IsReadModified   = false,
                ReturnBounds     = containBound
            };

            var nodesToRead = new HistoryReadValueIdCollection();

            nodesToRead.Add(m_nodeToContinue);

            Session.HistoryRead(
                null,
                new ExtensionObject(m_details),
                TimestampsToReturn.Both,
                false,
                nodesToRead,
                out var results,
                out var diagnosticInfos);

            ClientBase.ValidateResponse(results, nodesToRead);
            ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);

            if (StatusCode.IsBad(results[0].StatusCode))
            {
                throw new ServiceResultException(results[0].StatusCode);
            }

            var values = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;

            foreach (var value in values.DataValues)
            {
                yield return(value);
            }
        }
コード例 #24
0
        /// <summary>
        /// Fetches the recent history.
        /// </summary>
        private void ReadRaw(bool isReadModified)
        {
            ReadRawModifiedDetails details = new ReadRawModifiedDetails();

            details.StartTime        = (StartTimeCK.Checked)?StartTimeDP.Value.ToUniversalTime():DateTime.MinValue;
            details.EndTime          = (EndTimeCK.Checked)?EndTimeDP.Value.ToUniversalTime():DateTime.MinValue;
            details.NumValuesPerNode = (MaxReturnValuesCK.Checked)?(uint)MaxReturnValuesNP.Value:0;
            details.IsReadModified   = isReadModified;
            details.ReturnBounds     = (isReadModified)?false:ReturnBoundsCK.Checked;

            HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();
            HistoryReadValueId           nodeToRead  = new HistoryReadValueId();

            nodeToRead.NodeId = m_nodeId;
            nodesToRead.Add(nodeToRead);

            HistoryReadResultCollection results         = null;
            DiagnosticInfoCollection    diagnosticInfos = null;

            m_session.HistoryRead(
                null,
                new ExtensionObject(details),
                TimestampsToReturn.Both,
                false,
                nodesToRead,
                out results,
                out diagnosticInfos);

            ClientBase.ValidateResponse(results, nodesToRead);
            ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);

            if (StatusCode.IsBad(results[0].StatusCode))
            {
                throw new ServiceResultException(results[0].StatusCode);
            }

            HistoryData values = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;

            DisplayResults(values);

            // save any continuation point.
            SaveContinuationPoint(details, nodeToRead, results[0].ContinuationPoint);
        }
コード例 #25
0
        /// <summary>
        /// Get the application record.
        /// </summary>
        /// <param name="applicationId">The application id.</param>
        /// <returns>The application record for the specified application id.</returns>
        public ApplicationRecordDataType GetApplication(NodeId applicationId)
        {
            if (!IsConnected)
            {
                Connect();
            }

            var outputArguments = Session.Call(
                ExpandedNodeId.ToNodeId(Opc.Ua.Gds.ObjectIds.Directory, Session.NamespaceUris),
                ExpandedNodeId.ToNodeId(Opc.Ua.Gds.MethodIds.Directory_GetApplication, Session.NamespaceUris),
                applicationId);

            if (outputArguments.Count >= 1)
            {
                return(ExtensionObject.ToEncodeable(outputArguments[0] as ExtensionObject) as ApplicationRecordDataType);
            }

            return(null);
        }
コード例 #26
0
        /// <summary>读取一连串的历史数据,并将其转化成指定的类型</summary>
        /// <param name="url">节点的索引</param>
        /// <param name="start">开始时间</param>
        /// <param name="end">结束时间</param>
        /// <param name="count">读取的个数</param>
        /// <param name="containBound">是否包含边界</param>
        /// <returns></returns>
        public IEnumerable <T> ReadHistoryRawDataValues <T>(string url, DateTime start, DateTime end, uint count = 1, bool containBound = false)
        {
            HistoryReadValueId m_nodeToContinue = new HistoryReadValueId()
            {
                NodeId = new NodeId(url)
            };
            ReadRawModifiedDetails rawModifiedDetails = new ReadRawModifiedDetails();

            rawModifiedDetails.StartTime        = start.ToUniversalTime();
            rawModifiedDetails.EndTime          = end.ToUniversalTime();
            rawModifiedDetails.NumValuesPerNode = count;
            int num1 = 0;

            rawModifiedDetails.IsReadModified = num1 != 0;
            int num2 = containBound ? 1 : 0;

            rawModifiedDetails.ReturnBounds = num2 != 0;
            ReadRawModifiedDetails       m_details   = rawModifiedDetails;
            HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();

            nodesToRead.Add(m_nodeToContinue);
            HistoryReadResultCollection results;
            DiagnosticInfoCollection    diagnosticInfos;

            this.m_session.HistoryRead((RequestHeader)null, new ExtensionObject((object)m_details), TimestampsToReturn.Both, false, nodesToRead, out results, out diagnosticInfos);
            ClientBase.ValidateResponse((IList)results, (IList)nodesToRead);
            ClientBase.ValidateDiagnosticInfos(diagnosticInfos, (IList)nodesToRead);
            if (StatusCode.IsBad(results[0].StatusCode))
            {
                throw new ServiceResultException((ServiceResult)results[0].StatusCode);
            }
            HistoryData values = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;

            foreach (DataValue dataValue in (List <DataValue>)values.DataValues)
            {
                DataValue value = dataValue;
                yield return((T)value.Value);

                value = (DataValue)null;
            }
            List <DataValue> .Enumerator enumerator = new List <DataValue> .Enumerator();
        }
コード例 #27
0
        /// <summary>
        /// Initialize Conection properties from connection configuration object
        /// </summary>
        private void Initialize()
        {
            NetworkAddressUrlDataType networkAddressUrlState = ExtensionObject.ToEncodeable(PubSubConnectionConfiguration.Address)
                                                               as NetworkAddressUrlDataType;

            if (networkAddressUrlState == null)
            {
                Utils.Trace(Utils.TraceMasks.Error, "The configuration for connection {0} has invalid Address configuration.",
                            PubSubConnectionConfiguration.Name);
                return;
            }
            // set properties
            NetworkInterfaceName   = networkAddressUrlState.NetworkInterface;
            NetworkAddressEndPoint = UdpClientCreator.GetEndPoint(networkAddressUrlState.Url);

            if (NetworkAddressEndPoint == null)
            {
                Utils.Trace(Utils.TraceMasks.Error, "The configuration for connection {0} with Url:'{1}' resulted in an invalid endpoint.",
                            PubSubConnectionConfiguration.Name, networkAddressUrlState.Url);
            }
        }
コード例 #28
0
        public void ValidateUdpPubSubConnectionCreateNetworkMessage()
        {
            Assert.IsNotNull(m_udpPublisherConnection, "The UADP connection from standard configuration is invalid.");

            //Arrange
            WriterGroupDataType            writerGroup0    = m_udpPublisherConnection.PubSubConnectionConfiguration.WriterGroups.First();
            UadpWriterGroupMessageDataType messageSettings = ExtensionObject.ToEncodeable(writerGroup0.MessageSettings)
                                                             as UadpWriterGroupMessageDataType;

            //Act
            m_udpPublisherConnection.ResetSequenceNumber();

            var networkMessages = m_udpPublisherConnection.CreateNetworkMessages(writerGroup0, new WriterGroupPublishState());

            Assert.IsNotNull(networkMessages, "connection.CreateNetworkMessages shall not return null");
            var networkMessagesNetworkType = networkMessages.FirstOrDefault(net => net.IsMetaDataMessage == false);

            Assert.IsNotNull(networkMessagesNetworkType, "connection.CreateNetworkMessages shall return only one network message");

            UadpNetworkMessage networkMessage0 = networkMessagesNetworkType as UadpNetworkMessage;

            Assert.IsNotNull(networkMessage0, "networkMessageEncode should not be null");

            //Assert
            Assert.IsNotNull(networkMessage0, "CreateNetworkMessage did not return an UadpNetworkMessage.");

            Assert.AreEqual(networkMessage0.DataSetClassId, Guid.Empty, "UadpNetworkMessage.DataSetClassId is invalid.");
            Assert.AreEqual(networkMessage0.WriterGroupId, writerGroup0.WriterGroupId, "UadpNetworkMessage.WriterGroupId is invalid.");
            Assert.AreEqual(networkMessage0.UADPVersion, 1, "UadpNetworkMessage.UADPVersion is invalid.");
            Assert.AreEqual(networkMessage0.SequenceNumber, 1, "UadpNetworkMessage.SequenceNumber is not 1.");
            Assert.AreEqual(networkMessage0.GroupVersion, messageSettings.GroupVersion, "UadpNetworkMessage.GroupVersion is not valid.");
            Assert.AreEqual(networkMessage0.PublisherId, m_udpPublisherConnection.PubSubConnectionConfiguration.PublisherId.Value,
                            "UadpNetworkMessage.PublisherId is not valid.");
            Assert.IsNotNull(networkMessage0.DataSetMessages, "UadpNetworkMessage.UadpDataSetMessages is null.");
            Assert.AreEqual(networkMessage0.DataSetMessages.Count, 3, "UadpNetworkMessage.UadpDataSetMessages.Count is not 3.");
            //validate flags
            Assert.AreEqual((uint)networkMessage0.NetworkMessageContentMask, messageSettings.NetworkMessageContentMask,
                            "UadpNetworkMessage.messageSettings.NetworkMessageContentMask is not valid.");
        }
コード例 #29
0
        /// <summary>
        /// Validates a <see cref="PublishedDataSetDataType"/> configuration object.
        /// </summary>
        /// <param name="publishedDataSet">The <see cref="PublishedDataSetDataType"/> that is to be validated.</param>
        /// <returns>true if configuration is correct.</returns>
        public bool ValidatePublishedDataSet(PublishedDataSetDataType publishedDataSet)
        {
            if (publishedDataSet == null)
            {
                throw new ArgumentException(nameof(publishedDataSet));
            }
            if (publishedDataSet.DataSetMetaData == null)
            {
                Utils.Trace(Utils.TraceMasks.Error, "The DataSetMetaData field is null.");
                return false;
            }
            PublishedDataItemsDataType publishedDataItems = ExtensionObject.ToEncodeable(publishedDataSet.DataSetSource) as PublishedDataItemsDataType;
            if (publishedDataItems != null && publishedDataItems.PublishedData != null)
            {
                if (publishedDataItems.PublishedData.Count != publishedDataSet.DataSetMetaData.Fields.Count)
                {
                    Utils.Trace(Utils.TraceMasks.Error, "The DataSetSource.Count is different from DataSetMetaData.Fields.Count.");
                    return false;
                }
            }

            return true;
        }
コード例 #30
0
        /// <summary>
        /// Reads the last date in the archive (truncates milliseconds and converts to local).
        /// </summary>
        private DateTime ReadLastDate()
        {
            ReadRawModifiedDetails details = new ReadRawModifiedDetails();

            details.StartTime        = DateTime.MinValue;
            details.EndTime          = DateTime.UtcNow.AddDays(1);
            details.NumValuesPerNode = 1;
            details.IsReadModified   = false;
            details.ReturnBounds     = false;

            HistoryReadValueId nodeToRead = new HistoryReadValueId();

            nodeToRead.NodeId = m_nodeId;

            HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();

            nodesToRead.Add(nodeToRead);

            HistoryReadResultCollection results         = null;
            DiagnosticInfoCollection    diagnosticInfos = null;

            m_session.HistoryRead(
                null,
                new ExtensionObject(details),
                TimestampsToReturn.Source,
                false,
                nodesToRead,
                out results,
                out diagnosticInfos);

            Session.ValidateResponse(results, nodesToRead);
            Session.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);

            if (StatusCode.IsBad(results[0].StatusCode))
            {
                return(DateTime.MinValue);
            }

            HistoryData data = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;

            if (results == null)
            {
                return(DateTime.MinValue);
            }

            DateTime endTime = data.DataValues[0].SourceTimestamp;

            if (results[0].ContinuationPoint != null && results[0].ContinuationPoint.Length > 0)
            {
                nodeToRead.ContinuationPoint = results[0].ContinuationPoint;

                m_session.HistoryRead(
                    null,
                    new ExtensionObject(details),
                    TimestampsToReturn.Source,
                    true,
                    nodesToRead,
                    out results,
                    out diagnosticInfos);

                Session.ValidateResponse(results, nodesToRead);
                Session.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);
            }

            endTime = new DateTime(endTime.Year, endTime.Month, endTime.Day, endTime.Hour, endTime.Minute, endTime.Second, 0, DateTimeKind.Utc);
            endTime = endTime.AddSeconds(1);
            endTime = endTime.ToLocalTime();

            return(endTime);
        }