# 控制台终端

[English]

ESP-IDF 提供了 `console` 组件，它包含了开发基于串口的交互式控制终端所需要的所有模块，主要支持以下功能：

- 行编辑，由 linenoise 库具体实现，它支持处理退格键和方向键，支持回看命令的历史记录，支持命令的自动补全和参数提示。

- 将命令行拆分为参数列表。

- 参数解析，由 argtable3 库具体实现，该库提供解析 GNU 样式的命令行参数的 API。

- 用于注册和调度命令的函数。

- 帮助创建 REPL (Read-Evaluate-Print-Loop) 环境的函数。

备注

这些功能模块可以一起使用，也可以独立使用，例如仅使用行编辑和命令注册的功能，然后使用 `getopt` 函数或者自定义的函数来实现参数解析，而不是直接使用 argtable3 库。同样地，还可以使用更简单的命令输入方法（比如 `fgets` 函数）和其他用于命令分割和参数解析的方法。

备注

当在支持硬件 USB 串行接口的芯片上使用控制台应用程序时，建议禁用次级串口控制台输出。次级输出仅用于显示，对于交互式应用程序没有任何作用。

## 行编辑

行编辑功能允许用户通过按键输入来编辑命令，使用退格键删除符号，使用左/右键在命令中移动光标，使用上/下键导航到之前输入的命令，使用制表键（“Tab”）来自动补全命令。

备注

此功能依赖于终端应用程序对 ANSI 转义符的支持。因此，显示原始 UART 数据的串口监视器不能与行编辑库一同使用。如果运行 system/console 示例程序的时候看到的输出结果是 `[6n` 或者类似的转义字符而不是命令行提示符 `esp>` 时，就表明当前的串口监视器不支持 ANSI 转义字符。已知可用的串口监视程序有 GNU screen、minicom 和 esp-idf-monitor（可以通过在项目目录下执行 `idf.py monitor` 来调用）。

前往这里可以查看 linenoise 库提供的所有函数的描述。

### 配置

Linenoise 库不需要显式地初始化，但是在调用行编辑函数之前，可能需要对某些配置的默认值稍作修改。

- `linenoiseClearScreen()`

  使用转义字符清除终端屏幕，并将光标定位在左上角。

- `linenoiseSetMultiLine()`

  在单行和多行编辑模式之间进行切换。单行模式下，如果命令的长度超过终端的宽度，会在行内滚动命令文本以显示文本的结尾，在这种情况下，文本的开头部分会被隐藏。单行模式在每次按下按键时发送给屏幕刷新的数据比较少，与多行模式相比更不容易发生故障。另一方面，在单行模式下编辑命令和复制命令将变得更加困难。默认情况下开启的是单行模式。

- `linenoiseAllowEmpty()`

  > 设置 linenoise 库收到空行的解析行为，设置为 `true` 时返回长度为零的字符串 (`""`) ，设置为 `false` 时返回 `NULL`。默认情况下，将返回长度为零的字符串。

- `linenoiseSetMaxLineLen()`

  > 设置 linenoise 库中每行的最大长度，默认长度为 4096 字节，可以通过更新该默认值来优化 RAM 内存的使用。

### 主循环

- `linenoise()`

  在大多数情况下，控制台应用程序都会具有相同的工作形式——在某个循环中不断读取输入的内容，然后解析再处理。`linenoise()` 是专门用来获取用户按键输入的函数，当回车键被按下后会便返回完整的一行内容。因此可以用它来完成前面循环中的“读取”任务。

- `linenoiseFree()`

  必须调用此函数才能释放从 `linenoise()` 函数获取的命令行缓冲区。

### 提示和补全

- `linenoiseSetCompletionCallback()`

  当用户按下制表键时，linenoise 会调用 补全回调函数 ，该回调函数会检查当前已经输入的内容，然后调用 `linenoiseAddCompletion()` 函数来提供所有可能的补全后的命令列表。启用补全功能，需要事先调用 `linenoiseSetCompletionCallback()` 函数来注册补全回调函数。

  `console` 组件提供了一个现成的函数来为注册的命令提供补全功能 `esp_console_get_completion()` （见下文）。

- `linenoiseAddCompletion()`

  补全回调函数会通过调用此函数来通知 linenoise 库当前键入命令所有可能的补全结果。

