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

本文先贴出代码,参考u-boot命令行

/*
****************************************************************************
*	File        : cmd.c
*
*	Creat on    : Otc 08, 2018
*	Author      : Flinn
* 
*	@beirf      : 
*
*	@Note(s)    : 
*
****************************************************************************
*/


#include "HAL_Uart.h"
#include "cmd.h"

#define VER_MAJ		0
#define VER_MIN		1

typedef enum {
	FALSE = 0, 
	TRUE = 1
} bool; 

#ifndef NULL
#define NULL ((void *)0)
#endif

typedef unsigned char U8;
typedef unsigned short U16;
typedef unsigned int U32;

#define ARRAY_SIZE(a)	(sizeof(a) / sizeof(a[0]))


static cmd_tbl_t  * cli_cmd_start;
static cmd_tbl_t  * cli_cmd_end ;

int atoi_r (const char *str);


static void outc (const char c)
{
    UART_OUT(c);
}

static void outs(const char *str)
{
    while(*str++)
    {
        outc(*str);
    }
}

static void do_version (cmd_tbl_t *cmdtp)
{
	printf("version : %d.%d \r\n", VER_MAJ,VER_MIN);
}


REGISTER_CMD(
	ver,
	1,
	do_version,
	"print monitor version"
);

static char *version_history[] = {
	"ver     Date                description                    \r\n", 
	"0.1     Mar 1, 2018         initial version with cli       \r\n"
    };


static void do_history(void)
{
    U8 i;
    for(i = 0; i < ARRAY_SIZE(version_history); i++)
    {
        printf("%s", version_history[i]);
    }	
}

REGISTER_CMD(
	his,
	1,
	do_history,
	"print history informaton"
);


void do_help(void)
{
	cmd_tbl_t *cmdtp;
	int len = cli_cmd_end - cli_cmd_start;

	for (cmdtp = cli_cmd_start; cmdtp != cli_cmd_start + len; cmdtp++)
	{
		printf("%-8s %s \r\n",cmdtp->name, cmdtp->usage);
	}
}

REGISTER_CMD(
	help,
	1,
	do_help,
	"print help information "
);


#define DEF_PROMPT		"cmd:>"
void show_prompt()
{
	printf("\r\n%s:>",DEF_PROMPT);
}



/****************************************************************************/
static U32 hex2int(U8 ch)
{
	U8 val;
	if((ch >= 'A') && (ch <= 'F'))
		val = ch - 'A' + 10;
	else if((ch >= 'a') && (ch <= 'f'))
		val = ch - 'a' + 10;
	else if((ch >= '0') && (ch <= '9'))
		val = ch - '0';
	else
		val = 16;

	return val;
}

static U32 hexs_to_int(const char *exp)
{
	U8 ch;
	U32 result = 0;
	U32 digital;

	while('\0' != (ch = *exp++))
	{
		digital = hex2int(ch);

		if(digital != 16)  // fixme
		{
			result = result * 16 + digital;
		}
		else
		{
			break;
		}
	}
	
	return result;
}

U32 _TOU32(const char *exp)
{
	char first = *exp;
	char second = *exp + 1;
	U32 result;
	
	if(('0' == first) && ('1' == second)) //??? while not 'x'/'X'
	{
		result = hexs_to_int(exp + 2);  // skip prefix		
	}
	else if('-' == first)  // s32
	{
		return atoi_r(exp);
	}
	else
	{
		result = (U32)atoi_r(exp);
	}

	return result;
}


int isspace (int ch)
{
	if ((ch == ' ') || (ch == '\t'))	/* \n ??? */
		return 1;
	else
		return 0;
}

int isalnum (int ch)
{
	/* ASCII only */
	if (((ch >= '0') && (ch <= '9')) ||
		((ch >= 'A') && (ch <= 'Z')) ||
		((ch >= 'a') && (ch <= 'z')))
		return 1;
	else
		return 0;
}
int isdigit (int ch)
{
	/* ASCII only */
	if ((ch >= '0') && (ch <= '9'))
		return 1;
	else
		return 0;
}




int str_cmp(const char * s1, const char * s2)
{
        while (*s1 == *s2)
        {
                if (*s1 == '\0')
                        return 0;
                s1++;
                s2++;
        }

        return *s1 - *s2;
}

