idle: add IDLE_SLEEP_WHEN_CHARGING and IDLE_WAKE_ON_TOUCH

Addresses review feedback on #24:

- New config IDLE_SLEEP_WHEN_CHARGING (default false): while USB is
  plugged in we don't enter sleep and we wake immediately if power
  comes back. Covers both "I like watching Clawd animations on my
  plugged-in desk device" and "alternative hardware without a battery
  is always on USB, sleep would be odd."

- New config IDLE_WAKE_ON_TOUCH (default true): a touch on the dark
  panel wakes the device. The first touch is swallowed (mirrors the
  button wake-consumption), so tapping a dark screen wakes without
  also toggling splash<->usage. Set false to keep the original
  pets/sleeves-safe behaviour where touch is fully ignored while
  asleep.

power.{h,cpp} grow a power_is_vbus_in() helper backed by
pmu.isVbusIn() — distinct from isCharging() so the no-battery case
("plugged in, nothing to charge") is detected correctly.
This commit is contained in:
tobby168
2026-05-19 20:39:03 -07:00
parent 6655b0f6d0
commit e0829cebdf
5 changed files with 60 additions and 4 deletions
+11
View File
@@ -2,6 +2,7 @@
#include "idle.h" #include "idle.h"
#include "idle_cfg.h" #include "idle_cfg.h"
#include "display_cfg.h" // declares `extern Arduino_CO5300 *gfx;` #include "display_cfg.h" // declares `extern Arduino_CO5300 *gfx;`
#include "power.h"
enum IdleState { enum IdleState {
STATE_AWAKE, STATE_AWAKE,
@@ -69,6 +70,16 @@ bool idle_is_asleep(void) {
void idle_tick(void) { void idle_tick(void) {
uint32_t now = millis(); uint32_t now = millis();
// While on USB power (if configured), don't sleep — and wake from sleep
// when power comes back. Treats USB-in as continuous activity.
if (!IDLE_SLEEP_WHEN_CHARGING && power_is_vbus_in()) {
last_activity_ms = now;
if (state == STATE_ASLEEP || state == STATE_FADING_OUT) {
begin_fade(DISPLAY_DEFAULT_BRIGHTNESS, now);
state = STATE_FADING_IN;
}
}
switch (state) { switch (state) {
case STATE_AWAKE: case STATE_AWAKE:
if (now - last_activity_ms >= IDLE_TIMEOUT_MS) { if (now - last_activity_ms >= IDLE_TIMEOUT_MS) {
+12
View File
@@ -9,3 +9,15 @@
#define IDLE_FADE_STEP_MS 20 // tick interval per fade step #define IDLE_FADE_STEP_MS 20 // tick interval per fade step
#define DISPLAY_DEFAULT_BRIGHTNESS 200 // active-screen brightness #define DISPLAY_DEFAULT_BRIGHTNESS 200 // active-screen brightness
// When false, the device never enters sleep while USB power is present (also
// wakes from sleep when USB is plugged back in). Useful when sitting on a
// desk plugged in — also covers battery-less hardware that's always on USB.
// Set true to sleep regardless of power source.
#define IDLE_SLEEP_WHEN_CHARGING false
// When true, a touch on the dark panel wakes the device (first touch is
// consumed for wake only, second touch acts normally). When false, touch is
// fully ignored during sleep — useful if cats/sleeves brushing the panel
// overnight would be a problem.
#define IDLE_WAKE_ON_TOUCH true
+29 -4
View File
@@ -55,10 +55,35 @@ static void touch_read() {
touch_pressed = false; touch_pressed = false;
} }
// Touch never counts as user activity and is fully swallowed while the // Touch policy is driven by IDLE_WAKE_ON_TOUCH:
// panel is dark — avoids accidental wakes and prevents LVGL from secretly // true → a press edge while asleep wakes the device and the first
// toggling splash<->usage behind a black screen. // touch is swallowed (mirrors the button wake-consumption); a
if (idle_is_asleep()) touch_pressed = false; // press while awake counts as activity.
// false → touch never counts as activity and is fully swallowed while
// the panel is dark, so pets/sleeves can't wake it overnight
// and LVGL can't quietly toggle splash<->usage on a black panel.
if (IDLE_WAKE_ON_TOUCH) {
static bool touch_was = false;
static bool touch_wake_swallowed = false;
bool touch_now = touch_pressed;
if (touch_now && !touch_was) {
if (idle_consume_wake_press()) {
touch_wake_swallowed = true;
touch_pressed = false; // hide this press from LVGL
}
} else if (!touch_now && touch_was) {
if (touch_wake_swallowed) {
touch_wake_swallowed = false;
touch_pressed = false; // also hide the corresponding release
}
} else if (touch_now && touch_wake_swallowed) {
// Held finger through wake — keep hiding until release.
touch_pressed = false;
}
touch_was = touch_now;
} else {
if (idle_is_asleep()) touch_pressed = false;
}
} }
// ---- LVGL draw buffers (PSRAM-backed, partial render) ---- // ---- LVGL draw buffers (PSRAM-backed, partial render) ----
+7
View File
@@ -8,6 +8,7 @@
static int cached_pct = -1; static int cached_pct = -1;
static bool cached_charging = false; static bool cached_charging = false;
static bool cached_vbus = false;
static bool pwr_pressed_flag = false; static bool pwr_pressed_flag = false;
static uint32_t last_battery_ms = 0; static uint32_t last_battery_ms = 0;
static uint32_t last_charging_ms = 0; static uint32_t last_charging_ms = 0;
@@ -30,6 +31,7 @@ void power_init(void) {
pmu.enableIRQ(XPOWERS_AXP2101_PKEY_SHORT_IRQ); pmu.enableIRQ(XPOWERS_AXP2101_PKEY_SHORT_IRQ);
cached_charging = pmu.isCharging(); cached_charging = pmu.isCharging();
cached_vbus = pmu.isVbusIn();
cached_pct = pmu.getBatteryPercent(); cached_pct = pmu.getBatteryPercent();
} }
@@ -39,6 +41,7 @@ void power_tick(void) {
if (now - last_charging_ms >= CHARGING_POLL_MS) { if (now - last_charging_ms >= CHARGING_POLL_MS) {
last_charging_ms = now; last_charging_ms = now;
cached_charging = pmu.isCharging(); cached_charging = pmu.isCharging();
cached_vbus = pmu.isVbusIn();
} }
if (now - last_battery_ms >= BATTERY_POLL_MS) { if (now - last_battery_ms >= BATTERY_POLL_MS) {
@@ -65,6 +68,10 @@ bool power_is_charging(void) {
return cached_charging; return cached_charging;
} }
bool power_is_vbus_in(void) {
return cached_vbus;
}
bool power_pwr_pressed(void) { bool power_pwr_pressed(void) {
if (pwr_pressed_flag) { if (pwr_pressed_flag) {
pwr_pressed_flag = false; pwr_pressed_flag = false;
+1
View File
@@ -4,4 +4,5 @@ void power_init(void);
void power_tick(void); void power_tick(void);
int power_battery_pct(void); // 0-100, or -1 if no battery int power_battery_pct(void); // 0-100, or -1 if no battery
bool power_is_charging(void); bool power_is_charging(void);
bool power_is_vbus_in(void); // USB cable present (true even with no battery)
bool power_pwr_pressed(void); // true once per AXP2101 PWR button short-press bool power_pwr_pressed(void); // true once per AXP2101 PWR button short-press