From 9a9ac65defef1b42888ad19ba0aa38f1fe2b239e Mon Sep 17 00:00:00 2001 From: Rainer Keller Date: Mon, 8 Oct 2018 10:55:33 +0200 Subject: uacpp: Fix time converter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I9cc924f6ca834bebb4afd29255c5c63a7c6130eb Reviewed-by: Jannis Völker Reviewed-by: Maurice Kalinowski --- src/plugins/opcua/uacpp/quacppvalueconverter.cpp | 7 +++-- tests/auto/qopcuaclient/tst_client.cpp | 17 ++++++++++++ tests/open62541-testserver/main.cpp | 1 + tests/open62541-testserver/testserver.cpp | 33 ++++++++++++++++++++++++ tests/open62541-testserver/testserver.h | 1 + 5 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/plugins/opcua/uacpp/quacppvalueconverter.cpp b/src/plugins/opcua/uacpp/quacppvalueconverter.cpp index 58d0eb1..5aa4f5c 100644 --- a/src/plugins/opcua/uacpp/quacppvalueconverter.cpp +++ b/src/plugins/opcua/uacpp/quacppvalueconverter.cpp @@ -478,7 +478,8 @@ void scalarFromQVariant(const QVariant &var, OpcUa_Da { // OPC-UA part 3, Table C.9 const QDateTime uaEpochStart(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC); - const UaDateTime dt = UaDateTime(var.toDateTime().toMSecsSinceEpoch() - uaEpochStart.toMSecsSinceEpoch()); + // OpcUa time is defined in part 6, 5.2.2.5 in 100ns which need to be converted to milliseconds. + const UaDateTime dt = UaDateTime((var.toDateTime().toMSecsSinceEpoch() - uaEpochStart.toMSecsSinceEpoch()) * 10000); *ptr = dt; } @@ -952,7 +953,9 @@ QDateTime toQDateTime(const OpcUa_DateTime *dt) // OPC-UA part 3, Table C.9 const QDateTime uaEpochStart(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC); const UaDateTime temp(*dt); - return uaEpochStart.addMSecs(temp).toLocalTime(); + + // OpcUa time is defined in part 6, 5.2.2.5 in 100ns which need to be converted to milliseconds. + return uaEpochStart.addMSecs(((quint64)temp) / 10000).toLocalTime(); } } diff --git a/tests/auto/qopcuaclient/tst_client.cpp b/tests/auto/qopcuaclient/tst_client.cpp index 06ce0a9..f12a96a 100644 --- a/tests/auto/qopcuaclient/tst_client.cpp +++ b/tests/auto/qopcuaclient/tst_client.cpp @@ -462,6 +462,9 @@ private slots: defineDataMethod(addNamespace_data) void addNamespace(); + void fixedTimestamp(); + defineDataMethod(fixedTimestamp_data) + defineDataMethod(resolveBrowsePath_data) void resolveBrowsePath(); @@ -3621,6 +3624,20 @@ void Tst_QOpcUaClient::addNamespace() QCOMPARE(methodSpy.at(0).at(1).value(), updatedNamespaceArray.indexOf(newNamespaceName)); } +void Tst_QOpcUaClient::fixedTimestamp() +{ + QFETCH(QOpcUaClient *, opcuaClient); + OpcuaConnector connector(opcuaClient, m_endpoint); + + QScopedPointer node(opcuaClient->node("ns=2;s=Demo.Static.FixedTimestamp")); + QVERIFY(node != nullptr); + READ_MANDATORY_VARIABLE_NODE(node); + QVariant value = node->attribute(QOpcUa::NodeAttribute::Value); + QVERIFY(value.isValid()); + QCOMPARE(value.type(), QVariant::DateTime); + QCOMPARE(value.toDateTime(), QDateTime(QDate(2012, 12, 19), QTime(13, 37))); +} + void Tst_QOpcUaClient::connectionLost() { // Restart the test server if necessary diff --git a/tests/open62541-testserver/main.cpp b/tests/open62541-testserver/main.cpp index 58df107..bbd51a8 100644 --- a/tests/open62541-testserver/main.cpp +++ b/tests/open62541-testserver/main.cpp @@ -189,6 +189,7 @@ int main(int argc, char **argv) QOpcUa::Types::Argument); server.addVariable(testFolder, "ns=2;s=Demo.Static.Scalar.ExtensionObject", "ExtensionObjectScalarTest", QOpcUa::QExtensionObject(), QOpcUa::Types::ExtensionObject); + server.addNodeWithFixedTimestamp(testFolder, "ns=2;s=Demo.Static.FixedTimestamp", "FixedTimestamp"); // Create folders containing child nodes with string, guid and opaque node ids UA_NodeId testStringIdsFolder = server.addFolder("ns=3;s=testStringIdsFolder", "testStringIdsFolder"); diff --git a/tests/open62541-testserver/testserver.cpp b/tests/open62541-testserver/testserver.cpp index f7dd957..d83694d 100644 --- a/tests/open62541-testserver/testserver.cpp +++ b/tests/open62541-testserver/testserver.cpp @@ -552,4 +552,37 @@ UA_StatusCode TestServer::addNamespaceMethod(UA_Server *server, const UA_NodeId return UA_STATUSCODE_GOOD; } +UA_NodeId TestServer::addNodeWithFixedTimestamp(const UA_NodeId &folder, const QString &nodeId, const QString &displayName) +{ + UA_NodeId variableNodeId = Open62541Utils::nodeIdFromQString(nodeId); + + UA_VariableAttributes attr = UA_VariableAttributes_default; + attr.value = QOpen62541ValueConverter::toOpen62541Variant(QDateTime(QDate(2012, 12, 19), QTime(13, 37)), QOpcUa::DateTime); + attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", displayName.toUtf8().constData()); + attr.dataType = attr.value.type->typeId; + attr.accessLevel = UA_ACCESSLEVELMASK_READ; // Read Only + + UA_QualifiedName variableName; + variableName.namespaceIndex = variableNodeId.namespaceIndex; + variableName.name = attr.displayName.text; + + UA_NodeId resultId; + UA_StatusCode result = UA_Server_addVariableNode(m_server, + variableNodeId, + folder, + UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), + variableName, + UA_NODEID_NULL, + attr, + NULL, + &resultId); + + if (result != UA_STATUSCODE_GOOD) { + qWarning() << "Could not add variable:" << result; + return UA_NODEID_NULL; + } + + return resultId; +} + QT_END_NAMESPACE diff --git a/tests/open62541-testserver/testserver.h b/tests/open62541-testserver/testserver.h index f8a5ff9..2cebfd9 100644 --- a/tests/open62541-testserver/testserver.h +++ b/tests/open62541-testserver/testserver.h @@ -68,6 +68,7 @@ public: UA_NodeId addMultiplyMethod(const UA_NodeId &folder, const QString &variableNode, const QString &description); UA_NodeId addMultipleOutputArgumentsMethod(const UA_NodeId &folder, const QString &variableNode, const QString &description); UA_NodeId addAddNamespaceMethod(const UA_NodeId &folder, const QString &variableNode, const QString &description); + UA_NodeId addNodeWithFixedTimestamp(const UA_NodeId &folder, const QString &nodeId, const QString &displayName); static UA_StatusCode multiplyMethod(UA_Server *server, const UA_NodeId *sessionId, void *sessionHandle, const UA_NodeId *methodId, void *methodContext, -- cgit v1.2.3