qinyunti 发表于 2023-10-30 15:54

【ST多款开发板返场测评】STM32F767 Nucleo-144 实现简单的shell命令行交互

<div class='showpostmsg'><h1><b>前言</b></h1>

<p >前面我们实现了串口非阻塞的打印输出, 为了方便后面的而调试,我们继续实现简单的shell命令行交互。基于前面的串口的相关收发接口。</p>

<h1 ><b>代码</b></h1>

<p >基于前面的</p>

<pre>
<code class="language-cpp">uart_read

uart_debug_push

putchar-&gt;fputc</code></pre>

<p >接口</p>

<p >&nbsp;</p>

<p >关键数据结构是命令字符串和对应的执行函数的表格</p>

<pre>
<code class="language-cpp">typedef void ( * CommandFunc )( unsigned char *);

typedef struct

{

    unsigned char const* name;       

    CommandFunc func;          

    char const* helpstr;      

}shell_cmd_cfg;</code></pre>

<p >&nbsp;</p>

<p >核心代码是读取一行命令</p>

<pre>
<code class="language-cpp">static unsigned int shell_read_line(int get(unsigned char* tmp))

{

    unsigned char ch = '\r';

    unsigned int count;

    unsigned char tmp;

    /*??????"sh&gt;"*/

    if(cmd_buf=='\r')

    {

        printf("sh&gt;\r\n");

        memset(cmd_buf,0x00,sizeof(cmd_buf));

    }

    /*??????????,????*/

    if(get(&amp;tmp)==0)

    {

        ch = tmp;

    }

    else

    {

        return 0;

    }

    /*????????????????????0????????????"SH&gt;"*/

    if((ch == '\r' || ch == '\n' || ch &lt; ' ' || ch &gt; '~') &amp;&amp; (ch != '\b'))

    {

        if(cmd_buf_index==0)

        {

            printf("sh&gt;\r\n");

        }

        else

        {

            count = cmd_buf_index;

            cmd_buf=0;

            cmd_buf_index =0;

            printf("\r\n");

            return count;

        }

    }

    else

    {

        if(ch == '\b')

        {

            if(cmd_buf_index != 0)

            {

                cmd_buf_index--;

                putchar('\b');

                putchar(' ');

                putchar('\b');

                cmd_buf= '\0';

            }

        }

        else

        {

            /*??????????????????????????"*/

            putchar(ch);

            cmd_buf = ch;

            if(cmd_buf_index&gt;=(sizeof(cmd_buf)-1))

            {

                count = cmd_buf_index;

                cmd_buf=0;

                cmd_buf_index =0;

                printf("\r\n");

                return count;

            }

        }

    }

    return 0;

}



static int shell_getchar(unsigned char *data)

{

    int erro=0;

    //driver_uart_recv(getstdiouart(), data, 1,10,&amp;erro);

  if(0 == uart_read(data, 1))

{

erro = 1;

}

  else

  {

  //uart_write(data,1);

  }

    if(erro!=0)

    {

        return -1;

    }

    return 0;

}</code></pre>

<p >&nbsp;</p>

<p >读到一行命令后,根据命令字符串查找表格是否有对应的命令,找到了则调用对应的函数</p>

<pre>
<code class="language-cpp">void shell_exec_shellcmd(void)

{

    if(shell_read_line(shell_getchar))

    {

        shell_exec_cmdlist(cmd_buf);

    }

}

int shell_exec_cmdlist(unsigned char* cmd)

{

    int i;

    for (i=0; shell_cmd_list.name != 0; i++)

    {

        if (shell_cmd_check(cmd, shell_cmd_list.name) == 0)

        {

            shell_cmd_list.func(cmd);

            return 0;

        }            

    }

    if(shell_cmd_list.name == NULL)

    {

        printf("unkown command\r\n");

        return -1;

    }

    return 0;

}



static int shell_cmd_check(unsigned char *cmd, unsigned char const *str)

