| 1 | // Copyright (C) 2017 The Qt Company Ltd. |
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
| 3 | |
| 4 | #ifdef USE_SYSTEM_OPEN62541 |
| 5 | #include <open62541/types.h> |
| 6 | #else |
| 7 | #include "qopen62541.h" |
| 8 | #endif |
| 9 | |
| 10 | #include "qopen62541utils.h" |
| 11 | #include "qopen62541valueconverter.h" |
| 12 | |
| 13 | #include "qopcuadatavalue.h" |
| 14 | #include "qopcuamultidimensionalarray.h" |
| 15 | #include "qopcuastructuredefinition.h" |
| 16 | #include "qopcuaenumdefinition.h" |
| 17 | |
| 18 | #include <QtOpcUa/qopcuaargument.h> |
| 19 | #include <QtOpcUa/qopcuaattributeoperand.h> |
| 20 | #include <QtOpcUa/qopcuaaxisinformation.h> |
| 21 | #include <QtOpcUa/qopcuacomplexnumber.h> |
| 22 | #include <QtOpcUa/qopcuadiagnosticinfo.h> |
| 23 | #include <QtOpcUa/qopcuadoublecomplexnumber.h> |
| 24 | #include <QtOpcUa/qopcuaelementoperand.h> |
| 25 | #include <QtOpcUa/qopcuaenumfield.h> |
| 26 | #include <QtOpcUa/qopcuaeuinformation.h> |
| 27 | #include <QtOpcUa/qopcualiteraloperand.h> |
| 28 | #include <QtOpcUa/qopcualocalizedtext.h> |
| 29 | #include <QtOpcUa/qopcuaqualifiedname.h> |
| 30 | #include <QtOpcUa/qopcuarange.h> |
| 31 | #include <QtOpcUa/qopcuastructurefield.h> |
| 32 | #include <QtOpcUa/qopcuaxvalue.h> |
| 33 | |
| 34 | #include <QtCore/qdatetime.h> |
| 35 | #include <QtCore/qloggingcategory.h> |
| 36 | #include <QtCore/qtimezone.h> |
| 37 | #include <QtCore/quuid.h> |
| 38 | |
| 39 | #include <cstring> |
| 40 | |
| 41 | QT_BEGIN_NAMESPACE |
| 42 | |
| 43 | Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_OPEN62541) |
| 44 | |
| 45 | using namespace QOpcUa::NodeIds; |
| 46 | |
| 47 | namespace QOpen62541ValueConverter { |
| 48 | |
| 49 | UA_Variant toOpen62541Variant(const QVariant &value, QOpcUa::Types type) |
| 50 | { |
| 51 | UA_Variant open62541value; |
| 52 | UA_Variant_init(p: &open62541value); |
| 53 | |
| 54 | if (value.canConvert<QOpcUaMultiDimensionalArray>()) { |
| 55 | QOpcUaMultiDimensionalArray data = value.value<QOpcUaMultiDimensionalArray>(); |
| 56 | UA_Variant result = toOpen62541Variant(value: data.valueArray(), type); |
| 57 | |
| 58 | const auto &arrayDimensions = data.arrayDimensions(); |
| 59 | |
| 60 | if (!arrayDimensions.isEmpty()) { |
| 61 | // Ensure that the array dimensions size is < UINT32_MAX |
| 62 | if (static_cast<quint64>(arrayDimensions.size()) > (std::numeric_limits<quint32>::max)()) |
| 63 | return open62541value; |
| 64 | result.arrayDimensionsSize = arrayDimensions.size(); |
| 65 | result.arrayDimensions = static_cast<UA_UInt32 *>(UA_Array_new(size: result.arrayDimensionsSize, type: &UA_TYPES[UA_TYPES_UINT32])); |
| 66 | std::copy(first: arrayDimensions.constBegin(), last: arrayDimensions.constEnd(), result: result.arrayDimensions); |
| 67 | } |
| 68 | return result; |
| 69 | } |
| 70 | |
| 71 | if (value.metaType().id() == QMetaType::QVariantList && value.toList().size() == 0) |
| 72 | return open62541value; |
| 73 | |
| 74 | QVariant temp = (value.metaType().id() == QMetaType::QVariantList) ? value.toList().at(i: 0) : value; |
| 75 | QOpcUa::Types valueType = type == QOpcUa::Undefined ? |
| 76 | QOpcUa::metaTypeToQOpcUaType(type: static_cast<QMetaType::Type>(temp.metaType().id())) : type; |
| 77 | |
| 78 | const UA_DataType *dt = toDataType(valueType); |
| 79 | |
| 80 | switch (valueType) { |
| 81 | case QOpcUa::Boolean: |
| 82 | return arrayFromQVariant<UA_Boolean, bool>(var: value, type: dt); |
| 83 | case QOpcUa::SByte: |
| 84 | return arrayFromQVariant<UA_SByte, char>(var: value, type: dt); |
| 85 | case QOpcUa::Byte: |
| 86 | return arrayFromQVariant<UA_Byte, uchar>(var: value, type: dt); |
| 87 | case QOpcUa::Int16: |
| 88 | return arrayFromQVariant<UA_Int16, qint16>(var: value, type: dt); |
| 89 | case QOpcUa::UInt16: |
| 90 | return arrayFromQVariant<UA_UInt16, quint16>(var: value, type: dt); |
| 91 | case QOpcUa::Int32: |
| 92 | return arrayFromQVariant<UA_Int32, qint32>(var: value, type: dt); |
| 93 | case QOpcUa::UInt32: |
| 94 | return arrayFromQVariant<UA_UInt32, quint32>(var: value, type: dt); |
| 95 | case QOpcUa::Int64: |
| 96 | return arrayFromQVariant<UA_Int64, int64_t>(var: value, type: dt); |
| 97 | case QOpcUa::UInt64: |
| 98 | return arrayFromQVariant<UA_UInt64, uint64_t>(var: value, type: dt); |
| 99 | case QOpcUa::Float: |
| 100 | return arrayFromQVariant<UA_Float, float>(var: value, type: dt); |
| 101 | case QOpcUa::Double: |
| 102 | return arrayFromQVariant<UA_Double, double>(var: value, type: dt); |
| 103 | case QOpcUa::DateTime: |
| 104 | return arrayFromQVariant<UA_DateTime, QDateTime>(var: value, type: dt); |
| 105 | case QOpcUa::String: |
| 106 | return arrayFromQVariant<UA_String, QString>(var: value, type: dt); |
| 107 | case QOpcUa::LocalizedText: |
| 108 | return arrayFromQVariant<UA_LocalizedText, QOpcUaLocalizedText>(var: value, type: dt); |
| 109 | case QOpcUa::ByteString: |
| 110 | return arrayFromQVariant<UA_ByteString, QByteArray>(var: value, type: dt); |
| 111 | case QOpcUa::NodeId: |
| 112 | return arrayFromQVariant<UA_NodeId, QString>(var: value, type: dt); |
| 113 | case QOpcUa::Guid: |
| 114 | return arrayFromQVariant<UA_Guid, QUuid>(var: value, type: dt); |
| 115 | case QOpcUa::XmlElement: |
| 116 | return arrayFromQVariant<UA_XmlElement, QString>(var: value, type: dt); |
| 117 | case QOpcUa::QualifiedName: |
| 118 | return arrayFromQVariant<UA_QualifiedName, QOpcUaQualifiedName>(var: value, type: dt); |
| 119 | case QOpcUa::StatusCode: |
| 120 | return arrayFromQVariant<UA_StatusCode, QOpcUa::UaStatusCode>(var: value, type: dt); |
| 121 | case QOpcUa::Range: |
| 122 | return arrayFromQVariant<UA_Range, QOpcUaRange>(var: value, type: dt); |
| 123 | case QOpcUa::EUInformation: |
| 124 | return arrayFromQVariant<UA_EUInformation, QOpcUaEUInformation>(var: value, type: dt); |
| 125 | case QOpcUa::ComplexNumber: |
| 126 | return arrayFromQVariant<UA_ComplexNumberType, QOpcUaComplexNumber>(var: value, type: dt); |
| 127 | case QOpcUa::DoubleComplexNumber: |
| 128 | return arrayFromQVariant<UA_DoubleComplexNumberType, QOpcUaDoubleComplexNumber>(var: value, type: dt); |
| 129 | case QOpcUa::AxisInformation: |
| 130 | return arrayFromQVariant<UA_AxisInformation, QOpcUaAxisInformation>(var: value, type: dt); |
| 131 | case QOpcUa::XV: |
| 132 | return arrayFromQVariant<UA_XVType, QOpcUaXValue>(var: value, type: dt); |
| 133 | case QOpcUa::ExpandedNodeId: |
| 134 | return arrayFromQVariant<UA_ExpandedNodeId, QOpcUaExpandedNodeId>(var: value, type: dt); |
| 135 | case QOpcUa::Argument: |
| 136 | return arrayFromQVariant<UA_Argument, QOpcUaArgument>(var: value, type: dt); |
| 137 | case QOpcUa::SimpleAttributeOperand: |
| 138 | return arrayFromQVariant<UA_SimpleAttributeOperand, QOpcUaSimpleAttributeOperand>(var: value, type: dt); |
| 139 | case QOpcUa::AttributeOperand: |
| 140 | return arrayFromQVariant<UA_AttributeOperand, QOpcUaAttributeOperand>(var: value, type: dt); |
| 141 | case QOpcUa::LiteralOperand: |
| 142 | return arrayFromQVariant<UA_LiteralOperand, QOpcUaLiteralOperand>(var: value, type: dt); |
| 143 | case QOpcUa::ElementOperand: |
| 144 | return arrayFromQVariant<UA_SimpleAttributeOperand, QOpcUaSimpleAttributeOperand>(var: value, type: dt); |
| 145 | case QOpcUa::RelativePathElement: |
| 146 | return arrayFromQVariant<UA_RelativePathElement, QOpcUaRelativePathElement>(var: value, type: dt); |
| 147 | case QOpcUa::ContentFilterElement: |
| 148 | return arrayFromQVariant<UA_ContentFilterElement, QOpcUaContentFilterElement>(var: value, type: dt); |
| 149 | case QOpcUa::EventFilter: |
| 150 | return arrayFromQVariant<UA_EventFilter, QOpcUaMonitoringParameters::EventFilter>(var: value, type: dt); |
| 151 | case QOpcUa::ExtensionObject: |
| 152 | return arrayFromQVariant<UA_ExtensionObject, QOpcUaExtensionObject>(var: value, type: dt); |
| 153 | case QOpcUa::StructureDefinition: |
| 154 | return arrayFromQVariant<UA_StructureDefinition, QOpcUaStructureDefinition>(var: value, type: dt); |
| 155 | case QOpcUa::StructureField: |
| 156 | return arrayFromQVariant<UA_StructureField, QOpcUaStructureField>(var: value, type: dt); |
| 157 | case QOpcUa::EnumDefinition: |
| 158 | return arrayFromQVariant<UA_EnumDefinition, QOpcUaEnumDefinition>(var: value, type: dt); |
| 159 | case QOpcUa::EnumField: |
| 160 | return arrayFromQVariant<UA_EnumField, QOpcUaEnumField>(var: value, type: dt); |
| 161 | case QOpcUa::DiagnosticInfo: |
| 162 | return arrayFromQVariant<UA_DiagnosticInfo, QOpcUaDiagnosticInfo>(var: value, type: dt); |
| 163 | default: |
| 164 | qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Variant conversion to Open62541 for typeIndex" << type << " not implemented" ; |
| 165 | } |
| 166 | |
| 167 | return open62541value; |
| 168 | } |
| 169 | |
| 170 | QVariant toQVariant(const UA_Variant &value) |
| 171 | { |
| 172 | if (value.type == nullptr) { |
| 173 | return QVariant(); |
| 174 | } |
| 175 | |
| 176 | if (value.type == &UA_TYPES[UA_TYPES_BOOLEAN]) |
| 177 | return arrayToQVariant<bool, UA_Boolean>(var: value, type: QMetaType::Bool); |
| 178 | else if (value.type == &UA_TYPES[UA_TYPES_SBYTE]) |
| 179 | return arrayToQVariant<signed char, UA_SByte>(var: value, type: QMetaType::SChar); |
| 180 | else if (value.type == &UA_TYPES[UA_TYPES_BYTE]) |
| 181 | return arrayToQVariant<uchar, UA_Byte>(var: value, type: QMetaType::UChar); |
| 182 | else if (value.type == &UA_TYPES[UA_TYPES_INT16]) |
| 183 | return arrayToQVariant<qint16, UA_Int16>(var: value, type: QMetaType::Short); |
| 184 | else if (value.type == &UA_TYPES[UA_TYPES_UINT16]) |
| 185 | return arrayToQVariant<quint16, UA_UInt16>(var: value, type: QMetaType::UShort); |
| 186 | else if (value.type == &UA_TYPES[UA_TYPES_INT32]) |
| 187 | return arrayToQVariant<qint32, UA_Int32>(var: value, type: QMetaType::Int); |
| 188 | else if (value.type == &UA_TYPES[UA_TYPES_UINT32]) |
| 189 | return arrayToQVariant<quint32, UA_UInt32>(var: value, type: QMetaType::UInt); |
| 190 | else if (value.type == &UA_TYPES[UA_TYPES_INT64]) |
| 191 | return arrayToQVariant<int64_t, UA_Int64>(var: value, type: QMetaType::LongLong); |
| 192 | else if (value.type == &UA_TYPES[UA_TYPES_UINT64]) |
| 193 | return arrayToQVariant<uint64_t, UA_UInt64>(var: value, type: QMetaType::ULongLong); |
| 194 | else if (value.type == &UA_TYPES[UA_TYPES_FLOAT]) |
| 195 | return arrayToQVariant<float, UA_Float>(var: value, type: QMetaType::Float); |
| 196 | else if (value.type == &UA_TYPES[UA_TYPES_DOUBLE]) |
| 197 | return arrayToQVariant<double, UA_Double>(var: value, type: QMetaType::Double); |
| 198 | else if (value.type == &UA_TYPES[UA_TYPES_STRING]) |
| 199 | return arrayToQVariant<QString, UA_String>(var: value, type: QMetaType::QString); |
| 200 | else if (value.type == &UA_TYPES[UA_TYPES_BYTESTRING]) |
| 201 | return arrayToQVariant<QByteArray, UA_ByteString>(var: value, type: QMetaType::QByteArray); |
| 202 | else if (value.type == &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]) |
| 203 | return arrayToQVariant<QOpcUaLocalizedText, UA_LocalizedText>(var: value); |
| 204 | else if (value.type == &UA_TYPES[UA_TYPES_NODEID]) |
| 205 | return arrayToQVariant<QString, UA_NodeId>(var: value, type: QMetaType::QString); |
| 206 | else if (value.type == &UA_TYPES[UA_TYPES_DATETIME]) |
| 207 | return arrayToQVariant<QDateTime, UA_DateTime>(var: value, type: QMetaType::QDateTime); |
| 208 | else if (value.type == &UA_TYPES[UA_TYPES_GUID]) |
| 209 | return arrayToQVariant<QUuid, UA_Guid>(var: value, type: QMetaType::QUuid); |
| 210 | else if (value.type == &UA_TYPES[UA_TYPES_XMLELEMENT]) |
| 211 | return arrayToQVariant<QString, UA_XmlElement>(var: value, type: QMetaType::QString); |
| 212 | else if (value.type == &UA_TYPES[UA_TYPES_QUALIFIEDNAME]) |
| 213 | return arrayToQVariant<QOpcUaQualifiedName, UA_QualifiedName>(var: value); |
| 214 | else if (value.type == &UA_TYPES[UA_TYPES_STATUSCODE]) |
| 215 | return arrayToQVariant<QOpcUa::UaStatusCode, UA_StatusCode>(var: value, type: QMetaType::UInt); |
| 216 | else if (value.type == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) |
| 217 | return arrayToQVariant<QVariant, UA_ExtensionObject>(var: value); |
| 218 | else if (value.type == &UA_TYPES[UA_TYPES_EXPANDEDNODEID]) |
| 219 | return arrayToQVariant<QOpcUaExpandedNodeId, UA_ExpandedNodeId>(var: value); |
| 220 | else if (value.type == &UA_TYPES[UA_TYPES_ARGUMENT]) |
| 221 | return arrayToQVariant<QOpcUaArgument, UA_Argument>(var: value); |
| 222 | else if (value.type == &UA_TYPES[UA_TYPES_RANGE]) |
| 223 | return arrayToQVariant<QOpcUaRange, UA_Range>(var: value); |
| 224 | else if (value.type == &UA_TYPES[UA_TYPES_EUINFORMATION]) |
| 225 | return arrayToQVariant<QOpcUaEUInformation, UA_EUInformation>(var: value); |
| 226 | else if (value.type == &UA_TYPES[UA_TYPES_AXISINFORMATION]) |
| 227 | return arrayToQVariant<QOpcUaAxisInformation, UA_AxisInformation>(var: value); |
| 228 | else if (value.type == &UA_TYPES[UA_TYPES_COMPLEXNUMBERTYPE]) |
| 229 | return arrayToQVariant<QOpcUaComplexNumber, UA_ComplexNumberType>(var: value); |
| 230 | else if (value.type == &UA_TYPES[UA_TYPES_DOUBLECOMPLEXNUMBERTYPE]) |
| 231 | return arrayToQVariant<QOpcUaDoubleComplexNumber, UA_DoubleComplexNumberType>(var: value); |
| 232 | else if (value.type == &UA_TYPES[UA_TYPES_XVTYPE]) |
| 233 | return arrayToQVariant<QOpcUaXValue, UA_XVType>(var: value); |
| 234 | else if (value.type == &UA_TYPES[UA_TYPES_STRUCTUREDEFINITION]) |
| 235 | return arrayToQVariant<QOpcUaStructureDefinition, UA_StructureDefinition>(var: value); |
| 236 | else if (value.type == &UA_TYPES[UA_TYPES_STRUCTUREFIELD]) |
| 237 | return arrayToQVariant<QOpcUaStructureField, UA_StructureField>(var: value); |
| 238 | else if (value.type == &UA_TYPES[UA_TYPES_ENUMDEFINITION]) |
| 239 | return arrayToQVariant<QOpcUaEnumDefinition, UA_EnumDefinition>(var: value); |
| 240 | else if (value.type == &UA_TYPES[UA_TYPES_ENUMFIELD]) |
| 241 | return arrayToQVariant<QOpcUaEnumField, UA_EnumField>(var: value); |
| 242 | else if (value.type == &UA_TYPES[UA_TYPES_DIAGNOSTICINFO]) |
| 243 | return arrayToQVariant<QOpcUaDiagnosticInfo, UA_DiagnosticInfo>(var: value); |
| 244 | else if (value.type == &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]) |
| 245 | return arrayToQVariant<QOpcUaSimpleAttributeOperand, UA_SimpleAttributeOperand>(var: value); |
| 246 | else if (value.type == &UA_TYPES[UA_TYPES_ATTRIBUTEOPERAND]) |
| 247 | return arrayToQVariant<QOpcUaSimpleAttributeOperand, UA_SimpleAttributeOperand>(var: value); |
| 248 | else if (value.type == &UA_TYPES[UA_TYPES_LITERALOPERAND]) |
| 249 | return arrayToQVariant<QOpcUaLiteralOperand, UA_LiteralOperand>(var: value); |
| 250 | else if (value.type == &UA_TYPES[UA_TYPES_ELEMENTOPERAND]) |
| 251 | return arrayToQVariant<QOpcUaElementOperand, UA_ElementOperand>(var: value); |
| 252 | else if (value.type == &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT]) |
| 253 | return arrayToQVariant<QOpcUaRelativePathElement, UA_RelativePathElement>(var: value); |
| 254 | else if (value.type == &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT]) |
| 255 | return arrayToQVariant<QOpcUaContentFilterElement, UA_ContentFilterElement>(var: value); |
| 256 | else if (value.type == &UA_TYPES[UA_TYPES_EVENTFILTER]) |
| 257 | return arrayToQVariant<QOpcUaMonitoringParameters::EventFilter, UA_EventFilter>(var: value); |
| 258 | |
| 259 | return uaVariantToQtExtensionObject(var: value); |
| 260 | } |
| 261 | |
| 262 | const UA_DataType *toDataType(QOpcUa::Types valueType) |
| 263 | { |
| 264 | switch (valueType) { |
| 265 | case QOpcUa::Boolean: |
| 266 | return &UA_TYPES[UA_TYPES_BOOLEAN]; |
| 267 | case QOpcUa::Int32: |
| 268 | return &UA_TYPES[UA_TYPES_INT32]; |
| 269 | case QOpcUa::UInt32: |
| 270 | return &UA_TYPES[UA_TYPES_UINT32]; |
| 271 | case QOpcUa::Double: |
| 272 | return &UA_TYPES[UA_TYPES_DOUBLE]; |
| 273 | case QOpcUa::Float: |
| 274 | return &UA_TYPES[UA_TYPES_FLOAT]; |
| 275 | case QOpcUa::String: |
| 276 | return &UA_TYPES[UA_TYPES_STRING]; |
| 277 | case QOpcUa::LocalizedText: |
| 278 | return &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]; |
| 279 | case QOpcUa::DateTime: |
| 280 | return &UA_TYPES[UA_TYPES_DATETIME]; |
| 281 | case QOpcUa::UInt16: |
| 282 | return &UA_TYPES[UA_TYPES_UINT16]; |
| 283 | case QOpcUa::Int16: |
| 284 | return &UA_TYPES[UA_TYPES_INT16]; |
| 285 | case QOpcUa::UInt64: |
| 286 | return &UA_TYPES[UA_TYPES_UINT64]; |
| 287 | case QOpcUa::Int64: |
| 288 | return &UA_TYPES[UA_TYPES_INT64]; |
| 289 | case QOpcUa::Byte: |
| 290 | return &UA_TYPES[UA_TYPES_BYTE]; |
| 291 | case QOpcUa::SByte: |
| 292 | return &UA_TYPES[UA_TYPES_SBYTE]; |
| 293 | case QOpcUa::ByteString: |
| 294 | return &UA_TYPES[UA_TYPES_BYTESTRING]; |
| 295 | case QOpcUa::XmlElement: |
| 296 | return &UA_TYPES[UA_TYPES_XMLELEMENT]; |
| 297 | case QOpcUa::NodeId: |
| 298 | return &UA_TYPES[UA_TYPES_NODEID]; |
| 299 | case QOpcUa::Guid: |
| 300 | return &UA_TYPES[UA_TYPES_GUID]; |
| 301 | case QOpcUa::QualifiedName: |
| 302 | return &UA_TYPES[UA_TYPES_QUALIFIEDNAME]; |
| 303 | case QOpcUa::StatusCode: |
| 304 | return &UA_TYPES[UA_TYPES_STATUSCODE]; |
| 305 | case QOpcUa::Range: |
| 306 | return &UA_TYPES[UA_TYPES_RANGE]; |
| 307 | case QOpcUa::EUInformation: |
| 308 | return &UA_TYPES[UA_TYPES_EUINFORMATION]; |
| 309 | case QOpcUa::ComplexNumber: |
| 310 | return &UA_TYPES[UA_TYPES_COMPLEXNUMBERTYPE]; |
| 311 | case QOpcUa::DoubleComplexNumber: |
| 312 | return &UA_TYPES[UA_TYPES_DOUBLECOMPLEXNUMBERTYPE]; |
| 313 | case QOpcUa::AxisInformation: |
| 314 | return &UA_TYPES[UA_TYPES_AXISINFORMATION]; |
| 315 | case QOpcUa::XV: |
| 316 | return &UA_TYPES[UA_TYPES_XVTYPE]; |
| 317 | case QOpcUa::ExtensionObject: |
| 318 | return &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]; |
| 319 | case QOpcUa::ExpandedNodeId: |
| 320 | return &UA_TYPES[UA_TYPES_EXPANDEDNODEID]; |
| 321 | case QOpcUa::Argument: |
| 322 | return &UA_TYPES[UA_TYPES_ARGUMENT]; |
| 323 | case QOpcUa::StructureDefinition: |
| 324 | return &UA_TYPES[UA_TYPES_STRUCTUREDEFINITION]; |
| 325 | case QOpcUa::StructureField: |
| 326 | return &UA_TYPES[UA_TYPES_STRUCTUREFIELD]; |
| 327 | case QOpcUa::EnumDefinition: |
| 328 | return &UA_TYPES[UA_TYPES_ENUMDEFINITION]; |
| 329 | case QOpcUa::EnumField: |
| 330 | return &UA_TYPES[UA_TYPES_ENUMFIELD]; |
| 331 | case QOpcUa::DiagnosticInfo: |
| 332 | return &UA_TYPES[UA_TYPES_DIAGNOSTICINFO]; |
| 333 | case QOpcUa::SimpleAttributeOperand: |
| 334 | return &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]; |
| 335 | case QOpcUa::AttributeOperand: |
| 336 | return &UA_TYPES[UA_TYPES_ATTRIBUTEOPERAND]; |
| 337 | case QOpcUa::LiteralOperand: |
| 338 | return &UA_TYPES[UA_TYPES_LITERALOPERAND]; |
| 339 | case QOpcUa::ElementOperand: |
| 340 | return &UA_TYPES[UA_TYPES_ELEMENTOPERAND]; |
| 341 | case QOpcUa::RelativePathElement: |
| 342 | return &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT]; |
| 343 | case QOpcUa::ContentFilterElement: |
| 344 | return &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT]; |
| 345 | case QOpcUa::EventFilter: |
| 346 | return &UA_TYPES[UA_TYPES_EVENTFILTER]; |
| 347 | default: |
| 348 | qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Trying to convert undefined type:" << valueType; |
| 349 | return nullptr; |
| 350 | } |
| 351 | } |
| 352 | |
| 353 | template<typename TARGETTYPE, typename UATYPE> |
| 354 | TARGETTYPE scalarToQt(const UATYPE *data) |
| 355 | { |
| 356 | return *reinterpret_cast<const TARGETTYPE *>(data); |
| 357 | } |
| 358 | |
| 359 | template<> |
| 360 | QString scalarToQt<QString, UA_String>(const UA_String *data) |
| 361 | { |
| 362 | return QString::fromUtf8(utf8: reinterpret_cast<const char *>(data->data), size: data->length); |
| 363 | } |
| 364 | |
| 365 | template<> |
| 366 | QByteArray scalarToQt<QByteArray, UA_ByteString>(const UA_ByteString *data) |
| 367 | { |
| 368 | return QByteArray(reinterpret_cast<const char *>(data->data), data->length); |
| 369 | } |
| 370 | |
| 371 | template<> |
| 372 | QOpcUaLocalizedText scalarToQt<QOpcUaLocalizedText, UA_LocalizedText>(const UA_LocalizedText *data) |
| 373 | { |
| 374 | QOpcUaLocalizedText lt; |
| 375 | lt.setLocale(scalarToQt<QString, UA_String>(data: &(data->locale))); |
| 376 | lt.setText(scalarToQt<QString, UA_String>(data: &(data->text))); |
| 377 | return lt; |
| 378 | } |
| 379 | |
| 380 | template<> |
| 381 | QString scalarToQt<QString, UA_NodeId>(const UA_NodeId *data) |
| 382 | { |
| 383 | return Open62541Utils::nodeIdToQString(id: *data); |
| 384 | } |
| 385 | |
| 386 | template<> |
| 387 | QDateTime scalarToQt<QDateTime, UA_DateTime>(const UA_DateTime *data) |
| 388 | { |
| 389 | // OPC UA 1.05 part 6, 5.1.4 |
| 390 | if (*data == (std::numeric_limits<qint64>::min)() || *data == (std::numeric_limits<qint64>::max)()) |
| 391 | return QDateTime(); |
| 392 | |
| 393 | const QDateTime epochStart(QDate(1601, 1, 1), QTime(0, 0), QTimeZone::UTC); |
| 394 | return epochStart.addMSecs(msecs: *data / UA_DATETIME_MSEC).toLocalTime(); |
| 395 | } |
| 396 | |
| 397 | template<> |
| 398 | QOpcUaDataValue scalarToQt<QOpcUaDataValue, UA_DataValue>(const UA_DataValue *data) |
| 399 | { |
| 400 | QOpcUaDataValue result; |
| 401 | if (data->hasSourceTimestamp) |
| 402 | result.setSourceTimestamp(QOpen62541ValueConverter::scalarToQt<QDateTime, UA_DateTime>(data: &data->sourceTimestamp)); |
| 403 | if (data->hasServerTimestamp) |
| 404 | result.setServerTimestamp(QOpen62541ValueConverter::scalarToQt<QDateTime, UA_DateTime>(data: &data->serverTimestamp)); |
| 405 | if (data->hasValue) |
| 406 | result.setValue(QOpen62541ValueConverter::toQVariant(value: data->value)); |
| 407 | if (data->hasStatus) { |
| 408 | result.setStatusCode(QOpen62541ValueConverter::scalarToQt<QOpcUa::UaStatusCode, UA_StatusCode>(data: &data->status)); |
| 409 | } else { |
| 410 | result.setStatusCode(QOpcUa::UaStatusCode::Good); |
| 411 | } |
| 412 | if (data->hasServerPicoseconds) |
| 413 | result.setServerPicoseconds(data->serverPicoseconds); |
| 414 | if (data->hasSourcePicoseconds) |
| 415 | result.setSourcePicoseconds(data->sourcePicoseconds); |
| 416 | |
| 417 | return result; |
| 418 | } |
| 419 | |
| 420 | template<> |
| 421 | QUuid scalarToQt<QUuid, UA_Guid>(const UA_Guid *data) |
| 422 | { |
| 423 | return QUuid(data->data1, data->data2, data->data3, data->data4[0], data->data4[1], data->data4[2], |
| 424 | data->data4[3], data->data4[4], data->data4[5], data->data4[6], data->data4[7]); |
| 425 | } |
| 426 | |
| 427 | template<> |
| 428 | QOpcUaQualifiedName scalarToQt<QOpcUaQualifiedName, UA_QualifiedName>(const UA_QualifiedName *data) |
| 429 | { |
| 430 | QOpcUaQualifiedName temp; |
| 431 | temp.setNamespaceIndex(data->namespaceIndex); |
| 432 | temp.setName(scalarToQt<QString, UA_String>(data: &(data->name))); |
| 433 | return temp; |
| 434 | } |
| 435 | |
| 436 | template<> |
| 437 | QOpcUaArgument scalarToQt<QOpcUaArgument, UA_Argument>(const UA_Argument *data) |
| 438 | { |
| 439 | QOpcUaArgument temp; |
| 440 | temp.setValueRank(data->valueRank); |
| 441 | temp.setDataTypeId(Open62541Utils::nodeIdToQString(id: data->dataType)); |
| 442 | temp.setName(scalarToQt<QString, UA_String>(data: &data->name)); |
| 443 | temp.setDescription(scalarToQt<QOpcUaLocalizedText, UA_LocalizedText>(data: &data->description)); |
| 444 | for (size_t i = 0; i < data->arrayDimensionsSize; ++i) |
| 445 | temp.arrayDimensionsRef().append(t: data->arrayDimensions[i]); |
| 446 | return temp; |
| 447 | } |
| 448 | |
| 449 | template<> |
| 450 | QOpcUaRange scalarToQt<QOpcUaRange, UA_Range>(const UA_Range *data) |
| 451 | { |
| 452 | return QOpcUaRange(data->low, data->high); |
| 453 | } |
| 454 | |
| 455 | template<> |
| 456 | QOpcUaEUInformation scalarToQt<QOpcUaEUInformation, UA_EUInformation>(const UA_EUInformation *data) |
| 457 | { |
| 458 | return QOpcUaEUInformation(scalarToQt<QString, UA_String>(data: &data->namespaceUri), |
| 459 | data->unitId, |
| 460 | scalarToQt<QOpcUaLocalizedText, UA_LocalizedText>(data: &data->displayName), |
| 461 | scalarToQt<QOpcUaLocalizedText, UA_LocalizedText>(data: &data->description)); |
| 462 | } |
| 463 | |
| 464 | template<> |
| 465 | QOpcUaComplexNumber scalarToQt<QOpcUaComplexNumber, UA_ComplexNumberType>(const UA_ComplexNumberType *data) |
| 466 | { |
| 467 | return QOpcUaComplexNumber(data->real, data->imaginary); |
| 468 | } |
| 469 | |
| 470 | template<> |
| 471 | QOpcUaDoubleComplexNumber scalarToQt<QOpcUaDoubleComplexNumber, UA_DoubleComplexNumberType>( |
| 472 | const UA_DoubleComplexNumberType *data) |
| 473 | { |
| 474 | return QOpcUaDoubleComplexNumber(data->real, data->imaginary); |
| 475 | } |
| 476 | |
| 477 | template<> |
| 478 | QOpcUaAxisInformation scalarToQt<QOpcUaAxisInformation, UA_AxisInformation>(const UA_AxisInformation *data) |
| 479 | { |
| 480 | QList<double> axisSteps; |
| 481 | |
| 482 | if (data->axisStepsSize) { |
| 483 | axisSteps.reserve(asize: data->axisStepsSize); |
| 484 | std::copy(first: data->axisSteps, last: data->axisSteps + data->axisStepsSize, result: std::back_inserter(x&: axisSteps)); |
| 485 | } |
| 486 | |
| 487 | return QOpcUaAxisInformation(scalarToQt<QOpcUaEUInformation, UA_EUInformation>(data: &data->engineeringUnits), |
| 488 | scalarToQt<QOpcUaRange, UA_Range>(data: &data->eURange), |
| 489 | scalarToQt<QOpcUaLocalizedText, UA_LocalizedText>(data: &data->title), |
| 490 | static_cast<QOpcUa::AxisScale>(data->axisScaleType), |
| 491 | axisSteps); |
| 492 | } |
| 493 | |
| 494 | template<> |
| 495 | QOpcUaXValue scalarToQt<QOpcUaXValue, UA_XVType>(const UA_XVType *data) |
| 496 | { |
| 497 | return QOpcUaXValue(data->x, data->value); |
| 498 | } |
| 499 | |
| 500 | template<> |
| 501 | QOpcUaStructureField scalarToQt<QOpcUaStructureField, UA_StructureField>(const UA_StructureField *data) |
| 502 | { |
| 503 | QOpcUaStructureField temp; |
| 504 | temp.setName(scalarToQt<QString, UA_String>(data: &data->name)); |
| 505 | temp.setDescription(scalarToQt<QOpcUaLocalizedText, UA_LocalizedText>(data: &data->description)); |
| 506 | temp.setDataType(scalarToQt<QString, UA_NodeId>(data: &data->dataType)); |
| 507 | temp.setIsOptional(data->isOptional); |
| 508 | temp.setMaxStringLength(scalarToQt<quint32, UA_UInt32>(data: &data->maxStringLength)); |
| 509 | temp.setValueRank(scalarToQt<qint32, UA_Int32>(data: &data->valueRank)); |
| 510 | |
| 511 | QList<quint32> dimensions; |
| 512 | for (size_t i = 0; i < data->arrayDimensionsSize; ++i) |
| 513 | dimensions.append(t: data->arrayDimensions[i]); |
| 514 | temp.setArrayDimensions(dimensions); |
| 515 | return temp; |
| 516 | } |
| 517 | |
| 518 | template<> |
| 519 | QOpcUaStructureDefinition scalarToQt<QOpcUaStructureDefinition, UA_StructureDefinition>(const UA_StructureDefinition *data) |
| 520 | { |
| 521 | QOpcUaStructureDefinition temp; |
| 522 | temp.setBaseDataType(scalarToQt<QString, UA_NodeId>(data: &data->baseDataType)); |
| 523 | temp.setDefaultEncodingId(scalarToQt<QString, UA_NodeId>(data: &data->defaultEncodingId)); |
| 524 | temp.setStructureType(static_cast<QOpcUaStructureDefinition::StructureType>(data->structureType)); |
| 525 | |
| 526 | QList<QOpcUaStructureField> fields; |
| 527 | for (size_t i = 0; i < data->fieldsSize; ++i) |
| 528 | fields.append(t: scalarToQt<QOpcUaStructureField, UA_StructureField>(data: &data->fields[i])); |
| 529 | temp.setFields(fields); |
| 530 | return temp; |
| 531 | } |
| 532 | |
| 533 | template<> |
| 534 | QOpcUaEnumField scalarToQt<QOpcUaEnumField, UA_EnumField>(const UA_EnumField *data) |
| 535 | { |
| 536 | QOpcUaEnumField temp; |
| 537 | temp.setName(scalarToQt<QString, UA_String>(data: &data->name)); |
| 538 | temp.setDisplayName(scalarToQt<QOpcUaLocalizedText, UA_LocalizedText>(data: &data->displayName)); |
| 539 | temp.setValue(data->value); |
| 540 | temp.setDescription(scalarToQt<QOpcUaLocalizedText, UA_LocalizedText>(data: &data->description)); |
| 541 | |
| 542 | return temp; |
| 543 | } |
| 544 | |
| 545 | template<> |
| 546 | QOpcUaEnumDefinition scalarToQt<QOpcUaEnumDefinition, UA_EnumDefinition>(const UA_EnumDefinition *data) |
| 547 | { |
| 548 | QOpcUaEnumDefinition temp; |
| 549 | |
| 550 | QList<QOpcUaEnumField> fields; |
| 551 | for (size_t i = 0; i < data->fieldsSize; ++i) |
| 552 | fields.push_back(t: scalarToQt<QOpcUaEnumField, UA_EnumField>(data: &data->fields[i])); |
| 553 | temp.setFields(fields); |
| 554 | |
| 555 | return temp; |
| 556 | } |
| 557 | |
| 558 | template<> |
| 559 | QOpcUaDiagnosticInfo scalarToQt<QOpcUaDiagnosticInfo, UA_DiagnosticInfo>(const UA_DiagnosticInfo *data) |
| 560 | { |
| 561 | QOpcUaDiagnosticInfo temp; |
| 562 | |
| 563 | if (data->hasSymbolicId) { |
| 564 | temp.setHasSymbolicId(true); |
| 565 | temp.setSymbolicId(data->symbolicId); |
| 566 | } |
| 567 | |
| 568 | if (data->hasNamespaceUri) { |
| 569 | temp.setHasNamespaceUri(true); |
| 570 | temp.setNamespaceUri(data->namespaceUri); |
| 571 | } |
| 572 | |
| 573 | if (data->hasLocale) { |
| 574 | temp.setHasLocale(true); |
| 575 | temp.setLocale(data->locale); |
| 576 | } |
| 577 | |
| 578 | if (data->hasLocalizedText) { |
| 579 | temp.setHasLocalizedText(true); |
| 580 | temp.setLocalizedText(data->localizedText); |
| 581 | } |
| 582 | |
| 583 | if (data->hasAdditionalInfo) { |
| 584 | temp.setHasAdditionalInfo(true); |
| 585 | temp.setAdditionalInfo(scalarToQt<QString, UA_String>(data: &data->additionalInfo)); |
| 586 | } |
| 587 | |
| 588 | if (data->hasInnerStatusCode) { |
| 589 | temp.setHasInnerStatusCode(true); |
| 590 | temp.setInnerStatusCode(scalarToQt<QOpcUa::UaStatusCode, UA_StatusCode>(data: &data->innerStatusCode)); |
| 591 | } |
| 592 | |
| 593 | if (data->hasInnerDiagnosticInfo) { |
| 594 | temp.setHasInnerDiagnosticInfo(true); |
| 595 | if (data->innerDiagnosticInfo) |
| 596 | temp.setInnerDiagnosticInfo(scalarToQt<QOpcUaDiagnosticInfo, UA_DiagnosticInfo>(data: data->innerDiagnosticInfo)); |
| 597 | } |
| 598 | |
| 599 | return temp; |
| 600 | } |
| 601 | |
| 602 | template<> |
| 603 | QOpcUaSimpleAttributeOperand scalarToQt<QOpcUaSimpleAttributeOperand, UA_SimpleAttributeOperand>(const UA_SimpleAttributeOperand *data) |
| 604 | { |
| 605 | QOpcUaSimpleAttributeOperand result; |
| 606 | |
| 607 | result.setAttributeId(toQtAttributeId(attr: static_cast<UA_AttributeId>(data->attributeId))); |
| 608 | result.setIndexRange(scalarToQt<QString, UA_String>(data: &data->indexRange)); |
| 609 | result.setTypeId(scalarToQt<QString, UA_NodeId>(data: &data->typeDefinitionId)); |
| 610 | |
| 611 | QList<QOpcUaQualifiedName> browsePath; |
| 612 | for (size_t i = 0; i < data->browsePathSize; ++i) |
| 613 | browsePath.push_back(t: scalarToQt<QOpcUaQualifiedName, UA_QualifiedName>(data: &data->browsePath[i])); |
| 614 | |
| 615 | result.setBrowsePath(browsePath); |
| 616 | |
| 617 | return result; |
| 618 | } |
| 619 | |
| 620 | template<> |
| 621 | QOpcUaLiteralOperand scalarToQt<QOpcUaLiteralOperand, UA_LiteralOperand>(const UA_LiteralOperand *data) |
| 622 | { |
| 623 | QOpcUaLiteralOperand result; |
| 624 | result.setValue(toQVariant(value: data->value)); |
| 625 | result.setType(toQtDataType(type: data->value.type)); |
| 626 | |
| 627 | return result; |
| 628 | } |
| 629 | |
| 630 | template<> |
| 631 | QOpcUaElementOperand scalarToQt<QOpcUaElementOperand, UA_ElementOperand>(const UA_ElementOperand *data) |
| 632 | { |
| 633 | QOpcUaElementOperand result; |
| 634 | result.setIndex(data->index); |
| 635 | |
| 636 | return result; |
| 637 | } |
| 638 | |
| 639 | template<> |
| 640 | QOpcUaRelativePathElement scalarToQt<QOpcUaRelativePathElement, UA_RelativePathElement>(const UA_RelativePathElement *data) |
| 641 | { |
| 642 | QOpcUaRelativePathElement result; |
| 643 | result.setIncludeSubtypes(data->includeSubtypes); |
| 644 | result.setIsInverse(data->isInverse); |
| 645 | result.setReferenceTypeId(scalarToQt<QString, UA_NodeId>(data: &data->referenceTypeId)); |
| 646 | result.setTargetName(scalarToQt<QOpcUaQualifiedName, UA_QualifiedName>(data: &data->targetName)); |
| 647 | |
| 648 | return result; |
| 649 | } |
| 650 | |
| 651 | template<> |
| 652 | QOpcUaAttributeOperand scalarToQt<QOpcUaAttributeOperand, UA_AttributeOperand>(const UA_AttributeOperand *data) |
| 653 | { |
| 654 | QOpcUaAttributeOperand result; |
| 655 | result.setAttributeId(toQtAttributeId(attr: static_cast<UA_AttributeId>(data->attributeId))); |
| 656 | result.setNodeId(scalarToQt<QString, UA_NodeId>(data: &data->nodeId)); |
| 657 | result.setAlias(scalarToQt<QString, UA_String>(data: &data->alias)); |
| 658 | result.setIndexRange(scalarToQt<QString, UA_String>(data: &data->indexRange)); |
| 659 | |
| 660 | QList<QOpcUaRelativePathElement> browsePath; |
| 661 | |
| 662 | for (size_t i = 0; i < data->browsePath.elementsSize; ++i) |
| 663 | browsePath.push_back(t: scalarToQt<QOpcUaRelativePathElement, UA_RelativePathElement>(data: &data->browsePath.elements[i])); |
| 664 | |
| 665 | result.setBrowsePath(browsePath); |
| 666 | |
| 667 | return result; |
| 668 | } |
| 669 | |
| 670 | template<> |
| 671 | QOpcUaContentFilterElement scalarToQt<QOpcUaContentFilterElement, UA_ContentFilterElement>(const UA_ContentFilterElement *data) |
| 672 | { |
| 673 | QOpcUaContentFilterElement result; |
| 674 | |
| 675 | result.setFilterOperator(QOpcUaContentFilterElement::FilterOperator(data->filterOperator)); |
| 676 | QVariantList filterOperands; |
| 677 | |
| 678 | for (size_t i = 0; i < data->filterOperandsSize; ++i) { |
| 679 | if (data->filterOperands[i].encoding < UA_EXTENSIONOBJECT_DECODED) { |
| 680 | filterOperands.push_back(t: scalarToQt<QOpcUaExtensionObject, UA_ExtensionObject>(data: &data->filterOperands[i])); |
| 681 | } else if (data->filterOperands[i].content.decoded.type == &UA_TYPES[UA_TYPES_LITERALOPERAND]) { |
| 682 | filterOperands.push_back(t: scalarToQt<QOpcUaLiteralOperand, UA_LiteralOperand>( |
| 683 | data: static_cast<UA_LiteralOperand *>(data->filterOperands[i].content.decoded.data))); |
| 684 | } else if (data->filterOperands[i].content.decoded.type == &UA_TYPES[UA_TYPES_ELEMENTOPERAND]) { |
| 685 | filterOperands.push_back(t: scalarToQt<QOpcUaElementOperand, UA_ElementOperand>( |
| 686 | data: static_cast<UA_ElementOperand *>(data->filterOperands[i].content.decoded.data))); |
| 687 | } else if (data->filterOperands[i].content.decoded.type == &UA_TYPES[UA_TYPES_ATTRIBUTEOPERAND]) { |
| 688 | filterOperands.push_back(t: scalarToQt<QOpcUaAttributeOperand, UA_AttributeOperand>( |
| 689 | data: static_cast<UA_AttributeOperand *>(data->filterOperands[i].content.decoded.data))); |
| 690 | } else if (data->filterOperands[i].content.decoded.type == &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]) { |
| 691 | filterOperands.push_back(t: scalarToQt<QOpcUaSimpleAttributeOperand, UA_SimpleAttributeOperand>( |
| 692 | data: static_cast<UA_SimpleAttributeOperand *>(data->filterOperands[i].content.decoded.data))); |
| 693 | } else { |
| 694 | qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Unknown operand in content filter element, unable to convert" ; |
| 695 | return {}; |
| 696 | } |
| 697 | } |
| 698 | |
| 699 | result.setFilterOperands(filterOperands); |
| 700 | |
| 701 | return result; |
| 702 | } |
| 703 | |
| 704 | template<> |
| 705 | QOpcUaMonitoringParameters::EventFilter scalarToQt<QOpcUaMonitoringParameters::EventFilter, UA_EventFilter>(const UA_EventFilter *data) |
| 706 | { |
| 707 | QOpcUaMonitoringParameters::EventFilter eventFilter; |
| 708 | |
| 709 | for (size_t i = 0; i < data->selectClausesSize; ++i) { |
| 710 | eventFilter << scalarToQt<QOpcUaSimpleAttributeOperand, UA_SimpleAttributeOperand>(data: &data->selectClauses[i]); |
| 711 | } |
| 712 | |
| 713 | for (size_t i = 0; i < data->whereClause.elementsSize; ++i) { |
| 714 | eventFilter << scalarToQt<QOpcUaContentFilterElement, UA_ContentFilterElement>(data: &data->whereClause.elements[i]); |
| 715 | } |
| 716 | |
| 717 | return eventFilter; |
| 718 | } |
| 719 | |
| 720 | template <> |
| 721 | QVariant scalarToQt<QVariant, UA_ExtensionObject>(const UA_ExtensionObject *data) |
| 722 | { |
| 723 | // OPC UA 1.05 part 6, 5.2.2.15 states that an extension object can have no body, a ByteString encoded body |
| 724 | // or an XML encoded body. |
| 725 | |
| 726 | // Handle extension object without body |
| 727 | if (data->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) { |
| 728 | QOpcUaExtensionObject obj; |
| 729 | obj.setEncoding(QOpcUaExtensionObject::Encoding::NoBody); |
| 730 | return QVariant::fromValue(value: obj); |
| 731 | } |
| 732 | |
| 733 | // Some types are automatically decoded by open62541. In this case, the encoding is UA_EXTENSIONOBJECT_DECODED |
| 734 | if (data->encoding != UA_EXTENSIONOBJECT_ENCODED_XML && data->encoding != UA_EXTENSIONOBJECT_ENCODED_BYTESTRING && data->content.decoded.data) { |
| 735 | |
| 736 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_ARGUMENT] && data->content.decoded.data != nullptr) { |
| 737 | return scalarToQt<QOpcUaArgument, UA_Argument>(data: reinterpret_cast<UA_Argument *>(data->content.decoded.data)); |
| 738 | } |
| 739 | |
| 740 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_RANGE] && data->content.decoded.data != nullptr) { |
| 741 | return scalarToQt<QOpcUaRange, UA_Range>(data: reinterpret_cast<UA_Range *>(data->content.decoded.data)); |
| 742 | } |
| 743 | |
| 744 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_EUINFORMATION] && data->content.decoded.data) { |
| 745 | return scalarToQt<QOpcUaEUInformation, UA_EUInformation> |
| 746 | (data: reinterpret_cast<UA_EUInformation *>(data->content.decoded.data)); |
| 747 | } |
| 748 | |
| 749 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_COMPLEXNUMBERTYPE] && data->content.decoded.data) { |
| 750 | return scalarToQt<QOpcUaComplexNumber, UA_ComplexNumberType> |
| 751 | (data: reinterpret_cast<UA_ComplexNumberType *>(data->content.decoded.data)); |
| 752 | } |
| 753 | |
| 754 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_DOUBLECOMPLEXNUMBERTYPE] && data->content.decoded.data) { |
| 755 | return scalarToQt<QOpcUaDoubleComplexNumber, UA_DoubleComplexNumberType> |
| 756 | (data: reinterpret_cast<UA_DoubleComplexNumberType *>(data->content.decoded.data)); |
| 757 | } |
| 758 | |
| 759 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_AXISINFORMATION] && data->content.decoded.data) { |
| 760 | return scalarToQt<QOpcUaAxisInformation, UA_AxisInformation> |
| 761 | (data: reinterpret_cast<UA_AxisInformation *>(data->content.decoded.data)); |
| 762 | } |
| 763 | |
| 764 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_XVTYPE] && data->content.decoded.data) { |
| 765 | return scalarToQt<QOpcUaXValue, UA_XVType> |
| 766 | (data: reinterpret_cast<UA_XVType *>(data->content.decoded.data)); |
| 767 | } |
| 768 | |
| 769 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_STRUCTUREDEFINITION]) { |
| 770 | return scalarToQt<QOpcUaStructureDefinition, UA_StructureDefinition> |
| 771 | (data: reinterpret_cast<UA_StructureDefinition *>(data->content.decoded.data)); |
| 772 | } |
| 773 | |
| 774 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_STRUCTUREFIELD]) { |
| 775 | return scalarToQt<QOpcUaStructureField, UA_StructureField> |
| 776 | (data: reinterpret_cast<UA_StructureField *>(data->content.decoded.data)); |
| 777 | } |
| 778 | |
| 779 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_ENUMDEFINITION]) { |
| 780 | return scalarToQt<QOpcUaEnumDefinition, UA_EnumDefinition> |
| 781 | (data: reinterpret_cast<UA_EnumDefinition *>(data->content.decoded.data)); |
| 782 | } |
| 783 | |
| 784 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_ENUMFIELD]) { |
| 785 | return scalarToQt<QOpcUaEnumField, UA_EnumField> |
| 786 | (data: reinterpret_cast<UA_EnumField *>(data->content.decoded.data)); |
| 787 | } |
| 788 | |
| 789 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND] && data->content.decoded.data) { |
| 790 | return scalarToQt<QOpcUaSimpleAttributeOperand, UA_SimpleAttributeOperand> |
| 791 | (data: reinterpret_cast<UA_SimpleAttributeOperand *>(data->content.decoded.data)); |
| 792 | } |
| 793 | |
| 794 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_ATTRIBUTEOPERAND] && data->content.decoded.data) { |
| 795 | return scalarToQt<QOpcUaAttributeOperand, UA_AttributeOperand> |
| 796 | (data: reinterpret_cast<UA_AttributeOperand *>(data->content.decoded.data)); |
| 797 | } |
| 798 | |
| 799 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_LITERALOPERAND] && data->content.decoded.data) { |
| 800 | return scalarToQt<QOpcUaLiteralOperand, UA_LiteralOperand> |
| 801 | (data: reinterpret_cast<UA_LiteralOperand *>(data->content.decoded.data)); |
| 802 | } |
| 803 | |
| 804 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_ELEMENTOPERAND] && data->content.decoded.data) { |
| 805 | return scalarToQt<QOpcUaElementOperand, UA_ElementOperand> |
| 806 | (data: reinterpret_cast<UA_ElementOperand *>(data->content.decoded.data)); |
| 807 | } |
| 808 | |
| 809 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT] && data->content.decoded.data) { |
| 810 | return scalarToQt<QOpcUaRelativePathElement, UA_RelativePathElement> |
| 811 | (data: reinterpret_cast<UA_RelativePathElement *>(data->content.decoded.data)); |
| 812 | } |
| 813 | |
| 814 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT] && data->content.decoded.data) { |
| 815 | return scalarToQt<QOpcUaContentFilterElement, UA_ContentFilterElement> |
| 816 | (data: reinterpret_cast<UA_ContentFilterElement *>(data->content.decoded.data)); |
| 817 | } |
| 818 | |
| 819 | if (data->content.decoded.type == &UA_TYPES[UA_TYPES_EVENTFILTER] && data->content.decoded.data) { |
| 820 | return scalarToQt<QOpcUaMonitoringParameters::EventFilter, UA_EventFilter> |
| 821 | (data: reinterpret_cast<UA_EventFilter *>(data->content.decoded.data)); |
| 822 | } |
| 823 | |
| 824 | bool success = false; |
| 825 | const auto result = encodeAsBinaryExtensionObject(data: data->content.decoded.data, type: data->content.decoded.type, success: &success); |
| 826 | if (success) |
| 827 | return result; |
| 828 | |
| 829 | qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Failed to re-encode decoded extension object, unable to convert" << data->content.decoded.type->typeName; |
| 830 | return {}; |
| 831 | } |
| 832 | |
| 833 | QByteArray buffer = QByteArray::fromRawData(data: reinterpret_cast<const char *>(data->content.encoded.body.data), |
| 834 | size: data->content.encoded.body.length); |
| 835 | |
| 836 | // Return extension objects with binary or XML body as QOpcUaExtensionObject |
| 837 | QOpcUaExtensionObject obj; |
| 838 | obj.setEncoding(static_cast<QOpcUaExtensionObject::Encoding>(data->encoding)); |
| 839 | obj.setEncodingTypeId(Open62541Utils::nodeIdToQString(id: data->content.encoded.typeId)); |
| 840 | obj.setEncodedBody(QByteArray(buffer.constData(), buffer.size())); |
| 841 | return obj; |
| 842 | } |
| 843 | |
| 844 | template<> |
| 845 | QOpcUaExpandedNodeId scalarToQt<QOpcUaExpandedNodeId, UA_ExpandedNodeId>(const UA_ExpandedNodeId *data) |
| 846 | { |
| 847 | QOpcUaExpandedNodeId temp; |
| 848 | temp.setServerIndex(data->serverIndex); |
| 849 | temp.setNodeId(Open62541Utils::nodeIdToQString(id: data->nodeId)); |
| 850 | temp.setNamespaceUri(scalarToQt<QString, UA_String>(data: &data->namespaceUri)); |
| 851 | return temp; |
| 852 | } |
| 853 | |
| 854 | template<typename TARGETTYPE, typename UATYPE> |
| 855 | QVariant arrayToQVariant(const UA_Variant &var, QMetaType::Type type) |
| 856 | { |
| 857 | UATYPE *temp = static_cast<UATYPE *>(var.data); |
| 858 | |
| 859 | if (var.arrayLength > 0) { |
| 860 | QVariantList list(var.arrayLength); |
| 861 | for (size_t i = 0; i < var.arrayLength; ++i) { |
| 862 | QVariant tempVar = QVariant::fromValue(scalarToQt<TARGETTYPE, UATYPE>(&temp[i])); |
| 863 | if (type != QMetaType::UnknownType && type != static_cast<QMetaType::Type>(tempVar.metaType().id())) |
| 864 | tempVar.convert(type: QMetaType(type)); |
| 865 | list[i] = tempVar; |
| 866 | } |
| 867 | |
| 868 | if (var.arrayDimensionsSize > 0) { |
| 869 | // Ensure that the array dimensions fit in a QList |
| 870 | if (var.arrayDimensionsSize > static_cast<quint64>((std::numeric_limits<int>::max)())) |
| 871 | return QOpcUaMultiDimensionalArray(); |
| 872 | QList<quint32> arrayDimensions; |
| 873 | std::copy(first: var.arrayDimensions, last: var.arrayDimensions+var.arrayDimensionsSize, result: std::back_inserter(x&: arrayDimensions)); |
| 874 | return QOpcUaMultiDimensionalArray(list, arrayDimensions); |
| 875 | } |
| 876 | |
| 877 | if (list.size() == 1) |
| 878 | return list.at(i: 0); |
| 879 | else |
| 880 | return list; |
| 881 | } else if (UA_Variant_isScalar(v: &var)) { |
| 882 | QVariant tempVar = QVariant::fromValue(scalarToQt<TARGETTYPE, UATYPE>(temp)); |
| 883 | if (type != QMetaType::UnknownType && type != static_cast<QMetaType::Type>(tempVar.metaType().id())) |
| 884 | tempVar.convert(type: QMetaType(type)); |
| 885 | return tempVar; |
| 886 | } else if (var.arrayLength == 0 && var.data == UA_EMPTY_ARRAY_SENTINEL) { |
| 887 | return QVariantList(); // Return empty QVariantList for empty array |
| 888 | } |
| 889 | |
| 890 | return QVariant(); // Return empty QVariant for empty scalar variant |
| 891 | } |
| 892 | |
| 893 | template<typename TARGETTYPE, typename QTTYPE> |
| 894 | void scalarFromQt(const QTTYPE &value, TARGETTYPE *ptr) |
| 895 | { |
| 896 | *ptr = static_cast<TARGETTYPE>(value); |
| 897 | } |
| 898 | |
| 899 | template<> |
| 900 | void scalarFromQt<UA_DateTime, QDateTime>(const QDateTime &value, UA_DateTime *ptr) |
| 901 | { |
| 902 | if (!value.isValid()) { |
| 903 | *ptr = (std::numeric_limits<qint64>::min)(); |
| 904 | return; |
| 905 | } |
| 906 | |
| 907 | // OPC UA 1.05 part 6, 5.1.4 |
| 908 | const QDateTime uaEpochStart(QDate(1601, 1, 1), QTime(0, 0), QTimeZone::UTC); |
| 909 | |
| 910 | *ptr = UA_DATETIME_MSEC * (value.toMSecsSinceEpoch() - uaEpochStart.toMSecsSinceEpoch()); |
| 911 | } |
| 912 | |
| 913 | template<> |
| 914 | void scalarFromQt<UA_String, QString>(const QString &value, UA_String *ptr) |
| 915 | { |
| 916 | *ptr = UA_STRING_ALLOC(value.toUtf8().constData()); |
| 917 | } |
| 918 | |
| 919 | template<> |
| 920 | void scalarFromQt<UA_LocalizedText, QOpcUaLocalizedText>(const QOpcUaLocalizedText &value, UA_LocalizedText *ptr) |
| 921 | { |
| 922 | scalarFromQt<UA_String, QString>(value: value.locale(), ptr: &(ptr->locale)); |
| 923 | scalarFromQt<UA_String, QString>(value: value.text(), ptr: &(ptr->text)); |
| 924 | } |
| 925 | |
| 926 | template<> |
| 927 | void scalarFromQt<UA_ByteString, QByteArray>(const QByteArray &value, UA_ByteString *ptr) |
| 928 | { |
| 929 | ptr->length = value.size(); |
| 930 | UA_StatusCode success = UA_Array_copy(src: reinterpret_cast<const UA_Byte *>(value.constData()), |
| 931 | size: value.size(), dst: reinterpret_cast<void **>(&ptr->data), type: &UA_TYPES[UA_TYPES_BYTE]); |
| 932 | if (success != UA_STATUSCODE_GOOD) { |
| 933 | ptr->length = 0; |
| 934 | ptr->data = nullptr; |
| 935 | } |
| 936 | } |
| 937 | |
| 938 | template<> |
| 939 | void scalarFromQt<UA_NodeId, QString>(const QString &value, UA_NodeId *ptr) |
| 940 | { |
| 941 | *ptr = Open62541Utils::nodeIdFromQString(name: value); |
| 942 | } |
| 943 | |
| 944 | template<> |
| 945 | void scalarFromQt<UA_QualifiedName, QOpcUaQualifiedName>(const QOpcUaQualifiedName &value, UA_QualifiedName *ptr) |
| 946 | { |
| 947 | ptr->namespaceIndex = value.namespaceIndex(); |
| 948 | scalarFromQt<UA_String, QString>(value: value.name(), ptr: &(ptr->name)); |
| 949 | } |
| 950 | |
| 951 | template<> |
| 952 | void scalarFromQt<UA_Guid, QUuid>(const QUuid &value, UA_Guid *ptr) |
| 953 | { |
| 954 | ptr->data1 = value.data1; |
| 955 | ptr->data2 = value.data2; |
| 956 | ptr->data3 = value.data3; |
| 957 | std::memcpy(dest: ptr->data4, src: value.data4, n: sizeof(value.data4)); |
| 958 | } |
| 959 | |
| 960 | template<> |
| 961 | void scalarFromQt<UA_Range, QOpcUaRange>(const QOpcUaRange &value, UA_Range *ptr) |
| 962 | { |
| 963 | ptr->low = value.low(); |
| 964 | ptr->high = value.high(); |
| 965 | } |
| 966 | |
| 967 | template<> |
| 968 | void scalarFromQt<UA_EUInformation, QOpcUaEUInformation>(const QOpcUaEUInformation &value, UA_EUInformation *ptr) |
| 969 | { |
| 970 | scalarFromQt<UA_String, QString>(value: value.namespaceUri(), ptr: &ptr->namespaceUri); |
| 971 | scalarFromQt<UA_LocalizedText, QOpcUaLocalizedText>(value: value.description(), ptr: &ptr->description); |
| 972 | scalarFromQt<UA_LocalizedText, QOpcUaLocalizedText>(value: value.displayName(), ptr: &ptr->displayName); |
| 973 | ptr->unitId = value.unitId(); |
| 974 | } |
| 975 | |
| 976 | template<> |
| 977 | void scalarFromQt<UA_ComplexNumberType, QOpcUaComplexNumber>(const QOpcUaComplexNumber &value, UA_ComplexNumberType *ptr) |
| 978 | { |
| 979 | ptr->real = value.real(); |
| 980 | ptr->imaginary = value.imaginary(); |
| 981 | } |
| 982 | |
| 983 | template<> |
| 984 | void scalarFromQt<UA_DoubleComplexNumberType, QOpcUaDoubleComplexNumber>(const QOpcUaDoubleComplexNumber &value, UA_DoubleComplexNumberType *ptr) |
| 985 | { |
| 986 | ptr->real = value.real(); |
| 987 | ptr->imaginary = value.imaginary(); |
| 988 | } |
| 989 | |
| 990 | template<> |
| 991 | void scalarFromQt<UA_AxisInformation, QOpcUaAxisInformation>(const QOpcUaAxisInformation &value, UA_AxisInformation *ptr) |
| 992 | { |
| 993 | scalarFromQt<UA_LocalizedText, QOpcUaLocalizedText>(value: value.title(), ptr: &ptr->title); |
| 994 | scalarFromQt<UA_EUInformation, QOpcUaEUInformation>(value: value.engineeringUnits(), ptr: &ptr->engineeringUnits); |
| 995 | scalarFromQt<UA_Range, QOpcUaRange>(value: value.eURange(), ptr: &ptr->eURange); |
| 996 | ptr->axisScaleType = static_cast<UA_AxisScaleEnumeration>(value.axisScaleType()); |
| 997 | ptr->axisStepsSize = value.axisSteps().size(); |
| 998 | if (ptr->axisStepsSize) { |
| 999 | auto res = UA_Array_copy(src: value.axisSteps().constData(), size: ptr->axisStepsSize, dst: reinterpret_cast<void **>(&ptr->axisSteps), |
| 1000 | type: &UA_TYPES[UA_TYPES_DOUBLE]); |
| 1001 | |
| 1002 | if (res != UA_STATUSCODE_GOOD) |
| 1003 | qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Failed to copy axis steps" ; |
| 1004 | } else { |
| 1005 | ptr->axisSteps = nullptr; |
| 1006 | } |
| 1007 | } |
| 1008 | |
| 1009 | template<> |
| 1010 | void scalarFromQt<UA_XVType, QOpcUaXValue>(const QOpcUaXValue &value, UA_XVType *ptr) |
| 1011 | { |
| 1012 | ptr->x = value.x(); |
| 1013 | ptr->value = value.value(); |
| 1014 | } |
| 1015 | |
| 1016 | template<> |
| 1017 | void scalarFromQt<UA_StructureField, QOpcUaStructureField>(const QOpcUaStructureField &value, UA_StructureField *ptr) |
| 1018 | { |
| 1019 | scalarFromQt<UA_NodeId, QString>(value: value.dataType(), ptr: &ptr->dataType); |
| 1020 | ptr->maxStringLength = value.maxStringLength(); |
| 1021 | ptr->isOptional = value.isOptional(); |
| 1022 | ptr->valueRank = value.valueRank(); |
| 1023 | scalarFromQt<UA_String, QString>(value: value.name(), ptr: &ptr->name); |
| 1024 | scalarFromQt<UA_LocalizedText, QOpcUaLocalizedText>(value: value.description(), ptr: &ptr->description); |
| 1025 | |
| 1026 | ptr->arrayDimensionsSize = value.arrayDimensions().size(); |
| 1027 | if (ptr->arrayDimensionsSize) { |
| 1028 | ptr->arrayDimensions = static_cast<quint32 *>(UA_Array_new(size: ptr->arrayDimensionsSize, type: &UA_TYPES[UA_TYPES_UINT32])); |
| 1029 | |
| 1030 | for (int i = 0; i < value.arrayDimensions().size(); ++i) |
| 1031 | ptr->arrayDimensions[i] = value.arrayDimensions().at(i); |
| 1032 | } |
| 1033 | } |
| 1034 | |
| 1035 | template<> |
| 1036 | void scalarFromQt<UA_StructureDefinition, QOpcUaStructureDefinition>(const QOpcUaStructureDefinition &value, UA_StructureDefinition *ptr) |
| 1037 | { |
| 1038 | scalarFromQt<UA_NodeId, QString>(value: value.baseDataType(), ptr: &ptr->baseDataType); |
| 1039 | scalarFromQt<UA_NodeId, QString>(value: value.defaultEncodingId(), ptr: &ptr->defaultEncodingId); |
| 1040 | ptr->structureType = static_cast<UA_StructureType>(value.structureType()); |
| 1041 | |
| 1042 | if (!value.fields().isEmpty()) { |
| 1043 | ptr->fieldsSize = value.fields().size(); |
| 1044 | ptr->fields = static_cast<UA_StructureField *>(UA_Array_new(size: ptr->fieldsSize, type: &UA_TYPES[UA_TYPES_STRUCTUREFIELD])); |
| 1045 | |
| 1046 | for (int i = 0; i < value.fields().size(); ++i) |
| 1047 | scalarFromQt<UA_StructureField, QOpcUaStructureField>(value: value.fields().at(i), ptr: &ptr->fields[i]); |
| 1048 | } |
| 1049 | } |
| 1050 | |
| 1051 | template<> |
| 1052 | void scalarFromQt<UA_EnumField, QOpcUaEnumField>(const QOpcUaEnumField &value, UA_EnumField *ptr) |
| 1053 | { |
| 1054 | scalarFromQt<UA_String, QString>(value: value.name(), ptr: &ptr->name); |
| 1055 | scalarFromQt<UA_LocalizedText, QOpcUaLocalizedText>(value: value.description(), ptr: &ptr->description); |
| 1056 | scalarFromQt<UA_LocalizedText, QOpcUaLocalizedText>(value: value.displayName(), ptr: &ptr->displayName); |
| 1057 | ptr->value = value.value(); |
| 1058 | } |
| 1059 | |
| 1060 | template<> |
| 1061 | void scalarFromQt<UA_EnumDefinition, QOpcUaEnumDefinition>(const QOpcUaEnumDefinition &value, UA_EnumDefinition *ptr) |
| 1062 | { |
| 1063 | if (!value.fields().isEmpty()) { |
| 1064 | ptr->fieldsSize = value.fields().size(); |
| 1065 | ptr->fields = static_cast<UA_EnumField *>(UA_Array_new(size: ptr->fieldsSize, type: &UA_TYPES[UA_TYPES_ENUMFIELD])); |
| 1066 | |
| 1067 | for (int i = 0; i < value.fields().size(); ++i) |
| 1068 | scalarFromQt<UA_EnumField, QOpcUaEnumField>(value: value.fields().at(i), ptr: &ptr->fields[i]); |
| 1069 | } |
| 1070 | } |
| 1071 | |
| 1072 | template<> |
| 1073 | void scalarFromQt<UA_DiagnosticInfo, QOpcUaDiagnosticInfo>(const QOpcUaDiagnosticInfo &value, UA_DiagnosticInfo *ptr) |
| 1074 | { |
| 1075 | if (value.hasSymbolicId()) { |
| 1076 | ptr->hasSymbolicId = true; |
| 1077 | ptr->symbolicId = value.symbolicId(); |
| 1078 | } |
| 1079 | |
| 1080 | if (value.hasNamespaceUri()) { |
| 1081 | ptr->hasNamespaceUri = true; |
| 1082 | ptr->namespaceUri = value.namespaceUri(); |
| 1083 | } |
| 1084 | |
| 1085 | if (value.hasLocale()) { |
| 1086 | ptr->hasLocale = true; |
| 1087 | ptr->locale = value.locale(); |
| 1088 | } |
| 1089 | |
| 1090 | if (value.hasLocalizedText()) { |
| 1091 | ptr->hasLocalizedText = true; |
| 1092 | ptr->localizedText = value.localizedText(); |
| 1093 | } |
| 1094 | |
| 1095 | if (value.hasAdditionalInfo()) { |
| 1096 | ptr->hasAdditionalInfo = true; |
| 1097 | scalarFromQt<UA_String, QString>(value: value.additionalInfo(), ptr: &ptr->additionalInfo); |
| 1098 | } |
| 1099 | |
| 1100 | if (value.hasInnerStatusCode()) { |
| 1101 | ptr->hasInnerStatusCode = true; |
| 1102 | ptr->innerStatusCode = value.innerStatusCode(); |
| 1103 | } |
| 1104 | |
| 1105 | if (value.hasInnerDiagnosticInfo()) { |
| 1106 | ptr->hasInnerDiagnosticInfo = true; |
| 1107 | ptr->innerDiagnosticInfo = UA_DiagnosticInfo_new(); |
| 1108 | scalarFromQt<UA_DiagnosticInfo, QOpcUaDiagnosticInfo>(value: value.innerDiagnosticInfo(), ptr: ptr->innerDiagnosticInfo); |
| 1109 | } |
| 1110 | } |
| 1111 | |
| 1112 | template<> |
| 1113 | void scalarFromQt<UA_ExtensionObject, QOpcUaExtensionObject>(const QOpcUaExtensionObject &obj, UA_ExtensionObject *ptr) |
| 1114 | { |
| 1115 | QByteArray temp = obj.encodedBody(); |
| 1116 | UA_NodeId encodingId = Open62541Utils::nodeIdFromQString(name: obj.encodingTypeId()); |
| 1117 | UaDeleter<UA_NodeId> nodeIdDeleter(&encodingId, UA_NodeId_clear); |
| 1118 | createExtensionObject(data&: temp, typeEncodingId: encodingId, ptr, encoding: obj.encoding()); |
| 1119 | } |
| 1120 | |
| 1121 | template<> |
| 1122 | void scalarFromQt<UA_ExpandedNodeId, QOpcUaExpandedNodeId>(const QOpcUaExpandedNodeId &value, UA_ExpandedNodeId *ptr) |
| 1123 | { |
| 1124 | ptr->serverIndex = value.serverIndex(); |
| 1125 | scalarFromQt<UA_String, QString>(value: value.namespaceUri(), ptr: &ptr->namespaceUri); |
| 1126 | ptr->nodeId = Open62541Utils::nodeIdFromQString(name: value.nodeId()); |
| 1127 | } |
| 1128 | |
| 1129 | template<> |
| 1130 | void scalarFromQt<UA_Argument, QOpcUaArgument>(const QOpcUaArgument &value, UA_Argument *ptr) |
| 1131 | { |
| 1132 | ptr->valueRank = value.valueRank(); |
| 1133 | scalarFromQt<UA_LocalizedText, QOpcUaLocalizedText>(value: value.description(), ptr: &ptr->description); |
| 1134 | scalarFromQt<UA_String, QString>(value: value.name(), ptr: &ptr->name); |
| 1135 | ptr->dataType = Open62541Utils::nodeIdFromQString(name: value.dataTypeId()); |
| 1136 | ptr->arrayDimensionsSize = value.arrayDimensions().size(); |
| 1137 | UA_StatusCode res = UA_Array_copy(src: value.arrayDimensions().constData(), size: ptr->arrayDimensionsSize, |
| 1138 | dst: reinterpret_cast<void **>(&ptr->arrayDimensions), type: &UA_TYPES[UA_TYPES_UINT32]); |
| 1139 | if (res != UA_STATUSCODE_GOOD) |
| 1140 | ptr->arrayDimensionsSize = 0; |
| 1141 | } |
| 1142 | |
| 1143 | template<> |
| 1144 | void scalarFromQt<UA_SimpleAttributeOperand, QOpcUaSimpleAttributeOperand>(const QOpcUaSimpleAttributeOperand &value, UA_SimpleAttributeOperand *ptr) |
| 1145 | { |
| 1146 | ptr->attributeId = toUaAttributeId(attr: value.attributeId()); |
| 1147 | if (!value.indexRange().isEmpty()) |
| 1148 | scalarFromQt<UA_String, QString>(value: value.indexRange(), ptr: &ptr->indexRange); |
| 1149 | scalarFromQt<UA_NodeId, QString>(value: value.typeId(), ptr: &ptr->typeDefinitionId); |
| 1150 | ptr->browsePathSize = value.browsePath().size(); |
| 1151 | if (!value.browsePath().isEmpty()) { |
| 1152 | ptr->browsePath = static_cast<UA_QualifiedName *>(UA_Array_new(size: value.browsePath().size(), type: &UA_TYPES[UA_TYPES_QUALIFIEDNAME])); |
| 1153 | for (size_t i = 0; i < ptr->browsePathSize; ++i) |
| 1154 | scalarFromQt<UA_QualifiedName, QOpcUaQualifiedName>(value: value.browsePath().at(i), ptr: &ptr->browsePath[i]); |
| 1155 | } else { |
| 1156 | ptr->browsePath = static_cast<UA_QualifiedName *>(UA_EMPTY_ARRAY_SENTINEL); |
| 1157 | } |
| 1158 | } |
| 1159 | |
| 1160 | template<> |
| 1161 | void scalarFromQt<UA_LiteralOperand, QOpcUaLiteralOperand>(const QOpcUaLiteralOperand &value, UA_LiteralOperand *ptr) |
| 1162 | { |
| 1163 | ptr->value = toOpen62541Variant(value: value.value(), type: value.type()); |
| 1164 | } |
| 1165 | |
| 1166 | template<> |
| 1167 | void scalarFromQt<UA_ElementOperand, QOpcUaElementOperand>(const QOpcUaElementOperand &value, UA_ElementOperand *ptr) |
| 1168 | { |
| 1169 | ptr->index = value.index(); |
| 1170 | } |
| 1171 | |
| 1172 | template<> |
| 1173 | void scalarFromQt<UA_RelativePathElement, QOpcUaRelativePathElement>(const QOpcUaRelativePathElement &value, UA_RelativePathElement *ptr) |
| 1174 | { |
| 1175 | ptr->includeSubtypes = value.includeSubtypes(); |
| 1176 | ptr->isInverse = value.isInverse(); |
| 1177 | scalarFromQt<UA_NodeId, QString>(value: value.referenceTypeId(), ptr: &ptr->referenceTypeId); |
| 1178 | scalarFromQt<UA_QualifiedName, QOpcUaQualifiedName>(value: value.targetName(), ptr: &ptr->targetName); |
| 1179 | } |
| 1180 | |
| 1181 | template<> |
| 1182 | void scalarFromQt<UA_AttributeOperand, QOpcUaAttributeOperand>(const QOpcUaAttributeOperand &value, UA_AttributeOperand *ptr) |
| 1183 | { |
| 1184 | ptr->attributeId = toUaAttributeId(attr: value.attributeId()); |
| 1185 | scalarFromQt<UA_String, QString>(value: value.alias(), ptr: &ptr->alias); |
| 1186 | if (!value.indexRange().isEmpty()) |
| 1187 | scalarFromQt<UA_String, QString>(value: value.indexRange(), ptr: &ptr->indexRange); |
| 1188 | scalarFromQt<UA_NodeId, QString>(value: value.nodeId(), ptr: &ptr->nodeId); |
| 1189 | ptr->browsePath.elementsSize = value.browsePath().size(); |
| 1190 | if (ptr->browsePath.elementsSize) { |
| 1191 | ptr->browsePath.elements = static_cast<UA_RelativePathElement *>(UA_Array_new(size: ptr->browsePath.elementsSize, |
| 1192 | type: &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT])); |
| 1193 | for (size_t i = 0; i < ptr->browsePath.elementsSize; ++i) |
| 1194 | scalarFromQt<UA_RelativePathElement, QOpcUaRelativePathElement>(value: value.browsePath().at(i), |
| 1195 | ptr: &ptr->browsePath.elements[i]); |
| 1196 | } |
| 1197 | } |
| 1198 | |
| 1199 | template<> |
| 1200 | void scalarFromQt<UA_ContentFilterElement, QOpcUaContentFilterElement>(const QOpcUaContentFilterElement &value, UA_ContentFilterElement *ptr) |
| 1201 | { |
| 1202 | ptr->filterOperator = static_cast<UA_FilterOperator>(value.filterOperator()); |
| 1203 | ptr->filterOperandsSize = value.filterOperands().size(); |
| 1204 | if (ptr->filterOperandsSize) { |
| 1205 | ptr->filterOperands = static_cast<UA_ExtensionObject *>(UA_Array_new(size: ptr->filterOperandsSize, type: &UA_TYPES[UA_TYPES_EXTENSIONOBJECT])); |
| 1206 | |
| 1207 | for (size_t i = 0; i < ptr->filterOperandsSize; ++i) { |
| 1208 | if (value.filterOperands().at(i).canConvert<QOpcUaElementOperand>()) { |
| 1209 | const auto operand = UA_ElementOperand_new(); |
| 1210 | scalarFromQt<UA_ElementOperand, QOpcUaElementOperand>(value: value.filterOperands().at(i).value<QOpcUaElementOperand>(), ptr: operand); |
| 1211 | ptr->filterOperands[i].encoding = UA_EXTENSIONOBJECT_DECODED; |
| 1212 | ptr->filterOperands[i].content.decoded.data = operand; |
| 1213 | ptr->filterOperands[i].content.decoded.type = &UA_TYPES[UA_TYPES_ELEMENTOPERAND]; |
| 1214 | } else if (value.filterOperands().at(i).canConvert<QOpcUaLiteralOperand>()) { |
| 1215 | const auto operand = UA_LiteralOperand_new(); |
| 1216 | scalarFromQt<UA_LiteralOperand, QOpcUaLiteralOperand>(value: value.filterOperands().at(i).value<QOpcUaLiteralOperand>(), ptr: operand); |
| 1217 | ptr->filterOperands[i].encoding = UA_EXTENSIONOBJECT_DECODED; |
| 1218 | ptr->filterOperands[i].content.decoded.data = operand; |
| 1219 | ptr->filterOperands[i].content.decoded.type = &UA_TYPES[UA_TYPES_LITERALOPERAND]; |
| 1220 | } else if (value.filterOperands().at(i).canConvert<QOpcUaAttributeOperand>()) { |
| 1221 | const auto operand = UA_AttributeOperand_new(); |
| 1222 | scalarFromQt<UA_AttributeOperand, QOpcUaAttributeOperand>(value: value.filterOperands().at(i).value<QOpcUaAttributeOperand>(), ptr: operand); |
| 1223 | ptr->filterOperands[i].encoding = UA_EXTENSIONOBJECT_DECODED; |
| 1224 | ptr->filterOperands[i].content.decoded.data = operand; |
| 1225 | ptr->filterOperands[i].content.decoded.type = &UA_TYPES[UA_TYPES_ATTRIBUTEOPERAND]; |
| 1226 | } else if (value.filterOperands().at(i).canConvert<QOpcUaSimpleAttributeOperand>()) { |
| 1227 | const auto operand = UA_SimpleAttributeOperand_new(); |
| 1228 | scalarFromQt<UA_SimpleAttributeOperand, QOpcUaSimpleAttributeOperand>(value: value.filterOperands().at(i).value<QOpcUaSimpleAttributeOperand>(), ptr: operand); |
| 1229 | ptr->filterOperands[i].encoding = UA_EXTENSIONOBJECT_DECODED; |
| 1230 | ptr->filterOperands[i].content.decoded.data = operand; |
| 1231 | ptr->filterOperands[i].content.decoded.type = &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]; |
| 1232 | } else { |
| 1233 | qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Unsupported operand type in content filter element, unable to convert" ; |
| 1234 | UA_ContentFilterElement_clear(p: ptr); |
| 1235 | return; |
| 1236 | } |
| 1237 | } |
| 1238 | } |
| 1239 | } |
| 1240 | |
| 1241 | template<> |
| 1242 | void scalarFromQt<UA_EventFilter, QOpcUaMonitoringParameters::EventFilter>(const QOpcUaMonitoringParameters::EventFilter &value, UA_EventFilter *ptr) |
| 1243 | { |
| 1244 | ptr->selectClausesSize = value.selectClauses().size(); |
| 1245 | if (ptr->selectClausesSize) { |
| 1246 | ptr->selectClauses = static_cast<UA_SimpleAttributeOperand *>( |
| 1247 | UA_Array_new(size: ptr->selectClausesSize, type: &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND])); |
| 1248 | |
| 1249 | for (size_t i = 0; i < ptr->selectClausesSize; ++i) |
| 1250 | scalarFromQt<UA_SimpleAttributeOperand, QOpcUaSimpleAttributeOperand>(value: value.selectClauses().at(i), |
| 1251 | ptr: &ptr->selectClauses[i]); |
| 1252 | } |
| 1253 | |
| 1254 | ptr->whereClause.elementsSize = value.whereClause().size(); |
| 1255 | if (ptr->whereClause.elementsSize) { |
| 1256 | ptr->whereClause.elements = static_cast<UA_ContentFilterElement *>( |
| 1257 | UA_Array_new(size: ptr->whereClause.elementsSize, type: &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT])); |
| 1258 | |
| 1259 | for (size_t i = 0; i < ptr->whereClause.elementsSize; ++i) |
| 1260 | scalarFromQt<UA_ContentFilterElement, QOpcUaContentFilterElement>(value: value.whereClause().at(i), |
| 1261 | ptr: &ptr->whereClause.elements[i]); |
| 1262 | } |
| 1263 | } |
| 1264 | |
| 1265 | template<typename TARGETTYPE, typename QTTYPE> |
| 1266 | UA_Variant arrayFromQVariant(const QVariant &var, const UA_DataType *type) |
| 1267 | { |
| 1268 | UA_Variant open62541value; |
| 1269 | UA_Variant_init(p: &open62541value); |
| 1270 | |
| 1271 | if (type == nullptr) { |
| 1272 | qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Unable to convert QVariant to UA_Variant, unknown type" ; |
| 1273 | return open62541value; |
| 1274 | } |
| 1275 | |
| 1276 | if (var.metaType().id() == QMetaType::QVariantList) { |
| 1277 | const QVariantList list = var.toList(); |
| 1278 | if (list.isEmpty()) |
| 1279 | return open62541value; |
| 1280 | |
| 1281 | for (const auto &it : std::as_const(t: list)) { |
| 1282 | if (!it.canConvert<QTTYPE>()) { |
| 1283 | qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Value type" << var.typeName() << |
| 1284 | "in the QVariant does not match type parameter" << type->typeName; |
| 1285 | return open62541value; |
| 1286 | } |
| 1287 | } |
| 1288 | |
| 1289 | TARGETTYPE *arr = static_cast<TARGETTYPE *>(UA_Array_new(size: list.size(), type)); |
| 1290 | |
| 1291 | for (int i = 0; i < list.size(); ++i) |
| 1292 | scalarFromQt<TARGETTYPE, QTTYPE>(list[i].value<QTTYPE>(), &arr[i]); |
| 1293 | |
| 1294 | UA_Variant_setArray(&open62541value, arr, list.size(), type); |
| 1295 | return open62541value; |
| 1296 | } |
| 1297 | |
| 1298 | if (!var.canConvert<QTTYPE>()) { |
| 1299 | qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Value type" << var.typeName() << |
| 1300 | "in the QVariant does not match type parameter" << type->typeName; |
| 1301 | return open62541value; |
| 1302 | } |
| 1303 | |
| 1304 | TARGETTYPE *temp = static_cast<TARGETTYPE *>(UA_new(type)); |
| 1305 | scalarFromQt<TARGETTYPE, QTTYPE>(var.value<QTTYPE>(), temp); |
| 1306 | UA_Variant_setScalar(&open62541value, temp, type); |
| 1307 | return open62541value; |
| 1308 | } |
| 1309 | |
| 1310 | void createExtensionObject(QByteArray &data, const UA_NodeId &typeEncodingId, UA_ExtensionObject *ptr, QOpcUaExtensionObject::Encoding encoding) |
| 1311 | { |
| 1312 | UA_ExtensionObject obj; |
| 1313 | UA_ExtensionObject_init(p: &obj); |
| 1314 | |
| 1315 | if (!data.isEmpty() && encoding == QOpcUaExtensionObject::Encoding::NoBody) |
| 1316 | qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Data for extension object provided but will not be encoded because encoding format is set to skip the body" ; |
| 1317 | |
| 1318 | if (encoding != QOpcUaExtensionObject::Encoding::NoBody) { |
| 1319 | obj.encoding = static_cast<UA_ExtensionObjectEncoding>(encoding); |
| 1320 | obj.content.encoded.body.data = reinterpret_cast<UA_Byte *>(data.data()); |
| 1321 | obj.content.encoded.body.length = data.size(); |
| 1322 | } |
| 1323 | obj.content.encoded.typeId = typeEncodingId; |
| 1324 | UA_ExtensionObject_copy(src: &obj, dst: ptr); |
| 1325 | } |
| 1326 | |
| 1327 | QVariant uaVariantToQtExtensionObject(const UA_Variant &var) |
| 1328 | { |
| 1329 | if (UA_Variant_isScalar(v: &var)) { |
| 1330 | bool success = false; |
| 1331 | const auto result = encodeAsBinaryExtensionObject(data: var.data, type: var.type, success: &success); |
| 1332 | if (success) |
| 1333 | return result; |
| 1334 | |
| 1335 | qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Failed to re-encode decoded extension object, unable to convert" << var.type->typeName; |
| 1336 | return {}; |
| 1337 | } else if (var.arrayLength == 0 && var.data == UA_EMPTY_ARRAY_SENTINEL) { |
| 1338 | return QVariantList(); // Return empty QVariantList for empty array |
| 1339 | } else if (var.arrayLength > 0) { |
| 1340 | QVariantList values; |
| 1341 | values.reserve(asize: var.arrayLength); |
| 1342 | for (size_t i = 0; i < var.arrayLength; ++i) { |
| 1343 | bool success = false; |
| 1344 | values.push_back(t: encodeAsBinaryExtensionObject(data: static_cast<quint8 *>(var.data) + (i * var.type->memSize), type: var.type, success: &success)); |
| 1345 | |
| 1346 | if (!success) |
| 1347 | return {}; |
| 1348 | } |
| 1349 | |
| 1350 | if (var.arrayDimensionsSize > 0) { |
| 1351 | QOpcUaMultiDimensionalArray arr; |
| 1352 | arr.setValueArray(values); |
| 1353 | QList<quint32> arrayDimensions(var.arrayDimensionsSize); |
| 1354 | for (size_t i = 0; i < var.arrayDimensionsSize; ++i) |
| 1355 | arrayDimensions[i] = var.arrayDimensions[i]; |
| 1356 | arr.setArrayDimensions(arrayDimensions); |
| 1357 | return arr; |
| 1358 | } |
| 1359 | |
| 1360 | return values; |
| 1361 | } |
| 1362 | |
| 1363 | return QVariant(); |
| 1364 | } |
| 1365 | |
| 1366 | QOpcUaExtensionObject encodeAsBinaryExtensionObject(const void *data, const UA_DataType *type, bool *success) |
| 1367 | { |
| 1368 | if (!data || !type) { |
| 1369 | if (success) |
| 1370 | *success = false; |
| 1371 | return {}; |
| 1372 | } |
| 1373 | |
| 1374 | UA_ByteString encodedData; |
| 1375 | UA_ByteString_init(p: &encodedData); |
| 1376 | const auto encodeResult = UA_encodeBinary(p: data, type, outBuf: &encodedData); |
| 1377 | |
| 1378 | if (encodeResult != UA_STATUSCODE_GOOD) { |
| 1379 | if (success) |
| 1380 | *success = false; |
| 1381 | |
| 1382 | return {}; |
| 1383 | } |
| 1384 | |
| 1385 | QOpcUaExtensionObject result; |
| 1386 | result.setBinaryEncodedBody(encodedBody: scalarToQt<QByteArray, UA_ByteString>(data: &encodedData), typeId: scalarToQt<QString, UA_NodeId>(data: &type->typeId)); |
| 1387 | UA_ByteString_clear(p: &encodedData); |
| 1388 | result.setEncodingTypeId(scalarToQt<QString, UA_NodeId>(data: &type->binaryEncodingId)); |
| 1389 | |
| 1390 | if (success) |
| 1391 | *success = true; |
| 1392 | |
| 1393 | return result; |
| 1394 | } |
| 1395 | |
| 1396 | QOpcUa::Types toQtDataType(const UA_DataType *type) |
| 1397 | { |
| 1398 | if (type == &UA_TYPES[UA_TYPES_BOOLEAN]) |
| 1399 | return QOpcUa::Types::Boolean; |
| 1400 | if (type == &UA_TYPES[UA_TYPES_INT32]) |
| 1401 | return QOpcUa::Types::Int32; |
| 1402 | if (type == &UA_TYPES[UA_TYPES_UINT32]) |
| 1403 | return QOpcUa::Types::UInt32; |
| 1404 | if (type == &UA_TYPES[UA_TYPES_DOUBLE]) |
| 1405 | return QOpcUa::Types::Double; |
| 1406 | if (type == &UA_TYPES[UA_TYPES_FLOAT]) |
| 1407 | return QOpcUa::Types::Float; |
| 1408 | if (type == &UA_TYPES[UA_TYPES_STRING]) |
| 1409 | return QOpcUa::Types::String; |
| 1410 | if (type == &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]) |
| 1411 | return QOpcUa::Types::LocalizedText; |
| 1412 | if (type == &UA_TYPES[UA_TYPES_DATETIME]) |
| 1413 | return QOpcUa::Types::DateTime; |
| 1414 | if (type == &UA_TYPES[UA_TYPES_UINT16]) |
| 1415 | return QOpcUa::Types::UInt16; |
| 1416 | if (type == &UA_TYPES[UA_TYPES_INT16]) |
| 1417 | return QOpcUa::Types::Int16; |
| 1418 | if (type == &UA_TYPES[UA_TYPES_UINT64]) |
| 1419 | return QOpcUa::Types::UInt64; |
| 1420 | if (type == &UA_TYPES[UA_TYPES_INT64]) |
| 1421 | return QOpcUa::Types::Int64; |
| 1422 | if (type == &UA_TYPES[UA_TYPES_BYTE]) |
| 1423 | return QOpcUa::Types::Byte; |
| 1424 | if (type == &UA_TYPES[UA_TYPES_SBYTE]) |
| 1425 | return QOpcUa::Types::SByte; |
| 1426 | if (type == &UA_TYPES[UA_TYPES_BYTESTRING]) |
| 1427 | return QOpcUa::Types::ByteString; |
| 1428 | if (type == &UA_TYPES[UA_TYPES_XMLELEMENT]) |
| 1429 | return QOpcUa::Types::XmlElement; |
| 1430 | if (type == &UA_TYPES[UA_TYPES_NODEID]) |
| 1431 | return QOpcUa::Types::NodeId; |
| 1432 | if (type == &UA_TYPES[UA_TYPES_GUID]) |
| 1433 | return QOpcUa::Types::Guid; |
| 1434 | if (type == &UA_TYPES[UA_TYPES_QUALIFIEDNAME]) |
| 1435 | return QOpcUa::Types::QualifiedName; |
| 1436 | if (type == &UA_TYPES[UA_TYPES_STATUSCODE]) |
| 1437 | return QOpcUa::Types::StatusCode; |
| 1438 | if (type == &UA_TYPES[UA_TYPES_RANGE]) |
| 1439 | return QOpcUa::Types::Range; |
| 1440 | if (type == &UA_TYPES[UA_TYPES_EUINFORMATION]) |
| 1441 | return QOpcUa::Types::EUInformation; |
| 1442 | if (type == &UA_TYPES[UA_TYPES_COMPLEXNUMBERTYPE]) |
| 1443 | return QOpcUa::Types::ComplexNumber; |
| 1444 | if (type == &UA_TYPES[UA_TYPES_DOUBLECOMPLEXNUMBERTYPE]) |
| 1445 | return QOpcUa::Types::DoubleComplexNumber; |
| 1446 | if (type == &UA_TYPES[UA_TYPES_AXISINFORMATION]) |
| 1447 | return QOpcUa::Types::AxisInformation; |
| 1448 | if (type == &UA_TYPES[UA_TYPES_XVTYPE]) |
| 1449 | return QOpcUa::Types::XV; |
| 1450 | if (type == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) |
| 1451 | return QOpcUa::Types::ExtensionObject; |
| 1452 | if (type == &UA_TYPES[UA_TYPES_EXPANDEDNODEID]) |
| 1453 | return QOpcUa::Types::ExpandedNodeId; |
| 1454 | if (type == &UA_TYPES[UA_TYPES_ARGUMENT]) |
| 1455 | return QOpcUa::Types::Argument; |
| 1456 | if (type == &UA_TYPES[UA_TYPES_STRUCTUREDEFINITION]) |
| 1457 | return QOpcUa::Types::StructureDefinition; |
| 1458 | if (type == &UA_TYPES[UA_TYPES_STRUCTUREFIELD]) |
| 1459 | return QOpcUa::Types::StructureField; |
| 1460 | if (type == &UA_TYPES[UA_TYPES_ENUMDEFINITION]) |
| 1461 | return QOpcUa::Types::EnumDefinition; |
| 1462 | if (type == &UA_TYPES[UA_TYPES_ENUMFIELD]) |
| 1463 | return QOpcUa::Types::EnumField; |
| 1464 | if (type == &UA_TYPES[UA_TYPES_DIAGNOSTICINFO]) |
| 1465 | return QOpcUa::Types::DiagnosticInfo; |
| 1466 | if (type == &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]) |
| 1467 | return QOpcUa::Types::SimpleAttributeOperand; |
| 1468 | if (type == &UA_TYPES[UA_TYPES_ATTRIBUTEOPERAND]) |
| 1469 | return QOpcUa::Types::AttributeOperand; |
| 1470 | if (type == &UA_TYPES[UA_TYPES_LITERALOPERAND]) |
| 1471 | return QOpcUa::Types::LiteralOperand; |
| 1472 | if (type == &UA_TYPES[UA_TYPES_ELEMENTOPERAND]) |
| 1473 | return QOpcUa::Types::ElementOperand; |
| 1474 | if (type == &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT]) |
| 1475 | return QOpcUa::Types::RelativePathElement; |
| 1476 | if (type == &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT]) |
| 1477 | return QOpcUa::Types::ContentFilterElement; |
| 1478 | if (type == &UA_TYPES[UA_TYPES_EVENTFILTER]) |
| 1479 | return QOpcUa::Types::EventFilter; |
| 1480 | |
| 1481 | qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Trying to convert unhandled type:" << (type ? type->typeName : "Unknown" ); |
| 1482 | return QOpcUa::Types::Undefined; |
| 1483 | } |
| 1484 | } |
| 1485 | |
| 1486 | QT_END_NAMESPACE |
| 1487 | |