- `linenoiseSetHintsCallback()`

  每当用户的输入改变时，linenoise 就会调用此回调函数，检查到目前为止输入的命令行内容，然后提供带有提示信息的字符串（例如命令参数列表），然后会在同一行上用不同的颜色显示出该文本。

- `linenoiseSetFreeHintsCallback()`

  如果 提示回调函数 返回的提示字符串是动态分配的或者需要以其它方式回收，就需要使用 `linenoiseSetFreeHintsCallback()` 注册具体的清理函数。

### 历史记录

- `linenoiseHistorySetMaxLen()`

  该函数设置要保留在内存中的最近输入的命令的数量。用户通过使用向上/向下箭头来导航历史记录。

- `linenoiseHistoryAdd()`

  Linenoise 不会自动向历史记录中添加命令，应用程序需要调用此函数来将命令字符串添加到历史记录中。

- `linenoiseHistorySave()`

  该函数将命令的历史记录从 RAM 中保存为文本文件，例如保存到 SD 卡或者 flash 的文件系统中。

- `linenoiseHistoryLoad()`

  与 `linenoiseHistorySave` 相对应，从文件中加载历史记录。

- `linenoiseHistoryFree()`

  释放用于存储命令历史记录的内存。当使用完 linenoise 库后需要调用此函数。

## 将命令行拆分成参数列表

`console` 组件提供 `esp_console_split_argv()` 函数来将命令行字符串拆分为参数列表。该函数会返回参数的数量（`argc`）和一个指针数组，该指针数组可以作为 `argv` 参数传递给任何接受 `argc，argv` 格式参数的函数。

根据以下规则来将命令行拆分成参数列表：

- 参数由空格分隔

- 如果参数本身需要使用空格，可以使用 `\` （反斜杠）对它们进行转义

- 其它能被识别的转义字符有 `\\` （显示反斜杠本身）和 `\"` （显示双引号）

- 可以使用双引号来引用参数，引号只可能出现在参数的开头和结尾。参数中的引号必须如上所述进行转义。参数周围的引号会被 `esp_console_split_argv()` 函数删除

示例：

- `abc def 1 20 .3` > [ `abc`, `def`, `1`, `20`, `.3` ]

- `abc "123 456" def` > [ `abc`, `123 456`, `def` ]

