Andy Little
/
userMenu
Simple Menu for user config at startup etc
userMenu.h@0:694155408133, 2020-03-29 (annotated)
- Committer:
- skyscraper
- Date:
- Sun Mar 29 16:00:36 2020 +0000
- Revision:
- 0:694155408133
Initial commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
skyscraper | 0:694155408133 | 1 | /// |
skyscraper | 0:694155408133 | 2 | /// @file userMenu.h |
skyscraper | 0:694155408133 | 3 | /// @brief Simple commandline menu subsystem. |
skyscraper | 0:694155408133 | 4 | /// @discussion |
skyscraper | 0:694155408133 | 5 | /// Menu derived from old version of ArduPilot, used in ArduIMU.V3 |
skyscraper | 0:694155408133 | 6 | /// Originally from https://code.google.com/archive/p/ardu-imu/downloads |
skyscraper | 0:694155408133 | 7 | /// |
skyscraper | 0:694155408133 | 8 | /// The Menu class implements a simple CLI that accepts commands typed by |
skyscraper | 0:694155408133 | 9 | /// the user, and passes the arguments to those commands to a function |
skyscraper | 0:694155408133 | 10 | /// defined as handing the command. |
skyscraper | 0:694155408133 | 11 | /// |
skyscraper | 0:694155408133 | 12 | /// Commands are defined in an array of Menu::command structures passed |
skyscraper | 0:694155408133 | 13 | /// to the constructor. Each entry in the array defines one command. |
skyscraper | 0:694155408133 | 14 | /// |
skyscraper | 0:694155408133 | 15 | /// Arguments passed to the handler function are pre-converted to both |
skyscraper | 0:694155408133 | 16 | /// long and float for convenience. |
skyscraper | 0:694155408133 | 17 | |
skyscraper | 0:694155408133 | 18 | #ifndef SKYSCRAPER_MBED_USER_MENU_H_INCLUDED |
skyscraper | 0:694155408133 | 19 | #define SKYSCRAPER_MBED_USER_MENU_H_INCLUDED |
skyscraper | 0:694155408133 | 20 | |
skyscraper | 0:694155408133 | 21 | #include <inttypes.h> |
skyscraper | 0:694155408133 | 22 | |
skyscraper | 0:694155408133 | 23 | //#define MENU_COMMANDLINE_MAX 32 |
skyscraper | 0:694155408133 | 24 | //#define MENU_ARGS_MAX 4 |
skyscraper | 0:694155408133 | 25 | //#define MENU_COMMAND_MAX 14 |
skyscraper | 0:694155408133 | 26 | |
skyscraper | 0:694155408133 | 27 | /// Class defining and handling one menu tree |
skyscraper | 0:694155408133 | 28 | class Menu { |
skyscraper | 0:694155408133 | 29 | public: |
skyscraper | 0:694155408133 | 30 | |
skyscraper | 0:694155408133 | 31 | |
skyscraper | 0:694155408133 | 32 | static constexpr uint8_t commandlineLenMax = 32U; ///< maximum input line length |
skyscraper | 0:694155408133 | 33 | static constexpr uint8_t argsLenMax = 4U; ///< maximum number of arguments |
skyscraper | 0:694155408133 | 34 | static constexpr uint8_t commandNameLenMax = 14; ///< maximum length of a command name |
skyscraper | 0:694155408133 | 35 | /// argument passed to a menu function |
skyscraper | 0:694155408133 | 36 | /// |
skyscraper | 0:694155408133 | 37 | /// Space-delimited arguments are parsed from the commandline and |
skyscraper | 0:694155408133 | 38 | /// separated into these structures. |
skyscraper | 0:694155408133 | 39 | /// |
skyscraper | 0:694155408133 | 40 | /// If the argument cannot be parsed as a float or a long, the value |
skyscraper | 0:694155408133 | 41 | /// of f or i respectively is undefined. You should range-check |
skyscraper | 0:694155408133 | 42 | /// the inputs to your function. |
skyscraper | 0:694155408133 | 43 | /// |
skyscraper | 0:694155408133 | 44 | struct arg { |
skyscraper | 0:694155408133 | 45 | arg(): str{nullptr}, i{0},f{0.0}{} |
skyscraper | 0:694155408133 | 46 | const char *str; ///< string form of the argument |
skyscraper | 0:694155408133 | 47 | long i; ///< integer form of the argument (if a number) |
skyscraper | 0:694155408133 | 48 | float f; ///< floating point form of the argument (if a number) |
skyscraper | 0:694155408133 | 49 | }; |
skyscraper | 0:694155408133 | 50 | |
skyscraper | 0:694155408133 | 51 | /// menu command function |
skyscraper | 0:694155408133 | 52 | /// |
skyscraper | 0:694155408133 | 53 | /// Functions called by menu array entries are expected to be of this |
skyscraper | 0:694155408133 | 54 | /// type. |
skyscraper | 0:694155408133 | 55 | /// |
skyscraper | 0:694155408133 | 56 | /// @param argc The number of valid arguments, including the |
skyscraper | 0:694155408133 | 57 | /// name of the command in argv[0]. Will never be |
skyscraper | 0:694155408133 | 58 | /// more than argsLenMax. |
skyscraper | 0:694155408133 | 59 | /// @param argv Pointer to an array of Menu::arg structures |
skyscraper | 0:694155408133 | 60 | /// detailing any optional arguments given to the |
skyscraper | 0:694155408133 | 61 | /// command. argv[0] is always the name of the |
skyscraper | 0:694155408133 | 62 | /// command, so that the same function can be used |
skyscraper | 0:694155408133 | 63 | /// to handle more than one command. |
skyscraper | 0:694155408133 | 64 | /// |
skyscraper | 0:694155408133 | 65 | typedef int8_t (*func)(uint8_t argc, const struct arg *argv); |
skyscraper | 0:694155408133 | 66 | |
skyscraper | 0:694155408133 | 67 | /// menu pre-prompt function |
skyscraper | 0:694155408133 | 68 | /// |
skyscraper | 0:694155408133 | 69 | /// Called immediately before waiting for the user to type a command; can be |
skyscraper | 0:694155408133 | 70 | /// used to display help text or status, for example. |
skyscraper | 0:694155408133 | 71 | /// |
skyscraper | 0:694155408133 | 72 | /// If this function returns false, the menu exits. |
skyscraper | 0:694155408133 | 73 | /// |
skyscraper | 0:694155408133 | 74 | typedef bool (*preprompt)(void); |
skyscraper | 0:694155408133 | 75 | |
skyscraper | 0:694155408133 | 76 | /// menu command description |
skyscraper | 0:694155408133 | 77 | /// |
skyscraper | 0:694155408133 | 78 | struct command { |
skyscraper | 0:694155408133 | 79 | /// Name of the command, as typed or received. |
skyscraper | 0:694155408133 | 80 | /// Command names are limited in size to keep this structure compact. |
skyscraper | 0:694155408133 | 81 | /// |
skyscraper | 0:694155408133 | 82 | const char command[commandNameLenMax]; |
skyscraper | 0:694155408133 | 83 | |
skyscraper | 0:694155408133 | 84 | /// The function to call when the command is received. |
skyscraper | 0:694155408133 | 85 | /// |
skyscraper | 0:694155408133 | 86 | /// The argc argument will be at least 1, and no more than |
skyscraper | 0:694155408133 | 87 | /// argsLenMax. The argv array will be populated with |
skyscraper | 0:694155408133 | 88 | /// arguments typed/received up to argsLenMax. The command |
skyscraper | 0:694155408133 | 89 | /// name will always be in argv[0]. |
skyscraper | 0:694155408133 | 90 | /// |
skyscraper | 0:694155408133 | 91 | /// Commands may return -2 to cause the menu itself to exit. |
skyscraper | 0:694155408133 | 92 | /// The "?", "help" and "exit" commands are always defined, but |
skyscraper | 0:694155408133 | 93 | /// can be overridden by explicit entries in the command array. |
skyscraper | 0:694155408133 | 94 | /// |
skyscraper | 0:694155408133 | 95 | int8_t (*func)(uint8_t argc, const struct arg *argv); ///< callback function |
skyscraper | 0:694155408133 | 96 | }; |
skyscraper | 0:694155408133 | 97 | |
skyscraper | 0:694155408133 | 98 | /// constructor |
skyscraper | 0:694155408133 | 99 | /// |
skyscraper | 0:694155408133 | 100 | /// Note that you should normally not call the constructor directly. Use |
skyscraper | 0:694155408133 | 101 | /// the MENU and MENU2 macros defined below. |
skyscraper | 0:694155408133 | 102 | /// |
skyscraper | 0:694155408133 | 103 | /// @param prompt The prompt to be displayed with this menu. |
skyscraper | 0:694155408133 | 104 | /// @param commands An array of ::command structures in program memory (PROGMEM). |
skyscraper | 0:694155408133 | 105 | /// @param entries The number of entries in the menu. |
skyscraper | 0:694155408133 | 106 | /// |
skyscraper | 0:694155408133 | 107 | Menu(const char *prompt, const struct command *commands, uint8_t entries, preprompt ppfunc = 0); |
skyscraper | 0:694155408133 | 108 | |
skyscraper | 0:694155408133 | 109 | /// menu runner |
skyscraper | 0:694155408133 | 110 | void run(void); |
skyscraper | 0:694155408133 | 111 | |
skyscraper | 0:694155408133 | 112 | private: |
skyscraper | 0:694155408133 | 113 | /// Implements the default 'help' command. |
skyscraper | 0:694155408133 | 114 | /// |
skyscraper | 0:694155408133 | 115 | void _help(void); ///< implements the 'help' command |
skyscraper | 0:694155408133 | 116 | |
skyscraper | 0:694155408133 | 117 | /// calls the function for the n'th menu item |
skyscraper | 0:694155408133 | 118 | /// |
skyscraper | 0:694155408133 | 119 | /// @param n Index for the menu item to call |
skyscraper | 0:694155408133 | 120 | /// @param argc Number of arguments prepared for the menu item |
skyscraper | 0:694155408133 | 121 | /// |
skyscraper | 0:694155408133 | 122 | int8_t _call(uint8_t n, uint8_t argc); |
skyscraper | 0:694155408133 | 123 | |
skyscraper | 0:694155408133 | 124 | const char *_prompt; ///< prompt to display |
skyscraper | 0:694155408133 | 125 | const command *_commands; ///< array of commands |
skyscraper | 0:694155408133 | 126 | const uint8_t _entries; ///< size of the menu |
skyscraper | 0:694155408133 | 127 | const preprompt _ppfunc; ///< optional pre-prompt action |
skyscraper | 0:694155408133 | 128 | |
skyscraper | 0:694155408133 | 129 | static char _inbuf[commandlineLenMax]; ///< input buffer |
skyscraper | 0:694155408133 | 130 | static arg _argv[argsLenMax+ 1]; ///< arguments |
skyscraper | 0:694155408133 | 131 | }; |
skyscraper | 0:694155408133 | 132 | |
skyscraper | 0:694155408133 | 133 | /// Macros used to define a menu. |
skyscraper | 0:694155408133 | 134 | /// |
skyscraper | 0:694155408133 | 135 | /// The commands argument should be an arary of Menu::command structures, one |
skyscraper | 0:694155408133 | 136 | /// per command name. The array does not need to be terminated with any special |
skyscraper | 0:694155408133 | 137 | /// record. |
skyscraper | 0:694155408133 | 138 | /// |
skyscraper | 0:694155408133 | 139 | /// Use name.run() to run the menu. |
skyscraper | 0:694155408133 | 140 | /// |
skyscraper | 0:694155408133 | 141 | /// The MENU2 macro supports the optional pre-prompt printing function. |
skyscraper | 0:694155408133 | 142 | /// |
skyscraper | 0:694155408133 | 143 | #define MENU(name, prompt, commands) \ |
skyscraper | 0:694155408133 | 144 | static constexpr char __menu_name__ ##name[] = prompt; \ |
skyscraper | 0:694155408133 | 145 | static Menu name(__menu_name__ ##name, commands, sizeof(commands) / sizeof(commands[0])) |
skyscraper | 0:694155408133 | 146 | |
skyscraper | 0:694155408133 | 147 | #define MENU2(name, prompt, commands, preprompt) \ |
skyscraper | 0:694155408133 | 148 | static constexpr char __menu_name__ ##name[] = prompt; \ |
skyscraper | 0:694155408133 | 149 | static Menu name(__menu_name__ ##name, commands, sizeof(commands) / sizeof(commands[0]), preprompt) |
skyscraper | 0:694155408133 | 150 | |
skyscraper | 0:694155408133 | 151 | #endif |