1. 程式人生 > >嵌入式命令列操作(可移植性)

嵌入式命令列操作(可移植性)

本文件基於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);
}