tools: allow longer time periods
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Tue, 23 Apr 2024 10:04:51 +0000 (12:04 +0200)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Wed, 24 Apr 2024 07:55:36 +0000 (09:55 +0200)
We currently store time as microseconds in 32-bit integers and allow
seconds as the longest time unit when parsing command-line arguments
limiting the time period possible to specify when passing arguments such
as --hold-period to 35 minutes. Let's use 64-bit integers to vastly
increase that.

Use nanosleep() instead of usleep() to extend the possible sleep time
range.

Reported-by: Gunnar Thörnqvist <gunnar@igl.se>
Link: https://lore.kernel.org/r/20240423100452.32958-4-brgl@bgdev.pl
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
configure.ac
tools/gpioget.c
tools/gpiomon.c
tools/gpionotify.c
tools/gpioset.c
tools/tools-common.c
tools/tools-common.h

index 3b5bbf21f0b68147840bb18eefda8b67e1a56d61..a2370c5fa3e3ed83f6a33fcacb9509dd34aedec5 100644 (file)
@@ -120,6 +120,8 @@ AS_IF([test "x$with_tools" = xtrue],
        AC_CHECK_FUNC([asprintf], [], [FUNC_NOT_FOUND_TOOLS([asprintf])])
        AC_CHECK_FUNC([scandir], [], [FUNC_NOT_FOUND_TOOLS([scandir])])
        AC_CHECK_FUNC([versionsort], [], [FUNC_NOT_FOUND_TOOLS([versionsort])])
+       AC_CHECK_FUNC([strtoull], [], [FUNC_NOT_FOUND_TOOLS([strtoull])])
+       AC_CHECK_FUNC([nanosleep], [], [FUNC_NOT_FOUND_TOOLS([nanosleep])])
        AS_IF([test "x$with_gpioset_interactive" = xtrue],
                [PKG_CHECK_MODULES([LIBEDIT], [libedit >= 3.1])])
        ])
index f6117378dc7bac5f4ba5ced066a60c61153acfb2..bad7667f8cafa86982902a4f64294bc268505156 100644 (file)
@@ -19,7 +19,7 @@ struct config {
        bool unquoted;
        enum gpiod_line_bias bias;
        enum gpiod_line_direction direction;
-       unsigned int hold_period_us;
+       unsigned long long hold_period_us;
        const char *chip_id;
        const char *consumer;
 };
@@ -205,7 +205,7 @@ int main(int argc, char **argv)
                        die_perror("unable to request lines");
 
                if (cfg.hold_period_us)
-                       usleep(cfg.hold_period_us);
+                       sleep_us(cfg.hold_period_us);
 
                ret = gpiod_line_request_get_values(request, values);
                if (ret)
index 7135843348dbb204208a7ae14fb60574b962f7ff..88b5ccf67e3ee17ac0ee0541ea0d0ab72ae9953e 100644 (file)
@@ -5,6 +5,7 @@
 #include <getopt.h>
 #include <gpiod.h>
 #include <inttypes.h>
+#include <limits.h>
 #include <poll.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -24,13 +25,13 @@ struct config {
        enum gpiod_line_bias bias;
        enum gpiod_line_edge edges;
        int events_wanted;
-       unsigned int debounce_period_us;
+       unsigned long long debounce_period_us;
        const char *chip_id;
        const char *consumer;
        const char *fmt;
        enum gpiod_line_clock event_clock;
        int timestamp_fmt;
-       int idle_timeout;
+       long long idle_timeout;
 };
 
 static void print_help(void)
@@ -390,9 +391,14 @@ int main(int argc, char **argv)
        if (cfg.active_low)
                gpiod_line_settings_set_active_low(settings, true);
 
-       if (cfg.debounce_period_us)
+       if (cfg.debounce_period_us) {
+               if (cfg.debounce_period_us > UINT_MAX)
+                       die("maximum debounce period is %uus, got %lluus",
+                           UINT_MAX, cfg.debounce_period_us);
+
                gpiod_line_settings_set_debounce_period_us(
-                       settings, cfg.debounce_period_us);
+                       settings, (unsigned long)cfg.debounce_period_us);
+       }
 
        gpiod_line_settings_set_event_clock(settings, cfg.event_clock);
        gpiod_line_settings_set_edge_detection(settings, cfg.edges);
index 08f5da93b6f516ae497928cec53920ef28e3322f..e74ca9631db055fe697c2d803b33c4328e5c67f2 100644 (file)
@@ -23,7 +23,7 @@ struct config {
        const char *chip_id;
        const char *fmt;
        int timestamp_fmt;
-       int idle_timeout;
+       long long idle_timeout;
 };
 
 static void print_help(void)
