1
0
mirror of https://github.com/NevermindZZT/letter-shell.git synced 2025-01-21 10:02:54 +08:00

shell 3.0

This commit is contained in:
Letter 2020-01-17 17:51:32 +08:00
parent f3a81ebb90
commit 912bbf5851
13 changed files with 2594 additions and 1993 deletions

463
README.md
View File

@ -1,47 +1,51 @@
# letter shell # letter shell 3.0
![version](https://img.shields.io/badge/version-2.0.8-brightgreen.svg) ![version](https://img.shields.io/badge/version-3.0.0_beta1-brightgreen.svg)
![build](https://img.shields.io/badge/build-2020.01.14-brightgreen.svg) ![build](https://img.shields.io/badge/build-2020.01.17-brightgreen.svg)
![build](https://img.shields.io/badge/license-MIT-brightgreen.svg) ![build](https://img.shields.io/badge/license-MIT-brightgreen.svg)
一个体积极小的嵌入式shell 一个功能强大的嵌入式shell
- [letter shell](#letter-shell) ![shell_info.png](doc/img/shell_info.png)
- [功能](#%e5%8a%9f%e8%83%bd)
- [移植说明](#%e7%a7%bb%e6%a4%8d%e8%af%b4%e6%98%8e) - [letter shell 3.0](#letter-shell-30)
- [使用方式](#%e4%bd%bf%e7%94%a8%e6%96%b9%e5%bc%8f) - [简介](#简介)
- [函数定义](#%e5%87%bd%e6%95%b0%e5%ae%9a%e4%b9%89) - [功能](#功能)
- [main函数形式](#main%e5%87%bd%e6%95%b0%e5%bd%a2%e5%bc%8f) - [移植说明](#移植说明)
- [普通C函数形式](#%e6%99%ae%e9%80%9ac%e5%87%bd%e6%95%b0%e5%bd%a2%e5%bc%8f) - [使用方式](#使用方式)
- [在函数中获取当前shell对象](#%e5%9c%a8%e5%87%bd%e6%95%b0%e4%b8%ad%e8%8e%b7%e5%8f%96%e5%bd%93%e5%89%8dshell%e5%af%b9%e8%b1%a1) - [函数定义](#函数定义)
- [命令定义](#%e5%91%bd%e4%bb%a4%e5%ae%9a%e4%b9%89) - [main函数形式](#main函数形式)
- [命令导出方式](#%e5%91%bd%e4%bb%a4%e5%af%bc%e5%87%ba%e6%96%b9%e5%bc%8f) - [普通C函数形式](#普通c函数形式)
- [命令表方式](#%e5%91%bd%e4%bb%a4%e8%a1%a8%e6%96%b9%e5%bc%8f) - [在函数中获取当前shell对象](#在函数中获取当前shell对象)
- [组合按键](#%e7%bb%84%e5%90%88%e6%8c%89%e9%94%ae) - [命令定义](#命令定义)
- [shell变量](#shell%e5%8f%98%e9%87%8f) - [定义方式](#定义方式)
- [导出变量](#%e5%af%bc%e5%87%ba%e5%8f%98%e9%87%8f) - [定义宏说明](#定义宏说明)
- [读取变量](#%e8%af%bb%e5%8f%96%e5%8f%98%e9%87%8f) - [命令属性字段说明](#命令属性字段说明)
- [修改变量](#%e4%bf%ae%e6%94%b9%e5%8f%98%e9%87%8f) - [权限系统说明](#权限系统说明)
- [变量作为命令参数](#%e5%8f%98%e9%87%8f%e4%bd%9c%e4%b8%ba%e5%91%bd%e4%bb%a4%e5%8f%82%e6%95%b0) - [建议终端软件](#建议终端软件)
- [shell密码](#shell%e5%af%86%e7%a0%81)
- [建议终端软件](#%e5%bb%ba%e8%ae%ae%e7%bb%88%e7%ab%af%e8%bd%af%e4%bb%b6) ## 简介
- [更新日志](#%e6%9b%b4%e6%96%b0%e6%97%a5%e5%bf%97)
[letter shell 3.0](https://github.com/NevermindZZT/letter-shell/tree/shell3.0)是一个C语言编写的可以嵌入在程序中的嵌入式shell主要面向嵌入式设备以C语言函数为运行单位可以通过命令行调用运行程序中的函数
相对2.x版本letter shell 3.0增加了用户管理,权限管理,后续会增加对文件系统的支持
此外3.0版本修改了命令格式和定义2.x版本的工程需要经过简单的修改才能完成迁移
## 功能 ## 功能
- 命令自动补全使用tab键补全命令 - 命令自动补全
- 命令长帮助使用help [command]显示命令长帮助 - 快捷键功能定义
- 长帮助补全输入命令后双击tab键补全命令长帮助指令 - 命令权限管理
- 快捷键支持使用Ctrl + A~Z组合按键直接调用函数 - 用户管理
- shell变量支持在shell中查看和修改变量值支持变量作为命令参数 - 变量支持
- 登录密码支持在shell中使用登录密码支持超时自动锁定
## 移植说明 ## 移植说明
1. 定义shell对象 1. 定义shell对象
```C ```C
SHELL_TypeDef shell; Shell shell;
``` ```
2. 定义shell读写函数函数原型如下 2. 定义shell读写函数函数原型如下
@ -65,15 +69,21 @@
typedef void (*shellWrite)(const char); typedef void (*shellWrite)(const char);
``` ```
3. 调用shellInit进行初始化 3. 申请一片缓冲区
```C
char shellBuffer[512];
```
4. 调用shellInit进行初始化
```C ```C
shell.read = shellRead; shell.read = shellRead;
shell.write = shellWrite; shell.write = shellWrite;
shellInit(&shell); shellInit(&shell, shellBuffer, 512);
``` ```
4. 调用(建立)shell任务 5. 调用(建立)shell任务
对于运行在操作系统的情况,建立`shellTask`任务(确保sell_cfg.h中的配置无误)任务参数为shell对象 对于运行在操作系统的情况,建立`shellTask`任务(确保sell_cfg.h中的配置无误)任务参数为shell对象
@ -81,54 +91,53 @@
OsTaskCreate(shellTask, &shell, ...); OsTaskCreate(shellTask, &shell, ...);
``` ```
对于裸机环境,在主循环中调用`shellTask`,或者在接收到数据时,调用`shellInput` 对于裸机环境,在主循环中调用`shellTask`,或者在接收到数据时,调用`shellHandler`
5. 说明 6. 说明
- 对于中断方式使用shell不用定义`shell->read`,但需要在中断中调用`shellInput` - 对于中断方式使用shell不用定义`shell->read`,但需要在中断中调用`shellHandler`
- 对于在无操作系统环境下,可以使用查询的方式,使能```SHELL_UISNG_TASK```然后在循环中不断调用shellTask - 对于使用操作系统的情况,使能```SHEHLL_TASK_WHILE```宏然后创建shellTask任务
- 对于使用操作系统的情况,使能```SHELL_USING_TASK```和```SHEHLL_TASK_WHILE```宏然后创建shellTask任务
- 打印函数返回值,使能```SHELL_DISPLAY_RETURN```宏,返回值均作为整型数据打印
6. 其他配置 7. 其他配置
- 定义宏```SHELL_GET_TICK()```为获取系统tick函数使能tab双击操作用户长帮助补全 - 定义宏`SHELL_GET_TICK()`为获取系统tick函数使能tab双击操作用户长帮助补全
7. 配置宏 8. 配置宏
shell_cfg.h文件中包含了所有用于配置shell的宏在使用前需要根据需要进行配置 shell_cfg.h文件中包含了所有用于配置shell的宏在使用前需要根据需要进行配置
| 宏 | 意义 | | 宏 | 意义 |
| -------------------------- | ------------------------------ | | --------------------------- | ------------------------------ |
| SHELL_USING_TASK | 是否使用默认shell任务 |
| SHELL_USING_CMD_EXPORT | 是否使用命令导出方式 |
| SHELL_DISPLAY_RETURN | 是否显示命令调用函数返回值 |
| SHELL_TASK_WHILE | 是否使用默认shell任务while循环 | | SHELL_TASK_WHILE | 是否使用默认shell任务while循环 |
| SHELL_AUTO_PRASE | 是否使用shell参数自动解析 | | SHELL_USING_CMD_EXPORT | 是否使用命令导出方式 |
| SHELL_LONG_HELP | 是否使用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_COMMAND_MAX_LENGTH | shell命令最大长度 | | SHELL_COMMAND_MAX_LENGTH | shell命令最大长度 |
| SHELL_PARAMETER_MAX_NUMBER | shell命令参数最大数量 | | SHELL_PARAMETER_MAX_NUMBER | shell命令参数最大数量 |
| SHELL_HISTORY_MAX_NUMBER | 历史命令记录数量 | | SHELL_HISTORY_MAX_NUMBER | 历史命令记录数量 |
| SHELL_DOUBLE_CLICK_TIME | 双击间隔(ms) | | SHELL_DOUBLE_CLICK_TIME | 双击间隔(ms) |
| SHELL_GET_TICK() | 获取系统时间(ms) |
| SHELL_DEFAULT_COMMAND | shell默认提示符 |
| SHELL_MAX_NUMBER | 管理的最大shell数量 | | SHELL_MAX_NUMBER | 管理的最大shell数量 |
| SHELL_USING_AUTH | 是否使用密码功能 | | SHELL_GET_TICK() | 获取系统时间(ms) |
| SHELL_USER_PASSWORD | 用户密码 | | SHELL_DEFAULT_USER | shell默认用户 |
| SHELL_DEFAULT_USER_PASSWORD | 默认用户密码 |
| SHELL_LOCK_TIMEOUT | shell自动锁定超时 | | SHELL_LOCK_TIMEOUT | shell自动锁定超时 |
## 使用方式 ## 使用方式
### 函数定义 ### 函数定义
letter shell 支持两种形式的函数定义方式形如main函数定义的```func(int argc, char *agrv[])```以及形如普通C函数的定义```func(int i, char *str, ...)```,这两种方式目前不可共存,只能选择其中的一种,通过宏```SHELL_AUTO_PRASE```选择 letter shell 3.0同时支持两种形式的函数定义方式形如main函数定义的`func(int argc, char *agrv[])`以及形如普通C函数的定义`func(int i, char *str, ...)`,两种函数定义方式适用于不同的场景
#### main函数形式 #### main函数形式
使用此方式,一个函数定义的例子如下: 使用此方式,一个函数定义的例子如下:
```C ```C
func(int argc, char *agrv[]) int func(int argc, char *agrv[])
{ {
printf("%dparameter(s)\r\n", argc); printf("%dparameter(s)\r\n", argc);
for (char i = 1; i < argc; i++) for (char i = 1; i < argc; i++)
@ -136,13 +145,13 @@ func(int argc, char *agrv[])
printf("%s\r\n", argv[i]); printf("%s\r\n", argv[i]);
} }
} }
SHELL_EXPORT_CMD(func, func, test) SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), func, func, test);
``` ```
终端调用 终端调用
```sh ```sh
letter>>func "hello world" letter:/$ func "hello world"
2 parameter(s) 2 parameter(s)
hello world hello world
``` ```
@ -152,239 +161,195 @@ hello world
使用此方式shell会自动对参数进行转化处理目前支持二进制八进制十进制十六进制整形字符字符串的自动处理如果需要其他类型的参数请使用字符串的方式作为参数自行进行处理例子如下 使用此方式shell会自动对参数进行转化处理目前支持二进制八进制十进制十六进制整形字符字符串的自动处理如果需要其他类型的参数请使用字符串的方式作为参数自行进行处理例子如下
```C ```C
func(int i, char ch, char *str) int func(int i, char ch, char *str)
{ {
printf("input int: %d, char: %c, string: %s\r\n", i, ch, str); printf("input int: %d, char: %c, string: %s\r\n", i, ch, str);
} }
SHELL_EXPORT_CMD(func, func, test) SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC), func, func, test);
``` ```
终端调用 终端调用
```sh ```sh
letter>>func 666 'A' "hello world" letter:/$ func 666 'A' "hello world"
input int: 666, char: A, string: hello world input int: 666, char: A, string: hello world
``` ```
#### 在函数中获取当前shell对象 #### 在函数中获取当前shell对象
shell采取一个静态数组对定义的多个shell进行管理shell数量可以修改宏```SHELL_MAX_NUMBER```定义(为了不使用动态内存分配,此处通过数据进行管理)从而在shell执行的函数中可以调用```shellGetCurrent()```获得当前活动的shell对象从而可以实现某一个函数在不同的shell对象中发生不同的行为也可以通过这种方式获得shell对象后调用```shellDisplay(shell, string)```进行shell的输出 shell采取一个静态数组对定义的多个shell进行管理shell数量可以修改宏`SHELL_MAX_NUMBER`定义(为了不使用动态内存分配,此处通过数据进行管理)从而在shell执行的函数中可以调用`shellGetCurrent()`获得当前活动的shell对象从而可以实现某一个函数在不同的shell对象中发生不同的行为也可以通过这种方式获得shell对象后调用`shellWriteString(shell, string)`进行shell的输出
### 命令定义 ## 命令定义
letter shell 3.0将可执行的函数命令定义,用户定义,按键定义以及变量定义统一归为命令定义,使用相同的结构储存,查找和执行
### 定义方式
letter shell 支持使用命令导出方式和命令表方式进行命令的添加,定义,通过宏```SHELL_USING_CMD_EXPORT```控制 letter shell 支持使用命令导出方式和命令表方式进行命令的添加,定义,通过宏```SHELL_USING_CMD_EXPORT```控制
命令导出方式支持keilIAR(未测试)以及GCC 命令导出方式支持keilIAR(未测试)以及GCC
### 命令导出方式 1. 命令导出方式
letter shell 支持在函数体外部,采用定义常量的方式定义命令,例如```SHELL_EXPORT_CMD_EX(help, shellHelp, command help, help [command] --show help info of command);```,或者```SHELL_EXPORT_CMD(help, shellHelp, command help);``` letter shell 支持在函数体外部,采用定义常量的方式定义命令,例如`SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE (SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,help, shellHelp, show command info\r\nhelp [cmd]);`
对于使用keil进行编译需要在keil的target option中增加--keep shellCommand*,防止定义的命令被优化掉 对于使用keil进行编译需要在keil的target option中增加--keep shellCommand*,防止定义的命令被优化掉
使用GCC编译时需要在ld文件中的只读数据区(建议)添加: 使用GCC编译时需要在ld文件中的只读数据区(建议)添加:
```ld ```ld
_shell_command_start = .; _shell_command_start = .;
KEEP (*(shellCommand)) KEEP (*(shellCommand))
_shell_command_end = .; _shell_command_end = .;
``` ```
### 命令表方式 2. 命令表方式
- 当使用其他编译器时,暂时不支持使用类似keil中命令导出方式,需要在命令表中添加 - 当使用其他暂时不支持使用命令导出方式的编译器时,需要在`shell_cmd_list.c`文件的命令表中添加
```C ```C
const SHELL_CommandTypeDef shellDefaultCommandList[] = const SHELL_CommandTypeDef shellDefaultCommandList[] =
{ {
SHELL_CMD_ITEM_EX(help, shellHelp, command help, help [command] --show help info of command), SHELL_CMD_ITEM(
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,
help, shellHelp, show command info\r\nhelp [cmd]),
}; };
``` ```
- 其中带有EX的命令导出宏最后一个参数为命令的长帮助信息在shell中使用help [command]可查看帮助信息通过shell.h中的SHELL_LONG_HELP宏可设置是否使用此功能 ### 定义宏说明
### 组合按键 letter shell 3.0对可执行命令,按键,用户以及变量分别提供了一个宏,用于进行命令定义
letter shell支持使用Ctrl键加任意字母键的组合按键一键执行操作使用时在任意文件定义按键命令表 1. 可执行命令定义
使用宏`SHELL_EXPORT_CMD`定义可执行命令,定义如下
```C
/**
* @brief shell 命令定义
*
* @param _attr 命令属性
* @param _name 命令名
* @param _func 命令函数
* @param _desc 命令描述
*/
#define SHELL_EXPORT_CMD(_attr, _name, _func, _desc) \
const char shellCmd##_name[] = #_name; \
const char shellDesc##_name[] = #_desc; \
const ShellCommand \
shellCommand##_name SECTION("shellCommand") = \
{ \
.attr.value = _attr, \
.data.cmd.name = shellCmd##_name, \
.data.cmd.function = (int (*)())_func, \
.data.cmd.desc = shellDesc##_name \
}
```
2. 变量定义
使用宏`SHELL_EXPORT_VAR`定义变量,定义如下
```C
/**
* @brief shell 变量定义
*
* @param _attr 变量属性
* @param _name 变量名
* @param _value 变量值
* @param _desc 变量描述
*/
#define SHELL_EXPORT_VAR(_attr, _name, _value, _desc) \
const char shellCmd##_name[] = #_name; \
const char shellDesc##_name[] = #_desc; \
const ShellCommand \
shellVar##_name SECTION("shellCommand") = \
{ \
.attr.value = _attr, \
.data.var.name = shellCmd##_name, \
.data.var.value = (void *)_value, \
.data.var.desc = shellDesc##_name \
}
```
3. 用户定义
使用宏`SHELL_EXPORT_USER`定义用户,定义如下
```C
/**
* @brief shell 用户定义
*
* @param _attr 用户属性
* @param _name 用户名
* @param _password 用户密码
* @param _desc 用户描述
*/
#define SHELL_EXPORT_USER(_attr, _name, _password, _desc) \
const char shellCmd##_name[] = #_name; \
const char shellPassword##_name[] = #_password; \
const char shellDesc##_name[] = #_desc; \
const ShellCommand \
shellUser##_name SECTION("shellCommand") = \
{ \
.attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_USER), \
.data.user.name = shellCmd##_name, \
.data.user.password = shellPassword##_name, \
.data.user.desc = shellDesc##_name \
}
```
4. 按键定义
使用宏`SHELL_EXPORT_KEY`定义按键,定义如下
```C
/**
* @brief shell 按键定义
*
* @param _attr 按键属性
* @param _value 按键键值
* @param _func 按键函数
* @param _desc 按键描述
*/
#define SHELL_EXPORT_KEY(_attr, _value, _func, _desc) \
const char shellDesc##_value[] = #_desc; \
const ShellCommand \
shellKey##_value SECTION("shellCommand") = \
{ \
.attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_KEY), \
.data.key.value = _value, \
.data.key.function = (void (*)(Shell *))_func, \
.data.key.desc = shellDesc##_value \
}
```
按键键值为在终端输入按键会发送的字符串序列以大端模式表示比如在SecureCRT中断按下Tab键会发送0x0B则这个按键的键值为0x0B000000如果按下方向上会依次发送0x1B, 0x5B, 0x41, 则这个键的键值为0x1B5B4100
### 命令属性字段说明
在命令定义中,有一个`attr`字段,表示该命令的属性,具体定义为
```C ```C
SHELL_KeyFunctionDef keyFuncList[] = union
{ {
{SHELL_KEY_CTRL_T, switchUlog} struct
}; {
unsigned char permission : 8; /**< command权限 */
ShellCommandType type : 4; /**< command类型 */
unsigned char enableUnchecked : 1; /**< 在未校验密码的情况下可用 */
unsigned char disableReturn : 1; /**< 禁用返回值输出 */
} attrs;
int value;
} attr;
``` ```
然后使用`shellSetKeyFuncList`进行注册 在定义命令时,需要给定这些值,可以通过宏`SHELL_CMD_PERMISSION(permission)`, `SHELL_CMD_TYPE(type)`, `SHELL_CMD_ENABLE_UNCHECKED`, `SHELL_CMD_DISABLE_RETURN`快速声明
```C ### 权限系统说明
shellSetKeyFuncList(&shell, keyFuncList, sizeof(keyFuncList) / sizeof(SHELL_KeyFunctionDef));
```
### shell变量 letter shell 3.0的权限管理同用户定义紧密相关letter shell 3.0使用8个bit位表示命令权限当用户和命令的权限按位与为真或者命令权限为0时表示该用户拥有此命令的权限可以调用改命令
letter shell支持shell变量通过导出变量将变量进行注册可以在shell中读取修改变量的值可以将变量作为参数传递给shell命令
使用时在shell_cfg.h文件中将`SHELL_USING_VAR`修改为1
执行`vars`命令查看所有变量
#### 导出变量
使用变量导出方式时,通过宏`SHELL_EXPORT_VAR_INT`,`SHELL_EXPORT_VAR_SHORT`,`SHELL_EXPORT_VAR_CHAR`,`SHELL_EXPORT_VAR_POINTER`导出变量,例如:
```C
SHELL_EXPORT_VAR_INT(testVar1, testVar1, var for test);
```
使用变量表方式时,定义一个命令表,并调用`shellSetVariableList`进行注册,参考命令导出
#### 读取变量
shell变量使用`$[var]`的方式读取,直接在命令行输入即可,例如:
```sh
letter>>$testVar1
testVar1 = 100, 0x00000064
```
#### 修改变量
使用`setVar`命令修改变量,例如:
```sh
letter>>setVar testVar1 200
testVar1 = 200, 0x000000c8
```
#### 变量作为命令参数
直接使用`$[var]`即可将变量的值作为参数传递给shell命令例如
```sh
letter>>getVar $testVar1
```
### shell密码
letter shell支持shell密码支持在一定时间shell无操作时自动锁定
使能宏`SHELL_USING_AUTH`开启shell密码功能同时修改宏`SHELL_USER_PASSWORD`定义shell密码
在使用密码,并且宏`SHELL_GET_TICK()`有有效定义后可以使用shell超时自动锁定通过宏`SHELL_LOCK_TIMEOUT`设置超时时长当此宏设为0时禁用超时自动锁定功能
### 建议终端软件 ### 建议终端软件
- 对于基于串口移植letter shell建议使用secureCRT软件letter shell中的相关按键映射都是按照secureCRT进行设计的使用其他串口软件可能会出现某些功能无法使用的情况 - 对于基于串口移植letter shell建议使用secureCRT软件letter shell中的相关按键映射都是按照secureCRT进行设计的使用其他串口软件时可能需要修改键值
## 更新日志
- 2018/4/20 v1.0
- 第一版
- 2018/4/23 v1.1
- 加入对带参命令的支持
- 2018/4/25 v1.2
- 合并带参函数和不带参函数命令表
- 2018/7/10 v1.3
- 修复带参命令最后输入空格时传入参数数量出错的问题
- 修复不带参数调用带参命令时程序跑死的问题,指令处理相关代码优化
- 加入对于输入超出命令长度的情况的处理措施
- 2018/7/11 v1.4
- 新增对于方向键的处理,暂时未对方向键添加具体功能
- 修复单独的空格,制表符等无效操作被识别为指令进行解析,造成程序死机的问题
- 取消制表符作为参数分隔符的用途
- 2018/7/12 v1.5
- 新增历史命令的功能,使用上下方向键操作
- 新增tab键输入最近一条命令
- 无历史记录时tab键输入help命令
- 新增一条用于清屏的默认指令
- 2018/7/18 v1.6
- 修改tab键功能加入自动补全
- 无输入情况下按下tab输入help命令
- 有输入情况下,进行自动补全
- 2018/7/24 v1.7
- 增加SHELL_TypeDef结构体
- 采用新的命令添加方式,现在可以在任意文件的函数 外部采用宏SHELL_EXPORT_CMD进行命令定义
- 2018/7/26 v1.7.1
- 修复不使用带参函数(SHELL_USE_PARAMETER = 0)的情况下,无法匹配命令的问题
- 修复不使用历史命令(SHELL_USE_HISTORY = 0)的情况下,无法使用命令补全的问题
- 2018/8/9 v1.8
- 新增左右键移动光标功能方便对输错的命令进行修改使用宏SHELL_ALLOW_SHIFT开启
- 优化结构体成员命名
- 对开启移动光标功能后,输入参数过长的情况采用新的处理方式
- 2018/11/19 v1.8.3
- 修复不使用光标移动功能的时候,输入命令过长时无法正常删除的问题
- 针对不使用MDK编译重新加入命令表定义的方式
- 新增对双引号的识别处理,支持带空格的参数
- 2019/01/07 2.0.0
- 重构代码,优化逻辑结构,减少内存开销
- 新增shell扩展模块支持函数参数自动转化
- 精简shell可选项
- 新增多shell支持
- 2019/02/20 2.0.1
- 新增命令导出方式对于IARGCC的支持
- 新增命令长帮助
- 新增二进制参数支持
- 修复bug以及一些优化
- 2019/03/29 2.0.2
- 新增函数返回值打印
- 新增shell对象管理支持在shell调用的函数中获取当前shell对象
- bug修复
- 2019/08/16 2.0.3
- 新增一个shell格式化输出函数
- 2019/08/20 2.0.4
- 新增组合按键功能自定义
- 新增shell变量
- 2019/08/21 2.0.5
- 新增shell常量
- 修复bug以及一些优化
- 2019/11/16 2.0.6
- 修复历史命令概率性异常的问题
- 新增shell密码
- 一些细节优化
- 2019/11/30 2.0.7
- 新增shell超时自动锁定
- 修复未验证密码的情况下仍能查看历史命令使用tab查看命令表的问题
- 修复双击tab补全可能在使用多shell的时候有冲突的问题
- 细节优化
- 2020/01/14 2.0.8
- 修复命令名过长时,显示命令列表异常的问题
- 修复命令被限制在256个的问题

View File

@ -0,0 +1,119 @@
/**
* @file shell_cfg.h
* @author Letter (nevermindzzt@gmail.com)
* @brief shell config
* @version 3.0.0
* @date 2019-12-31
*
* @copyright (c) 2019 Letter
*
*/
#ifndef __SHELL_CFG_H__
#define __SHELL_CFG_H__
#include "stm32f4xx_hal.h"
/**
* @brief 使shell任务while循环使`SHELL_USING_TASK`
* 使`shellTask()`使shell
* 使`shellTask()`
*/
#define SHELL_TASK_WHILE 1
/**
* @brief 使
* 使使`SHELL_EXPORT_CMD()`
* shell命令使
*/
#define SHELL_USING_CMD_EXPORT 1
/**
* @brief
*/
#define SHELL_HELP_LIST_USER 0
/**
* @brief
*/
#define SHELL_HELP_LIST_VAR 0
/**
* @brief
*/
#define SHELL_HELP_LIST_KEY 0
/**
* @brief 使LF作为命令行回车触发
* SHELL_ENTER_CR同时开启
*/
#define SHELL_ENTER_LF 0
/**
* @brief 使CR作为命令行回车触发
* SHELL_ENTER_LF同时开启
*/
#define SHELL_ENTER_CR 0
/**
* @brief 使CRLF作为命令行回车触发
* SHELL_ENTER_LF或SHELL_ENTER_CR同时开启
*/
#define SHELL_ENTER_CRLF 1
/**
* @brief shell命令参数最大数量
* 8使
*/
#define SHELL_PARAMETER_MAX_NUMBER 8
/**
* @brief
*/
#define SHELL_HISTORY_MAX_NUMBER 5
/**
* @brief (ms)
* 使`SHELL_LONG_HELP`tab补全help的时间间隔
*/
#define SHELL_DOUBLE_CLICK_TIME 200
/**
* @brief shell数量
*/
#define SHELL_MAX_NUMBER 5
/**
* @brief shell格式化输出的缓冲大小
* 0使shell格式化输出
*/
#define SHELL_PRINT_BUFFER 128
/**
* @brief (ms)
* Tick`HAL_GetTick()`
* @note 使tab补全命令help使shell超时锁定
*/
#define SHELL_GET_TICK() HAL_GetTick()
/**
* @brief shell默认用户
*/
#define SHELL_DEFAULT_USER "letter"
/**
* @brief shell默认用户密码
* ""
*/
#define SHELL_DEFAULT_USER_PASSWORD ""
/**
* @brief shell自动锁定超时
* 使`SHELL_USING_AUTH`shell
* 0`SHELL_GET_TICK()`
* @note 使`SHELL_GET_TICK()`
*/
#define SHELL_LOCK_TIMEOUT 0 * 60 * 1000
#endif

View File

@ -0,0 +1,62 @@
/**
* @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 "serial.h"
#include "stm32f4xx_hal.h"
#include "usart.h"
Shell shell;
char shellBuffer[512];
/**
* @brief shell写
*
* @param data
*/
void userShellWrite(char data)
{
serialTransmit(&debugSerial, (uint8_t *)&data, 1, 0xFF);
}
/**
* @brief shell读
*
* @param data
* @return char
*/
signed char userShellRead(char *data)
{
if (serialReceive(&debugSerial, (uint8_t *)data, 1, 0) == 1)
{
return 0;
}
else
{
return -1;
}
}
/**
* @brief shell初始化
*
*/
void userShellInit(void)
{
shell.write = userShellWrite;
shell.read = userShellRead;
shellInit(&shell, shellBuffer, 512);
}

View File

@ -0,0 +1,21 @@
/**
* @file shell_port.h
* @author Letter (NevermindZZT@gmail.com)
* @brief
* @version 0.1
* @date 2019-02-22
*
* @Copyright (c) 2019 Unicook
*
*/
#ifndef __SHELL_PORT_H__
#define __SHELL_PORT_H__
#include "serial.h"
#include "shell.h"
extern Shell shell;
void userShellInit(void);
#endif

BIN
doc/img/shell_info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

1304
shell.c

File diff suppressed because it is too large Load Diff

363
shell.h
View File

@ -1,363 +0,0 @@
/**
* @file shell.h
* @author Letter (NevermindZZT@gmail.com)
* @brief letter shell
* @version 2.0.0
* @date 2018-12-29
*
* @Copyright (c) 2018 Letter
*
*/
#ifndef __SHELL_H__
#define __SHELL_H__
#include "shell_cfg.h"
#if SHELL_USING_AUTH == 1
#if !defined(SHELL_USER_PASSWORD)
#error "please config shell user password (int shell_cfg.h) "
#endif
#endif
#define SHELL_VERSION "2.0.8" /**< 版本号 */
/**
* @brief shell键值定义
*
*/
#define SHELL_KEY_LF 0x0A
#define SHELL_KEY_CR 0x0D
#define SHELL_KEY_TAB 0x09
#define SHELL_KEY_BACKSPACE 0x08
#define SHELL_KEY_DELETE 0x7F
#define SHELL_KEY_ESC 0x1B
#define SHELL_KEY_CTRL_T 0x14
#define SHELL_KEY_CTRL_A 0x01
#define SHELL_KEY_CTRL_B 0x02
#define SHELL_KEY_CTRL_C 0x03
#define SHELL_KEY_CTRL_D 0x04
#define SHELL_KEY_CTRL_E 0x05
#define SHELL_KEY_CTRL_F 0x06
#define SHELL_KEY_CTRL_G 0x07
#define SHELL_KEY_CTRL_H 0x08
#define SHELL_KEY_CTRL_I 0x09
#define SHELL_KEY_CTRL_J 0x0A
#define SHELL_KEY_CTRL_K 0x0B
#define SHELL_KEY_CTRL_L 0x0C
#define SHELL_KEY_CTRL_M 0x0D
#define SHELL_KEY_CTRL_N 0x0E
#define SHELL_KEY_CTRL_O 0x0F
#define SHELL_KEY_CTRL_P 0x10
#define SHELL_KEY_CTRL_Q 0x11
#define SHELL_KEY_CTRL_R 0x12
#define SHELL_KEY_CTRL_S 0x13
#define SHELL_KEY_CTRL_T 0x14
#define SHELL_KEY_CTRL_U 0x15
#define SHELL_KEY_CTRL_V 0x16
#define SHELL_KEY_CTRL_W 0x17
#define SHELL_KEY_CTRL_X 0x18
#define SHELL_KEY_CTRL_Y 0x19
#define SHELL_KEY_CTRL_Z 0x1A
/**
* @brief shell变量类型定义
*
*/
#define SHELL_VAR_INT 0
#define SHELL_VAR_SHORT 1
#define SHELL_VAR_CHAR 2
#define SHELL_VAR_POINTER 3
#define SHELL_VAL 4
#if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && __ARMCC_VERSION >= 6000000)
#define SECTION(x) __attribute__((section(x)))
#elif defined(__ICCARM__)
#define SECTION(x) @ x
#elif defined(__GNUC__)
#define SECTION(x) __attribute__((section(x)))
#else
#define SECTION(x)
#endif
/**
* @brief shell命令导出
*
* @attention keil,iar的编译器以及gccreadme
*/
#if SHELL_USING_CMD_EXPORT == 1
#if SHELL_LONG_HELP == 1
#define SHELL_EXPORT_CMD(cmd, func, desc) \
const char shellCmd##cmd[] = #cmd; \
const char shellDesc##cmd[] = #desc; \
const SHELL_CommandTypeDef \
shellCommand##cmd SECTION("shellCommand") = \
{ \
shellCmd##cmd, \
(int (*)())func, \
shellDesc##cmd, \
(void *)0 \
}
#define SHELL_EXPORT_CMD_EX(cmd, func, desc, help) \
const char shellCmd##cmd[] = #cmd; \
const char shellDesc##cmd[] = #desc; \
const char shellHelp##cmd[] = #help; \
const SHELL_CommandTypeDef \
shellCommand##cmd SECTION("shellCommand") = \
{ \
shellCmd##cmd, \
(int (*)())func, \
shellDesc##cmd, \
shellHelp##cmd \
}
#else /** SHELL_LONG_HELP == 1 */
#define SHELL_EXPORT_CMD(cmd, func, desc) \
const char shellCmd##cmd[] = #cmd; \
const char shellDesc##cmd[] = #desc; \
const SHELL_CommandTypeDef \
shellCommand##cmd SECTION("shellCommand") = \
{ \
shellCmd##cmd, \
(int (*)())func, \
shellDesc##cmd \
}
#define SHELL_EXPORT_CMD_EX(cmd, func, desc, help) \
const char shellCmd##cmd[] = #cmd; \
const char shellDesc##cmd[] = #desc; \
const SHELL_CommandTypeDef \
shellCommand##cmd SECTION("shellCommand") = \
{ \
shellCmd##cmd, \
(int (*)())func, \
shellDesc##cmd \
}
#endif /** SHELL_LONG_HELP == 1 */
#if SHELL_USING_VAR == 1
#define SHELL_EXPORT_VAR(var, variable, desc, type) \
const char shellVar##var[] = #var; \
const char shellDesc##var[] = #desc; \
const SHELL_VaribaleTypeDef \
shellVariable##var SECTION("shellVariable") = \
{ \
shellVar##var, \
(void *)(variable), \
shellDesc##var, \
type \
}
#else
#define SHELL_EXPORT_VAR(var, variable, desc, type)
#endif /** SHELL_USING_VAR == 1 */
#else
#define SHELL_EXPORT_CMD(cmd, func, desc)
#define SHELL_EXPORT_CMD_EX(cmd, func, desc, help)
#define SHELL_EXPORT_VAR(var, variable, desc, type)
#endif /** SHELL_USING_CMD_EXPORT == 1 */
#define SHELL_EXPORT_VAR_INT(var, variable, desc) \
SHELL_EXPORT_VAR(var, &variable, desc, SHELL_VAR_INT)
#define SHELL_EXPORT_VAR_SHORT(var, variable, desc) \
SHELL_EXPORT_VAR(var, &variable, desc, SHELL_VAR_SHORT)
#define SHELL_EXPORT_VAR_CHAR(var, variable, desc) \
SHELL_EXPORT_VAR(var, &variable, desc, SHELL_VAR_CHAR)
#define SHELL_EXPORT_VAR_POINTER(var, variable, desc) \
SHELL_EXPORT_VAR(var, variable, desc, SHELL_VAR_POINTER)
#define SHELL_EXPORT_VAL(val, value, desc) \
SHELL_EXPORT_VAR(val, value, desc, SHELL_VAL)
/**
* @brief shell命令条目
*
* @note shell命令通过命令表的方式定义
*/
#if SHELL_USING_CMD_EXPORT == 0
#if SHELL_LONG_HELP == 1
#define SHELL_CMD_ITEM(cmd, func, desc) \
{ \
#cmd, \
(int (*)())func, \
#desc, \
(void *)0 \
}
#define SHELL_CMD_ITEM_EX(cmd, func, desc, help) \
{ \
#cmd, \
(int (*)())func, \
#desc, \
#help \
}
#else /** SHELL_LONG_HELP == 1 */
#define SHELL_CMD_ITEM(cmd, func, desc) \
{ \
#cmd, \
(int (*)())func, \
#desc \
}
#define SHELL_CMD_ITEM_EX(cmd, func, desc, help) \
{ \
#cmd, \
(int (*)())func, \
#desc, \
}
#endif /** SHELL_LONG_HELP == 1 */
#define SHELL_VAR_ITEM(var, variable, desc, type) \
{ \
#var, \
varialbe, \
#desc, \
type, \
}
#define SHELL_VAR_ITEM_INT(var, variable, desc) \
SHELL_VAR_ITEM(var, &variable, desc, SHELL_VAR_INT)
#define SHELL_VAR_ITEM_SHORT(var, variable, desc) \
SHELL_VAR_ITEM(var, &variable, desc, SHELL_VAR_SHORT)
#define SHELL_VAR_ITEM_CHAR(var, variable, desc) \
SHELL_VAR_ITEM(var, &variable, desc, SHELL_VAR_CHAR)
#define SHELL_VAR_ITEM_POINTER(var, variable, desc) \
SHELL_VAR_ITEM(var, variable, desc, SHELL_VAR_POINTER)
#endif /** SHELL_USING_CMD_EXPORT == 0 */
/**
* @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);
/**
* @brief shell指令执行函数原型
*
*/
typedef int (*shellFunction)();
/**
* @brief shell输入状态
*
*/
typedef enum
{
SHELL_IN_NORMAL = 0,
SHELL_ANSI_ESC,
SHELL_ANSI_CSI,
}SHELL_InputMode;
/**
* @brief shell
*
*/
typedef struct
{
const char *name; /**< shell命令名称 */
shellFunction function; /**< shell命令函数 */
const char *desc; /**< shell命令描述 */
#if SHELL_LONG_HELP == 1
const char *help; /**< shell长帮助信息 */
#endif
}SHELL_CommandTypeDef;
#if SHELL_USING_VAR == 1
/**
* @brief shell
*
*/
typedef struct
{
const char *name; /**< shell变量名称 */
const void *value; /**< shell变量值 */
const char *desc; /**< shell变量描述 */
const int type; /**< shell变量类型 */
} SHELL_VaribaleTypeDef;
#endif /** SHELL_USING_VAR == 1 */
/**
* @brief shell对象定义
*
*/
typedef struct
{
char *command; /**< shell命令提示符 */
char buffer[SHELL_COMMAND_MAX_LENGTH]; /**< shell命令缓冲 */
unsigned short length; /**< shell命令长度 */
unsigned short cursor; /**< shell光标位置 */
char *param[SHELL_PARAMETER_MAX_NUMBER]; /**< shell参数 */
char history[SHELL_HISTORY_MAX_NUMBER][SHELL_COMMAND_MAX_LENGTH]; /**< 历史记录 */
unsigned short historyCount; /**< 历史记录数量 */
short historyFlag; /**< 当前记录位置 */
short historyOffset; /**< 历史记录偏移 */
SHELL_CommandTypeDef *commandBase; /**< 命令表基址 */
unsigned short commandNumber; /**< 命令数量 */
#if SHELL_USING_VAR == 1
SHELL_VaribaleTypeDef *variableBase; /**< 变量表基址 */
unsigned short variableNumber; /**< 变量数量 */
#endif
int keyFuncBase; /**< 按键响应表基址 */
unsigned short keyFuncNumber; /**< 按键响应数量 */
struct
{
unsigned char inputMode : 2; /**< 输入模式 */
unsigned char isActive: 1; /**< 是否是当前活动shell */
unsigned char tabFlag : 1; /**< tab标志 */
unsigned char authFlag : 1; /**< 密码标志 */
} status; /**< shell状态 */
shellRead read; /**< shell读字符 */
shellWrite write; /**< shell写字符 */
#if SHELL_LONG_HELP == 1 || (SHELL_USING_AUTH && SHELL_LOCK_TIMEOUT > 0)
int activeTime; /**< shell激活时间戳 */
#endif
}SHELL_TypeDef;
/**
* @brief shell按键功能定义
*
*/
typedef struct
{
unsigned char keyCode; /**< shell按键键值 */
void (*keyFunction)(SHELL_TypeDef *); /**< 按键响应函数 */
} SHELL_KeyFunctionDef;
void shellInit(SHELL_TypeDef *shell);
void shellSetCommandList(SHELL_TypeDef *shell, SHELL_CommandTypeDef *base, unsigned short size);
#if SHELL_USING_VAR == 1
void shellSetVariableList(SHELL_TypeDef *shell, SHELL_VaribaleTypeDef *base, unsigned short size);
int shellGetVariable(SHELL_TypeDef *shell, char *var);
#endif /** SHELL_USING_VAR == 1 */
void shellSetKeyFuncList(SHELL_TypeDef *shell, SHELL_KeyFunctionDef *base, unsigned short size);
SHELL_TypeDef *shellGetCurrent(void);
void shellPrint(SHELL_TypeDef *shell, char *fmt, ...);
unsigned short shellDisplay(SHELL_TypeDef *shell, const char *string);
void shellHandler(SHELL_TypeDef *shell, char data);
#define shellInput shellHandler
void shellHelp(int argc, char *argv[]);
void shellClear(void);
#if SHELL_USING_TASK == 1
void shellTask(void *param);
#endif
#endif

1653
src/shell.c Normal file

File diff suppressed because it is too large Load Diff

327
src/shell.h Normal file
View File

@ -0,0 +1,327 @@
/**
* @file shell.h
* @author Letter (NevermindZZT@gmail.com)
* @brief letter shell
* @version 3.0.0
* @date 2019-12-30
*
* @Copyright (c) 2020 Letter
*
*/
#ifndef __SHELL_H__
#define __SHELL_H__
#include "shell_cfg.h"
#define SHELL_VERSION "3.0.0-beta1" /**< 版本号 */
/**
* @brief shell
*
* @param expr
* @param action
*/
#define SHELL_ASSERT(expr, action) \
if (!(expr)) { \
action; \
}
/**
* @brief shell
*
* @param permission
*/
#define SHELL_CMD_PERMISSION(permission) \
(permission & 0x000000FF)
/**
* @brief shell
*
* @param type
*/
#define SHELL_CMD_TYPE(type) \
((type & 0x0000000F) << 8)
#define SHELL_CMD_ENABLE_UNCHECKED \
(1 << 12)
#define SHELL_CMD_DISABLE_RETURN \
(1 << 13)
#if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && __ARMCC_VERSION >= 6000000)
#define SECTION(x) __attribute__((section(x)))
#elif defined(__ICCARM__)
#define SECTION(x) @ x
#elif defined(__GNUC__)
#define SECTION(x) __attribute__((section(x)))
#else
#define SECTION(x)
#endif
#if SHELL_USING_CMD_EXPORT == 1
/**
* @brief shell
*
* @param _attr
* @param _name
* @param _func
* @param _desc
*/
#define SHELL_EXPORT_CMD(_attr, _name, _func, _desc) \
const char shellCmd##_name[] = #_name; \
const char shellDesc##_name[] = #_desc; \
const ShellCommand \
shellCommand##_name SECTION("shellCommand") = \
{ \
.attr.value = _attr, \
.data.cmd.name = shellCmd##_name, \
.data.cmd.function = (int (*)())_func, \
.data.cmd.desc = shellDesc##_name \
}
/**
* @brief shell
*
* @param _attr
* @param _name
* @param _value
* @param _desc
*/
#define SHELL_EXPORT_VAR(_attr, _name, _value, _desc) \
const char shellCmd##_name[] = #_name; \
const char shellDesc##_name[] = #_desc; \
const ShellCommand \
shellVar##_name SECTION("shellCommand") = \
{ \
.attr.value = _attr, \
.data.var.name = shellCmd##_name, \
.data.var.value = (void *)_value, \
.data.var.desc = shellDesc##_name \
}
/**
* @brief shell
*
* @param _attr
* @param _name
* @param _password
* @param _desc
*/
#define SHELL_EXPORT_USER(_attr, _name, _password, _desc) \
const char shellCmd##_name[] = #_name; \
const char shellPassword##_name[] = #_password; \
const char shellDesc##_name[] = #_desc; \
const ShellCommand \
shellUser##_name SECTION("shellCommand") = \
{ \
.attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_USER), \
.data.user.name = shellCmd##_name, \
.data.user.password = shellPassword##_name, \
.data.user.desc = shellDesc##_name \
}
/**
* @brief shell
*
* @param _attr
* @param _value
* @param _func
* @param _desc
*/
#define SHELL_EXPORT_KEY(_attr, _value, _func, _desc) \
const char shellDesc##_value[] = #_desc; \
const ShellCommand \
shellKey##_value SECTION("shellCommand") = \
{ \
.attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_KEY), \
.data.key.value = _value, \
.data.key.function = (void (*)(Shell *))_func, \
.data.key.desc = shellDesc##_value \
}
#else
/**
* @brief shell item定义
*
* @param _attr
* @param _name
* @param _func
* @param _desc
*/
#define SHELL_CMD_ITEM(_attr, _name, _func, _desc) \
{ \
.attr.value = _attr, \
.data.cmd.name = #_name, \
.data.cmd.function = (int (*)())_func, \
.data.cmd.desc = #_desc \
}
/**
* @brief shell item定义
*
* @param _attr
* @param _name
* @param _value
* @param _desc
*/
#define SHELL_VAR_ITEM(_attr, _name, _value, _desc) \
{ \
.attr.value = _attr, \
.data.var.name = #_name, \
.data.var.value = (void *)_value, \
.data.var.desc = #_desc \
}
/**
* @brief shell item定义
*
* @param _attr
* @param _name
* @param _password
* @param _desc
*/
#define SHELL_USER_ITEM(_attr, _name, _password, _desc) \
{ \
.attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_USER), \
.data.user.name = #_name, \
.data.user.password = #_password, \
.data.user.desc = #_desc \
}
/**
* @brief shell item定义
*
* @param _attr
* @param _value
* @param _func
* @param _desc
*/
#define SHELL_KEY_ITEM(_attr, _value, _func, _desc) \
{ \
.attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_KEY), \
.data.key.value = _value, \
.data.key.function = (void (*)(Shell *))_func, \
.data.key.desc = #_desc \
}
#define SHELL_EXPORT_CMD(_attr, _name, _func, _desc)
#define SHELL_EXPORT_VAR(_attr, _name, _value, _desc)
#define SHELL_EXPORT_USER(_attr, _name, _password, _desc)
#define SHELL_EXPORT_KEY(_attr, _value, _func, _desc)
#endif /** SHELL_USING_CMD_EXPORT == 1 */
/**
* @brief shell command类型
*/
typedef enum
{
SHELL_TYPE_CMD_MAIN = 0, /**< main形式命令 */
SHELL_TYPE_CMD_FUNC, /**< C函数形式命令 */
SHELL_TYPE_VAR_INT, /**< int型变量 */
SHELL_TYPE_VAR_SHORT, /**< short型变量 */
SHELL_TYPE_VAR_CHAR, /**< char型变量 */
SHELL_TYPE_VAR_POINT, /**< 指针型变量 */
SHELL_TYPE_VAL, /**< 常量 */
SHELL_TYPE_USER, /**< 用户 */
SHELL_TYPE_KEY, /**< 按键 */
} ShellCommandType;
/**
* @brief Shell定义
*/
typedef struct
{
struct
{
const struct shell_command *user; /**< 当前用户 */
int activeTime; /**< shell激活时间 */
} info;
struct
{
unsigned short length; /**< 输入数据长度 */
unsigned short cursor; /**< 当前光标位置 */
char *buffer; /**< 输入缓冲 */
unsigned short bufferSize; /**< 输入缓冲大小 */
char *param[SHELL_PARAMETER_MAX_NUMBER]; /**< 参数 */
unsigned short paramCount; /**< 参数数量 */
int keyValue; /**< 输入按键键值 */
} parser;
struct
{
char *item[SHELL_HISTORY_MAX_NUMBER]; /**< 历史记录 */
unsigned short number; /**< 历史记录数 */
unsigned short record; /**< 当前记录位置 */
signed short offset; /**< 当前历史记录偏移 */
} history;
struct
{
void *base; /**< 命令表基址 */
unsigned short count; /**< 命令数量 */
} commandList;
struct
{
unsigned char isChecked : 1; /**< 密码校验通过 */
unsigned char isActive : 1; /**< 当前活动Shell */
unsigned char tabFlag : 1; /**< tab标志 */
} status;
signed char (*read)(char *); /**< shell读函数 */
void (*write)(const char); /**< shell写函数 */
} Shell;
/**
* @brief shell command定义
*/
typedef struct shell_command
{
union
{
struct
{
unsigned char permission : 8; /**< command权限 */
ShellCommandType type : 4; /**< command类型 */
unsigned char enableUnchecked : 1; /**< 在未校验密码的情况下可用 */
unsigned char disableReturn : 1; /**< 禁用返回值输出 */
} attrs;
int value;
} attr; /**< 属性 */
union
{
struct
{
const char *name; /**< 命令名 */
int (*function)(); /**< 命令执行函数 */
const char *desc; /**< 命令描述 */
} cmd; /**< 命令定义 */
struct
{
const char *name; /**< 变量名 */
void *value; /**< 变量值 */
const char *desc; /**< 变量描述 */
} var; /**< 变量定义 */
struct
{
const char *name; /**< 用户名 */
const char *password; /**< 用户密码 */
const char *desc; /**< 用户描述 */
} user; /**< 用户定义 */
struct
{
int value; /**< 按键键值 */
void (*function)(Shell *); /**< 按键执行函数 */
const char *desc; /**< 按键描述 */
} key; /**< 按键定义 */
} data;
} ShellCommand;
void shellInit(Shell *shell, char *buffer, unsigned short size);
void shellHandler(Shell *shell, char data);
void shellTask(void *param);
#endif

View File

@ -1,9 +1,9 @@
/** /**
* @file shell_cfg.h * @file shell_cfg.h
* @author Letter (NevermindZZT@gmail.com) * @author Letter (nevermindzzt@gmail.com)
* @brief shell config * @brief shell config
* @version 0.1 * @version 3.0.0
* @date 2019-04-11 * @date 2019-12-31
* *
* @copyright (c) 2019 Letter * @copyright (c) 2019 Letter
* *
@ -12,11 +12,6 @@
#ifndef __SHELL_CFG_H__ #ifndef __SHELL_CFG_H__
#define __SHELL_CFG_H__ #define __SHELL_CFG_H__
/**
* @brief 使shell任务
* 使使`shellTask()`shell任务使`shellTask()`
*/
#define SHELL_USING_TASK 0
/** /**
* @brief 使shell任务while循环使`SHELL_USING_TASK` * @brief 使shell任务while循环使`SHELL_USING_TASK`
@ -27,41 +22,43 @@
/** /**
* @brief 使 * @brief 使
* 使使`SHELL_EXPORT_CMD()``SHELL_EXPORT_CMD_EX()` * 使使`SHELL_EXPORT_CMD()`
* shell命令使 * shell命令使
*/ */
#define SHELL_USING_CMD_EXPORT 1 #define SHELL_USING_CMD_EXPORT 1
/** /**
* @brief 使 * @brief
*
*/ */
#define SHELL_USING_VAR 0 #define SHELL_HELP_LIST_USER 0
/** /**
* @brief * @brief
* 使shell命令之后会以整形和十六进制的方式打印函数的返回值
*/ */
#define SHELL_DISPLAY_RETURN 1 #define SHELL_HELP_LIST_VAR 0
/** /**
* @brief 使shell参数自动解析 * @brief
* 使C函数形式的命令shell会自动转换参数
* main函数形式的命令
*/ */
#define SHELL_AUTO_PRASE 1 #define SHELL_HELP_LIST_KEY 0
/** /**
* @brief 使shell长帮助 * @brief 使LF作为命令行回车触发
* 使 * SHELL_ENTER_CR同时开启
*/ */
#define SHELL_LONG_HELP 1 #define SHELL_ENTER_LF 1
/** /**
* @brief shell命令最大长度 * @brief 使CR作为命令行回车触发
* * SHELL_ENTER_LF同时开启
*/ */
#define SHELL_COMMAND_MAX_LENGTH 50 #define SHELL_ENTER_CR 1
/**
* @brief 使CRLF作为命令行回车触发
* SHELL_ENTER_LF或SHELL_ENTER_CR同时开启
*/
#define SHELL_ENTER_CRLF 0
/** /**
* @brief shell命令参数最大数量 * @brief shell命令参数最大数量
@ -99,19 +96,15 @@
#define SHELL_GET_TICK() 0 #define SHELL_GET_TICK() 0
/** /**
* @brief shell默认提示符 * @brief shell默认用户
*/ */
#define SHELL_DEFAULT_COMMAND "\r\nletter>>" #define SHELL_DEFAULT_USER "letter"
/** /**
* @brief 使 * @brief shell默认用户密码
* ""
*/ */
#define SHELL_USING_AUTH 0 #define SHELL_DEFAULT_USER_PASSWORD ""
/**
* @brief shell用户密码
*/
#define SHELL_USER_PASSWORD "letter"
/** /**
* @brief shell自动锁定超时 * @brief shell自动锁定超时
@ -119,6 +112,6 @@
* 0`SHELL_GET_TICK()` * 0`SHELL_GET_TICK()`
* @note 使`SHELL_GET_TICK()` * @note 使`SHELL_GET_TICK()`
*/ */
#define SHELL_LOCK_TIMEOUT 5 * 60 * 1000 #define SHELL_LOCK_TIMEOUT 0 * 60 * 1000
#endif #endif

98
src/shell_cmd_list.c Normal file
View File

@ -0,0 +1,98 @@
/**
* @file shell_cmd_list.c
* @author Letter (zhengkeqiang@ut.cn)
* @brief shell cmd list
* @version 0.1
* @date 2020-01-17
*
* @copyright (c) 2020 Unicook
*
*/
#include "shell.h"
#if SHELL_USING_CMD_EXPORT != 1
extern int shellSetVar(char *name, int value);
extern void shellUp(Shell *shell);
extern void shellDown(Shell *shell);
extern void shellRight(Shell *shell);
extern void shellLeft(Shell *shell);
extern void shellTab(Shell *shell);
extern void shellBackspace(Shell *shell);
extern void shellDelete(Shell *shell);
extern void shellEnter(Shell *shell);
extern void shellHelp(int argc, char *argv[]);
extern void shellUsers(void);
extern void shellCmds(void);
extern void shellVars(void);
extern void shellKeys(void);
extern void shellClear(void);
/**
* @brief shell命令表
*
*/
const ShellCommand shellCommandList[] =
{
{.attr.value=SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_USER),
.data.user.name = SHELL_DEFAULT_USER,
.data.user.password = SHELL_DEFAULT_USER_PASSWORD,
.data.user.desc = "defalut user"},
SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),
setVar, shellSetVar, set var),
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0), 0x1B5B4100, shellUp, up),
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0), 0x1B5B4200, shellDown, down),
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
0x1B5B4300, shellRight, right),
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
0x1B5B4400, shellLeft, left),
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0), 0x09000000, shellTab, tab),
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
0x08000000, shellBackspace, backspace),
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
0x7F000000, shellDelete, delete),
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
0x1B5B337E, shellDelete, delete),
#if SHELL_ENTER_LF == 1
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
0x0A000000, shellEnter, enter),
#endif
#if SHELL_ENTER_CR == 1
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
0x0D000000, shellEnter, enter),
#endif
#if SHELL_ENTER_CRLF == 1
SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
0x0D0A0000, shellEnter, enter),
#endif
SHELL_CMD_ITEM(
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,
help, shellHelp, show command info\r\nhelp [cmd]),
SHELL_CMD_ITEM(
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
users, shellUsers, list all user),
SHELL_CMD_ITEM(
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
cmds, shellCmds, list all cmd),
SHELL_CMD_ITEM(
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
vars, shellVars, list all var),
SHELL_CMD_ITEM(
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
keys, shellKeys, list all key),
SHELL_CMD_ITEM(
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
clear, shellClear, clear console),
};
/**
* @brief shell命令表大小
*
*/
const unsigned short shellCommandCount
= sizeof(shellCommandList) / sizeof(ShellCommand);
#endif

