diff options
author | Juha Vuolle <juha.vuolle@insta.fi> | 2022-05-02 13:04:21 +0300 |
---|---|---|
committer | Juha Vuolle <juha.vuolle@insta.fi> | 2022-05-12 09:06:13 +0300 |
commit | ca96a42035255b4355e4d8ddba7f5da7b9006577 (patch) | |
tree | 072961c41bcc4f55a0b98214426c093b298c15ae /src | |
parent | e043bb633f44cc85080973857e6485a8f3801d30 (diff) |
Fix Bluez BT LE battery reading
This commit addresses two related issues:
- From Bluez 5.55 onwards the battery service is available
through both GattService1 and Battery1 interface. This
broke the current implementation in a way that the battery
level was always '0'. This patch uses the GattService1
interface if available
- The Battery1 interface is not always available during the
service discovery, it's not generated yet. This causes
the service to be missed. This patch also checks if the
battery remote service is available also from 'Device1'
interface
This commit has been tested with Bluez versions 5.42..5.63
with Qt6, and with few selected versions with Qt5
Fixes: QTBUG-70222
Change-Id: I963947937cf85c8082fb044afe223f41e141b7c0
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
(cherry picked from commit e7604172ff7bdab8f3936c84a866476aee576e54)
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/bluetooth/qlowenergycontroller_bluezdbus.cpp | 62 |
1 files changed, 51 insertions, 11 deletions
diff --git a/src/bluetooth/qlowenergycontroller_bluezdbus.cpp b/src/bluetooth/qlowenergycontroller_bluezdbus.cpp index 5420cd8e..65ed2afd 100644 --- a/src/bluetooth/qlowenergycontroller_bluezdbus.cpp +++ b/src/bluetooth/qlowenergycontroller_bluezdbus.cpp @@ -415,7 +415,8 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServices() Q_Q(QLowEnergyController); auto setupServicePrivate = [&, q]( - QLowEnergyService::ServiceType type, const QBluetoothUuid &uuid, const QString &path){ + QLowEnergyService::ServiceType type, const QBluetoothUuid &uuid, + const QString &path, const bool battery1Interface = false){ QSharedPointer<QLowEnergyServicePrivate> priv = QSharedPointer<QLowEnergyServicePrivate>::create(); priv->uuid = uuid; priv->type = type; // we make a guess we cannot validate @@ -423,8 +424,11 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServices() GattService serviceContainer; serviceContainer.servicePath = path; - if (uuid == QBluetoothUuid::BatteryService) + + if (battery1Interface) { + qCDebug(QT_BT_BLUEZ) << "Using Battery1 interface to emulate generic interface"; serviceContainer.hasBatteryService = true; + } serviceList.insert(priv->uuid, priv); dbusServices.insert(priv->uuid, serviceContainer); @@ -434,25 +438,50 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServices() const ManagedObjectList managedObjectList = reply.value(); const QString servicePathPrefix = device->path().append(QStringLiteral("/service")); + + // The Bluez battery service (0x180f) support has evolved over time and needs additional logic: + // + // * Until 5.47 Bluez exposes battery services via generic interface (GattService1) only + // * Between 5.48..5.54 Bluez exposes battery service as a dedicated 'Battery1' interface only + // * From 5.55 Bluez exposes both the generic service as well as the dedicated 'Battery1' + // + // To hide the difference from users the 'Battery1' interface will be used to emulate the + // generic interface. Importantly also the GattService1 interface, if available, is available + // early whereas the Battery1 interface may be available only later (generated too late for + // this service discovery's purposes) + // + // The precedence for battery service here is as follows: + // * If available via GattService1, use that and ignore possible Battery1 interface + // * If Battery1 interface is available or the 'org.bluez.Device1' lists battery service + // amongst list of available services, mark the service such that the code will later + // look up the Battery1 service details + bool gattBatteryService{false}; + QString batteryServicePath; + for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) { const InterfaceList &ifaceList = it.value(); if (!it.key().path().startsWith(device->path())) continue; - // Since Bluez 5.48 battery services (0x180f) are no longer exposed - // as generic services under servicePathPrefix. - // A dedicated org.bluez.Battery1 interface is exposed. Here we are going to revert - // Bettery1 to the generic pattern. if (it.key().path() == device->path()) { - // find Battery1 service + // See if the battery service is available or is assumed to be available later for (InterfaceList::const_iterator battIter = ifaceList.constBegin(); battIter != ifaceList.constEnd(); ++battIter) { const QString &iface = battIter.key(); if (iface == QStringLiteral("org.bluez.Battery1")) { - qCDebug(QT_BT_BLUEZ) << "Found dedicated Battery service -> emulating generic btle access"; - setupServicePrivate(QLowEnergyService::PrimaryService, - QBluetoothUuid::BatteryService, - it.key().path()); + qCDebug(QT_BT_BLUEZ) << "Dedicated Battery1 service available"; + batteryServicePath = it.key().path(); + break; + } else if (iface == QStringLiteral("org.bluez.Device1")) { + for (auto const& uuid : + battIter.value()[QStringLiteral("UUIDs")].toStringList()) { + if (QBluetoothUuid(uuid) == + QBluetoothUuid::ServiceClassUuid::BatteryService) { + qCDebug(QT_BT_BLUEZ) << "Battery service listed as available service"; + batteryServicePath = it.key().path(); + break; + } + } } } continue; @@ -468,6 +497,11 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServices() QScopedPointer<OrgBluezGattService1Interface> service(new OrgBluezGattService1Interface( QStringLiteral("org.bluez"),it.key().path(), QDBusConnection::systemBus(), this)); + if (QBluetoothUuid(service->uUID()) == + QBluetoothUuid::ServiceClassUuid::BatteryService) { + qCDebug(QT_BT_BLUEZ) << "Using battery service via GattService1 interface"; + gattBatteryService = true; + } setupServicePrivate(service->primary() ? QLowEnergyService::PrimaryService : QLowEnergyService::IncludedService, @@ -476,6 +510,12 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServices() } } + if (!gattBatteryService && !batteryServicePath.isEmpty()) { + setupServicePrivate(QLowEnergyService::PrimaryService, + QBluetoothUuid::ServiceClassUuid::BatteryService, + batteryServicePath, true); + } + setState(QLowEnergyController::DiscoveredState); emit q->discoveryFinished(); } |