完整的工程间附件,替换\STM32Cube_FW_H5_V1.2.0\Projects\NUCLEO-H533RE\Applications\ThreadX\Tx_Thread_Creation
一.前言
前面我们实现了标准输入输出的交互,为了进一步方面人机交互,我们在此基础上继续实现简单的shell。
参考微信公众号”嵌入式Lee”的文章:https://mp.weixin.qq.com/s/XLmbJn0SKoDT1aLdxHDrbg
一个超级精简高可移植的shell命令行C实现
二.准备
添加shell.c/h 和shell_func.c/h到工程中
代码分别如下
shell.c
#include <stdint.h>
#include "shell.h"
shell_read_pf s_input_pf = 0; /* ?????? */
shell_write_pf s_output_pf = 0; /* ?????? */
shell_cmd_cfg* s_cmd_cfg_pst = 0; /* ?????? */
uint8_t s_enableecho_u8 = 0; /* ????echo?? */
static uint8_t s_cmd_buf_au8[SHELL_CMD_LEN]="\r"; /* ????? */
static uint32_t s_cmd_buf_index_u32 = 0; /* ??????????? */
/**
* ??????
*/
static void shell_putchar(uint8_t val)
{
uint8_t tmp;
if(s_output_pf != 0)
{
tmp = val;
s_output_pf(&tmp, 1);
}
}
/**
* ???????
*/
static void shell_putstring(char* str)
{
uint32_t len = 0;
uint8_t*p = (uint8_t*)str;
while(*str++)
{
len++;
}
s_output_pf(p, len);
}
/**
* ?????
*/
static int shell_getchar(uint8_t *data)
{
if(s_input_pf == 0)
{
return -1;
}
if(0 == s_input_pf(data, 1))
{
return -1;
}
else
{
return 0;
}
}
/**
* ??????????
* ??????????
*/
static uint32_t shell_cmd_len(uint8_t *cmd)
{
uint8_t *p = cmd;
uint32_t len = 0;
while((*p != ' ') && (*p != 0))
{
p++;
len++;
}
return len;
}
/**
* ???????????,????0
*/
static int shell_cmd_check(uint8_t *cmd, uint8_t *str)
{
uint32_t len1 = shell_cmd_len(cmd);
uint32_t len2 = shell_cmd_len(str);
if(len1 != len2)
{
return -1;
}
for(uint32_t i=0; i<len1; i++)
{
if(*cmd++ != *str++)
{
return -1;
}
}
return 0;
}
/**
* ??????
*/
static uint32_t shell_read_line(void)
{
uint8_t ch;
uint32_t count;
/* ????sh> */
if(s_cmd_buf_au8[0]=='\r')
{
shell_putstring("sh>\r\n");
s_cmd_buf_au8[0] = 0;
}
/* ????????? */
if(shell_getchar(&ch) !=0 )
{
return 0;
}
/* ???????????????,?????????
* ????????,????????
*/
if((ch == '\r' || ch == '\n' || ch < ' ' || ch > '~') && (ch != '\b'))
{
if(s_cmd_buf_index_u32==0)
{
/* ?????????????????,?????sh> */
shell_putstring("sh>\r\n");
}
else
{
/* ????????,???????????????
* ?????????,?????,??????
* ???????0
*/
count = s_cmd_buf_index_u32;
s_cmd_buf_au8[s_cmd_buf_index_u32]=0;
s_cmd_buf_index_u32 =0;
shell_putstring("\r\n");
return count;
}
}
else
{
if(ch == '\b')
{
/* ????,???????????????,????? */
if(s_cmd_buf_index_u32 != 0)
{
s_cmd_buf_index_u32--;
shell_putchar('\b');
shell_putchar(' ');
shell_putchar('\b');
s_cmd_buf_au8[s_cmd_buf_index_u32]= '\0';
}
}
else
{
/* ?????,??????
* ??????????????-1,?????????
* -1?????????0??
*/
if(s_enableecho_u8 != 0)
{
shell_putchar(ch);
}
s_cmd_buf_au8[s_cmd_buf_index_u32++] = ch;
if(s_cmd_buf_index_u32>=(sizeof(s_cmd_buf_au8)-1))
{
count = s_cmd_buf_index_u32;
s_cmd_buf_au8[s_cmd_buf_index_u32]=0;
s_cmd_buf_index_u32 =0;
shell_putstring("\r\n");
return count;
}
}
}
return 0;
}
/**
* ??????????
*/
static int shell_exec_cmdlist(uint8_t* cmd)
{
int i;
if(s_cmd_cfg_pst == 0)
{
return -1;
}
for (i=0; s_cmd_cfg_pst[i].name != 0; i++)
{
if (shell_cmd_check(cmd, s_cmd_cfg_pst[i].name) == 0)
{
s_cmd_cfg_pst[i].func(cmd);
return 0;
}
}
if(s_cmd_cfg_pst[i].name == 0)
{
shell_putstring("unkown command\r\n");
return -1;
}
return 0;
}
/**
* ????,????
*/
void shell_exec(void)
{
if(shell_read_line() > 0)
{
shell_exec_cmdlist(s_cmd_buf_au8);
}
}
/**
* ????,???????
*/
void shell_set_itf(shell_read_pf input, shell_write_pf output, shell_cmd_cfg* cmd_list, uint8_t enableecho)
{
s_input_pf = input;
s_output_pf = output;
s_cmd_cfg_pst = cmd_list;
s_enableecho_u8 = enableecho;
}
shell.h
#ifndef SHELL_H
#define SHELL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#define SHELL_CMD_LEN 64 /**< ??????? */
typedef void (*shell_command_pf)(uint8_t *); /**< ?????? */
typedef uint32_t (*shell_read_pf)(uint8_t *buff, uint32_t len); /**< ????? */
typedef void (*shell_write_pf)(uint8_t *buff, uint32_t len); /**< ????? */
/**
* \struct shell_cmd_cfg
* ????
*/
typedef struct
{
uint8_t * name; /**< ????? */
shell_command_pf func; /**< ?????? */
uint8_t * helpstr; /**< ?????? */
}shell_cmd_cfg;
/**
* \fn shell_exec
* ???????,??????,????????????
* ???
*/
void shell_exec(void);
/**
* \fn shell_set_itf
* ??????????,??????
* ??shell_exec_shellcmd??,???????????
* \param[in] input \ref shell_read_pf ????
* \param[in] output \ref shell_write_pf ????
* \param[in] cmd_list \ref shell_cmd_cfg ????
* \param[in] enableecho 0:?????, ???:????
*/
void shell_set_itf(shell_read_pf input, shell_write_pf output, shell_cmd_cfg* cmd_list, uint8_t enableecho);
#ifdef __cplusplus
}
#endif
#endif
shell_func.c
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "shell.h"
#include "shell_func.h"
#include "xprintf.h"
static void helpfunc(uint8_t* param);
/**
* ???????0,??????
*/
const shell_cmd_cfg g_shell_cmd_list_ast[ ] =
{
{ (uint8_t*)"help", helpfunc, (uint8_t*)"help"},
{ (uint8_t*)0, 0 , 0},
};
void helpfunc(uint8_t* param)
{
(void)param;
unsigned int i;
xprintf("\r\n");
xprintf("**************\r\n");
xprintf("* SHELL *\r\n");
xprintf("* V1.0 *\r\n");
xprintf("**************\r\n");
xprintf("\r\n");
for (i=0; g_shell_cmd_list_ast[i].name != 0; i++)
{
xprintf("%02d.",i);
xprintf("%-16s",g_shell_cmd_list_ast[i].name);
xprintf("%s\r\n",g_shell_cmd_list_ast[i].helpstr);
}
}
shell_func.h
#ifndef SHELL_FUNC_H
#define SHELL_FUNC_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern const shell_cmd_cfg g_shell_cmd_list_ast[ ];
#ifdef __cplusplus
}
#endif
#endif
三.初始化接口
Main_task.c中
#include “shell.h”
#include "shell_func.h"
uint32_t uart_api_read(uint8_t *buff, uint32_t len)
{
return uart_read(buff,len);
}
void uart_api_write(uint8_t *buff, uint32_t len)
{
uart_write(buff,len);
}
static void main_task_entry(ULONG thread_input)
{
tx_thread_sleep(100); /* wait uart and xprintf init done */
xprintf("start main task\r\n");
while(1)
{
#if 0
uint32_t len = uart_read(rx_buffer,sizeof(rx_buffer));
if(len > 0)
{
uart_write(rx_buffer,len);
}
//uart_write(tx_buffer,sizeof(tx_buffer));
tx_thread_sleep(1);
#endif
#if 0
xprintf("%d\n", 1234); /* "1234" */
xprintf("%6d,%3d%%\n", -200, 5); /* " -200, 5%" */
xprintf("%-6u\n", 100); /* "100 " */
xprintf("%ld\n", 12345678); /* "12345678" */
xprintf("%llu\n", 0x100000000); /* "4294967296" <XF_USE_LLI> */
xprintf("%lld\n", -1LL); /* "-1" <XF_USE_LLI> */
xprintf("%04x\n", 0xA3); /* "00a3" */
xprintf("%08lX\n", 0x123ABC); /* "00123ABC" */
xprintf("%016b\n", 0x550F); /* "0101010100001111" */
xprintf("%*d\n", 6, 100); /* " 100" */
xprintf("%s\n", "abcdefg"); /* "abcdefg" */
xprintf("%5s\n", "abc"); /* " abc" */
xprintf("%-5s\n", "abc"); /* "abc " */
xprintf("%.5s\n", "abcdefg"); /* "abcde" */
xprintf("%-5.2s\n", "abcdefg"); /* "ab " */
xprintf("%c\n", 'a'); /* "a" */
xprintf("%12f\n", 10.0); /* " 10.000000" <XF_USE_FP> */
xprintf("%.4E\n", 123.45678); /* "1.2346E+02" <XF_USE_FP> */
#endif
shell_set_itf(uart_api_read, uart_api_write, (shell_cmd_cfg*)g_shell_cmd_list_ast, 1);
while(1)
{
#if 0
char input_buffer[32];
char* str = input_buffer;
xprintf("please input two int\r\n");
xgets(input_buffer, sizeof(input_buffer));
long a;
xatoi(&str,&a);
long b;
xatoi(&str,&b);
xprintf("%d+%d=%d\r\n",a,b,a+b);
#endif
shell_exec();
tx_thread_sleep(1);
}
}
}
四.测试
输入help回车调用help对应的接口打印如下
五.总结
以上实现了shell命令行交互,后面就可以方便的实现自己的命令,方便开发调试了。