1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtBluetooth module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qlowenergycontroller.h"
41
42#include "qlowenergycharacteristicdata.h"
43#include "qlowenergyconnectionparameters.h"
44#include "qlowenergydescriptordata.h"
45#include "qlowenergyservicedata.h"
46
47#include <QtBluetooth/QBluetoothLocalDevice>
48#include <QtCore/QLoggingCategory>
49
50
51#if QT_CONFIG(bluez) && !defined(QT_BLUEZ_NO_BTLE)
52#include "bluez/bluez5_helper_p.h"
53#include "qlowenergycontroller_bluezdbus_p.h"
54#include "qlowenergycontroller_bluez_p.h"
55#elif defined(QT_ANDROID_BLUETOOTH)
56#include "qlowenergycontroller_android_p.h"
57#elif defined(QT_WINRT_BLUETOOTH)
58#include "qtbluetoothglobal_p.h"
59#include "qlowenergycontroller_winrt_p.h"
60#if QT_CONFIG(winrt_btle_no_pairing)
61#include "qlowenergycontroller_winrt_new_p.h"
62#endif
63#elif defined(QT_WIN_BLUETOOTH)
64#include "qlowenergycontroller_win_p.h"
65#elif defined(Q_OS_DARWIN)
66#include "qlowenergycontroller_darwin_p.h"
67#else
68#include "qlowenergycontroller_dummy_p.h"
69#endif
70
71#include <algorithm>
72
73QT_BEGIN_NAMESPACE
74
75Q_DECLARE_LOGGING_CATEGORY(QT_BT)
76Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
77
78/*!
79 \class QLowEnergyController
80 \inmodule QtBluetooth
81 \brief The QLowEnergyController class provides access to Bluetooth
82 Low Energy Devices.
83
84 \since 5.4
85
86 QLowEnergyController acts as the entry point for Bluetooth Low Energy
87 development.
88
89 Bluetooth Low Energy defines two types of devices; the peripheral and
90 the central. Each role performs a different task. The peripheral device
91 provides data which is utilized by central devices. An example might be a
92 humidity sensor which measures the moisture in a winter garden. A device
93 such as a mobile phone might read the sensor's value and display it to the user
94 in the greater context of all sensors in the same environment. In this case
95 the sensor is the peripheral device and the mobile phone acts as the
96 central device.
97
98 A controller in the central role is created via the \l createCentral() factory method.
99 Such an object essentially acts as a placeholder towards a remote Low Energy peripheral
100 device, enabling features such as service discovery and state tracking.
101
102 After having created a controller object in the central role, the first step is to establish
103 a connection via \l connectToDevice().
104 Once the connection has been established, the controller's \l state()
105 changes to \l QLowEnergyController::ConnectedState and the \l connected()
106 signal is emitted. It is important to mention that some platforms such as
107 a BlueZ based Linux cannot maintain two connected instances of
108 \l QLowEnergyController to the same remote device. In such cases the second
109 call to \l connectToDevice() may fail. This limitation may disappear at some
110 stage in the future. The \l disconnectFromDevice() function is used to break
111 the existing connection.
112
113 The second step after establishing the connection is to discover the services
114 offered by the remote peripheral device. This process is started via
115 \l discoverServices() and has finished once the \l discoveryFinished() signal
116 has been emitted. The discovered services can be enumerated via
117 \l services().
118
119 The last step is to create service objects. The \l createServiceObject()
120 function acts as factory for each service object and expects the service
121 UUID as parameter. The calling context should take ownership of the returned
122 \l QLowEnergyService instance.
123
124 Any \l QLowEnergyService, \l QLowEnergyCharacteristic or
125 \l QLowEnergyDescriptor instance which is later created from this controller's
126 connection becomes invalid as soon as the controller disconnects from the
127 remote Bluetooth Low Energy device.
128
129 A controller in the peripheral role is created via the \l createPeripheral() factory method.
130 Such an object acts as a peripheral device itself, enabling features such as advertising
131 services and allowing clients to get notified about changes to characteristic values.
132
133 After having created a controller object in the peripheral role, the first step is to
134 populate the set of GATT services offered to client devices via calls to \l addService().
135 Afterwards, one would call \l startAdvertising() to let the device broadcast some data
136 and, depending on the type of advertising being done, also listen for incoming connections
137 from GATT clients.
138
139 \sa QLowEnergyService, QLowEnergyCharacteristic, QLowEnergyDescriptor
140 \sa QLowEnergyAdvertisingParameters, QLowEnergyAdvertisingData
141*/
142
143/*!
144 \enum QLowEnergyController::Error
145
146 Indicates all possible error conditions found during the controller's
147 existence.
148
149 \value NoError No error has occurred.
150 \value UnknownError An unknown error has occurred.
151 \value UnknownRemoteDeviceError The remote Bluetooth Low Energy device with the address passed to
152 the constructor of this class cannot be found.
153 \value NetworkError The attempt to read from or write to the
154 remote device failed.
155 \value InvalidBluetoothAdapterError The local Bluetooth device with the address passed to
156 the constructor of this class cannot be found or
157 there is no local Bluetooth device.
158 \value ConnectionError The attempt to connect to the remote device failed.
159 This value was introduced by Qt 5.5.
160 \value AdvertisingError The attempt to start advertising failed.
161 This value was introduced by Qt 5.7.
162 \value RemoteHostClosedError The remote device closed the connection.
163 This value was introduced by Qt 5.10.
164 \value AuthorizationError The local Bluetooth device closed the connection due to
165 insufficient authorization.
166 This value was introduced by Qt 5.14.
167*/
168
169/*!
170 \enum QLowEnergyController::ControllerState
171
172 Indicates the state of the controller object.
173
174 \value UnconnectedState The controller is not connected to a remote device.
175 \value ConnectingState The controller is attempting to connect to a remote device.
176 \value ConnectedState The controller is connected to a remote device.
177 \value DiscoveringState The controller is retrieving the list of services offered
178 by the remote device.
179 \value DiscoveredState The controller has discovered all services offered by the
180 remote device.
181 \value ClosingState The controller is about to be disconnected from the remote device.
182 \value AdvertisingState The controller is currently advertising data.
183 This value was introduced by Qt 5.7.
184*/
185
186/*!
187 \enum QLowEnergyController::RemoteAddressType
188
189 Indicates what type of Bluetooth address the remote device uses.
190
191 \value PublicAddress The remote device uses a public Bluetooth address.
192 \value RandomAddress A random address is a Bluetooth Low Energy security feature.
193 Peripherals using such addresses may frequently change their
194 Bluetooth address. This information is needed when trying to
195 connect to a peripheral.
196 */
197
198/*!
199 \enum QLowEnergyController::Role
200
201 Indicates the role of the controller object.
202
203 \value CentralRole
204 The controller acts as a client interacting with a remote device which is in the peripheral
205 role. The controller can initiate connections, discover services and
206 read and write characteristics.
207 \value PeripheralRole
208 The controller can be used to advertise services and handle incoming
209 connections and client requests, acting as a GATT server. A remote device connected to
210 the controller is in the central role.
211
212 \sa QLowEnergyController::createCentral()
213 \sa QLowEnergyController::createPeripheral()
214 \since 5.7
215 \note The peripheral role is currently only supported on Linux. In addition, handling the
216 "Signed Write" ATT command on the server side requires BlueZ 5 and kernel version 3.7
217 or newer.
218 */
219
220
221/*!
222 \fn void QLowEnergyController::connected()
223
224 This signal is emitted when the controller successfully connects to the remote
225 Low Energy device (if the controller is in the \l CentralRole) or if a remote Low Energy
226 device connected to the controller (if the controller is in the \l PeripheralRole).
227 On iOS and OS X this signal is not reliable if the controller is in the \l PeripheralRole
228 - the controller only guesses that some central connected to our peripheral as
229 soon as this central tries to write/read a characteristic/descriptor.
230*/
231
232/*!
233 \fn void QLowEnergyController::disconnected()
234
235 This signal is emitted when the controller disconnects from the remote
236 Low Energy device or vice versa. On iOS and OS X this signal is unreliable
237 if the controller is in the \l PeripheralRole.
238*/
239
240/*!
241 \fn void QLowEnergyController::stateChanged(ControllerState state)
242
243 This signal is emitted when the controller's state changes. The new
244 \a state can also be retrieved via \l state().
245
246 \sa state()
247*/
248
249/*!
250 \fn void QLowEnergyController::error(QLowEnergyController::Error newError)
251
252 This signal is emitted when an error occurs.
253 The \a newError parameter describes the error that occurred.
254
255 \sa error(), errorString()
256*/
257
258/*!
259 \fn void QLowEnergyController::serviceDiscovered(const QBluetoothUuid &newService)
260
261 This signal is emitted each time a new service is discovered. The
262 \a newService parameter contains the UUID of the found service.
263
264 This signal can only be emitted if the controller is in the \c CentralRole.
265
266 \sa discoverServices(), discoveryFinished()
267*/
268
269/*!
270 \fn void QLowEnergyController::discoveryFinished()
271
272 This signal is emitted when the running service discovery finishes.
273 The signal is not emitted if the discovery process finishes with
274 an error.
275
276 This signal can only be emitted if the controller is in the \l CentralRole.
277
278 \sa discoverServices(), error()
279*/
280
281/*!
282 \fn void QLowEnergyController::connectionUpdated(const QLowEnergyConnectionParameters &newParameters)
283
284 This signal is emitted when the connection parameters change. This can happen as a result
285 of calling \l requestConnectionUpdate() or due to other reasons, for instance because
286 the other side of the connection requested new parameters. The new values can be retrieved
287 from \a newParameters.
288
289 \since 5.7
290 \sa requestConnectionUpdate()
291*/
292
293
294void registerQLowEnergyControllerMetaType()
295{
296 static bool initDone = false;
297 if (!initDone) {
298 qRegisterMetaType<QLowEnergyController::ControllerState>();
299 qRegisterMetaType<QLowEnergyController::Error>();
300 qRegisterMetaType<QLowEnergyConnectionParameters>();
301 qRegisterMetaType<QLowEnergyCharacteristic>();
302 qRegisterMetaType<QLowEnergyDescriptor>();
303 initDone = true;
304 }
305}
306
307static QLowEnergyControllerPrivate *privateController(QLowEnergyController::Role role)
308{
309#if QT_CONFIG(bluez) && !defined(QT_BLUEZ_NO_BTLE)
310 // The new DBUS implementation only supports Central role for now
311 // For Peripheral role support see QTBUG-66909
312 if (role == QLowEnergyController::CentralRole
313 && bluetoothdVersion() >= QVersionNumber(5, 42)) {
314 qCWarning(QT_BT) << "Using BlueZ LE DBus API";
315 return new QLowEnergyControllerPrivateBluezDBus();
316 } else {
317 qCWarning(QT_BT) << "Using BlueZ kernel ATT interface";
318 return new QLowEnergyControllerPrivateBluez();
319 }
320#elif defined(QT_ANDROID_BLUETOOTH)
321 Q_UNUSED(role);
322 return new QLowEnergyControllerPrivateAndroid();
323#elif defined(QT_WINRT_BLUETOOTH)
324 Q_UNUSED(role);
325#if QT_CONFIG(winrt_btle_no_pairing)
326 return createWinRTLowEnergyController();
327#else
328 qCDebug(QT_BT_WINRT) << "Using pre 15063 low energy controller";
329 return new QLowEnergyControllerPrivateWinRT();
330#endif
331#elif defined(QT_WIN_BLUETOOTH)
332 Q_UNUSED(role);
333 return new QLowEnergyControllerPrivateWin32();
334#elif defined(Q_OS_DARWIN)
335 Q_UNUSED(role)
336 return new QLowEnergyControllerPrivateDarwin();
337#else
338 Q_UNUSED(role);
339 return new QLowEnergyControllerPrivateCommon();
340#endif
341}
342
343/*!
344 Constructs a new instance of this class with \a parent.
345
346 The \a remoteDevice must contain the address of the
347 remote Bluetooth Low Energy device to which this object
348 should attempt to connect later on.
349
350 The controller uses the local default Bluetooth adapter for
351 the connection management.
352
353 \obsolete
354 */
355QLowEnergyController::QLowEnergyController(
356 const QBluetoothAddress &remoteDevice,
357 QObject *parent)
358 : QObject(parent)
359{
360 // Note: a central created using this ctor is useless
361 // on Darwin - no way to use addresses when connecting.
362
363 d_ptr = privateController(role: CentralRole);
364
365 Q_D(QLowEnergyController);
366 d->q_ptr = this;
367 d->role = CentralRole;
368 d->remoteDevice = remoteDevice;
369 d->localAdapter = QBluetoothLocalDevice().address();
370 d->addressType = QLowEnergyController::PublicAddress;
371 d->init();
372}
373
374/*!
375 Constructs a new instance of this class with \a parent.
376
377 The \a remoteDeviceInfo must contain the details of the
378 remote Bluetooth Low Energy device to which this object
379 should attempt to connect later on.
380
381 The controller uses the local default Bluetooth adapter for
382 the connection management.
383
384 \since 5.5
385 \obsolete
386*/
387QLowEnergyController::QLowEnergyController(
388 const QBluetoothDeviceInfo &remoteDeviceInfo,
389 QObject *parent)
390 : QObject(parent)
391{
392 d_ptr = privateController(role: CentralRole);
393
394 Q_D(QLowEnergyController);
395 d->q_ptr = this;
396 d->role = CentralRole;
397 d->deviceUuid = remoteDeviceInfo.deviceUuid();
398 d->remoteDevice = remoteDeviceInfo.address();
399 d->localAdapter = QBluetoothLocalDevice().address();
400 d->addressType = QLowEnergyController::PublicAddress;
401 d->remoteName = remoteDeviceInfo.name();
402 d->init();
403}
404
405/*!
406 Constructs a new instance of this class with \a parent.
407
408 The \a remoteDevice must contain the address of the
409 remote Bluetooth Low Energy device to which this object
410 should attempt to connect later on.
411
412 The connection is established via \a localDevice. If \a localDevice
413 is invalid, the local default device is automatically selected. If
414 \a localDevice specifies a local device that is not a local Bluetooth
415 adapter, \l error() is set to \l InvalidBluetoothAdapterError once
416 \l connectToDevice() is called.
417
418 \obsolete
419 */
420QLowEnergyController::QLowEnergyController(
421 const QBluetoothAddress &remoteDevice,
422 const QBluetoothAddress &localDevice,
423 QObject *parent)
424 : QObject(parent)
425{
426 // Note: a central create using this ctor is useless on
427 // Darwin (CoreBluetooth does not work with addresses).
428 d_ptr = privateController(role: CentralRole);
429
430 Q_D(QLowEnergyController);
431 d->q_ptr = this;
432 d->role = CentralRole;
433 d->remoteDevice = remoteDevice;
434 d->localAdapter = localDevice;
435 d->init();
436}
437
438/*!
439 Returns a new object of this class that is in the \l CentralRole and has the
440 parent object \a parent.
441 The \a remoteDevice refers to the device that a connection will be established to later.
442
443 The controller uses the local default Bluetooth adapter for the connection management.
444
445 \sa QLowEnergyController::CentralRole
446 \since 5.7
447 */
448QLowEnergyController *QLowEnergyController::createCentral(const QBluetoothDeviceInfo &remoteDevice,
449 QObject *parent)
450{
451 return new QLowEnergyController(remoteDevice, parent);
452}
453
454/*!
455 Returns a new instance of this class with \a parent.
456
457 The \a remoteDevice must contain the address of the remote Bluetooth Low
458 Energy device to which this object should attempt to connect later on.
459
460 The connection is established via \a localDevice. If \a localDevice is invalid,
461 the local default device is automatically selected. If \a localDevice specifies
462 a local device that is not a local Bluetooth adapter, \l error() is set to
463 \l InvalidBluetoothAdapterError once \l connectToDevice() is called.
464
465 Note that specifying the local device to be used for the connection is only
466 possible when using BlueZ. All other platforms do not support this feature.
467
468 \since 5.14
469 */
470QLowEnergyController *QLowEnergyController::createCentral(const QBluetoothAddress &remoteDevice,
471 const QBluetoothAddress &localDevice,
472 QObject *parent)
473{
474 return new QLowEnergyController(remoteDevice, localDevice, parent);
475}
476
477
478/*!
479 Returns a new object of this class that is in the \l PeripheralRole and has the
480 parent object \a parent.
481 Typically, the next step is to call \l startAdvertising() on the returned object.
482
483 The controller uses the local default Bluetooth adapter for the connection management.
484
485 \sa QLowEnergyController::PeripheralRole
486 \since 5.7
487 */
488QLowEnergyController *QLowEnergyController::createPeripheral(QObject *parent)
489{
490 return new QLowEnergyController(parent);
491}
492
493QLowEnergyController::QLowEnergyController(QObject *parent)
494 : QObject(parent)
495{
496 d_ptr = privateController(role: PeripheralRole);
497
498 Q_D(QLowEnergyController);
499 d->q_ptr = this;
500 d->role = PeripheralRole;
501 d->localAdapter = QBluetoothLocalDevice().address();
502 d->init();
503}
504
505/*!
506 Destroys the QLowEnergyController instance.
507 */
508QLowEnergyController::~QLowEnergyController()
509{
510 disconnectFromDevice(); //in case we were connected
511 delete d_ptr;
512}
513
514/*!
515 Returns the address of the local Bluetooth adapter being used for the
516 communication.
517
518 If this class instance was requested to use the default adapter
519 but there was no default adapter when creating this
520 class instance, the returned \l QBluetoothAddress will be null.
521
522 \sa QBluetoothAddress::isNull()
523 */
524QBluetoothAddress QLowEnergyController::localAddress() const
525{
526 return d_ptr->localAdapter;
527}
528
529/*!
530 Returns the address of the remote Bluetooth Low Energy device.
531
532 For a controller in the \l CentralRole, this value will always be the one passed in when
533 the controller object was created. For a controller in the \l PeripheralRole, this value
534 is the address of the currently connected client device. In particular, this address will
535 be invalid if the controller is not currently in the \l ConnectedState.
536 */
537QBluetoothAddress QLowEnergyController::remoteAddress() const
538{
539 return d_ptr->remoteDevice;
540}
541
542/*!
543 Returns the unique identifier of the remote Bluetooth Low Energy device.
544
545 On macOS/iOS/tvOS CoreBluetooth does not expose/accept hardware addresses for
546 LE devices; instead developers are supposed to use unique 128-bit UUIDs, generated
547 by CoreBluetooth. These UUIDS will stay constant for the same central <-> peripheral
548 pair and we use them when connecting to a remote device. For a controller in the
549 \l CentralRole, this value will always be the one passed in when the controller
550 object was created. For a controller in the \l PeripheralRole, this value is invalid.
551
552 \since 5.8
553 */
554QBluetoothUuid QLowEnergyController::remoteDeviceUuid() const
555{
556 return d_ptr->deviceUuid;
557}
558
559/*!
560 Returns the name of the remote Bluetooth Low Energy device, if the controller is in the
561 \l CentralRole. Otherwise the result is unspecified.
562
563 \since 5.5
564 */
565QString QLowEnergyController::remoteName() const
566{
567 return d_ptr->remoteName;
568}
569
570/*!
571 Returns the current state of the controller.
572
573 \sa stateChanged()
574 */
575QLowEnergyController::ControllerState QLowEnergyController::state() const
576{
577 return d_ptr->state;
578}
579
580/*!
581 Returns the type of \l remoteAddress(). By default, this value is initialized
582 to \l PublicAddress.
583
584 \sa setRemoteAddressType()
585 */
586QLowEnergyController::RemoteAddressType QLowEnergyController::remoteAddressType() const
587{
588 return d_ptr->addressType;
589}
590
591/*!
592 Sets the remote address \a type. The type is required to connect
593 to the remote Bluetooth Low Energy device.
594
595 This attribute is only required to be set on Linux/BlueZ systems with older
596 Linux kernels (v3.3 or lower), or if CAP_NET_ADMIN is not set for the executable.
597 The default value of the attribute is \l RandomAddress.
598
599 \note All other platforms handle this flag transparently and therefore applications
600 can ignore it entirely. On Linux, the address type flag is not directly exposed
601 by BlueZ although some use cases do require this information. The only way to detect
602 the flag is via the Linux kernel's Bluetooth Management API (kernel
603 version 3.4+ required). This API requires CAP_NET_ADMIN capabilities though. If the
604 local QtBluetooth process has this capability set QtBluetooth will use the API. This
605 assumes that \l QBluetoothDeviceDiscoveryAgent was used prior to calling
606 \l QLowEnergyController::connectToDevice().
607 */
608void QLowEnergyController::setRemoteAddressType(
609 QLowEnergyController::RemoteAddressType type)
610{
611 d_ptr->addressType = type;
612}
613
614/*!
615 Connects to the remote Bluetooth Low Energy device.
616
617 This function does nothing if the controller's \l state()
618 is not equal to \l UnconnectedState. The \l connected() signal is emitted
619 once the connection is successfully established.
620
621 On Linux/BlueZ systems, it is not possible to connect to the same
622 remote device using two instances of this class. The second call
623 to this function may fail with an error. This limitation may
624 be removed in future releases.
625
626 \sa disconnectFromDevice()
627 */
628void QLowEnergyController::connectToDevice()
629{
630 Q_D(QLowEnergyController);
631
632 if (role() != CentralRole) {
633 qCWarning(QT_BT) << "Connection can only be established while in central role";
634 return;
635 }
636
637 if (!d->isValidLocalAdapter()) {
638 d->setError(QLowEnergyController::InvalidBluetoothAdapterError);
639 return;
640 }
641
642 if (state() != QLowEnergyController::UnconnectedState)
643 return;
644
645 d->connectToDevice();
646}
647
648/*!
649 Disconnects from the remote device.
650
651 Any \l QLowEnergyService, \l QLowEnergyCharacteristic or \l QLowEnergyDescriptor
652 instance that resulted from the current connection is automatically invalidated.
653 Once any of those objects become invalid they remain invalid even if this
654 controller object reconnects.
655
656 This function does nothing if the controller is in the \l UnconnectedState.
657
658 If the controller is in the peripheral role, it stops advertising and removes
659 all services which have previously been added via \l addService().
660 To reuse the QLowEnergyController instance the application must re-add services
661 and restart the advertising mode by calling \l startAdvertising().
662
663 \sa connectToDevice()
664 */
665void QLowEnergyController::disconnectFromDevice()
666{
667 Q_D(QLowEnergyController);
668
669 if (state() == QLowEnergyController::UnconnectedState)
670 return;
671
672 d->invalidateServices();
673 d->disconnectFromDevice();
674}
675
676/*!
677 Initiates the service discovery process.
678
679 The discovery progress is indicated via the \l serviceDiscovered() signal.
680 The \l discoveryFinished() signal is emitted when the process has finished.
681
682 If the controller instance is not connected or the controller has performed
683 the service discovery already this function will do nothing.
684
685 \note Some platforms internally cache the service list of a device
686 which was discovered in the past. This can be problematic if the remote device
687 changed its list of services or their inclusion tree. If this behavior is a
688 problem, the best workaround is to temporarily turn Bluetooth off. This
689 causes a reset of the cache data. Currently Android exhibits such a
690 cache behavior.
691 */
692void QLowEnergyController::discoverServices()
693{
694 Q_D(QLowEnergyController);
695
696 if (d->role != CentralRole) {
697 qCWarning(QT_BT) << "Cannot discover services in peripheral role";
698 return;
699 }
700 if (d->state != QLowEnergyController::ConnectedState)
701 return;
702
703 d->setState(QLowEnergyController::DiscoveringState);
704 d->discoverServices();
705}
706
707/*!
708 Returns the list of services offered by the remote device, if the controller is in
709 the \l CentralRole. Otherwise, the result is unspecified.
710
711 The list contains all primary and secondary services.
712
713 \sa createServiceObject()
714 */
715QList<QBluetoothUuid> QLowEnergyController::services() const
716{
717 return d_ptr->serviceList.keys();
718}
719
720/*!
721 Creates an instance of the service represented by \a serviceUuid.
722 The \a serviceUuid parameter must have been obtained via
723 \l services().
724
725 The caller takes ownership of the returned pointer and may pass
726 a \a parent parameter as default owner.
727
728 This function returns a null pointer if no service with
729 \a serviceUuid can be found on the remote device or the controller
730 is disconnected.
731
732 This function can return instances for secondary services
733 too. The include relationships between services can be expressed
734 via \l QLowEnergyService::includedServices().
735
736 If this function is called multiple times using the same service UUID,
737 the returned \l QLowEnergyService instances share their internal
738 data. Therefore if one of the instances initiates the discovery
739 of the service details, the other instances automatically
740 transition into the discovery state too.
741
742 \sa services()
743 */
744QLowEnergyService *QLowEnergyController::createServiceObject(
745 const QBluetoothUuid &serviceUuid, QObject *parent)
746{
747 Q_D(QLowEnergyController);
748
749 QLowEnergyService *service = nullptr;
750
751 ServiceDataMap::const_iterator it = d->serviceList.constFind(akey: serviceUuid);
752 if (it != d->serviceList.constEnd()) {
753 const QSharedPointer<QLowEnergyServicePrivate> &serviceData = it.value();
754
755 service = new QLowEnergyService(serviceData, parent);
756 }
757
758 return service;
759}
760
761/*!
762 Starts advertising the data given in \a advertisingData and \a scanResponseData, using
763 the parameters set in \a parameters. The controller has to be in the \l PeripheralRole.
764 If \a parameters indicates that the advertisement should be connectable, then this function
765 also starts listening for incoming client connections.
766
767 Providing \a scanResponseData is not required, as it is not applicable for certain
768 configurations of \c parameters. \a advertisingData and \a scanResponseData are limited
769 to 31 byte user data. If, for example, several 128bit uuids are added to \a advertisingData,
770 the advertised packets may not contain all uuids. The existing limit may have caused the truncation
771 of uuids. In such cases \a scanResponseData may be used for additional information.
772
773 If this object is currently not in the \l UnconnectedState, nothing happens.
774 \note Advertising will stop automatically once a client connects to the local device.
775
776 \since 5.7
777 \sa stopAdvertising()
778 */
779void QLowEnergyController::startAdvertising(const QLowEnergyAdvertisingParameters &parameters,
780 const QLowEnergyAdvertisingData &advertisingData,
781 const QLowEnergyAdvertisingData &scanResponseData)
782{
783 Q_D(QLowEnergyController);
784 if (role() != PeripheralRole) {
785 qCWarning(QT_BT) << "Cannot start advertising in central role" << state();
786 return;
787 }
788 if (state() != UnconnectedState) {
789 qCWarning(QT_BT) << "Cannot start advertising in state" << state();
790 return;
791 }
792 d->startAdvertising(parameters, advertisingData, scanResponseData);
793}
794
795/*!
796 Stops advertising, if this object is currently in the advertising state.
797
798 The controller has to be in the \l PeripheralRole for this function to work.
799 It does not invalidate services which have previously been added via \l addService().
800
801 \since 5.7
802 \sa startAdvertising()
803 */
804void QLowEnergyController::stopAdvertising()
805{
806 Q_D(QLowEnergyController);
807 if (state() != AdvertisingState) {
808 qCDebug(QT_BT) << "stopAdvertising called in state" << state();
809 return;
810 }
811 d->stopAdvertising();
812}
813
814/*!
815 Constructs and returns a \l QLowEnergyService object with \a parent from \a service.
816 The controller must be in the \l PeripheralRole and in the \l UnconnectedState. The \a service
817 object must be valid.
818
819 \note Once the peripheral instance is disconnected from the remote central device or
820 if \l disconnectFromDevice() is manually called, every service definition that was
821 previously added via this function is removed from the peripheral. Therefore this function
822 must be called again before re-advertising this peripheral controller instance. The described
823 behavior is connection specific and therefore not dependent on whether \l stopAdvertising()
824 was called.
825
826 \since 5.7
827 \sa stopAdvertising(), disconnectFromDevice(), QLowEnergyServiceData::addIncludedService
828 */
829QLowEnergyService *QLowEnergyController::addService(const QLowEnergyServiceData &service,
830 QObject *parent)
831{
832 if (role() != PeripheralRole) {
833 qCWarning(QT_BT) << "Services can only be added in the peripheral role";
834 return nullptr;
835 }
836 if (state() != UnconnectedState) {
837 qCWarning(QT_BT) << "Services can only be added in unconnected state";
838 return nullptr;
839 }
840 if (!service.isValid()) {
841 qCWarning(QT_BT) << "Not adding invalid service";
842 return nullptr;
843 }
844
845 Q_D(QLowEnergyController);
846 QLowEnergyService *newService = d->addServiceHelper(service);
847 if (newService)
848 newService->setParent(parent);
849
850 return newService;
851}
852
853
854/*!
855 Requests the controller to update the connection according to \a parameters.
856 If the request is successful, the \l connectionUpdated() signal will be emitted
857 with the actual new parameters. See the \l QLowEnergyConnectionParameters class for more
858 information on connection parameters.
859
860 Android only indirectly permits the adjustment of this parameter set.
861 The connection parameters are separated into three categories (high, low & balanced priority).
862 Each category implies a pre-configured set of values for
863 \l QLowEnergyConnectionParameters::minimumInterval(),
864 \l QLowEnergyConnectionParameters::maximumInterval() and
865 \l QLowEnergyConnectionParameters::latency(). Although the connection request is an asynchronous
866 operation, Android does not provide a callback stating the result of the request. This is
867 an acknowledged Android bug. Due to this bug Android does not emit the \l connectionUpdated()
868 signal.
869
870 \note Currently, this functionality is only implemented on Linux and Android.
871
872 \sa connectionUpdated()
873 \since 5.7
874 */
875void QLowEnergyController::requestConnectionUpdate(const QLowEnergyConnectionParameters &parameters)
876{
877 switch (state()) {
878 case ConnectedState:
879 case DiscoveredState:
880 case DiscoveringState:
881 d_ptr->requestConnectionUpdate(parameters);
882 break;
883 default:
884 qCWarning(QT_BT) << "Connection update request only possible in connected state";
885 }
886}
887
888/*!
889 Returns the last occurred error or \l NoError.
890*/
891QLowEnergyController::Error QLowEnergyController::error() const
892{
893 return d_ptr->error;
894}
895
896/*!
897 Returns a textual representation of the last occurred error.
898 The string is translated.
899*/
900QString QLowEnergyController::errorString() const
901{
902 return d_ptr->errorString;
903}
904
905/*!
906 Returns the role that this controller object is in.
907
908 The role is determined when constructing a QLowEnergyController instance
909 using \l createCentral() or \l createPeripheral().
910
911 \since 5.7
912 */
913QLowEnergyController::Role QLowEnergyController::role() const
914{
915 return d_ptr->role;
916}
917
918QT_END_NAMESPACE
919

source code of qtconnectivity/src/bluetooth/qlowenergycontroller.cpp