【嵌入式】开源shell命令行的移植和使用(2)——letter-shell

目录

一 背景说明

二 移植准备

三 移植过程

四 自定义命令

五 实际使用


一 背景说明

        之前使用过一款开源shell工具 nr_micro_shell (【嵌入式】开源shell命令行的移植和使用(1)——nr_micro_shell-CSDN博客),感觉功能还不够强大,故换了一个类似的开源shell工具 letter-shell

        shell是一个C语言编写的,可以嵌入在程序中的嵌入式shell,主要面向嵌入式设备,以C语言函数为运行单位,可以通过命令行调用,运行程序中的函数。相对2.x版本,letter shell 3.x增加了用户管理,权限管理,以及对文件系统的初步支持。此外3.x版本修改了命令格式和定义,2.x版本的工程需要经过简单的修改才能完成迁移。若只需要使用基础功能,可以使用letter shell 2.x版本。

        功能包括:

  • 命令自动补全
  • 快捷键功能定义
  • 命令权限管理
  • 用户管理
  • 变量支持
  • 代理函数和参数代理解析

二 移植准备

【1】letter-shell下载地址——gitee:

letter-shell: letter shell一个嵌入式小型shell,特别适用于单片机系统。

【2】letter-shell下载地址——github:

https://github.com/NevermindZZT/letter-shell

【3】提前准备好芯片UART串口的初始化以及收发接口。

三 移植过程

【1】目录移植:将下载好的letter-shell文件解压到自己的工程目录下,并在IDE中包含所需的src中的源文件以及头文件,另外将demo中的 shell_port.c 以及 shell_port.h 也移到src目录下一并处理:

        此时编译一下,可能会出现报错,自行处理一下。

【2】根据自己需要修改 shell_cfg.h 中的基础配置:

意义
SHELL_TASK_WHILE是否使用默认shell任务while循环
SHELL_USING_CMD_EXPORT是否使用命令导出方式
SHELL_USING_COMPANION是否使用shell伴生对象功能
SHELL_SUPPORT_END_LINE是否支持shell尾行模式
SHELL_HELP_LIST_USER是否在输入命令列表中列出用户
SHELL_HELP_LIST_VAR是否在输入命令列表中列出变量
SHELL_HELP_LIST_KEY是否在输入命令列表中列出按键
SHELL_ENTER_LF使用LF作为命令行回车触发
SHELL_ENTER_CR使用CR作为命令行回车触发
SHELL_ENTER_CRLF使用CRLF作为命令行回车触发
SHELL_EXEC_UNDEF_FUNC使用执行未导出函数的功能
SHELL_COMMAND_MAX_LENGTHshell命令最大长度
SHELL_PARAMETER_MAX_NUMBERshell命令参数最大数量
SHELL_HISTORY_MAX_NUMBER历史命令记录数量
SHELL_DOUBLE_CLICK_TIME双击间隔(ms)
SHELL_QUICK_HELP快速帮助
SHELL_MAX_NUMBER管理的最大shell数量
SHELL_GET_TICK()获取系统时间(ms)
SHELL_USING_LOCK是否使用锁
SHELL_MALLOC(size)内存分配函数(shell本身不需要)
SHELL_FREE(obj)内存释放函数(shell本身不需要)
SHELL_SHOW_INFO是否显示shell信息
SHELL_CLS_WHEN_LOGIN是否在登录后清除命令行
SHELL_DEFAULT_USERshell默认用户
SHELL_DEFAULT_USER_PASSWORD默认用户密码
SHELL_LOCK_TIMEOUTshell自动锁定超时
SHELL_USING_FUNC_SIGNATURE使用函数签名

        如无特殊需要,可以使用默认配置。

【3】修改接口文件 shell_port.c :

        (i)改写 userShellWrite 为自己的串口输出接口

/**
 * @brief 用户shell写
 * 
 * @param data 数据
 * @param len 数据长度
 * 
 * @return short 实际写入的数据长度
 */
short userShellWrite(char *data, unsigned short len)
{
    int i;
	
	for(i=0;i<len;i++){
        Uart_SendDataPollTimeOut(M0P_UART0, (uint8_t)data[i], SystemCoreClock/DBG_PRINTF_BAUDRATE);
	}
 
	return 0;
}

        (ii)串口接收中断中嵌入 shellHandler(&shell, ch) 以接收输入字符

