对于嵌入式系统而言,特别对于没有使用操作系统,裸机运行程序的嵌入式系统,如何高效便捷的进行系统调试往往是一个比较令人头疼的问题。不久前,我接触到一个国产嵌入式操作系统,Thread RTOS,其中,该系统集成的finsh shell工具让我有种眼前一亮的感觉,它将shell工具引入到嵌入式系统中,极大的方便了系统的调试。
然而,finsh shell运行在操作系统之上,体积也比较大,对于某些小型嵌入式设备,基本是与其无缘了,既然如此,我们为何不自己编写一个shell呢。
我们首先对shell的运行原理进行分析,通过在命令行输入命令,shell对命令进行解析,然后执行相应的操作,更通俗的,就是使用输入的字符串,匹配到对应的函数,然后执行。那么,我们需要建立一个命令-函数的一一对应的关系,定义结构体。
typedef struct
{
uint8_t *name; //shell命令名称
shellFunction function; //shell命令函数
uint8_t *desc; //shell命令描述
}SHELL_CommandTypeDef; //shell命令定义
其中,shellFunction为函数指针类型,定义为
typedef void (*shellFunction)();
有了定义之后,我们建立一个表,将所有的命令以及对应的函数进行声明
/**
* shell 命令表,使用 {command, function, description} 的格式添加命令
* 其中
* command 为命令,字符串格式,长度不能超过 SHELL_PARAMETER_MAX_LENGTH
* 若不使用带参命令,则长度不超过SHELL_COMMAND_MAX_LENGTH
* function 为该命令调用的函数,支持(void *)(void)类型的无参函数以及与带参主函数
* 类似的(void *)(uint32_t argc, uint8_t *argv[])类型的带参函数,其中,
* argc 为参数个数,argv 为参数,参数皆为字符串格式,需自行进行数据转换
* description 为对命令的描述,字符串格式
*/
const SHELL_CommandTypeDef shellCommandList[] =
{
/*command function description*/
{(uint8_t *)"letter", shellLetter, (uint8_t *)"letter shell"},
{(uint8_t *)"reboot", shellReboot, (uint8_t *)"reboot system"},
{(uint8_t *)"help", shellShowCommandList, (uint8_t *)"show command list"},
{(uint8_t *)"clear", shellClear, (uint8_t *)"clear command line"},
{(uint8_t *)"iap", iapMain, (uint8_t *)"iap"},
{(uint8_t *)"tftp", iapTftp, (uint8_t *)"start TFTP server"},
{(uint8_t *)"userApp", iapJumpToApplication, (uint8_t *)"run user application"},
{(uint8_t *)"erase", (void (*)(