6#include "darwin/btperipheralmanager_p.h"
8#include "darwin/btcentralmanager_p.h"
9#include "darwin/btutility_p.h"
10#include "darwin/uistrings_p.h"
18#include <QtCore/qloggingcategory.h>
19#include <QtCore/qsharedpointer.h>
20#include <QtCore/qbytearray.h>
21#include <QtCore/qglobal.h>
22#include <QtCore/qstring.h>
23#include <QtCore/qlist.h>
24#include <QtCore/qcoreapplication.h>
25#include <QtCore/qpermissions.h>
31typedef QSharedPointer<QLowEnergyServicePrivate> ServicePrivate;
34ServicePrivate qt_createLEService(QLowEnergyControllerPrivateDarwin *controller, CBService *cbService,
bool included)
36 Q_ASSERT_X(controller, Q_FUNC_INFO,
"invalid controller (null)");
37 Q_ASSERT_X(cbService, Q_FUNC_INFO,
"invalid service (nil)");
39 CBUUID *
const cbUuid = cbService.UUID;
41 qCDebug(QT_BT_DARWIN) <<
"invalid service, UUID is nil";
42 return ServicePrivate();
45 const QBluetoothUuid qtUuid(DarwinBluetooth::qt_uuid(cbUuid));
47 return ServicePrivate();
49 ServicePrivate newService(
new QLowEnergyServicePrivate);
50 newService->uuid = qtUuid;
51 newService->setController(controller);
54 newService->type |= QLowEnergyService::IncludedService;
58
59
60
61
62
63
67typedef QList<QBluetoothUuid> UUIDList;
69UUIDList qt_servicesUuids(NSArray *services)
73 if (!services || !services.count)
78 for (CBService *s in services)
79 uuids.append(DarwinBluetooth::qt_uuid(s.UUID));
86QLowEnergyControllerPrivateDarwin::QLowEnergyControllerPrivateDarwin()
88 void registerQLowEnergyControllerMetaType();
89 registerQLowEnergyControllerMetaType();
90 qRegisterMetaType<QLowEnergyHandle>(
"QLowEnergyHandle");
91 qRegisterMetaType<QSharedPointer<QLowEnergyServicePrivate>>();
94QLowEnergyControllerPrivateDarwin::~QLowEnergyControllerPrivateDarwin()
96 if (
const auto leQueue = DarwinBluetooth::qt_LE_queue()) {
97 if (role == QLowEnergyController::CentralRole) {
98 const auto manager = centralManager.getAs<DarwinBTCentralManager>();
99 dispatch_sync(leQueue, ^{
103 const auto manager = peripheralManager.getAs<DarwinBTPeripheralManager>();
104 dispatch_sync(leQueue, ^{
111bool QLowEnergyControllerPrivateDarwin::isValid()
const
113 return centralManager || peripheralManager;
116void QLowEnergyControllerPrivateDarwin::init()
123bool QLowEnergyControllerPrivateDarwin::lazyInit()
125 using namespace DarwinBluetooth;
127 if (peripheralManager || centralManager)
130 if (qApp->checkPermission(QBluetoothPermission{}) != Qt::PermissionStatus::Granted) {
131 qCWarning(QT_BT_DARWIN,
132 "Use of Bluetooth LE must be explicitly requested by the application.");
133 setError(QLowEnergyController::MissingPermissionsError);
137 std::unique_ptr<LECBManagerNotifier> notifier = std::make_unique<LECBManagerNotifier>();
138 if (role == QLowEnergyController::PeripheralRole) {
139 peripheralManager.reset([[DarwinBTPeripheralManager alloc] initWith:notifier.get()],
140 DarwinBluetooth::RetainPolicy::noInitialRetain);
141 Q_ASSERT(peripheralManager);
143 centralManager.reset([[DarwinBTCentralManager alloc] initWith:notifier.get()],
144 DarwinBluetooth::RetainPolicy::noInitialRetain);
145 Q_ASSERT(centralManager);
149 if (!connectSlots(notifier.get()))
150 qCWarning(QT_BT_DARWIN) <<
"failed to connect to notifier's signal(s)";
158void QLowEnergyControllerPrivateDarwin::connectToDevice()
160 Q_ASSERT_X(state == QLowEnergyController::UnconnectedState,
161 Q_FUNC_INFO,
"invalid state");
163 if (deviceUuid.isNull()) {
165 return _q_CBManagerError(QLowEnergyController::UnknownRemoteDeviceError);
172 Q_ASSERT_X(role != QLowEnergyController::PeripheralRole,
173 Q_FUNC_INFO,
"invalid role (peripheral)");
175 dispatch_queue_t leQueue(DarwinBluetooth::qt_LE_queue());
176 Q_ASSERT_X(leQueue, Q_FUNC_INFO,
"invalid LE queue (nullptr)");
178 setError(QLowEnergyController::NoError);
179 setState(QLowEnergyController::ConnectingState);
181 const QBluetoothUuid deviceUuidCopy(deviceUuid);
182 DarwinBTCentralManager *manager = centralManager.getAs<DarwinBTCentralManager>();
183 dispatch_async(leQueue, ^{
184 [manager connectToDevice:deviceUuidCopy];
188void QLowEnergyControllerPrivateDarwin::disconnectFromDevice()
192 if (role == QLowEnergyController::PeripheralRole) {
195 return stopAdvertising();
198 const auto oldState = state;
200 if (dispatch_queue_t leQueue = DarwinBluetooth::qt_LE_queue()) {
201 setState(QLowEnergyController::ClosingState);
202 invalidateServices();
204 auto manager = centralManager.getAs<DarwinBTCentralManager>();
205 dispatch_async(leQueue, ^{
206 [manager disconnectFromDevice];
209 if (oldState == QLowEnergyController::ConnectingState) {
214 setState(QLowEnergyController::UnconnectedState);
217 qCCritical(QT_BT_DARWIN) <<
"qt LE queue is nil, "
218 "can not dispatch 'disconnect'";
222void QLowEnergyControllerPrivateDarwin::discoverServices()
224 Q_ASSERT_X(state != QLowEnergyController::UnconnectedState,
225 Q_FUNC_INFO,
"not connected to peripheral");
226 Q_ASSERT_X(role != QLowEnergyController::PeripheralRole,
227 Q_FUNC_INFO,
"invalid role (peripheral)");
231 dispatch_queue_t leQueue(DarwinBluetooth::qt_LE_queue());
232 Q_ASSERT_X(leQueue, Q_FUNC_INFO,
"LE queue not found");
234 setState(QLowEnergyController::DiscoveringState);
236 DarwinBTCentralManager *manager = centralManager.getAs<DarwinBTCentralManager>();
237 dispatch_async(leQueue, ^{
238 [manager discoverServices];
242void QLowEnergyControllerPrivateDarwin::discoverServiceDetails(
243 const QBluetoothUuid &serviceUuid, QLowEnergyService::DiscoveryMode mode)
246 if (state != QLowEnergyController::DiscoveredState) {
247 qCWarning(QT_BT_DARWIN) <<
"can not discover service details in the current state, "
248 "QLowEnergyController::DiscoveredState is expected";
252 if (!serviceList.contains(serviceUuid)) {
253 qCWarning(QT_BT_DARWIN) <<
"unknown service: " << serviceUuid;
257 dispatch_queue_t leQueue(DarwinBluetooth::qt_LE_queue());
260 ServicePrivate qtService(serviceList.value(serviceUuid));
261 qtService->setState(QLowEnergyService::RemoteServiceDiscovering);
263 DarwinBTCentralManager *manager = centralManager.getAs<DarwinBTCentralManager>();
264 const QBluetoothUuid serviceUuidCopy(serviceUuid);
265 dispatch_async(leQueue, ^{
266 [manager discoverServiceDetails:serviceUuidCopy readValues:mode == QLowEnergyService::FullDiscovery];
270void QLowEnergyControllerPrivateDarwin::requestConnectionUpdate(
const QLowEnergyConnectionParameters ¶ms)
274 qCWarning(QT_BT_DARWIN) <<
"Connection update not implemented on your platform";
277void QLowEnergyControllerPrivateDarwin::addToGenericAttributeList(
const QLowEnergyServiceData &service,
278 QLowEnergyHandle startHandle)
283 Q_UNUSED(startHandle);
286int QLowEnergyControllerPrivateDarwin::mtu()
const
291 __block
int mtu = DarwinBluetooth::defaultMtu;
295 if (
const auto leQueue = DarwinBluetooth::qt_LE_queue()) {
296 const auto *manager = centralManager.getAs<DarwinBTCentralManager>();
297 dispatch_sync(leQueue, ^{
305void QLowEnergyControllerPrivateDarwin::readRssi()
307 Q_ASSERT(role == QLowEnergyController::CentralRole);
308 Q_ASSERT(state == QLowEnergyController::ConnectedState ||
309 state == QLowEnergyController::DiscoveringState ||
310 state == QLowEnergyController::DiscoveredState);
312 if (
const auto leQueue = DarwinBluetooth::qt_LE_queue()) {
313 const auto *manager = centralManager.getAs<DarwinBTCentralManager>();
314 dispatch_async(leQueue, ^{
320QLowEnergyService * QLowEnergyControllerPrivateDarwin::addServiceHelper(
const QLowEnergyServiceData &service)
322 if (!lazyInit() || !isValid()) {
323 qCWarning(QT_BT_DARWIN) <<
"invalid peripheral";
327 for (
auto includedService : service.includedServices())
328 includedService->d_ptr->type |= QLowEnergyService::IncludedService;
330 const auto manager = peripheralManager.getAs<DarwinBTPeripheralManager>();
332 if (
const auto servicePrivate = [manager addService:service]) {
333 servicePrivate->setController(
this);
334 servicePrivate->state = QLowEnergyService::LocalService;
335 localServices.insert(servicePrivate->uuid, servicePrivate);
336 return new QLowEnergyService(servicePrivate);
342void QLowEnergyControllerPrivateDarwin::_q_connected()
344 setState(QLowEnergyController::ConnectedState);
345 emit q_ptr->connected();
348void QLowEnergyControllerPrivateDarwin::_q_disconnected()
350 if (role == QLowEnergyController::CentralRole)
351 invalidateServices();
353 setState(QLowEnergyController::UnconnectedState);
354 emit q_ptr->disconnected();
357void QLowEnergyControllerPrivateDarwin::_q_mtuChanged(
int newValue)
359 emit q_ptr->mtuChanged(newValue);
362void QLowEnergyControllerPrivateDarwin::_q_serviceDiscoveryFinished()
364 Q_ASSERT_X(state == QLowEnergyController::DiscoveringState,
365 Q_FUNC_INFO,
"invalid state");
367 using namespace DarwinBluetooth;
371 NSArray *
const services = [centralManager.getAs<DarwinBTCentralManager>() peripheral].services;
376 if (services && [services count]) {
377 QMap<QBluetoothUuid, CBService *> discoveredCBServices;
382 for (CBService *cbService in services) {
383 const ServicePrivate newService(qt_createLEService(
this, cbService,
false));
384 if (!newService.data())
386 if (serviceList.contains(newService->uuid)) {
388 qCDebug(QT_BT_DARWIN) <<
"discovered service with a duplicated UUID"
392 serviceList.insert(newService->uuid, newService);
393 discoveredCBServices.insert(newService->uuid, cbService);
396 ObjCStrongReference<NSMutableArray> toVisit([[NSMutableArray alloc] initWithArray:services], RetainPolicy::noInitialRetain);
397 ObjCStrongReference<NSMutableArray> toVisitNext([[NSMutableArray alloc] init], RetainPolicy::noInitialRetain);
398 ObjCStrongReference<NSMutableSet> visited([[NSMutableSet alloc] init], RetainPolicy::noInitialRetain);
401 for (NSUInteger i = 0, e = [toVisit count]; i < e; ++i) {
402 CBService *
const s = [toVisit objectAtIndex:i];
403 if (![visited containsObject:s]) {
404 [visited addObject:s];
405 if (s.includedServices && s.includedServices.count)
406 [toVisitNext addObjectsFromArray:s.includedServices];
409 const QBluetoothUuid uuid(qt_uuid(s.UUID));
410 if (serviceList.contains(uuid) && discoveredCBServices.value(uuid) == s) {
411 ServicePrivate qtService(serviceList.value(uuid));
413 qtService->includedServices.append(qt_servicesUuids(s.includedServices));
417 if (![toVisitNext count])
420 for (NSUInteger i = 0, e = [toVisitNext count]; i < e; ++i) {
421 CBService *
const s = [toVisitNext objectAtIndex:i];
422 const QBluetoothUuid uuid(qt_uuid(s.UUID));
423 if (serviceList.contains(uuid)) {
424 if (discoveredCBServices.value(uuid) == s) {
425 ServicePrivate qtService(serviceList.value(uuid));
426 qtService->type |= QLowEnergyService::IncludedService;
430 ServicePrivate newService(qt_createLEService(
this, s,
true));
431 serviceList.insert(newService->uuid, newService);
432 discoveredCBServices.insert(newService->uuid, s);
436 toVisit.swap(toVisitNext);
437 toVisitNext.reset([[NSMutableArray alloc] init], RetainPolicy::noInitialRetain);
440 qCDebug(QT_BT_DARWIN) <<
"no services found";
444 state = QLowEnergyController::DiscoveredState;
446 for (
auto it = serviceList.constBegin(); it != serviceList.constEnd(); ++it) {
447 QMetaObject::invokeMethod(q_ptr,
"serviceDiscovered", Qt::QueuedConnection,
448 Q_ARG(QBluetoothUuid, it.key()));
451 QMetaObject::invokeMethod(q_ptr,
"stateChanged", Qt::QueuedConnection, Q_ARG(QLowEnergyController::ControllerState, state));
452 QMetaObject::invokeMethod(q_ptr,
"discoveryFinished", Qt::QueuedConnection);
455void QLowEnergyControllerPrivateDarwin::_q_serviceDetailsDiscoveryFinished(QSharedPointer<QLowEnergyServicePrivate> service)
461 if (!serviceList.contains(service->uuid)) {
462 qCDebug(QT_BT_DARWIN) <<
"unknown service uuid:"
467 ServicePrivate qtService(serviceList.value(service->uuid));
469 qtService->startHandle = service->startHandle;
470 qtService->endHandle = service->endHandle;
471 qtService->characteristicList = service->characteristicList;
473 qtService->setState(QLowEnergyService::RemoteServiceDiscovered);
476void QLowEnergyControllerPrivateDarwin::_q_servicesWereModified()
478 if (!(state == QLowEnergyController::DiscoveringState
479 || state == QLowEnergyController::DiscoveredState)) {
480 qCWarning(QT_BT_DARWIN) <<
"services were modified while controller is not in Discovered/Discovering state";
484 if (state == QLowEnergyController::DiscoveredState)
485 invalidateServices();
487 setState(QLowEnergyController::ConnectedState);
488 q_ptr->discoverServices();
491void QLowEnergyControllerPrivateDarwin::_q_characteristicRead(QLowEnergyHandle charHandle,
492 const QByteArray &value)
494 Q_ASSERT_X(charHandle, Q_FUNC_INFO,
"invalid characteristic handle(0)");
496 ServicePrivate service(serviceForHandle(charHandle));
497 if (service.isNull())
500 QLowEnergyCharacteristic characteristic(characteristicForHandle(charHandle));
501 if (!characteristic.isValid()) {
502 qCWarning(QT_BT_DARWIN) <<
"unknown characteristic";
506 if (characteristic.properties() & QLowEnergyCharacteristic::Read)
507 updateValueOfCharacteristic(charHandle, value,
false);
509 emit service->characteristicRead(characteristic, value);
512void QLowEnergyControllerPrivateDarwin::_q_characteristicWritten(QLowEnergyHandle charHandle,
513 const QByteArray &value)
515 Q_ASSERT_X(charHandle, Q_FUNC_INFO,
"invalid characteristic handle(0)");
517 ServicePrivate service(serviceForHandle(charHandle));
518 if (service.isNull()) {
519 qCWarning(QT_BT_DARWIN) <<
"can not find service for characteristic handle"
524 QLowEnergyCharacteristic characteristic(characteristicForHandle(charHandle));
525 if (!characteristic.isValid()) {
526 qCWarning(QT_BT_DARWIN) <<
"unknown characteristic";
530 if (characteristic.properties() & QLowEnergyCharacteristic::Read)
531 updateValueOfCharacteristic(charHandle, value,
false);
533 emit service->characteristicWritten(characteristic, value);
536void QLowEnergyControllerPrivateDarwin::_q_characteristicUpdated(QLowEnergyHandle charHandle,
537 const QByteArray &value)
541 Q_ASSERT_X(charHandle, Q_FUNC_INFO,
"invalid characteristic handle(0)");
543 ServicePrivate service(serviceForHandle(charHandle));
544 if (service.isNull()) {
553 QLowEnergyCharacteristic characteristic(characteristicForHandle(charHandle));
554 if (!characteristic.isValid()) {
555 qCWarning(QT_BT_DARWIN) <<
"unknown characteristic";
559 if (characteristic.properties() & QLowEnergyCharacteristic::Read)
560 updateValueOfCharacteristic(charHandle, value,
false);
562 emit service->characteristicChanged(characteristic, value);
565void QLowEnergyControllerPrivateDarwin::_q_descriptorRead(QLowEnergyHandle dHandle,
566 const QByteArray &value)
568 Q_ASSERT_X(dHandle, Q_FUNC_INFO,
"invalid descriptor handle (0)");
570 const QLowEnergyDescriptor qtDescriptor(descriptorForHandle(dHandle));
571 if (!qtDescriptor.isValid()) {
572 qCWarning(QT_BT_DARWIN) <<
"unknown descriptor" << dHandle;
576 ServicePrivate service(serviceForHandle(qtDescriptor.characteristicHandle()));
577 updateValueOfDescriptor(qtDescriptor.characteristicHandle(), dHandle, value,
false);
578 emit service->descriptorRead(qtDescriptor, value);
581void QLowEnergyControllerPrivateDarwin::_q_descriptorWritten(QLowEnergyHandle dHandle,
582 const QByteArray &value)
584 Q_ASSERT_X(dHandle, Q_FUNC_INFO,
"invalid descriptor handle (0)");
586 const QLowEnergyDescriptor qtDescriptor(descriptorForHandle(dHandle));
587 if (!qtDescriptor.isValid()) {
588 qCWarning(QT_BT_DARWIN) <<
"unknown descriptor" << dHandle;
592 ServicePrivate service(serviceForHandle(qtDescriptor.characteristicHandle()));
594 updateValueOfDescriptor(qtDescriptor.characteristicHandle(), dHandle, value,
false);
595 emit service->descriptorWritten(qtDescriptor, value);
598void QLowEnergyControllerPrivateDarwin::_q_notificationEnabled(QLowEnergyHandle charHandle,
608 Q_ASSERT_X(role == QLowEnergyController::PeripheralRole, Q_FUNC_INFO,
609 "controller has an invalid role, 'peripheral' expected");
610 Q_ASSERT_X(charHandle, Q_FUNC_INFO,
"invalid characteristic handle (0)");
612 const QLowEnergyCharacteristic qtChar(characteristicForHandle(charHandle));
613 if (!qtChar.isValid()) {
614 qCWarning(QT_BT_DARWIN) <<
"unknown characteristic" << charHandle;
618 const QLowEnergyDescriptor qtDescriptor =
619 qtChar.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
620 if (!qtDescriptor.isValid()) {
621 qCWarning(QT_BT_DARWIN) <<
"characteristic" << charHandle
622 <<
"does not have a client characteristic "
627 ServicePrivate service(serviceForHandle(charHandle));
628 if (service.data()) {
633 QByteArray value(2, 0);
636 updateValueOfDescriptor(charHandle, qtDescriptor.handle(), value,
false);
637 emit service->descriptorWritten(qtDescriptor, value);
641void QLowEnergyControllerPrivateDarwin::_q_LEnotSupported()
649void QLowEnergyControllerPrivateDarwin::_q_CBManagerError(QLowEnergyController::Error errorCode)
651 qCDebug(QT_BT_DARWIN) <<
"QLowEnergyController error:" << errorCode <<
"in state:" << state;
656 if (state == QLowEnergyController::ConnectingState
657 || state == QLowEnergyController::AdvertisingState) {
658 setState(QLowEnergyController::UnconnectedState);
659 }
else if (state == QLowEnergyController::DiscoveringState) {
661 setState(QLowEnergyController::ConnectedState);
662 emit q_ptr->discoveryFinished();
669void QLowEnergyControllerPrivateDarwin::_q_CBManagerError(
const QBluetoothUuid &serviceUuid,
670 QLowEnergyController::Error errorCode)
676 if (serviceList.contains(serviceUuid)) {
677 ServicePrivate qtService(serviceList.value(serviceUuid));
678 qtService->setState(QLowEnergyService::InvalidService);
680 qCDebug(QT_BT_DARWIN) <<
"error reported for unknown service"
685void QLowEnergyControllerPrivateDarwin::_q_CBManagerError(
const QBluetoothUuid &serviceUuid,
686 QLowEnergyService::ServiceError errorCode)
688 if (!serviceList.contains(serviceUuid)) {
689 qCDebug(QT_BT_DARWIN) <<
"unknown service uuid:"
694 ServicePrivate service(serviceList.value(serviceUuid));
695 service->setError(errorCode);
698void QLowEnergyControllerPrivateDarwin::setNotifyValue(QSharedPointer<QLowEnergyServicePrivate> service,
699 QLowEnergyHandle charHandle,
700 const QByteArray &newValue)
702 Q_ASSERT_X(!service.isNull(), Q_FUNC_INFO,
"invalid service (null)");
704 if (role == QLowEnergyController::PeripheralRole) {
705 qCWarning(QT_BT_DARWIN) <<
"invalid role (peripheral)";
706 service->setError(QLowEnergyService::DescriptorWriteError);
710 if (newValue.size() > 2) {
715 qCWarning(QT_BT_DARWIN) <<
"client characteristic configuration descriptor"
716 "is 2 bytes, but value size is: " << newValue.size();
717 service->setError(QLowEnergyService::DescriptorWriteError);
721 if (!serviceList.contains(service->uuid)) {
722 qCWarning(QT_BT_DARWIN) <<
"no service with uuid:" << service->uuid <<
"found";
726 if (!service->characteristicList.contains(charHandle)) {
727 qCDebug(QT_BT_DARWIN) <<
"no characteristic with handle:"
728 << charHandle <<
"found";
732 dispatch_queue_t leQueue(DarwinBluetooth::qt_LE_queue());
733 Q_ASSERT_X(leQueue, Q_FUNC_INFO,
"no LE queue found");
735 DarwinBTCentralManager *manager = centralManager.getAs<DarwinBTCentralManager>();
736 const QBluetoothUuid serviceUuid(service->uuid);
737 const QByteArray newValueCopy(newValue);
738 dispatch_async(leQueue, ^{
739 [manager setNotifyValue:newValueCopy
740 forCharacteristic:charHandle
741 onService:serviceUuid];
745void QLowEnergyControllerPrivateDarwin::readCharacteristic(
const QSharedPointer<QLowEnergyServicePrivate> service,
746 const QLowEnergyHandle charHandle)
748 Q_ASSERT_X(!service.isNull(), Q_FUNC_INFO,
"invalid service (null)");
750 if (role == QLowEnergyController::PeripheralRole) {
751 qCWarning(QT_BT_DARWIN) <<
"invalid role (peripheral)";
755 if (!serviceList.contains(service->uuid)) {
756 qCWarning(QT_BT_DARWIN) <<
"no service with uuid:"
757 << service->uuid <<
"found";
761 if (!service->characteristicList.contains(charHandle)) {
762 qCDebug(QT_BT_DARWIN) <<
"no characteristic with handle:"
763 << charHandle <<
"found";
767 dispatch_queue_t leQueue(DarwinBluetooth::qt_LE_queue());
768 Q_ASSERT_X(leQueue, Q_FUNC_INFO,
"no LE queue found");
771 DarwinBTCentralManager *manager = centralManager.getAs<DarwinBTCentralManager>();
772 const QBluetoothUuid serviceUuid(service->uuid);
773 dispatch_async(leQueue, ^{
774 [manager readCharacteristic:charHandle onService:serviceUuid];
778void QLowEnergyControllerPrivateDarwin::writeCharacteristic(
const QSharedPointer<QLowEnergyServicePrivate> service,
779 const QLowEnergyHandle charHandle,
const QByteArray &newValue,
780 QLowEnergyService::WriteMode mode)
782 Q_ASSERT_X(!service.isNull(), Q_FUNC_INFO,
"invalid service (null)");
787 if (!serviceList.contains(service->uuid) && !localServices.contains(service->uuid)) {
788 qCWarning(QT_BT_DARWIN) <<
"no service with uuid:"
789 << service->uuid <<
" found";
793 if (!service->characteristicList.contains(charHandle)) {
794 qCDebug(QT_BT_DARWIN) <<
"no characteristic with handle:"
795 << charHandle <<
" found";
799 dispatch_queue_t leQueue(DarwinBluetooth::qt_LE_queue());
800 Q_ASSERT_X(leQueue, Q_FUNC_INFO,
"no LE queue found");
802 const QByteArray newValueCopy(newValue);
803 if (role == QLowEnergyController::CentralRole) {
804 const QBluetoothUuid serviceUuid(service->uuid);
805 const auto manager = centralManager.getAs<DarwinBTCentralManager>();
806 dispatch_async(leQueue, ^{
807 [manager write:newValueCopy
808 charHandle:charHandle
809 onService:serviceUuid
810 withResponse:mode == QLowEnergyService::WriteWithResponse];
813 const auto manager = peripheralManager.getAs<DarwinBTPeripheralManager>();
814 dispatch_async(leQueue, ^{
815 [manager write:newValueCopy charHandle:charHandle];
820quint16 QLowEnergyControllerPrivateDarwin::updateValueOfCharacteristic(QLowEnergyHandle charHandle,
821 const QByteArray &value,
824 QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
825 if (!service.isNull()) {
826 CharacteristicDataMap::iterator charIt = service->characteristicList.find(charHandle);
827 if (charIt != service->characteristicList.end()) {
828 QLowEnergyServicePrivate::CharData &charData = charIt.value();
830 charData.value += value;
832 charData.value = value;
834 return charData.value.size();
841void QLowEnergyControllerPrivateDarwin::readDescriptor(
const QSharedPointer<QLowEnergyServicePrivate> service,
842 const QLowEnergyHandle charHandle,
843 const QLowEnergyHandle descriptorHandle)
845 Q_UNUSED(charHandle);
847 Q_ASSERT_X(!service.isNull(), Q_FUNC_INFO,
"invalid service (null)");
849 if (role == QLowEnergyController::PeripheralRole) {
850 qCWarning(QT_BT_DARWIN) <<
"invalid role (peripheral)";
854 if (!serviceList.contains(service->uuid)) {
855 qCWarning(QT_BT_DARWIN) <<
"no service with uuid:"
856 << service->uuid <<
"found";
860 dispatch_queue_t leQueue(DarwinBluetooth::qt_LE_queue());
862 qCWarning(QT_BT_DARWIN) <<
"no LE queue found";
866 const QBluetoothUuid serviceUuid(service->uuid);
867 DarwinBTCentralManager *
const manager = centralManager.getAs<DarwinBTCentralManager>();
868 dispatch_async(leQueue, ^{
869 [manager readDescriptor:descriptorHandle
870 onService:serviceUuid];
874void QLowEnergyControllerPrivateDarwin::writeDescriptor(
const QSharedPointer<QLowEnergyServicePrivate> service,
875 const QLowEnergyHandle charHandle,
876 const QLowEnergyHandle descriptorHandle,
877 const QByteArray &newValue)
879 Q_UNUSED(charHandle);
881 Q_ASSERT_X(!service.isNull(), Q_FUNC_INFO,
"invalid service (null)");
883 if (role == QLowEnergyController::PeripheralRole) {
884 qCWarning(QT_BT_DARWIN) <<
"invalid role (peripheral)";
891 if (!serviceList.contains(service->uuid)) {
892 qCWarning(QT_BT_DARWIN) <<
"no service with uuid:"
893 << service->uuid <<
" found";
897 dispatch_queue_t leQueue(DarwinBluetooth::qt_LE_queue());
898 Q_ASSERT_X(leQueue, Q_FUNC_INFO,
"no LE queue found");
900 const QBluetoothUuid serviceUuid(service->uuid);
901 DarwinBTCentralManager *
const manager = centralManager.getAs<DarwinBTCentralManager>();
902 const QByteArray newValueCopy(newValue);
903 dispatch_async(leQueue, ^{
904 [manager write:newValueCopy
905 descHandle:descriptorHandle
906 onService:serviceUuid];
910quint16 QLowEnergyControllerPrivateDarwin::updateValueOfDescriptor(QLowEnergyHandle charHandle, QLowEnergyHandle descHandle,
911 const QByteArray &value,
bool appendValue)
913 QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
914 if (!service.isNull()) {
915 CharacteristicDataMap::iterator charIt = service->characteristicList.find(charHandle);
916 if (charIt != service->characteristicList.end()) {
917 QLowEnergyServicePrivate::CharData &charData = charIt.value();
919 DescriptorDataMap::iterator descIt = charData.descriptorList.find(descHandle);
920 if (descIt != charData.descriptorList.end()) {
921 QLowEnergyServicePrivate::DescData &descDetails = descIt.value();
924 descDetails.value += value;
926 descDetails.value = value;
928 return descDetails.value.size();
936bool QLowEnergyControllerPrivateDarwin::connectSlots(DarwinBluetooth::LECBManagerNotifier *notifier)
938 using DarwinBluetooth::LECBManagerNotifier;
940 Q_ASSERT_X(notifier, Q_FUNC_INFO,
"invalid notifier object (null)");
942 bool ok = connect(notifier, &LECBManagerNotifier::connected,
943 this, &QLowEnergyControllerPrivateDarwin::_q_connected);
944 ok = ok && connect(notifier, &LECBManagerNotifier::disconnected,
945 this, &QLowEnergyControllerPrivateDarwin::_q_disconnected);
946 ok = ok && connect(notifier, &LECBManagerNotifier::serviceDiscoveryFinished,
947 this, &QLowEnergyControllerPrivateDarwin::_q_serviceDiscoveryFinished);
948 ok = ok && connect(notifier, &LECBManagerNotifier::servicesWereModified,
949 this, &QLowEnergyControllerPrivateDarwin::_q_servicesWereModified);
950 ok = ok && connect(notifier, &LECBManagerNotifier::serviceDetailsDiscoveryFinished,
951 this, &QLowEnergyControllerPrivateDarwin::_q_serviceDetailsDiscoveryFinished);
952 ok = ok && connect(notifier, &LECBManagerNotifier::characteristicRead,
953 this, &QLowEnergyControllerPrivateDarwin::_q_characteristicRead);
954 ok = ok && connect(notifier, &LECBManagerNotifier::characteristicWritten,
955 this, &QLowEnergyControllerPrivateDarwin::_q_characteristicWritten);
956 ok = ok && connect(notifier, &LECBManagerNotifier::characteristicUpdated,
957 this, &QLowEnergyControllerPrivateDarwin::_q_characteristicUpdated);
958 ok = ok && connect(notifier, &LECBManagerNotifier::descriptorRead,
959 this, &QLowEnergyControllerPrivateDarwin::_q_descriptorRead);
960 ok = ok && connect(notifier, &LECBManagerNotifier::descriptorWritten,
961 this, &QLowEnergyControllerPrivateDarwin::_q_descriptorWritten);
962 ok = ok && connect(notifier, &LECBManagerNotifier::notificationEnabled,
963 this, &QLowEnergyControllerPrivateDarwin::_q_notificationEnabled);
964 ok = ok && connect(notifier, &LECBManagerNotifier::LEnotSupported,
965 this, &QLowEnergyControllerPrivateDarwin::_q_LEnotSupported);
966 ok = ok && connect(notifier, SIGNAL(CBManagerError(QLowEnergyController::Error)),
967 this, SLOT(_q_CBManagerError(QLowEnergyController::Error)));
968 ok = ok && connect(notifier, SIGNAL(CBManagerError(
const QBluetoothUuid &, QLowEnergyController::Error)),
969 this, SLOT(_q_CBManagerError(
const QBluetoothUuid &, QLowEnergyController::Error)));
970 ok = ok && connect(notifier, SIGNAL(CBManagerError(
const QBluetoothUuid &, QLowEnergyService::ServiceError)),
971 this, SLOT(_q_CBManagerError(
const QBluetoothUuid &, QLowEnergyService::ServiceError)));
972 ok = ok && connect(notifier, &LECBManagerNotifier::mtuChanged,
this,
973 &QLowEnergyControllerPrivateDarwin::_q_mtuChanged);
974 ok = ok && connect(notifier, &LECBManagerNotifier::rssiUpdated, q_ptr,
975 &QLowEnergyController::rssiRead, Qt::QueuedConnection);
978 notifier->disconnect();
983void QLowEnergyControllerPrivateDarwin::startAdvertising(
const QLowEnergyAdvertisingParameters ¶ms,
984 const QLowEnergyAdvertisingData &advertisingData,
985 const QLowEnergyAdvertisingData &scanResponseData)
990 auto leQueue(DarwinBluetooth::qt_LE_queue());
991 Q_ASSERT_X(leQueue, Q_FUNC_INFO,
"invalid LE queue (nullptr)");
993 const auto manager = peripheralManager.getAs<DarwinBTPeripheralManager>();
994 [manager setParameters:params data:advertisingData scanResponse:scanResponseData];
996 setState(QLowEnergyController::AdvertisingState);
998 dispatch_async(leQueue, ^{
999 [manager startAdvertising];
1003void QLowEnergyControllerPrivateDarwin::stopAdvertising()
1006 return _q_CBManagerError(QLowEnergyController::UnknownError);
1008 if (state != QLowEnergyController::AdvertisingState) {
1009 qCDebug(QT_BT_DARWIN) <<
"cannot stop advertising, called in state" << state;
1013 const auto leQueue = DarwinBluetooth::qt_LE_queue();
1014 Q_ASSERT_X(leQueue, Q_FUNC_INFO,
"invalid LE queue (nullptr)");
1015 const auto manager = peripheralManager.getAs<DarwinBTPeripheralManager>();
1016 dispatch_sync(leQueue, ^{
1017 [manager stopAdvertising];
1020 setState(QLowEnergyController::UnconnectedState);
#define QT_BT_MAC_AUTORELEASEPOOL