嵌入式C简单易用的Shell、CLI比较

1,852 阅读4分钟

这里给出的shell 代码(或称为lsh、cli)都是在 GitHub上开源项目。

   在大学里写一个Shell代码可能是必需的,它不仅可以提高程序能力,在实际程序应用中也非常方便,同时也可以以此为基础扩展其它功能。

shell 使用步骤:

Shell不仅要稳定可靠,还要简单易用,以下三点是必要的。

初始化:在这一步中, shell 将读取并执行其配置文件。这里还注册了shell 的功能函数、初始化输入输出端口等。 运行处理: shell 从标准输入(可以是交互式的或文件)读取命令并执行它们并输出运行结果。 结束退出:在不需要shell后,shell 执行关闭命令,释放内存等。 严格按照这三点实现目的是为了简单而易用。

目标已经明确,那是写一个shell,还是不要重造轮子呢?当然是后者。

下面是几个开源shell:

letter-shell :github.com/NevermindZZ…

lwshell : github.com/MaJerle/lws…

Shell : github.com/geekfactory…

uC-Shell :github.com/weston-embe…

letter-shell :

   letter-shell其功能强大,并且一直在更新演化,其资料也较多请搜索网络。

lwshell :

   lwshell是MaJerle开源,他不仅开源有lwshell, 还有lwrb,lwprintf等等。其官网还有详细说明资料。其开源项目无其它依懒,直接可移植使用。

Shell:

   跟lwshell相差不大,真是简单到漏水,但也满足基本需求。

uC-Shell:

   这个就是著名的uc-os的开源附件。其功能强大,设计精巧,其程序说明还和原理方法都有详细指引。经典设计和久经沙场不得不让人佩服。唯一不足是依懒uc库,这些都不是问题,有源码可以随意DIY。

前面讲到基本使用步骤,下面列出shell使用方法

shell循环方式:

在裸机中以while非阻塞式循环。 在裸机中以1mS定时非阻塞式循环。 在OS系统中以1ms间隔周期非阻塞式循环。 在OS系统中以消息、事件、信号等任务同步的方式阻塞式循环。 第一种最为简单,其余依次递增。

对于这四种循环方式,其shell 在运行过程中做了什么,分为以下四个工作内容。

Shell循环工作内容:

读取:从标准输入读取命令和数据串。 解析:将命令字符串分成程序和参数。 执行:运行解析的命令。 输出: 输出执行结果 以上为Shell的整体结构,图示如下所示

12.png

下面以lwshell和shell的代码为示范:

我们以shell基本循环中的第一个为例. 以祼机while形式循环处理。

我们以STM32cubeMx生成的任意一个工程的Main函数并在while循环中加入shell函数,注意在这我项目中我们将lwshell和shell同时进行运行。

为了调试方便我们用SEGGER_RTT作为输出。

int main(void) { HAL_Init(); SystemClock_Config();

rtt_init();

shell_shell_init();
shell_shell_register();

lwshell_shell_init(); 
lwshell_register();

while (1) {
    read_port();
    shell_task();
    lwshell_task();
}

} 在最后没有作退出处理,而是让shell一直工作。

下面我们来看项目工程:

13.png

下面为函数代码:

void shell_shell_init(void) { // 初始化注册读写功能函数 shell_init(shell_read, shell_shell_write, 0); xprintf("Shell_shell initialization complete\r\n"); }

// Add commands to the shell void shell_shell_register(void) { shell_register(command_mycommand, ("shellcmd")); shell_register(command_othercommand, ("shell")); shell_register(Simultaneous_processing_command, ("cmd")); }

void lwshell_shell_init(void) { lwshell_init(); lwshell_set_output_fn(lwshell_out); xprintf("lwshell_shell initialization complete\r\n"); }

// Add commands to the shell void lwshell_register(void) { /* Define shell commands */ lwshell_register_cmd("lwshell", lwshell_command, "lwshell running command"); lwshell_register_cmd("lw", lwshell_othercommand, "lwshell other command");
lwshell_register_cmd("cmd", lwshell_othercommand, "lwshell other command"); }

void lwshell_task(void) { uint8_t input; if(RingBuf_get(&lwshellRB, &input) == true) { lwshell_input((const void *)&input, sizeof(input)); } } 我们注册了五个命令调用函数,分别为Shell库和lwshell库分别单独操作各两个函数,另一个为两个库同时调用一个函数,共用一个命令“cmd”。如下:

int command_mycommand(int argc, char** argv)

int command_othercommand(int argc, char** argv)

int32_t lwshell_command(int32_t argc, char** argv)

int32_t lwshell_othercommand(int32_t argc, char** argv)

int32_t Simultaneous_processing_command(int32_t argc, char** argv)

{ xprintf("Shell_shell Running "mycommand" now argv: %d\r\n",argc); for(int32_t i = 0; i < argc; ++i) { xprintf("ARG[%d]: %s\r\n", (int)i, argv[i]); } xprintf("Exit..."); return SHELL_RET_SUCCESS; } 其函数执行的功能都是一样。这里只列出一个。

Shell库的执行命令为:shellcmd; shell; cmd

Lwshell库的执行命令为:lwshell; lw; cmd

Cmd为两个共用命令。

测试效果如下:

11.gif 项目中包含一个SEGGER_RTT文件,一个环形队列库,一个xprintf打印库,还有两个shell库和我增加一个测试用例。

[运行在微控制器上的简单易用的shell源文件-C/C++文档类资源-CSDN下载]