diff options
Diffstat (limited to 'src/bluetooth/darwin')
37 files changed, 684 insertions, 2611 deletions
diff --git a/src/bluetooth/darwin/btcentralmanager.mm b/src/bluetooth/darwin/btcentralmanager.mm index 86950302..55eaf2a0 100644 --- a/src/bluetooth/darwin/btcentralmanager.mm +++ b/src/bluetooth/darwin/btcentralmanager.mm @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qlowenergyserviceprivate_p.h" #include "qlowenergycharacteristic.h" @@ -45,6 +9,7 @@ #include <QtCore/qloggingcategory.h> #include <QtCore/qdebug.h> +#include <QtCore/qmap.h> #include <algorithm> #include <vector> @@ -87,7 +52,7 @@ ObjCStrongReference<NSError> qt_timeoutNSError(OperationTimeout type) // after all (except callbacks checking if an operation was successful // or not). Q_ASSERT(type != OperationTimeout::none); - Q_UNUSED(type) + Q_UNUSED(type); NSError *nsError = [[NSError alloc] initWithDomain:CBErrorDomain code:CBErrorOperationCancelled userInfo:nil]; @@ -106,7 +71,7 @@ QT_END_NAMESPACE QT_USE_NAMESPACE -@interface QT_MANGLE_NAMESPACE(DarwinBTCentralManager) (PrivateAPI) +@interface DarwinBTCentralManager (PrivateAPI) - (void)watchAfter:(id)object timeout:(DarwinBluetooth::OperationTimeout)type; - (bool)objectIsUnderWatch:(id)object operation:(DarwinBluetooth::OperationTimeout)type; @@ -138,7 +103,9 @@ QT_USE_NAMESPACE @end -@implementation QT_MANGLE_NAMESPACE(DarwinBTCentralManager) +using DiscoveryMode = QLowEnergyService::DiscoveryMode; + +@implementation DarwinBTCentralManager { @private CBCentralManager *manager; @@ -159,7 +126,7 @@ QT_USE_NAMESPACE // We'd like to avoid loops in a services' topology: DarwinBluetooth::ObjCStrongReference<NSMutableSet> visitedServices; - QList<QBluetoothUuid> servicesToDiscoverDetails; + QMap<QBluetoothUuid, DiscoveryMode> servicesToDiscoverDetails; DarwinBluetooth::ServiceHash serviceMap; DarwinBluetooth::CharHash charMap; @@ -177,6 +144,7 @@ QT_USE_NAMESPACE std::vector<DarwinBluetooth::GCDTimer> timeoutWatchdogs; CBPeripheral *peripheral; + int lastKnownMtu; } - (id)initWith:(DarwinBluetooth::LECBManagerNotifier *)aNotifier @@ -203,6 +171,8 @@ QT_USE_NAMESPACE if (!timeoutMS) timeoutMS = 20000; + + lastKnownMtu = defaultMtu; } return self; @@ -241,7 +211,7 @@ QT_USE_NAMESPACE { using namespace DarwinBluetooth; - GCDTimer newWatcher([[GCDTimerObjC alloc] initWithDelegate:self], RetainPolicy::noInitialRetain); + GCDTimer newWatcher([[DarwinBTGCDTimer alloc] initWithDelegate:self], RetainPolicy::noInitialRetain); [newWatcher watchAfter:object withTimeoutType:type]; timeoutWatchdogs.push_back(newWatcher); [newWatcher startWithTimeout:timeoutMS step:200]; @@ -270,11 +240,11 @@ QT_USE_NAMESPACE - (void)timeout:(id)sender { - Q_UNUSED(sender) + Q_UNUSED(sender); using namespace DarwinBluetooth; - GCDTimerObjC *watcher = static_cast<GCDTimerObjC *>(sender); + DarwinBTGCDTimer *watcher = static_cast<DarwinBTGCDTimer *>(sender); id cbObject = [watcher objectUnderWatch]; const OperationTimeout type = [watcher timeoutType]; @@ -371,7 +341,7 @@ QT_USE_NAMESPACE } - const quint128 qtUuidData(deviceUuid.toUInt128()); + const QUuid::Id128Bytes qtUuidData(deviceUuid.toBytes()); uuid_t uuidData = {}; std::copy(qtUuidData.data, qtUuidData.data + 16, uuidData); const ObjCScopedPointer<NSUUID> nsUuid([[NSUUID alloc] initWithUUIDBytes:uuidData], RetainPolicy::noInitialRetain); @@ -383,11 +353,11 @@ QT_USE_NAMESPACE } [uuids addObject:nsUuid]; - // With the latest CoreBluetooth, we can synchronously retrive peripherals: + // With the latest CoreBluetooth, we can synchronously retrieve peripherals: QT_BT_MAC_AUTORELEASEPOOL; NSArray *const peripherals = [manager retrievePeripheralsWithIdentifiers:uuids]; if (!peripherals || peripherals.count != 1) { - qCWarning(QT_BT_DARWIN) << "failed to retrive a peripheral"; + qCWarning(QT_BT_DARWIN) << "failed to retrieve a peripheral"; if (notifier) emit notifier->CBManagerError(QLowEnergyController::UnknownRemoteDeviceError); return; @@ -411,6 +381,7 @@ QT_USE_NAMESPACE if (notifier) emit notifier->connected(); } else { + [self setMtu:defaultMtu]; qCDebug(QT_BT_DARWIN) << "trying to connect"; managerState = CentralManagerConnecting; [manager connectPeripheral:peripheral options:nil]; @@ -469,7 +440,6 @@ QT_USE_NAMESPACE //parameter to nil is considerably slower and is not recommended." // // ... but we'd like to have them all: - [peripheral setDelegate:self]; managerState = CentralManagerDiscovering; [self watchAfter:peripheral timeout:OperationTimeout::serviceDiscovery]; [peripheral discoverServices:nil]; @@ -506,6 +476,7 @@ QT_USE_NAMESPACE } - (void)discoverServiceDetails:(const QBluetoothUuid &)serviceUuid + readValues:(bool) read { // This function does not change 'managerState', since it // can be called concurrently (not waiting for the previous @@ -526,7 +497,8 @@ QT_USE_NAMESPACE QT_BT_MAC_AUTORELEASEPOOL; if (CBService *const service = [self serviceForUUID:serviceUuid]) { - servicesToDiscoverDetails.append(serviceUuid); + const auto mode = read ? DiscoveryMode::FullDiscovery : DiscoveryMode::SkipValueDiscovery; + servicesToDiscoverDetails[serviceUuid] = mode; [self watchAfter:service timeout:OperationTimeout::characteristicsDiscovery]; [peripheral discoverCharacteristics:nil forService:service]; return; @@ -627,7 +599,8 @@ QT_USE_NAMESPACE QT_BT_MAC_AUTORELEASEPOOL; const QBluetoothUuid serviceUuid(qt_uuid(service.UUID)); - servicesToDiscoverDetails.removeAll(serviceUuid); + const bool skipValues = servicesToDiscoverDetails[serviceUuid] == DiscoveryMode::SkipValueDiscovery; + servicesToDiscoverDetails.remove(serviceUuid); const NSUInteger nHandles = qt_countGATTEntries(service); Q_ASSERT_X(nHandles, Q_FUNC_INFO, "unexpected number of GATT entires"); @@ -667,7 +640,8 @@ QT_USE_NAMESPACE newChar.uuid = qt_uuid(c.UUID); const int cbProps = c.properties & 0xff; newChar.properties = static_cast<QLowEnergyCharacteristic::PropertyTypes>(cbProps); - newChar.value = qt_bytearray(c.value); + if (!skipValues) + newChar.value = qt_bytearray(c.value); newChar.valueHandle = lastValidHandle; NSArray *const ds = c.descriptors; @@ -683,7 +657,7 @@ QT_USE_NAMESPACE newDesc.value = qt_bytearray(static_cast<NSObject *>(d.value)); descList[lastValidHandle] = newDesc; // Check, if it's client characteristic configuration descriptor: - if (newDesc.uuid == QBluetoothUuid::ClientCharacteristicConfiguration) { + if (newDesc.uuid == QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration) { if (newDesc.value.size() && (newDesc.value[0] & 3)) [peripheral setNotifyValue:YES forCharacteristic:c]; } @@ -807,7 +781,7 @@ QT_USE_NAMESPACE CBCharacteristic *const characteristic = charMap[request.handle]; if (request.type == LERequest::ClientConfiguration) { - const QBluetoothUuid qtUuid(QBluetoothUuid::ClientCharacteristicConfiguration); + const QBluetoothUuid qtUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration); CBDescriptor *const descriptor = [self descriptor:qtUuid forCharacteristic:characteristic]; Q_ASSERT_X(descriptor, Q_FUNC_INFO, "no client characteristic " "configuration descriptor found"); @@ -847,6 +821,41 @@ QT_USE_NAMESPACE } } +- (void)setMtu:(int)newMtu +{ + if (lastKnownMtu == newMtu) + return; + lastKnownMtu = newMtu; + if (notifier) + emit notifier->mtuChanged(newMtu); +} + +- (int)mtu +{ + using namespace DarwinBluetooth; + + if (![self isConnected]) { + [self setMtu:defaultMtu]; + return defaultMtu; + } + + Q_ASSERT(peripheral); + const NSUInteger maxLen = [peripheral maximumWriteValueLengthForType: + CBCharacteristicWriteWithoutResponse]; + if (maxLen > std::numeric_limits<int>::max() - 3) + [self setMtu:defaultMtu]; + else + [self setMtu:int(maxLen) + 3]; + + return lastKnownMtu; +} + +- (void)readRssi +{ + Q_ASSERT([self isConnected]); + [peripheral readRSSI]; +} + - (void)setNotifyValue:(const QByteArray &)value forCharacteristic:(QLowEnergyHandle)charHandle onService:(const QBluetoothUuid &)serviceUuid @@ -868,7 +877,7 @@ QT_USE_NAMESPACE // At the moment we call setNotifyValue _only_ from 'writeDescriptor'; // from Qt's API POV it's a descriptor write operation and we must report // it back, so check _now_ that we really have this descriptor. - const QBluetoothUuid qtUuid(QBluetoothUuid::ClientCharacteristicConfiguration); + const QBluetoothUuid qtUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration); if (![self descriptor:qtUuid forCharacteristic:charMap[charHandle]]) { qCWarning(QT_BT_DARWIN) << "no client characteristic configuration found"; if (notifier) { @@ -1240,17 +1249,13 @@ QT_USE_NAMESPACE // Let's check some states we do not like first: if (state == CBManagerStateUnsupported || state == CBManagerStateUnauthorized) { - if (managerState == CentralManagerUpdating) { - // We tried to connect just to realize, LE is not supported. Report this. - managerState = CentralManagerIdle; - if (notifier) + managerState = CentralManagerIdle; + // The LE is not supported or its usage was not authorized + if (notifier) { + if (state == CBManagerStateUnsupported) emit notifier->LEnotSupported(); - } else { - // TODO: if we are here, LE _was_ supported and we first managed to update - // and reset managerState from CentralManagerUpdating. - managerState = CentralManagerIdle; - if (notifier) - emit notifier->CBManagerError(QLowEnergyController::InvalidBluetoothAdapterError); + else + emit notifier->CBManagerError(QLowEnergyController::MissingPermissionsError); } [self stopWatchers]; return; @@ -1288,14 +1293,18 @@ QT_USE_NAMESPACE - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)aPeripheral { - Q_UNUSED(central) - Q_UNUSED(aPeripheral) + Q_UNUSED(central); + Q_UNUSED(aPeripheral); if (managerState != DarwinBluetooth::CentralManagerConnecting) { // We called cancel but before disconnected, managed to connect? return; } + void([self mtu]); + + [peripheral setDelegate:self]; + managerState = DarwinBluetooth::CentralManagerIdle; if (notifier) emit notifier->connected(); @@ -1304,9 +1313,9 @@ QT_USE_NAMESPACE - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)aPeripheral error:(NSError *)error { - Q_UNUSED(central) - Q_UNUSED(aPeripheral) - Q_UNUSED(error) + Q_UNUSED(central); + Q_UNUSED(aPeripheral); + Q_UNUSED(error); if (managerState != DarwinBluetooth::CentralManagerConnecting) { // Canceled already. @@ -1322,8 +1331,8 @@ QT_USE_NAMESPACE - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)aPeripheral error:(NSError *)error { - Q_UNUSED(central) - Q_UNUSED(aPeripheral) + Q_UNUSED(central); + Q_UNUSED(aPeripheral); // Clear internal caches/data. [self reset]; @@ -1344,7 +1353,7 @@ QT_USE_NAMESPACE - (void)peripheral:(CBPeripheral *)aPeripheral didDiscoverServices:(NSError *)error { - Q_UNUSED(aPeripheral) + Q_UNUSED(aPeripheral); using namespace DarwinBluetooth; @@ -1365,8 +1374,10 @@ QT_USE_NAMESPACE if (error) { NSLog(@"%s failed with error %@", Q_FUNC_INFO, error); // TODO: better error mapping required. + // Emit an error which also causes the service discovery finished() signal if (notifier) emit notifier->CBManagerError(QLowEnergyController::UnknownError); + return; } [self discoverIncludedServices]; @@ -1375,8 +1386,8 @@ QT_USE_NAMESPACE - (void)peripheral:(CBPeripheral *)aPeripheral didModifyServices:(NSArray<CBService *> *)invalidatedServices { - Q_UNUSED(aPeripheral) - Q_UNUSED(invalidatedServices) + Q_UNUSED(aPeripheral); + Q_UNUSED(invalidatedServices); qCWarning(QT_BT_DARWIN) << "The peripheral has modified its services."; // "This method is invoked whenever one or more services of a peripheral have changed. @@ -1400,7 +1411,7 @@ QT_USE_NAMESPACE - (void)peripheral:(CBPeripheral *)aPeripheral didDiscoverIncludedServicesForService:(CBService *)service error:(NSError *)error { - Q_UNUSED(aPeripheral) + Q_UNUSED(aPeripheral); using namespace DarwinBluetooth; @@ -1478,7 +1489,7 @@ QT_USE_NAMESPACE { // This method does not change 'managerState', we can have several // discoveries active. - Q_UNUSED(aPeripheral) + Q_UNUSED(aPeripheral); if (!notifier) { // Detached. @@ -1494,15 +1505,22 @@ QT_USE_NAMESPACE [self stopWatchingAfter:service operation:OperationTimeout::characteristicsDiscovery]; + const auto qtUuid = qt_uuid(service.UUID); + const bool skipRead = servicesToDiscoverDetails[qtUuid] == DiscoveryMode::SkipValueDiscovery; + Q_ASSERT_X(managerState != CentralManagerUpdating, Q_FUNC_INFO, "invalid state"); if (error) { 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->CBManagerError(qt_uuid(service.UUID), QLowEnergyController::UnknownError); + emit notifier->CBManagerError(qtUuid, QLowEnergyController::UnknownError); } + if (skipRead) { + [self serviceDetailsDiscoveryFinished:service]; + return; + } [self readCharacteristics:service]; } @@ -1510,7 +1528,7 @@ QT_USE_NAMESPACE didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { - Q_UNUSED(aPeripheral) + Q_UNUSED(aPeripheral); if (!notifier) // Detached. return; @@ -1592,7 +1610,7 @@ QT_USE_NAMESPACE { // This method does not change 'managerState', we can // have several discoveries active at the same time. - Q_UNUSED(aPeripheral) + Q_UNUSED(aPeripheral); if (!notifier) { // Detached, no need to continue ... @@ -1628,7 +1646,7 @@ QT_USE_NAMESPACE didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error { - Q_UNUSED(aPeripheral) + Q_UNUSED(aPeripheral); Q_ASSERT_X(peripheral, Q_FUNC_INFO, "invalid peripheral (nil)"); @@ -1713,8 +1731,8 @@ QT_USE_NAMESPACE didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { - Q_UNUSED(aPeripheral) - Q_UNUSED(characteristic) + Q_UNUSED(aPeripheral); + Q_UNUSED(characteristic); if (!notifier) { // Detached. @@ -1762,7 +1780,7 @@ QT_USE_NAMESPACE didWriteValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error { - Q_UNUSED(aPeripheral) + Q_UNUSED(aPeripheral); if (!notifier) { // Detached already. @@ -1798,7 +1816,7 @@ QT_USE_NAMESPACE didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { - Q_UNUSED(aPeripheral) + Q_UNUSED(aPeripheral); if (!notifier) return; @@ -1809,7 +1827,7 @@ QT_USE_NAMESPACE requestPending = false; - const QBluetoothUuid qtUuid(QBluetoothUuid::ClientCharacteristicConfiguration); + const QBluetoothUuid qtUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration); CBDescriptor *const descriptor = [self descriptor:qtUuid forCharacteristic:characteristic]; const QByteArray valueToReport(valuesToWrite.value(descriptor, QByteArray())); const int nRemoved = valuesToWrite.remove(descriptor); @@ -1827,6 +1845,26 @@ QT_USE_NAMESPACE [self performNextRequest]; } +- (void)peripheral:(CBPeripheral *)aPeripheral didReadRSSI:(NSNumber *)RSSI error:(nullable NSError *)error +{ + Q_UNUSED(aPeripheral); + + if (!notifier) // This controller was detached. + return; + + if (error) { + NSLog(@"Reading RSSI finished with error: %@", error); + return emit notifier->CBManagerError(QLowEnergyController::RssiReadError); + } + + if (!RSSI) { + qCWarning(QT_BT_DARWIN, "Reading RSSI returned no value"); + return emit notifier->CBManagerError(QLowEnergyController::RssiReadError); + } + + emit notifier->rssiUpdated(qint16([RSSI shortValue])); +} + - (void)detach { if (notifier) { diff --git a/src/bluetooth/darwin/btcentralmanager_p.h b/src/bluetooth/darwin/btcentralmanager_p.h index 0b5c8fbb..3986228e 100644 --- a/src/bluetooth/darwin/btcentralmanager_p.h +++ b/src/bluetooth/darwin/btcentralmanager_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTCENTRALMANAGER_P_H #define BTCENTRALMANAGER_P_H @@ -52,11 +16,12 @@ // #include "qlowenergycontroller.h" -#include "qlowenergyservice.h" #include "qbluetoothuuid.h" #include "btgcdtimer_p.h" #include "btutility_p.h" +#include <QtCore/private/qcore_mac_p.h> + #include <QtCore/qbytearray.h> #include <QtCore/qglobal.h> #include <QtCore/qqueue.h> @@ -68,8 +33,6 @@ QT_BEGIN_NAMESPACE -class QLowEnergyServicePrivate; - namespace DarwinBluetooth { class LECBManagerNotifier; @@ -147,7 +110,11 @@ QT_END_NAMESPACE - (void)disconnectFromDevice; - (void)discoverServices; -- (void)discoverServiceDetails:(const QT_PREPEND_NAMESPACE(QBluetoothUuid) &)serviceUuid; +- (void)discoverServiceDetails:(const QT_PREPEND_NAMESPACE(QBluetoothUuid) &)serviceUuid + readValues:(bool)read; + +- (int)mtu; +- (void)readRssi; - (void)setNotifyValue:(const QT_PREPEND_NAMESPACE(QByteArray) &)value forCharacteristic:(QT_PREPEND_NAMESPACE(QLowEnergyHandle))charHandle @@ -172,4 +139,6 @@ QT_END_NAMESPACE @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTCentralManager); + #endif diff --git a/src/bluetooth/darwin/btconnectionmonitor.mm b/src/bluetooth/darwin/btconnectionmonitor.mm index f9adfde8..12dd7884 100644 --- a/src/bluetooth/darwin/btconnectionmonitor.mm +++ b/src/bluetooth/darwin/btconnectionmonitor.mm @@ -1,57 +1,16 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "btconnectionmonitor_p.h" #include "btutility_p.h" -#include <QtCore/qdebug.h> - -QT_BEGIN_NAMESPACE +#include "qbluetoothaddress.h" +#include <QtCore/qdebug.h> -QT_END_NAMESPACE - -#ifdef QT_NAMESPACE -using namespace QT_NAMESPACE; -#endif +QT_USE_NAMESPACE -@implementation QT_MANGLE_NAMESPACE(DarwinBTConnectionMonitor) +@implementation DarwinBTConnectionMonitor { QT_PREPEND_NAMESPACE(DarwinBluetooth::ConnectionMonitor) *monitor; IOBluetoothUserNotification *discoveryNotification; @@ -74,27 +33,30 @@ using namespace QT_NAMESPACE; - (void)dealloc { - [discoveryNotification unregister]; - [discoveryNotification release]; - - for (IOBluetoothUserNotification *n in foundConnections) - [n unregister]; - - [foundConnections release]; - + Q_ASSERT_X(!monitor, "-dealloc", + "Connection monitor was not stopped, calling -stopMonitoring is required"); [super dealloc]; } - (void)connectionNotification:(IOBluetoothUserNotification *)aNotification withDevice:(IOBluetoothDevice *)device { - Q_UNUSED(aNotification) + Q_UNUSED(aNotification); typedef IOBluetoothUserNotification Notification; if (!device) return; + if (!monitor) { + // Rather surprising: monitor == nullptr means we stopped monitoring. + // So apparently this thingie is still alive and keeps receiving + // notifications. + qCWarning(QT_BT_DARWIN, + "Connection notification received in a monitor that was cancelled"); + return; + } + QT_BT_MAC_AUTORELEASEPOOL; // All Obj-C objects are autoreleased. @@ -130,4 +92,18 @@ using namespace QT_NAMESPACE; monitor->deviceDisconnected(deviceAddress); } +-(void)stopMonitoring +{ + monitor = nullptr; + [discoveryNotification unregister]; + [discoveryNotification release]; + discoveryNotification = nil; + + for (IOBluetoothUserNotification *n in foundConnections) + [n unregister]; + + [foundConnections release]; + foundConnections = nil; +} + @end diff --git a/src/bluetooth/darwin/btconnectionmonitor_p.h b/src/bluetooth/darwin/btconnectionmonitor_p.h index e3b7b90d..f4f5c7ea 100644 --- a/src/bluetooth/darwin/btconnectionmonitor_p.h +++ b/src/bluetooth/darwin/btconnectionmonitor_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTCONNECTIONMONITOR_P_H #define BTCONNECTIONMONITOR_P_H @@ -51,9 +15,10 @@ // We mean it. // -#include "qbluetoothaddress.h" #include "btdelegates_p.h" +#include <QtCore/private/qcore_mac_p.h> + #include <QtCore/qglobal.h> #include <Foundation/Foundation.h> @@ -66,6 +31,9 @@ - (void)connectionNotification:(id)notification withDevice:(IOBluetoothDevice *)device; - (void)connectionClosedNotification:(id)notification withDevice:(IOBluetoothDevice *)device; +- (void)stopMonitoring; @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTConnectionMonitor); + #endif diff --git a/src/bluetooth/darwin/btdelegates.cpp b/src/bluetooth/darwin/btdelegates.cpp index 531ca1df..fc86778f 100644 --- a/src/bluetooth/darwin/btdelegates.cpp +++ b/src/bluetooth/darwin/btdelegates.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "btdelegates_p.h" diff --git a/src/bluetooth/darwin/btdelegates_p.h b/src/bluetooth/darwin/btdelegates_p.h index 11fbcc28..7dd9fde5 100644 --- a/src/bluetooth/darwin/btdelegates_p.h +++ b/src/bluetooth/darwin/btdelegates_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTDELEGATES_P_H #define BTDELEGATES_P_H @@ -51,24 +15,18 @@ // We mean it. // -#include "qbluetoothdevicediscoveryagent.h" -#include "qlowenergycontroller.h" -#include "qbluetooth.h" - -#include <QtCore/qsharedpointer.h> -#include <QtCore/qglobal.h> +#include <QtCore/private/qglobal_p.h> #if defined(Q_OS_MACOS) #include <IOKit/IOReturn.h> +#include <cstddef> #include <cstdint> QT_BEGIN_NAMESPACE -class QLowEnergyServicePrivate; class QBluetoothAddress; -class QByteArray; namespace DarwinBluetooth { diff --git a/src/bluetooth/darwin/btdeviceinquiry.mm b/src/bluetooth/darwin/btdeviceinquiry.mm index ad59a4a4..19401ee3 100644 --- a/src/bluetooth/darwin/btdeviceinquiry.mm +++ b/src/bluetooth/darwin/btdeviceinquiry.mm @@ -1,55 +1,26 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "btdeviceinquiry_p.h" #include "btutility_p.h" #include <QtCore/qloggingcategory.h> +#include <QtCore/qtimer.h> #include <QtCore/qdebug.h> +#include <memory> + QT_USE_NAMESPACE -@implementation QT_MANGLE_NAMESPACE(DarwinBTClassicDeviceInquiry) +const uint8_t IOBlueoothInquiryLengthS = 15; + +@implementation DarwinBTClassicDeviceInquiry { IOBluetoothDeviceInquiry *m_inquiry; bool m_active; DarwinBluetooth::DeviceInquiryDelegate *m_delegate;//C++ "delegate" + + std::unique_ptr<QTimer> watchDog; } - (id)initWithDelegate:(DarwinBluetooth::DeviceInquiryDelegate *)delegate @@ -60,7 +31,13 @@ QT_USE_NAMESPACE m_inquiry = [[IOBluetoothDeviceInquiry inquiryWithDelegate:self] retain]; if (m_inquiry) { - [m_inquiry setInquiryLength:15]; + // Inquiry length is 15 seconds. Starting from macOS 10.15.7 + // (the lowest version I was able to test on, though initially + // the problem was found on macOS 11, arm64 machine and then + // confirmed on macOS 12 Beta 4), it seems to be ignored, + // thus scan never stops. See -start for how we try to prevent + // this. + [m_inquiry setInquiryLength:IOBlueoothInquiryLengthS]; [m_inquiry setUpdateNewDeviceNames:NO];//Useless, disable! m_delegate = delegate; } else { @@ -99,12 +76,29 @@ QT_USE_NAMESPACE m_active = true; [m_inquiry clearFoundDevices]; + + qCDebug(QT_BT_DARWIN) << "Starting device inquiry with" + << IOBlueoothInquiryLengthS << "second timeout limit."; const IOReturn result = [m_inquiry start]; if (result != kIOReturnSuccess) { // QtBluetooth will probably convert an error into UnknownError, - // loosing the actual information. - qCWarning(QT_BT_DARWIN) << "failed with IOKit error code:" << result; + // losing the actual information. + qCWarning(QT_BT_DARWIN) << "device inquiry start failed with IOKit error code:" << result; m_active = false; + } else { + // Docs say it's 10 s. by default, we set it to 15 s. (see -initWithDelegate:), + // and it may fail to finish. + watchDog.reset(new QTimer); + watchDog->connect(watchDog.get(), &QTimer::timeout, watchDog.get(), [self]{ + qCWarning(QT_BT_DARWIN, "Manually interrupting IOBluetoothDeviceInquiry"); + qCDebug(QT_BT_DARWIN) << "Found devices:" << [m_inquiry foundDevices]; + [self stop]; + }); + + watchDog->setSingleShot(true); + // +2 to give IOBluetooth a chance to stop it first: + watchDog->setInterval((IOBlueoothInquiryLengthS + 2) * 1000); + watchDog->start(); } return result; @@ -112,40 +106,38 @@ QT_USE_NAMESPACE - (IOReturn)stop { - if (m_active) { - Q_ASSERT_X(m_inquiry, Q_FUNC_INFO, "active but nil inquiry"); - - m_active = false; - const IOReturn res = [m_inquiry stop]; - if (res != kIOReturnSuccess) - m_active = true; - else - qCDebug(QT_BT_DARWIN) << "-stop, success (waiting for 'inquiryComplete')"; + if (!m_active) + return kIOReturnSuccess; - return res; - } + Q_ASSERT_X(m_inquiry, Q_FUNC_INFO, "active but nil inquiry"); - return kIOReturnSuccess; + return [m_inquiry stop]; } - (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry *)sender error:(IOReturn)error aborted:(BOOL)aborted { - Q_UNUSED(aborted) + qCDebug(QT_BT_DARWIN) << "deviceInquiryComplete, error:" << error + << "user-stopped:" << aborted; + if (!m_active) + return; if (sender != m_inquiry) // Can never happen in the current version. return; - m_active = false; - Q_ASSERT_X(m_delegate, Q_FUNC_INFO, "invalid device inquiry delegate (null)"); - if (error != kIOReturnSuccess) { + if (error != kIOReturnSuccess && !aborted) { // QtBluetooth has not too many error codes, 'UnknownError' is not really - // useful, report the actual error code here: + // useful, log the actual error code here: qCWarning(QT_BT_DARWIN) << "IOKit error code: " << error; - m_delegate->error(error); + // Let watchDog to stop it, calling -stop at timeout, otherwise, + // it looks like inquiry continues even after this error and + // keeps reporting new devices found. } else { + // Either a normal completion or from a timer slot. + watchDog.reset(); + m_active = false; m_delegate->inquiryFinished(); } } @@ -153,16 +145,23 @@ QT_USE_NAMESPACE - (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry *)sender device:(IOBluetoothDevice *)device { + qCDebug(QT_BT_DARWIN) << "deviceInquiryDeviceFound:" << [device nameOrAddress]; if (sender != m_inquiry) // Can never happen in the current version. return; + if (!m_active) { + // We are not expecting new device(s) to be found after we reported 'finished'. + qCWarning(QT_BT_DARWIN, "IOBluetooth device found after inquiry complete/interrupted"); + return; + } + Q_ASSERT_X(m_delegate, Q_FUNC_INFO, "invalid device inquiry delegate (null)"); m_delegate->classicDeviceFound(device); } - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry *)sender { - Q_UNUSED(sender) + Q_UNUSED(sender); } @end diff --git a/src/bluetooth/darwin/btdeviceinquiry_p.h b/src/bluetooth/darwin/btdeviceinquiry_p.h index fa4fd01c..66a91d53 100644 --- a/src/bluetooth/darwin/btdeviceinquiry_p.h +++ b/src/bluetooth/darwin/btdeviceinquiry_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTDEVICEINQUIRY_P_H #define BTDEVICEINQUIRY_P_H @@ -53,6 +17,8 @@ #include "btdelegates_p.h" +#include <QtCore/private/qcore_mac_p.h> + #include <QtCore/qglobal.h> #include <Foundation/Foundation.h> @@ -80,4 +46,6 @@ @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTClassicDeviceInquiry); + #endif diff --git a/src/bluetooth/darwin/btdevicepair.mm b/src/bluetooth/darwin/btdevicepair.mm index 947385f2..e76516fb 100644 --- a/src/bluetooth/darwin/btdevicepair.mm +++ b/src/bluetooth/darwin/btdevicepair.mm @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "btdevicepair_p.h" #include "btutility_p.h" @@ -63,7 +27,7 @@ QT_END_NAMESPACE QT_USE_NAMESPACE -@implementation QT_MANGLE_NAMESPACE(DarwinBTClassicPairing) +@implementation DarwinBTClassicPairing { QT_PREPEND_NAMESPACE(QBluetoothAddress) m_targetAddress; @@ -160,17 +124,17 @@ QT_USE_NAMESPACE - (void)devicePairingStarted:(id)sender { - Q_UNUSED(sender) + Q_UNUSED(sender); } - (void)devicePairingConnecting:(id)sender { - Q_UNUSED(sender) + Q_UNUSED(sender); } - (void)deviceParingPINCodeRequest:(id)sender { - Q_UNUSED(sender) + Q_UNUSED(sender); } - (void)devicePairingUserConfirmationRequest:(id)sender @@ -187,8 +151,8 @@ QT_USE_NAMESPACE - (void)devicePairingUserPasskeyNotification:(id)sender passkey:(BluetoothPasskey)passkey { - Q_UNUSED(sender) - Q_UNUSED(passkey) + Q_UNUSED(sender); + Q_UNUSED(passkey); } - (void)devicePairingFinished:(id)sender error:(IOReturn)error @@ -208,8 +172,8 @@ QT_USE_NAMESPACE - (void)deviceSimplePairingComplete:(id)sender status:(BluetoothHCIEventStatus)status { - Q_UNUSED(sender) - Q_UNUSED(status) + Q_UNUSED(sender); + Q_UNUSED(status); } @end diff --git a/src/bluetooth/darwin/btdevicepair_p.h b/src/bluetooth/darwin/btdevicepair_p.h index 1b361258..1b2f9ab6 100644 --- a/src/bluetooth/darwin/btdevicepair_p.h +++ b/src/bluetooth/darwin/btdevicepair_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTDEVICEPAIR_P_H #define BTDEVICEPAIR_P_H @@ -55,6 +19,8 @@ #include "btdelegates_p.h" #include "btutility_p.h" +#include <QtCore/private/qcore_mac_p.h> + #include <QtCore/qglobal.h> #include <Foundation/Foundation.h> @@ -106,5 +72,6 @@ QT_END_NAMESPACE @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTClassicPairing); #endif diff --git a/src/bluetooth/darwin/btgcdtimer.mm b/src/bluetooth/darwin/btgcdtimer.mm index 9105a8fb..6b8633a4 100644 --- a/src/bluetooth/darwin/btgcdtimer.mm +++ b/src/bluetooth/darwin/btgcdtimer.mm @@ -1,45 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2018 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "btgcdtimer_p.h" #include "btutility_p.h" +#include <QtCore/qelapsedtimer.h> #include <QtCore/qdebug.h> #include <algorithm> @@ -47,7 +12,7 @@ QT_USE_NAMESPACE using namespace DarwinBluetooth; -@implementation QT_MANGLE_NAMESPACE(DarwinBTGCDTimer) { +@implementation DarwinBTGCDTimer { @private qint64 timeoutMS; qint64 timeoutStepMS; diff --git a/src/bluetooth/darwin/btgcdtimer_p.h b/src/bluetooth/darwin/btgcdtimer_p.h index dd67d6e8..b927336b 100644 --- a/src/bluetooth/darwin/btgcdtimer_p.h +++ b/src/bluetooth/darwin/btgcdtimer_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2018 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTGCDTIMER_P_H #define BTGCDTIMER_P_H @@ -53,7 +17,8 @@ #include "btutility_p.h" -#include <QtCore/qelapsedtimer.h> +#include <QtCore/private/qcore_mac_p.h> + #include <QtCore/qglobal.h> #include <Foundation/Foundation.h> @@ -93,12 +58,13 @@ QT_END_NAMESPACE - (QT_PREPEND_NAMESPACE(DarwinBluetooth)::OperationTimeout)timeoutType; @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTGCDTimer); + QT_BEGIN_NAMESPACE namespace DarwinBluetooth { -using GCDTimerObjC = QT_MANGLE_NAMESPACE(DarwinBTGCDTimer); -using GCDTimer = ObjCStrongReference<GCDTimerObjC>; +using GCDTimer = ObjCStrongReference<DarwinBTGCDTimer>; } // namespace DarwinBluetooth diff --git a/src/bluetooth/darwin/btl2capchannel.mm b/src/bluetooth/darwin/btl2capchannel.mm index e440a0ee..17c1d168 100644 --- a/src/bluetooth/darwin/btl2capchannel.mm +++ b/src/bluetooth/darwin/btl2capchannel.mm @@ -1,44 +1,8 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -#include "btl2capchannel_p.h" #include "qbluetoothaddress.h" +#include "btl2capchannel_p.h" #include "btdelegates_p.h" #include "btutility_p.h" @@ -47,7 +11,7 @@ QT_USE_NAMESPACE -@implementation QT_MANGLE_NAMESPACE(DarwinBTL2CAPChannel) +@implementation DarwinBTL2CAPChannel { QT_PREPEND_NAMESPACE(DarwinBluetooth)::ChannelDelegate *delegate; IOBluetoothDevice *device; @@ -148,7 +112,7 @@ QT_USE_NAMESPACE - (void)l2capChannelData:(IOBluetoothL2CAPChannel*)l2capChannel data:(void *)dataPointer length:(size_t)dataLength { - Q_UNUSED(l2capChannel) + Q_UNUSED(l2capChannel); Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)"); @@ -159,7 +123,7 @@ QT_USE_NAMESPACE - (void)l2capChannelOpenComplete:(IOBluetoothL2CAPChannel*) l2capChannel status:(IOReturn)error { - Q_UNUSED(l2capChannel) + Q_UNUSED(l2capChannel); Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)"); @@ -173,7 +137,7 @@ QT_USE_NAMESPACE - (void)l2capChannelClosed:(IOBluetoothL2CAPChannel*)l2capChannel { - Q_UNUSED(l2capChannel) + Q_UNUSED(l2capChannel); Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)"); delegate->channelClosed(); @@ -182,14 +146,14 @@ QT_USE_NAMESPACE - (void)l2capChannelReconfigured:(IOBluetoothL2CAPChannel*)l2capChannel { - Q_UNUSED(l2capChannel) + Q_UNUSED(l2capChannel); } - (void)l2capChannelWriteComplete:(IOBluetoothL2CAPChannel*)l2capChannel refcon:(void*)refcon status:(IOReturn)error { - Q_UNUSED(l2capChannel) - Q_UNUSED(refcon) + Q_UNUSED(l2capChannel); + Q_UNUSED(refcon); Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)"); @@ -201,7 +165,7 @@ QT_USE_NAMESPACE - (void)l2capChannelQueueSpaceAvailable:(IOBluetoothL2CAPChannel*)l2capChannel { - Q_UNUSED(l2capChannel) + Q_UNUSED(l2capChannel); } // Aux. methods. diff --git a/src/bluetooth/darwin/btl2capchannel_p.h b/src/bluetooth/darwin/btl2capchannel_p.h index 32122fe8..68d24aba 100644 --- a/src/bluetooth/darwin/btl2capchannel_p.h +++ b/src/bluetooth/darwin/btl2capchannel_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTL2CAPCHANNEL_P_H #define BTL2CAPCHANNEL_P_H @@ -51,7 +15,8 @@ // We mean it. // -#include <QtCore/qglobal.h> +#include <QtCore/private/qcore_mac_p.h> +#include <QtCore/private/qglobal_p.h> #include <Foundation/Foundation.h> @@ -115,4 +80,6 @@ QT_END_NAMESPACE @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTL2CAPChannel); + #endif diff --git a/src/bluetooth/darwin/btledeviceinquiry.mm b/src/bluetooth/darwin/btledeviceinquiry.mm index 107ffc5b..2611aae0 100644 --- a/src/bluetooth/darwin/btledeviceinquiry.mm +++ b/src/bluetooth/darwin/btledeviceinquiry.mm @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qbluetoothdeviceinfo.h" #include "btledeviceinquiry_p.h" @@ -46,6 +10,7 @@ #include <QtCore/qloggingcategory.h> #include <QtCore/qdebug.h> #include <QtCore/qendian.h> +#include <QtCore/qlist.h> #include <algorithm> @@ -60,7 +25,7 @@ QBluetoothUuid qt_uuid(NSUUID *nsUuid) uuid_t uuidData = {}; [nsUuid getUUIDBytes:uuidData]; - quint128 qtUuidData = {}; + QUuid::Id128Bytes qtUuidData = {}; std::copy(uuidData, uuidData + 16, qtUuidData.data); return QBluetoothUuid(qtUuidData); } @@ -81,8 +46,9 @@ struct AdvertisementData { // For now, we "parse": QString localName; - QVector<QBluetoothUuid> serviceUuids; + QList<QBluetoothUuid> serviceUuids; QHash<quint16, QByteArray> manufacturerData; + QHash<QBluetoothUuid, QByteArray> serviceData; // TODO: other keys probably? AdvertisementData(NSDictionary *AdvertisementData); }; @@ -108,6 +74,13 @@ AdvertisementData::AdvertisementData(NSDictionary *advertisementData) serviceUuids << qt_uuid(cbUuid); } + NSDictionary *advdict = [advertisementData objectForKey:CBAdvertisementDataServiceDataKey]; + if (advdict) { + [advdict enumerateKeysAndObjectsUsingBlock:^(CBUUID *key, NSData *val, BOOL *) { + serviceData.insert(qt_uuid(key), QByteArray::fromNSData(static_cast<NSData *>(val))); + }]; + } + value = [advertisementData objectForKey:CBAdvertisementDataManufacturerDataKey]; if (value && [value isKindOfClass:[NSData class]]) { QByteArray data = QByteArray::fromNSData(static_cast<NSData *>(value)); @@ -121,12 +94,12 @@ QT_END_NAMESPACE QT_USE_NAMESPACE -@interface QT_MANGLE_NAMESPACE(DarwinBTLEDeviceInquiry)(PrivateAPI) +@interface DarwinBTLEDeviceInquiry (PrivateAPI) - (void)stopScanSafe; - (void)stopNotifier; @end -@implementation QT_MANGLE_NAMESPACE(DarwinBTLEDeviceInquiry) +@implementation DarwinBTLEDeviceInquiry { LECBManagerNotifier *notifier; ObjCScopedPointer<CBCentralManager> manager; @@ -161,7 +134,7 @@ QT_USE_NAMESPACE - (void)timeout:(id)sender { - Q_UNUSED(sender) + Q_UNUSED(sender); if (internalState == InquiryActive) { [self stopScanSafe]; @@ -211,13 +184,21 @@ QT_USE_NAMESPACE if (inquiryTimeoutMS > 0) { [elapsedTimer cancelTimer]; - elapsedTimer.reset([[GCDTimerObjC alloc] initWithDelegate:self], RetainPolicy::noInitialRetain); + elapsedTimer.reset([[DarwinBTGCDTimer alloc] initWithDelegate:self], RetainPolicy::noInitialRetain); [elapsedTimer startWithTimeout:inquiryTimeoutMS step:timeStepMS]; } - [manager scanForPeripheralsWithServices:nil options:nil]; + // ### Qt 6.x: remove the use of env. variable, as soon as a proper public API is in place. + bool envOk = false; + const int env = qEnvironmentVariableIntValue("QT_BLUETOOTH_SCAN_ENABLE_DUPLICATES", &envOk); + if (envOk && env) { + [manager scanForPeripheralsWithServices:nil + options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @YES}]; + } else { + [manager scanForPeripheralsWithServices:nil options:nil]; + } } // Else we ignore. - } else if (state == CBManagerStateUnsupported || state == CBManagerStateUnauthorized) { + } else if (state == CBManagerStateUnsupported) { if (internalState == InquiryActive) { [self stopScanSafe]; // Not sure how this is possible at all, @@ -228,7 +209,12 @@ QT_USE_NAMESPACE internalState = ErrorLENotSupported; emit notifier->LEnotSupported(); } - + [manager setDelegate:nil]; + } else if (state == CBManagerStateUnauthorized) { + if (internalState == InquiryActive) + [self stopScanSafe]; + internalState = ErrorNotAuthorized; + emit notifier->CBManagerError(QBluetoothDeviceDiscoveryAgent::MissingPermissionsError); [manager setDelegate:nil]; } else if (state == CBManagerStatePoweredOff) { @@ -239,12 +225,12 @@ QT_USE_NAMESPACE // we'll receive 'PoweredOn' state update later. // No change in internalState. Wait for 30 seconds. [elapsedTimer cancelTimer]; - elapsedTimer.reset([[GCDTimerObjC alloc] initWithDelegate:self], RetainPolicy::noInitialRetain); + elapsedTimer.reset([[DarwinBTGCDTimer alloc] initWithDelegate:self], RetainPolicy::noInitialRetain); [elapsedTimer startWithTimeout:powerOffTimeoutMS step:300]; return; } #else - Q_UNUSED(powerOffTimeoutMS) + Q_UNUSED(powerOffTimeoutMS); #endif // Q_OS_MACOS [elapsedTimer cancelTimer]; [self stopScanSafe]; @@ -351,10 +337,14 @@ QT_USE_NAMESPACE if (qtAdvData.serviceUuids.size()) newDeviceInfo.setServiceUuids(qtAdvData.serviceUuids); - const QList<quint16> keys = qtAdvData.manufacturerData.keys(); - for (quint16 key : keys) + const QList<quint16> keysManufacturer = qtAdvData.manufacturerData.keys(); + for (quint16 key : keysManufacturer) newDeviceInfo.setManufacturerData(key, qtAdvData.manufacturerData.value(key)); + const QList<QBluetoothUuid> keysService = qtAdvData.serviceData.keys(); + for (QBluetoothUuid key : keysService) + newDeviceInfo.setServiceData(key, qtAdvData.serviceData.value(key)); + // CoreBluetooth scans only for LE devices. newDeviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration); emit notifier->deviceDiscovered(newDeviceInfo); diff --git a/src/bluetooth/darwin/btledeviceinquiry_p.h b/src/bluetooth/darwin/btledeviceinquiry_p.h index 58c66e56..edc393d8 100644 --- a/src/bluetooth/darwin/btledeviceinquiry_p.h +++ b/src/bluetooth/darwin/btledeviceinquiry_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTLEDEVICEINQUIRY_P_H #define BTLEDEVICEINQUIRY_P_H @@ -56,8 +20,9 @@ #include "btgcdtimer_p.h" #include "btutility_p.h" +#include <QtCore/private/qcore_mac_p.h> + #include <QtCore/qglobal.h> -#include <QtCore/qlist.h> #include <Foundation/Foundation.h> @@ -86,7 +51,8 @@ enum LEInquiryState InquiryFinished, InquiryCancelled, ErrorPoweredOff, - ErrorLENotSupported + ErrorLENotSupported, + ErrorNotAuthorized }; @interface QT_MANGLE_NAMESPACE(DarwinBTLEDeviceInquiry) : NSObject<CBCentralManagerDelegate, QT_MANGLE_NAMESPACE(GCDTimerDelegate)> @@ -100,4 +66,6 @@ enum LEInquiryState @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTLEDeviceInquiry); + #endif diff --git a/src/bluetooth/darwin/btnotifier.cpp b/src/bluetooth/darwin/btnotifier.cpp index 24f54a09..6ab7e473 100644 --- a/src/bluetooth/darwin/btnotifier.cpp +++ b/src/bluetooth/darwin/btnotifier.cpp @@ -1 +1,4 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + #include "btnotifier_p.h" diff --git a/src/bluetooth/darwin/btnotifier_p.h b/src/bluetooth/darwin/btnotifier_p.h index e074a225..64a285e2 100644 --- a/src/bluetooth/darwin/btnotifier_p.h +++ b/src/bluetooth/darwin/btnotifier_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTNOTIFIER_P_H #define BTNOTIFIER_P_H @@ -51,7 +15,6 @@ // We mean it. // - #include "qbluetoothdevicediscoveryagent.h" #include "qlowenergycontroller.h" #include "qbluetoothdeviceinfo.h" @@ -60,7 +23,7 @@ #include <QtCore/qsharedpointer.h> #include <QtCore/qbytearray.h> -#include <QtCore/qglobal.h> +#include <QtCore/private/qglobal_p.h> #include <QtCore/qobject.h> QT_BEGIN_NAMESPACE @@ -81,6 +44,8 @@ Q_SIGNALS: void connected(); void disconnected(); + void mtuChanged(int newValue); + void serviceDiscoveryFinished(); void serviceDetailsDiscoveryFinished(QSharedPointer<QLowEnergyServicePrivate> service); void characteristicRead(QLowEnergyHandle charHandle, const QByteArray &value); @@ -90,6 +55,7 @@ Q_SIGNALS: void descriptorWritten(QLowEnergyHandle descHandle, const QByteArray &value); void notificationEnabled(QLowEnergyHandle charHandle, bool enabled); void servicesWereModified(); + void rssiUpdated(qint16 newValue); void LEnotSupported(); void CBManagerError(QBluetoothDeviceDiscoveryAgent::Error error); diff --git a/src/bluetooth/darwin/btobexsession.mm b/src/bluetooth/darwin/btobexsession.mm deleted file mode 100644 index ecf010ba..00000000 --- a/src/bluetooth/darwin/btobexsession.mm +++ /dev/null @@ -1,843 +0,0 @@ -/**************************************************************************** -** -** 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 "qbluetoothaddress.h" -#include "btobexsession_p.h" -#include "btutility_p.h" - -#include <QtCore/qloggingcategory.h> -#include <QtCore/qvector.h> -#include <QtCore/qdebug.h> -#include <QtCore/qlist.h> - -#include <algorithm> -#include <cstddef> -#include <limits> - -QT_BEGIN_NAMESPACE - -namespace DarwinBluetooth -{ - -OBEXSessionDelegate::~OBEXSessionDelegate() -{ -} - -namespace { - -using NSDataPtr = NSMutableData *; - -struct OBEXHeader -{ - OBEXHeader() : headerID(0) - { - } - - quint8 headerID; - QVariant value; -}; - -enum { - // Bits 7 and 8 == header's format. - OBEXHeaderFormatMask = 0xc0, - // - OBEXHeaderFormatUnicode = 0, // 87 - OBEXHeaderFormatByteSequence = 0x40, // 0100 0000 - OBEXHeaderFormat1Byte = 0x80, // 1000 0000 - OBEXHeaderFormat4Byte = 0xc0, // 1100 0000 - -}; - -quint32 extract_uint32(const uint8_t *bytes) -{ - // Four byte value, high byte first. - Q_ASSERT_X(bytes, Q_FUNC_INFO, "invalid input data (null)"); - - uint32_t value = uint32_t(); - std::copy(bytes, bytes + sizeof value, reinterpret_cast<uint8_t *>(&value)); - - return NSSwapBigIntToHost(value); -} - -quint16 extract_uint16(const uint8_t *bytes) -{ - // Two byte value, high byte first. - Q_ASSERT_X(bytes, Q_FUNC_INFO, "invalid input data (null)"); - - uint16_t value = uint16_t(); - std::copy(bytes, bytes + sizeof value, reinterpret_cast<uint8_t *>(&value)); - - return NSSwapBigShortToHost(value); -} - -QString extract_qstring(const uint8_t *bytes, quint16 stringLength) -{ - if (bytes && stringLength) { - NSString * const nsString = [[NSString alloc] initWithBytes:bytes - length:stringLength - encoding:NSUnicodeStringEncoding]; - if (nsString) - return QString::fromNSString(nsString); - } - - // Empty string is an error, "valid" empty strings are - // handled separately. - return QString(); -} - -QList<OBEXHeader> qt_bluetooth_headers(const uint8_t *data, std::size_t length) -{ - // Convert a data from IOBluetooth into something, Qt understands. - // Possible formats (bits 7 and 8): - // 1. 00 Two bytes of length folowed by a null-terminated - // Unicode text string (length is unsigned integer; - // it covers the header ID and the whole of the header - // value, including the length bytes and the two bytes - // of null terminator. - // 2. 01 Two bytes of length followed by a byte sequence (length - // is an unsigned integer sent high byte first; it covers - // the header ID and the whole of the header value). - // 3. 10 A single byte value. - // 4. 11 A four byte value, sent high byte first. - - Q_ASSERT_X(data, Q_FUNC_INFO, "invalid data (null)"); - Q_ASSERT_X(length >= 2, Q_FUNC_INFO, "invalid data length"); - - Q_UNUSED(data) - Q_UNUSED(length) - - QList<OBEXHeader> empty; - QList<OBEXHeader> qtHeaders; - - for (std::size_t i = 0; i < length;) { - std::size_t headerLength = 0; - OBEXHeader header; - header.headerID = data[i]; - - switch (data[i] & OBEXHeaderFormatMask) { - case OBEXHeaderFormatUnicode: - { - if (i + 3 > length) - return empty; - headerLength = extract_uint16(data + i + 1); - // Invalid length or input data: - if (headerLength < 3 || i + headerLength > length) - return empty; - if (headerLength == 3 || headerLength == 5) { // Can 5 ever happen? - header.value.fromValue<QString>(QString()); - } else if (headerLength > 5) {// TODO: We do not check now, that the string actually valid. - const QString value(extract_qstring(data + i + 3, headerLength - 5)); - if (!value.length()) // Some error? - return empty; - header.value.setValue<QString>(value); - } else // Still something weird. - return empty; - break; - } - case OBEXHeaderFormatByteSequence: - { - if (i + 3 > length) - return empty; - headerLength = extract_uint16(data + i + 1); - // Something is wrong: - if (headerLength < 3 || i + headerLength > length) - return empty; - QVector<unsigned char> value; - if (headerLength > 3) { - value.resize(headerLength - 3); - std::copy(data, data + headerLength, value.begin()); - } - header.value.setValue<QVector<unsigned char> >(value); - break; - } - case OBEXHeaderFormat1Byte: - { - // 1 byte integer + 1 byte headerID == 2 - if (i + 2 > length) - return empty; - headerLength = 2; - header.value.setValue<quint8>(data[i + 1]); - break; - } - case OBEXHeaderFormat4Byte: - { - // 4 byte integer + 1 byte headerID == 5 - if (i + 5 > length) - return empty; - headerLength = 5; - header.value.setValue<quint32>(extract_uint32(data + i + 1)); - break; - } - default: - qCWarning(QT_BT_DARWIN) << "invalid header format"; - return empty; - } - - i += headerLength; - qtHeaders.push_back(header); - } - - return qtHeaders; -} - -bool append_uint16(ObjCStrongReference<NSMutableData> headers, uint16_t value) -{ - if (!headers) - return false; - - const NSUInteger length = [headers length]; - const uint16_t valueSwapped = NSSwapHostShortToBig(value); - [headers appendBytes:&valueSwapped length:sizeof valueSwapped]; - - return [headers length] - length == 2; -} - - -bool append_four_byte_header(ObjCStrongReference<NSMutableData> headers, uint8_t headerID, - uint32_t headerValue) -{ - if (!headers) - return false; - - const NSUInteger length = [headers length]; - // Header ID (1 byte) - [headers appendBytes:&headerID length:1]; - // Header value (4 bytes) - const uint32_t valueSwapped(NSSwapHostIntToBig(headerValue)); - [headers appendBytes:&valueSwapped length:sizeof valueSwapped]; - - return [headers length] - length == 5; -} - -bool append_unicode_header(ObjCStrongReference<NSMutableData> headers, uint8_t headerID, - const QString &string) -{ - // Two bytes of length followed by a null-terminated - // Unicode text string. Length is unsigned integer, - // it covers the header ID and the whole of the header - // value, including the length bytes and the two bytes - // of null terminator. - // All Obj-C objects are autoreleased. - - if (!headers) - return false; - - QT_BT_MAC_AUTORELEASEPOOL; - - const NSUInteger initialLength = [headers length]; - [headers appendBytes:&headerID length:1]; - - if (!string.length()) { - // Empty string. The length is 3 - // (header ID + length value itself). - return append_uint16(headers, 3); - } - - NSString *const nsString = string.toNSString(); - if (!nsString) - return false; - - // TODO: check if the encodings is right. It was NSUnicodeStringEncoding but - // byte order was wrong. Also, I do not need BOM check anymore? - NSData *const data = [nsString dataUsingEncoding:NSUTF16BigEndianStringEncoding]; - if (!data) - return false; - - // This data can include byte-order marker (BOM) and does not include - // a null terminator. Anyway, the length must be >= 2. - NSUInteger length = [data length]; - if (length < 2) - return false; - - const uint8_t *dataPtr = static_cast<const uint8_t *>([data bytes]); - if ((dataPtr[0] == 0xff && dataPtr[1] == 0xfe) - || (dataPtr[0] == 0xfe && dataPtr[1] == 0xff)) { - if (length == 2) //Something weird? - return false; - // Skip a BOM. - dataPtr += 2; - length -= 2; - } - - // headerID + length == 3, string's length + 2 - // bytes for a null terminator. - if (!append_uint16(headers, length + 3 + 2)) - return false; - - [headers appendBytes:dataPtr length:length]; - const uint8_t nullTerminator[2] = {}; - [headers appendBytes:nullTerminator length:2]; - - return [headers length] - initialLength == length + 3 + 2; -} - -ObjCStrongReference<NSMutableData> next_data_chunk(QIODevice &inputStream, IOBluetoothOBEXSession *session, - NSUInteger headersLength, bool &isLast) -{ - // Work only for OBEX put (we request a specific payload length). - Q_ASSERT_X(session, Q_FUNC_INFO, "invalid OBEX session (nil)"); - - const OBEXMaxPacketLength packetSize = [session getAvailableCommandPayloadLength:kOBEXOpCodePut]; - if (!packetSize || headersLength >= packetSize) - return ObjCStrongReference<NSMutableData>(); - - const OBEXMaxPacketLength maxBodySize = packetSize - headersLength; - - QVector<char> block(maxBodySize); - const int realSize = inputStream.read(block.data(), block.size()); - if (realSize <= 0) { - // Well, either the last or an error. - isLast = true; - return ObjCStrongReference<NSMutableData>(); - } - - ObjCStrongReference<NSMutableData> chunk([NSMutableData dataWithBytes:block.data() - length:realSize], RetainPolicy::doInitialRetain); - if (chunk && [chunk length]) { - // If it actually was the last chunk - // of a length == maxBodySize, we'll - // send one more packet (empty though)? - isLast = [chunk length] < maxBodySize; - } - - return chunk; -} - -bool check_connect_event(const OBEXSessionEvent *e, OBEXError &error, OBEXOpCode &response) -{ - Q_ASSERT_X(e, Q_FUNC_INFO, "invalid event (null)"); - - // This function tries to extract either an error code or a - // server response code. "Good" event has type connect command respond - // and reponse code 0XA0. Everything else is a "bad" event and - // means connect failed. - - // If it's an error event - return the error. - // If it's connect response - extract the response code. - // If it's something else (is it possible?) - set general error. - - if (e->type == kOBEXSessionEventTypeError) { - error = e->u.errorData.error; - return false; - } if (e->type == kOBEXSessionEventTypeConnectCommandResponseReceived) { - // We can read response code only for such an event. - response = e->u.connectCommandResponseData.serverResponseOpCode; - return response == kOBEXResponseCodeSuccessWithFinalBit; - } else { - qCWarning(QT_BT_DARWIN) << "unexpected event type"; - error = kOBEXGeneralError; - return false; - } -} - -bool check_put_event(const OBEXSessionEvent *e, OBEXError &error, OBEXOpCode &response) -{ - Q_ASSERT_X(e, Q_FUNC_INFO, "invalid event (null)"); - - // See the comments above. - - if (e->type == kOBEXSessionEventTypeError) { - error = e->u.errorData.error; - return false; - } else if (e->type == kOBEXSessionEventTypePutCommandResponseReceived) { - response = e->u.putCommandResponseData.serverResponseOpCode; - return response == kOBEXResponseCodeContinueWithFinalBit || - response == kOBEXResponseCodeSuccessWithFinalBit; - } else { - qCWarning(QT_BT_DARWIN) << "unexpected event type"; - error = kOBEXGeneralError; - return false; - } -} - -bool check_abort_event(const OBEXSessionEvent *e, OBEXError &error, OBEXOpCode &response) -{ - Q_ASSERT_X(e, Q_FUNC_INFO, "invalid event (null)"); - - if (e->type == kOBEXSessionEventTypeError) { - error = e->u.errorData.error; - return false; - } else if (e->type == kOBEXSessionEventTypeAbortCommandResponseReceived) { - response = e->u.abortCommandResponseData.serverResponseOpCode; - return response == kOBEXResponseCodeSuccessWithFinalBit; - } else { - qCWarning(QT_BT_DARWIN) << "unexpected event type"; - return false; - } -} - -} // Unnamed namespace. -} // namespace DarwinBluetooth. - -QT_END_NAMESPACE - -QT_USE_NAMESPACE - -@interface QT_MANGLE_NAMESPACE(DarwinBTOBEXSession) (PrivateAPI) - -// OBEXDisconnect returns void - it's considered to be always -// successful. These methods are "private API" - no need to expose them, -// for internal use only. -- (void)OBEXDisconnect; -- (void)OBEXDisconnectHandler:(const OBEXSessionEvent*)event; - -@end - -@implementation QT_MANGLE_NAMESPACE(DarwinBTOBEXSession) -{ - QT_PREPEND_NAMESPACE(DarwinBluetooth)::OBEXSessionDelegate *delegate; - IOBluetoothDevice *device; - quint16 channelID; - IOBluetoothOBEXSession *session; - - QT_PREPEND_NAMESPACE(DarwinBluetooth)::OBEXRequest currentRequest; - - bool connected; - bool connectionIDFound; - quint32 connectionID; - - QT_PREPEND_NAMESPACE(QIODevice) *inputStream; - - // TODO: switch to scoped pointers or strong reference objects instead. - NSMutableData *headersData; - NSMutableData *bodyData; - - quint32 bytesSent; - bool pendingAbort; -} - -+ (OBEXMaxPacketLength) maxPacketLength -{ - // Some arbitrary number, we'll adjust it as soon as - // we connected, asking a session about packet size for - // a particular command. - return 0x1000; -} - -- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(DarwinBluetooth::OBEXSessionDelegate) *)aDelegate - remoteDevice:(const QBluetoothAddress &)deviceAddress channelID:(quint16)port -{ - Q_ASSERT_X(aDelegate, Q_FUNC_INFO, "invalid delegate (null)"); - Q_ASSERT_X(!deviceAddress.isNull(), Q_FUNC_INFO, "invalid remote device address"); - Q_ASSERT_X(port, Q_FUNC_INFO, "invalid port (0)"); - - if (self = [super init]) { - connected = false; - currentRequest = DarwinBluetooth::OBEXNoop; - connectionID = 0; - connectionIDFound = false; - - const BluetoothDeviceAddress addr(DarwinBluetooth::iobluetooth_address(deviceAddress)); - device = [[IOBluetoothDevice deviceWithAddress:&addr] retain]; - if (!device) { - qCWarning(QT_BT_DARWIN) << "failed to create an IOBluetoothDevice"; - return self; - } - - session = [[IOBluetoothOBEXSession alloc] initWithDevice:device channelID:port]; - if (!session) { - qCWarning(QT_BT_DARWIN) << "failed to create an OBEX session"; - return self; - } - - delegate = aDelegate; - channelID = port; - } - - return self; -} - -- (void)dealloc -{ - [device release]; - [session release]; - - [headersData release]; - [bodyData release]; - - [super dealloc]; -} - -- (OBEXError)OBEXConnect -{ - if (!session) { - qCWarning(QT_BT_DARWIN) << "invalid session (nil)"; - return kOBEXGeneralError; - } - - // That's a "single-shot" operation: - Q_ASSERT_X(currentRequest == DarwinBluetooth::OBEXNoop, Q_FUNC_INFO, - "can not connect in this state (another request is active)"); - - connected = false; - connectionIDFound = false; - connectionID = 0; - currentRequest = DarwinBluetooth::OBEXConnect; - - const OBEXError status = [session OBEXConnect:kOBEXConnectFlagNone - maxPacketLength:[QT_MANGLE_NAMESPACE(DarwinBTOBEXSession) maxPacketLength] - optionalHeaders:nullptr - optionalHeadersLength:0 - eventSelector:@selector(OBEXConnectHandler:) - selectorTarget:self - refCon:nullptr]; - - if (status != kOBEXSuccess) { - currentRequest = DarwinBluetooth::OBEXNoop; - // Already connected is still ok for us? - connected = status == kOBEXSessionAlreadyConnectedError; - } - - return status; -} - -- (void)OBEXConnectHandler:(const OBEXSessionEvent*)event -{ - using namespace DarwinBluetooth; - - Q_ASSERT_X(session, Q_FUNC_INFO, "invalid session (nil)"); - - if (pendingAbort) { - currentRequest = OBEXNoop; - [self OBEXAbort]; - return; - } - - if (currentRequest != OBEXConnect) { - qCWarning(QT_BT_DARWIN) << "called while there is no " - "active connect request"; - return; - } - - currentRequest = OBEXNoop; - - OBEXError errorCode = kOBEXSuccess; - OBEXOpCode responseCode = kOBEXResponseCodeSuccessWithFinalBit; - - if (!check_connect_event(event, errorCode, responseCode)) { - // OBEX connect failed. - if (delegate) - delegate->OBEXConnectError(errorCode, responseCode); - return; - } - - const OBEXConnectCommandResponseData *const response = &event->u.connectCommandResponseData; - if (response->headerDataPtr && response->headerDataLength >= 2) { - // 2 == 1 byte headerID + at least 1 byte headerValue ... - const QList<OBEXHeader> headers(qt_bluetooth_headers(static_cast<const uint8_t *>(response->headerDataPtr), - response->headerDataLength)); - // ConnectionID is used when multiplexing OBEX connections - // to identify which particular connection this object is - // being sent on. When used, this _must_ be the first - // header sent. - - for (const OBEXHeader &header : headers) { - if (header.headerID == kOBEXHeaderIDConnectionID) { - connectionID = header.value.value<quint32>(); - connectionIDFound = true; - break; - } - } - } - - connected = true; - - if (delegate) - delegate->OBEXConnectSuccess(); -} - -- (OBEXError)OBEXAbort -{ - using namespace DarwinBluetooth; - - Q_ASSERT_X(session, Q_FUNC_INFO, "invalid OBEX session (nil)"); - - if (currentRequest == OBEXNoop) { - pendingAbort = false; - - if (![self isConnected]) - return kOBEXSessionNotConnectedError; - - currentRequest = OBEXAbort; - const OBEXError status = [session OBEXAbort:nullptr - optionalHeadersLength:0 - eventSelector:@selector(OBEXAbortHandler:) - selectorTarget:self - refCon:nullptr]; - if (status != kOBEXSuccess) - currentRequest = OBEXNoop; - - return status; - } else { - // We're in the middle of some request, wait - // for any handler to be called first. - pendingAbort = true; - return kOBEXSuccess; - } -} - -- (void)OBEXAbortHandler:(const OBEXSessionEvent*)event -{ - using namespace DarwinBluetooth; - - Q_ASSERT_X(session, Q_FUNC_INFO, "invalid OBEX session (nil)"); - - if (currentRequest != OBEXAbort) { - qCWarning(QT_BT_DARWIN) << "called while there " - "is no ABORT request"; - return; - } - - pendingAbort = false; - currentRequest = OBEXNoop; - - if (delegate) { - OBEXError error = kOBEXSuccess; - OBEXOpCode response = kOBEXResponseCodeSuccessWithFinalBit; - if (check_abort_event(event, error, response)) - delegate->OBEXAbortSuccess(); - } -} - -- (OBEXError)OBEXPutFile:(QT_PREPEND_NAMESPACE(QIODevice) *)input withName:(const QString &)name -{ - using namespace DarwinBluetooth; - - if (!session || ![self isConnected]) - return kOBEXSessionNotConnectedError; - - Q_ASSERT_X(currentRequest == OBEXNoop, Q_FUNC_INFO, - "the current session has an active request already"); - Q_ASSERT_X(input, Q_FUNC_INFO, "invalid input stream (null)"); - Q_ASSERT_X(input->isReadable(), Q_FUNC_INFO, "invalid input stream (not readable)"); - - // We send a put request with a couple of headers (size/file name/may be connection ID) + - // a payload. - const qint64 fileSize = input->size(); - if (fileSize <= 0 || fileSize >= std::numeric_limits<uint32_t>::max()) { - qCWarning(QT_BT_DARWIN) << "invalid input file size"; - return kOBEXBadArgumentError; - } - - ObjCStrongReference<NSMutableData> headers([[NSMutableData alloc] init], RetainPolicy::noInitialRetain); - if (!headers) { - qCWarning(QT_BT_DARWIN) << "failed to allocate headers"; - return kOBEXNoResourcesError; - } - - // Now we append headers with: Connection ID (if any), - // file name, file size, the first (and probably the only) chunk of data - // from the input stream and send a put request. - - if (connectionIDFound) { - if (!append_four_byte_header(headers, kOBEXHeaderIDConnectionID, connectionID)) { - qCWarning(QT_BT_DARWIN) << "failed to append connection ID header"; - return kOBEXNoResourcesError; - } - } - - if (name.length()) { - if (!append_unicode_header(headers, kOBEXHeaderIDName, name)) { - qCWarning(QT_BT_DARWIN) << "failed to append a unicode string"; - return kOBEXNoResourcesError; - } - } - - if (fileSize && !input->isSequential()) - append_four_byte_header(headers, kOBEXHeaderIDLength, uint32_t(fileSize)); - - bool lastChunk = false; - ObjCStrongReference<NSMutableData> chunk(next_data_chunk(*input, session, [headers length], lastChunk)); - if (!chunk || ![chunk length]) { - // We do not support PUT-DELETE (?) - // At least the first chunk is expected to be non-empty. - qCWarning(QT_BT_DARWIN) << "invalid input stream"; - return kOBEXBadArgumentError; - } - - currentRequest = OBEXPut; - - const OBEXError status = [session OBEXPut:lastChunk - headersData:[headers mutableBytes] - headersDataLength:[headers length] - bodyData:[chunk mutableBytes] - bodyDataLength:[chunk length] - eventSelector:@selector(OBEXPutHandler:) - selectorTarget:self - refCon:nullptr]; - - if (status == kOBEXSuccess) { - if (delegate && fileSize && !input->isSequential()) - delegate->OBEXPutDataSent([chunk length], fileSize); - - bytesSent = [chunk length]; - headersData = NSDataPtr(headers.release()); - bodyData = NSDataPtr(chunk.release()); - inputStream = input; - } else { - // PUT request failed and we now - // want to close a connection/session. - currentRequest = OBEXNoop; - // Try to cleanup (disconnect). - [self OBEXDisconnect]; - } - - return status; -} - -- (void)OBEXPutHandler:(const OBEXSessionEvent*)event -{ - using namespace DarwinBluetooth; - - Q_ASSERT_X(session, Q_FUNC_INFO, "invalid OBEX session (nil)"); - - if (pendingAbort) { - currentRequest = OBEXNoop; - [self OBEXAbort]; - return; - } - - if (currentRequest != OBEXPut) { - qCWarning(QT_BT_DARWIN) << "called while the current " - "request is not a put request"; - return; - } - - OBEXError error = kOBEXSuccess; - OBEXOpCode responseCode = kOBEXResponseCodeSuccessWithFinalBit; - if (!check_put_event(event, error, responseCode)) { - currentRequest = OBEXNoop; - if (delegate) - delegate->OBEXPutError(error, responseCode); - [self OBEXDisconnect]; - return; - } - - // Now try to send more data if we have any. - if (responseCode == kOBEXResponseCodeContinueWithFinalBit) { - // Send more data. - bool lastChunk = false; - // 0 for the headers length, no more headers. - ObjCStrongReference<NSMutableData> chunk(next_data_chunk(*inputStream, session, 0, lastChunk)); - if (!chunk && !lastChunk) { - qCWarning(QT_BT_DARWIN) << "failed to allocate the next memory chunk"; - return; - } - - void *dataPtr = chunk ? [chunk mutableBytes] : nullptr; - const NSUInteger dataSize = chunk ? [chunk length] : 0; - const OBEXError status = [session OBEXPut:lastChunk - headersData:nullptr - headersDataLength:0 - bodyData:dataPtr - bodyDataLength:dataSize - eventSelector:@selector(OBEXPutHandler:) - selectorTarget:self - refCon:nullptr]; - - if (status != kOBEXSuccess) { - qCWarning(QT_BT_DARWIN) << "failed to send the next memory chunk"; - currentRequest = OBEXNoop; - if (delegate) // Response code is not important here. - delegate->OBEXPutError(kOBEXNoResourcesError, 0); - - [self OBEXDisconnect]; - } else { - [bodyData release]; - bytesSent += [chunk length]; - bodyData = NSDataPtr(chunk.release()); - - if (delegate && !inputStream->isSequential()) - delegate->OBEXPutDataSent(bytesSent, inputStream->size()); - } - } else if (responseCode == kOBEXResponseCodeSuccessWithFinalBit) { - currentRequest = OBEXNoop; - if (delegate) - delegate->OBEXPutSuccess(); - - [self OBEXDisconnect]; - } -} - -- (void)OBEXDisconnect -{ - Q_ASSERT_X(session, Q_FUNC_INFO, "invalid session (nil)"); - - currentRequest = DarwinBluetooth::OBEXDisconnect; - - [session OBEXDisconnect:nullptr - optionalHeadersLength:0 - eventSelector:@selector(OBEXDisconnectHandler:) - selectorTarget:self - refCon:nullptr]; -} - -- (void)OBEXDisconnectHandler:(const OBEXSessionEvent*)event -{ - Q_UNUSED(event) - - Q_ASSERT_X(session, Q_FUNC_INFO, "invalid session (nil)"); - - // Event can have an error type, but there's nothing - // we can do - even "cleanup" failed. - connected = false; -} - -- (bool)isConnected -{ - return device && session && connected; -} - -- (void)closeSession -{ - // Clear the delegate and reset the request, - // do not try any of OBEX commands - the session will be deleted - // immediately. - delegate = nullptr; - // This will stop any handler (callback) preventing - // any read/write to potentially deleted objects. - currentRequest = DarwinBluetooth::OBEXNoop; -} - -- (bool)hasActiveRequest -{ - return currentRequest != DarwinBluetooth::OBEXNoop && !pendingAbort; -} - -@end diff --git a/src/bluetooth/darwin/btobexsession_p.h b/src/bluetooth/darwin/btobexsession_p.h deleted file mode 100644 index 11c6d226..00000000 --- a/src/bluetooth/darwin/btobexsession_p.h +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************** -** -** 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 BTOBEXSESSION_P_H -#define BTOBEXSESSION_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/qvariant.h> -#include <QtCore/qglobal.h> - -#include <Foundation/Foundation.h> - -#include <IOBluetooth/IOBluetooth.h> - -// TODO: all this code must be removed in Qt 6? - -@class QT_MANGLE_NAMESPACE(DarwinBTOBEXSession); - -QT_BEGIN_NAMESPACE - -class QBluetoothAddress; -class QIODevice; -class QString; - -namespace DarwinBluetooth -{ - -class OBEXSessionDelegate -{ -public: - typedef QT_MANGLE_NAMESPACE(DarwinBTOBEXSession) ObjCOBEXSession; - - virtual ~OBEXSessionDelegate(); - - virtual void OBEXConnectError(OBEXError error, OBEXOpCode responseCode) = 0; - virtual void OBEXConnectSuccess() = 0; - - virtual void OBEXAbortSuccess() = 0; - - virtual void OBEXPutDataSent(quint32 current, quint32 total) = 0; - virtual void OBEXPutSuccess() = 0; - virtual void OBEXPutError(OBEXError error, OBEXOpCode responseCode) = 0; -}; - -enum OBEXRequest { - OBEXNoop, - OBEXConnect, - OBEXDisconnect, - OBEXPut, - OBEXGet, - OBEXSetPath, - OBEXAbort -}; - -} // namespace DarwinBluetooth - -QT_END_NAMESPACE - -// OBEX Session, it's a "single-shot" operation as our QBluetoothTransferReply is -// (it does not have an interface to re-send data or re-use the same transfer reply). -// It either succeeds or fails and tries to cleanup in any case. -@interface QT_MANGLE_NAMESPACE(DarwinBTOBEXSession) : NSObject - -- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(DarwinBluetooth::OBEXSessionDelegate) *)aDelegate - remoteDevice:(const QBluetoothAddress &)deviceAddress channelID:(quint16)port; - -- (void)dealloc; - -// Below I have pairs: OBEX operation and its callback method. -- (OBEXError)OBEXConnect; -- (void)OBEXConnectHandler:(const OBEXSessionEvent*)event; - -- (OBEXError)OBEXAbort; -- (void)OBEXAbortHandler:(const OBEXSessionEvent*)event; - -- (OBEXError)OBEXPutFile:(QT_PREPEND_NAMESPACE(QIODevice) *)inputStream withName:(const QString &)name; -- (void)OBEXPutHandler:(const OBEXSessionEvent*)event; - -// Aux. methods. -- (bool)isConnected; - -// To be called from C++ destructors. OBEXSession is not -// valid anymore after this call (no more OBEX operations -// can be executed). It's an ABORT/DISCONNECT sequence. -// It also resets a delegate to null. -- (void)closeSession; -// -- (bool)hasActiveRequest; - -@end - -#endif diff --git a/src/bluetooth/darwin/btperipheralmanager.mm b/src/bluetooth/darwin/btperipheralmanager.mm index 3336d8c5..78a328cc 100644 --- a/src/bluetooth/darwin/btperipheralmanager.mm +++ b/src/bluetooth/darwin/btperipheralmanager.mm @@ -1,44 +1,7 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - - +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#include "qlowenergyadvertisingparameters.h" #include "qlowenergycharacteristicdata.h" #include "qlowenergydescriptordata.h" #include "btperipheralmanager_p.h" @@ -46,11 +9,15 @@ #include "btnotifier_p.h" #include "qbluetooth.h" +#include <QtCore/qstring.h> #include <QtCore/qdebug.h> #include <QtCore/qlist.h> #include <algorithm> +#include <vector> #include <limits> +#include <deque> +#include <map> namespace { @@ -76,10 +43,10 @@ CBAttributePermissions cb_permissions(const QLowEnergyCharacteristicData &data) if (props & QLEC::Read) cbFlags = CBAttributePermissions(cbFlags | CBAttributePermissionsReadable); - if (data.writeConstraints() & QBluetooth::AttEncryptionRequired) + if (data.writeConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired) cbFlags = CBAttributePermissions(cbFlags | CBAttributePermissionsWriteEncryptionRequired); - if (data.readConstraints() & QBluetooth::AttEncryptionRequired) + if (data.readConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired) cbFlags = CBAttributePermissions(cbFlags | CBAttributePermissionsReadEncryptionRequired); return cbFlags; @@ -105,8 +72,8 @@ ObjCStrongReference<CBMutableDescriptor> create_descriptor(const QLowEnergyDescr CBUUIDCharacteristicUserDescriptionString and CBUUIDCharacteristicFormatString" */ - if (data.uuid() != QBluetoothUuid::CharacteristicUserDescription && - data.uuid() != QBluetoothUuid::CharacteristicPresentationFormat) { + if (data.uuid() != QBluetoothUuid::DescriptorType::CharacteristicUserDescription && + data.uuid() != QBluetoothUuid::DescriptorType::CharacteristicPresentationFormat) { qCWarning(QT_BT_DARWIN) << "unsupported descriptor" << data.uuid(); return {}; } @@ -116,7 +83,7 @@ ObjCStrongReference<CBMutableDescriptor> create_descriptor(const QLowEnergyDescr // 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) { + if (data.uuid() == QBluetoothUuid::DescriptorType::CharacteristicUserDescription) { const QString asQString(QString::fromUtf8(data.value())); value.reset(asQString.toNSString(), RetainPolicy::doInitialRetain); // toNSString is auto-released, we have to retain. } else { @@ -134,14 +101,14 @@ 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()); + quint32 nEntries = 1 + quint32(data.includedServices().size()); for (const auto &ch : data.characteristics()) { if (maxu32 - 2 < nEntries) return {}; nEntries += 2; - if (maxu32 - ch.descriptors().count() < nEntries) + if (maxu32 - ch.descriptors().size() < nEntries) return {}; - nEntries += ch.descriptors().count(); + nEntries += ch.descriptors().size(); } return nEntries; @@ -159,10 +126,9 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) } -@interface QT_MANGLE_NAMESPACE(DarwinBTPeripheralManager) (PrivateAPI) +@interface DarwinBTPeripheralManager (PrivateAPI) - (void)addConnectedCentral:(CBCentral *)central; -- (void)removeConnectedCentral:(CBCentral *)central; - (CBService *)findIncludedService:(const QBluetoothUuid &)qtUUID; - (void)addIncludedServices:(const QLowEnergyServiceData &)data @@ -177,7 +143,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) @end -@implementation QT_MANGLE_NAMESPACE(DarwinBTPeripheralManager) +@implementation DarwinBTPeripheralManager { ObjCScopedPointer<CBPeripheralManager> manager; LECBManagerNotifier *notifier; @@ -200,10 +166,9 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) std::deque<UpdateRequest> updateQueue; - ObjCScopedPointer<NSMutableSet> connectedCentrals; - PeripheralState state; NSUInteger maxNotificationValueLength; + decltype(services.size()) nOfFailedAds; } - (id)initWith:(LECBManagerNotifier *)aNotifier @@ -213,8 +178,6 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) notifier = aNotifier; state = PeripheralState::idle; nextServiceToAdd = {}; - connectedCentrals.reset([[NSMutableSet alloc] init], - DarwinBluetooth::RetainPolicy::noInitialRetain); maxNotificationValueLength = std::numeric_limits<NSUInteger>::max(); } @@ -274,7 +237,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) data:(const QLowEnergyAdvertisingData &)data scanResponse:(const QLowEnergyAdvertisingData &)scanResponse { - Q_UNUSED(parameters) + Q_UNUSED(parameters); // This is the last method we call on the controller's thread // before starting advertising on the Qt's LE queue. @@ -311,7 +274,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) forKey:CBAdvertisementDataLocalNameKey]; } - if (!data.services().count() && !scanResponse.services().count()) + if (data.services().isEmpty() && scanResponse.services().isEmpty()) return; const ObjCScopedPointer<NSMutableArray> uuids([[NSMutableArray alloc] init], @@ -388,7 +351,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) } const auto & range = valueRanges[charHandle]; - if (value.size() < int(range.first) || value.size() > int(range.second) + if (value.size() < qsizetype(range.first) || value.size() > qsizetype(range.second) #ifdef Q_OS_IOS || value.size() > DarwinBluetooth::maxValueLength) { #else @@ -434,6 +397,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) [manager removeAllServices]; nextServiceToAdd = {}; state = PeripheralState::advertising; + nOfFailedAds = 0; [self addServicesToPeripheral]; } return; @@ -444,7 +408,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) advertising has stopped and that any connected centrals have been disconnected." */ - [connectedCentrals removeAllObjects]; + maxNotificationValueLength = std::numeric_limits<NSUInteger>::max(); if (state == PeripheralState::advertising) { state = PeripheralState::waitingForPowerOn; @@ -459,22 +423,17 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) explicitly added again." */ - if (peripheral.state == CBManagerStateUnauthorized || peripheral.state == CBManagerStateUnsupported) { + if (peripheral.state == CBManagerStateUnsupported) { + state = PeripheralState::idle; emit notifier->LEnotSupported(); + } else if (peripheral.state == CBManagerStateUnauthorized) { state = PeripheralState::idle; + emit notifier->CBManagerError(QLowEnergyController::MissingPermissionsError); } #pragma clang diagnostic pop } -- (void)peripheralManager:(CBPeripheralManager *)peripheral - willRestoreState:(NSDictionary *)dict -{ - Q_UNUSED(peripheral) - Q_UNUSED(dict) - // NOOP atm. -} - - (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error { @@ -491,28 +450,32 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) - (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error { - Q_UNUSED(service) + 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 (++nOfFailedAds == services.size()) { + emit notifier->CBManagerError(QLowEnergyController::AdvertisingError); + state = PeripheralState::idle; + return; + } } - if (nextServiceToAdd == services.size()) + if (nextServiceToAdd == services.size()) { + nOfFailedAds = 0; // Discard any failed, some services made it into advertising. [manager startAdvertising:[advertisementData count] ? advertisementData.get() : nil]; - else + } else { [self addServicesToPeripheral]; + } } - (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic { - Q_UNUSED(characteristic) + Q_UNUSED(characteristic); if (peripheral != manager || !notifier) return; @@ -526,17 +489,15 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) - (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic { - Q_UNUSED(characteristic) + Q_UNUSED(characteristic); if (peripheral != manager || !notifier) return; - [self removeConnectedCentral:central]; - - if (![connectedCentrals count]) { - if (const auto handle = charMap.key(characteristic)) + const auto handle = charMap.key(characteristic); + if (![static_cast<CBMutableCharacteristic*>(characteristic).subscribedCentrals count] + && handle) emit notifier->notificationEnabled(handle, false); - } } - (void)peripheralManager:(CBPeripheralManager *)peripheral @@ -632,7 +593,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) [self writeValueForCharacteristic:charHandle withWriteRequest:request]; } - for (const auto pair : updated) { + for (const auto &pair : updated) { const auto handle = pair.first; NSMutableData *value = charValues[handle]; value.length = pair.second; @@ -667,8 +628,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) while (updateQueue.size()) { const auto &request = updateQueue.front(); if (charMap.contains(request.charHandle)) { - if ([connectedCentrals count] - && maxNotificationValueLength < [request.value length]) { + if (maxNotificationValueLength < [request.value length]) { qCWarning(QT_BT_DARWIN) << "value of length" << [request.value length] << "will possibly be truncated to" << maxNotificationValueLength; @@ -705,33 +665,8 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) 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(); - } - - if (![connectedCentrals count]) - maxNotificationValueLength = std::numeric_limits<NSUInteger>::max(); } - (CBService *)findIncludedService:(const QBluetoothUuid &)qtUUID @@ -801,7 +736,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data) } #ifdef Q_OS_IOS - if (ch.value().length() > DarwinBluetooth::maxValueLength) { + if (ch.value().size() > DarwinBluetooth::maxValueLength) { qCWarning(QT_BT_DARWIN) << "addCharacteristicsAndDescritptors: " "value exceeds the maximal permitted " "value length (" diff --git a/src/bluetooth/darwin/btperipheralmanager_p.h b/src/bluetooth/darwin/btperipheralmanager_p.h index e09165ac..3bd7ceb7 100644 --- a/src/bluetooth/darwin/btperipheralmanager_p.h +++ b/src/bluetooth/darwin/btperipheralmanager_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTPERIPHERALMANAGER_P_H #define BTPERIPHERALMANAGER_P_H @@ -53,18 +17,17 @@ #include "btutility_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/qpair.h> #include <QtCore/qmap.h> +#include <QtCore/private/qcore_mac_p.h> + #include <vector> #include <deque> #include <map> @@ -75,6 +38,8 @@ QT_BEGIN_NAMESPACE +class QLowEnergyAdvertisingParameters; +class QLowEnergyAdvertisingData; class QLowEnergyServiceData; namespace DarwinBluetooth @@ -142,8 +107,6 @@ using ValueRange = QPair<NSUInteger, NSUInteger>; // 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 @@ -160,4 +123,6 @@ using ValueRange = QPair<NSUInteger, NSUInteger>; @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTPeripheralManager); + #endif diff --git a/src/bluetooth/darwin/btraii.mm b/src/bluetooth/darwin/btraii.mm index 486c3c14..acf95ae2 100644 --- a/src/bluetooth/darwin/btraii.mm +++ b/src/bluetooth/darwin/btraii.mm @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "btraii_p.h" diff --git a/src/bluetooth/darwin/btraii_p.h b/src/bluetooth/darwin/btraii_p.h index c7a159cb..1ba5d35e 100644 --- a/src/bluetooth/darwin/btraii_p.h +++ b/src/bluetooth/darwin/btraii_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTRAII_P_H #define BTRAII_P_H @@ -51,7 +15,7 @@ // We mean it. // -#include <QtCore/qglobal.h> +#include <QtCore/private/qglobal_p.h> #include <utility> @@ -76,10 +40,6 @@ enum class RetainPolicy // Objective-C compiler to work. Member-function template 'getAs' is // a convenience shortcut giving the desired pointer type in // Objective-C++ files (*.mm). - -// TODO: on top of these classes I can build ObjCStrongReference (it's -// now inside osxbtutils_p.h, a template class that does have type -// information needed but works only in Objective-C++ environment. class StrongReference { public: diff --git a/src/bluetooth/darwin/btrfcommchannel.mm b/src/bluetooth/darwin/btrfcommchannel.mm index 0cac3c6d..821944ec 100644 --- a/src/bluetooth/darwin/btrfcommchannel.mm +++ b/src/bluetooth/darwin/btrfcommchannel.mm @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "btrfcommchannel_p.h" #include "qbluetoothaddress.h" @@ -44,7 +8,7 @@ QT_USE_NAMESPACE -@implementation QT_MANGLE_NAMESPACE(DarwinBTRFCOMMChannel) +@implementation DarwinBTRFCOMMChannel { QT_PREPEND_NAMESPACE(DarwinBluetooth)::ChannelDelegate *delegate; IOBluetoothDevice *device; @@ -140,7 +104,7 @@ QT_USE_NAMESPACE - (void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel data:(void *)dataPointer length:(size_t)dataLength { - Q_UNUSED(rfcommChannel) + Q_UNUSED(rfcommChannel); Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)"); @@ -155,7 +119,7 @@ QT_USE_NAMESPACE - (void)rfcommChannelOpenComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel status:(IOReturn)error { - Q_UNUSED(rfcommChannel) + Q_UNUSED(rfcommChannel); Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)"); @@ -169,7 +133,7 @@ QT_USE_NAMESPACE - (void)rfcommChannelClosed:(IOBluetoothRFCOMMChannel*)rfcommChannel { - Q_UNUSED(rfcommChannel) + Q_UNUSED(rfcommChannel); Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)"); delegate->channelClosed(); @@ -178,19 +142,19 @@ QT_USE_NAMESPACE - (void)rfcommChannelControlSignalsChanged:(IOBluetoothRFCOMMChannel*)rfcommChannel { - Q_UNUSED(rfcommChannel) + Q_UNUSED(rfcommChannel); } - (void)rfcommChannelFlowControlChanged:(IOBluetoothRFCOMMChannel*)rfcommChannel { - Q_UNUSED(rfcommChannel) + Q_UNUSED(rfcommChannel); } - (void)rfcommChannelWriteComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel refcon:(void*)refcon status:(IOReturn)error { - Q_UNUSED(rfcommChannel) - Q_UNUSED(refcon) + Q_UNUSED(rfcommChannel); + Q_UNUSED(refcon); Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)"); @@ -202,7 +166,7 @@ QT_USE_NAMESPACE - (void)rfcommChannelQueueSpaceAvailable:(IOBluetoothRFCOMMChannel*)rfcommChannel { - Q_UNUSED(rfcommChannel) + Q_UNUSED(rfcommChannel); } - (BluetoothRFCOMMChannelID)getChannelID diff --git a/src/bluetooth/darwin/btrfcommchannel_p.h b/src/bluetooth/darwin/btrfcommchannel_p.h index 25299092..dd32c49a 100644 --- a/src/bluetooth/darwin/btrfcommchannel_p.h +++ b/src/bluetooth/darwin/btrfcommchannel_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTRFCOMMCHANNEL_P_H #define BTRFCOMMCHANNEL_P_H @@ -51,7 +15,8 @@ // We mean it. // -#include <QtCore/qglobal.h> +#include <QtCore/private/qglobal_p.h> +#include <QtCore/private/qcore_mac_p.h> #include <Foundation/Foundation.h> @@ -102,7 +67,8 @@ QT_END_NAMESPACE - (IOReturn) writeSync:(void*)data length:(UInt16)length; - (IOReturn) writeAsync:(void*)data length:(UInt16)length; - @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTRFCOMMChannel); + #endif diff --git a/src/bluetooth/darwin/btsdpinquiry.mm b/src/bluetooth/darwin/btsdpinquiry.mm index 468d5445..f3a235a6 100644 --- a/src/bluetooth/darwin/btsdpinquiry.mm +++ b/src/bluetooth/darwin/btsdpinquiry.mm @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qbluetoothserviceinfo.h" #include "btsdpinquiry_p.h" @@ -43,8 +7,12 @@ #include "btdelegates_p.h" #include "btutility_p.h" +#include <QtCore/qoperatingsystemversion.h> #include <QtCore/qvariant.h> #include <QtCore/qstring.h> +#include <QtCore/qtimer.h> + +#include <memory> QT_BEGIN_NAMESPACE @@ -52,6 +20,8 @@ namespace DarwinBluetooth { namespace { +const int basebandConnectTimeoutMS = 20000; + QBluetoothUuid sdp_element_to_uuid(IOBluetoothSDPDataElement *element) { QT_BT_MAC_AUTORELEASEPOOL; @@ -71,18 +41,27 @@ QBluetoothUuid extract_service_ID(IOBluetoothSDPServiceRecord *record) return sdp_element_to_uuid([record getAttributeDataElement:kBluetoothSDPAttributeIdentifierServiceID]); } -QVector<QBluetoothUuid> extract_service_class_ID_list(IOBluetoothSDPServiceRecord *record) +QList<QBluetoothUuid> extract_service_class_ID_list(IOBluetoothSDPServiceRecord *record) { Q_ASSERT(record); QT_BT_MAC_AUTORELEASEPOOL; IOBluetoothSDPDataElement *const idList = [record getAttributeDataElement:kBluetoothSDPAttributeIdentifierServiceClassIDList]; - if (!idList || [idList getTypeDescriptor] != kBluetoothSDPDataElementTypeDataElementSequence) - return {}; - QVector<QBluetoothUuid> uuids; - NSArray *const arr = [idList getArrayValue]; + QList<QBluetoothUuid> uuids; + if (!idList) + return uuids; + + NSArray *arr = nil; + if ([idList getTypeDescriptor] == kBluetoothSDPDataElementTypeDataElementSequence) + arr = [idList getArrayValue]; + else if ([idList getTypeDescriptor] == kBluetoothSDPDataElementTypeUUID) + arr = @[idList]; + + if (!arr) + return uuids; + for (IOBluetoothSDPDataElement *dataElement in arr) { const auto qtUuid = sdp_element_to_uuid(dataElement); if (!qtUuid.isNull()) @@ -92,7 +71,7 @@ QVector<QBluetoothUuid> extract_service_class_ID_list(IOBluetoothSDPServiceRecor return uuids; } -QBluetoothServiceInfo::Sequence service_class_ID_list_to_sequence(const QVector<QBluetoothUuid> &uuids) +QBluetoothServiceInfo::Sequence service_class_ID_list_to_sequence(const QList<QBluetoothUuid> &uuids) { if (uuids.isEmpty()) return {}; @@ -170,15 +149,15 @@ void extract_service_record(IOBluetoothSDPServiceRecord *record, QBluetoothServi if (!serviceUuid.isNull()) serviceInfo.setServiceUuid(serviceUuid); - const QVector<QBluetoothUuid> uuids(extract_service_class_ID_list(record)); + const QList<QBluetoothUuid> uuids(extract_service_class_ID_list(record)); const auto sequence = service_class_ID_list_to_sequence(uuids); if (!sequence.isEmpty()) serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, sequence); } -QVector<QBluetoothUuid> extract_services_uuids(IOBluetoothDevice *device) +QList<QBluetoothUuid> extract_services_uuids(IOBluetoothDevice *device) { - QVector<QBluetoothUuid> uuids; + QList<QBluetoothUuid> uuids; // All "temporary" obj-c objects are autoreleased. QT_BT_MAC_AUTORELEASEPOOL; @@ -192,7 +171,7 @@ QVector<QBluetoothUuid> extract_services_uuids(IOBluetoothDevice *device) if (!serviceID.isNull()) uuids.push_back(serviceID); - const QVector<QBluetoothUuid> idList(extract_service_class_ID_list(record)); + const QList<QBluetoothUuid> idList(extract_service_class_ID_list(record)); if (idList.size()) uuids.append(idList); } @@ -208,11 +187,14 @@ QT_USE_NAMESPACE using namespace DarwinBluetooth; -@implementation QT_MANGLE_NAMESPACE(DarwinBTSDPInquiry) +@implementation DarwinBTSDPInquiry { QT_PREPEND_NAMESPACE(DarwinBluetooth::SDPInquiryDelegate) *delegate; ObjCScopedPointer<IOBluetoothDevice> device; bool isActive; + + // Needed to workaround a broken SDP on Monterey: + std::unique_ptr<QTimer> connectionWatchdog; } - (id)initWithDelegate:(DarwinBluetooth::SDPInquiryDelegate *)aDelegate @@ -241,17 +223,40 @@ using namespace DarwinBluetooth; return [self performSDPQueryWithDevice:address filters:emptyFilter]; } +- (void)interruptSDPQuery +{ + // To be only executed on timer. + Q_ASSERT(connectionWatchdog.get()); + // If device was reset, so the timer should be, we can never be here then. + Q_ASSERT(device.get()); + + Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)"); + qCDebug(QT_BT_DARWIN) << "couldn't connect to device" << [device nameOrAddress] + << ", ending SDP inquiry."; + + // Stop the watchdog and close the connection as otherwise there could be + // later "connectionComplete" callbacks + connectionWatchdog->stop(); + [device closeConnection]; + + delegate->SDPInquiryError(device, kIOReturnTimeout); + device.reset(); + isActive = false; +} + - (IOReturn)performSDPQueryWithDevice:(const QBluetoothAddress &)address filters:(const QList<QBluetoothUuid> &)qtFilters { Q_ASSERT_X(!isActive, Q_FUNC_INFO, "SDP query in progress"); Q_ASSERT_X(!address.isNull(), Q_FUNC_INFO, "invalid target device address"); + qCDebug(QT_BT_DARWIN) << "Starting and SDP inquiry for address:" << address; QT_BT_MAC_AUTORELEASEPOOL; // We first try to allocate "filters": ObjCScopedPointer<NSMutableArray> array; - if (qtFilters.size()) { + if (QOperatingSystemVersion::current() <= QOperatingSystemVersion::MacOSBigSur + && qtFilters.size()) { // See the comment about filters on Monterey below. array.reset([[NSMutableArray alloc] init], RetainPolicy::noInitialRetain); if (!array) { qCCritical(QT_BT_DARWIN) << "failed to allocate an uuid filter"; @@ -264,7 +269,7 @@ using namespace DarwinBluetooth; [array addObject:uuid]; } - if (int([array count]) != qtFilters.size()) { + if (qsizetype([array count]) != qtFilters.size()) { qCCritical(QT_BT_DARWIN) << "failed to create an uuid filter"; return kIOReturnError; } @@ -276,8 +281,65 @@ using namespace DarwinBluetooth; qCCritical(QT_BT_DARWIN) << "failed to create an IOBluetoothDevice object"; return kIOReturnError; } + qCDebug(QT_BT_DARWIN) << "Device" << [device nameOrAddress] << "connected:" + << bool([device isConnected]) << "paired:" << bool([device isPaired]); IOReturn result = kIOReturnSuccess; + + if (QOperatingSystemVersion::current() > QOperatingSystemVersion::MacOSBigSur) { + // SDP query on Monterey does not follow its own documented/expected behavior: + // - a simple performSDPQuery was previously ensuring baseband connection + // to be opened, now it does not do so, instead logs a warning and returns + // immediately. + // - a version with UUID filters simply does nothing except it immediately + // returns kIOReturnSuccess. + + // If the device was not yet connected, connect it first + if (![device isConnected]) { + qCDebug(QT_BT_DARWIN) << "Device" << [device nameOrAddress] + << "is not connected, connecting it first"; + result = [device openConnection:self]; + // The connection may succeed immediately. But if it didn't, start a connection timer + // which has two guardian roles: + // 1. Guard against connect attempt taking too long time + // 2. Sometimes on Monterey the callback indicating "connection completion" is + // not received even though the connection has in fact succeeded + if (![device isConnected]) { + qCDebug(QT_BT_DARWIN) << "Starting connection monitor for device" + << [device nameOrAddress] << "with timeout limit of" + << basebandConnectTimeoutMS/1000 << "seconds."; + connectionWatchdog.reset(new QTimer); + connectionWatchdog->setSingleShot(false); + QObject::connect(connectionWatchdog.get(), &QTimer::timeout, + connectionWatchdog.get(), + [self] () { + qCDebug(QT_BT_DARWIN) << "Connection monitor timeout for device:" + << [device nameOrAddress] + << ", connected:" << bool([device isConnected]); + // Device can sometimes get properly connected without IOBluetooth + // calling the connectionComplete callback, so we check the status here + if ([device isConnected]) + [self connectionComplete:device status:kIOReturnSuccess]; + else + [self interruptSDPQuery]; + }); + connectionWatchdog->start(basebandConnectTimeoutMS); + } + } + + if ([device isConnected]) + result = [device performSDPQuery:self]; + + if (result != kIOReturnSuccess) { + qCCritical(QT_BT_DARWIN, "failed to start an SDP query"); + device.reset(); + } else { + isActive = true; + } + + return result; + } // Monterey's code path. + if (qtFilters.size()) result = [device performSDPQuery:self uuids:array]; else @@ -293,16 +355,45 @@ using namespace DarwinBluetooth; return result; } +- (void)connectionComplete:(IOBluetoothDevice *)aDevice status:(IOReturn)status +{ + qCDebug(QT_BT_DARWIN) << "connectionComplete for device" << [aDevice nameOrAddress] + << "with status:" << status; + if (aDevice != device) { + // Connection was previously cancelled, probably, due to the timeout. + return; + } + + // The connectionComplete may be invoked by either the IOBluetooth callback or our + // connection watchdog. In either case stop the watchdog if it exists + if (connectionWatchdog) + connectionWatchdog->stop(); + + if (status == kIOReturnSuccess) + status = [aDevice performSDPQuery:self]; + + if (status != kIOReturnSuccess) { + isActive = false; + qCWarning(QT_BT_DARWIN, "failed to open connection or start an SDP query"); + Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)"); + delegate->SDPInquiryError(aDevice, status); + } +} + - (void)stopSDPQuery { - // There is no API to stop it, - // but there is a 'stop' member-function in Qt and - // after it's called sdpQueryComplete must be somehow ignored. + // There is no API to stop it SDP on device, but there is a 'stop' + // member-function in Qt and after it's called sdpQueryComplete + // must be somehow ignored (device != aDevice in a callback). device.reset(); + isActive = false; + connectionWatchdog.reset(); } - (void)sdpQueryComplete:(IOBluetoothDevice *)aDevice status:(IOReturn)status { + qCDebug(QT_BT_DARWIN) << "sdpQueryComplete for device:" << [aDevice nameOrAddress] + << "with status:" << status; // Can happen - there is no legal way to cancel an SDP query, // after the 'reset' device can never be // the same as the cancelled one. @@ -313,6 +404,15 @@ using namespace DarwinBluetooth; isActive = false; + // If we used the manual connection establishment, close the + // connection here. Otherwise the IOBluetooth may call stray + // connectionComplete or sdpQueryCompletes + if (connectionWatchdog) { + qCDebug(QT_BT_DARWIN) << "Closing the connection established for SDP inquiry."; + connectionWatchdog.reset(); + [device closeConnection]; + } + if (status != kIOReturnSuccess) delegate->SDPInquiryError(aDevice, status); else diff --git a/src/bluetooth/darwin/btsdpinquiry_p.h b/src/bluetooth/darwin/btsdpinquiry_p.h index 6cce5703..74d7c850 100644 --- a/src/bluetooth/darwin/btsdpinquiry_p.h +++ b/src/bluetooth/darwin/btsdpinquiry_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTSDPINQUIRY_H #define BTSDPINQUIRY_H @@ -54,9 +18,9 @@ #include "qbluetoothaddress.h" #include "qbluetoothuuid.h" -#include <QtCore/qglobal.h> +#include <QtCore/private/qglobal_p.h> +#include <QtCore/private/qcore_mac_p.h> #include <QtCore/qlist.h> -#include <QtCore/qvector.h> #include <Foundation/Foundation.h> @@ -75,7 +39,7 @@ class SDPInquiryDelegate; void extract_service_record(IOBluetoothSDPServiceRecord *record, QBluetoothServiceInfo &serviceInfo); QVariant extract_attribute_value(IOBluetoothSDPDataElement *dataElement); -QVector<QBluetoothUuid> extract_services_uuids(IOBluetoothDevice *device); +QList<QBluetoothUuid> extract_services_uuids(IOBluetoothDevice *device); } // namespace DarwinBluetooth @@ -96,4 +60,6 @@ QT_END_NAMESPACE @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTSDPInquiry); + #endif diff --git a/src/bluetooth/darwin/btservicerecord.mm b/src/bluetooth/darwin/btservicerecord.mm index dd711504..5c2e5184 100644 --- a/src/bluetooth/darwin/btservicerecord.mm +++ b/src/bluetooth/darwin/btservicerecord.mm @@ -1,48 +1,11 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qbluetoothserviceinfo.h" #include "btservicerecord_p.h" #include <QtCore/qvariant.h> #include <QtCore/qdebug.h> -#include <QtCore/qmap.h> #include <QtCore/qurl.h> #include <IOBluetooth/IOBluetooth.h> @@ -79,7 +42,7 @@ QBluetoothUuid profile_uuid(const QBluetoothServiceInfo &serviceInfo) if (var.isValid()) { const Sequence seq(var.value<Sequence>()); - for (int i = 0; i < seq.count(); ++i) { + for (qsizetype i = 0; i < seq.size(); ++i) { QBluetoothUuid uuid(seq.at(i).value<QBluetoothUuid>()); if (uuid.isNull()) continue; @@ -147,7 +110,7 @@ void add_attribute(const QVariant &var, AttributeId key, Dictionary dict) return; const Number num(variant_to_nsnumber<ValueType>(var)); - [dict setObject:num forKey:[NSString stringWithFormat:@"%d", int(key)]]; + [dict setObject:num forKey:[NSString stringWithFormat:@"%x", int(key)]]; } template<> @@ -159,9 +122,9 @@ void add_attribute<QString>(const QVariant &var, AttributeId key, Dictionary dic return; const QString string(var.value<QString>()); - if (string.length()) { + if (!string.isEmpty()) { if (NSString *const nsString = string.toNSString()) - [dict setObject:nsString forKey:[NSString stringWithFormat:@"%d", int(key)]]; + [dict setObject:nsString forKey:[NSString stringWithFormat:@"%x", int(key)]]; } } @@ -174,7 +137,7 @@ void add_attribute<QBluetoothUuid>(const QVariant &var, AttributeId key, Diction return; SDPUUid ioUUID(iobluetooth_uuid(var.value<QBluetoothUuid>())); - [dict setObject:ioUUID forKey:[NSString stringWithFormat:@"%d", int(key)]]; + [dict setObject:ioUUID forKey:[NSString stringWithFormat:@"%x", int(key)]]; } template<> @@ -185,9 +148,9 @@ void add_attribute<QUrl>(const QVariant &var, AttributeId key, Dictionary dict) if (!var.canConvert<QUrl>()) return; - Q_UNUSED(var) - Q_UNUSED(key) - Q_UNUSED(dict) + Q_UNUSED(var); + Q_UNUSED(key); + Q_UNUSED(dict); // TODO: not clear how should I pass an url in a dictionary, NSURL does not work. } @@ -208,6 +171,25 @@ void add_attribute(const QVariant &var, NSMutableArray *list) } template<> +void add_attribute<unsigned short>(const QVariant &var, NSMutableArray *list) +{ + Q_ASSERT_X(list, Q_FUNC_INFO, "invalid list (nil)"); + + if (!var.canConvert<unsigned short>()) + return; + + const Number num(variant_to_nsnumber<unsigned short>(var)); + + NSDictionary* dict = @{ + @"DataElementType" : [NSNumber numberWithInt:1], + @"DataElementSize" : [NSNumber numberWithInt:2], + @"DataElementValue" : num + }; + + [list addObject: dict]; +} + +template<> void add_attribute<QString>(const QVariant &var, NSMutableArray *list) { Q_ASSERT_X(list, Q_FUNC_INFO, "invalid list (nil)"); @@ -216,7 +198,7 @@ void add_attribute<QString>(const QVariant &var, NSMutableArray *list) return; const QString string(var.value<QString>()); - if (string.length()) { + if (!string.isEmpty()) { if (NSString *const nsString = string.toNSString()) [list addObject:nsString]; } @@ -242,8 +224,8 @@ void add_attribute<QUrl>(const QVariant &var, NSMutableArray *list) if (!var.canConvert<QUrl>()) return; - Q_UNUSED(var) - Q_UNUSED(list) + Q_UNUSED(var); + Q_UNUSED(list); // TODO: not clear how should I pass an url in a dictionary, NSURL does not work. } @@ -274,7 +256,7 @@ void add_rfcomm_protocol_descriptor_list(uint16 channelID, Dictionary dict) [rfcommList addObject:rfcommDict]; [descriptorList addObject:rfcommList]; - [dict setObject:descriptorList forKey:[NSString stringWithFormat:@"%d", + [dict setObject:descriptorList forKey:[NSString stringWithFormat:@"%x", kBluetoothSDPAttributeIdentifierProtocolDescriptorList]]; } @@ -300,7 +282,7 @@ void add_l2cap_protocol_descriptor_list(uint16 psm, Dictionary dict) [l2capList addObject:l2capDict]; [descriptorList addObject:l2capList]; - [dict setObject:descriptorList forKey:[NSString stringWithFormat:@"%d", + [dict setObject:descriptorList forKey:[NSString stringWithFormat:@"%x", kBluetoothSDPAttributeIdentifierProtocolDescriptorList]]; } @@ -311,10 +293,10 @@ bool add_attribute(const QVariant &var, AttributeId key, NSMutableArray *list) if (var.canConvert<Sequence>()) return false; - if (var.canConvert<QString>()) { + if (var.typeId() == QMetaType::QString) { //ServiceName, ServiceDescription, ServiceProvider. add_attribute<QString>(var, list); - } else if (var.canConvert<QBluetoothUuid>()) { + } else if (var.userType() == qMetaTypeId<QBluetoothUuid>()) { add_attribute<QBluetoothUuid>(var, list); } else { // Here we need 'key' to understand the type. @@ -326,6 +308,9 @@ bool add_attribute(const QVariant &var, AttributeId key, NSMutableArray *list) case QSInfo::ServiceInfoTimeToLive: add_attribute<unsigned>(var, list); break; + case QSInfo::BluetoothProfileDescriptorList: + add_attribute<unsigned short>(var, list); + break; case QSInfo::ServiceAvailability: add_attribute<unsigned char>(var, list); break; @@ -349,10 +334,10 @@ bool add_attribute(const QBluetoothServiceInfo &serviceInfo, AttributeId key, Di if (var.canConvert<Sequence>()) return false; - if (var.canConvert<QString>()) { + if (var.typeId() == QMetaType::QString) { //ServiceName, ServiceDescription, ServiceProvider. add_attribute<QString>(var, key, dict); - } else if (var.canConvert<QBluetoothUuid>()) { + } else if (var.userType() == qMetaTypeId<QBluetoothUuid>()) { add_attribute<QBluetoothUuid>(serviceInfo.attribute(key), key, dict); } else { // We can have different integer types actually, so I have to check @@ -386,14 +371,15 @@ bool add_sequence_attribute(const QVariant &var, AttributeId key, NSMutableArray if (var.isNull() || !var.canConvert<Sequence>()) return false; + NSMutableArray *const nested = [NSMutableArray array]; + [list addObject:nested]; + const Sequence sequence(var.value<Sequence>()); for (const QVariant &var : sequence) { if (var.canConvert<Sequence>()) { - NSMutableArray *const nested = [NSMutableArray array]; add_sequence_attribute(var, key, nested); - [list addObject:nested]; } else { - add_attribute(var, key, list); + add_attribute(var, key, nested); } } @@ -416,8 +402,7 @@ bool add_sequence_attribute(const QBluetoothServiceInfo &serviceInfo, AttributeI if (!add_sequence_attribute(element, key, list)) add_attribute(element, key, list); } - [dict setObject:list forKey:[NSString stringWithFormat:@"%d", int(key)]]; - + [dict setObject:list forKey:[NSString stringWithFormat:@"%x", int(key)]]; return true; } diff --git a/src/bluetooth/darwin/btservicerecord_p.h b/src/bluetooth/darwin/btservicerecord_p.h index 6b5b0374..fc882d91 100644 --- a/src/bluetooth/darwin/btservicerecord_p.h +++ b/src/bluetooth/darwin/btservicerecord_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTSERVICERECORD_P_H #define BTSERVICERECORD_P_H diff --git a/src/bluetooth/darwin/btsocketlistener.mm b/src/bluetooth/darwin/btsocketlistener.mm index 505fec14..073e8944 100644 --- a/src/bluetooth/darwin/btsocketlistener.mm +++ b/src/bluetooth/darwin/btsocketlistener.mm @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "btsocketlistener_p.h" #include "btdelegates_p.h" @@ -45,7 +9,7 @@ QT_USE_NAMESPACE -@implementation QT_MANGLE_NAMESPACE(DarwinBTSocketListener) +@implementation DarwinBTSocketListener { IOBluetoothUserNotification *connectionNotification; QT_PREPEND_NAMESPACE(DarwinBluetooth::SocketListener) *delegate; @@ -105,7 +69,7 @@ QT_USE_NAMESPACE - (void)rfcommOpenNotification:(IOBluetoothUserNotification *)notification channel:(IOBluetoothRFCOMMChannel *)newChannel { - Q_UNUSED(notification) + Q_UNUSED(notification); Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)"); delegate->openNotifyRFCOMM(newChannel); @@ -114,7 +78,7 @@ QT_USE_NAMESPACE - (void)l2capOpenNotification:(IOBluetoothUserNotification *)notification channel:(IOBluetoothL2CAPChannel *)newChannel { - Q_UNUSED(notification) + Q_UNUSED(notification); Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)"); delegate->openNotifyL2CAP(newChannel); diff --git a/src/bluetooth/darwin/btsocketlistener_p.h b/src/bluetooth/darwin/btsocketlistener_p.h index 4b9b267a..82950ec2 100644 --- a/src/bluetooth/darwin/btsocketlistener_p.h +++ b/src/bluetooth/darwin/btsocketlistener_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTSOCKETLISTENER_P_H #define BTSOCKETLISTENER_P_H @@ -51,7 +15,8 @@ // We mean it. // -#include <QtCore/qglobal.h> +#include <QtCore/private/qglobal_p.h> +#include <QtCore/private/qcore_mac_p.h> #include <Foundation/Foundation.h> @@ -88,4 +53,6 @@ QT_END_NAMESPACE @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTSocketListener); + #endif diff --git a/src/bluetooth/darwin/btutility.mm b/src/bluetooth/darwin/btutility.mm index 07c22c1c..e9f2156f 100644 --- a/src/bluetooth/darwin/btutility.mm +++ b/src/bluetooth/darwin/btutility.mm @@ -1,47 +1,12 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qlowenergycharacteristicdata.h" #include "qbluetoothaddress.h" -#include "btutility_p.h" #include "qbluetoothuuid.h" +#include "btutility_p.h" +#include <QtCore/qoperatingsystemversion.h> #include <QtCore/qendian.h> #include <QtCore/qstring.h> @@ -62,10 +27,12 @@ Q_LOGGING_CATEGORY(QT_BT_DARWIN, "qt.bluetooth.darwin") namespace DarwinBluetooth { -const int defaultLEScanTimeoutMS = 25000; +const int defaultLEScanTimeoutMS = 40000; // We use it only on iOS for now: const int maxValueLength = 512; +const int defaultMtu = 23; + QString qt_address(NSString *address) { if (address && address.length) { @@ -114,7 +81,7 @@ BluetoothDeviceAddress iobluetooth_address(const QBluetoothAddress &qAddress) ObjCStrongReference<IOBluetoothSDPUUID> iobluetooth_uuid(const QBluetoothUuid &uuid) { const unsigned nBytes = 128 / std::numeric_limits<unsigned char>::digits; - const quint128 intVal(uuid.toUInt128()); + const QUuid::Id128Bytes intVal(uuid.toBytes()); const ObjCStrongReference<IOBluetoothSDPUUID> iobtUUID([IOBluetoothSDPUUID uuidWithBytes:intVal.data length:nBytes], RetainPolicy::doInitialRetain); @@ -128,7 +95,7 @@ QBluetoothUuid qt_uuid(IOBluetoothSDPUUID *uuid) return qtUuid; // TODO: ensure the correct byte-order!!! - quint128 uuidVal = {}; + QUuid::Id128Bytes uuidVal = {}; const quint8 *const source = static_cast<const quint8 *>([uuid bytes]); std::copy(source, source + 16, uuidVal.data); return QBluetoothUuid(uuidVal); @@ -169,7 +136,6 @@ void qt_test_iobluetooth_runloop() #endif // !QT_IOS_BLUETOOTH - // Apple has: CBUUID, NSUUID, CFUUID, IOBluetoothSDPUUID // and it's handy to have several converters: @@ -177,8 +143,7 @@ QBluetoothUuid qt_uuid(CBUUID *uuid) { // Apples' docs say "128 bit" and "16-bit UUIDs are implicitly // pre-filled with the Bluetooth Base UUID." - // But Core Bluetooth can return CBUUID objects of length 2 - // (16-bit, so they are not pre-filled?). + // But Core Bluetooth can return CBUUID objects of length 2, 4, and 16. if (!uuid) return QBluetoothUuid(); @@ -190,40 +155,35 @@ QBluetoothUuid qt_uuid(CBUUID *uuid) // Seems to be in big-endian. const uchar *const src = static_cast<const uchar *>(uuid.data.bytes); return QBluetoothUuid(qFromBigEndian<quint16>(src)); + } else if (uuid.data.length == 4) { + const uchar *const src = static_cast<const uchar *>(uuid.data.bytes); + return QBluetoothUuid(qFromBigEndian<quint32>(src)); } else if (uuid.data.length == 16) { - quint128 qtUuidData = {}; + QUuid::Id128Bytes qtUuidData = {}; const quint8 *const source = static_cast<const quint8 *>(uuid.data.bytes); std::copy(source, source + 16, qtUuidData.data); return QBluetoothUuid(qtUuidData); } - qCDebug(QT_BT_DARWIN) << "qt_uuid, invalid CBUUID, 2 or 16 bytes expected, but got " + qCDebug(QT_BT_DARWIN) << "qt_uuid, invalid CBUUID, 2, 4, or 16 bytes expected, but got " << uuid.data.length << " bytes length"; return QBluetoothUuid(); } -QCFType<CFUUIDRef> cf_uuid(const QBluetoothUuid &qtUuid) -{ - const quint128 qtUuidData = qtUuid.toUInt128(); - const quint8 *const data = qtUuidData.data; - - CFUUIDBytes bytes = {data[0], data[1], data[2], data[3], - data[4], data[5], data[6], data[7], - data[8], data[9], data[10], data[11], - data[12], data[13], data[14], data[15]}; - - CFUUIDRef cfUuid = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, bytes); - return cfUuid; -} - ObjCStrongReference<CBUUID> cb_uuid(const QBluetoothUuid &qtUuid) { - QCFType<CFUUIDRef> cfUuid(cf_uuid(qtUuid)); - if (!cfUuid) - return ObjCStrongReference<CBUUID>(); + bool ok = false; + const auto asUInt16 = qToBigEndian(qtUuid.toUInt16(&ok)); + const auto asUInt128 = qtUuid.toBytes(); + + const NSUInteger length = ok ? sizeof asUInt16 : sizeof asUInt128; + const void *bytes = &asUInt128; + if (ok) + bytes = &asUInt16; - ObjCStrongReference<CBUUID> cbUuid([CBUUID UUIDWithCFUUID:cfUuid], RetainPolicy::doInitialRetain); + NSData *uuidData = [NSData dataWithBytes:bytes length:length]; + ObjCStrongReference<CBUUID> cbUuid([CBUUID UUIDWithData:uuidData], RetainPolicy::doInitialRetain); return cbUuid; } diff --git a/src/bluetooth/darwin/btutility_p.h b/src/bluetooth/darwin/btutility_p.h index b65544e2..87f4a719 100644 --- a/src/bluetooth/darwin/btutility_p.h +++ b/src/bluetooth/darwin/btutility_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef BTUTILITY_P_H #define BTUTILITY_P_H @@ -71,6 +35,7 @@ QT_BEGIN_NAMESPACE class QLowEnergyCharacteristicData; class QBluetoothAddress; class QBluetoothUuid; +class QString; namespace DarwinBluetooth { @@ -156,6 +121,7 @@ dispatch_queue_t qt_LE_queue(); extern const int defaultLEScanTimeoutMS; extern const int maxValueLength; +extern const int defaultMtu; } // namespace DarwinBluetooth @@ -163,23 +129,4 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_DARWIN) QT_END_NAMESPACE -#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(101300) && QT_MACOS_DEPLOYMENT_TARGET_BELOW(101300) - - // In the macOS 10.13 SDK, the identifier property was moved from the CBPeripheral - // and CBCentral classes to a new CBPeer base class. Because CBPeer is only available - // on macOS 10.13 and above, the same is true for -[CBPeer identifier]. However, - // since we know that the derived classes have always had this property, - // we'll explicitly mark its availability here. This will not adversely affect - // using the identifier through the CBPeer base class, which will still require macOS 10.13. - -@interface CBPeripheral (UnguardedWorkaround) -@property (readonly, nonatomic) NSUUID *identifier NS_AVAILABLE(10_7, 5_0); -@end - -@interface CBCentral (UnguardedWorkaround) -@property (readonly, nonatomic) NSUUID *identifier NS_AVAILABLE(10_7, 5_0); -@end - -#endif // QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE - #endif // BTUTILITY_P_H diff --git a/src/bluetooth/darwin/darwinbt.pri b/src/bluetooth/darwin/darwinbt.pri deleted file mode 100644 index b419007a..00000000 --- a/src/bluetooth/darwin/darwinbt.pri +++ /dev/null @@ -1,48 +0,0 @@ -SOURCES += darwin/uistrings.cpp \ - darwin/btnotifier.cpp \ - darwin/btdelegates.cpp \ - darwin/btledeviceinquiry.mm \ - darwin/btcentralmanager.mm - -HEADERS += darwin/uistrings_p.h \ - darwin/btgcdtimer_p.h \ - darwin/btraii_p.h \ - darwin/btdelegates_p.h \ - darwin/btutility_p.h \ - darwin/btledeviceinquiry_p.h \ - darwin/btcentralmanager_p.h \ - darwin/btnotifier_p.h - -OBJECTIVE_SOURCES += darwin/btgcdtimer.mm \ - darwin/btraii.mm \ - darwin/btutility.mm - -#QMAKE_CXXFLAGS_WARN_ON += -Wno-nullability-completeness - -macos { - HEADERS += darwin/btdevicepair_p.h \ - darwin/btdeviceinquiry_p.h \ - darwin/btconnectionmonitor_p.h \ - darwin/btsdpinquiry_p.h \ - darwin/btrfcommchannel_p.h \ - darwin/btl2capchannel_p.h \ - darwin/btservicerecord_p.h \ - darwin/btsocketlistener_p.h \ - darwin/btobexsession_p.h - - OBJECTIVE_SOURCES += darwin/btdevicepair.mm \ - darwin/btdeviceinquiry.mm \ - darwin/btconnectionmonitor.mm \ - darwin/btsdpinquiry.mm \ - darwin/btrfcommchannel.mm \ - darwin/btl2capchannel.mm \ - darwin/btservicerecord.mm \ - darwin/btsocketlistener.mm \ - darwin/btobexsession.mm -} - -macos | ios { - HEADERS += darwin/btperipheralmanager_p.h - - OBJECTIVE_SOURCES += darwin/btperipheralmanager.mm -} diff --git a/src/bluetooth/darwin/uistrings.cpp b/src/bluetooth/darwin/uistrings.cpp index 7260417f..9f93b23c 100644 --- a/src/bluetooth/darwin/uistrings.cpp +++ b/src/bluetooth/darwin/uistrings.cpp @@ -1,44 +1,10 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "uistrings_p.h" +#include <qttranslation.h> + // Translatable messages should go into this .cpp file for them to // be picked up by lupdate. @@ -50,6 +16,7 @@ const char DD_INVALID_ADAPTER[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAg const char DD_IO[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAgent", "Input Output Error"); const char DD_NOTSUPPORTED[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAgent", "Bluetooth LE is not supported"); const char DD_UNKNOWN_ERROR[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAgent", "Unknown error"); +const char DD_MISSING_PERMISSION[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAgent", "Missing permission"); const char DD_NOT_STARTED[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAgent", "Cannot start device inquiry"); const char DD_NOT_STARTED_LE[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAgent", "Cannot start low energy device inquiry"); const char DD_NOT_STOPPED[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAgent", "Discovery cannot be stopped"); @@ -84,5 +51,6 @@ const char LEC_RDEV_NO_FOUND[] = QT_TRANSLATE_NOOP("QLowEnergyController", "Remo const char LEC_NO_LOCAL_DEV[] = QT_TRANSLATE_NOOP("QLowEnergyController", "Cannot find local adapter"); const char LEC_IO_ERROR[] = QT_TRANSLATE_NOOP("QLowEnergyController", "Error occurred during connection I/O"); const char LEC_UNKNOWN_ERROR[] = QT_TRANSLATE_NOOP("QLowEnergyController", "Unknown Error"); +const char LEC_MISSING_PERMISSION[] = QT_TRANSLATE_NOOP("QLowEnergyController", "Missing permission"); QT_END_NAMESPACE diff --git a/src/bluetooth/darwin/uistrings_p.h b/src/bluetooth/darwin/uistrings_p.h index 999a8c6d..11cfb24f 100644 --- a/src/bluetooth/darwin/uistrings_p.h +++ b/src/bluetooth/darwin/uistrings_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef TRANSLATIONS_H #define TRANSLATIONS_H @@ -51,8 +15,9 @@ // We mean it. // -#include <QtCore/QCoreApplication> -#include <QtCore/QString> +#include <QtCore/qglobal.h> + +#include <QtCore/private/qglobal_p.h> QT_BEGIN_NAMESPACE @@ -63,6 +28,7 @@ extern const char DD_INVALID_ADAPTER[]; extern const char DD_IO[]; extern const char DD_NOTSUPPORTED[]; extern const char DD_UNKNOWN_ERROR[]; +extern const char DD_MISSING_PERMISSION[]; extern const char DD_NOT_STARTED[]; extern const char DD_NOT_STARTED_LE[]; extern const char DD_NOT_STOPPED[]; @@ -101,6 +67,7 @@ extern const char LEC_RDEV_NO_FOUND[]; extern const char LEC_NO_LOCAL_DEV[]; extern const char LEC_IO_ERROR[]; extern const char LEC_UNKNOWN_ERROR[]; +extern const char LEC_MISSING_PERMISSION[]; QT_END_NAMESPACE |