Change the way pre-prompt printing works to avoid having to deal with "magic" menu entries.

Add a default 'exit' command to back out of a menu.

git-svn-id: https://arducopter.googlecode.com/svn/trunk@546 f9c3cf11-9bcb-44bc-f272-b75c42450872
This commit is contained in:
DrZiplok@gmail.com 2010-09-24 07:31:59 +00:00
parent 064dda10bf
commit e2184615d9
2 changed files with 33 additions and 15 deletions

View File

@ -20,6 +20,11 @@ public:
/// menu command function /// menu command function
/// ///
typedef int (*func)(uint8_t argc, const struct arg *argv); typedef int (*func)(uint8_t argc, const struct arg *argv);
/// menu pre-prompt function
///
/// If this function returns false, the menu exits.
typedef bool (*preprompt)(void);
/// menu command description /// menu command description
/// ///
@ -28,8 +33,6 @@ public:
struct command { struct command {
/// Name of the command, as typed or received. /// Name of the command, as typed or received.
/// Command names are limited in size to keep this structure compact. /// Command names are limited in size to keep this structure compact.
/// If the first command in the menu is named '*', it will be called
/// each time before printing the prompt.
const char command[MENU_COMMAND_MAX]; const char command[MENU_COMMAND_MAX];
/// The function to call when the command is received. /// The function to call when the command is received.
@ -37,6 +40,8 @@ public:
/// MENU_ARGS_MAX. The argv array will be populated with /// MENU_ARGS_MAX. The argv array will be populated with
/// arguments typed/received up to MENU_ARGS_MAX. The command /// arguments typed/received up to MENU_ARGS_MAX. The command
/// name will always be in argv[0]. /// name will always be in argv[0].
/// Commands may return -2 to cause the menu itself to exit.
/// The "?", "help" and "exit" commands are always defined.
int (*func)(uint8_t argc, const struct arg *argv); ///< callback function int (*func)(uint8_t argc, const struct arg *argv); ///< callback function
}; };
@ -46,7 +51,7 @@ public:
/// @param commands An array of ::command structures. /// @param commands An array of ::command structures.
/// @param entries The number of entries in the menu. /// @param entries The number of entries in the menu.
/// ///
Menu(const char *prompt, const struct command *commands, uint8_t entries); Menu(const char *prompt, const struct command *commands, uint8_t entries, preprompt ppfunc = 0);
/// menu runner /// menu runner
void run(void); void run(void);
@ -62,19 +67,27 @@ private:
/// @param argc Number of arguments prepared for the menu item /// @param argc Number of arguments prepared for the menu item
/// ///
int _call(uint8_t n, uint8_t argc); int _call(uint8_t n, uint8_t argc);
const char *_prompt; ///< prompt to display const char *_prompt; ///< prompt to display
const command *_commands; ///< array of commands const command *_commands; ///< array of commands
const uint8_t _entries; ///< size of the menu const uint8_t _entries; ///< size of the menu
const preprompt _ppfunc; ///< optional pre-prompt action
static char _inbuf[MENU_COMMANDLINE_MAX]; ///< input buffer static char _inbuf[MENU_COMMANDLINE_MAX]; ///< input buffer
static arg _argv[MENU_ARGS_MAX + 1]; ///< arguments static arg _argv[MENU_ARGS_MAX + 1]; ///< arguments
}; };
/// Macro used to define a menu. /// Macros used to define a menu.
/// ///
/// Use name.run() to run the menu. /// Use name.run() to run the menu.
/// ///
/// The MENU2 macro supports the optional pre-prompt printing function.
///
#define MENU(name, prompt, commands) \ #define MENU(name, prompt, commands) \
static const char __menu_name__ ##name[] PROGMEM = prompt; \ static const char __menu_name__ ##name[] PROGMEM = prompt; \
static Menu name(__menu_name__ ##name, commands, sizeof(commands) / sizeof(commands[0])) static Menu name(__menu_name__ ##name, commands, sizeof(commands) / sizeof(commands[0]))
#define MENU2(name, prompt, commands, preprompt) \
static const char __menu_name__ ##name[] PROGMEM = prompt; \
static Menu name(__menu_name__ ##name, commands, sizeof(commands) / sizeof(commands[0]), preprompt)

View File

@ -17,10 +17,11 @@ char Menu::_inbuf[MENU_COMMANDLINE_MAX];
Menu::arg Menu::_argv[MENU_ARGS_MAX + 1]; Menu::arg Menu::_argv[MENU_ARGS_MAX + 1];
// constructor // constructor
Menu::Menu(const prog_char *prompt, const Menu::command *commands, uint8_t entries) : Menu::Menu(const prog_char *prompt, const Menu::command *commands, uint8_t entries, preprompt ppfunc) :
_prompt(prompt), _prompt(prompt),
_commands(commands), _commands(commands),
_entries(entries) _entries(entries),
_ppfunc(ppfunc)
{ {
} }
@ -35,12 +36,10 @@ Menu::run(void)
// loop performing commands // loop performing commands
for (;;) { for (;;) {
// if the first command is called '*', call it before displaying the menu // run the pre-prompt function, if one is defined
if ("*", _commands[0].command) { if ((NULL != _ppfunc) && !_ppfunc())
if (-2 == _call(0, 0)) return;
return;
}
// loop reading characters from the input // loop reading characters from the input
len = 0; len = 0;
Serial.printf("%S] ", _prompt); Serial.printf("%S] ", _prompt);
@ -91,12 +90,18 @@ Menu::run(void)
ret = _call(i, argc); ret = _call(i, argc);
if (-2 == ret) if (-2 == ret)
return; return;
break;
} }
} }
// if the menu doesn't provide more comprehensive help, print the command list // implicit commands
if ((i == _entries) && (!strcmp(_argv[0].str, "?") || (!strcmp_P(_argv[0].str, PSTR("help"))))) if (i == _entries) {
_help(); if (!strcmp(_argv[0].str, "?") || (!strcmp_P(_argv[0].str, PSTR("help")))) {
_help();
} else if (!strcmp_P(_argv[0].str, PSTR("exit"))) {
return;
}
}
} }
} }