mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH v2 1/3] commands: edit: factor out getwinsize and export it for reuse
@ 2024-07-01 10:35 Ahmad Fatoum
  2024-07-01 10:35 ` [PATCH v2 2/3] lib: strtox: implement new simple_strtofract Ahmad Fatoum
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Ahmad Fatoum @ 2024-07-01 10:35 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

This function is currently only used by the sedit command, but can be
useful for other "full-screen" commands as well.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
  - no change
---
 commands/edit.c | 85 +++++++------------------------------------------
 include/term.h  |  8 +++++
 lib/Makefile    |  1 +
 lib/term.c      | 69 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 90 insertions(+), 73 deletions(-)
 create mode 100644 include/term.h
 create mode 100644 lib/term.c

diff --git a/commands/edit.c b/commands/edit.c
index dea383aae7a6..893fa0271d83 100644
--- a/commands/edit.c
+++ b/commands/edit.c
@@ -13,6 +13,7 @@
 #include <xfuncs.h>
 #include <linux/stat.h>
 #include <console.h>
+#include <term.h>
 
 #define TABSPACE 8
 
@@ -40,11 +41,6 @@ static struct line *curline;	/* line where the cursor is */
 static struct line *scrline;	/* the first line on screen */
 static int scrcol = 0;		/* the first column on screen */
 
-static void pos(int x, int y)
-{
-	printf("\x1b[%d;%dH", y + 2, x + 1);
-}
-
 static char *screenline(char *line, int *pos)
 {
 	int i, outpos = 0;
@@ -95,10 +91,10 @@ static int setpos(char *line, int position)
 static void refresh_line(struct line *line, int ypos)
 {
 	char *str = screenline(line->data, NULL) + scrcol;
-	pos(0, ypos);
+	term_setpos(0, ypos);
 	str[screenwidth] = 0;
 	printf("%s\x1b[K", str);
-	pos(cursx, cursy);
+	term_setpos(cursx, cursy);
 }
 
 /*
@@ -119,7 +115,7 @@ static void refresh(int full)
 			if (scrline->next == lastscrline) {
 				printf("\x1b[1T");
 				refresh_line(scrline, 0);
-				pos(0, screenheight);
+				term_setpos(0, screenheight);
 				printf("%*s", screenwidth, "");
 				return;
 			}
@@ -149,7 +145,7 @@ static void refresh(int full)
 
 	i++;
 	while (i < screenheight) {
-		pos(0, i++);
+		term_setpos(0, i++);
 		printf("~");
 	}
 }
@@ -346,68 +342,11 @@ static void merge_line(struct line *line)
 
 #define ESC "\033"
 
-static void getwinsize(void)
-{
-	int n;
-	char *endp;
-	struct console_device *cdev;
-	const char esc[] = ESC "7" ESC "[r" ESC "[999;999H" ESC "[6n";
-	char buf[64];
-
-	screenwidth = screenheight = 256;
-
-	for_each_console(cdev) {
-		int width, height;
-		uint64_t start;
-
-		if (!(cdev->f_active & CONSOLE_STDIN))
-			continue;
-		if (!(cdev->f_active & CONSOLE_STDOUT))
-			continue;
-
-		memset(buf, 0, sizeof(buf));
-
-		cdev->puts(cdev, esc, sizeof(esc));
-
-		n = 0;
-
-		start = get_time_ns();
-
-		while (1) {
-			if (is_timeout(start, 100 * MSECOND))
-				break;
-
-			if (!cdev->tstc(cdev))
-				continue;
-
-			buf[n] = cdev->getc(cdev);
-
-			if (buf[n] == 'R')
-				break;
-
-			n++;
-		}
-
-		if (buf[0] != 27)
-			continue;
-		if (buf[1] != '[')
-			continue;
-
-		height = simple_strtoul(buf + 2, &endp, 10);
-		width = simple_strtoul(endp + 1, NULL, 10);
-
-		screenwidth = min(screenwidth, width);
-		screenheight = min(screenheight, height);
-	}
-
-	pos(0, 0);
-}
-
 static void statusbar(const char *str)
 {
-	pos(0, screenheight+1);
+	term_setpos(0, screenheight+1);
 	printf("%*c\r%s", screenwidth, ' ', str);
-	pos(cursx, cursy);
+	term_setpos(cursx, cursy);
 }
 
 static int read_modal_key(bool is_modal)
@@ -563,7 +502,7 @@ static int do_edit(int argc, char *argv[])
 	/* check if we are not called as "edit" */
 	if (*argv[0] != 'e') {
 		smartscroll = 1;
-		getwinsize();
+		term_getsize(&screenwidth, &screenheight);
 
 		/* check if we are called as "vi" */
 		if (*argv[0] == 'v')
@@ -597,12 +536,12 @@ static int do_edit(int argc, char *argv[])
 
 	printf("\x1b[2J");
 
-	pos(0, -1);
+	term_setpos(0, -1);
 
 	if (is_vi) {
 		screenheight -= 2;
 		printf("\x1b[7m%*c\x1b[0m", screenwidth , ' ');
-		pos(0, screenheight-1);
+		term_setpos(0, screenheight-1);
 		printf("\x1b[7m%*c\x1b[0m", screenwidth , ' ');
 		printf("\r\x1b[7m%-25s\x1b[0m", argv[1]);
 	} else {
@@ -613,7 +552,7 @@ static int do_edit(int argc, char *argv[])
 	if (smartscroll)
 		printf("\x1b[2;%dr", screenheight);
 
-	pos(0, 0);
+	term_setpos(0, 0);
 
 	screenheight--; /* status line */
 
@@ -652,7 +591,7 @@ static int do_edit(int argc, char *argv[])
 
 		lastscrcol  = scrcol;
 		lastscrline = scrline;
-		pos(cursx, cursy);
+		term_setpos(cursx, cursy);
 
 again:
 		c = read_modal_key(is_vi);
diff --git a/include/term.h b/include/term.h
new file mode 100644
index 000000000000..097f84681d49
--- /dev/null
+++ b/include/term.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __TERM_H
+#define __TERM_H
+
+void term_setpos(int x, int y);
+void term_getsize(int *screenwidth, int *screenheight);
+
+#endif /* __LIBBB_H */
diff --git a/lib/Makefile b/lib/Makefile
index 54866f59cc05..0dde52527f41 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 obj-y			+= bcd.o
+obj-y			+= term.o
 obj-$(CONFIG_BOOTSTRAP)	+= bootstrap/
 obj-pbl-y		+= ctype.o
 obj-y			+= rbtree.o
diff --git a/lib/term.c b/lib/term.c
new file mode 100644
index 000000000000..64dd5e430478
--- /dev/null
+++ b/lib/term.c
@@ -0,0 +1,69 @@
+#include <console.h>
+#include <term.h>
+
+void term_setpos(int x, int y)
+{
+	printf("\x1b[%d;%dH", y + 2, x + 1);
+}
+
+void term_getsize(int *screenwidth, int *screenheight)
+{
+	int n;
+	char *endp;
+	struct console_device *cdev;
+	const char esc[] = "\e7" "\e[r" "\e[999;999H" "\e[6n";
+	char buf[64];
+
+	if (screenwidth)
+		*screenwidth = 256;
+	if (screenheight)
+		*screenheight = 256;
+
+	for_each_console(cdev) {
+		int width, height;
+		uint64_t start;
+
+		if (!(cdev->f_active & CONSOLE_STDIN))
+			continue;
+		if (!(cdev->f_active & CONSOLE_STDOUT))
+			continue;
+
+		memset(buf, 0, sizeof(buf));
+
+		cdev->puts(cdev, esc, sizeof(esc));
+
+		n = 0;
+
+		start = get_time_ns();
+
+		while (1) {
+			if (is_timeout(start, 100 * MSECOND))
+				break;
+
+			if (!cdev->tstc(cdev))
+				continue;
+
+			buf[n] = cdev->getc(cdev);
+
+			if (buf[n] == 'R')
+				break;
+
+			n++;
+		}
+
+		if (buf[0] != 27)
+			continue;
+		if (buf[1] != '[')
+			continue;
+
+		height = simple_strtoul(buf + 2, &endp, 10);
+		width = simple_strtoul(endp + 1, NULL, 10);
+
+		if (screenwidth)
+			*screenwidth = min(*screenwidth, width);
+		if (screenheight)
+			*screenheight = min(*screenheight, height);
+	}
+
+	term_setpos(0, 0);
+}
-- 
2.39.2




^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2 2/3] lib: strtox: implement new simple_strtofract
  2024-07-01 10:35 [PATCH v2 1/3] commands: edit: factor out getwinsize and export it for reuse Ahmad Fatoum
@ 2024-07-01 10:35 ` Ahmad Fatoum
  2024-07-01 10:35 ` [PATCH v2 3/3] commands: watch: add new command Ahmad Fatoum
  2024-07-01 13:26 ` [PATCH v2 1/3] commands: edit: factor out getwinsize and export it for reuse Sascha Hauer
  2 siblings, 0 replies; 4+ messages in thread
