tiny4412 基础(七)移植command

先看效果图

这个图是在裸机下跑的,移植了u-boot的command, 新的u-boot改成cli(命令行接口)

使用起来非常方便:

static int do_version (struct cmd_tbl_s *cmd_tbl_t, int argc, int type, char * const argv[])
{
	puts("version : V1.0 \r\n");
	return 0;
}

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

在任意文件里面都可以添加命令。

REGISTER_CMD宏即

#define REGISTER_CMD(name,maxargs,type,handler,usage) \
	const cmd_tbl_t cmd_##name __attribute__ ((section (".cli_cmd"))) =  {#name, maxargs, type, handler, usage}

也即REGISTER_CMD宏定义的命令最终都会链接到“.cli_cmd”段里面,在链接脚本里面:


SECTIONS
{
        . = 0x02023400;

        .text : {
                src/head.o
                * (.text)
        }

        .data : {
                * (.data)
        }

        __cli_cmd_start = .;
        .cli_cmd : {
                *(.cli_cmd)
        }
        __cli_cmd_end = .;

        bss_start = .;
        .bss : {
                * (.bss)
        }

        bss_end  = .;
}

可以看到.cli_cmd字段。

上面简单描述了效果即简单解析。

目录结构

 

.
├── basic.lds
├── common
├── HAL
│   ├── uart.c
│   └── uart.h
├── include
│   ├── system_clock.h
│   └── tiny4412.h
├── Makefile
├── src
│   ├── command.c
│   ├── command.h
│   ├── head.S
│   ├── main.c
│   └── system_clock.c
└── tools
    ├── bl2.bin
    ├── E4412_N.bl1.bin
    ├── E4412_tzsw.bin
    ├── Makefile
    ├── mkbl2
    ├── sd_fuse.sh
    └── V310-EVT1-mkbl2.c

其中basic.lds就是链接脚本,内容在上面以及贴出来了。

Makefile

CC      = /home/flinn/tools/4.5.1/bin/arm-none-linux-gnueabi-gcc
LD      = /home/flinn/tools/4.5.1/bin/arm-none-linux-gnueabi-ld
AR      = /home/flinn/tools/4.5.1/bin/arm-none-linux-gnueabi-ar
OBJCOPY = /home/flinn/tools/4.5.1/bin/arm-none-linux-gnueabi-objcopy
OBJDUMP = /home/flinn/tools/4.5.1/bin/arm-none-linux-gnueabi-objdump


CFLAGS          := -Wall -O2 -nostdlib -fno-builtin \
                -I./include \
                -I./HAL \
                -I./common \
                -I./src \
                -lgcc -L/home/flinn/tools/4.5.1/arm-none-linux-gnueabi/lib

OBJS := src/head.o src/main.o src/system_clock.o HAL/uart.o src/command.o

VER = 1.0
TARGET = tiny4412_$(VER).bin

$(TARGET): $(OBJS)
        ${LD} -Tbasic.lds -o $(TARGET)_elf $^
        ${OBJCOPY} -O binary -S $(TARGET)_elf $@
        ${OBJDUMP} -D -m arm $(TARGET)_elf > $(TARGET).dis


%.o:%.c
        ${CC}  $(CFLAGS) -c -o $@ $<

%.o:%.S
        ${CC}  $(CFLAGS) -c -o $@ $<

clean:
        rm -f $(TARGET) $(TARGET)_elf $(TARGET).dis *.o *.bin $(OBJS)

main

main很简单:

include "tiny4412.h"
#include "system_clock.h"
#include "uart.h"
#include "command.h"


int main(void)
{
        int i = 0;

        system_clock_init();

        uart_init();
        command_init();


        puts("\r\nstart...\r\n");

        while (1)
        {
                command_loop();
        }

        return 0;
}

其中需要初始化串口。

command_init()和command_loop()两个实现都在src/command.c里面

