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 (auto service: values)
123 if (service->startHandle <= handle && handle <= service->endHandle)
124 return service;
125
126 return QSharedPointer<QLowEnergyServicePrivate>();
127}
128
129/*!
130 Returns a valid characteristic if the given handle is the
131 handle of the characteristic itself or one of its descriptors
132 */
134 QLowEnergyHandle handle)
135{
136 QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(handle);
137 if (service.isNull())
138 return QLowEnergyCharacteristic();
139
140 if (service->characteristicList.isEmpty())
141 return QLowEnergyCharacteristic();
142
143 // check whether it is the handle of a characteristic header
144 if (service->characteristicList.contains(handle))
145 return QLowEnergyCharacteristic(service, handle);
146
147 // check whether it is the handle of the characteristic value or its descriptors
148 QList<QLowEnergyHandle> charHandles = service->characteristicList.keys();
149 std::sort(charHandles.begin(), charHandles.end());
150 for (qsizetype i = charHandles.size() - 1; i >= 0; --i) {
151 if (charHandles.at(i) > handle)
152 continue;
153
154 return QLowEnergyCharacteristic(service, charHandles.at(i));
155 }
156
157 return QLowEnergyCharacteristic();
158}
159
160/*!
161 Returns a valid descriptor if \a handle belongs to a descriptor;
162 otherwise an invalid one.
163 */
165 QLowEnergyHandle handle)
166{
167 const QLowEnergyCharacteristic matchingChar = characteristicForHandle(handle);
168 if (!matchingChar.isValid())
169 return QLowEnergyDescriptor();
170
171 const QLowEnergyServicePrivate::CharData charData = matchingChar.
172 d_ptr->characteristicList[matchingChar.attributeHandle()];
173
174 if (charData.descriptorList.contains(handle))
175 return QLowEnergyDescriptor(matchingChar.d_ptr, matchingChar.attributeHandle(),
176 handle);
177
178 return QLowEnergyDescriptor();
179}
180
181/*!
182 Returns the length of the updated characteristic value.
183 */
185 QLowEnergyHandle charHandle,const QByteArray &value, bool appendValue)
186{
187 QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
188 if (!service.isNull()) {
189 CharacteristicDataMap::iterator charIt = service->characteristicList.find(charHandle);
190 if (charIt != service->characteristicList.end()) {
191 QLowEnergyServicePrivate::CharData &charDetails = charIt.value();
192
193 if (appendValue)
194 charDetails.value += value;
195 else
196 charDetails.value = value;
197
198 return charDetails.value.size();
199 }
200 }
201
202 return 0;
203}
204
205/*!
206 Returns the length of the updated descriptor value.
207 */
209 QLowEnergyHandle charHandle, QLowEnergyHandle descriptorHandle,
210 const QByteArray &value, bool appendValue)
211{
212 QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
213 if (!service.isNull()) {
214 CharacteristicDataMap::iterator charIt = service->characteristicList.find(charHandle);
215 if (charIt != service->characteristicList.end()) {
216 QLowEnergyServicePrivate::CharData &charDetails = charIt.value();
217
218 DescriptorDataMap::iterator descIt = charDetails.descriptorList.find(descriptorHandle);
219 if (descIt != charDetails.descriptorList.end()) {
220 QLowEnergyServicePrivate::DescData &descDetails = descIt.value();
221
222 if (appendValue)
223 descDetails.value += value;
224 else
225 descDetails.value = value;
226
227 return descDetails.value.size();
228 }
229 }
230 }
231
232 return 0;
233}
234
236{
237 for (QSharedPointer<QLowEnergyServicePrivate> service : serviceList.values())
238 service->setController(nullptr);
239
240 for (QSharedPointer<QLowEnergyServicePrivate> service : localServices.values())
241 service->setController(nullptr);
242
243 serviceList.clear();
244 localServices.clear();
245 lastLocalHandle = {};
246}
247
249 const QLowEnergyServiceData &service)
250{
251 // Spec says services "should" be grouped by uuid length (16-bit first, then 128-bit).
252 // Since this is not mandatory, we ignore it here and let the caller take responsibility
253 // for it.
254
255 const auto servicePrivate = QSharedPointer<QLowEnergyServicePrivate>::create();
256 servicePrivate->setController(this);
257 servicePrivate->state = QLowEnergyService::LocalService;
258 servicePrivate->uuid = service.uuid();
259 servicePrivate->type = service.type() == QLowEnergyServiceData::ServiceTypePrimary
260 ? QLowEnergyService::PrimaryService : QLowEnergyService::IncludedService;
261 const QList<QLowEnergyService *> includedServices = service.includedServices();
262 for (QLowEnergyService * const includedService : includedServices) {
263 servicePrivate->includedServices << includedService->serviceUuid();
264 includedService->d_ptr->type |= QLowEnergyService::IncludedService;
265 }
266
267 // Spec v4.2, Vol 3, Part G, Section 3.
268 const QLowEnergyHandle oldLastHandle = this->lastLocalHandle;
269 servicePrivate->startHandle = ++this->lastLocalHandle; // Service declaration.
270 this->lastLocalHandle += servicePrivate->includedServices.size(); // Include declarations.
271 const QList<QLowEnergyCharacteristicData> characteristics = service.characteristics();
272 for (const QLowEnergyCharacteristicData &cd : characteristics) {
273 const QLowEnergyHandle declHandle = ++this->lastLocalHandle;
274 QLowEnergyServicePrivate::CharData charData;
275 charData.valueHandle = ++this->lastLocalHandle;
276 charData.uuid = cd.uuid();
277 charData.properties = cd.properties();
278 charData.value = cd.value();
279 const QList<QLowEnergyDescriptorData> descriptors = cd.descriptors();
280 for (const QLowEnergyDescriptorData &dd : descriptors) {
281 QLowEnergyServicePrivate::DescData descData;
282 descData.uuid = dd.uuid();
283 descData.value = dd.value();
284 charData.descriptorList.insert(++this->lastLocalHandle, descData);
285 }
286 servicePrivate->characteristicList.insert(declHandle, charData);
287 }
288 servicePrivate->endHandle = this->lastLocalHandle;
289 const bool handleOverflow = this->lastLocalHandle <= oldLastHandle;
290 if (handleOverflow) {
291 qCWarning(QT_BT) << "Not enough attribute handles left to create this service";
292 this->lastLocalHandle = oldLastHandle;
293 return nullptr;
294 }
295
296 if (localServices.contains(servicePrivate->uuid)) {
297 qCWarning(QT_BT) << "Overriding existing local service with uuid"
298 << servicePrivate->uuid;
299 }
300 this->localServices.insert(servicePrivate->uuid, servicePrivate);
301
302 this->addToGenericAttributeList(service, servicePrivate->startHandle);
303 return new QLowEnergyService(servicePrivate);
304}
305
307{
308 qCWarning(QT_BT, "This platform does not support reading RSSI");
309 setError(QLowEnergyController::RssiReadError);
310}
311
312QT_END_NAMESPACE
313
314#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.