summaryrefslogtreecommitdiffstats
path: root/src/plugins/opcua/open62541/qopen62541backend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/opcua/open62541/qopen62541backend.cpp')
-rw-r--r--src/plugins/opcua/open62541/qopen62541backend.cpp91
1 files changed, 91 insertions, 0 deletions
diff --git a/src/plugins/opcua/open62541/qopen62541backend.cpp b/src/plugins/opcua/open62541/qopen62541backend.cpp
index 5816bd7..6bfa58e 100644
--- a/src/plugins/opcua/open62541/qopen62541backend.cpp
+++ b/src/plugins/opcua/open62541/qopen62541backend.cpp
@@ -572,6 +572,54 @@ void Open62541AsyncBackend::writeNodeAttributes(const QList<QOpcUaWriteItem> &no
m_asyncBatchWriteContext[requestId] = { nodesToWrite };
}
+void Open62541AsyncBackend::readHistoryRaw(QOpcUaHistoryReadRawRequest request, QList<QByteArray> continuationPoints, bool releaseContinuationPoints, quint64 handle)
+{
+ if (!continuationPoints.empty() && continuationPoints.size() != request.nodesToRead().size()) {
+ emit historyDataAvailable({}, {}, QOpcUa::UaStatusCode::BadInternalError, handle);
+ return;
+ }
+
+ UA_HistoryReadRequest uarequest;
+ UA_HistoryReadRequest_init(&uarequest);
+ uarequest.nodesToReadSize = request.nodesToRead().size();
+ uarequest.nodesToRead = static_cast<UA_HistoryReadValueId*>(UA_Array_new(uarequest.nodesToReadSize, &UA_TYPES[UA_TYPES_HISTORYREADVALUEID]));
+ for (size_t i = 0; i < uarequest.nodesToReadSize; ++i) {
+ uarequest.nodesToRead[i].nodeId = Open62541Utils::nodeIdFromQString(request.nodesToRead().at(i).nodeId());
+ QOpen62541ValueConverter::scalarFromQt<UA_String, QString>(request.nodesToRead().at(i).indexRange(), &uarequest.nodesToRead[i].indexRange);
+ uarequest.nodesToRead[i].dataEncoding = UA_QUALIFIEDNAME_ALLOC(0, "Default Binary");
+ if (!continuationPoints.isEmpty())
+ QOpen62541ValueConverter::scalarFromQt<UA_ByteString, QByteArray>(continuationPoints.at(i), &uarequest.nodesToRead[i].continuationPoint);
+ }
+ uarequest.timestampsToReturn = UA_TIMESTAMPSTORETURN_BOTH;
+
+ if (releaseContinuationPoints)
+ uarequest.releaseContinuationPoints = releaseContinuationPoints;
+
+ uarequest.historyReadDetails.encoding = UA_EXTENSIONOBJECT_DECODED;
+ uarequest.historyReadDetails.content.decoded.type = &UA_TYPES[UA_TYPES_READRAWMODIFIEDDETAILS];
+ UA_ReadRawModifiedDetails *details = UA_ReadRawModifiedDetails_new();
+ uarequest.historyReadDetails.content.decoded.data = details;
+ QOpen62541ValueConverter::scalarFromQt<UA_DateTime, QDateTime>(request.startTimestamp(), &details->startTime);
+ QOpen62541ValueConverter::scalarFromQt<UA_DateTime, QDateTime>(request.endTimestamp(), &details->endTime);
+ details->isReadModified = UA_FALSE;
+ details->returnBounds = request.returnBounds();
+ details->numValuesPerNode = request.numValuesPerNode();
+
+ quint32 requestId = 0;
+ UA_StatusCode resultCode = __UA_Client_AsyncServiceEx(m_uaclient, &uarequest, &UA_TYPES[UA_TYPES_HISTORYREADREQUEST], &asyncReadHistoryDataCallBack,
+ &UA_TYPES[UA_TYPES_HISTORYREADRESPONSE], this, &requestId, m_asyncRequestTimeout);
+
+ UA_HistoryReadRequest_clear(&uarequest);
+
+ if (resultCode != UA_STATUSCODE_GOOD) {
+ qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Read history data failed:" << resultCode;
+ emit historyDataAvailable({}, {}, QOpcUa::UaStatusCode(resultCode), handle);
+ return;
+ }
+
+ m_asyncReadHistoryDataContext[requestId] = {handle, request};
+}
+
void Open62541AsyncBackend::addNode(const QOpcUaAddNodeItem &nodeToAdd)
{
UA_AddNodesRequest req;
@@ -1429,6 +1477,49 @@ void Open62541AsyncBackend::asyncBatchWriteCallback(UA_Client *client, void *use
}
}
+void Open62541AsyncBackend::asyncReadHistoryDataCallBack(UA_Client *client, void *userdata, UA_UInt32 requestId, void *response)
+{
+ Q_UNUSED(client);
+
+ Open62541AsyncBackend *backend = static_cast<Open62541AsyncBackend *>(userdata);
+ AsyncReadHistoryDataContext context = backend->m_asyncReadHistoryDataContext.take(requestId);
+
+ UA_HistoryReadResponse* res = static_cast<UA_HistoryReadResponse*>(response);
+
+ QList<QByteArray> continuationPoints;
+
+ QList<QOpcUaHistoryData> historyData;
+
+ for (size_t i = 0; i < res->resultsSize; ++i) {
+ if (res->results[i].historyData.encoding != UA_EXTENSIONOBJECT_DECODED) {
+ emit backend->historyDataAvailable({}, {}, QOpcUa::UaStatusCode(res->responseHeader.serviceResult), context.handle);
+ return;
+ }
+
+ historyData.push_back(QOpcUaHistoryData(context.historyReadRawRequest.nodesToRead().at(i).nodeId()));
+
+ historyData[i].setStatusCode(QOpcUa::UaStatusCode(res->results[i].statusCode));
+
+ if (res->results[i].statusCode != UA_STATUSCODE_GOOD)
+ continue;
+
+ if (res->results[i].historyData.content.decoded.type != &UA_TYPES[UA_TYPES_HISTORYDATA]) {
+ historyData[i].setStatusCode(QOpcUa::UaStatusCode::BadInternalError);
+ continue;
+ }
+
+ UA_HistoryData *data = static_cast<UA_HistoryData *>(res->results[i].historyData.content.decoded.data);
+ for (size_t j = 0; j < data->dataValuesSize; ++j) {
+ const QOpcUaDataValue value = QOpen62541ValueConverter::scalarToQt<QOpcUaDataValue, UA_DataValue>(&data->dataValues[j]);
+ historyData[i].addValue(value);
+ }
+
+ continuationPoints.push_back(QOpen62541ValueConverter::scalarToQt<QByteArray, UA_ByteString>(&res->results[i].continuationPoint));
+ }
+
+ emit backend->historyDataAvailable(historyData, continuationPoints, QOpcUa::UaStatusCode(res->responseHeader.serviceResult), context.handle);
+}
+
bool Open62541AsyncBackend::loadFileToByteString(const QString &location, UA_ByteString *target) const
{
if (location.isEmpty()) {