LISA Shell 命令行示例
源码位置: samples/subsys/lisa_shell 查看源码
功能说明
演示 LISA Shell 组件的完整使用方法,通过5个典型示例展示如何创建和注册各种类型的 Shell 命令。
本示例是学习 LISA Shell 命令开发的完整教程,涵盖从简单命令到复杂命令组的各种使用场景,每个示例都包含详细的中文注释说明。
硬件连接
PA2: UART0 RX (接收)
PA3: UART0 TX (发送)
连接到 PC 串口工具,配置为 115200, 8N1, 无流控
示例步骤
初始化 LISA Shell 组件
实现5种不同类型的命令示例
使用
SHELL_EXPORT_CMD宏注册命令通过串口工具连接并执行命令
观察各种命令的实现和效果
编译
重要提示:在编译前,请先确认您使用的开发板型号。SDK 目前支持以下开发板:
arcs_evb - ARCS EVB 评估板
arcs_mini - ARCS Mini 开发板
根据您的开发板型号,选择对应的编译命令:
在示例目录下执行编译:
# 使用 arcs_evb 开发板
./build.sh -C -DBOARD=arcs_evb
# 或使用 arcs_mini 开发板
./build.sh -C -DBOARD=arcs_mini
Note
如果在 SDK 根目录执行,需要指定示例路径:
# 使用 arcs_evb 开发板
./build.sh -C -S samples/<示例路径> -DBOARD=arcs_evb
# 或使用 arcs_mini 开发板
./build.sh -C -S samples/<示例路径> -DBOARD=arcs_mini
Note
确保已安装对应的工具链。
烧录
编译完成后,使用 SDK tools 目录下的 cskburn 工具烧录固件:
./tools/burn/cskburn -s /dev/ttyUSB0 -b 3000000 0x0 build/arcs.bin -C arcs
Note
烧录参数说明:
-s /dev/ttyUSB0:串口设备路径,需要根据实际情况修改 - Linux 系统:通常是/dev/ttyUSB0或/dev/ttyACM0- 可通过ls /dev/tty*命令查看可用串口设备 - 不同开发板或 USB 转串口芯片可能使用不同的设备名-b 3000000:烧录波特率(3Mbps)0x0:烧录起始地址build/arcs.bin:编译生成的固件路径-C arcs:芯片类型
注意事项:
确保开发板已正确连接到电脑
如果无法识别串口设备,请检查 USB 连接线是否正常,或尝试其他 USB 端口
预期输出
终端日志:
[INFO] [shell] === LISA Shell Usage Sample ===
[INFO] [shell] Shell initialized successfully
[INFO] [shell]
[INFO] [shell] This sample demonstrates:
[INFO] [shell] 1. Simple command (version)
[INFO] [shell] 2. Command with parameters (echo)
[INFO] [shell] 3. Optional parameters (memread)
[INFO] [shell] 4. Command group (info)
[INFO] [shell] 5. Command options (list)
[INFO] [shell]
[INFO] [shell] Type 'help' in shell to see all commands
串口工具交互:
letter shell 3.1
arcs@shell:/>help
version : show system version
echo : echo the input message
memread : read memory content
info : system information commands
list : list files (-l: verbose, -a: all)
...
arcs@shell:/>version
ARCS SDK Version: 1.0.0
Build Date: Jan 15 2025 10:30:45
arcs@shell:/>echo hello world
hello world
arcs@shell:/>memread 0x20000000 32
Memory at 0x20000000 (32 bytes):
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
-------------------------------------------------------
20000000: 12 34 56 78 9A BC DE F0 11 22 33 44 55 66 77 88
20000010: AA BB CC DD EE FF 00 11 22 33 44 55 66 77 88 99
arcs@shell:/>info
Usage: info <subcommand>
Available subcommands:
version - Show version
tasks - Show task list
arcs@shell:/>info version
Version: 1.0.0
arcs@shell:/>info tasks
Task List:
Name State Pri Stack Num
---------------------------------------------
IDLE R 0 128 1
shell_task B 5 512 2
main_task B 10 256 3
---------------------------------------------
arcs@shell:/>list
File List:
main.c shell.c
arcs@shell:/>list -l
File List:
Name Size Date
------------------------------------------
main.c 1234 2025-01-15
shell.c 5678 2025-01-14
核心 API
API |
说明 |
|---|---|
|
初始化 LISA Shell 组件 |
|
注册命令到 Shell |
|
在 Shell 中输出信息 |
|
输出日志信息 |
关键代码
/* 定义命令处理函数 */
static int cmd_version(int argc, char **argv)
{
printf("ARCS SDK Version: 1.0.0\n");
printf("Build Date: %s %s\n", __DATE__, __TIME__);
return 0;
}
/* 注册命令到 Shell */
SHELL_EXPORT_CMD(
SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
version, /* Shell 中的命令名 */
cmd_version, /* 命令处理函数 */
show system version /* 帮助信息 */
);
示例详解
示例1: 简单命令 (version)
演示最基本的命令实现,不需要处理任何参数。
static int cmd_version(int argc, char **argv)
{
printf("ARCS SDK Version: 1.0.0\n");
printf("Build Date: %s %s\n", __DATE__, __TIME__);
return 0;
}
/* 注册命令 */
SHELL_EXPORT_CMD(
SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
version, /* Shell 中的命令名 */
cmd_version, /* 命令处理函数 */
show system version /* 帮助信息 */
);
要点:
命令函数返回 0 表示成功,-1 表示失败
使用
printf()输出信息到 ShellSHELL_EXPORT_CMD必须在全局作用域使用
示例2: 带参数命令 (echo)
演示如何接收和处理用户输入的参数。
static int cmd_echo(int argc, char **argv)
{
/* argc: 参数个数 */
/* argv: 参数数组,argv[0]是第一个参数 */
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;
}
要点:
argc不包括命令名本身,只计算参数个数argv[0]是第一个参数(不是命令名)需要检查参数个数,避免数组越界
示例3: 可选参数 (memread)
演示如何处理必选参数和可选参数的组合。
static int cmd_memread(int argc, char **argv)
{
uint32_t addr;
uint32_t len = 64; /* 可选参数的默认值 */
if (argc < 1) {
/* 必选参数缺失 */
printf("Usage: memread <address> [length]\n");
return -1;
}
/* 解析必选参数 */
addr = strtoul(argv[0], NULL, 0);
/* 解析可选参数 */
if (argc >= 2) {
len = strtoul(argv[1], NULL, 0);
}
/* 使用参数... */
}
要点:
可选参数需要设置合理的默认值
使用
strtoul()可以自动识别十进制和十六进制(0x前缀)需要对参数进行有效性检查
示例4: 命令组 (info)
演示如何组织多个相关子命令为一个命令组。
/* 定义子命令表 */
static const struct shell_cmd_entry info_cmds[] = {
{"version", subcmd_info_version, "Show version"},
{"tasks", subcmd_info_tasks, "Show task list"},
};
/* 命令组处理函数 */
static int cmd_info_handler(int argc, char **argv)
{
/* argc包括命令名, argv[0]是命令名 info */
/* argv[1] 是子命令名 */
if (argc == 1) {
/* 没有子命令,显示帮助 */
info_show_help();
return 0;
}
/* 查找子命令 */
const char *subcmd = argv[1];
for (int i = 0; i < count; i++) {
if (strcmp(info_cmds[i].name, subcmd) == 0) {
/* 执行子命令,传递剩余参数 */
return info_cmds[i].handler(argc - 2, argv + 2);
}
}
/* 未找到子命令 */
printf("Error: unknown subcommand '%s'\n", subcmd);
return -1;
}
/* 注册命令组(注意使用 SHELL_CMD_DISABLE_RETURN 标志) */
SHELL_EXPORT_CMD(
SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_DISABLE_RETURN,
info,
cmd_info_handler,
system information commands
);
要点:
命令组的
argc包括命令名,argv[0]是命令名子命令名在
argv[1]传递给子命令的参数需要调整:
argc-2,argv+2命令组通常添加
SHELL_CMD_DISABLE_RETURN标志
示例5: 命令选项 (list)
演示如何解析和处理类似 -l, -a 这样的命令行选项。
static int cmd_list(int argc, char **argv)
{
int verbose = 0; /* -l 选项 */
int show_all = 0; /* -a 选项 */
/* 解析选项 */
for (int i = 0; i < argc; i++) {
if (argv[i][0] == '-') {
/* 这是一个选项 */
for (int j = 1; argv[i][j] != '\0'; j++) {
if (argv[i][j] == 'l') {
verbose = 1;
} else if (argv[i][j] == 'a') {
show_all = 1;
}
}
}
}
/* 根据选项执行不同的逻辑 */
if (verbose) {
/* 详细输出 */
} else {
/* 简单输出 */
}
}
要点:
选项以
-开头支持组合选项如
-la根据选项标志执行不同的逻辑
配置说明
在 prj.conf 中需要启用以下配置:
# 启用 LISA Shell
CONFIG_LISA_SHELL=y
注意事项
命令注册位置:
SHELL_EXPORT_CMD宏必须在全局作用域使用,不能在函数内部参数索引: 命令函数的
argc不包括命令名,argv[0]是第一个参数命令组参数: 命令组处理函数的
argc包括命令名,argv[0]是命令名本身返回值: 命令函数返回 0 表示成功,-1 表示失败
日志接口: 使用
LISA_LOGI()/LISA_LOGE()输出日志,消息使用英文注释规范: 代码注释使用中文,便于理解功能
内存安全: 访问内存地址前需要检查有效性,避免系统崩溃