1
0
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:
Ondrej Jirman
2024-03-28 20:39:07 +01:00
parent 4ff207710b
commit 0fadd1906a

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+ // 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 <common.h>
#include <bootflow.h> #include <bootflow.h>
@@ -14,6 +14,10 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <video_font_8x16.h> #include <video_font_8x16.h>
#include <touchpanel.h> #include <touchpanel.h>
#include <led.h>
#include <button.h>
#include <sysreset.h>
#include <cli.h>
#define VIDEO_FONT_HEIGHT 16 #define VIDEO_FONT_HEIGHT 16
#define VIDEO_FONT_WIDTH 8 #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) static void painter_line_h(struct painter* p, int dx, u32 color)
{ {
if (dx < 0) { 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) static void painter_line_v(struct painter* p, int dy, u32 color)
{ {
if (dy < 0) { 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); painter_move_dxy(p, VIDEO_FONT_WIDTH * 2, 0);
} }
__maybe_unused
static void painter_char(struct painter* p, char ch, u32 color) static void painter_char(struct painter* p, char ch, u32 color)
{ {
int i, row; int i, row;
@@ -368,6 +375,11 @@ struct tmenu_boot_item {
int action; 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[]) static int do_tmenu_bootflow(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{ {
struct udevice *vdev, *tdev, *cdev; struct udevice *vdev, *tdev, *cdev;
@@ -390,6 +402,8 @@ start_again:
struct tmenu_boot_item items[64] = {}; struct tmenu_boot_item items[64] = {};
int n_items = 0; int n_items = 0;
int bmp_loaded = 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; struct bootflow *bflow;
for (ret = bootflow_first_glob(&bflow); !ret; ret = bootflow_next_glob(&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) if (cfg->bmp && !bmp_loaded && get_pxe_file(ctx, cfg->bmp, image_load_addr) == 1)
bmp_loaded = 1; bmp_loaded = 1;
if (timeout < cfg->timeout)
timeout = cfg->timeout;
struct list_head *pos; struct list_head *pos;
list_for_each(pos, &cfg->labels) { list_for_each(pos, &cfg->labels) {
struct pxe_label *label = list_entry(pos, struct pxe_label, list); struct pxe_label *label = list_entry(pos, struct pxe_label, list);
struct tmenu_boot_item *it = &items[n_items++]; 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); //printf("label %s - %s %s\n", label->num, label->name, label->menu);
it->id = n_items; it->id = n_items;
@@ -550,8 +571,8 @@ start_again:
i->y = top + row * (gap + item_h); i->y = top + row * (gap + item_h);
i->w = item_w; i->w = item_w;
i->h = item_h; i->h = item_h;
i->fill = 0xff755f10; i->fill = MENU_COLOR_INACTIVE;
i->text_color = 0xffffffff; i->text_color = MENU_COLOR_TEXT;
i->id = idx; i->id = idx;
snprintf(i->text, sizeof i->text, "%s", items[idx].label); snprintf(i->text, sizeof i->text, "%s", items[idx].label);
@@ -561,6 +582,7 @@ start_again:
int selected = -1; int selected = -1;
int redraw = 1; int redraw = 1;
int highlighted = autoselect >= 0 ? autoselect : 0;
ret = touchpanel_start(tdev); ret = touchpanel_start(tdev);
if (ret < 0) { if (ret < 0) {
@@ -568,8 +590,68 @@ start_again:
goto out_restore_console; 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: next:
while (1) { 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) { if (redraw) {
ui_draw(ui_items, n_items, &p); ui_draw(ui_items, n_items, &p);
video_sync(vdev, true); video_sync(vdev, true);
@@ -586,7 +668,11 @@ next:
break; 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++) { for (int idx = 0; idx < ret; idx++) {
int tx = touches[idx].x; int tx = touches[idx].x;
int ty = touches[idx].y; int ty = touches[idx].y;
@@ -594,12 +680,13 @@ next:
struct ui_item* hit = ui_hit_find(ui_items, n_items, tx, ty); struct ui_item* hit = ui_hit_find(ui_items, n_items, tx, ty);
if (hit) { if (hit) {
selected = hit->id; selected = hit->id;
hit->fill = 0xffb19019; hit->fill = MENU_COLOR_CHOSEN;
redraw = 1; redraw = 1;
goto next; goto next;
} }
} }
// final selection processing
if (selected != -1) { if (selected != -1) {
struct tmenu_boot_item *it = &items[selected]; struct tmenu_boot_item *it = &items[selected];
@@ -639,7 +726,7 @@ next:
} }
} }
out_stop_touch: //out_stop_touch:
ret = touchpanel_stop(tdev); ret = touchpanel_stop(tdev);
if (ret < 0) if (ret < 0)
printf("Failed to stop %s, err=%d\n", tdev->name, ret); printf("Failed to stop %s, err=%d\n", tdev->name, ret);