当前位置: 首页 > article >正文

rtthread学习笔记系列(3) -- FINSH模块

文章目录

  • 3. FINSH模块
    • 3.1MSH
      • 3.1.1初始化
        • 3.1.1.1FSymtab段
        • 3.1.1.2 宏
      • 3.1.2遍历FINSH命令
      • 3.1.3TAB补全实现
        • 3.1.3.1 `msh_auto_complete`
        • 3.1.3.2 `msh_opt_auto_complete`
      • 3.1.4 TAB 子选项自动补全
    • 3.2 SHELL
      • 3.2.1 `finsh_system_init`分配finsh结构体使用内存
      • 3.2.2 `finsh_thread_entry`
      • 3.2.3 历史命令显示
      • 3.2.4 MSH命令执行
    • 3.3 cmd&msh_parse&&msh_file

3. FINSH模块

https://github.com/wdfk-prog/RT-Thread-Study

3.1MSH

3.1.1初始化

  1. 根据链接脚本指明FINSH使用内存空间 _syscall_table_begin _syscall_table_end的地址
3.1.1.1FSymtab段
        . = ALIGN(4);
        __fsymtab_start = .;
        KEEP(*(FSymTab))
        __fsymtab_end = .;
  • __fsymtab_start__fsymtab_end用于指明finsh使用内存
  • FSymTab用于存放所有注册命令的结构体 struct finsh_syscall,包括命令名称,命令选项,命令描述,命令函数执行地址信息
3.1.1.2 宏
/**
 * @ingroup msh
 *
 * This macro exports a command to module shell.
 *
 * @param command is the name of the command.
 * @param desc is the description of the command, which will show in help list.
 * @param opt This is an option, enter any content to enable option completion
 */
/* MSH_CMD_EXPORT(command, desc) or MSH_CMD_EXPORT(command, desc, opt) */
#define MSH_CMD_EXPORT(...)                                 \
    __MSH_GET_MACRO(__VA_ARGS__, _MSH_FUNCTION_CMD2_OPT,    \
        _MSH_FUNCTION_CMD2)(__VA_ARGS__)

#define __MSH_GET_MACRO(_1, _2, _3, _FUN, ...)  _FUN

#define _MSH_FUNCTION_CMD2(a0, a1)       \
        MSH_FUNCTION_EXPORT_CMD(a0, a0, a1, 0)