/**************************************************************************
* 函数名称: Uart0_IRQHandler
* 功能描述: 串口接收中断
**************************************************************************/
void Uart0_IRQHandler(void)
{
    uint8_t ch;

    if(Uart_GetStatus(M0P_UART0, UartRC))       //UART0数据接收
    {
        Uart_ClrStatus(M0P_UART0, UartRC);      //清中断状态位
        ch = Uart_ReceiveData(M0P_UART0);       //接收数据字节
        shellHandler(&shell, ch);
    }
    
    if(Uart_GetStatus(M0P_UART0, UartTC))         //UART0数据发送
    {
        Uart_ClrStatus(M0P_UART0, UartTC);        //清中断状态位
    }
}

        (iii)用户shell初始化 userShellInit

/**
 * @brief 用户shell初始化
 * 
 */
void userShellInit(void)
{
    shell.write = userShellWrite;
    shellInit(&shell, shellBuffer, 512);
}

【4】在程序初始化的时候调用串口的初始化以及shell初始化接口(userShellInit()),上电之后即可看到letter_shell的logo,按TAB键即可看到注册的几个命令:

#include "shell_port.h"
 
int main(void)
{
    //串口初始化
    Dbg_Init();
    Dbg_Cfg();
 
    //命令行初始化
    userShellInit();
 
    while(1)
    {
        
    }
}

四 自定义命令

        在 shell.c 中编辑以及自定义命令。自定义命令分为两步,第一步定义命令函数,第二步使用SHELL_EXPORT_CMD 导入命令列表

【1】定义命令函数

        letter shell 3.x同时支持两种形式的函数定义方式,形如main函数定义的func(int argc, char *agrv[])以及形如普通C函数的定义func(int i, char *str, ...),两种函数定义方式适用于不同的场景。

        (i)main函数形式(属性为SHELL_TYPE_CMD_MAIN):使用此方式,一个函数定义的例子如下:

int func(int argc, char *agrv[])
{
    printf("%dparameter(s)\r\n", argc);
    for (char i = 1; i < argc; i++)
    {
        printf("%s\r\n", argv[i]);
    }
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), func, func, test);

           终端调用:

letter:/$ func "hello world"
2 parameter(s)
hello world

        (注1:main函数形式下,如果要导入 flaot 类型的参数,可以使用 sscanf 来格式化输入:)

void shellSet(int argc, char *argv[])
{
    float t_vset;

    if(argc > 1)
    {
        if(!strcmp("v", argv[1]))
        {
            if(argc > 2)
            {
                sscanf(argv[2], "%f", &t_vset);
                printf("Change V-USET to %f V!\r\n", t_vset);
            }
        }
    }
}

        (ii)普通C函数形式(属性为SHELL_TYPE_CMD_FUNC):使用此方式,shell会自动对参数进行转化处理,目前支持二进制,八进制,十进制,十六进制整形,字符,字符串的自动处理,如果需要其他类型的参数,请使用代理参数解析的方式(参考代理函数和代理参数解析),或者使用字符串的方式作为参数,自行进行处理,例子如下:

int func(int i, char ch, char *str)
{
    printf("input int: %d, char: %c, string: %s\r\n", i, ch, str);
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC), func, func, test);

           终端调用:

letter:/$ func 666 'A' "hello world"
input int: 666, char: A, string: hello world

        (注2:普通C函数形式下,如果要导入 flaot 类型的参数,可以使用代理函数命令导出宏定义命令:

void test(int a, float b, int c, float d)
{
    printf("%d, %f, %d, %f \r\n", a, b, c, d);
}
SHELL_EXPORT_CMD_AGENCY(SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),
test, test, test,
p1, SHELL_PARAM_FLOAT(p2), p3, SHELL_PARAM_FLOAT(p4));

        (iii)letter_shell还提供了诸如变量使用在函数中获取当前shell对象执行未导出函数等其他应用,具体可以参考gitee中的使用说明自行发掘。

        

【2】使用 SHELL_EXPORT_CMD 导入命令列表,其参数定义如下:

参数

描述

_attr

命令属性

_name

命令名

_func

命令函数

_desc

