Preface
Previously we implemented the serial port driver. Based on this, we further implemented the serial port command line to facilitate subsequent development and debugging.
Implementation ideas
Based on the previous serial port interface, the main loop continuously queries the serial port data, and writes the data into the command line cache.
Check that reading from the serial port is not blocked.
If a line of string is read, the table is passed to see if there is a command corresponding to the string. If so, the corresponding callback function is executed.
data structure
Table of string commands and corresponding functions
typedef struct
{
unsigned char const* name;
CommandFunc func;
char const* helpstr;
}shell_cmd_cfg;
Implementing the interface
Read serial port
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;
}
send
Send can also implement putchar printf or redirect printf to implement
Redirect printf as follows
uart_ep.c
#include <stdio.h>
int fputc(int ch, FILE *f)
{
(void)f;
uart_sendbyte((uint8_t)ch);
return ch;
}
Read a line
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[0]=='\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[cmd_buf_index]=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[cmd_buf_index]= '\0';
}
}
else
{
/*??????????????????????????"*/
putchar(ch);
cmd_buf[cmd_buf_index++] = ch;
if(cmd_buf_index>=(sizeof(cmd_buf)-1))
{
count = cmd_buf_index;
cmd_buf[cmd_buf_index]=0;
cmd_buf_index =0;
printf("\r\n");
return count;
}
}
}
return 0;
}
test
In the main loop
for(;;)
{
shell_exec_shellcmd();
}
Use the host terminal assistant to connect, there is a command help by default
Type help and press Enter to view supported commands.
Code
shell.c
#include <stdio.h>
#include <string.h>
#include "shell.h"
extern uint32_t uart_read(uint8_t* buffer, uint32_t len);
extern uint32_t uart_write(uint8_t* buffer, uint32_t len);
#define SHELL_CMD_LEN 64
extern const shell_cmd_cfg shell_cmd_list[ ];
static unsigned char cmd_buf[SHELL_CMD_LEN]="\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[0]=='\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[cmd_buf_index]=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[cmd_buf_index]= '\0';
}
}
else
{
/*??????????????????????????"*/
putchar(ch);
cmd_buf[cmd_buf_index++] = ch;
if(cmd_buf_index>=(sizeof(cmd_buf)-1))
{
count = cmd_buf_index;
cmd_buf[cmd_buf_index]=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[i].name != 0; i++)
{
if (shell_cmd_check(cmd, shell_cmd_list[i].name) == 0)
{
shell_cmd_list[i].func(cmd);
return 0;
}
}
if(shell_cmd_list[i].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);
}
}
shell.h
#ifndef _SHELL_H_
#define _SHELL_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
typedef void ( * CommandFunc )( void *);
typedef struct
{
unsigned char const* name;
CommandFunc func;
char const* helpstr;
}shell_cmd_cfg;
#define SHELL_CMDBUF_SIZE 64
void shell_exec_shellcmd(void);
int shell_exec_cmdlist(unsigned char* cmd);
#ifdef __cplusplus
}
#endif
#endif
shell_func.c
#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(void* 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[i].name != 0; i++)
{
printf("%02d.",i);
printf("%-16s",shell_cmd_list[i].name);
printf("%s\r\n",shell_cmd_list[i].helpstr);
}
}
shell_func.h
#ifndef __SHELL_FUN_H
#define __SHELL_FUN_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void HelpFun(void* param);
#ifdef __cplusplus
}
#endif
#endif
Summarize
The above implements a simple command line, which facilitates subsequent development and testing.