以上代码没有实现itoa,strlen, printf ,  vsprintf等标准库函数,并运行在tiny4412裸机上,对于其他平台,比如fpga,stm32, msp430, 51等平台,一般IDE支持标准库函数,移植起来更方便。熟悉u-boot移植的人来说,cli接口是必不可少的调试神器。

所有代码由以下方式获取:

git clone git@github.com:fanglinn/tiny4412.git

最后还是补充一下:
如果你想使用以上框架,需要做如下几点:

1.在Makefile里面修改你的编译器gcc路径

2.实现uart底层读写函数,必须实现putc, puts, getc, tstc四个函数,分别表示发送字符,发送字符串, 获 
  取一个字符, 监测是否有数据来

3.插入SD卡,使用sudo fdisk -l来识别,比如/dev/sdc

4.进入tools目录,执行sudo ./sd_fuse /dev/sdc 即可

最后还是贴上代码,以便自己后面使用:

src/command.c

#include "command.h"
#include "uart.h"

char console_buffer[CONFIG_SYS_CBSIZE + 1];	/* console I/O buffer	*/
static const char erase_seq[] = "\b \b";		/* erase sequence	*/
static const char   tab_seq[] = "        ";		/* used to expand TABs	*/


static cmd_tbl_t  * CLI_cmd_start;
static cmd_tbl_t  * CLI_cmd_end ;



static int do_version (struct cmd_tbl_s *cmd_tbl_t, int argc, int type, char * const argv[])
{
	puts("version : V1.0 \r\n");
	return 0;
}

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


int do_help(struct cmd_tbl_s *cmd, int argc, int type, char * const argv[])
{
	cmd_tbl_t *cmdtp;
	int len = CLI_cmd_end - CLI_cmd_start;

	for (cmdtp = CLI_cmd_start; cmdtp != CLI_cmd_start + len; cmdtp++)
	{
		puts(cmdtp->name);
		puts("\t");
		puts(cmdtp->usage);
		puts("\r\n");
	}
	
	return 0;
}

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


char * strcpy(char * dest,const char *src)
{
	char *tmp = dest;

	while ((*dest++ = *src++) != '\0')
		/* nothing */;
	return tmp;
}

unsigned int strlen(const char * s)
{
	const char *sc;

	for (sc = s; *sc != '\0'; ++sc)
		/* nothing */;
	return sc - s;
}

int strcmp(const char * cs,const char * ct)
{
	register signed char __res;

	while (1) {
		if ((__res = *cs - *ct++) != 0 || !*cs++)
			break;
	}

	return __res;
}




static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
{
	char *s;

	if (*np == 0) {
		return (p);
	}

	if (*(--p) == '\t') {			/* will retype the whole line	*/
		while (*colp > plen) {
			puts (erase_seq);
			(*colp)--;
		}
		for (s=buffer; s<p; ++s) {
			if (*s == '\t') {
				puts (tab_seq+((*colp) & 07));
				*colp += 8 - ((*colp) & 07);
			} else {
				++(*colp);
				putc (*s);
			}
		}
	} else {
		puts (erase_seq);
		(*colp)--;
	}
	(*np)--;
	return (p);
}


