[原创] 【瑞萨RA8D1开发板,基于M85内核的图形MCU】移植精简的shell

qinyunti   2024-7-25 00:05 楼主

前面我们移植了xprintf可以方便的打印输出和输入,为了方便后面调试开发,我们进一步移植一个精简的shell,实现命令行交互。

 

参考微信公众号”嵌入式Lee”的文章

https://mp.weixin.qq.com/s/XLmbJn0SKoDT1aLdxHDrbg 一个超级精简高可移植的shell命令行C实现

 

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 512                                          /**< ??????? */

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如下,可以添加自己的命令,默认实现了help命令,打印所有命令信息


#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

实现接口

static uint32_t shell_read_port(uint8_t *buff, uint32_t len)
{
return uart_read(buff,len);
}

static void shell_write_port(uint8_t *buff, uint32_t len)
{
uart_send(buff,len);
}

设置接口

#include "shell.h"

#include "shell_func.h"

 

    shell_set_itf(shell_read_port, shell_write_port, (shell_cmd_cfg*)g_shell_cmd_list_ast, 1);

 

测试

void blinky_thread_entry (void * pvParameters)
{
uart_init();
xdev_out(xprintf_out_port);
xdev_in(xprintf_in_port);
shell_set_itf(shell_read_port, shell_write_port, (shell_cmd_cfg*)g_shell_cmd_list_ast, 1);

while(1)
{
shell_exec();
vTaskDelay(1);
}

 

效果如下,上输入help回车,打印所有支持的命令

image-20240725000226-1.png  

 

后面就可以方便添加更多自己的命令,方便调试开发。

回复评论 (1)

 

后面就可以方便添加更多自己的命令,方便调试开发。

确实是一个非常好的工具!

点赞  2024-7-25 08:27
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复