剖析RT-Thread中console与finsh组件实现(2)[通俗易懂]

剖析RT-Thread中console与finsh组件实现(2)[通俗易懂]接上一章剖析RT-Thread中finsh组件实现(1),rt_device具体定义如下:其中内核基类定义如下:所以刚才串口1初始化后名称被初始化为了“usart1”,与刚才设置终端时入参刚好可以匹配。而这个标志是类型标志,串口类型即为RT_Object_Class_Device,同时也是一个静态类,所以会或上0x80其实rt_device中最重要的是传入了设备回调与操作函数指针,这些指针此时指向的是串口1的一系列操作函数。这些函数被初始化在串口1初始化的rt_hw_serial

大家好,又见面了,我是你们的朋友全栈君。

接上一章剖析RT-Thread中finsh组件实现(1)rt_device 具体定义如下:
在这里插入图片描述
其中内核基类定义如下:
在这里插入图片描述
所以刚才串口1初始化后名称被初始化为了 “usart1” ,与刚才设置终端时入参刚好可以匹配。而这个标志是类型标志,串口类型即为 RT_Object_Class_Device ,同时也是一个静态类,所以会或上0x80
在这里插入图片描述
其实 rt_device 中最重要的是传入了设备回调与操作函数指针,这些指针此时指向的是串口1的一系列操作函数。这些函数被初始化在串口1初始化的 rt_hw_serial_register 函数里在这里插入图片描述
当得到返回的 rt_device 后,紧接着是打开这个设备,然后把当前控制台设置为新开打的设备:
在这里插入图片描述
到这里控制台初始化结束,然后后面就一直运行到main函数里。而shell的设置很容易想到,和之前串口初始化一样,还有一部分也被设置在自动化初始化的段里。
在文件shell.c里最后一句话
在这里插入图片描述
这里把finsh的初始化放在了应用初始化里,即段后缀.6里。初始化具体内容如下:
在这里插入图片描述
tips

段名 + $$Base或$$Limit是MDK里用法,配合keep链接时保留一个段内的数据
 a$$Base代表段名为a的首地址
 a$$Limit代表段名为a的结尾

可以看到MDK链接选项卡参数是:
在这里插入图片描述
官方文档解释
finsh_system_function_init 函数也很简单,直接设置两个全局变量:
在这里插入图片描述
shell结构体定义如下:
在这里插入图片描述
我们先看一下信号量初始化:
在这里插入图片描述
最后finsh接收与发送其实都在finsh线程里完成:(删除掉了一些没有通过预编译的代码)

