Summary
When the device boots with charger power connected but the battery check fails because the fuel gauge is still in system-down / precharge range, the firmware should immediately show the red pulsing precharge indication.
Currently the startup path either shows POWER_CONNECTED briefly or powers down before the normal battery state machinery can publish PRECHARGING, so users may see no red pulse even though the charger is still precharging the cell.
Current behavior
In PowerManager::begin():
check_battery() may return false when the BQ27220 reports SYSDWN.
- If charger power is connected, the code continues into the charging branch.
- That branch initializes
oe_state.charging_state = POWER_CONNECTED, which maps to orange.
PRECHARGING is only set later from fuel_gauge_work_handler() when charger state is charging and bat.SYSDWN is true.
Relevant code:
src/Battery/PowerManager.cpp: startup battery check and charging branch around check_battery(), POWER_CONNECTED, and state_indicator.init().
src/Battery/PowerManager.cpp: fuel_gauge_work_handler() maps charging + SYSDWN to PRECHARGING.
src/utils/StateIndicator.cpp: PRECHARGING maps to led_controller.pulse(LED_RED, ...).
Expected behavior
If battery check fails but charger power is present, the device should enter a charging-only/preboot recovery mode and immediately set the indicator to PRECHARGING when the failing reason is compatible with precharge/system-down recovery.
This should make the LED behavior match the README entry:
Red pulsing: Pre-charge phase or system-down voltage not yet cleared
Proposed implementation
-
Change the battery check from a plain boolean to a richer result/reason, for example:
OK
SYS_DOWN
VOLTAGE_TOO_LOW
TEMP_OUT_OF_RANGE
READ_ERROR
-
In PowerManager::begin():
- If battery check fails and charger is not connected: power down as today.
- If battery check fails and charger is connected:
- initialize the state indicator immediately;
- set
oe_state.charging_state = PRECHARGING for SYS_DOWN / precharge-compatible failures;
- set
FAULT or another explicit state for non-recoverable failures such as unsafe temperature;
- schedule the normal charge controller work and remain in the charger-present wait loop.
-
Keep fuel_gauge_work_handler() as the ongoing source of truth after startup. It can continue to update PRECHARGING, CHARGING, FAULT, etc. once periodic charger/fuel-gauge reads are available.
-
Improve I2C read error handling in the battery drivers so failed fuel-gauge reads do not silently become zero-like values that can be misclassified as real voltage, temperature, or flag data.
Why this matters
When a deeply discharged device is plugged in, it may be doing the correct hardware recovery/precharge behavior but provide no clear user feedback. Showing red pulse immediately in this mode makes the device state understandable and aligns runtime behavior with the documented battery LED states.
Summary
When the device boots with charger power connected but the battery check fails because the fuel gauge is still in system-down / precharge range, the firmware should immediately show the red pulsing precharge indication.
Currently the startup path either shows
POWER_CONNECTEDbriefly or powers down before the normal battery state machinery can publishPRECHARGING, so users may see no red pulse even though the charger is still precharging the cell.Current behavior
In
PowerManager::begin():check_battery()may returnfalsewhen the BQ27220 reportsSYSDWN.oe_state.charging_state = POWER_CONNECTED, which maps to orange.PRECHARGINGis only set later fromfuel_gauge_work_handler()when charger state ischargingandbat.SYSDWNis true.Relevant code:
src/Battery/PowerManager.cpp: startup battery check and charging branch aroundcheck_battery(),POWER_CONNECTED, andstate_indicator.init().src/Battery/PowerManager.cpp:fuel_gauge_work_handler()mapscharging + SYSDWNtoPRECHARGING.src/utils/StateIndicator.cpp:PRECHARGINGmaps toled_controller.pulse(LED_RED, ...).Expected behavior
If battery check fails but charger power is present, the device should enter a charging-only/preboot recovery mode and immediately set the indicator to
PRECHARGINGwhen the failing reason is compatible with precharge/system-down recovery.This should make the LED behavior match the README entry:
Proposed implementation
Change the battery check from a plain boolean to a richer result/reason, for example:
OKSYS_DOWNVOLTAGE_TOO_LOWTEMP_OUT_OF_RANGEREAD_ERRORIn
PowerManager::begin():oe_state.charging_state = PRECHARGINGforSYS_DOWN/ precharge-compatible failures;FAULTor another explicit state for non-recoverable failures such as unsafe temperature;Keep
fuel_gauge_work_handler()as the ongoing source of truth after startup. It can continue to updatePRECHARGING,CHARGING,FAULT, etc. once periodic charger/fuel-gauge reads are available.Improve I2C read error handling in the battery drivers so failed fuel-gauge reads do not silently become zero-like values that can be misclassified as real voltage, temperature, or flag data.
Why this matters
When a deeply discharged device is plugged in, it may be doing the correct hardware recovery/precharge behavior but provide no clear user feedback. Showing red pulse immediately in this mode makes the device state understandable and aligns runtime behavior with the documented battery LED states.