diff options
Diffstat (limited to 'src/plugins/opcua/open62541/qopen62541backend.cpp')
-rw-r--r-- | src/plugins/opcua/open62541/qopen62541backend.cpp | 91 |
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()) { |