From: Ahmad Fatoum @ 2024-07-01 10:35 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

We have no floating point support in barebox and no strtod. Still some
user interaction could benefit from being able to supply command
arguments or device parameters in a format with decimal points.

This new simple_strtofract() function parses a fixed point format consisting
of a 32 bit integer and 32 bit fractional part and returns it multiplied
by a division argument. e.g.

  simple_strtofract("1.02", NULL, 1000) == 1020

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
  - no change
---
 include/linux/kernel.h |  1 +
 lib/strtox.c           | 57 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index cd7dac73f93a..dd108ba0abf7 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -92,6 +92,7 @@ extern unsigned long simple_strtoul(const char *,char **,unsigned int);
 extern long simple_strtol(const char *,char **,unsigned int);
 extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
 extern long long simple_strtoll(const char *,char **,unsigned int);
+extern s64 simple_strtofract(const char *cp, char **endp, u32 division);
 
 /* The `const' in roundup() prevents gcc-3.3 from calling __divdi3 */
 #define roundup(x, y) (					\
diff --git a/lib/strtox.c b/lib/strtox.c
index 76927743a72c..5ef0f0923a9e 100644
--- a/lib/strtox.c
+++ b/lib/strtox.c
@@ -78,3 +78,60 @@ long long simple_strtoll(const char *cp, char **endp, unsigned int base)
 	return simple_strtoull(cp, endp, base);
 }
 EXPORT_SYMBOL(simple_strtoll);
