blob: c87b6ec812855de9c44949964c179064a7633902 [file] [log] [blame]
Simon Glassb5c8fea2023-01-06 08:52:43 -06001.. SPDX-License-Identifier: GPL-2.0+
2
3Expo menu
4=========
5
6U-Boot provides a menu implementation for use with selecting bootflows and
7changing U-Boot settings. This is in early stages of development.
8
9Motivation
10----------
11
12U-Boot already has a text-based menu system accessed via the
13:doc:`../usage/cmd/bootmenu`. This works using environment variables, or via
14some EFI-specific hacks.
15
16The command makes use of a lower-level `menu` implementation, which is quite
17flexible and can be used to make menu hierarchies.
18
19However this system is not flexible enough for use with standard boot. It does
20not support a graphical user interface and cannot currently support anything
21more than a very simple list of items. While it does support multiple menus in
22hierarchies, these are implemented by the caller. See for example `eficonfig.c`.
23
24Another challenge with the current menu implementation is that it controls
25the event loop, such that bootmenu_loop() does not return until a key is
26pressed. This makes it difficult to implement dynamic displays or to do other
27things while the menu is running, such as searching for more bootflows.
28
29For these reasons an attempt has been made to develop a more flexible system
30which can handle menus as well as other elements. This is called 'expo', short
31for exposition, in an attempt to avoid common words like display, screen, menu
32and the like. The primary goal is to support Verified Boot for Embedded (VBE),
33although it is available to any boot method, using the 'bootflow menu' command.
34
35Efforts have been made to use common code with the existing menu, including
36key processing in particular.
37
38Previous work looked at integrating Nuklear into U-Boot. This works fine and
39could provide a way to provide a more flexible UI, perhaps with expo dealing
40with the interface to Nuklear. But this is quite a big step and it may be years
41before this becomes desirable, if at all. For now, U-Boot only needs a fairly
42simple set of menus and options, so rendering them directly is fairly
43straightforward.
44
45Concepts
46--------
47
48The creator of the expo is here called a `controller` and it controls most
49aspects of the expo. This is the code that you must write to use expo.
50
51An `expo` is a set of scenes which can be presented to the user one at a time,
52to show information and obtain input from the user.
53
54A `scene` is a collection of objects which are displayed together on the screen.
55Only one scene is visible at a time and scenes do not share objects.
56
57A `scene object` is something that appears in the scene, such as some text, an
58image or a menu. Objects can be positioned and hidden.
59
60A `menu object` contains a title, a set of `menu items` and a pointer to the
61current item. Menu items consist of a keypress (indicating what to press to
62select the item), label and description. All three are shown in a single line
63within the menu. Items can also have a preview image, which is shown when the
64item is highlighted.
65
Simon Glass7e5b6372023-10-01 19:13:40 -060066A `textline object` contains a label and an editable string.
67
68All components have a name. This is mostly for debugging, so it is easy to see
69what object is referred to, although the name is also used for saving values.
70Of course the ID numbers can help as well, but they are less easy to
71distinguish.
Simon Glassb5c8fea2023-01-06 08:52:43 -060072
73While the expo implementation provides support for handling keypresses and
74rendering on the display or serial port, it does not actually deal with reading
75input from the user, nor what should be done when a particular menu item is
76selected. This is deliberate since having the event loop outside the expo is
77more flexible, particularly in a single-threaded environment like U-Boot.
78
79Everything within an expo has a unique ID number. This is done so that it is
80easy to refer to things after the expo has been created. The expectation is that
81the controller declares an enum containing all of the elements in the expo,
82passing the ID of each object as it is created. When a menu item is selected,
83its ID is returned. When a object's font or position needs to change, the ID is
84passed to expo functions to indicate which object it is. It is possible for expo
85to auto-allocate IDs, but this is not recommended. The use of IDs is a
86convenience, removing the need for the controller to store pointers to objects,
87or even the IDs of objects. Programmatic creation of many items in a loop can be
88handled by allocating space in the enum for a maximum number of items, then
89adding the loop count to the enum values to obtain unique IDs.
90
Simon Glass9af34152023-06-01 10:22:47 -060091Where dynamic IDs are need, use expo_set_dynamic_start() to set the start value,
92so that they are allocated above the starting (enum) IDs.
93
Simon Glassb5c8fea2023-01-06 08:52:43 -060094All text strings are stored in a structure attached to the expo, referenced by
95a text ID. This makes it easier at some point to implement multiple languages or
96to support Unicode strings.
97
98Menu objects do not have their own text and image objects. Instead they simply
99refer to objects which have been created. So a menu item is just a collection
100of IDs of text and image objects. When adding a menu item you must create these
101objects first, then create the menu item, passing in the relevant IDs.
102
103Creating an expo
104----------------
105
Simon Glass82cafee2023-06-01 10:23:01 -0600106To create an expo programmatically, use `expo_new()` followed by `scene_new()`
107to create a scene. Then add objects to the scene, using functions like
108`scene_txt_str()` and `scene_menu()`. For every menu item, add text and image
109objects, then create the menu item with `scene_menuitem()`, referring to those
110objects.
111
112To create an expo using a description file, see :ref:`expo_format` below.
Simon Glassb5c8fea2023-01-06 08:52:43 -0600113
114Layout
115------
116
117Individual objects can be positioned using `scene_obj_set_pos()`. Menu items
118cannot be positioned manually: this is done by `scene_arrange()` which is called
119automatically when something changes. The menu itself determines the position of
120its items.
121
122Rendering
123---------
124
125Rendering is performed by calling `expo_render()`. This uses either the
126vidconsole, if present, or the serial console in `text mode`. Expo handles
127presentation automatically in either case, without any change in how the expo is
128created.
129
130For the vidconsole, Truetype fonts can be used if enabled, to enhance the
131quality of the display. For text mode, each menu item is shown in a single line,
132allowing easy selection using arrow keys.
133
134Input
135-----
136
137The controller is responsible for collecting keyboard input. A good way to do
138this is to use `cli_ch_process()`, since it handles conversion of escape
139sequences into keys. However, expo has some special menu-key codes for
140navigating the interface. These are defined in `enum bootmenu_key` and include
141`BKEY_UP` for moving up and `BKEY_SELECT` for selecting an item. You can use
Simon Glass7e5b6372023-10-01 19:13:40 -0600142`bootmenu_conv_key()` to convert an ASCII key into one of these, but if it
143returns a value >= `BKEY_FIRST_EXTRA` then you should pass the unmodified ASCII
144key to the expo, since it may be used by textline objects.
Simon Glassb5c8fea2023-01-06 08:52:43 -0600145
146Once a keypress is decoded, call `expo_send_key()` to send it to the expo. This
147may cause an update to the expo state and may produce an action.
148
149Actions
150-------
151
152Call `expo_action_get()` in the event loop to check for any actions that the
153expo wants to report. These can include selecting a particular menu item, or
154quitting the menu. Processing of these is the responsibility of your controller.
155
156Event loop
157----------
158
159Expo is intended to be used in an event loop. For an example loop, see
160`bootflow_menu_run()`. It is possible to perform other work in your event loop,
161such as scanning devices for more bootflows.
162
163Themes
164------
165
Simon Glass2e593892023-06-01 10:22:53 -0600166Expo supports simple themes, for setting the font size, for example. Use the
167expo_apply_theme() function to load a theme, passing a node with the required
168properties:
169
170font-size
171 Font size to use for all text (type: u32)
172
Simon Glass7230fdb2023-06-01 10:23:00 -0600173menu-inset
174 Number of pixels to inset the menu on the sides and top (type: u32)
175
176menuitem-gap-y
177 Number of pixels between menu items
178
Simon Glass82cafee2023-06-01 10:23:01 -0600179Pop-up mode
180-----------
181
182Expos support two modes. The simple mode is used for selecting from a single
183menu, e.g. when choosing with OS to boot. In this mode the menu items are shown
184in a list (label, > pointer, key and description) and can be chosen using arrow
185keys and enter::
186
187 U-Boot Boot Menu
188
189 UP and DOWN to choose, ENTER to select
190
191 mmc1 > 0 Fedora-Workstation-armhfp-31-1.9
192 mmc3 1 Armbian
193
194The popup mode allows multiple menus to be present in a scene. Each is shown
195just as its title and label, as with the `CPU Speed` and `AC Power` menus here::
196
197 Test Configuration
198
199
200 CPU Speed <2 GHz> (highlighted)
201
202 AC Power Always Off
203
204
205 UP and DOWN to choose, ENTER to select
206
207
Simon Glassa0874dc2023-06-01 10:23:02 -0600208.. _expo_format:
209
Simon Glass82cafee2023-06-01 10:23:01 -0600210Expo Format
211-----------
212
213It can be tedious to create a complex expo using code. Expo supports a
214data-driven approach, where the expo description is in a devicetree file. This
215makes it easier and faster to create and edit the description. An expo builder
216is provided to convert this format into an expo structure.
217
218Layout of the expo scenes is handled automatically, based on a set of simple
Simon Glassa0874dc2023-06-01 10:23:02 -0600219rules. The :doc:`../usage/cmd/cedit` can be used to load a configuration
220and create an expo from it.
Simon Glass82cafee2023-06-01 10:23:01 -0600221
222Top-level node
223~~~~~~~~~~~~~~
224
225The top-level node has the following properties:
226
227dynamic-start
228 type: u32, optional
229
230 Specifies the start of the dynamically allocated objects. This results in
231 a call to expo_set_dynamic_start().
232
233The top-level node has the following subnodes:
234
235scenes
236 Specifies the scenes in the expo, each one being a subnode
237
238strings
239 Specifies the strings in the expo, each one being a subnode
240
241`scenes` node
242~~~~~~~~~~~~~
243
244Contains a list of scene subnodes. The name of each subnode is passed as the
245name to `scene_new()`.
246
247`strings` node
248~~~~~~~~~~~~~~
249
250Contains a list of string subnodes. The name of each subnode is ignored.
251
252`strings` subnodes
253~~~~~~~~~~~~~~~~~~
254
255Each subnode defines a string which can be used by scenes and objects. Each
256string has an ID number which is used to refer to it.
257
258The `strings` subnodes have the following properties:
259
260id
261 type: u32, required
262
263 Specifies the ID number for the string.
264
265value:
266 type: string, required
267
268 Specifies the string text. For now only a single value is supported. Future
269 work may add support for multiple languages by using a value for each
270 language.
271
272Scene nodes (`scenes` subnodes)
273~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
274
275Each subnode of the `scenes` node contains a scene description.
276
277Most properties can use either a string or a string ID. For example, a `title`
278property can be used to provide the title for a menu; alternatively a `title-id`
279property can provide the string ID of the title. If both are present, the
280ID takes preference, except that if a string with that ID does not exist, it
281falls back to using the string from the property (`title` in this example). The
282description below shows these are alternative properties with the same
283description.
284
285The scene nodes have the following properties:
286
287id
288 type: u32, required
289
290 Specifies the ID number for the string.
291
292title / title-id
293 type: string / u32, required
294
295 Specifies the title of the scene. This is shown at the top of the scene.
296
297prompt / prompt-id
298 type: string / u32, required
299
300 Specifies a prompt for the scene. This is shown at the bottom of the scene.
301
302The scene nodes have a subnode for each object in the scene.
303
304Object nodes
305~~~~~~~~~~~~
306
307The object-node name is used as the name of the object, e.g. when calling
308`scene_menu()` to create a menu.
309
310Object nodes have the following common properties:
311
312type
313 type: string, required
314
315 Specifies the type of the object. Valid types are:
316
317 "menu"
318 Menu containing items which can be selected by the user
319
Simon Glass7e5b6372023-10-01 19:13:40 -0600320 "textline"
321 A line of text which can be edited
322
Simon Glass82cafee2023-06-01 10:23:01 -0600323id
324 type: u32, required
325
326 Specifies the ID of the object. This is used when referring to the object.
327
Simon Glasseb6c71b2023-08-14 16:40:37 -0600328Where CMOS RAM is used for reading and writing settings, the following
329additional properties are required:
330
331start-bit
332 Specifies the first bit in the CMOS RAM to use for this setting. For a RAM
333 with 0x100 bytes, there are 0x800 bit locations. For example, register 0x80
334 holds bits 0x400 to 0x407.
335
336bit-length
337 Specifies the number of CMOS RAM bits to use for this setting. The bits
338 extend from `start-bit` to `start-bit + bit-length - 1`. Note that the bits
339 must be contiguous.
Simon Glass82cafee2023-06-01 10:23:01 -0600340
341Menu nodes have the following additional properties:
342
343title / title-id
344 type: string / u32, required
345
346 Specifies the title of the menu. This is shown to the left of the area for
347 this menu.
348
349item-id
350 type: u32 list, required
351
352 Specifies the ID for each menu item. These are used for checking which item
353 has been selected.
354
355item-label / item-label-id
356 type: string list / u32 list, required
357
358 Specifies the label for each item in the menu. These are shown to the user.
359 In 'popup' mode these form the items in the menu.
360
361key-label / key-label-id
362 type: string list / u32 list, optional
363
364 Specifies the key for each item in the menu. These are currently only
365 intended for use in simple mode.
366
367desc-label / desc-label-id
368 type: string list / u32 list, optional
369
370 Specifies the description for each item in the menu. These are currently
371 only intended for use in simple mode.
372
Simon Glass7e5b6372023-10-01 19:13:40 -0600373Textline nodes have the following additional properties:
374
375label / label-id
376 type: string / u32, required
377
378 Specifies the label of the textline. This is shown to the left of the area
379 for this textline.
380
381edit-id
382 type: u32, required
383
384 Specifies the ID of the of the editable text object. This can be used to
385 obtain the text from the textline
386
387max-chars:
388 type: u32, required
389
390 Specifies the maximum number of characters permitted to be in the textline.
391 The user will be prevented from adding more.
392
Simon Glass82cafee2023-06-01 10:23:01 -0600393
394Expo layout
395~~~~~~~~~~~
396
397The `expo_arrange()` function can be called to arrange the expo objects in a
398suitable manner. For each scene it puts the title at the top, the prompt at the
399bottom and the objects in order from top to bottom.
400
Simon Glassc5aacf52023-08-14 16:40:29 -0600401
402.. _expo_example:
403
Simon Glass82cafee2023-06-01 10:23:01 -0600404Expo format example
405~~~~~~~~~~~~~~~~~~~
406
407This example shows an expo with a single scene consisting of two menus. The
408scene title is specified using a string from the strings table, but all other
409strings are provided inline in the nodes where they are used.
410
411::
412
Simon Glassd5737b32023-08-14 16:40:28 -0600413 /* this comment is parsed by the expo.py tool to insert the values below
Simon Glass82cafee2023-06-01 10:23:01 -0600414
Simon Glassd5737b32023-08-14 16:40:28 -0600415 enum {
416 ZERO,
417 ID_PROMPT,
418 ID_SCENE1,
419 ID_SCENE1_TITLE,
Simon Glass82cafee2023-06-01 10:23:01 -0600420
Simon Glassd5737b32023-08-14 16:40:28 -0600421 ID_CPU_SPEED,
422 ID_CPU_SPEED_TITLE,
423 ID_CPU_SPEED_1,
424 ID_CPU_SPEED_2,
425 ID_CPU_SPEED_3,
Simon Glass82cafee2023-06-01 10:23:01 -0600426
Simon Glassd5737b32023-08-14 16:40:28 -0600427 ID_POWER_LOSS,
428 ID_AC_OFF,
429 ID_AC_ON,
430 ID_AC_MEMORY,
431
Simon Glass7e5b6372023-10-01 19:13:40 -0600432 ID_MACHINE_NAME,
433 ID_MACHINE_NAME_EDIT,
434
Simon Glassd5737b32023-08-14 16:40:28 -0600435 ID_DYNAMIC_START,
436 */
Simon Glass82cafee2023-06-01 10:23:01 -0600437
438 &cedit {
439 dynamic-start = <ID_DYNAMIC_START>;
440
441 scenes {
442 main {
443 id = <ID_SCENE1>;
444
445 /* value refers to the matching id in /strings */
446 title-id = <ID_SCENE1_TITLE>;
447
448 /* simple string is used as it is */
449 prompt = "UP and DOWN to choose, ENTER to select";
450
451 /* defines a menu within the scene */
452 cpu-speed {
453 type = "menu";
454 id = <ID_CPU_SPEED>;
455
456 /*
457 * has both string and ID. The string is ignored
458 * if the ID is present and points to a string
459 */
460 title = "CPU speed";
461 title-id = <ID_CPU_SPEED_TITLE>;
462
463 /* menu items as simple strings */
464 item-label = "2 GHz", "2.5 GHz", "3 GHz";
465
466 /* IDs for the menu items */
467 item-id = <ID_CPU_SPEED_1 ID_CPU_SPEED_2
468 ID_CPU_SPEED_3>;
469 };
470
471 power-loss {
472 type = "menu";
473 id = <ID_POWER_LOSS>;
474
475 title = "AC Power";
476 item-label = "Always Off", "Always On",
477 "Memory";
478
479 item-id = <ID_AC_OFF ID_AC_ON ID_AC_MEMORY>;
480 };
Simon Glass7e5b6372023-10-01 19:13:40 -0600481
482 machine-name {
483 id = <ID_MACHINE_NAME>;
484 type = "textline";
485 max-chars = <20>;
486 title = "Machine name";
487 edit-id = <ID_MACHINE_NAME_EDIT>;
Simon Glass82cafee2023-06-01 10:23:01 -0600488 };
489 };
490
491 strings {
492 title {
493 id = <ID_SCENE1_TITLE>;
494 value = "Test Configuration";
495 value-es = "configuraciĆ³n de prueba";
496 };
497 };
498 };
499
Simon Glassb5c8fea2023-01-06 08:52:43 -0600500
501API documentation
502-----------------
503
504.. kernel-doc:: include/expo.h
505
506Future ideas
507------------
508
509Some ideas for future work:
510
511- Default menu item and a timeout
Simon Glassb5c8fea2023-01-06 08:52:43 -0600512- Image formats other than BMP
513- Use of ANSI sequences to control a serial terminal
514- Colour selection
Simon Glass7e5b6372023-10-01 19:13:40 -0600515- Support for more widgets, e.g. numeric, radio/option
Simon Glassb5c8fea2023-01-06 08:52:43 -0600516- Mouse support
517- Integrate Nuklear, NxWidgets or some other library for a richer UI
518- Optimise rendering by only updating the display with changes since last render
519- Use expo to replace the existing menu implementation
520- Add a Kconfig option to drop the names to save code / data space
521- Add a Kconfig option to disable vidconsole support to save code / data space
522- Support both graphical and text menus at the same time on different devices
Simon Glassb5c8fea2023-01-06 08:52:43 -0600523- Support unicode
524- Support curses for proper serial-terminal menus
Simon Glass82cafee2023-06-01 10:23:01 -0600525- Add support for large menus which need to scroll
Simon Glasseb6c71b2023-08-14 16:40:37 -0600526- Update expo.py tool to check for overlapping names and CMOS locations
Simon Glassb5c8fea2023-01-06 08:52:43 -0600527
528.. Simon Glass <sjg@chromium.org>
529.. 7-Oct-22