FinSH

finSH介绍

FinSH 是 RT-Thread 的命令行组件,提供一套供用户在命令行调用的操作接口,主要用于调试或查看系统信息。它可以使用串口 / 以太网 / USB 等与 PC 机进行通信。

命令执行过程

FinSH 命令执行流程图

功能:

  1. 支持鉴权,可在系统配置中选择打开/关闭。(TODO:具体操作过程)
  2. tap键自动补全命令,如果什么都没有输入会列出所有命令。(TODO:原理)
    按键功能描述
    Tab 键当没有输入任何字符时按下 Tab 键将会打印当前系统支持的所有命令。若已经输入部分字符时按下 Tab 键,将会查找匹配的命令,也会按照文件系统的当前目录下的文件名进行补全,并可以继续输入,多次补全
    ↑↓键上下翻阅最近输入的历史命令
    退格键删除符
    ←→键向左或向右移动标
  3. 历史命令查看。(上下键翻阅)
  4. FinSH 完全采用 ANSI C 编写,具备极好的移植性。(前面章节中介绍的函数方式动态地向 FinSH 添加符号,FinSH 将不会动态申请内存??什么方式?)

传统命令行模式msh VS C-style模式

最初 FinSH 仅支持 C-Style 模式,后来随着 RT-Thread 的不断发展,C-Style 模式在运行脚本或者程序时不太方便,而使用传统的 shell 方式则比较方便。另外,C-Style 模式下,FinSH 占用体积比较大。(TODO:为什么会比较大)出于这些考虑,在 RT-Thread 中增加了 msh 模式,msh 模式体积小,使用方便,推荐使用 msh 模式。

  1. modemshC-style
    examplecommand [arg1] [arg2] […]list_thread()
    switchexit ===>to c-style modemsh() ===> to msh mode
    cmd defineMSH_CMD_EXPORT(name, desc);
    MSH_CMD_EXPORT_ALIAS
    FINSH_FUNCTION_EXPORT(name,desc);
    FINSH_VAR_EXPORT(name, type, desc);
    FINSH_FUNCTION_EXPORT_ALIAS(name, alias, desc);(当函数名称超过16个字节的时候,需要导出别名,否则执行会出错,在重命名的命令名字前加 __cmd_ 就可以将命令导出到 msh 模式,否则,命令会被导出到 C-Style 模式)

FinSH功能配置

在rt-thread配置文件rt-config.h 中,在env开发环境下,可以使用menuconfig 命令在图形化界面当中进行配置。

宏定义取值类型描述默认值
#define RT_USING_FINSH使能 FinSH开启
#define FINSH_THREAD_NAME字符串FinSH 线程的名字“tshell”
#define FINSH_USING_HISTORY打开历史回溯功能开启
#define FINSH_HISTORY_LINES整数型能回溯的历史命令行数5
#define FINSH_USING_SYMTAB可以在 FinSH 中使用符号表开启
#define FINSH_USING_DESCRIPTION给每个 FinSH 的符号添加一段描述开启
#define FINSH_USING_MSH使能 msh 模式开启
#define FINSH_USING_MSH_ONLY只使用 msh 模式开启
#define FINSH_ARG_MAX整数型最大输入参数数量10
#define FINSH_USING_AUTH使能权限验证关闭
#define FINSH_DEFAULT_PASSWORD字符串权限验证密码关闭

FiniSH代码阅读提示:

每次的命令执行都是在 FinSH 线程(即 tshell 线程)的上下文中完成。

初始化:finsh_system_init() 函数。

输出:在 RT-Thread 中依赖 rt_kprintf() 输出。在启动函数 rt_hw_board_init() 中,rt_console_set_device(const char* name) 函数设置了 FinSH 的打印输出设备。

输入:获得了信号量后,调用rt_device_read() 函数从设备 (选用串口设备) 中获得一个字符然后处理。而 rx_sem 信号量的释放通过调用 rx_indicate() 函数以完成对 FinSH 线程的输入通知。通常的过程是,当串口接收中断发生时(即串口有输入),接受中断服务例程调用 rx_indicate() 函数通知 FinSH 线程有输入,而后 FinSH 线程获取串口输入最后做相应的命令处理。

TODO:获得一个字符就处理吗?还是整个命令获得了再处理?

FinSH代码阅读

文件结构
route:rt-thread/components/finish
├─ finsh