static bool check_cmd(const char *name, cmd_tbl_t **cmd)
{
        bool found = FALSE;

        printf("cmd : %s \r\n", name);

        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;
}

int parse_line (char *line, char *argv[])
{
	int nargs = 0;
	printf ("parse_line: \"%s\"\r\n", line);

	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);
}


#define MAX_ARGS_CNT            10
#define MAX_ARGS_LENGTH         32
#define MAX_CMDLINE_LEN         64

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);

        printf("\r\ncheck the token argv %s  argc : %d  \r\n",(char *)argv[0], argc);

        if(TRUE == check_cmd((const char *)argv[0], &cmd))
        {
                printf("got! cmd : %s argc : %d \r\n", cmd->name, cmd->maxargs);

                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]);
        }
}


static char erase_seq[] = "\b \b";		/* erase sequence	*/
static char tab_seq[] = "        ";		/* used to expand TABs	*/
char console_buffer[CONFIG_SYS_CBSIZE];
static int	index = 0;				/* buffer index		*/

void cmdline_run(void)
{
    	
    char *p = &console_buffer[index];
    char * p_buf = p;
	
    char c;
    
    int count = UART_Rx(&c, 1);
    
    if(1 == count){
    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;
            }
    }
    
    
}
}



void cmdline_init(void)
{
	extern unsigned char Load$$CMDREG$$Base[];
	extern unsigned char Load$$CMDREG$$Limit[];

	unsigned long cmd_addr = (unsigned long)Load$$CMDREG$$Base;
	unsigned long cmd_end = (unsigned long)Load$$CMDREG$$Limit;	
	
	//CLI_OUT("cmd addr:%08x, limit:%08x\r\n", cmd_addr, cmd_end);
	
	cli_cmd_start =(cmd_tbl_t  *)cmd_addr;
	cli_cmd_end  = (cmd_tbl_t  *)cmd_end;
}

// TODO : if stdlib.h(atoi(),...) is available , remove follows
unsigned long strtoul_r (char *str, char **ptr, int base)
{
    unsigned long rvalue = 0;
   int neg = 0;
   int c;

   /* Validate parameters */
   if ((str != NULL) && (base >= 0) && (base <= 36))
   {
        /* Skip leading white spaces */
        while (isspace(*str))
        {
            ++str;
        }
        
        /* Check for notations */
       switch (str[0])
        {
            case '0':
              if (base == 0)
              {
                 if ((str[1] == 'x') || (str[1] == 'X'))
                 {
                        base = 16;
                    str += 2;
                 }
                 else
                 {
                    base = 8;
                    str++;
                 }
             }
             break;
        
            case '-':
                neg = 1;
              str++;
              break;

           case '+':
              str++;
                break;

            default:
                break;
        }

        if (base == 0)
            base = 10;
        
        while (isalnum(c = *str))
      {
		/* Convert char to num in 0..36 */
         if ((c -= ('a' - 10)) < 10)         /* 'a'..'z' */
            if ((c += ('a' - 'A')) < 10)     /* 'A'..'Z' */
               c += ('A' - '0' - 10);        /* '0'..'9' */

		/* check c against base */
		if (c >= base)
			break;

		if (neg)
			rvalue = (rvalue * base) - c;
		else
			rvalue = (rvalue * base) + c;

         ++str;
		}
	}
   /* Upon exit, 'str' points to the character at which valid info */
   /* STOPS.  No chars including and beyond 'str' are used.        */

	if (ptr != NULL)
			*ptr = str;
		
		return rvalue;
}

int atoi_r (const char *str)
{
   char *s = (char *)str;
   
   return ((int)strtoul_r(s, NULL, 10));
}

头文件

/*
****************************************************************************
*	File        : cmd.h
*
*	Creat on    : Otc 08, 2018
*	Author      : Flinn
* 
*	@beirf      : 
*
*	@Note(s)    : 
*
****************************************************************************
*/

#ifndef _CMD_H
#define _CMD_H

#include <stdarg.h>



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}


#define CONFIG_SYS_CBSIZE		256      /* buffer size of console */



    
#define MAX_ARGS_CNT            10
#define MAX_ARGS_LENGTH         32



void cmdline_run(void);
void cmdline_init(void);


#endif /* _CMD_H */

运行效果:

平台stm32 和arm9, msp430等等:

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

以上多余打印是调试时解析bug用的,可以去除。