Shell 组件

简介

LISA Shell 是一个基于 Letter Shell 的命令行交互组件,为 ARCS SDK 提供串口命令行界面支持。通过 UART 接口,用户可以在终端中执行自定义命令、查看系统信息、调试应用程序等。

主要特性

  • UART 串口通信:基于 lisa_uart 驱动实现串口收发

  • FreeRTOS 任务集成:独立的 shell 任务处理用户输入

  • 灵活配置:通过 Kconfig 配置任务优先级、缓冲区大小等参数

  • 日志集成:自动接管系统日志输出到串口

  • 命令扩展:支持使用 SHELL_EXPORT_CMD 宏注册自定义命令

  • 多种回车模式:支持 LF、CR、CRLF 等多种命令行回车触发方式

组件架构

┌─────────────────────────────────────────┐
│           用户应用程序                    │
│  ┌──────────────────────────────────┐   │
│  │  SHELL_EXPORT_CMD 宏注册命令      │   │
│  └──────────────────────────────────┘   │
└─────────────┬───────────────────────────┘
              │
┌─────────────▼───────────────────────────┐
│          LISA Shell 组件                 │
│  ┌──────────────┐  ┌──────────────┐    │
│  │ shell_task   │  │ shell_write  │    │
│  │  (接收处理)   │  │  (输出函数)   │    │
│  └──────┬───────┘  └──────┬───────┘    │
│         │                 │             │
│  ┌──────▼─────────────────▼───────┐    │
│  │    Letter Shell 核心库         │    │
│  │  (命令解析、命令管理、TAB补全)  │    │
│  └──────────────────────────────┬─┘    │
└─────────────────────────────────┼──────┘
                                  │
┌─────────────────────────────────▼──────┐
│          lisa_uart 驱动                 │
│  (UART 接收/发送、缓冲区管理)            │
└────────────────────────────────────────┘

配置选项

menuconfigprj.conf 中可配置以下选项:

基本配置

配置项

说明

默认值

CONFIG_LISA_SHELL

启用 LISA Shell 组件

n

任务配置

配置项

说明

默认值

范围

CONFIG_LISA_SHELL_TASK_STACK_SIZE

Shell 任务栈大小 (字节)

1024

-

CONFIG_LISA_SHELL_TASK_PRIORITY

Shell 任务优先级

5

0-31

缓冲区配置

配置项

说明

默认值

CONFIG_LISA_SHELL_BUFFER_SIZE

Shell 命令缓冲区大小 (字节)

512

CONFIG_LISA_SHELL_RX_BUF_SIZE

UART 接收缓冲区大小 (字节)

32

CONFIG_LISA_SHELL_SCAN_BUFFER

格式化输入缓冲区大小 (字节)

128

行为配置

配置项

说明

默认值

CONFIG_LISA_SHELL_SUPPORT_END_LINE

支持尾行模式

y

CONFIG_LISA_SHELL_ENTER_LF

使用 LF (\n) 作为回车触发

y

CONFIG_LISA_SHELL_ENTER_CR

使用 CR (\r) 作为回车触发

y

CONFIG_LISA_SHELL_ENTER_CRLF

使用 CRLF (\r\n) 作为回车触发

n

注意SHELL_ENTER_CRLF 不能与 SHELL_ENTER_LFSHELL_ENTER_CR 同时启用。

快速开始

1. 启用组件

在项目的 prj.conf 文件中添加:

CONFIG_LISA_SHELL=y

2. 配置 UART 设备

LISA Shell 使用系统日志 UART 设备,需要配置对应的 UART:

# 选择 UART0 作为 Shell 串口
CONFIG_SYSLOG_UART_DEVICE_UART0=y

3. 初始化 Shell

在应用程序的 main 函数中调用初始化函数:

#include "lisa_shell.h"

int main(int argc, char **argv)
{
    // 初始化 shell
    lisa_shell_init();

    // 你的应用代码
    while (1) {
        vTaskDelay(1000);
    }

    return 0;
}

4. 注册自定义命令

使用 SHELL_EXPORT_CMD 宏注册命令:

#include "shell.h"

// 简单命令示例
static int cmd_hello(int argc, char **argv)
{
    printf("Hello World\n");
    return 0;
}