void finsh_thread_entry(void *parameter)
{ 
   
    char ch;

    /* normal is echo mode */
#ifndef FINSH_ECHO_DISABLE_DEFAULT
    shell->echo_mode = 1;	//开启回显,即能看到输入的cmd
#else
    shell->echo_mode = 0;
#endif
#ifndef RT_USING_POSIX
    /* set console device as shell device */
    if (shell->device == RT_NULL)
    { 
   
        rt_device_t console = rt_console_get_device();	//获取到之前设置的终端,即usart1
        if (console)
        { 
   
            finsh_set_device(console->parent.name);
        }
    }
#endif
    rt_kprintf(FINSH_PROMPT);

    while (1)
    { 
   
        ch = finsh_getchar();

        /* * handle control key * up key : 0x1b 0x5b 0x41 * down key: 0x1b 0x5b 0x42 * right key:0x1b 0x5b 0x43 * left key: 0x1b 0x5b 0x44 */
        if (ch == 0x1b)
        { 
   
            shell->stat = WAIT_SPEC_KEY;
            continue;
        }
        else if (shell->stat == WAIT_SPEC_KEY)
        { 
   
            if (ch == 0x5b)
            { 
   
                shell->stat = WAIT_FUNC_KEY;
                continue;
            }

            shell->stat = WAIT_NORMAL;
        }
        else if (shell->stat == WAIT_FUNC_KEY)
        { 
   
            shell->stat = WAIT_NORMAL;

            if (ch == 0x41) /* up key */
            { 
   
#ifdef FINSH_USING_HISTORY //显示历史cmd,完成↑翻看历史记录功能
                /* prev history */
                if (shell->current_history > 0)
                    shell->current_history --;
                else
                { 
   
                    shell->current_history = 0;
                    continue;
                }

                /* copy the history command */
                memcpy(shell->line, &shell->cmd_history[shell->current_history][0],
                       FINSH_CMD_SIZE);
                shell->line_curpos = shell->line_position = strlen(shell->line);
                shell_handle_history(shell);
#endif
                continue;
            }
            else if (ch == 0x42) /* down key */
            { 
   
#ifdef FINSH_USING_HISTORY //显示历史cmd,完成↓翻看历史记录功能
                /* next history */
                if (shell->current_history < shell->history_count - 1)
                    shell->current_history ++;
                else
                { 
   
                    /* set to the end of history */
                    if (shell->history_count != 0)
                        shell->current_history = shell->history_count - 1;
                    else
                        continue;
                }

                memcpy(shell->line, &shell->cmd_history[shell->current_history][0],
                       FINSH_CMD_SIZE);
                shell->line_curpos = shell->line_position = strlen(shell->line);
                shell_handle_history(shell);
#endif
                continue;
            }
            else if (ch == 0x44) /* left key */					//←功能
            { 
   
                if (shell->line_curpos)
                { 
   
                    rt_kprintf("\b");
                    shell->line_curpos --;
                }

                continue;
            }
            else if (ch == 0x43) /* right key */				//→功能 
            { 
   
                if (shell->line_curpos < shell->line_position)
                { 
   
                    rt_kprintf("%c", shell->line[shell->line_curpos]);
                    shell->line_curpos ++;
                }

                continue;
            }
        }

        /* received null or error */
        if (ch == '\0' || ch == 0xFF) continue;
        /* handle tab key */									//代码补全
        else if (ch == '\t')
        { 
   
            int i;
            /* move the cursor to the beginning of line */
            for (i = 0; i < shell->line_curpos; i++)
                rt_kprintf("\b");

            /* auto complete */
            shell_auto_complete(&shell->line[0]);
            /* re-calculate position */
            shell->line_curpos = shell->line_position = strlen(shell->line);

            continue;
        }
        /* handle backspace key */							//退格
        else if (ch == 0x7f || ch == 0x08)
        { 
   
            /* note that shell->line_curpos >= 0 */
            if (shell->line_curpos == 0)
                continue;

            shell->line_position--;
            shell->line_curpos--;

            if (shell->line_position > shell->line_curpos)
            { 
   
                int i;

                rt_memmove(&shell->line[shell->line_curpos],
                           &shell->line[shell->line_curpos + 1],
                           shell->line_position - shell->line_curpos);
                shell->line[shell->line_position] = 0;

                rt_kprintf("\b%s \b", &shell->line[shell->line_curpos]);

                /* move the cursor to the origin position */
                for (i = shell->line_curpos; i <= shell->line_position; i++)
                    rt_kprintf("\b");
            }
            else
            { 
   
                rt_kprintf("\b \b");
                shell->line[shell->line_position] = 0;
            }

            continue;
        }

        /* handle end of line, break */
        if (ch == '\r' || ch == '\n')
        { 
   
#ifdef FINSH_USING_HISTORY
            shell_push_history(shell);						//显示历史内容到shell 
#endif

#ifdef FINSH_USING_MSH
            if (msh_is_used() == RT_TRUE)
            { 
   
                if (shell->echo_mode)
                    rt_kprintf("\n");
                msh_exec(shell->line, shell->line_position);	//实际对比指令
            }
            else
#endif
            { 
   
            }

            rt_kprintf(FINSH_PROMPT);
            memset(shell->line, 0, sizeof(shell->line));
            shell->line_curpos = shell->line_position = 0;
            continue;
        }

        /* it's a large line, discard it */
        if (shell->line_position >= FINSH_CMD_SIZE)
            shell->line_position = 0;

        /* normal character */
        if (shell->line_curpos < shell->line_position)
        { 
   
            int i;

            rt_memmove(&shell->line[shell->line_curpos + 1],
                       &shell->line[shell->line_curpos],
                       shell->line_position - shell->line_curpos);
            shell->line[shell->line_curpos] = ch;
            if (shell->echo_mode)
                rt_kprintf("%s", &shell->line[shell->line_curpos]);

            /* move the cursor to new position */
            for (i = shell->line_curpos; i < shell->line_position; i++)
                rt_kprintf("\b");
        }
        else
        { 
   
            shell->line[shell->line_position] = ch;
            if (shell->echo_mode)
                rt_kprintf("%c", ch);
        }

        ch = 0;
        shell->line_position ++;
        shell->line_curpos++;
        if (shell->line_position >= FINSH_CMD_SIZE)
        { 
   
            /* clear command line */
            shell->line_position = 0;
            shell->line_curpos = 0;
        }
    } /* end of device read */
}

