Skip to contentSkip to conversation

tools: gpiomon: add initial-state option

PATCH Superseded [email protected] 2 participants 2 messages Jan 5 – Jan 6 GPIO

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 tools: gpiomon: add initial-state option

From: Shaarang Tyagi <[email protected]>

Add a gpiomon initial-state command line option to display initial line states, this is diplayed before waiting for events.

---
 tools/gpiomon.c | 39 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)
tools/gpiomon.c +37 -2
index 88b5ccf..4d109c3 100644
@@ -32,6 +32,7 @@ struct config {
 	enum gpiod_line_clock event_clock;
 	int timestamp_fmt;
 	long long idle_timeout;
+	bool initial_state;
 };
 
 static void print_help(void)
@@ -69,6 +70,7 @@ static void print_help(void)
 	printf("  -p, --debounce-period <period>\n");
 	printf("\t\t\tdebounce the line(s) with the specified period\n");
 	printf("  -q, --quiet\t\tdon't generate any output\n");
+	printf("  -S, --initial-state\t\tprint initial states of the lines\n");
 	printf("  -s, --strict\t\tabort if requested line names are not unique\n");
 	printf("      --unquoted\tdon't quote line or consumer names\n");
 	printf("      --utc\t\tformat event timestamps as UTC (default for 'realtime')\n");
