【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->fputc</code></pre>
<p >接口</p>
<p > </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 > </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>"*/
if(cmd_buf=='\r')
{
printf("sh>\r\n");
memset(cmd_buf,0x00,sizeof(cmd_buf));
}
/*??????????,????*/
if(get(&tmp)==0)
{
ch = tmp;
}
else
{
return 0;
}
/*????????????????????0????????????"SH>"*/
if((ch == '\r' || ch == '\n' || ch < ' ' || ch > '~') && (ch != '\b'))
{
if(cmd_buf_index==0)
{
printf("sh>\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>=(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,&erro);
if(0 == uart_read(data, 1))
{
erro = 1;
}
else
{
//uart_write(data,1);
}
if(erro!=0)
{
return -1;
}
return 0;
}</code></pre>
<p > </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 != ' ') && (*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 > </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 > </p>
<p > </p>
<p > </p>
<h1 ><b>测试</b></h1>
<p > </p>
<p >测试主循环中</p>
<pre>
<code class="language-cpp">#include "shell.h"
while (1)
{
uart_debug_send(16);
shell_exec_shellcmd();
}</code></pre>
<p > </p>
<p >可以看到打印如下</p>
<p > </p>
<p > </p>
<p >代码如下</p>
<p >shell.c</p>
<pre>
<code class="language-cpp">#include <stdio.h>
#include <string.h>
#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,&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 != ' ') && (*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>"*/
if(cmd_buf=='\r')
{
printf("sh>\r\n");
memset(cmd_buf,0x00,sizeof(cmd_buf));
}
/*??????????,????*/
if(get(&tmp)==0)
{
ch = tmp;
}
else
{
return 0;
}
/*????????????????????0????????????"SH>"*/
if((ch == '\r' || ch == '\n' || ch < ' ' || ch > '~') && (ch != '\b'))
{
if(cmd_buf_index==0)
{
printf("sh>\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>=(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 <stdint.h>
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 <stdio.h>
#include <stdint.h>
#include <string.h>
#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 <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void HelpFun(unsigned char* param);
#ifdef __cplusplus
}
#endif
#endif</code></pre>
<h1 ><b>总结</b></h1>
<p >基于前面的串口接口,快速实现了shell命令行,方便以后交互调试使用,相关代码也是可移植可复用到其他项目。</p>
<p > </p>
<p > </p>
<p > </p>
<p > </p>
<p > </p>
<p > </p>
<p > </p>
<p > </p>
<p > </p>
<p > </p>
<p > </p>
<p > </p>
<p > </p>
<p > </p>
<p > </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]