Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qlowenergycontrollerbase.cpp
Go to the documentation of this file.
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
5
6#include <QtCore/QLoggingCategory>
7
8#include <QtBluetooth/QBluetoothLocalDevice>
9#include <QtBluetooth/QLowEnergyCharacteristicData>
10#include <QtBluetooth/QLowEnergyDescriptorData>
11#include <QtBluetooth/QLowEnergyServiceData>
12
14
15Q_DECLARE_LOGGING_CATEGORY(QT_BT)
16
17/*!
18 \class QLowEnergyControllerPrivate
19 \inmodule QtBluetooth
20 \internal
21*/
22QLowEnergyControllerPrivate::QLowEnergyControllerPrivate()
23 : QObject()
24{
25}
26
30
32{
33#if defined(QT_WINRT_BLUETOOTH) || defined(Q_OS_DARWIN)
34 return true;
35#endif
36 if (localAdapter.isNull())
37 return false;
38
39 const QList<QBluetoothHostInfo> foundAdapters = QBluetoothLocalDevice::allDevices();
40 bool adapterFound = false;
41
42 for (const QBluetoothHostInfo &info : foundAdapters) {
43 if (info.address() == localAdapter) {
44 adapterFound = true;
45 break;
46 }
47 }
48
49 return adapterFound;
50}
51
52
54 QLowEnergyController::Error newError)
55{
56 Q_Q(QLowEnergyController);
57 error = newError;
58
59 switch (newError) {
60 case QLowEnergyController::UnknownRemoteDeviceError:
61 errorString = QLowEnergyController::tr("Remote device cannot be found");
62 break;
63 case QLowEnergyController::InvalidBluetoothAdapterError:
64 errorString = QLowEnergyController::tr("Cannot find local adapter");
65 break;
66 case QLowEnergyController::NetworkError:
67 errorString = QLowEnergyController::tr("Error occurred during connection I/O");
68 break;
69 case QLowEnergyController::ConnectionError:
70 errorString = QLowEnergyController::tr("Error occurred trying to connect to remote device.");
71 break;
72 case QLowEnergyController::AdvertisingError:
73 errorString = QLowEnergyController::tr("Error occurred trying to start advertising");
74 break;
75 case QLowEnergyController::RemoteHostClosedError:
76 errorString = QLowEnergyController::tr("Remote device closed the connection");
77 break;
78 case QLowEnergyController::AuthorizationError:
79 errorString = QLowEnergyController::tr("Failed to authorize on the remote device");
80 break;
81 case QLowEnergyController::MissingPermissionsError:
82 errorString = QLowEnergyController::tr("Missing permissions error");
83 break;
84 case QLowEnergyController::RssiReadError:
85 errorString = QLowEnergyController::tr("Error reading RSSI value");
86 break;
87 case QLowEnergyController::NoError:
88 return;
89 default:
90 case QLowEnergyController::UnknownError:
91 errorString = QLowEnergyController::tr("Unknown Error");
92 break;
93 }
94
95 emit q->errorOccurred(newError);
96}
97
99 QLowEnergyController::ControllerState newState)
100{
101 qCDebug(QT_BT) << "QLowEnergyControllerPrivate setting state to" << newState;
102 Q_Q(QLowEnergyController);
103 if (state == newState)
104 return;
105
106 state = newState;
107 if (state == QLowEnergyController::UnconnectedState
108 && role == QLowEnergyController::PeripheralRole) {
109 remoteDevice.clear();
110 }
111 emit q->stateChanged(state);
112}
113
115 QLowEnergyHandle handle)
116{
117 ServiceDataMap &currentList = serviceList;
118 if (role == QLowEnergyController::PeripheralRole)
119 currentList = localServices;
120
121 const QList<QSharedPointer<QLowEnergyServicePrivate>> values = currentList.values();
122 for (const auto &service: values) {
123 if (service->startHandle <= handle && handle <= service->endHandle)
124 return service;
125 }
126
127 return QSharedPointer<QLowEnergyServicePrivate>();
128}
129
130/*!
131 Returns a valid characteristic if the given handle is the
132 handle of the characteristic itself or one of its descriptors
133 */
135 QLowEnergyHandle handle)
136{
137 QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(handle);
138 if (service.isNull())
139 return QLowEnergyCharacteristic();
140
141 if (service->characteristicList.isEmpty())
142 return QLowEnergyCharacteristic();
143
144 // check whether it is the handle of a characteristic header
145 if (service->characteristicList.contains(handle))
146 return QLowEnergyCharacteristic(service, handle);
147
148 // check whether it is the handle of the characteristic value or its descriptors
149 QList<QLowEnergyHandle> charHandles = service->characteristicList.keys();
150 std::sort(charHandles.begin(), charHandles.end());
151 for (qsizetype i = charHandles.size() - 1; i >= 0; --i) {
152 if (charHandles.at(i) > handle)
153 continue;
154
155 return QLowEnergyCharacteristic(service, charHandles.at(i));
156 }
157
158 return QLowEnergyCharacteristic();
159}
160
161/*!
162 Returns a valid descriptor if \a handle belongs to a descriptor;
163 otherwise an invalid one.
164 */
166 QLowEnergyHandle handle)
167{
168 const QLowEnergyCharacteristic matchingChar = characteristicForHandle(handle);
169 if (!matchingChar.isValid())
170 return QLowEnergyDescriptor();
171
172 const QLowEnergyServicePrivate::CharData charData = matchingChar.
173 d_ptr->characteristicList[matchingChar.attributeHandle()];
174
175 if (charData.descriptorList.contains(handle))
176 return QLowEnergyDescriptor(matchingChar.d_ptr, matchingChar.attributeHandle(),
177 handle);
178
179 return QLowEnergyDescriptor();
180}
181
182/*!
183 Returns the length of the updated characteristic value.
184 */
186 QLowEnergyHandle charHandle,const QByteArray &value, bool appendValue)
187{
188 QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
189 if (!service.isNull()) {
190 CharacteristicDataMap::iterator charIt = service->characteristicList.find(charHandle);
191 if (charIt != service->characteristicList.end()) {
192 QLowEnergyServicePrivate::CharData &charDetails = charIt.value();
193
194 if (appendValue)
195 charDetails.value += value;
196 else
197 charDetails.value = value;
198
199 return charDetails.value.size();
200 }
201 }
202
203 return 0;
204}
205
206/*!
207 Returns the length of the updated descriptor value.
208 */
210 QLowEnergyHandle charHandle, QLowEnergyHandle descriptorHandle,
211 const QByteArray &value, bool appendValue)
212{
213 QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
214 if (!service.isNull()) {
215 CharacteristicDataMap::iterator charIt = service->characteristicList.find(charHandle);
216 if (charIt != service->characteristicList.end()) {
217 QLowEnergyServicePrivate::CharData &charDetails = charIt.value();
218
219 DescriptorDataMap::iterator descIt = charDetails.descriptorList.find(descriptorHandle);
220 if (descIt != charDetails.descriptorList.end()) {
221 QLowEnergyServicePrivate::DescData &descDetails = descIt.value();
222
223 if (appendValue)
224 descDetails.value += value;
225 else
226 descDetails.value = value;
227
228 return descDetails.value.size();
229 }
230 }
231 }
232
233 return 0;
234}
235
237{
238 for (const QSharedPointer<QLowEnergyServicePrivate> &service : std::as_const(serviceList))
239 service->setController(nullptr);
240
241 for (const QSharedPointer<QLowEnergyServicePrivate> &service : std::as_const(localServices))
242 service->setController(nullptr);
243
244 serviceList.clear();
245 localServices.clear();
246 lastLocalHandle = {};
247}
248
250 const QLowEnergyServiceData &service)
251{
252 // Spec says services "should" be grouped by uuid length (16-bit first, then 128-bit).
253 // Since this is not mandatory, we ignore it here and let the caller take responsibility
254 // for it.
255
256 const auto servicePrivate = QSharedPointer<QLowEnergyServicePrivate>::create();
257 servicePrivate->setController(this);
258 servicePrivate->state = QLowEnergyService::LocalService;
259 servicePrivate->uuid = service.uuid();
260 servicePrivate->type = service.type() == QLowEnergyServiceData::ServiceTypePrimary
261 ? QLowEnergyService::PrimaryService : QLowEnergyService::IncludedService;
262 const QList<QLowEnergyService *> includedServices = service.includedServices();
263 for (QLowEnergyService * const includedService : includedServices) {
264 servicePrivate->includedServices << includedService->serviceUuid();
265 includedService->d_ptr->type |= QLowEnergyService::IncludedService;
266 }
267
268 // Spec v4.2, Vol 3, Part G, Section 3.
269 const QLowEnergyHandle oldLastHandle = this->lastLocalHandle;
270 servicePrivate->startHandle = ++this->lastLocalHandle; // Service declaration.
271 this->lastLocalHandle += servicePrivate->includedServices.size(); // Include declarations.
272 const QList<QLowEnergyCharacteristicData> characteristics = service.characteristics();
273 for (const QLowEnergyCharacteristicData &cd : characteristics) {
274 const QLowEnergyHandle declHandle = ++this->lastLocalHandle;
275 QLowEnergyServicePrivate::CharData charData;
276 charData.valueHandle = ++this->lastLocalHandle;
277 charData.uuid = cd.uuid();
278 charData.properties = cd.properties();
279 charData.value = cd.value();
280 const QList<QLowEnergyDescriptorData> descriptors = cd.descriptors();
281 for (const QLowEnergyDescriptorData &dd : descriptors) {
282 QLowEnergyServicePrivate::DescData descData;
283 descData.uuid = dd.uuid();
284 descData.value = dd.value();
285 charData.descriptorList.insert(++this->lastLocalHandle, descData);
286 }
287 servicePrivate->characteristicList.insert(declHandle, charData);
288 }
289 servicePrivate->endHandle = this->lastLocalHandle;
290 const bool handleOverflow = this->lastLocalHandle <= oldLastHandle;
291 if (handleOverflow) {
292 qCWarning(QT_BT) << "Not enough attribute handles left to create this service";
293 this->lastLocalHandle = oldLastHandle;
294 return nullptr;
295 }
296
297 if (localServices.contains(servicePrivate->uuid)) {
298 qCWarning(QT_BT) << "Overriding existing local service with uuid"
299 << servicePrivate->uuid;
300 }
301 this->localServices.insert(servicePrivate->uuid, servicePrivate);
302
303 this->addToGenericAttributeList(service, servicePrivate->startHandle);
304 return new QLowEnergyService(servicePrivate);
305}
306
308{
309 qCWarning(QT_BT, "This platform does not support reading RSSI");
310 setError(QLowEnergyController::RssiReadError);
311}
312
313QT_END_NAMESPACE
314
315#include "moc_qlowenergycontrollerbase_p.cpp"
QLowEnergyCharacteristic characteristicForHandle(QLowEnergyHandle handle)
Returns a valid characteristic if the given handle is the handle of the characteristic itself or one ...
QSharedPointer< QLowEnergyServicePrivate > serviceForHandle(QLowEnergyHandle handle)
quint16 updateValueOfDescriptor(QLowEnergyHandle charHandle, QLowEnergyHandle descriptorHandle, const QByteArray &value, bool appendValue)
Returns the length of the updated descriptor value.
QLowEnergyDescriptor descriptorForHandle(QLowEnergyHandle handle)
Returns a valid descriptor if handle belongs to a descriptor; otherwise an invalid one.
void setError(QLowEnergyController::Error newError)
quint16 updateValueOfCharacteristic(QLowEnergyHandle charHandle, const QByteArray &value, bool appendValue)
Returns the length of the updated characteristic value.
virtual QLowEnergyService * addServiceHelper(const QLowEnergyServiceData &service)
void setState(QLowEnergyController::ControllerState newState)
Combined button and popup list for selecting options.