From c5d4a041483c52f16f9f47adae41225d8ad90595 Mon Sep 17 00:00:00 2001 From: Roman Smirnov Date: Fri, 14 Nov 2025 15:11:36 +0300 Subject: [PATCH] shared/battery: improve the display of the charge level The battery charge level may fluctuate due to uncalibrated sensors. Commit smooths out such fluctuations. The algorithm for determining uncalibrated sensors consists of finding the number of changes in charge direction (i.e., "spikes"). If the number of spikes is zero, the device is charging or discharging. If there is one spike, it may mean that the device has started charging or has been disconnected from charging. If there are two or more spikes, this is a clear indication of an uncalibrated sensor. Check that the battery charge is fluctuating. If the battery charge is fluctuating, use the average charge value, otherwise use the current value. Fixes: https://github.com/bluez/bluez/issues/1612 --- Makefile.am | 3 +- src/battery.c | 10 ++++- src/shared/battery.c | 96 ++++++++++++++++++++++++++++++++++++++++++++ src/shared/battery.h | 21 ++++++++++ 4 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 src/shared/battery.c create mode 100644 src/shared/battery.h diff --git a/Makefile.am b/Makefile.am index e8b31a564..8e7721bef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -244,7 +244,8 @@ shared_sources = src/shared/io.h src/shared/timeout.h \ src/shared/ccp.h src/shared/ccp.c \ src/shared/lc3.h src/shared/tty.h \ src/shared/bap-defs.h \ - src/shared/asha.h src/shared/asha.c + src/shared/asha.h src/shared/asha.c \ + src/shared/battery.h src/shared/battery.c if READLINE shared_sources += src/shared/shell.c src/shared/shell.h diff --git a/src/battery.c b/src/battery.c index 4c1ea79d9..fa30fde47 100644 --- a/src/battery.c +++ b/src/battery.c @@ -19,6 +19,7 @@ #include "gdbus/gdbus.h" #include "bluetooth/bluetooth.h" +#include "src/shared/battery.h" #include "src/shared/queue.h" #include "src/shared/util.h" #include "battery.h" @@ -39,6 +40,7 @@ struct btd_battery { uint8_t percentage; /* valid between 0 to 100 inclusively */ char *source; /* Descriptive source of the battery info */ char *provider_path; /* The provider root path, if any */ + struct bt_battery *filter; }; struct btd_battery_provider_manager { @@ -96,6 +98,7 @@ static struct btd_battery *battery_new(const char *path, const char *source, battery->source = g_strdup(source); if (provider_path) battery->provider_path = g_strdup(provider_path); + battery->filter = bt_battery_new(); return battery; } @@ -108,6 +111,11 @@ static void battery_free(struct btd_battery *battery) if (battery->source) g_free(battery->source); + if (battery->filter) { + bt_battery_free(battery->filter); + free(battery->filter); + } + free(battery); } @@ -234,7 +242,7 @@ bool btd_battery_update(struct btd_battery *battery, uint8_t percentage) if (battery->percentage == percentage) return true; - battery->percentage = percentage; + battery->percentage = bt_battery_charge(battery->filter, percentage); g_dbus_emit_property_changed(btd_get_dbus_connection(), battery->path, BATTERY_INTERFACE, "Percentage"); diff --git a/src/shared/battery.c b/src/shared/battery.c new file mode 100644 index 000000000..33cec3a8c --- /dev/null +++ b/src/shared/battery.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2025 Open Mobile Platform LLC + * + * + */ + +#include +#include + +#include "src/shared/battery.h" +#include "src/shared/queue.h" +#include "src/shared/util.h" + +struct bt_battery { + struct queue *last_charges; /* last charges received */ + uint8_t avg_charge; /* average battery charge */ + bool is_fluctuating; /* true, if the battery sensor fluctuates */ +}; + +struct bt_battery *bt_battery_new(void) +{ + struct bt_battery *battery; + + battery = new0(struct bt_battery, 1); + battery->last_charges = queue_new(); + battery->avg_charge = 0; + battery->is_fluctuating = false; + + return battery; +} + +void bt_battery_free(struct bt_battery *battery) +{ + if (battery->last_charges) + queue_destroy(battery->last_charges, NULL); +} + +static void bt_battery_check_fluctuations(struct bt_battery *battery) +{ + const struct queue_entry *entry; + uint8_t spikes = 0; + int8_t step; + int8_t direction = 0; + int8_t prev_direction; + uintptr_t prev_charge; + uintptr_t next_charge = 0; + uint16_t sum_charge = 0; + + for (entry = queue_get_entries(battery->last_charges); entry->next; + entry = entry->next) { + prev_direction = direction; + prev_charge = PTR_TO_UINT(entry->data); + next_charge = PTR_TO_UINT(entry->next->data); + step = next_charge - prev_charge; + sum_charge += prev_charge; + + /* + * The battery charge fluctuates too much, + * which may indicate a battery problem, so + * the actual value should be displayed. + */ + if (abs(step) >= MAX_CHARGE_STEP) { + battery->is_fluctuating = false; + return; + } + + if (step > 0) + direction = 1; + else if (step < 0) + direction = -1; + + if (direction != prev_direction && prev_direction) + spikes++; + } + + sum_charge += next_charge; + battery->avg_charge = sum_charge / LAST_CHARGES_SIZE; + + battery->is_fluctuating = (spikes > 1) ? true : false; +} + +uint8_t bt_battery_charge(struct bt_battery *battery, uint8_t percentage) +{ + queue_push_tail(battery->last_charges, UINT_TO_PTR(percentage)); + + if (queue_length(battery->last_charges) == LAST_CHARGES_SIZE) { + bt_battery_check_fluctuations(battery); + queue_pop_head(battery->last_charges); + } + + return (battery->is_fluctuating) ? battery->avg_charge : percentage; +} diff --git a/src/shared/battery.h b/src/shared/battery.h new file mode 100644 index 000000000..457acbc63 --- /dev/null +++ b/src/shared/battery.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2025 Open Mobile Platform LLC + * + * + */ + +#include + +#define LAST_CHARGES_SIZE 8 +#define MAX_CHARGE_STEP 5 + +struct bt_battery; + +struct bt_battery *bt_battery_new(void); +void bt_battery_free(struct bt_battery *battery); + +uint8_t bt_battery_charge(struct bt_battery *battery, uint8_t percentage); -- 2.47.3