#define _MSH_FUNCTION_CMD2_OPT(a0, a1, a2)       \
        MSH_FUNCTION_EXPORT_CMD(a0, a0, a1, a0##_msh_options)

#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc)                      \
                const char __fsym_##cmd##_name[] rt_section(".rodata.name") = #cmd;    \
                const char __fsym_##cmd##_desc[] rt_section(".rodata.name") = #desc;   \
                rt_used const struct finsh_syscall __fsym_##cmd rt_section("FSymTab")= \
                {                           \
                    __fsym_##cmd##_name,    \
                    __fsym_##cmd##_desc,    \
                    (syscall_func)&name     \
                };
  1. 宏过载语法,选择2个参数使用 MSH_FUNCTION_CMD2,_MSH_FUNCTION_CMD2的desc为0;3个参数使用 MSH_FUNCTION_CMD2_OPT
  2. 定义字符串成员,地址定义为.rodata.name;内容为#cmd;
const char __fsym_##cmd##_name[] rt_section(".rodata.name") = #cmd;    \
const char __fsym_##cmd##_desc[] rt_section(".rodata.name") = #desc;   \
  1. __fsym_##cmd存储名称,细节,挂钩的函数指针地址

3.1.2遍历FINSH命令

    for (index = _syscall_table_begin;
            index < _syscall_table_end;
            FINSH_NEXT_SYSCALL(index))
    {
  
    }

3.1.3TAB补全实现

  1. 判断输入为 /t
  2. 将光标移动到行首;使用 /b退格,一个个退回删除之前的显示字符
  3. 将命令首地址传入 shell_auto_complete
  4. 计算偏移地址
  • shell_auto_complete
3.1.3.1 msh_auto_complete
  1. 首地址为 /0,即无输入任何字符串,直接TAB /t,则调用 msh_cmd输出所有支持的命令
  2. 匹配命令名字,并输出命令
        for (index = _syscall_table_begin; index < _syscall_table_end; FINSH_NEXT_SYSCALL(index))
        {
            /* skip finsh shell function */
            cmd_name = (const char *) index->name;
            if (strncmp(prefix, cmd_name, strlen(prefix)) == 0)
            {
                if (min_length == 0)
                {
                    /* set name_ptr */
                    name_ptr = cmd_name;
                    /* set initial length */
                    min_length = strlen(name_ptr);
                }

                length = str_common(name_ptr, cmd_name);
                if (length < min_length)
                    min_length = length;

                rt_kprintf("%s\n", cmd_name);
            }
        }
  1. 输出提示字符 msh />与命令输入的字符串
 rt_kprintf("%s%s", FINSH_PROMPT, prefix);
  • finsh_get_prompt输出提示
#define FINSH_PROMPT        finsh_get_prompt()

finsh_prompt_custom 用于自定义替换默认提示
finsh_set_prompt("artpi@root");
3.1.3.2 msh_opt_auto_complete
   argc = msh_get_argc(prefix, &opt_str);
    if (argc)
    {
        opt = msh_get_cmd_opt(prefix);
    }
    else if (!msh_get_cmd(prefix, strlen(prefix)) && (' ' == prefix[strlen(prefix) - 1]))
    {
        opt = msh_get_cmd_opt(prefix);
    }
  1. msh_get_argc 获取命令空格之后参数
  2. 没获取到参数时,判断 prefix不是一个已知的命令,并且命令行字符串的最后一个字符是空格
  3. msh_get_cmd_opt获取 syscall_table中是否有匹配的命令
  4. argc为0,输出 msh_opt_help所有的命令?
  5. msh_opt_completemsh_auto_complete作用相同

3.1.4 TAB 子选项自动补全

  1. msh_opt_auto_complete
  2. 使用完成命令注册
#define CMD_OPTIONS_STATEMENT(command) static struct msh_cmd_opt command##_msh_options[];
#define CMD_OPTIONS_NODE_START(command) static struct msh_cmd_opt command##_msh_options[] = {
#define CMD_OPTIONS_NODE(_id, _name, _des) {.id = _id, .name = #_name, .des = #_des},
#define CMD_OPTIONS_NODE_END    {0},};


CMD_OPTIONS_NODE_START(vref_temp_get)
CMD_OPTIONS_NODE(1, write, tx data)
CMD_OPTIONS_NODE(2, irq, irq list)
CMD_OPTIONS_NODE(3, speed-test, eth physical speed test)
CMD_OPTIONS_NODE_END

3.2 SHELL

3.2.1 finsh_system_init分配finsh结构体使用内存

  1. 创建 finsh_thread_entry线程
  2. 创建信号量,用于阻塞接字符串;信号量由控制台设备对象解除
  3. 设置提示模式
  4. INIT_APP_EXPORT中调用

3.2.2 finsh_thread_entry

  1. 获取控制台设备对象

  2. 获取控制台密码用于密码确认

    • finsh_wait_auth
      • 阻塞等待获取密码;密码输入显示 *
      • 敲入回车认为密码输入完成
      • 进入密码验证判断;失败线程阻塞等待2S再次获取输入字符
  3. 进入控制台线程

    1. finsh_getchar
    • rt_sem_take(&shell->rx_sem, RT_WAITING_FOREVER);等待信号量释放
      • finsh_rx_ind函数中释放信号量
    1. handle control key判断
         /*
             * handle control key
             * up key  : 0x1b 0x5b 0x41
             * down key: 0x1b 0x5b 0x42
             * right key:0x1b 0x5b 0x43
             * left key: 0x1b 0x5b 0x44
             */
    
    • 上下键:历史命令显示
    • 左右键:移动当前光标
    • tab键 补全命令
    • 删除键:删除
    • 回车键:执行msh命令
  4. 设置控制台设备模式

/**
 * @ingroup finsh
 *
 * This function sets the input device of finsh shell.
 *
 * @param device_name the name of new input device.
 */
void finsh_set_device(const char *device_name)
{
    rt_device_t dev = RT_NULL;

    RT_ASSERT(shell != RT_NULL);
    dev = rt_device_find(device_name);
    if (dev == RT_NULL)
    {
        rt_kprintf("finsh: can not find device: %s\n", device_name);
        return;
    }

    /* check whether it's a same device */
    if (dev == shell->device) return;
    /* open this device and set the new device in finsh shell */
    if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | \
                       RT_DEVICE_FLAG_STREAM) == RT_EOK)
    {
        if (shell->device != RT_NULL)
        {
            /* close old finsh device */
            rt_device_close(shell->device);
            rt_device_set_rx_indicate(shell->device, RT_NULL);
        }

        /* clear line buffer before switch to new device */
        rt_memset(shell->line, 0, sizeof(shell->line));
        shell->line_curpos = shell->line_position = 0;

        shell->device = dev;
        rt_device_set_rx_indicate(dev, finsh_rx_ind);
    }
}

3.2.3 历史命令显示

  1. 回车存入历史命令 shell_push_history
  2. 上下键显示历史命令 shell_handle_history

3.2.4 MSH命令执行

3.3 cmd&msh_parse&&msh_file

  • 一些系统命令的输出
  • 一些共用的解析
  • 文件系统的命令支持

http://www.kler.cn/a/505747.html

相关文章:

  • 【Compose multiplatform教程】05 IOS环境编译
  • 7.STM32F407ZGT6-RTC
  • C#类型转换
  • Vue Diff 算法完全解析
  • redis缓存篇知识点总结
  • html辅助标签与样式表
  • 寄存器 reg
  • 【学习笔记】GitLab 使用技巧和说明和配置和使用方法
  • [操作系统] 深入理解约翰·冯·诺伊曼体系
  • DNS介绍(1):基本概念
  • 如何确保API调用安全
  • Flink (三):核心概念(并行度、算子链、任务槽)
  • 算法面试准备 - 手撕系列第一期 - Softmax
  • WPF-01理解XAML
  • 不用PLC和板卡,一台电脑就可以控制伺服
  • Vue.js 动态组件与异步组件
  • 字典和 JSON 文本的格式区别
  • 【漫话机器学习系列】044.热点对特性的影响(Effect Of One Hot On Feature Importance)
  • Rust 正则表达式完全指南
  • zerox - 使用视觉模型将 PDF 转换为 Markdown
  • 机器学习中的凸函数和梯度下降法
  • 海康MV-EB435i立体相机SDK安装(ROS 2)
  • 瑞芯微 RK 系列 RK3588 使用 ffmpeg-rockchip 实现 MPP 视频硬件编解码-代码版
  • 设计模式学习手册(四)(原型模式)
  • C++—17、C++ 中的类和结构体的区别
  • 《计算机网络》课后探研题书面报告_了解PPPoE协议