summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/bluetooth/osx/osxbtcentralmanager.mm35
-rw-r--r--src/bluetooth/osx/osxbtcentralmanagerdelegate_p.h2
-rw-r--r--src/bluetooth/osx/osxbtutility.mm29
-rw-r--r--src/bluetooth/qlowenergycontroller_osx.mm60
4 files changed, 114 insertions, 12 deletions
diff --git a/src/bluetooth/osx/osxbtcentralmanager.mm b/src/bluetooth/osx/osxbtcentralmanager.mm
index d2e45832..32fad1db 100644
--- a/src/bluetooth/osx/osxbtcentralmanager.mm
+++ b/src/bluetooth/osx/osxbtcentralmanager.mm
@@ -252,6 +252,20 @@ using namespace QT_NAMESPACE;
- (void)discoverServices
{
+ Q_ASSERT_X(peripheral, "-discoverServices", "invalid peripheral (nil)");
+ Q_ASSERT_X(managerState == OSXBluetooth::CentralManagerIdle,
+ "-discoverServices", "invalid state");
+
+ // From Apple's docs:
+ //
+ //"If the servicesUUIDs parameter is nil, all the available
+ //services of the peripheral are returned; setting the
+ //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];
}
- (bool)discoverServiceDetails:(const QBluetoothUuid &)serviceUuid
@@ -425,7 +439,26 @@ using namespace QT_NAMESPACE;
- (void)peripheral:(CBPeripheral *)aPeripheral didDiscoverServices:(NSError *)error
{
Q_UNUSED(aPeripheral)
- Q_UNUSED(error)
+
+
+ if (managerState != OSXBluetooth::CentralManagerDiscovering) {
+ // Canceled by -disconnectFromDevice.
+ return;
+ }
+
+ managerState = OSXBluetooth::CentralManagerIdle;
+
+ if (error) {
+ // NSLog, not qCDebug/Warning - to print the error.
+ NSLog(@"-peripheral:didDiscoverServices:, failed with error %@", error);
+ // TODO: better error mapping required.
+ delegate->error(QLowEnergyController::UnknownError);
+ } else {
+ QT_BT_MAC_AUTORELEASEPOOL;
+
+ OSXBluetooth::ObjCStrongReference<NSArray> services(peripheral.services, true);
+ delegate->serviceDiscoveryFinished(services);
+ }
}
diff --git a/src/bluetooth/osx/osxbtcentralmanagerdelegate_p.h b/src/bluetooth/osx/osxbtcentralmanagerdelegate_p.h
index 65b5e61f..196e14d0 100644
--- a/src/bluetooth/osx/osxbtcentralmanagerdelegate_p.h
+++ b/src/bluetooth/osx/osxbtcentralmanagerdelegate_p.h
@@ -54,6 +54,8 @@
// and later in the delegate's -centralManagerDidUpdateState: we are trying to finally release
// a manager. Otherwise, this thing dies even with ARC.
+// TODO: can not reproduce this crash anymore ... probably, this class will be removed soon.
+
@interface QT_MANGLE_NAMESPACE(OSXBTCentralManagerTransientDelegate) : NSObject<CBCentralManagerDelegate>
{
CBCentralManager *manager;
diff --git a/src/bluetooth/osx/osxbtutility.mm b/src/bluetooth/osx/osxbtutility.mm
index 74ee84e6..69e94434 100644
--- a/src/bluetooth/osx/osxbtutility.mm
+++ b/src/bluetooth/osx/osxbtutility.mm
@@ -165,19 +165,38 @@ QString qt_error_string(IOReturn errorCode)
QBluetoothUuid qt_uuid(CBUUID *uuid)
{
+ // Apples' docs say "128 bit" and "16-bit UUIDs are implicitly
+ // pre-filled with the Bluetooth Base UUID."
+ // But Core Bluetooth can return CBUUID objects of length 2
+ // (16-bit, so they are not pre-filled?).
+
if (!uuid)
return QBluetoothUuid();
QT_BT_MAC_AUTORELEASEPOOL;
- if (uuid.data.length != 16) // TODO: warning?
+ if (uuid.data.length == 2) {
+ // TODO: this is .. UGLY :)
+ quint16 qtUuidData = 0;
+ const quint8 *const source = static_cast<const quint8 *>(uuid.data.bytes);
+ std::copy(source, source + 2, &qtUuidData);
+
+ return QBluetoothUuid(qtUuidData);
+ } else if (uuid.data.length == 16) {
+ quint128 qtUuidData = {};
+ const quint8 *const source = static_cast<const quint8 *>(uuid.data.bytes);
+ std::copy(source, source + 16, qtUuidData.data);
+
+ return QBluetoothUuid(qtUuidData);
+ } else {
+ qCDebug(QT_BT_OSX) << "qt_uuid, invalid CBUUID, 2 or 16 bytes expected, but got "
+ << uuid.data.length << " bytes length";
return QBluetoothUuid();
+ }
- quint128 qtUuidData = {};
- const quint8 *const source = static_cast<const quint8 *>(uuid.data.bytes);
- std::copy(source, source + 16, qtUuidData.data);
+ if (uuid.data.length != 16) // TODO: warning?
+ return QBluetoothUuid();
- return QBluetoothUuid(qtUuidData);
}
CFStrongReference<CFUUIDRef> cf_uuid(const QBluetoothUuid &qtUuid)
diff --git a/src/bluetooth/qlowenergycontroller_osx.mm b/src/bluetooth/qlowenergycontroller_osx.mm
index 6e62844c..a2db5c0a 100644
--- a/src/bluetooth/qlowenergycontroller_osx.mm
+++ b/src/bluetooth/qlowenergycontroller_osx.mm
@@ -122,7 +122,37 @@ void QLowEnergyControllerPrivateOSX::connectSuccess()
void QLowEnergyControllerPrivateOSX::serviceDiscoveryFinished(LEServices services)
{
- Q_UNUSED(services)
+ Q_ASSERT_X(controllerState == QLowEnergyController::DiscoveringState,
+ "serviceDiscoveryFinished", "invalid state");
+
+ QT_BT_MAC_AUTORELEASEPOOL;
+
+ for (CBService *service in services.data()) {
+ if (CBUUID *const uuid = service.UUID) {
+ const QBluetoothUuid qtUuid(OSXBluetooth::qt_uuid(uuid));
+ if (discoveredServices.find(qtUuid) != discoveredServices.end()) {
+ qCDebug(QT_BT_OSX) << "QBluetoothLowEnergyControllerPrivateOSX::serviceDiscoveryFinished(), "
+ "a duplicate service UUID found: " << qtUuid;
+ continue;
+ }
+
+ QSharedPointer<QLowEnergyServicePrivate> newService(new QLowEnergyServicePrivate);
+ newService->uuid = qtUuid;
+#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_6_0)
+ if (!service.isPrimary) {
+ newService->type &= ~QLowEnergyService::PrimaryService;
+ newService->type |= QLowEnergyService::IncludedService;
+ }
+#endif
+ newService->setController(this);
+ discoveredServices.insert(qtUuid, newService);
+ emit q_ptr->serviceDiscovered(qtUuid);
+ }
+ }
+
+ controllerState = QLowEnergyController::DiscoveredState;
+ emit q_ptr->stateChanged(QLowEnergyController::DiscoveredState);
+ emit q_ptr->discoveryFinished();
}
void QLowEnergyControllerPrivateOSX::includedServicesDiscoveryFinished(const QBluetoothUuid &serviceUuid,
@@ -184,7 +214,7 @@ void QLowEnergyControllerPrivateOSX::error(QLowEnergyController::Error errorCode
void QLowEnergyControllerPrivateOSX::error(const QBluetoothUuid &serviceUuid,
QLowEnergyController::Error errorCode)
{
- // Service/characteristics-related errors.
+ // Errors reported while discovering service details etc.
Q_UNUSED(serviceUuid)
Q_UNUSED(errorCode)
}
@@ -228,6 +258,13 @@ void QLowEnergyControllerPrivateOSX::connectToDevice()
void QLowEnergyControllerPrivateOSX::discoverServices()
{
+ Q_ASSERT_X(isValid(), "discoverServices", "invalid private controller");
+ Q_ASSERT_X(controllerState != QLowEnergyController::UnconnectedState,
+ "discoverServices", "not connected to peripheral");
+
+ controllerState = QLowEnergyController::DiscoveringState;
+ emit q_ptr->stateChanged(QLowEnergyController::DiscoveringState);
+ [centralManager discoverServices];
}
void QLowEnergyControllerPrivateOSX::discoverServiceDetails(const QBluetoothUuid &serviceUuid)
@@ -347,19 +384,30 @@ void QLowEnergyController::disconnectFromDevice()
void QLowEnergyController::discoverServices()
{
+ if (state() != ConnectedState)
+ return;
+
+ OSX_D_PTR;
+
+ osx_d_ptr->discoverServices();
}
QList<QBluetoothUuid> QLowEnergyController::services() const
{
- return QList<QBluetoothUuid>();
+ OSX_D_PTR;
+
+ return osx_d_ptr->discoveredServices.keys();
}
QLowEnergyService *QLowEnergyController::createServiceObject(const QBluetoothUuid &serviceUuid,
QObject *parent)
{
- Q_UNUSED(serviceUuid)
- Q_UNUSED(parent)
- return Q_NULLPTR;
+ OSX_D_PTR;
+
+ if (!osx_d_ptr->discoveredServices.contains(serviceUuid))
+ return Q_NULLPTR;
+
+ return new QLowEnergyService(osx_d_ptr->discoveredServices.value(serviceUuid), parent);
}
QLowEnergyController::Error QLowEnergyController::error() const