Files
lucky-cat/components/app_composition/src/runtime/app_composition_default_runtime.c
T

246 lines
9.6 KiB
C

/*
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "app_composition.h"
#include <stdio.h>
#include "control_plane.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#ifndef CONFIG_TQ_BOOT_SEQUENCE_DRY_RUN
#define CONFIG_TQ_BOOT_SEQUENCE_DRY_RUN 0
#endif
#ifndef CONFIG_TQ_BOOT_SOUND_TIMEOUT_MS
#define CONFIG_TQ_BOOT_SOUND_TIMEOUT_MS 3000
#endif
static const char *TAG = "app_comp_boot";
typedef enum {
APP_COMPOSITION_BOOT_STAGE_POWER_HOLD = 1,
APP_COMPOSITION_BOOT_STAGE_STORAGE_PREPARE,
APP_COMPOSITION_BOOT_STAGE_AUDIO_INIT,
APP_COMPOSITION_BOOT_STAGE_BOOT_SOUND,
APP_COMPOSITION_BOOT_STAGE_AUDIO_READY,
APP_COMPOSITION_BOOT_STAGE_LCD_DEVICE,
APP_COMPOSITION_BOOT_STAGE_LCD_RENDER_LOOP,
APP_COMPOSITION_BOOT_STAGE_PLATFORM_DOMAIN,
APP_COMPOSITION_BOOT_STAGE_TURNTABLE_CALIBRATION,
APP_COMPOSITION_BOOT_STAGE_WIFI_BOOTSTRAP,
APP_COMPOSITION_BOOT_STAGE_RUNTIME_WORKERS,
APP_COMPOSITION_BOOT_STAGE_NETWORK_SERVICES,
} app_composition_boot_stage_t;
static void app_composition_log_stage(app_composition_boot_stage_t stage,
const char *name,
const char *event)
{
ESP_LOGI(TAG, "boot stage %02d %-24s event=%s", (int)stage, name, event);
}
static void app_composition_log_stage_result(app_composition_boot_stage_t stage,
const char *name,
esp_err_t result)
{
ESP_LOGI(TAG,
"boot stage %02d %-24s result=%s",
(int)stage,
name,
esp_err_to_name(result));
}
static void app_composition_log_stage_skipped(app_composition_boot_stage_t stage,
const char *name,
const char *reason)
{
ESP_LOGI(TAG, "boot stage %02d %-24s skipped=%s", (int)stage, name, reason);
}
static esp_err_t app_composition_run_plan_a_boot_sequence(void)
{
app_composition_log_stage(APP_COMPOSITION_BOOT_STAGE_POWER_HOLD,
"power_hold",
"configured_or_disabled_by_platform_core");
app_composition_log_stage(APP_COMPOSITION_BOOT_STAGE_STORAGE_PREPARE,
"storage_prepare",
"control_plane_prepare_runtime_storage");
esp_err_t err = control_plane_prepare_runtime_storage();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Runtime storage prepare failed: %s", esp_err_to_name(err));
return err;
}
esp_err_t battery_guard_err = control_plane_battery_apply_boot_guard();
if (battery_guard_err != ESP_OK &&
battery_guard_err != ESP_ERR_NOT_SUPPORTED) {
ESP_LOGW(TAG,
"Battery boot guard failed, continue boot: %s",
esp_err_to_name(battery_guard_err));
}
app_composition_log_stage(APP_COMPOSITION_BOOT_STAGE_AUDIO_INIT,
"audio_init",
"boot_sound_policy_begin");
app_composition_log_stage(APP_COMPOSITION_BOOT_STAGE_BOOT_SOUND,
"boot_sound",
"play_boot_sound_with_timeout");
esp_err_t boot_sound_err =
control_plane_play_boot_sound(CONFIG_TQ_BOOT_SOUND_TIMEOUT_MS);
if (boot_sound_err != ESP_OK) {
ESP_LOGW(TAG,
"Boot sound unavailable, continue boot: %s",
esp_err_to_name(boot_sound_err));
}
app_composition_log_stage(APP_COMPOSITION_BOOT_STAGE_AUDIO_READY,
"audio_ready",
"boot_sound_policy_end_keep_runtime");
#if CONFIG_TQ_SCREEN_ENABLE
app_composition_log_stage(APP_COMPOSITION_BOOT_STAGE_LCD_DEVICE,
"lcd_device",
"control_plane_init_lcd_device");
esp_err_t lcd_err = control_plane_init_lcd_device();
app_composition_log_stage_result(APP_COMPOSITION_BOOT_STAGE_LCD_DEVICE,
"lcd_device",
lcd_err);
bool lcd_ready = (lcd_err == ESP_OK);
if (lcd_ready) {
app_composition_log_stage(APP_COMPOSITION_BOOT_STAGE_LCD_RENDER_LOOP,
"lcd_render_loop",
"control_plane_start_lcd_render_worker");
esp_err_t lcd_worker_err = control_plane_start_lcd_render_worker();
app_composition_log_stage_result(APP_COMPOSITION_BOOT_STAGE_LCD_RENDER_LOOP,
"lcd_render_loop",
lcd_worker_err);
if (lcd_worker_err != ESP_OK) {
lcd_ready = false;
}
} else {
app_composition_log_stage_skipped(APP_COMPOSITION_BOOT_STAGE_LCD_RENDER_LOOP,
"lcd_render_loop",
"lcd_device_unavailable");
}
#else
app_composition_log_stage_skipped(APP_COMPOSITION_BOOT_STAGE_LCD_DEVICE,
"lcd_device",
"disabled_by_config");
app_composition_log_stage_skipped(APP_COMPOSITION_BOOT_STAGE_LCD_RENDER_LOOP,
"lcd_render_loop",
"disabled_by_config");
#endif
app_composition_log_stage(APP_COMPOSITION_BOOT_STAGE_PLATFORM_DOMAIN,
"platform_domain",
"control_plane_init");
err = control_plane_init();
if (err != ESP_OK) {
ESP_LOGE(TAG, "control_plane_init failed: %s", esp_err_to_name(err));
return err;
}
esp_err_t battery_err = control_plane_battery_service_start();
if (battery_err != ESP_OK && battery_err != ESP_ERR_NOT_SUPPORTED) {
ESP_LOGW(TAG,
"Early battery service start failed, continue boot: %s",
esp_err_to_name(battery_err));
}
#if CONFIG_TQ_FACTORY_CLI_ENABLE
err = control_plane_factory_cli_start();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Factory CLI start failed: %s", esp_err_to_name(err));
return err;
}
#endif
#if CONFIG_TQ_SCREEN_ENABLE
if (lcd_ready) {
esp_err_t expression_err = control_plane_request_boot_expression();
if (expression_err != ESP_OK) {
ESP_LOGW(TAG,
"Boot LCD expression request failed: %s",
esp_err_to_name(expression_err));
}
}
#endif
#if CONFIG_TQ_BOOT_TURNTABLE_CALIBRATION_ENABLE
app_composition_log_stage(APP_COMPOSITION_BOOT_STAGE_TURNTABLE_CALIBRATION,
"turntable_calibration",
"control_plane_calibrate");
esp_err_t calibration_err = control_plane_calibrate();
if (calibration_err != ESP_OK) {
ESP_LOGW(TAG,
"Boot turntable calibration failed, continue degraded: %s",
esp_err_to_name(calibration_err));
}
#else
app_composition_log_stage_skipped(APP_COMPOSITION_BOOT_STAGE_TURNTABLE_CALIBRATION,
"turntable_calibration",
"disabled_by_config");
#endif
app_composition_log_stage(APP_COMPOSITION_BOOT_STAGE_WIFI_BOOTSTRAP,
"wifi_bootstrap",
"control_plane_bootstrap_connectivity");
esp_err_t wifi_err = control_plane_bootstrap_connectivity(CONFIG_MULTIMODAL_WIFI_SSID,
CONFIG_MULTIMODAL_WIFI_PASSWORD,
CONFIG_MULTIMODAL_CONNECT_TIMEOUT_MS);
if (wifi_err != ESP_OK) {
ESP_LOGW(TAG, "Connectivity bootstrap failed: %s", esp_err_to_name(wifi_err));
}
bool provisioning_active = control_plane_is_mini_program_provisioning_running();
app_composition_log_stage(APP_COMPOSITION_BOOT_STAGE_RUNTIME_WORKERS,
"runtime_workers",
provisioning_active
? "deferred_until_ble_provisioning_completes"
: "control_plane_start_runtime_workers");
if (provisioning_active) {
ESP_LOGI(TAG,
"Full runtime workers deferred while BLE provisioning is active");
} else {
err = control_plane_start_runtime_workers();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Runtime worker start failed: %s", esp_err_to_name(err));
return err;
}
}
app_composition_log_stage(APP_COMPOSITION_BOOT_STAGE_NETWORK_SERVICES,
"network_services",
provisioning_active
? "deferred_with_runtime_workers"
: "started_by_runtime_workers_after_readiness");
return ESP_OK;
}
esp_err_t app_composition_start_default_runtime(void)
{
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
ESP_LOGI(TAG, "========================================");
ESP_LOGI(TAG, " App Composition Boot Plan A");
ESP_LOGI(TAG, " dry_run=%d", CONFIG_TQ_BOOT_SEQUENCE_DRY_RUN);
ESP_LOGI(TAG, "========================================");
#if CONFIG_TQ_BOOT_SEQUENCE_DRY_RUN
ESP_LOGE(TAG, "Plan A dry-run is enabled; disable CONFIG_TQ_BOOT_SEQUENCE_DRY_RUN");
return ESP_ERR_NOT_SUPPORTED;
#else
return app_composition_run_plan_a_boot_sequence();
#endif
}