summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/osx
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@theqtcompany.com>2015-11-26 18:04:58 +0100
committerTimur Pocheptsov <timur.pocheptsov@theqtcompany.com>2015-12-10 13:41:42 +0000
commit5e73fbe10d14cc1fedba4c2e327ebf2b07bc1a9e (patch)
tree1ed50be64e67a40530f1ea41702c5ee29fea2977 /src/bluetooth/osx
parent2402bb9421ab8ba4479b7a4e9566b682146f70ff (diff)
qlowenergycontroller_osx - move delegate to the qt_LE_queue
ATM CBCentralManager's delegate does its work on the main queue. With CoreFoundation event dispatcher it's now possible to use QtBluetooth from non-gui thread (more generally - from a thread other than main). This makes main queue useless - and we have to move to a dedicated dispatch queue. Also, we have to make sure we do not have race conditioins/dead-locks. This patch: 1. decouples OSXBTLECentralManager and QLowEnergyController so that these two objects working (potentially) on different threads do not share any data and do not have to use locks, removes the explicit 'delegate' interface/inheritance and replaces them with LECentralNotifier class - to be able to use Qt's signal/slot mechanics for inter-thread communication. 2. all OSXBTLECentralManager's are now executed on qt_LE_queue queue to avoid any race-conditions (since they potentially update manager's internal state). 3. Results/errors are now reported using LECentralNotifier's object (QLowEnergyController has corresponding slots connected to the notifier) Task-number: QTBUG-49476 Change-Id: Ie07cdc13ad559c96a7d2ff010843fb7bcce07c99 Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
Diffstat (limited to 'src/bluetooth/osx')
-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
5 files changed, 344 insertions, 245 deletions
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