您的位置:首页 > 运维架构 > Shell

基于MDK平台 cortex-M3 shell 的实现

2015-10-29 14:41 525 查看
每次写完代码最头疼的就是测试,大多数时间都得花在这里。要么用串口调试助手、要么用上位机。至于串口调度助手效率,大家都懂的。但又不想每次都写一个上位机、闲暇之余模仿u-boot和rtt-shell 写了一个shell,大多数代码都来自U-BOOT的、做了小小的阉割。

使用方法

/*在需要登记命令的文件内包含shell.h、console.h两个头文件 */

例:

REG_CMD --命令登记宏

(

printconf, --命令名

3, --命令的最大参数个数

do_printconf, --命令处理函数(函数的类型遵循 int (*cmd_callback)(struct cmd_tbl_t *, int argc, char **argv))

"显示系统配置", --简单的使用说明

"打印系统配置信息." --详细使用说明

);

另外由于所有的命令列表都编译到了cmdlist代码段,所以需要在编译器中设置防止cmdlist被优化。





暂时没心思写详细说明,直接给出代码。

代码主要由四个文件组成(Console.c、Console.h、shell.c、shell.h)

Console提供打印移植接口

/*console.h*/

#ifndef _CONSOLE_H_

#define _CONSOLE_H_

#include "app_type.h"

void console_init(void);

void console_putc(const char c);

void console_puts(const char * s);

bool console_get(char *c);

char console_getc(void);

/*---对输入格式化字符串进行检测---*/

void console_printf (const char *fmt, ...) __attribute__((format(printf,1,2)));

#endif

/*console.c*/

#include "includes.h"

#include <stdio.h>

#include <stdarg.h>

#include <stdbool.h>

#include <string.h>

/**==========================================================

*@brief 控制台初始化

*@param none

==========================================================*/

void console_init(void){}

/**==========================================================

*@brief 输出一个字符到串口控制台

*@param c

==========================================================*/

void console_putc(const char c){}

/**==========================================================

*@brief 输出一个字符串到串口控制台

*@param s

==========================================================*/

void console_puts(const char * s){}

/**==========================================================

*@brief 从串口控制台获取一个输入字符

*@retval true:成功获取

==========================================================*/

bool console_get(char *c){}

/**==========================================================

*@brief 从串口控制台获取一个输入字符

*@retval c

*@attetion 阻塞方式调用

==========================================================*/

char console_getc(void){}

static char printbuffer[128];

/**==========================================================

*@brief 打印一个格式化字符串到串口控制台

*@retval

==========================================================*/

void console_printf (const char *fmt, ...)

{

va_list args;

va_start (args, fmt);

vsprintf (printbuffer, fmt, args); //将输入参考格式化后放到缓冲区

va_end (args);

console_puts (printbuffer);

}

/*shell 提供命令处理*/

/*shell.h*/

/**********************************************************************

* @file shell.h

* @brief 命令行处理

*

* @version 1.0

* @date 2015-06-09

* @author roger

*

* Copyright(C) 2015

* All rights reserved.

* Copyright(C) 2015 QQ 932896234

* @reference u-boot

*

***********************************************************************/

#ifndef __SHELL_H_

#define __SHELL_H_

#ifndef NULL

#define NULL 0

#endif

#define CFG_MAXARGS 16 /*最大参数个数-----------------*/

#define CFG_MAXCMDS 30 /*最多允许定义的命令个数-------*/

/*----------------------------------------------------------------------------------------------------------

* Monitor Command Table

--------------------------------------------------------------------------------------------------------*/

typedef struct cmd_tbl_t

{

char *name;
/* 命令名 */

char maxargs;
/*最大参数个数 */

/*命令(处理)回调函数 */

int (*cmd_callback)(struct cmd_tbl_t *, int argc, char **argv);

char *usage;
/* 简单使用说明 */

char *help;

}cmd_tbl_t;

/*外部声明*/

int run_command(char *cmdline);

void run_shell(void);

char *readline (const char * prompt);

int parse_line(char *line, char *argv[]);

#define REG_CMD(name,maxargs,cmdProc,usage,help) \

const cmd_tbl_t __cmdline_##name \

__attribute__ ((unused,section ("cmdlist"))) \

