文章参考笔记
源码获取
letter-shell: 项目源码-letter-shell-NevermindZZT (gitee.com)
移植参考
‘letterShell STM32移植 - 代码先锋网 (codeleading.com)https://www.codeleading.com/article/24354023097/
SHELL
在计算机科学中,Shell俗称壳(用来区别于核),是指“为使用者提供操作界面”的软件(command interpreter,命令解析器)。它类似于DOS下的COMMAND.COM和后来的cmd.exe。它接收用户命令,然后调用相应的应用程序。
同时它又是一种程序设计语言。作为命令语言,它交互式解释和执行用户输入的命令或者自动地解释和执行预先设定好的一连串的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。
简介
letter shell 3.0是一个C语言编写的,可以嵌入在程序中的嵌入式shell,主要面向嵌入式设备,以C语言函数为运行单位,可以通过命令行调用,运行程序中的函数
相对2.x版本,letter shell 3.0增加了用户管理,权限管理,后续会增加对文件系统的支持
此外3.0版本修改了命令格式和定义,2.x版本的工程需要经过简单的修改才能完成迁移
若只需要使用基础功能,可以使用letter shell 2.x版本
使用说明可参考Letter shell 3.0 全新出发
应用场景
嵌入式项目中,调试阶段打印SPI Flash、LCD屏幕这些,我希望可以在串口直接调用某几个功能函数开始执行,当移植了shell之后,在代码中只需要添加一行宏定义,就可以在串口中调用此函数开始执行。
功能
-
命令自动补全
-
快捷键功能定义
-
命令权限管理
-
用户管理
-
变量支持
项目地址
GitHub - NevermindZZT/letter-shell: letter shellhttps://github.com/NevermindZZT/letter-shell
移植配置(KEIL)
移植适配前请添加这两项内容,否则会导致错误出现
Misc controls中添加相关示例
--keep shellCommand*
移植说明
导入Letter-Shell核心文件
这里新建了一个Group,取名为shell_letter,将核心文件导入;
并新建shell_port.c,shell_port.h;这两个文件需要自己编写的,适应自己的平台的移植文件,只需要改这个就行,另外还有一个cfg的头文件,是用于配置shell的。
宏定义配置
letter-shell具备很多功能,可以通过宏定义来开启或者关闭,在shell_cfg.h
文件中根据需要进行配置:
编写移植文件shell_port.c
代码如下:
此处有两种方式编写文件
第一种:采用主程序循环读取
在shellTask中,会循环调用 shell.read函数,即我们自己编写的读字符函数。会根据函数返回值判断是否执行句柄函数。
* @file shell_port.c
* @author Letter (NevermindZZT@gmail.com)
* @brief
* @version 0.1
* @date 2019-02-22
*
* @Copyright (c) 2019 Unicook
*
*/
#include "shell.h"
#include "usart.h"
#include "shell_port.h"
#include "stdio.h"
Shell shell;
char shellBuffer[512];
/**
* @brief 用户shell写
*
* @param data 数据
*/
void userShellWrite(char data)
{
USARTX_SendChar(data);
}
/**
* @brief 用户shell读
*
* @param data 数据
* @return char 状态
*/
signed char userShellRead(char *data)
{
*data = 0;
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
*data = USART_ReceiveData(USART1);
}
USART_ClearFlag(USART1, USART_FLAG_RXNE);
if (*data == 0) {
return -1;
}
return 0;
}
/**
* @brief 用户shell初始化
*
*/
void userShellInit(void)
{
shell.write = userShellWrite;
shell.read = userShellRead;
shellInit(&shell, shellBuffer, 512);
}
需要清除标志位。
正常接受字符,则返回0, 异常接受字符,则返回-1.
第二种:采用中断读取
主要调用“shellHandler”函数
* @file shell_port.c
* @author Letter (NevermindZZT@gmail.com)
* @brief
* @version 0.1
* @date 2019-02-22
*
* @Copyright (c) 2019 Unicook
*
*/
#include "shell.h"
#include "usart.h"
#include "shell_port.h"
#include "stdio.h"
Shell shell;
char shellBuffer[512];
/**
* @brief 用户shell写
*
* @param data 数据
*/
void userShellWrite(char data)
{
USARTX_SendChar(data);
}
/**
* @brief 用户shell读
*
* @param data 数据
* @return char 状态
*/
signed char userShellRead(char *data)
{
return 0;
}
/**
* @brief 用户shell初始化
*
*/
void userShellInit(void)
{
shell.write = userShellWrite;
shell.read = userShellRead;
shellInit(&shell, shellBuffer, 512);
}
void USART1_IRQHandler(void)
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(USART1);
shellHandler(&shell, Res);
}
}
显示效果如下:
应用程序编写
应用函数可以写在主函数中,也可以写在接口函数中
注意事项:letter shell 3.0同时支持两种形式的函数定义方式,形如main函数定义的func(int argc, char *agrv[])
以及形如普通C函数的定义func(int i, char *str, ...)
,两种函数定义方式适用于不同的场景。
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
普通C函数形式
使用此方式,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
变量使用
letter shell 3.0支持导出变量,通过命令行查看,设置以及使用变量的值
导出变量
变量导出使用SHELL_EXPORT_VAR宏,支持整形(char, short, int),字符串,指针以及节点变量,变量导出需要使用引用的方式,如果不允许对变量进行修改,在属性中添加SHELL_CMD_READ_ONLY
int varInt = 0;
SHELL_EXPORT_VAR(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_VAR_INT), varInt, &varInt, test);
char str[] = "test string";
SHELL_EXPORT_VAR(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_VAR_STRING), varStr, str, test);
Log log;
SHELL_EXPORT_VAR(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_VAR_POINT), log, &log, test);
查看变量
在命令行直接输入导出的变量名即可查看变量当前的值
letter:/$ varInt
varInt = 0, 0x00000000
letter:/$ varStr
varStr = "test string"
修改变量
使用setVar命令修改变量的值,对于字符串型变量,请确认字符串有分配足够的空间,指针类型的变量不可修改
letter:/$ setVar varInt 45678
varInt = 45678, 0x0000b26e
letter:/$ setVar varStr "hello"
varStr = "hello"
使用变量
letter shell 3.0的变量可以在命令中作为参数传递,对于需要传递结构体引用到命令中的场景特别适用,使用$+变量名的方式传递
letter:/$ shellPrint $shell "hello world\r\n"
hello world
letter shell建议使用secureCRT软件,letter shell中的相关按键映射都是按照secureCRT进行设计的,使用其他串口软件时,可能需要修改键值