{

    unsigned int len1 = shell_cmd_len((unsigned char const *)cmd);

    unsigned int len2 = shell_cmd_len(str);

    if(len1 != len2)

    {

        return 1;

    }

    return memcmp(cmd, str, len1);

}



static unsigned int shell_cmd_len(unsigned char const *cmd)

{

    unsigned char const *p = cmd;

    unsigned int len = 0;

    while((*p != ' ') &amp;&amp; (*p != 0))

    {

        p++;

        len++;

    }

    return len;

}



添加一个命令只需在shell_func.c以下数组中添加一行

const shell_cmd_cfg shell_cmd_list[ ] =

{

  { (const uint8_t*)"help",         HelpFun,         "help"},

  { (const uint8_t*)0, 0 , 0},

};</code></pre>

<p >&nbsp;</p>

<p >并实现函数</p>

<pre>
<code class="language-cpp">void HelpFun(unsigned char* param)

{

  (void)param;

    unsigned int i;

    printf("\r\n");

    printf("**************\r\n");

    printf("*   SHELL    *\r\n");

    printf("*   V1.0     *\r\n");

    printf("**************\r\n");

    printf("\r\n");

    for (i=0; shell_cmd_list.name != 0; i++)

    {

        printf("%02d.",i);

        printf("%-16s",shell_cmd_list.name);

        printf("%s\r\n",shell_cmd_list.helpstr);

    }

}



</code></pre>

<p >头文件shell_func.h中申明函数</p>

<pre>
<code class="language-cpp">void HelpFun(unsigned char* param);</code></pre>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<h1 ><b>测试</b></h1>

<p >&nbsp;</p>

<p >测试主循环中</p>

<pre>
<code class="language-cpp">#include "shell.h"



  while (1)

  {

uart_debug_send(16);

shell_exec_shellcmd();

  }</code></pre>

<p >&nbsp;</p>

<p >可以看到打印如下</p>

<p > &nbsp;</p>

<p >&nbsp;</p>

<p >代码如下</p>

<p >shell.c</p>

<pre>
<code class="language-cpp">#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include "shell.h"

extern uint32_t uart_read(uint8_t* buffer, uint32_t len);
extern uint32_t uart_debug_push(uint8_t* buffer, uint32_t len);

#define SHELL_CMD_LEN 64                  
extern const shell_cmd_cfg shell_cmd_list[ ];   
static unsigned char cmd_buf="\r";
static unsigned int cmd_buf_index=0;

static int shell_getchar(unsigned char *data)
{
    int erro=0;
    //driver_uart_recv(getstdiouart(), data, 1,10,&amp;erro);
          if(0 == uart_read(data, 1))
                {
                        erro = 1;
                }
          else
          {
                  //uart_write(data,1);
          }
    if(erro!=0)
    {
      return -1;
    }
    return 0;
}

static unsigned int shell_cmd_len(unsigned char const *cmd)
{
    unsigned char const *p = cmd;
    unsigned int len = 0;
    while((*p != ' ') &amp;&amp; (*p != 0))
    {
      p++;
      len++;
    }
    return len;
}

static int shell_cmd_check(unsigned char *cmd, unsigned char const *str)
{
    unsigned int len1 = shell_cmd_len((unsigned char const *)cmd);
    unsigned int len2 = shell_cmd_len(str);
    if(len1 != len2)
    {
      return 1;
    }
    return memcmp(cmd, str, len1);
}

