嵌入式命令列操作(可移植性)
阿新 • • 發佈:2018-11-05
本文件基於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);
}