[Concept,v2,5/9] video: Add a write subcommand

Message ID 20251002154554.4129220-6-sjg@u-boot.org
State New
Headers
Series video: Tidy up embedded graphical images |

Commit Message

Simon Glass Oct. 2, 2025, 3:45 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

This allows writing strings at particular positions on the display,
using either character or pixel positions.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
Suggested-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
---

(no changes since v1)

 cmd/video.c             | 62 +++++++++++++++++++++++++++++++++++++++--
 doc/usage/cmd/video.rst | 45 ++++++++++++++++++++++++------
 test/dm/video.c         |  9 ++++++
 3 files changed, 105 insertions(+), 11 deletions(-)
  

Patch

diff --git a/cmd/video.c b/cmd/video.c
index 9f3a91959df..503433b9a63 100644
--- a/cmd/video.c
+++ b/cmd/video.c
@@ -47,6 +47,59 @@  static int do_video_puts(struct cmd_tbl *cmdtp, int flag, int argc,
 	return ret ? CMD_RET_FAILURE : 0;
 }
 
+static int do_video_write(struct cmd_tbl *cmdtp, int flag, int argc,
+			  char *const argv[])
+{
+	struct vidconsole_priv *priv;
+	bool use_pixels = false;
+	struct udevice *dev;
+	int ret, i;
+
+	if (argc < 3)
+		return CMD_RET_USAGE;
+
+	if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev))
+		return CMD_RET_FAILURE;
+	priv = dev_get_uclass_priv(dev);
+
+	/* Check for -p flag */
+	if (!strcmp(argv[1], "-p")) {
+		use_pixels = true;
+		argc--;
+		argv++;
+	}
+
+	if (argc < 3 || !(argc % 2))
+		return CMD_RET_USAGE;
+
+	for (i = 1; i < argc; i += 2) {
+		uint col, row;
+		char *pos = argv[i];
+		char *colon = strchr(pos, ':');
+
+		if (!colon)
+			return CMD_RET_USAGE;
+
+		col = hextoul(pos, NULL);
+		row = hextoul(colon + 1, NULL);
+
+		if (use_pixels)
+			vidconsole_set_cursor_pos(dev, col, row);
+		else
+			vidconsole_position_cursor(dev, col, row);
+
+		ret = vidconsole_put_string(dev, argv[i + 1]);
+		if (ret)
+			return CMD_RET_FAILURE;
+	}
+
+	ret = video_sync(dev->parent, false);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	return 0;
+}
+
 U_BOOT_CMD(
 	setcurs, 3,	1,	do_video_setcursor,
 	"set cursor position within screen",
@@ -60,9 +113,12 @@  U_BOOT_CMD(
 );
 
 U_BOOT_LONGHELP(video,
-	"setcursor <col> <row> - Set cursor position\n"
-	"video puts <string>         - Write string at current position");
+	"setcursor <col> <row>                - Set cursor position\n"
+	"video puts <string>                        - Write string at current position\n"
+	"video write [-p] [<col>:<row> <string>]... - Write strings at specified positions\n"
+	"         -p: Use pixel coordinates instead of character positions");
 
 U_BOOT_CMD_WITH_SUBCMDS(video, "Video commands", video_help_text,
 	U_BOOT_SUBCMD_MKENT(setcursor, 3, 1, do_video_setcursor),
-	U_BOOT_SUBCMD_MKENT(puts, 2, 1, do_video_puts));
+	U_BOOT_SUBCMD_MKENT(puts, 2, 1, do_video_puts),
+	U_BOOT_SUBCMD_MKENT(write, CONFIG_SYS_MAXARGS, 1, do_video_write));
diff --git a/doc/usage/cmd/video.rst b/doc/usage/cmd/video.rst
index 1e7c7f0c050..288260bd979 100644
--- a/doc/usage/cmd/video.rst
+++ b/doc/usage/cmd/video.rst
@@ -13,18 +13,13 @@  Synopsis
 
     video setcursor <col> <row>
     video puts <string>
+    video write [<col>:<row> <string>]...
 
 Description
 -----------
 
-The video command provides access to the video-console subsystem.
-
-video setcursor
-~~~~~~~~~~~~~~~
-
-    video setcursor <col> <row>
-
-Set the cursor position on the video console.
+The video command provides access to the video-console subsystem. Common
+arguments are as follows:
 
 col
     Column position in hex, with 0 being the left side. Note that this is the
@@ -36,6 +31,13 @@  row
     text-row position, so the number of pixels per position depends on the
     font size.
 
+video setcursor
+~~~~~~~~~~~~~~~
+
+    video setcursor <col> <row>
+
+Set the cursor position on the video console.
+
 video puts
 ~~~~~~~~~~
 
@@ -46,6 +48,24 @@  Write a string to the video console at the current cursor position.
 string
     Text string to display
 
+video write
+~~~~~~~~~~~
+
+    video write [-p] [<col>:<row> <string>]...
+
+Write one or more strings to the video console at specified positions. Each
+position/string pair sets the cursor to the specified location and writes the
+string. Multiple position/string pairs can be provided to write to multiple
+locations in a single command.
+
+-p
+    Use pixel coordinates instead of character positions. When specified, the
+    col and row values are interpreted as pixel offsets and converted to
+    character positions based on the current font size.
+
+string
+    Text string to display at the specified position
+
 Examples
 --------
 
@@ -61,6 +81,15 @@  Print at different positions::
     => video setcursor 0 10
     => video puts "Line 16"
 
+Write text at multiple positions::
+
+    => video write 0:0 "Top left" 0:a "Line 10"
+    => video write 0:a "First column in line10" 2a:0 "Text column 42"
+
+Write text using pixel coordinates::
+
+    => video write -p 0:0 "Top left corner" a0:80 "Pixel position"
+
 Configuration
 -------------
 
diff --git a/test/dm/video.c b/test/dm/video.c
index af305e60268..598e71411f5 100644
--- a/test/dm/video.c
+++ b/test/dm/video.c
@@ -1102,6 +1102,15 @@  static int dm_test_video_cmd(struct unit_test_state *uts)
 	ut_asserteq(272, video_compress_fb(uts, dev, false));
 	ut_assertok(video_check_copy_fb(uts, dev));
 
+	ut_assertok(run_command(
+		"video write 14:6 \"Multi\" 19:7 \"Write\"", 0));
+	ut_asserteq(381, video_compress_fb(uts, dev, false));
+	ut_assertok(video_check_copy_fb(uts, dev));
+
+	ut_assertok(run_command("video write -p a3:34 \"Pixels\"", 0));
+	ut_asserteq(440, video_compress_fb(uts, dev, false));
+	ut_assertok(video_check_copy_fb(uts, dev));
+
 	return 0;
 }
 DM_TEST(dm_test_video_cmd, UTF_SCAN_PDATA | UTF_SCAN_FDT);