summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@theqtcompany.com>2015-12-21 09:59:24 +0100
committerAlex Blasche <alexander.blasche@theqtcompany.com>2015-12-21 09:59:52 +0100
commit237ce0ec871c1850dab5f53e89df0296f62d90b5 (patch)
treef6bd5ce73c91583ba7f589e2e4df460d6bc6033f /src
parent4cafd5cac8e920c6decbb974bf548e9c8f935d24 (diff)
parentf6c982457cb8458224d127a42aac80ae02c2c593 (diff)
Merge remote-tracking branch 'gerrit/5.6' into dev
Diffstat (limited to 'src')
-rw-r--r--src/bluetooth/android/jni_android.cpp2
-rw-r--r--src/bluetooth/osx/osxbt.pri8
-rw-r--r--src/bluetooth/osx/osxbtcentralmanager.mm411
-rw-r--r--src/bluetooth/osx/osxbtcentralmanager_p.h77
-rw-r--r--src/bluetooth/osx/osxbtnotifier.cpp1
-rw-r--r--src/bluetooth/osx/osxbtnotifier_p.h92
-rw-r--r--src/bluetooth/osx/osxbtobexsession_p.h11
-rw-r--r--src/bluetooth/qbluetoothserviceinfo.cpp1
-rw-r--r--src/bluetooth/qbluetoothtransferreply.cpp1
-rw-r--r--src/bluetooth/qlowenergycontroller_android.cpp4
-rw-r--r--src/bluetooth/qlowenergycontroller_osx.mm342
-rw-r--r--src/bluetooth/qlowenergycontroller_osx_p.h58
-rw-r--r--src/bluetooth/qlowenergyservice.cpp8
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp4
-rw-r--r--src/nfc/qqmlndefrecord.cpp5
-rw-r--r--src/nfc/qqmlndefrecord.h1
16 files changed, 641 insertions, 385 deletions
diff --git a/src/bluetooth/android/jni_android.cpp b/src/bluetooth/android/jni_android.cpp
index b4209500..061d7d96 100644
--- a/src/bluetooth/android/jni_android.cpp
+++ b/src/bluetooth/android/jni_android.cpp
@@ -249,7 +249,7 @@ static bool registerNatives(JNIEnv *env)
FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver");
if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
- __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives for BraodcastReceiver failed");
+ __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives for BroadcastReceiver failed");
return false;
}
diff --git a/src/bluetooth/osx/osxbt.pri b/src/bluetooth/osx/osxbt.pri
index 06389fcc..bb382866 100644
--- a/src/bluetooth/osx/osxbt.pri
+++ b/src/bluetooth/osx/osxbt.pri
@@ -1,4 +1,4 @@
-SOURCES += osx/uistrings.cpp
+SOURCES += osx/uistrings.cpp osx/osxbtnotifier.cpp
PRIVATE_HEADERS += osx/uistrings_p.h
CONFIG(osx) {
@@ -15,7 +15,8 @@ CONFIG(osx) {
osx/osxbtobexsession_p.h \
osx/osxbtledeviceinquiry_p.h \
osx/corebluetoothwrapper_p.h \
- osx/osxbtcentralmanager_p.h
+ osx/osxbtcentralmanager_p.h \
+ osx/osxbtnotifier_p.h
OBJECTIVE_SOURCES += osx/osxbtutility.mm \
osx/osxbtdevicepair.mm \
@@ -34,7 +35,8 @@ CONFIG(osx) {
PRIVATE_HEADERS += osx/osxbtutility_p.h \
osx/osxbtledeviceinquiry_p.h \
osx/corebluetoothwrapper_p.h \
- osx/osxbtcentralmanager_p.h
+ osx/osxbtcentralmanager_p.h \
+ osx/osxbtnotifier_p.h
OBJECTIVE_SOURCES += osx/osxbtutility.mm \
osx/osxbtledeviceinquiry.mm \
diff --git a/src/bluetooth/osx/osxbtcentralmanager.mm b/src/bluetooth/osx/osxbtcentralmanager.mm
index 614e4ae5..2f881f79 100644
--- a/src/bluetooth/osx/osxbtcentralmanager.mm
+++ b/src/bluetooth/osx/osxbtcentralmanager.mm
@@ -34,7 +34,7 @@
#include "qlowenergyserviceprivate_p.h"
#include "qlowenergycharacteristic.h"
#include "osxbtcentralmanager_p.h"
-
+#include "osxbtnotifier_p.h"
#include <QtCore/qloggingcategory.h>
#include <QtCore/qsysinfo.h>
@@ -45,11 +45,11 @@
QT_BEGIN_NAMESPACE
-namespace OSXBluetooth {
+Q_DECLARE_METATYPE(QLowEnergyCharacteristic)
+Q_DECLARE_METATYPE(QLowEnergyDescriptor)
+Q_DECLARE_METATYPE(QLowEnergyHandle)
-CentralManagerDelegate::~CentralManagerDelegate()
-{
-}
+namespace OSXBluetooth {
NSUInteger qt_countGATTEntries(CBService *service)
{
@@ -80,15 +80,12 @@ NSUInteger qt_countGATTEntries(CBService *service)
QT_END_NAMESPACE
-
-#ifdef QT_NAMESPACE
-using namespace QT_NAMESPACE;
-#endif
+QT_USE_NAMESPACE
@interface QT_MANGLE_NAMESPACE(OSXBTCentralManager) (PrivateAPI)
-- (QLowEnergyController::Error)connectToDevice; // "Device" is in Qt's world ...
-- (void)connectToPeripheral; // "Peripheral" is in Core Bluetooth.
+- (void)retrievePeripheralAndConnect;
+- (void)connectToPeripheral;
- (void)discoverIncludedServices;
- (void)readCharacteristics:(CBService *)service;
- (void)serviceDetailsDiscoveryFinished:(CBService *)service;
@@ -114,16 +111,14 @@ using namespace QT_NAMESPACE;
@implementation QT_MANGLE_NAMESPACE(OSXBTCentralManager)
-- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(OSXBluetooth)::CentralManagerDelegate *)aDelegate
+- (id)initWith:(OSXBluetooth::LECentralNotifier *)aNotifier
{
- Q_ASSERT_X(aDelegate, Q_FUNC_INFO, "invalid delegate (null)");
-
if (self = [super init]) {
manager = nil;
managerState = OSXBluetooth::CentralManagerIdle;
disconnectPending = false;
peripheral = nil;
- delegate = aDelegate;
+ notifier = aNotifier;
currentService = 0;
lastValidHandle = 0;
requestPending = false;
@@ -150,32 +145,37 @@ using namespace QT_NAMESPACE;
[peripheral setDelegate:nil];
[peripheral release];
+ if (notifier)
+ notifier->deleteLater();
+
[super dealloc];
}
-- (QLowEnergyController::Error)connectToDevice:(const QBluetoothUuid &)aDeviceUuid
+- (void)connectToDevice:(const QBluetoothUuid &)aDeviceUuid
{
- Q_ASSERT_X(managerState == OSXBluetooth::CentralManagerIdle,
- Q_FUNC_INFO, "invalid state");
-
+ disconnectPending = false; // Cancel the previous disconnect if any.
deviceUuid = aDeviceUuid;
if (!manager) {
- managerState = OSXBluetooth::CentralManagerUpdating; // We'll have to wait for updated state.
- manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
+ // The first time we try to connect, no manager created yet,
+ // no status update received.
+ if (const dispatch_queue_t leQueue = OSXBluetooth::qt_LE_queue()) {
+ managerState = OSXBluetooth::CentralManagerUpdating;
+ manager = [[CBCentralManager alloc] initWithDelegate:self queue:leQueue];
+ }
+
if (!manager) {
managerState = OSXBluetooth::CentralManagerIdle;
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to allocate a "
- "central manager";
- return QLowEnergyController::ConnectionError;
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to allocate a central manager";
+ if (notifier)
+ emit notifier->CBCentralManagerError(QLowEnergyController::ConnectionError);
}
- return QLowEnergyController::NoError;
- } else {
- return [self connectToDevice];
+ } else if (managerState != OSXBluetooth::CentralManagerUpdating) {
+ [self retrievePeripheralAndConnect];
}
}
-- (QLowEnergyController::Error)connectToDevice
+- (void)retrievePeripheralAndConnect
{
Q_ASSERT_X(manager, Q_FUNC_INFO, "invalid central manager (nil)");
Q_ASSERT_X(managerState == OSXBluetooth::CentralManagerIdle,
@@ -183,13 +183,14 @@ using namespace QT_NAMESPACE;
if ([self isConnected]) {
qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "already connected";
- delegate->connectSuccess();
- return QLowEnergyController::NoError;
+ if (notifier)
+ emit notifier->connected();
+ return;
} else if (peripheral) {
// Was retrieved already, but not connected
// or disconnected.
[self connectToPeripheral];
- return QLowEnergyController::NoError;
+ return;
}
using namespace OSXBluetooth;
@@ -198,7 +199,9 @@ using namespace QT_NAMESPACE;
ObjCScopedPointer<NSMutableArray> uuids([[NSMutableArray alloc] init]);
if (!uuids) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to allocate identifiers";
- return QLowEnergyController::ConnectionError;
+ if (notifier)
+ emit notifier->CBCentralManagerError(QLowEnergyController::ConnectionError);
+ return;
}
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_7_0)
@@ -210,43 +213,47 @@ using namespace QT_NAMESPACE;
const ObjCScopedPointer<NSUUID> nsUuid([[NSUUID alloc] initWithUUIDBytes:uuidData]);
if (!nsUuid) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to allocate NSUUID identifier";
- return QLowEnergyController::ConnectionError;
+ if (notifier)
+ emit notifier->CBCentralManagerError(QLowEnergyController::ConnectionError);
+ return;
}
[uuids addObject:nsUuid];
-
// With the latest CoreBluetooth, we can synchronously retrive peripherals:
QT_BT_MAC_AUTORELEASEPOOL;
NSArray *const peripherals = [manager retrievePeripheralsWithIdentifiers:uuids];
if (!peripherals || peripherals.count != 1) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to retrive a peripheral";
- return QLowEnergyController::UnknownRemoteDeviceError;
+ if (notifier)
+ emit notifier->CBCentralManagerError(QLowEnergyController::UnknownRemoteDeviceError);
+ return;
}
peripheral = [static_cast<CBPeripheral *>([peripherals objectAtIndex:0]) retain];
[self connectToPeripheral];
-
- return QLowEnergyController::NoError;
+ return;
}
#endif
// Either SDK or the target is below 10.9/7.0
if (![manager respondsToSelector:@selector(retrievePeripherals:)]) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to retrive a peripheral";
- return QLowEnergyController::UnknownRemoteDeviceError;
+ if (notifier)
+ emit notifier->CBCentralManagerError(QLowEnergyController::UnknownRemoteDeviceError);
+ return;
}
OSXBluetooth::CFStrongReference<CFUUIDRef> cfUuid(OSXBluetooth::cf_uuid(deviceUuid));
if (!cfUuid) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to create CFUUID object";
- return QLowEnergyController::ConnectionError;
+ if (notifier)
+ emit notifier->CBCentralManagerError(QLowEnergyController::ConnectionError);
+ return;
}
- // TODO: With ARC this cast will be illegal:
+ // With ARC this cast will be illegal:
[uuids addObject:(id)cfUuid.data()];
// Unfortunately, with old Core Bluetooth this call is asynchronous ...
managerState = OSXBluetooth::CentralManagerConnecting;
[manager performSelector:@selector(retrievePeripherals:) withObject:uuids.data()];
-
- return QLowEnergyController::NoError;
}
- (void)connectToPeripheral
@@ -259,7 +266,8 @@ using namespace QT_NAMESPACE;
// The state is still the same - connecting.
if ([self isConnected]) {
qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "already connected";
- delegate->connectSuccess();
+ if (notifier)
+ emit notifier->connected();
} else {
qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "trying to connect";
managerState = OSXBluetooth::CentralManagerConnecting;
@@ -291,10 +299,17 @@ using namespace QT_NAMESPACE;
[self reset];
if (managerState == OSXBluetooth::CentralManagerUpdating) {
- disconnectPending = true;
+ disconnectPending = true; // this is for 'didUpdate' method.
+ if (notifier) {
+ // We were waiting for the first update
+ // with 'PoweredOn' status, when suddenly got disconnected called.
+ // Since we have not attempted to connect yet, emit now.
+ // Note: we do not change the state, since we still maybe interested
+ // in the status update before the next connect attempt.
+ emit notifier->disconnected();
+ }
} else {
disconnectPending = false;
-
if ([self isConnected])
managerState = OSXBluetooth::CentralManagerDisconnecting;
else
@@ -303,8 +318,9 @@ using namespace QT_NAMESPACE;
// We have to call -cancelPeripheralConnection: even
// if not connected (to cancel a pending connect attempt).
// Unfortunately, didDisconnect callback is not always called
- // (despite of Apple's docs saying it _must_).
- [manager cancelPeripheralConnection:peripheral];
+ // (despite of Apple's docs saying it _must_ be).
+ if (peripheral)
+ [manager cancelPeripheralConnection:peripheral];
}
}
@@ -321,7 +337,6 @@ using namespace QT_NAMESPACE;
//parameter to nil is considerably slower and is not recommended."
//
// ... but we'd like to have them all:
-
[peripheral setDelegate:self];
managerState = OSXBluetooth::CentralManagerDiscovering;
[peripheral discoverServices:nil];
@@ -331,19 +346,17 @@ using namespace QT_NAMESPACE;
{
using namespace OSXBluetooth;
- Q_ASSERT_X(managerState == CentralManagerIdle, Q_FUNC_INFO,
- "invalid state");
+ Q_ASSERT_X(managerState == CentralManagerIdle, Q_FUNC_INFO, "invalid state");
Q_ASSERT_X(manager, Q_FUNC_INFO, "invalid manager (nil)");
Q_ASSERT_X(peripheral, Q_FUNC_INFO, "invalid peripheral (nil)");
QT_BT_MAC_AUTORELEASEPOOL;
NSArray *const services = peripheral.services;
- if (!services || !services.count) { // Actually, !services.count works in both cases, but ...
+ if (!services || !services.count) {
// A peripheral without any services at all.
- Q_ASSERT_X(delegate, Q_FUNC_INFO,
- "invalid delegate (null)");
- delegate->serviceDiscoveryFinished(ObjCStrongReference<NSArray>());
+ if (notifier)
+ emit notifier->serviceDiscoveryFinished();
} else {
// 'reset' also calls retain on a parameter.
servicesToVisitNext.reset(nil);
@@ -358,7 +371,7 @@ using namespace QT_NAMESPACE;
}
}
-- (bool)discoverServiceDetails:(const QBluetoothUuid &)serviceUuid
+- (void)discoverServiceDetails:(const QBluetoothUuid &)serviceUuid
{
// This function does not change 'managerState', since it
// can be called concurrently (not waiting for the previous
@@ -373,7 +386,7 @@ using namespace QT_NAMESPACE;
if (servicesToDiscoverDetails.contains(serviceUuid)) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO <<"already discovering for "
<< serviceUuid;
- return true;
+ return;
}
QT_BT_MAC_AUTORELEASEPOOL;
@@ -381,13 +394,16 @@ using namespace QT_NAMESPACE;
if (CBService *const service = [self serviceForUUID:serviceUuid]) {
servicesToDiscoverDetails.append(serviceUuid);
[peripheral discoverCharacteristics:nil forService:service];
- return true;
+ return;
}
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unknown service uuid "
<< serviceUuid;
- return false;
+ if (notifier) {
+ emit notifier->CBCentralManagerError(serviceUuid,
+ QLowEnergyService::UnknownError);
+ }
}
- (void)readCharacteristics:(CBService *)service
@@ -400,11 +416,9 @@ using namespace QT_NAMESPACE;
QT_BT_MAC_AUTORELEASEPOOL;
- Q_ASSERT_X(managerState != CentralManagerUpdating, Q_FUNC_INFO,
- "invalid state");
+ Q_ASSERT_X(managerState != CentralManagerUpdating, Q_FUNC_INFO, "invalid state");
Q_ASSERT_X(manager, Q_FUNC_INFO, "invalid manager (nil)");
Q_ASSERT_X(peripheral, Q_FUNC_INFO, "invalid peripheral (nil)");
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
if (!service.characteristics || !service.characteristics.count)
return [self serviceDetailsDiscoveryFinished:service];
@@ -444,20 +458,16 @@ using namespace QT_NAMESPACE;
- (void)readDescriptors:(CBService *)service
{
- Q_ASSERT_X(service, "-readDescriptors:",
- "invalid service (nil)");
+ Q_ASSERT_X(service, Q_FUNC_INFO, "invalid service (nil)");
Q_ASSERT_X(managerState != OSXBluetooth::CentralManagerUpdating,
- "-readDescriptors:",
- "invalid state");
- Q_ASSERT_X(peripheral, "-readDescriptors:",
- "invalid peripheral (nil)");
+ Q_FUNC_INFO, "invalid state");
+ Q_ASSERT_X(peripheral, Q_FUNC_INFO, "invalid peripheral (nil)");
QT_BT_MAC_AUTORELEASEPOOL;
NSArray *const cs = service.characteristics;
// We can never be here if we have no characteristics.
- Q_ASSERT_X(cs && cs.count, "-readDescriptors:",
- "invalid service");
+ Q_ASSERT_X(cs && cs.count, Q_FUNC_INFO, "invalid service");
for (CBCharacteristic *c in cs) {
if (c.descriptors && c.descriptors.count)
return [peripheral readValueForDescriptor:[c.descriptors objectAtIndex:0]];
@@ -469,9 +479,7 @@ using namespace QT_NAMESPACE;
- (void)serviceDetailsDiscoveryFinished:(CBService *)service
{
- //
Q_ASSERT_X(service, Q_FUNC_INFO, "invalid service (nil)");
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
using namespace OSXBluetooth;
@@ -487,7 +495,8 @@ using namespace QT_NAMESPACE;
if (nHandles >= maxHandle || lastValidHandle > maxHandle - nHandles) {
// Well, that's unlikely :) But we must be sure.
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "can not allocate more handles";
- delegate->error(serviceUuid, QLowEnergyService::OperationError);
+ if (notifier)
+ notifier->CBCentralManagerError(serviceUuid, QLowEnergyService::OperationError);
return;
}
@@ -550,8 +559,8 @@ using namespace QT_NAMESPACE;
qtService->endHandle = lastValidHandle;
- ObjCStrongReference<CBService> leService(service, true);
- delegate->serviceDetailsDiscoveryFinished(qtService);
+ if (notifier)
+ emit notifier->serviceDetailsDiscoveryFinished(qtService);
}
- (void)performNextRequest
@@ -694,28 +703,37 @@ using namespace QT_NAMESPACE;
}
}
-- (bool)setNotifyValue:(const QByteArray &)value
- forCharacteristic:(QT_PREPEND_NAMESPACE(QLowEnergyHandle))charHandle
+- (void)setNotifyValue:(const QByteArray &)value
+ forCharacteristic:(QLowEnergyHandle)charHandle
+ onService:(const QBluetoothUuid &)serviceUuid
{
using namespace OSXBluetooth;
Q_ASSERT_X(charHandle, Q_FUNC_INFO, "invalid characteristic handle (0)");
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
if (!charMap.contains(charHandle)) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO
- << "unknown characteristic handle " << charHandle;
- return false;
+ << "unknown characteristic handle "
+ << charHandle;
+ if (notifier) {
+ emit notifier->CBCentralManagerError(serviceUuid,
+ QLowEnergyService::DescriptorWriteError);
+ }
+ return;
}
// At the moment we call setNotifyValue _only_ from 'writeDescriptor';
- // from Qt's API POV it's a descriptor write oprtation and we must report
+ // from Qt's API POV it's a descriptor write operation and we must report
// it back, so check _now_ that we really have this descriptor.
const QBluetoothUuid qtUuid(QBluetoothUuid::ClientCharacteristicConfiguration);
if (![self descriptor:qtUuid forCharacteristic:charMap[charHandle]]) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO
<< "no client characteristic configuration found";
- return false;
+ if (notifier) {
+ emit notifier->CBCentralManagerError(serviceUuid,
+ QLowEnergyService::DescriptorWriteError);
+ }
+ return;
}
LERequest request;
@@ -725,11 +743,10 @@ using namespace QT_NAMESPACE;
requests.enqueue(request);
[self performNextRequest];
-
- return true;
}
-- (bool)readCharacteristic:(QT_PREPEND_NAMESPACE(QLowEnergyHandle))charHandle
+- (void)readCharacteristic:(QLowEnergyHandle)charHandle
+ onService:(const QBluetoothUuid &)serviceUuid
{
using namespace OSXBluetooth;
@@ -739,7 +756,12 @@ using namespace QT_NAMESPACE;
if (!charMap.contains(charHandle)) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "characteristic: " << charHandle << " not found";
- return false;
+ if (notifier) {
+ emit notifier->CBCentralManagerError(serviceUuid,
+ QLowEnergyService::CharacteristicReadError);
+
+ }
+ return;
}
LERequest request;
@@ -748,12 +770,11 @@ using namespace QT_NAMESPACE;
requests.enqueue(request);
[self performNextRequest];
-
- return true;
}
-- (bool)write:(const QT_PREPEND_NAMESPACE(QByteArray) &)value
- charHandle:(QT_PREPEND_NAMESPACE(QLowEnergyHandle))charHandle
+- (void)write:(const QByteArray &)value
+ charHandle:(QLowEnergyHandle)charHandle
+ onService:(const QBluetoothUuid &)serviceUuid
withResponse:(bool)withResponse
{
using namespace OSXBluetooth;
@@ -763,8 +784,13 @@ using namespace QT_NAMESPACE;
QT_BT_MAC_AUTORELEASEPOOL;
if (!charMap.contains(charHandle)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "characteristic: " << charHandle << " not found";
- return false;
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "characteristic: "
+ << charHandle << " not found";
+ if (notifier) {
+ emit notifier->CBCentralManagerError(serviceUuid,
+ QLowEnergyService::CharacteristicWriteError);
+ }
+ return;
}
LERequest request;
@@ -775,11 +801,10 @@ using namespace QT_NAMESPACE;
requests.enqueue(request);
[self performNextRequest];
-
- return true;
}
-- (bool)readDescriptor:(QT_PREPEND_NAMESPACE(QLowEnergyHandle))descHandle
+- (void)readDescriptor:(QLowEnergyHandle)descHandle
+ onService:(const QBluetoothUuid &)serviceUuid
{
using namespace OSXBluetooth;
@@ -788,7 +813,11 @@ using namespace QT_NAMESPACE;
if (!descMap.contains(descHandle)) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "handle:"
<< descHandle << "not found";
- return false;
+ if (notifier) {
+ emit notifier->CBCentralManagerError(serviceUuid,
+ QLowEnergyService::DescriptorReadError);
+ }
+ return;
}
LERequest request;
@@ -797,11 +826,11 @@ using namespace QT_NAMESPACE;
requests.enqueue(request);
[self performNextRequest];
-
- return true;
}
-- (bool)write:(const QByteArray &)value descHandle:(QLowEnergyHandle)descHandle
+- (void)write:(const QByteArray &)value
+ descHandle:(QLowEnergyHandle)descHandle
+ onService:(const QBluetoothUuid &)serviceUuid
{
using namespace OSXBluetooth;
@@ -810,7 +839,11 @@ using namespace QT_NAMESPACE;
if (!descMap.contains(descHandle)) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "handle: "
<< descHandle << " not found";
- return false;
+ if (notifier) {
+ emit notifier->CBCentralManagerError(serviceUuid,
+ QLowEnergyService::DescriptorWriteError);
+ }
+ return;
}
LERequest request;
@@ -820,8 +853,6 @@ using namespace QT_NAMESPACE;
requests.enqueue(request);
[self performNextRequest];
-
- return true;
}
// Aux. methods:
@@ -1039,8 +1070,6 @@ using namespace QT_NAMESPACE;
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
-
using namespace OSXBluetooth;
const CBCentralManagerState state = central.state;
@@ -1055,47 +1084,42 @@ using namespace QT_NAMESPACE;
return;
}
- if (disconnectPending) {
- disconnectPending = false;
- managerState = OSXBluetooth::CentralManagerIdle;
- return [self disconnectFromDevice];
- }
-
// Let's check some states we do not like first:
if (state == CBCentralManagerStateUnsupported || state == CBCentralManagerStateUnauthorized) {
if (managerState == CentralManagerUpdating) {
// We tried to connect just to realize, LE is not supported. Report this.
managerState = CentralManagerIdle;
- delegate->LEnotSupported();
+ if (notifier)
+ emit notifier->LEnotSupported();
} else {
// TODO: if we are here, LE _was_ supported and we first managed to update
// and reset managerState from CentralManagerUpdating.
managerState = CentralManagerIdle;
- delegate->error(QLowEnergyController::InvalidBluetoothAdapterError);
+ if (notifier)
+ emit notifier->CBCentralManagerError(QLowEnergyController::InvalidBluetoothAdapterError);
}
return;
}
if (state == CBCentralManagerStatePoweredOff) {
+ managerState = CentralManagerIdle;
if (managerState == CentralManagerUpdating) {
- // I've seen this instead of Unsopported on OS X.
- managerState = CentralManagerIdle;
- delegate->LEnotSupported();
+ // I've seen this instead of Unsupported on OS X.
+ if (notifier)
+ emit notifier->LEnotSupported();
} else {
- managerState = CentralManagerIdle;
// TODO: we need a better error +
// what will happen if later the state changes to PoweredOn???
- delegate->error(QLowEnergyController::InvalidBluetoothAdapterError);
+ if (notifier)
+ emit notifier->CBCentralManagerError(QLowEnergyController::InvalidBluetoothAdapterError);
}
return;
}
if (state == CBCentralManagerStatePoweredOn) {
- if (managerState == CentralManagerUpdating) {
+ if (managerState == CentralManagerUpdating && !disconnectPending) {
managerState = CentralManagerIdle;
- const QLowEnergyController::Error status = [self connectToDevice];
- if (status != QLowEnergyController::NoError)// An allocation problem?
- delegate->error(status);
+ [self retrievePeripheralAndConnect];
}
} else {
// We actually handled all known states, but .. Core Bluetooth can change?
@@ -1118,12 +1142,9 @@ using namespace QT_NAMESPACE;
managerState = OSXBluetooth::CentralManagerIdle;
if (!peripherals || peripherals.count != 1) {
- Q_ASSERT_X(delegate, Q_FUNC_INFO,
- "invalid delegate (null)");
-
qCDebug(QT_BT_OSX) << Q_FUNC_INFO <<"unexpected number of peripherals (!= 1)";
-
- delegate->error(QLowEnergyController::UnknownRemoteDeviceError);
+ if (notifier)
+ emit notifier->CBCentralManagerError(QLowEnergyController::UnknownRemoteDeviceError);
} else {
peripheral = [static_cast<CBPeripheral *>([peripherals objectAtIndex:0]) retain];
[self connectToPeripheral];
@@ -1135,15 +1156,14 @@ using namespace QT_NAMESPACE;
Q_UNUSED(central)
Q_UNUSED(aPeripheral)
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
-
if (managerState != OSXBluetooth::CentralManagerConnecting) {
// We called cancel but before disconnected, managed to connect?
return;
}
managerState = OSXBluetooth::CentralManagerIdle;
- delegate->connectSuccess();
+ if (notifier)
+ emit notifier->connected();
}
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)aPeripheral
@@ -1153,8 +1173,6 @@ using namespace QT_NAMESPACE;
Q_UNUSED(aPeripheral)
Q_UNUSED(error)
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
-
if (managerState != OSXBluetooth::CentralManagerConnecting) {
// Canceled already.
return;
@@ -1162,7 +1180,8 @@ using namespace QT_NAMESPACE;
managerState = OSXBluetooth::CentralManagerIdle;
// TODO: better error mapping is required.
- delegate->error(QLowEnergyController::UnknownRemoteDeviceError);
+ if (notifier)
+ notifier->CBCentralManagerError(QLowEnergyController::UnknownRemoteDeviceError);
}
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)aPeripheral
@@ -1171,19 +1190,18 @@ using namespace QT_NAMESPACE;
Q_UNUSED(central)
Q_UNUSED(aPeripheral)
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
-
// Clear internal caches/data.
[self reset];
if (error && managerState == OSXBluetooth::CentralManagerDisconnecting) {
managerState = OSXBluetooth::CentralManagerIdle;
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to disconnect";
- // TODO: instead of 'unknown' - .. ?
- delegate->error(QLowEnergyController::UnknownRemoteDeviceError);
+ if (notifier)
+ emit notifier->CBCentralManagerError(QLowEnergyController::UnknownRemoteDeviceError);
} else {
managerState = OSXBluetooth::CentralManagerIdle;
- delegate->disconnected();
+ if (notifier)
+ emit notifier->disconnected();
}
}
@@ -1201,10 +1219,10 @@ using namespace QT_NAMESPACE;
managerState = OSXBluetooth::CentralManagerIdle;
if (error) {
- // NSLog, not qCDebug/Warning - to print the error.
NSLog(@"%s failed with error %@", Q_FUNC_INFO, error);
// TODO: better error mapping required.
- delegate->error(QLowEnergyController::UnknownError);
+ if (notifier)
+ emit notifier->CBCentralManagerError(QLowEnergyController::UnknownError);
} else {
[self discoverIncludedServices];
}
@@ -1225,14 +1243,11 @@ using namespace QT_NAMESPACE;
QT_BT_MAC_AUTORELEASEPOOL;
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
Q_ASSERT_X(peripheral, Q_FUNC_INFO, "invalid peripheral (nil)");
- // TODO: asserts on other "pointers" ...
managerState = CentralManagerIdle;
if (error) {
- // NSLog, not qCWarning/Critical - to log the actual NSError and service UUID.
NSLog(@"%s: finished with error %@ for service %@",
Q_FUNC_INFO, error, service.UUID);
} else if (service.includedServices && service.includedServices.count) {
@@ -1279,8 +1294,8 @@ using namespace QT_NAMESPACE;
servicesToVisit.reset(nil);
servicesToVisitNext.reset(nil);
- const ObjCStrongReference<NSArray> services(peripheral.services, true); // true == retain.
- delegate->serviceDiscoveryFinished(services);
+ if (notifier)
+ emit notifier->serviceDiscoveryFinished();
}
- (void)peripheral:(CBPeripheral *)aPeripheral didDiscoverCharacteristicsForService:(CBService *)service
@@ -1290,21 +1305,20 @@ using namespace QT_NAMESPACE;
// discoveries active.
Q_UNUSED(aPeripheral)
- // TODO: check that this can never be called after cancelPeripheralConnection was executed.
+ if (!notifier) {
+ // Detached.
+ return;
+ }
using namespace OSXBluetooth;
- Q_ASSERT_X(managerState != CentralManagerUpdating,
- Q_FUNC_INFO, "invalid state");
- Q_ASSERT_X(delegate, Q_FUNC_INFO,
- "invalid delegate (null)");
+ Q_ASSERT_X(managerState != CentralManagerUpdating, Q_FUNC_INFO, "invalid state");
if (error) {
- // NSLog to show the actual NSError (can contain something interesting).
NSLog(@"%s failed with error: %@", Q_FUNC_INFO, error);
// We did not discover any characteristics and can not discover descriptors,
// inform our delegate (it will set a service state also).
- delegate->error(qt_uuid(service.UUID), QLowEnergyController::UnknownError);
+ emit notifier->CBCentralManagerError(qt_uuid(service.UUID), QLowEnergyController::UnknownError);
} else {
[self readCharacteristics:service];
}
@@ -1316,11 +1330,15 @@ using namespace QT_NAMESPACE;
{
Q_UNUSED(aPeripheral)
+ if (!notifier) {
+ // Detached.
+ return;
+ }
+
using namespace OSXBluetooth;
Q_ASSERT_X(managerState != CentralManagerUpdating, Q_FUNC_INFO, "invalid state");
Q_ASSERT_X(peripheral, Q_FUNC_INFO, "invalid peripheral (nil)");
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
QT_BT_MAC_AUTORELEASEPOOL;
// First, let's check if we're discovering a service details now.
@@ -1330,13 +1348,12 @@ using namespace QT_NAMESPACE;
const QLowEnergyHandle chHandle = charMap.key(characteristic);
if (error) {
- // Use NSLog, not qCDebug/qCWarning to log the actual error.
NSLog(@"%s failed with error %@", Q_FUNC_INFO, error);
if (!isDetailsDiscovery) {
if (chHandle && chHandle == currentReadHandle) {
currentReadHandle = 0;
requestPending = false;
- delegate->error(qtUuid, QLowEnergyService::CharacteristicReadError);
+ emit notifier->CBCentralManagerError(qtUuid, QLowEnergyService::CharacteristicReadError);
[self performNextRequest];
}
return;
@@ -1370,10 +1387,10 @@ using namespace QT_NAMESPACE;
requestPending = false;
currentReadHandle = 0;
//
- delegate->characteristicReadNotification(chHandle, qt_bytearray(characteristic.value));
+ emit notifier->characteristicRead(chHandle, qt_bytearray(characteristic.value));
[self performNextRequest];
} else {
- delegate->characteristicUpdateNotification(chHandle, qt_bytearray(characteristic.value));
+ emit notifier->characteristicUpdated(chHandle, qt_bytearray(characteristic.value));
}
}
}
@@ -1386,12 +1403,16 @@ using namespace QT_NAMESPACE;
// have several discoveries active at the same time.
Q_UNUSED(aPeripheral)
+ if (!notifier) {
+ // Detached, no need to continue ...
+ return;
+ }
+
QT_BT_MAC_AUTORELEASEPOOL;
using namespace OSXBluetooth;
if (error) {
- // Log the error using NSLog:
NSLog(@"%s failed with error %@", Q_FUNC_INFO, error);
// We can continue though ...
}
@@ -1413,6 +1434,11 @@ using namespace QT_NAMESPACE;
Q_ASSERT_X(peripheral, Q_FUNC_INFO, "invalid peripheral (nil)");
+ if (!notifier) {
+ // Detached ...
+ return;
+ }
+
QT_BT_MAC_AUTORELEASEPOOL;
using namespace OSXBluetooth;
@@ -1423,14 +1449,13 @@ using namespace QT_NAMESPACE;
const QLowEnergyHandle dHandle = descMap.key(descriptor);
if (error) {
- // NSLog to log the actual error ...
NSLog(@"%s failed with error %@", Q_FUNC_INFO, error);
if (!isDetailsDiscovery) {
if (dHandle && dHandle == currentReadHandle) {
currentReadHandle = 0;
requestPending = false;
- delegate->error(qtUuid, QLowEnergyService::DescriptorReadError);
+ emit notifier->CBCentralManagerError(qtUuid, QLowEnergyService::DescriptorReadError);
[self performNextRequest];
}
return;
@@ -1470,7 +1495,7 @@ using namespace QT_NAMESPACE;
if (dHandle == currentReadHandle) {
currentReadHandle = 0;
requestPending = false;
- delegate->descriptorReadNotification(dHandle, qt_bytearray(static_cast<NSObject *>(descriptor.value)));
+ emit notifier->descriptorRead(dHandle, qt_bytearray(static_cast<NSObject *>(descriptor.value)));
[self performNextRequest];
}
}
@@ -1483,6 +1508,11 @@ using namespace QT_NAMESPACE;
Q_UNUSED(aPeripheral)
Q_UNUSED(characteristic)
+ if (!notifier) {
+ // Detached.
+ return;
+ }
+
// From docs:
//
// "This method is invoked only when your app calls the writeValue:forCharacteristic:type:
@@ -1496,8 +1526,6 @@ using namespace QT_NAMESPACE;
requestPending = false;
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
-
// Error or not, but the cached value has to be deleted ...
const QByteArray valueToReport(valuesToWrite.value(characteristic, QByteArray()));
@@ -1507,15 +1535,12 @@ using namespace QT_NAMESPACE;
}
if (error) {
- // Use NSLog to log the actual error:
NSLog(@"%s failed with error %@", Q_FUNC_INFO, error);
- delegate->error(qt_uuid(characteristic.service.UUID),
- QLowEnergyService::CharacteristicWriteError);
+ emit notifier->CBCentralManagerError(qt_uuid(characteristic.service.UUID),
+ QLowEnergyService::CharacteristicWriteError);
} else {
- // Keys are unique.
const QLowEnergyHandle cHandle = charMap.key(characteristic);
- Q_ASSERT_X(cHandle, Q_FUNC_INFO, "invalid handle, not found in the characteristics map");
- delegate->characteristicWriteNotification(cHandle, valueToReport);
+ emit notifier->characteristicWritten(cHandle, valueToReport);
}
[self performNextRequest];
@@ -1527,7 +1552,10 @@ using namespace QT_NAMESPACE;
{
Q_UNUSED(aPeripheral)
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
+ if (!notifier) {
+ // Detached already.
+ return;
+ }
using namespace OSXBluetooth;
@@ -1535,23 +1563,20 @@ using namespace QT_NAMESPACE;
requestPending = false;
- using namespace OSXBluetooth;
-
// Error or not, a value (if any) must be removed.
const QByteArray valueToReport(valuesToWrite.value(descriptor, QByteArray()));
if (!valuesToWrite.remove(descriptor))
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no updated value found";
if (error) {
- // NSLog to log the actual NSError:
NSLog(@"%s failed with error %@", Q_FUNC_INFO, error);
- delegate->error(qt_uuid(descriptor.characteristic.service.UUID),
- QLowEnergyService::DescriptorWriteError);
+ emit notifier->CBCentralManagerError(qt_uuid(descriptor.characteristic.service.UUID),
+ QLowEnergyService::DescriptorWriteError);
} else {
const QLowEnergyHandle dHandle = descMap.key(descriptor);
Q_ASSERT_X(dHandle, Q_FUNC_INFO,
"descriptor not found in the descriptors map");
- delegate->descriptorWriteNotification(dHandle, valueToReport);
+ emit notifier->descriptorWritten(dHandle, valueToReport);
}
[self performNextRequest];
@@ -1563,40 +1588,42 @@ using namespace QT_NAMESPACE;
{
Q_UNUSED(aPeripheral)
+ if (!notifier)
+ return;
+
using namespace OSXBluetooth;
QT_BT_MAC_AUTORELEASEPOOL;
requestPending = false;
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (nil)");
-
const QBluetoothUuid qtUuid(QBluetoothUuid::ClientCharacteristicConfiguration);
CBDescriptor *const descriptor = [self descriptor:qtUuid forCharacteristic:characteristic];
const QByteArray valueToReport(valuesToWrite.value(descriptor, QByteArray()));
const int nRemoved = valuesToWrite.remove(descriptor);
if (error) {
- // NSLog to log the actual NSError:
NSLog(@"%s failed with error %@", Q_FUNC_INFO, error);
- delegate->error(qt_uuid(characteristic.service.UUID),
- // In Qt's API it's a descriptor write actually.
- QLowEnergyService::DescriptorWriteError);
- } else {
- if (nRemoved) {
- const QLowEnergyHandle dHandle = descMap.key(descriptor);
- delegate->descriptorWriteNotification(dHandle, valueToReport);
- } else {
- /*
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << ": notification value set to "
- << int(characteristic.isNotifying)
- << " but no client characteristic configuration descriptor found"
- " or no previous writeDescriptor request found";
- */
- }
+ // In Qt's API it's a descriptor write actually.
+ emit notifier->CBCentralManagerError(qt_uuid(characteristic.service.UUID),
+ QLowEnergyService::DescriptorWriteError);
+ } else if (nRemoved) {
+ const QLowEnergyHandle dHandle = descMap.key(descriptor);
+ emit notifier->descriptorWritten(dHandle, valueToReport);
}
[self performNextRequest];
}
+- (void)detach
+{
+ if (notifier) {
+ notifier->disconnect();
+ notifier->deleteLater();
+ notifier = 0;
+ }
+
+ [self disconnectFromDevice];
+}
+
@end
diff --git a/src/bluetooth/osx/osxbtcentralmanager_p.h b/src/bluetooth/osx/osxbtcentralmanager_p.h
index 429bae91..1ff33c12 100644
--- a/src/bluetooth/osx/osxbtcentralmanager_p.h
+++ b/src/bluetooth/osx/osxbtcentralmanager_p.h
@@ -69,41 +69,7 @@ class QLowEnergyServicePrivate;
namespace OSXBluetooth {
-class CentralManagerDelegate
-{
-public:
- typedef QT_MANGLE_NAMESPACE(OSXBTCentralManager) ObjCCentralManager;
- typedef ObjCStrongReference<NSArray> LEServices;
- typedef QSharedPointer<QLowEnergyServicePrivate> LEService;
- typedef ObjCStrongReference<CBCharacteristic> LECharacteristic;
-
- virtual ~CentralManagerDelegate();
-
- virtual void LEnotSupported() = 0;
- virtual void connectSuccess() = 0;
- virtual void serviceDiscoveryFinished(LEServices services) = 0;
- virtual void serviceDetailsDiscoveryFinished(LEService service) = 0;
- virtual void characteristicReadNotification(QLowEnergyHandle charHandle,
- const QByteArray &value) = 0;
- virtual void characteristicWriteNotification(QLowEnergyHandle charHandle,
- const QByteArray &value) = 0;
- virtual void characteristicUpdateNotification(QLowEnergyHandle charHandle,
- const QByteArray &value) = 0;
- virtual void descriptorReadNotification(QLowEnergyHandle descHandle,
- const QByteArray &value) = 0;
- virtual void descriptorWriteNotification(QLowEnergyHandle descHandle,
- const QByteArray &value) = 0;
- virtual void disconnected() = 0;
-
- // General errors.
- virtual void error(QLowEnergyController::Error error) = 0;
- // Service related errors.
- virtual void error(const QBluetoothUuid &serviceUuid,
- QLowEnergyController::Error error) = 0;
- // Characteristics/descriptors related errors.
- virtual void error(const QBluetoothUuid &serviceUuid,
- QLowEnergyService::ServiceError error) = 0;
-};
+class LECentralNotifier;
enum CentralManagerState
{
@@ -126,8 +92,8 @@ typedef QHash<QLowEnergyHandle, CBService *> ServiceHash;
typedef QHash<QLowEnergyHandle, CBCharacteristic *> CharHash;
typedef QHash<QLowEnergyHandle, CBDescriptor *> DescHash;
-// Descriptor/charactesirsti read/write requests
-// - we have to serialize 'concurrent' write requests.
+// Descriptor/charactesirstic read/write requests
+// - we have to serialize 'concurrent' requests.
struct LERequest {
enum RequestType {
CharRead,
@@ -165,14 +131,14 @@ QT_END_NAMESPACE
@interface QT_MANGLE_NAMESPACE(OSXBTCentralManager) : NSObject<CBCentralManagerDelegate, CBPeripheralDelegate>
{
+@private
CBCentralManager *manager;
QT_PREPEND_NAMESPACE(OSXBluetooth)::CentralManagerState managerState;
bool disconnectPending;
QT_PREPEND_NAMESPACE(QBluetoothUuid) deviceUuid;
- CBPeripheral *peripheral;
- QT_PREPEND_NAMESPACE(OSXBluetooth)::CentralManagerDelegate *delegate;
+ QT_PREPEND_NAMESPACE(OSXBluetooth)::LECentralNotifier *notifier;
// Quite a verbose service discovery machinery
// (a "graph traversal").
@@ -197,32 +163,43 @@ QT_END_NAMESPACE
QT_PREPEND_NAMESPACE(QLowEnergyHandle) currentReadHandle;
QT_PREPEND_NAMESPACE(OSXBluetooth)::ValueHash valuesToWrite;
+@public
+ CBPeripheral *peripheral;
}
-- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(OSXBluetooth)::CentralManagerDelegate *)aDelegate;
+- (id)initWith:(QT_PREPEND_NAMESPACE(OSXBluetooth)::LECentralNotifier *)notifier;
- (void)dealloc;
-- (QT_PREPEND_NAMESPACE(QLowEnergyController)::Error)
- connectToDevice:(const QT_PREPEND_NAMESPACE(QBluetoothUuid) &)aDeviceUuid;
+// IMPORTANT: _all_ these methods are to be executed on qt_LE_queue,
+// when passing parameters - C++ objects _must_ be copied (see the controller's code).
+- (void)connectToDevice:(const QT_PREPEND_NAMESPACE(QBluetoothUuid) &)aDeviceUuid;
- (void)disconnectFromDevice;
- (void)discoverServices;
-- (bool)discoverServiceDetails:(const QT_PREPEND_NAMESPACE(QBluetoothUuid) &)serviceUuid;
+- (void)discoverServiceDetails:(const QT_PREPEND_NAMESPACE(QBluetoothUuid) &)serviceUuid;
-- (bool)setNotifyValue:(const QT_PREPEND_NAMESPACE(QByteArray) &)value
- forCharacteristic:(QT_PREPEND_NAMESPACE(QLowEnergyHandle))charHandle;
+- (void)setNotifyValue:(const QT_PREPEND_NAMESPACE(QByteArray) &)value
+ forCharacteristic:(QT_PREPEND_NAMESPACE(QLowEnergyHandle))charHandle
+ onService:(const QT_PREPEND_NAMESPACE(QBluetoothUuid) &)serviceUuid;
-- (bool)readCharacteristic:(QT_PREPEND_NAMESPACE(QLowEnergyHandle))charHandle;
+- (void)readCharacteristic:(QT_PREPEND_NAMESPACE(QLowEnergyHandle))charHandle
+ onService:(const QT_PREPEND_NAMESPACE(QBluetoothUuid) &)serviceUuid;
-- (bool)write:(const QT_PREPEND_NAMESPACE(QByteArray) &)value
+- (void)write:(const QT_PREPEND_NAMESPACE(QByteArray) &)value
charHandle:(QT_PREPEND_NAMESPACE(QLowEnergyHandle))charHandle
+ onService:(const QT_PREPEND_NAMESPACE(QBluetoothUuid) &)serviceUuid
withResponse:(bool)writeWithResponse;
-- (bool)readDescriptor:(QT_PREPEND_NAMESPACE(QLowEnergyHandle))descHandle;
+- (void)readDescriptor:(QT_PREPEND_NAMESPACE(QLowEnergyHandle))descHandle
+ onService:(const QT_PREPEND_NAMESPACE(QBluetoothUuid) &)serviceUuid;
+
+- (void)write:(const QT_PREPEND_NAMESPACE(QByteArray) &)value
+ descHandle:(QT_PREPEND_NAMESPACE(QLowEnergyHandle))descHandle
+ onService:(const QT_PREPEND_NAMESPACE(QBluetoothUuid) &)serviceUuid;
+
+- (void)detach;
-- (bool)write:(const QT_PREPEND_NAMESPACE(QByteArray) &)value
- descHandle:(QT_PREPEND_NAMESPACE(QLowEnergyHandle))descHandle;
@end
#endif
diff --git a/src/bluetooth/osx/osxbtnotifier.cpp b/src/bluetooth/osx/osxbtnotifier.cpp
new file mode 100644
index 00000000..0e0343cf
--- /dev/null
+++ b/src/bluetooth/osx/osxbtnotifier.cpp
@@ -0,0 +1 @@
+#include "osxbtnotifier_p.h"
diff --git a/src/bluetooth/osx/osxbtnotifier_p.h b/src/bluetooth/osx/osxbtnotifier_p.h
new file mode 100644
index 00000000..7b4d18e4
--- /dev/null
+++ b/src/bluetooth/osx/osxbtnotifier_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OSXBTNOTIFIER_P_H
+#define OSXBTNOTIFIER_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 "qlowenergycontroller.h"
+#include "qbluetoothuuid.h"
+#include "qbluetooth.h"
+
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QLowEnergyServicePrivate;
+
+namespace OSXBluetooth
+{
+
+class LECentralNotifier : public QObject
+{
+ Q_OBJECT
+
+Q_SIGNALS:
+ void connected();
+ void disconnected();
+
+ void serviceDiscoveryFinished();
+ void serviceDetailsDiscoveryFinished(QSharedPointer<QLowEnergyServicePrivate> service);
+ void characteristicRead(QLowEnergyHandle charHandle, const QByteArray &value);
+ void characteristicWritten(QLowEnergyHandle charHandle, const QByteArray &value);
+ void characteristicUpdated(QLowEnergyHandle charHandle, const QByteArray &value);
+ void descriptorRead(QLowEnergyHandle descHandle, const QByteArray &value);
+ void descriptorWritten(QLowEnergyHandle descHandle, const QByteArray &value);
+
+ void LEnotSupported();
+ void CBCentralManagerError(QLowEnergyController::Error error);
+ void CBCentralManagerError(const QBluetoothUuid &serviceUuid, QLowEnergyController::Error error);
+ void CBCentralManagerError(const QBluetoothUuid &serviceUuid, QLowEnergyService::ServiceError error);
+
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/bluetooth/osx/osxbtobexsession_p.h b/src/bluetooth/osx/osxbtobexsession_p.h
index ac2699cf..0e72ecea 100644
--- a/src/bluetooth/osx/osxbtobexsession_p.h
+++ b/src/bluetooth/osx/osxbtobexsession_p.h
@@ -31,6 +31,17 @@
**
****************************************************************************/
+//
+// 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/qvariant.h>
#include <QtCore/qglobal.h>
diff --git a/src/bluetooth/qbluetoothserviceinfo.cpp b/src/bluetooth/qbluetoothserviceinfo.cpp
index fefb2549..f41f1e79 100644
--- a/src/bluetooth/qbluetoothserviceinfo.cpp
+++ b/src/bluetooth/qbluetoothserviceinfo.cpp
@@ -548,6 +548,7 @@ static void dumpAttributeVariant(const QVariant &var, const QString indent)
break;
case QMetaType::UShort:
qDebug("%sushort %u", indent.toLocal8Bit().constData(), var.toUInt());
+ break;
case QMetaType::UInt:
qDebug("%suint %u", indent.toLocal8Bit().constData(), var.toUInt());
break;
diff --git a/src/bluetooth/qbluetoothtransferreply.cpp b/src/bluetooth/qbluetoothtransferreply.cpp
index e0d30a60..9c5d976d 100644
--- a/src/bluetooth/qbluetoothtransferreply.cpp
+++ b/src/bluetooth/qbluetoothtransferreply.cpp
@@ -200,6 +200,7 @@ void QBluetoothTransferReply::setRequest(const QBluetoothTransferRequest &reques
*/
QBluetoothTransferReplyPrivate::QBluetoothTransferReplyPrivate()
+ : m_manager(0)
{
}
diff --git a/src/bluetooth/qlowenergycontroller_android.cpp b/src/bluetooth/qlowenergycontroller_android.cpp
index 767c91f8..fd4ea753 100644
--- a/src/bluetooth/qlowenergycontroller_android.cpp
+++ b/src/bluetooth/qlowenergycontroller_android.cpp
@@ -263,7 +263,7 @@ void QLowEnergyControllerPrivate::readCharacteristic(
}
if (!result)
- service->setError(QLowEnergyService::CharacteristicWriteError);
+ service->setError(QLowEnergyService::CharacteristicReadError);
}
void QLowEnergyControllerPrivate::readDescriptor(
@@ -289,7 +289,7 @@ void QLowEnergyControllerPrivate::readDescriptor(
}
if (!result)
- service->setError(QLowEnergyService::DescriptorWriteError);
+ service->setError(QLowEnergyService::DescriptorReadError);
}
void QLowEnergyControllerPrivate::connectionUpdated(
diff --git a/src/bluetooth/qlowenergycontroller_osx.mm b/src/bluetooth/qlowenergycontroller_osx.mm
index 396f82bb..e38442e2 100644
--- a/src/bluetooth/qlowenergycontroller_osx.mm
+++ b/src/bluetooth/qlowenergycontroller_osx.mm
@@ -62,6 +62,8 @@ static void registerQLowEnergyControllerMetaType()
if (!initDone) {
qRegisterMetaType<QLowEnergyController::ControllerState>();
qRegisterMetaType<QLowEnergyController::Error>();
+ qRegisterMetaType<QLowEnergyHandle>("QLowEnergyHandle");
+ qRegisterMetaType<QSharedPointer<QLowEnergyServicePrivate> >();
initDone = true;
}
}
@@ -139,12 +141,23 @@ QLowEnergyControllerPrivateOSX::QLowEnergyControllerPrivateOSX(QLowEnergyControl
// This is the "wrong" constructor - no valid device UUID to connect later.
Q_ASSERT_X(q, Q_FUNC_INFO, "invalid q_ptr (null)");
+
+ using OSXBluetooth::LECentralNotifier;
+
// We still create a manager, to simplify error handling later.
- centralManager.reset([[ObjCCentralManager alloc] initWithDelegate:this]);
+ QScopedPointer<LECentralNotifier> notifier(new LECentralNotifier);
+ centralManager.reset([[ObjCCentralManager alloc] initWith:notifier.data()]);
if (!centralManager) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO
<< "failed to initialize central manager";
+ return;
+ } else if (!connectSlots(notifier.data())) {
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO
+ << "failed to connect to notifier's signals";
}
+
+ // Ownership was taken by central manager.
+ notifier.take();
}
QLowEnergyControllerPrivateOSX::QLowEnergyControllerPrivateOSX(QLowEnergyController *q,
@@ -160,33 +173,41 @@ QLowEnergyControllerPrivateOSX::QLowEnergyControllerPrivateOSX(QLowEnergyControl
registerQLowEnergyControllerMetaType();
Q_ASSERT_X(q, Q_FUNC_INFO, "invalid q_ptr (null)");
- centralManager.reset([[ObjCCentralManager alloc] initWithDelegate:this]);
+
+ using OSXBluetooth::LECentralNotifier;
+
+ QScopedPointer<LECentralNotifier> notifier(new LECentralNotifier);
+ centralManager.reset([[ObjCCentralManager alloc] initWith:notifier.data()]);
if (!centralManager) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO
<< "failed to initialize central manager";
+ return;
+ } else if (!connectSlots(notifier.data())) {
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO
+ << "failed to connect to notifier's signals";
}
+
+ // Ownership was taken by central manager.
+ notifier.take();
}
QLowEnergyControllerPrivateOSX::~QLowEnergyControllerPrivateOSX()
{
+ // TODO: dispatch_sync 'setDelegate:Q_NULLPRT' to our CBCentralManager's delegate.
+ if (dispatch_queue_t leQueue = OSXBluetooth::qt_LE_queue()) {
+ ObjCCentralManager *manager = centralManager.data();
+ dispatch_sync(leQueue, ^{
+ [manager detach];
+ });
+ }
}
bool QLowEnergyControllerPrivateOSX::isValid() const
{
- // isValid means only "was able to allocate all resources",
- // nothing more.
return centralManager;
}
-void QLowEnergyControllerPrivateOSX::LEnotSupported()
-{
- // Report as an error. But this should not be possible
- // actually: before connecting to any device, we have
- // to discover it, if it was discovered ... LE _must_
- // be supported.
-}
-
-void QLowEnergyControllerPrivateOSX::connectSuccess()
+void QLowEnergyControllerPrivateOSX::_q_connected()
{
Q_ASSERT_X(controllerState == QLowEnergyController::ConnectingState,
Q_FUNC_INFO, "invalid state");
@@ -199,7 +220,17 @@ void QLowEnergyControllerPrivateOSX::connectSuccess()
}
}
-void QLowEnergyControllerPrivateOSX::serviceDiscoveryFinished(LEServices services)
+void QLowEnergyControllerPrivateOSX::_q_disconnected()
+{
+ controllerState = QLowEnergyController::UnconnectedState;
+
+ if (!isConnecting) {
+ emit q_ptr->stateChanged(QLowEnergyController::UnconnectedState);
+ emit q_ptr->disconnected();
+ }
+}
+
+void QLowEnergyControllerPrivateOSX::_q_serviceDiscoveryFinished()
{
Q_ASSERT_X(controllerState == QLowEnergyController::DiscoveringState,
Q_FUNC_INFO, "invalid state");
@@ -208,6 +239,7 @@ void QLowEnergyControllerPrivateOSX::serviceDiscoveryFinished(LEServices service
QT_BT_MAC_AUTORELEASEPOOL;
+ NSArray *const services = centralManager.data()->peripheral.services;
// Now we have to traverse the discovered services tree.
// Essentially it's an iterative version of more complicated code from the
// OSXBTCentralManager's code.
@@ -218,7 +250,7 @@ void QLowEnergyControllerPrivateOSX::serviceDiscoveryFinished(LEServices service
// during the pass 2); we also ignore duplicates (== services with the same UUID)
// - since we do not have a way to distinguish them later
// (our API is using uuids when creating QLowEnergyServices).
- for (CBService *cbService in services.data()) {
+ for (CBService *cbService in services) {
const ServicePrivate newService(qt_createLEService(this, cbService, false));
if (!newService.data())
continue;
@@ -281,7 +313,6 @@ void QLowEnergyControllerPrivateOSX::serviceDiscoveryFinished(LEServices service
for (ServiceMap::const_iterator it = discoveredServices.constBegin(); it != discoveredServices.constEnd(); ++it) {
const QBluetoothUuid &uuid = it.key();
-
QMetaObject::invokeMethod(q_ptr, "serviceDiscovered", Qt::QueuedConnection,
Q_ARG(QBluetoothUuid, uuid));
}
@@ -292,12 +323,12 @@ void QLowEnergyControllerPrivateOSX::serviceDiscoveryFinished(LEServices service
QMetaObject::invokeMethod(q_ptr, "discoveryFinished", Qt::QueuedConnection);
}
-void QLowEnergyControllerPrivateOSX::serviceDetailsDiscoveryFinished(LEService service)
+void QLowEnergyControllerPrivateOSX::_q_serviceDetailsDiscoveryFinished(QSharedPointer<QLowEnergyServicePrivate> service)
{
- Q_ASSERT_X(!service.isNull(), Q_FUNC_INFO, "invalid service (null)");
-
QT_BT_MAC_AUTORELEASEPOOL;
+ Q_ASSERT(service);
+
if (!discoveredServices.contains(service->uuid)) {
qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "unknown service uuid: "
<< service->uuid;
@@ -313,8 +344,8 @@ void QLowEnergyControllerPrivateOSX::serviceDetailsDiscoveryFinished(LEService s
qtService->setState(QLowEnergyService::ServiceDiscovered);
}
-void QLowEnergyControllerPrivateOSX::characteristicReadNotification(QLowEnergyHandle charHandle,
- const QByteArray &value)
+void QLowEnergyControllerPrivateOSX::_q_characteristicRead(QLowEnergyHandle charHandle,
+ const QByteArray &value)
{
Q_ASSERT_X(charHandle, Q_FUNC_INFO, "invalid characteristic handle(0)");
@@ -334,8 +365,8 @@ void QLowEnergyControllerPrivateOSX::characteristicReadNotification(QLowEnergyHa
emit service->characteristicRead(characteristic, value);
}
-void QLowEnergyControllerPrivateOSX::characteristicWriteNotification(QLowEnergyHandle charHandle,
- const QByteArray &value)
+void QLowEnergyControllerPrivateOSX::_q_characteristicWritten(QLowEnergyHandle charHandle,
+ const QByteArray &value)
{
Q_ASSERT_X(charHandle, Q_FUNC_INFO, "invalid characteristic handle(0)");
@@ -358,8 +389,8 @@ void QLowEnergyControllerPrivateOSX::characteristicWriteNotification(QLowEnergyH
emit service->characteristicWritten(characteristic, value);
}
-void QLowEnergyControllerPrivateOSX::characteristicUpdateNotification(QLowEnergyHandle charHandle,
- const QByteArray &value)
+void QLowEnergyControllerPrivateOSX::_q_characteristicUpdated(QLowEnergyHandle charHandle,
+ const QByteArray &value)
{
// TODO: write/update notifications are quite similar (except asserts/warnings messages
// and different signals emitted). Merge them into one function?
@@ -387,7 +418,8 @@ void QLowEnergyControllerPrivateOSX::characteristicUpdateNotification(QLowEnergy
emit service->characteristicChanged(characteristic, value);
}
-void QLowEnergyControllerPrivateOSX::descriptorReadNotification(QLowEnergyHandle dHandle, const QByteArray &value)
+void QLowEnergyControllerPrivateOSX::_q_descriptorRead(QLowEnergyHandle dHandle,
+ const QByteArray &value)
{
Q_ASSERT_X(dHandle, Q_FUNC_INFO, "invalid descriptor handle (0)");
@@ -402,7 +434,8 @@ void QLowEnergyControllerPrivateOSX::descriptorReadNotification(QLowEnergyHandle
emit service->descriptorRead(qtDescriptor, value);
}
-void QLowEnergyControllerPrivateOSX::descriptorWriteNotification(QLowEnergyHandle dHandle, const QByteArray &value)
+void QLowEnergyControllerPrivateOSX::_q_descriptorWritten(QLowEnergyHandle dHandle,
+ const QByteArray &value)
{
Q_ASSERT_X(dHandle, Q_FUNC_INFO, "invalid descriptor handle (0)");
@@ -418,29 +451,18 @@ void QLowEnergyControllerPrivateOSX::descriptorWriteNotification(QLowEnergyHandl
emit service->descriptorWritten(qtDescriptor, value);
}
-void QLowEnergyControllerPrivateOSX::disconnected()
+void QLowEnergyControllerPrivateOSX::_q_LEnotSupported()
{
- controllerState = QLowEnergyController::UnconnectedState;
-
- if (!isConnecting) {
- emit q_ptr->stateChanged(QLowEnergyController::UnconnectedState);
- emit q_ptr->disconnected();
- }
+ // Report as an error. But this should not be possible
+ // actually: before connecting to any device, we have
+ // to discover it, if it was discovered ... LE _must_
+ // be supported.
}
-void QLowEnergyControllerPrivateOSX::error(QLowEnergyController::Error errorCode)
+void QLowEnergyControllerPrivateOSX::_q_CBCentralManagerError(QLowEnergyController::Error errorCode)
{
// Errors reported during connect and general errors.
- // We're still in connectToDevice,
- // some error was reported synchronously.
- // Return, the error will be correctly set later
- // by connectToDevice.
- if (isConnecting) {
- lastError = errorCode;
- return;
- }
-
setErrorDescription(errorCode);
emit q_ptr->error(lastError);
@@ -454,8 +476,8 @@ void QLowEnergyControllerPrivateOSX::error(QLowEnergyController::Error errorCode
// a service/characteristic - related error.
}
-void QLowEnergyControllerPrivateOSX::error(const QBluetoothUuid &serviceUuid,
- QLowEnergyController::Error errorCode)
+void QLowEnergyControllerPrivateOSX::_q_CBCentralManagerError(const QBluetoothUuid &serviceUuid,
+ QLowEnergyController::Error errorCode)
{
// Errors reported while discovering service details etc.
Q_UNUSED(errorCode) // TODO: setError?
@@ -470,8 +492,8 @@ void QLowEnergyControllerPrivateOSX::error(const QBluetoothUuid &serviceUuid,
}
}
-void QLowEnergyControllerPrivateOSX::error(const QBluetoothUuid &serviceUuid,
- QLowEnergyService::ServiceError errorCode)
+void QLowEnergyControllerPrivateOSX::_q_CBCentralManagerError(const QBluetoothUuid &serviceUuid,
+ QLowEnergyService::ServiceError errorCode)
{
if (!discoveredServices.contains(serviceUuid)) {
qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "unknown service uuid: "
@@ -493,30 +515,21 @@ void QLowEnergyControllerPrivateOSX::connectToDevice()
Q_ASSERT_X(!isConnecting, Q_FUNC_INFO,
"recursive connectToDevice call");
- setErrorDescription(QLowEnergyController::NoError);
+ dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
+ if (!leQueue) {
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ setErrorDescription(QLowEnergyController::UnknownError);
+ return;
+ }
- isConnecting = true;// Do not emit signals if some callback is executed synchronously.
+ setErrorDescription(QLowEnergyController::NoError);
controllerState = QLowEnergyController::ConnectingState;
- const QLowEnergyController::Error status = [centralManager connectToDevice:deviceUuid];
- isConnecting = false;
- if (status == QLowEnergyController::NoError && lastError == QLowEnergyController::NoError) {
- emit q_ptr->stateChanged(controllerState);
- if (controllerState == QLowEnergyController::ConnectedState) {
- // If a peripheral is connected already from the Core Bluetooth's
- // POV:
- emit q_ptr->connected();
- } else if (controllerState == QLowEnergyController::UnconnectedState) {
- // Ooops, tried to connect, got peripheral disconnect instead -
- // this happens with Core Bluetooth.
- emit q_ptr->disconnected();
- }
- } else if (status != QLowEnergyController::NoError) {
- error(status);
- } else {
- // Re-set the error/description and emit.
- error(lastError);
- }
+ const QBluetoothUuid deviceUuidCopy(deviceUuid);
+ ObjCCentralManager *manager = centralManager.data();
+ dispatch_async(leQueue, ^{
+ [manager connectToDevice:deviceUuidCopy];
+ });
}
void QLowEnergyControllerPrivateOSX::discoverServices()
@@ -525,9 +538,20 @@ void QLowEnergyControllerPrivateOSX::discoverServices()
Q_ASSERT_X(controllerState != QLowEnergyController::UnconnectedState,
Q_FUNC_INFO, "not connected to peripheral");
+ dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
+ if (!leQueue) {
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ setErrorDescription(QLowEnergyController::UnknownError);
+ return;
+ }
+
controllerState = QLowEnergyController::DiscoveringState;
emit q_ptr->stateChanged(QLowEnergyController::DiscoveringState);
- [centralManager discoverServices];
+
+ ObjCCentralManager *manager = centralManager.data();
+ dispatch_async(leQueue, ^{
+ [manager discoverServices];
+ });
}
void QLowEnergyControllerPrivateOSX::discoverServiceDetails(const QBluetoothUuid &serviceUuid)
@@ -546,14 +570,20 @@ void QLowEnergyControllerPrivateOSX::discoverServiceDetails(const QBluetoothUuid
return;
}
- ServicePrivate qtService(discoveredServices.value(serviceUuid));
- if ([centralManager discoverServiceDetails:serviceUuid]) {
- qtService->setState(QLowEnergyService::DiscoveringServices);
- } else {
- // The error is returned by CentralManager - no
- // service with a given UUID found on a peripheral.
- qtService->setState(QLowEnergyService::InvalidService);
+ dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
+ if (!leQueue) {
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ return;
}
+
+ ServicePrivate qtService(discoveredServices.value(serviceUuid));
+ qtService->setState(QLowEnergyService::DiscoveringServices);
+ // Copy objects ...
+ ObjCCentralManager *manager = centralManager.data();
+ const QBluetoothUuid serviceUuidCopy(serviceUuid);
+ dispatch_async(leQueue, ^{
+ [manager discoverServiceDetails:serviceUuidCopy];
+ });
}
void QLowEnergyControllerPrivateOSX::setNotifyValue(QSharedPointer<QLowEnergyServicePrivate> service,
@@ -586,8 +616,19 @@ void QLowEnergyControllerPrivateOSX::setNotifyValue(QSharedPointer<QLowEnergySer
return;
}
- if (![centralManager setNotifyValue:newValue forCharacteristic:charHandle])
- service->setError(QLowEnergyService::DescriptorWriteError);
+ dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
+ if (!leQueue) {
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ return;
+ }
+ ObjCCentralManager *manager = centralManager.data();
+ const QBluetoothUuid serviceUuid(service->uuid);
+ const QByteArray newValueCopy(newValue);
+ dispatch_async(leQueue, ^{
+ [manager setNotifyValue:newValueCopy
+ forCharacteristic:charHandle
+ onService:serviceUuid];
+ });
}
void QLowEnergyControllerPrivateOSX::readCharacteristic(QSharedPointer<QLowEnergyServicePrivate> service,
@@ -608,8 +649,17 @@ void QLowEnergyControllerPrivateOSX::readCharacteristic(QSharedPointer<QLowEnerg
return;
}
- if (![centralManager readCharacteristic:charHandle])
- service->setError(QLowEnergyService::CharacteristicReadError);
+ dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
+ if (!leQueue) {
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ return;
+ }
+ // Attention! We have to copy UUID.
+ ObjCCentralManager *manager = centralManager.data();
+ const QBluetoothUuid serviceUuid(service->uuid);
+ dispatch_async(leQueue, ^{
+ [manager readCharacteristic:charHandle onService:serviceUuid];
+ });
}
void QLowEnergyControllerPrivateOSX::writeCharacteristic(QSharedPointer<QLowEnergyServicePrivate> service,
@@ -634,11 +684,21 @@ void QLowEnergyControllerPrivateOSX::writeCharacteristic(QSharedPointer<QLowEner
return;
}
- const bool result = [centralManager write:newValue
- charHandle:charHandle
- withResponse:writeWithResponse];
- if (!result)
- service->setError(QLowEnergyService::CharacteristicWriteError);
+ dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
+ if (!leQueue) {
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ return;
+ }
+ // Attention! Copy objects!
+ const QBluetoothUuid serviceUuid(service->uuid);
+ const QByteArray newValueCopy(newValue);
+ ObjCCentralManager *const manager = centralManager.data();
+ dispatch_async(leQueue, ^{
+ [manager write:newValueCopy
+ charHandle:charHandle
+ onService:serviceUuid
+ withResponse:writeWithResponse];
+ });
}
quint16 QLowEnergyControllerPrivateOSX::updateValueOfCharacteristic(QLowEnergyHandle charHandle,
@@ -650,7 +710,6 @@ quint16 QLowEnergyControllerPrivateOSX::updateValueOfCharacteristic(QLowEnergyHa
CharacteristicDataMap::iterator charIt = service->characteristicList.find(charHandle);
if (charIt != service->characteristicList.end()) {
QLowEnergyServicePrivate::CharData &charData = charIt.value();
-
if (appendValue)
charData.value += value;
else
@@ -675,8 +734,18 @@ void QLowEnergyControllerPrivateOSX::readDescriptor(QSharedPointer<QLowEnergySer
return;
}
- if (![centralManager readDescriptor:descriptorHandle])
- service->setError(QLowEnergyService::DescriptorReadError);
+ dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
+ if (!leQueue) {
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ return;
+ }
+ // Attention! Copy objects!
+ const QBluetoothUuid serviceUuid(service->uuid);
+ ObjCCentralManager * const manager = centralManager.data();
+ dispatch_async(leQueue, ^{
+ [manager readDescriptor:descriptorHandle
+ onService:serviceUuid];
+ });
}
void QLowEnergyControllerPrivateOSX::writeDescriptor(QSharedPointer<QLowEnergyServicePrivate> service,
@@ -695,8 +764,20 @@ void QLowEnergyControllerPrivateOSX::writeDescriptor(QSharedPointer<QLowEnergySe
return;
}
- if (![centralManager write:newValue descHandle:descriptorHandle])
- service->setError(QLowEnergyService::DescriptorWriteError);
+ dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
+ if (!leQueue) {
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ return;
+ }
+ // Attention! Copy objects!
+ const QBluetoothUuid serviceUuid(service->uuid);
+ ObjCCentralManager * const manager = centralManager.data();
+ const QByteArray newValueCopy(newValue);
+ dispatch_async(leQueue, ^{
+ [manager write:newValueCopy
+ descHandle:descriptorHandle
+ onService:serviceUuid];
+ });
}
quint16 QLowEnergyControllerPrivateOSX::updateValueOfDescriptor(QLowEnergyHandle charHandle, QLowEnergyHandle descHandle,
@@ -812,6 +893,45 @@ void QLowEnergyControllerPrivateOSX::invalidateServices()
discoveredServices.clear();
}
+bool QLowEnergyControllerPrivateOSX::connectSlots(OSXBluetooth::LECentralNotifier *notifier)
+{
+ using OSXBluetooth::LECentralNotifier;
+
+ Q_ASSERT_X(notifier, Q_FUNC_INFO, "invalid notifier object (null)");
+
+ bool ok = connect(notifier, &LECentralNotifier::connected,
+ this, &QLowEnergyControllerPrivateOSX::_q_connected);
+ ok = ok && connect(notifier, &LECentralNotifier::disconnected,
+ this, &QLowEnergyControllerPrivateOSX::_q_disconnected);
+ ok = ok && connect(notifier, &LECentralNotifier::serviceDiscoveryFinished,
+ this, &QLowEnergyControllerPrivateOSX::_q_serviceDiscoveryFinished);
+ ok = ok && connect(notifier, &LECentralNotifier::serviceDetailsDiscoveryFinished,
+ this, &QLowEnergyControllerPrivateOSX::_q_serviceDetailsDiscoveryFinished);
+ ok = ok && connect(notifier, &LECentralNotifier::characteristicRead,
+ this, &QLowEnergyControllerPrivateOSX::_q_characteristicRead);
+ ok = ok && connect(notifier, &LECentralNotifier::characteristicWritten,
+ this, &QLowEnergyControllerPrivateOSX::_q_characteristicWritten);
+ ok = ok && connect(notifier, &LECentralNotifier::characteristicUpdated,
+ this, &QLowEnergyControllerPrivateOSX::_q_characteristicUpdated);
+ ok = ok && connect(notifier, &LECentralNotifier::descriptorRead,
+ this, &QLowEnergyControllerPrivateOSX::_q_descriptorRead);
+ ok = ok && connect(notifier, &LECentralNotifier::descriptorWritten,
+ this, &QLowEnergyControllerPrivateOSX::_q_descriptorWritten);
+ ok = ok && connect(notifier, &LECentralNotifier::LEnotSupported,
+ this, &QLowEnergyControllerPrivateOSX::_q_LEnotSupported);
+ ok = ok && connect(notifier, SIGNAL(CBCentralManagerError(QLowEnergyController::Error)),
+ this, SLOT(_q_CBCentralManagerError(QLowEnergyController::Error)));
+ ok = ok && connect(notifier, SIGNAL(CBCentralManagerError(const QBluetoothUuid &, QLowEnergyController::Error)),
+ this, SLOT(_q_CBCentralManagerError(const QBluetoothUuid &, QLowEnergyController::Error)));
+ ok = ok && connect(notifier, SIGNAL(CBCentralManagerError(const QBluetoothUuid &, QLowEnergyService::ServiceError)),
+ this, SLOT(_q_CBCentralManagerError(const QBluetoothUuid &, QLowEnergyService::ServiceError)));
+
+ if (!ok)
+ notifier->disconnect();
+
+ return ok;
+}
+
QLowEnergyController::QLowEnergyController(const QBluetoothAddress &remoteAddress,
QObject *parent)
: QObject(parent),
@@ -909,11 +1029,11 @@ void QLowEnergyController::connectToDevice()
// A memory allocation problem.
if (!osx_d_ptr->isValid())
- return osx_d_ptr->error(UnknownError);
+ return osx_d_ptr->_q_CBCentralManagerError(UnknownError);
// No QBluetoothDeviceInfo provided during construction.
if (osx_d_ptr->deviceUuid.isNull())
- return osx_d_ptr->error(UnknownRemoteDeviceError);
+ return osx_d_ptr->_q_CBCentralManagerError(UnknownRemoteDeviceError);
if (osx_d_ptr->controllerState != UnconnectedState)
return;
@@ -931,18 +1051,28 @@ void QLowEnergyController::disconnectFromDevice()
if (osx_d_ptr->isValid()) {
const ControllerState oldState = osx_d_ptr->controllerState;
- osx_d_ptr->controllerState = ClosingState;
- emit stateChanged(ClosingState);
- osx_d_ptr->invalidateServices();
- [osx_d_ptr->centralManager disconnectFromDevice];
-
- if (oldState == ConnectingState) {
- // With a pending connect attempt there is no
- // guarantee we'll ever have didDisconnect callback,
- // set the state here and now to make sure we still
- // can connect.
- osx_d_ptr->controllerState = UnconnectedState;
- emit stateChanged(UnconnectedState);
+ if (dispatch_queue_t leQueue = OSXBluetooth::qt_LE_queue()) {
+ osx_d_ptr->controllerState = ClosingState;
+ emit stateChanged(ClosingState);
+ osx_d_ptr->invalidateServices();
+
+ QT_MANGLE_NAMESPACE(OSXBTCentralManager) *manager
+ = osx_d_ptr->centralManager.data();
+ dispatch_async(leQueue, ^{
+ [manager disconnectFromDevice];
+ });
+
+ if (oldState == ConnectingState) {
+ // With a pending connect attempt there is no
+ // guarantee we'll ever have didDisconnect callback,
+ // set the state here and now to make sure we still
+ // can connect.
+ osx_d_ptr->controllerState = UnconnectedState;
+ emit stateChanged(UnconnectedState);
+ }
+ } else {
+ qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "qt LE queue is nil,"
+ << "can not dispatch 'disconnect'";
}
}
}
@@ -996,3 +1126,5 @@ QString QLowEnergyController::errorString() const
}
QT_END_NAMESPACE
+
+#include "moc_qlowenergycontroller_osx_p.cpp"
diff --git a/src/bluetooth/qlowenergycontroller_osx_p.h b/src/bluetooth/qlowenergycontroller_osx_p.h
index 1c1cb1cd..2d1b2e95 100644
--- a/src/bluetooth/qlowenergycontroller_osx_p.h
+++ b/src/bluetooth/qlowenergycontroller_osx_p.h
@@ -49,6 +49,7 @@
#include "osx/osxbtcentralmanager_p.h"
#include "qlowenergycontroller_p.h"
#include "qlowenergycontroller.h"
+#include "osx/osxbtnotifier_p.h"
#include "osx/osxbtutility_p.h"
#include "qbluetoothaddress.h"
#include "qbluetoothuuid.h"
@@ -60,14 +61,22 @@
QT_BEGIN_NAMESPACE
+namespace OSXBluetooth
+{
+
+class LECentralNotifier;
+
+}
+
class QByteArray;
-// The suffix OSX is not the very right, it's also iOS.
-class QLowEnergyControllerPrivateOSX : public QLowEnergyControllerPrivate,
- public OSXBluetooth::CentralManagerDelegate
+// While suffix 'OSX', it's also for iOS.
+class QLowEnergyControllerPrivateOSX : public QLowEnergyControllerPrivate
{
friend class QLowEnergyController;
friend class QLowEnergyService;
+
+ Q_OBJECT
public:
QLowEnergyControllerPrivateOSX(QLowEnergyController *q);
QLowEnergyControllerPrivateOSX(QLowEnergyController *q,
@@ -76,30 +85,25 @@ public:
bool isValid() const;
-private:
- // CentralManagerDelegate:
- void LEnotSupported() Q_DECL_OVERRIDE;
- void connectSuccess() Q_DECL_OVERRIDE;
-
- void serviceDiscoveryFinished(LEServices services) Q_DECL_OVERRIDE;
- void serviceDetailsDiscoveryFinished(LEService service) Q_DECL_OVERRIDE;
- void characteristicReadNotification(QLowEnergyHandle charHandle,
- const QByteArray &value) Q_DECL_OVERRIDE;
- void characteristicWriteNotification(QLowEnergyHandle charHandle,
- const QByteArray &newValue) Q_DECL_OVERRIDE;
- void characteristicUpdateNotification(QLowEnergyHandle charHandle,
- const QByteArray &value) Q_DECL_OVERRIDE;
- void descriptorReadNotification(QLowEnergyHandle descHandle,
- const QByteArray &value) Q_DECL_OVERRIDE;
- void descriptorWriteNotification(QLowEnergyHandle descHandle,
- const QByteArray &newValue) Q_DECL_OVERRIDE;
- void disconnected() Q_DECL_OVERRIDE;
- void error(QLowEnergyController::Error errorCode) Q_DECL_OVERRIDE;
- void error(const QBluetoothUuid &serviceUuid,
- QLowEnergyController::Error errorCode) Q_DECL_OVERRIDE;
- void error(const QBluetoothUuid &serviceUuid,
- QLowEnergyService::ServiceError error) Q_DECL_OVERRIDE;
+private Q_SLOTS:
+ void _q_connected();
+ void _q_disconnected();
+
+ void _q_serviceDiscoveryFinished();
+ void _q_serviceDetailsDiscoveryFinished(QSharedPointer<QLowEnergyServicePrivate> service);
+
+ void _q_characteristicRead(QLowEnergyHandle charHandle, const QByteArray &value);
+ void _q_characteristicWritten(QLowEnergyHandle charHandle, const QByteArray &value);
+ void _q_characteristicUpdated(QLowEnergyHandle charHandle, const QByteArray &value);
+ void _q_descriptorRead(QLowEnergyHandle descHandle, const QByteArray &value);
+ void _q_descriptorWritten(QLowEnergyHandle charHandle, const QByteArray &value);
+ void _q_LEnotSupported();
+ void _q_CBCentralManagerError(QLowEnergyController::Error error);
+ void _q_CBCentralManagerError(const QBluetoothUuid &serviceUuid, QLowEnergyController::Error error);
+ void _q_CBCentralManagerError(const QBluetoothUuid &serviceUuid, QLowEnergyService::ServiceError error);
+
+private:
void connectToDevice();
void discoverServices();
void discoverServiceDetails(const QBluetoothUuid &serviceUuid);
@@ -139,6 +143,7 @@ private:
void setErrorDescription(QLowEnergyController::Error errorCode);
void invalidateServices();
+ bool connectSlots(OSXBluetooth::LECentralNotifier *notifier);
QLowEnergyController *q_ptr;
QBluetoothUuid deviceUuid;
@@ -159,6 +164,7 @@ private:
QLowEnergyController::ControllerState controllerState;
QLowEnergyController::RemoteAddressType addressType;
+ typedef QT_MANGLE_NAMESPACE(OSXBTCentralManager) ObjCCentralManager;
typedef OSXBluetooth::ObjCScopedPointer<ObjCCentralManager> CentralManager;
CentralManager centralManager;
diff --git a/src/bluetooth/qlowenergyservice.cpp b/src/bluetooth/qlowenergyservice.cpp
index 9cccbc93..30a66db8 100644
--- a/src/bluetooth/qlowenergyservice.cpp
+++ b/src/bluetooth/qlowenergyservice.cpp
@@ -584,13 +584,13 @@ bool QLowEnergyService::contains(const QLowEnergyCharacteristic &characteristic)
serialised. A queue is employed when issuing multiple requests at the same time.
The queue does not eliminate duplicated read requests for the same characteristic.
- A characteristic can only be read if the service is in the \l ServiceDiscovered state,
- belongs to the service. If one of these conditions is
+ A characteristic can only be read if the service is in the \l ServiceDiscovered state
+ and belongs to the service. If one of these conditions is
not true the \l QLowEnergyService::OperationError is set.
\note Calling this function despite \l QLowEnergyCharacteristic::properties() reporting a non-readable property
always attempts to read the characteristic's value on the hardware. If the hardware
- returns with an error the \l CharacteristicWriteError is set.
+ returns with an error the \l CharacteristicReadError is set.
\sa characteristicRead(), writeCharacteristic()
@@ -630,7 +630,7 @@ void QLowEnergyService::readCharacteristic(
\note Currently, it is not possible to use signed or reliable writes as defined by the
Bluetooth specification.
- A characteristic can only be written if this service is in the \l ServiceDiscovered state,
+ A characteristic can only be written if this service is in the \l ServiceDiscovered state
and belongs to the service. If one of these conditions is
not true the \l QLowEnergyService::OperationError is set.
diff --git a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp
index 65941fec..c9559296 100644
--- a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp
+++ b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp
@@ -314,7 +314,7 @@ void QDeclarativeBluetoothDiscoveryModel::serviceDiscovered(const QBluetoothServ
\qmlsignal BluetoothDiscoveryModel::deviceDiscovered(string device)
This signal is emitted when a new device is discovered. \a device contains
- the Bluetooth address of the discovred device.
+ the Bluetooth address of the discovered device.
The corresponding handler is \c onDeviceDiscovered.
*/
@@ -365,7 +365,7 @@ void QDeclarativeBluetoothDiscoveryModel::setDiscoveryMode(DiscoveryMode discove
\qmlproperty bool BluetoothDiscoveryModel::running
This property starts or stops discovery. A restart of the discovery process
- requires setting this property to \c false and subsequemtly to \c true again.
+ requires setting this property to \c false and subsequently to \c true again.
*/
diff --git a/src/nfc/qqmlndefrecord.cpp b/src/nfc/qqmlndefrecord.cpp
index 278cc583..b204d4d0 100644
--- a/src/nfc/qqmlndefrecord.cpp
+++ b/src/nfc/qqmlndefrecord.cpp
@@ -243,6 +243,11 @@ QQmlNdefRecord::QQmlNdefRecord(const QNdefRecord &record, QObject *parent)
d_ptr->record = record;
}
+QQmlNdefRecord::~QQmlNdefRecord()
+{
+ delete d_ptr;
+}
+
/*!
\enum QQmlNdefRecord::TypeNameFormat
diff --git a/src/nfc/qqmlndefrecord.h b/src/nfc/qqmlndefrecord.h
index dbd947ee..93a3106e 100644
--- a/src/nfc/qqmlndefrecord.h
+++ b/src/nfc/qqmlndefrecord.h
@@ -65,6 +65,7 @@ public:
explicit QQmlNdefRecord(QObject *parent = 0);
explicit QQmlNdefRecord(const QNdefRecord &record, QObject *parent = 0);
+ ~QQmlNdefRecord();
QString type() const;
void setType(const QString &t);