Subversion Repositories Projects

Rev

Go to most recent revision | 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