整个while里两个关键函数 finsh_set_devicefinsh_getchar
一个是把设备与终端连接起来,另一个是接收函数。先看 finsh_set_device
在这里插入图片描述
上一章在串口初始化的时候串口1并没有初始化接收回调,就是为了在这里把接收回调设为shell接收回调。实际操作如下:
在这里插入图片描述
回调函数具体内容如下:
在这里插入图片描述
可以看到就是释放一个shell的接收信号量,也就是在接收到数据后会主动释放一个 rx_sem 信号量。
释放具体过程如下:
在这里插入图片描述
下面分析 finsh_getchar 函数,函数内容如下:
在这里插入图片描述
其中 rt_device_read 函数不做展开,里面其实就是调用传入device的read函数指针,读取成功返回读取到的数据长度,数据存于ch内。我们看一下 rt_sem_take 这个函数,内容如下:
在这里插入图片描述
这里第二个入参time为-1,所以会一直等待,直到接收到数据触发接收回调,线程恢复,处理数据。
输入内容与所存cmd对比函数为 msh_exec ,内容如下:
在这里插入图片描述
实际操作在 _msh_exec_cmd 里:
在这里插入图片描述
msh_get_cmd 函数内容如下:
在这里插入图片描述
msh_split 用来分隔命令后面带有的参数,返回值为参数个数(参数间一般是用空格来切分的)。先把argv这个临时数组变量清空,然后把字符串存于argv。这个地方和main()函数类似,在很多地方都规定了main函数格式为

int main(int argc,char **argv);

实际运行就一句:
在这里插入图片描述
运行结果存于retp里。

剖析RT-Thread中console与finsh组件实现(3)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/144976.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 子查询关键字-ALL、ANY、SOME、IN、EXISTS「建议收藏」

    子查询关键字-ALL、ANY、SOME、IN、EXISTS「建议收藏」子查询关键字-ALL、ANY、SOME、IN、EXISTSALLselectfromwherec>all(查询语句)等价于selectfromwherec>result1andc>result2andc>result3特点: 1:all与子查询返回的所有值比较为true则返回true 2:ALL可以与=><>=<=<>结合使用 3:all表示指定列中的值必须要大于子查询集中的每一个值

    2022年7月27日
    8
  • 回顾外滩踩踏事件,吸取的教训[通俗易懂]

    回顾外滩踩踏事件,吸取的教训[通俗易懂]外滩踩踏事故:悲剧为何发生?外滩踩踏事故:悲剧为何发生?截至当前,上海外滩踩踏事故已造成36人遇难、47人受伤。事故发生的原因初步显现,为外滩观景平台的人流对冲。很多人认为这种归因过于简单,更何况

    2022年7月1日
    188
  • 原码/反码/补码在线计算器[通俗易懂]

    原码/反码/补码在线计算器[通俗易懂]原码/反码/补码计算器,在线计算给定整数的原码/反码/补码。工具链接:http://www.atoolbox.net/Tool.php?Id=952原码,反码和补码的概念对于一个数,计算机要使用一定的编码方式进行存储.原码,反码,补码是机器存储一个具体数字的编码方式.原码:原码就是早期用来表示数字的一种方式:一个正数,转换为二进制位就是这个正数的原码。负数的绝对值转换成二进制位然后在高位补1就是这个负数的原码。举例:int类型的3的原码是11B(B表示二进制位)

    2022年4月19日
    1.4K
  • element ui 图片加载失败_vue 3.x 中使用element-ui时, el-image图片加载失败!!「建议收藏」

    element ui 图片加载失败_vue 3.x 中使用element-ui时, el-image图片加载失败!!「建议收藏」问题描述vuecreateele命令创建了一个vue3.x的项目cdelecnpminpmrunserve把项目跑起来cnpmielement-ui-S安装element-ui修改HelloWorld.vue(增加使用el-image及其他组件),跑起来后,el-image对应的图片显示加载失败,但如果换成绝对地址就能正确加载,不知道什么原因!问题出现的环境背景及…

    2022年5月22日
    57
  • 一女程序员被判 9 个月:因薪酬等问题离职,rm -f * 删库,瘫痪 6 个小时[通俗易懂]

    一女程序员被判 9 个月:因薪酬等问题离职,rm -f * 删库,瘫痪 6 个小时

    2022年2月20日
    51
  • 一个完整的测试计划模板英文_测试方案和测试计划

    一个完整的测试计划模板英文_测试方案和测试计划引言编写目的编号确定项目描述1确定测试范围确定被测项目中功能模块,子功能模块等需要测试的范围。2确定测试需求确定每个功能结果定义,确定此功能是否存在缺陷。3确定测试策略确定对项目做哪些测试。如:功能测试,性能测试等。4确定测试方法确定对每个策略是用哪些方法。如:边界值,等价类等。5确定测试工具如:功能测试使用Seleium,性…

    2022年9月25日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号