在线时间2417 小时
UID3327992
注册时间2018-4-5
NXP金币3529
TA的每日心情 | 奋斗 昨天 09:21 |
---|
签到天数: 1954 天 [LV.Master]伴坛终老
版主
- 积分
- 17447
- 最后登录
- 2024-5-10
|
本帖最后由 流水源 于 2023-6-15 16:58 编辑
本次研究移植letter-shell。letter-shell一个功能强大的嵌入式shell,是一个C语言编写的,可以嵌入在程序中的嵌入式shell,主要面向嵌入式设备,以C语言函数为运行单位,可以通过命令行调用,运行程序中的函数。地址:https://github.com/NevermindZZT/letter-shell
功能- 命令自动补全
- 快捷键功能定义
- 命令权限管理
- 用户管理
- 变量支持
- 代理函数和参数代理解析
下面开始移植:移植流程官方仓库说明的很清晰,看说明照着做一遍基本就可以了。
//初始化接口,对接串口。
- #include "shell_cfg_user.h"
- #include "drv_uart.h"
- #include "shell.h"
- Shell shell;
- char shellBuffer[512];
- /**
- * @brief 用户shell写
- *
- * @param data 数据
- * @param len 数据长度
- *
- * @return short 实际写入的数据长度
- */
- short userShellWrite(char *data, unsigned short len)
- {
- for(uint32_t i=0;i<len;i++)
- stdout_putchar(data[i]);
- return len;
- }
- /**
- * @brief 用户shell读
- *
- * @param data 数据
- * @param len 数据长度
- *
- * @return short 实际读取到
- */
- short userShellRead(char *data, unsigned short len)
- {
- uint32_t rlen = 0;
- for(uint32_t i=0;i<len;i++)
- {
- if(shell_uart_rx.read_i != shell_uart_rx.write_i)
- {
- data[rlen++] = shell_uart_rx.buff[shell_uart_rx.read_i++];
- shell_uart_rx.read_i &= 0x7f;
- }
- }
- return rlen;
- }
- /**
- * @brief 用户shell上锁
- *
- * @param shell shell
- *
- * @return int 0
- */
- int userShellLock(Shell *shell)
- {
- return 0;
- }
- /**
- * @brief 用户shell解锁
- *
- * @param shell shell
- *
- * @return int 0
- */
- int userShellUnlock(Shell *shell)
- {
- return 0;
- }
- /**
- * @brief 用户shell初始化
- *
- */
- void userShellInit(void)
- {
- shell.write = userShellWrite;
- shell.read = userShellRead;
- // shell.lock = userShellLock;
- // shell.unlock = userShellUnlock;
- shellInit(&shell, shellBuffer, 512);
- }
复制代码
串口部分:
初始化调用:userShellInit(); //letter shell
主循环中调用:shell_usart_loop();调用shellHandler()处理串口接收的字符。
- void drv_usart_gpio_init(void)
- {
- usart_config_t USART_InitStructure;
-
- CLOCK_Select(kUART0_Clk_From_MainClk);
- RESET_PeripheralReset(kUART0_RST_N_SHIFT_RSTn);
-
- USART_GetDefaultConfig(&USART_InitStructure);
- USART_InitStructure.baudRate_Bps = 115200;
- USART_InitStructure.enableRx = 1U;
- USART_InitStructure.enableTx = 1U;
- USART_Init(USART0, &USART_InitStructure, CLOCK_GetMainClkFreq());
-
- //使能UARTx RC中断
- USART_EnableInterrupts(USART0, kUSART_RxReadyInterruptEnable);
- //优先级,无优先级分组
- NVIC_SetPriority(USART0_IRQn, 0);
- //UARTx中断使能
- NVIC_EnableIRQ(USART0_IRQn);
- #if UART_SHELL == LETTER_SHELL
- userShellInit(); //letter shell
- #elif UART_SHELL == NR_MICRO_SHELL
- shell_init();
- #endif
- }
- int stdout_putchar (int ch)
- {
- while (0 == (USART_GetStatusFlags(USART0) & USART_STAT_TXRDY_MASK));
- USART_WriteByte(USART0, (uint8_t)ch);
-
- return ch;
- }
- int fputc(int ch,FILE *f)
- {
- return stdout_putchar(ch);
- }
- fifo_buffer shell_uart_rx=
- {
- .read_i = 0,
- .write_i = 0,
- };
- void shell_usart_loop(void)
- {
- if(shell_uart_rx.read_i != shell_uart_rx.write_i)
- {
- #if UART_SHELL == LETTER_SHELL
- shellHandler(&shell, shell_uart_rx.buff[shell_uart_rx.read_i++]); //letter shell
- #elif UART_SHELL == NR_MICRO_SHELL
- shell(shell_uart_rx.buff[shell_uart_rx.read_i++]);
- #endif
- shell_uart_rx.read_i &= 0x7f;
- }
- }
- void USART0_IRQHandler(void)
- {
- uint32_t statusFlag;
- uint32_t ch;
-
- statusFlag = USART0->STAT;
- if((statusFlag & USART_STAT_RXRDY_MASK) != 0)
- {
- ch = USART_ReadByte(USART0);
- if(((shell_uart_rx.write_i+1)&0x7f) != shell_uart_rx.read_i)
- {
- shell_uart_rx.buff[shell_uart_rx.write_i++] = ch & 0xff;
- shell_uart_rx.write_i &= 0x7f;
- }
- }
- USART0->STAT |= statusFlag;
- }
复制代码
使用方法,仓库内也有说明和例子。
例如添加用户的定义:
//测试添加用户:
SHELL_EXPORT_USER(SHELL_CMD_PERMISSION(0xFF), root, 666666, root user);
SHELL_EXPORT_USER(SHELL_CMD_PERMISSION(0x01), LSY, 666666, test user);
这里添加了2个用户,root和LSY。密码都是666666.但是2个用户权限不同。
letter-shell有2种添加函数命令方式。
第一种main函数形式。看如下例子,使用int argc, char *argv[]参数,并给函数添加不同权限。
默认的letter用户是使用不了下面函数命令的,
新加的root拥有下面2个函数func和func2权限.
新加的LSY只拥有func的权限。
- //测试添加mian命令
- int func(int argc, char *argv[])
- {
- printf("%d parameter(s)\r\n", argc);
- for (char i = 1; i < argc; i++)
- {
- printf("%s\r\n", argv[i]);
- }
- return 0;
- }
- SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0x01)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), func, func, test1);
- SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0x02)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), func2, func, test2);
- //letter:/$ func "hello world"
- //2 parameter(s)
- //hello world
复制代码
第二种是普通C函数形式:
如下例子:主要是函数参数方式不同。在输入命令参数时的方式就不同。
这个例子设置函数权限为0,意思是所有用户都拥有这个函数权限。
- //测试添加func命令
- int func1(int i, char ch, char *str)
- {
- printf("input int: %d, char: %c, string: %s\r\n", i, ch, str);
- return 0;
- }
- SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC), func1, func1, test3);
- //letter:/$ func1 666 'A' "hello world"
- //input int: 666, char: A, string: hello world
-
复制代码
添加变量方式:
这里权限使用0xFF,标识除了权限为0的用户,其他用户都可以操作这个变量。
- uint32_t muzhu_cnt;
- SHELL_EXPORT_VAR(SHELL_CMD_PERMISSION(0xFF) | SHELL_CMD_TYPE(SHELL_TYPE_VAR_INT),muzhu_cnt,&muzhu_cnt,muzhu-count);
复制代码
下面测试一下效果:
这是默认用户letter时效果。
下面切换到root用户看看,直接输入root回车,然后输入密码666666.
下面切换LSY用户效果:
可以看到不同用户下,命令根据权限的不同。执行的命令也不同。
工程添加的文件:shell_port.c,shell_port.h,shell_cfg_user.h为添加的接口文件。
shell_cfg_user.h添加的配置:
- #if 0
- #define SHELL_TASK_WHILE //是否使用默认shell任务while循环
- #define SHELL_USING_CMD_EXPORT //是否使用命令导出方式
- #define SHELL_USING_COMPANION //是否使用shell伴生对象功能
- #define SHELL_SUPPORT_END_LINE //是否支持shell尾行模式
- #define SHELL_HELP_LIST_USER //是否在输入命令列表中列出用户
- #define SHELL_HELP_LIST_VAR //是否在输入命令列表中列出变量
- #define SHELL_HELP_LIST_KEY //是否在输入命令列表中列出按键
- #define SHELL_ENTER_LF //使用LF作为命令行回车触发
- #define SHELL_ENTER_CR //使用CR作为命令行回车触发
- #define SHELL_ENTER_CRLF //使用CRLF作为命令行回车触发
- #define SHELL_EXEC_UNDEF_FUNC //使用执行未导出函数的功能
- #define SHELL_COMMAND_MAX_LENGTH //shell命令最大长度
- #define SHELL_PARAMETER_MAX_NUMBER //shell命令参数最大数量
- #define SHELL_HISTORY_MAX_NUMBER //历史命令记录数量
- #define SHELL_DOUBLE_CLICK_TIME //双击间隔(ms)
- #define SHELL_QUICK_HELP //快速帮助
- #define SHELL_MAX_NUMBER //管理的最大shell数量
- #define SHELL_GET_TICK() //获取系统时间(ms)
- #define SHELL_USING_LOCK //是否使用锁
- #define SHELL_MALLOC(size) //内存分配函数(shell本身不需要)
- #define SHELL_FREE(obj) //内存释放函数(shell本身不需要)
- #define SHELL_SHOW_INFO //是否显示shell信息
- #define SHELL_CLS_WHEN_LOGIN //是否在登录后清除命令行
- #define SHELL_DEFAULT_USER //shell默认用户
- #define SHELL_DEFAULT_USER_PASSWORD //默认用户密码
- #define SHELL_LOCK_TIMEOUT //shell自动锁定超时
- #endif
- /**
- * @brief 是否使用shell伴生对象
- * 一些扩展的组件(文件系统支持,日志工具等)需要使用伴生对象
- */
- #define SHELL_USING_COMPANION 1
- /**
- * @brief 支持shell尾行模式
- */
- #define SHELL_SUPPORT_END_LINE 1
- /**
- * @brief 使用LF作为命令行回车触发
- * 可以和SHELL_ENTER_CR同时开启
- */
- #define SHELL_ENTER_LF 1
- /**
- * @brief 使用CR作为命令行回车触发
- * 可以和SHELL_ENTER_LF同时开启
- */
- #define SHELL_ENTER_CR 1
- /**
- * @brief 使用CRLF作为命令行回车触发
- * 不可以和SHELL_ENTER_LF或SHELL_ENTER_CR同时开启
- */
- #define SHELL_ENTER_CRLF 0
- /**
- * @brief shell格式化输入的缓冲大小
- * 为0时不使用shell格式化输入
- * @note shell格式化输入会阻塞shellTask, 仅适用于在有操作系统的情况下使用
- */
- //#define SHELL_SCAN_BUFFER 0
- /**
- * @brief 获取系统时间(ms)
- * 定义此宏为获取系统Tick,如`HAL_GetTick()`
- * @note 此宏不定义时无法使用双击tab补全命令help,无法使用shell超时锁定
- */
- //#define SHELL_GET_TICK() HAL_GetTick()
- /**
- * @brief 使用锁
- * @note 使用shell锁时,需要对加锁和解锁进行实现
- */
- //#define SHELL_USING_LOCK 0
- /**
- * @brief shell内存分配
- * shell本身不需要此接口,若使用shell伴生对象,需要进行定义
- */
- #define SHELL_MALLOC(size) malloc(size)
- /**
- * @brief shell内存释放
- * shell本身不需要此接口,若使用shell伴生对象,需要进行定义
- */
- #define SHELL_FREE(obj) free(obj)
复制代码
|
|