+
+static unsigned int simple_strtouint(const char *cp, char **endp, unsigned int base)
+{
+	unsigned int ret;
+
+	ret = simple_strtoull(cp, endp, base);
+	if (ret != (unsigned int)ret) {
+		if (endp)
+			*endp = (char *)cp;
+		return  0;
+	}
+
+	return ret;
+}
+
+s64 simple_strtofract(const char *cp, char **endp, u32 division)
+{
+	char *end = (char *)cp;
+	s64 integer, fract, scale, result = 0;
+	int fract_len = 0, sign = 1;
+
+	switch (*cp) {
+	case '-':
+		sign = -1;
+		fallthrough;
+	case '+':
+		cp++;
+	}
+
+	if (!isdigit(*cp))
+		goto out;
+
+	integer = simple_strtouint(cp, &end, 10);
+	if (end == cp)
+		goto out;
+
+	if (*end == '.' || *end == ',') {
+		cp = end + 1;
+		fract = simple_strtouint(cp, &end, 10);
+		fract_len = end - cp;
+	}
+
+	result = integer * division;
+
+	scale = 1;
+	for (int i = 0; i < fract_len; i++)
+		scale *= 10;
+	if (fract_len > 0)
+		result += (fract * division) / scale;
+
+out:
+	if (endp)
+		*endp = end;
+
+	return sign * result;
+}
+EXPORT_SYMBOL(simple_strtofract);
-- 
2.39.2