命令描述
/**
     * @brief shell 命令定义
     * 
     * @param _attr 命令属性
     * @param _name 命令名
     * @param _func 命令函数
     * @param _desc 命令描述
     * @param ... 其他参数
     */
    #define SHELL_EXPORT_CMD(_attr, _name, _func, _desc, ...) \
            const char shellCmd##_name[] = #_name; \
            const char shellDesc##_name[] = #_desc; \
            SHELL_USED const ShellCommand \
            shellCommand##_name SHELL_SECTION("shellCommand") =  \
            { \
                .attr.value = _attr, \
                .data.cmd.name = shellCmd##_name, \
                .data.cmd.function = (int (*)())_func, \
                .data.cmd.desc = shellDesc##_name, \
                ##__VA_ARGS__ \
            }

        至此,移植结束。

五 实际使用

        实际使用的效果如下:

        补充:自己调试的时候遇到一个问题:实际使用shell的时候,有时候按空格或者退格键会使得程序直接重启,更换了串口波特率9600为115200之后,问题解决。具体原因不明,希望有大神看到能够帮忙解惑

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/196326.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】了解进程的基础知识

进程 1. 进程的概念1.1 进程的理解1.2 Linux下的进程1.3 查看进程属性1.4 getpid和getppid 2. 创建进程3. 进程状态4. 进程优先级5. 进程切换6. 环境变量7. 本地变量与内建命令 1. 进程的概念 一个已经加载到内存中的程序&#xff0c;叫做进程&#xff08;也叫任务&#xff09…

echarts点击事件

有这么个需求要点击叶片的时候跳转页面 代码&#xff1a;点击之后 报错了 解决办法 1、使用箭头函数&#xff08;箭头函数没有自己的 this&#xff0c;所以在箭头函数中使用 this 时&#xff0c;其指向与外层作用域相同。&#xff09;或者使用闭包来解决上下文的问题。 2、使…

QT基础实践之QQ登录界面

文章目录 QQ登录界面源码分享演示图代码分析 QQ登录界面 源码分享 链接&#xff1a;https://pan.baidu.com/s/1v_J4WQjZoSAoMrIpx88PbA 提取码&#xff1a;qwer 记得把图片放入Debug文件 演示图 代码分析 已注释 较为详细 widget.h #ifndef WIDGET_H #define WIDGET_H#inc…

Leetcode98 验证二叉搜索树

题意理解&#xff1a; 首先明确二叉树的定义&#xff0c;对于所有节点&#xff0c;根节点的值大于左子树所有节点的值&#xff0c;小于右子树所有节点的值。 注意一个误区&#xff1a; 根节点简单和左孩子&#xff0c;右孩子比大小是不够的&#xff0c;要和子树比&#xff0c;…

Django项目部署本地windows IIS(详细版)和static文件设置(页面样式正常显示)

目录 必要条件&#xff1a; 一、下载并启用wfastcgi 二、window安装 IIS功能 三、IIS管理器中添加网站 1、复制项目 2、复制wfastcgi.py文件 3、创建文件web.config 4、添加网站&#xff0c;填写信息 5、启动fastcgi程序 6、修改进程标识 四、static文件设置和正确显…

凝聚数字经济发展新力量,四象科技受邀出席2023全球数商大会

11月25日&#xff0c;2023全球数商大会在上海开幕。本届大会以“数联全球、商通未来”为主题&#xff0c;上海市委副书记、市长龚正出席大会并宣布大会开幕&#xff0c;国家发展改革委党组成员&#xff0c;国家数据局党组书记、局长刘烈宏&#xff0c;上海市副市长陈杰致辞。四…

智能学习台灯_AI摄像头学习机基于MTk8175方案

智能学习台灯是一款专为中小学生设计的学习辅助工具&#xff0c;具有多项突出的参数和功能。首先&#xff0c;它采用了基于联发科MTK平台的解决方案&#xff0c;内置了12纳米四核Cortex-A53处理器&#xff0c;提供了稳定而高效的性能。操作系统方面&#xff0c;智能学习台灯运行…

山西临县“5·7”火灾事故调查报告公布,揭秘富维烟火报警系统

近日&#xff0c;山西临县“57”火灾事故调查报告震惊全国&#xff0c;提醒我们火灾防控的重要性。在这起悲剧中&#xff0c;我们深刻认识到&#xff0c;及时发现火灾并迅速应对至关重要。这不仅是对生命安全的保护&#xff0c;也是对财产损失的有效减少。而在这方面&#xff0…

SQL注入-报错注入