// 带参数的命令示例
static int cmd_echo(int argc, char **argv)
{
    if (argc < 1) {
        printf("Usage: echo <message>\n");
        return -1;
    }

    for (int i = 0; i < argc; i++) {
        printf("%s ", argv[i]);
    }
    printf("\n");

    return 0;
}

// 注册命令
SHELL_EXPORT_CMD(
    SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
    hello,
    cmd_hello,
    "Print hello world"
);

SHELL_EXPORT_CMD(
    SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
    echo,
    cmd_echo,
    "Echo arguments"
);

5. 命令组示例

创建命令组来组织相关的命令:

// 命令表
struct cmd_entry {
    char *name;
    int (*exec)(int argc, char **argv);
    char *help;
};

static int subcmd_test(int argc, char **argv)
{
    printf("Running test...\n");
    return 0;
}

static int subcmd_info(int argc, char **argv)
{
    printf("System information\n");
    return 0;
}

static const struct cmd_entry my_cmds[] = {
    {"test", subcmd_test, "Run test"},
    {"info", subcmd_info, "Show info"},
};

// 命令组处理函数
static int cmd_group_handler(int argc, char **argv)
{
    if (argc == 1) {
        // 显示帮助
        printf("Available subcommands:\n");
        for (int i = 0; i < sizeof(my_cmds) / sizeof(my_cmds[0]); i++) {
            printf("  %-10s : %s\n", my_cmds[i].name, my_cmds[i].help);
        }
        return 0;
    }

    // 查找并执行子命令
    for (int i = 0; i < sizeof(my_cmds) / sizeof(my_cmds[0]); i++) {
        if (strcmp(my_cmds[i].name, argv[1]) == 0) {
            return my_cmds[i].exec(argc - 2, argv + 2);
        }
    }

    printf("Unknown subcommand: %s\n", argv[1]);
    return -1;
}

// 注册命令组
SHELL_EXPORT_CMD(
    SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_DISABLE_RETURN,
    myapp,
    cmd_group_handler,
    "My application command group"
);

API 参考

lisa_shell_init

int lisa_shell_init(void);

功能:初始化 LISA Shell 组件

返回值

  • 0:初始化成功

  • -1:初始化失败(UART 设备未就绪、配置失败或内存分配失败)

说明

  • 自动配置 UART 设备(波特率、缓冲区等)

  • 创建 shell 任务进行命令接收和处理

  • 将系统日志输出重定向到 shell 串口

注意事项

  1. UART 设备共享:Shell 使用系统日志的 UART 设备,确保日志和 Shell 配置一致

  2. 任务优先级:根据系统需求调整 Shell 任务优先级,避免影响实时性要求高的任务

  3. 缓冲区大小:根据命令复杂度和长度调整 SHELL_BUFFER_SIZE

  4. 内存分配:Shell 使用动态内存分配,确保系统有足够的堆内存

  5. 命令注册SHELL_EXPORT_CMD 宏必须在全局作用域使用,不能在函数内部

  6. 格式化输入SHELL_SCAN_BUFFER 功能会阻塞 shell 任务,仅适用于 RTOS 环境

常见问题

Q: Shell 初始化失败怎么办?

A: 检查以下几点:

  • UART 设备是否正确配置并初始化

  • 系统是否有足够的堆内存

  • CONFIG_SYSLOG_UART_DEVICE_UARTx 配置是否正确

Q: 无法输入命令?

A: 检查:

  • 串口终端配置(波特率、数据位等)是否正确

  • UART 引脚连接是否正常

  • 回车触发模式(LF/CR/CRLF)配置是否与终端匹配

Q: 命令注册后在 help 中看不到?

A: 确保:

  • 命令正确使用了 SHELL_EXPORT_CMD

  • 宏调用在全局作用域(不在函数内部)

  • 对应的源文件已链接到最终二进制文件

依赖项

  • SDK_MODULE_LETTER_SHELL:Letter Shell 核心库

  • LISA_PORTING:LISA 平台移植层

  • lisa_uart:UART 驱动

  • lisa_log:日志系统

  • lisa_mem:内存管理

  • FreeRTOS:实时操作系统