│  ├─ cmd.c                // place rt-thread  cmd

│  ├─ finsh.h            // cmd export相关的宏和函数的声明,涉及到的函数的声明(TODO:函数实现在哪?)

│  ├─ msh.c                // msh cmd search & excution funcitons

│  ├─ msh.h                // msh cmd search & excution funcitons API

│  ├─ msh_file.c        // some os cmd define(cd/pwd/mkfs/mount/...)

│  ├─ msh_parse.c        // msh cmd parse

│  ├─ msh_parse.h        // msh cmd parse API

│  ├─ shell.c            // shell context and cmd read

│  ├─ shell.h            // struct define and API set

│  ├─ Kconfig            // project config file for menuconfig

│  └─ SConscript        // scons project file



初始化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1M5zlpzZ-1667636697535)(a1992662197db6b981a36dd150b62ae0.png)]

finSH的初始化放在rt_components_init()的applilication init functions部分。

调用关系:

rtthread_startup() -->

rt_system_scheduler_start() -->

main_thread_entry(void *parameter) -->

rt_components_init(void) -->

finsh_system_init(void) -->

分出另一个线程 -->

finsh_thread_entry(void *parameter).


finsh_system_init() 下finsh_system_function_init() 的作用是什么呢?

答:初始化两个指针,一个指向所有命令的最开始,一个指向命令的最结尾。

CMD define逻辑

macro call :FINSH_FUNCTION_EXPORT(name, desc) --> MSH_FUNCTION_EXPORT_CMD(name, cmd, desc)

MSH_FUNCTION_EXPORT_CMD逻辑
#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc)        \     

​        const char __fsym_##cmd##_name[] = #cmd;       \    /* cmd name to str */

​        const char __fsym_##cmd##_desc[] = #desc;      \    /* cmd description to str */

​        __declspec(allocate("FSymTab$f"))              \    /* put next struct to this section */

​        const struct finsh_syscall __fsym_##cmd =      \

​        {                                              \

​          __fsym_##cmd##_name,                           \

​          __fsym_##cmd##_desc,                           \

​          (syscall_func)&name                           \

​        };
FinSH CMD 处理逻辑

finsh_thread_entry函数用于处理来自用户的输入,大概有以下几个功能:

  • 鉴权
  • 循环读取一个字符串并处理:
    • 特殊字符的处理: 上下左右、制表符、回退、回车。对应历史命令读取、光标移动、命令和路径补全、删除当前命令、执行命令功能。
    • 普通字符,放入字符串存储等待处理。
流程图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PsFWhmpP-1667636697536)(6fc6a5a21447eeb3ce2ceeedebc41719.png)]

FinSH shell 状态机

初步阅读代码,我的理解是这个是为了处理上下左右四个键的输入方式而设计的。

WAIT_NORMAL // shell 处于等待接收正常字符的状态

WAIT_SPEC_KEY // shell 处于等待接收方向键的特殊字符的状态

WAIT_FUNC_KEY // shell 处于等待接收功能键的状态

相关的特殊按键的获取方式:

ps:在Win的env工具下仿真模拟msh读取不到上下左右的按键,猜测和windows 和 linux 下的按键的输入值不同有关。

KeyLinuxKeyWindows
Up0x1B 0x5B 0x41Up0xE0 0x48
Down0x1B 0x5B 0x42Down0xE0 0x50
Left0x1B 0x5B 0x44Left0xE0 0x4B
Right0x1B 0x5B 0x43Right0xE0 0x4D
FinSH context
struct finsh_shell
{
    struct rt_semaphore rx_sem;

​    enum input_stat stat;

​    rt_uint8_t echo_mode: 1;
​    rt_uint8_t prompt_mode: 1;

#ifdef FINSH_USING_HISTORY
    rt_uint16_t current_history;
    rt_uint16_t history_count;

​    char cmd_history[FINSH_HISTORY_LINES][FINSH_CMD_SIZE];
#endif

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

#if !defined(RT_USING_POSIX_STDIO) && defined(RT_USING_DEVICE)
    rt_device_t device;
#endif

#ifdef FINSH_USING_AUTH
    char password[FINSH_PASSWORD_MAX];
#endif
};
FinSH input信息读取

rt_hw_board_init()中调用rt_device_t rt_console_set_device(const char *name)注册了console device。

请添加图片描述

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值