/* * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include #include #include "esp_err.h" #ifdef __cplusplus extern "C" { #endif typedef enum { CONTROL_PLANE_DIRECTION_CMD_UNKNOWN = 0, CONTROL_PLANE_DIRECTION_CMD_HELP, CONTROL_PLANE_DIRECTION_CMD_POSITION, CONTROL_PLANE_DIRECTION_CMD_DIRECTION, CONTROL_PLANE_DIRECTION_CMD_CALIBRATE } control_plane_direction_command_t; typedef enum { CONTROL_PLANE_MODEL_COMMAND_UNKNOWN = 0, CONTROL_PLANE_MODEL_COMMAND_DIRECTION, CONTROL_PLANE_MODEL_COMMAND_CALIBRATE, CONTROL_PLANE_MODEL_COMMAND_CHOUQIAN, CONTROL_PLANE_MODEL_COMMAND_WEATHER, CONTROL_PLANE_MODEL_COMMAND_LUCKY_COLOR, } control_plane_model_command_type_t; typedef void (*control_plane_model_command_callback_t)( control_plane_model_command_type_t command_type, const char *value, size_t value_index, bool value_index_valid, void *user_data); typedef enum { CONTROL_PLANE_MULTIMODAL_RESPOND_TYPE_TRANSCRIPT = 0, CONTROL_PLANE_MULTIMODAL_RESPOND_TYPE_PROMPT, } control_plane_multimodal_respond_type_t; typedef struct { control_plane_multimodal_respond_type_t type; const char *text; /* * Optional JSON object serialized as payload.parameters for * RequestToRespond. Use this for documented fields such as images and * biz_params. NULL or empty means no parameters object is sent. */ const char *parameters_json; } control_plane_multimodal_respond_request_t; typedef struct { /* * JSON object serialized as payload.parameters for UpdateInfo. Expected * fields follow docs/websocket.md: images, client_info, and biz_params. */ const char *parameters_json; } control_plane_multimodal_update_info_request_t; typedef enum { CONTROL_PLANE_OTA_STATE_DISABLED = 0, CONTROL_PLANE_OTA_STATE_IDLE, CONTROL_PLANE_OTA_STATE_WAITING_FOR_NETWORK, CONTROL_PLANE_OTA_STATE_WAITING_FOR_RESOURCES, CONTROL_PLANE_OTA_STATE_CHECKING, CONTROL_PLANE_OTA_STATE_WAITING_FOR_CONFIRMATION, CONTROL_PLANE_OTA_STATE_DOWNLOADING, CONTROL_PLANE_OTA_STATE_READY_TO_REBOOT, CONTROL_PLANE_OTA_STATE_ERROR, CONTROL_PLANE_OTA_STATE_STOPPED, } control_plane_ota_state_t; typedef struct { control_plane_ota_state_t state; bool running; bool forced; bool confirmed; char target_version[32]; uint64_t bytes_received; uint64_t total_bytes; uint32_t consecutive_failures; int last_http_status; esp_err_t last_error; } control_plane_ota_snapshot_t; esp_err_t control_plane_init(void); /** * @brief Start battery sensing and charge-status presentation. * * Safe to call repeatedly. This service is intentionally started before * connectivity bootstrap so battery and charger indications do not depend on * Wi-Fi, provisioning, or server readiness. */ esp_err_t control_plane_battery_service_start(void); /** * @brief Prepare platform-backed persistent storage before runtime workers start. * * This is idempotent and has no Wi-Fi or actuator side effects. It exists so the * composition layer can start non-blocking workers before connectivity bootstrap * without racing NVS-backed stores. */ esp_err_t control_plane_prepare_runtime_storage(void); /** * @brief Parse one direction command without side effects. * * Initialization contract: * - `control_plane_init()` must be called explicitly first. * - No implicit lazy initialization is performed by query/parse APIs. * - Returns `CONTROL_PLANE_DIRECTION_CMD_UNKNOWN` when uninitialized. */ control_plane_direction_command_t control_plane_parse_direction_command(const char *input, size_t *out_direction_index); esp_err_t control_plane_rotate_to_angle(float target_angle); esp_err_t control_plane_rotate_to_direction(size_t direction_index); /** * @brief Parse and execute one direction command line. * * Execution policy: * - `DIRECTION`: perform rotation to parsed target direction. * - `CALIBRATE`: run calibration with default timeout policy. * - `HELP`/`POSITION`/`UNKNOWN`: parse only, no actuator side effects. * * Returns: * - `ESP_OK` for non-action commands or successful action commands. * - Error from action executor for failing `DIRECTION`/`CALIBRATE`. */ esp_err_t control_plane_execute_direction_command(const char *input, control_plane_direction_command_t *out_command, size_t *out_direction_index); /** * @brief Run calibration with explicit timeout budget. * * Semantics: * - `timeout_ms <= 0`: use internal default timeout. * - Returns `ESP_ERR_TIMEOUT` when calibration cannot finish in time. * - If calibration switch is already active at entry, implementation may * perform a bounded release-and-rehome sequence before setting the * calibrated angle. */ esp_err_t control_plane_calibrate_with_timeout(int timeout_ms); esp_err_t control_plane_calibrate(void); /** * @brief Bootstrap Wi-Fi connectivity for runtime. * * Semantics: * - `connect_timeout_ms <= 0`: apply internal default timeout. * - Operation is safe to call repeatedly; existing good state is reused when possible. * - Returns `ESP_OK` when STA is connected or mini-program BLE provisioning is active. * - On timeout/failure, function returns explicit error and does not continue hidden * destructive retries after return. */ esp_err_t control_plane_bootstrap_connectivity(const char *seed_ssid, const char *seed_password, int connect_timeout_ms); bool control_plane_is_sta_connected(void); esp_err_t control_plane_stop_mini_program_provisioning(int timeout_ms); bool control_plane_is_mini_program_provisioning_running(void); /** * @brief Execute the Plan A boot sound policy with bounded caller semantics. * * The current platform voice-prompt backend may return ESP_ERR_NOT_SUPPORTED; * callers should log and continue boot in that case. */ esp_err_t control_plane_play_boot_sound(int timeout_ms); /** * @brief Start multimodal client runtime. * * Semantics: * - Idempotent for repeated calls when runtime is already active. * - Creates/starts required background tasks with bounded startup behavior. * - Returns explicit error when startup cannot complete. */ esp_err_t control_plane_start_multimodal_client(void); /** * @brief Stop multimodal client runtime and owned background tasks. * * Semantics: * - Idempotent and safe to call repeatedly. * - Requests cooperative stop first, then applies bounded waits for worker teardown. * - Returns an explicit error if teardown does not complete. */ esp_err_t control_plane_stop_multimodal_client(void); esp_err_t control_plane_register_model_command_callback(control_plane_model_command_callback_t cb, void *user_data); /** * @brief Cancel an active push2talk speech input. * * Sends the protocol `CancelSpeech` directive for the active multimodal task * and stops local uplink capture. */ esp_err_t control_plane_multimodal_cancel_speech(void); /** * @brief Ask the active multimodal session to respond to local text. * * Requires an active task in `DialogStateChanged(Listening)` state. The request * is encoded as the documented `RequestToRespond` directive. */ esp_err_t control_plane_multimodal_request_to_respond( const control_plane_multimodal_respond_request_t *request); /** * @brief Update per-session multimodal context. * * Encodes `request->parameters_json` as the documented UpdateInfo * `payload.parameters` object. */ esp_err_t control_plane_multimodal_update_info( const control_plane_multimodal_update_info_request_t *request); /** * @brief Start control-plane owned runtime workers. * * This includes model-command dispatch worker and connectivity-gated multimodal startup worker. * Safe to call repeatedly. */ esp_err_t control_plane_start_runtime_workers(void); void control_plane_stop_runtime_workers(void); esp_err_t control_plane_start_ota_service(void); esp_err_t control_plane_stop_ota_service(int timeout_ms); esp_err_t control_plane_get_ota_snapshot(control_plane_ota_snapshot_t *out); /** * @brief Start the staged event observer runtime only. * * This starts the system event dispatcher and key input observer so module * events can be verified through logs. It intentionally does not start LCD, * Wi-Fi, WebSocket, fortune, LAN HTTP, motor, or audio business workers. */ esp_err_t control_plane_start_event_observer_runtime(void); void control_plane_stop_event_observer_runtime(void); /** * @brief Daily fortune policy (control_plane-owned). * * The daily fortune worker is started by `control_plane_start_runtime_workers()` * when `CONFIG_FORTUNE_ENABLE` is set. It waits for STA connectivity and SNTP * time, fetches the favorable-color and wealth-direction result for the local * date, persists it, applies the direction, and reschedules for local 00:00. * * `control_plane_fortune_refresh_now()` requests an immediate refetch+apply * (e.g. after provisioning, or for manual testing). Returns * `ESP_ERR_INVALID_STATE` when the worker is not running and * `ESP_ERR_NOT_SUPPORTED` when the feature is disabled at build time. */ esp_err_t control_plane_fortune_refresh_now(void); esp_err_t control_plane_init_lcd_device(void); esp_err_t control_plane_start_lcd_render_worker(void); void control_plane_start_lcd_render_loop(void); esp_err_t control_plane_request_boot_expression(void); /** * @brief Stop LCD render loop with bounded teardown. * * `timeout_ms < 0` is invalid, zero requests asynchronous stop, and positive * values wait up to the bound before lower layers apply deterministic fallback. */ esp_err_t control_plane_stop_lcd_render_loop(int timeout_ms); /** * @brief Start the factory provisioning serial CLI on the console UART. * * Spawns a control-plane-owned worker that reads `\r\n`-delimited commands and * replies with `OK` / `ERROR ` / JSON lines. Idempotent (a no-op if * already running). Used for device identity provisioning and reading/signing * device-auth key material during manufacturing. */ esp_err_t control_plane_factory_cli_start(void); /** * @brief Stop the factory CLI worker (cooperative request + bounded teardown). * * Idempotent and safe to call repeatedly. */ void control_plane_factory_cli_stop(void); #ifdef __cplusplus } #endif