lubanlite一段有意思的代码
一段关于控制台注册的代码实现。代码来源:Airchip Luban-Lite
首先是注册代码的定义:
/********************************************************
* 注册控制台命令时的编译器属性定义
* __attribute__((used)): 告诉编译器该函数或变量是实际使用到的,即使没有引用也要保留
* __attribute__((section(".tinyspl.console.cmd"))): 告诉编译器将该函数或变量放到.tinyspl.console.cmd段中
********************************************************/
#define __console_init \
__attribute__((used)) __attribute__((section(".tinyspl.console.cmd")))
/********************************************************
* 控制台命令初始化结构体定义
* cmdname: 命令名称
* proc: 命令处理函数
* mode: 命令模式,0表示普通模式,1表示后台模式
* initialized: 是否已经初始化
* help: 命令帮助信息
********************************************************/
struct console_init_cmd {
const char *cmdname;
int (*proc)(int argc, char **argv);
uint8_t mode;
bool initialized;
const char *help;
};
/********************************************************
* 控制台命令注册宏定义
* _cmd: 命令名称
* _proc: 命令处理函数
* _help: 命令帮助信息
********************************************************/
#define CONSOLE_CMD(_cmd, _proc, _help) \
__console_init struct console_init_cmd console_init_cmd_##_cmd = { \
.cmdname = #_cmd, .proc = _proc, .initialized = false, .help = _help \
};
使用的时候,首先调用console_init
遍历整个.tinyspl.console.cmd
段
/**********************************
* 控制台初始化函数
**********************************/
void console_init(void)
{
//命令起始地址和结束地址。
//其中__console_init_start和__console_init_start是由编译器自动生成的,
//用来存放所有的控制台初始化命令。
struct console_init_cmd *cmd_start =
(struct console_init_cmd *)&__console_init_start;
struct console_init_cmd *cmd_end =
(struct console_init_cmd *)&__console_init_start;
struct console_init_cmd *p;
if (!(g_console = malloc(sizeof(struct tiny_console))))
return;
memset(g_console, 0, sizeof(struct tiny_console));
console_set_prompt(g_console, CONSOLE_PROMPT);
console_set_sysname(g_console, CONSOLE_SYSNAME);
//向控制台注册基本命令
console_register_cmd("help", console_help, "Show all commands.");
console_register_cmd("history", console_history, "Show history.");
console_register_cmd("version", console_version, "Show version.");
for (p = cmd_start; p < cmd_end; p++) {
if (p->initialized)
continue;
//向控制台注册.tinyspl.console.cmd段中定义的所有命令
console_register_init_cmds(p->cmdname);
}
return;
}
其中__console_init_start和__console_init_start在链接文件中定义
.data : {
. = ALIGN(0x8) ;
__data_start__ = . ;
__sdata = . ;
.......
*(.gcc_except_table)
*(.gcc_except_table*)
. = ALIGN(8) ;
__console_init_start = .; //段起始地址
KEEP(*(.tinyspl.console.cmd))
. = ALIGN(8) ;
__console_init_end = .; //段结束地址
__global_pointer$ = .;
......
__edata = .;
__data_end__ = .;
. = ALIGN(0x8) ;
注册函数就是使用一个链表,保存所有的命令,和命令的入口函数。
查找函数就是比较命令名称,返回命令对应的结构体。
struct console_cmd *console_find_cmd_by_name(const char *name);
struct console_cmd *console_register_cmd(const char *cmd,
int (*proc)(int, char **),
const char *help);
使用:在其他任何地方都可以使用CONSOLE_CMD
注册一条命令(App)和入口函数,然后就可以通过控制台来运行这段代码。