summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJuha Vuolle <juha.vuolle@insta.fi>2022-05-02 13:04:21 +0300
committerJuha Vuolle <juha.vuolle@insta.fi>2022-05-12 09:06:13 +0300
commitca96a42035255b4355e4d8ddba7f5da7b9006577 (patch)
tree072961c41bcc4f55a0b98214426c093b298c15ae /src
parente043bb633f44cc85080973857e6485a8f3801d30 (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.cpp62
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();
}