本文档基于stm32f103并移植到F407, MSP430,以及s3c2440
最终效果如下:
以上多余打印是调试时解析bug用的,可以去除。
本文参考u-boot命令行,重点部分有三个:①数据定义 ②获取串口数据(1个字节) ③解析数据
数据定义
typedef void (*CLI_handler)();
struct cmd_tbl_s {
char *name; /* Command Name */
int maxargs; /* maximum number of arguments */
CLI_handler cmd; /* Implementation function */
char *usage; /* Usage message (short) */
};
typedef struct cmd_tbl_s cmd_tbl_t;
#define REGISTER_CMD(name,maxargs,handler,usage) \
const cmd_tbl_t strcmd_##name __attribute__ ((section ("cmd"))) = {#name, maxargs, handler, usage}
获取串口数据
判断串口是否有数据:
int UART_tstc(void)
{
return (USART2->SR & 0x0020); // RXNE
}
读取数据
u8 UART_getc(void)
{
return (u8)(UART_BASE->DR & 0xFF);
}
定义一个全局数组,保存串口信息
char console_buffer[256];
static int index = 0; /* buffer index */
数据获取和解析
void cmdline_run(void)
{
char *p = &console_buffer[index];
char * p_buf = p;
char c;
if(UART_tstc()){
c = (char)UART_getc();
switch (c)
{
case '\r': /* Enter */
case '\n':
*p = '\0';
printf ("\r\n");
run_command(console_buffer); /* 回车表示一个命令结束 */
show_prompt();
index = 0; // next cmd
break;
case '\0': /* nul */
return;
case 0x03: /* ^C - break */
p_buf[0] = '\0'; /* discard input */
return ;
case 0x08: /* ^H - backspace */
case 0x7F: /* DEL - backspace */
//p=delete_char(p_buf, p, &col, &n, plen);
printf("%s",erase_seq); /* 删除一个字符 */
p--; /* update the index */
index--;
break;
default:
if (index < CONFIG_SYS_CBSIZE-2) /* 普通字符就保存 */
{
if (c == '\t') /* expand TABs */
outs (tab_seq);
else
outc (c);
*p++ = c;
++index;
}
}
}
}
再看show_prompt
#define DEF_PROMPT "cmd:>"
void show_prompt()
{
printf("\r\n%s",DEF_PROMPT);
}
run_command:
void run_command(const char *cmdBuf)
{
cmd_tbl_t *cmd;
char *argv[MAX_ARGS_CNT + 1];
int argc = 0;
char destLine[MAX_CMDLINE_LEN];
const char *src = cmdBuf;
char *dest = destLine;
while(*src != '\0')
{
*dest++ = *src++;
}
*dest = '\0';
dest = destLine;
if(*dest == '\0') // invalid
return;
argc = parse_line(dest, argv); /* 解析参数,去掉空格 */
if(TRUE == check_cmd((const char *)argv[0], &cmd)) /* 判断命令字是否定义 */
{
if(argc != cmd->maxargs )
{
printf("\nargs not matched ! \r\n");
return;
}
// excute the handler
switch(argc)
{
case 0:
cmd->cmd();
break;
case 1:
cmd->cmd(_TOU32(argv[1]));
break;
case 2:
cmd->cmd(_TOU32(argv[1]), _TOU32(argv[2]));
break;
default:
break;
}
}
else
{
printf("Unrecognized cmd , check %s with 'help' \r\n", argv[0]);
}
}
再看check_cmd,主要看参数是否在cli_cmd_start~cli_cmd_end之间,该地址定义在链接脚本
static bool check_cmd(const char *name, cmd_tbl_t **cmd)
{
bool found = FALSE;
cmd_tbl_t *cmdtp;
int len = cli_cmd_end - cli_cmd_start;
for (cmdtp = cli_cmd_start; cmdtp != cli_cmd_start + len; cmdtp++)
{
if(0 == str_cmp(name, cmdtp->name))
{
*cmd = cmdtp;
found = TRUE;
break;
}
}
return found;
}
数据解析
解析参数parse_line
int parse_line (char *line, char *argv[])
{
int nargs = 0;
while (nargs < MAX_ARGS_CNT) {
/* skip any white space */
while ((*line == ' ') || (*line == '\t')) {
++line;
}
if (*line == '\0') { /* end of line, no more args */
argv[nargs] = NULL;
return (nargs);
}
argv[nargs++] = line; /* begin of argument string */
/* find end of string */
while (*line && (*line != ' ') && (*line != '\t')) {
++line;
}
if (*line == '\0') { /* end of line, no more args */
argv[nargs] = NULL;
return (nargs);
}
*line++ = '\0'; /* terminate current arg */
}
printf ("** Too many args (max. %d) **\r\n", MAX_ARGS_CNT);
return (nargs);
}