- ``a\ b\\c\"` > [ `a b\c"` ]

## 参数解析

对于参数解析，`console` 组件使用 argtable3 库。有关 argtable3 的介绍请查看 教程 或者 Github 仓库中的 示例代码 。

## 命令的注册与调度

`console` 组件包含了一些工具函数，用来注册命令，将用户输入的命令和已经注册的命令进行匹配，使用命令行输入的参数调用命令。

应用程序首先调用 `esp_console_init()` 来初始化命令注册模块，然后调用 `esp_console_cmd_register()` 函数注册命令处理程序。

对于每个命令，应用程序需要提供以下信息（需要以 `esp_console_cmd_t` 结构体的形式给出）：

- 命令名字（不含空格的字符串）

- 帮助文档，解释该命令的用途

- 可选的提示文本，列出命令的参数。如果应用程序使用 `Argtable3` 库来解析参数，则可以通过提供指向 argtable 参数定义结构体的指针来自动生成提示文本

- 命令处理函数（无上下文），或

- 命令处理函数（有上下文）。如要使用此函数，则必须在调用其他命令 之前 调用 `esp_console_cmd_set_context()` 初始化上下文。

备注

使用接受上下文的命令处理函数或者不接受上下文的命令处理函数均可，但两者不能同时使用。如果使用接受上下文的命令处理程序函数，则必须调用 `esp_console_cmd_set_context()` 初始化上下文，否则该函数可能会访问未初始化的上下文。

命令注册模块还提供了其它函数：

- `esp_console_run()`

  该函数接受命令行字符串，使用 `esp_console_split_argv()` 函数将其拆分为 argc/argv 形式的参数列表，在已经注册的组件列表中查找命令，如果找到，则执行其对应的处理程序。

- `esp_console_register_help_command()`

  将 `help` 命令添加到已注册命令列表中，此命令将会以列表的方式打印所有注册的命令及其参数和帮助文本。

- `esp_console_get_completion()`

  与 linenoise 库中的 `linenoiseSetCompletionCallback()` 一同使用的回调函数，根据已经注册的命令列表为 linenoise 提供补全功能。

- `esp_console_get_hint()`

  与 linenoise 库中 `linenoiseSetHintsCallback()` 一同使用的回调函数，为 linenoise 提供已经注册的命令的参数提示功能。

## 初始化 REPL 环境

除了上述的各种函数，`console` 组件还提供了一些 API 来帮助创建一个基本的 REPL 环境。

在一个典型的 console 应用中，你只需要调用 `esp_console_new_repl_uart()`，它会为你初始化好构建在 UART 基础上的 REPL 环境，其中包括安装 UART 驱动，基本的 console 配置，创建一个新的线程来执行 REPL 任务，注册一些基本的命令（比如 help 命令）。

之后你可以使用 `esp_console_cmd_register()` 来注册其它命令。REPL 环境在初始化后需要再调用 `esp_console_start_repl()` 函数才能开始运行。

## 应用示例

- system/console/basic 演示了如何使用控制台组件的 REPL（读-评估-打印循环）API 在 ESP32 上创建一个交互式 Shell，该 Shell 可以通过串行接口控制，支持 UART 和 USB 接口，并可以作为需要命令行接口的应用程序的基础。

- system/console/advanced 演示了如何使用控制台组件在 ESP32 上创建一个交互式 Shell，该 Shell 可以通过串行接口控制，支持 UART 和 USB 接口，可作为需要命令行接口的应用程序的基础。

## API 参考

### Header File

- components/console/esp_console.h

- This header file can be included with:

  >     #include "esp_console.h"

- This header file is a part of the API provided by the `console` component. To declare that your component depends on `console`, add the following to your CMakeLists.txt:

  >     REQUIRES console

  > or

  >     PRIV_REQUIRES console

### Functions

esp_err_t esp_console_init(const esp_console_config_t *config)

  initialize console module

  备注

  Call this once before using other console module features

  参数:

    config -- console configuration

  返回:

    - ESP_OK on success

    - ESP_ERR_NO_MEM if out of memory

    - ESP_ERR_INVALID_STATE if already initialized

    - ESP_ERR_INVALID_ARG if the configuration is invalid

esp_err_t esp_console_deinit(void)

  de-initialize console module

  备注

  Call this once when done using console module functions

  返回:

    - ESP_OK on success

    - ESP_ERR_INVALID_STATE if not initialized yet

esp_err_t esp_console_cmd_register(const esp_console_cmd_t *cmd)

  Register console command.

  备注

  If the member `func_w_context` of cmd is set instead of func, then the member `context` is passed to the function pointed to by `func_w_context`.

  参数:

    cmd -- pointer to the command description; can point to a temporary value

  返回:

    - ESP_OK on success

    - ESP_ERR_NO_MEM if out of memory

    - ESP_ERR_INVALID_ARG if command description includes invalid arguments

    - ESP_ERR_INVALID_ARG if both func and func_w_context members of cmd are non-NULL

    - ESP_ERR_INVALID_ARG if both func and func_w_context members of cmd are NULL

esp_err_t esp_console_cmd_deregister(const char *cmd_name)

  Deregister console command.

  参数:

    cmd_name -- Name of the command to be deregistered. Must not be NULL, must not contain spaces.

  返回:

    - ESP_OK on success

    - ESP_ERR_INVALID_ARG if command is not registered

esp_err_t esp_console_run(const char *cmdline, int *cmd_ret)

  Run command line.

  参数:

    - cmdline -- command line (command name followed by a number of arguments)

    - cmd_ret -- [out] return code from the command (set if command was run)

  返回:

    - ESP_OK, if command was run

    - ESP_ERR_INVALID_ARG, if the command line is empty, or only contained whitespace

    - ESP_ERR_NOT_FOUND, if command with given name wasn't registered

    - ESP_ERR_INVALID_STATE, if esp_console_init wasn't called

size_t esp_console_split_argv(char *line, char **argv, size_t argv_size)

  Split command line into arguments in place.

      * - This function finds whitespace-separated arguments in the given input line.
      *
      *     'abc def 1 20 .3' -> [ 'abc', 'def', '1', '20', '.3' ]
      *
      * - Argument which include spaces may be surrounded with quotes. In this case
      *   spaces are preserved and quotes are stripped.
      *
      *     'abc "123 456" def' -> [ 'abc', '123 456', 'def' ]
      *
      * - Escape sequences may be used to produce backslash, double quote, and space:
      *
      *     'a\ b\\c\"' -> [ 'a b\c"' ]
      *

  备注

  Pointers to at most argv_size - 1 arguments are returned in argv array. The pointer after the last one (i.e. argv[argc]) is set to NULL.

  参数:

    - line -- pointer to buffer to parse; it is modified in place

    - argv -- array where the pointers to arguments are written

    - argv_size -- number of elements in argv_array (max. number of arguments)

  返回:

    number of arguments found (argc)

void esp_console_get_completion(const char *buf, linenoiseCompletions *lc)

  Callback which provides command completion for linenoise library.

  When using linenoise for line editing, command completion support can be enabled like this:

  linenoiseSetCompletionCallback(&esp_console_get_completion);

  参数:

    - buf -- the string typed by the user

    - lc -- linenoiseCompletions to be filled in

const char *esp_console_get_hint(const char *buf, int *color, int *bold)

  Callback which provides command hints for linenoise library.

  When using linenoise for line editing, hints support can be enabled as follows:

  linenoiseSetHintsCallback((linenoiseHintsCallback*) &esp_console_get_hint);

  The extra cast is needed because linenoiseHintsCallback is defined as returning a char* instead of const char*.

  参数:

    - buf -- line typed by the user

    - color -- [out] ANSI color code to be used when displaying the hint

    - bold -- [out] set to 1 if hint has to be displayed in bold

  返回:

    string containing the hint text. This string is persistent and should not be freed (i.e. linenoiseSetFreeHintsCallback should not be used).

esp_err_t esp_console_register_help_command(void)

  Register a 'help' command.

  Default 'help' command prints the list of registered commands along with hints and help strings if no additional argument is given. If an additional argument is given, the help command will look for a command with the same name and only print the hints and help strings of that command.

  返回:

    - ESP_OK on success

    - ESP_ERR_INVALID_STATE, if esp_console_init wasn't called

esp_err_t esp_console_set_help_verbose_level(esp_console_help_verbose_level_e verbose_level)

  Set the verbose level for 'help' command.

  Set the verbose level for 'help' command. Higher verbose level shows more details. Valid verbose_level values are described in esp_console_help_verbose_level_e and must be lower than `ESP_CONSOLE_HELP_VERBOSE_LEVEL_MAX_NUM`.

  返回:

    - ESP_OK on success

    - ESP_ERR_INVALID_ARG, if invalid verbose level is provided

esp_err_t esp_console_new_repl_uart(const esp_console_dev_uart_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl)

  Establish a console REPL environment over UART driver.

  Attention

    This function is meant to be used in the examples to make the code more compact. Applications which use console functionality should be based on the underlying linenoise and esp_console functions.

  备注

  This is an all-in-one function to establish the environment needed for REPL, includes:

  - Install the UART driver on the console UART (8n1, 115200, REF_TICK clock source)

  - Configures the stdin/stdout to go through the UART driver

  - Initializes linenoise

  - Spawn new thread to run REPL in the background

  参数:

    - dev_config -- [in] UART device configuration

    - repl_config -- [in] REPL configuration

    - ret_repl -- [out] return REPL handle after initialization succeed, return NULL otherwise

  返回:

    - ESP_OK on success

    - ESP_FAIL Parameter error

esp_err_t esp_console_start_repl(esp_console_repl_t *repl)

  Start REPL environment.

  备注

  Once the REPL gets started, it won't be stopped until the user calls repl->del(repl) to destroy the REPL environment.

  参数:

    repl -- [in] REPL handle returned from esp_console_new_repl_xxx

  返回:

    - ESP_OK on success

    - ESP_ERR_INVALID_STATE, if repl has started already

### Structures

struct esp_console_config_t

  Parameters for console initialization.

  Public Members

  size_t max_cmdline_length

    length of command line buffer, in bytes

  size_t max_cmdline_args

    maximum number of command line arguments to parse

  uint32_t heap_alloc_caps

    where to (e.g. MALLOC_CAP_SPIRAM) allocate heap objects such as cmds used by esp_console

  int hint_color

    ASCII color code of hint text.

  int hint_bold

    Set to 1 to print hint text in bold.

struct esp_console_repl_config_t

  Parameters for console REPL (Read Eval Print Loop)

  Public Members

  uint32_t max_history_len

    maximum length for the history

  const char *history_save_path

    file path used to save history commands, set to NULL won't save to file system

  uint32_t task_stack_size

    repl task stack size

  uint32_t task_priority

    repl task priority

  BaseType_t task_core_id

    repl task affinity, i.e. which core the task is pinned to

  const char *prompt

    prompt (NULL represents default: "esp> ")

  size_t max_cmdline_length

    maximum length of a command line. If 0, default value will be used

struct esp_console_dev_uart_config_t

  Parameters for console device: UART.

  Public Members

  int channel

    UART channel number (count from zero)

  int baud_rate

    Communication baud rate.

  int tx_gpio_num

    GPIO number for TX path, -1 means using default one.

  int rx_gpio_num

    GPIO number for RX path, -1 means using default one.

struct esp_console_cmd_t

  Console command description.

  Public Members

  const char *command

    Command name. Must not be NULL, must not contain spaces. The pointer must be valid until the call to esp_console_deinit.

  const char *help

    Help text for the command, shown by help command. If set, the pointer must be valid until the call to esp_console_deinit. If not set, the command will not be listed in 'help' output.

  const char *hint

    Hint text, usually lists possible arguments. If set to NULL, and 'argtable' field is non-NULL, hint will be generated automatically

  esp_console_cmd_func_t func

    Pointer to a function which implements the command.

    备注

    : Setting both `func` and `func_w_context` is not allowed.

  void *argtable

    Array or structure of pointers to arg_xxx structures, may be NULL. Used to generate hint text if 'hint' is set to NULL. Array/structure which this field points to must end with an arg_end. Only used for the duration of esp_console_cmd_register call.

  esp_console_cmd_func_with_context_t func_w_context

    Pointer to a context aware function which implements the command.

    备注

    : Setting both `func` and `func_w_context` is not allowed.

  void *context

    Context pointer to user-defined per-command context data. This is used if context aware function `func_w_context` is set.

struct esp_console_repl_s

  Console REPL base structure.

  Public Members

  esp_err_t (*del)(esp_console_repl_t *repl)

    Delete console REPL environment.

    Param repl:

      [in] REPL handle returned from esp_console_new_repl_xxx

    Return:

      - ESP_OK on success

      - ESP_FAIL on errors

### Macros

ESP_CONSOLE_CONFIG_DEFAULT()

  Default console configuration value.

ESP_CONSOLE_REPL_CONFIG_DEFAULT()

  Default console repl configuration value.

ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT()

### Type Definitions

typedef struct linenoiseCompletions linenoiseCompletions

typedef int (*esp_console_cmd_func_t)(int argc, char **argv)

  Console command main function.

  Param argc:

    number of arguments

  Param argv:

    array with argc entries, each pointing to a zero-terminated string argument

  Return:

    console command return code, 0 indicates "success"

typedef int (*esp_console_cmd_func_with_context_t)(void *context, int argc, char **argv)

  Console command main function, with context.

  Param context:

    a user context given at invocation

  Param argc:

    number of arguments

  Param argv:

    array with argc entries, each pointing to a zero-terminated string argument

  Return:

    console command return code, 0 indicates "success"

typedef struct esp_console_repl_s esp_console_repl_t

  Type defined for console REPL.

### Enumerations

enum esp_console_help_verbose_level_e

  Values:

  enumerator ESP_CONSOLE_HELP_VERBOSE_LEVEL_0
  enumerator ESP_CONSOLE_HELP_VERBOSE_LEVEL_1
  enumerator ESP_CONSOLE_HELP_VERBOSE_LEVEL_MAX_NUM

此文档对您有帮助吗？

- 反馈已收到，谢谢！
- 如果您有其他意见，欢迎填写乐鑫文档反馈表。

- 我们重视您的反馈。
- 您可以填写乐鑫文档反馈表告诉我们如何改进该文档。