summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@theqtcompany.com>2016-07-13 14:27:55 +0200
committerAlex Blasche <alexander.blasche@theqtcompany.com>2016-07-13 14:27:55 +0200
commit20949d791463e571bd3a8549933b5b91019f754f (patch)
tree1dcd9c0c3833aeba40f074b8b26da3656868fa54 /src
parentda0973e98ebd0d81523839ea255015c4a2e646a7 (diff)
parent1de888375e3bafb44c9cc8dafce68e2b6b4f7a48 (diff)
Merge remote-tracking branch 'gerrit/dev' into btle
Adds the minimum compile requirements for the new QBluetoothDeviceDiscoveryAgent API. Change-Id: Idfe07bee63de9d2849ab68eb455d0be470591795
Diffstat (limited to 'src')
-rw-r--r--src/bluetooth/bluetooth.pro9
-rw-r--r--src/bluetooth/doc/qtbluetooth.qdocconf1
-rw-r--r--src/bluetooth/doc/src/bluetooth-index.qdoc7
-rw-r--r--src/bluetooth/doc/src/bluetooth-le-overview.qdoc56
-rw-r--r--src/bluetooth/lecmaccalculator.cpp2
-rw-r--r--src/bluetooth/osx/osxbtledeviceinquiry.mm145
-rw-r--r--src/bluetooth/osx/osxbtledeviceinquiry_p.h31
-rw-r--r--src/bluetooth/osx/osxbtnotifier_p.h6
-rw-r--r--src/bluetooth/osx/osxbtutility.mm7
-rw-r--r--src/bluetooth/osx/osxbtutility_p.h16
-rw-r--r--src/bluetooth/qbluetooth.cpp1
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent.cpp114
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent.h17
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp20
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp28
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm191
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm215
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp12
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_p.h4
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp8
-rw-r--r--src/bluetooth/qbluetoothdevicediscoverytimer_osx_p.h85
-rw-r--r--src/bluetooth/qlowenergycontroller.cpp23
-rw-r--r--src/bluetooth/qlowenergycontroller_osx.mm4
-rw-r--r--src/bluetooth/qlowenergyservice.cpp1
24 files changed, 581 insertions, 422 deletions
diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro
index b4beda67..b2b7f54c 100644
--- a/src/bluetooth/bluetooth.pro
+++ b/src/bluetooth/bluetooth.pro
@@ -109,6 +109,7 @@ config_bluez:qtHaveModule(dbus) {
message("Bluez version is too old to support Bluetooth Low Energy.")
message("Only classic Bluetooth will be available.")
DEFINES += QT_BLUEZ_NO_BTLE
+ include(dummy/dummy.pri)
SOURCES += \
qlowenergycontroller_p.cpp
}
@@ -152,14 +153,10 @@ config_bluez:qtHaveModule(dbus) {
qlowenergycontroller_osx.mm \
qlowenergyservice_osx.mm
- SOURCES += \
- qlowenergycontroller_p.cpp
-
PRIVATE_HEADERS += qbluetoothsocket_osx_p.h \
qbluetoothserver_osx_p.h \
qbluetoothtransferreply_osx_p.h \
qbluetoothtransferreply_osx_p.h \
- qbluetoothdevicediscoverytimer_osx_p.h \
qlowenergycontroller_osx_p.h
SOURCES -= qbluetoothdevicediscoveryagent.cpp
@@ -181,12 +178,10 @@ config_bluez:qtHaveModule(dbus) {
qlowenergyservice_osx.mm
PRIVATE_HEADERS += \
- qlowenergycontroller_osx_p.h \
- qbluetoothdevicediscoverytimer_osx_p.h
+ qlowenergycontroller_osx_p.h
include(osx/osxbt.pri)
SOURCES += \
- qbluetoothdevicediscoveryagent_p.cpp \
qbluetoothlocaldevice_p.cpp \
qbluetoothserviceinfo_p.cpp \
qbluetoothservicediscoveryagent_p.cpp \
diff --git a/src/bluetooth/doc/qtbluetooth.qdocconf b/src/bluetooth/doc/qtbluetooth.qdocconf
index 52061d7e..aa485cdb 100644
--- a/src/bluetooth/doc/qtbluetooth.qdocconf
+++ b/src/bluetooth/doc/qtbluetooth.qdocconf
@@ -47,6 +47,7 @@ exampledirs += ../../../examples/bluetooth \
snippets/ \
../
+manifestmeta.thumbnail.names = "QtBluetooth/Bluetooth Low Energy Heart Rate Server Example"
imagedirs += images
diff --git a/src/bluetooth/doc/src/bluetooth-index.qdoc b/src/bluetooth/doc/src/bluetooth-index.qdoc
index 51c79ca4..f110179f 100644
--- a/src/bluetooth/doc/src/bluetooth-index.qdoc
+++ b/src/bluetooth/doc/src/bluetooth-index.qdoc
@@ -45,10 +45,13 @@ for transferring data between devices. Bluetooth connectivity is based on
basic device management, such as scanning for devices, gathering information
about them, and exchanging data between them.
-Qt 5.5 contains the first full release of the new Qt Bluetooth
-Low Energy API. Further details can be found in the
+Qt Bluetooth supports Bluetooth Low Energy development for client/central role use cases.
+Further details can be found in the
\l {Bluetooth Low Energy Overview}{Bluetooth Low Energy Overview} section.
+A new addition in this Qt Bluetooth 5.7 release covers support for Bluetooth Low Energy
+applications performing the peripheral/server role. This new API is a Technology Preview.
+
\section1 Getting Started
To use the C++ library in your application, add the following configuration
diff --git a/src/bluetooth/doc/src/bluetooth-le-overview.qdoc b/src/bluetooth/doc/src/bluetooth-le-overview.qdoc
index a6b8defa..8e78c487 100644
--- a/src/bluetooth/doc/src/bluetooth-le-overview.qdoc
+++ b/src/bluetooth/doc/src/bluetooth-le-overview.qdoc
@@ -168,19 +168,6 @@ Low Energy devices.
The example code below is taken from the \l {heartlistener}{Heart Listener} and
\l {heartrate-server}{Heart Rate Server} examples.
- \section2 Advertising Services
-
- If we are implementing a GATT server application on a peripheral device, we need to define the
- services we want to offer to central devices and advertise them:
-
- \snippet heartrate-server/main.cpp Advertising Data
- \snippet heartrate-server/main.cpp Start Advertising
- \snippet heartrate-server/main.cpp Advertising Data
-
- Now potential clients can connect to our device, discover the provided service and
- register themselves to get notified of changes to the characteristic value.
- This part of the API is covered in the following sections.
-
\section2 Establishing a Connection
To be able to read and write the characteristics of the Bluetooth Low Energy peripheral device,
@@ -257,4 +244,47 @@ Low Energy devices.
\l {https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx}{Bluetooth SIG} whereas others
may follow a custom protocol. The above code snippet demonstrates how to the read the standardized
HeartRate value.
+
+ \section2 Advertising Services
+
+ If we are implementing a GATT server application on a peripheral device, we need to define the
+ services we want to offer to central devices and advertise them:
+
+ \snippet heartrate-server/main.cpp Advertising Data
+ \snippet heartrate-server/main.cpp Start Advertising
+
+ Now potential clients can connect to our device, discover the provided service and
+ register themselves to get notified of changes to the characteristic value.
+ This part of the API was already covered by the above sections.
+
+ \section2 Implementing a Service on the Peripheral Device
+
+ The first step is to define the service, its characteristics and descriptors. This is achieved
+ using the \l QLowEnergyServiceData, \l QLowEnergyCharacteristicData and
+ \l QLowEnergyDescriptorData classes. These classes act as containers or building blocks for the
+ essential information that comprises the to-be-defined Bluetooth Low Energy service.
+ The code snippet below defines a simple HeartRate service which publishes
+ the measured beats per minute. An example where such a service could be used is a wrist watch.
+
+ \snippet heartrate-server/main.cpp Service Data
+
+ The resulting \c serviceData object can be published as described in the
+ \l {Advertising Services} section above. Despite the partial information overlap between the
+ information wrapped by \l QLowEnergyServiceData and \l QLowEnergyAdvertisingData the two classes
+ serve two very different tasks. The advertising data is published to nearby devices and often
+ limited in scope due to its size restriction of 29 bytes. Therefore they are not always 100%
+ complete. By comparison the service data contained inside of \l QLowEnergyServiceData provides
+ the complete set of service data and only becomes visible to the connecting client when a
+ connection with an active service discovery has been performed.
+
+ The next section demonstrates how the service can update the heart rate value. Depending on the
+ nature of the service it may have to comply with the official service definition
+ as defined on \l {https://www.bluetooth.org}. Other services may be completely custom. The
+ heart rate service was adopted and its specification can be found under
+ \l {https://www.bluetooth.com/specifications/adopted-specifications}.
+
+ \snippet heartrate-server/main.cpp Provide Heartbeat
+
+ In general characteristic and descriptor value updates on the peripheral device use the same
+ methods as connecting Bluetooth Low Energy devices.
*/
diff --git a/src/bluetooth/lecmaccalculator.cpp b/src/bluetooth/lecmaccalculator.cpp
index 1cda9576..47fef7df 100644
--- a/src/bluetooth/lecmaccalculator.cpp
+++ b/src/bluetooth/lecmaccalculator.cpp
@@ -72,7 +72,7 @@ LeCmacCalculator::LeCmacCalculator()
sa.salg_family = AF_ALG;
strcpy(reinterpret_cast<char *>(sa.salg_type), "hash");
strcpy(reinterpret_cast<char *>(sa.salg_name), "cmac(aes)");
- if (bind(m_baseSocket, reinterpret_cast<sockaddr *>(&sa), sizeof sa) == -1) {
+ if (::bind(m_baseSocket, reinterpret_cast<sockaddr *>(&sa), sizeof sa) == -1) {
qCWarning(QT_BT_BLUEZ) << "bind() failed for crypto socket:" << strerror(errno);
return;
}
diff --git a/src/bluetooth/osx/osxbtledeviceinquiry.mm b/src/bluetooth/osx/osxbtledeviceinquiry.mm
index 58cecccc..7f522c14 100644
--- a/src/bluetooth/osx/osxbtledeviceinquiry.mm
+++ b/src/bluetooth/osx/osxbtledeviceinquiry.mm
@@ -39,6 +39,7 @@
#include "osxbtledeviceinquiry_p.h"
#include "qbluetoothdeviceinfo.h"
+#include "osxbtnotifier_p.h"
#include "qbluetoothuuid.h"
#include "osxbtutility_p.h"
@@ -47,6 +48,8 @@
#include "corebluetoothwrapper_p.h"
+#include <algorithm>
+
QT_BEGIN_NAMESPACE
namespace OSXBluetooth {
@@ -63,30 +66,35 @@ QBluetoothUuid qt_uuid(NSUUID *nsUuid)
return QBluetoothUuid(qtUuidData);
}
-}
+const int timeStepMS = 100;
+const int powerOffTimeoutMS = 30000;
+const qreal powerOffTimeStepS = 30. / 100.;
-QT_END_NAMESPACE
-
-#ifdef QT_NAMESPACE
+}
-using namespace QT_NAMESPACE;
+QT_END_NAMESPACE
-#endif
+QT_USE_NAMESPACE
@interface QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry) (PrivateAPI) <CBCentralManagerDelegate>
+// These two methods are scheduled with a small time step
+// within a given timeout, they either re-schedule
+// themselves or emit a signal/stop some operation.
- (void)stopScan;
- (void)handlePoweredOff;
@end
@implementation QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry)
-- (id)init
+-(id)initWithNotifier:(LECBManagerNotifier *)aNotifier
{
if (self = [super init]) {
+ Q_ASSERT(aNotifier);
+ notifier = aNotifier;
uuids.reset([[NSMutableSet alloc] init]);
internalState = InquiryStarting;
- state.store(int(internalState));
+ inquiryTimeoutMS = OSXBluetooth::defaultLEScanTimeoutMS;
}
return self;
@@ -100,27 +108,36 @@ using namespace QT_NAMESPACE;
[manager stopScan];
}
+ if (notifier) {
+ notifier->disconnect();
+ notifier->deleteLater();
+ }
+
[super dealloc];
}
- (void)stopScan
{
- // Scan's "timeout" - we consider LE device
- // discovery finished.
using namespace OSXBluetooth;
+ // We never schedule stopScan if there is no timeout:
+ Q_ASSERT(inquiryTimeoutMS > 0);
+
if (internalState == InquiryActive) {
- if (scanTimer.elapsed() >= qt_LE_deviceInquiryLength() * 1000) {
- // We indeed stop now:
+ const int elapsed = scanTimer.elapsed();
+ if (elapsed >= inquiryTimeoutMS) {
[manager stopScan];
[manager setDelegate:nil];
internalState = InquiryFinished;
- state.store(int(internalState));
+ Q_ASSERT(notifier);
+ emit notifier->discoveryFinished();
} else {
+ // Re-schedule 'stopScan':
dispatch_queue_t leQueue(qt_LE_queue());
Q_ASSERT(leQueue);
+ const int timeChunkMS = std::min(inquiryTimeoutMS - elapsed, timeStepMS);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
- int64_t(qt_LE_deviceInquiryLength() / 100. * NSEC_PER_SEC)),
+ int64_t(timeChunkMS / 1000. * NSEC_PER_SEC)),
leQueue,
^{
[self stopScan];
@@ -135,30 +152,32 @@ using namespace QT_NAMESPACE;
// the system shows an alert asking to enable
// Bluetooth in the 'Settings' app. If not done yet (after 30
// seconds) - we consider it an error.
+ using namespace OSXBluetooth;
+
if (internalState == InquiryStarting) {
- if (errorTimer.elapsed() >= 30000) {
+ if (errorTimer.elapsed() >= powerOffTimeoutMS) {
[manager setDelegate:nil];
internalState = ErrorPoweredOff;
- state.store(int(internalState));
+ Q_ASSERT(notifier);
+ emit notifier->CBManagerError(QBluetoothDeviceDiscoveryAgent::PoweredOffError);
} else {
- dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
+ dispatch_queue_t leQueue(qt_LE_queue());
Q_ASSERT(leQueue);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
- (int64_t)(30 / 100. * NSEC_PER_SEC)),
+ (int64_t)(powerOffTimeStepS * NSEC_PER_SEC)),
leQueue,
^{
[self handlePoweredOff];
});
-
}
}
}
-- (void)start
+- (void)startWithTimeout:(int)timeout
{
dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
-
Q_ASSERT(leQueue);
+ inquiryTimeoutMS = timeout;
manager.reset([[CBCentralManager alloc] initWithDelegate:self queue:leQueue]);
}
@@ -170,6 +189,8 @@ using namespace QT_NAMESPACE;
if (internalState != InquiryActive && internalState != InquiryStarting)
return;
+ Q_ASSERT(notifier);
+
using namespace OSXBluetooth;
dispatch_queue_t leQueue(qt_LE_queue());
@@ -179,39 +200,50 @@ using namespace QT_NAMESPACE;
if (cbState == CBCentralManagerStatePoweredOn) {
if (internalState == InquiryStarting) {
internalState = InquiryActive;
- // Scan time is actually 10 seconds. Having a block with such delay can prevent
- // 'self' from being deleted in time, which is not good. So we split this
- // 10 s. timeout into smaller 'chunks'.
- scanTimer.start();
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
- int64_t(qt_LE_deviceInquiryLength() / 100. * NSEC_PER_SEC)),
- leQueue,
- ^{
- [self stopScan];
- });
+
+ if (inquiryTimeoutMS > 0) {
+ // We have a finite-length discovery, schedule stopScan,
+ // with a smaller time step, otherwise it can prevent
+ // 'self' from being deleted in time, which is not good
+ // (the block will retain 'self', waiting for timeout).
+ scanTimer.start();
+ const int timeChunkMS = std::min(timeStepMS, inquiryTimeoutMS);
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
+ int64_t(timeChunkMS / 1000. * NSEC_PER_SEC)),
+ leQueue,
+ ^{
+ [self stopScan];
+ });
+ }
+
[manager scanForPeripheralsWithServices:nil options:nil];
} // Else we ignore.
- } else if (state == CBCentralManagerStateUnsupported || state == CBCentralManagerStateUnauthorized) {
+ } else if (cbState == CBCentralManagerStateUnsupported
+ || cbState == CBCentralManagerStateUnauthorized) {
if (internalState == InquiryActive) {
[manager stopScan];
- // Not sure how this is possible at all, probably, can never happen.
+ // Not sure how this is possible at all,
+ // probably, can never happen.
internalState = ErrorPoweredOff;
+ emit notifier->CBManagerError(QBluetoothDeviceDiscoveryAgent::PoweredOffError);
} else {
internalState = ErrorLENotSupported;
+ emit notifier->LEnotSupported();
}
[manager setDelegate:nil];
} else if (cbState == CBCentralManagerStatePoweredOff) {
if (internalState == InquiryStarting) {
#ifndef Q_OS_OSX
- // On iOS a user can see at this point an alert asking to enable
- // Bluetooth in the "Settings" app. If a user does,
+ // On iOS a user can see at this point an alert asking to
+ // enable Bluetooth in the "Settings" app. If a user does,
// we'll receive 'PoweredOn' state update later.
- // No change in state. Wait for 30 seconds (we split it into 'chunks' not
- // to retain 'self' for too long ) ...
+ // No change in internalState. Wait for 30 seconds
+ // (we split it into smaller steps not to retain 'self' for
+ // too long ) ...
errorTimer.start();
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
- (int64_t)(30 / 100. * NSEC_PER_SEC)),
+ (int64_t)(powerOffTimeStepS * NSEC_PER_SEC)),
leQueue,
^{
[self handlePoweredOff];
@@ -219,9 +251,10 @@ using namespace QT_NAMESPACE;
return;
#endif
internalState = ErrorPoweredOff;
+ emit notifier->CBManagerError(QBluetoothDeviceDiscoveryAgent::PoweredOffError);
} else {
- internalState = ErrorPoweredOff;
[manager stopScan];
+ emit notifier->CBManagerError(QBluetoothDeviceDiscoveryAgent::PoweredOffError);
}
[manager setDelegate:nil];
@@ -237,8 +270,6 @@ using namespace QT_NAMESPACE;
// lost; an update is imminent. "
// Wait for this imminent update.
}
-
- state.store(int(internalState));
}
- (void)stop
@@ -248,11 +279,16 @@ using namespace QT_NAMESPACE;
[manager setDelegate:nil];
internalState = InquiryCancelled;
- state.store(int(internalState));
+
+ notifier->disconnect();
+ notifier->deleteLater();
+ notifier = nullptr;
}
-- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral
- advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
+- (void)centralManager:(CBCentralManager *)central
+ didDiscoverPeripheral:(CBPeripheral *)peripheral
+ advertisementData:(NSDictionary *)advertisementData
+ RSSI:(NSNumber *)RSSI
{
Q_UNUSED(advertisementData);
@@ -264,9 +300,10 @@ using namespace QT_NAMESPACE;
if (internalState != InquiryActive)
return;
- QBluetoothUuid deviceUuid;
-
+ if (!notifier)
+ return;
+ QBluetoothUuid deviceUuid;
if (!peripheral.identifier) {
qCWarning(QT_BT_OSX) << "peripheral without NSUUID";
@@ -274,7 +311,9 @@ using namespace QT_NAMESPACE;
}
if ([uuids containsObject:peripheral.identifier]) {
- // We already know this peripheral ...
+ // TODO: my understanding of the same peripheral reported many times seems
+ // to be outdated or even wrong - nowadays it's reported twice and the
+ // second time (AFAIK) more info can be extracted ...
return;
}
@@ -296,17 +335,7 @@ using namespace QT_NAMESPACE;
newDeviceInfo.setRssi([RSSI shortValue]);
// CoreBluetooth scans only for LE devices.
newDeviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration);
- devices.append(newDeviceInfo);
-}
-
-- (LEInquiryState) inquiryState
-{
- return LEInquiryState(state.load());
-}
-
-- (const QList<QBluetoothDeviceInfo> &)discoveredDevices
-{
- return devices;
+ emit notifier->deviceDiscovered(newDeviceInfo);
}
@end
diff --git a/src/bluetooth/osx/osxbtledeviceinquiry_p.h b/src/bluetooth/osx/osxbtledeviceinquiry_p.h
index 24bf181e..d79272be 100644
--- a/src/bluetooth/osx/osxbtledeviceinquiry_p.h
+++ b/src/bluetooth/osx/osxbtledeviceinquiry_p.h
@@ -57,7 +57,6 @@
#include <QtCore/qelapsedtimer.h>
#include <QtCore/qglobal.h>
-#include <QtCore/qatomic.h>
#include <QtCore/qlist.h>
#include <Foundation/Foundation.h>
@@ -69,8 +68,20 @@ QT_BEGIN_NAMESPACE
class QBluetoothUuid;
+namespace OSXBluetooth
+{
+
+class LECBManagerNotifier;
+
+}
+
QT_END_NAMESPACE
+// Ugly but all these QT_PREPEND_NAMESPACE etc. are even worse ...
+using OSXBluetooth::LECBManagerNotifier;
+using OSXBluetooth::ObjCScopedPointer;
+using QT_PREPEND_NAMESPACE(QElapsedTimer);
+
enum LEInquiryState
{
InquiryStarting,
@@ -83,29 +94,27 @@ enum LEInquiryState
@interface QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry) : NSObject
{
- QT_PREPEND_NAMESPACE(OSXBluetooth)::ObjCScopedPointer<NSMutableSet> uuids;
- QT_PREPEND_NAMESPACE(OSXBluetooth)::ObjCScopedPointer<CBCentralManager> manager;
+ LECBManagerNotifier *notifier;
+ ObjCScopedPointer<NSMutableSet> uuids;
+ ObjCScopedPointer<CBCentralManager> manager;
QList<QBluetoothDeviceInfo> devices;
-
LEInquiryState internalState;
- QT_PREPEND_NAMESPACE(QAtomicInt) state;
+ int inquiryTimeoutMS;
// Timers to check if we can execute delayed callbacks:
QT_PREPEND_NAMESPACE(QElapsedTimer) errorTimer;
QT_PREPEND_NAMESPACE(QElapsedTimer) scanTimer;
}
-- (id)init;
+- (id)initWithNotifier:(LECBManagerNotifier *)aNotifier;
- (void)dealloc;
-// IMPORTANT: both 'start' and 'stop' are to be executed on the "Qt's LE queue".
-- (void)start;
+// IMPORTANT: both 'startWithTimeout' and 'stop'
+// can be executed only on the "Qt's LE queue".
+- (void)startWithTimeout:(int)timeout;
- (void)stop;
-- (LEInquiryState)inquiryState;
-- (const QList<QBluetoothDeviceInfo> &)discoveredDevices;
-
@end
#endif
diff --git a/src/bluetooth/osx/osxbtnotifier_p.h b/src/bluetooth/osx/osxbtnotifier_p.h
index 3059e2d3..0ffd7f51 100644
--- a/src/bluetooth/osx/osxbtnotifier_p.h
+++ b/src/bluetooth/osx/osxbtnotifier_p.h
@@ -52,7 +52,9 @@
//
+#include "qbluetoothdevicediscoveryagent.h"
#include "qlowenergycontroller.h"
+#include "qbluetoothdeviceinfo.h"
#include "qbluetoothuuid.h"
#include "qbluetooth.h"
@@ -73,6 +75,9 @@ class LECBManagerNotifier : public QObject
Q_OBJECT
Q_SIGNALS:
+ void deviceDiscovered(QBluetoothDeviceInfo deviceInfo);
+ void discoveryFinished();
+
void connected();
void disconnected();
@@ -85,6 +90,7 @@ Q_SIGNALS:
void descriptorWritten(QLowEnergyHandle descHandle, const QByteArray &value);
void LEnotSupported();
+ void CBManagerError(QBluetoothDeviceDiscoveryAgent::Error error);
void CBManagerError(QLowEnergyController::Error error);
void CBManagerError(const QBluetoothUuid &serviceUuid, QLowEnergyController::Error error);
void CBManagerError(const QBluetoothUuid &serviceUuid, QLowEnergyService::ServiceError error);
diff --git a/src/bluetooth/osx/osxbtutility.mm b/src/bluetooth/osx/osxbtutility.mm
index f579b2a4..29159cdb 100644
--- a/src/bluetooth/osx/osxbtutility.mm
+++ b/src/bluetooth/osx/osxbtutility.mm
@@ -68,6 +68,8 @@ Q_LOGGING_CATEGORY(QT_BT_OSX, "qt.bluetooth.ios")
namespace OSXBluetooth {
+const int defaultLEScanTimeoutMS = 25000;
+
QString qt_address(NSString *address)
{
if (address && address.length) {
@@ -348,11 +350,6 @@ dispatch_queue_t qt_LE_queue()
return leQueue.data();
}
-unsigned qt_LE_deviceInquiryLength()
-{
- return 10;
-}
-
}
QT_END_NAMESPACE
diff --git a/src/bluetooth/osx/osxbtutility_p.h b/src/bluetooth/osx/osxbtutility_p.h
index 5e616b74..28ecfec9 100644
--- a/src/bluetooth/osx/osxbtutility_p.h
+++ b/src/bluetooth/osx/osxbtutility_p.h
@@ -53,7 +53,6 @@
#include <QtCore/qloggingcategory.h>
#include <QtCore/qscopedpointer.h>
-#include <QtCore/qsysinfo.h>
#include <QtCore/qglobal.h>
#include <Foundation/Foundation.h>
@@ -302,20 +301,9 @@ QByteArray qt_bytearray(NSData *data);
QByteArray qt_bytearray(NSObject *data);
ObjCStrongReference<NSData> data_from_bytearray(const QByteArray & qtData);
-inline QSysInfo::MacVersion qt_OS_limit(QSysInfo::MacVersion osxVersion, QSysInfo::MacVersion iosVersion)
-{
-#ifdef Q_OS_OSX
- Q_UNUSED(iosVersion)
- return osxVersion;
-#else
- Q_UNUSED(osxVersion)
- return iosVersion;
-#endif
-}
-
dispatch_queue_t qt_LE_queue();
-// LE scan, in seconds.
-unsigned qt_LE_deviceInquiryLength();
+
+extern const int defaultLEScanTimeoutMS;
} // namespace OSXBluetooth
diff --git a/src/bluetooth/qbluetooth.cpp b/src/bluetooth/qbluetooth.cpp
index f83f92c9..37a4774d 100644
--- a/src/bluetooth/qbluetooth.cpp
+++ b/src/bluetooth/qbluetooth.cpp
@@ -76,6 +76,7 @@ namespace QBluetooth {
/*!
\enum QBluetooth::AttAccessConstraint
+ \since 5.7
This enum describes the possible requirements for reading or writing an ATT attribute.
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent.cpp
index b6faee75..3dbbc9e3 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent.cpp
@@ -40,9 +40,12 @@
#include "qbluetoothdevicediscoveryagent.h"
#include "qbluetoothdevicediscoveryagent_p.h"
+#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QT_BT)
+
/*!
\class QBluetoothDeviceDiscoveryAgent
\inmodule QtBluetooth
@@ -88,6 +91,8 @@ QT_BEGIN_NAMESPACE
platform. The error is set in response to a call to \l start().
An example for such cases are iOS versions below 5.0 which do not support
Bluetooth device search at all. This value was introduced by Qt 5.5.
+ \value UnsupportedDiscoveryMethod One of the requested discovery methods is not supported by
+ the current platform. This value was introduced by Qt 5.8.
\value UnknownError An unknown error has occurred.
*/
@@ -110,6 +115,22 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \enum QBluetoothDeviceDiscoveryAgent::DiscoveryMethod
+
+ This enum descibes the type of discovery method employed by the QBluetoothDeviceDiscoveryAgent.
+
+ \value NoMethod The discovery is not possible. None of the available
+ methods are supported.
+ \value ClassicMethod The discovery process searches for Bluetooth Classic
+ (BaseRate) devices.
+ \value LowEnergyMethod The discovery process searches for Bluetooth Low Energy
+ devices.
+
+ \sa supportedDiscoveryMethods()
+ \since 5.8
+*/
+
+/*!
\fn void QBluetoothDeviceDiscoveryAgent::deviceDiscovered(const QBluetoothDeviceInfo &info)
This signal is emitted when the Bluetooth device described by \a info is discovered.
@@ -232,16 +253,105 @@ QList<QBluetoothDeviceInfo> QBluetoothDeviceDiscoveryAgent::discoveredDevices()
}
/*!
+ Sets the maximum search time for Bluetooth Low Energy device search to
+ \a timeout in milliseconds. If \a timeout is \c 0 the discovery runs
+ until \l stop() is called.
+
+ This reflects the fact that the discovery process for Bluetooth Low Energy devices
+ is mostly open ended. The platform continues to look for more devices until the search is
+ manually stopped. The timeout ensures that the search is aborted after \a timeout milliseconds.
+ Of course, it is still possible to manually abort the discovery by calling \l stop().
+
+ The new timeout value does not take effect until the device search is restarted.
+ In addition the timeout does not affect the classic Bluetooth device search. Depending on
+ the platform the classic search may add more time to the total discovery process
+ beyond \a timeout.
+
+ \sa lowEnergyDiscoveryTimeout()
+ \since 5.8
+ */
+void QBluetoothDeviceDiscoveryAgent::setLowEnergyDiscoveryTimeout(int timeout)
+{
+ Q_D(QBluetoothDeviceDiscoveryAgent);
+
+ // cannot deliberately turn it off
+ if (d->lowEnergySearchTimeout < 0 || timeout < 0) {
+ qCDebug(QT_BT) << "The Bluetooth Low Energy device discovery timeout cannot be negative "
+ "or set on a backend which does not support this feature.";
+ return;
+ }
+
+ d->lowEnergySearchTimeout = timeout;
+}
+
+/*!
+ Returns a timeout in milliseconds that is applied to the Bluetooth Low Energy device search.
+ A value of \c -1 implies that the platform does not support this property and the timeout for
+ the device search cannot be adjusted. A return value of \c 0
+ implies a never-ending search which must be manually stopped via \l stop().
+
+ \sa setLowEnergyDiscoveryTimeout()
+ \since 5.8
+ */
+int QBluetoothDeviceDiscoveryAgent::lowEnergyDiscoveryTimeout() const
+{
+ Q_D(const QBluetoothDeviceDiscoveryAgent);
+ return d->lowEnergySearchTimeout;
+}
+
+/*!
+ \fn QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods()
+
+ This function returns the discovery methods supported by the current platform.
+ It can be used to limit the scope of the device discovery.
+
+ \since 5.8
+*/
+
+/*!
Starts Bluetooth device discovery, if it is not already started.
The deviceDiscovered() signal is emitted as each device is discovered. The finished() signal
- is emitted once device discovery is complete.
+ is emitted once device discovery is complete. The discovery utilizes the maximum set of
+ supported discovery methods on the platform.
+
+ \sa supportedDiscoveryMethods()
*/
void QBluetoothDeviceDiscoveryAgent::start()
{
Q_D(QBluetoothDeviceDiscoveryAgent);
if (!isActive() && d->lastError != InvalidBluetoothAdapterError)
- d->start();
+ d->start(supportedDiscoveryMethods());
+}
+
+/*!
+ Start Bluetooth device discovery, if it is not already started and the provided
+ \a methods are supported.
+ The discovery \a methods limit the scope of the device search.
+ For example, if the target service or device is a Bluetooth Low Energy device,
+ this function could be used to limit the search to Bluetooth Low Energy devices and
+ thereby reduces the discovery time significantly.
+
+ \since 5.8
+*/
+void QBluetoothDeviceDiscoveryAgent::start(DiscoveryMethods methods)
+{
+ if (methods == NoMethod)
+ return;
+
+ DiscoveryMethods supported =
+ QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods();
+
+ Q_D(QBluetoothDeviceDiscoveryAgent);
+ if (!((supported & methods) == methods)) {
+ d->lastError = UnsupportedDiscoveryMethod;
+ d->errorString = QBluetoothDeviceDiscoveryAgent::tr("One or more device discovery methods "
+ "are not supported on this platform");
+ emit error(d->lastError);
+ }
+
+ if (!isActive() && d->lastError != InvalidBluetoothAdapterError)
+ d->start(methods);
}
/*!
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent.h b/src/bluetooth/qbluetoothdevicediscoveryagent.h
index 954ae704..84087605 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent.h
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent.h
@@ -65,6 +65,7 @@ public:
PoweredOffError,
InvalidBluetoothAdapterError,
UnsupportedPlatformError,
+ UnsupportedDiscoveryMethod,
UnknownError = 100 // New errors must be added before Unknown error
};
Q_ENUM(Error)
@@ -75,6 +76,15 @@ public:
};
Q_ENUM(InquiryType)
+ enum DiscoveryMethod
+ {
+ NoMethod = 0x0,
+ ClassicMethod = 0x01,
+ LowEnergyMethod = 0x02,
+ };
+ Q_DECLARE_FLAGS(DiscoveryMethods, DiscoveryMethod)
+ Q_FLAG(DiscoveryMethods)
+
explicit QBluetoothDeviceDiscoveryAgent(QObject *parent = Q_NULLPTR);
explicit QBluetoothDeviceDiscoveryAgent(const QBluetoothAddress &deviceAdapter,
QObject *parent = Q_NULLPTR);
@@ -91,8 +101,13 @@ public:
QList<QBluetoothDeviceInfo> discoveredDevices() const;
+ void setLowEnergyDiscoveryTimeout(int msTimeout);
+ int lowEnergyDiscoveryTimeout() const;
+
+ static DiscoveryMethods supportedDiscoveryMethods();
public Q_SLOTS:
void start();
+ void start(DiscoveryMethods method);
void stop();
Q_SIGNALS:
@@ -116,6 +131,8 @@ private:
#endif
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods)
+
QT_END_NAMESPACE
#endif
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp
index 5f163dfd..e3421e08 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp
@@ -66,6 +66,7 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(
leScanTimeout(0),
pendingCancel(false),
pendingStart(false),
+ lowEnergySearchTimeout(25000),
q_ptr(parent)
{
adapter = QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter",
@@ -93,8 +94,16 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
return m_active != NoScanActive;
}
-void QBluetoothDeviceDiscoveryAgentPrivate::start()
+QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods()
{
+ return (LowEnergyMethod | ClassicMethod);
+}
+
+void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
+{
+ //TODO Implement discovery method handling (see input parameter)
+ requestedMethods = methods;
+
if (pendingCancel) {
pendingStart = true;
return;
@@ -192,7 +201,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::processSdpDiscoveryFinished()
emit q->canceled();
} else if (pendingStart) {
pendingStart = pendingCancel = false;
- start();
+ start(requestedMethods);
} else {
// check that it didn't finish due to turned off Bluetooth Device
const int state = adapter.callMethod<jint>("getState");
@@ -278,15 +287,18 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startLowEnergyScan()
return;
}
+ // wait interval and sum up what was found
if (!leScanTimeout) {
leScanTimeout = new QTimer(this);
leScanTimeout->setSingleShot(true);
- leScanTimeout->setInterval(25000);
connect(leScanTimeout, &QTimer::timeout,
this, &QBluetoothDeviceDiscoveryAgentPrivate::stopLowEnergyScan);
}
- leScanTimeout->start();
+ if (lowEnergySearchTimeout > 0) { // otherwise no timeout and stop() required
+ leScanTimeout->setInterval(lowEnergySearchTimeout);
+ leScanTimeout->start();
+ }
}
void QBluetoothDeviceDiscoveryAgentPrivate::stopLowEnergyScan()
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp
index 0243d31f..5288eaf8 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp
@@ -68,10 +68,12 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(
adapterBluez5(0),
discoveryTimer(0),
useExtendedDiscovery(false),
+ lowEnergySearchTimeout(-1), // remains -1 on BlueZ 4 -> timeout not supported
q_ptr(parent)
{
Q_Q(QBluetoothDeviceDiscoveryAgent);
if (isBluez5()) {
+ lowEnergySearchTimeout = 20000;
managerBluez5 = new OrgFreedesktopDBusObjectManagerInterface(
QStringLiteral("org.bluez"),
QStringLiteral("/"),
@@ -115,8 +117,17 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
return (adapter || adapterBluez5);
}
-void QBluetoothDeviceDiscoveryAgentPrivate::start()
+QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods()
{
+ return (ClassicMethod | LowEnergyMethod);
+}
+
+void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods /*methods*/)
+{
+ // Currently both BlueZ backends do not distinguish discovery methods.
+ // The DBus API's always return both device types. Therefore we ignore
+ // the passed in methods.
+
if (pendingCancel == true) {
pendingStart = true;
return;
@@ -273,16 +284,18 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startBluez5()
}
}
- // wait 20s and sum up what was found
+ // wait interval and sum up what was found
if (!discoveryTimer) {
discoveryTimer = new QTimer(q);
discoveryTimer->setSingleShot(true);
- discoveryTimer->setInterval(20000); // 20s
QObject::connect(discoveryTimer, SIGNAL(timeout()),
q, SLOT(_q_discoveryFinished()));
}
- discoveryTimer->start();
+ if (lowEnergySearchTimeout > 0) { // otherwise no timeout and stop() required
+ discoveryTimer->setInterval(lowEnergySearchTimeout);
+ discoveryTimer->start();
+ }
}
void QBluetoothDeviceDiscoveryAgentPrivate::stop()
@@ -436,7 +449,9 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_propertyChanged(const QString &na
pendingStart = false;
pendingCancel = false;
- start();
+ // start parameter ignored since Bluez 4 doesn't distinguish them
+ start(QBluetoothDeviceDiscoveryAgent::ClassicMethod
+ | QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
} else {
// happens when agent is created while other agent called StopDiscovery()
if (!adapter)
@@ -514,7 +529,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_discoveryFinished()
} else if (pendingStart) {
pendingStart = false;
pendingCancel = false;
- start();
+ start(QBluetoothDeviceDiscoveryAgent::ClassicMethod
+ | QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
} else {
emit q->finished();
}
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm b/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm
index 0e4b460f..6d41ebf0 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm
@@ -37,16 +37,17 @@
**
****************************************************************************/
-#include "qbluetoothdevicediscoverytimer_osx_p.h"
#include "qbluetoothdevicediscoveryagent.h"
#include "osx/osxbtledeviceinquiry_p.h"
#include "qbluetoothlocaldevice.h"
#include "qbluetoothdeviceinfo.h"
+#include "osx/osxbtnotifier_p.h"
#include "osx/osxbtutility_p.h"
#include "osx/uistrings_p.h"
#include "qbluetoothuuid.h"
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qobject.h>
#include <QtCore/qglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qdebug.h>
@@ -56,12 +57,24 @@
QT_BEGIN_NAMESPACE
-using OSXBluetooth::ObjCScopedPointer;
+namespace
+{
+
+void registerQDeviceDiscoveryMetaType()
+{
+ static bool initDone = false;
+ if (!initDone) {
+ qRegisterMetaType<QBluetoothDeviceInfo>();
+ qRegisterMetaType<QBluetoothDeviceDiscoveryAgent::Error>();
+ initDone = true;
+ }
+}
+
+}//namespace
-class QBluetoothDeviceDiscoveryAgentPrivate
+class QBluetoothDeviceDiscoveryAgentPrivate : public QObject
{
friend class QBluetoothDeviceDiscoveryAgent;
- friend class OSXBluetooth::DDATimerHandler;
public:
QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress &address,
@@ -70,17 +83,16 @@ public:
bool isActive() const;
- void start();
+ void start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods m);
void stop();
private:
- typedef QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry) LEDeviceInquiryObjC;
+ using LEDeviceInquiryObjC = QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry);
void LEinquiryError(QBluetoothDeviceDiscoveryAgent::Error error);
void LEnotSupported();
void LEdeviceFound(const QBluetoothDeviceInfo &info);
void LEinquiryFinished();
- void checkLETimeout();
void setError(QBluetoothDeviceDiscoveryAgent::Error, const QString &text = QString());
@@ -91,63 +103,30 @@ private:
QBluetoothDeviceDiscoveryAgent::InquiryType inquiryType;
- typedef ObjCScopedPointer<LEDeviceInquiryObjC> LEDeviceInquiry;
+ using LEDeviceInquiry = OSXBluetooth::ObjCScopedPointer<LEDeviceInquiryObjC>;
LEDeviceInquiry inquiryLE;
- typedef QList<QBluetoothDeviceInfo> DevicesList;
+ using DevicesList = QList<QBluetoothDeviceInfo>;
DevicesList discoveredDevices;
bool startPending;
bool stopPending;
- QScopedPointer<OSXBluetooth::DDATimerHandler> timer;
+ int lowEnergySearchTimeout;
};
-namespace OSXBluetooth {
-
-DDATimerHandler::DDATimerHandler(QBluetoothDeviceDiscoveryAgentPrivate *d)
- : owner(d)
-{
- Q_ASSERT_X(owner, Q_FUNC_INFO, "invalid pointer");
-
- timer.setSingleShot(false);
- connect(&timer, &QTimer::timeout, this, &DDATimerHandler::onTimer);
-}
-
-void DDATimerHandler::start(int msec)
-{
- Q_ASSERT_X(msec > 0, Q_FUNC_INFO, "invalid time interval");
- if (timer.isActive()) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "timer is active";
- return;
- }
-
- timer.start(msec);
-}
-
-void DDATimerHandler::stop()
-{
- timer.stop();
-}
-
-void DDATimerHandler::onTimer()
-{
- Q_ASSERT(owner);
- owner->checkLETimeout();
-}
-
-}
-
QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress &adapter,
QBluetoothDeviceDiscoveryAgent *q) :
q_ptr(q),
lastError(QBluetoothDeviceDiscoveryAgent::NoError),
inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry),
startPending(false),
- stopPending(false)
+ stopPending(false),
+ lowEnergySearchTimeout(OSXBluetooth::defaultLEScanTimeoutMS)
{
Q_UNUSED(adapter);
+ registerQDeviceDiscoveryMetaType();
Q_ASSERT_X(q != Q_NULLPTR, Q_FUNC_INFO, "invalid q_ptr (null)");
}
@@ -158,7 +137,7 @@ QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate()
if (dispatch_queue_t leQueue = OSXBluetooth::qt_LE_queue()) {
// Local variable to be retained ...
LEDeviceInquiryObjC *inq = inquiryLE.data();
- dispatch_async(leQueue, ^{
+ dispatch_sync(leQueue, ^{
[inq stop];
});
}
@@ -175,7 +154,7 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
return inquiryLE;
}
-void QBluetoothDeviceDiscoveryAgentPrivate::start()
+void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods /*methods*/)
{
Q_ASSERT_X(!isActive(), Q_FUNC_INFO, "called on active device discovery agent");
@@ -186,26 +165,37 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start()
using namespace OSXBluetooth;
- inquiryLE.reset([[LEDeviceInquiryObjC alloc] init]);
+ QScopedPointer<LECBManagerNotifier> notifier(new LECBManagerNotifier);
+ // Connections:
+ using ErrMemFunPtr = void (LECBManagerNotifier::*)(QBluetoothDeviceDiscoveryAgent::Error);
+ notifier->connect(notifier.data(), ErrMemFunPtr(&LECBManagerNotifier::CBManagerError),
+ this, &QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError);
+ notifier->connect(notifier.data(), &LECBManagerNotifier::LEnotSupported,
+ this, &QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported);
+ notifier->connect(notifier.data(), &LECBManagerNotifier::discoveryFinished,
+ this, &QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished);
+ notifier->connect(notifier.data(), &LECBManagerNotifier::deviceDiscovered,
+ this, &QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceFound);
+
+ inquiryLE.reset([[LEDeviceInquiryObjC alloc] initWithNotifier:notifier.data()]);
+ if (inquiryLE)
+ notifier.take(); // Whatever happens next, inquiryLE is already the owner ...
+
dispatch_queue_t leQueue(qt_LE_queue());
if (!leQueue || !inquiryLE) {
setError(QBluetoothDeviceDiscoveryAgent::UnknownError,
QCoreApplication::translate(DEV_DISCOVERY, DD_NOT_STARTED));
emit q_ptr->error(lastError);
+ return;
}
discoveredDevices.clear();
setError(QBluetoothDeviceDiscoveryAgent::NoError);
- // CoreBluetooth does not have a timeout. We start a timer here
- // and check if scan really started and if yes if we have a timeout.
- timer.reset(new OSXBluetooth::DDATimerHandler(this));
- timer->start(2000);
-
// Create a local variable - to have a strong referece in a block.
LEDeviceInquiryObjC *inq = inquiryLE.data();
dispatch_async(leQueue, ^{
- [inq start];
+ [inq startWithTimeout:lowEnergySearchTimeout];
});
}
@@ -223,7 +213,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop()
// Create a local variable - to have a strong referece in a block.
LEDeviceInquiryObjC *inq = inquiryLE.data();
- dispatch_async(leQueue, ^{
+ dispatch_sync(leQueue, ^{
[inq stop];
});
// We consider LE scan to be stopped immediately and
@@ -241,7 +231,6 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError(QBluetoothDeviceDisco
Q_FUNC_INFO, "unexpected error");
inquiryLE.reset();
- timer->stop();
startPending = false;
stopPending = false;
@@ -252,7 +241,6 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError(QBluetoothDeviceDisco
void QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported()
{
inquiryLE.reset();
- timer->stop();
startPending = false;
stopPending = false;
@@ -281,7 +269,6 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceFound(const QBluetoothDevice
void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished()
{
inquiryLE.reset();
- timer->stop();
if (stopPending && !startPending) {
stopPending = false;
@@ -289,47 +276,14 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished()
} else if (startPending) {
startPending = false;
stopPending = false;
- start();
+ // always the same method for start() on iOS
+ // classic search not supported
+ start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
} else {
emit q_ptr->finished();
}
}
-void QBluetoothDeviceDiscoveryAgentPrivate::checkLETimeout()
-{
- Q_ASSERT_X(inquiryLE, Q_FUNC_INFO, "LE device inquiry is nil");
-
- using namespace OSXBluetooth;
-
- const LEInquiryState state([inquiryLE inquiryState]);
- if (state == InquiryStarting || state == InquiryActive)
- return; // Wait ...
-
- if (state == ErrorPoweredOff)
- return LEinquiryError(QBluetoothDeviceDiscoveryAgent::PoweredOffError);
-
- if (state == ErrorLENotSupported)
- return LEnotSupported();
-
- if (state == InquiryFinished) {
- // Process found devices if any ...
- const QList<QBluetoothDeviceInfo> leDevices([inquiryLE discoveredDevices]);
- foreach (const QBluetoothDeviceInfo &info, leDevices) {
- // We were cancelled on a previous device discovered signal ...
- if (!inquiryLE)
- break;
- LEdeviceFound(info);
- }
-
- if (inquiryLE)
- LEinquiryFinished();
- return;
- }
-
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unexpected inquiry state in LE timeout";
- // Actually, this deserves an assert :)
-}
-
void QBluetoothDeviceDiscoveryAgentPrivate::setError(QBluetoothDeviceDiscoveryAgent::Error error,
const QString &text)
{
@@ -373,7 +327,7 @@ QBluetoothDeviceDiscoveryAgent::QBluetoothDeviceDiscoveryAgent(
d_ptr(new QBluetoothDeviceDiscoveryAgentPrivate(deviceAdapter, this))
{
if (!deviceAdapter.isNull()) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "local device address is "
+ qCWarning(QT_BT_OSX) << "local device address is "
"not available, provided address is ignored";
d_ptr->setError(InvalidBluetoothAdapterError);
}
@@ -399,16 +353,40 @@ QList<QBluetoothDeviceInfo> QBluetoothDeviceDiscoveryAgent::discoveredDevices()
return d_ptr->discoveredDevices;
}
+QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods()
+{
+ return LowEnergyMethod;
+}
+
void QBluetoothDeviceDiscoveryAgent::start()
{
if (d_ptr->lastError != InvalidBluetoothAdapterError) {
if (!isActive())
- d_ptr->start();
+ d_ptr->start(supportedDiscoveryMethods());
else
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "already started";
+ qCDebug(QT_BT_OSX) << "already started";
}
}
+void QBluetoothDeviceDiscoveryAgent::start(DiscoveryMethods methods)
+{
+ if (methods == NoMethod)
+ return;
+
+ DiscoveryMethods supported =
+ QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods();
+
+ if (!((supported & methods) == methods)) {
+ d_ptr->lastError = UnsupportedDiscoveryMethod;
+ d_ptr->errorString = QBluetoothDeviceDiscoveryAgent::tr("One or more device discovery methods "
+ "are not supported on this platform");
+ emit error(d_ptr->lastError);
+ }
+
+ if (!isActive() && d_ptr->lastError != InvalidBluetoothAdapterError)
+ d_ptr->start(methods);
+}
+
void QBluetoothDeviceDiscoveryAgent::stop()
{
if (isActive() && d_ptr->lastError != InvalidBluetoothAdapterError)
@@ -430,4 +408,21 @@ QString QBluetoothDeviceDiscoveryAgent::errorString() const
return d_ptr->errorString;
}
+int QBluetoothDeviceDiscoveryAgent::lowEnergyDiscoveryTimeout() const
+{
+ return d_ptr->lowEnergySearchTimeout;
+}
+
+void QBluetoothDeviceDiscoveryAgent::setLowEnergyDiscoveryTimeout(int timeout)
+{
+ // cannot deliberately turn it off
+ if (timeout < 0) {
+ qCDebug(QT_BT_OSX) << "The Bluetooth Low Energy device discovery timeout cannot be negative.";
+ return;
+ }
+
+ d_ptr->lowEnergySearchTimeout = timeout;
+ return;
+}
+
QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm b/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm
index 0ead4e36..ba74da97 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm
@@ -37,21 +37,21 @@
**
****************************************************************************/
-#include "qbluetoothdevicediscoverytimer_osx_p.h"
#include "qbluetoothdevicediscoveryagent.h"
#include "osx/osxbtledeviceinquiry_p.h"
#include "osx/osxbtdeviceinquiry_p.h"
#include "qbluetoothlocaldevice.h"
#include "osx/osxbtsdpinquiry_p.h"
#include "qbluetoothdeviceinfo.h"
+#include "osx/osxbtnotifier_p.h"
#include "osx/osxbtutility_p.h"
-#include "osx/uistrings_p.h"
#include "qbluetoothhostinfo.h"
+#include "qbluetoothaddress.h"
+#include "osx/uistrings_p.h"
#include "qbluetoothuuid.h"
#include <QtCore/qloggingcategory.h>
#include <QtCore/qscopedpointer.h>
-#include <QtCore/qdatetime.h>
#include <QtCore/qglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qdebug.h>
@@ -63,23 +63,39 @@
QT_BEGIN_NAMESPACE
-using OSXBluetooth::ObjCScopedPointer;
+namespace
+{
-class QBluetoothDeviceDiscoveryAgentPrivate : public OSXBluetooth::DeviceInquiryDelegate
+void registerQDeviceDiscoveryMetaType()
+{
+ static bool initDone = false;
+ if (!initDone) {
+ qRegisterMetaType<QBluetoothDeviceInfo>();
+ qRegisterMetaType<QBluetoothDeviceDiscoveryAgent::Error>();
+ initDone = true;
+ }
+}
+
+}//namespace
+
+class QBluetoothDeviceDiscoveryAgentPrivate : public QObject,
+ public OSXBluetooth::DeviceInquiryDelegate
{
friend class QBluetoothDeviceDiscoveryAgent;
- friend class OSXBluetooth::DDATimerHandler;
public:
- typedef QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry) LEDeviceInquiryObjC;
+ template<class T>
+ using ObjCScopedPointer = OSXBluetooth::ObjCScopedPointer<T>;
+ using LEDeviceInquiryObjC = QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry);
QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress & address,
QBluetoothDeviceDiscoveryAgent *q);
- virtual ~QBluetoothDeviceDiscoveryAgentPrivate();
+
+ ~QBluetoothDeviceDiscoveryAgentPrivate() Q_DECL_OVERRIDE;
bool isValid() const;
bool isActive() const;
- void start();
+ void start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods m);
void startLE();
void stop();
@@ -95,7 +111,6 @@ private:
void error(IOBluetoothDeviceInquiry *inq, IOReturn error) Q_DECL_OVERRIDE;
void deviceFound(IOBluetoothDeviceInquiry *inq, IOBluetoothDevice *device) Q_DECL_OVERRIDE;
- //
void LEinquiryFinished();
void LEinquiryError(QBluetoothDeviceDiscoveryAgent::Error error);
void LEnotSupported();
@@ -105,9 +120,8 @@ private:
void deviceFound(const QBluetoothDeviceInfo &newDeviceInfo);
void setError(IOReturn error, const QString &text = QString());
- void setError(QBluetoothDeviceDiscoveryAgent::Error, const QString &text = QString());
-
- void checkLETimeout();
+ void setError(QBluetoothDeviceDiscoveryAgent::Error,
+ const QString &text = QString());
QBluetoothDeviceDiscoveryAgent *q_ptr;
AgentState agentState;
@@ -122,56 +136,22 @@ private:
QBluetoothDeviceDiscoveryAgent::InquiryType inquiryType;
- typedef ObjCScopedPointer<DeviceInquiryObjC> DeviceInquiry;
+ using DeviceInquiry = ObjCScopedPointer<DeviceInquiryObjC>;
DeviceInquiry inquiry;
- typedef ObjCScopedPointer<LEDeviceInquiryObjC> LEDeviceInquiry;
+ using LEDeviceInquiry = ObjCScopedPointer<LEDeviceInquiryObjC>;
LEDeviceInquiry inquiryLE;
- typedef ObjCScopedPointer<IOBluetoothHostController> HostController;
+ using HostController = ObjCScopedPointer<IOBluetoothHostController>;
HostController hostController;
- typedef QList<QBluetoothDeviceInfo> DevicesList;
+ using DevicesList = QList<QBluetoothDeviceInfo>;
DevicesList discoveredDevices;
- QScopedPointer<OSXBluetooth::DDATimerHandler> timer;
+ int lowEnergySearchTimeout;
+ QBluetoothDeviceDiscoveryAgent::DiscoveryMethods requestedMethods;
};
-namespace OSXBluetooth {
-
-DDATimerHandler::DDATimerHandler(QBluetoothDeviceDiscoveryAgentPrivate *d)
- : owner(d)
-{
- Q_ASSERT_X(owner, Q_FUNC_INFO, "invalid pointer");
-
- timer.setSingleShot(false);
- connect(&timer, &QTimer::timeout, this, &DDATimerHandler::onTimer);
-}
-
-void DDATimerHandler::start(int msec)
-{
- Q_ASSERT_X(msec > 0, Q_FUNC_INFO, "invalid time interval");
- if (timer.isActive()) {
- qCWarning(QT_BT_OSX) << "timer is active";
- return;
- }
-
- timer.start(msec);
-}
-
-void DDATimerHandler::stop()
-{
- timer.stop();
-}
-
-void DDATimerHandler::onTimer()
-{
- Q_ASSERT(owner);
- owner->checkLETimeout();
-}
-
-}
-
QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress &adapter,
QBluetoothDeviceDiscoveryAgent *q) :
q_ptr(q),
@@ -180,8 +160,11 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(con
startPending(false),
stopPending(false),
lastError(QBluetoothDeviceDiscoveryAgent::NoError),
- inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry)
+ inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry),
+ lowEnergySearchTimeout(OSXBluetooth::defaultLEScanTimeoutMS)
{
+ registerQDeviceDiscoveryMetaType();
+
Q_ASSERT_X(q != Q_NULLPTR, Q_FUNC_INFO, "invalid q_ptr (null)");
HostController controller([[IOBluetoothHostController defaultController] retain]);
@@ -207,7 +190,7 @@ QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate()
if (dispatch_queue_t leQueue = OSXBluetooth::qt_LE_queue()) {
// Local variable to be retained ...
LEDeviceInquiryObjC *inq = inquiryLE.data();
- dispatch_async(leQueue, ^{
+ dispatch_sync(leQueue, ^{
[inq stop];
});
}
@@ -235,13 +218,16 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
return agentState != NonActive;
}
-void QBluetoothDeviceDiscoveryAgentPrivate::start()
+void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
{
Q_ASSERT_X(isValid(), Q_FUNC_INFO, "called on invalid device discovery agent");
Q_ASSERT_X(!isActive(), Q_FUNC_INFO, "called on active device discovery agent");
Q_ASSERT_X(lastError != QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError,
Q_FUNC_INFO, "called with an invalid Bluetooth adapter");
+ //TODO Implement discovery method handling (see input parameter)
+ requestedMethods = methods;
+
if (stopPending) {
startPending = true;
return;
@@ -268,7 +254,23 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startLE()
using namespace OSXBluetooth;
- inquiryLE.reset([[LEDeviceInquiryObjC alloc] init]);
+ QScopedPointer<LECBManagerNotifier> notifier(new LECBManagerNotifier);
+ // Connections:
+ using ErrMemFunPtr = void (LECBManagerNotifier::*)(QBluetoothDeviceDiscoveryAgent::Error);
+ notifier->connect(notifier.data(), ErrMemFunPtr(&LECBManagerNotifier::CBManagerError),
+ this, &QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError);
+ notifier->connect(notifier.data(), &LECBManagerNotifier::LEnotSupported,
+ this, &QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported);
+ notifier->connect(notifier.data(), &LECBManagerNotifier::discoveryFinished,
+ this, &QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished);
+ using DeviceMemFunPtr = void (QBluetoothDeviceDiscoveryAgentPrivate::*)(const QBluetoothDeviceInfo &);
+ notifier->connect(notifier.data(), &LECBManagerNotifier::deviceDiscovered,
+ this, DeviceMemFunPtr(&QBluetoothDeviceDiscoveryAgentPrivate::deviceFound));
+
+ // Check queue and create scanner:
+ inquiryLE.reset([[LEDeviceInquiryObjC alloc] initWithNotifier:notifier.data()]);
+ if (inquiryLE)
+ notifier.take(); // Whatever happens next, inquiryLE is already the owner ...
dispatch_queue_t leQueue(qt_LE_queue());
if (!leQueue || !inquiryLE) {
@@ -276,18 +278,15 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startLE()
QCoreApplication::translate(DEV_DISCOVERY, DD_NOT_STARTED_LE));
agentState = NonActive;
emit q_ptr->error(lastError);
+ return;
}
+ // Now start in on LE queue:
agentState = LEScan;
- // CoreBluetooth does not have a timeout. We start a timer here
- // and check if scan is active/finished/finished with error(s).
- timer.reset(new OSXBluetooth::DDATimerHandler(this));
- timer->start(2000);
-
// We need the local variable so that it's retained ...
LEDeviceInquiryObjC *inq = inquiryLE.data();
dispatch_async(leQueue, ^{
- [inq start];
+ [inq startWithTimeout:lowEnergySearchTimeout];
});
}
@@ -320,7 +319,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop()
Q_ASSERT(leQueue);
// We need the local variable so that it's retained ...
LEDeviceInquiryObjC *inq = inquiryLE.data();
- dispatch_async(leQueue, ^{
+ dispatch_sync(leQueue, ^{
[inq stop];
});
// We consider LE scan to be stopped immediately and
@@ -345,7 +344,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::inquiryFinished(IOBluetoothDeviceInq
} else if (startPending) {
startPending = false;
stopPending = false;
- start();
+ start(requestedMethods);
} else {
// We can be here _only_ if a classic scan
// finished in a normal way (not cancelled).
@@ -444,49 +443,16 @@ void QBluetoothDeviceDiscoveryAgentPrivate::setError(QBluetoothDeviceDiscoveryAg
qCDebug(QT_BT_OSX) << "error set: "<<errorString;
}
-void QBluetoothDeviceDiscoveryAgentPrivate::checkLETimeout()
-{
- Q_ASSERT_X(agentState == LEScan, Q_FUNC_INFO, "invalid agent state");
- Q_ASSERT_X(inquiryLE, Q_FUNC_INFO, "LE device inquiry is nil");
-
- using namespace OSXBluetooth;
-
- const LEInquiryState state([inquiryLE inquiryState]);
- if (state == InquiryStarting || state == InquiryActive)
- return; // Wait ...
-
- if (state == ErrorPoweredOff)
- return LEinquiryError(QBluetoothDeviceDiscoveryAgent::PoweredOffError);
-
- if (state == ErrorLENotSupported)
- return LEnotSupported();
-
- if (state == InquiryFinished) {
- // Process found devices if any ...
- const QList<QBluetoothDeviceInfo> leDevices([inquiryLE discoveredDevices]);
- foreach (const QBluetoothDeviceInfo &info, leDevices) {
- // We were cancelled on a previous device discovered signal ...
- if (agentState != LEScan)
- break;
- deviceFound(info);
- }
-
- if (agentState == LEScan)
- LEinquiryFinished();
- return;
- }
-
- qCWarning(QT_BT_OSX) << "unexpected inquiry state in LE timeout";
-}
-
void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError(QBluetoothDeviceDiscoveryAgent::Error error)
{
// At the moment the only error reported can be 'powered off' error, it happens
// after the LE scan started (so we have LE support and this is a real PoweredOffError).
Q_ASSERT(error == QBluetoothDeviceDiscoveryAgent::PoweredOffError);
- timer->stop();
inquiryLE.reset();
+
+ startPending = false;
+ stopPending = false;
agentState = NonActive;
setError(error);
emit q_ptr->error(lastError);
@@ -504,7 +470,6 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished()
// The same logic as in inquiryFinished, but does not start LE scan.
agentState = NonActive;
inquiryLE.reset();
- timer->stop();
if (stopPending && !startPending) {
stopPending = false;
@@ -512,7 +477,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished()
} else if (startPending) {
startPending = false;
stopPending = false;
- start(); //Start from a classic scan again.
+ start(requestedMethods); //Start again.
} else {
emit q_ptr->finished();
}
@@ -582,12 +547,17 @@ QList<QBluetoothDeviceInfo> QBluetoothDeviceDiscoveryAgent::discoveredDevices()
return d_ptr->discoveredDevices;
}
+QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods()
+{
+ return (ClassicMethod | LowEnergyMethod);
+}
+
void QBluetoothDeviceDiscoveryAgent::start()
{
if (d_ptr->lastError != InvalidBluetoothAdapterError) {
if (d_ptr->isValid()) {
if (!isActive())
- d_ptr->start();
+ d_ptr->start(supportedDiscoveryMethods());
} else {
// We previously failed to initialize d_ptr correctly:
// either some memory allocation problem or
@@ -598,6 +568,26 @@ void QBluetoothDeviceDiscoveryAgent::start()
}
}
+void QBluetoothDeviceDiscoveryAgent::start(DiscoveryMethods methods)
+{
+ if (methods == NoMethod)
+ return;
+
+ DiscoveryMethods supported =
+ QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods();
+
+ Q_D(QBluetoothDeviceDiscoveryAgent);
+ if (!((supported & methods) == methods)) {
+ d_ptr->lastError = UnsupportedDiscoveryMethod;
+ d_ptr->errorString = QBluetoothDeviceDiscoveryAgent::tr("One or more device discovery methods "
+ "are not supported on this platform");
+ emit error(d_ptr->lastError);
+ }
+
+ if (!isActive() && d_ptr->lastError != InvalidBluetoothAdapterError)
+ d_ptr->start(methods);
+}
+
void QBluetoothDeviceDiscoveryAgent::stop()
{
if (d_ptr->isValid()) {
@@ -624,4 +614,21 @@ QString QBluetoothDeviceDiscoveryAgent::errorString() const
return d_ptr->errorString;
}
+void QBluetoothDeviceDiscoveryAgent::setLowEnergyDiscoveryTimeout(int timeout)
+{
+ // cannot deliberately turn it off
+ if (timeout < 0) {
+ qCDebug(QT_BT_OSX) << "The Bluetooth Low Energy device discovery timeout cannot be negative.";
+ return;
+ }
+
+ d_ptr->lowEnergySearchTimeout = timeout;
+ return;
+}
+
+int QBluetoothDeviceDiscoveryAgent::lowEnergyDiscoveryTimeout() const
+{
+ return d_ptr->lowEnergySearchTimeout;
+}
+
QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp
index f7780722..e3646db9 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp
@@ -42,9 +42,7 @@
#include "qbluetoothaddress.h"
#include "qbluetoothuuid.h"
-#ifndef QT_IOS_BLUETOOTH
#include "dummy/dummy_helper_p.h"
-#endif
#define QT_DEVICEDISCOVERY_DEBUG
@@ -55,12 +53,11 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(
QBluetoothDeviceDiscoveryAgent *parent)
: inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry),
lastError(QBluetoothDeviceDiscoveryAgent::NoError),
+ lowEnergySearchTimeout(-1),
q_ptr(parent)
{
Q_UNUSED(deviceAdapter);
-#ifndef QT_IOS_BLUETOOTH
printDummyWarning();
-#endif
}
QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate()
@@ -72,7 +69,12 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
return false;
}
-void QBluetoothDeviceDiscoveryAgentPrivate::start()
+QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods()
+{
+ return QBluetoothDeviceDiscoveryAgent::NoMethod;
+}
+
+void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods)
{
Q_Q(QBluetoothDeviceDiscoveryAgent);
lastError = QBluetoothDeviceDiscoveryAgent::UnsupportedPlatformError;
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h
index c8b15510..06cf29c2 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h
@@ -99,7 +99,7 @@ public:
QBluetoothDeviceDiscoveryAgent *parent);
~QBluetoothDeviceDiscoveryAgentPrivate();
- void start();
+ void start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods);
void stop();
bool isActive() const;
@@ -168,6 +168,8 @@ private:
QPointer<QWinRTBluetoothDeviceDiscoveryWorker> worker;
#endif
+ int lowEnergySearchTimeout;
+ QBluetoothDeviceDiscoveryAgent::DiscoveryMethods requestedMethods;
QBluetoothDeviceDiscoveryAgent *q_ptr;
};
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
index f8a5fca1..bfa39fc1 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
@@ -287,6 +287,7 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(
: inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry),
lastError(QBluetoothDeviceDiscoveryAgent::NoError),
+ lowEnergySearchTimeout(-1), // TODO
q_ptr(parent)
{
Q_UNUSED(deviceAdapter);
@@ -302,7 +303,12 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
return worker;
}
-void QBluetoothDeviceDiscoveryAgentPrivate::start()
+QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods()
+{
+ return (ClassicMethod | LowEnergyMethod);
+}
+
+void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods)
{
if (worker)
return;
diff --git a/src/bluetooth/qbluetoothdevicediscoverytimer_osx_p.h b/src/bluetooth/qbluetoothdevicediscoverytimer_osx_p.h
deleted file mode 100644
index 88906ffd..00000000
--- a/src/bluetooth/qbluetoothdevicediscoverytimer_osx_p.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QBLUETOOTHDEVICEDISCOVERYTIMER_OSX_P_H
-#define QBLUETOOTHDEVICEDISCOVERYTIMER_OSX_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qglobal.h>
-#include <QtCore/qtimer.h>
-
-QT_BEGIN_NAMESPACE
-
-class QBluetoothDeviceDiscoveryAgentPrivate;
-
-namespace OSXBluetooth {
-
-class DDATimerHandler : public QObject
-{
- Q_OBJECT
-
-public:
- DDATimerHandler(QBluetoothDeviceDiscoveryAgentPrivate *d);
-
- void start(int msec);
- void stop();
-
-private slots:
- void onTimer();
-
-private:
- QTimer timer;
- QBluetoothDeviceDiscoveryAgentPrivate *owner;
-};
-
-}
-
-QT_END_NAMESPACE
-
-#endif // QBLUETOOTHDEVICEDISCOVERYTIMER_OSX_P_H
diff --git a/src/bluetooth/qlowenergycontroller.cpp b/src/bluetooth/qlowenergycontroller.cpp
index f70e03c6..0095b90a 100644
--- a/src/bluetooth/qlowenergycontroller.cpp
+++ b/src/bluetooth/qlowenergycontroller.cpp
@@ -154,6 +154,7 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT)
remote device.
\value ClosingState The controller is about to be disconnected from the remote device.
\value AdvertisingState The controller is currently advertising data.
+ This value was introduced by Qt 5.7.
*/
/*!
@@ -259,6 +260,7 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT)
the other side of the connection requested new parameters. The new values can be retrieved
from \a newParameters.
+ \since 5.7
\sa requestConnectionUpdate()
*/
@@ -557,9 +559,11 @@ QLowEnergyController::QLowEnergyController(
Returns a new object of this class that is in the \l CentralRole and has the
parent object \a parent.
The \a remoteDevice refers to the device that a connection will be established to later.
- *
+
The controller uses the local default Bluetooth adapter for the connection management.
+
\sa QLowEnergyController::CentralRole
+ \since 5.7
*/
QLowEnergyController *QLowEnergyController::createCentral(const QBluetoothDeviceInfo &remoteDevice,
QObject *parent)
@@ -574,7 +578,9 @@ QLowEnergyController *QLowEnergyController::createCentral(const QBluetoothDevice
Typically, the next step is to call \l startAdvertising() on the returned object.
The controller uses the local default Bluetooth adapter for the connection management.
+
\sa QLowEnergyController::PeripheralRole
+ \since 5.7
*/
QLowEnergyController *QLowEnergyController::createPeripheral(QObject *parent)
{
@@ -818,6 +824,9 @@ QLowEnergyService *QLowEnergyController::createServiceObject(
If this object is currently not in the \l UnconnectedState, nothing happens.
\note Advertising will stop automatically once a client connects to the local device.
+
+ \since 5.7
+ \sa stopAdvertising()
*/
void QLowEnergyController::startAdvertising(const QLowEnergyAdvertisingParameters &parameters,
const QLowEnergyAdvertisingData &advertisingData,
@@ -837,6 +846,9 @@ void QLowEnergyController::startAdvertising(const QLowEnergyAdvertisingParameter
/*!
Stops advertising, if this object is currently in the advertising state.
+
+ \since 5.7
+ \sa startAdvertising()
*/
void QLowEnergyController::stopAdvertising()
{
@@ -852,6 +864,8 @@ void QLowEnergyController::stopAdvertising()
Constructs and returns a \l QLowEnergyService object with \a parent from \a service.
The controller must be in the \l PeripheralRole and in the \l UnconnectedState. The \a service
object must be valid.
+
+ \since 5.7
\sa QLowEnergyServiceData::addIncludedService
*/
QLowEnergyService *QLowEnergyController::addService(const QLowEnergyServiceData &service,
@@ -923,6 +937,8 @@ QLowEnergyService *QLowEnergyController::addService(const QLowEnergyServiceData
with the actual new parameters.
See the \l QLowEnergyConnectionParameters class for more information on connection parameters.
\note Currently, this functionality is only implemented on Linux.
+
+ \since 5.7
*/
void QLowEnergyController::requestConnectionUpdate(const QLowEnergyConnectionParameters &parameters)
{
@@ -952,6 +968,11 @@ QString QLowEnergyController::errorString() const
/*!
Returns the role that this controller object is in.
+
+ The role is determined when constructing a QLowEnergyController instance
+ using \l createCentral() or \l createPeripheral().
+
+ \since 5.7
*/
QLowEnergyController::Role QLowEnergyController::role() const
{
diff --git a/src/bluetooth/qlowenergycontroller_osx.mm b/src/bluetooth/qlowenergycontroller_osx.mm
index 5c4c7c37..6e85e630 100644
--- a/src/bluetooth/qlowenergycontroller_osx.mm
+++ b/src/bluetooth/qlowenergycontroller_osx.mm
@@ -103,7 +103,6 @@ ServicePrivate qt_createLEService(QLowEnergyControllerPrivateOSX *controller, CB
// TODO: isPrimary is ... always 'NO' - to be investigated.
/*
- using OSXBluetooth::qt_OS_limit;
if (!cbService.isPrimary) {
// Our guess included/not was probably wrong.
newService->type &= ~QLowEnergyService::PrimaryService;
@@ -147,12 +146,9 @@ QLowEnergyControllerPrivateOSX::QLowEnergyControllerPrivateOSX(QLowEnergyControl
Q_ASSERT_X(q, Q_FUNC_INFO, "invalid q_ptr (null)");
using OSXBluetooth::LECBManagerNotifier;
- using OSXBluetooth::qt_OS_limit;
role = r;
-
-
QScopedPointer<LECBManagerNotifier> notifier(new LECBManagerNotifier);
if (role == QLowEnergyController::PeripheralRole) {
#ifndef Q_OS_TVOS
diff --git a/src/bluetooth/qlowenergyservice.cpp b/src/bluetooth/qlowenergyservice.cpp
index 1e5c363d..e9722f81 100644
--- a/src/bluetooth/qlowenergyservice.cpp
+++ b/src/bluetooth/qlowenergyservice.cpp
@@ -229,6 +229,7 @@ QT_BEGIN_NAMESPACE
\value LocalService The service is associated with a controller object in the
\l{QLowEnergyController::PeripheralRole}{peripheral role}. Such
service objects do not change their state.
+ This value was introduced by Qt 5.7.
*/
/*!