From b10ebd11abdd75ad17b6f6b5250fa12be31a19c8 Mon Sep 17 00:00:00 2001 From: Letter Date: Wed, 2 Jun 2021 22:27:48 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20passthrough=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E6=97=A0=E8=BE=93=E5=85=A5=E7=8A=B6=E6=80=81=E4=B8=8B?= =?UTF-8?q?=E5=9B=9E=E8=BD=A6=E6=97=A0=E5=93=8D=E5=BA=94=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extensions/shell_enhance/shell_passthrough.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/extensions/shell_enhance/shell_passthrough.c b/extensions/shell_enhance/shell_passthrough.c index f951c58..654dfd8 100644 --- a/extensions/shell_enhance/shell_passthrough.c +++ b/extensions/shell_enhance/shell_passthrough.c @@ -40,15 +40,14 @@ unsigned int shellPassthrough(Shell *shell, const char *prompt, ShellPassthrough { if (data == '\r' || data == '\n') { - if (shell->parser.length == 0) + shellWriteString(shell, "\r\n"); + if (shell->parser.length != 0) { - continue; + shell->parser.buffer[shell->parser.length] = 0; + handler(shell->parser.buffer, shell->parser.length); + shell->parser.length = 0; + shell->parser.cursor = 0; } - shellWriteString(shell, "\r\n"); - shell->parser.buffer[shell->parser.length] = 0; - handler(shell->parser.buffer, shell->parser.length); - shell->parser.length = 0; - shell->parser.cursor = 0; shellWriteString(shell, prompt); } else if (data == SHELL_PASSTHROUGH_EXIT_KEY) From e383e5a6bbf804831c49c6453188ea775dac081a Mon Sep 17 00:00:00 2001 From: Letter Date: Wed, 2 Jun 2021 22:37:53 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20passthrough=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E9=80=80=E5=87=BA=E6=97=B6=E7=BC=93=E5=86=B2=E5=8C=BA?= =?UTF-8?q?=E6=9C=AA=E6=B8=85=E7=A9=BA=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extensions/shell_enhance/shell_passthrough.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extensions/shell_enhance/shell_passthrough.c b/extensions/shell_enhance/shell_passthrough.c index 654dfd8..fec78a5 100644 --- a/extensions/shell_enhance/shell_passthrough.c +++ b/extensions/shell_enhance/shell_passthrough.c @@ -53,6 +53,8 @@ unsigned int shellPassthrough(Shell *shell, const char *prompt, ShellPassthrough else if (data == SHELL_PASSTHROUGH_EXIT_KEY) { shellWriteString(shell, "\r\n"); + shell->parser.length = 0; + shell->parser.cursor = 0; return -1; } else From fe95543f6b9c2c729d226f91b243c527a578b7d8 Mon Sep 17 00:00:00 2001 From: Letter Date: Sat, 5 Jun 2021 23:04:53 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20x86=20demo=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E8=BF=87=E5=BF=AB=E6=97=B6=E7=9A=84=E5=9B=9E=E6=98=BE?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo/x86-gcc/shell_port.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/demo/x86-gcc/shell_port.c b/demo/x86-gcc/shell_port.c index 8b5e50f..877b8ea 100644 --- a/demo/x86-gcc/shell_port.c +++ b/demo/x86-gcc/shell_port.c @@ -73,8 +73,8 @@ unsigned short userShellRead(char *data, unsigned short len) { *data++ = getchar(); } - system("stty icanon"); - system("stty echo"); + // system("stty icanon"); + // system("stty echo"); return len; } @@ -142,8 +142,8 @@ void userShellInit(void) log.write = terminalLogWrite; logRegister(&log, &shell); - logDebug("hello world"); - logHexDump(LOG_ALL_OBJ, LOG_DEBUG, (void *)&shell, sizeof(shell)); + // logDebug("hello world"); + // logHexDump(LOG_ALL_OBJ, LOG_DEBUG, (void *)&shell, sizeof(shell)); } From 6b79f9a4a14b0e47a96108d393f56a1319951978 Mon Sep 17 00:00:00 2001 From: Letter Date: Sat, 12 Jun 2021 16:39:12 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E5=8F=8C=E5=87=BBtab?= =?UTF-8?q?=E5=BF=AB=E9=80=9F=E5=B8=AE=E5=8A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + demo/x86-gcc/shell_cfg.h | 9 ++++++- demo/x86-gcc/shell_port.c | 13 ++++++++++ src/shell.c | 50 ++++++++++++++++++++++++++------------- src/shell_cfg.h | 7 ++++++ 5 files changed, 63 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index d7550c4..93ec93d 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,7 @@ | 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 | 是否使用锁 | diff --git a/demo/x86-gcc/shell_cfg.h b/demo/x86-gcc/shell_cfg.h index 974f5bf..78a1860 100644 --- a/demo/x86-gcc/shell_cfg.h +++ b/demo/x86-gcc/shell_cfg.h @@ -13,6 +13,7 @@ #define __SHELL_CFG_H__ #include "stdlib.h" +unsigned int userGetTick(); /** * @brief 是否使用默认shell任务while循环,使能宏`SHELL_USING_TASK`后此宏有意义 @@ -101,6 +102,12 @@ */ #define SHELL_DOUBLE_CLICK_TIME 200 +/** + * @brief 快速帮助 + * 作用于双击tab的场景,当使能此宏时,双击tab不会对命令进行help补全,而是直接显示对应命令的帮助信息 + */ +#define SHELL_QUICK_HELP 1 + /** * @brief 管理的最大shell数量 */ @@ -124,7 +131,7 @@ * 定义此宏为获取系统Tick,如`HAL_GetTick()` * @note 此宏不定义时无法使用双击tab补全命令help,无法使用shell超时锁定 */ -#define SHELL_GET_TICK() 0 +#define SHELL_GET_TICK() userGetTick() /** * @brief 使用锁 diff --git a/demo/x86-gcc/shell_port.c b/demo/x86-gcc/shell_port.c index 877b8ea..f882298 100644 --- a/demo/x86-gcc/shell_port.c +++ b/demo/x86-gcc/shell_port.c @@ -18,6 +18,7 @@ #include #include #include +#include Shell shell; char shellBuffer[512]; @@ -28,6 +29,18 @@ Log log = { .level = LOG_DEBUG }; +/** + * @brief 获取系统tick + * + * @return unsigned int 系统tick + */ +unsigned int userGetTick() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000 + tv.tv_usec / 1000) & 0x7FFFFFFF; +} + /** * @brief 日志写函数实现 * diff --git a/src/shell.c b/src/shell.c index a5daebc..d22d346 100644 --- a/src/shell.c +++ b/src/shell.c @@ -158,6 +158,7 @@ ShellCommand* shellSeekCommand(Shell *shell, const char *cmd, ShellCommand *base, unsigned short compareLength); +static void shellWriteCommandHelp(Shell *shell, char *cmd); /** * @brief shell 初始化 @@ -1543,6 +1544,12 @@ void shellTab(Shell *shell) && shell->status.tabFlag && SHELL_GET_TICK() - shell->info.activeTime < SHELL_DOUBLE_CLICK_TIME) { + #if SHELL_QUICK_HELP == 1 + shellWriteString(shell, "\r\n"); + shellWriteCommandHelp(shell, shell->parser.buffer); + shellWritePrompt(shell, 1); + shellWriteString(shell, shell->parser.buffer); + #else shellClearCommandLine(shell); for (short i = shell->parser.length; i >= 0; i--) { @@ -1553,6 +1560,7 @@ void shellTab(Shell *shell) shell->parser.length += 5; shell->parser.cursor = shell->parser.length; shellWriteString(shell, shell->parser.buffer); + #endif } else { @@ -1614,6 +1622,31 @@ SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED, 0x0D0A0000, shellEnter, enter); #endif +/** + * @brief shell 写命令帮助信息 + * + * @param shell shell对象 + * @param cmd 命令字符串 + */ +static void shellWriteCommandHelp(Shell *shell, char *cmd) +{ + ShellCommand *command = shellSeekCommand(shell, + cmd, + shell->commandList.base, + 0); + if (command) + { + shellWriteString(shell, shellText[SHELL_TEXT_HELP_HEADER]); + shellWriteString(shell, shellGetCommandName(command)); + shellWriteString(shell, "\r\n"); + shellWriteString(shell, shellGetCommandDesc(command)); + shellWriteString(shell, "\r\n"); + } + else + { + shellWriteString(shell, shellText[SHELL_TEXT_CMD_NOT_FOUND]); + } +} /** * @brief shell help @@ -1631,22 +1664,7 @@ void shellHelp(int argc, char *argv[]) } else if (argc > 1) { - ShellCommand *command = shellSeekCommand(shell, - argv[1], - shell->commandList.base, - 0); - if (command) - { - shellWriteString(shell, shellText[SHELL_TEXT_HELP_HEADER]); - shellWriteString(shell, shellGetCommandName(command)); - shellWriteString(shell, "\r\n"); - shellWriteString(shell, shellGetCommandDesc(command)); - shellWriteString(shell, "\r\n"); - } - else - { - shellWriteString(shell, shellText[SHELL_TEXT_CMD_NOT_FOUND]); - } + shellWriteCommandHelp(shell, argv[1]); } } SHELL_EXPORT_CMD( diff --git a/src/shell_cfg.h b/src/shell_cfg.h index 37cabaf..55e1393 100644 --- a/src/shell_cfg.h +++ b/src/shell_cfg.h @@ -100,6 +100,13 @@ */ #define SHELL_DOUBLE_CLICK_TIME 200 +/** + * @brief 快速帮助 + * 作用于双击tab的场景,当使能此宏时,双击tab不会对命令进行help补全,而是直接显示对应命令的帮助信息 + */ +#define SHELL_QUICK_HELP 1 + + /** * @brief 管理的最大shell数量 */ From a34f08ab6ff9980cc076c78d11039f42e958405c Mon Sep 17 00:00:00 2001 From: Letter Date: Sun, 27 Jun 2021 12:28:28 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E4=BC=98=E5=8C=96=20=E6=9C=80=E5=A4=A7?= =?UTF-8?q?=E5=8E=86=E5=8F=B2=E8=AE=B0=E5=BD=95=E8=AE=BE=E7=BD=AE=E4=B8=BA?= =?UTF-8?q?0s=E6=97=B6=E7=A7=BB=E9=99=A4=E7=9B=B8=E5=85=B3=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++---- src/shell.c | 15 ++++++++++++--- src/shell.h | 4 +++- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 93ec93d..fe3d468 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # letter shell 3.x -![version](https://img.shields.io/badge/version-3.1.0-brightgreen.svg) +![version](https://img.shields.io/badge/version-3.1.1-brightgreen.svg) ![standard](https://img.shields.io/badge/standard-c99-brightgreen.svg) -![build](https://img.shields.io/badge/build-2021.05.24-brightgreen.svg) +![build](https://img.shields.io/badge/build-2021.06.27-brightgreen.svg) ![license](https://img.shields.io/badge/license-MIT-brightgreen.svg) 一个功能强大的嵌入式shell @@ -284,7 +284,7 @@ letter shell采取一个静态数组对定义的多个shell进行管理,shell ### 执行未导出函数 -letter shell支持通过函数地址直接执行函数,可以方便执行那些没有导出,但是有临时需要使用的函数,使用命令`exec [addr] [args]`执行,使用此功能需要开启`SHELL_EXEC_UNDEF_FUNC`宏,注意,由于直接操作函数地址执行,如果给进的地址有误,可能引起程序崩溃 +letter shell支持通过函数地址直接执行函数,可以方便执行那些没有导出,但是又临时需要使用的函数,使用命令`exec [addr] [args]`执行,使用此功能需要开启`SHELL_EXEC_UNDEF_FUNC`宏,注意,由于直接操作函数地址执行,如果给进的地址有误,可能引起程序崩溃 函数的地址可以通过编译生成的文件查找,比如说对于keil,可以在`.map`文件中查找到每个函数的地址,对于keil,`.map`文件中的地址需要偏移一个字节,才可以成功执行,比如说`shellClear`函数地址为`0x08028620`,则通过`exec`执行应为`exec 0x08028621` @@ -298,7 +298,7 @@ letter shell 3.x将可执行的函数命令定义,用户定义,按键定义 letter shell 支持使用命令导出方式和命令表方式进行命令的添加,定义,通过宏```SHELL_USING_CMD_EXPORT```控制 -命令导出方式支持keil,IAR(未测试)以及GCC +命令导出方式支持keil,IAR以及GCC 1. 命令导出方式 diff --git a/src/shell.c b/src/shell.c index d22d346..507e8e1 100644 --- a/src/shell.c +++ b/src/shell.c @@ -169,18 +169,21 @@ void shellInit(Shell *shell, char *buffer, unsigned short size) { shell->parser.length = 0; shell->parser.cursor = 0; - shell->history.offset = 0; - shell->history.number = 0; - shell->history.record = 0; shell->info.user = NULL; shell->status.isChecked = 1; shell->parser.buffer = buffer; shell->parser.bufferSize = size / (SHELL_HISTORY_MAX_NUMBER + 1); + +#if SHELL_HISTORY_MAX_NUMBER > 0 + shell->history.offset = 0; + shell->history.number = 0; + shell->history.record = 0; for (short i = 0; i < SHELL_HISTORY_MAX_NUMBER; i++) { shell->history.item[i] = buffer + shell->parser.bufferSize * (i + 1); } +#endif /** SHELL_HISTORY_MAX_NUMBER > 0 */ #if SHELL_USING_CMD_EXPORT == 1 #if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && __ARMCC_VERSION >= 6000000) @@ -1272,6 +1275,7 @@ static void shellWriteReturnValue(Shell *shell, int value) } +#if SHELL_HISTORY_MAX_NUMBER > 0 /** * @brief shell历史记录添加 * @@ -1351,6 +1355,7 @@ static void shellHistory(Shell *shell, signed char dir) } } +#endif /** SHELL_HISTORY_MAX_NUMBER > 0 */ /** @@ -1383,7 +1388,9 @@ void shellExec(Shell *shell) if (shell->status.isChecked) { + #if SHELL_HISTORY_MAX_NUMBER > 0 shellHistoryAdd(shell); + #endif /** SHELL_HISTORY_MAX_NUMBER > 0 */ shellParserParam(shell); shell->parser.length = shell->parser.cursor = 0; if (shell->parser.paramCount == 0) @@ -1412,6 +1419,7 @@ void shellExec(Shell *shell) } +#if SHELL_HISTORY_MAX_NUMBER > 0 /** * @brief shell上方向键输入 * @@ -1434,6 +1442,7 @@ void shellDown(Shell *shell) shellHistory(shell, -1); } SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0), 0x1B5B4200, shellDown, down); +#endif /** SHELL_HISTORY_MAX_NUMBER > 0 */ /** diff --git a/src/shell.h b/src/shell.h index 5f2aa56..f05a5e3 100644 --- a/src/shell.h +++ b/src/shell.h @@ -14,7 +14,7 @@ #include "shell_cfg.h" -#define SHELL_VERSION "3.1.0" /**< 版本号 */ +#define SHELL_VERSION "3.1.1" /**< 版本号 */ /** @@ -341,6 +341,7 @@ typedef struct shell_def unsigned short paramCount; /**< 参数数量 */ int keyValue; /**< 输入按键键值 */ } parser; +#if SHELL_HISTORY_MAX_NUMBER > 0 struct { char *item[SHELL_HISTORY_MAX_NUMBER]; /**< 历史记录 */ @@ -348,6 +349,7 @@ typedef struct shell_def unsigned short record; /**< 当前记录位置 */ signed short offset; /**< 当前历史记录偏移 */ } history; +#endif /** SHELL_HISTORY_MAX_NUMBER > 0 */ struct { void *base; /**< 命令表基址 */