= {#name, maxargs, cmdProc, usage,help}

#endif

/*shell.c*/

/**********************************************************************

* @file shell.c

* @brief 命令行处理程序

*

* @version 1.0

* @date 2015-06-09

* @author roger

*

* Copyright(C) 2015 QQ 932896234

* All rights reserved.

* reference u-boot

*

***********************************************************************/

#include "shell.h"

#include "console.h"

#include <string.h>

#define CFG_CBSIZE 64

static char console_buffer[CFG_CBSIZE]; /* */

#define erase_seq "\b \b" /* erase sequence */

static const char tab_seq[]=" "; /* used to expand TABs */

#define console_prompt "[Fire-fight]#"

#ifdef __CC_ARM /* ARM C Compiler */

extern const int cmdlist$$Base;

extern const int cmdlist$$Limit;

#define cmd_start cmdlist$$Base

#define cmd_end cmdlist$$Limit

#else

#error "The compiler does not support this shell."

#endif

/**====================================================================

* find command table entry for a command

* cmd_name :命令名

=======================================================================*/

cmd_tbl_t *find_cmd (const char *cmd_name)

{

cmd_tbl_t *cmdPtr;

const char *p;

int len;

/*==================================================================

* Some commands allow length modifiers (like "cp.b");

* compare command name only until first dot.

-------------------------------------------------------------------*/

len = ((p = strchr(cmd_name, '.')) == NULL) ? strlen (cmd_name) : (p - cmd_name);

/*扫描所有命令========================================================*/

for ( cmdPtr = (cmd_tbl_t*)&cmd_start; cmdPtr < (cmd_tbl_t*)&cmd_end ; cmdPtr++)

{

if (strncmp (cmd_name, cmdPtr->name, len) == 0) /*匹配命令=======*/

{

if (len == strlen (cmdPtr->name))

return cmdPtr;

}

}

return NULL; /* not found or ambiguous command */

}

/***************************************************************************

*brief

*param

* buffer :字符缓冲区指针,

* p :指向当前字符的下一位置的指针

* colp :指向列计数

* np :指向已输出的字符数

* plen :提示符长度

*

***************************************************************************/

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)

{

console_puts (erase_seq);

(*colp)--;

}

for (s=buffer; s<p; ++s)

{

if (*s == '\t')

{

console_puts (tab_seq+((*colp) & 07));

*colp += 8 - ((*colp) & 07);

}

else

{

++(*colp);

console_putc (*s);

}

}

}

else

{

console_puts (erase_seq);

(*colp)--;

}

(*np)--;

return (p);

}

/***************************************************************************

* brief : 读一行

* param : prompt :命令行提示符

* Return: 输入的字符数

* -1 if break

* -2 if timed out

* 字符串将会放到console_buffer中

* attengion 调用该函数会阻塞当前进程运行

***************************************************************************/

char *readline (const char * prompt)

{

char *p = console_buffer;

int n = 0; /* buffer index */

int plen = 0; /* prompt length */

int col; /* output column cnt */

char c;

if (prompt) /*打印提示符 */

{

plen = strlen (prompt);

console_puts (prompt);

}

col = plen; /*光标位置 */

for (;;)

{

c = console_getc(); /*读取一个字符------------*/

/*

* Special character handling

*/

switch (c)

{

case '\r': /*回车键 */

case '\n':

*p = '\0'; /*加入结束符 */

console_puts ("\r\n");

return console_buffer; /*完成输入,返回输入字符个数*/

case '\0': /* nul */

continue;

case 0x03: /* ^C - break */

console_buffer[0] = '\0'; /* discard input */

return (NULL);

case 0x15: /* ^U - erase line */

while (col > plen) /*清空一行 */

{

console_puts (erase_seq); /*删除当前输入 */

--col;

}

p = console_buffer; /*重新指向缓冲区 */

n = 0;

continue;

case 0x17: /* ^W - erase word */

p=delete_char(console_buffer, p, &col, &n, plen);

while ((n > 0) && (*p != ' '))

{

p=delete_char(console_buffer, p, &col, &n, plen);

}

continue;

case 0x08: /* ^H - backspace */

case 0x7F: /* DEL - backspace */

p = delete_char(console_buffer, p, &col, &n, plen);

continue;

default:

/*

* 正常字符处理

*/

if (n < CFG_CBSIZE - 2)

{

if (c == '\t') { /* expand TABs */

console_puts (tab_seq+ (col&07));

col += 8 - (col&07);

}

else

{

++col; /*回显--------------*/

console_putc (c);

}

*p++ = c; /*将输入字符送到缓冲区*/

++n;

}

else

{ /*缓冲区满 */

console_putc ('\a');

}

}

}

}

/**************************************************************************

*brief 解析一行字符串

*param line

*output argv[] 参数列表

*return 参数个数

***************************************************************************/

int parse_line(char *line, char *argv[])

{

int nargs = 0; /*参数个数------------*/

#ifdef DEBUG_PARSER

console_printf ("parse_line: \"%s\"\n", line);

#endif

while (nargs < CFG_MAXARGS)

{

while ((*line == ' ') || (*line == '\t')) /*跳过空格及制表符-----*/

{

++line;

}

if (*line == '\0') /*判断是否到达字符串末尾*/

{

argv[nargs] = NULL;

#ifdef DEBUG_PARSER

console_printf ("parse_line: nargs=%d\n", nargs);

#endif

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;

#ifdef DEBUG_PARSER

console_printf ("parse_line: nargs=%d\n", nargs);

#endif

return (nargs);

}

/*加入'\0'作为参数结尾标记 */

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

}

console_printf ("** Too many args (max. %d) **\n", CFG_MAXARGS);

#ifdef DEBUG_PARSER

console_printf ("parse_line: nargs=%d\n", nargs);

#endif

return (nargs);

}

