# letter shell 3.x
![version](https://img.shields.io/badge/version-3.2.0-brightgreen.svg)
![standard](https://img.shields.io/badge/standard-c99-brightgreen.svg)
![build](https://img.shields.io/badge/build-2023.04.15-brightgreen.svg)
![license](https://img.shields.io/badge/license-MIT-brightgreen.svg)
一个功能强大的嵌入式shell
![shell_info.png](doc/img/shell_info.png)
- [letter shell 3.x](#letter-shell-3x)
- [简介](#简介)
- [功能](#功能)
- [移植说明](#移植说明)
- [使用方式](#使用方式)
- [函数定义](#函数定义)
- [main函数形式](#main函数形式)
- [普通C函数形式](#普通c函数形式)
- [变量使用](#变量使用)
- [在函数中获取当前shell对象](#在函数中获取当前shell对象)
- [执行未导出函数](#执行未导出函数)
- [命令定义](#命令定义)
- [定义方式](#定义方式)
- [定义宏说明](#定义宏说明)
- [命令属性字段说明](#命令属性字段说明)
- [代理函数和代理参数解析](#代理函数和代理参数解析)
- [函数签名](#函数签名)
- [自定义类型解析](#自定义类型解析)
- [权限系统说明](#权限系统说明)
- [锁说明](#锁说明)
- [伴生对象](#伴生对象)
- [尾行模式](#尾行模式)
- [建议终端软件](#建议终端软件)
- [命令遍历工具](#命令遍历工具)
- [x86 demo](#x86-demo)
## 简介
[letter shell](https://github.com/NevermindZZT/letter-shell)是一个C语言编写的,可以嵌入在程序中的嵌入式shell,主要面向嵌入式设备,以C语言函数为运行单位,可以通过命令行调用,运行程序中的函数
相对2.x版本,letter shell 3.x增加了用户管理,权限管理,以及对文件系统的初步支持
此外3.x版本修改了命令格式和定义,2.x版本的工程需要经过简单的修改才能完成迁移
若只需要使用基础功能,可以使用[letter shell 2.x](https://github.com/NevermindZZT/letter-shell/tree/shell2.x)版本
使用说明可参考[Letter shell 3.0 全新出发](https://nevermindzzt.github.io/2020/01/19/Letter%20shell%203.0%E5%85%A8%E6%96%B0%E5%87%BA%E5%8F%91/)
如果从3.0版本迁移到3.1以上版本,请注意3.1版本对读写函数原型的修改
## 功能
- 命令自动补全
- 快捷键功能定义
- 命令权限管理
- 用户管理
- 变量支持
- 代理函数和参数代理解析
## 移植说明
1. 定义shell对象
```C
Shell shell;
```
2. 定义shell读,写函数
对于使用letter shell 3.0版本,读写函数原型如下:
```C
/**
* @brief shell读取数据函数原型
*
* @param char shell读取的字符
*
* @return char 0 读取数据成功
* @return char -1 读取数据失败
*/
typedef signed char (*shellRead)(char *);
/**
* @brief shell写数据函数原型
*
* @param const char 需写的字符
*/
typedef void (*shellWrite)(const char);
```
对于使用letter shell 3.1版本,为了优化效率,修改了读写函数原型,如下:
```C
/**
* @brief shell读取数据函数原型
*
* @param data shell读取的字符
* @param len 请求读取的字符数量
*
* @return unsigned short 实际读取到的字符数量
*/
typedef unsigned short (*shellRead)(char *data, unsigned short len);
/**
* @brief shell写数据函数原型
*
* @param data 需写的字符数据
* @param len 需要写入的字符数
*
* @return unsigned short 实际写入的字符数量
*/
typedef unsigned short (*shellWrite)(char *data, unsigned short len);
```
3. 申请一片缓冲区
```C
char shellBuffer[512];
```
4. 调用shellInit进行初始化
```C
shell.read = shellRead;
shell.write = shellWrite;
shellInit(&shell, shellBuffer, 512);
```
5. 调用(建立)shell任务
对于运行在操作系统的情况,建立`shellTask`任务(确保sell_cfg.h中的配置无误),任务参数为shell对象
```C
OsTaskCreate(shellTask, &shell, ...);
```
对于裸机环境,在主循环中调用`shellTask`,或者在接收到数据时,调用`shellHandler`
6. 说明
- 对于中断方式使用shell,不用定义`shell->read`,但需要在中断中调用`shellHandler`
- 对于使用操作系统的情况,使能`SHEHLL_TASK_WHILE`宏,然后创建shellTask任务
7. 其他配置
- 定义宏`SHELL_GET_TICK()`为获取系统tick函数,使能tab双击操作,用户长帮助补全
8. 配置宏
shell_cfg.h文件中包含了所有用于配置shell的宏,在使用前,需要根据需要进行配置
建议采用 overlay 的方式,新建一个头文件,例如 `shell_cfg_user.h`,然后定义编译宏 `SHELL_CFG_USER="shell_cfg_user.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_LENGTH | shell命令最大长度 |
| SHELL_PARAMETER_MAX_NUMBER | shell命令参数最大数量 |
| 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_USER | shell默认用户 |
| SHELL_DEFAULT_USER_PASSWORD | 默认用户密码 |
| SHELL_LOCK_TIMEOUT | shell自动锁定超时 |
| SHELL_USING_FUNC_SIGNATURE | 使用函数签名 |
## 使用方式
### 函数定义
letter shell 3.x同时支持两种形式的函数定义方式,形如main函数定义的`func(int argc, char *agrv[])`以及形如普通C函数的定义`func(int i, char *str, ...)`,两种函数定义方式适用于不同的场景
#### main函数形式
使用此方式,一个函数定义的例子如下:
```C
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_MAI