feat(power): switch to physical power-key shutdown control

This commit is contained in:
admin
2026-03-02 15:16:23 +08:00
parent 673b257c4f
commit 67922d37b9
8 changed files with 396 additions and 23 deletions

View File

@@ -8,6 +8,7 @@ idf_component_register(
"src/display_lcd_decode_image.c"
"src/display_st7789p3.c"
"src/platform_mic_key.c"
"src/platform_power_key.c"
"src/voice_audio.c"
"src/runtime_policy.c"
INCLUDE_DIRS

View File

@@ -90,6 +90,21 @@ esp_err_t platform_mic_key_init(void);
void platform_mic_key_deinit(void);
esp_err_t platform_mic_key_set_event_callback(platform_mic_key_event_cb_t cb, void *user_data);
// ---------- power_key ----------
typedef enum {
PLATFORM_POWER_KEY_EVENT_LONG_PRESS = 0,
PLATFORM_POWER_KEY_EVENT_PRESS_UP,
} platform_power_key_event_t;
typedef void (*platform_power_key_event_cb_t)(platform_power_key_event_t event, void *user_data);
esp_err_t platform_power_key_init(void);
void platform_power_key_deinit(void);
esp_err_t platform_power_key_set_event_callback(platform_power_key_event_cb_t cb, void *user_data);
// Controls the board hold line: true keeps power on, false releases hold.
esp_err_t platform_power_hold_set(bool hold_on);
// ---------- voice_audio ----------
typedef struct {
uint32_t sample_rate;

View File

@@ -239,3 +239,23 @@ esp_err_t platform_bootstrap_init(void) {
s_initialized = true;
return ESP_OK;
}
esp_err_t platform_power_hold_set(bool hold_on) {
if (CONFIG_TQ_POWER_HOLD_PIN < 0) {
return ESP_ERR_NOT_SUPPORTED;
}
int level = hold_on ? 1 : 0;
if (!s_board_gpio_initialized) {
return board_gpio_config_output(CONFIG_TQ_POWER_HOLD_PIN, level, "power_hold");
}
esp_err_t err = gpio_set_level(CONFIG_TQ_POWER_HOLD_PIN, level);
if (err != ESP_OK) {
ESP_LOGE(TAG, "gpio_set_level failed: power_hold pin=%d level=%d err=%s",
CONFIG_TQ_POWER_HOLD_PIN,
level,
esp_err_to_name(err));
}
return err;
}

View File

@@ -0,0 +1,125 @@
#include "platform.h"
#include <stddef.h>
#include "button_gpio.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "iot_button.h"
#include "sdkconfig.h"
static const char *TAG = "platform_power_key";
static const uint16_t POWER_KEY_SHORT_PRESS_MS = 40;
static const uint16_t POWER_KEY_LONG_PRESS_MS = 2000;
static button_handle_t s_power_key_button;
static platform_power_key_event_cb_t s_event_cb;
static void *s_event_cb_user_data;
static portMUX_TYPE s_event_cb_lock = portMUX_INITIALIZER_UNLOCKED;
static void power_key_dispatch_event(platform_power_key_event_t event) {
platform_power_key_event_cb_t cb = NULL;
void *user_data = NULL;
portENTER_CRITICAL(&s_event_cb_lock);
cb = s_event_cb;
user_data = s_event_cb_user_data;
portEXIT_CRITICAL(&s_event_cb_lock);
if (cb != NULL) {
cb(event, user_data);
}
}
static void power_key_long_press_cb(void *button_handle, void *usr_data) {
(void)button_handle;
(void)usr_data;
power_key_dispatch_event(PLATFORM_POWER_KEY_EVENT_LONG_PRESS);
}
static void power_key_press_up_cb(void *button_handle, void *usr_data) {
(void)button_handle;
(void)usr_data;
power_key_dispatch_event(PLATFORM_POWER_KEY_EVENT_PRESS_UP);
}
esp_err_t platform_power_key_init(void) {
if (CONFIG_TQ_POWER_KEY_PIN < 0) {
ESP_LOGW(TAG, "POWER_KEY disabled by config: pin=%d", CONFIG_TQ_POWER_KEY_PIN);
return ESP_ERR_NOT_SUPPORTED;
}
if (s_power_key_button != NULL) {
return ESP_OK;
}
button_config_t button_cfg = {
.long_press_time = POWER_KEY_LONG_PRESS_MS,
.short_press_time = POWER_KEY_SHORT_PRESS_MS,
};
button_gpio_config_t gpio_cfg = {
.gpio_num = CONFIG_TQ_POWER_KEY_PIN,
.active_level = 0,
.enable_power_save = false,
.disable_pull = false,
};
esp_err_t err = iot_button_new_gpio_device(&button_cfg, &gpio_cfg, &s_power_key_button);
if (err != ESP_OK) {
ESP_LOGE(TAG,
"iot_button_new_gpio_device failed: pin=%d err=%s",
CONFIG_TQ_POWER_KEY_PIN,
esp_err_to_name(err));
return err;
}
err = iot_button_register_cb(s_power_key_button,
BUTTON_LONG_PRESS_START,
NULL,
power_key_long_press_cb,
NULL);
if (err != ESP_OK) {
ESP_LOGE(TAG, "register BUTTON_LONG_PRESS_START failed: %s", esp_err_to_name(err));
(void)iot_button_delete(s_power_key_button);
s_power_key_button = NULL;
return err;
}
err = iot_button_register_cb(s_power_key_button, BUTTON_PRESS_UP, NULL, power_key_press_up_cb, NULL);
if (err != ESP_OK) {
ESP_LOGE(TAG, "register BUTTON_PRESS_UP failed: %s", esp_err_to_name(err));
(void)iot_button_delete(s_power_key_button);
s_power_key_button = NULL;
return err;
}
ESP_LOGI(TAG,
"POWER_KEY initialized: gpio=%d active_level=low long_press_ms=%u",
CONFIG_TQ_POWER_KEY_PIN,
(unsigned)POWER_KEY_LONG_PRESS_MS);
return ESP_OK;
}
void platform_power_key_deinit(void) {
if (s_power_key_button != NULL) {
(void)iot_button_delete(s_power_key_button);
s_power_key_button = NULL;
}
portENTER_CRITICAL(&s_event_cb_lock);
s_event_cb = NULL;
s_event_cb_user_data = NULL;
portEXIT_CRITICAL(&s_event_cb_lock);
}
esp_err_t platform_power_key_set_event_callback(platform_power_key_event_cb_t cb, void *user_data) {
if (s_power_key_button == NULL) {
return ESP_ERR_INVALID_STATE;
}
portENTER_CRITICAL(&s_event_cb_lock);
s_event_cb = cb;
s_event_cb_user_data = user_data;
portEXIT_CRITICAL(&s_event_cb_lock);
return ESP_OK;
}