View File

@ -2,8 +2,8 @@
* @file shell_ext.c * @file shell_ext.c
* @author Letter (NevermindZZT@gmail.com) * @author Letter (NevermindZZT@gmail.com)
* @brief shell extensions * @brief shell extensions
* @version 1.0.0 * @version 3.0.0
* @date 2019-01-05 * @date 2019-12-31
* *
* @Copyright (c) 2019 Letter * @Copyright (c) 2019 Letter
* *
@ -14,6 +14,12 @@
#include "shell_ext.h" #include "shell_ext.h"
extern ShellCommand* shellSeekCommand(Shell *shell,
const char *cmd,
ShellCommand *base,
unsigned short compareLength);
extern int shellGetVarValue(Shell *shell, ShellCommand *command);
/** /**
* @brief * @brief
* *
@ -231,13 +237,38 @@ static unsigned int shellExtParseNumber(char *string)
} }
/**
* @brief
*
* @param shell shell对象
* @param var
* @return unsigned int
*/
static unsigned int shellExtParseVar(Shell *shell, char *var)
{
ShellCommand *command = shellSeekCommand(shell,
var + 1,
shell->commandList.base,
0);
if (command)
{
return shellGetVarValue(shell, command);
}
else
{
return 0;
}
}
/** /**
* @brief * @brief
* *
* @param shell shell对象
* @param string * @param string
* @return unsigned int * @return unsigned int
*/ */
unsigned int shellExtParsePara(char *string) unsigned int shellExtParsePara(Shell *shell, char *string)
{ {
if (*string == '\'' && *(string + 1)) if (*string == '\'' && *(string + 1))
{ {
@ -247,12 +278,10 @@ unsigned int shellExtParsePara(char *string)
{ {
return (unsigned int)shellExtParseNumber(string); return (unsigned int)shellExtParseNumber(string);
} }
#if SHELL_USING_VAR == 1
else if (*string == '$' && *(string + 1)) else if (*string == '$' && *(string + 1))
{ {
return (unsigned int )shellGetVariable(shellGetCurrent(), string); return shellExtParseVar(shell, string);
} }
#endif /** SHELL_USING_VAR == 1 */
else if (*string) else if (*string)
{ {
return (unsigned int)shellExtParseString(string); return (unsigned int)shellExtParseString(string);
@ -264,12 +293,13 @@ unsigned int shellExtParsePara(char *string)
/** /**
* @brief * @brief
* *
* @param shell shell对象
* @param function * @param function
* @param argc * @param argc
* @param argv * @param argv
* @return int * @return int
*/ */
int shellExtRun(shellFunction function, int argc, char *argv[]) int shellExtRun(Shell *shell, int (*function)(), int argc, char *argv[])
{ {
switch (argc) switch (argc)
{ {
@ -277,34 +307,34 @@ int shellExtRun(shellFunction function, int argc, char *argv[])
return function(); return function();
// break; // break;
case 2: case 2:
return function(shellExtParsePara(argv[1])); return function(shellExtParsePara(shell, argv[1]));
// break; // break;
case 3: case 3:
return function(shellExtParsePara(argv[1]), shellExtParsePara(argv[2])); return function(shellExtParsePara(shell, argv[1]), shellExtParsePara(shell, argv[2]));
// break; // break;
case 4: case 4:
return function(shellExtParsePara(argv[1]), shellExtParsePara(argv[2]), return function(shellExtParsePara(shell, argv[1]), shellExtParsePara(shell, argv[2]),
shellExtParsePara(argv[3])); shellExtParsePara(shell, argv[3]));
// break; // break;
case 5: case 5:
return function(shellExtParsePara(argv[1]), shellExtParsePara(argv[2]), return function(shellExtParsePara(shell, argv[1]), shellExtParsePara(shell, argv[2]),
shellExtParsePara(argv[3]), shellExtParsePara(argv[4])); shellExtParsePara(shell, argv[3]), shellExtParsePara(shell, argv[4]));
// break; // break;
case 6: case 6:
return function(shellExtParsePara(argv[1]), shellExtParsePara(argv[2]), return function(shellExtParsePara(shell, argv[1]), shellExtParsePara(shell, argv[2]),
shellExtParsePara(argv[3]), shellExtParsePara(argv[4]), shellExtParsePara(shell, argv[3]), shellExtParsePara(shell, argv[4]),
shellExtParsePara(argv[5])); shellExtParsePara(shell, argv[5]));
// break; // break;
case 7: case 7:
return function(shellExtParsePara(argv[1]), shellExtParsePara(argv[2]), return function(shellExtParsePara(shell, argv[1]), shellExtParsePara(shell, argv[2]),
shellExtParsePara(argv[3]), shellExtParsePara(argv[4]), shellExtParsePara(shell, argv[3]), shellExtParsePara(shell, argv[4]),
shellExtParsePara(argv[5]), shellExtParsePara(argv[6])); shellExtParsePara(shell, argv[5]), shellExtParsePara(shell, argv[6]));
// break; // break;
case 8: case 8:
return function(shellExtParsePara(argv[1]), shellExtParsePara(argv[2]), return function(shellExtParsePara(shell, argv[1]), shellExtParsePara(shell, argv[2]),
shellExtParsePara(argv[3]), shellExtParsePara(argv[4]), shellExtParsePara(shell, argv[3]), shellExtParsePara(shell, argv[4]),
shellExtParsePara(argv[5]), shellExtParsePara(argv[6]), shellExtParsePara(shell, argv[5]), shellExtParsePara(shell, argv[6]),
shellExtParsePara(argv[7])); shellExtParsePara(shell, argv[7]));
// break; // break;
default: default:
return -1; return -1;

View File

@ -2,8 +2,8 @@
* @file shell_ext.h * @file shell_ext.h
* @author Letter (NevermindZZT@gmail.com) * @author Letter (NevermindZZT@gmail.com)
* @brief shell extensions * @brief shell extensions
* @version 1.0.0 * @version 3.0.0
* @date 2019-01-05 * @date 2019-12-31
* *
* @Copyright (c) 2019 Letter * @Copyright (c) 2019 Letter
* *
@ -27,7 +27,7 @@ typedef enum
NUM_TYPE_FLOAT /**< 浮点型 */ NUM_TYPE_FLOAT /**< 浮点型 */
} NUM_Type; } NUM_Type;
unsigned int shellExtParsePara(char *string); unsigned int shellExtParsePara(Shell *shell, char *string);
int shellExtRun(shellFunction function, int argc, char *argv[]); int shellExtRun(Shell *shell, int (*function)(), int argc, char *argv[]);
#endif #endif