UBOOT通用菜单menu的实现

1. 概述
在uboot中经常需要开发一个菜单,用来进行一些选项类的操作,如下图所示
UBOOT通用菜单menu的实现
网上有很多介绍菜单的开发方法,但很多都是自己开发,没有统一的开发框架。最近研究uboot代码时发现,其实uboot(版本为2016)代码中有一个菜单框架,以及使用这个框架的一个具体例子,可以根据自己的需要进行适当的修改,用起来非常方便。
2.具体实现
菜单框架代码位于/common/menu.c文件中,这个是一个菜单框架,提供了对外的一些使用接口。
使用这个框架代码的实例代码是位于/cmd/bootmenu.c,里面通过使用框架,完成了一个简单的菜单

但这个实例代码在实际使用过程中,个人认为存在几个不足
1.每个菜单项都是以环境变量的方式保存,不是很直观
2.执行命令时,只能是调用run_command()执行基本的boot命令,不能将菜单和具体的某个实现函数关联到一起。
3.不能进行菜单的级联
4.执行完菜单选项后,不能继续回到当前菜单界面。

针对上面的几个问题,把bootmenu.c中的代码修改一下,就可以实现一个很方便的菜单。
修改的思路如下:
1.bootmenu_create()函数
源代码是通过对环境变量解析,循环获取bootmenu_entry,然后创建entry。entry中,有两个关键字段title和command,主要对这两个字段进行赋值。也就是完成对"key-value"的一个映射。
修改点:
通过环境变量定义菜单的选项,非常不直观,通过以下方式自定义一个结构体,看起来就直观很多。
struct bootmenu_item
{
    char title[64];             /* title of entry */
    char command_key[64];       /* hush command of entry */
    void (*command_fun) (void);
};
static struct bootmenu_item items[] = {
    {"Modify Net Parameters""modify_net_paras", modify_net_paras},
    {"Download Boot""download_boot", download_boot},
    {"Download Image""download_image", download_image},
    {"Download DTB""download_dtb", download_dtb},
    {"U-Boot console", ENTER_CONSOLE, enter_console},
    {"Exit", EXIT_MENU, exit_menu},
};

通过定义一个bootmenu_item 类型的数组,直观的展现菜单选项的内容。bootmenu_create()中将解析环境变量修改为解析定义的数组即可。

2.bootmenu_show()函数
源代码在确定用户选择的entry后,选择该entry的command字符串,然后执行run_command(command, 0)命令,完成命令的执行。
修改点:
通过上面自定义的结构体,完成一个command_keycommand_fun的映射。然后自己实现一个exec_command)()函数。由于框架帮我们匹配到了command_key,所以该函数主要是通过key找到对应的fun函数并执行。
static void exec_command(char *command_key)
{
    int i = 0;
    for (i = 0; i < sizeof(items) / sizeof(struct bootmenu_item); i++)
    {
        if (!strcmp(items[i].command_key, command_key))
        {
            items[i].command_fun();
            break;
        }
    }
}

3.bootmenu_show()函数
源码中,在执行完命令后,函数直接返回,那么菜单也不再显示,直接进入了uboot命令行界面。
修改点:
在执行完后,如果有些选项,我们需要再次显示,那么可以通过goto语句,跳到该函数的入口处,重新执行整个流程,从而打印出了整个菜单。

通过以上的修改,就实现了利用uboot中的菜单框架,自定义实现了自己的uboot菜单,非常方便。