mirror of
https://xff.cz/git/u-boot/
synced 2025-08-31 16:22:36 +02:00
cmd: tmenu: Add extlinux timeout support and button controls
This commit is contained in:
99
cmd/tmenu.c
99
cmd/tmenu.c
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2018 Ondrej Jirman <megous@megous.com>
|
||||
* Copyright (C) 2018-2024 Ondrej Jirman <megous@megous.com>
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <bootflow.h>
|
||||
@@ -14,6 +14,10 @@
|
||||
#include <linux/delay.h>
|
||||
#include <video_font_8x16.h>
|
||||
#include <touchpanel.h>
|
||||
#include <led.h>
|
||||
#include <button.h>
|
||||
#include <sysreset.h>
|
||||
#include <cli.h>
|
||||
|
||||
#define VIDEO_FONT_HEIGHT 16
|
||||
#define VIDEO_FONT_WIDTH 8
|
||||
@@ -60,6 +64,7 @@ static void painter_rect_fill(struct painter* p, uint w, uint h, u32 color)
|
||||
}
|
||||
}
|
||||
|
||||
__maybe_unused
|
||||
static void painter_line_h(struct painter* p, int dx, u32 color)
|
||||
{
|
||||
if (dx < 0) {
|
||||
@@ -71,6 +76,7 @@ static void painter_line_h(struct painter* p, int dx, u32 color)
|
||||
}
|
||||
}
|
||||
|
||||
__maybe_unused
|
||||
static void painter_line_v(struct painter* p, int dy, u32 color)
|
||||
{
|
||||
if (dy < 0) {
|
||||
@@ -107,6 +113,7 @@ static void painter_bigchar(struct painter* p, char ch, u32 color)
|
||||
painter_move_dxy(p, VIDEO_FONT_WIDTH * 2, 0);
|
||||
}
|
||||
|
||||
__maybe_unused
|
||||
static void painter_char(struct painter* p, char ch, u32 color)
|
||||
{
|
||||
int i, row;
|
||||
@@ -368,6 +375,11 @@ struct tmenu_boot_item {
|
||||
int action;
|
||||
};
|
||||
|
||||
#define MENU_COLOR_CHOSEN 0xff15801Fu
|
||||
#define MENU_COLOR_HIGHLIGHT 0xffb19019u
|
||||
#define MENU_COLOR_INACTIVE 0xff755f10u
|
||||
#define MENU_COLOR_TEXT 0xffffffffu
|
||||
|
||||
static int do_tmenu_bootflow(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
struct udevice *vdev, *tdev, *cdev;
|
||||
@@ -390,6 +402,8 @@ start_again:
|
||||
struct tmenu_boot_item items[64] = {};
|
||||
int n_items = 0;
|
||||
int bmp_loaded = 0;
|
||||
int timeout = 0; // 0 = no timeout, >0 number of 0.1s to wait
|
||||
int autoselect = -1; // which item is autoselected by extlinux.conf (for timeout)
|
||||
|
||||
struct bootflow *bflow;
|
||||
for (ret = bootflow_first_glob(&bflow); !ret; ret = bootflow_next_glob(&bflow)) {
|
||||
@@ -420,11 +434,18 @@ start_again:
|
||||
if (cfg->bmp && !bmp_loaded && get_pxe_file(ctx, cfg->bmp, image_load_addr) == 1)
|
||||
bmp_loaded = 1;
|
||||
|
||||
if (timeout < cfg->timeout)
|
||||
timeout = cfg->timeout;
|
||||
|
||||
struct list_head *pos;
|
||||
list_for_each(pos, &cfg->labels) {
|
||||
struct pxe_label *label = list_entry(pos, struct pxe_label, list);
|
||||
struct tmenu_boot_item *it = &items[n_items++];
|
||||
|
||||
// select default option for boot
|
||||
if (autoselect < 0 && label->name && cfg->default_label && !strcmp(label->name, cfg->default_label))
|
||||
autoselect = n_items - 1;
|
||||
|
||||
//printf("label %s - %s %s\n", label->num, label->name, label->menu);
|
||||
|
||||
it->id = n_items;
|
||||
@@ -550,8 +571,8 @@ start_again:
|
||||
i->y = top + row * (gap + item_h);
|
||||
i->w = item_w;
|
||||
i->h = item_h;
|
||||
i->fill = 0xff755f10;
|
||||
i->text_color = 0xffffffff;
|
||||
i->fill = MENU_COLOR_INACTIVE;
|
||||
i->text_color = MENU_COLOR_TEXT;
|
||||
i->id = idx;
|
||||
|
||||
snprintf(i->text, sizeof i->text, "%s", items[idx].label);
|
||||
@@ -561,6 +582,7 @@ start_again:
|
||||
|
||||
int selected = -1;
|
||||
int redraw = 1;
|
||||
int highlighted = autoselect >= 0 ? autoselect : 0;
|
||||
|
||||
ret = touchpanel_start(tdev);
|
||||
if (ret < 0) {
|
||||
@@ -568,8 +590,68 @@ start_again:
|
||||
goto out_restore_console;
|
||||
}
|
||||
|
||||
struct udevice *led_g = NULL, *led_r = NULL, *led_b = NULL;
|
||||
uclass_get_device_by_name(UCLASS_LED, "led-red", &led_r);
|
||||
uclass_get_device_by_name(UCLASS_LED, "led-green", &led_g);
|
||||
uclass_get_device_by_name(UCLASS_LED, "led-blue", &led_b);
|
||||
|
||||
enum { VOL_UP, VOL_DOWN, POWER };
|
||||
struct btn { struct udevice *dev; int prev; int cur; int press; int release; } btns[3] = {};
|
||||
button_get_by_label("Volume Up", &btns[VOL_UP].dev);
|
||||
button_get_by_label("Volume Down", &btns[VOL_DOWN].dev);
|
||||
button_get_by_label("Power", &btns[POWER].dev);
|
||||
|
||||
int cycles = 0;
|
||||
next:
|
||||
while (1) {
|
||||
for (int i = 0; i < ARRAY_SIZE(btns); i++) {
|
||||
struct btn* b = &btns[i];
|
||||
b->prev = b->cur;
|
||||
b->cur = b->dev && button_get_state(b->dev) == BUTTON_ON;
|
||||
b->press = b->cur && !b->prev;
|
||||
b->release = !b->cur && b->prev;
|
||||
|
||||
// any button press cancels the timeout
|
||||
if (b->cur)
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
// menu up/down navigation feedback
|
||||
if (btns[VOL_UP].press) {
|
||||
highlighted--;
|
||||
if (highlighted < 0)
|
||||
highlighted = n_items - 1;
|
||||
redraw = true;
|
||||
} else if (btns[VOL_DOWN].press) {
|
||||
highlighted = (highlighted + 1) % n_items;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if (redraw)
|
||||
for (int i = 0; i < n_items; i++)
|
||||
ui_items[i].fill = i == highlighted ? MENU_COLOR_HIGHLIGHT : MENU_COLOR_INACTIVE;
|
||||
|
||||
// power button press
|
||||
if (btns[POWER].press) {
|
||||
ui_items[highlighted].fill = MENU_COLOR_CHOSEN;
|
||||
redraw = true;
|
||||
if (led_g)
|
||||
led_set_state(led_g, LEDST_ON);
|
||||
} else if (btns[POWER].release) {
|
||||
selected = highlighted;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
// handle autoselect timeout
|
||||
if (autoselect >= 0 && timeout > 0 && timeout == cycles / 2) {
|
||||
selected = autoselect;
|
||||
ui_items[selected].fill = MENU_COLOR_CHOSEN;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
cycles++;
|
||||
|
||||
// UI drawing
|
||||
if (redraw) {
|
||||
ui_draw(ui_items, n_items, &p);
|
||||
video_sync(vdev, true);
|
||||
@@ -586,7 +668,11 @@ next:
|
||||
break;
|
||||
}
|
||||
|
||||
/* find first matching tap down */
|
||||
// cancel timeout on touch
|
||||
if (ret > 0)
|
||||
timeout = 0;
|
||||
|
||||
// find first matching tap down
|
||||
for (int idx = 0; idx < ret; idx++) {
|
||||
int tx = touches[idx].x;
|
||||
int ty = touches[idx].y;
|
||||
@@ -594,12 +680,13 @@ next:
|
||||
struct ui_item* hit = ui_hit_find(ui_items, n_items, tx, ty);
|
||||
if (hit) {
|
||||
selected = hit->id;
|
||||
hit->fill = 0xffb19019;
|
||||
hit->fill = MENU_COLOR_CHOSEN;
|
||||
redraw = 1;
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
// final selection processing
|
||||
if (selected != -1) {
|
||||
struct tmenu_boot_item *it = &items[selected];
|
||||
|
||||
@@ -639,7 +726,7 @@ next:
|
||||
}
|
||||
}
|
||||
|
||||
out_stop_touch:
|
||||
//out_stop_touch:
|
||||
ret = touchpanel_stop(tdev);
|
||||
if (ret < 0)
|
||||
printf("Failed to stop %s, err=%d\n", tdev->name, ret);
|
||||
|
Reference in New Issue
Block a user