aboutsummaryrefslogtreecommitdiffstats
path: root/quantum
diff options
context:
space:
mode:
authorJoel Challis2025-08-17 02:14:48 +0200
committerGitHub2025-08-17 02:14:48 +0200
commitcc696a2ae838a9639335ca8eb3cb3b794c06bc33 (patch)
tree901b54bda536acb5503c6cf924b0f30bca1a174e /quantum
parentf29d8117bf877a4df1f88f40e0131f4465748540 (diff)
Refactor battery driver (#25550)
Diffstat (limited to 'quantum')
-rw-r--r--quantum/battery/battery.c41
-rw-r--r--quantum/battery/battery.h46
-rw-r--r--quantum/battery/tests/battery_tests.cpp97
-rw-r--r--quantum/battery/tests/rules.mk7
-rw-r--r--quantum/battery/tests/testlist.mk2
-rw-r--r--quantum/keyboard.c6
-rw-r--r--quantum/quantum.h4
7 files changed, 200 insertions, 3 deletions
diff --git a/quantum/battery/battery.c b/quantum/battery/battery.c
new file mode 100644
index 0000000000..faf3c5a214
--- /dev/null
+++ b/quantum/battery/battery.c
@@ -0,0 +1,41 @@
+// Copyright 2025 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "battery_driver.h"
+#include "battery.h"
+#include "timer.h"
+
+#ifndef BATTERY_SAMPLE_INTERVAL
+# define BATTERY_SAMPLE_INTERVAL 30000
+#endif
+
+static uint8_t last_bat_level = 100;
+
+void battery_init(void) {
+ battery_driver_init();
+
+ last_bat_level = battery_driver_sample_percent();
+}
+
+__attribute__((weak)) void battery_percent_changed_user(uint8_t level) {}
+__attribute__((weak)) void battery_percent_changed_kb(uint8_t level) {}
+
+static void handle_percent_changed(void) {
+ battery_percent_changed_user(last_bat_level);
+ battery_percent_changed_kb(last_bat_level);
+}
+
+void battery_task(void) {
+ static uint32_t bat_timer = 0;
+ if (timer_elapsed32(bat_timer) > BATTERY_SAMPLE_INTERVAL) {
+ last_bat_level = battery_driver_sample_percent();
+
+ handle_percent_changed();
+
+ bat_timer = timer_read32();
+ }
+}
+
+uint8_t battery_get_percent(void) {
+ return last_bat_level;
+}
diff --git a/quantum/battery/battery.h b/quantum/battery/battery.h
new file mode 100644
index 0000000000..0985723eaa
--- /dev/null
+++ b/quantum/battery/battery.h
@@ -0,0 +1,46 @@
+// Copyright 2025 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <stdint.h>
+
+/**
+ * \file
+ *
+ * \defgroup battery Battery API
+ *
+ * \brief API to query battery status.
+ * \{
+ */
+
+/**
+ * \brief Initialize the battery driver.
+ */
+void battery_init(void);
+
+/**
+ * \brief Perform housekeeping tasks.
+ */
+void battery_task(void);
+
+/**
+ * \brief Sample battery level.
+ *
+ * \return The battery percentage, in the range 0-100.
+ */
+uint8_t battery_get_percent(void);
+
+/**
+ * \brief user hook called when battery level changed.
+ *
+ */
+void battery_percent_changed_user(uint8_t level);
+
+/**
+ * \brief keyboard hook called when battery level changed.
+ *
+ */
+void battery_percent_changed_kb(uint8_t level);
+
+/** \} */
diff --git a/quantum/battery/tests/battery_tests.cpp b/quantum/battery/tests/battery_tests.cpp
new file mode 100644
index 0000000000..ee011be8a8
--- /dev/null
+++ b/quantum/battery/tests/battery_tests.cpp
@@ -0,0 +1,97 @@
+// Copyright 2025 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "gtest/gtest.h"
+#include "gmock/gmock.h"
+
+using testing::_;
+
+class BatteryDriverMock {
+ public:
+ virtual ~BatteryDriverMock() {}
+
+ // mock methods
+ MOCK_METHOD0(battery_driver_init, void(void));
+ MOCK_METHOD0(battery_driver_sample_percent, uint8_t(void));
+ MOCK_METHOD1(battery_percent_changed_kb, void(uint8_t));
+};
+
+class BatteryTest : public ::testing::Test {
+ public:
+ BatteryTest() {
+ _batteryDriverMock.reset(new ::testing::NiceMock<BatteryDriverMock>());
+ }
+ virtual ~BatteryTest() {
+ _batteryDriverMock.reset();
+ }
+
+ static std::unique_ptr<BatteryDriverMock> _batteryDriverMock;
+};
+
+std::unique_ptr<BatteryDriverMock> BatteryTest::_batteryDriverMock;
+
+extern "C" {
+#include "quantum/battery/battery.h"
+#include "timer.h"
+
+void advance_time(uint32_t ms);
+
+void battery_driver_init(void) {
+ if (BatteryTest::_batteryDriverMock) {
+ BatteryTest::_batteryDriverMock->battery_driver_init();
+ }
+}
+
+uint8_t battery_driver_sample_percent(void) {
+ if (BatteryTest::_batteryDriverMock) {
+ return BatteryTest::_batteryDriverMock->battery_driver_sample_percent();
+ }
+ return 255;
+}
+
+void battery_percent_changed_kb(uint8_t level) {
+ if (BatteryTest::_batteryDriverMock) {
+ BatteryTest::_batteryDriverMock->battery_percent_changed_kb(level);
+ }
+}
+}
+
+TEST_F(BatteryTest, TestInit) {
+ // init driver and initial sample
+ EXPECT_CALL(*_batteryDriverMock, battery_driver_init()).Times(1);
+ EXPECT_CALL(*_batteryDriverMock, battery_driver_sample_percent()).Times(1);
+
+ battery_init();
+}
+
+TEST_F(BatteryTest, TestSampleCached) {
+ // sample before timeout
+ EXPECT_CALL(*_batteryDriverMock, battery_driver_sample_percent()).Times(0);
+
+ advance_time(1);
+ battery_task();
+}
+
+TEST_F(BatteryTest, TestSampleNotCached) {
+ // sample after timeout
+ EXPECT_CALL(*_batteryDriverMock, battery_driver_sample_percent()).Times(1);
+
+ advance_time(60000);
+ battery_task();
+}
+
+TEST_F(BatteryTest, TestGet) {
+ // sample does not directly sample
+ EXPECT_CALL(*_batteryDriverMock, battery_driver_sample_percent()).Times(0);
+
+ battery_get_percent();
+}
+
+TEST_F(BatteryTest, TestChanged) {
+ // callbacks on value changed
+ EXPECT_CALL(*_batteryDriverMock, battery_percent_changed_kb(_)).Times(1);
+
+ battery_task();
+ advance_time(60000);
+ battery_task();
+}
diff --git a/quantum/battery/tests/rules.mk b/quantum/battery/tests/rules.mk
new file mode 100644
index 0000000000..86980f1020
--- /dev/null
+++ b/quantum/battery/tests/rules.mk
@@ -0,0 +1,7 @@
+VPATH += $(DRIVER_PATH)/battery
+
+battery_SRC := \
+ $(PLATFORM_PATH)/timer.c \
+ $(PLATFORM_PATH)/$(PLATFORM_KEY)/timer.c \
+ $(QUANTUM_PATH)/battery/battery.c \
+ $(QUANTUM_PATH)/battery/tests/battery_tests.cpp \
diff --git a/quantum/battery/tests/testlist.mk b/quantum/battery/tests/testlist.mk
new file mode 100644
index 0000000000..e91da865a0
--- /dev/null
+++ b/quantum/battery/tests/testlist.mk
@@ -0,0 +1,2 @@
+TEST_LIST += \
+ battery \
diff --git a/quantum/keyboard.c b/quantum/keyboard.c
index bf4890a51d..173c696e2d 100644
--- a/quantum/keyboard.c
+++ b/quantum/keyboard.c
@@ -122,7 +122,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef SPLIT_KEYBOARD
# include "split_util.h"
#endif
-#ifdef BATTERY_DRIVER
+#ifdef BATTERY_ENABLE
# include "battery.h"
#endif
#ifdef BLUETOOTH_ENABLE
@@ -532,7 +532,7 @@ void keyboard_init(void) {
// init after split init
pointing_device_init();
#endif
-#ifdef BATTERY_DRIVER
+#ifdef BATTERY_ENABLE
battery_init();
#endif
#ifdef BLUETOOTH_ENABLE
@@ -779,7 +779,7 @@ void keyboard_task(void) {
joystick_task();
#endif
-#ifdef BATTERY_DRIVER
+#ifdef BATTERY_ENABLE
battery_task();
#endif
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 0036cd784b..176c8a292d 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -63,6 +63,10 @@
# include "bootmagic.h"
#endif
+#ifdef BATTERY_ENABLE
+# include "battery.h"
+#endif
+
#ifdef DEFERRED_EXEC_ENABLE
# include "deferred_exec.h"
#endif