| 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 | |