Andy Little
/
userMenu
Simple Menu for user config at startup etc
userMenu.h
- Committer:
- skyscraper
- Date:
- 2020-03-29
- Revision:
- 0:694155408133
File content as of revision 0:694155408133:
/// /// @file userMenu.h /// @brief Simple commandline menu subsystem. /// @discussion /// Menu derived from old version of ArduPilot, used in ArduIMU.V3 /// Originally from https://code.google.com/archive/p/ardu-imu/downloads /// /// The Menu class implements a simple CLI that accepts commands typed by /// the user, and passes the arguments to those commands to a function /// defined as handing the command. /// /// Commands are defined in an array of Menu::command structures passed /// to the constructor. Each entry in the array defines one command. /// /// Arguments passed to the handler function are pre-converted to both /// long and float for convenience. #ifndef SKYSCRAPER_MBED_USER_MENU_H_INCLUDED #define SKYSCRAPER_MBED_USER_MENU_H_INCLUDED #include <inttypes.h> //#define MENU_COMMANDLINE_MAX 32 //#define MENU_ARGS_MAX 4 //#define MENU_COMMAND_MAX 14 /// Class defining and handling one menu tree class Menu { public: static constexpr uint8_t commandlineLenMax = 32U; ///< maximum input line length static constexpr uint8_t argsLenMax = 4U; ///< maximum number of arguments static constexpr uint8_t commandNameLenMax = 14; ///< maximum length of a command name /// argument passed to a menu function /// /// Space-delimited arguments are parsed from the commandline and /// separated into these structures. /// /// If the argument cannot be parsed as a float or a long, the value /// of f or i respectively is undefined. You should range-check /// the inputs to your function. /// struct arg { arg(): str{nullptr}, i{0},f{0.0}{} const char *str; ///< string form of the argument long i; ///< integer form of the argument (if a number) float f; ///< floating point form of the argument (if a number) }; /// menu command function /// /// Functions called by menu array entries are expected to be of this /// type. /// /// @param argc The number of valid arguments, including the /// name of the command in argv[0]. Will never be /// more than argsLenMax. /// @param argv Pointer to an array of Menu::arg structures /// detailing any optional arguments given to the /// command. argv[0] is always the name of the /// command, so that the same function can be used /// to handle more than one command. /// typedef int8_t (*func)(uint8_t argc, const struct arg *argv); /// menu pre-prompt function /// /// Called immediately before waiting for the user to type a command; can be /// used to display help text or status, for example. /// /// If this function returns false, the menu exits. /// typedef bool (*preprompt)(void); /// menu command description /// struct command { /// Name of the command, as typed or received. /// Command names are limited in size to keep this structure compact. /// const char command[commandNameLenMax]; /// The function to call when the command is received. /// /// The argc argument will be at least 1, and no more than /// argsLenMax. The argv array will be populated with /// arguments typed/received up to argsLenMax. The command /// 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, but /// can be overridden by explicit entries in the command array. /// int8_t (*func)(uint8_t argc, const struct arg *argv); ///< callback function }; /// constructor /// /// Note that you should normally not call the constructor directly. Use /// the MENU and MENU2 macros defined below. /// /// @param prompt The prompt to be displayed with this menu. /// @param commands An array of ::command structures in program memory (PROGMEM). /// @param entries The number of entries in the menu. /// Menu(const char *prompt, const struct command *commands, uint8_t entries, preprompt ppfunc = 0); /// menu runner void run(void); private: /// Implements the default 'help' command. /// void _help(void); ///< implements the 'help' command /// calls the function for the n'th menu item /// /// @param n Index for the menu item to call /// @param argc Number of arguments prepared for the menu item /// int8_t _call(uint8_t n, uint8_t argc); const char *_prompt; ///< prompt to display const command *_commands; ///< array of commands const uint8_t _entries; ///< size of the menu const preprompt _ppfunc; ///< optional pre-prompt action static char _inbuf[commandlineLenMax]; ///< input buffer static arg _argv[argsLenMax+ 1]; ///< arguments }; /// Macros used to define a menu. /// /// The commands argument should be an arary of Menu::command structures, one /// per command name. The array does not need to be terminated with any special /// record. /// /// Use name.run() to run the menu. /// /// The MENU2 macro supports the optional pre-prompt printing function. /// #define MENU(name, prompt, commands) \ static constexpr char __menu_name__ ##name[] = prompt; \ static Menu name(__menu_name__ ##name, commands, sizeof(commands) / sizeof(commands[0])) #define MENU2(name, prompt, commands, preprompt) \ static constexpr char __menu_name__ ##name[] = prompt; \ static Menu name(__menu_name__ ##name, commands, sizeof(commands) / sizeof(commands[0]), preprompt) #endif