int readline_into_buffer(const char *const prompt, char *buffer, int timeout)
{
	char *p = buffer;
	char * p_buf = p;
	int	n = 0;				/* buffer index		*/
	int	plen = 0;			/* prompt length	*/
	int	col;				/* output column cnt	*/
	char	c;

	/* print prompt */
	if (prompt) {
		plen = strlen (prompt);
		puts (prompt);
	}
	col = plen;

	for (;;)
	{
		c = getc();
		/*
		 * Special character handling
		 */
		switch (c){
		case '\r':			/* Enter		*/
		case '\n':
			*p = '\0';
			puts ("\r\n");
			return p - p_buf;

		case '\0':			/* nul			*/
			continue;

		case 0x03:			/* ^C - break		*/
			p_buf[0] = '\0';	/* discard input */
			return -1;

		case 0x15:			/* ^U - erase line	*/
			while (col > plen) {
				puts (erase_seq);
				--col;
			}
			p = p_buf;
			n = 0;
			continue;

		case 0x17:			/* ^W - erase word	*/
			p=delete_char(p_buf, p, &col, &n, plen);
			while ((n > 0) && (*p != ' ')) {
				p=delete_char(p_buf, p, &col, &n, plen);
			}
			continue;

		case 0x08:			/* ^H  - backspace	*/
		case 0x7F:			/* DEL - backspace	*/
			p=delete_char(p_buf, p, &col, &n, plen);
			continue;

		default:
			/*
			 * Must be a normal character then
			 */
			if (n < CONFIG_SYS_CBSIZE-2) {
				if (c == '\t') {	/* expand TABs */
					puts (tab_seq+(col&07));
					col += 8 - (col&07);
				} else {
					char buf[2];

					/*
					 * Echo input using puts() to force an
					 * LCD flush if we are using an LCD
					 */
					++col;
					buf[0] = c;
					buf[1] = '\0';
					puts(buf);
				}
				*p++ = c;
				++n;
			} else {			/* Buffer full		*/
				putc ('\a');
			}
		}
	}
}

int readline (const char *const prompt)
{
	/*
	 * If console_buffer isn't 0-length the user will be prompted to modify
	 * it instead of entering it from scratch as desired.
	 */
	console_buffer[0] = '\0';

	return readline_into_buffer(prompt, console_buffer, 0);
}

int parse_line (char *line, char *argv[])
{
	int nargs = 0;

	while (nargs < CONFIG_SYS_MAXARGS) {

		/* skip any white space */
		while (isblank(*line))
			++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 && !isblank(*line))
			++line;

		if (*line == '\0') {	/* end of line, no more args	*/
			argv[nargs] = NULL;
			return nargs;
		}

		*line++ = '\0';		/* terminate current arg	 */
	}

	puts ("** Too many args (max) **\n");

	return (nargs);
}

static int find_cmd (const char *name, cmd_tbl_t **cmd)
{
	int found = 0;

	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 == strcmp(name, cmdtp->name))
		{
			*cmd = cmdtp;
			found = 1;
			break;
		}
	}

	return found;
}

int cmd_usage(const cmd_tbl_t *cmdtp)
{
	//printf("%s - %s\n\n", cmdtp->name, cmdtp->usage);
	return 1;
}

static int cmd_call(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	int result;

	result = (cmdtp->cmd)(cmdtp, flag, argc, argv);
	if (result)
		puts("Command failed");
	return result;
}


enum command_ret_t cmd_process(int flag, int argc, char * const argv[],
			       int *repeatable, unsigned long *ticks)
{
	enum command_ret_t rc = CMD_RET_SUCCESS;
	cmd_tbl_t *cmdtp;
	int found = 0;

	/* Look up command in command table */
	found = find_cmd(argv[0], &cmdtp);
	if (found == 0) {
		puts("Unknown command  '");
		puts(argv[0]);
		puts("' - try 'help'\r\n");
		return 1;
	}

	/* found - check max args */
	if (argc > cmdtp->maxargs)
		rc = CMD_RET_USAGE;


	/* If OK so far, then do the command */
	if (!rc) {
		rc = cmd_call(cmdtp, flag, argc, argv);
	}
	if (rc == CMD_RET_USAGE)
		rc = cmd_usage(cmdtp);
	return rc;
}

