善哉!善哉!
【 在 eggcar (eggcar) 的大作中提到: 】
: 标 题: [原创]ECShell - 基于ECLayer的ARM-CM轻量级Shell实现
: 发信站: 水木社区 (Sun May 10 00:40:07 2020), 站内
:
:
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中调用了:
: [upload=1][/upload]
:
: --
: ※ 修改:·eggcar 于 May 10 01:14:55 2020 修改本文·[FROM: 111.192.202.*]
: ※ 来源:·水木社区
http://www.newsmth.net·[FROM: 111.192.202.*]
--
修改:eggcar FROM 111.192.202.*
FROM 111.196.247.*