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