tools: gpiomon: add initial-state option
PATCH v2 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.
---
Changes in v2:
- allocation of "values" moved to if block.
- existing variable pollfds was freed.
- option -S changed to -I.
- Added to the unit test.
--- tests/scripts/gpiod-bash-test-helper.inc | 0 tools/gpio-tools-test.bash | 16 +++++++++++++++ tools/gpioget.c | 18 +---------------- tools/gpiomon.c | 25 +++++++++++++++++++++++- tools/tools-common.c | 21 ++++++++++++++++++++ tools/tools-common.h | 2 ++ 6 files changed, 64 insertions(+), 18 deletions(-) mode change 100644 => 100755 tests/scripts/gpiod-bash-test-helper.inc
tests/scripts/gpiod-bash-test-helper.inc +0 -0
tools/gpio-tools-test.bash +16 -0
@@ -2235,6 +2235,22 @@ test_gpiomon_with_custom_format_unknown_specifier() { output_is "%x" } +test_gpiomon_with_initial_state() { + gpiosim_chip sim0 num_lines=8 + + gpiosim_set_pull sim0 2 pull-up + gpiosim_set_pull sim0 3 pull-up + gpiosim_set_pull sim0 5 pull-up + gpiosim_set_pull sim0 7 pull-up + + local sim0=${GPIOSIM_CHIP_NAME[sim0]} + + run_prog gpiomon --initial-state --chip "$sim0" 0 1 2 3 4 5 6 7 + + output_is \ +"Initial line state(s): \"0\"=inactive \"1\"=inactive \"2\"=active \"3\"=active \"4\"=inactive \"5\"=active \"6\"=inactive \"7\"=active" + status_is 124 +} # # gpionotify test cases #
tools/gpioget.c +1 -17
@@ -139,12 +139,10 @@ int main(int argc, char **argv)struct gpiod_line_config *line_cfg;struct line_resolver *resolver;enum gpiod_line_value *values; -struct resolved_line *line;struct gpiod_chip *chip;unsigned int *offsets;int i, num_lines, ret;struct config cfg; -const char *fmt;set_prog_name (argv[0 ]); i =parse_config (argc, argv, &cfg);
@@ -216,21 +214,7 @@ int main(int argc, char **argv)gpiod_line_request_release (request);gpiod_chip_close (chip); } - - fmt = cfg.unquoted ?"%s=%s" :"\"%s\"=%s" ; - -for (i =0 ; i < resolver->num_lines; i++) { - line = &resolver->lines[i]; -if (cfg.numeric) -printf ("%d" , line->value); -else -printf (fmt, line->id, - line->value ?"active" :"inactive" ); - -if (i != resolver->num_lines -1 ) -printf (" " ); - } -printf ("\n" ); +print_line_vals (resolver, cfg.unquoted, cfg.numeric);free_line_resolver (resolver);gpiod_request_config_free (req_cfg);
tools/gpiomon.c +24 -1
@@ -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 (" -I, --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:qshvI" ;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, 'I' }, { 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 'I' : + cfg->initial_state = true; +break ;case 'h' :print_help ();exit (EXIT_SUCCESS );
@@ -363,6 +369,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,6 +430,7 @@ 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)die ("out of memory" );
@@ -445,6 +453,20 @@ int main(int argc, char **argv)die_perror ("unable to request lines on chip %s" , resolver->chips[i].path); +if (cfg.initial_state) { + values =calloc (resolver->num_lines,sizeof (*values)); +if (!values) +die ("out of memory" ); + 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); +printf ("Initial line state(s): " ); +print_line_vals (resolver, cfg.unquoted, false); +free (values); + } + pollfds[i].fd =gpiod_line_request_get_fd (requests[i]); pollfds[i].events =POLLIN ;gpiod_chip_close (chip);
@@ -508,6 +530,7 @@ done:free_line_resolver (resolver);gpiod_edge_event_buffer_free (event_buffer);free (offsets); +free (pollfds);return EXIT_SUCCESS ; }
tools/tools-common.c +21 -0
@@ -402,6 +402,27 @@ void print_line_id(struct line_resolver *resolver, int chip_num,printf (fmt, lname); } +void print_line_vals (struct line_resolver *resolver,bool is_unquoted, +bool is_numeric) +{ +int i; +const char *fmt = is_unquoted ?"%s=%s" :"\"%s\"=%s" ; + +for (i =0 ; i < resolver->num_lines; i++) { +struct resolved_line *line = &resolver->lines[i]; + +if (is_numeric) +printf ("%d" , line->value); +else +printf (fmt, line->id, + line->value ?"active" :"inactive" ); + +if (i != resolver->num_lines -1 ) +printf (" " ); + } +printf ("\n" ); +} +static int chip_dir_filter (const struct dirent *entry) {struct stat sb;
tools/tools-common.h +2 -0
@@ -99,6 +99,8 @@ void print_event_time(uint64_t evtime, int format);void print_line_attributes (struct gpiod_line_info *info,bool unquoted_strings);void print_line_id (struct line_resolver *resolver,int chip_num,unsigned int offset,const char *chip_id,bool unquoted); +void print_line_vals (struct line_resolver *resolver,bool is_unquoted, +bool is_numeric);bool chip_path_lookup (const char *id,char **path_ptr);int chip_paths (const char *id,char ***paths_ptr);int all_chip_paths (char ***paths_ptr);
Bartosz Golaszewski
maintainerQuoted 3 lines · On Mon, Jan 19, 2026 at 9:01 PM <[email protected]> wrote:
From: Shaarang Tyagi <[email protected]>
Thanks, looks much better.
Quoted 3 lines
Add a gpiomon initial-state command line option to display initial line states, this is diplayed before waiting for events.
Please also mention that you factor out the gpioget code into tools-common.
Quoted 6 lines
Signed-off-by Shaarang Tyagi <[email protected]>---
Changes in v2:
- allocation of "values" moved to if block.
- existing variable pollfds was freed.
This doesn't belong into this commit, see below.
Quoted 2 lines
- option -S changed to -I.
- Added to the unit test.
I think you forgot to mention the reuse of print_line_vals() here.
[snip]
Quoted 6 lines
tools/gpio-tools-test.bash +5
-0+test_gpiomon_with_initial_state() { + gpiosim_chip sim0 num_lines=8 + + gpiosim_set_pull sim0 2 pull-up + gpiosim_set_pull sim0 3 pull-up
tools/gpio-tools-test.bash test_gpiomon_with_custom_format_unknown_specifier() { · line 2252
Quoted 10 lines
tools/gpio-tools-test.bash +10
-0+ gpiosim_set_pull sim0 5 pull-up + gpiosim_set_pull sim0 7 pull-up + + local sim0=${GPIOSIM_CHIP_NAME[sim0]} + + run_prog gpiomon --initial-state --chip "$sim0" 0 1 2 3 4 5 6 7 + + output_is \ +"Initial line state(s): \"0\"=inactive \"1\"=inactive \"2\"=active \"3\"=active \"4\"=inactive \"5\"=active \"6\"=inactive \"7\"=active" + status_is 124
You effectively wait for the timeout to kick in and accept the error status as proper result. It also makes this test case very slow. Please see what other gpiomon tests do and do the same - use the dut_run and dut_kill.
[snip]
tools/gpiomon.c int main(int argc, char **argv) · line 459
Quoted 9 lines
tools/gpiomon.c +4
-0@@ -445,6 +453,20 @@ int main(int argc, char **argv)die_perror ("unable to request lines on chip %s" , resolver->chips[i].path); +if (cfg.initial_state) { + values =calloc (resolver->num_lines,sizeof (*values)); +if (!values) +die ("out of memory" );
Add a newline.
tools/gpiomon.c int main(int argc, char **argv) · line 465
Quoted 6 lines
tools/gpiomon.c +6
-0+ 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); +printf ("Initial line state(s): " );
This is unneeded and will make parsing harder. Please drop this and align the initial output with what gpioget does.
tools/gpiomon.c int main(int argc, char **argv) · line 466
Quoted 1 line
tools/gpiomon.c +1
-0+print_line_vals (resolver, cfg.unquoted, false);
Would it be a lot of work to also add the -N/--numeric switch like what gpioget has here? The -N flag is free in gpiomon.
tools/gpiomon.c done: · line 533
Quoted 11 lines
tools/gpiomon.c +4
-0+free (values); + } + pollfds[i].fd =gpiod_line_request_get_fd (requests[i]); pollfds[i].events =POLLIN ;gpiod_chip_close (chip);@@ -508,6 +530,7 @@ done:free_line_resolver (resolver);gpiod_edge_event_buffer_free (event_buffer);free (offsets); +free (pollfds);
This should be a separate patch with a Fixes: tag.
[snip]
With the above fixed LGTM.
Bart