Simple Menu for user config at startup etc

Revision:
0:694155408133
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/userMenu.h	Sun Mar 29 16:00:36 2020 +0000
@@ -0,0 +1,151 @@
+///
+/// @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