index 863da4a8bc77dd2fbcb048b96a17ce56adbbfc69..46dde0789a17dfb864e6796f2520ac86b23800fb 100644 (file)
@@ -28,8 +28,8 @@ struct config {
        enum gpiod_line_bias bias;
        enum gpiod_line_drive drive;
        int toggles;
-       unsigned int *toggle_periods;
-       unsigned int hold_period_us;
+       unsigned long long *toggle_periods;
+       unsigned long long hold_period_us;
        const char *chip_id;
        const char *consumer;
 };
@@ -94,10 +94,10 @@ static int parse_drive_or_die(const char *option)
        return 0;
 }
 
-static int parse_periods_or_die(char *option, unsigned int **periods)
+static int parse_periods_or_die(char *option, unsigned long long **periods)
 {
        int i, num_periods = 1;
-       unsigned int *pp;
+       unsigned long long *pp;
        char *end;
 
        for (i = 0; option[i] != '\0'; i++)
@@ -376,7 +376,7 @@ static void toggle_all_lines(struct line_resolver *resolver)
  * and apply the values to the requests.
  * offset and values are scratch pads for working.
  */
-static void toggle_sequence(int toggles, unsigned int *toggle_periods,
+static void toggle_sequence(int toggles, unsigned long long *toggle_periods,
                            struct gpiod_line_request **requests,
                            struct line_resolver *resolver,
                            unsigned int *offsets,
@@ -388,7 +388,7 @@ static void toggle_sequence(int toggles, unsigned int *toggle_periods,
                return;
 
        for (;;) {
-               usleep(toggle_periods[i]);
+               sleep_us(toggle_periods[i]);
                toggle_all_lines(resolver);
                apply_values(requests, resolver, offsets, values);
 
@@ -826,7 +826,7 @@ static void interact(struct gpiod_line_request **requests,
                                printf("invalid period: '%s'\n", words[1]);
                                goto cmd_ok;
                        }
-                       usleep(period_us);
+                       sleep_us(period_us);
                        goto cmd_ok;
                }
 
@@ -981,7 +981,7 @@ int main(int argc, char **argv)
        }
 
        if (cfg.hold_period_us)
-               usleep(cfg.hold_period_us);
+               sleep_us(cfg.hold_period_us);
 
 #ifdef GPIOSET_INTERACTIVE
        if (cfg.interactive)
index 64592d329c2f3270d6a7c1dbf35182abd6efad39..500e9a2b4202652ed1e9e437ad0963f113364b3e 100644 (file)
@@ -112,12 +112,12 @@ int parse_bias_or_die(const char *option)
        return GPIOD_LINE_BIAS_DISABLED;
 }
 
-int parse_period(const char *option)
+long long parse_period(const char *option)
 {
-       unsigned long p, m = 0;
+       unsigned long long p, m = 0;
        char *end;
 
-       p = strtoul(option, &end, 10);
+       p = strtoull(option, &end, 10);
 
        switch (*end) {
        case 'u':
@@ -147,15 +147,15 @@ int parse_period(const char *option)
        }
 
        p *= m;
-       if (*end != '\0' || p > INT_MAX)
+       if (*end != '\0' || p > LLONG_MAX)
                return -1;
 
        return p;
 }
 
-unsigned int parse_period_or_die(const char *option)
+unsigned long long parse_period_or_die(const char *option)
 {
-       int period = parse_period(option);
+       long long period = parse_period(option);
 
        if (period < 0)
                die("invalid period: %s", option);
@@ -163,6 +163,16 @@ unsigned int parse_period_or_die(const char *option)
        return period;
 }
 
+void sleep_us(unsigned long long period)
+{
+       struct timespec spec;
+
+       spec.tv_sec = period / 1000000;
+       spec.tv_nsec = (period % 1000000) * 1000;
+
+       nanosleep(&spec, NULL);
+}
+
 int parse_uint(const char *option)
 {
        unsigned long o;
index c82317afe3357f029a262782016e447912d772ea..bc63080ff044da1389c35456d6b9656883594bb6 100644 (file)
@@ -87,8 +87,9 @@ void die(const char *fmt, ...) NORETURN PRINTF(1, 2);
 void die_perror(const char *fmt, ...) NORETURN PRINTF(1, 2);
 void print_version(void);
 int parse_bias_or_die(const char *option);
-int parse_period(const char *option);
-unsigned int parse_period_or_die(const char *option);
+long long parse_period(const char *option);
+unsigned long long parse_period_or_die(const char *option);
+void sleep_us(unsigned long long period);
 int parse_uint(const char *option);
 unsigned int parse_uint_or_die(const char *option);
 void print_bias_help(void);