1/*
2 * BluezQt - Asynchronous Bluez wrapper library
3 *
4 * SPDX-FileCopyrightText: 2021 Ivan Podkurkov <podkiva2@gmail.com>
5 *
6 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8
9#include "gattserviceremote_p.h"
10#include "gattserviceremote.h"
11#include "gattcharacteristicremote_p.h"
12#include "gattcharacteristicremote.h"
13#include "device_p.h"
14#include "device.h"
15#include "adapter.h"
16#include "input.h"
17#include "input_p.h"
18#include "mediaplayer.h"
19#include "mediaplayer_p.h"
20#include "utils.h"
21#include "macros.h"
22
23namespace BluezQt
24{
25
26GattServiceRemotePrivate::GattServiceRemotePrivate(const QString &path, const QVariantMap &properties, const DevicePtr &device)
27 : QObject()
28 , m_dbusProperties(nullptr)
29 , m_primary(false)
30 , m_device(device)
31 , m_handle(0)
32{
33 m_bluezGattService = new BluezGattService(Strings::orgBluez(), path, DBusConnection::orgBluez(), this);
34
35 init(properties);
36}
37
38void GattServiceRemotePrivate::init(const QVariantMap &properties)
39{
40 m_dbusProperties = new DBusProperties(Strings::orgBluez(), m_bluezGattService->path(),
41 DBusConnection::orgBluez(), this);
42
43 // Init properties
44 m_uuid = properties.value(QStringLiteral("UUID")).toString();
45 m_primary = properties.value(QStringLiteral("Primary")).toBool();
46 m_includes = properties.value(QStringLiteral("Includes")).value<QList<QDBusObjectPath>>();
47 m_handle = static_cast<quint16>(properties.value(QStringLiteral("Handle")).toUInt());
48
49}
50
51void GattServiceRemotePrivate::interfacesAdded(const QString &path, const QVariantMapMap &interfaces)
52{
53 bool changed = false;
54 QVariantMapMap::const_iterator it;
55
56 for (it = interfaces.constBegin(); it != interfaces.constEnd(); ++it) {
57 if (it.key() == Strings::orgBluezGattCharacteristic1()) {
58 addGattCharacteristic(gattCharacteristicPath: path,properties: it.value());
59 changed = true;
60 }
61 }
62
63 for (auto& ch: m_characteristics) {
64 if (path.startsWith(s: ch->ubi())) {
65 ch->d->interfacesAdded(path, interfaces);
66 changed = true;
67 }
68 }
69
70 if (changed) {
71 Q_EMIT q.lock().data()->serviceChanged(service: q.toStrongRef());
72 }
73}
74
75void GattServiceRemotePrivate::interfacesRemoved(const QString &path, const QStringList &interfaces)
76{
77 Q_UNUSED(path)
78 bool changed = false;
79
80 for (auto& interface : interfaces) {
81 if (interface == Strings::orgBluezGattCharacteristic1()) {
82 removeGattCharacteristic(gattCharacteristicPath: path);
83 changed = true;
84 }
85 }
86
87 for (auto& ch: m_characteristics) {
88 if (path.startsWith(s: ch->ubi())) {
89 ch->d->interfacesRemoved(path, interfaces);
90 changed = true;
91 }
92 }
93
94 if (changed) {
95 Q_EMIT q.lock().data()->serviceChanged(service: q.toStrongRef());
96 }
97}
98
99void GattServiceRemotePrivate::addGattCharacteristic(const QString &gattCharacteristicPath, const QVariantMap &properties)
100{
101 // Check if we have the right path
102 if (m_bluezGattService->path() != properties.value(QStringLiteral("Service")).value<QDBusObjectPath>().path()) {
103 return;
104 }
105
106 GattServiceRemotePtr service = GattServiceRemotePtr(this->q);
107
108 if (!service) {
109 return;
110 }
111
112 GattCharacteristicRemotePtr gattCharacteristic = GattCharacteristicRemotePtr(new GattCharacteristicRemote(gattCharacteristicPath, properties, service));
113 gattCharacteristic->d->q = gattCharacteristic.toWeakRef();
114 m_characteristics.append(t: gattCharacteristic);
115
116 Q_EMIT service->gattCharacteristicAdded(characteristic: gattCharacteristic);
117 Q_EMIT service->characteristicsChanged(characteristics: m_characteristics);
118
119 // Connections
120 connect(sender: gattCharacteristic.data(),signal: &GattCharacteristicRemote::characteristicChanged,context: q.lock().data(),slot: &GattServiceRemote::gattCharacteristicChanged);
121}
122
123void GattServiceRemotePrivate::removeGattCharacteristic(const QString &gattCharacteristicPath)
124{
125 GattServiceRemotePtr service = GattServiceRemotePtr(this->q);
126
127 if (!service) {
128 return;
129 }
130
131 GattCharacteristicRemotePtr gattCharacteristic = nullptr;
132 for (int i=0; i < service->characteristics().size(); ++i) {
133 if (service->characteristics().at(i)->ubi() == gattCharacteristicPath) {
134 gattCharacteristic = service->characteristics().at(i);
135 }
136 }
137
138 if (gattCharacteristic == nullptr) {
139 return;
140 }
141
142 m_characteristics.removeOne(t: gattCharacteristic);
143
144 Q_EMIT service->gattCharacteristicRemoved(characteristic: gattCharacteristic);
145 Q_EMIT service->characteristicsChanged(characteristics: m_characteristics);
146
147 // Connections
148 disconnect(sender: gattCharacteristic.data(),signal: &GattCharacteristicRemote::characteristicChanged,receiver: q.lock().data(),slot: &GattServiceRemote::gattCharacteristicChanged);
149}
150
151QDBusPendingReply<> GattServiceRemotePrivate::setDBusProperty(const QString &name, const QVariant &value)
152{
153 return m_dbusProperties->Set(interface_name: Strings::orgBluezGattService1(), property_name: name, value: QDBusVariant(value));
154}
155
156void GattServiceRemotePrivate::propertiesChanged(const QString &path, const QString &interface, const QVariantMap &changed, const QStringList &invalidated)
157{
158 if (interface == Strings::orgBluezGattCharacteristic1() || interface == Strings::orgBluezGattDescriptor1()) {
159 for (GattCharacteristicRemotePtr characteristic : m_characteristics) {
160 if (path.startsWith(s: characteristic->ubi())) {
161 characteristic->d->propertiesChanged(path, interface, changed, invalidated);
162 return;
163 }
164 }
165 } else if (interface != Strings::orgBluezGattService1()) {
166 return;
167 }
168
169 QVariantMap::const_iterator i;
170 for (i = changed.constBegin(); i != changed.constEnd(); ++i) {
171 const QVariant &value = i.value();
172 const QString &property = i.key();
173
174 if (property == QLatin1String("UUID")) {
175 PROPERTY_CHANGED(m_uuid, toString, uuidChanged);
176 } else if (property == QLatin1String("Primary")) {
177 PROPERTY_CHANGED(m_primary, toBool, primaryChanged);
178 } else if (property == QLatin1String("Includes")) {
179 PROPERTY_CHANGED2(m_includes, value.value<QList<QDBusObjectPath>>(), includesChanged);
180 } else if (property == QLatin1String("Handle")) {
181 PROPERTY_CHANGED2(m_handle, value.value<quint16>(), handleChanged);
182 }
183 }
184
185 for (auto& property : invalidated) {
186 if (property == QLatin1String("UUID")) {
187 PROPERTY_INVALIDATED(m_uuid, QString(), uuidChanged);
188 } else if (property == QLatin1String("Primary")) {
189 PROPERTY_INVALIDATED(m_primary, false, primaryChanged);
190 } else if (property == QLatin1String("Includes")) {
191 PROPERTY_INVALIDATED(m_includes, QList<QDBusObjectPath>(), includesChanged);
192 } else if (property == QLatin1String("Handle")) {
193 PROPERTY_INVALIDATED(m_handle, quint16(), handleChanged);
194 }
195 }
196
197 q.lock().data()->serviceChanged(service: q.toStrongRef());
198}
199
200} // namespace BluezQt
201
202#include "moc_gattserviceremote_p.cpp"
203

source code of bluez-qt/src/gattserviceremote_p.cpp