blob: cc7c36173dbe929f77a87f040f3deacbf2eb8a97 [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 Glassd8ff97c2024-10-14 16:31:57 -060091Some standard IDs are reserved for certain purposes. These are defined by
92`enum expo_id_t` and start at 1. `EXPOID_BASE_ID` defines the first ID which
93can be used for an expo.
94
95An ID of 0 is invalid. If this is specified in an expo call then a valid
96'dynamic IDs is allocated. Use expo_set_dynamic_start() to set the start
97value, so that they are allocated above the starting (enum) IDs.
Simon Glass9af34152023-06-01 10:22:47 -060098
Simon Glassb5c8fea2023-01-06 08:52:43 -060099All text strings are stored in a structure attached to the expo, referenced by
100a text ID. This makes it easier at some point to implement multiple languages or
101to support Unicode strings.
102
103Menu objects do not have their own text and image objects. Instead they simply
104refer to objects which have been created. So a menu item is just a collection
105of IDs of text and image objects. When adding a menu item you must create these
106objects first, then create the menu item, passing in the relevant IDs.
107
108Creating an expo
109----------------
110
Simon Glass82cafee2023-06-01 10:23:01 -0600111To create an expo programmatically, use `expo_new()` followed by `scene_new()`
112to create a scene. Then add objects to the scene, using functions like
113`scene_txt_str()` and `scene_menu()`. For every menu item, add text and image
114objects, then create the menu item with `scene_menuitem()`, referring to those
115objects.
116
117To create an expo using a description file, see :ref:`expo_format` below.
Simon Glassb5c8fea2023-01-06 08:52:43 -0600118
119Layout
120------
121
122Individual objects can be positioned using `scene_obj_set_pos()`. Menu items
123cannot be positioned manually: this is done by `scene_arrange()` which is called
124automatically when something changes. The menu itself determines the position of
125its items.
126
127Rendering
128---------
129
130Rendering is performed by calling `expo_render()`. This uses either the
131vidconsole, if present, or the serial console in `text mode`. Expo handles
132presentation automatically in either case, without any change in how the expo is
133created.
134
135For the vidconsole, Truetype fonts can be used if enabled, to enhance the
136quality of the display. For text mode, each menu item is shown in a single line,
137allowing easy selection using arrow keys.
138
139Input
140-----
141
142The controller is responsible for collecting keyboard input. A good way to do
143this is to use `cli_ch_process()`, since it handles conversion of escape
144sequences into keys. However, expo has some special menu-key codes for
145navigating the interface. These are defined in `enum bootmenu_key` and include
146`BKEY_UP` for moving up and `BKEY_SELECT` for selecting an item. You can use
Simon Glass7e5b6372023-10-01 19:13:40 -0600147`bootmenu_conv_key()` to convert an ASCII key into one of these, but if it
148returns a value >= `BKEY_FIRST_EXTRA` then you should pass the unmodified ASCII
149key to the expo, since it may be used by textline objects.
Simon Glassb5c8fea2023-01-06 08:52:43 -0600150
151Once a keypress is decoded, call `expo_send_key()` to send it to the expo. This
152may cause an update to the expo state and may produce an action.
153
154Actions
155-------
156
157Call `expo_action_get()` in the event loop to check for any actions that the
158expo wants to report. These can include selecting a particular menu item, or
159quitting the menu. Processing of these is the responsibility of your controller.
160
161Event loop
162----------
163
164Expo is intended to be used in an event loop. For an example loop, see
165`bootflow_menu_run()`. It is possible to perform other work in your event loop,
166such as scanning devices for more bootflows.
167
168Themes
169------
170
Simon Glass2e593892023-06-01 10:22:53 -0600171Expo supports simple themes, for setting the font size, for example. Use the
172expo_apply_theme() function to load a theme, passing a node with the required
173properties:
174
175font-size
176 Font size to use for all text (type: u32)
177
Simon Glass7230fdb2023-06-01 10:23:00 -0600178menu-inset
179 Number of pixels to inset the menu on the sides and top (type: u32)
180
181menuitem-gap-y
182 Number of pixels between menu items
183
Simon Glass54eca1d2024-10-14 16:31:55 -0600184menu-title-margin-x
185 Number of pixels between right side of menu title to the left size of the
186 menu labels
187
Simon Glass82cafee2023-06-01 10:23:01 -0600188Pop-up mode
189-----------
190
191Expos support two modes. The simple mode is used for selecting from a single
192menu, e.g. when choosing with OS to boot. In this mode the menu items are shown
193in a list (label, > pointer, key and description) and can be chosen using arrow
194keys and enter::
195
196 U-Boot Boot Menu
197
198 UP and DOWN to choose, ENTER to select
199
200 mmc1 > 0 Fedora-Workstation-armhfp-31-1.9
201 mmc3 1 Armbian
202
203The popup mode allows multiple menus to be present in a scene. Each is shown
204just as its title and label, as with the `CPU Speed` and `AC Power` menus here::
205
206 Test Configuration
207
208
209 CPU Speed <2 GHz> (highlighted)
210
211 AC Power Always Off
212
213
214 UP and DOWN to choose, ENTER to select
215
216
Simon Glassa0874dc2023-06-01 10:23:02 -0600217.. _expo_format:
218
Simon Glass82cafee2023-06-01 10:23:01 -0600219Expo Format
220-----------
221
222It can be tedious to create a complex expo using code. Expo supports a
223data-driven approach, where the expo description is in a devicetree file. This
224makes it easier and faster to create and edit the description. An expo builder
225is provided to convert this format into an expo structure.
226
227Layout of the expo scenes is handled automatically, based on a set of simple
Simon Glassa0874dc2023-06-01 10:23:02 -0600228rules. The :doc:`../usage/cmd/cedit` can be used to load a configuration
229and create an expo from it.
Simon Glass82cafee2023-06-01 10:23:01 -0600230
231Top-level node
232~~~~~~~~~~~~~~
233
234The top-level node has the following properties:
235
236dynamic-start
237 type: u32, optional
238
239 Specifies the start of the dynamically allocated objects. This results in
240 a call to expo_set_dynamic_start().
241
242The top-level node has the following subnodes:
243
244scenes
245 Specifies the scenes in the expo, each one being a subnode
246
247strings
248 Specifies the strings in the expo, each one being a subnode
249
250`scenes` node
251~~~~~~~~~~~~~
252
253Contains a list of scene subnodes. The name of each subnode is passed as the
254name to `scene_new()`.
255
256`strings` node
257~~~~~~~~~~~~~~
258
259Contains a list of string subnodes. The name of each subnode is ignored.
260
261`strings` subnodes
262~~~~~~~~~~~~~~~~~~
263
264Each subnode defines a string which can be used by scenes and objects. Each
265string has an ID number which is used to refer to it.
266
267The `strings` subnodes have the following properties:
268
269id
270 type: u32, required
271
272 Specifies the ID number for the string.
273
274value:
275 type: string, required
276
277 Specifies the string text. For now only a single value is supported. Future
278 work may add support for multiple languages by using a value for each
279 language.
280
281Scene nodes (`scenes` subnodes)
282~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
283
284Each subnode of the `scenes` node contains a scene description.
285
286Most properties can use either a string or a string ID. For example, a `title`
287property can be used to provide the title for a menu; alternatively a `title-id`
288property can provide the string ID of the title. If both are present, the
289ID takes preference, except that if a string with that ID does not exist, it
290falls back to using the string from the property (`title` in this example). The
291description below shows these are alternative properties with the same
292description.
293
294The scene nodes have the following properties:
295
296id
297 type: u32, required
298
299 Specifies the ID number for the string.
300
301title / title-id
302 type: string / u32, required
303
304 Specifies the title of the scene. This is shown at the top of the scene.
305
306prompt / prompt-id
307 type: string / u32, required
308
309 Specifies a prompt for the scene. This is shown at the bottom of the scene.
310
311The scene nodes have a subnode for each object in the scene.
312
313Object nodes
314~~~~~~~~~~~~
315
316The object-node name is used as the name of the object, e.g. when calling
317`scene_menu()` to create a menu.
318
319Object nodes have the following common properties:
320
321type
322 type: string, required
323
324 Specifies the type of the object. Valid types are:
325
326 "menu"
327 Menu containing items which can be selected by the user
328
Simon Glass7e5b6372023-10-01 19:13:40 -0600329 "textline"
330 A line of text which can be edited
331
Simon Glass82cafee2023-06-01 10:23:01 -0600332id
333 type: u32, required
334
335 Specifies the ID of the object. This is used when referring to the object.
336
Simon Glasseb6c71b2023-08-14 16:40:37 -0600337Where CMOS RAM is used for reading and writing settings, the following
338additional properties are required:
339
340start-bit
341 Specifies the first bit in the CMOS RAM to use for this setting. For a RAM
342 with 0x100 bytes, there are 0x800 bit locations. For example, register 0x80
343 holds bits 0x400 to 0x407.
344
345bit-length
346 Specifies the number of CMOS RAM bits to use for this setting. The bits
347 extend from `start-bit` to `start-bit + bit-length - 1`. Note that the bits
348 must be contiguous.
Simon Glass82cafee2023-06-01 10:23:01 -0600349
350Menu nodes have the following additional properties:
351
352title / title-id
353 type: string / u32, required
354
355 Specifies the title of the menu. This is shown to the left of the area for
356 this menu.
357
358item-id
359 type: u32 list, required
360
361 Specifies the ID for each menu item. These are used for checking which item
362 has been selected.
363
Simon Glass012e1e82024-10-14 16:31:58 -0600364item-value
365 type: u32 list, optional
366
367 Specifies the value for each menu item. These are used for saving and
368 loading. If this is omitted the value is its position in the menu (0..n-1).
369 Valid values are positive and negative integers INT_MIN...(INT_MAX - 1).
370
Simon Glass82cafee2023-06-01 10:23:01 -0600371item-label / item-label-id
372 type: string list / u32 list, required
373
374 Specifies the label for each item in the menu. These are shown to the user.
375 In 'popup' mode these form the items in the menu.
376
377key-label / key-label-id
378 type: string list / u32 list, optional
379
380 Specifies the key for each item in the menu. These are currently only
381 intended for use in simple mode.
382
383desc-label / desc-label-id
384 type: string list / u32 list, optional
385
386 Specifies the description for each item in the menu. These are currently
387 only intended for use in simple mode.
388
Simon Glass7e5b6372023-10-01 19:13:40 -0600389Textline nodes have the following additional properties:
390
391label / label-id
392 type: string / u32, required
393
394 Specifies the label of the textline. This is shown to the left of the area
395 for this textline.
396
397edit-id
398 type: u32, required
399
400 Specifies the ID of the of the editable text object. This can be used to
401 obtain the text from the textline
402
403max-chars:
404 type: u32, required
405
406 Specifies the maximum number of characters permitted to be in the textline.
407 The user will be prevented from adding more.
408
Simon Glass82cafee2023-06-01 10:23:01 -0600409
410Expo layout
411~~~~~~~~~~~
412
413The `expo_arrange()` function can be called to arrange the expo objects in a
414suitable manner. For each scene it puts the title at the top, the prompt at the
415bottom and the objects in order from top to bottom.
416
Simon Glassc5aacf52023-08-14 16:40:29 -0600417
418.. _expo_example:
419
Simon Glass82cafee2023-06-01 10:23:01 -0600420Expo format example
421~~~~~~~~~~~~~~~~~~~
422
423This example shows an expo with a single scene consisting of two menus. The
424scene title is specified using a string from the strings table, but all other
425strings are provided inline in the nodes where they are used.
426
427::
428
Simon Glassd5737b32023-08-14 16:40:28 -0600429 /* this comment is parsed by the expo.py tool to insert the values below
Simon Glass82cafee2023-06-01 10:23:01 -0600430
Simon Glassd5737b32023-08-14 16:40:28 -0600431 enum {
Simon Glassd8ff97c2024-10-14 16:31:57 -0600432 ID_PROMPT = EXPOID_BASE_ID,
Simon Glassd5737b32023-08-14 16:40:28 -0600433 ID_SCENE1,
434 ID_SCENE1_TITLE,
Simon Glass82cafee2023-06-01 10:23:01 -0600435
Simon Glassd5737b32023-08-14 16:40:28 -0600436 ID_CPU_SPEED,
437 ID_CPU_SPEED_TITLE,
438 ID_CPU_SPEED_1,
439 ID_CPU_SPEED_2,
440 ID_CPU_SPEED_3,
Simon Glass82cafee2023-06-01 10:23:01 -0600441
Simon Glassd5737b32023-08-14 16:40:28 -0600442 ID_POWER_LOSS,
443 ID_AC_OFF,
444 ID_AC_ON,
445 ID_AC_MEMORY,
446
Simon Glass7e5b6372023-10-01 19:13:40 -0600447 ID_MACHINE_NAME,
448 ID_MACHINE_NAME_EDIT,
449
Simon Glassd5737b32023-08-14 16:40:28 -0600450 ID_DYNAMIC_START,
451 */
Simon Glass82cafee2023-06-01 10:23:01 -0600452
453 &cedit {
454 dynamic-start = <ID_DYNAMIC_START>;
455
456 scenes {
457 main {
458 id = <ID_SCENE1>;
459
460 /* value refers to the matching id in /strings */
461 title-id = <ID_SCENE1_TITLE>;
462
463 /* simple string is used as it is */
464 prompt = "UP and DOWN to choose, ENTER to select";
465
466 /* defines a menu within the scene */
467 cpu-speed {
468 type = "menu";
469 id = <ID_CPU_SPEED>;
470
471 /*
472 * has both string and ID. The string is ignored
473 * if the ID is present and points to a string
474 */
475 title = "CPU speed";
476 title-id = <ID_CPU_SPEED_TITLE>;
477
478 /* menu items as simple strings */
479 item-label = "2 GHz", "2.5 GHz", "3 GHz";
480
481 /* IDs for the menu items */
482 item-id = <ID_CPU_SPEED_1 ID_CPU_SPEED_2
483 ID_CPU_SPEED_3>;
Simon Glass012e1e82024-10-14 16:31:58 -0600484
485 /* values for the menu items */
486 item-value = <(-1) 3 6>;
Simon Glass82cafee2023-06-01 10:23:01 -0600487 };
488
489 power-loss {
490 type = "menu";
491 id = <ID_POWER_LOSS>;
492
493 title = "AC Power";
494 item-label = "Always Off", "Always On",
495 "Memory";
496
497 item-id = <ID_AC_OFF ID_AC_ON ID_AC_MEMORY>;
498 };
Simon Glass7e5b6372023-10-01 19:13:40 -0600499
500 machine-name {
501 id = <ID_MACHINE_NAME>;
502 type = "textline";
503 max-chars = <20>;
504 title = "Machine name";
505 edit-id = <ID_MACHINE_NAME_EDIT>;
Simon Glass82cafee2023-06-01 10:23:01 -0600506 };
507 };
508
509 strings {
510 title {
511 id = <ID_SCENE1_TITLE>;
512 value = "Test Configuration";
513 value-es = "configuraciĆ³n de prueba";
514 };
515 };
516 };
517
Simon Glassb5c8fea2023-01-06 08:52:43 -0600518
519API documentation
520-----------------
521
522.. kernel-doc:: include/expo.h
523
524Future ideas
525------------
526
527Some ideas for future work:
528
529- Default menu item and a timeout
Simon Glassb5c8fea2023-01-06 08:52:43 -0600530- Image formats other than BMP
531- Use of ANSI sequences to control a serial terminal
532- Colour selection
Simon Glass7e5b6372023-10-01 19:13:40 -0600533- Support for more widgets, e.g. numeric, radio/option
Simon Glassb5c8fea2023-01-06 08:52:43 -0600534- Mouse support
535- Integrate Nuklear, NxWidgets or some other library for a richer UI
536- Optimise rendering by only updating the display with changes since last render
537- Use expo to replace the existing menu implementation
538- Add a Kconfig option to drop the names to save code / data space
539- Add a Kconfig option to disable vidconsole support to save code / data space
540- Support both graphical and text menus at the same time on different devices
Simon Glassb5c8fea2023-01-06 08:52:43 -0600541- Support unicode
542- Support curses for proper serial-terminal menus
Simon Glass82cafee2023-06-01 10:23:01 -0600543- Add support for large menus which need to scroll
Simon Glasseb6c71b2023-08-14 16:40:37 -0600544- Update expo.py tool to check for overlapping names and CMOS locations
Simon Glassb5c8fea2023-01-06 08:52:43 -0600545
546.. Simon Glass <sjg@chromium.org>
547.. 7-Oct-22