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