13#include <IOBluetooth/IOBluetooth.h>
26#include <QtCore/qloggingcategory.h>
27#include <QtCore/qcoreapplication.h>
28#include <QtCore/qpermissions.h>
29#include <QtCore/qvector.h>
30#include <QtCore/qglobal.h>
31#include <QtCore/qstring.h>
32#include <QtCore/qdebug.h>
34#include <Foundation/Foundation.h>
36#include <CoreBluetooth/CoreBluetooth.h>
45 static bool initDone =
false;
47 qRegisterMetaType<QBluetoothDeviceInfo>();
48 qRegisterMetaType<QBluetoothDeviceDiscoveryAgent::Error>();
57 adapterAddress(adapter),
58 agentState(NonActive),
74 if (inquiryLE && agentState != NonActive) {
79 dispatch_sync(leQueue, ^{
94 return agentState != NonActive;
107 IOBluetoothHostController *hostController = [IOBluetoothHostController defaultController];
108 if (!hostController) {
109 qCWarning(QT_BT_DARWIN) <<
"No default Bluetooth controller found";
113 }
else if ([hostController powerState] != kBluetoothHCIPowerStateON) {
114 qCWarning(QT_BT_DARWIN) <<
"Default Bluetooth controller is OFF";
118 }
else if (!adapterAddress.isNull()) {
120 NSString *
const hciAddress = [hostController addressAsString];
122 qCWarning(QT_BT_DARWIN) <<
"Provided address" << adapterAddress
123 <<
"does not match with adapter:" << hciAddress;
143 "Use of Bluetooth LE requires explicitly requested permissions.");
162 agentState = NonActive;
163 discoveredDevices.
clear();
167 return startClassic();
175void QBluetoothDeviceDiscoveryAgentPrivate::startClassic()
190 qCCritical(QT_BT_DARWIN) <<
"failed to initialize an Classic device inquiry";
198 agentState = ClassicScan;
201 if (
res != kIOReturnSuccess) {
203 agentState = NonActive;
210void QBluetoothDeviceDiscoveryAgentPrivate::startLE()
217 std::unique_ptr<LECBManagerNotifier>
notifier = std::make_unique<LECBManagerNotifier>();
221 this, &QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError);
223 this, &QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported);
225 this, &QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished);
228 this, DeviceMemFunPtr(&QBluetoothDeviceDiscoveryAgentPrivate::deviceFound));
237 if (!leQueue || !inquiryLE) {
240 agentState = NonActive;
249 dispatch_async(leQueue, ^{
250 [inq startWithTimeout:lowEnergySearchTimeout];
258 Q_FUNC_INFO,
"called with invalid bluetooth adapter");
262 const bool prevStart = startPending;
263 startPending =
false;
269 if (agentState == ClassicScan) {
271 if (
res != kIOReturnSuccess) {
272 qCWarning(QT_BT_DARWIN) <<
"failed to stop";
273 startPending = prevStart;
287 dispatch_sync(leQueue, ^{
298void QBluetoothDeviceDiscoveryAgentPrivate::inquiryFinished()
302 agentState = NonActive;
304 if (stopPending && !startPending) {
307 }
else if (startPending) {
308 startPending =
false;
310 start(requestedMethods);
324void QBluetoothDeviceDiscoveryAgentPrivate::error(IOReturn
error)
326 startPending =
false;
334void QBluetoothDeviceDiscoveryAgentPrivate::classicDeviceFound(
void *
obj)
336 auto device =
static_cast<IOBluetoothDevice *
>(
obj);
340 "invalid agent state (expected classic scan)");
346 if (deviceAddress.isNull()) {
347 qCWarning(QT_BT_DARWIN) <<
"invalid Bluetooth address";
355 const auto classOfDevice =
qint32(
device.classOfDevice);
359 deviceInfo.setRssi(
device.RSSI);
362 deviceInfo.setServiceUuids(uuids);
364 deviceFound(deviceInfo);
367void QBluetoothDeviceDiscoveryAgentPrivate::setError(IOReturn
error,
const QString &
text)
369 if (
error == kIOReturnSuccess)
371 else if (
error == kIOReturnNoPower)
420 startPending =
false;
422 agentState = NonActive;
427void QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported()
429 qCDebug(QT_BT_DARWIN) <<
"no Bluetooth LE support";
444 startPending =
false;
451void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished()
454 agentState = NonActive;
457 if (stopPending && !startPending) {
460 }
else if (startPending) {
461 startPending =
false;
463 start(requestedMethods);
469void QBluetoothDeviceDiscoveryAgentPrivate::deviceFound(
const QBluetoothDeviceInfo &newDeviceInfo)
484 if (discoveredDevices[
i].
rssi() != newDeviceInfo.
rssi()) {
485 qCDebug(QT_BT_DARWIN) <<
"Updating RSSI for" << newDeviceInfo.
address()
486 << newDeviceInfo.
rssi();
487 discoveredDevices[
i].setRssi(newDeviceInfo.
rssi());
491 if (discoveredDevices[
i].manufacturerData() != newDeviceInfo.
manufacturerData()) {
492 qCDebug(QT_BT_DARWIN) <<
"Updating manufacturer data for" << newDeviceInfo.
address();
495 discoveredDevices[
i].setManufacturerData(
key, newDeviceInfo.manufacturerData(
key));
499 if (discoveredDevices[
i].serviceData() != newDeviceInfo.
serviceData()) {
500 qCDebug(QT_BT_DARWIN) <<
"Updating service data for" << newDeviceInfo.
address();
503 discoveredDevices[
i].setServiceData(
key, newDeviceInfo.serviceData(
key));
507 if (lowEnergySearchTimeout > 0) {
508 if (discoveredDevices[
i] != newDeviceInfo) {
509 discoveredDevices.
replace(
i, newDeviceInfo);
519 discoveredDevices.
replace(
i, newDeviceInfo);
530 if (discoveredDevices[
i] == newDeviceInfo)
533 discoveredDevices.
replace(
i, newDeviceInfo);
543 discoveredDevices.
append(newDeviceInfo);
550 return ClassicMethod | LowEnergyMethod;
552 return LowEnergyMethod;
static JNINativeMethod methods[]
QBluetoothUuid deviceUuid
DarwinBluetooth::LECBManagerNotifier * notifier
IOBluetoothDevice * device
#define QT_BT_MAC_AUTORELEASEPOOL
~QBluetoothDeviceDiscoveryAgentPrivate()
void start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress &deviceAdapter, QBluetoothDeviceDiscoveryAgent *parent)
static DiscoveryMethods supportedDiscoveryMethods()
This function returns the discovery methods supported by the current platform.
void errorOccurred(QBluetoothDeviceDiscoveryAgent::Error error)
This signal is emitted when an error occurs during Bluetooth device discovery.
void canceled()
This signal is emitted when device discovery is aborted by a call to stop().
void finished()
This signal is emitted when Bluetooth device discovery completes.
void deviceUpdated(const QBluetoothDeviceInfo &info, QBluetoothDeviceInfo::Fields updatedFields)
This signal is emitted when the agent receives additional information about the Bluetooth device desc...
void deviceDiscovered(const QBluetoothDeviceInfo &info)
This signal is emitted when the Bluetooth device described by info is discovered.
Error
Indicates all possible error conditions found during Bluetooth device discovery.
@ MissingPermissionsError
@ UnsupportedPlatformError
@ InvalidBluetoothAdapterError
@ UnsupportedDiscoveryMethod
QList< QBluetoothUuid > serviceIds() const
Returns all service data IDs from advertisement packets attached to this device information.
@ LowEnergyCoreConfiguration
@ BaseRateCoreConfiguration
QBluetoothAddress address() const
Returns the address of the device.
QByteArray manufacturerData(quint16 manufacturerId) const
Returns the data associated with the given manufacturerId.
QBluetoothDeviceInfo::CoreConfigurations coreConfigurations() const
Returns the configuration of the device.
QList< quint16 > manufacturerIds() const
Returns all manufacturer IDs from advertisement packets attached to this device information.
QBluetoothUuid deviceUuid() const
Returns a unique identifier for a Bluetooth device without an address.
QByteArray serviceData(const QBluetoothUuid &serviceId) const
Returns the data associated with the given serviceId.
qint16 rssi() const
Returns the signal strength when the device was last scanned.
Access Bluetooth peripherals.
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
qsizetype size() const noexcept
void replace(qsizetype i, parameter_type t)
void append(parameter_type t)
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
\macro QT_RESTRICTED_CAST_FROM_ASCII
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
quint64 getAddress(const unsigned char *&s, const ElfData &context)
QList< QBluetoothUuid > extract_services_uuids(IOBluetoothDevice *device)
const int defaultLEScanTimeoutMS
QString qt_address(NSString *address)
void qt_test_iobluetooth_runloop()
dispatch_queue_t qt_LE_queue()
Combined button and popup list for selecting options.
void registerQDeviceDiscoveryMetaType()
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError * error
static QDBusError::ErrorType get(const char *name)
#define qCCritical(category,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLuint GLuint64EXT address
GLdouble GLdouble GLdouble GLdouble q
static void setError(QJsonObject *response, const QString &msg)
#define Q_ASSERT_X(cond, x, msg)
const char DD_NOT_STOPPED[]
const char DD_NOT_STARTED[]
const char DD_POWERED_OFF[]
const char DD_NOT_STARTED_LE[]
const char DD_NOTSUPPORTED[]
const char DD_UNKNOWN_ERROR[]
QT_BEGIN_NAMESPACE const char DEV_DISCOVERY[]
const char DD_INVALID_ADAPTER[]
const char DD_MISSING_PERMISSION[]