@@ -113,7 +115,7 @@ static int parse_event_clock_or_die(const char *option)
 
 static int parse_config(int argc, char **argv, struct config *cfg)
 {
-	static const char *const shortopts = "+b:c:C:e:E:hF:ln:p:qshv";
+	static const char *const shortopts = "+b:c:C:e:E:hF:ln:p:qshvS";
 
 	const struct option longopts[] = {
 		{ "active-low",	no_argument,	NULL,		'l' },
@@ -136,6 +138,7 @@ static int parse_config(int argc, char **argv, struct config *cfg)
 		{ "unquoted",	no_argument,	NULL,		'Q' },
 		{ "utc",	no_argument,	&cfg->timestamp_fmt,	1 },
 		{ "version",	no_argument,	NULL,		'v' },
+		{ "initial-state",	no_argument,	NULL,		'S' },
 		{ GETOPT_NULL_LONGOPT },
 	};
 
@@ -197,6 +200,9 @@ static int parse_config(int argc, char **argv, struct config *cfg)
 		case 's':
 			cfg->strict = true;
 			break;
+		case 'S':
+			cfg->initial_state = true;
+			break;
 		case 'h':
 			print_help();
 			exit(EXIT_SUCCESS);
@@ -353,6 +359,24 @@ static void event_print(struct gpiod_edge_event *event,
 		event_print_human_readable(event, resolver, chip_num, cfg);
 }
 
+static void initial_line_values_print(struct line_resolver *resolver,
+			struct config *cfg)
+{
+	printf("\nInitial line state(s): ");
+	int i;
+	const char *fmt = cfg->unquoted ? "%s=%s" : "\"%s\"=%s";
+
+	for (i = 0; i < resolver->num_lines; i++) {
+		struct resolved_line *line = &resolver->lines[i];
+
+		printf(fmt, line->id,
+		line->value ? "active" : "inactive");
+		if (i != resolver->num_lines - 1)
+			printf(" ");
+	}
+	printf("\n");
+}
+
 int main(int argc, char **argv)
 {
 	struct gpiod_edge_event_buffer *event_buffer;
@@ -363,6 +387,7 @@ int main(int argc, char **argv)
 	int num_lines, events_done = 0;
 	struct gpiod_edge_event *event;
 	struct line_resolver *resolver;
+	enum gpiod_line_value *values;
 	struct timespec idle_timeout;
 	struct gpiod_chip *chip;
 	struct pollfd *pollfds;
@@ -423,7 +448,9 @@ int main(int argc, char **argv)
 	requests = calloc(resolver->num_chips, sizeof(*requests));
 	pollfds = calloc(resolver->num_chips, sizeof(*pollfds));
 	offsets = calloc(resolver->num_lines, sizeof(*offsets));
-	if (!requests || !pollfds || !offsets)
+	values = calloc(resolver->num_lines, sizeof(*values));
+
+	if (!requests || !pollfds || !offsets || !values)
 		die("out of memory");
 
 	for (i = 0; i < resolver->num_chips; i++) {
@@ -445,6 +472,14 @@ int main(int argc, char **argv)
 			die_perror("unable to request lines on chip %s",
 				   resolver->chips[i].path);
 
+		if (cfg.initial_state) {
+			ret = gpiod_line_request_get_values(requests[i], values);
+			if (ret)
+				die_perror("unable to read GPIO line values");
+			set_line_values(resolver, i, values);
+			initial_line_values_print(resolver, &cfg);
+		}
+
 		pollfds[i].fd = gpiod_line_request_get_fd(requests[i]);
 		pollfds[i].events = POLLIN;
 		gpiod_chip_close(chip);
#1 lore raw
Quoted 5 lines · On Mon, Jan 5, 2026 at 6:06 PM <[email protected]> wrote:

From: Shaarang Tyagi <[email protected]>

Add a gpiomon initial-state command line option to display initial line states, this is diplayed before waiting for events.

Hi! Thanks for doing this. Can you also add some test-cases to tools/gpio-tools-test.bash?

Quoted 3 lines

Tested-by is a tag added by third party developers who tested code you authored. Don't add your own T-b to your patches. I sure do expect you to test code you're sending. :)

Quoted 18 lines
---
 tools/gpiomon.c | 39 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)
tools/gpiomon.c +1 -0
index 88b5ccf..4d109c3 100644
@@ -32,6 +32,7 @@ struct config {
        enum gpiod_line_clock event_clock;
        int timestamp_fmt;
        long long idle_timeout;
+       bool initial_state;
 };
 
 static void print_help(void)

tools/gpiomon.c static void print_help(void) · line 73

Quoted 4 lines
tools/gpiomon.c +1 -0
@@ -69,6 +70,7 @@ static void print_help(void)
        printf("  -p, --debounce-period <period>\n");
        printf("\t\t\tdebounce the line(s) with the specified period\n");
        printf("  -q, --quiet\t\tdon't generate any output\n");
+       printf("  -S, --initial-state\t\tprint initial states of the lines\n");

Can you make it -i instead?

Quoted 41 lines
tools/gpiomon.c +12 -1
        printf("  -s, --strict\t\tabort if requested line names are not unique\n");
        printf("      --unquoted\tdon't quote line or consumer names\n");
        printf("      --utc\t\tformat event timestamps as UTC (default for 'realtime')\n");
@@ -113,7 +115,7 @@ static int parse_event_clock_or_die(const char *option)
 
 static int parse_config(int argc, char **argv, struct config *cfg)
 {
-       static const char *const shortopts = "+b:c:C:e:E:hF:ln:p:qshv";
+       static const char *const shortopts = "+b:c:C:e:E:hF:ln:p:qshvS";
 
        const struct option longopts[] = {
                { "active-low", no_argument,    NULL,           'l' },
@@ -136,6 +138,7 @@ static int parse_config(int argc, char **argv, struct config *cfg)
                { "unquoted",   no_argument,    NULL,           'Q' },
                { "utc",        no_argument,    &cfg->timestamp_fmt,    1 },
                { "version",    no_argument,    NULL,           'v' },
+               { "initial-state",      no_argument,    NULL,           'S' },
                { GETOPT_NULL_LONGOPT },
        };
 
@@ -197,6 +200,9 @@ static int parse_config(int argc, char **argv, struct config *cfg)
                case 's':
                        cfg->strict = true;
                        break;
+               case 'S':
+                       cfg->initial_state = true;
+                       break;
                case 'h':
                        print_help();
                        exit(EXIT_SUCCESS);
@@ -353,6 +359,24 @@ static void event_print(struct gpiod_edge_event *event,
                event_print_human_readable(event, resolver, chip_num, cfg);
 }
 
+static void initial_line_values_print(struct line_resolver *resolver,
+                       struct config *cfg)
+{
+       printf("\nInitial line state(s): ");
+       int i;
+       const char *fmt = cfg->unquoted ? "%s=%s" : "\"%s\"=%s";
+

tools/gpiomon.c static void event_print(struct gpiod_edge_event *event, · line 378

Quoted 10 lines
tools/gpiomon.c +10 -0
+       for (i = 0; i < resolver->num_lines; i++) {
+               struct resolved_line *line = &resolver->lines[i];
+
+               printf(fmt, line->id,
+               line->value ? "active" : "inactive");
+               if (i != resolver->num_lines - 1)
+                       printf(" ");
+       }
+       printf("\n");
+}

It's not a hill I'll die on but gpioset already implements code for doing this. Any chance you could abstract parts of it into tools-common.c and reuse it here instead?

Quoted 13 lines
tools/gpiomon.c +2 -0
+
 int main(int argc, char **argv)
 {
        struct gpiod_edge_event_buffer *event_buffer;
@@ -363,6 +387,7 @@ int main(int argc, char **argv)
        int num_lines, events_done = 0;
        struct gpiod_edge_event *event;
        struct line_resolver *resolver;
+       enum gpiod_line_value *values;
        struct timespec idle_timeout;
        struct gpiod_chip *chip;
        struct pollfd *pollfds;

tools/gpiomon.c int main(int argc, char **argv) · line 451

Quoted 5 lines
tools/gpiomon.c +1 -1
@@ -423,7 +448,9 @@ int main(int argc, char **argv)
        requests = calloc(resolver->num_chips, sizeof(*requests));
        pollfds = calloc(resolver->num_chips, sizeof(*pollfds));
        offsets = calloc(resolver->num_lines, sizeof(*offsets));
-       if (!requests || !pollfds || !offsets)
+       values = calloc(resolver->num_lines, sizeof(*values));

This can fail (I mean, not on linux but still, it's good practice), please check the return value. And free this memory at the end like we do for everything else.

tools/gpiomon.c int main(int argc, char **argv) · line 478

Quoted 13 lines
tools/gpiomon.c +6 -0
+
+       if (!requests || !pollfds || !offsets || !values)
                die("out of memory");
 
        for (i = 0; i < resolver->num_chips; i++) {
@@ -445,6 +472,14 @@ int main(int argc, char **argv)
                        die_perror("unable to request lines on chip %s",
                                   resolver->chips[i].path);
 
+               if (cfg.initial_state) {
+                       ret = gpiod_line_request_get_values(requests[i], values);
+                       if (ret)
+                               die_perror("unable to read GPIO line values");

It doesn't seem like you use values elsewhere, maybe you can allocate it only if needed inside this block?

tools/gpiomon.c int main(int argc, char **argv) · line 485

Quoted 8 lines
tools/gpiomon.c +4 -0
+                       set_line_values(resolver, i, values);
+                       initial_line_values_print(resolver, &cfg);
+               }
+
                pollfds[i].fd = gpiod_line_request_get_fd(requests[i]);
                pollfds[i].events = POLLIN;
                gpiod_chip_close(chip);

Bart