static char *argv[CFG_MAXARGS + 1]; /*参数列表 */

/**===========================================================================

*@brief 运行一个命令

*@param cmdline 命令行

*@retval 0表示运行失败

============================================================================*/

int run_command(char *cmdline)

{

int argc; /*参数个数 */

cmd_tbl_t *cmdtp;

/* Extract arguments */

if ((argc = parse_line (cmdline, argv)) == 0)

{

return 0;

}

else if (strcmp(argv[0],"clear") == 0)

{

return 0;

}

/* 从命令表中查找一个命令-----------------------------------------------*/

if ((cmdtp = find_cmd(argv[0])) == NULL)

{

console_printf ("Unknown command '%s' - try 'help'\r\n", argv[0]);

return 0;

}

/* found - check max args */

if (argc > cmdtp->maxargs)

{

console_printf ("Usage:\n%s\n", cmdtp->usage);

console_printf ("argc=%d,maxargs=%d", argc , cmdtp->maxargs);

return 0;

}

if (cmdtp->cmdProc == NULL) /*判断处理函数是否存在*/

{

console_printf ("%s\r\n", cmdtp->usage);

}

/* OK - call function to run the command */

else

{

(cmdtp->cmdProc) (cmdtp, argc, argv);

}

return 1;

}

/*=============================================================

* for long help messages

=============================================================*/

int do_help (cmd_tbl_t * cmdtp, int argc, char *argv[])

{

int i;

int rcode = 0;

int j, swaps;

cmd_tbl_t *cmd_array[CFG_MAXCMDS];

/*计算出命令个数------------------------------------------*/

int cmd_items = (cmd_tbl_t*)&cmd_end - (cmd_tbl_t*)&cmd_start;

/*限制命令个数,避免缓冲区溢出-----------------------------*/

if (cmd_items > CFG_MAXCMDS)

{

cmd_items = CFG_MAXCMDS;

}

if (argc == 1)

{

cmdtp = (cmd_tbl_t *)&cmd_start;

for (i = 0; i < cmd_items; i++)

{

cmd_array[i] = cmdtp++;

}

/* 对命令列表进行排序---------------------------------*/

for (i = cmd_items - 1; i > 0; --i)

{

swaps = 0;

for (j = 0; j < i; ++j)

{

if (strcmp (cmd_array[j]->name,

cmd_array[j + 1]->name) > 0)

{

cmd_tbl_t *tmp;

tmp = cmd_array[j];

cmd_array[j] = cmd_array[j + 1];

cmd_array[j + 1] = tmp;

++swaps;

}

}

if (!swaps)

break;

}

console_puts("\r\n");

for (i = 0; i < cmd_items; i++)

{

console_puts(cmd_array[i]->name); /*打印命令名--------*/

/*对齐调整*/

j = strlen(cmd_array[i]->name);

if (j < 10)

{

j = 10 - j;

}

while (j--)console_putc(' ');

console_puts("- ");

console_puts(cmd_array[i]->usage); /*命令使用信息------*/

console_puts("\r\n");

}

return 0;

}

for (i = 1; i < argc; ++i) /*列出命令的详细信息*/

{

if ((cmdtp = find_cmd (argv[i])) != NULL)

{

console_puts (cmdtp->name);

console_puts (" :\r\n");

if (cmdtp->help)

{

console_puts (cmdtp->help);

}

else

{

console_puts ("- No help available.\n");

rcode = 1;

}

console_putc ('\n');

}

else

{

console_printf ("Unknown command '%s' - try 'help'"

" without arguments for list of all"

" known commands\n\n", argv[i]

);

rcode = 1;

}

}

return rcode;

}

/**==========================================================================

登记帮助命令

============================================================================*/

REG_CMD

(

help, CFG_MAXARGS, do_help,

"print online help",

""

);

const cmd_tbl_t __cmdline_help_ __attribute__ ((unused,section ("cmdlist"))) =

{

"?", CFG_MAXARGS,do_help,

"alias for 'help'",

""

};

/**===========================================================================

*@brief 运行命令行系统

============================================================================*/

void run_shell(void)

{

char *cmdline;

cmdline = readline(console_prompt); /*读一行 */

if (cmdline == NULL)return;

if (strlen(cmdline) >= CFG_CBSIZE)

{

console_puts ("## Command too long!\n");

return;

}

run_command(cmdline);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: