ESP CLI Service
简介
CLI Service 是 ESP Service 的子类,把 ESP-IDF 控制台的串口交互嵌入服务生命周期。它提供两层命令:内置静态系统命令,以及由服务管理器驱动的动态服务命令与工具命令。通过串口终端即可完成交互式调试与运行时控制。
备注
需要 ESP-IDF >= 5.4。
功能清单
UART REPL 集成:
esp_consoleREPL 直接嵌入服务生命周期,调用esp_service_start()时启动,停止/销毁时关闭内置系统命令:自动注册
sys_heap、sys_chip、sys_uptime、sys_reboot静态命令:通过
esp_cli_service_register_static_command()在 REPL 启动前后随时注册任意esp_console_cmd_t动态
svc命令:从终端列出、查看和控制(start/stop/pause/resume)已跟踪的服务动态
tool命令:枚举并调用esp_service_manager暴露的 JSON Schema 工具,支持key=value和--json两种参数传入方式所有公开 API 由内部互斥锁保护,可从任意任务安全调用
技术拆解
命令体系
REPL 上挂载的命令分为三类:内置系统命令始终可用;应用通过 esp_cli_service_register_static_command() 注册的静态命令;以及在绑定 esp_service_manager 后才可用的 svc / tool 动态命令。调用 esp_service_start() 后 REPL 任务被创建,所有待注册的静态命令随即注册到 esp_console。
flowchart TD
UART[UART 终端] --> REPL[esp_console REPL]
REPL --> Sys["内置 sys_* 命令"]
REPL --> Static["静态命令"]
REPL --> Dyn["动态命令(需绑定 manager)"]
Dyn --> Svc["svc 命令:已跟踪服务 / manager"]
Dyn --> Tool["tool 命令:manager 工具注册表"]
esp_cli_service_config_t cfg = ESP_CLI_SERVICE_CONFIG_DEFAULT();
cfg.prompt = "app>";
esp_cli_service_t *cli = NULL;
esp_cli_service_create(&cfg, &cli);
esp_cli_service_track_service(cli, (esp_service_t *)my_svc, "audio");
const esp_console_cmd_t my_cmd = {
.command = "version",
.help = "Print firmware version",
.func = cmd_version,
};
esp_cli_service_register_static_command(cli, &my_cmd);
esp_service_start((esp_service_t *)cli);
svc 与 tool 命令
svc 命令(list / info / start / stop / pause / resume)优先展示通过 esp_cli_service_track_service() 显式跟踪的服务,其次是绑定的 esp_service_manager 中登记的服务。tool 命令(list / info / call)枚举管理器暴露的 JSON Schema 工具;tool call 会按工具的 inputSchema 把 key=value 键值对序列化成 JSON 对象,支持 string、integer、number、boolean 类型,遇到 array 或 object 等复杂类型时改用 --json 传入原始 JSON 参数。管理器通过配置中的 manager 字段或运行期调用 esp_cli_service_bind_manager() 绑定,两种动态命令都依赖这一步。
应用示例
components/esp_cli_service/examples/提供独立示例,执行idf.py set-target <chip>后idf.py build flash monitor即可上板体验。
FAQ
Q1:串口终端上没有出现提示符怎么办?
先确认已调用 esp_service_start()(REPL 任务只在启动时创建),再检查终端模拟器选择的 UART 端口和波特率是否匹配 IDF menuconfig 中配置的 console UART;如果注册的命令分配了较多数据,默认 4096 字节的 task_stack 未必够用,需要适当增大。
Q2:为什么 ``svc`` / ``tool`` 命令提示 “manager not bound”?
这两类动态命令都需要先绑定 esp_service_manager:在配置中设置 cfg.manager,或在运行期调用 esp_cli_service_bind_manager() 之后再使用。
API 参考
Header File
Functions
-
esp_err_t esp_cli_service_create(const esp_cli_service_config_t *cfg, esp_cli_service_t **out)
Create a CLI service handle (UART REPL backed by esp_console)
备注
Not ISR-safe. Not thread-safe for concurrent creation of the same logical instance; typical use is from one init task. May allocate heap memory.
备注
Internal mutex acquisition may block briefly when contended.
- 参数:
cfg – [in] Configuration;
struct_sizemust equalsizeof(esp_cli_service_config_t)out – [out] Receives new handle on success; set to NULL on error
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG cfg or out is NULL, or struct_size is wrong
ESP_ERR_NO_MEM Allocation failed
-
esp_err_t esp_cli_service_destroy(esp_cli_service_t *svc)
Destroy a CLI service and free its resources.
Stops the REPL if running, frees tracked/static command state, and invalidates @a svc.
备注
After this returns, svc must not be used even if the return code is not ESP_OK (resources are still released).
备注
Not ISR-safe. Not thread-safe against concurrent use of svc or its REPL task; call when the service is quiesced.
- 参数:
svc – [in] Handle from esp_cli_service_create
- 返回:
ESP_OK On success.
ESP_ERR_INVALID_ARG svc is NULL.
Other Error from underlying service teardown; all resources are freed regardless.
-
esp_err_t esp_cli_service_bind_manager(esp_cli_service_t *svc, esp_service_manager_t *mgr)
Bind or replace the service manager used for dynamic
svc/toolcommands.备注
Not ISR-safe. Thread-safe with other APIs on the same handle (mutex held briefly). May block briefly when acquiring an internal mutex.
- 参数:
svc – [in] Service handle
mgr – [in] Manager pointer (may be NULL to clear)
- 返回:
ESP_OK Manager bound.
ESP_ERR_INVALID_ARG svc is NULL.
ESP_ERR_TIMEOUT Mutex acquisition timed out.
-
esp_err_t esp_cli_service_track_service(esp_cli_service_t *svc, esp_service_t *service, const char *category)
Track a service by name for
svclist / lifecycle commands.If the name already exists, updates category and service pointer.
备注
Not ISR-safe. Thread-safe with other APIs on the same handle.
- 参数:
svc – [in] Service handle
service – [in] Service to track (name from
esp_service_get_name)category – [in] Category string for display (may be NULL, stored as empty string)
- 返回:
ESP_OK Tracked (created or updated).
ESP_ERR_INVALID_ARG svc or service is NULL; service name is empty.
ESP_ERR_NO_MEM Allocation failed.
ESP_ERR_TIMEOUT Mutex acquisition timed out.
Other Error from esp_service_get_name.
-
esp_err_t esp_cli_service_untrack_service(esp_cli_service_t *svc, const char *name)
Remove a tracked service entry by logical service name.
备注
Not ISR-safe. Thread-safe with other APIs on the same handle.
- 参数:
svc – [in] Service handle
name – [in] Service name previously tracked
- 返回:
ESP_OK Service untracked.
ESP_ERR_INVALID_ARG svc is NULL or name is empty.
ESP_ERR_NOT_FOUND name not in the tracked list.
ESP_ERR_TIMEOUT Mutex acquisition timed out.
-
esp_err_t esp_cli_service_register_static_command(esp_cli_service_t *svc, const esp_console_cmd_t *cmd)
Register an extra static esp_console command before or after REPL start.
Command name must be a single token (no spaces). Strings are copied; the @a cmd descriptor need only live for the call. If the REPL is already running, the command is registered with esp_console immediately.
备注
Not ISR-safe. Thread-safe with other APIs on the same handle. Do not register from inside another command handler unless re-entrancy is safe for esp_console on your IDF version.
- 参数:
svc – [in] Service handle
cmd – [in] Command descriptor (see
esp_console_cmd_t)
- 返回:
ESP_OK Command registered.
ESP_ERR_INVALID_ARG svc or cmd is NULL; invalid command descriptor.
ESP_ERR_INVALID_STATE Command name already registered.
ESP_ERR_NO_MEM Allocation or storage failed.
ESP_ERR_TIMEOUT Mutex acquisition timed out.
Structures
-
struct esp_cli_service_config_t
CLI service creation configuration.
Set @c struct_size to @c sizeof(esp_cli_service_config_t) on every call. The @c reserved fields must be zero. Use @ref ESP_CLI_SERVICE_CONFIG_DEFAULT() unless you intentionally override fields. String ownership: @c prompt is copied internally; the pointer in @a cfg only needs to remain valid for the duration of @ref esp_cli_service_create. @c base_cfg fields follow @c esp_service_init rules.
Public Members
-
uint32_t struct_size
Must equal
sizeof(esp_cli_service_config_t)
-
uint32_t reserved[2]
Reserved; must be zero
-
esp_service_config_t base_cfg
Core service registration configuration
-
const char *prompt
REPL prompt string (copied on create)
-
uint16_t max_cmdline_length
Maximum command line length for esp_console
-
uint32_t task_stack
REPL task stack size in bytes
-
uint32_t task_prio
REPL task priority
-
esp_service_manager_t *manager
Optional manager for
toolcommands
-
uint32_t struct_size
Macros
-
ESP_CLI_SERVICE_CONFIG_DEFAULT()
Type Definitions
-
typedef struct esp_cli_service esp_cli_service_t