blob: f13761995d3f4446f8bc1f99ba5a1a5f8b37fa22 [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
66All components have a name. This is purely for debugging, so it is easy to see
67what object is referred to. Of course the ID numbers can help as well, but they
68are less easy to distinguish.
69
70While the expo implementation provides support for handling keypresses and
71rendering on the display or serial port, it does not actually deal with reading
72input from the user, nor what should be done when a particular menu item is
73selected. This is deliberate since having the event loop outside the expo is
74more flexible, particularly in a single-threaded environment like U-Boot.
75
76Everything within an expo has a unique ID number. This is done so that it is
77easy to refer to things after the expo has been created. The expectation is that
78the controller declares an enum containing all of the elements in the expo,
79passing the ID of each object as it is created. When a menu item is selected,
80its ID is returned. When a object's font or position needs to change, the ID is
81passed to expo functions to indicate which object it is. It is possible for expo
82to auto-allocate IDs, but this is not recommended. The use of IDs is a
83convenience, removing the need for the controller to store pointers to objects,
84or even the IDs of objects. Programmatic creation of many items in a loop can be
85handled by allocating space in the enum for a maximum number of items, then
86adding the loop count to the enum values to obtain unique IDs.
87
Simon Glass9af34152023-06-01 10:22:47 -060088Where dynamic IDs are need, use expo_set_dynamic_start() to set the start value,
89so that they are allocated above the starting (enum) IDs.
90
Simon Glassb5c8fea2023-01-06 08:52:43 -060091All text strings are stored in a structure attached to the expo, referenced by
92a text ID. This makes it easier at some point to implement multiple languages or
93to support Unicode strings.
94
95Menu objects do not have their own text and image objects. Instead they simply
96refer to objects which have been created. So a menu item is just a collection
97of IDs of text and image objects. When adding a menu item you must create these
98objects first, then create the menu item, passing in the relevant IDs.
99
100Creating an expo
101----------------
102
Simon Glass82cafee2023-06-01 10:23:01 -0600103To create an expo programmatically, use `expo_new()` followed by `scene_new()`
104to create a scene. Then add objects to the scene, using functions like
105`scene_txt_str()` and `scene_menu()`. For every menu item, add text and image
106objects, then create the menu item with `scene_menuitem()`, referring to those
107objects.
108
109To create an expo using a description file, see :ref:`expo_format` below.
Simon Glassb5c8fea2023-01-06 08:52:43 -0600110
111Layout
112------
113
114Individual objects can be positioned using `scene_obj_set_pos()`. Menu items
115cannot be positioned manually: this is done by `scene_arrange()` which is called
116automatically when something changes. The menu itself determines the position of
117its items.
118
119Rendering
120---------
121
122Rendering is performed by calling `expo_render()`. This uses either the
123vidconsole, if present, or the serial console in `text mode`. Expo handles
124presentation automatically in either case, without any change in how the expo is
125created.
126
127For the vidconsole, Truetype fonts can be used if enabled, to enhance the
128quality of the display. For text mode, each menu item is shown in a single line,
129allowing easy selection using arrow keys.
130
131Input
132-----
133
134The controller is responsible for collecting keyboard input. A good way to do
135this is to use `cli_ch_process()`, since it handles conversion of escape
136sequences into keys. However, expo has some special menu-key codes for
137navigating the interface. These are defined in `enum bootmenu_key` and include
138`BKEY_UP` for moving up and `BKEY_SELECT` for selecting an item. You can use
139`bootmenu_conv_key()` to convert an ASCII key into one of these.
140
141Once a keypress is decoded, call `expo_send_key()` to send it to the expo. This
142may cause an update to the expo state and may produce an action.
143
144Actions
145-------
146
147Call `expo_action_get()` in the event loop to check for any actions that the
148expo wants to report. These can include selecting a particular menu item, or
149quitting the menu. Processing of these is the responsibility of your controller.
150
151Event loop
152----------
153
154Expo is intended to be used in an event loop. For an example loop, see
155`bootflow_menu_run()`. It is possible to perform other work in your event loop,
156such as scanning devices for more bootflows.
157
158Themes
159------
160
Simon Glass2e593892023-06-01 10:22:53 -0600161Expo supports simple themes, for setting the font size, for example. Use the
162expo_apply_theme() function to load a theme, passing a node with the required
163properties:
164
165font-size
166 Font size to use for all text (type: u32)
167
Simon Glass7230fdb2023-06-01 10:23:00 -0600168menu-inset
169 Number of pixels to inset the menu on the sides and top (type: u32)
170
171menuitem-gap-y
172 Number of pixels between menu items
173
Simon Glass82cafee2023-06-01 10:23:01 -0600174Pop-up mode
175-----------
176
177Expos support two modes. The simple mode is used for selecting from a single
178menu, e.g. when choosing with OS to boot. In this mode the menu items are shown
179in a list (label, > pointer, key and description) and can be chosen using arrow
180keys and enter::
181
182 U-Boot Boot Menu
183
184 UP and DOWN to choose, ENTER to select
185
186 mmc1 > 0 Fedora-Workstation-armhfp-31-1.9
187 mmc3 1 Armbian
188
189The popup mode allows multiple menus to be present in a scene. Each is shown
190just as its title and label, as with the `CPU Speed` and `AC Power` menus here::
191
192 Test Configuration
193
194
195 CPU Speed <2 GHz> (highlighted)
196
197 AC Power Always Off
198
199
200 UP and DOWN to choose, ENTER to select
201
202
Simon Glassa0874dc2023-06-01 10:23:02 -0600203.. _expo_format:
204
Simon Glass82cafee2023-06-01 10:23:01 -0600205Expo Format
206-----------
207
208It can be tedious to create a complex expo using code. Expo supports a
209data-driven approach, where the expo description is in a devicetree file. This
210makes it easier and faster to create and edit the description. An expo builder
211is provided to convert this format into an expo structure.
212
213Layout of the expo scenes is handled automatically, based on a set of simple
Simon Glassa0874dc2023-06-01 10:23:02 -0600214rules. The :doc:`../usage/cmd/cedit` can be used to load a configuration
215and create an expo from it.
Simon Glass82cafee2023-06-01 10:23:01 -0600216
217Top-level node
218~~~~~~~~~~~~~~
219
220The top-level node has the following properties:
221
222dynamic-start
223 type: u32, optional
224
225 Specifies the start of the dynamically allocated objects. This results in
226 a call to expo_set_dynamic_start().
227
228The top-level node has the following subnodes:
229
230scenes
231 Specifies the scenes in the expo, each one being a subnode
232
233strings
234 Specifies the strings in the expo, each one being a subnode
235
236`scenes` node
237~~~~~~~~~~~~~
238
239Contains a list of scene subnodes. The name of each subnode is passed as the
240name to `scene_new()`.
241
242`strings` node
243~~~~~~~~~~~~~~
244
245Contains a list of string subnodes. The name of each subnode is ignored.
246
247`strings` subnodes
248~~~~~~~~~~~~~~~~~~
249
250Each subnode defines a string which can be used by scenes and objects. Each
251string has an ID number which is used to refer to it.
252
253The `strings` subnodes have the following properties:
254
255id
256 type: u32, required
257
258 Specifies the ID number for the string.
259
260value:
261 type: string, required
262
263 Specifies the string text. For now only a single value is supported. Future
264 work may add support for multiple languages by using a value for each
265 language.
266
267Scene nodes (`scenes` subnodes)
268~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
269
270Each subnode of the `scenes` node contains a scene description.
271
272Most properties can use either a string or a string ID. For example, a `title`
273property can be used to provide the title for a menu; alternatively a `title-id`
274property can provide the string ID of the title. If both are present, the
275ID takes preference, except that if a string with that ID does not exist, it
276falls back to using the string from the property (`title` in this example). The
277description below shows these are alternative properties with the same
278description.
279
280The scene nodes have the following properties:
281
282id
283 type: u32, required
284
285 Specifies the ID number for the string.
286
287title / title-id
288 type: string / u32, required
289
290 Specifies the title of the scene. This is shown at the top of the scene.
291
292prompt / prompt-id
293 type: string / u32, required
294
295 Specifies a prompt for the scene. This is shown at the bottom of the scene.
296
297The scene nodes have a subnode for each object in the scene.
298
299Object nodes
300~~~~~~~~~~~~
301
302The object-node name is used as the name of the object, e.g. when calling
303`scene_menu()` to create a menu.
304
305Object nodes have the following common properties:
306
307type
308 type: string, required
309
310 Specifies the type of the object. Valid types are:
311
312 "menu"
313 Menu containing items which can be selected by the user
314
315id
316 type: u32, required
317
318 Specifies the ID of the object. This is used when referring to the object.
319
Simon Glasseb6c71b2023-08-14 16:40:37 -0600320Where CMOS RAM is used for reading and writing settings, the following
321additional properties are required:
322
323start-bit
324 Specifies the first bit in the CMOS RAM to use for this setting. For a RAM
325 with 0x100 bytes, there are 0x800 bit locations. For example, register 0x80
326 holds bits 0x400 to 0x407.
327
328bit-length
329 Specifies the number of CMOS RAM bits to use for this setting. The bits
330 extend from `start-bit` to `start-bit + bit-length - 1`. Note that the bits
331 must be contiguous.
Simon Glass82cafee2023-06-01 10:23:01 -0600332
333Menu nodes have the following additional properties:
334
335title / title-id
336 type: string / u32, required
337
338 Specifies the title of the menu. This is shown to the left of the area for
339 this menu.
340
341item-id
342 type: u32 list, required
343
344 Specifies the ID for each menu item. These are used for checking which item
345 has been selected.
346
347item-label / item-label-id
348 type: string list / u32 list, required
349
350 Specifies the label for each item in the menu. These are shown to the user.
351 In 'popup' mode these form the items in the menu.
352
353key-label / key-label-id
354 type: string list / u32 list, optional
355
356 Specifies the key for each item in the menu. These are currently only
357 intended for use in simple mode.
358
359desc-label / desc-label-id
360 type: string list / u32 list, optional
361
362 Specifies the description for each item in the menu. These are currently
363 only intended for use in simple mode.
364
365
366Expo layout
367~~~~~~~~~~~
368
369The `expo_arrange()` function can be called to arrange the expo objects in a
370suitable manner. For each scene it puts the title at the top, the prompt at the
371bottom and the objects in order from top to bottom.
372
Simon Glassc5aacf52023-08-14 16:40:29 -0600373
374.. _expo_example:
375
Simon Glass82cafee2023-06-01 10:23:01 -0600376Expo format example
377~~~~~~~~~~~~~~~~~~~
378
379This example shows an expo with a single scene consisting of two menus. The
380scene title is specified using a string from the strings table, but all other
381strings are provided inline in the nodes where they are used.
382
383::
384
Simon Glassd5737b32023-08-14 16:40:28 -0600385 /* this comment is parsed by the expo.py tool to insert the values below
Simon Glass82cafee2023-06-01 10:23:01 -0600386
Simon Glassd5737b32023-08-14 16:40:28 -0600387 enum {
388 ZERO,
389 ID_PROMPT,
390 ID_SCENE1,
391 ID_SCENE1_TITLE,
Simon Glass82cafee2023-06-01 10:23:01 -0600392
Simon Glassd5737b32023-08-14 16:40:28 -0600393 ID_CPU_SPEED,
394 ID_CPU_SPEED_TITLE,
395 ID_CPU_SPEED_1,
396 ID_CPU_SPEED_2,
397 ID_CPU_SPEED_3,
Simon Glass82cafee2023-06-01 10:23:01 -0600398
Simon Glassd5737b32023-08-14 16:40:28 -0600399 ID_POWER_LOSS,
400 ID_AC_OFF,
401 ID_AC_ON,
402 ID_AC_MEMORY,
403
404 ID_DYNAMIC_START,
405 */
Simon Glass82cafee2023-06-01 10:23:01 -0600406
407 &cedit {
408 dynamic-start = <ID_DYNAMIC_START>;
409
410 scenes {
411 main {
412 id = <ID_SCENE1>;
413
414 /* value refers to the matching id in /strings */
415 title-id = <ID_SCENE1_TITLE>;
416
417 /* simple string is used as it is */
418 prompt = "UP and DOWN to choose, ENTER to select";
419
420 /* defines a menu within the scene */
421 cpu-speed {
422 type = "menu";
423 id = <ID_CPU_SPEED>;
424
425 /*
426 * has both string and ID. The string is ignored
427 * if the ID is present and points to a string
428 */
429 title = "CPU speed";
430 title-id = <ID_CPU_SPEED_TITLE>;
431
432 /* menu items as simple strings */
433 item-label = "2 GHz", "2.5 GHz", "3 GHz";
434
435 /* IDs for the menu items */
436 item-id = <ID_CPU_SPEED_1 ID_CPU_SPEED_2
437 ID_CPU_SPEED_3>;
438 };
439
440 power-loss {
441 type = "menu";
442 id = <ID_POWER_LOSS>;
443
444 title = "AC Power";
445 item-label = "Always Off", "Always On",
446 "Memory";
447
448 item-id = <ID_AC_OFF ID_AC_ON ID_AC_MEMORY>;
449 };
450 };
451 };
452
453 strings {
454 title {
455 id = <ID_SCENE1_TITLE>;
456 value = "Test Configuration";
457 value-es = "configuraciĆ³n de prueba";
458 };
459 };
460 };
461
Simon Glassb5c8fea2023-01-06 08:52:43 -0600462
463API documentation
464-----------------
465
466.. kernel-doc:: include/expo.h
467
468Future ideas
469------------
470
471Some ideas for future work:
472
473- Default menu item and a timeout
Simon Glassb5c8fea2023-01-06 08:52:43 -0600474- Image formats other than BMP
475- Use of ANSI sequences to control a serial terminal
476- Colour selection
Simon Glass82cafee2023-06-01 10:23:01 -0600477- Support for more widgets, e.g. text, numeric, radio/option
Simon Glassb5c8fea2023-01-06 08:52:43 -0600478- Mouse support
479- Integrate Nuklear, NxWidgets or some other library for a richer UI
480- Optimise rendering by only updating the display with changes since last render
481- Use expo to replace the existing menu implementation
482- Add a Kconfig option to drop the names to save code / data space
483- Add a Kconfig option to disable vidconsole support to save code / data space
484- Support both graphical and text menus at the same time on different devices
Simon Glassb5c8fea2023-01-06 08:52:43 -0600485- Support unicode
486- Support curses for proper serial-terminal menus
Simon Glass82cafee2023-06-01 10:23:01 -0600487- Add support for large menus which need to scroll
Simon Glasseb6c71b2023-08-14 16:40:37 -0600488- Update expo.py tool to check for overlapping names and CMOS locations
Simon Glassb5c8fea2023-01-06 08:52:43 -0600489
490.. Simon Glass <sjg@chromium.org>
491.. 7-Oct-22