From e82f0ac137fa4695158d0cc5a40374fac6c820c0 Mon Sep 17 00:00:00 2001 From: Juli Date: Thu, 17 Sep 2026 15:12:53 +0200 Subject: [PATCH] Require the button to confirm a knob wake A knob turn still wakes the chip (the RTC can't tell gestures apart), but the firmware now stays dark and checks the button: held while turning it boots at once; otherwise the ring glows for 2.5 s waiting for a click and goes back to deep sleep if none comes. Screen and Wi-Fi never start for an accidental nudge. --- README.md | 9 +++++---- main/main.c | 1 + main/power.c | 29 +++++++++++++++++++++++++++++ main/power.h | 4 ++++ 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 245b792..fb0eaf4 100644 --- a/README.md +++ b/README.md @@ -76,10 +76,11 @@ Entries: off**, the board name with its IP, and the power source. *Power off* switches the peripheral rail off (screen, ring, codec) and puts the -ESP32-S3 into deep sleep; turning the knob wakes it and it boots as normal. The -encoder's push button is deliberately not a wake source: it is GPIO 0, and a -press that is still held when the chip resets would land it in the ROM -bootloader instead. +ESP32-S3 into deep sleep. To wake it, **hold the button and turn the knob** — +or turn it and then click within 2.5 s while the ring glows softly. A plain +nudge of the knob wakes the chip (the RTC can't tell gestures apart) but the +firmware notices the missing button and goes straight back to sleep without +ever lighting the screen. The menu closes by itself after 45 s without input. diff --git a/main/main.c b/main/main.c index 0a3e136..812b1d6 100644 --- a/main/main.c +++ b/main/main.c @@ -34,6 +34,7 @@ void app_main(void) settings_init(); leds_init(); leds_set_brightness(settings.led_brightness); + power_confirm_wake(); // may go back to sleep instead of returning leds_set_mode(LED_BREATHE, 0x404040); display_init(); diff --git a/main/power.c b/main/power.c index 53a2e98..72137a9 100644 --- a/main/power.c +++ b/main/power.c @@ -7,6 +7,7 @@ #include "driver/rtc_io.h" #include "esp_log.h" #include "esp_sleep.h" +#include "esp_timer.h" #include "esp_wifi.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -52,6 +53,34 @@ void power_off(void) esp_deep_sleep_start(); } +#define CONFIRM_WINDOW_MS 2500 + +void power_confirm_wake(void) +{ + if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_EXT1) return; + gpio_config_t btn = {.pin_bit_mask = 1ULL << board->enc_btn, .mode = GPIO_MODE_INPUT, .pull_up_en = 1}; + gpio_config(&btn); + if (!gpio_get_level(board->enc_btn)) { + ESP_LOGI(TAG, "wake confirmed: button held while turning"); + return; + } + leds_set_mode(LED_BREATHE, 0x302838); // soft hint: "click to wake" + int64_t deadline = esp_timer_get_time() / 1000 + CONFIRM_WINDOW_MS; + while (esp_timer_get_time() / 1000 < deadline) { + if (!gpio_get_level(board->enc_btn)) { + ESP_LOGI(TAG, "wake confirmed: click"); + return; + } + vTaskDelay(pdMS_TO_TICKS(20)); + } + ESP_LOGI(TAG, "knob nudge without the button; back to sleep"); + leds_set_mode(LED_OFF, 0); + vTaskDelay(pdMS_TO_TICKS(80)); + gpio_set_level(board->pwr_en, 0); + arm_knob_wakeup(); + esp_deep_sleep_start(); +} + void power_report_wakeup(void) { esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); diff --git a/main/power.h b/main/power.h index c37499b..2d87341 100644 --- a/main/power.h +++ b/main/power.h @@ -3,3 +3,7 @@ void power_off(void) __attribute__((noreturn)); // Logs how we came up (cold boot vs. knob wake). void power_report_wakeup(void); +// After a knob wake, insists on the button: held while turning, or clicked within a +// short window while the ring glows. Otherwise goes straight back to sleep (no return). +// Returns normally on a cold boot or a confirmed wake. Needs the LED driver up. +void power_confirm_wake(void);