https://github.com/eggcar/ECShell最近需要在STM32上提供一个shell界面,实现基本的人机交互。本以为能随便找个库把这活干了,结果花了一些时间在网上搜索开源项目,没有找到符合我内心预期的现成项目(只有rt-thread的finsh完成度很高,但是跟rt-thread绑定的太深了)。于是趁51假期在家轮了一个。
基于我的
ECLayer VFS层,在ECLayer中添加了基于lwip的socket封装后,ECShell可以同时支持串口、TCP/TLS及其他流式文件接口。不使用静态和全局变量,可同时例化多个对象。
通过ECLayer的封装,支持有RTOS和无RTOS的配置。
行编辑功能基于
LineNoise库,但是LineNoise本身不太符合我的设计要求,因此做了比较大的删改。时间原因没有把全部功能都导入进来,将来再说。
命令行参数解析我导入了
optparse库,可以直接用标准的getopt() getopt_long()式api进行解析。参数拆分是我自己实现的函数split_line_to_argv(),支持单引号、双引号对含空白符的参数做包装。
命令的存储查询基于
avlmap。将来会添加配置选项选择链表存储,牺牲一部分查询性能来降低资源消耗。
shell命令的实现示例:
int ecshell_cmd_clear_screen(int argc, char *argv[], void *env)
{
int32_t ifd, ofd;
ifd = ((ecshell_env_t *)env)->stdin_fd;
ofd = ((ecshell_env_t *)env)->stdout_fd;
const char help_info[] =
CSI_SGR(SGR_COL_FRONT(COL_CYAN)) "clear" CSI_SGR(SGR_COL_FRONT(COL_DEFAULT)) "\r\n"
"Clear screen.\r\n";
const char err_info[] =
CSI_SGR(SGR_COL_FRONT(COL_RED)) "Invalid argument.\r\n" CSI_SGR(SGR_COL_FRONT(COL_DEFAULT)) "\r\n";
struct optparse_long longopts[] = {
{"help", 'h', OPTPARSE_NONE},
{0},
};
struct optparse options;
optparse_init(&options, argv);
int option;
while ((option = optparse_long(&options, longopts, NULL)) != -1) {
switch (option) {
case 'h':
write(ofd, help_info, strlen(help_info));
return 0;
default:
write(ofd, err_info, strlen(err_info));
return 0;
}
}
write(ofd, "\x1b[H\x1b[2J", 7);
return 0;
}
然后对命令进行注册:
void ecshell_cmd_map_init(void)
{
avl_map_init(&cmd_map, BKDRHash, strcmp);
/** Begin to regist your own cmds */
REGIST_COMMAND(ecshell_cmd_clear_screen, "clear");
}
启动shell也很简单,开一个线程(有RTOS)或者直接初始化调用(无RTOS):
#define DEBUG_DEVICE_NAME "/drivers/stm32/uart5"
void StartDefaultTask(void *argument)
{
shell_fd = open(DEBUG_DEVICE_NAME, O_RDWR);
ecshell_cmd_map_init();
ecshell_t *shell = ecshell_new(shell_fd, shell_fd, e_SHELLTYPE_Default, 0);
for (;;) {
shell_run(shell);
}
}
需要注意的是,在进入shell_run()之前,需要将fd设置为阻塞模式(open时不使用O_NOBLOCK或调用fcntl清除O_NOBLOCK标志位)。命令程序里如果需要改为非阻塞模式,在退出命令函数之前需要改回阻塞模式。将来大概会添加选项允许shell_run()运行在非阻塞模式下。
然后就可以在shell中调用了:
--
修改:eggcar FROM 111.192.202.*
FROM 111.192.202.*