static int builtin_run_command(const char *cmd, int flag) 
{
	char cmdbuf[CONFIG_SYS_CBSIZE];	/* working copy of cmd		*/
	char *token;			/* start of token in cmdbuf	*/
	char *sep;			/* end of token (separator) in cmdbuf */

	char *str = cmdbuf;
	char *argv[CONFIG_SYS_MAXARGS + 1];	/* NULL terminated	*/
	int argc, inquotes;
	int repeatable = 1;
	int rc = 0;

	
	if (!cmd || !*cmd) {
		return -1;	/* empty command */
	}
	
	if (strlen(cmd) >= CONFIG_SYS_CBSIZE) {
		puts ("## Command too long!\r\n");
		return -1;
	}
	
	strcpy (cmdbuf, cmd);

	while (*str) {
		/*
		 * Find separator, or string end
		 * Allow simple escape of ';' by writing "\;"
		 */
		for (inquotes = 0, sep = str; *sep; sep++) {
			if ((*sep=='\'') &&
			    (*(sep-1) != '\\'))
				inquotes=!inquotes;

			if (!inquotes &&
			    (*sep == ';') &&	/* separator		*/
			    ( sep != str) &&	/* past string start	*/
			    (*(sep-1) != '\\'))	/* and NOT escaped	*/
				break;
		}

		/*
		 * Limit the token to data between separators
		 */
		token = str;
		if (*sep) {
			str = sep + 1;	/* start of command for next pass */
			*sep = '\0';
		}
		else
			str = sep;	/* no more commands for next pass */


		/* Extract arguments */
		if ((argc = parse_line (token, argv)) == 0) {
			rc = -1;	/* no command at all */
			continue;
		}

		if (cmd_process(flag, argc, argv, &repeatable, NULL))
			rc = -1;

	}

	return rc ? rc : repeatable;
}


/*
 * Run a command using the selected parser.
 *
 * @param cmd	Command to run
 * @param flag	Execution flags (CMD_FLAG_...)
 * @return 0 on success, or != 0 on error.
 */
int run_command(const char *cmd, int flag)
{
	if (builtin_run_command(cmd, flag) == -1)
		return 1;

	return 0;
}


void command_loop(void)
{
	static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
	int len;
	int rc = 1;
	int flag;

	/*
	 * Main Loop for Monitor Command Processing
	 */
	for (;;) {
		len = readline (CONFIG_SYS_PROMPT);

		flag = 0;	/* assume no special flags for now */
		if (len > 0)
			strcpy (lastcommand, console_buffer);

		if (len == -1)
			puts ("<INTERRUPT>\n");
		else
			rc = run_command(lastcommand, flag);

		if (rc <= 0) {
			/* invalid command or not repeatable, forget it */
			lastcommand[0] = 0;
		}
	}
}

void command_init(void)
{
	extern cmd_tbl_t __cli_cmd_start,__cli_cmd_end;

	CLI_cmd_start = &__cli_cmd_start;
	CLI_cmd_end = &__cli_cmd_end;
}

src/command.h

#ifndef _COMMAND_H
#define _COMMAND_H

#define ARG_TYPE_NONE		9       /* idle */
#define ARG_TYPE_S32		0
#define ARG_TYPE_U32		1
#define ARG_TYPE_BOOL		2
#define ARG_TYPE_STR		3


#define CONFIG_SYS_PROMPT		"flinn@tiny4412 # "
#define CONFIG_SYS_CBSIZE		256	/* Console I/O Buffer Size */
#define CONFIG_SYS_PBSIZE		384	/* Print Buffer Size */
#define CONFIG_SYS_MAXARGS		16	/* max number of command args */


enum command_ret_t {
	CMD_RET_SUCCESS,	/* 0 = Success */
	CMD_RET_FAILURE,	/* 1 = Failure */
	CMD_RET_USAGE = -1,	/* Failure, please report 'usage' error */
};

struct cmd_tbl_s {
	char		*name;		/* Command Name			*/
	int		maxargs;	/* maximum number of arguments	*/
	int		type;
	int		(*cmd)(struct cmd_tbl_s *, int, int, char * const []);
	char		*usage;		/* Usage message	(short)	*/
};

typedef struct cmd_tbl_s	cmd_tbl_t;

#define REGISTER_CMD(name,maxargs,type,handler,usage) \
	const cmd_tbl_t cmd_##name __attribute__ ((section (".cli_cmd"))) =  {#name, maxargs, type, handler, usage}


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

#define isblank(c)	(c == ' ' || c == '\t')


void command_loop(void);
void command_init(void);


#endif /* _COMMAND_H */

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值