[U-Boot] [PATCH 13/14] New command bootmenu: ANSI terminal Boot Menu support

Marek Vasut marek.vasut at gmail.com
Wed Jan 25 19:18:50 CET 2012


>  * Added some ANSI escape codes definitions in common.h
>  * Configuration is done via env variables bootmenu_delay and
> bootmenu_<num>:
> 
>     bootmenu_delay=<delay>
>     bootmenu_<num>="<title>=<commands>"
> 
>     (title and commands are separated by first char '=')
> 
>     <delay> is delay in seconds of autobooting first entry
>     <num> is boot menu entry, starting from zero
>     <title> is text shown in boot screen
>     <commands> are commands which will be executed when menu entry is
> selected

Do you need this command if you already have common/menu.c?

M

> 
>  * First argument of bootmenu command override bootmenu_delay env
>  * If env bootmenu_delay or bootmenu arg is not specified, delay is 10
> seconds * If delay is 0, no entry will be shown on screen and first will
> be called * If delay is less then 0, no autoboot delay will be used
>  * Boot Menu will stop finding next menu entry if last was not defined
>  * Boot Menu always add menu entry "U-Boot console" at end of all entries
> 
>  * Example using:
> 
>     setenv bootmenu_0 Boot 1. kernel=bootm 0x82000000  # Set first menu
> entry setenv bootmenu_1 Boot 2. kernel=bootm 0x83000000  # Set second menu
> entry setenv bootmenu_2 Reset board=reset                # Set third menu
> entry setenv bootmenu_3 U-Boot boot order=boot           # Set fourth menu
> entry setenv bootmenu_4  # Empty string is end of all bootmenu entries
> bootmenu 20        # Run bootmenu with autoboot delay 20s
> 
> Signed-off-by: Pali Rohár <pali.rohar at gmail.com>
> ---
> Changes since original version:
>    - ANSI bootmenu command: use puts instead printf
>    - Merged parts of patch "Add some ANSI escape codes definitions in
> common.h"
> 
>  common/Makefile          |    1 +
>  common/cmd_bootmenu.c    |  366
> ++++++++++++++++++++++++++++++++++++++++++++++ include/common.h         | 
>  13 ++
>  include/config_cmd_all.h |    1 +
>  4 files changed, 381 insertions(+), 0 deletions(-)
>  create mode 100644 common/cmd_bootmenu.c
> 
> diff --git a/common/Makefile b/common/Makefile
> index e1efd45..7402bfb 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -67,6 +67,7 @@ COBJS-$(CONFIG_CMD_SOURCE) += cmd_source.o
>  COBJS-$(CONFIG_CMD_BDI) += cmd_bdinfo.o
>  COBJS-$(CONFIG_CMD_BEDBUG) += bedbug.o cmd_bedbug.o
>  COBJS-$(CONFIG_CMD_BMP) += cmd_bmp.o
> +COBJS-$(CONFIG_CMD_BOOTMENU) += cmd_bootmenu.o
>  COBJS-$(CONFIG_CMD_BOOTLDR) += cmd_bootldr.o
>  COBJS-$(CONFIG_CMD_CACHE) += cmd_cache.o
>  COBJS-$(CONFIG_CMD_CLEAR) += cmd_clear.o
> diff --git a/common/cmd_bootmenu.c b/common/cmd_bootmenu.c
> new file mode 100644
> index 0000000..931ed18
> --- /dev/null
> +++ b/common/cmd_bootmenu.c
> @@ -0,0 +1,366 @@
> +/*
> + * (C) Copyright 2011 Pali Rohár <pali.rohar at gmail.com>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <watchdog.h>
> +#include <linux/string.h>
> +
> +#ifdef CONFIG_SYS_HUSH_PARSER
> +#include <hush.h>
> +#endif
> +
> +static char *get_option(int n)
> +{
> +
> +	char name[] = "bootmenu_\0\0";
> +
> +	if (n < 0 || n > 99)
> +		return NULL;
> +
> +	sprintf(name+9, "%d", n);
> +
> +	return getenv(name);
> +
> +}
> +
> +static char *get_end_of_title(char *str)
> +{
> +
> +	if (!str)
> +		return NULL;
> +
> +	return strchr(str, '=');
> +
> +}
> +
> +static int print_title(char *begin, char *end)
> +{
> +
> +	if (!begin || !end || end < begin)
> +		return 1;
> +
> +	while (begin != end)
> +		putc(*(begin++));
> +
> +	return 0;
> +
> +}
> +
> +static int print_entry(int n, int reverse)
> +{
> +
> +	char *str = get_option(n);
> +	char *end = get_end_of_title(str);
> +
> +	if (!end)
> +		return 1;
> +
> +	printf(ANSI_CURSOR_POSITION, n+4, 1);
> +
> +	if (reverse)
> +		puts(ANSI_COLOR_REVERSE);
> +
> +	puts("     ");
> +	print_title(str, end);
> +	puts(ANSI_CLEAR_LINE_TO_END);
> +
> +	if (reverse)
> +		puts(ANSI_COLOR_RESET);
> +
> +	return 0;
> +
> +}
> +
> +static int print_menu(int active)
> +{
> +
> +	int n = 0;
> +
> +	printf(ANSI_CURSOR_POSITION, 1, 1);
> +	puts(ANSI_CLEAR_LINE);
> +	printf(ANSI_CURSOR_POSITION, 2, 1);
> +	puts("  *** U-Boot BOOT MENU ***");
> +	puts(ANSI_CLEAR_LINE_TO_END);
> +	printf(ANSI_CURSOR_POSITION, 3, 1);
> +	puts(ANSI_CLEAR_LINE);
> +
> +	while (1) {
> +
> +		int ret = print_entry(n, n == active ? 1 : 0);
> +
> +		if (ret == 1)
> +			break;
> +
> +		++n;
> +
> +	}
> +
> +	printf(ANSI_CURSOR_POSITION, n+4, 1);
> +
> +	if (n == active)
> +		puts(ANSI_COLOR_REVERSE);
> +
> +	puts("     U-Boot console");
> +	puts(ANSI_CLEAR_LINE_TO_END);
> +
> +	if (n == active)
> +		puts(ANSI_COLOR_RESET);
> +
> +	printf(ANSI_CURSOR_POSITION, n+5, 1);
> +	puts(ANSI_CLEAR_LINE);
> +	printf(ANSI_CURSOR_POSITION, n+6, 1);
> +	puts("  Press UP/DOWN to move, ENTER to select");
> +	puts(ANSI_CLEAR_LINE_TO_END);
> +	printf(ANSI_CURSOR_POSITION, n+7, 1);
> +	puts(ANSI_CLEAR_LINE);
> +
> +	return n;
> +
> +}
> +
> +int do_bootmenu(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
> +{
> +
> +	int active = 0;
> +	int abort = 0;
> +	int key = 0; /* 0 - NONE, 1 - UP, 2 - DOWN, 3 - SELECT */
> +	int esc = 0;
> +	int count = 0;
> +	int delay = 10;
> +	int instant = 0;
> +	char *delay_str = NULL;
> +
> +	if (argc >= 2)
> +		delay_str = argv[1];
> +
> +	if (!delay_str)
> +		delay_str = getenv("bootmenu_delay");
> +
> +	if (delay_str)
> +		delay = (int)simple_strtol(delay_str, NULL, 10);
> +
> +	if (delay == 0) {
> +
> +		/* prevent setting U-Boot console as first menu entry */
> +		if (get_end_of_title(get_option(0)))
> +			count = 1;
> +
> +		instant = 1;
> +
> +	}
> +
> +	if (delay < 0)
> +		abort = 1;
> +
> +	if (!instant) {
> +
> +		puts(ANSI_CURSOR_HIDE);
> +		puts(ANSI_CLEAR_CONSOLE);
> +		printf(ANSI_CURSOR_POSITION, 1, 1);
> +
> +	}
> +
> +	while (1) {
> +
> +		if (abort || delay > 0)
> +			count = print_menu(active);
> +
> +		if (!abort) {
> +
> +			if (delay > 0)
> +				printf("  Hit any key to stop autoboot: %2d ",
> +						delay);
> +
> +			while (delay > 0) {
> +
> +				int i;
> +
> +				for (i = 0; i < 100; ++i) {
> +
> +					if (tstc()) {
> +
> +						abort = 1;
> +						key = getc();
> +
> +						if (key == '\e') {
> +							esc = 1;
> +							key = 0;
> +						} else if (key == '\r')
> +							key = 3;
> +						else
> +							key = 0;
> +
> +						break;
> +
> +					}
> +
> +					WATCHDOG_RESET();
> +					udelay(10000);
> +
> +				}
> +
> +				if (abort)
> +					break;
> +
> +				--delay;
> +				printf("\b\b\b%2d ", delay);
> +
> +			}
> +
> +			if (delay <= 0)
> +				key = 3;
> +
> +		} else {
> +
> +			while (!tstc()) {
> +
> +				WATCHDOG_RESET();
> +				udelay(10000);
> +
> +			}
> +
> +			key = getc();
> +
> +			if (esc == 0) {
> +
> +				if (key == '\e') {
> +					esc = 1;
> +					key = 0;
> +				}
> +
> +			} else if (esc == 1) {
> +
> +				if (key == '[') {
> +					esc = 2;
> +					key = 0;
> +				} else
> +					esc = 0;
> +
> +			} else if (esc == 2 || esc == 3) {
> +
> +				if (esc == 2 && key == '1') {
> +					esc = 3;
> +					key = 0;
> +				} else
> +					esc = 0;
> +
> +				if (key == 'A')
> +					key = 1;
> +				else if (key == 'B')
> +					key = 2;
> +				else
> +					key = 0;
> +
> +			}
> +
> +			if (key == '\r')
> +				key = 3;
> +
> +		}
> +
> +		if (key == 1) {
> +
> +			if (active > 0)
> +				--active;
> +
> +		} else if (key == 2) {
> +
> +			if (active < count)
> +				++active;
> +
> +		} else if (key == 3) {
> +
> +			char *str;
> +			char *end;
> +
> +			putc('\n');
> +
> +			if (!instant) {
> +
> +				puts(ANSI_CURSOR_SHOW);
> +				puts(ANSI_CLEAR_CONSOLE);
> +				printf(ANSI_CURSOR_POSITION, 1, 1);
> +
> +			}
> +
> +			WATCHDOG_RESET();
> +
> +			/* last entry is always U-Boot console */
> +			if (active == count) {
> +
> +				puts("Starting U-Boot console\n\n");
> +				return 0;
> +
> +			}
> +
> +			str = get_option(active);
> +			end = get_end_of_title(str);
> +
> +			if (!end) {
> +
> +				printf("Invalid Boot Menu entry %d\n", active);
> +				puts("Starting U-Boot console\n\n");
> +				return 0;
> +
> +			}
> +
> +			if (!end[1]) {
> +
> +				printf("Invalid Boot Menu entry %d: ", active);
> +				print_title(str, end);
> +				puts("\nStarting U-Boot console\n\n");
> +				return 0;
> +
> +			}
> +
> +			printf("Booting Boot Menu entry %d: ", active);
> +			print_title(str, end);
> +			puts(" ...\n\n");
> +
> +#ifndef CONFIG_SYS_HUSH_PARSER
> +			run_command(end+1, 0);
> +#else
> +			parse_string_outer(end+1, FLAG_PARSE_SEMICOLON |
> +					FLAG_EXIT_FROM_LOOP);
> +#endif
> +
> +			printf("\nFailed booting Boot Menu entry %d: ", active);
> +			print_title(str, end);
> +			puts("\nStarting U-Boot console\n\n");
> +			return 0;
> +
> +		}
> +
> +	}
> +
> +	/* never happends */
> +	return 1;
> +
> +}
> +
> +U_BOOT_CMD(
> +	bootmenu, 2, 1, do_bootmenu,
> +	"ANSI terminal bootmenu",
> +	"[delay]\n"
> +	"    - show ANSI terminal bootmenu with autoboot delay (default 10s)"
> +);
> diff --git a/include/common.h b/include/common.h
> index 9c0449e..c6dd2ea 100644
> --- a/include/common.h
> +++ b/include/common.h
> @@ -754,8 +754,21 @@ int	disable_ctrlc (int);	/* 1 to disable, 0 to 
enable
> Control-C detect */ * ANSI terminal
>   */
> 
> +#define ANSI_CURSOR_UP			"\e[%dA"
> +#define ANSI_CURSOR_DOWN		"\e[%dB"
> +#define ANSI_CURSOR_FORWARD		"\e[%dC"
> +#define ANSI_CURSOR_BACK		"\e[%dD"
> +#define ANSI_CURSOR_NEXTLINE		"\e[%dE"
> +#define ANSI_CURSOR_PREVIOUSLINE	"\e[%dF"
> +#define ANSI_CURSOR_COLUMN		"\e[%dG"
>  #define ANSI_CURSOR_POSITION		"\e[%d;%dH"
> +#define ANSI_CURSOR_SHOW		"\e[?25h"
> +#define ANSI_CURSOR_HIDE		"\e[?25l"
>  #define ANSI_CLEAR_CONSOLE		"\e[2J"
> +#define ANSI_CLEAR_LINE_TO_END		"\e[0K"
> +#define ANSI_CLEAR_LINE			"\e[2K"
> +#define ANSI_COLOR_RESET		"\e[0m"
> +#define ANSI_COLOR_REVERSE		"\e[7m"
> 
>  /*
>   * STDIO based functions (can always be used)
> diff --git a/include/config_cmd_all.h b/include/config_cmd_all.h
> index 3f25eba..8c0a648 100644
> --- a/include/config_cmd_all.h
> +++ b/include/config_cmd_all.h
> @@ -20,6 +20,7 @@
>  #define CONFIG_CMD_BEDBUG	/* Include BedBug Debugger	*/
>  #define CONFIG_CMD_BMP		/* BMP support			*/
>  #define CONFIG_CMD_BOOTD	/* bootd			*/
> +#define CONFIG_CMD_BOOTMENU	/* ANSI terminal Boot Menu	*/
>  #define CONFIG_CMD_BSP		/* Board Specific functions	*/
>  #define CONFIG_CMD_CACHE	/* icache, dcache		*/
>  #define CONFIG_CMD_CDP		/* Cisco Discovery Protocol	*/


More information about the U-Boot mailing list