嵌入式技术论坛
直播中

贾飞小

7年用户 1757经验值
私信 关注
[经验]

RTThread shell分析

1.shell主要原理

shell代码部分在components/finsh/shell.c 下,其主要原理是创建一个tshell线程,在空闲时获取字符,如果输入/n 字符,则调用msh_exec 来解析指令,在msh_exec 中,代码会寻找是否有相对应的指令,如果没有,则打印报错,输入的指令出错,如果有则调用cmd_func()来执行指令,cmd_func是一个声明,定义如下
typedef int (cmd_function_t)(int argc, char *argv);
在调用之前,代码会提取出我们输入的指令和参数,也就说,我们最后的指令调用,都会变成函数的调用

2.有部分操作会使用ansi转义字符,定义如下

ANSI转义序列是一种带内信号的转义序列标准,用于控制视频文本终端上的光标位置、颜色和其他选项。在文本中嵌入确定的字节序列,大部分以ESC转义字符和”[“字符开始,终端会把这些字节序列解释为相应的指令,而不是普通的字符编码。

在rt-thread中,ansi主要是在输出是对相应的内容进行控制,比如clear命令,简单了解即可

3.代码解析

1.重要结构认识

比较重要的结构体有finsh_shell,这个结构体代表着我们输入的字符串,里面重要的成员有

char line[FINSH_CMD_SIZE + 1]
rt_uint16_t line_position;
rt_uint16_t line_curpos;

第一个是我们输入的字符存放的地方,第二个为字符的长度,第三个为光标在的地方,因为有时候我们会按左右键,导致光标的位置和字符的长度不一样,这一点很值得注意

普通字符处理

1.jpg

首先代码544行,通过finsh_getchar获取了字符,如果这个字符不是特殊含义的字符,最终就会当作普通字符处理。

普通字符的处理在shell.c 的729-750行,729行判断当前的光标在是否在最后(因为你可以通过左右键改变光标位置),如果当前光标不在最后,733行rt-memmove 函数,肉眼可见的就是将当前指针后面的字符向后移1位,736行插入字符,如果光标就在字符串最后,746行直接放入line中

对 上下左右键 的处理

之前我们提到rt-thread使用了ANSI转义字符,在这里就可以体现,在我们点击键盘上的 上键 是,计算机实际上是识别为了 0x1b 0x5b 0x41这三个ascii码,0x1b是esc的ascii码,0x5b是[的ascii码,0x41是A的ascii码

一下是上下左右键的ascii码

1.jpg

代码557-574 行,就是判断我们输入的是不是上下左右键,如果是 shell->stat 的表示就会被置为WAIT_FUNC_KEY ,之后在判断具体是哪个键值

对上键的处理

1.jpg

576行判断输入的字符是行上键,578行,如果打开了FINSH_USING_HISTORY 功能,580-587判断shell->current_history 的值,589行,将对应的历史指令赋值到当前指令上,

591行设置光标位置和代码长度,592行调用shell_handle_history,代码如下

可以看到,这个部分的主要内容是清楚上一行,并且输出刚刚处理的内容,清楚上一行的指令在452行

对下键的处理

1.jpg

这个部分和对上键的处理大同小异,不在赘述

对左键的处理

1.jpg

这部分代码比较简单,判断如果当前光标位置大于0,将齐减1,退一格

对右键的处理

1.jpg

对右键的处理比较好玩,因为没有字符让光标前进一个,所以干脆就打印一边原来位置的字符,并且让光标位置加一,这样看起来就好像只有光标动,其他没动

对错误字符的处理

1.jpg

不理他,直接不处理

对tab的处理

1.jpg

647将光标退到最前面,651补全代码并且输出,653将光标位置和指令长度重新复制

对backspace 和 del 的处理

1.jpg

这边的处理分两种情况,分别是光标是否在最后,如果在最后,就比较好处理,684行直接把原来的字符用空格覆盖掉,即可,如果光标不在最后一行,671行调用rt_memmove把前面一个位置的字符覆盖,其他代码和插入字符的代码类似

对/n 和/r 的处理

1.jpg

shell_push_history 是将当前的指令放到cmd_history 这样的话,我们才可以用上键对之前的代码进行操作,699-704则是打印换行,然后调用msh_exec执行我们的命令,718-721行将指令清空。

原作者:KIMI_7569

更多回帖

发帖
×
20
完善资料,
赚取积分