Files
t-embed-insecam-widget/main/power.c
T
Juli 89dfdf09a6 24 favourite slots and a Power off menu entry
Power off drops the peripheral rail (PWR_ON low), sleeps the panel and
puts the chip into deep sleep with ext1 wake armed on the encoder pins,
choosing any-low or any-high from the knob's resting state so a single
detent wakes it. The button (GPIO0) is not a wake source on purpose.
2026-09-17 02:20:48 +02:00

61 lines
2.1 KiB
C

#include "power.h"
#include "board.h"
#include "display.h"
#include "leds.h"
#include "ui.h"
#include "driver/gpio.h"
#include "driver/rtc_io.h"
#include "esp_log.h"
#include "esp_sleep.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static const char *TAG = "power";
// Arm ext1 wake on the encoder pins. The S3 has one level mode for all selected
// pins, so pick it from the knob's resting state: pins that are high wake on
// low; if both rest low, wake on high. A single detent toggles both pins.
static void arm_knob_wakeup(void)
{
int pins[2] = {board->enc_a, board->enc_b};
uint64_t high = 0, low = 0;
for (int i = 0; i < 2; i++) {
rtc_gpio_init(pins[i]);
rtc_gpio_set_direction(pins[i], RTC_GPIO_MODE_INPUT_ONLY);
rtc_gpio_pulldown_dis(pins[i]);
rtc_gpio_pullup_en(pins[i]);
}
vTaskDelay(pdMS_TO_TICKS(5));
for (int i = 0; i < 2; i++) {
if (rtc_gpio_get_level(pins[i])) high |= 1ULL << pins[i];
else low |= 1ULL << pins[i];
}
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); // keeps the RTC pull-ups alive
if (high) esp_sleep_enable_ext1_wakeup_io(high, ESP_EXT1_WAKEUP_ANY_LOW);
else esp_sleep_enable_ext1_wakeup_io(low, ESP_EXT1_WAKEUP_ANY_HIGH);
ESP_LOGI(TAG, "wake on knob: A%d=%d B%d=%d", board->enc_a, !!(high & (1ULL << board->enc_a)),
board->enc_b, !!(high & (1ULL << board->enc_b)));
}
void power_off(void)
{
ESP_LOGI(TAG, "powering off");
ui_status("Off", "turn the knob to wake");
vTaskDelay(pdMS_TO_TICKS(700));
leds_set_mode(LED_OFF, 0);
vTaskDelay(pdMS_TO_TICKS(80)); // let the ring task push the dark frame
display_off();
esp_wifi_stop();
gpio_set_level(board->pwr_en, 0); // peripheral rail off (screen, ring, codec)
arm_knob_wakeup();
esp_deep_sleep_start();
}
void power_report_wakeup(void)
{
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
if (cause == ESP_SLEEP_WAKEUP_EXT1) ESP_LOGI(TAG, "woken by the knob");
else if (cause != ESP_SLEEP_WAKEUP_UNDEFINED) ESP_LOGI(TAG, "wakeup cause %d", cause);
}