summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--src/bluetooth/osx/osxbt.pri13
-rw-r--r--src/bluetooth/osx/osxbtcentralmanager.mm218
-rw-r--r--src/bluetooth/osx/osxbtcentralmanager_p.h6
-rw-r--r--src/bluetooth/osx/osxbtdeviceinquiry.mm8
-rw-r--r--src/bluetooth/osx/osxbtdevicepair.mm18
-rw-r--r--src/bluetooth/osx/osxbtl2capchannel.mm8
-rw-r--r--src/bluetooth/osx/osxbtledeviceinquiry.mm79
-rw-r--r--src/bluetooth/osx/osxbtnotifier_p.h8
-rw-r--r--src/bluetooth/osx/osxbtobexsession.mm38
-rw-r--r--src/bluetooth/osx/osxbtperipheralmanager.mm754
-rw-r--r--src/bluetooth/osx/osxbtperipheralmanager_p.h176
-rw-r--r--src/bluetooth/osx/osxbtrfcommchannel.mm8
-rw-r--r--src/bluetooth/osx/osxbtsdpinquiry.mm8
-rw-r--r--src/bluetooth/osx/osxbtutility.mm1
-rw-r--r--src/bluetooth/osx/osxbtutility_p.h4
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm15
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_osx.mm21
-rw-r--r--src/bluetooth/qbluetoothserver_osx.mm35
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_osx.mm2
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_osx.mm100
-rw-r--r--src/bluetooth/qbluetoothsocket_osx.mm12
-rw-r--r--src/bluetooth/qbluetoothtransferreply_osx.mm13
-rw-r--r--src/bluetooth/qlowenergycontroller.cpp6
-rw-r--r--src/bluetooth/qlowenergycontroller_osx.mm459
-rw-r--r--src/bluetooth/qlowenergycontroller_osx_p.h28
-rw-r--r--src/bluetooth/qlowenergyservice_osx.mm6
27 files changed, 1453 insertions, 593 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 4ef70163..aefa1e70 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,3 +1,3 @@
load(qt_build_config)
-MODULE_VERSION = 5.7.0
+MODULE_VERSION = 5.8.0
diff --git a/src/bluetooth/osx/osxbt.pri b/src/bluetooth/osx/osxbt.pri
index bb382866..8d5486f4 100644
--- a/src/bluetooth/osx/osxbt.pri
+++ b/src/bluetooth/osx/osxbt.pri
@@ -1,5 +1,6 @@
SOURCES += osx/uistrings.cpp osx/osxbtnotifier.cpp
PRIVATE_HEADERS += osx/uistrings_p.h
+//QMAKE_CXXFLAGS_WARN_ON += -Wno-nullability-completeness
CONFIG(osx) {
PRIVATE_HEADERS += osx/osxbtutility_p.h \
@@ -16,7 +17,8 @@ CONFIG(osx) {
osx/osxbtledeviceinquiry_p.h \
osx/corebluetoothwrapper_p.h \
osx/osxbtcentralmanager_p.h \
- osx/osxbtnotifier_p.h
+ osx/osxbtnotifier_p.h \
+ osx/osxbtperipheralmanager_p.h
OBJECTIVE_SOURCES += osx/osxbtutility.mm \
osx/osxbtdevicepair.mm \
@@ -30,15 +32,22 @@ CONFIG(osx) {
osx/osxbtsocketlistener.mm \
osx/osxbtobexsession.mm \
osx/osxbtledeviceinquiry.mm \
- osx/osxbtcentralmanager.mm
+ osx/osxbtcentralmanager.mm \
+ osx/osxbtperipheralmanager.mm
} else {
PRIVATE_HEADERS += osx/osxbtutility_p.h \
osx/osxbtledeviceinquiry_p.h \
osx/corebluetoothwrapper_p.h \
osx/osxbtcentralmanager_p.h \
osx/osxbtnotifier_p.h
+ ios {
+ PRIVATE_HEADERS += osx/osxbtperipheralmanager_p.h
+ }
OBJECTIVE_SOURCES += osx/osxbtutility.mm \
osx/osxbtledeviceinquiry.mm \
osx/osxbtcentralmanager.mm
+ ios {
+ OBJECTIVE_SOURCES += osx/osxbtperipheralmanager.mm
+ }
}
diff --git a/src/bluetooth/osx/osxbtcentralmanager.mm b/src/bluetooth/osx/osxbtcentralmanager.mm
index 62009845..55a06021 100644
--- a/src/bluetooth/osx/osxbtcentralmanager.mm
+++ b/src/bluetooth/osx/osxbtcentralmanager.mm
@@ -43,7 +43,6 @@
#include "osxbtnotifier_p.h"
#include <QtCore/qloggingcategory.h>
-#include <QtCore/qsysinfo.h>
#include <QtCore/qdebug.h>
#include <algorithm>
@@ -116,7 +115,7 @@ QT_END_NAMESPACE
@implementation QT_MANGLE_NAMESPACE(OSXBTCentralManager)
-- (id)initWith:(OSXBluetooth::LECentralNotifier *)aNotifier
+- (id)initWith:(OSXBluetooth::LECBManagerNotifier *)aNotifier
{
if (self = [super init]) {
manager = nil;
@@ -171,9 +170,9 @@ QT_END_NAMESPACE
if (!manager) {
managerState = OSXBluetooth::CentralManagerIdle;
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to allocate a central manager";
+ qCWarning(QT_BT_OSX) << "failed to allocate a central manager";
if (notifier)
- emit notifier->CBCentralManagerError(QLowEnergyController::ConnectionError);
+ emit notifier->CBManagerError(QLowEnergyController::ConnectionError);
}
} else if (managerState != OSXBluetooth::CentralManagerUpdating) {
[self retrievePeripheralAndConnect];
@@ -187,7 +186,7 @@ QT_END_NAMESPACE
Q_FUNC_INFO, "invalid state");
if ([self isConnected]) {
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "already connected";
+ qCDebug(QT_BT_OSX) << "already connected";
if (notifier)
emit notifier->connected();
return;
@@ -203,62 +202,37 @@ QT_END_NAMESPACE
// Retrieve a peripheral first ...
ObjCScopedPointer<NSMutableArray> uuids([[NSMutableArray alloc] init]);
if (!uuids) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to allocate identifiers";
+ qCWarning(QT_BT_OSX) << "failed to allocate identifiers";
if (notifier)
- emit notifier->CBCentralManagerError(QLowEnergyController::ConnectionError);
+ emit notifier->CBManagerError(QLowEnergyController::ConnectionError);
return;
}
-#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_7_0)
- if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_9, QSysInfo::MV_IOS_7_0)) {
- const quint128 qtUuidData(deviceUuid.toUInt128());
- // STATIC_ASSERT on sizes would be handy!
- uuid_t uuidData = {};
- std::copy(qtUuidData.data, qtUuidData.data + 16, uuidData);
- const ObjCScopedPointer<NSUUID> nsUuid([[NSUUID alloc] initWithUUIDBytes:uuidData]);
- if (!nsUuid) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to allocate NSUUID identifier";
- 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";
- if (notifier)
- emit notifier->CBCentralManagerError(QLowEnergyController::UnknownRemoteDeviceError);
- return;
- }
-
- peripheral = [static_cast<CBPeripheral *>([peripherals objectAtIndex:0]) retain];
- [self connectToPeripheral];
- 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";
+ const quint128 qtUuidData(deviceUuid.toUInt128());
+ uuid_t uuidData = {};
+ std::copy(qtUuidData.data, qtUuidData.data + 16, uuidData);
+ const ObjCScopedPointer<NSUUID> nsUuid([[NSUUID alloc] initWithUUIDBytes:uuidData]);
+ if (!nsUuid) {
+ qCWarning(QT_BT_OSX) << "failed to allocate NSUUID identifier";
if (notifier)
- emit notifier->CBCentralManagerError(QLowEnergyController::UnknownRemoteDeviceError);
+ emit notifier->CBManagerError(QLowEnergyController::ConnectionError);
return;
}
- OSXBluetooth::CFStrongReference<CFUUIDRef> cfUuid(OSXBluetooth::cf_uuid(deviceUuid));
- if (!cfUuid) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to create CFUUID object";
+ [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) << "failed to retrive a peripheral";
if (notifier)
- emit notifier->CBCentralManagerError(QLowEnergyController::ConnectionError);
+ emit notifier->CBManagerError(QLowEnergyController::UnknownRemoteDeviceError);
return;
}
- // 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()];
+
+ peripheral = [static_cast<CBPeripheral *>([peripherals objectAtIndex:0]) retain];
+ [self connectToPeripheral];
}
- (void)connectToPeripheral
@@ -270,11 +244,11 @@ QT_END_NAMESPACE
// The state is still the same - connecting.
if ([self isConnected]) {
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "already connected";
+ qCDebug(QT_BT_OSX) << "already connected";
if (notifier)
emit notifier->connected();
} else {
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "trying to connect";
+ qCDebug(QT_BT_OSX) << "trying to connect";
managerState = OSXBluetooth::CentralManagerConnecting;
[manager connectPeripheral:peripheral options:nil];
}
@@ -285,18 +259,7 @@ QT_END_NAMESPACE
if (!peripheral)
return false;
-#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_7_0)
- using OSXBluetooth::qt_OS_limit;
-
- if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_9, QSysInfo::MV_IOS_7_0))
- return peripheral.state == CBPeripheralStateConnected;
-#endif
- // Either SDK or the target is below 10.9/7.0 ...
- if (![peripheral respondsToSelector:@selector(isConnected)])
- return false;
-
- // Ugly cast to deal with id being a pointer ...
- return reinterpret_cast<quintptr>([peripheral performSelector:@selector(isConnected)]);
+ return peripheral.state == CBPeripheralStateConnected;
}
- (void)disconnectFromDevice
@@ -389,7 +352,7 @@ QT_END_NAMESPACE
Q_ASSERT_X(peripheral, Q_FUNC_INFO, "invalid peripheral (nil)");
if (servicesToDiscoverDetails.contains(serviceUuid)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO <<"already discovering for "
+ qCWarning(QT_BT_OSX) << "already discovering for"
<< serviceUuid;
return;
}
@@ -402,11 +365,11 @@ QT_END_NAMESPACE
return;
}
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unknown service uuid "
+ qCWarning(QT_BT_OSX) << "unknown service uuid"
<< serviceUuid;
if (notifier) {
- emit notifier->CBCentralManagerError(serviceUuid,
+ emit notifier->CBManagerError(serviceUuid,
QLowEnergyService::UnknownError);
}
}
@@ -499,9 +462,9 @@ QT_END_NAMESPACE
const QLowEnergyHandle maxHandle = std::numeric_limits<QLowEnergyHandle>::max();
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";
+ qCWarning(QT_BT_OSX) << "can not allocate more handles";
if (notifier)
- notifier->CBCentralManagerError(serviceUuid, QLowEnergyService::OperationError);
+ notifier->CBManagerError(serviceUuid, QLowEnergyService::OperationError);
return;
}
@@ -603,7 +566,7 @@ QT_END_NAMESPACE
const LERequest request(requests.dequeue());
if (request.type == LERequest::CharRead) {
if (!charMap.contains(request.handle)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "characteristic with handle"
+ qCWarning(QT_BT_OSX) << "characteristic with handle"
<< request.handle << "not found";
return [self performNextRequest];
}
@@ -613,7 +576,7 @@ QT_END_NAMESPACE
[peripheral readValueForCharacteristic:charMap[request.handle]];
} else {
if (!descMap.contains(request.handle)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "descriptor with handle"
+ qCWarning(QT_BT_OSX) << "descriptor with handle"
<< request.handle << "not found";
return [self performNextRequest];
}
@@ -640,8 +603,8 @@ QT_END_NAMESPACE
if (request.type == LERequest::DescWrite) {
if (!descMap.contains(request.handle)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "handle: "
- << request.handle << " not found";
+ qCWarning(QT_BT_OSX) << "handle:" << request.handle
+ << "not found";
return [self performNextRequest];
}
@@ -649,8 +612,7 @@ QT_END_NAMESPACE
ObjCStrongReference<NSData> data(data_from_bytearray(request.value));
if (!data) {
// Even if qtData.size() == 0, we still need NSData object.
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed "
- "to allocate an NSData object";
+ qCWarning(QT_BT_OSX) << "failed to allocate an NSData object";
return [self performNextRequest];
}
@@ -661,8 +623,8 @@ QT_END_NAMESPACE
return [peripheral writeValue:data.data() forDescriptor:descriptor];
} else {
if (!charMap.contains(request.handle)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "characteristic with "
- "handle: " << request.handle << " not found";
+ qCWarning(QT_BT_OSX) << "characteristic with handle:"
+ << request.handle << "not found";
return [self performNextRequest];
}
@@ -687,7 +649,7 @@ QT_END_NAMESPACE
ObjCStrongReference<NSData> data(data_from_bytearray(request.value));
if (!data) {
// Even if qtData.size() == 0, we still need NSData object.
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to allocate NSData object";
+ qCWarning(QT_BT_OSX) << "failed to allocate NSData object";
return [self performNextRequest];
}
@@ -717,11 +679,10 @@ QT_END_NAMESPACE
Q_ASSERT_X(charHandle, Q_FUNC_INFO, "invalid characteristic handle (0)");
if (!charMap.contains(charHandle)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO
- << "unknown characteristic handle "
+ qCWarning(QT_BT_OSX) << "unknown characteristic handle"
<< charHandle;
if (notifier) {
- emit notifier->CBCentralManagerError(serviceUuid,
+ emit notifier->CBManagerError(serviceUuid,
QLowEnergyService::DescriptorWriteError);
}
return;
@@ -732,10 +693,9 @@ QT_END_NAMESPACE
// 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";
+ qCWarning(QT_BT_OSX) << "no client characteristic configuration found";
if (notifier) {
- emit notifier->CBCentralManagerError(serviceUuid,
+ emit notifier->CBManagerError(serviceUuid,
QLowEnergyService::DescriptorWriteError);
}
return;
@@ -760,9 +720,9 @@ QT_END_NAMESPACE
QT_BT_MAC_AUTORELEASEPOOL;
if (!charMap.contains(charHandle)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "characteristic: " << charHandle << " not found";
+ qCWarning(QT_BT_OSX) << "characteristic:" << charHandle << "not found";
if (notifier) {
- emit notifier->CBCentralManagerError(serviceUuid,
+ emit notifier->CBManagerError(serviceUuid,
QLowEnergyService::CharacteristicReadError);
}
@@ -789,10 +749,9 @@ QT_END_NAMESPACE
QT_BT_MAC_AUTORELEASEPOOL;
if (!charMap.contains(charHandle)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "characteristic: "
- << charHandle << " not found";
+ qCWarning(QT_BT_OSX) << "characteristic:" << charHandle << "not found";
if (notifier) {
- emit notifier->CBCentralManagerError(serviceUuid,
+ emit notifier->CBManagerError(serviceUuid,
QLowEnergyService::CharacteristicWriteError);
}
return;
@@ -816,10 +775,9 @@ QT_END_NAMESPACE
Q_ASSERT_X(descHandle, Q_FUNC_INFO, "invalid descriptor handle (0)");
if (!descMap.contains(descHandle)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "handle:"
- << descHandle << "not found";
+ qCWarning(QT_BT_OSX) << "handle:" << descHandle << "not found";
if (notifier) {
- emit notifier->CBCentralManagerError(serviceUuid,
+ emit notifier->CBManagerError(serviceUuid,
QLowEnergyService::DescriptorReadError);
}
return;
@@ -842,10 +800,9 @@ QT_END_NAMESPACE
Q_ASSERT_X(descHandle, Q_FUNC_INFO, "invalid descriptor handle (0)");
if (!descMap.contains(descHandle)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "handle: "
- << descHandle << " not found";
+ qCWarning(QT_BT_OSX) << "handle:" << descHandle << "not found";
if (notifier) {
- emit notifier->CBCentralManagerError(serviceUuid,
+ emit notifier->CBManagerError(serviceUuid,
QLowEnergyService::DescriptorWriteError);
}
return;
@@ -1029,27 +986,25 @@ QT_END_NAMESPACE
if ([obj isKindOfClass:[CBCharacteristic class]]) {
CBCharacteristic *const ch = static_cast<CBCharacteristic *>(obj);
if (!charMap.key(ch)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unexpected "
- "characteristic, no handle found";
+ qCWarning(QT_BT_OSX) << "unexpected characteristic, no handle found";
return false;
}
} else if ([obj isKindOfClass:[CBDescriptor class]]) {
CBDescriptor *const d = static_cast<CBDescriptor *>(obj);
if (!descMap.key(d)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unexpected "
- "descriptor, no handle found";
+ qCWarning(QT_BT_OSX) << "unexpected descriptor, no handle found";
return false;
}
} else {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "invalid object, "
- "characteristic or descriptor required";
+ qCWarning(QT_BT_OSX) << "invalid object, characteristic "
+ "or descriptor required";
return false;
}
if (valuesToWrite.contains(obj)) {
// It can be a result of some previous errors - for example,
// we never got a callback from a previous write.
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "already has a cached value for this "
+ qCWarning(QT_BT_OSX) << "already has a cached value for this "
"object, the value will be replaced";
}
@@ -1101,7 +1056,7 @@ QT_END_NAMESPACE
// and reset managerState from CentralManagerUpdating.
managerState = CentralManagerIdle;
if (notifier)
- emit notifier->CBCentralManagerError(QLowEnergyController::InvalidBluetoothAdapterError);
+ emit notifier->CBManagerError(QLowEnergyController::InvalidBluetoothAdapterError);
}
return;
}
@@ -1116,7 +1071,7 @@ QT_END_NAMESPACE
// TODO: we need a better error +
// what will happen if later the state changes to PoweredOn???
if (notifier)
- emit notifier->CBCentralManagerError(QLowEnergyController::InvalidBluetoothAdapterError);
+ emit notifier->CBManagerError(QLowEnergyController::InvalidBluetoothAdapterError);
}
return;
}
@@ -1132,30 +1087,6 @@ QT_END_NAMESPACE
}
}
-- (void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals
-{
- Q_UNUSED(central)
-
- // This method is required for iOS before 7.0 and OS X below 10.9.
- Q_ASSERT_X(manager, Q_FUNC_INFO, "invalid central manager (nil)");
-
- if (managerState != OSXBluetooth::CentralManagerConnecting) {
- // Canceled by calling -disconnectFromDevice method.
- return;
- }
-
- managerState = OSXBluetooth::CentralManagerIdle;
-
- if (!peripherals || peripherals.count != 1) {
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO <<"unexpected number of peripherals (!= 1)";
- if (notifier)
- emit notifier->CBCentralManagerError(QLowEnergyController::UnknownRemoteDeviceError);
- } else {
- peripheral = [static_cast<CBPeripheral *>([peripherals objectAtIndex:0]) retain];
- [self connectToPeripheral];
- }
-}
-
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)aPeripheral
{
Q_UNUSED(central)
@@ -1186,7 +1117,7 @@ QT_END_NAMESPACE
managerState = OSXBluetooth::CentralManagerIdle;
// TODO: better error mapping is required.
if (notifier)
- notifier->CBCentralManagerError(QLowEnergyController::UnknownRemoteDeviceError);
+ notifier->CBManagerError(QLowEnergyController::UnknownRemoteDeviceError);
}
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)aPeripheral
@@ -1200,9 +1131,9 @@ QT_END_NAMESPACE
if (error && managerState == OSXBluetooth::CentralManagerDisconnecting) {
managerState = OSXBluetooth::CentralManagerIdle;
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to disconnect";
+ qCWarning(QT_BT_OSX) << "failed to disconnect";
if (notifier)
- emit notifier->CBCentralManagerError(QLowEnergyController::UnknownRemoteDeviceError);
+ emit notifier->CBManagerError(QLowEnergyController::UnknownRemoteDeviceError);
} else {
managerState = OSXBluetooth::CentralManagerIdle;
if (notifier)
@@ -1227,7 +1158,7 @@ QT_END_NAMESPACE
NSLog(@"%s failed with error %@", Q_FUNC_INFO, error);
// TODO: better error mapping required.
if (notifier)
- emit notifier->CBCentralManagerError(QLowEnergyController::UnknownError);
+ emit notifier->CBManagerError(QLowEnergyController::UnknownError);
} else {
[self discoverIncludedServices];
}
@@ -1323,7 +1254,7 @@ QT_END_NAMESPACE
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).
- emit notifier->CBCentralManagerError(qt_uuid(service.UUID), QLowEnergyController::UnknownError);
+ emit notifier->CBManagerError(qt_uuid(service.UUID), QLowEnergyController::UnknownError);
} else {
[self readCharacteristics:service];
}
@@ -1358,7 +1289,7 @@ QT_END_NAMESPACE
if (chHandle && chHandle == currentReadHandle) {
currentReadHandle = 0;
requestPending = false;
- emit notifier->CBCentralManagerError(qtUuid, QLowEnergyService::CharacteristicReadError);
+ emit notifier->CBManagerError(qtUuid, QLowEnergyService::CharacteristicReadError);
[self performNextRequest];
}
return;
@@ -1381,7 +1312,7 @@ QT_END_NAMESPACE
// updated values ...
// TODO: this must be properly tested.
if (!chHandle) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "unexpected update notification, "
+ qCCritical(QT_BT_OSX) << "unexpected update notification, "
"no characteristic handle found";
return;
}
@@ -1460,7 +1391,7 @@ QT_END_NAMESPACE
if (dHandle && dHandle == currentReadHandle) {
currentReadHandle = 0;
requestPending = false;
- emit notifier->CBCentralManagerError(qtUuid, QLowEnergyService::DescriptorReadError);
+ emit notifier->CBManagerError(qtUuid, QLowEnergyService::DescriptorReadError);
[self performNextRequest];
}
return;
@@ -1492,7 +1423,7 @@ QT_END_NAMESPACE
}
} else {
if (!dHandle) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "unexpected value update notification, "
+ qCCritical(QT_BT_OSX) << "unexpected value update notification, "
"no descriptor handle found";
return;
}
@@ -1535,13 +1466,13 @@ QT_END_NAMESPACE
// Error or not, but the cached value has to be deleted ...
const QByteArray valueToReport(valuesToWrite.value(characteristic, QByteArray()));
if (!valuesToWrite.remove(characteristic)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no updated value found"
- " for characteristic";
+ qCWarning(QT_BT_OSX) << "no updated value found "
+ "for characteristic";
}
if (error) {
NSLog(@"%s failed with error %@", Q_FUNC_INFO, error);
- emit notifier->CBCentralManagerError(qt_uuid(characteristic.service.UUID),
+ emit notifier->CBManagerError(qt_uuid(characteristic.service.UUID),
QLowEnergyService::CharacteristicWriteError);
} else {
const QLowEnergyHandle cHandle = charMap.key(characteristic);
@@ -1571,16 +1502,15 @@ QT_END_NAMESPACE
// 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";
+ qCWarning(QT_BT_OSX) << "no updated value found";
if (error) {
NSLog(@"%s failed with error %@", Q_FUNC_INFO, error);
- emit notifier->CBCentralManagerError(qt_uuid(descriptor.characteristic.service.UUID),
+ emit notifier->CBManagerError(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");
+ Q_ASSERT_X(dHandle, Q_FUNC_INFO, "descriptor not found in the descriptors map");
emit notifier->descriptorWritten(dHandle, valueToReport);
}
@@ -1610,7 +1540,7 @@ QT_END_NAMESPACE
if (error) {
NSLog(@"%s failed with error %@", Q_FUNC_INFO, error);
// In Qt's API it's a descriptor write actually.
- emit notifier->CBCentralManagerError(qt_uuid(characteristic.service.UUID),
+ emit notifier->CBManagerError(qt_uuid(characteristic.service.UUID),
QLowEnergyService::DescriptorWriteError);
} else if (nRemoved) {
const QLowEnergyHandle dHandle = descMap.key(descriptor);
diff --git a/src/bluetooth/osx/osxbtcentralmanager_p.h b/src/bluetooth/osx/osxbtcentralmanager_p.h
index e64e5baf..5453822f 100644
--- a/src/bluetooth/osx/osxbtcentralmanager_p.h
+++ b/src/bluetooth/osx/osxbtcentralmanager_p.h
@@ -75,7 +75,7 @@ class QLowEnergyServicePrivate;
namespace OSXBluetooth {
-class LECentralNotifier;
+class LECBManagerNotifier;
enum CentralManagerState
{
@@ -144,7 +144,7 @@ QT_END_NAMESPACE
QT_PREPEND_NAMESPACE(QBluetoothUuid) deviceUuid;
- QT_PREPEND_NAMESPACE(OSXBluetooth)::LECentralNotifier *notifier;
+ QT_PREPEND_NAMESPACE(OSXBluetooth)::LECBManagerNotifier *notifier;
// Quite a verbose service discovery machinery
// (a "graph traversal").
@@ -173,7 +173,7 @@ QT_END_NAMESPACE
CBPeripheral *peripheral;
}
-- (id)initWith:(QT_PREPEND_NAMESPACE(OSXBluetooth)::LECentralNotifier *)notifier;
+- (id)initWith:(QT_PREPEND_NAMESPACE(OSXBluetooth)::LECBManagerNotifier *)notifier;
- (void)dealloc;
// IMPORTANT: _all_ these methods are to be executed on qt_LE_queue,
diff --git a/src/bluetooth/osx/osxbtdeviceinquiry.mm b/src/bluetooth/osx/osxbtdeviceinquiry.mm
index 36a95a5a..a47ed5a1 100644
--- a/src/bluetooth/osx/osxbtdeviceinquiry.mm
+++ b/src/bluetooth/osx/osxbtdeviceinquiry.mm
@@ -78,8 +78,7 @@ using namespace QT_NAMESPACE;
[m_inquiry setUpdateNewDeviceNames:NO];//Useless, disable!
m_delegate = delegate;
} else {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to create "
- "a device inquiry";
+ qCCritical(QT_BT_OSX) << "failed to create a device inquiry";
}
m_active = false;
@@ -118,8 +117,7 @@ using namespace QT_NAMESPACE;
if (result != kIOReturnSuccess) {
// QtBluetooth will probably convert an error into UnknownError,
// loosing the actual information.
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO <<"failed with "
- "IOKit error code: " << result;
+ qCWarning(QT_BT_OSX) << "failed with IOKit error code:" << result;
m_active = false;
}
@@ -157,7 +155,7 @@ using namespace QT_NAMESPACE;
if (error != kIOReturnSuccess) {
// QtBluetooth has not too many error codes, 'UnknownError' is not really
// useful, report the actual error code here:
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "IOKit error code: " << error;
+ qCWarning(QT_BT_OSX) << "IOKit error code: " << error;
m_delegate->error(sender, error);
} else {
m_delegate->inquiryFinished(sender);
diff --git a/src/bluetooth/osx/osxbtdevicepair.mm b/src/bluetooth/osx/osxbtdevicepair.mm
index 737a312f..e2d96ce4 100644
--- a/src/bluetooth/osx/osxbtdevicepair.mm
+++ b/src/bluetooth/osx/osxbtdevicepair.mm
@@ -41,7 +41,6 @@
#include "osxbtutility_p.h"
#include <QtCore/qloggingcategory.h>
-#include <QtCore/qsysinfo.h>
#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
@@ -91,18 +90,8 @@ using namespace QT_NAMESPACE;
- (void)dealloc
{
-#if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9)
- // Stop also sets a delegate to nil (Apple's docs).
- // 10.9 only.
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_9)
- [m_pairing stop];
- else
- [m_pairing setDelegate:nil];
-#else
- [m_pairing setDelegate:nil];
-#endif
+ [m_pairing stop];
[m_pairing release];
-
[super dealloc];
}
@@ -119,14 +108,13 @@ using namespace QT_NAMESPACE;
// Device is autoreleased.
IOBluetoothDevice *const device = [IOBluetoothDevice deviceWithAddress:&iobtAddress];
if (!device) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to create a device "
- "to pair with";
+ qCCritical(QT_BT_OSX) << "failed to create a device to pair with";
return kIOReturnError;
}
m_pairing = [[IOBluetoothDevicePair pairWithDevice:device] retain];
if (!m_pairing) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to create pair";
+ qCCritical(QT_BT_OSX) << "failed to create pair";
return kIOReturnError;
}
diff --git a/src/bluetooth/osx/osxbtl2capchannel.mm b/src/bluetooth/osx/osxbtl2capchannel.mm
index 2d596654..3156c0d2 100644
--- a/src/bluetooth/osx/osxbtl2capchannel.mm
+++ b/src/bluetooth/osx/osxbtl2capchannel.mm
@@ -106,13 +106,13 @@ using namespace QT_NAMESPACE;
withPSM:(BluetoothL2CAPChannelID)psm
{
if (address.isNull()) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "invalid peer address";
+ qCCritical(QT_BT_OSX) << "invalid peer address";
return kIOReturnNoDevice;
}
// Can never be called twice.
if (connected || device || channel) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "connection is already active";
+ qCCritical(QT_BT_OSX) << "connection is already active";
return kIOReturnStillOpen;
}
@@ -121,13 +121,13 @@ using namespace QT_NAMESPACE;
const BluetoothDeviceAddress iobtAddress = OSXBluetooth::iobluetooth_address(address);
device = [IOBluetoothDevice deviceWithAddress:&iobtAddress];
if (!device) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to create a device";
+ qCCritical(QT_BT_OSX) << "failed to create a device";
return kIOReturnNoDevice;
}
const IOReturn status = [device openL2CAPChannelAsync:&channel withPSM:psm delegate:self];
if (status != kIOReturnSuccess) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to open L2CAP channel";
+ qCCritical(QT_BT_OSX) << "failed to open L2CAP channel";
// device is still autoreleased.
device = nil;
return status;
diff --git a/src/bluetooth/osx/osxbtledeviceinquiry.mm b/src/bluetooth/osx/osxbtledeviceinquiry.mm
index 88370fa6..58cecccc 100644
--- a/src/bluetooth/osx/osxbtledeviceinquiry.mm
+++ b/src/bluetooth/osx/osxbtledeviceinquiry.mm
@@ -43,7 +43,6 @@
#include "osxbtutility_p.h"
#include <QtCore/qloggingcategory.h>
-#include <QtCore/qsysinfo.h>
#include <QtCore/qdebug.h>
#include "corebluetoothwrapper_p.h"
@@ -52,8 +51,6 @@ QT_BEGIN_NAMESPACE
namespace OSXBluetooth {
-#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_6_0)
-
QBluetoothUuid qt_uuid(NSUUID *nsUuid)
{
if (!nsUuid)
@@ -66,38 +63,6 @@ QBluetoothUuid qt_uuid(NSUUID *nsUuid)
return QBluetoothUuid(qtUuidData);
}
-#endif
-
-QBluetoothUuid qt_uuid(CFUUIDRef uuid)
-{
- if (!uuid)
- return QBluetoothUuid();
-
- const CFUUIDBytes data = CFUUIDGetUUIDBytes(uuid);
- quint128 qtUuidData = {{data.byte0, data.byte1, data.byte2, data.byte3,
- data.byte4, data.byte5, data.byte6, data.byte7,
- data.byte8, data.byte9, data.byte10, data.byte11,
- data.byte12, data.byte13, data.byte14, data.byte15}};
-
- return QBluetoothUuid(qtUuidData);
-}
-
-typedef ObjCStrongReference<NSString> StringStrongReference;
-
-StringStrongReference uuid_as_nsstring(CFUUIDRef uuid)
-{
- // We use the UUDI's string representation as a key in a dictionary.
- if (!uuid)
- return StringStrongReference();
-
- CFStringRef cfStr = CFUUIDCreateString(kCFAllocatorDefault, uuid);
- if (!cfStr)
- return StringStrongReference();
-
- // Imporant: with ARC this will require a different cast/ownership!
- return StringStrongReference((NSString *)cfStr, false);
-}
-
}
@@ -301,47 +266,23 @@ using namespace QT_NAMESPACE;
QBluetoothUuid deviceUuid;
-#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_7_0)
- if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_9, QSysInfo::MV_IOS_7_0)) {
- if (!peripheral.identifier) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "peripheral without NSUUID";
- return;
- }
- if ([uuids containsObject:peripheral.identifier]) {
- // We already know this peripheral ...
- return;
- }
- [uuids addObject:peripheral.identifier];
- deviceUuid = OSXBluetooth::qt_uuid(peripheral.identifier);
+ if (!peripheral.identifier) {
+ qCWarning(QT_BT_OSX) << "peripheral without NSUUID";
+ return;
}
-#endif
- // Either SDK or the target is below 10.9/7.0:
- // The property UUID was finally removed in iOS 9, we have
- // to avoid compilation errors ...
- if (deviceUuid.isNull()) {
- CFUUIDRef cfUUID = Q_NULLPTR;
- if ([peripheral respondsToSelector:@selector(UUID)]) {
- // This will require a bridged cast if we switch to ARC ...
- cfUUID = reinterpret_cast<CFUUIDRef>([peripheral performSelector:@selector(UUID)]);
- }
-
- if (!cfUUID) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "peripheral without CFUUID";
- return;
- }
-
- StringStrongReference key(uuid_as_nsstring(cfUUID));
- if ([uuids containsObject:key.data()])
- return; // We've seen this peripheral before ...
- [uuids addObject:key.data()];
- deviceUuid = OSXBluetooth::qt_uuid(cfUUID);
+ if ([uuids containsObject:peripheral.identifier]) {
+ // We already know this peripheral ...
+ return;
}
+ [uuids addObject:peripheral.identifier];
+ deviceUuid = OSXBluetooth::qt_uuid(peripheral.identifier);
+
if (deviceUuid.isNull()) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no way to address peripheral, QBluetoothUuid is null";
+ qCWarning(QT_BT_OSX) << "no way to address peripheral, QBluetoothUuid is null";
return;
}
diff --git a/src/bluetooth/osx/osxbtnotifier_p.h b/src/bluetooth/osx/osxbtnotifier_p.h
index 6cb2b019..3059e2d3 100644
--- a/src/bluetooth/osx/osxbtnotifier_p.h
+++ b/src/bluetooth/osx/osxbtnotifier_p.h
@@ -68,7 +68,7 @@ class QLowEnergyServicePrivate;
namespace OSXBluetooth
{
-class LECentralNotifier : public QObject
+class LECBManagerNotifier : public QObject
{
Q_OBJECT
@@ -85,9 +85,9 @@ Q_SIGNALS:
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);
+ void CBManagerError(QLowEnergyController::Error error);
+ void CBManagerError(const QBluetoothUuid &serviceUuid, QLowEnergyController::Error error);
+ void CBManagerError(const QBluetoothUuid &serviceUuid, QLowEnergyService::ServiceError error);
};
diff --git a/src/bluetooth/osx/osxbtobexsession.mm b/src/bluetooth/osx/osxbtobexsession.mm
index 4e4013f3..9fd82487 100644
--- a/src/bluetooth/osx/osxbtobexsession.mm
+++ b/src/bluetooth/osx/osxbtobexsession.mm
@@ -203,7 +203,7 @@ QList<OBEXHeader> qt_bluetooth_headers(const uint8_t *data, std::size_t length)
break;
}
default:
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "invalid header format";
+ qCWarning(QT_BT_OSX) << "invalid header format";
return empty;
}
@@ -358,7 +358,7 @@ bool check_connect_event(const OBEXSessionEvent *e, OBEXError &error, OBEXOpCode
response = e->u.connectCommandResponseData.serverResponseOpCode;
return response == kOBEXResponseCodeSuccessWithFinalBit;
} else {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unexpected event type";
+ qCWarning(QT_BT_OSX) << "unexpected event type";
error = kOBEXGeneralError;
return false;
}
@@ -378,7 +378,7 @@ bool check_put_event(const OBEXSessionEvent *e, OBEXError &error, OBEXOpCode &re
return response == kOBEXResponseCodeContinueWithFinalBit ||
response == kOBEXResponseCodeSuccessWithFinalBit;
} else {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unexpected event type";
+ qCWarning(QT_BT_OSX) << "unexpected event type";
error = kOBEXGeneralError;
return false;
}
@@ -395,7 +395,7 @@ bool check_abort_event(const OBEXSessionEvent *e, OBEXError &error, OBEXOpCode &
response = e->u.abortCommandResponseData.serverResponseOpCode;
return response == kOBEXResponseCodeSuccessWithFinalBit;
} else {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unexpected event type";
+ qCWarning(QT_BT_OSX) << "unexpected event type";
return false;
}
}
@@ -447,13 +447,13 @@ using namespace QT_NAMESPACE;
const BluetoothDeviceAddress addr(OSXBluetooth::iobluetooth_address(deviceAddress));
device = [[IOBluetoothDevice deviceWithAddress:&addr] retain];
if (!device) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to create an IOBluetoothDevice";
+ qCWarning(QT_BT_OSX) << "failed to create an IOBluetoothDevice";
return self;
}
session = [[IOBluetoothOBEXSession alloc] initWithDevice:device channelID:port];
if (!session) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to create an OBEX session";
+ qCWarning(QT_BT_OSX) << "failed to create an OBEX session";
return self;
}
@@ -478,7 +478,7 @@ using namespace QT_NAMESPACE;
- (OBEXError)OBEXConnect
{
if (!session) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "invalid session (nil)";
+ qCWarning(QT_BT_OSX) << "invalid session (nil)";
return kOBEXGeneralError;
}
@@ -521,7 +521,7 @@ using namespace QT_NAMESPACE;
}
if (currentRequest != OBEXConnect) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "called while there is no "
+ qCWarning(QT_BT_OSX) << "called while there is no "
"active connect request";
return;
}
@@ -600,7 +600,7 @@ using namespace QT_NAMESPACE;
Q_ASSERT_X(session, Q_FUNC_INFO, "invalid OBEX session (nil)");
if (currentRequest != OBEXAbort) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "called while there "
+ qCWarning(QT_BT_OSX) << "called while there "
"is no ABORT request";
return;
}
@@ -632,13 +632,13 @@ using namespace QT_NAMESPACE;
// a payload.
const qint64 fileSize = input->size();
if (fileSize <= 0 || fileSize >= std::numeric_limits<uint32_t>::max()) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "invalid input file size";
+ qCWarning(QT_BT_OSX) << "invalid input file size";
return kOBEXBadArgumentError;
}
ObjCStrongReference<NSMutableData> headers([[NSMutableData alloc] init], false);
if (!headers) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to allocate headers";
+ qCWarning(QT_BT_OSX) << "failed to allocate headers";
return kOBEXNoResourcesError;
}
@@ -648,16 +648,14 @@ using namespace QT_NAMESPACE;
if (connectionIDFound) {
if (!append_four_byte_header(headers, kOBEXHeaderIDConnectionID, connectionID)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to "
- "append connection ID header";
+ qCWarning(QT_BT_OSX) << "failed to append connection ID header";
return kOBEXNoResourcesError;
}
}
if (name.length()) {
if (!append_unicode_header(headers, kOBEXHeaderIDName, name)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to append "
- "a unicode string";
+ qCWarning(QT_BT_OSX) << "failed to append a unicode string";
return kOBEXNoResourcesError;
}
}
@@ -670,7 +668,7 @@ using namespace QT_NAMESPACE;
if (!chunk || ![chunk length]) {
// We do not support PUT-DELETE (?)
// At least the first chunk is expected to be non-empty.
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "invalid input stream";
+ qCWarning(QT_BT_OSX) << "invalid input stream";
return kOBEXBadArgumentError;
}
@@ -717,7 +715,7 @@ using namespace QT_NAMESPACE;
}
if (currentRequest != OBEXPut) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "called while the current "
+ qCWarning(QT_BT_OSX) << "called while the current "
"request is not a put request";
return;
}
@@ -739,8 +737,7 @@ using namespace QT_NAMESPACE;
// 0 for the headers length, no more headers.
ObjCStrongReference<NSMutableData> chunk(next_data_chunk(*inputStream, session, 0, lastChunk));
if (!chunk && !lastChunk) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to "
- "allocate the next memory chunk";
+ qCWarning(QT_BT_OSX) << "failed to allocate the next memory chunk";
return;
}
@@ -756,8 +753,7 @@ using namespace QT_NAMESPACE;
refCon:Q_NULLPTR];
if (status != kOBEXSuccess) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to "
- "send the next memory chunk";
+ qCWarning(QT_BT_OSX) << "failed to send the next memory chunk";
currentRequest = OBEXNoop;
if (delegate) // Response code is not important here.
delegate->OBEXPutError(kOBEXNoResourcesError, 0);
diff --git a/src/bluetooth/osx/osxbtperipheralmanager.mm b/src/bluetooth/osx/osxbtperipheralmanager.mm
new file mode 100644
index 00000000..4731fdd2
--- /dev/null
+++ b/src/bluetooth/osx/osxbtperipheralmanager.mm
@@ -0,0 +1,754 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+
+#include "qlowenergycharacteristicdata.h"
+#include "qlowenergydescriptordata.h"
+#include "osxbtperipheralmanager_p.h"
+#include "qlowenergyservicedata.h"
+#include "osxbtnotifier_p.h"
+#include "qbluetooth.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qlist.h>
+
+#include <algorithm>
+#include <limits>
+#include <set>
+
+namespace
+{
+
+CBCharacteristicProperties cb_properties(const QLowEnergyCharacteristicData &data)
+{
+ // Direct 'mapping' is ok.
+ return CBCharacteristicProperties(int(data.properties()));
+}
+
+CBAttributePermissions cb_permissions(const QLowEnergyCharacteristicData &data)
+{
+ using QLEC = QLowEnergyCharacteristic;
+
+ const auto props = data.properties();
+ CBAttributePermissions cbFlags = {};
+
+ if ((props & QLEC::Write) || (props & QLEC::WriteNoResponse)
+ || (props & QLEC::WriteSigned)) {
+ cbFlags = CBAttributePermissions(cbFlags | CBAttributePermissionsWriteable);
+ }
+
+ if (props & QLEC::Read)
+ cbFlags = CBAttributePermissions(cbFlags | CBAttributePermissionsReadable);
+
+ if (data.writeConstraints() & QBluetooth::AttEncryptionRequired)
+ cbFlags = CBAttributePermissions(cbFlags | CBAttributePermissionsWriteEncryptionRequired);
+
+ if (data.readConstraints() & QBluetooth::AttEncryptionRequired)
+ cbFlags = CBAttributePermissions(cbFlags | CBAttributePermissionsReadEncryptionRequired);
+
+ return cbFlags;
+}
+
+ObjCStrongReference<CBMutableCharacteristic> create_characteristic(const QLowEnergyCharacteristicData &data)
+{
+ const ObjCStrongReference<CBMutableCharacteristic> ch([[CBMutableCharacteristic alloc] initWithType:cb_uuid(data.uuid())
+ properties:cb_properties(data)
+ value:nil
+ permissions:cb_permissions(data)],
+ false /*do not retain*/);
+ return ch;
+}
+
+ObjCStrongReference<CBMutableDescriptor> create_descriptor(const QLowEnergyDescriptorData &data)
+{
+ // CoreBluetooth supports only:
+ /*
+ "That said, only two of these are currently supported when creating local,
+ mutable descriptors: the characteristic user description descriptor and
+ the characteristic format descriptor, represented by the CBUUID constants
+ CBUUIDCharacteristicUserDescriptionString and CBUUIDCharacteristicFormatString"
+ */
+
+ if (data.uuid() != QBluetoothUuid::CharacteristicUserDescription &&
+ data.uuid() != QBluetoothUuid::CharacteristicPresentationFormat) {
+ qCWarning(QT_BT_OSX) << "unsupported descriptor" << data.uuid();
+ return {};
+ }
+
+ QT_BT_MAC_AUTORELEASEPOOL
+
+ // Descriptors are immutable with CoreBluetooth, that's why we
+ // have to provide a value here and not able to change it later.
+ ObjCStrongReference<NSObject> value;
+ if (data.uuid() == QBluetoothUuid::CharacteristicUserDescription) {
+ const QString asQString(QString::fromUtf8(data.value()));
+ value.reset(asQString.toNSString());
+ } else {
+ const auto nsData = data_from_bytearray(data.value());
+ value.reset(nsData.data());
+ }
+
+ const ObjCStrongReference<CBMutableDescriptor> d([[CBMutableDescriptor alloc]
+ initWithType:cb_uuid(data.uuid())
+ value:value], false /*do not retain*/);
+ return d;
+}
+
+quint32 qt_countGATTEntries(const QLowEnergyServiceData &data)
+{
+ const auto maxu32 = std::numeric_limits<quint32>::max();
+ // + 1 for a service itself.
+ quint32 nEntries = 1 + quint32(data.includedServices().count());
+ for (const auto &ch : data.characteristics()) {
+ if (maxu32 - 2 < nEntries)
+ return {};
+ nEntries += 2;
+ if (maxu32 - ch.descriptors().count() < nEntries)
+ return {};
+ nEntries += ch.descriptors().count();
+ }
+
+ return nEntries;
+}
+
+}
+
+@interface QT_MANGLE_NAMESPACE(OSXBTPeripheralManager) (PrivateAPI)
+
+- (void)addConnectedCentral:(CBCentral *)central;
+- (void)removeConnectedCentral:(CBCentral *)central;
+- (CBService *)findIncludedService:(const QBluetoothUuid &)qtUUID;
+
+- (void)addIncludedServices:(const QLowEnergyServiceData &)data
+ to:(CBMutableService *)cbService
+ qtService:(QLowEnergyServicePrivate *)qtService;
+
+- (void)addCharacteristicsAndDescriptors:(const QLowEnergyServiceData &)data
+ to:(CBMutableService *)cbService
+ qtService:(QLowEnergyServicePrivate *)qtService;
+
+- (CBATTError)validateWriteRequest:(CBATTRequest *)request;
+
+@end
+
+@implementation QT_MANGLE_NAMESPACE(OSXBTPeripheralManager)
+
+- (id)initWith:(LECBManagerNotifier *)aNotifier
+{
+ if (self = [super init]) {
+ Q_ASSERT(aNotifier);
+ notifier = aNotifier;
+ state = PeripheralState::idle;
+ nextServiceToAdd = {};
+ connectedCentrals.reset([[NSMutableSet alloc] init]);
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [self detach];
+ [super dealloc];
+}
+
+- (QSharedPointer<QLowEnergyServicePrivate>)addService:(const QLowEnergyServiceData &)data
+{
+ using QLES = QLowEnergyService;
+
+ const auto nEntries = qt_countGATTEntries(data);
+ if (!nEntries || nEntries > std::numeric_limits<QLowEnergyHandle>::max() - lastHandle) {
+ qCCritical(QT_BT_OSX) << "addService: not enough handles";
+ return {};
+ }
+
+ QT_BT_MAC_AUTORELEASEPOOL
+
+ const BOOL primary = data.type() == QLowEnergyServiceData::ServiceTypePrimary;
+ const auto cbUUID = cb_uuid(data.uuid());
+
+ const ObjCStrongReference<CBMutableService>
+ newCBService([[CBMutableService alloc] initWithType:cbUUID primary:primary],
+ false /*do not retain*/);
+
+ if (!newCBService) {
+ qCCritical(QT_BT_OSX) << "addService: failed to create CBMutableService";
+ return {};
+ }
+
+ auto newQtService = QSharedPointer<QLowEnergyServicePrivate>::create();
+ newQtService->state = QLowEnergyService::LocalService;
+ newQtService->uuid = data.uuid();
+ newQtService->type = primary ? QLES::PrimaryService : QLES::IncludedService;
+ newQtService->startHandle = ++lastHandle;
+ // Controller will be set by ... controller :)
+
+ [self addIncludedServices:data to:newCBService qtService:newQtService.data()];
+ [self addCharacteristicsAndDescriptors:data to:newCBService qtService:newQtService.data()];
+
+ services.push_back(newCBService);
+ serviceIndex[data.uuid()] = newCBService;
+
+ return newQtService;
+}
+
+- (void) setParameters:(const QLowEnergyAdvertisingParameters &)parameters
+ data:(const QLowEnergyAdvertisingData &)data
+ scanResponse:(const QLowEnergyAdvertisingData &)scanResponse
+{
+ Q_UNUSED(parameters)
+
+ // This is the last method we call on the controller's thread
+ // before starting advertising on the Qt's LE queue.
+ // From Apple's docs:
+ /*
+ - (void)startAdvertising:(NSDictionary *)advertisementData
+
+ Advertises peripheral manager data.
+
+ * advertisementData
+
+ - An optional dictionary containing the data you want to advertise.
+ The possible keys of an advertisementData dictionary are detailed in CBCentralManagerDelegate
+ Protocol Reference. That said, only two of the keys are supported for peripheral manager objects:
+ CBAdvertisementDataLocalNameKey and CBAdvertisementDataServiceUUIDsKey.
+ */
+
+ QT_BT_MAC_AUTORELEASEPOOL
+
+ advertisementData.reset([[NSMutableDictionary alloc] init]);
+ if (!advertisementData) {
+ qCWarning(QT_BT_OSX) << "setParameters: failed to allocate "
+ "NSMutableDictonary (advertisementData)";
+ return;
+ }
+
+ auto localName = scanResponse.localName();
+ if (!localName.size())
+ localName = data.localName();
+
+ if (localName.size()) {
+ [advertisementData setObject:localName.toNSString()
+ forKey:CBAdvertisementDataLocalNameKey];
+ }
+
+ if (!data.services().count() && !scanResponse.services().count())
+ return;
+
+ const ObjCScopedPointer<NSMutableArray> uuids([[NSMutableArray alloc] init]);
+ if (!uuids) {
+ qCWarning(QT_BT_OSX) << "setParameters: failed to allocate "
+ "NSMutableArray (services uuids)";
+ return;
+ }
+
+
+ for (const auto &qtUUID : data.services()) {
+ const auto cbUUID = cb_uuid(qtUUID);
+ if (cbUUID)
+ [uuids addObject:cbUUID];
+ }
+
+ for (const auto &qtUUID : scanResponse.services()) {
+ const auto cbUUID = cb_uuid(qtUUID);
+ if (cbUUID)
+ [uuids addObject:cbUUID];
+ }
+
+ if ([uuids count]) {
+ [advertisementData setObject:uuids
+ forKey:CBAdvertisementDataServiceUUIDsKey];
+ }
+}
+
+- (void)startAdvertising
+{
+ state = PeripheralState::waitingForPowerOn;
+ if (manager)
+ [manager setDelegate:nil];
+ manager.reset([[CBPeripheralManager alloc] initWithDelegate:self
+ queue:OSXBluetooth::qt_LE_queue()]);
+}
+
+- (void)stopAdvertising
+{
+ [manager stopAdvertising];
+ state = PeripheralState::idle;
+}
+
+- (void)detach
+{
+ if (notifier) {
+ notifier->disconnect();
+ notifier->deleteLater();
+ notifier = nullptr;
+ }
+
+ if (state == PeripheralState::advertising) {
+ [manager stopAdvertising];
+ [manager setDelegate:nil];
+ state = PeripheralState::idle;
+ }
+}
+
+- (void)write:(const QByteArray &)value
+ charHandle:(QLowEnergyHandle)charHandle
+{
+ if (!notifier)
+ return;
+
+ QT_BT_MAC_AUTORELEASEPOOL
+
+ if (!charMap.contains(charHandle)) {
+ emit notifier->CBManagerError(QLowEnergyController::UnknownError);
+ return;
+ }
+
+ const auto nsData = data_from_bytearray(value);
+ charValues[charHandle] = nsData;
+ updateQueue.push_back(UpdateRequest{charHandle, nsData});
+ [self sendUpdateRequests];
+}
+
+- (void) addServicesToPeripheral
+{
+ Q_ASSERT(manager);
+
+ if (nextServiceToAdd < services.size())
+ [manager addService:services[nextServiceToAdd++]];
+}
+
+// CBPeripheralManagerDelegate:
+
+- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
+{
+ if (peripheral != manager || !notifier)
+ return;
+
+ if (peripheral.state == CBPeripheralManagerStatePoweredOn) {
+ // "Bluetooth is currently powered on and is available to use."
+ if (state == PeripheralState::waitingForPowerOn) {
+ [manager removeAllServices];
+ nextServiceToAdd = {};
+ state = PeripheralState::advertising;
+ [self addServicesToPeripheral];
+ }
+ return;
+ }
+
+ /*
+ "A state with a value lower than CBPeripheralManagerStatePoweredOn implies that
+ advertising has stopped and that any connected centrals have been disconnected."
+ */
+
+ [connectedCentrals removeAllObjects];
+
+ if (state == PeripheralState::advertising) {
+ state = PeripheralState::waitingForPowerOn;
+ } else if (state == PeripheralState::connected) {
+ state = PeripheralState::idle;
+ emit notifier->disconnected();
+ }
+
+ // The next four states are _below_ "powered off"; according to the docs:
+ /*
+ "In addition, the local database is cleared and all services must be
+ explicitly added again."
+ */
+
+ if (peripheral.state == CBPeripheralManagerStateUnauthorized ||
+ peripheral.state == CBPeripheralManagerStateUnsupported) {
+ emit notifier->LEnotSupported();
+ state = PeripheralState::idle;
+ }
+}
+
+- (void)peripheralManager:(CBPeripheralManager *)peripheral
+ willRestoreState:(NSDictionary *)dict
+{
+ Q_UNUSED(peripheral)
+ Q_UNUSED(dict)
+ // NOOP atm.
+}
+
+- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral
+ error:(NSError *)error
+{
+ if (peripheral != manager || !notifier)
+ return;
+
+ if (error) {
+ NSLog(@"failed to start advertising, error: %@", error);
+ state = PeripheralState::idle;
+ emit notifier->CBManagerError(QLowEnergyController::AdvertisingError);
+ }
+}
+
+- (void)peripheralManager:(CBPeripheralManager *)peripheral
+ didAddService:(CBService *)service error:(NSError *)error
+{
+ Q_UNUSED(service)
+
+ if (peripheral != manager || !notifier)
+ return;
+
+ if (error) {
+ NSLog(@"failed to add a service, error: %@", error);
+ emit notifier->CBManagerError(QLowEnergyController::AdvertisingError);
+ state = PeripheralState::idle;
+ return;
+ }
+
+ if (nextServiceToAdd == services.size())
+ [manager startAdvertising:[advertisementData count] ? advertisementData.data() : nil];
+ else
+ [self addServicesToPeripheral];
+}
+
+- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central
+ didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
+{
+ Q_UNUSED(characteristic)
+
+ if (peripheral != manager || !notifier)
+ return;
+
+ [self addConnectedCentral:central];
+}
+
+- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central
+ didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic
+{
+ Q_UNUSED(characteristic)
+
+ if (peripheral != manager || !notifier)
+ return;
+
+ [self removeConnectedCentral:central];
+}
+
+- (void)peripheralManager:(CBPeripheralManager *)peripheral
+ didReceiveReadRequest:(CBATTRequest *)request
+{
+ if (peripheral != manager || !notifier)
+ return;
+
+ QT_BT_MAC_AUTORELEASEPOOL
+
+ const auto handle = charMap.key(request.characteristic);
+ if (!handle || !charValues.contains(handle)) {
+ qCWarning(QT_BT_OSX) << "invalid read request, unknown characteristic";
+ [manager respondToRequest:request withResult:CBATTErrorInvalidHandle];
+ return;
+ }
+
+ const auto &value = charValues[handle];
+ if (request.offset > [value length]) {
+ qCWarning(QT_BT_OSX) << "invalid offset in a read request";
+ [manager respondToRequest:request withResult:CBATTErrorInvalidOffset];
+ return;
+ }
+
+ [self addConnectedCentral:request.central];
+
+ NSData *dataToSend = nil;
+ if (!request.offset) {
+ dataToSend = value;
+ } else {
+ dataToSend = [value subdataWithRange:
+ NSMakeRange(request.offset, [value length] - request.offset)];
+ }
+
+ request.value = dataToSend;
+ [manager respondToRequest:request withResult:CBATTErrorSuccess];
+}
+
+- (void)peripheralManager:(CBPeripheralManager *)peripheral
+ didReceiveWriteRequests:(NSArray *)requests
+{
+ QT_BT_MAC_AUTORELEASEPOOL
+
+ if (peripheral != manager || !notifier) {
+ // Detached already.
+ return;
+ }
+
+ // We first test if all requests are valid
+ // since CoreBluetooth requires "all or none"
+ // and respond only _once_ to the first one.
+ for (CBATTRequest *request in requests) {
+ const auto status = [self validateWriteRequest:request];
+ if (status != CBATTErrorSuccess) {
+ [manager respondToRequest:[requests objectAtIndex:0]
+ withResult:status];
+ return;
+ }
+ }
+
+ std::set<QLowEnergyHandle> updated;
+
+ for (CBATTRequest *request in requests) {
+ // Transition to 'connected' if needed.
+ [self addConnectedCentral:request.central];
+
+ const auto charHandle = charMap.key(request.characteristic);
+ updated.insert(charHandle);
+ NSMutableData *const data = static_cast<NSMutableData *>(charValues[charHandle]);
+ [data replaceBytesInRange:NSMakeRange(request.offset, request.value.length)
+ withBytes:data.bytes];
+ }
+
+ for (const auto handle : updated)
+ emit notifier->characteristicUpdated(handle, qt_bytearray(charValues[handle]));
+
+ if (requests.count) {
+ [manager respondToRequest:[requests objectAtIndex:0]
+ withResult:CBATTErrorSuccess];
+ }
+}
+
+- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral
+{
+ if (peripheral != manager || !notifier) {
+ // Detached.
+ return;
+ }
+
+ [self sendUpdateRequests];
+}
+
+- (void)sendUpdateRequests
+{
+ QT_BT_MAC_AUTORELEASEPOOL
+
+ while (updateQueue.size()) {
+ const auto &request = updateQueue.front();
+ Q_ASSERT(charMap.contains(request.charHandle));
+ const BOOL res = [manager updateValue:request.value
+ forCharacteristic:static_cast<CBMutableCharacteristic *>(charMap[request.charHandle])
+ onSubscribedCentrals:nil];
+ if (!res) {
+ // Have to wait for the 'ManagerIsReadyToUpdate'.
+ break;
+ }
+
+ updateQueue.pop_front();
+ }
+}
+
+// Private API:
+
+- (void)addConnectedCentral:(CBCentral *)central
+{
+ if (!central)
+ return;
+
+ if (!notifier) {
+ // We were detached.
+ return;
+ }
+
+ QT_BT_MAC_AUTORELEASEPOOL
+
+ if (state == PeripheralState::advertising) {
+ state = PeripheralState::connected;
+ [manager stopAdvertising];
+ emit notifier->connected();
+ }
+
+ if (![connectedCentrals containsObject:central.identifier])
+ [connectedCentrals addObject:central.identifier];
+}
+
+- (void)removeConnectedCentral:(CBCentral *)central
+{
+ if (!notifier) {
+ // Detached.
+ return;
+ }
+
+ QT_BT_MAC_AUTORELEASEPOOL
+
+ if ([connectedCentrals containsObject:central.identifier])
+ [connectedCentrals removeObject:central.identifier];
+
+ if (state == PeripheralState::connected && ![connectedCentrals count]) {
+ state = PeripheralState::idle;
+ emit notifier->disconnected();
+ }
+}
+
+- (CBService *)findIncludedService:(const QBluetoothUuid &)qtUUID
+{
+ const auto it = serviceIndex.find(qtUUID);
+ if (it == serviceIndex.end())
+ return nil;
+
+ return it->second;
+}
+
+- (void)addIncludedServices:(const QLowEnergyServiceData &)data
+ to:(CBMutableService *)cbService
+ qtService:(QLowEnergyServicePrivate *)qtService
+{
+ Q_ASSERT(cbService);
+ Q_ASSERT(qtService);
+
+ QT_BT_MAC_AUTORELEASEPOOL
+
+ ObjCScopedPointer<NSMutableArray> included([[NSMutableArray alloc] init]);
+ if (!included) {
+ qCWarning(QT_BT_OSX) << "addIncludedSerivces: failed "
+ "to allocate NSMutableArray";
+ return;
+ }
+
+ for (auto includedService : data.includedServices()) {
+ if (CBService *cbs = [self findIncludedService:includedService->serviceUuid()]) {
+ [included addObject:cbs];
+ qtService->includedServices << includedService->serviceUuid();
+ ++lastHandle;
+ } else {
+ qCWarning(QT_BT_OSX) << "can not use" << includedService->serviceUuid()
+ << "as included, it has to be added first";
+ }
+ }
+
+ if ([included count])
+ cbService.includedServices = included;
+}
+
+- (void)addCharacteristicsAndDescriptors:(const QLowEnergyServiceData &)data
+ to:(CBMutableService *)cbService
+ qtService:(QLowEnergyServicePrivate *)qtService
+{
+ Q_ASSERT(cbService);
+ Q_ASSERT(qtService);
+
+ QT_BT_MAC_AUTORELEASEPOOL
+
+ ObjCScopedPointer<NSMutableArray> newCBChars([[NSMutableArray alloc] init]);
+ if (!newCBChars) {
+ qCWarning(QT_BT_OSX) << "addCharacteristicsAndDescritptors: "
+ "failed to allocate NSMutableArray "
+ "(characteristics)";
+ return;
+ }
+
+ for (const auto &ch : data.characteristics()) {
+ const auto cbChar(create_characteristic(ch));
+ if (!cbChar) {
+ qCWarning(QT_BT_OSX) << "addCharacteristicsAndDescritptors: "
+ "failed to allocate a characteristic";
+ continue;
+ }
+
+ const auto nsData(data_from_bytearray(ch.value()));
+ if (!nsData) {
+ qCWarning(QT_BT_OSX) << "addCharacteristicsAndDescritptors: "
+ "addService: failed to allocate NSData (char value)";
+ continue;
+ }
+
+ [newCBChars addObject:cbChar];
+
+ const auto declHandle = ++lastHandle;
+ // CB part:
+ charMap[declHandle] = cbChar;
+ charValues[declHandle] = data_from_bytearray(ch.value());
+ // QT part:
+ QLowEnergyServicePrivate::CharData charData;
+ charData.valueHandle = ++lastHandle;
+ charData.uuid = ch.uuid();
+ charData.properties = ch.properties();
+ charData.value = ch.value();
+
+ const ObjCScopedPointer<NSMutableArray> newCBDescs([[NSMutableArray alloc] init]);
+ if (!newCBDescs) {
+ qCWarning(QT_BT_OSX) << "addCharacteristicsAndDescritptors: "
+ "failed to allocate NSMutableArray "
+ "(descriptors)";
+ continue;
+ }
+
+ for (const auto &desc : ch.descriptors()) {
+ // CB part:
+ const auto cbDesc(create_descriptor(desc));
+ const auto descHandle = ++lastHandle;
+ if (cbDesc) {
+ // See comments in create_descriptor on
+ // why cbDesc can be nil.
+ [newCBDescs addObject:cbDesc];
+ }
+ // QT part:
+ QLowEnergyServicePrivate::DescData descData;
+ descData.uuid = desc.uuid();
+ descData.value = desc.value();
+ charData.descriptorList.insert(descHandle, descData);
+ }
+
+ if ([newCBDescs count])
+ cbChar.data().descriptors = newCBDescs.data(); // retains
+
+ qtService->characteristicList.insert(declHandle, charData);
+ }
+
+ if ([newCBChars count])
+ cbService.characteristics = newCBChars.data();
+}
+
+- (CBATTError)validateWriteRequest:(CBATTRequest *)request
+{
+ Q_ASSERT(request);
+
+ QT_BT_MAC_AUTORELEASEPOOL
+
+ const auto handle = charMap.key(request.characteristic);
+ if (!handle || !charValues.contains(handle))
+ return CBATTErrorInvalidHandle;
+
+ NSMutableData *data = static_cast<NSMutableData *>(charValues[handle]);
+ if (request.offset > data.length || request.value.length > data.length - request.offset)
+ return CBATTErrorInvalidOffset;
+
+ return CBATTErrorSuccess;
+}
+
+@end
diff --git a/src/bluetooth/osx/osxbtperipheralmanager_p.h b/src/bluetooth/osx/osxbtperipheralmanager_p.h
new file mode 100644
index 00000000..481a9fab
--- /dev/null
+++ b/src/bluetooth/osx/osxbtperipheralmanager_p.h
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OSXBTPERIPHERALMANAGER_P_H
+#define OSXBTPERIPHERALMANAGER_P_H
+
+
+#include "osxbtutility_p.h"
+
+#include "qlowenergyadvertisingparameters.h"
+#include "qlowenergyserviceprivate_p.h"
+#include "qbluetoothuuid.h"
+#include "qbluetooth.h"
+
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qsysinfo.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qmap.h>
+
+#include <vector>
+#include <deque>
+#include <map>
+
+// Foundation.h must be included before corebluetoothwrapper_p.h -
+// a workaround for a broken 10.9 SDK.
+#include <Foundation/Foundation.h>
+
+#include "corebluetoothwrapper_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QLowEnergyServiceData;
+
+namespace OSXBluetooth
+{
+
+class LECBManagerNotifier;
+
+}
+
+QT_END_NAMESPACE
+
+
+// Exposing names in a header is ugly, but constant QT_PREPEND_NAMESPACE is even worse ...
+// After all, this header is to be included only in its own and controller's *.mm files.
+
+QT_USE_NAMESPACE
+
+using namespace OSXBluetooth;
+
+
+template<class Type>
+using GenericLEMap = QMap<QLowEnergyHandle, Type>;
+
+enum class PeripheralState
+{
+ idle,
+ waitingForPowerOn,
+ advertising,
+ connected
+};
+
+struct UpdateRequest
+{
+ UpdateRequest() = default;
+ UpdateRequest(QLowEnergyHandle handle, const ObjCStrongReference<NSData> &val)
+ : charHandle(handle),
+ value(val)
+ {
+ }
+
+ QLowEnergyHandle charHandle = {};
+ ObjCStrongReference<NSData> value;
+};
+
+@interface QT_MANGLE_NAMESPACE(OSXBTPeripheralManager) : NSObject<CBPeripheralManagerDelegate>
+{
+ ObjCScopedPointer<CBPeripheralManager> manager;
+ LECBManagerNotifier *notifier;
+
+ QLowEnergyHandle lastHandle;
+ // Services in this vector are placed in such order:
+ // the one that has included services, must
+ // follow its included services to avoid exceptions from CBPeripheralManager.
+ std::vector<ObjCStrongReference<CBMutableService>> services;
+ decltype(services.size()) nextServiceToAdd;
+
+ // Lookup map for included services:
+ std::map<QBluetoothUuid, CBService *> serviceIndex;
+ ObjCScopedPointer<NSMutableDictionary> advertisementData;
+
+ GenericLEMap<CBCharacteristic *> charMap;
+ GenericLEMap<ObjCStrongReference<NSData>> charValues;
+
+ std::deque<UpdateRequest> updateQueue;
+
+ ObjCScopedPointer<NSMutableSet> connectedCentrals;
+
+ PeripheralState state;
+}
+
+- (id)initWith:(LECBManagerNotifier *)notifier;
+- (void)dealloc;
+
+- (QSharedPointer<QLowEnergyServicePrivate>)addService:(const QLowEnergyServiceData &)data;
+- (void) setParameters:(const QLowEnergyAdvertisingParameters &)parameters
+ data:(const QLowEnergyAdvertisingData &)data
+ scanResponse:(const QLowEnergyAdvertisingData &)scanResponse;
+
+// To be executed on the Qt's special BTLE dispatch queue.
+- (void)startAdvertising;
+- (void)stopAdvertising;
+- (void)detach;
+
+- (void)write:(const QByteArray &)value
+ charHandle:(QLowEnergyHandle)charHandle;
+
+
+// CBPeripheralManagerDelegate's callbacks (BTLE queue).
+- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral;
+- (void)peripheralManager:(CBPeripheralManager *)peripheral
+ willRestoreState:(NSDictionary *)dict;
+- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral
+ error:(NSError *)error;
+- (void)peripheralManager:(CBPeripheralManager *)peripheral
+ didAddService:(CBService *)service error:(NSError *)error;
+- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central
+ didSubscribeToCharacteristic:(CBCharacteristic *)characteristic;
+- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central
+ didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic;
+- (void)peripheralManager:(CBPeripheralManager *)peripheral
+ didReceiveReadRequest:(CBATTRequest *)request;
+- (void)peripheralManager:(CBPeripheralManager *)peripheral
+ didReceiveWriteRequests:(NSArray *)requests;
+- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral;
+
+@end
+
+#endif
diff --git a/src/bluetooth/osx/osxbtrfcommchannel.mm b/src/bluetooth/osx/osxbtrfcommchannel.mm
index b2ee8b64..08e8c53a 100644
--- a/src/bluetooth/osx/osxbtrfcommchannel.mm
+++ b/src/bluetooth/osx/osxbtrfcommchannel.mm
@@ -99,13 +99,13 @@ using namespace QT_NAMESPACE;
withChannelID:(BluetoothRFCOMMChannelID)channelID
{
if (address.isNull()) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "invalid peer address";
+ qCCritical(QT_BT_OSX) << "invalid peer address";
return kIOReturnNoDevice;
}
// Can never be called twice.
if (connected || device || channel) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "connection is already active";
+ qCCritical(QT_BT_OSX) << "connection is already active";
return kIOReturnStillOpen;
}
@@ -114,14 +114,14 @@ using namespace QT_NAMESPACE;
const BluetoothDeviceAddress iobtAddress = OSXBluetooth::iobluetooth_address(address);
device = [IOBluetoothDevice deviceWithAddress:&iobtAddress];
if (!device) { // TODO: do I always check this BTW??? Apple's docs say nothing about nil.
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to create a device";
+ qCCritical(QT_BT_OSX) << "failed to create a device";
return kIOReturnNoDevice;
}
const IOReturn status = [device openRFCOMMChannelAsync:&channel
withChannelID:channelID delegate:self];
if (status != kIOReturnSuccess) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to open L2CAP channel";
+ qCCritical(QT_BT_OSX) << "failed to open L2CAP channel";
// device is still autoreleased.
device = nil;
return status;
diff --git a/src/bluetooth/osx/osxbtsdpinquiry.mm b/src/bluetooth/osx/osxbtsdpinquiry.mm
index 28dc2342..490ae234 100644
--- a/src/bluetooth/osx/osxbtsdpinquiry.mm
+++ b/src/bluetooth/osx/osxbtsdpinquiry.mm
@@ -190,7 +190,7 @@ using namespace OSXBluetooth;
if (qtFilters.size()) {
array.reset([[NSMutableArray alloc] init]);
if (!array) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to allocate an uuid filter";
+ qCCritical(QT_BT_OSX) << "failed to allocate an uuid filter";
return kIOReturnError;
}
@@ -201,7 +201,7 @@ using namespace OSXBluetooth;
}
if (int([array count]) != qtFilters.size()) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to create an uuid filter";
+ qCCritical(QT_BT_OSX) << "failed to create an uuid filter";
return kIOReturnError;
}
}
@@ -209,7 +209,7 @@ using namespace OSXBluetooth;
const BluetoothDeviceAddress iobtAddress(iobluetooth_address(address));
ObjCScopedPointer<IOBluetoothDevice> newDevice([[IOBluetoothDevice deviceWithAddress:&iobtAddress] retain]);
if (!newDevice) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to create an IOBluetoothDevice object";
+ qCCritical(QT_BT_OSX) << "failed to create an IOBluetoothDevice object";
return kIOReturnError;
}
@@ -223,7 +223,7 @@ using namespace OSXBluetooth;
result = [device performSDPQuery:self];
if (result != kIOReturnSuccess) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to start an SDP query";
+ qCCritical(QT_BT_OSX) << "failed to start an SDP query";
device = oldDevice.take();
} else {
isActive = true;
diff --git a/src/bluetooth/osx/osxbtutility.mm b/src/bluetooth/osx/osxbtutility.mm
index ef34b63f..f579b2a4 100644
--- a/src/bluetooth/osx/osxbtutility.mm
+++ b/src/bluetooth/osx/osxbtutility.mm
@@ -37,6 +37,7 @@
**
****************************************************************************/
+#include "qlowenergycharacteristicdata.h"
#include "qbluetoothaddress.h"
#include "osxbtutility_p.h"
#include "qbluetoothuuid.h"
diff --git a/src/bluetooth/osx/osxbtutility_p.h b/src/bluetooth/osx/osxbtutility_p.h
index 14178162..5e616b74 100644
--- a/src/bluetooth/osx/osxbtutility_p.h
+++ b/src/bluetooth/osx/osxbtutility_p.h
@@ -64,6 +64,8 @@
QT_BEGIN_NAMESPACE
+class QLowEnergyCharacteristicData;
+class QBluetoothAddress;
class QBluetoothUuid;
namespace OSXBluetooth {
@@ -282,7 +284,7 @@ QString qt_address(NSString *address);
#ifndef QT_IOS_BLUETOOTH
-class QBluetoothAddress qt_address(const BluetoothDeviceAddress *address);
+QBluetoothAddress qt_address(const BluetoothDeviceAddress *address);
BluetoothDeviceAddress iobluetooth_address(const QBluetoothAddress &address);
ObjCStrongReference<IOBluetoothSDPUUID> iobluetooth_uuid(const QBluetoothUuid &uuid);
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm b/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm
index 620833de..0ead4e36 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm
@@ -152,7 +152,7 @@ void DDATimerHandler::start(int msec)
{
Q_ASSERT_X(msec > 0, Q_FUNC_INFO, "invalid time interval");
if (timer.isActive()) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "timer is active";
+ qCWarning(QT_BT_OSX) << "timer is active";
return;
}
@@ -186,15 +186,13 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(con
HostController controller([[IOBluetoothHostController defaultController] retain]);
if (!controller || [controller powerState] != kBluetoothHCIPowerStateON) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "no default host "
- "controller or adapter is off";
+ qCCritical(QT_BT_OSX) << "no default host controller or adapter is off";
return;
}
DeviceInquiry newInquiry([[DeviceInquiryObjC alloc]initWithDelegate:this]);
if (!newInquiry) { // Obj-C's way of "reporting errors":
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to "
- "initialize an inquiry";
+ qCCritical(QT_BT_OSX) << "failed to initialize an inquiry";
return;
}
@@ -311,7 +309,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop()
if (agentState == ClassicScan) {
const IOReturn res = [inquiry stop];
if (res != kIOReturnSuccess) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to stop";
+ qCWarning(QT_BT_OSX) << "failed to stop";
startPending = prevStart;
stopPending = false;
setError(res, QCoreApplication::translate(DEV_DISCOVERY, DD_NOT_STOPPED));
@@ -385,7 +383,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFound(IOBluetoothDeviceInquiry
// Let's collect some info about this device:
const QBluetoothAddress deviceAddress(OSXBluetooth::qt_address([device getAddress]));
if (deviceAddress.isNull()) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "invalid Bluetooth address";
+ qCWarning(QT_BT_OSX) << "invalid Bluetooth address";
return;
}
@@ -478,8 +476,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::checkLETimeout()
return;
}
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unexpected inquiry state in LE timeout";
- // Actually, this deserves an assert :)
+ qCWarning(QT_BT_OSX) << "unexpected inquiry state in LE timeout";
}
void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError(QBluetoothDeviceDiscoveryAgent::Error error)
diff --git a/src/bluetooth/qbluetoothlocaldevice_osx.mm b/src/bluetooth/qbluetoothlocaldevice_osx.mm
index 1d58363d..9fa060d2 100644
--- a/src/bluetooth/qbluetoothlocaldevice_osx.mm
+++ b/src/bluetooth/qbluetoothlocaldevice_osx.mm
@@ -119,29 +119,25 @@ QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice
HostController defaultController([[IOBluetoothHostController defaultController] retain]);
if (!defaultController) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to "
- "init a host controller object";
+ qCCritical(QT_BT_OSX) << "failed to init a host controller object";
return;
}
if (!address.isNull()) {
NSString *const hciAddress = [defaultController addressAsString];
if (!hciAddress) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to "
- "obtain an address";
+ qCCritical(QT_BT_OSX) << "failed to obtain an address";
return;
}
BluetoothDeviceAddress iobtAddress = {};
if (IOBluetoothNSStringToDeviceAddress(hciAddress, &iobtAddress) != kIOReturnSuccess) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "invalid "
- "local device's address";
+ qCCritical(QT_BT_OSX) << "invalid local device's address";
return;
}
if (address != OSXBluetooth::qt_address(&iobtAddress)) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "invalid "
- "local device's address";
+ qCCritical(QT_BT_OSX) << "invalid local device's address";
return;
}
}
@@ -184,8 +180,7 @@ void QBluetoothLocalDevicePrivate::requestPairing(const QBluetoothAddress &addre
if ([device isPaired]) {
emitPairingFinished(address, pairing, true);
} else if ([pos.value() start] != kIOReturnSuccess) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to "
- "start a new pairing request";
+ qCCritical(QT_BT_OSX) << "failed to start a new pairing request";
emitError(QBluetoothLocalDevice::PairingError, true);
}
return;
@@ -196,8 +191,7 @@ void QBluetoothLocalDevicePrivate::requestPairing(const QBluetoothAddress &addre
// it'll just finish with success (skipping any intermediate steps).
PairingRequest newRequest([[ObjCPairingRequest alloc] initWithTarget:address delegate:this], false);
if (!newRequest) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to "
- "allocate a new pairing request";
+ qCCritical(QT_BT_OSX) << "failed to allocate a new pairing request";
emitError(QBluetoothLocalDevice::PairingError, true);
return;
}
@@ -206,8 +200,7 @@ void QBluetoothLocalDevicePrivate::requestPairing(const QBluetoothAddress &addre
const IOReturn result = [newRequest start];
if (result != kIOReturnSuccess) {
pairingRequests.erase(pos);
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to "
- "start a new pairing request";
+ qCCritical(QT_BT_OSX) << "failed to start a new pairing request";
emitError(QBluetoothLocalDevice::PairingError, true);
}
}
diff --git a/src/bluetooth/qbluetoothserver_osx.mm b/src/bluetooth/qbluetoothserver_osx.mm
index 1aaa2201..3828263c 100644
--- a/src/bluetooth/qbluetoothserver_osx.mm
+++ b/src/bluetooth/qbluetoothserver_osx.mm
@@ -96,7 +96,7 @@ QBluetoothServerPrivate::QBluetoothServerPrivate(QSInfo::Protocol type, QBluetoo
{
Q_ASSERT_X(q_ptr, Q_FUNC_INFO, "invalid q_ptr (null)");
if (serverType == QSInfo::UnknownProtocol)
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unknown protocol";
+ qCWarning(QT_BT_OSX) << "unknown protocol";
}
QBluetoothServerPrivate::~QBluetoothServerPrivate()
@@ -117,7 +117,7 @@ bool QBluetoothServerPrivate::startListener(quint16 realPort)
Q_ASSERT_X(realPort, Q_FUNC_INFO, "invalid port");
if (serverType == QSInfo::UnknownProtocol) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "invalid protocol";
+ qCWarning(QT_BT_OSX) << "invalid protocol";
return false;
}
@@ -218,7 +218,7 @@ void QBluetoothServerPrivate::registerServer(QBluetoothServerPrivate *server, qu
Q_ASSERT_X(!psmIsBusy(port), Q_FUNC_INFO, "port is busy");
busyPSMs()[port] = server;
} else {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "can not register a server "
+ qCWarning(QT_BT_OSX) << "can not register a server "
"with unknown protocol type";
}
}
@@ -235,7 +235,7 @@ QBluetoothServerPrivate *QBluetoothServerPrivate::registeredServer(quint16 port,
if (it != busyPSMs().end())
return it.value();
} else {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "invalid protocol";
+ qCWarning(QT_BT_OSX) << "invalid protocol";
}
return Q_NULLPTR;
@@ -252,17 +252,17 @@ void QBluetoothServerPrivate::unregisterServer(QBluetoothServerPrivate *server)
if (it != busyChannels().end()) {
busyChannels().erase(it);
} else {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "server is not registered";
+ qCWarning(QT_BT_OSX) << "server is not registered";
}
} else if (type == QSInfo::L2capProtocol) {
ServerMapIterator it = busyPSMs().find(port);
if (it != busyPSMs().end()) {
busyPSMs().erase(it);
} else {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "server is not registered";
+ qCWarning(QT_BT_OSX) << "server is not registered";
}
} else {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "invalid protocol";
+ qCWarning(QT_BT_OSX) << "invalid protocol";
}
}
@@ -293,16 +293,15 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
typedef QBluetoothServerPrivate::ObjCListener ObjCListener;
if (d_ptr->listener) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "already in listen mode, "
- "close server first";
+ qCWarning(QT_BT_OSX) << "already in listen mode, close server first";
return false;
}
const QBluetoothLocalDevice device(address);
if (!device.isValid()) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "device does not support Bluetooth or "
+ qCWarning(QT_BT_OSX) << "device does not support Bluetooth or"
<< address.toString()
- << " is not a valid local adapter";
+ << "is not a valid local adapter";
d_ptr->lastError = UnknownError;
emit error(UnknownError);
return false;
@@ -310,7 +309,7 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
const QBluetoothLocalDevice::HostMode hostMode = device.hostMode();
if (hostMode == QBluetoothLocalDevice::HostPoweredOff) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "Bluetooth device is powered off";
+ qCWarning(QT_BT_OSX) << "Bluetooth device is powered off";
d_ptr->lastError = PoweredOffError;
emit error(PoweredOffError);
return false;
@@ -319,7 +318,7 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
const QSInfo::Protocol type = d_ptr->serverType;
if (type == QSInfo::UnknownProtocol) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "invalid protocol";
+ qCWarning(QT_BT_OSX) << "invalid protocol";
d_ptr->lastError = UnsupportedProtocolError;
emit error(d_ptr->lastError);
return false;
@@ -333,14 +332,14 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
if (port) {
if (type == QSInfo::RfcommProtocol) {
if (d_ptr->channelIsBusy(port)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO <<"server port: "
- << port << "already registered";
+ qCWarning(QT_BT_OSX) << "server port:" << port
+ << "already registered";
d_ptr->lastError = ServiceAlreadyRegisteredError;
}
} else {
if (d_ptr->psmIsBusy(port)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "server port: "
- << port << "already registered";
+ qCWarning(QT_BT_OSX) << "server port:" << port
+ << "already registered";
d_ptr->lastError = ServiceAlreadyRegisteredError;
}
}
@@ -355,7 +354,7 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
}
if (!port) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "all ports are busy";
+ qCWarning(QT_BT_OSX) << "all ports are busy";
d_ptr->lastError = ServiceAlreadyRegisteredError;
emit error(d_ptr->lastError);
return false;
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_osx.mm b/src/bluetooth/qbluetoothservicediscoveryagent_osx.mm
index 71877fc5..dc9d4ee9 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_osx.mm
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_osx.mm
@@ -336,7 +336,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::SDPInquiryError(IOBluetoothDevice *
{
Q_UNUSED(device)
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "inquiry failed with IOKit code: " << int(errorCode);
+ qCWarning(QT_BT_OSX) << "inquiry failed with IOKit code:" << int(errorCode);
discoveredDevices.clear();
// TODO: find a better mapping from IOReturn to QBluetoothServiceDiscoveryAgent::Error.
diff --git a/src/bluetooth/qbluetoothserviceinfo_osx.mm b/src/bluetooth/qbluetoothserviceinfo_osx.mm
index f2cba6cf..67392226 100644
--- a/src/bluetooth/qbluetoothserviceinfo_osx.mm
+++ b/src/bluetooth/qbluetoothserviceinfo_osx.mm
@@ -45,7 +45,6 @@
#include <QtCore/qloggingcategory.h>
#include <QtCore/qvariant.h>
-#include <QtCore/qsysinfo.h>
#include <QtCore/qglobal.h>
#include <QtCore/qmutex.h>
#include <QtCore/qmap.h>
@@ -57,44 +56,6 @@
QT_BEGIN_NAMESPACE
-namespace {
-
-// This is not in osxbtutility_p, since it's not required
-// in general and just fixes the problem with SDK < 10.9,
-// where we have to care about about IOBluetoothSDPServiceRecordRef.
-class ServiceRecordRefGuard
-{
-public:
- ServiceRecordRefGuard()
- : recordRef(Q_NULLPTR)
- {
- }
- explicit ServiceRecordRefGuard(IOBluetoothSDPServiceRecordRef r)
- : recordRef(r)
- {
- }
- ~ServiceRecordRefGuard()
- {
- if (recordRef) // Requires non-NULL pointers.
- CFRelease(recordRef);
- }
-
- void reset(IOBluetoothSDPServiceRecordRef r)
- {
- if (recordRef)
- CFRelease(recordRef);
- // Take the ownership:
- recordRef = r;
- }
-
-private:
- IOBluetoothSDPServiceRecordRef recordRef;
-
- Q_DISABLE_COPY(ServiceRecordRefGuard)
-};
-
-}
-
class QBluetoothServiceInfoPrivate
{
public:
@@ -145,48 +106,23 @@ bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &loca
serviceDict(iobluetooth_service_dictionary(*q_ptr));
if (!serviceDict) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to create a service dictionary";
+ qCWarning(QT_BT_OSX) << "failed to create a service dictionary";
return false;
}
- ServiceRecordRefGuard refGuard;
SDPRecord newRecord;
-#if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9)
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_9) {
- newRecord.reset([[IOBluetoothSDPServiceRecord
- publishedServiceRecordWithDictionary:serviceDict] retain]);
- } else {
-#else
- {
-#endif
- IOBluetoothSDPServiceRecordRef recordRef = Q_NULLPTR;
- // With ARC this will require a different cast?
- const IOReturn status = IOBluetoothAddServiceDict((CFDictionaryRef)serviceDict.data(), &recordRef);
- if (status != kIOReturnSuccess) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to register a service record";
- return false;
- }
-
- refGuard.reset(recordRef);
- newRecord.reset([[IOBluetoothSDPServiceRecord withSDPServiceRecordRef:recordRef] retain]);
- // It's weird, but ... it's not possible to release a record ref yet.
- }
+ newRecord.reset([[IOBluetoothSDPServiceRecord
+ publishedServiceRecordWithDictionary:serviceDict] retain]);
if (!newRecord) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to register a service record";
- // In case of SDK < 10.9 it's not possible to remove a service record ...
- // no way to obtain record handle yet.
+ qCWarning(QT_BT_OSX) << "failed to register a service record";
return false;
}
BluetoothSDPServiceRecordHandle newRecordHandle = 0;
if ([newRecord getServiceRecordHandle:&newRecordHandle] != kIOReturnSuccess) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to register a service record";
-#if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9)
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_9)
- [newRecord removeServiceRecord];
-#endif
- // With SDK < 10.9 there is no way to unregister at this point ...
+ qCWarning(QT_BT_OSX) << "failed to register a service record";
+ [newRecord removeServiceRecord];
return false;
}
@@ -212,17 +148,8 @@ bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &loca
}
if (!configured) {
-#if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9)
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_9) {
- [newRecord removeServiceRecord];
- } else {
-#else
- {// Just to balance braces ...
-#endif
- IOBluetoothRemoveServiceWithRecordHandle(newRecordHandle);
- }
-
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to register a service record";
+ [newRecord removeServiceRecord];
+ qCWarning(QT_BT_OSX) << "failed to register a service record";
return false;
}
@@ -248,16 +175,7 @@ bool QBluetoothServiceInfoPrivate::unregisterService()
Q_ASSERT_X(serviceRecord, Q_FUNC_INFO, "service registered, but serviceRecord is nil");
-#if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9)
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_9) {
- [serviceRecord removeServiceRecord];
- } else {
-#else
- {
-#endif
- // Assert on newRecordHandle? Is 0 a valid/invalid handle?
- IOBluetoothRemoveServiceWithRecordHandle(serviceRecordHandle);
- }
+ [serviceRecord removeServiceRecord];
serviceRecord.reset(nil);
diff --git a/src/bluetooth/qbluetoothsocket_osx.mm b/src/bluetooth/qbluetoothsocket_osx.mm
index b16a2cf9..83c4e88a 100644
--- a/src/bluetooth/qbluetoothsocket_osx.mm
+++ b/src/bluetooth/qbluetoothsocket_osx.mm
@@ -447,7 +447,7 @@ qint64 QBluetoothSocket::bytesToWrite() const
void QBluetoothSocket::connectToService(const QBluetoothServiceInfo &service, OpenMode openMode)
{
if (state() != UnconnectedState && state() != ServiceLookupState) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "called on a busy socket";
+ qCWarning(QT_BT_OSX) << "called on a busy socket";
d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_CONNECT_IN_PROGRESS);
setSocketError(OperationError);
return;
@@ -463,8 +463,8 @@ void QBluetoothSocket::connectToService(const QBluetoothServiceInfo &service, Op
} else {
// Try service discovery.
if (service.serviceUuid().isNull()) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "No port, "
- "no PSM, and no UUID provided, unable to connect";
+ qCWarning(QT_BT_OSX) << "No port, no PSM, and no "
+ "UUID provided, unable to connect";
return;
}
@@ -476,7 +476,7 @@ void QBluetoothSocket::connectToService(const QBluetoothAddress &address, const
OpenMode openMode)
{
if (state() != QBluetoothSocket::UnconnectedState) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "called on a busy socket";
+ qCWarning(QT_BT_OSX) << "called on a busy socket";
d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_CONNECT_IN_PROGRESS);
setSocketError(QBluetoothSocket::OperationError);
return;
@@ -493,7 +493,7 @@ void QBluetoothSocket::connectToService(const QBluetoothAddress &address, quint1
OpenMode openMode)
{
if (state() != QBluetoothSocket::UnconnectedState) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "called on a busy socket";
+ qCWarning(QT_BT_OSX) << "called on a busy socket";
d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_CONNECT_IN_PROGRESS);
setSocketError(OperationError);
return;
@@ -534,7 +534,7 @@ void QBluetoothSocket::setSocketState(QBluetoothSocket::SocketState state)
// We can register for L2CAP/RFCOMM open notifications,
// that's different from 'listen' and is implemented
// in QBluetoothServer.
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "listening sockets are not supported";
+ qCWarning(QT_BT_OSX) << "listening sockets are not supported";
}
}
diff --git a/src/bluetooth/qbluetoothtransferreply_osx.mm b/src/bluetooth/qbluetoothtransferreply_osx.mm
index 99c6cab1..02133860 100644
--- a/src/bluetooth/qbluetoothtransferreply_osx.mm
+++ b/src/bluetooth/qbluetoothtransferreply_osx.mm
@@ -177,7 +177,7 @@ void QBluetoothTransferReplyOSXPrivate::sendConnect(const QBluetoothAddress &dev
errorString.clear();
if (device.isNull() || !channelID) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "invalid device address or port";
+ qCWarning(QT_BT_OSX) << "invalid device address or port";
setReplyError(QBluetoothTransferReply::HostNotFoundError,
QCoreApplication::translate(TRANSFER_REPLY, TR_INVAL_TARGET));
return;
@@ -186,7 +186,7 @@ void QBluetoothTransferReplyOSXPrivate::sendConnect(const QBluetoothAddress &dev
OBEXSession newSession([[ObjCOBEXSession alloc] initWithDelegate:this
remoteDevice:device channelID:channelID]);
if (!newSession) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to allocate OSXBTOBEXSession object";
+ qCWarning(QT_BT_OSX) << "failed to allocate OSXBTOBEXSession object";
setReplyError(QBluetoothTransferReply::UnknownError,
QCoreApplication::translate(TRANSFER_REPLY, TR_SESSION_NO_START));
@@ -201,7 +201,7 @@ void QBluetoothTransferReplyOSXPrivate::sendConnect(const QBluetoothAddress &dev
if ([session isConnected])
sendPut();// Connected, send a PUT request.
} else {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "OBEXConnect failed";
+ qCWarning(QT_BT_OSX) << "OBEXConnect failed";
if (error == QBluetoothTransferReply::NoError) {
// The error is not set yet.
@@ -355,7 +355,7 @@ QBluetoothTransferReplyOSX::QBluetoothTransferReplyOSX(QIODevice *input,
if (input) {
QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection);
} else {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "invalid input stream (null)";
+ qCWarning(QT_BT_OSX) << "invalid input stream (null)";
osx_d_ptr->requestComplete = true;
osx_d_ptr->errorString = QCoreApplication::translate(TRANSFER_REPLY, TR_INVALID_DEVICE);
osx_d_ptr->error = FileNotFoundError;
@@ -416,7 +416,7 @@ bool QBluetoothTransferReplyOSX::start()
if (!osx_d_ptr->isActive()) {
// Step 0: find a channelID.
if (request().address().isNull()) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "invalid device address";
+ qCWarning(QT_BT_OSX) << "invalid device address";
osx_d_ptr->setReplyError(HostNotFoundError,
QCoreApplication::translate(TRANSFER_REPLY, TR_INVAL_TARGET));
return false;
@@ -455,7 +455,8 @@ void QBluetoothTransferReplyOSX::serviceDiscoveryFinished()
void QBluetoothTransferReplyOSX::serviceDiscoveryError(QBluetoothServiceDiscoveryAgent::Error errorCode)
{
- Q_ASSERT_X(osx_d_ptr->agent.data(), Q_FUNC_INFO, "invalid service discovery agent (null)");
+ Q_ASSERT_X(osx_d_ptr->agent.data(), Q_FUNC_INFO,
+ "invalid service discovery agent (null)");
if (errorCode == QBluetoothServiceDiscoveryAgent::PoweredOffError) {
// There's nothing else we can do.
diff --git a/src/bluetooth/qlowenergycontroller.cpp b/src/bluetooth/qlowenergycontroller.cpp
index 7f3995ed..eeff4ab0 100644
--- a/src/bluetooth/qlowenergycontroller.cpp
+++ b/src/bluetooth/qlowenergycontroller.cpp
@@ -197,13 +197,17 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT)
This signal is emitted when the controller successfully connects to the remote
Low Energy device (if the controller is in the \l CentralRole) or if a remote Low Energy
device connected to the controller (if the controller is in the \l PeripheralRole).
+ On iOS and OS X this signal is not reliable if the controller is in the \l PeripheralRole
+ - the controller only guesses that some central connected to our peripheral as
+ soon as this central tries to write/read a characteristic/descriptor.
*/
/*!
\fn void QLowEnergyController::disconnected()
This signal is emitted when the controller disconnects from the remote
- Low Energy device or vice versa.
+ Low Energy device or vice versa. On iOS and OS X this signal is unreliable
+ if the controller is in the \l PeripheralRole.
*/
/*!
diff --git a/src/bluetooth/qlowenergycontroller_osx.mm b/src/bluetooth/qlowenergycontroller_osx.mm
index 47f65965..5c4c7c37 100644
--- a/src/bluetooth/qlowenergycontroller_osx.mm
+++ b/src/bluetooth/qlowenergycontroller_osx.mm
@@ -38,11 +38,14 @@
**
****************************************************************************/
+#include "osx/osxbtnotifier_p.h"
#include "osx/osxbtutility_p.h"
#include "osx/uistrings_p.h"
+
#include "qlowenergyserviceprivate_p.h"
#include "qlowenergycontroller_osx_p.h"
+#include "qlowenergyservicedata.h"
#include "qbluetoothlocaldevice.h"
#include "qbluetoothdeviceinfo.h"
#include "qlowenergycontroller.h"
@@ -51,7 +54,6 @@
#include <QtCore/qloggingcategory.h>
#include <QtCore/qsharedpointer.h>
#include <QtCore/qbytearray.h>
-#include <QtCore/qsysinfo.h>
#include <QtCore/qglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
@@ -84,8 +86,7 @@ ServicePrivate qt_createLEService(QLowEnergyControllerPrivateOSX *controller, CB
CBUUID *const cbUuid = cbService.UUID;
if (!cbUuid) {
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "invalid service, "
- "UUID is nil";
+ qCDebug(QT_BT_OSX) << "invalid service, UUID is nil";
return ServicePrivate();
}
@@ -102,18 +103,13 @@ ServicePrivate qt_createLEService(QLowEnergyControllerPrivateOSX *controller, CB
// TODO: isPrimary is ... always 'NO' - to be investigated.
/*
- #if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_6_0)
using OSXBluetooth::qt_OS_limit;
- if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_9, QSysInfo::MV_IOS_6_0)) {
- if (!cbService.isPrimary) {
- // Our guess included/not was probably wrong.
- newService->type &= ~QLowEnergyService::PrimaryService;
- newService->type |= QLowEnergyService::IncludedService;
- }
+ if (!cbService.isPrimary) {
+ // Our guess included/not was probably wrong.
+ newService->type &= ~QLowEnergyService::PrimaryService;
+ newService->type |= QLowEnergyService::IncludedService;
}
- #endif
*/
- // No such property before 10_9/6_0.
return newService;
}
@@ -136,36 +132,8 @@ UUIDList qt_servicesUuids(NSArray *services)
}
-QLowEnergyControllerPrivateOSX::QLowEnergyControllerPrivateOSX(QLowEnergyController *q)
- : q_ptr(q),
- lastError(QLowEnergyController::NoError),
- controllerState(QLowEnergyController::UnconnectedState),
- addressType(QLowEnergyController::PublicAddress)
-{
- registerQLowEnergyControllerMetaType();
-
- // 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.
- 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,
+QLowEnergyControllerPrivateOSX::QLowEnergyControllerPrivateOSX(QLowEnergyController::Role r,
+ QLowEnergyController *q,
const QBluetoothDeviceInfo &deviceInfo)
: q_ptr(q),
deviceUuid(deviceInfo.deviceUuid()),
@@ -178,44 +146,70 @@ QLowEnergyControllerPrivateOSX::QLowEnergyControllerPrivateOSX(QLowEnergyControl
Q_ASSERT_X(q, Q_FUNC_INFO, "invalid q_ptr (null)");
- using OSXBluetooth::LECentralNotifier;
+ using OSXBluetooth::LECBManagerNotifier;
+ using OSXBluetooth::qt_OS_limit;
+
+ role = r;
+
+
- 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";
+ QScopedPointer<LECBManagerNotifier> notifier(new LECBManagerNotifier);
+ if (role == QLowEnergyController::PeripheralRole) {
+#ifndef Q_OS_TVOS
+ peripheralManager.reset([[ObjCPeripheralManager alloc] initWith:notifier.data()]);
+ if (!peripheralManager) {
+ qCWarning(QT_BT_OSX) << "failed to initialize peripheral manager";
+ return;
+ }
+#else
+ qCWarning(QT_BT_OSX) << "peripheral role is not supported on your platform";
return;
- } else if (!connectSlots(notifier.data())) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO
- << "failed to connect to notifier's signals";
+#endif
+ } else {
+ centralManager.reset([[ObjCCentralManager alloc] initWith:notifier.data()]);
+ if (!centralManager) {
+ qCWarning(QT_BT_OSX) << "failed to initialize central manager";
+ return;
+ }
}
+ if (!connectSlots(notifier.data())) {
+ qCWarning(QT_BT_OSX) << "failed to connect to notifier's signal(s)";
+ }
// 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];
- });
+ if (const auto leQueue = OSXBluetooth::qt_LE_queue()) {
+ if (role == QLowEnergyController::CentralRole) {
+ const auto manager = centralManager.data();
+ dispatch_sync(leQueue, ^{
+ [manager detach];
+ });
+ } else {
+#ifndef Q_OS_TVOS
+ const auto manager = peripheralManager.data();
+ dispatch_sync(leQueue, ^{
+ [manager detach];
+ });
+#endif
+ }
}
}
bool QLowEnergyControllerPrivateOSX::isValid() const
{
+#ifdef Q_OS_TVOS
return centralManager;
+#else
+ return centralManager || peripheralManager;
+#endif
}
void QLowEnergyControllerPrivateOSX::_q_connected()
{
- Q_ASSERT_X(controllerState == QLowEnergyController::ConnectingState,
- Q_FUNC_INFO, "invalid state");
-
controllerState = QLowEnergyController::ConnectedState;
emit q_ptr->stateChanged(QLowEnergyController::ConnectedState);
@@ -226,10 +220,11 @@ void QLowEnergyControllerPrivateOSX::_q_disconnected()
{
controllerState = QLowEnergyController::UnconnectedState;
- invalidateServices();
+ if (role == QLowEnergyController::CentralRole)
+ invalidateServices();
+
emit q_ptr->stateChanged(QLowEnergyController::UnconnectedState);
emit q_ptr->disconnected();
-
}
void QLowEnergyControllerPrivateOSX::_q_serviceDiscoveryFinished()
@@ -258,7 +253,7 @@ void QLowEnergyControllerPrivateOSX::_q_serviceDiscoveryFinished()
continue;
if (discoveredServices.contains(newService->uuid)) {
// It's a bit stupid we first created it ...
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "discovered service with a duplicated UUID "
+ qCDebug(QT_BT_OSX) << "discovered service with a duplicated UUID"
<< newService->uuid;
continue;
}
@@ -310,7 +305,7 @@ void QLowEnergyControllerPrivateOSX::_q_serviceDiscoveryFinished()
toVisitNext.resetWithoutRetain([[NSMutableArray alloc] init]);
}
} else {
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "no services found";
+ qCDebug(QT_BT_OSX) << "no services found";
}
for (ServiceMap::const_iterator it = discoveredServices.constBegin(); it != discoveredServices.constEnd(); ++it) {
@@ -332,7 +327,7 @@ void QLowEnergyControllerPrivateOSX::_q_serviceDetailsDiscoveryFinished(QSharedP
Q_ASSERT(service);
if (!discoveredServices.contains(service->uuid)) {
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "unknown service uuid: "
+ qCDebug(QT_BT_OSX) << "unknown service uuid:"
<< service->uuid;
return;
}
@@ -357,7 +352,7 @@ void QLowEnergyControllerPrivateOSX::_q_characteristicRead(QLowEnergyHandle char
QLowEnergyCharacteristic characteristic(characteristicForHandle(charHandle));
if (!characteristic.isValid()) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unknown characteristic";
+ qCWarning(QT_BT_OSX) << "unknown characteristic";
return;
}
@@ -374,14 +369,14 @@ void QLowEnergyControllerPrivateOSX::_q_characteristicWritten(QLowEnergyHandle c
ServicePrivate service(serviceForHandle(charHandle));
if (service.isNull()) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "can not find service for characteristic handle "
+ qCWarning(QT_BT_OSX) << "can not find service for characteristic handle"
<< charHandle;
return;
}
QLowEnergyCharacteristic characteristic(characteristicForHandle(charHandle));
if (!characteristic.isValid()) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unknown characteristic";
+ qCWarning(QT_BT_OSX) << "unknown characteristic";
return;
}
@@ -410,7 +405,7 @@ void QLowEnergyControllerPrivateOSX::_q_characteristicUpdated(QLowEnergyHandle c
QLowEnergyCharacteristic characteristic(characteristicForHandle(charHandle));
if (!characteristic.isValid()) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unknown characteristic";
+ qCWarning(QT_BT_OSX) << "unknown characteristic";
return;
}
@@ -427,7 +422,7 @@ void QLowEnergyControllerPrivateOSX::_q_descriptorRead(QLowEnergyHandle dHandle,
const QLowEnergyDescriptor qtDescriptor(descriptorForHandle(dHandle));
if (!qtDescriptor.isValid()) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unknown descriptor " << dHandle;
+ qCWarning(QT_BT_OSX) << "unknown descriptor" << dHandle;
return;
}
@@ -443,7 +438,7 @@ void QLowEnergyControllerPrivateOSX::_q_descriptorWritten(QLowEnergyHandle dHand
const QLowEnergyDescriptor qtDescriptor(descriptorForHandle(dHandle));
if (!qtDescriptor.isValid()) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unknown descriptor " << dHandle;
+ qCWarning(QT_BT_OSX) << "unknown descriptor" << dHandle;
return;
}
@@ -461,7 +456,7 @@ void QLowEnergyControllerPrivateOSX::_q_LEnotSupported()
// be supported.
}
-void QLowEnergyControllerPrivateOSX::_q_CBCentralManagerError(QLowEnergyController::Error errorCode)
+void QLowEnergyControllerPrivateOSX::_q_CBManagerError(QLowEnergyController::Error errorCode)
{
// Errors reported during connect and general errors.
@@ -478,8 +473,8 @@ void QLowEnergyControllerPrivateOSX::_q_CBCentralManagerError(QLowEnergyControll
// a service/characteristic - related error.
}
-void QLowEnergyControllerPrivateOSX::_q_CBCentralManagerError(const QBluetoothUuid &serviceUuid,
- QLowEnergyController::Error errorCode)
+void QLowEnergyControllerPrivateOSX::_q_CBManagerError(const QBluetoothUuid &serviceUuid,
+ QLowEnergyController::Error errorCode)
{
// Errors reported while discovering service details etc.
Q_UNUSED(errorCode) // TODO: setError?
@@ -489,16 +484,16 @@ void QLowEnergyControllerPrivateOSX::_q_CBCentralManagerError(const QBluetoothUu
ServicePrivate qtService(discoveredServices.value(serviceUuid));
qtService->setState(QLowEnergyService::InvalidService);
} else {
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "error reported for unknown service "
+ qCDebug(QT_BT_OSX) << "error reported for unknown service"
<< serviceUuid;
}
}
-void QLowEnergyControllerPrivateOSX::_q_CBCentralManagerError(const QBluetoothUuid &serviceUuid,
- QLowEnergyService::ServiceError errorCode)
+void QLowEnergyControllerPrivateOSX::_q_CBManagerError(const QBluetoothUuid &serviceUuid,
+ QLowEnergyService::ServiceError errorCode)
{
if (!discoveredServices.contains(serviceUuid)) {
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "unknown service uuid: "
+ qCDebug(QT_BT_OSX) << "unknown service uuid:"
<< serviceUuid;
return;
}
@@ -514,10 +509,12 @@ void QLowEnergyControllerPrivateOSX::connectToDevice()
Q_FUNC_INFO, "invalid state");
Q_ASSERT_X(!deviceUuid.isNull(), Q_FUNC_INFO,
"invalid private controller (no device uuid)");
+ Q_ASSERT_X(role != QLowEnergyController::PeripheralRole,
+ Q_FUNC_INFO, "invalid role (peripheral)");
dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
if (!leQueue) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ qCWarning(QT_BT_OSX) << "no LE queue found";
setErrorDescription(QLowEnergyController::UnknownError);
return;
}
@@ -537,10 +534,12 @@ void QLowEnergyControllerPrivateOSX::discoverServices()
Q_ASSERT_X(isValid(), Q_FUNC_INFO, "invalid private controller");
Q_ASSERT_X(controllerState != QLowEnergyController::UnconnectedState,
Q_FUNC_INFO, "not connected to peripheral");
+ Q_ASSERT_X(role != QLowEnergyController::PeripheralRole,
+ Q_FUNC_INFO, "invalid role (peripheral)");
dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
if (!leQueue) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ qCWarning(QT_BT_OSX) << "no LE queue found";
setErrorDescription(QLowEnergyController::UnknownError);
return;
}
@@ -559,20 +558,21 @@ void QLowEnergyControllerPrivateOSX::discoverServiceDetails(const QBluetoothUuid
Q_ASSERT_X(isValid(), Q_FUNC_INFO, "invalid private controller");
if (controllerState != QLowEnergyController::DiscoveredState) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO
- << "can not discover service details in the current state, "
- << "QLowEnergyController::DiscoveredState is expected";
+ // This will also exclude peripheral role, since controller
+ // can never be in discovered state ...
+ qCWarning(QT_BT_OSX) << "can not discover service details in the current state, "
+ "QLowEnergyController::DiscoveredState is expected";
return;
}
if (!discoveredServices.contains(serviceUuid)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unknown service: " << serviceUuid;
+ qCWarning(QT_BT_OSX) << "unknown service: " << serviceUuid;
return;
}
dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
if (!leQueue) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ qCWarning(QT_BT_OSX) << "no LE queue found";
return;
}
@@ -593,32 +593,37 @@ void QLowEnergyControllerPrivateOSX::setNotifyValue(QSharedPointer<QLowEnergySer
Q_ASSERT_X(!service.isNull(), Q_FUNC_INFO, "invalid service (null)");
Q_ASSERT_X(isValid(), Q_FUNC_INFO, "invalid controller");
+ if (role == QLowEnergyController::PeripheralRole) {
+ qCWarning(QT_BT_OSX) << "invalid role (peripheral)";
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ return;
+ }
+
if (newValue.size() > 2) {
// Qt's API requires an error on such write.
// With Core Bluetooth we do not write any descriptor,
// but instead call a special method. So it's better to
// intercept wrong data size here:
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "client characteristic configuration descriptor "
+ qCWarning(QT_BT_OSX) << "client characteristic configuration descriptor"
"is 2 bytes, but value size is: " << newValue.size();
service->setError(QLowEnergyService::DescriptorWriteError);
return;
}
if (!discoveredServices.contains(service->uuid)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no service with uuid: "
- << service->uuid << " found";
+ qCWarning(QT_BT_OSX) << "no service with uuid:" << service->uuid << "found";
return;
}
if (!service->characteristicList.contains(charHandle)) {
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "no characteristic with handle: "
- << charHandle << " found";
+ qCDebug(QT_BT_OSX) << "no characteristic with handle:"
+ << charHandle << "found";
return;
}
dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
if (!leQueue) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ qCWarning(QT_BT_OSX) << "no LE queue found";
return;
}
ObjCCentralManager *manager = centralManager.data();
@@ -637,21 +642,26 @@ void QLowEnergyControllerPrivateOSX::readCharacteristic(QSharedPointer<QLowEnerg
Q_ASSERT_X(!service.isNull(), Q_FUNC_INFO, "invalid service (null)");
Q_ASSERT_X(isValid(), Q_FUNC_INFO, "invalid controller");
+ if (role == QLowEnergyController::PeripheralRole) {
+ qCWarning(QT_BT_OSX) << "invalid role (peripheral)";
+ return;
+ }
+
if (!discoveredServices.contains(service->uuid)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no service with uuid:"
+ qCWarning(QT_BT_OSX) << "no service with uuid:"
<< service->uuid << "found";
return;
}
if (!service->characteristicList.contains(charHandle)) {
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "no characteristic with handle:"
+ qCDebug(QT_BT_OSX) << "no characteristic with handle:"
<< charHandle << "found";
return;
}
dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
if (!leQueue) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ qCWarning(QT_BT_OSX) << "no LE queue found";
return;
}
// Attention! We have to copy UUID.
@@ -669,36 +679,47 @@ void QLowEnergyControllerPrivateOSX::writeCharacteristic(QSharedPointer<QLowEner
Q_ASSERT_X(!service.isNull(), Q_FUNC_INFO, "invalid service (null)");
Q_ASSERT_X(isValid(), Q_FUNC_INFO, "invalid controller");
- // We can work only with services, found on a given peripheral
- // (== created by the given LE controller),
- // otherwise we can not write anything at all.
+ // We can work only with services found on a given peripheral
+ // (== created by the given LE controller).
+
if (!discoveredServices.contains(service->uuid)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no service with uuid: "
+ qCWarning(QT_BT_OSX) << "no service with uuid:"
<< service->uuid << " found";
return;
}
if (!service->characteristicList.contains(charHandle)) {
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "no characteristic with handle: "
+ qCDebug(QT_BT_OSX) << "no characteristic with handle:"
<< charHandle << " found";
return;
}
dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
if (!leQueue) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ qCWarning(QT_BT_OSX) << "no LE queue found";
return;
}
- // Attention! Copy objects!
- const QBluetoothUuid serviceUuid(service->uuid);
+ // Attention! We have to copy objects!
const QByteArray newValueCopy(newValue);
- ObjCCentralManager *const manager = centralManager.data();
- dispatch_async(leQueue, ^{
- [manager write:newValueCopy
- charHandle:charHandle
+ if (role == QLowEnergyController::CentralRole) {
+ const QBluetoothUuid serviceUuid(service->uuid);
+ const auto manager = centralManager.data();
+ dispatch_async(leQueue, ^{
+ [manager write:newValueCopy
+ charHandle:charHandle
onService:serviceUuid
withResponse:mode == QLowEnergyService::WriteWithResponse];
- });
+ });
+ } else {
+#ifndef Q_OS_TVOS
+ const auto manager = peripheralManager.data();
+ dispatch_async(leQueue, ^{
+ [manager write:newValueCopy charHandle:charHandle];
+ });
+#else
+ qCWarning(QT_BT_OSX) << "peripheral role is not supported on your platform";
+#endif
+ }
}
quint16 QLowEnergyControllerPrivateOSX::updateValueOfCharacteristic(QLowEnergyHandle charHandle,
@@ -728,15 +749,20 @@ void QLowEnergyControllerPrivateOSX::readDescriptor(QSharedPointer<QLowEnergySer
Q_ASSERT_X(!service.isNull(), Q_FUNC_INFO, "invalid service (null)");
Q_ASSERT_X(isValid(), Q_FUNC_INFO, "invalid controller");
+ if (role == QLowEnergyController::PeripheralRole) {
+ qCWarning(QT_BT_OSX) << "invalid role (peripheral)";
+ return;
+ }
+
if (!discoveredServices.contains(service->uuid)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no service with uuid:"
+ qCWarning(QT_BT_OSX) << "no service with uuid:"
<< service->uuid << "found";
return;
}
dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
if (!leQueue) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ qCWarning(QT_BT_OSX) << "no LE queue found";
return;
}
// Attention! Copy objects!
@@ -755,18 +781,23 @@ void QLowEnergyControllerPrivateOSX::writeDescriptor(QSharedPointer<QLowEnergySe
Q_ASSERT_X(!service.isNull(), Q_FUNC_INFO, "invalid service (null)");
Q_ASSERT_X(isValid(), Q_FUNC_INFO, "invalid controller");
+ if (role == QLowEnergyController::PeripheralRole) {
+ qCWarning(QT_BT_OSX) << "invalid role (peripheral)";
+ return;
+ }
+
// We can work only with services found on a given peripheral
// (== created by the given LE controller),
// otherwise we can not write anything at all.
if (!discoveredServices.contains(service->uuid)) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no service with uuid: "
+ qCWarning(QT_BT_OSX) << "no service with uuid:"
<< service->uuid << " found";
return;
}
dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
if (!leQueue) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no LE queue found";
+ qCWarning(QT_BT_OSX) << "no LE queue found";
return;
}
// Attention! Copy objects!
@@ -868,17 +899,23 @@ void QLowEnergyControllerPrivateOSX::setErrorDescription(QLowEnergyController::E
errorString.clear();
break;
case QLowEnergyController::UnknownRemoteDeviceError:
- errorString = QCoreApplication::translate(LE_CONTROLLER, LEC_RDEV_NO_FOUND);
+ errorString = QLowEnergyController::tr("Remote device cannot be found");
break;
case QLowEnergyController::InvalidBluetoothAdapterError:
- errorString = QCoreApplication::translate(LE_CONTROLLER, LEC_NO_LOCAL_DEV);
+ errorString = QLowEnergyController::tr("Cannot find local adapter");
break;
case QLowEnergyController::NetworkError:
- errorString = QCoreApplication::translate(LE_CONTROLLER, LEC_IO_ERROR);
+ errorString = QLowEnergyController::tr("Error occurred during connection I/O");
+ break;
+ case QLowEnergyController::ConnectionError:
+ errorString = QLowEnergyController::tr("Error occurred trying to connect to remote device.");
+ break;
+ case QLowEnergyController::AdvertisingError:
+ errorString = QLowEnergyController::tr("Error occurred trying to start advertising");
break;
case QLowEnergyController::UnknownError:
default:
- errorString = QCoreApplication::translate(LE_CONTROLLER, LEC_UNKNOWN_ERROR);
+ errorString = QLowEnergyController::tr("Unknown Error");
break;
}
}
@@ -893,38 +930,38 @@ void QLowEnergyControllerPrivateOSX::invalidateServices()
discoveredServices.clear();
}
-bool QLowEnergyControllerPrivateOSX::connectSlots(OSXBluetooth::LECentralNotifier *notifier)
+bool QLowEnergyControllerPrivateOSX::connectSlots(OSXBluetooth::LECBManagerNotifier *notifier)
{
- using OSXBluetooth::LECentralNotifier;
+ using OSXBluetooth::LECBManagerNotifier;
Q_ASSERT_X(notifier, Q_FUNC_INFO, "invalid notifier object (null)");
- bool ok = connect(notifier, &LECentralNotifier::connected,
+ bool ok = connect(notifier, &LECBManagerNotifier::connected,
this, &QLowEnergyControllerPrivateOSX::_q_connected);
- ok = ok && connect(notifier, &LECentralNotifier::disconnected,
+ ok = ok && connect(notifier, &LECBManagerNotifier::disconnected,
this, &QLowEnergyControllerPrivateOSX::_q_disconnected);
- ok = ok && connect(notifier, &LECentralNotifier::serviceDiscoveryFinished,
+ ok = ok && connect(notifier, &LECBManagerNotifier::serviceDiscoveryFinished,
this, &QLowEnergyControllerPrivateOSX::_q_serviceDiscoveryFinished);
- ok = ok && connect(notifier, &LECentralNotifier::serviceDetailsDiscoveryFinished,
+ ok = ok && connect(notifier, &LECBManagerNotifier::serviceDetailsDiscoveryFinished,
this, &QLowEnergyControllerPrivateOSX::_q_serviceDetailsDiscoveryFinished);
- ok = ok && connect(notifier, &LECentralNotifier::characteristicRead,
+ ok = ok && connect(notifier, &LECBManagerNotifier::characteristicRead,
this, &QLowEnergyControllerPrivateOSX::_q_characteristicRead);
- ok = ok && connect(notifier, &LECentralNotifier::characteristicWritten,
+ ok = ok && connect(notifier, &LECBManagerNotifier::characteristicWritten,
this, &QLowEnergyControllerPrivateOSX::_q_characteristicWritten);
- ok = ok && connect(notifier, &LECentralNotifier::characteristicUpdated,
+ ok = ok && connect(notifier, &LECBManagerNotifier::characteristicUpdated,
this, &QLowEnergyControllerPrivateOSX::_q_characteristicUpdated);
- ok = ok && connect(notifier, &LECentralNotifier::descriptorRead,
+ ok = ok && connect(notifier, &LECBManagerNotifier::descriptorRead,
this, &QLowEnergyControllerPrivateOSX::_q_descriptorRead);
- ok = ok && connect(notifier, &LECentralNotifier::descriptorWritten,
+ ok = ok && connect(notifier, &LECBManagerNotifier::descriptorWritten,
this, &QLowEnergyControllerPrivateOSX::_q_descriptorWritten);
- ok = ok && connect(notifier, &LECentralNotifier::LEnotSupported,
+ ok = ok && connect(notifier, &LECBManagerNotifier::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)));
+ ok = ok && connect(notifier, SIGNAL(CBManagerError(QLowEnergyController::Error)),
+ this, SLOT(_q_CBManagerError(QLowEnergyController::Error)));
+ ok = ok && connect(notifier, SIGNAL(CBManagerError(const QBluetoothUuid &, QLowEnergyController::Error)),
+ this, SLOT(_q_CBManagerError(const QBluetoothUuid &, QLowEnergyController::Error)));
+ ok = ok && connect(notifier, SIGNAL(CBManagerError(const QBluetoothUuid &, QLowEnergyService::ServiceError)),
+ this, SLOT(_q_CBManagerError(const QBluetoothUuid &, QLowEnergyService::ServiceError)));
if (!ok)
notifier->disconnect();
@@ -935,26 +972,24 @@ bool QLowEnergyControllerPrivateOSX::connectSlots(OSXBluetooth::LECentralNotifie
QLowEnergyController::QLowEnergyController(const QBluetoothAddress &remoteAddress,
QObject *parent)
: QObject(parent),
- d_ptr(new QLowEnergyControllerPrivateOSX(this))
+ d_ptr(new QLowEnergyControllerPrivateOSX(CentralRole, this))
{
OSX_D_PTR;
- osx_d_ptr->role = CentralRole;
osx_d_ptr->remoteAddress = remoteAddress;
osx_d_ptr->localAddress = QBluetoothLocalDevice().address();
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "construction with remote address "
+ qCWarning(QT_BT_OSX) << "construction with remote address "
"is not supported!";
}
QLowEnergyController::QLowEnergyController(const QBluetoothDeviceInfo &remoteDevice,
QObject *parent)
: QObject(parent),
- d_ptr(new QLowEnergyControllerPrivateOSX(this, remoteDevice))
+ d_ptr(new QLowEnergyControllerPrivateOSX(CentralRole, this, remoteDevice))
{
OSX_D_PTR;
- osx_d_ptr->role = CentralRole;
osx_d_ptr->localAddress = QBluetoothLocalDevice().address();
// That's the only "real" ctor - with Core Bluetooth we need a _valid_ deviceUuid
// from 'remoteDevice'.
@@ -964,24 +999,23 @@ QLowEnergyController::QLowEnergyController(const QBluetoothAddress &remoteAddres
const QBluetoothAddress &localAddress,
QObject *parent)
: QObject(parent),
- d_ptr(new QLowEnergyControllerPrivateOSX(this))
+ d_ptr(new QLowEnergyControllerPrivateOSX(CentralRole, this))
{
OSX_D_PTR;
- osx_d_ptr->role = CentralRole;
osx_d_ptr->remoteAddress = remoteAddress;
osx_d_ptr->localAddress = localAddress;
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "construction with remote/local "
+ qCWarning(QT_BT_OSX) << "construction with remote/local "
"addresses is not supported!";
}
QLowEnergyController::QLowEnergyController(QObject *parent)
- : QObject(parent), d_ptr(new QLowEnergyControllerPrivateOSX(this))
+ : QObject(parent),
+ d_ptr(new QLowEnergyControllerPrivateOSX(PeripheralRole, this))
{
OSX_D_PTR;
- osx_d_ptr->role = PeripheralRole;
osx_d_ptr->localAddress = QBluetoothLocalDevice().address();
}
@@ -1059,11 +1093,16 @@ void QLowEnergyController::connectToDevice()
// A memory allocation problem.
if (!osx_d_ptr->isValid())
- return osx_d_ptr->_q_CBCentralManagerError(UnknownError);
+ return osx_d_ptr->_q_CBManagerError(UnknownError);
+
+ if (role() == PeripheralRole) {
+ qCWarning(QT_BT_OSX) << "can not connect in peripheral role";
+ return osx_d_ptr->_q_CBManagerError(ConnectionError);
+ }
// No QBluetoothDeviceInfo provided during construction.
if (osx_d_ptr->deviceUuid.isNull())
- return osx_d_ptr->_q_CBCentralManagerError(UnknownRemoteDeviceError);
+ return osx_d_ptr->_q_CBManagerError(UnknownRemoteDeviceError);
if (osx_d_ptr->controllerState != UnconnectedState)
return;
@@ -1078,6 +1117,11 @@ void QLowEnergyController::disconnectFromDevice()
OSX_D_PTR;
+ if (role() != CentralRole) {
+ qCWarning(QT_BT_OSX) << "can not disconnect while in central role";
+ return osx_d_ptr->_q_CBManagerError(ConnectionError);
+ }
+
if (osx_d_ptr->isValid()) {
const ControllerState oldState = osx_d_ptr->controllerState;
@@ -1101,14 +1145,19 @@ void QLowEnergyController::disconnectFromDevice()
emit stateChanged(UnconnectedState);
}
} else {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "qt LE queue is nil,"
- << "can not dispatch 'disconnect'";
+ qCCritical(QT_BT_OSX) << "qt LE queue is nil, "
+ "can not dispatch 'disconnect'";
}
}
}
void QLowEnergyController::discoverServices()
{
+ if (role() == PeripheralRole) {
+ qCWarning(QT_BT_OSX) << "invalid role (peripheral)";
+ return;
+ }
+
if (state() != ConnectedState)
return;
@@ -1159,30 +1208,126 @@ void QLowEnergyController::startAdvertising(const QLowEnergyAdvertisingParameter
const QLowEnergyAdvertisingData &advertisingData,
const QLowEnergyAdvertisingData &scanResponseData)
{
- Q_UNUSED(params);
- Q_UNUSED(advertisingData);
- Q_UNUSED(scanResponseData);
- qCWarning(QT_BT_OSX) << "LE advertising not implemented for OS X";
+#ifdef Q_OS_TVOS
+ Q_UNUSED(params)
+ Q_UNUSED(advertisingData)
+ Q_UNUSED(scanResponseData)
+ qCWarning(QT_BT_OSX) << "advertising is not supported on your platform";
+#else
+ OSX_D_PTR;
+
+ if (!osx_d_ptr->isValid())
+ return osx_d_ptr->_q_CBManagerError(UnknownError);
+
+ if (role() != PeripheralRole) {
+ qCWarning(QT_BT_OSX) << "invalid role";
+ return;
+ }
+
+ if (state() != UnconnectedState) {
+ qCWarning(QT_BT_OSX) << "invalid state" << state();
+ return;
+ }
+
+ auto leQueue(OSXBluetooth::qt_LE_queue());
+ if (!leQueue) {
+ qCWarning(QT_BT_OSX) << "no LE queue found";
+ osx_d_ptr->setErrorDescription(QLowEnergyController::UnknownError);
+ return;
+ }
+
+ [osx_d_ptr->peripheralManager setParameters:params
+ data:advertisingData
+ scanResponse:scanResponseData];
+
+ osx_d_ptr->controllerState = AdvertisingState;
+ emit stateChanged(AdvertisingState);
+
+ const auto manager = osx_d_ptr->peripheralManager.data();
+ dispatch_async(leQueue, ^{
+ [manager startAdvertising];
+ });
+#endif
}
void QLowEnergyController::stopAdvertising()
{
- qCWarning(QT_BT_OSX) << "LE advertising not implemented for OS X";
+#ifdef Q_OS_TVOS
+ qCWarning(QT_BT_OSX) << "advertising is not supported on your platform";
+#else
+ OSX_D_PTR;
+
+ if (!osx_d_ptr->isValid())
+ return osx_d_ptr->_q_CBManagerError(UnknownError);
+
+ if (state() != AdvertisingState) {
+ qCDebug(QT_BT_OSX) << "called in state" << state();
+ return;
+ }
+
+ if (const auto leQueue = OSXBluetooth::qt_LE_queue()) {
+ const auto manager = osx_d_ptr->peripheralManager.data();
+ dispatch_sync(leQueue, ^{
+ [manager stopAdvertising];
+ });
+
+ osx_d_ptr->controllerState = UnconnectedState;
+ emit stateChanged(UnconnectedState);
+ } else {
+ qCWarning(QT_BT_OSX) << "no LE queue found";
+ osx_d_ptr->setErrorDescription(QLowEnergyController::UnknownError);
+ return;
+ }
+#endif
}
-QLowEnergyService *QLowEnergyController::addService(const QLowEnergyServiceData &service,
+QLowEnergyService *QLowEnergyController::addService(const QLowEnergyServiceData &data,
QObject *parent)
{
- Q_UNUSED(service);
- Q_UNUSED(parent);
- qCWarning(QT_BT_OSX) << "GATT server functionality not implemented for OS X";
+#ifdef Q_OS_TVOS
+ Q_UNUSED(data)
+ Q_UNUSED(parent)
+ qCWarning(QT_BT_OSX) << "peripheral role is not supported on your platform";
+#else
+ OSX_D_PTR;
+
+ if (!osx_d_ptr->isValid()) {
+ osx_d_ptr->_q_CBManagerError(UnknownError);
+ return nullptr;
+ }
+
+ if (role() != PeripheralRole) {
+ qCWarning(QT_BT_OSX) << "not in peripheral role";
+ return nullptr;
+ }
+
+ if (state() != UnconnectedState) {
+ qCWarning(QT_BT_OSX) << "invalid state";
+ return nullptr;
+ }
+
+ if (!data.isValid()) {
+ qCWarning(QT_BT_OSX) << "invalid service";
+ return nullptr;
+ }
+
+ for (auto includedService : data.includedServices())
+ includedService->d_ptr->type |= QLowEnergyService::IncludedService;
+
+ if (const auto servicePrivate = [osx_d_ptr->peripheralManager addService:data]) {
+ servicePrivate->setController(osx_d_ptr);
+ osx_d_ptr->discoveredServices.insert(servicePrivate->uuid, servicePrivate);
+ return new QLowEnergyService(servicePrivate, parent);
+ }
+#endif
+
return nullptr;
}
void QLowEnergyController::requestConnectionUpdate(const QLowEnergyConnectionParameters &params)
{
Q_UNUSED(params);
- qCWarning(QT_BT_OSX) << "Connection update not implemented for OS X";
+ qCWarning(QT_BT_OSX) << "Connection update not implemented on your platform";
}
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergycontroller_osx_p.h b/src/bluetooth/qlowenergycontroller_osx_p.h
index 853e1f9b..b7399ed7 100644
--- a/src/bluetooth/qlowenergycontroller_osx_p.h
+++ b/src/bluetooth/qlowenergycontroller_osx_p.h
@@ -51,6 +51,7 @@
// We mean it.
//
+#include "osx/osxbtperipheralmanager_p.h"
#include "qlowenergyserviceprivate_p.h"
#include "osx/osxbtcentralmanager_p.h"
#include "qlowenergycontroller_p.h"
@@ -61,6 +62,7 @@
#include "qbluetoothuuid.h"
#include <QtCore/qsharedpointer.h>
+#include <QtCore/qsysinfo.h>
#include <QtCore/qglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qmap.h>
@@ -70,13 +72,13 @@ QT_BEGIN_NAMESPACE
namespace OSXBluetooth
{
-class LECentralNotifier;
+class LECBManagerNotifier;
}
class QByteArray;
-// While suffix 'OSX', it's also for iOS.
+// Suffix 'OSX' is a legacy, it's also iOS.
class QLowEnergyControllerPrivateOSX : public QLowEnergyControllerPrivate
{
friend class QLowEnergyController;
@@ -84,9 +86,8 @@ class QLowEnergyControllerPrivateOSX : public QLowEnergyControllerPrivate
Q_OBJECT
public:
- QLowEnergyControllerPrivateOSX(QLowEnergyController *q);
- QLowEnergyControllerPrivateOSX(QLowEnergyController *q,
- const QBluetoothDeviceInfo &uuid);
+ QLowEnergyControllerPrivateOSX(QLowEnergyController::Role role, QLowEnergyController *q,
+ const QBluetoothDeviceInfo &info = QBluetoothDeviceInfo());
~QLowEnergyControllerPrivateOSX();
bool isValid() const;
@@ -105,18 +106,15 @@ private Q_SLOTS:
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);
+ void _q_CBManagerError(QLowEnergyController::Error error);
+ void _q_CBManagerError(const QBluetoothUuid &serviceUuid, QLowEnergyController::Error error);
+ void _q_CBManagerError(const QBluetoothUuid &serviceUuid, QLowEnergyService::ServiceError error);
private:
void connectToDevice();
void discoverServices();
void discoverServiceDetails(const QBluetoothUuid &serviceUuid);
- // TODO: all these read/write /setNotify can be simplified -
- // by just passing either characteristic or descriptor (that
- // has all needed information - service, handle, etc.).
void setNotifyValue(QSharedPointer<QLowEnergyServicePrivate> service,
QLowEnergyHandle charHandle, const QByteArray &newValue);
@@ -149,7 +147,7 @@ private:
void setErrorDescription(QLowEnergyController::Error errorCode);
void invalidateServices();
- bool connectSlots(OSXBluetooth::LECentralNotifier *notifier);
+ bool connectSlots(OSXBluetooth::LECBManagerNotifier *notifier);
QLowEnergyController *q_ptr;
QBluetoothUuid deviceUuid;
@@ -170,6 +168,12 @@ private:
typedef OSXBluetooth::ObjCScopedPointer<ObjCCentralManager> CentralManager;
CentralManager centralManager;
+#ifndef Q_OS_TVOS
+ typedef QT_MANGLE_NAMESPACE(OSXBTPeripheralManager) ObjCPeripheralManager;
+ typedef OSXBluetooth::ObjCScopedPointer<ObjCPeripheralManager> PeripheralManager;
+ PeripheralManager peripheralManager;
+#endif
+
typedef QMap<QBluetoothUuid, QSharedPointer<QLowEnergyServicePrivate> > ServiceMap;
typedef ServiceMap::const_iterator ConstServiceIterator;
typedef ServiceMap::iterator ServiceIterator;
diff --git a/src/bluetooth/qlowenergyservice_osx.mm b/src/bluetooth/qlowenergyservice_osx.mm
index 97d64040..52c2ac87 100644
--- a/src/bluetooth/qlowenergyservice_osx.mm
+++ b/src/bluetooth/qlowenergyservice_osx.mm
@@ -208,7 +208,9 @@ void QLowEnergyService::writeCharacteristic(const QLowEnergyCharacteristic &ch,
WriteMode mode)
{
QLowEnergyControllerPrivateOSX *const controller = qt_mac_le_controller(d_ptr);
- if (controller == Q_NULLPTR || state() != ServiceDiscovered || !contains(ch)) {
+ if (controller == Q_NULLPTR ||
+ (controller->role == QLowEnergyController::CentralRole && state() != ServiceDiscovered) ||
+ !contains(ch)) {
d_ptr->setError(QLowEnergyService::OperationError);
return;
}
@@ -250,6 +252,8 @@ void QLowEnergyService::writeDescriptor(const QLowEnergyDescriptor &descriptor,
{
QLowEnergyControllerPrivateOSX *const controller = qt_mac_le_controller(d_ptr);
if (controller == Q_NULLPTR || state() != ServiceDiscovered || !contains(descriptor)) {
+ // This operation error also includes LE controller in the peripheral role:
+ // on iOS/OS X - descriptors are immutable.
d_ptr->setError(OperationError);
return;
}