1 | // Copyright (C) 2016 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 | #ifndef QOPCUANODE_P_H |
5 | #define QOPCUANODE_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include <QtOpcUa/qopcuaclient.h> |
19 | #include <QtOpcUa/qopcuanode.h> |
20 | #include <QtOpcUa/qopcuaeventfilterresult.h> |
21 | #include <private/qopcuanodeimpl_p.h> |
22 | |
23 | #include <private/qobject_p.h> |
24 | #include <QtCore/qpointer.h> |
25 | #include <QtCore/qscopedpointer.h> |
26 | #include <QtCore/qhash.h> |
27 | |
28 | #include <array> |
29 | |
30 | QT_BEGIN_NAMESPACE |
31 | |
32 | class QOpcUaNodePrivate : public QObjectPrivate |
33 | { |
34 | Q_DECLARE_PUBLIC(QOpcUaNode) |
35 | |
36 | public: |
37 | QOpcUaNodePrivate(QOpcUaNodeImpl *impl, QOpcUaClient *client) |
38 | : m_impl(impl) |
39 | , m_client(client) |
40 | { |
41 | } |
42 | |
43 | void createConnections() |
44 | { |
45 | Q_Q(QOpcUaNode); |
46 | |
47 | size_t index = 0; |
48 | m_connections[index++] = QObject::connect(sender: m_impl.get(), signal: &QOpcUaNodeImpl::attributesRead, |
49 | context: q, slot: [this](QList<QOpcUaReadResult> attr, QOpcUa::UaStatusCode serviceResult) |
50 | { |
51 | handleAttributesRead(attr, serviceResult); |
52 | }); |
53 | |
54 | m_connections[index++] = QObject::connect(sender: m_impl.get(), signal: &QOpcUaNodeImpl::attributeWritten, |
55 | context: q, slot: [this](QOpcUa::NodeAttribute attr, QVariant value, QOpcUa::UaStatusCode statusCode) |
56 | { |
57 | handleAttributesWritten(attr, value, statusCode); |
58 | }); |
59 | |
60 | m_connections[index++] = QObject::connect(sender: m_impl.get(), signal: &QOpcUaNodeImpl::dataChangeOccurred, |
61 | context: q, slot: [this](QOpcUa::NodeAttribute attr, QOpcUaReadResult value) |
62 | { |
63 | this->m_nodeAttributes[attr] = value; |
64 | Q_Q(QOpcUaNode); |
65 | emit q->dataChangeOccurred(attr, value: value.value()); |
66 | emit q->attributeUpdated(attr, value: value.value()); |
67 | |
68 | if (attr == QOpcUa::NodeAttribute::Value) |
69 | emit q->valueAttributeUpdated(value: value.value()); |
70 | }); |
71 | |
72 | m_connections[index++] = QObject::connect(sender: m_impl.get(), signal: &QOpcUaNodeImpl::monitoringEnableDisable, |
73 | context: q, slot: [this](QOpcUa::NodeAttribute attr, bool subscribe, QOpcUaMonitoringParameters status) |
74 | { |
75 | handleMonitoringEnableDisable(attr, subscribe, status); |
76 | }); |
77 | |
78 | m_connections[index++] = QObject::connect(sender: m_impl.get(), signal: &QOpcUaNodeImpl::monitoringStatusChanged, |
79 | context: q, slot: [this](QOpcUa::NodeAttribute attr, QOpcUaMonitoringParameters::Parameters items, QOpcUaMonitoringParameters param) |
80 | { |
81 | handleMonitoringStatusChange(attr, items, param); |
82 | }); |
83 | |
84 | m_connections[index++] = |
85 | QObject::connect(sender: m_impl.get(), signal: &QOpcUaNodeImpl::methodCallFinished, context: q, |
86 | slot: &QOpcUaNode::methodCallFinished); |
87 | |
88 | m_connections[index++] = QObject::connect(sender: m_impl.get(), signal: &QOpcUaNodeImpl::browseFinished, |
89 | context: q, slot: &QOpcUaNode::browseFinished); |
90 | |
91 | m_connections[index++] = |
92 | QObject::connect(sender: m_impl.get(), signal: &QOpcUaNodeImpl::resolveBrowsePathFinished, context: q, |
93 | slot: &QOpcUaNode::resolveBrowsePathFinished); |
94 | |
95 | m_connections[index++] = QObject::connect(sender: m_impl.get(), signal: &QOpcUaNodeImpl::eventOccurred, |
96 | context: q, slot: &QOpcUaNode::eventOccurred); |
97 | |
98 | Q_ASSERT(index == m_connections.size()); |
99 | } |
100 | |
101 | ~QOpcUaNodePrivate() |
102 | { |
103 | for (auto &c : m_connections) |
104 | QObject::disconnect(c); |
105 | |
106 | // Disable remaining monitorings |
107 | QOpcUa::NodeAttributes attr; |
108 | for (auto it = m_monitoringStatus.constBegin(); it != m_monitoringStatus.constEnd(); ++it) { |
109 | if (it->statusCode() == QOpcUa::UaStatusCode::Good) |
110 | attr |= it.key(); |
111 | } |
112 | if (attr != 0 && m_impl) { |
113 | m_impl->disableMonitoring(attr); |
114 | } |
115 | } |
116 | |
117 | void handleAttributesRead(const QList<QOpcUaReadResult> &attr, |
118 | QOpcUa::UaStatusCode serviceResult) |
119 | { |
120 | QOpcUa::NodeAttributes updatedAttributes; |
121 | Q_Q(QOpcUaNode); |
122 | |
123 | for (auto &entry : std::as_const(t: attr)) { |
124 | if (serviceResult == QOpcUa::UaStatusCode::Good) |
125 | m_nodeAttributes.insert(key: entry.attribute(), value: entry); |
126 | else { |
127 | QOpcUaReadResult temp = entry; |
128 | temp.setStatusCode(serviceResult); |
129 | temp.setValue(QVariant()); |
130 | m_nodeAttributes.insert(key: entry.attribute(), value: temp); |
131 | } |
132 | |
133 | updatedAttributes |= entry.attribute(); |
134 | emit q->attributeUpdated(attr: entry.attribute(), value: entry.value()); |
135 | |
136 | if (entry.attribute() == QOpcUa::NodeAttribute::Value) |
137 | emit q->valueAttributeUpdated(value: entry.value()); |
138 | } |
139 | |
140 | emit q->attributeRead(attributes: updatedAttributes); |
141 | } |
142 | |
143 | void handleAttributesWritten(QOpcUa::NodeAttribute attr, const QVariant &value, |
144 | QOpcUa::UaStatusCode statusCode) |
145 | { |
146 | m_nodeAttributes[attr].setStatusCode(statusCode); |
147 | Q_Q(QOpcUaNode); |
148 | |
149 | if (statusCode == QOpcUa::UaStatusCode::Good) { |
150 | m_nodeAttributes[attr].setValue(value); |
151 | emit q->attributeUpdated(attr, value); |
152 | |
153 | if (attr == QOpcUa::NodeAttribute::Value) |
154 | emit q->valueAttributeUpdated(value); |
155 | } |
156 | |
157 | emit q->attributeWritten(attribute: attr, statusCode); |
158 | } |
159 | |
160 | void handleMonitoringEnableDisable(QOpcUa::NodeAttribute attr, bool subscribe, |
161 | const QOpcUaMonitoringParameters &status) |
162 | { |
163 | if (subscribe == true) { |
164 | if (status.statusCode() != QOpcUa::UaStatusCode::BadEntryExists) // Don't overwrite a valid entry |
165 | m_monitoringStatus.insert(key: attr, value: status); |
166 | Q_Q(QOpcUaNode); |
167 | emit q->enableMonitoringFinished(attr, statusCode: status.statusCode()); |
168 | } |
169 | else { |
170 | m_monitoringStatus.remove(key: attr); |
171 | Q_Q(QOpcUaNode); |
172 | emit q->disableMonitoringFinished(attr, statusCode: status.statusCode()); |
173 | } |
174 | } |
175 | |
176 | void handleMonitoringStatusChange(QOpcUa::NodeAttribute attr, |
177 | QOpcUaMonitoringParameters::Parameters items, |
178 | const QOpcUaMonitoringParameters ¶m) |
179 | { |
180 | auto it = m_monitoringStatus.find(key: attr); |
181 | if (param.statusCode() == QOpcUa::UaStatusCode::Good && it != m_monitoringStatus.end()) { |
182 | if (items & QOpcUaMonitoringParameters::Parameter::PublishingEnabled) |
183 | it->setPublishingEnabled(param.isPublishingEnabled()); |
184 | if (items & QOpcUaMonitoringParameters::Parameter::PublishingInterval) |
185 | it->setPublishingInterval(param.publishingInterval()); |
186 | if (items & QOpcUaMonitoringParameters::Parameter::LifetimeCount) |
187 | it->setLifetimeCount(param.lifetimeCount()); |
188 | if (items & QOpcUaMonitoringParameters::Parameter::MaxKeepAliveCount) |
189 | it->setMaxKeepAliveCount(param.maxKeepAliveCount()); |
190 | if (items & QOpcUaMonitoringParameters::Parameter::MaxNotificationsPerPublish) |
191 | it->setMaxNotificationsPerPublish(param.maxNotificationsPerPublish()); |
192 | if (items & QOpcUaMonitoringParameters::Parameter::Priority) |
193 | it->setPriority(param.priority()); |
194 | if (items & QOpcUaMonitoringParameters::Parameter::SamplingInterval) |
195 | it->setSamplingInterval(param.samplingInterval()); |
196 | if (items & QOpcUaMonitoringParameters::Parameter::Filter) { |
197 | if (param.filter().canConvert<QOpcUaMonitoringParameters::DataChangeFilter>()) |
198 | it->setFilter(param.filter().value<QOpcUaMonitoringParameters::DataChangeFilter>()); |
199 | else if (param.filter().canConvert<QOpcUaMonitoringParameters::EventFilter>()) |
200 | it->setFilter(param.filter().value<QOpcUaMonitoringParameters::EventFilter>()); |
201 | else if (param.filter().isNull()) |
202 | it->clearFilter(); |
203 | if (param.filterResult().canConvert<QOpcUaEventFilterResult>()) |
204 | it->setFilterResult(param.filterResult().value<QOpcUaEventFilterResult>()); |
205 | else if (param.filterResult().isNull()) |
206 | it->clearFilterResult(); |
207 | } |
208 | if (items & QOpcUaMonitoringParameters::Parameter::QueueSize) |
209 | it->setQueueSize(param.queueSize()); |
210 | if (items & QOpcUaMonitoringParameters::Parameter::DiscardOldest) |
211 | it->setDiscardOldest(param.discardOldest()); |
212 | if (items & QOpcUaMonitoringParameters::Parameter::MonitoringMode) |
213 | it->setMonitoringMode(param.monitoringMode()); |
214 | if (items & QOpcUaMonitoringParameters::Parameter::TriggeredItemIds) { |
215 | it->setTriggeredItemIds(param.triggeredItemIds()); |
216 | it->setFailedTriggeredItemsStatus(param.failedTriggeredItemsStatus()); |
217 | } |
218 | } |
219 | |
220 | Q_Q(QOpcUaNode); |
221 | emit q->monitoringStatusChanged(attr, items, statusCode: param.statusCode()); |
222 | } |
223 | |
224 | QScopedPointer<QOpcUaNodeImpl> m_impl; |
225 | QPointer<QOpcUaClient> m_client; |
226 | |
227 | QHash<QOpcUa::NodeAttribute, QOpcUaReadResult> m_nodeAttributes; |
228 | QHash<QOpcUa::NodeAttribute, QOpcUaMonitoringParameters> m_monitoringStatus; |
229 | |
230 | std::array<QMetaObject::Connection, 9> m_connections; |
231 | }; |
232 | |
233 | QT_END_NAMESPACE |
234 | |
235 | #endif // QOPCUANODE_P_H |
236 | |