1 | // Copyright (C) 2015 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 "qopcuatype.h" |
5 | |
6 | #include <QMetaEnum> |
7 | #include <QRegularExpression> |
8 | #include <QUuid> |
9 | #include <QString> |
10 | #include <QList> |
11 | |
12 | QT_BEGIN_NAMESPACE |
13 | |
14 | /*! |
15 | \namespace QOpcUa |
16 | \inmodule QtOpcua |
17 | |
18 | \brief The QOpcUa namespace contains miscellaneous identifiers used throughout the Qt OPC UA library. |
19 | */ |
20 | |
21 | /*! |
22 | \enum QOpcUa::NodeClass |
23 | |
24 | This enum specifies the class a node belongs to. OPC-UA specifies a fixed |
25 | set of eight different classes. |
26 | |
27 | \value Undefined The node class is not known. This is the case before |
28 | the NodeClass attribute has been read on the server. |
29 | |
30 | \value Object An Object node. |
31 | \value Variable A Variable node. |
32 | \value Method A Method node. |
33 | \value ObjectType An ObjectType node. |
34 | \value VariableType A VariableType node. |
35 | \value ReferenceType A ReferenceType node. |
36 | \value DataType A DataType node. |
37 | \value View A View node. |
38 | */ |
39 | |
40 | /*! |
41 | \enum QOpcUa::ReferenceTypeId |
42 | |
43 | This enum contains the reference types specified in OPC-UA part 3, 7. |
44 | They are used to filter for a certain reference type in \l QOpcUaNode::browseChildren |
45 | and for the reference type information in \l QOpcUaReferenceDescription. |
46 | |
47 | \value Unspecified Not a valid reference type. |
48 | \value References The abstract base type for all references. |
49 | \value NonHierarchicalReferences The abstract base type for all non-hierarchical references. |
50 | \value HierarchicalReferences The abstract base type for all hierarchical references. |
51 | \value HasChild The abstract base type for all non-looping hierarchical references. |
52 | \value Organizes The type for hierarchical references that are used to organize nodes. |
53 | \value HasEventSource The type for non-looping hierarchical references that are used to organize event sources. |
54 | \value HasModellingRule The type for references from instance declarations to modelling rule nodes. |
55 | \value HasEncoding The type for references from data type nodes to to data type encoding nodes. |
56 | \value HasDescription The type for references from data type encoding nodes to data type description nodes. |
57 | \value HasTypeDefinition The type for references from a instance node to its type definition node. |
58 | \value GeneratesEvent The type for references from a node to an event type that is raised by node. |
59 | \value Aggregates The type for non-looping hierarchical references that are used to aggregate nodes into complex types. |
60 | \value HasSubtype The type for non-looping hierarchical references that are used to define sub types. |
61 | \value HasProperty The type for non-looping hierarchical reference from a node to its property. |
62 | \value HasComponent The type for non-looping hierarchical reference from a node to its component. |
63 | \value HasNotifier The type for non-looping hierarchical references that are used to indicate how events propagate from node to node. |
64 | \value HasOrderedComponent The type for non-looping hierarchical reference from a node to its component when the order of references matters. |
65 | \value FromState The type for a reference to the state before a transition. |
66 | \value ToState The type for a reference to the state after a transition. |
67 | \value HasCause The type for a reference to a method that can cause a transition to occur. |
68 | \value HasEffect The type for a reference to an event that may be raised when a transition occurs. |
69 | \value HasHistoricalConfiguration The type for a reference to the historical configuration for a data variable. |
70 | \value HasSubStateMachine The type for a reference to a substate for a state. |
71 | \value HasArgumentDescription The type for a reference to an argument description |
72 | \value HasOptionalInputArgumentDescription The type for a reference to an optional input argument description |
73 | \value AlwaysGeneratesEvent The type for references from a node to an event type that is always raised by node. |
74 | \value HasTrueSubState The type for references from a TRUE super state node to a subordinate state node. |
75 | \value HasFalseSubState The type for references from a FALSE super state node to a subordinate state node. |
76 | \value HasCondition The type for references from a ConditionSource node to a Condition. |
77 | \value HasPubSubConnection The type for a reference to a PubSub connection |
78 | \value DataSetToWriter The type for a reference to a data set writer |
79 | \value HasGuard The type for a reference to a guard |
80 | \value HasDataSetWriter The type for a reference to a data set writer |
81 | \value HasDataSetReader The type for a reference to data set reader |
82 | \value HasAlarmSuppressionGroup The type for a reference to an alarm suppression group |
83 | \value AlarmGroupMember The type for a reference to an alarm group member |
84 | \value HasEffectDisable The type for a reference to an alarm which is disabled by a transition |
85 | \value HasDictionaryEntry The type for a reference to a dictionary entry |
86 | \value HasInterface The type for a reference to an interface |
87 | \value HasAddIn The type for a reference to an addin |
88 | \value HasEffectEnable The type for a reference to an alarm which is enabled by a transition |
89 | \value HasEffectSuppressed The type for a reference to an alarm which is suppressed by a transition |
90 | \value HasEffectUnsuppressed The type for a reference to an alarm which is unsuppressed by a transition |
91 | \value HasWriterGroup The type for a reference to a writer group |
92 | \value HasReaderGroup The type for a reference to a reader group |
93 | \value AliasFor The type for a reference to the node represented by an alias |
94 | */ |
95 | |
96 | /*! |
97 | \enum QOpcUa::NodeAttribute |
98 | |
99 | This enum contains the 22 node attributes defined in OPC-UA part 4, 5. |
100 | |
101 | \value None No node attribute. |
102 | \value NodeId Mandatory for all nodes. Contains the node's id in the OPC UA address space. |
103 | \value NodeClass Mandatory for all nodes. Contains the node id describing the node class of the node. |
104 | \value BrowseName Mandatory for all nodes. Contains a non-localized human readable name of the node. |
105 | \value DisplayName Mandatory for all nodes. Contains a localized human readable name for display purposes. |
106 | \value Description Contains a localized human readable description of the node. |
107 | \value WriteMask Contains a bit mask. Each bit corresponds to a writable attribute (OPC-UA part 3, Table 3). |
108 | \value UserWriteMask Same as WriteMask but for the current user. |
109 | \value IsAbstract True if the node is an abstract type which means that no nodes of this type shall exist. |
110 | \value Symmetric True if a reference's meaning is the same seen from both ends. |
111 | \value InverseName The localized inverse name of a reference (for example "HasSubtype" has the InverseName "SubtypeOf"). |
112 | \value ContainsNoLoops True if there is no way to get back to a node following forward references in the current view. |
113 | \value EventNotifier Contains a bit mask used to indicate if subscribing to events and access to historic events is supported (OPC-UA part 3, Table 5). |
114 | \value Value The value of a Variable node. |
115 | \value DataType The NodeId of the Value attribute's data type (for example "ns=0;i=13" for DateTime, see https://opcfoundation.org/UA/schemas/1.03/NodeIds.csv). |
116 | \value ValueRank Contains information about the structure of the Value attribute (scalar/array) (OPC-UA part 3, Table 8). |
117 | \value ArrayDimensions An array containing the length for each dimension of a multi-dimensional array. |
118 | \value AccessLevel Contains a bit mask. Each bit corresponds to an access capability (OPC-UA part 3, Table 8). |
119 | \value UserAccessLevel Same as AccessLevel, but for the current user. |
120 | \value MinimumSamplingInterval Contains the shortest possible interval in which the server is able to sample the value. |
121 | \value Historizing True if historical data is collected. |
122 | \value Executable True if the node is currently executable. Only relevant for Method nodes. |
123 | \value UserExecutable Same as Executable, but for the current user. |
124 | */ |
125 | |
126 | /*! |
127 | \enum QOpcUa::WriteMaskBit |
128 | |
129 | This enum contains all possible bits for the WriteMask and UserWriteMask node attributes |
130 | defined in OPC-UA part 3, Table 3. |
131 | |
132 | \value None No attribute is writable. |
133 | \value AccessLevel The AccessLevel attribute is writable. |
134 | \value ArrayDimensions The ArrayDimensions attribute is writable. |
135 | \value BrowseName The BrowseName attribute is writable. |
136 | \value ContainsNoLoops The ContainsNoLoops attribute is writable. |
137 | \value DataType The DataType attribute is writable. |
138 | \value Description The Description attribute is writable. |
139 | \value DisplayName The DisplayName attribute is writable. |
140 | \value EventNotifier The EventNotifier attribute is writable. |
141 | \value Executable The Executable attribute is writable. |
142 | \value Historizing The Historizing attribute is writable. |
143 | \value InverseName The InverseName attribute is writable. |
144 | \value IsAbstract The IsAbstract attribute is writable. |
145 | \value MinimumSamplingInterval The MinimumSamplingInterval attribute is writable. |
146 | \value NodeClass The NodeClass attribute is writable. |
147 | \value NodeId The NodeId attribute is writable. |
148 | \value Symmetric The Symmetric attribute is writable. |
149 | \value UserAccessLevel The UserAccessLevel attribute is writable. |
150 | \value UserExecutable The UserExecutable attribute is writable. |
151 | \value UserWriteMask The UserWriteMask attribute is writable. |
152 | \value ValueRank The ValueRank attribute is writable. |
153 | \value WriteMask The WriteMask attribute is writable. |
154 | \value ValueForVariableType The Value attribute of a variable type is writable. |
155 | */ |
156 | |
157 | /*! |
158 | \enum QOpcUa::AccessLevelBit |
159 | |
160 | This enum contains all possible bits for the AccessLevel and UserAccessLevel node attributes |
161 | defined in OPC-UA part 3, Table 8. |
162 | |
163 | \value None No read access to the Value attribute is permitted. |
164 | \value CurrentRead The current value can be read. |
165 | \value CurrentWrite The current value can be written. |
166 | \value HistoryRead The history of the value is readable. |
167 | \value HistoryWrite The history of the value is writable. |
168 | \value SemanticChange The property variable generates SemanticChangeEvents. |
169 | \value StatusWrite The status code of the value is writable. |
170 | \value TimestampWrite The SourceTimestamp is writable. |
171 | */ |
172 | |
173 | /*! |
174 | \enum QOpcUa::EventNotifierBit |
175 | |
176 | This enum contains all possible bits for the EventNotifier node attribute |
177 | defined in OPC-UA part 3, Table 6. |
178 | |
179 | \value None The node can't be used to interact with events. |
180 | \value SubscribeToEvents A client can subscribe to events. |
181 | \value HistoryRead A client can read the event history. |
182 | \value HistoryWrite A client can write the event history. |
183 | */ |
184 | |
185 | /*! |
186 | \fn inline uint QOpcUa::qHash(const QOpcUa::NodeAttribute& attr) |
187 | |
188 | Returns a \l QHash key for \a attr. |
189 | */ |
190 | |
191 | /*! |
192 | \enum QOpcUa::Types |
193 | |
194 | Enumerates the types supported by Qt OPC UA. |
195 | |
196 | \value Boolean |
197 | \value Int32 |
198 | \value UInt32 |
199 | \value Double |
200 | \value Float |
201 | \value String |
202 | \value LocalizedText |
203 | \value DateTime |
204 | \value UInt16 |
205 | \value Int16 |
206 | \value UInt64 |
207 | \value Int64 |
208 | \value Byte |
209 | \value SByte |
210 | \value ByteString |
211 | \value XmlElement |
212 | \value NodeId |
213 | \value Guid |
214 | \value QualifiedName A name qualified by an OPC UA namespace index. |
215 | \value StatusCode |
216 | \value ExtensionObject A data structure which contains a serialized object. |
217 | \value Range A range composed from the two double values low and high. |
218 | \value EUInformation The unit of measurement for an analog value. |
219 | \value ComplexNumber The OPC UA ComplexNumber type. |
220 | \value DoubleComplexNumber The OPC UA DoubleComplexNumber type. |
221 | \value AxisInformation Information about an axis. |
222 | \value XV A float value with a double precision position on an axis. |
223 | \value ExpandedNodeId A node id with additional namespace URI and server index. |
224 | \value Argument The OPC UA Argument type. |
225 | \value Undefined |
226 | */ |
227 | |
228 | /*! |
229 | \enum QOpcUa::UaStatusCode |
230 | |
231 | Enumerates all status codes from \l {https://opcfoundation.org/UA/schemas/1.03/Opc.Ua.StatusCodes.csv} |
232 | |
233 | \value Good |
234 | \value BadUnexpectedError |
235 | \value BadInternalError |
236 | \value BadOutOfMemory |
237 | \value BadResourceUnavailable |
238 | \value BadCommunicationError |
239 | \value BadEncodingError |
240 | \value BadDecodingError |
241 | \value BadEncodingLimitsExceeded |
242 | \value BadRequestTooLarge |
243 | \value BadResponseTooLarge |
244 | \value BadUnknownResponse |
245 | \value BadTimeout |
246 | \value BadServiceUnsupported |
247 | \value BadShutdown |
248 | \value BadServerNotConnected |
249 | \value BadServerHalted |
250 | \value BadNothingToDo |
251 | \value BadTooManyOperations |
252 | \value BadTooManyMonitoredItems |
253 | \value BadDataTypeIdUnknown |
254 | \value BadCertificateInvalid |
255 | \value BadSecurityChecksFailed |
256 | \value BadCertificateTimeInvalid |
257 | \value BadCertificateIssuerTimeInvalid |
258 | \value BadCertificateHostNameInvalid |
259 | \value BadCertificateUriInvalid |
260 | \value BadCertificateUseNotAllowed |
261 | \value BadCertificateIssuerUseNotAllowed |
262 | \value BadCertificateUntrusted |
263 | \value BadCertificateRevocationUnknown |
264 | \value BadCertificateIssuerRevocationUnknown |
265 | \value BadCertificateRevoked |
266 | \value BadCertificateIssuerRevoked |
267 | \value BadCertificateChainIncomplete |
268 | \value BadUserAccessDenied |
269 | \value BadIdentityTokenInvalid |
270 | \value BadIdentityTokenRejected |
271 | \value BadSecureChannelIdInvalid |
272 | \value BadInvalidTimestamp |
273 | \value BadNonceInvalid |
274 | \value BadSessionIdInvalid |
275 | \value BadSessionClosed |
276 | \value BadSessionNotActivated |
277 | \value BadSubscriptionIdInvalid |
278 | \value BadRequestHeaderInvalid |
279 | \value BadTimestampsToReturnInvalid |
280 | \value BadRequestCancelledByClient |
281 | \value BadTooManyArguments |
282 | \value GoodSubscriptionTransferred |
283 | \value GoodCompletesAsynchronously |
284 | \value GoodOverload |
285 | \value GoodClamped |
286 | \value BadNoCommunication |
287 | \value BadWaitingForInitialData |
288 | \value BadNodeIdInvalid |
289 | \value BadNodeIdUnknown |
290 | \value BadAttributeIdInvalid |
291 | \value BadIndexRangeInvalid |
292 | \value BadIndexRangeNoData |
293 | \value BadDataEncodingInvalid |
294 | \value BadDataEncodingUnsupported |
295 | \value BadNotReadable |
296 | \value BadNotWritable |
297 | \value BadOutOfRange |
298 | \value BadNotSupported |
299 | \value BadNotFound |
300 | \value BadObjectDeleted |
301 | \value BadNotImplemented |
302 | \value BadMonitoringModeInvalid |
303 | \value BadMonitoredItemIdInvalid |
304 | \value BadMonitoredItemFilterInvalid |
305 | \value BadMonitoredItemFilterUnsupported |
306 | \value BadFilterNotAllowed |
307 | \value BadStructureMissing |
308 | \value BadEventFilterInvalid |
309 | \value BadContentFilterInvalid |
310 | \value BadFilterOperatorInvalid |
311 | \value BadFilterOperatorUnsupported |
312 | \value BadFilterOperandCountMismatch |
313 | \value BadFilterOperandInvalid |
314 | \value BadFilterElementInvalid |
315 | \value BadFilterLiteralInvalid |
316 | \value BadContinuationPointInvalid |
317 | \value BadNoContinuationPoints |
318 | \value BadReferenceTypeIdInvalid |
319 | \value BadBrowseDirectionInvalid |
320 | \value BadNodeNotInView |
321 | \value BadServerUriInvalid |
322 | \value BadServerNameMissing |
323 | \value BadDiscoveryUrlMissing |
324 | \value BadSempahoreFileMissing |
325 | \value BadRequestTypeInvalid |
326 | \value BadSecurityModeRejected |
327 | \value BadSecurityPolicyRejected |
328 | \value BadTooManySessions |
329 | \value BadUserSignatureInvalid |
330 | \value BadApplicationSignatureInvalid |
331 | \value BadNoValidCertificates |
332 | \value BadIdentityChangeNotSupported |
333 | \value BadRequestCancelledByRequest |
334 | \value BadParentNodeIdInvalid |
335 | \value BadReferenceNotAllowed |
336 | \value BadNodeIdRejected |
337 | \value BadNodeIdExists |
338 | \value BadNodeClassInvalid |
339 | \value BadBrowseNameInvalid |
340 | \value BadBrowseNameDuplicated |
341 | \value BadNodeAttributesInvalid |
342 | \value BadTypeDefinitionInvalid |
343 | \value BadSourceNodeIdInvalid |
344 | \value BadTargetNodeIdInvalid |
345 | \value BadDuplicateReferenceNotAllowed |
346 | \value BadInvalidSelfReference |
347 | \value BadReferenceLocalOnly |
348 | \value BadNoDeleteRights |
349 | \value UncertainReferenceNotDeleted |
350 | \value BadServerIndexInvalid |
351 | \value BadViewIdUnknown |
352 | \value BadViewTimestampInvalid |
353 | \value BadViewParameterMismatch |
354 | \value BadViewVersionInvalid |
355 | \value UncertainNotAllNodesAvailable |
356 | \value GoodResultsMayBeIncomplete |
357 | \value BadNotTypeDefinition |
358 | \value UncertainReferenceOutOfServer |
359 | \value BadTooManyMatches |
360 | \value BadQueryTooComplex |
361 | \value BadNoMatch |
362 | \value BadMaxAgeInvalid |
363 | \value BadSecurityModeInsufficient |
364 | \value BadHistoryOperationInvalid |
365 | \value BadHistoryOperationUnsupported |
366 | \value BadInvalidTimestampArgument |
367 | \value BadWriteNotSupported |
368 | \value BadTypeMismatch |
369 | \value BadMethodInvalid |
370 | \value BadArgumentsMissing |
371 | \value BadTooManySubscriptions |
372 | \value BadTooManyPublishRequests |
373 | \value BadNoSubscription |
374 | \value BadSequenceNumberUnknown |
375 | \value BadMessageNotAvailable |
376 | \value BadInsufficientClientProfile |
377 | \value BadStateNotActive |
378 | \value BadTcpServerTooBusy |
379 | \value BadTcpMessageTypeInvalid |
380 | \value BadTcpSecureChannelUnknown |
381 | \value BadTcpMessageTooLarge |
382 | \value BadTcpNotEnoughResources |
383 | \value BadTcpInternalError |
384 | \value BadTcpEndpointUrlInvalid |
385 | \value BadRequestInterrupted |
386 | \value BadRequestTimeout |
387 | \value BadSecureChannelClosed |
388 | \value BadSecureChannelTokenUnknown |
389 | \value BadSequenceNumberInvalid |
390 | \value BadProtocolVersionUnsupported |
391 | \value BadConfigurationError |
392 | \value BadNotConnected |
393 | \value BadDeviceFailure |
394 | \value BadSensorFailure |
395 | \value BadOutOfService |
396 | \value BadDeadbandFilterInvalid |
397 | \value UncertainNoCommunicationLastUsableValue |
398 | \value UncertainLastUsableValue |
399 | \value UncertainSubstituteValue |
400 | \value UncertainInitialValue |
401 | \value UncertainSensorNotAccurate |
402 | \value UncertainEngineeringUnitsExceeded |
403 | \value UncertainSubNormal |
404 | \value GoodLocalOverride |
405 | \value BadRefreshInProgress |
406 | \value BadConditionAlreadyDisabled |
407 | \value BadConditionAlreadyEnabled |
408 | \value BadConditionDisabled |
409 | \value BadEventIdUnknown |
410 | \value BadEventNotAcknowledgeable |
411 | \value BadDialogNotActive |
412 | \value BadDialogResponseInvalid |
413 | \value BadConditionBranchAlreadyAcked |
414 | \value BadConditionBranchAlreadyConfirmed |
415 | \value BadConditionAlreadyShelved |
416 | \value BadConditionNotShelved |
417 | \value BadShelvingTimeOutOfRange |
418 | \value BadNoData |
419 | \value BadBoundNotFound |
420 | \value BadBoundNotSupported |
421 | \value BadDataLost |
422 | \value BadDataUnavailable |
423 | \value BadEntryExists |
424 | \value BadNoEntryExists |
425 | \value BadTimestampNotSupported |
426 | \value GoodEntryInserted |
427 | \value GoodEntryReplaced |
428 | \value UncertainDataSubNormal |
429 | \value GoodNoData |
430 | \value GoodMoreData |
431 | \value BadAggregateListMismatch |
432 | \value BadAggregateNotSupported |
433 | \value BadAggregateInvalidInputs |
434 | \value BadAggregateConfigurationRejected |
435 | \value GoodDataIgnored |
436 | \value BadRequestNotAllowed |
437 | \value GoodEdited |
438 | \value GoodPostActionFailed |
439 | \value UncertainDominantValueChanged |
440 | \value GoodDependentValueChanged |
441 | \value BadDominantValueChanged |
442 | \value UncertainDependentValueChanged |
443 | \value BadDependentValueChanged |
444 | \value GoodCommunicationEvent |
445 | \value GoodShutdownEvent |
446 | \value GoodCallAgain |
447 | \value GoodNonCriticalTimeout |
448 | \value BadInvalidArgument |
449 | \value BadConnectionRejected |
450 | \value BadDisconnect |
451 | \value BadConnectionClosed |
452 | \value BadInvalidState |
453 | \value BadEndOfStream |
454 | \value BadNoDataAvailable |
455 | \value BadWaitingForResponse |
456 | \value BadOperationAbandoned |
457 | \value BadExpectedStreamToBlock |
458 | \value BadWouldBlock |
459 | \value BadSyntaxError |
460 | \value BadMaxConnectionsReached |
461 | */ |
462 | |
463 | /*! |
464 | \enum QOpcUa::ErrorCategory |
465 | |
466 | This enum contains simplified categories for OPC UA errors. |
467 | |
468 | \value NoError The operation has been successful. |
469 | \value NodeError There is a problem with the node, e. g. it does not exist. |
470 | \value AttributeError The attributes to operate on where invalid. |
471 | \value PermissionError The user did not have the permission to perform the operation. |
472 | \value ArgumentError The arguments supplied by the user were invalid or incomplete. |
473 | \value TypeError There has been a type mismatch for a write operation. |
474 | \value ConnectionError Communication with the server did not work as expected. |
475 | \value UnspecifiedError Any error that is not categorized. The detailed status code must be checked. |
476 | */ |
477 | |
478 | /*! |
479 | This method can be used to check if a call has successfully finished. |
480 | |
481 | Returns \c true if \a statusCode's severity field is Good. |
482 | */ |
483 | bool QOpcUa::isSuccessStatus(QOpcUa::UaStatusCode statusCode) |
484 | { |
485 | return (statusCode & 0xC0000000) == 0; |
486 | } |
487 | |
488 | /*! |
489 | \typedef QOpcUa::TypedVariant |
490 | |
491 | This is QPair<QVariant, QOpcUa::Types>. |
492 | */ |
493 | |
494 | static bool isNodeError(QOpcUa::UaStatusCode statusCode) |
495 | { |
496 | switch (statusCode) { |
497 | case QOpcUa::UaStatusCode::BadMethodInvalid: |
498 | case QOpcUa::UaStatusCode::BadNodeIdInvalid: |
499 | case QOpcUa::UaStatusCode::BadNodeIdExists: |
500 | case QOpcUa::UaStatusCode::BadNodeIdRejected: |
501 | case QOpcUa::UaStatusCode::BadNodeIdUnknown: |
502 | case QOpcUa::UaStatusCode::BadObjectDeleted: |
503 | return true; |
504 | default: |
505 | return false; |
506 | } |
507 | } |
508 | |
509 | static bool isAttributeError(QOpcUa::UaStatusCode statusCode) |
510 | { |
511 | switch (statusCode) { |
512 | case QOpcUa::UaStatusCode::BadAttributeIdInvalid: |
513 | case QOpcUa::UaStatusCode::BadNodeAttributesInvalid: |
514 | return true; |
515 | default: |
516 | return false; |
517 | } |
518 | } |
519 | |
520 | static bool isPermissionError(QOpcUa::UaStatusCode statusCode) |
521 | { |
522 | switch (statusCode) { |
523 | case QOpcUa::UaStatusCode::BadUserAccessDenied: |
524 | case QOpcUa::UaStatusCode::BadNotWritable: |
525 | case QOpcUa::UaStatusCode::BadNoDeleteRights: |
526 | case QOpcUa::UaStatusCode::BadNotReadable: |
527 | return true; |
528 | default: |
529 | return false; |
530 | } |
531 | } |
532 | |
533 | static bool isArgumentError(QOpcUa::UaStatusCode statusCode) |
534 | { |
535 | switch (statusCode) { |
536 | case QOpcUa::UaStatusCode::BadArgumentsMissing: |
537 | case QOpcUa::UaStatusCode::BadInvalidArgument: |
538 | case QOpcUa::UaStatusCode::BadTooManyArguments: |
539 | case QOpcUa::UaStatusCode::BadInvalidTimestampArgument: |
540 | return true; |
541 | default: |
542 | return false; |
543 | } |
544 | } |
545 | |
546 | static bool isTypeError(QOpcUa::UaStatusCode statusCode) |
547 | { |
548 | switch (statusCode) { |
549 | case QOpcUa::UaStatusCode::BadTypeMismatch: |
550 | case QOpcUa::UaStatusCode::BadInvalidTimestampArgument: |
551 | return true; |
552 | default: |
553 | return false; |
554 | } |
555 | } |
556 | |
557 | static bool isConnectionError(QOpcUa::UaStatusCode statusCode) |
558 | { |
559 | switch (statusCode) { |
560 | case QOpcUa::UaStatusCode::BadConnectionClosed: |
561 | case QOpcUa::UaStatusCode::BadNoCommunication: |
562 | return true; |
563 | default: |
564 | return false; |
565 | } |
566 | } |
567 | |
568 | /*! |
569 | Converts \a statusCode to an \l ErrorCategory. \l ErrorCategory can be used in cases where the |
570 | exact error is not important. |
571 | |
572 | For error handling dependent on status codes, the full status code must be used instead. |
573 | The meaning of the status codes for the different services is documented in OPC-UA part 4. |
574 | |
575 | If \a statusCode has not been categorized, UnspecifiedError is returned. In this case, the user |
576 | must check the full status code. |
577 | */ |
578 | QOpcUa::ErrorCategory QOpcUa::errorCategory(QOpcUa::UaStatusCode statusCode) |
579 | { |
580 | if (isSuccessStatus(statusCode)) |
581 | return QOpcUa::ErrorCategory::NoError; |
582 | if (isNodeError(statusCode)) |
583 | return QOpcUa::ErrorCategory::NodeError; |
584 | if (isAttributeError(statusCode)) |
585 | return QOpcUa::ErrorCategory::AttributeError; |
586 | if (isPermissionError(statusCode)) |
587 | return QOpcUa::ErrorCategory::PermissionError; |
588 | if (isArgumentError(statusCode)) |
589 | return QOpcUa::ErrorCategory::ArgumentError; |
590 | if (isTypeError(statusCode)) |
591 | return QOpcUa::ErrorCategory::TypeError; |
592 | if (isConnectionError(statusCode)) |
593 | return QOpcUa::ErrorCategory::ConnectionError; |
594 | |
595 | return QOpcUa::ErrorCategory::UnspecifiedError; |
596 | } |
597 | |
598 | /*! |
599 | Creates a node id string from the namespace index \a ns and the string \a identifier. |
600 | \sa QOpcUaNode |
601 | */ |
602 | QString QOpcUa::nodeIdFromString(quint16 ns, const QString &identifier) |
603 | { |
604 | return QStringLiteral("ns=%1;s=%2" ).arg(a: ns).arg(a: identifier); |
605 | } |
606 | |
607 | /*! |
608 | Creates a node id string from the namespace index \a ns and the byte string \a identifier. |
609 | \sa QOpcUaNode |
610 | */ |
611 | QString QOpcUa::nodeIdFromByteString(quint16 ns, const QByteArray &identifier) |
612 | { |
613 | return QStringLiteral("ns=%1;b=%2" ).arg(a: ns).arg(a: QString::fromUtf8(ba: identifier.toBase64())); |
614 | } |
615 | |
616 | /*! |
617 | Creates a node id string from the namespace index \a ns and the GUID \a identifier. |
618 | \sa QOpcUaNode |
619 | */ |
620 | QString QOpcUa::nodeIdFromGuid(quint16 ns, const QUuid &identifier) |
621 | { |
622 | return QStringLiteral("ns=%1;g=" ).arg(a: ns).append(v: QStringView(identifier.toString()).mid(pos: 1, n: 36)); // Remove enclosing {...}; |
623 | } |
624 | |
625 | /*! |
626 | Creates a node id string from the namespace index \a ns and the integer \a identifier. |
627 | \sa QOpcUaNode |
628 | */ |
629 | QString QOpcUa::nodeIdFromInteger(quint16 ns, quint32 identifier) |
630 | { |
631 | return QStringLiteral("ns=%1;i=%2" ).arg(a: ns).arg(a: identifier); |
632 | } |
633 | |
634 | /*! |
635 | Creates a node id string for the reference type id \a referenceType. |
636 | */ |
637 | QString QOpcUa::nodeIdFromReferenceType(QOpcUa::ReferenceTypeId referenceType) |
638 | { |
639 | return QStringLiteral("ns=0;i=%1" ).arg(a: static_cast<quint32>(referenceType)); |
640 | } |
641 | |
642 | /*! |
643 | Splits the node id string \a nodeIdString in its components. |
644 | The namespace index of the node id will be copied into \a nsIndex. |
645 | The identifier string is copied into \a identifier and the identifier type |
646 | (i, s, g, b) is copied into \a identifierType. |
647 | |
648 | Returns \c true if the node id could be split successfully. |
649 | |
650 | For example, "ns=1;s=MyString" is split into 1, 's' and "MyString". |
651 | If no namespace index is given, ns=0 is assumed. |
652 | */ |
653 | bool QOpcUa::nodeIdStringSplit(const QString &nodeIdString, quint16 *nsIndex, QString *identifier, char *identifierType) |
654 | { |
655 | quint16 namespaceIndex = 0; |
656 | |
657 | QStringList components = nodeIdString.split(sep: QLatin1String(";" )); |
658 | |
659 | if (components.size() > 2) |
660 | return false; |
661 | |
662 | if (components.size() == 2 && components.at(i: 0).contains(re: QRegularExpression(QLatin1String("^ns=[0-9]+" )))) { |
663 | bool success = false; |
664 | uint ns = QStringView(components.at(i: 0)).mid(pos: 3).toUInt(ok: &success); |
665 | if (!success || ns > (std::numeric_limits<quint16>::max)()) |
666 | return false; |
667 | namespaceIndex = ns; |
668 | } |
669 | |
670 | if (components.last().size() < 3) |
671 | return false; |
672 | |
673 | if (!components.last().contains(re: QRegularExpression(QLatin1String("^[isgb]=" )))) |
674 | return false; |
675 | |
676 | if (nsIndex) |
677 | *nsIndex = namespaceIndex; |
678 | if (identifier) |
679 | *identifier = QStringView(components.last()).mid(pos: 2).toString(); |
680 | if (identifierType) |
681 | *identifierType = components.last().at(i: 0).toLatin1(); |
682 | |
683 | return true; |
684 | } |
685 | |
686 | /*! |
687 | Returns \c true if the two node ids \a first and \a second have the same namespace index and identifier. |
688 | A node id string without a namespace index is assumed to be in namespace 0. |
689 | */ |
690 | bool QOpcUa::nodeIdEquals(const QString &first, const QString &second) |
691 | { |
692 | const QStringView fView(first); |
693 | const QStringView sView(second); |
694 | if (first.startsWith(s: QLatin1String("ns=0;" )) && !second.startsWith(s: QLatin1String("ns=" ))) |
695 | return fView.mid(pos: 5) == sView; |
696 | else if (second.startsWith(s: QLatin1String("ns=0;" )) && !first.startsWith(s: QLatin1String("ns=" ))) |
697 | return sView.mid(pos: 5) == fView; |
698 | else |
699 | return first == second; |
700 | } |
701 | |
702 | /*! |
703 | Returns a node id string for the namespace 0 identifier \a id. |
704 | */ |
705 | QString QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0 id) |
706 | { |
707 | return QStringLiteral("ns=0;i=%1" ).arg(a: quint32(id)); |
708 | } |
709 | |
710 | /*! |
711 | Returns the enum value from \l QOpcUa::NodeIds::Namespace0 for \a nodeId. |
712 | |
713 | If the node id is not in namespace 0 or doesn't have a numeric |
714 | identifier which is part of the OPC Foundation's NodeIds.csv file, |
715 | \l {QOpcUa::NodeIds::Namespace0} {Unknown} is returned. |
716 | |
717 | If Qt OPC UA has been configured with -no-feature-ns0idnames, |
718 | the check if the numeric identifier is part of the NodeIds.csv |
719 | file is omitted. If the node id is in namespace 0 and has a |
720 | numeric identifier, the identifier is returned regardless if it |
721 | is part of the \l QOpcUa::NodeIds::Namespace0 enum. |
722 | */ |
723 | QOpcUa::NodeIds::Namespace0 QOpcUa::namespace0IdFromNodeId(const QString &nodeId) |
724 | { |
725 | if (!nodeId.startsWith(s: QLatin1String("ns=0;i=" ))) |
726 | return QOpcUa::NodeIds::Namespace0::Unknown; |
727 | |
728 | const QStringView sv = QStringView{nodeId}.mid(pos: 7); |
729 | |
730 | bool ok = false; |
731 | quint32 identifier = sv.toUInt(ok: &ok); |
732 | |
733 | if (!ok) |
734 | return QOpcUa::NodeIds::Namespace0::Unknown; |
735 | |
736 | #ifndef QT_OPCUA_NO_NS0IDNAMES |
737 | if (!QMetaEnum::fromType<QOpcUa::NodeIds::Namespace0>().valueToKey(value: identifier)) |
738 | return QOpcUa::NodeIds::Namespace0::Unknown; |
739 | #endif |
740 | |
741 | return QOpcUa::NodeIds::Namespace0(identifier); |
742 | } |
743 | |
744 | /*! |
745 | Returns the name of the namespace 0 node id \a id. |
746 | |
747 | If \a id is unknown or Qt OPC UA has been configured with -no-feature-ns0idnames, |
748 | an empty string is returned. |
749 | */ |
750 | QString QOpcUa::namespace0IdName(QOpcUa::NodeIds::Namespace0 id) |
751 | { |
752 | #ifdef QT_OPCUA_NO_NS0IDNAMES |
753 | Q_UNUSED(id); |
754 | return QString(); |
755 | #else |
756 | if (id == QOpcUa::NodeIds::Namespace0::Unknown) |
757 | return QString(); |
758 | return QString::fromUtf8(utf8: QMetaEnum::fromType<QOpcUa::NodeIds::Namespace0>().valueToKey(value: quint32(id))); |
759 | #endif |
760 | } |
761 | |
762 | /*! |
763 | \enum QOpcUa::AxisScale |
764 | |
765 | The AxisScale enum as defined by OPC-UA part 8, 5.6.7. |
766 | |
767 | \value Linear |
768 | \value Log |
769 | \value Ln |
770 | */ |
771 | |
772 | /*! |
773 | Returns a textual representation of \a statusCode. |
774 | |
775 | Currently, this is the name of the enum value but may be a real message in future releases. |
776 | */ |
777 | QString QOpcUa::statusToString(QOpcUa::UaStatusCode statusCode) |
778 | { |
779 | const auto enumerator = QMetaEnum::fromType<QOpcUa::UaStatusCode>(); |
780 | const auto key = enumerator.valueToKey(value: statusCode); |
781 | if (key) |
782 | return QString::fromLatin1(ba: key); |
783 | else |
784 | return QLatin1String("Invalid enum value for UaStatusCode" ); |
785 | } |
786 | |
787 | /*! |
788 | \since 5.13 |
789 | |
790 | Returns the Qt OPC UA type from \a type. |
791 | In case the type does not map, \c QOpcUa::Undefined is returned. |
792 | */ |
793 | QOpcUa::Types QOpcUa::metaTypeToQOpcUaType(QMetaType::Type type) { |
794 | switch (type) { |
795 | case QMetaType::Bool: |
796 | return QOpcUa::Boolean; |
797 | case QMetaType::UChar: |
798 | return QOpcUa::Byte; |
799 | case QMetaType::Char: |
800 | return QOpcUa::SByte; |
801 | case QMetaType::UShort: |
802 | return QOpcUa::UInt16; |
803 | case QMetaType::Short: |
804 | return QOpcUa::Int16; |
805 | case QMetaType::Int: |
806 | return QOpcUa::Int32; |
807 | case QMetaType::UInt: |
808 | return QOpcUa::UInt32; |
809 | case QMetaType::ULongLong: |
810 | return QOpcUa::UInt64; |
811 | case QMetaType::LongLong: |
812 | return QOpcUa::Int64; |
813 | case QMetaType::Double: |
814 | return QOpcUa::Double; |
815 | case QMetaType::Float: |
816 | return QOpcUa::Float; |
817 | case QMetaType::QString: |
818 | return QOpcUa::String; |
819 | case QMetaType::QDateTime: |
820 | return QOpcUa::DateTime; |
821 | case QMetaType::QByteArray: |
822 | return QOpcUa::ByteString; |
823 | case QMetaType::QUuid: |
824 | return QOpcUa::Guid; |
825 | default: |
826 | break; |
827 | } |
828 | return QOpcUa::Undefined; |
829 | } |
830 | |
831 | QOpcUa::Types QOpcUa::opcUaDataTypeToQOpcUaType(const QString &type) |
832 | { |
833 | if (type == QStringLiteral("ns=0;i=1" )) |
834 | return QOpcUa::Boolean; |
835 | else if (type == QStringLiteral("ns=0;i=3" )) |
836 | return QOpcUa::Byte; |
837 | else if (type == QStringLiteral("ns=0;i=2" )) |
838 | return QOpcUa::SByte; |
839 | else if (type == QStringLiteral("ns=0;i=5" )) |
840 | return QOpcUa::UInt16; |
841 | else if (type == QStringLiteral("ns=0;i=4" )) |
842 | return QOpcUa::Int16; |
843 | else if (type == QStringLiteral("ns=0;i=6" )) |
844 | return QOpcUa::Int32; |
845 | else if (type == QStringLiteral("ns=0;i=7" )) |
846 | return QOpcUa::UInt32; |
847 | else if (type == QStringLiteral("ns=0;i=9" )) |
848 | return QOpcUa::UInt64; |
849 | else if (type == QStringLiteral("ns=0;i=8" )) |
850 | return QOpcUa::Int64; |
851 | else if (type == QStringLiteral("ns=0;i=11" )) |
852 | return QOpcUa::Double; |
853 | else if (type == QStringLiteral("ns=0;i=10" )) |
854 | return QOpcUa::Float; |
855 | else if (type == QStringLiteral("ns=0;i=12" )) |
856 | return QOpcUa::String; |
857 | else if (type == QStringLiteral("ns=0;i=13" )) |
858 | return QOpcUa::DateTime; |
859 | else if (type == QStringLiteral("ns=0;i=15" )) |
860 | return QOpcUa::ByteString; |
861 | else if (type == QStringLiteral("ns=0;i=14" )) |
862 | return QOpcUa::Guid; |
863 | else |
864 | return QOpcUa::Undefined; |
865 | } |
866 | |
867 | /*! |
868 | \since QtOpcUa 5.14 |
869 | |
870 | Returns \c true if \a securityPolicy is a secure policy, \c false |
871 | otherwise. |
872 | */ |
873 | bool QOpcUa::isSecurePolicy(const QString &securityPolicy) |
874 | { |
875 | return securityPolicy == QLatin1String("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15" ) || |
876 | securityPolicy == QLatin1String("http://opcfoundation.org/UA/SecurityPolicy#Basic256" ) || |
877 | securityPolicy == QLatin1String("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256" ) || |
878 | securityPolicy == QLatin1String("http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep" ) || |
879 | securityPolicy == QLatin1String("http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss" ); |
880 | } |
881 | |
882 | QT_END_NAMESPACE |
883 | |
884 | |