1// Copyright (C) 2021 basysKom GmbH, opensource@basyskom.com
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qopcuahistoryreadresponseimpl_p.h"
5
6QT_BEGIN_NAMESPACE
7
8quint64 QOpcUaHistoryReadResponseImpl::m_currentHandle = 0;
9
10QOpcUaHistoryReadResponseImpl::QOpcUaHistoryReadResponseImpl(const QOpcUaHistoryReadRawRequest &request)
11 : m_requestType(RequestType::ReadRaw)
12 , m_readRawRequest(request)
13 , m_handle(++m_currentHandle)
14{
15}
16
17QOpcUaHistoryReadResponseImpl::QOpcUaHistoryReadResponseImpl(const QOpcUaHistoryReadEventRequest &request)
18 : m_requestType(RequestType::ReadEvent)
19 , m_readEventRequest(request)
20 , m_handle(++m_currentHandle)
21{
22}
23
24QOpcUaHistoryReadResponseImpl::~QOpcUaHistoryReadResponseImpl()
25{
26 releaseContinuationPoints();
27}
28
29bool QOpcUaHistoryReadResponseImpl::hasMoreData() const
30{
31 return m_state == QOpcUaHistoryReadResponse::State::MoreDataAvailable;
32}
33
34bool QOpcUaHistoryReadResponseImpl::readMoreData()
35{
36 if (!hasMoreData())
37 return false;
38
39 if (m_requestType == RequestType::ReadRaw) {
40 const auto request = createReadRawRequestWithContinuationPoints();
41 emit historyReadRawRequested(request, continuationPoints: m_continuationPoints, releaseContinuationPoints: false, handle: handle());
42 return true;
43 } else if (m_requestType == RequestType::ReadEvent) {
44 const auto request = createEventRequestWithContinuationPoints();
45 emit historyReadEventsRequested(request, continuationPoints: m_continuationPoints, releaseContinuationPoints: false, handle: handle());
46 return true;
47 }
48
49 return false;
50}
51
52QOpcUaHistoryReadResponse::State QOpcUaHistoryReadResponseImpl::state() const
53{
54 return m_state;
55}
56
57bool QOpcUaHistoryReadResponseImpl::releaseContinuationPoints()
58{
59 if (m_requestType == RequestType::ReadRaw) {
60 const auto request = createReadRawRequestWithContinuationPoints();
61
62 if (!request.nodesToRead().isEmpty())
63 emit historyReadRawRequested(request, continuationPoints: m_continuationPoints, releaseContinuationPoints: true, handle: handle());
64
65 m_continuationPoints.clear();
66
67 setState(QOpcUaHistoryReadResponse::State::Finished);
68 } else if (m_requestType == RequestType::ReadEvent) {
69 const auto request = createEventRequestWithContinuationPoints();
70
71 if (!request.nodesToRead().isEmpty())
72 emit historyReadEventsRequested(request, continuationPoints: m_continuationPoints, releaseContinuationPoints: true, handle: handle());
73
74 m_continuationPoints.clear();
75
76 setState(QOpcUaHistoryReadResponse::State::Finished);
77 };
78
79 return true;
80}
81
82QList<QOpcUaHistoryData> QOpcUaHistoryReadResponseImpl::data() const
83{
84 return m_data;
85}
86
87QList<QOpcUaHistoryEvent> QOpcUaHistoryReadResponseImpl::events() const
88{
89 return m_events;
90}
91
92QOpcUa::UaStatusCode QOpcUaHistoryReadResponseImpl::serviceResult() const
93{
94 return m_serviceResult;
95}
96
97void QOpcUaHistoryReadResponseImpl::handleDataAvailable(const QList<QOpcUaHistoryData> &data, const QList<QByteArray> &continuationPoints,
98 QOpcUa::UaStatusCode serviceResult, quint64 responseHandle)
99{
100 if (responseHandle != handle())
101 return;
102
103 m_serviceResult = serviceResult;
104 m_continuationPoints = continuationPoints;
105
106 if (m_data.empty()) {
107 m_data = data;
108 } else {
109 int index = 0;
110 for (const auto &result : data) {
111 auto &target = m_data[m_dataMapping.at(i: index++)];
112 target.setStatusCode(result.statusCode());
113 const auto tempResult = result.result();
114 for (const auto &value : tempResult) {
115 target.addValue(value);
116 }
117 }
118 }
119
120 bool found = false;
121 for (const auto &continuationPoint : std::as_const(t&: m_continuationPoints)) {
122 if (!continuationPoint.isEmpty()) {
123 setState(QOpcUaHistoryReadResponse::State::MoreDataAvailable);
124 found = true;
125 break;
126 }
127 }
128
129 if (!found)
130 setState(QOpcUaHistoryReadResponse::State::Finished);
131
132 emit readHistoryDataFinished(results: m_data, serviceResult: m_serviceResult);
133}
134
135void QOpcUaHistoryReadResponseImpl::handleEventsAvailable(const QList<QOpcUaHistoryEvent> &data, const QList<QByteArray> &continuationPoints,
136 QOpcUa::UaStatusCode serviceResult, quint64 responseHandle)
137{
138 if (responseHandle != handle())
139 return;
140
141 m_serviceResult = serviceResult;
142 m_continuationPoints = continuationPoints;
143
144 if (m_events.empty()) {
145 m_events = data;
146 } else {
147 int index = 0;
148 for (const auto &result : data) {
149 auto &target = m_events[m_dataMapping.at(i: index++)];
150 target.setStatusCode(result.statusCode());
151 const auto tempEvents = result.events();
152 for (const auto &event : tempEvents) {
153 target.addEvent(value: event);
154 }
155 }
156 }
157
158 bool found = false;
159 for (const auto &continuationPoint : std::as_const(t&: m_continuationPoints)) {
160 if (!continuationPoint.isEmpty()) {
161 setState(QOpcUaHistoryReadResponse::State::MoreDataAvailable);
162 found = true;
163 break;
164 }
165 }
166
167 if (!found)
168 setState(QOpcUaHistoryReadResponse::State::Finished);
169
170 emit readHistoryEventsFinished(results: m_events, serviceResult: m_serviceResult);
171}
172
173void QOpcUaHistoryReadResponseImpl::handleRequestError(quint64 requestHandle)
174{
175 if (requestHandle == handle())
176 setState(QOpcUaHistoryReadResponse::State::Error);
177}
178
179quint64 QOpcUaHistoryReadResponseImpl::handle() const
180{
181 return m_handle;
182}
183
184void QOpcUaHistoryReadResponseImpl::setState(QOpcUaHistoryReadResponse::State state)
185{
186 if (m_state != state) {
187 m_state = state;
188 emit stateChanged(state);
189 }
190}
191
192QOpcUaHistoryReadRawRequest QOpcUaHistoryReadResponseImpl::createReadRawRequestWithContinuationPoints()
193{
194 QOpcUaHistoryReadRawRequest request;
195 request.setStartTimestamp(m_readRawRequest.startTimestamp());
196 request.setEndTimestamp(m_readRawRequest.endTimestamp());
197 request.setNumValuesPerNode(m_readRawRequest.numValuesPerNode());
198 request.setReturnBounds(m_readRawRequest.returnBounds());
199 request.setTimestampsToReturn(m_readRawRequest.timestampsToReturn());
200
201 int arrayIndex = 0;
202 QList<int> newDataMapping;
203 QList<QByteArray> newContinuationPoints;
204
205 for (const auto &continuationPoint : std::as_const(t&: m_continuationPoints)) {
206 int mappingIndex = 0;
207 if (m_dataMapping.empty())
208 mappingIndex = arrayIndex;
209 else
210 mappingIndex = m_dataMapping.at(i: arrayIndex);
211
212 if (!continuationPoint.isEmpty()) {
213 newDataMapping.push_back(t: mappingIndex);
214 newContinuationPoints.push_back(t: continuationPoint);
215 request.addNodeToRead(nodeToRead: m_readRawRequest.nodesToRead().at(i: mappingIndex));
216 }
217
218 ++arrayIndex;
219 }
220
221 m_dataMapping = newDataMapping;
222 m_continuationPoints = newContinuationPoints;
223
224 return request;
225}
226
227QOpcUaHistoryReadEventRequest QOpcUaHistoryReadResponseImpl::createEventRequestWithContinuationPoints()
228{
229 QOpcUaHistoryReadEventRequest request;
230 request.setStartTimestamp(m_readEventRequest.startTimestamp());
231 request.setEndTimestamp(m_readEventRequest.endTimestamp());
232 request.setNumValuesPerNode(m_readEventRequest.numValuesPerNode());
233 request.setFilter(m_readEventRequest.filter());
234
235 int arrayIndex = 0;
236 QList<int> newDataMapping;
237 QList<QByteArray> newContinuationPoints;
238
239 for (const auto &continuationPoint : std::as_const(t&: m_continuationPoints)) {
240 int mappingIndex = 0;
241 if (m_dataMapping.empty())
242 mappingIndex = arrayIndex;
243 else
244 mappingIndex = m_dataMapping.at(i: arrayIndex);
245
246 if (!continuationPoint.isEmpty()) {
247 newDataMapping.push_back(t: mappingIndex);
248 newContinuationPoints.push_back(t: continuationPoint);
249 request.addNodeToRead(nodeToRead: m_readEventRequest.nodesToRead().at(i: mappingIndex));
250 }
251
252 ++arrayIndex;
253 }
254
255 m_dataMapping = newDataMapping;
256 m_continuationPoints = newContinuationPoints;
257
258 return request;
259}
260
261QT_END_NAMESPACE
262

source code of qtopcua/src/opcua/client/qopcuahistoryreadresponseimpl.cpp