6#include <QtBluetooth/QBluetoothHostInfo>
7#include <QtBluetooth/QBluetoothUuid>
8#include <QtConcurrent/QtConcurrentRun>
9#include <QtCore/QCoreApplication>
10#include <QtCore/QPermissions>
11#include <QtCore/QTimer>
12#include <QtCore/QVariantMap>
22 qCDebug(BluetoothConfigurationLog) <<
this;
28 , _device(copy->device())
29 , _connectedRssi(copy->connectedRssi())
30 , _serviceUuid(copy->_serviceUuid)
31 , _readCharacteristicUuid(copy->readCharacteristicUuid())
32 , _writeCharacteristicUuid(copy->writeCharacteristicUuid())
34 qCDebug(BluetoothConfigurationLog) <<
this;
41 if (_adapterWatcher) {
42 _adapterWatcher->cancel();
43 _adapterWatcher->waitForFinished();
46 qCDebug(BluetoothConfigurationLog) <<
this;
49bool BluetoothConfiguration::_createLocalDevice(
const QBluetoothAddress &address)
52 _localDevice->disconnect();
53 _localDevice->deleteLater();
54 _localDevice =
nullptr;
57 _localDevice =
new QBluetoothLocalDevice(
address,
this);
59 if (!_localDevice->isValid()) {
60 qCWarning(BluetoothConfigurationLog) <<
"Failed to initialize Bluetooth adapter:" <<
address.toString();
61 _localDevice->deleteLater();
62 _localDevice =
nullptr;
66 _connectLocalDeviceSignals();
68 qCDebug(BluetoothConfigurationLog) <<
"Initialized Bluetooth adapter:" << _localDevice->name() << _localDevice->address().toString();
73void BluetoothConfiguration::_connectLocalDeviceSignals()
75 if (!_localDevice || !_localDevice->isValid()) {
79 (void) connect(_localDevice.data(), &QBluetoothLocalDevice::hostModeStateChanged,
80 this, &BluetoothConfiguration::_onHostModeStateChanged);
81 (void) connect(_localDevice.data(), &QBluetoothLocalDevice::deviceConnected,
82 this, &BluetoothConfiguration::_onDeviceConnected);
83 (void) connect(_localDevice.data(), &QBluetoothLocalDevice::deviceDisconnected,
84 this, &BluetoothConfiguration::_onDeviceDisconnected);
85 (void) connect(_localDevice.data(), &QBluetoothLocalDevice::pairingFinished,
86 this, &BluetoothConfiguration::_onPairingFinished);
87 (void) connect(_localDevice.data(), &QBluetoothLocalDevice::errorOccurred,
88 this, &BluetoothConfiguration::_onLocalDeviceErrorOccurred);
91void BluetoothConfiguration::_initDeviceDiscoveryAgent()
93 if (!_deviceDiscoveryAgent) {
94 _deviceDiscoveryAgent =
new QBluetoothDeviceDiscoveryAgent(
this);
96 _deviceDiscoveryAgent->setLowEnergyDiscoveryTimeout(15000);
98 (void) connect(_deviceDiscoveryAgent.data(), &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
99 this, &BluetoothConfiguration::_deviceDiscovered);
100 (void) connect(_deviceDiscoveryAgent.data(), &QBluetoothDeviceDiscoveryAgent::canceled,
102 (void) connect(_deviceDiscoveryAgent.data(), &QBluetoothDeviceDiscoveryAgent::finished,
103 this, &BluetoothConfiguration::_onDiscoveryFinished);
104 (void) connect(_deviceDiscoveryAgent.data(), &QBluetoothDeviceDiscoveryAgent::errorOccurred,
105 this, &BluetoothConfiguration::_onDiscoveryErrorOccurred);
107 (void) connect(_deviceDiscoveryAgent.data(), &QBluetoothDeviceDiscoveryAgent::deviceUpdated,
108 this, &BluetoothConfiguration::_deviceUpdated);
112 if (!_availableAdapters.isEmpty()) {
113 const QVariantMap adapter = _availableAdapters.first().toMap();
114 const QBluetoothAddress
address(adapter.value(
"address").toString());
116 (void) _createLocalDevice(
address);
119 _refreshAvailableAdaptersAsync();
124void BluetoothConfiguration::_refreshAvailableAdaptersAsync()
126 if (_adapterEnumerationInProgress) {
130 _adapterEnumerationInProgress =
true;
132 if (!_adapterWatcher) {
133 _adapterWatcher =
new QFutureWatcher<QList<QBluetoothHostInfo>>(
this);
134 (void) connect(_adapterWatcher.data(), &QFutureWatcher<QList<QBluetoothHostInfo>>::finished,
this, [
this]() {
135 _adapterEnumerationInProgress =
false;
136 _updateAvailableAdapters(_adapterWatcher->future().result());
140 _adapterWatcher->setFuture(QtConcurrent::run([]() {
141 return QBluetoothLocalDevice::allDevices();
145void BluetoothConfiguration::_updateAvailableAdapters(
const QList<QBluetoothHostInfo> &hosts)
147 QVariantList adapters;
148 const QBluetoothAddress selectedAddress = (_localDevice && _localDevice->isValid())
149 ? _localDevice->address()
150 : QBluetoothAddress();
152 for (
const QBluetoothHostInfo &host : hosts) {
154 adapter[
"name"] = host.name();
155 adapter[
"address"] = host.address().toString();
156 adapter[
"selected"] = (!selectedAddress.isNull() && (host.address() == selectedAddress));
157 adapters.append(adapter);
160 if (_availableAdapters != adapters) {
161 _availableAdapters = adapters;
166bool BluetoothConfiguration::_ensureLocalDevice()
168 if (_localDevice && _localDevice->isValid()) {
173 for (
const QVariant &entry : std::as_const(_availableAdapters)) {
174 const QBluetoothAddress
address(entry.toMap().value(
"address").toString());
181 const QList<QBluetoothHostInfo> hosts = QBluetoothLocalDevice::allDevices();
182 if (!hosts.isEmpty()) {
183 _updateAvailableAdapters(hosts);
184 for (
const QBluetoothHostInfo &host : hosts) {
185 if (!host.address().isNull() && _createLocalDevice(host.address())) {
192 _localDevice =
new QBluetoothLocalDevice(
this);
193 if (_localDevice->isValid()) {
194 _connectLocalDeviceSignals();
199 _localDevice->deleteLater();
200 _localDevice =
nullptr;
204void BluetoothConfiguration::_deviceUpdated(
const QBluetoothDeviceInfo &info, QBluetoothDeviceInfo::Fields updatedFields)
206 qCDebug(BluetoothConfigurationLog) <<
"Device Updated:" << info.name() <<
"Fields:" << updatedFields;
208 if (!info.isValid() || (updatedFields == QBluetoothDeviceInfo::Field::None)) {
209 qCDebug(BluetoothConfigurationVerboseLog) <<
"Ignoring device update: invalid or no updated fields"
210 << info.name() << info.address().toString() << updatedFields;
215 for (QBluetoothDeviceInfo &dev : _deviceList) {
216 if (dev.address() == info.address()) {
218 if (updatedFields & QBluetoothDeviceInfo::Field::RSSI) {
219 dev.setRssi(info.rssi());
221 if (updatedFields & QBluetoothDeviceInfo::Field::ManufacturerData) {
222 const QMultiHash<quint16, QByteArray> data = info.manufacturerData();
223 for (quint16
id : info.manufacturerIds()) {
224 dev.setManufacturerData(
id, data.value(
id));
227 if (updatedFields & QBluetoothDeviceInfo::Field::ServiceData) {
228 const QMultiHash<QBluetoothUuid, QByteArray> data = info.serviceData();
229 for (
const QBluetoothUuid &uuid : info.serviceIds()) {
230 dev.setServiceData(uuid, data.value(uuid));
233 if (updatedFields & QBluetoothDeviceInfo::Field::All) {
237 if (_device.address() == dev.address()) {
244 if (!found && _isDeviceCompatibleWithMode(info)) {
245 _deviceList.append(info);
247 if (_device.address() == info.address()) {
253bool BluetoothConfiguration::_isDeviceCompatibleWithMode(
const QBluetoothDeviceInfo &info)
const
257 if (info.coreConfigurations() == QBluetoothDeviceInfo::UnknownCoreConfiguration) {
262 return (info.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration);
264 return (info.coreConfigurations() & QBluetoothDeviceInfo::BaseRateCoreConfiguration) ||
265 (info.coreConfigurations() & QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration);
286 if (!bluetoothSource) {
287 qCWarning(BluetoothConfigurationLog) <<
"Invalid source configuration type";
291 if (_mode != bluetoothSource->
mode()) {
292 _mode = bluetoothSource->
mode();
296 if (_device.address() != bluetoothSource->
device().address()) {
297 _device = bluetoothSource->
device();
301 if (_serviceUuid != bluetoothSource->_serviceUuid) {
302 _serviceUuid = bluetoothSource->_serviceUuid;
324 settings.beginGroup(root);
328 const QString
deviceName = settings.value(
"deviceName").toString();
329 const QBluetoothAddress
address(settings.value(
"address").toString());
335 _serviceUuid = QBluetoothUuid(settings.value(
"serviceUuid", _serviceUuid.toString()).toString());
336 _readCharacteristicUuid = QBluetoothUuid(settings.value(
"readCharUuid", _readCharacteristicUuid.toString()).toString());
337 _writeCharacteristicUuid = QBluetoothUuid(settings.value(
"writeCharUuid", _writeCharacteristicUuid.toString()).toString());
344 settings.beginGroup(root);
346 settings.setValue(
"mode",
static_cast<int>(_mode));
347 settings.setValue(
"deviceName", _device.name());
348 settings.setValue(
"address", _device.address().toString());
349 settings.setValue(
"serviceUuid", _serviceUuid.toString());
350 settings.setValue(
"readCharUuid", _readCharacteristicUuid.toString());
351 settings.setValue(
"writeCharUuid", _writeCharacteristicUuid.toString());
361 return tr(
"Bluetooth Not Available");
371 return _devicesModelCache;
376 if (_connectedRssi != rssi) {
377 _connectedRssi = rssi;
385 const QBluetoothAddress selAddr = _device.address();
386 if (!selAddr.isNull()) {
387 for (
const QBluetoothDeviceInfo &dev : _deviceList) {
388 if (dev.address() == selAddr) {
398 const QBluetoothUuid newUuid(uuid);
399 if (!uuid.isEmpty() && newUuid.isNull()) {
400 emit
errorOccurred(tr(
"Invalid service UUID format: %1").arg(uuid));
403 if (_serviceUuid != newUuid) {
404 _serviceUuid = newUuid;
411 const QBluetoothUuid newUuid(uuid);
412 if (!uuid.isEmpty() && newUuid.isNull()) {
413 emit
errorOccurred(tr(
"Invalid read characteristic UUID format: %1").arg(uuid));
416 if (_readCharacteristicUuid != newUuid) {
417 _readCharacteristicUuid = newUuid;
424 const QBluetoothUuid newUuid(uuid);
425 if (!uuid.isEmpty() && newUuid.isNull()) {
426 emit
errorOccurred(tr(
"Invalid write characteristic UUID format: %1").arg(uuid));
429 if (_writeCharacteristicUuid != newUuid) {
430 _writeCharacteristicUuid = newUuid;
437 _initDeviceDiscoveryAgent();
439 if (!_deviceDiscoveryAgent) {
444 QBluetoothPermission permission;
445 permission.setCommunicationModes(QBluetoothPermission::Access);
446 const Qt::PermissionStatus status = QCoreApplication::instance()->checkPermission(permission);
447 if (status == Qt::PermissionStatus::Undetermined) {
448 QCoreApplication::instance()->requestPermission(permission,
this, [
this](
const QPermission &perm) {
449 if (perm.status() == Qt::PermissionStatus::Granted) {
452 errorOccurred(tr(
"Bluetooth Permission Denied"));
456 }
else if (status != Qt::PermissionStatus::Granted) {
462 if (_localDevice && _localDevice->isValid() && (_localDevice->hostMode() == QBluetoothLocalDevice::HostPoweredOff)) {
463 _localDevice->powerOn();
470 _deviceDiscoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
472 _deviceDiscoveryAgent->start(QBluetoothDeviceDiscoveryAgent::ClassicMethod);
480 if (_deviceDiscoveryAgent &&
scanning()) {
481 _deviceDiscoveryAgent->stop();
487 for (
const QBluetoothDeviceInfo &info : std::as_const(_deviceList)) {
488 if (info.name() ==
name) {
490 _applySelectedDevice(info);
501 const QBluetoothAddress addr(
address);
506 for (
const QBluetoothDeviceInfo &info : std::as_const(_deviceList)) {
507 if (info.address() == addr) {
509 _applySelectedDevice(info);
515void BluetoothConfiguration::_applySelectedDevice(
const QBluetoothDeviceInfo &info)
520 const QList<QBluetoothUuid> serviceUuids = info.serviceUuids();
521 if (!serviceUuids.isEmpty()) {
523 for (
const QBluetoothUuid &uuid : serviceUuids) {
539 _serviceUuid = serviceUuids.first();
540 _readCharacteristicUuid = QBluetoothUuid();
541 _writeCharacteristicUuid = QBluetoothUuid();
557 return _deviceDiscoveryAgent && _deviceDiscoveryAgent->isActive();
560void BluetoothConfiguration::_requestHostMode(QBluetoothLocalDevice::HostMode mode)
562 if (!_localDevice || !_localDevice->isValid()) {
567 if (_localDevice->hostMode() ==
mode) {
572 if (_hostModeRequestPending) {
573 _queuedHostMode =
mode;
574 _hasQueuedHostModeRequest =
true;
575 if (_requestedHostMode !=
mode) {
576 qCDebug(BluetoothConfigurationLog) <<
"Host mode change already pending; queueing request"
577 << _requestedHostMode <<
"->" <<
mode;
582 _requestedHostMode =
mode;
583 _hasQueuedHostModeRequest =
false;
584 _hostModeRequestPending =
true;
585 _localDevice->setHostMode(
mode);
588void BluetoothConfiguration::_deviceDiscovered(
const QBluetoothDeviceInfo &info)
590 if (!info.isValid()) {
591 qCDebug(BluetoothConfigurationVerboseLog) <<
"Ignoring discovered device: invalid device info"
592 << info.name() << info.address().toString();
596 if (!_isDeviceCompatibleWithMode(info)) {
597 qCDebug(BluetoothConfigurationVerboseLog) <<
"Ignoring discovered device: incompatible with mode"
600 <<
"CoreCfg:" << info.coreConfigurations();
604 int existingIndex = -1;
605 for (
int i = 0; i < _deviceList.size(); ++i) {
606 if (_deviceList[i].
address() == info.address()) {
612 if (existingIndex >= 0) {
613 _deviceList[existingIndex] = info;
620 int sameNameIndex = -1;
621 for (
int i = 0; i < _deviceList.size(); ++i) {
622 if (_deviceList[i].
name() == info.name()) {
627 if (sameNameIndex >= 0) {
628 const bool replace = (_deviceList[sameNameIndex].address() != info.address());
630 _deviceList[sameNameIndex] = info;
633 if ((_device.name() == info.name()) && (_device.address() != info.address())) {
645 _deviceList.append(info);
649 <<
"device discovered:" << info.
name()
650 <<
"Address:" << info.
address().toString()
651 <<
"RSSI:" << info.rssi();
654void BluetoothConfiguration::_onDiscoveryFinished()
660void BluetoothConfiguration::_updateDeviceList()
663 for (
const QBluetoothDeviceInfo &info : std::as_const(_deviceList)) {
665 device[
"name"] = info.name();
666 device[
"address"] = info.address().toString();
667 if (info.rssi() != 0) {
668 device[
"rssi"] = info.rssi();
672 if (_devicesModelCache != model) {
673 _devicesModelCache = model;
674 qCDebug(BluetoothConfigurationVerboseLog) <<
"Bluetooth devices model updated. Count:" << _devicesModelCache.size();
679void BluetoothConfiguration::_onDiscoveryErrorOccurred(QBluetoothDeviceDiscoveryAgent::Error
error)
682 if (_deviceDiscoveryAgent) {
683 errorString = _deviceDiscoveryAgent->errorString();
688 qCWarning(BluetoothConfigurationLog) <<
"Bluetooth discovery error:" <<
error <<
errorString;
692void BluetoothConfiguration::_onHostModeStateChanged(QBluetoothLocalDevice::HostMode mode)
694 _hostModeRequestPending =
false;
698 case QBluetoothLocalDevice::HostPoweredOff:
699 modeString = tr(
"Powered Off");
701 case QBluetoothLocalDevice::HostConnectable:
702 modeString = tr(
"Connectable");
704 case QBluetoothLocalDevice::HostDiscoverable:
705 modeString = tr(
"Discoverable");
707 case QBluetoothLocalDevice::HostDiscoverableLimitedInquiry:
708 modeString = tr(
"Discoverable (Limited Inquiry)");
712 qCDebug(BluetoothConfigurationLog) <<
"Bluetooth adapter mode changed to:" << modeString;
715 if (_hasQueuedHostModeRequest) {
716 const QBluetoothLocalDevice::HostMode queuedMode = _queuedHostMode;
717 _hasQueuedHostModeRequest =
false;
718 if (queuedMode !=
mode) {
719 QTimer::singleShot(0,
this, [
this, queuedMode]() {
720 _requestHostMode(queuedMode);
725 if ((
mode == QBluetoothLocalDevice::HostPoweredOff) &&
scanning()) {
731void BluetoothConfiguration::_onDeviceConnected(
const QBluetoothAddress &address)
733 qCDebug(BluetoothConfigurationLog) <<
"Device connected to adapter:" <<
address.toString();
734 for (
const QBluetoothDeviceInfo &dev : std::as_const(_deviceList)) {
735 if (dev.address() ==
address) {
736 qCDebug(BluetoothConfigurationLog) <<
"Connected device:" << dev.name();
742void BluetoothConfiguration::_onDeviceDisconnected(
const QBluetoothAddress &address)
744 qCDebug(BluetoothConfigurationLog) <<
"Device disconnected from adapter:" <<
address.toString();
745 for (
const QBluetoothDeviceInfo &dev : std::as_const(_deviceList)) {
746 if (dev.address() ==
address) {
747 qCDebug(BluetoothConfigurationLog) <<
"Disconnected device:" << dev.name();
753void BluetoothConfiguration::_onPairingFinished(
const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing)
755 QString pairingStatus;
757 case QBluetoothLocalDevice::Unpaired:
758 pairingStatus = tr(
"Unpaired");
760 case QBluetoothLocalDevice::Paired:
761 pairingStatus = tr(
"Paired");
763 case QBluetoothLocalDevice::AuthorizedPaired:
764 pairingStatus = tr(
"Authorized Paired");
768 qCDebug(BluetoothConfigurationLog) <<
"Pairing finished for device:" <<
address.toString() <<
"Status:" << pairingStatus;
771 for (
const QBluetoothDeviceInfo &dev : std::as_const(_deviceList)) {
772 if (dev.address() ==
address) {
778 if (pairing == QBluetoothLocalDevice::Unpaired) {
780 ? tr(
"Device %1 unpaired").arg(
address.toString())
782 qCInfo(BluetoothConfigurationLog) << msg;
785 ? tr(
"Device %1 paired successfully").arg(
address.toString())
787 qCInfo(BluetoothConfigurationLog) << msg;
794void BluetoothConfiguration::_onLocalDeviceErrorOccurred(QBluetoothLocalDevice::Error
error)
798 case QBluetoothLocalDevice::PairingError:
801 case QBluetoothLocalDevice::MissingPermissionsError:
804 case QBluetoothLocalDevice::UnknownError:
806 errorString = tr(
"Unknown Bluetooth Adapter Error");
810 qCWarning(BluetoothConfigurationLog) <<
"Local Bluetooth device error:" <<
error <<
errorString;
816 if (!_localDevice || !_localDevice->isValid()) {
822 emit
errorOccurred(tr(
"Pairing is only supported for Classic Bluetooth"));
826 const QBluetoothAddress addr(
address);
832 qCDebug(BluetoothConfigurationLog) <<
"Requesting pairing with device:" <<
address;
833 _localDevice->requestPairing(addr, QBluetoothLocalDevice::Paired);
838 if (!_localDevice || !_localDevice->isValid()) {
844 emit
errorOccurred(tr(
"Unpairing is only supported for Classic Bluetooth"));
848 const QBluetoothAddress addr(
address);
854 qCDebug(BluetoothConfigurationLog) <<
"Removing pairing with device:" <<
address;
855 _localDevice->requestPairing(addr, QBluetoothLocalDevice::Unpaired);
860 if (!_localDevice || !_localDevice->isValid()) {
861 return tr(
"Adapter unavailable");
865 return tr(
"N/A (BLE mode)");
868 const QBluetoothAddress addr(
address);
870 return tr(
"Invalid address");
873 const QBluetoothLocalDevice::Pairing pairingStatus = _localDevice->pairingStatus(addr);
874 switch (pairingStatus) {
875 case QBluetoothLocalDevice::Unpaired:
876 return tr(
"Unpaired");
877 case QBluetoothLocalDevice::Paired:
879 case QBluetoothLocalDevice::AuthorizedPaired:
880 return tr(
"Authorized Paired");
882 return tr(
"Unknown");
892 const QBluetoothAddress addr(
address);
897 const QBluetoothLocalDevice::Pairing status = _localDevice->pairingStatus(addr);
898 return (status == QBluetoothLocalDevice::Paired || status == QBluetoothLocalDevice::AuthorizedPaired);
903 if (!_localDevice || !_localDevice->isValid()) {
907 const QBluetoothLocalDevice::HostMode
mode = _localDevice->hostMode();
908 return (
mode == QBluetoothLocalDevice::HostDiscoverable ||
mode == QBluetoothLocalDevice::HostDiscoverableLimitedInquiry);
913 return _localDevice && _localDevice->isValid();
918 if (!_localDevice || !_localDevice->isValid()) {
921 return _localDevice->address().toString();
926 if (!_localDevice || !_localDevice->isValid()) {
929 return _localDevice->name();
934 if (!_localDevice || !_localDevice->isValid()) {
937 return _localDevice->hostMode() != QBluetoothLocalDevice::HostPoweredOff;
942 QVariantList pairedDevices;
944 if (!_localDevice || !_localDevice->isValid()) {
945 return pairedDevices;
948 const QList<QBluetoothAddress> connectedAddresses = _localDevice->connectedDevices();
950 for (
const QBluetoothDeviceInfo &dev : std::as_const(_deviceList)) {
951 const QBluetoothLocalDevice::Pairing pairingStatus = _localDevice->pairingStatus(dev.address());
952 if (pairingStatus != QBluetoothLocalDevice::Unpaired) {
954 device[
"name"] = dev.name();
955 device[
"address"] = dev.address().toString();
958 if (pairingStatus == QBluetoothLocalDevice::AuthorizedPaired) {
959 device[
"pairingStatus"] = tr(
"Authorized");
961 device[
"pairingStatus"] = tr(
"Paired");
964 device[
"connected"] = connectedAddresses.contains(dev.address());
966 if (dev.rssi() != 0) {
967 device[
"rssi"] = dev.rssi();
970 pairedDevices.append(
device);
974 return pairedDevices;
979 QVariantList connectedDevices;
981 if (!_localDevice || !_localDevice->isValid()) {
982 return connectedDevices;
985 const QList<QBluetoothAddress> connectedAddresses = _localDevice->connectedDevices();
987 for (
const QBluetoothAddress &addr : connectedAddresses) {
989 device[
"address"] = addr.toString();
990 device[
"connected"] =
true;
993 for (
const QBluetoothDeviceInfo &dev : std::as_const(_deviceList)) {
994 if (dev.address() == addr) {
996 if (dev.rssi() != 0) {
997 device[
"rssi"] = dev.rssi();
1004 connectedDevices.append(
device);
1007 return connectedDevices;
1012 if (!_ensureLocalDevice()) {
1014 _refreshAvailableAdaptersAsync();
1018 const bool wasPoweredOff = (_localDevice->hostMode() == QBluetoothLocalDevice::HostPoweredOff);
1020 qCDebug(BluetoothConfigurationLog) <<
"Powering on Bluetooth adapter";
1024 if (wasPoweredOff) {
1025 _requestedHostMode = QBluetoothLocalDevice::HostConnectable;
1026 _hostModeRequestPending =
true;
1029 _localDevice->powerOn();
1033 if (wasPoweredOff && !_deferredPowerOnFixPending) {
1034 _deferredPowerOnFixPending =
true;
1035 QTimer::singleShot(1500,
this, [
this]() {
1036 _deferredPowerOnFixPending =
false;
1037 if (!_localDevice || !_localDevice->isValid()) {
1041 if (_localDevice->hostMode() == QBluetoothLocalDevice::HostPoweredOff) {
1042 _hostModeRequestPending = false;
1043 qCDebug(BluetoothConfigurationLog) <<
"Power-on fallback: requesting connectable host mode";
1044 _requestHostMode(QBluetoothLocalDevice::HostConnectable);
1045 }
else if (_hostModeRequestPending) {
1047 _hostModeRequestPending =
false;
1049 if (_hasQueuedHostModeRequest) {
1050 const QBluetoothLocalDevice::HostMode queuedMode = _queuedHostMode;
1051 _hasQueuedHostModeRequest =
false;
1052 if (queuedMode != _localDevice->hostMode()) {
1053 _requestHostMode(queuedMode);
1065 if (!_localDevice || !_localDevice->isValid()) {
1074 if (_localDevice->hostMode() == QBluetoothLocalDevice::HostPoweredOff) {
1078 qCDebug(BluetoothConfigurationLog) <<
"Powering off Bluetooth adapter";
1079 _requestHostMode(QBluetoothLocalDevice::HostPoweredOff);
1084 if (!_localDevice || !_localDevice->isValid()) {
1090 if (_localDevice->hostMode() == QBluetoothLocalDevice::HostDiscoverable) {
1093 qCDebug(BluetoothConfigurationLog) <<
"Making Bluetooth adapter discoverable";
1094 _requestHostMode(QBluetoothLocalDevice::HostDiscoverable);
1096 if (_localDevice->hostMode() == QBluetoothLocalDevice::HostConnectable) {
1099 qCDebug(BluetoothConfigurationLog) <<
"Making Bluetooth adapter connectable only";
1100 _requestHostMode(QBluetoothLocalDevice::HostConnectable);
1106 if (_availableAdapters.isEmpty()) {
1107 _refreshAvailableAdaptersAsync();
1109 return _availableAdapters;
1114 const QBluetoothAddress addr(
address);
1115 if (addr.isNull()) {
1120 if (!_availableAdapters.isEmpty()) {
1122 for (
const QVariant &entry : std::as_const(_availableAdapters)) {
1123 const QVariantMap adapter = entry.toMap();
1124 if (QBluetoothAddress(adapter.value(
"address").toString()) == addr) {
1131 _refreshAvailableAdaptersAsync();
1140 if (!_createLocalDevice(addr)) {
1142 _refreshAvailableAdaptersAsync();
1146 bool selectionUpdated =
false;
1147 for (QVariant &entry : _availableAdapters) {
1148 QVariantMap adapter = entry.toMap();
1149 if (adapter.isEmpty()) {
1153 const bool selected = (QBluetoothAddress(adapter.value(
"address").toString()) == addr);
1154 if (adapter.value(
"selected").toBool() != selected) {
1155 adapter[
"selected"] = selected;
1157 selectionUpdated =
true;
1161 if (_availableAdapters.isEmpty() && _localDevice && _localDevice->isValid()) {
1162 QVariantMap adapter;
1163 adapter[
"name"] = _localDevice->name();
1164 adapter[
"address"] = _localDevice->address().toString();
1165 adapter[
"selected"] =
true;
1166 _availableAdapters.append(adapter);
1167 selectionUpdated =
true;
1170 if (selectionUpdated) {
1177 if (!_localDevice || !_localDevice->isValid()) {
1178 return tr(
"Unavailable");
1181 switch (_localDevice->hostMode()) {
1182 case QBluetoothLocalDevice::HostPoweredOff:
1183 return tr(
"Powered Off");
1184 case QBluetoothLocalDevice::HostConnectable:
1185 return tr(
"Connectable");
1186 case QBluetoothLocalDevice::HostDiscoverable:
1187 return tr(
"Discoverable");
1188 case QBluetoothLocalDevice::HostDiscoverableLimitedInquiry:
1189 return tr(
"Discoverable (Limited)");
1191 return tr(
"Unknown");
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void serviceUuidChanged()
static const QBluetoothUuid NORDIC_UART_SERVICE
static const QBluetoothUuid NORDIC_UART_RX_CHAR
void errorOccurred(const QString &errorString)
Q_INVOKABLE bool isDiscoverable() const
Q_INVOKABLE QString getAdapterAddress() const
Q_INVOKABLE void setDevice(const QString &name)
Q_INVOKABLE QVariantList getAllPairedDevices() const
Q_INVOKABLE void requestPairing(const QString &address)
void devicesModelChanged()
void pairingStatusChanged()
Q_INVOKABLE void setAdapterDiscoverable(bool discoverable)
Q_INVOKABLE bool isAdapterAvailable() const
Q_INVOKABLE void powerOffAdapter()
qint16 selectedRssi() const
Q_INVOKABLE void selectAdapter(const QString &address)
Q_INVOKABLE QVariantList getConnectedDevices() const
Q_INVOKABLE void powerOnAdapter()
QString serviceUuid() const
void connectedRssiChanged()
void loadSettings(QSettings &settings, const QString &root) override
static bool isBluetoothAvailable()
Q_INVOKABLE QString getPairingStatus(const QString &address) const
const QBluetoothDeviceInfo & device() const
Q_INVOKABLE bool isPaired(const QString &address) const
void setMode(BluetoothMode mode)
QVariantList devicesModel() const
void selectedRssiChanged()
const QBluetoothUuid & writeCharacteristicUuid() const
const QBluetoothUuid & readCharacteristicUuid() const
void setConnectedRssi(qint16 rssi)
static const QBluetoothUuid TI_SENSORTAG_SERVICE
BluetoothMode mode() const
~BluetoothConfiguration() override
static const QBluetoothUuid NORDIC_UART_TX_CHAR
QString settingsTitle() const override
Settings Title, Pure virtual method providing the Title for the (QML) settings dialog.
qint16 connectedRssi() const
void saveSettings(QSettings &settings, const QString &root) const override
static const QBluetoothUuid TI_SENSORTAG_CHAR
void setWriteUuid(const QString &uuid)
Q_INVOKABLE bool isAdapterPoweredOn() const
BluetoothConfiguration(const QString &name, QObject *parent=nullptr)
Q_INVOKABLE void stopScan()
Q_INVOKABLE QVariantList getAllAvailableAdapters()
Q_INVOKABLE void removePairing(const QString &address)
Q_INVOKABLE QString getHostMode() const
Q_INVOKABLE void setDeviceByAddress(const QString &address)
void adapterStateChanged()
QString deviceName() const
void setServiceUuid(const QString &uuid)
Q_INVOKABLE void startScan()
Q_INVOKABLE QString getAdapterName() const
void setReadUuid(const QString &uuid)
void copyFrom(const LinkConfiguration *source) override
Interface holding link specific settings.
virtual void copyFrom(const LinkConfiguration *source)
bool isBluetoothAvailable()
Check if Bluetooth is available on this device.