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

@@ -6,11 +6,23 @@
#include "esp_timer.h"
#include "domain.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
static const char *TAG = "control_plane_lifecycle";
static SemaphoreHandle_t s_lock;
static QueueHandle_t s_power_key_queue;
static TaskHandle_t s_power_key_task;
typedef enum {
POWER_KEY_CMD_SHUTDOWN_REQUEST = 0,
} power_key_cmd_t;
static const uint16_t POWER_KEY_QUEUE_LEN = 4;
static const uint16_t POWER_KEY_TASK_STACK = 4096;
static const uint16_t POWER_KEY_STOP_RETRY_COUNT = 30;
static const uint16_t POWER_KEY_STOP_RETRY_INTERVAL_MS = 100;
typedef struct {
control_plane_lifecycle_state_t state;
esp_err_t last_error;
@@ -96,6 +108,89 @@ static esp_err_t lifecycle_stop_system_runtime(void) {
return system_runtime_shutdown();
}
static void lifecycle_power_key_event_cb(domain_power_event_t event, void *user_data) {
(void)user_data;
if (event != DOMAIN_POWER_EVENT_SHUTDOWN_REQUEST || s_power_key_queue == NULL) {
return;
}
power_key_cmd_t cmd = POWER_KEY_CMD_SHUTDOWN_REQUEST;
BaseType_t queued = xQueueSend(s_power_key_queue, &cmd, 0);
if (queued == pdTRUE) {
return;
}
power_key_cmd_t dropped = POWER_KEY_CMD_SHUTDOWN_REQUEST;
(void)xQueueReceive(s_power_key_queue, &dropped, 0);
(void)xQueueSend(s_power_key_queue, &cmd, 0);
}
static void lifecycle_power_key_task_main(void *arg) {
(void)arg;
while (true) {
power_key_cmd_t cmd = POWER_KEY_CMD_SHUTDOWN_REQUEST;
if (xQueueReceive(s_power_key_queue, &cmd, portMAX_DELAY) != pdTRUE) {
continue;
}
if (cmd != POWER_KEY_CMD_SHUTDOWN_REQUEST) {
continue;
}
ESP_LOGW(TAG, "POWER_KEY long press detected: stopping services and powering off");
esp_err_t stop_rc = ESP_ERR_INVALID_STATE;
for (uint16_t attempt = 0; attempt < POWER_KEY_STOP_RETRY_COUNT; ++attempt) {
stop_rc = control_plane_lifecycle_stop();
if (stop_rc != ESP_ERR_INVALID_STATE) {
break;
}
vTaskDelay(pdMS_TO_TICKS(POWER_KEY_STOP_RETRY_INTERVAL_MS));
}
if (stop_rc != ESP_OK && stop_rc != ESP_ERR_INVALID_STATE) {
ESP_LOGW(TAG, "lifecycle stop during power-off failed: %s", esp_err_to_name(stop_rc));
}
// Keep a tiny gap so last logs/stop actions can flush before hold release.
vTaskDelay(pdMS_TO_TICKS(50));
esp_err_t power_rc = system_runtime_power_off();
if (power_rc != ESP_OK && power_rc != ESP_ERR_NOT_SUPPORTED) {
ESP_LOGE(TAG, "system runtime power-off failed: %s", esp_err_to_name(power_rc));
}
}
}
static esp_err_t lifecycle_power_key_worker_init(void) {
if (s_power_key_queue == NULL) {
s_power_key_queue = xQueueCreate(POWER_KEY_QUEUE_LEN, sizeof(power_key_cmd_t));
if (s_power_key_queue == NULL) {
return ESP_ERR_NO_MEM;
}
}
if (s_power_key_task == NULL) {
BaseType_t ok = xTaskCreate(lifecycle_power_key_task_main,
"power_key_ctrl",
POWER_KEY_TASK_STACK,
NULL,
5,
&s_power_key_task);
if (ok != pdPASS) {
vQueueDelete(s_power_key_queue);
s_power_key_queue = NULL;
return ESP_ERR_NO_MEM;
}
}
return system_runtime_set_power_event_callback(lifecycle_power_key_event_cb, NULL);
}
static void lifecycle_power_key_worker_unbind(void) {
(void)system_runtime_set_power_event_callback(NULL, NULL);
}
typedef esp_err_t (*lifecycle_step_fn_t)(void);
static esp_err_t lifecycle_run_step_with_retry(const char *stage, lifecycle_step_fn_t fn) {
@@ -162,6 +257,12 @@ esp_err_t control_plane_lifecycle_start(void) {
}
system_started = true;
failed_stage = "power_key_binding";
rc = lifecycle_power_key_worker_init();
if (rc != ESP_OK) {
goto start_failed;
}
failed_stage = "printer_protocol";
rc = lifecycle_run_step_with_retry("printer_protocol", lifecycle_start_printer_protocol);
if (rc != ESP_OK) {
@@ -194,6 +295,7 @@ start_failed:
(void)lifecycle_stop_printer_protocol();
}
if (system_started) {
lifecycle_power_key_worker_unbind();
(void)lifecycle_stop_system_runtime();
}
@@ -228,6 +330,8 @@ esp_err_t control_plane_lifecycle_stop(void) {
lifecycle_set_state_locked(CONTROL_PLANE_LIFECYCLE_STATE_STOPPING, ESP_OK, "stopping");
xSemaphoreGive(s_lock);
lifecycle_power_key_worker_unbind();
esp_err_t first_err = ESP_OK;
esp_err_t rc = lifecycle_stop_voice();