From e917aed88a0d7ee5a0a5c8225a52a477af323bd8 Mon Sep 17 00:00:00 2001 From: Chris Brien Date: Tue, 11 Aug 2026 11:38:40 -0400 Subject: [PATCH] firmware: ignore failed PMIC power-key reads --- firmware/main/hal/board/stackchan.cc | 7 ++++++- firmware/tests/test_power_key_fail_safe.py | 23 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 firmware/tests/test_power_key_fail_safe.py diff --git a/firmware/main/hal/board/stackchan.cc b/firmware/main/hal/board/stackchan.cc index bd92027e1..857d301c3 100644 --- a/firmware/main/hal/board/stackchan.cc +++ b/firmware/main/hal/board/stackchan.cc @@ -87,7 +87,12 @@ class Pmic : public Axp2101 { // (W1C) so subsequent polls only fire on new presses. bool ConsumePekLongPress() { - uint8_t status = ReadReg(0x49); + // ReadReg() returns 0xFF on I2C failure, which would look like every + // IRQ bit is set and falsely trigger a shutdown. ReadRegs() leaves the + // caller-provided buffer untouched on failure, so initialise it to a + // safe value and fail closed when the PMIC cannot be read. + uint8_t status = 0; + ReadRegs(0x49, &status, 1); if (status & 0x04) { WriteReg(0x49, 0x04); return true; diff --git a/firmware/tests/test_power_key_fail_safe.py b/firmware/tests/test_power_key_fail_safe.py new file mode 100644 index 000000000..756182482 --- /dev/null +++ b/firmware/tests/test_power_key_fail_safe.py @@ -0,0 +1,23 @@ +"""Host-side source contract for fail-safe PMIC power-key polling.""" + +from pathlib import Path +import unittest + + +ROOT = Path(__file__).resolve().parents[1] +BOARD = (ROOT / "main/hal/board/stackchan.cc").read_text() + + +class TestPowerKeyFailSafe(unittest.TestCase): + def test_failed_status_read_cannot_look_like_a_long_press(self): + handler = BOARD.split("bool ConsumePekLongPress()", 1)[1].split( + "bool IsExternalPowerConnected()", 1 + )[0] + + self.assertIn("uint8_t status = 0;", handler) + self.assertIn("ReadRegs(0x49, &status, 1);", handler) + self.assertNotIn("ReadReg(0x49)", handler) + + +if __name__ == "__main__": + unittest.main()