目录 一&#xff0c;sql报错注入概述&#xff1a; 二&#xff0c;报错注入函数&#xff1a; extractvalue() updatexml() floor()、rand()、count()、group by联用 其它函数 三&#xff0c;SQL报错注入实例&#xff1a; extractvalue() floor()、rand()、count()、grou…

统计学中两组数据如何进行差异性(相关性)分析?

变量说明&#xff1a; 在确定分析方法前&#xff0c;我们需要了解手中的数据类型&#xff0c;这是最基础也是有必要的&#xff0c;在所有的数据类型中&#xff0c;我们将数据类型分为分类变量也为定类变量和连续变量也称为定量变量&#xff0c;那么什么是定类变量&#xff1f;…

通达信抛物线SAR指标原理详解、参数设置及选股公式

抛物线指标(SAR)是由技术分析大师威尔斯威尔德(Welles Wilder)发明的&#xff0c;在其1978 年出版的《技术交易系统新概念》一书中介绍了该指标。SAR指标通过跟踪股票价格的动态变化&#xff0c;在走势图上以一系列点的形式显示&#xff0c;提供了一种判断趋势反转的方法&#…

E云管家开发自动转发朋友圈

简要描述&#xff1a; 转发朋友圈&#xff0c;直接xml数据。(对谁不可见) 请求URL&#xff1a; http://域名地址/forwardSns 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参…

9.增删改操作

目录 一、插入操作 1、为表的所有字段插入数据 2、为表的指定字段插入数据 3、同时插入多条记录 4、将查询结果插入表中&#xff1a; 二、更新操作 三、删除操作 四、练习题 一、插入操作 在使用数据库之前&#xff0c;数据库中必须要有数据&#xff0c;MYSQL中使INSE…

SimpleDateFormat在多线程下的安全问题

目录 情景重现 SimpleDateFormat解析 解决方案 局部变量 加锁 使用线程变量 使用DateTimeFormatter 情景重现 SimpleDateFormat类是Java开发中的一个日期时间的转化类。它可以满足绝大多数的开发场景&#xff0c;但是在高并发下会出现并发问题。接下来查看下文中的案例。…

JavaEE(SpringMVC)期末复习(选择+填空+解答)

文章目录 JavaEE期末复习一、单选题&#xff1a;二、多选题三、填空题四、解答 JavaEE期末复习 一、单选题&#xff1a; 1.Spring的核⼼技术是&#xff08; A &#xff09;&#xff1f; A依赖注入 B.JdbcTmplate C.声明式事务 D.资源访问 Spring的核心技术包括依赖注入&#x…

​无人机摄影测量

无人机摄影测量技术是传统航空摄影测量手段的有力补充&#xff0c;具有机动灵活、高效快速、精细准确、作业成本低、生产周期短、影像获取空间分辨率高、高危地区探测等优势。无人机与航空摄影测量相结合使得“无人机数字低空遥感”成为航空遥感领域的一个崭新发展方向。无人机…

SpringCloud 微服务全栈体系(十八)

第十一章 分布式搜索引擎 elasticsearch 八、RestClient 查询文档 文档的查询同样适用 RestHighLevelClient 对象&#xff0c;基本步骤包括&#xff1a; 准备 Request 对象准备请求参数发起请求解析响应 1. 快速入门 以 match_all 查询为例 1.1 发起查询请求 代码解读&…

⑤【Sorted Set】Redis常用数据类型: ZSet [使用手册]

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 目录 ⑤Redis Zset 操作命令汇总1. zadd 添加或…

Unity RenderFeature架构分析

自定义RenderFeature接口流程 URP内部ScriptableRenderPass分析 public、protected属性 renderPassEvent &#xff1a;渲染事件发生的时刻colorAttachments &#xff1a;渲染的颜色纹理列表 m_ColorAttachmentscolorAttachment &#xff1a;m_ColorAttachments[0];depthAttac…

【解决方案】基于边缘计算技术的安科瑞综合管廊能效管理平台

平台背景 综合管廊一般是建于城市地下用于容纳两类及以上城市工程管线的构筑物及附属设施&#xff0c;将电力、自来水、热力、煤气、电信、网络等市政公用管线根据规划要求集中敷设在同一个构建物内&#xff0c;实施统一设计、施工、管理的市政公用隧道空间&#xff0c;并且还…