static unsigned int shell_read_line(int get(unsigned char* tmp))
{
    unsigned char ch = '\r';
    unsigned int count;
    unsigned char tmp;
    /*??????"sh&gt;"*/
    if(cmd_buf=='\r')
    {
      printf("sh&gt;\r\n");
      memset(cmd_buf,0x00,sizeof(cmd_buf));
    }
    /*??????????,????*/
    if(get(&amp;tmp)==0)
    {
      ch = tmp;
    }
    else
    {
      return 0;
    }
    /*????????????????????0????????????"SH&gt;"*/
    if((ch == '\r' || ch == '\n' || ch &lt; ' ' || ch &gt; '~') &amp;&amp; (ch != '\b'))
    {
      if(cmd_buf_index==0)
      {
            printf("sh&gt;\r\n");
      }
      else
      {
            count = cmd_buf_index;
            cmd_buf=0;
            cmd_buf_index =0;
            printf("\r\n");
            return count;
      }
    }
    else
    {
      if(ch == '\b')
      {
            if(cmd_buf_index != 0)
            {
                cmd_buf_index--;
                putchar('\b');
                putchar(' ');
                putchar('\b');
                cmd_buf= '\0';
            }
      }
      else
      {
            /*??????????????????????????"*/
            putchar(ch);
            cmd_buf = ch;
            if(cmd_buf_index&gt;=(sizeof(cmd_buf)-1))
            {
                count = cmd_buf_index;
                cmd_buf=0;
                cmd_buf_index =0;
                printf("\r\n");
                return count;
            }
      }
    }
    return 0;
}


int shell_exec_cmdlist(unsigned char* cmd)
{
    int i;
    for (i=0; shell_cmd_list.name != 0; i++)
    {
      if (shell_cmd_check(cmd, shell_cmd_list.name) == 0)
      {
            shell_cmd_list.func(cmd);
            return 0;
      }            
    }
    if(shell_cmd_list.name == NULL)
    {
      printf("unkown command\r\n");
      return -1;
    }
    return 0;
}

void shell_exec_shellcmd(void)
{
    if(shell_read_line(shell_getchar))
    {
      shell_exec_cmdlist(cmd_buf);
    }
}</code></pre>

<p >shell.h</p>

<pre>
<code class="language-cpp">#ifndef _SHELL_H_
#define _SHELL_H_

#ifdef __cplusplus
extern "C" {
#endif
   
#include &lt;stdint.h&gt;

typedef void ( * CommandFunc )( unsigned char *);


typedef struct
{
    unsigned char const* name;      
    CommandFunc func;         
    char const* helpstr;      
}shell_cmd_cfg;

#define SHELL_CMDBUF_SIZE64         


void shell_exec_shellcmd(void);

int shell_exec_cmdlist(unsigned char* cmd);


#ifdef __cplusplus
}
#endif

#endif</code></pre>

<p >shell_func.c</p>

<pre>
<code class="language-cpp">#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;string.h&gt;
#include "shell_func.h"
#include "shell.h"

const shell_cmd_cfg shell_cmd_list[ ] =
{
{ (const uint8_t*)"help",         HelpFun,         "help"},
{ (const uint8_t*)0,                0 , 0},
};

void HelpFun(unsigned char* param)
{
          (void)param;
    unsigned int i;
    printf("\r\n");
    printf("**************\r\n");
    printf("*   SHELL    *\r\n");
    printf("*   V1.0   *\r\n");
    printf("**************\r\n");
    printf("\r\n");
    for (i=0; shell_cmd_list.name != 0; i++)
    {
      printf("%02d.",i);
      printf("%-16s",shell_cmd_list.name);
      printf("%s\r\n",shell_cmd_list.helpstr);
    }
}

</code></pre>

<p >shell_func.h</p>

<pre>
<code class="language-cpp">#ifndef __SHELL_FUN_H
#define __SHELL_FUN_H

#include &lt;stdint.h&gt;

#ifdef __cplusplus
extern "C" {
#endif

void HelpFun(unsigned char* param);

#ifdef __cplusplus
}
#endif

#endif</code></pre>

<h1 ><b>总结</b></h1>

<p >基于前面的串口接口,快速实现了shell命令行,方便以后交互调试使用,相关代码也是可移植可复用到其他项目。</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>
页: [1]
查看完整版本: 【ST多款开发板返场测评】STM32F767 Nucleo-144 实现简单的shell命令行交互