summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/qlowenergycontroller_osx.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/bluetooth/qlowenergycontroller_osx.mm')
-rw-r--r--src/bluetooth/qlowenergycontroller_osx.mm457
1 files changed, 299 insertions, 158 deletions
diff --git a/src/bluetooth/qlowenergycontroller_osx.mm b/src/bluetooth/qlowenergycontroller_osx.mm
index 47f65965..6e85e630 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,12 @@ 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 +131,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 +145,67 @@ QLowEnergyControllerPrivateOSX::QLowEnergyControllerPrivateOSX(QLowEnergyControl
Q_ASSERT_X(q, Q_FUNC_INFO, "invalid q_ptr (null)");
- using OSXBluetooth::LECentralNotifier;
+ using OSXBluetooth::LECBManagerNotifier;
+
+ 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 +216,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 +249,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 +301,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 +323,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 +348,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 +365,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 +401,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 +418,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 +434,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 +452,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 +469,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 +480,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 +505,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 +530,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 +554,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 +589,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 +638,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 +675,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 +745,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 +777,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 +895,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 +926,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 +968,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 +995,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 +1089,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 +1113,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 +1141,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 +1204,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