^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2 3/3] commands: watch: add new command
  2024-07-01 10:35 [PATCH v2 1/3] commands: edit: factor out getwinsize and export it for reuse Ahmad Fatoum
  2024-07-01 10:35 ` [PATCH v2 2/3] lib: strtox: implement new simple_strtofract Ahmad Fatoum
@ 2024-07-01 10:35 ` Ahmad Fatoum
  2024-07-01 13:26 ` [PATCH v2 1/3] commands: edit: factor out getwinsize and export it for reuse Sascha Hauer
  2 siblings, 0 replies; 4+ messages in thread
From: Ahmad Fatoum @ 2024-07-01 10:35 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

For testing proper operation of IIO devices, it can be useful to monitor
changes in the reading reported by the hwmon command. This is now
possible by using `watch -n 0.5 hwmon`.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
  - return success when command is interrupted (Sascha)
  - free all allocated buffers on exit (Sascha)
  - Print title by default (Sascha)
  - Remove useless duplicate ctrlc() in outer loop condition
---
 commands/Kconfig  |  6 +++
 commands/Makefile |  1 +
 commands/watch.c  | 99 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 106 insertions(+)
 create mode 100644 commands/watch.c

diff --git a/commands/Kconfig b/commands/Kconfig
index c9c4be67e098..5b512f1bbac7 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -2417,6 +2417,12 @@ config CMD_TIME
 	  Note: This command depends on COMMAND being interruptible,
 	  otherwise the timer may overrun resulting in incorrect results
 
+config CMD_WATCH
+	bool "watch"
+	help
+	  watch is used to execute a command periodically, showing
+	  output to the screen.
+
 config CMD_UPTIME
 	bool "uptime"
 	help
diff --git a/commands/Makefile b/commands/Makefile
index f3e8e944a931..4ca7ba7eb609 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_CMD_WD)		+= wd.o
 obj-$(CONFIG_CMD_LED_TRIGGER)	+= trigger.o
 obj-$(CONFIG_CMD_USB)		+= usb.o
 obj-$(CONFIG_CMD_TIME)		+= time.o
+obj-$(CONFIG_CMD_WATCH)		+= watch.o
 obj-$(CONFIG_CMD_UPTIME)	+= uptime.o
 obj-$(CONFIG_CMD_OFTREE)	+= oftree.o
 obj-$(CONFIG_CMD_OF_COMPATIBLE)	+= of_compatible.o
diff --git a/commands/watch.c b/commands/watch.c
new file mode 100644
index 000000000000..64b59abb107d
--- /dev/null
+++ b/commands/watch.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Port of Mini watch implementation from busybox
+ *
+ * Copyright (C) 2001 by Michael Habermann <mhabermann@gmx.de>
+ * Copyrigjt (C) Mar 16, 2003 Manuel Novoa III   (mjn3@codepoet.org)
+ */
+
+#include <common.h>
+#include <command.h>
+#include <clock.h>
+#include <linux/math64.h>
+#include <malloc.h>
+#include <getopt.h>
+#include <term.h>
+#include <rtc.h>
+
+static int do_watch(int argc , char *argv[])
+{
+	const char *period_str = "2.0";
+	u64 period_ns, start;
+	bool print_header = true;
+	int opt;
+	unsigned width, new_width;
+	char *end, *header, *cmd;
+
+	while ((opt = getopt(argc, argv, "+n:t")) > 0) {
+		switch (opt) {
+		case 'n':
+			period_str = optarg;
+			break;
+		case 't':
+			print_header = false;
+			break;
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 1)
+		return COMMAND_ERROR_USAGE;
+
+	period_ns = simple_strtofract(period_str, &end, NSEC_PER_SEC);
+	if (*end)
+		return -EINVAL;
+
+	cmd = strjoin(" ", argv, argc);
+
+	width = (unsigned)-1; // make sure first time new_width != width
+	header = NULL;
+
+	while (true) {
+		/* home; clear to the end of screen */
+		printf("\e[H\e[J");
+
+		if (print_header) {
+			term_getsize(&new_width, NULL);
+			if (new_width != width) {
+				width = new_width;
+				free(header);
+				header = xasprintf("Every %ss: %-*s",
+						   period_str, (int)width, cmd);
+			}
+
+			printf("%s\n\n", header);
+		}
+
+		run_command(cmd);
+
+		start = get_time_ns();
+		while (!is_timeout(start, period_ns)) {
+			if (ctrlc())
+				goto out;
+		}
+	}
+
+out:
+	free(header);
+	free(cmd);
+
+	return 0;
+}
+
+BAREBOX_CMD_HELP_START(watch)
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-n SEC", "Period (default 2)")
+BAREBOX_CMD_HELP_OPT ("-t",	"Don't print header")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(watch)
+	.cmd		= do_watch,
+	BAREBOX_CMD_DESC("run program periodically")
+	BAREBOX_CMD_OPTS("[-n SEC] [-t] PROG ARGS")
+	BAREBOX_CMD_GROUP(CMD_GRP_MISC)
+	BAREBOX_CMD_HELP(cmd_watch_help)
+BAREBOX_CMD_END
-- 
2.39.2




^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 1/3] commands: edit: factor out getwinsize and export it for reuse
  2024-07-01 10:35 [PATCH v2 1/3] commands: edit: factor out getwinsize and export it for reuse Ahmad Fatoum
  2024-07-01 10:35 ` [PATCH v2 2/3] lib: strtox: implement new simple_strtofract Ahmad Fatoum
  2024-07-01 10:35 ` [PATCH v2 3/3] commands: watch: add new command Ahmad Fatoum
@ 2024-07-01 13:26 ` Sascha Hauer
  2 siblings, 0 replies; 4+ messages in thread
From: Sascha Hauer @ 2024-07-01 13:26 UTC (permalink / raw)
  To: barebox, Ahmad Fatoum


On Mon, 01 Jul 2024 12:35:12 +0200, Ahmad Fatoum wrote:
> This function is currently only used by the sedit command, but can be
> useful for other "full-screen" commands as well.
> 
> 

Applied, thanks!

[1/3] commands: edit: factor out getwinsize and export it for reuse
      https://git.pengutronix.de/cgit/barebox/commit/?id=7daa9f29a85c (link may not be stable)
[2/3] lib: strtox: implement new simple_strtofract
      https://git.pengutronix.de/cgit/barebox/commit/?id=8482a230cd6c (link may not be stable)
[3/3] commands: watch: add new command
      https://git.pengutronix.de/cgit/barebox/commit/?id=f2598a140c00 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer@pengutronix.de>




^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2024-07-01 13:26 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-07-01 10:35 [PATCH v2 1/3] commands: edit: factor out getwinsize and export it for reuse Ahmad Fatoum
2024-07-01 10:35 ` [PATCH v2 2/3] lib: strtox: implement new simple_strtofract Ahmad Fatoum
2024-07-01 10:35 ` [PATCH v2 3/3] commands: watch: add new command Ahmad Fatoum
2024-07-01 13:26 ` [PATCH v2 1/3] commands: edit: factor out getwinsize and export it for reuse Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox