* [libgpiod][PATCH v3 01/14] core: add support for bias flags
2019-11-25 14:31 [libgpiod][PATCH v3 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
@ 2019-11-25 14:31 ` Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 02/14] tests: add tests " Kent Gibson
` (12 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Kent Gibson @ 2019-11-25 14:31 UTC (permalink / raw)
To: linux-gpio, bgolaszewski; +Cc: Kent Gibson
Extend the libgpiod API to support the bias flags recently added to the
kernel GPIO uAPI. The core change is the addition of
GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP
and GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN flags to be passed into
line_request functions, and the addition of gpiod_line_bias to return the
bias state of lines.
Variants of the ctxless functions that accept an active_low flag
are added to also accept other flags. The variant names add a "_ext"
suffix to the name of the original function.
Based on initial work by Drew Fustini <drew@pdp7.com>.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
include/gpiod.h | 183 ++++++++++++++++++++++++++++++++++++++++++++++++
lib/core.c | 32 ++++++---
lib/ctxless.c | 114 +++++++++++++++++++++++++++---
3 files changed, 311 insertions(+), 18 deletions(-)
diff --git a/include/gpiod.h b/include/gpiod.h
index 3fc1c0c..86c3ea9 100644
--- a/include/gpiod.h
+++ b/include/gpiod.h
@@ -84,6 +84,22 @@ struct gpiod_line_bulk;
* the need to use the gpiod_* structures or to keep track of resources.
*/
+/**
+ * @brief Miscellaneous GPIO flags.
+ */
+enum {
+ GPIOD_CTXLESS_FLAG_OPEN_DRAIN = GPIOD_BIT(0),
+ /**< The line is an open-drain port. */
+ GPIOD_CTXLESS_FLAG_OPEN_SOURCE = GPIOD_BIT(1),
+ /**< The line is an open-source port. */
+ GPIOD_CTXLESS_FLAG_BIAS_DISABLE = GPIOD_BIT(2),
+ /**< The line has neither either pull-up nor pull-down resistor */
+ GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN = GPIOD_BIT(3),
+ /**< The line has pull-down resistor enabled */
+ GPIOD_CTXLESS_FLAG_BIAS_PULL_UP = GPIOD_BIT(4),
+ /**< The line has pull-up resistor enabled */
+};
+
/**
* @brief Read current value from a single GPIO line.
* @param device Name, path, number or label of the gpiochip.
@@ -95,6 +111,19 @@ struct gpiod_line_bulk;
int gpiod_ctxless_get_value(const char *device, unsigned int offset,
bool active_low, const char *consumer) GPIOD_API;
+/**
+ * @brief Read current value from a single GPIO line.
+ * @param device Name, path, number or label of the gpiochip.
+ * @param offset Offset of the GPIO line.
+ * @param active_low The active state of this line - true if low.
+ * @param consumer Name of the consumer.
+ * @param flags The flags for the line.
+ * @return 0 or 1 (GPIO value) if the operation succeeds, -1 on error.
+ */
+int gpiod_ctxless_get_value_ext(const char *device, unsigned int offset,
+ bool active_low, const char *consumer,
+ int flags) GPIOD_API;
+
/**
* @brief Read current values from a set of GPIO lines.
* @param device Name, path, number or label of the gpiochip.
@@ -110,6 +139,23 @@ int gpiod_ctxless_get_value_multiple(const char *device,
unsigned int num_lines, bool active_low,
const char *consumer) GPIOD_API;
+/**
+ * @brief Read current values from a set of GPIO lines.
+ * @param device Name, path, number or label of the gpiochip.
+ * @param offsets Array of offsets of lines whose values should be read.
+ * @param values Buffer in which the values will be stored.
+ * @param num_lines Number of lines, must be > 0.
+ * @param active_low The active state of this line - true if low.
+ * @param consumer Name of the consumer.
+ * @param flags The flags for the lines.
+ * @return 0 if the operation succeeds, -1 on error.
+ */
+int gpiod_ctxless_get_value_multiple_ext(const char *device,
+ const unsigned int *offsets,
+ int *values, unsigned int num_lines,
+ bool active_low, const char *consumer,
+ int flags) GPIOD_API;
+
/**
* @brief Simple set value callback signature.
*/
@@ -133,6 +179,26 @@ int gpiod_ctxless_set_value(const char *device, unsigned int offset, int value,
gpiod_ctxless_set_value_cb cb,
void *data) GPIOD_API;
+/**
+ * @brief Set value of a single GPIO line.
+ * @param device Name, path, number or label of the gpiochip.
+ * @param offset The offset of the GPIO line.
+ * @param value New value (0 or 1).
+ * @param active_low The active state of this line - true if low.
+ * @param consumer Name of the consumer.
+ * @param cb Optional callback function that will be called right after setting
+ * the value. Users can use this, for example, to pause the execution
+ * after toggling a GPIO.
+ * @param data Optional user data that will be passed to the callback function.
+ * @param flags The flags for the line.
+ * @return 0 if the operation succeeds, -1 on error.
+ */
+int gpiod_ctxless_set_value_ext(const char *device, unsigned int offset,
+ int value, bool active_low,
+ const char *consumer,
+ gpiod_ctxless_set_value_cb cb,
+ void *data, int flags) GPIOD_API;
+
/**
* @brief Set values of multiple GPIO lines.
* @param device Name, path, number or label of the gpiochip.
@@ -153,6 +219,29 @@ int gpiod_ctxless_set_value_multiple(const char *device,
gpiod_ctxless_set_value_cb cb,
void *data) GPIOD_API;
+/**
+ * @brief Set values of multiple GPIO lines.
+ * @param device Name, path, number or label of the gpiochip.
+ * @param offsets Array of offsets of lines the values of which should be set.
+ * @param values Array of integers containing new values.
+ * @param num_lines Number of lines, must be > 0.
+ * @param active_low The active state of this line - true if low.
+ * @param consumer Name of the consumer.
+ * @param cb Optional callback function that will be called right after setting
+ * all values. Works the same as in ::gpiod_ctxless_set_value.
+ * @param data Optional user data that will be passed to the callback function.
+ * @param flags The flags for the lines.
+ * @return 0 if the operation succeeds, -1 on error.
+ */
+int gpiod_ctxless_set_value_multiple_ext(const char *device,
+ const unsigned int *offsets,
+ const int *values,
+ unsigned int num_lines,
+ bool active_low,
+ const char *consumer,
+ gpiod_ctxless_set_value_cb cb,
+ void *data, int flags) GPIOD_API;
+
/**
* @brief Event types that the ctxless event monitor can wait for.
*/
@@ -327,6 +416,31 @@ int gpiod_ctxless_event_monitor(const char *device, int event_type,
gpiod_ctxless_event_handle_cb event_cb,
void *data) GPIOD_API;
+/**
+ * @brief Wait for events on a single GPIO line.
+ * @param device Name, path, number or label of the gpiochip.
+ * @param event_type Type of events to listen for.
+ * @param offset GPIO line offset to monitor.
+ * @param active_low The active state of this line - true if low.
+ * @param consumer Name of the consumer.
+ * @param timeout Maximum wait time for each iteration.
+ * @param poll_cb Callback function to call when waiting for events.
+ * @param event_cb Callback function to call for each line event.
+ * @param data User data passed to the callback.
+ * @param flags The flags for the line.
+ * @return 0 if no errors were encountered, -1 if an error occurred.
+ * @note The way the ctxless event loop works is described in detail in
+ * ::gpiod_ctxless_event_monitor_multiple - this is just a wrapper aound
+ * this routine which calls it for a single GPIO line.
+ */
+int gpiod_ctxless_event_monitor_ext(const char *device, int event_type,
+ unsigned int offset, bool active_low,
+ const char *consumer,
+ const struct timespec *timeout,
+ gpiod_ctxless_event_poll_cb poll_cb,
+ gpiod_ctxless_event_handle_cb event_cb,
+ void *data, int flags) GPIOD_API;
+
/**
* @brief Wait for events on multiple GPIO lines.
* @param device Name, path, number or label of the gpiochip.
@@ -366,6 +480,47 @@ int gpiod_ctxless_event_monitor_multiple(
gpiod_ctxless_event_handle_cb event_cb,
void *data) GPIOD_API;
+/**
+ * @brief Wait for events on multiple GPIO lines.
+ * @param device Name, path, number or label of the gpiochip.
+ * @param event_type Type of events to listen for.
+ * @param offsets Array of GPIO line offsets to monitor.
+ * @param num_lines Number of lines to monitor.
+ * @param active_low The active state of this line - true if low.
+ * @param consumer Name of the consumer.
+ * @param timeout Maximum wait time for each iteration.
+ * @param poll_cb Callback function to call when waiting for events. Can
+ * be NULL.
+ * @param event_cb Callback function to call on event occurrence.
+ * @param data User data passed to the callback.
+ * @param flags The flags for the lines.
+ * @return 0 no errors were encountered, -1 if an error occurred.
+ * @note The poll callback can be NULL in which case the routine will fall
+ * back to a basic, ppoll() based callback.
+ *
+ * Internally this routine opens the GPIO chip, requests the set of lines for
+ * the type of events specified in the event_type parameter and calls the
+ * polling callback in a loop. The role of the polling callback is to detect
+ * input events on a set of file descriptors and notify the caller about the
+ * fds ready for reading.
+ *
+ * The ctxless event loop then reads each queued event from marked descriptors
+ * and calls the event callback. Both callbacks can stop the loop at any
+ * point.
+ *
+ * The poll_cb argument can be NULL in which case the function falls back to
+ * a default, ppoll() based callback.
+ */
+int gpiod_ctxless_event_monitor_multiple_ext(
+ const char *device, int event_type,
+ const unsigned int *offsets,
+ unsigned int num_lines, bool active_low,
+ const char *consumer, const struct timespec *timeout,
+ gpiod_ctxless_event_poll_cb poll_cb,
+ gpiod_ctxless_event_handle_cb event_cb,
+ void *data, int flags) GPIOD_API;
+
+
/**
* @brief Determine the chip name and line offset of a line with given name.
* @param name The name of the GPIO line to lookup.
@@ -658,6 +813,20 @@ enum {
/**< The active state of a GPIO is active-low. */
};
+/**
+ * @brief Possible internal bias settings.
+ */
+enum {
+ GPIOD_LINE_BIAS_AS_IS = 1,
+ /**< The internal bias state is unknown. */
+ GPIOD_LINE_BIAS_DISABLE,
+ /**< The internal bias is disabled. */
+ GPIOD_LINE_BIAS_PULL_UP,
+ /**< The internal pull-up bias is enabled. */
+ GPIOD_LINE_BIAS_PULL_DOWN,
+ /**< The internal pull-down bias is enabled. */
+};
+
/**
* @brief Read the GPIO line offset.
* @param line GPIO line object.
@@ -697,6 +866,14 @@ int gpiod_line_direction(struct gpiod_line *line) GPIOD_API;
*/
int gpiod_line_active_state(struct gpiod_line *line) GPIOD_API;
+/**
+ * @brief Read the GPIO line bias setting.
+ * @param line GPIO line object.
+ * @return Returns GPIOD_LINE_BIAS_PULL_UP, GPIOD_LINE_BIAS_PULL_DOWN,
+ * GPIOD_LINE_BIAS_DISABLE or GPIOD_LINE_BIAS_AS_IS.
+ */
+int gpiod_line_bias(struct gpiod_line *line) GPIOD_API;
+
/**
* @brief Check if the line is currently in use.
* @param line GPIO line object.
@@ -787,6 +964,12 @@ enum {
/**< The line is an open-source port. */
GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW = GPIOD_BIT(2),
/**< The active state of the line is low (high is the default). */
+ GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE = GPIOD_BIT(3),
+ /**< The line has neither either pull-up nor pull-down resistor */
+ GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN = GPIOD_BIT(4),
+ /**< The line has pull-down resistor enabled */
+ GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP = GPIOD_BIT(5),
+ /**< The line has pull-up resistor enabled */
};
/**
diff --git a/lib/core.c b/lib/core.c
index a21918c..0465de9 100644
--- a/lib/core.c
+++ b/lib/core.c
@@ -36,9 +36,7 @@ struct gpiod_line {
unsigned int offset;
int direction;
int active_state;
- bool used;
- bool open_source;
- bool open_drain;
+ __u32 info_flags;
int state;
@@ -349,19 +347,31 @@ int gpiod_line_active_state(struct gpiod_line *line)
return line->active_state;
}
+int gpiod_line_bias(struct gpiod_line *line)
+{
+ if (line->info_flags & GPIOLINE_FLAG_BIAS_DISABLE)
+ return GPIOD_LINE_BIAS_DISABLE;
+ if (line->info_flags & GPIOLINE_FLAG_BIAS_PULL_UP)
+ return GPIOD_LINE_BIAS_PULL_UP;
+ if (line->info_flags & GPIOLINE_FLAG_BIAS_PULL_DOWN)
+ return GPIOD_LINE_BIAS_PULL_DOWN;
+
+ return GPIOD_LINE_BIAS_AS_IS;
+}
+
bool gpiod_line_is_used(struct gpiod_line *line)
{
- return line->used;
+ return line->info_flags & GPIOLINE_FLAG_KERNEL;
}
bool gpiod_line_is_open_drain(struct gpiod_line *line)
{
- return line->open_drain;
+ return line->info_flags & GPIOLINE_FLAG_OPEN_DRAIN;
}
bool gpiod_line_is_open_source(struct gpiod_line *line)
{
- return line->open_source;
+ return line->info_flags & GPIOLINE_FLAG_OPEN_SOURCE;
}
bool gpiod_line_needs_update(struct gpiod_line *line GPIOD_UNUSED)
@@ -388,9 +398,7 @@ int gpiod_line_update(struct gpiod_line *line)
? GPIOD_LINE_ACTIVE_STATE_LOW
: GPIOD_LINE_ACTIVE_STATE_HIGH;
- line->used = info.flags & GPIOLINE_FLAG_KERNEL;
- line->open_drain = info.flags & GPIOLINE_FLAG_OPEN_DRAIN;
- line->open_source = info.flags & GPIOLINE_FLAG_OPEN_SOURCE;
+ line->info_flags = info.flags;
strncpy(line->name, info.name, sizeof(line->name));
strncpy(line->consumer, info.consumer, sizeof(line->consumer));
@@ -461,6 +469,12 @@ static __u32 line_request_flag_to_gpio_handleflag(int flags)
hflags |= GPIOHANDLE_REQUEST_OPEN_SOURCE;
if (flags & GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW)
hflags |= GPIOHANDLE_REQUEST_ACTIVE_LOW;
+ if (flags & GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE)
+ hflags |= GPIOHANDLE_REQUEST_BIAS_DISABLE;
+ if (flags & GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN)
+ hflags |= GPIOHANDLE_REQUEST_BIAS_PULL_DOWN;
+ if (flags & GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP)
+ hflags |= GPIOHANDLE_REQUEST_BIAS_PULL_UP;
return hflags;
}
diff --git a/lib/ctxless.c b/lib/ctxless.c
index ba85018..014475c 100644
--- a/lib/ctxless.c
+++ b/lib/ctxless.c
@@ -14,6 +14,26 @@
#include <stdio.h>
#include <string.h>
+static int ctxless_flags_to_line_request_flags(bool active_low, int flags)
+{
+ int req_flags = 0;
+
+ if (active_low)
+ req_flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
+ if (flags & GPIOD_CTXLESS_FLAG_OPEN_DRAIN)
+ req_flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN;
+ if (flags & GPIOD_CTXLESS_FLAG_OPEN_SOURCE)
+ req_flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE;
+ if (flags & GPIOD_CTXLESS_FLAG_BIAS_DISABLE)
+ req_flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE;
+ if (flags & GPIOD_CTXLESS_FLAG_BIAS_PULL_UP)
+ req_flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
+ if (flags & GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN)
+ req_flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
+
+ return req_flags;
+}
+
int gpiod_ctxless_get_value(const char *device, unsigned int offset,
bool active_low, const char *consumer)
{
@@ -27,16 +47,44 @@ int gpiod_ctxless_get_value(const char *device, unsigned int offset,
return value;
}
+int gpiod_ctxless_get_value_ext(const char *device, unsigned int offset,
+ bool active_low, const char *consumer,
+ int flags)
+{
+ int value, rv;
+
+ rv = gpiod_ctxless_get_value_multiple_ext(device, &offset, &value, 1,
+ active_low, consumer, flags);
+ if (rv < 0)
+ return rv;
+
+ return value;
+}
+
int gpiod_ctxless_get_value_multiple(const char *device,
const unsigned int *offsets, int *values,
unsigned int num_lines, bool active_low,
const char *consumer)
+{
+ int rv;
+
+ rv = gpiod_ctxless_get_value_multiple_ext(device, offsets, values,
+ num_lines, active_low,
+ consumer, 0);
+ return rv;
+}
+
+int gpiod_ctxless_get_value_multiple_ext(const char *device,
+ const unsigned int *offsets,
+ int *values, unsigned int num_lines,
+ bool active_low,
+ const char *consumer, int flags)
{
struct gpiod_line_bulk bulk;
struct gpiod_chip *chip;
struct gpiod_line *line;
unsigned int i;
- int rv, flags;
+ int rv, req_flags;
if (!num_lines || num_lines > GPIOD_LINE_BULK_MAX_LINES) {
errno = EINVAL;
@@ -59,9 +107,8 @@ int gpiod_ctxless_get_value_multiple(const char *device,
gpiod_line_bulk_add(&bulk, line);
}
- flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0;
-
- rv = gpiod_line_request_bulk_input_flags(&bulk, consumer, flags);
+ req_flags = ctxless_flags_to_line_request_flags(active_low, flags);
+ rv = gpiod_line_request_bulk_input_flags(&bulk, consumer, req_flags);
if (rv < 0) {
gpiod_chip_close(chip);
return -1;
@@ -83,17 +130,39 @@ int gpiod_ctxless_set_value(const char *device, unsigned int offset, int value,
active_low, consumer, cb, data);
}
+int gpiod_ctxless_set_value_ext(const char *device, unsigned int offset,
+ int value, bool active_low,
+ const char *consumer,
+ gpiod_ctxless_set_value_cb cb,
+ void *data, int flags)
+{
+ return gpiod_ctxless_set_value_multiple_ext(device, &offset, &value,
+ 1, active_low, consumer,
+ cb, data, flags);
+}
+
int gpiod_ctxless_set_value_multiple(const char *device,
const unsigned int *offsets,
const int *values, unsigned int num_lines,
bool active_low, const char *consumer,
gpiod_ctxless_set_value_cb cb, void *data)
+{
+ return gpiod_ctxless_set_value_multiple_ext(device, offsets, values,
+ num_lines, active_low,
+ consumer, cb, data, 0);
+}
+
+int gpiod_ctxless_set_value_multiple_ext(
+ const char *device, const unsigned int *offsets,
+ const int *values, unsigned int num_lines,
+ bool active_low, const char *consumer,
+ gpiod_ctxless_set_value_cb cb, void *data, int flags)
{
struct gpiod_line_bulk bulk;
struct gpiod_chip *chip;
struct gpiod_line *line;
unsigned int i;
- int rv, flags;
+ int rv, req_flags;
if (!num_lines || num_lines > GPIOD_LINE_BULK_MAX_LINES) {
errno = EINVAL;
@@ -116,10 +185,9 @@ int gpiod_ctxless_set_value_multiple(const char *device,
gpiod_line_bulk_add(&bulk, line);
}
- flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0;
-
+ req_flags = ctxless_flags_to_line_request_flags(active_low, flags);
rv = gpiod_line_request_bulk_output_flags(&bulk, consumer,
- flags, values);
+ req_flags, values);
if (rv < 0) {
gpiod_chip_close(chip);
return -1;
@@ -216,6 +284,19 @@ int gpiod_ctxless_event_monitor(const char *device, int event_type,
poll_cb, event_cb, data);
}
+int gpiod_ctxless_event_monitor_ext(const char *device, int event_type,
+ unsigned int offset, bool active_low,
+ const char *consumer,
+ const struct timespec *timeout,
+ gpiod_ctxless_event_poll_cb poll_cb,
+ gpiod_ctxless_event_handle_cb event_cb,
+ void *data, int flags)
+{
+ return gpiod_ctxless_event_monitor_multiple_ext(
+ device, event_type, &offset, 1, active_low,
+ consumer, timeout, poll_cb, event_cb, data, flags);
+}
+
int gpiod_ctxless_event_monitor_multiple(
const char *device, int event_type,
const unsigned int *offsets,
@@ -225,6 +306,21 @@ int gpiod_ctxless_event_monitor_multiple(
gpiod_ctxless_event_poll_cb poll_cb,
gpiod_ctxless_event_handle_cb event_cb,
void *data)
+{
+ return gpiod_ctxless_event_monitor_multiple_ext(
+ device, event_type, offsets,
+ num_lines, active_low, consumer, timeout,
+ poll_cb, event_cb, data, 0);
+}
+
+int gpiod_ctxless_event_monitor_multiple_ext(
+ const char *device, int event_type,
+ const unsigned int *offsets,
+ unsigned int num_lines, bool active_low,
+ const char *consumer, const struct timespec *timeout,
+ gpiod_ctxless_event_poll_cb poll_cb,
+ gpiod_ctxless_event_handle_cb event_cb,
+ void *data, int flags)
{
struct gpiod_ctxless_event_poll_fd fds[GPIOD_LINE_BULK_MAX_LINES];
struct gpiod_line_request_config conf;
@@ -259,7 +355,7 @@ int gpiod_ctxless_event_monitor_multiple(
gpiod_line_bulk_add(&bulk, line);
}
- conf.flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0;
+ conf.flags = ctxless_flags_to_line_request_flags(active_low, flags);
conf.consumer = consumer;
if (event_type == GPIOD_CTXLESS_EVENT_RISING_EDGE) {
--
2.24.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [libgpiod][PATCH v3 02/14] tests: add tests for bias flags
2019-11-25 14:31 [libgpiod][PATCH v3 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 01/14] core: add support for bias flags Kent Gibson
@ 2019-11-25 14:31 ` Kent Gibson
2019-11-28 10:28 ` Bartosz Golaszewski
2019-11-25 14:31 ` [libgpiod][PATCH v3 03/14] bindings: cxx: add support " Kent Gibson
` (11 subsequent siblings)
13 siblings, 1 reply; 21+ messages in thread
From: Kent Gibson @ 2019-11-25 14:31 UTC (permalink / raw)
To: linux-gpio, bgolaszewski; +Cc: Kent Gibson
Extend test coverage over the bias flags, gpiod_line_bias and the extended
ctxless functions.
Also update existing tests to check bias flags where line state is checked.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
tests/tests-ctxless.c | 64 +++++++++++++++++++++-
tests/tests-event.c | 120 ++++++++++++++++++++++++++++++++++++++++++
tests/tests-line.c | 98 ++++++++++++++++++++++++++++++++++
3 files changed, 280 insertions(+), 2 deletions(-)
diff --git a/tests/tests-ctxless.c b/tests/tests-ctxless.c
index c1e1ca6..76b9a7c 100644
--- a/tests/tests-ctxless.c
+++ b/tests/tests-ctxless.c
@@ -26,11 +26,41 @@ GPIOD_TEST_CASE(get_value, 0, { 8 })
g_assert_cmpint(ret, ==, 1);
}
-static void set_value_check(gpointer data G_GNUC_UNUSED)
+GPIOD_TEST_CASE(get_value_ext, 0, { 8 })
+{
+ gint ret;
+
+ ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
+ false, GPIOD_TEST_CONSUMER,
+ GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN);
+ g_assert_cmpint(ret, ==, 0);
+
+ ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
+ false, GPIOD_TEST_CONSUMER,
+ GPIOD_CTXLESS_FLAG_BIAS_PULL_UP);
+ g_assert_cmpint(ret, ==, 1);
+
+ ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
+ true, GPIOD_TEST_CONSUMER
+ , GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN);
+ g_assert_cmpint(ret, ==, 1);
+
+ ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
+ true, GPIOD_TEST_CONSUMER,
+ GPIOD_CTXLESS_FLAG_BIAS_PULL_UP);
+ g_assert_cmpint(ret, ==, 0);
+}
+
+static void set_value_check_hi(gpointer data G_GNUC_UNUSED)
{
g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 1);
}
+static void set_value_check_lo(gpointer data G_GNUC_UNUSED)
+{
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
+}
+
GPIOD_TEST_CASE(set_value, 0, { 8 })
{
gint ret;
@@ -39,13 +69,43 @@ GPIOD_TEST_CASE(set_value, 0, { 8 })
ret = gpiod_ctxless_set_value(gpiod_test_chip_name(0), 3, 1,
false, GPIOD_TEST_CONSUMER,
- set_value_check, NULL);
+ set_value_check_hi, NULL);
gpiod_test_return_if_failed();
g_assert_cmpint(ret, ==, 0);
g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
}
+GPIOD_TEST_CASE(set_value_ext, 0, { 8 })
+{
+ gint ret;
+
+ gpiod_test_chip_set_pull(0, 3, 0);
+
+ ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 1,
+ false, GPIOD_TEST_CONSUMER,
+ set_value_check_hi, NULL, 0);
+ gpiod_test_return_if_failed();
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
+
+ /* test drive flags by checking that sets are caught by emulation */
+ ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 1,
+ false, GPIOD_TEST_CONSUMER, set_value_check_lo,
+ NULL, GPIOD_CTXLESS_FLAG_OPEN_DRAIN);
+ gpiod_test_return_if_failed();
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
+
+ gpiod_test_chip_set_pull(0, 3, 1);
+ ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 0,
+ false, GPIOD_TEST_CONSUMER, set_value_check_hi,
+ NULL, GPIOD_CTXLESS_FLAG_OPEN_SOURCE);
+ gpiod_test_return_if_failed();
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 1);
+}
+
static const guint get_value_multiple_offsets[] = {
1, 3, 4, 5, 6, 7, 8, 9, 13, 14
};
diff --git a/tests/tests-event.c b/tests/tests-event.c
index 28b77ec..d425d1a 100644
--- a/tests/tests-event.c
+++ b/tests/tests-event.c
@@ -196,6 +196,126 @@ GPIOD_TEST_CASE(both_edges_active_low, 0, { 8 })
g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
}
+GPIOD_TEST_CASE(both_edges_bias_disable, 0, { 8 })
+{
+ g_autoptr(GpiodTestEventThread) ev_thread = NULL;
+ g_autoptr(gpiod_chip_struct) chip = NULL;
+ struct timespec ts = { 1, 0 };
+ struct gpiod_line_event ev;
+ struct gpiod_line *line;
+ gint ret;
+
+ chip = gpiod_chip_open(gpiod_test_chip_path(0));
+ g_assert_nonnull(chip);
+ gpiod_test_return_if_failed();
+
+ line = gpiod_chip_get_line(chip, 7);
+ g_assert_nonnull(line);
+ gpiod_test_return_if_failed();
+
+ ret = gpiod_line_request_both_edges_events_flags(line,
+ GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE);
+ g_assert_cmpint(ret, ==, 0);
+
+ ev_thread = gpiod_test_start_event_thread(0, 7, 100);
+
+ ret = gpiod_line_event_wait(line, &ts);
+ g_assert_cmpint(ret, ==, 1);
+
+ ret = gpiod_line_event_read(line, &ev);
+ g_assert_cmpint(ret, ==, 0);
+
+ g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
+
+ ret = gpiod_line_event_wait(line, &ts);
+ g_assert_cmpint(ret, ==, 1);
+
+ ret = gpiod_line_event_read(line, &ev);
+ g_assert_cmpint(ret, ==, 0);
+
+ g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_FALLING_EDGE);
+}
+
+GPIOD_TEST_CASE(both_edges_bias_pull_down, 0, { 8 })
+{
+ g_autoptr(GpiodTestEventThread) ev_thread = NULL;
+ g_autoptr(gpiod_chip_struct) chip = NULL;
+ struct timespec ts = { 1, 0 };
+ struct gpiod_line_event ev;
+ struct gpiod_line *line;
+ gint ret;
+
+ chip = gpiod_chip_open(gpiod_test_chip_path(0));
+ g_assert_nonnull(chip);
+ gpiod_test_return_if_failed();
+
+ line = gpiod_chip_get_line(chip, 7);
+ g_assert_nonnull(line);
+ gpiod_test_return_if_failed();
+
+ ret = gpiod_line_request_both_edges_events_flags(line,
+ GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN);
+ g_assert_cmpint(ret, ==, 0);
+
+ ev_thread = gpiod_test_start_event_thread(0, 7, 100);
+
+ ret = gpiod_line_event_wait(line, &ts);
+ g_assert_cmpint(ret, ==, 1);
+
+ ret = gpiod_line_event_read(line, &ev);
+ g_assert_cmpint(ret, ==, 0);
+
+ g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
+
+ ret = gpiod_line_event_wait(line, &ts);
+ g_assert_cmpint(ret, ==, 1);
+
+ ret = gpiod_line_event_read(line, &ev);
+ g_assert_cmpint(ret, ==, 0);
+
+ g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_FALLING_EDGE);
+}
+
+GPIOD_TEST_CASE(both_edges_bias_pull_up, 0, { 8 })
+{
+ g_autoptr(GpiodTestEventThread) ev_thread = NULL;
+ g_autoptr(gpiod_chip_struct) chip = NULL;
+ struct timespec ts = { 1, 0 };
+ struct gpiod_line_event ev;
+ struct gpiod_line *line;
+ gint ret;
+
+ chip = gpiod_chip_open(gpiod_test_chip_path(0));
+ g_assert_nonnull(chip);
+ gpiod_test_return_if_failed();
+
+ line = gpiod_chip_get_line(chip, 7);
+ g_assert_nonnull(line);
+ gpiod_test_return_if_failed();
+
+ ret = gpiod_line_request_both_edges_events_flags(line,
+ GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
+ g_assert_cmpint(ret, ==, 0);
+
+ ev_thread = gpiod_test_start_event_thread(0, 7, 100);
+
+ ret = gpiod_line_event_wait(line, &ts);
+ g_assert_cmpint(ret, ==, 1);
+
+ ret = gpiod_line_event_read(line, &ev);
+ g_assert_cmpint(ret, ==, 0);
+
+ g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_FALLING_EDGE);
+
+ ret = gpiod_line_event_wait(line, &ts);
+ g_assert_cmpint(ret, ==, 1);
+
+ ret = gpiod_line_event_read(line, &ev);
+ g_assert_cmpint(ret, ==, 0);
+
+ g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
+}
+
GPIOD_TEST_CASE(falling_edge_active_low, 0, { 8 })
{
g_autoptr(GpiodTestEventThread) ev_thread = NULL;
diff --git a/tests/tests-line.c b/tests/tests-line.c
index 205c622..4bf7c02 100644
--- a/tests/tests-line.c
+++ b/tests/tests-line.c
@@ -502,6 +502,7 @@ GPIOD_TEST_CASE(misc_flags, 0, { 8 })
g_assert_false(gpiod_line_is_used(line));
g_assert_false(gpiod_line_is_open_drain(line));
g_assert_false(gpiod_line_is_open_source(line));
+ g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
config.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT;
config.consumer = GPIOD_TEST_CONSUMER;
@@ -513,6 +514,7 @@ GPIOD_TEST_CASE(misc_flags, 0, { 8 })
g_assert_true(gpiod_line_is_used(line));
g_assert_true(gpiod_line_is_open_drain(line));
g_assert_false(gpiod_line_is_open_source(line));
+ g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
g_assert_cmpint(gpiod_line_direction(line), ==,
GPIOD_LINE_DIRECTION_OUTPUT);
@@ -526,8 +528,11 @@ GPIOD_TEST_CASE(misc_flags, 0, { 8 })
g_assert_true(gpiod_line_is_used(line));
g_assert_false(gpiod_line_is_open_drain(line));
g_assert_true(gpiod_line_is_open_source(line));
+ g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
g_assert_cmpint(gpiod_line_direction(line), ==,
GPIOD_LINE_DIRECTION_OUTPUT);
+
+ gpiod_line_release(line);
}
GPIOD_TEST_CASE(misc_flags_work_together, 0, { 8 })
@@ -561,6 +566,7 @@ GPIOD_TEST_CASE(misc_flags_work_together, 0, { 8 })
g_assert_true(gpiod_line_is_used(line));
g_assert_true(gpiod_line_is_open_drain(line));
g_assert_false(gpiod_line_is_open_source(line));
+ g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
g_assert_cmpint(gpiod_line_active_state(line), ==,
GPIOD_LINE_ACTIVE_STATE_LOW);
g_assert_cmpint(gpiod_line_direction(line), ==,
@@ -577,8 +583,59 @@ GPIOD_TEST_CASE(misc_flags_work_together, 0, { 8 })
g_assert_true(gpiod_line_is_used(line));
g_assert_false(gpiod_line_is_open_drain(line));
g_assert_true(gpiod_line_is_open_source(line));
+ g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
g_assert_cmpint(gpiod_line_active_state(line), ==,
GPIOD_LINE_ACTIVE_STATE_LOW);
+
+ gpiod_line_release(line);
+
+ /*
+ * Verify that pull-up/down flags work together
+ * with active_low.
+ */
+
+ config.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT;
+ config.flags = GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN |
+ GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
+
+ ret = gpiod_line_request(line, &config, 0);
+ g_assert_cmpint(ret, ==, 0);
+
+ g_assert_true(gpiod_line_is_used(line));
+ g_assert_false(gpiod_line_is_open_drain(line));
+ g_assert_false(gpiod_line_is_open_source(line));
+ g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_DOWN);
+ g_assert_cmpint(gpiod_line_active_state(line), ==,
+ GPIOD_LINE_ACTIVE_STATE_LOW);
+ g_assert_cmpint(gpiod_line_direction(line), ==,
+ GPIOD_LINE_DIRECTION_INPUT);
+
+ ret = gpiod_line_get_value(line);
+ g_assert_cmpint(ret, ==, 1);
+ g_assert_cmpint(errno, ==, 0);
+
+ gpiod_line_release(line);
+
+ config.flags = GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP |
+ GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
+
+ ret = gpiod_line_request(line, &config, 0);
+ g_assert_cmpint(ret, ==, 0);
+
+ g_assert_true(gpiod_line_is_used(line));
+ g_assert_false(gpiod_line_is_open_drain(line));
+ g_assert_false(gpiod_line_is_open_source(line));
+ g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_UP);
+ g_assert_cmpint(gpiod_line_active_state(line), ==,
+ GPIOD_LINE_ACTIVE_STATE_LOW);
+ g_assert_cmpint(gpiod_line_direction(line), ==,
+ GPIOD_LINE_DIRECTION_INPUT);
+
+ ret = gpiod_line_get_value(line);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(errno, ==, 0);
+
+ gpiod_line_release(line);
}
GPIOD_TEST_CASE(open_source_open_drain_input_mode, 0, { 8 })
@@ -627,6 +684,47 @@ GPIOD_TEST_CASE(open_source_open_drain_simultaneously, 0, { 8 })
g_assert_cmpint(errno, ==, EINVAL);
}
+GPIOD_TEST_CASE(multiple_bias_flags, 0, { 8 })
+{
+ g_autoptr(gpiod_chip_struct) chip = NULL;
+ struct gpiod_line *line;
+ gint ret;
+
+ chip = gpiod_chip_open(gpiod_test_chip_path(0));
+ g_assert_nonnull(chip);
+ gpiod_test_return_if_failed();
+
+ line = gpiod_chip_get_line(chip, 2);
+ g_assert_nonnull(line);
+ gpiod_test_return_if_failed();
+
+ ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
+ GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE |
+ GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN);
+ g_assert_cmpint(ret, ==, -1);
+ g_assert_cmpint(errno, ==, EINVAL);
+
+ ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
+ GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE |
+ GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
+ g_assert_cmpint(ret, ==, -1);
+ g_assert_cmpint(errno, ==, EINVAL);
+
+ ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
+ GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN |
+ GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
+ g_assert_cmpint(ret, ==, -1);
+ g_assert_cmpint(errno, ==, EINVAL);
+
+ ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
+ GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE |
+ GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN |
+ GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
+ g_assert_cmpint(ret, ==, -1);
+ g_assert_cmpint(errno, ==, EINVAL);
+}
+
+
/* Verify that the reference counting of the line fd handle works correctly. */
GPIOD_TEST_CASE(release_one_use_another, 0, { 8 })
{
--
2.24.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [libgpiod][PATCH v3 02/14] tests: add tests for bias flags
2019-11-25 14:31 ` [libgpiod][PATCH v3 02/14] tests: add tests " Kent Gibson
@ 2019-11-28 10:28 ` Bartosz Golaszewski
0 siblings, 0 replies; 21+ messages in thread
From: Bartosz Golaszewski @ 2019-11-28 10:28 UTC (permalink / raw)
To: Kent Gibson; +Cc: linux-gpio
pon., 25 lis 2019 o 15:32 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> Extend test coverage over the bias flags, gpiod_line_bias and the extended
> ctxless functions.
>
> Also update existing tests to check bias flags where line state is checked.
>
The kernel changes this relies on will first be available in v5.5, so
you need to change MIN_KERNEL_VERSION here and elsewhere (C++ and
Python tests).
> Signed-off-by: Kent Gibson <warthog618@gmail.com>
> ---
> tests/tests-ctxless.c | 64 +++++++++++++++++++++-
> tests/tests-event.c | 120 ++++++++++++++++++++++++++++++++++++++++++
> tests/tests-line.c | 98 ++++++++++++++++++++++++++++++++++
> 3 files changed, 280 insertions(+), 2 deletions(-)
>
> diff --git a/tests/tests-ctxless.c b/tests/tests-ctxless.c
> index c1e1ca6..76b9a7c 100644
> --- a/tests/tests-ctxless.c
> +++ b/tests/tests-ctxless.c
> @@ -26,11 +26,41 @@ GPIOD_TEST_CASE(get_value, 0, { 8 })
> g_assert_cmpint(ret, ==, 1);
> }
>
> -static void set_value_check(gpointer data G_GNUC_UNUSED)
> +GPIOD_TEST_CASE(get_value_ext, 0, { 8 })
> +{
> + gint ret;
> +
> + ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
> + false, GPIOD_TEST_CONSUMER,
> + GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN);
> + g_assert_cmpint(ret, ==, 0);
> +
> + ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
> + false, GPIOD_TEST_CONSUMER,
> + GPIOD_CTXLESS_FLAG_BIAS_PULL_UP);
> + g_assert_cmpint(ret, ==, 1);
> +
> + ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
> + true, GPIOD_TEST_CONSUMER
> + , GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN);
> + g_assert_cmpint(ret, ==, 1);
> +
> + ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
> + true, GPIOD_TEST_CONSUMER,
> + GPIOD_CTXLESS_FLAG_BIAS_PULL_UP);
> + g_assert_cmpint(ret, ==, 0);
> +}
> +
> +static void set_value_check_hi(gpointer data G_GNUC_UNUSED)
> {
> g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 1);
> }
>
> +static void set_value_check_lo(gpointer data G_GNUC_UNUSED)
> +{
> + g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
> +}
> +
> GPIOD_TEST_CASE(set_value, 0, { 8 })
> {
> gint ret;
> @@ -39,13 +69,43 @@ GPIOD_TEST_CASE(set_value, 0, { 8 })
>
> ret = gpiod_ctxless_set_value(gpiod_test_chip_name(0), 3, 1,
> false, GPIOD_TEST_CONSUMER,
> - set_value_check, NULL);
> + set_value_check_hi, NULL);
> gpiod_test_return_if_failed();
> g_assert_cmpint(ret, ==, 0);
>
> g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
> }
>
> +GPIOD_TEST_CASE(set_value_ext, 0, { 8 })
> +{
> + gint ret;
> +
> + gpiod_test_chip_set_pull(0, 3, 0);
> +
> + ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 1,
> + false, GPIOD_TEST_CONSUMER,
> + set_value_check_hi, NULL, 0);
> + gpiod_test_return_if_failed();
> + g_assert_cmpint(ret, ==, 0);
> + g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
> +
> + /* test drive flags by checking that sets are caught by emulation */
> + ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 1,
> + false, GPIOD_TEST_CONSUMER, set_value_check_lo,
> + NULL, GPIOD_CTXLESS_FLAG_OPEN_DRAIN);
> + gpiod_test_return_if_failed();
> + g_assert_cmpint(ret, ==, 0);
> + g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
> +
> + gpiod_test_chip_set_pull(0, 3, 1);
> + ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 0,
> + false, GPIOD_TEST_CONSUMER, set_value_check_hi,
> + NULL, GPIOD_CTXLESS_FLAG_OPEN_SOURCE);
> + gpiod_test_return_if_failed();
> + g_assert_cmpint(ret, ==, 0);
> + g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 1);
> +}
> +
> static const guint get_value_multiple_offsets[] = {
> 1, 3, 4, 5, 6, 7, 8, 9, 13, 14
> };
> diff --git a/tests/tests-event.c b/tests/tests-event.c
> index 28b77ec..d425d1a 100644
> --- a/tests/tests-event.c
> +++ b/tests/tests-event.c
> @@ -196,6 +196,126 @@ GPIOD_TEST_CASE(both_edges_active_low, 0, { 8 })
> g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
> }
>
> +GPIOD_TEST_CASE(both_edges_bias_disable, 0, { 8 })
> +{
> + g_autoptr(GpiodTestEventThread) ev_thread = NULL;
> + g_autoptr(gpiod_chip_struct) chip = NULL;
> + struct timespec ts = { 1, 0 };
> + struct gpiod_line_event ev;
> + struct gpiod_line *line;
> + gint ret;
> +
> + chip = gpiod_chip_open(gpiod_test_chip_path(0));
> + g_assert_nonnull(chip);
> + gpiod_test_return_if_failed();
> +
> + line = gpiod_chip_get_line(chip, 7);
> + g_assert_nonnull(line);
> + gpiod_test_return_if_failed();
> +
> + ret = gpiod_line_request_both_edges_events_flags(line,
> + GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE);
> + g_assert_cmpint(ret, ==, 0);
> +
> + ev_thread = gpiod_test_start_event_thread(0, 7, 100);
> +
> + ret = gpiod_line_event_wait(line, &ts);
> + g_assert_cmpint(ret, ==, 1);
> +
> + ret = gpiod_line_event_read(line, &ev);
> + g_assert_cmpint(ret, ==, 0);
> +
> + g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
> +
> + ret = gpiod_line_event_wait(line, &ts);
> + g_assert_cmpint(ret, ==, 1);
> +
> + ret = gpiod_line_event_read(line, &ev);
> + g_assert_cmpint(ret, ==, 0);
> +
> + g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_FALLING_EDGE);
> +}
> +
> +GPIOD_TEST_CASE(both_edges_bias_pull_down, 0, { 8 })
> +{
> + g_autoptr(GpiodTestEventThread) ev_thread = NULL;
> + g_autoptr(gpiod_chip_struct) chip = NULL;
> + struct timespec ts = { 1, 0 };
> + struct gpiod_line_event ev;
> + struct gpiod_line *line;
> + gint ret;
> +
> + chip = gpiod_chip_open(gpiod_test_chip_path(0));
> + g_assert_nonnull(chip);
> + gpiod_test_return_if_failed();
> +
> + line = gpiod_chip_get_line(chip, 7);
> + g_assert_nonnull(line);
> + gpiod_test_return_if_failed();
> +
> + ret = gpiod_line_request_both_edges_events_flags(line,
> + GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN);
> + g_assert_cmpint(ret, ==, 0);
> +
> + ev_thread = gpiod_test_start_event_thread(0, 7, 100);
> +
> + ret = gpiod_line_event_wait(line, &ts);
> + g_assert_cmpint(ret, ==, 1);
> +
> + ret = gpiod_line_event_read(line, &ev);
> + g_assert_cmpint(ret, ==, 0);
> +
> + g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
> +
> + ret = gpiod_line_event_wait(line, &ts);
> + g_assert_cmpint(ret, ==, 1);
> +
> + ret = gpiod_line_event_read(line, &ev);
> + g_assert_cmpint(ret, ==, 0);
> +
> + g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_FALLING_EDGE);
> +}
> +
> +GPIOD_TEST_CASE(both_edges_bias_pull_up, 0, { 8 })
> +{
> + g_autoptr(GpiodTestEventThread) ev_thread = NULL;
> + g_autoptr(gpiod_chip_struct) chip = NULL;
> + struct timespec ts = { 1, 0 };
> + struct gpiod_line_event ev;
> + struct gpiod_line *line;
> + gint ret;
> +
> + chip = gpiod_chip_open(gpiod_test_chip_path(0));
> + g_assert_nonnull(chip);
> + gpiod_test_return_if_failed();
> +
> + line = gpiod_chip_get_line(chip, 7);
> + g_assert_nonnull(line);
> + gpiod_test_return_if_failed();
> +
> + ret = gpiod_line_request_both_edges_events_flags(line,
> + GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
> + g_assert_cmpint(ret, ==, 0);
> +
> + ev_thread = gpiod_test_start_event_thread(0, 7, 100);
> +
> + ret = gpiod_line_event_wait(line, &ts);
> + g_assert_cmpint(ret, ==, 1);
> +
> + ret = gpiod_line_event_read(line, &ev);
> + g_assert_cmpint(ret, ==, 0);
> +
> + g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_FALLING_EDGE);
> +
> + ret = gpiod_line_event_wait(line, &ts);
> + g_assert_cmpint(ret, ==, 1);
> +
> + ret = gpiod_line_event_read(line, &ev);
> + g_assert_cmpint(ret, ==, 0);
> +
> + g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
> +}
> +
> GPIOD_TEST_CASE(falling_edge_active_low, 0, { 8 })
> {
> g_autoptr(GpiodTestEventThread) ev_thread = NULL;
> diff --git a/tests/tests-line.c b/tests/tests-line.c
> index 205c622..4bf7c02 100644
> --- a/tests/tests-line.c
> +++ b/tests/tests-line.c
> @@ -502,6 +502,7 @@ GPIOD_TEST_CASE(misc_flags, 0, { 8 })
> g_assert_false(gpiod_line_is_used(line));
> g_assert_false(gpiod_line_is_open_drain(line));
> g_assert_false(gpiod_line_is_open_source(line));
> + g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
>
> config.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT;
> config.consumer = GPIOD_TEST_CONSUMER;
> @@ -513,6 +514,7 @@ GPIOD_TEST_CASE(misc_flags, 0, { 8 })
> g_assert_true(gpiod_line_is_used(line));
> g_assert_true(gpiod_line_is_open_drain(line));
> g_assert_false(gpiod_line_is_open_source(line));
> + g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
> g_assert_cmpint(gpiod_line_direction(line), ==,
> GPIOD_LINE_DIRECTION_OUTPUT);
>
> @@ -526,8 +528,11 @@ GPIOD_TEST_CASE(misc_flags, 0, { 8 })
> g_assert_true(gpiod_line_is_used(line));
> g_assert_false(gpiod_line_is_open_drain(line));
> g_assert_true(gpiod_line_is_open_source(line));
> + g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
> g_assert_cmpint(gpiod_line_direction(line), ==,
> GPIOD_LINE_DIRECTION_OUTPUT);
> +
> + gpiod_line_release(line);
> }
>
> GPIOD_TEST_CASE(misc_flags_work_together, 0, { 8 })
> @@ -561,6 +566,7 @@ GPIOD_TEST_CASE(misc_flags_work_together, 0, { 8 })
> g_assert_true(gpiod_line_is_used(line));
> g_assert_true(gpiod_line_is_open_drain(line));
> g_assert_false(gpiod_line_is_open_source(line));
> + g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
> g_assert_cmpint(gpiod_line_active_state(line), ==,
> GPIOD_LINE_ACTIVE_STATE_LOW);
> g_assert_cmpint(gpiod_line_direction(line), ==,
> @@ -577,8 +583,59 @@ GPIOD_TEST_CASE(misc_flags_work_together, 0, { 8 })
> g_assert_true(gpiod_line_is_used(line));
> g_assert_false(gpiod_line_is_open_drain(line));
> g_assert_true(gpiod_line_is_open_source(line));
> + g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
> g_assert_cmpint(gpiod_line_active_state(line), ==,
> GPIOD_LINE_ACTIVE_STATE_LOW);
> +
> + gpiod_line_release(line);
> +
> + /*
> + * Verify that pull-up/down flags work together
> + * with active_low.
> + */
> +
> + config.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT;
> + config.flags = GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN |
> + GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
> +
> + ret = gpiod_line_request(line, &config, 0);
> + g_assert_cmpint(ret, ==, 0);
> +
> + g_assert_true(gpiod_line_is_used(line));
> + g_assert_false(gpiod_line_is_open_drain(line));
> + g_assert_false(gpiod_line_is_open_source(line));
> + g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_DOWN);
> + g_assert_cmpint(gpiod_line_active_state(line), ==,
> + GPIOD_LINE_ACTIVE_STATE_LOW);
> + g_assert_cmpint(gpiod_line_direction(line), ==,
> + GPIOD_LINE_DIRECTION_INPUT);
> +
> + ret = gpiod_line_get_value(line);
> + g_assert_cmpint(ret, ==, 1);
> + g_assert_cmpint(errno, ==, 0);
> +
> + gpiod_line_release(line);
> +
> + config.flags = GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP |
> + GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
> +
> + ret = gpiod_line_request(line, &config, 0);
> + g_assert_cmpint(ret, ==, 0);
> +
> + g_assert_true(gpiod_line_is_used(line));
> + g_assert_false(gpiod_line_is_open_drain(line));
> + g_assert_false(gpiod_line_is_open_source(line));
> + g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_UP);
> + g_assert_cmpint(gpiod_line_active_state(line), ==,
> + GPIOD_LINE_ACTIVE_STATE_LOW);
> + g_assert_cmpint(gpiod_line_direction(line), ==,
> + GPIOD_LINE_DIRECTION_INPUT);
> +
> + ret = gpiod_line_get_value(line);
> + g_assert_cmpint(ret, ==, 0);
> + g_assert_cmpint(errno, ==, 0);
> +
> + gpiod_line_release(line);
> }
>
> GPIOD_TEST_CASE(open_source_open_drain_input_mode, 0, { 8 })
> @@ -627,6 +684,47 @@ GPIOD_TEST_CASE(open_source_open_drain_simultaneously, 0, { 8 })
> g_assert_cmpint(errno, ==, EINVAL);
> }
>
> +GPIOD_TEST_CASE(multiple_bias_flags, 0, { 8 })
> +{
> + g_autoptr(gpiod_chip_struct) chip = NULL;
> + struct gpiod_line *line;
> + gint ret;
> +
> + chip = gpiod_chip_open(gpiod_test_chip_path(0));
> + g_assert_nonnull(chip);
> + gpiod_test_return_if_failed();
> +
> + line = gpiod_chip_get_line(chip, 2);
> + g_assert_nonnull(line);
> + gpiod_test_return_if_failed();
> +
> + ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
> + GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE |
> + GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN);
> + g_assert_cmpint(ret, ==, -1);
> + g_assert_cmpint(errno, ==, EINVAL);
> +
> + ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
> + GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE |
> + GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
> + g_assert_cmpint(ret, ==, -1);
> + g_assert_cmpint(errno, ==, EINVAL);
> +
> + ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
> + GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN |
> + GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
> + g_assert_cmpint(ret, ==, -1);
> + g_assert_cmpint(errno, ==, EINVAL);
> +
> + ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
> + GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE |
> + GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN |
> + GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
> + g_assert_cmpint(ret, ==, -1);
> + g_assert_cmpint(errno, ==, EINVAL);
> +}
> +
> +
> /* Verify that the reference counting of the line fd handle works correctly. */
> GPIOD_TEST_CASE(release_one_use_another, 0, { 8 })
> {
> --
> 2.24.0
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [libgpiod][PATCH v3 03/14] bindings: cxx: add support for bias flags
2019-11-25 14:31 [libgpiod][PATCH v3 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 01/14] core: add support for bias flags Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 02/14] tests: add tests " Kent Gibson
@ 2019-11-25 14:31 ` Kent Gibson
2019-11-28 10:29 ` Bartosz Golaszewski
2019-11-25 14:31 ` [libgpiod][PATCH v3 04/14] bindings: cxx: tests: add tests " Kent Gibson
` (10 subsequent siblings)
13 siblings, 1 reply; 21+ messages in thread
From: Kent Gibson @ 2019-11-25 14:31 UTC (permalink / raw)
To: linux-gpio, bgolaszewski; +Cc: Kent Gibson
Add support for bias flags in line requests and returning the line bias
setting via a bias accessor.
Based on initial work by Drew Fustini <drew@pdp7.com>.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
bindings/cxx/gpiod.hpp | 26 ++++++++++++++++++++++++++
bindings/cxx/line.cpp | 19 +++++++++++++++++++
bindings/cxx/line_bulk.cpp | 6 ++++++
3 files changed, 51 insertions(+)
diff --git a/bindings/cxx/gpiod.hpp b/bindings/cxx/gpiod.hpp
index b5a9401..2b1a6ab 100644
--- a/bindings/cxx/gpiod.hpp
+++ b/bindings/cxx/gpiod.hpp
@@ -233,6 +233,12 @@ struct line_request
/**< The line is an open-source port. */
GPIOD_API static const ::std::bitset<32> FLAG_OPEN_DRAIN;
/**< The line is an open-drain port. */
+ GPIOD_API static const ::std::bitset<32> FLAG_BIAS_DISABLE;
+ /**< The line has neither pull-up nor pull-down resistor enabled */
+ GPIOD_API static const ::std::bitset<32> FLAG_BIAS_PULL_DOWN;
+ /**< The line has a configurable pull-down resistor enabled */
+ GPIOD_API static const ::std::bitset<32> FLAG_BIAS_PULL_UP;
+ /**< The line has a configurable pull-up resistor enabled */
::std::string consumer;
/**< Consumer name to pass to the request. */
@@ -320,6 +326,12 @@ public:
*/
GPIOD_API int active_state(void) const;
+ /**
+ * @brief Get current bias of this line.
+ * @return Current bias setting.
+ */
+ GPIOD_API int bias(void) const;
+
/**
* @brief Check if this line is used by the kernel or other user space
* process.
@@ -456,6 +468,20 @@ public:
/**< Line's active state is high. */
};
+ /**
+ * @brief Possible bias settings.
+ */
+ enum : int {
+ BIAS_AS_IS = 1,
+ /**< Line's bias state is unknown. */
+ BIAS_DISABLE,
+ /**< Line's internal bias is disabled. */
+ BIAS_PULL_UP,
+ /**< Line's internal pull-up bias is enabled. */
+ BIAS_PULL_DOWN,
+ /**< Line's internal pull-down bias is enabled. */
+ };
+
private:
line(::gpiod_line* line, const chip& owner);
diff --git a/bindings/cxx/line.cpp b/bindings/cxx/line.cpp
index df6eada..dd6bb6a 100644
--- a/bindings/cxx/line.cpp
+++ b/bindings/cxx/line.cpp
@@ -67,6 +67,25 @@ int line::active_state(void) const
return active == GPIOD_LINE_ACTIVE_STATE_HIGH ? ACTIVE_HIGH : ACTIVE_LOW;
}
+int line::bias(void) const
+{
+ this->throw_if_null();
+
+ int bias = ::gpiod_line_bias(this->_m_line);
+
+ switch (bias) {
+ case GPIOD_LINE_BIAS_PULL_UP:
+ return BIAS_PULL_UP;
+ case GPIOD_LINE_BIAS_PULL_DOWN:
+ return BIAS_PULL_DOWN;
+ case GPIOD_LINE_BIAS_DISABLE:
+ return BIAS_DISABLE;
+ case GPIOD_LINE_BIAS_AS_IS:
+ default:
+ return BIAS_AS_IS;
+ }
+}
+
bool line::is_used(void) const
{
this->throw_if_null();
diff --git a/bindings/cxx/line_bulk.cpp b/bindings/cxx/line_bulk.cpp
index c708c8b..5f1cac4 100644
--- a/bindings/cxx/line_bulk.cpp
+++ b/bindings/cxx/line_bulk.cpp
@@ -14,6 +14,9 @@ namespace gpiod {
const ::std::bitset<32> line_request::FLAG_ACTIVE_LOW(GPIOD_BIT(0));
const ::std::bitset<32> line_request::FLAG_OPEN_SOURCE(GPIOD_BIT(1));
const ::std::bitset<32> line_request::FLAG_OPEN_DRAIN(GPIOD_BIT(2));
+const ::std::bitset<32> line_request::FLAG_BIAS_DISABLE(GPIOD_BIT(3));
+const ::std::bitset<32> line_request::FLAG_BIAS_PULL_DOWN(GPIOD_BIT(4));
+const ::std::bitset<32> line_request::FLAG_BIAS_PULL_UP(GPIOD_BIT(5));
namespace {
@@ -38,6 +41,9 @@ const ::std::map<::std::bitset<32>, int, bitset_cmp> reqflag_mapping = {
{ line_request::FLAG_ACTIVE_LOW, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW, },
{ line_request::FLAG_OPEN_DRAIN, GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN, },
{ line_request::FLAG_OPEN_SOURCE, GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE, },
+ { line_request::FLAG_BIAS_DISABLE, GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE, },
+ { line_request::FLAG_BIAS_PULL_DOWN, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN, },
+ { line_request::FLAG_BIAS_PULL_UP, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP, },
};
} /* namespace */
--
2.24.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [libgpiod][PATCH v3 03/14] bindings: cxx: add support for bias flags
2019-11-25 14:31 ` [libgpiod][PATCH v3 03/14] bindings: cxx: add support " Kent Gibson
@ 2019-11-28 10:29 ` Bartosz Golaszewski
0 siblings, 0 replies; 21+ messages in thread
From: Bartosz Golaszewski @ 2019-11-28 10:29 UTC (permalink / raw)
To: Kent Gibson; +Cc: linux-gpio
pon., 25 lis 2019 o 15:32 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> Add support for bias flags in line requests and returning the line bias
> setting via a bias accessor.
>
> Based on initial work by Drew Fustini <drew@pdp7.com>.
>
> Signed-off-by: Kent Gibson <warthog618@gmail.com>
> ---
> bindings/cxx/gpiod.hpp | 26 ++++++++++++++++++++++++++
> bindings/cxx/line.cpp | 19 +++++++++++++++++++
> bindings/cxx/line_bulk.cpp | 6 ++++++
> 3 files changed, 51 insertions(+)
>
> diff --git a/bindings/cxx/gpiod.hpp b/bindings/cxx/gpiod.hpp
> index b5a9401..2b1a6ab 100644
> --- a/bindings/cxx/gpiod.hpp
> +++ b/bindings/cxx/gpiod.hpp
> @@ -233,6 +233,12 @@ struct line_request
> /**< The line is an open-source port. */
> GPIOD_API static const ::std::bitset<32> FLAG_OPEN_DRAIN;
> /**< The line is an open-drain port. */
> + GPIOD_API static const ::std::bitset<32> FLAG_BIAS_DISABLE;
> + /**< The line has neither pull-up nor pull-down resistor enabled */
> + GPIOD_API static const ::std::bitset<32> FLAG_BIAS_PULL_DOWN;
> + /**< The line has a configurable pull-down resistor enabled */
> + GPIOD_API static const ::std::bitset<32> FLAG_BIAS_PULL_UP;
> + /**< The line has a configurable pull-up resistor enabled */
>
> ::std::string consumer;
> /**< Consumer name to pass to the request. */
> @@ -320,6 +326,12 @@ public:
> */
> GPIOD_API int active_state(void) const;
>
> + /**
> + * @brief Get current bias of this line.
> + * @return Current bias setting.
> + */
> + GPIOD_API int bias(void) const;
> +
> /**
> * @brief Check if this line is used by the kernel or other user space
> * process.
> @@ -456,6 +468,20 @@ public:
> /**< Line's active state is high. */
> };
>
> + /**
> + * @brief Possible bias settings.
> + */
> + enum : int {
> + BIAS_AS_IS = 1,
> + /**< Line's bias state is unknown. */
> + BIAS_DISABLE,
> + /**< Line's internal bias is disabled. */
> + BIAS_PULL_UP,
> + /**< Line's internal pull-up bias is enabled. */
> + BIAS_PULL_DOWN,
> + /**< Line's internal pull-down bias is enabled. */
> + };
> +
> private:
>
> line(::gpiod_line* line, const chip& owner);
> diff --git a/bindings/cxx/line.cpp b/bindings/cxx/line.cpp
> index df6eada..dd6bb6a 100644
> --- a/bindings/cxx/line.cpp
> +++ b/bindings/cxx/line.cpp
> @@ -67,6 +67,25 @@ int line::active_state(void) const
> return active == GPIOD_LINE_ACTIVE_STATE_HIGH ? ACTIVE_HIGH : ACTIVE_LOW;
> }
>
> +int line::bias(void) const
> +{
> + this->throw_if_null();
> +
> + int bias = ::gpiod_line_bias(this->_m_line);
> +
> + switch (bias) {
> + case GPIOD_LINE_BIAS_PULL_UP:
> + return BIAS_PULL_UP;
> + case GPIOD_LINE_BIAS_PULL_DOWN:
> + return BIAS_PULL_DOWN;
> + case GPIOD_LINE_BIAS_DISABLE:
> + return BIAS_DISABLE;
> + case GPIOD_LINE_BIAS_AS_IS:
> + default:
> + return BIAS_AS_IS;
> + }
I think that for consistency with other mappings, this can be made
shorter by using std::map - please see line_bulk.cpp.
Bart
> +}
> +
> bool line::is_used(void) const
> {
> this->throw_if_null();
> diff --git a/bindings/cxx/line_bulk.cpp b/bindings/cxx/line_bulk.cpp
> index c708c8b..5f1cac4 100644
> --- a/bindings/cxx/line_bulk.cpp
> +++ b/bindings/cxx/line_bulk.cpp
> @@ -14,6 +14,9 @@ namespace gpiod {
> const ::std::bitset<32> line_request::FLAG_ACTIVE_LOW(GPIOD_BIT(0));
> const ::std::bitset<32> line_request::FLAG_OPEN_SOURCE(GPIOD_BIT(1));
> const ::std::bitset<32> line_request::FLAG_OPEN_DRAIN(GPIOD_BIT(2));
> +const ::std::bitset<32> line_request::FLAG_BIAS_DISABLE(GPIOD_BIT(3));
> +const ::std::bitset<32> line_request::FLAG_BIAS_PULL_DOWN(GPIOD_BIT(4));
> +const ::std::bitset<32> line_request::FLAG_BIAS_PULL_UP(GPIOD_BIT(5));
>
> namespace {
>
> @@ -38,6 +41,9 @@ const ::std::map<::std::bitset<32>, int, bitset_cmp> reqflag_mapping = {
> { line_request::FLAG_ACTIVE_LOW, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW, },
> { line_request::FLAG_OPEN_DRAIN, GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN, },
> { line_request::FLAG_OPEN_SOURCE, GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE, },
> + { line_request::FLAG_BIAS_DISABLE, GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE, },
> + { line_request::FLAG_BIAS_PULL_DOWN, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN, },
> + { line_request::FLAG_BIAS_PULL_UP, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP, },
> };
>
> } /* namespace */
> --
> 2.24.0
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [libgpiod][PATCH v3 04/14] bindings: cxx: tests: add tests for bias flags
2019-11-25 14:31 [libgpiod][PATCH v3 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
` (2 preceding siblings ...)
2019-11-25 14:31 ` [libgpiod][PATCH v3 03/14] bindings: cxx: add support " Kent Gibson
@ 2019-11-25 14:31 ` Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 05/14] bindings: python: add support " Kent Gibson
` (9 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Kent Gibson @ 2019-11-25 14:31 UTC (permalink / raw)
To: linux-gpio, bgolaszewski; +Cc: Kent Gibson
Extend test coverage over the bias flags in requests and the bias setting
returned by line.bias().
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
bindings/cxx/tests/tests-line.cpp | 87 +++++++++++++++++++++++++++++++
1 file changed, 87 insertions(+)
diff --git a/bindings/cxx/tests/tests-line.cpp b/bindings/cxx/tests/tests-line.cpp
index fedaa05..9a0b488 100644
--- a/bindings/cxx/tests/tests-line.cpp
+++ b/bindings/cxx/tests/tests-line.cpp
@@ -52,6 +52,9 @@ TEST_CASE("Line information can be correctly retrieved", "[line]")
REQUIRE(line.consumer().empty());
REQUIRE_FALSE(line.is_requested());
REQUIRE_FALSE(line.is_used());
+ REQUIRE_FALSE(line.is_open_drain());
+ REQUIRE_FALSE(line.is_open_source());
+ REQUIRE(line.bias() == ::gpiod::line::BIAS_AS_IS);
}
SECTION("exported line")
@@ -68,6 +71,9 @@ TEST_CASE("Line information can be correctly retrieved", "[line]")
REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
REQUIRE(line.is_requested());
REQUIRE(line.is_used());
+ REQUIRE_FALSE(line.is_open_drain());
+ REQUIRE_FALSE(line.is_open_source());
+ REQUIRE(line.bias() == ::gpiod::line::BIAS_AS_IS);
}
SECTION("exported line with flags")
@@ -88,6 +94,87 @@ TEST_CASE("Line information can be correctly retrieved", "[line]")
REQUIRE(line.is_used());
REQUIRE(line.is_open_drain());
REQUIRE_FALSE(line.is_open_source());
+ REQUIRE(line.bias() == ::gpiod::line::BIAS_AS_IS);
+ }
+
+ SECTION("exported open source line")
+ {
+ ::gpiod::line_request config;
+
+ config.consumer = consumer.c_str();
+ config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+ config.flags = ::gpiod::line_request::FLAG_OPEN_SOURCE;
+ line.request(config);
+
+ REQUIRE(line.offset() == 4);
+ REQUIRE(line.name() == "gpio-mockup-A-4");
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
+ REQUIRE(line.is_requested());
+ REQUIRE(line.is_used());
+ REQUIRE_FALSE(line.is_open_drain());
+ REQUIRE(line.is_open_source());
+ REQUIRE(line.bias() == ::gpiod::line::BIAS_AS_IS);
+ }
+
+ SECTION("exported bias disable line")
+ {
+ ::gpiod::line_request config;
+
+ config.consumer = consumer.c_str();
+ config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+ config.flags = ::gpiod::line_request::FLAG_BIAS_DISABLE;
+ line.request(config);
+
+ REQUIRE(line.offset() == 4);
+ REQUIRE(line.name() == "gpio-mockup-A-4");
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
+ REQUIRE(line.is_requested());
+ REQUIRE(line.is_used());
+ REQUIRE_FALSE(line.is_open_drain());
+ REQUIRE_FALSE(line.is_open_source());
+ REQUIRE(line.bias() == ::gpiod::line::BIAS_DISABLE);
+ }
+
+ SECTION("exported pull-down line")
+ {
+ ::gpiod::line_request config;
+
+ config.consumer = consumer.c_str();
+ config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+ config.flags = ::gpiod::line_request::FLAG_BIAS_PULL_DOWN;
+ line.request(config);
+
+ REQUIRE(line.offset() == 4);
+ REQUIRE(line.name() == "gpio-mockup-A-4");
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
+ REQUIRE(line.is_requested());
+ REQUIRE(line.is_used());
+ REQUIRE_FALSE(line.is_open_drain());
+ REQUIRE_FALSE(line.is_open_source());
+ REQUIRE(line.bias() == ::gpiod::line::BIAS_PULL_DOWN);
+ }
+
+ SECTION("exported pull-up line")
+ {
+ ::gpiod::line_request config;
+
+ config.consumer = consumer.c_str();
+ config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+ config.flags = ::gpiod::line_request::FLAG_BIAS_PULL_UP;
+ line.request(config);
+
+ REQUIRE(line.offset() == 4);
+ REQUIRE(line.name() == "gpio-mockup-A-4");
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
+ REQUIRE(line.is_requested());
+ REQUIRE(line.is_used());
+ REQUIRE_FALSE(line.is_open_drain());
+ REQUIRE_FALSE(line.is_open_source());
+ REQUIRE(line.bias() == ::gpiod::line::BIAS_PULL_UP);
}
SECTION("update line info")
--
2.24.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [libgpiod][PATCH v3 05/14] bindings: python: add support for bias flags
2019-11-25 14:31 [libgpiod][PATCH v3 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
` (3 preceding siblings ...)
2019-11-25 14:31 ` [libgpiod][PATCH v3 04/14] bindings: cxx: tests: add tests " Kent Gibson
@ 2019-11-25 14:31 ` Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 06/14] bindings: python: tests: add tests " Kent Gibson
` (8 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Kent Gibson @ 2019-11-25 14:31 UTC (permalink / raw)
To: linux-gpio, bgolaszewski; +Cc: Kent Gibson
Add support for bias flags in line requests and returning the line bias
setting via a bias accessor.
Based on initial work by Drew Fustini <drew@pdp7.com>.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
bindings/python/gpiodmodule.c | 82 +++++++++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)
diff --git a/bindings/python/gpiodmodule.c b/bindings/python/gpiodmodule.c
index 2f6ef51..4723771 100644
--- a/bindings/python/gpiodmodule.c
+++ b/bindings/python/gpiodmodule.c
@@ -60,6 +60,9 @@ enum {
gpiod_LINE_REQ_FLAG_OPEN_DRAIN = GPIOD_BIT(0),
gpiod_LINE_REQ_FLAG_OPEN_SOURCE = GPIOD_BIT(1),
gpiod_LINE_REQ_FLAG_ACTIVE_LOW = GPIOD_BIT(2),
+ gpiod_LINE_REQ_FLAG_BIAS_DISABLE = GPIOD_BIT(3),
+ gpiod_LINE_REQ_FLAG_BIAS_PULL_DOWN = GPIOD_BIT(4),
+ gpiod_LINE_REQ_FLAG_BIAS_PULL_UP = GPIOD_BIT(5),
};
enum {
@@ -72,6 +75,13 @@ enum {
gpiod_ACTIVE_LOW,
};
+enum {
+ gpiod_BIAS_AS_IS = 1,
+ gpiod_BIAS_DISABLE,
+ gpiod_BIAS_PULL_UP,
+ gpiod_BIAS_PULL_DOWN,
+};
+
enum {
gpiod_RISING_EDGE = 1,
gpiod_FALLING_EDGE,
@@ -358,6 +368,34 @@ static PyObject *gpiod_Line_active_state(gpiod_LineObject *self,
return ret;
}
+PyDoc_STRVAR(gpiod_Line_bias_doc,
+"bias() -> integer\n"
+"\n"
+"Get the bias setting of this GPIO line.");
+
+static PyObject *gpiod_Line_bias(gpiod_LineObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ int bias;
+
+ if (gpiod_ChipIsClosed(self->owner))
+ return NULL;
+
+ bias = gpiod_line_bias(self->line);
+
+ switch (bias) {
+ case GPIOD_LINE_BIAS_PULL_UP:
+ return Py_BuildValue("I", gpiod_BIAS_PULL_UP);
+ case GPIOD_LINE_BIAS_PULL_DOWN:
+ return Py_BuildValue("I", gpiod_BIAS_PULL_DOWN);
+ case GPIOD_LINE_BIAS_DISABLE:
+ return Py_BuildValue("I", gpiod_BIAS_DISABLE);
+ case GPIOD_LINE_BIAS_AS_IS:
+ default:
+ return Py_BuildValue("I", gpiod_BIAS_AS_IS);
+ }
+}
+
PyDoc_STRVAR(gpiod_Line_is_used_doc,
"is_used() -> boolean\n"
"\n"
@@ -752,6 +790,12 @@ static PyMethodDef gpiod_Line_methods[] = {
.ml_flags = METH_NOARGS,
.ml_doc = gpiod_Line_active_state_doc,
},
+ {
+ .ml_name = "bias",
+ .ml_meth = (PyCFunction)gpiod_Line_bias,
+ .ml_flags = METH_NOARGS,
+ .ml_doc = gpiod_Line_bias_doc,
+ },
{
.ml_name = "is_used",
.ml_meth = (PyCFunction)gpiod_Line_is_used,
@@ -1030,6 +1074,12 @@ static void gpiod_MakeRequestConfig(struct gpiod_line_request_config *conf,
conf->flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE;
if (flags & gpiod_LINE_REQ_FLAG_ACTIVE_LOW)
conf->flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
+ if (flags & gpiod_LINE_REQ_FLAG_BIAS_DISABLE)
+ conf->flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE;
+ if (flags & gpiod_LINE_REQ_FLAG_BIAS_PULL_DOWN)
+ conf->flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
+ if (flags & gpiod_LINE_REQ_FLAG_BIAS_PULL_UP)
+ conf->flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
}
PyDoc_STRVAR(gpiod_LineBulk_request_doc,
@@ -2313,6 +2363,26 @@ static gpiod_ConstDescr gpiod_ConstList[] = {
.name = "ACTIVE_LOW",
.val = gpiod_ACTIVE_LOW,
},
+ {
+ .typeobj = &gpiod_LineType,
+ .name = "BIAS_AS_IS",
+ .val = gpiod_BIAS_AS_IS,
+ },
+ {
+ .typeobj = &gpiod_LineType,
+ .name = "BIAS_DISABLE",
+ .val = gpiod_BIAS_DISABLE,
+ },
+ {
+ .typeobj = &gpiod_LineType,
+ .name = "BIAS_PULL_UP",
+ .val = gpiod_BIAS_PULL_UP,
+ },
+ {
+ .typeobj = &gpiod_LineType,
+ .name = "BIAS_PULL_DOWN",
+ .val = gpiod_BIAS_PULL_DOWN,
+ },
{
.typeobj = &gpiod_LineEventType,
.name = "RISING_EDGE",
@@ -2381,6 +2451,18 @@ static gpiod_ModuleConst gpiod_ModuleConsts[] = {
.name = "LINE_REQ_FLAG_ACTIVE_LOW",
.value = gpiod_LINE_REQ_FLAG_ACTIVE_LOW,
},
+ {
+ .name = "LINE_REQ_FLAG_BIAS_DISABLE",
+ .value = gpiod_LINE_REQ_FLAG_BIAS_DISABLE,
+ },
+ {
+ .name = "LINE_REQ_FLAG_BIAS_PULL_DOWN",
+ .value = gpiod_LINE_REQ_FLAG_BIAS_PULL_DOWN,
+ },
+ {
+ .name = "LINE_REQ_FLAG_BIAS_PULL_UP",
+ .value = gpiod_LINE_REQ_FLAG_BIAS_PULL_UP,
+ },
{ }
};
--
2.24.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [libgpiod][PATCH v3 06/14] bindings: python: tests: add tests for bias flags
2019-11-25 14:31 [libgpiod][PATCH v3 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
` (4 preceding siblings ...)
2019-11-25 14:31 ` [libgpiod][PATCH v3 05/14] bindings: python: add support " Kent Gibson
@ 2019-11-25 14:31 ` Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 07/14] core: add support for SET_CONFIG Kent Gibson
` (7 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Kent Gibson @ 2019-11-25 14:31 UTC (permalink / raw)
To: linux-gpio, bgolaszewski; +Cc: Kent Gibson
Extend test coverage to cover the bias flags in requests and the bias
setting returned by line.bias().
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
bindings/python/tests/gpiod_py_test.py | 91 ++++++++++++++++++++++++++
1 file changed, 91 insertions(+)
diff --git a/bindings/python/tests/gpiod_py_test.py b/bindings/python/tests/gpiod_py_test.py
index ed31c8e..9330b43 100755
--- a/bindings/python/tests/gpiod_py_test.py
+++ b/bindings/python/tests/gpiod_py_test.py
@@ -306,6 +306,97 @@ class LineInfo(MockupTestCase):
self.assertTrue(line.is_requested())
self.assertTrue(line.is_open_drain())
self.assertFalse(line.is_open_source())
+ self.assertEqual(line.bias(), gpiod.Line.BIAS_AS_IS)
+
+ def test_exported_open_drain_line(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(4)
+ flags = gpiod.LINE_REQ_FLAG_OPEN_DRAIN
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT,
+ flags=flags)
+ self.assertEqual(line.offset(), 4)
+ self.assertEqual(line.name(), 'gpio-mockup-A-4')
+ self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_HIGH)
+ self.assertEqual(line.consumer(), default_consumer)
+ self.assertTrue(line.is_used())
+ self.assertTrue(line.is_requested())
+ self.assertTrue(line.is_open_drain())
+ self.assertFalse(line.is_open_source())
+ self.assertEqual(line.bias(), gpiod.Line.BIAS_AS_IS)
+
+ def test_exported_open_source_line(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(4)
+ flags = gpiod.LINE_REQ_FLAG_OPEN_SOURCE
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT,
+ flags=flags)
+ self.assertEqual(line.offset(), 4)
+ self.assertEqual(line.name(), 'gpio-mockup-A-4')
+ self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_HIGH)
+ self.assertEqual(line.consumer(), default_consumer)
+ self.assertTrue(line.is_used())
+ self.assertTrue(line.is_requested())
+ self.assertFalse(line.is_open_drain())
+ self.assertTrue(line.is_open_source())
+ self.assertEqual(line.bias(), gpiod.Line.BIAS_AS_IS)
+
+ def test_exported_bias_disable_line(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(4)
+ flags = gpiod.LINE_REQ_FLAG_BIAS_DISABLE
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT,
+ flags=flags)
+ self.assertEqual(line.offset(), 4)
+ self.assertEqual(line.name(), 'gpio-mockup-A-4')
+ self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_HIGH)
+ self.assertEqual(line.consumer(), default_consumer)
+ self.assertTrue(line.is_used())
+ self.assertTrue(line.is_requested())
+ self.assertFalse(line.is_open_drain())
+ self.assertFalse(line.is_open_source())
+ self.assertEqual(line.bias(), gpiod.Line.BIAS_DISABLE)
+
+ def test_exported_bias_pull_down_line(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(4)
+ flags = gpiod.LINE_REQ_FLAG_BIAS_PULL_DOWN
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT,
+ flags=flags)
+ self.assertEqual(line.offset(), 4)
+ self.assertEqual(line.name(), 'gpio-mockup-A-4')
+ self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_HIGH)
+ self.assertEqual(line.consumer(), default_consumer)
+ self.assertTrue(line.is_used())
+ self.assertTrue(line.is_requested())
+ self.assertFalse(line.is_open_drain())
+ self.assertFalse(line.is_open_source())
+ self.assertEqual(line.bias(), gpiod.Line.BIAS_PULL_DOWN)
+
+ def test_exported_bias_pull_up_line(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(4)
+ flags = gpiod.LINE_REQ_FLAG_BIAS_PULL_UP
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT,
+ flags=flags)
+ self.assertEqual(line.offset(), 4)
+ self.assertEqual(line.name(), 'gpio-mockup-A-4')
+ self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_HIGH)
+ self.assertEqual(line.consumer(), default_consumer)
+ self.assertTrue(line.is_used())
+ self.assertTrue(line.is_requested())
+ self.assertFalse(line.is_open_drain())
+ self.assertFalse(line.is_open_source())
+ self.assertEqual(line.bias(), gpiod.Line.BIAS_PULL_UP)
def test_update_line_info(self):
with gpiod.Chip(mockup.chip_name(0)) as chip:
--
2.24.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [libgpiod][PATCH v3 07/14] core: add support for SET_CONFIG
2019-11-25 14:31 [libgpiod][PATCH v3 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
` (5 preceding siblings ...)
2019-11-25 14:31 ` [libgpiod][PATCH v3 06/14] bindings: python: tests: add tests " Kent Gibson
@ 2019-11-25 14:31 ` Kent Gibson
2019-11-28 10:29 ` Bartosz Golaszewski
2019-11-25 14:31 ` [libgpiod][PATCH v3 08/14] tests: add tests " Kent Gibson
` (6 subsequent siblings)
13 siblings, 1 reply; 21+ messages in thread
From: Kent Gibson @ 2019-11-25 14:31 UTC (permalink / raw)
To: linux-gpio, bgolaszewski; +Cc: Kent Gibson
Extend the libgpiod API to support the setting line configuration using the
GPIO GPIOHANDLE_SET_CONFIG_IOCTL uAPI ioctl.
The core change is the addition of gpiod_line_set_config, which provides a
low level wrapper around the ioctl.
Additionally, higher level helper functions, gpiod_line_set_flags,
gpiod_line_set_direction_input, and gpiod_line_set_direction_output provide
slightly simplified APIs for common use cases.
Bulk forms of all functions are also provided.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
include/gpiod.h | 123 +++++++++++++++++++++++++++++++
lib/core.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 307 insertions(+), 3 deletions(-)
diff --git a/include/gpiod.h b/include/gpiod.h
index 86c3ea9..185e2f4 100644
--- a/include/gpiod.h
+++ b/include/gpiod.h
@@ -1246,6 +1246,15 @@ void gpiod_line_release_bulk(struct gpiod_line_bulk *bulk) GPIOD_API;
*/
bool gpiod_line_is_requested(struct gpiod_line *line) GPIOD_API;
+/**
+ * @brief Check if the calling user has ownership of this line for values,
+ * not events.
+ * @param line GPIO line object.
+ * @return True if given line was requested for reading/setting values,
+ * false otherwise.
+ */
+bool gpiod_line_is_requested_values(struct gpiod_line *line) GPIOD_API;
+
/**
* @brief Check if the calling user has neither requested ownership of this
* line nor configured any event notifications.
@@ -1296,6 +1305,7 @@ int gpiod_line_set_value(struct gpiod_line *line, int value) GPIOD_API;
* @brief Set the values of a set of GPIO lines.
* @param bulk Set of GPIO lines to reserve.
* @param values An array holding line_bulk->num_lines new values for lines.
+ * A NULL pointer is interpreted as a logical low for all lines.
* @return 0 is the operation succeeds. In case of an error this routine
* returns -1 and sets the last error number.
*
@@ -1305,6 +1315,119 @@ int gpiod_line_set_value(struct gpiod_line *line, int value) GPIOD_API;
int gpiod_line_set_value_bulk(struct gpiod_line_bulk *bulk,
const int *values) GPIOD_API;
+/**
+ * @}
+ *
+ * @defgroup __line_config__ Setting line configuration
+ * @{
+ */
+
+/**
+ * @brief Update the configuration of a single GPIO line.
+ * @param line GPIO line object.
+ * @param direction Updated direction which may be one of
+ * GPIOD_LINE_REQUEST_DIRECTION_AS_IS,
+ * GPIOD_LINE_REQUEST_DIRECTION_INPUT, or
+ * GPIOD_LINE_REQUEST_DIRECTION_OUTPUT.
+ * @param flags Replacement flags.
+ * @param value The new output value for the line when direction is
+ * GPIOD_LINE_REQUEST_DIRECTION_OUTPUT.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ */
+int gpiod_line_set_config(struct gpiod_line *line, int direction,
+ int flags, int value) GPIOD_API;
+
+/**
+ * @brief Update the configuration of a set of GPIO lines.
+ * @param bulk Set of GPIO lines.
+ * @param direction Updated direction which may be one of
+ * GPIOD_LINE_REQUEST_DIRECTION_AS_IS,
+ * GPIOD_LINE_REQUEST_DIRECTION_INPUT, or
+ * GPIOD_LINE_REQUEST_DIRECTION_OUTPUT.
+ * @param flags Replacement flags.
+ * @param values An array holding line_bulk->num_lines new logical values
+ * for lines when direction is
+ * GPIOD_LINE_REQUEST_DIRECTION_OUTPUT.
+ * A NULL pointer is interpreted as a logical low for all lines.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ *
+ * If the lines were not previously requested together, the behavior is
+ * undefined.
+ */
+int gpiod_line_set_config_bulk(struct gpiod_line_bulk *bulk,
+ int direction, int flags,
+ const int *values) GPIOD_API;
+
+
+/**
+ * @brief Update the configuration flags of a single GPIO line.
+ * @param line GPIO line object.
+ * @param flags Replacement flags.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ */
+int gpiod_line_set_flags(struct gpiod_line *line, int flags) GPIOD_API;
+
+/**
+ * @brief Update the configuration flags of a set of GPIO lines.
+ * @param bulk Set of GPIO lines.
+ * @param flags Replacement flags.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ *
+ * If the lines were not previously requested together, the behavior is
+ * undefined.
+ */
+int gpiod_line_set_flags_bulk(struct gpiod_line_bulk *bulk,
+ int flags) GPIOD_API;
+
+/**
+ * @brief Set the direction of a single GPIO line to input.
+ * @param line GPIO line object.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ */
+int gpiod_line_set_direction_input(struct gpiod_line *line) GPIOD_API;
+
+/**
+ * @brief Set the direction of a set of GPIO lines to input.
+ * @param bulk Set of GPIO lines.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ *
+ * If the lines were not previously requested together, the behavior is
+ * undefined.
+ */
+int gpiod_line_set_direction_input_bulk(struct gpiod_line_bulk *bulk
+ ) GPIOD_API;
+
+/**
+ * @brief Set the direction of a single GPIO line to output.
+ * @param line GPIO line object.
+ * @param value The logical value output on the line.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ */
+int gpiod_line_set_direction_output(struct gpiod_line *line,
+ int value) GPIOD_API;
+
+/**
+ * @brief Set the direction of a set of GPIO lines to output.
+ * @param bulk Set of GPIO lines.
+ * @param values An array holding line_bulk->num_lines new logical values
+ * for lines. A NULL pointer is interpreted as a logical low
+ * for all lines.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ *
+ * If the lines were not previously requested together, the behavior is
+ * undefined.
+ */
+int gpiod_line_set_direction_output_bulk(struct gpiod_line_bulk *bulk,
+ const int *values) GPIOD_API;
+
/**
* @}
*
diff --git a/lib/core.c b/lib/core.c
index 0465de9..71bb4fb 100644
--- a/lib/core.c
+++ b/lib/core.c
@@ -34,10 +34,26 @@ struct line_fd_handle {
struct gpiod_line {
unsigned int offset;
+
+ /* The GPIOD_LINE_DIRECTION */
int direction;
+
+ /* The GPIOD_LINE_ACTIVE_STATE */
int active_state;
+
+ /* The logical value last written to the line. */
+ int output_value;
+
+ /* The GPIOLINE_FLAGs returned by GPIO_GET_LINEINFO_IOCTL */
__u32 info_flags;
+ /* The GPIOD_LINE_REQUEST_FLAGs provided to request the line. */
+ __u32 req_flags;
+
+ /*
+ * Indicator of LINE_FREE, LINE_REQUESTED_VALUES or
+ * LINE_REQUESTED_EVENTS
+ */
int state;
struct gpiod_chip *chip;
@@ -445,6 +461,20 @@ static bool line_bulk_all_requested(struct gpiod_line_bulk *bulk)
return true;
}
+static bool line_bulk_all_requested_values(struct gpiod_line_bulk *bulk)
+{
+ struct gpiod_line *line, **lineptr;
+
+ gpiod_line_bulk_foreach_line(bulk, line, lineptr) {
+ if (!gpiod_line_is_requested_values(line)) {
+ errno = EPERM;
+ return false;
+ }
+ }
+
+ return true;
+}
+
static bool line_bulk_all_free(struct gpiod_line_bulk *bulk)
{
struct gpiod_line *line, **lineptr;
@@ -459,6 +489,27 @@ static bool line_bulk_all_free(struct gpiod_line_bulk *bulk)
return true;
}
+static bool line_request_direction_is_valid(int direction)
+{
+ if ((direction == GPIOD_LINE_REQUEST_DIRECTION_AS_IS) ||
+ (direction == GPIOD_LINE_REQUEST_DIRECTION_INPUT) ||
+ (direction == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT))
+ return true;
+
+ errno = EINVAL;
+ return false;
+}
+
+static __u32 line_request_direction_to_gpio_handleflag(int direction)
+{
+ if (direction == GPIOD_LINE_REQUEST_DIRECTION_INPUT)
+ return GPIOHANDLE_REQUEST_INPUT;
+ if (direction == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
+ return GPIOHANDLE_REQUEST_OUTPUT;
+
+ return 0;
+}
+
static __u32 line_request_flag_to_gpio_handleflag(int flags)
{
int hflags = 0;
@@ -483,7 +534,7 @@ static int line_request_values(struct gpiod_line_bulk *bulk,
const struct gpiod_line_request_config *config,
const int *default_vals)
{
- struct gpiod_line *line, **lineptr;
+ struct gpiod_line *line;
struct line_fd_handle *line_fd;
struct gpiohandle_request req;
unsigned int i;
@@ -512,7 +563,6 @@ static int line_request_values(struct gpiod_line_bulk *bulk,
else if (config->request_type == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
req.flags |= GPIOHANDLE_REQUEST_OUTPUT;
-
gpiod_line_bulk_foreach_line_off(bulk, line, i) {
req.lineoffsets[i] = gpiod_line_offset(line);
if (config->request_type ==
@@ -536,8 +586,12 @@ static int line_request_values(struct gpiod_line_bulk *bulk,
if (!line_fd)
return -1;
- gpiod_line_bulk_foreach_line(bulk, line, lineptr) {
+ gpiod_line_bulk_foreach_line_off(bulk, line, i) {
line->state = LINE_REQUESTED_VALUES;
+ line->req_flags = config->flags;
+ if (config->request_type ==
+ GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
+ line->output_value = req.default_values[i];
line_set_fd(line, line_fd);
rv = gpiod_line_update(line);
@@ -583,6 +637,7 @@ static int line_request_event_single(struct gpiod_line *line,
return -1;
line->state = LINE_REQUESTED_EVENTS;
+ line->req_flags = config->flags;
line_set_fd(line, line_fd);
rv = gpiod_line_update(line);
@@ -686,6 +741,11 @@ bool gpiod_line_is_requested(struct gpiod_line *line)
line->state == LINE_REQUESTED_EVENTS);
}
+bool gpiod_line_is_requested_values(struct gpiod_line *line)
+{
+ return (line->state == LINE_REQUESTED_VALUES);
+}
+
bool gpiod_line_is_free(struct gpiod_line *line)
{
return line->state == LINE_FREE;
@@ -766,9 +826,130 @@ int gpiod_line_set_value_bulk(struct gpiod_line_bulk *bulk, const int *values)
if (rv < 0)
return -1;
+ gpiod_line_bulk_foreach_line_off(bulk, line, i)
+ line->output_value = data.values[i];
+
return 0;
}
+int gpiod_line_set_config(struct gpiod_line *line, int direction,
+ int flags, int value)
+{
+ struct gpiod_line_bulk bulk;
+
+ gpiod_line_bulk_init(&bulk);
+ gpiod_line_bulk_add(&bulk, line);
+
+ return gpiod_line_set_config_bulk(&bulk, direction, flags, &value);
+}
+
+int gpiod_line_set_config_bulk(struct gpiod_line_bulk *bulk,
+ int direction, int flags,
+ const int *values)
+{
+ struct gpiohandle_config hcfg;
+ struct gpiod_line *line;
+ unsigned int i;
+ int rv, fd;
+
+ if (!line_bulk_same_chip(bulk) ||
+ !line_bulk_all_requested_values(bulk))
+ return -1;
+
+ if (!line_request_direction_is_valid(direction))
+ return -1;
+
+ memset(&hcfg, 0, sizeof(hcfg));
+
+ hcfg.flags = line_request_flag_to_gpio_handleflag(flags);
+ hcfg.flags |= line_request_direction_to_gpio_handleflag(direction);
+ if (direction == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT && values) {
+ for (i = 0; i < gpiod_line_bulk_num_lines(bulk); i++)
+ hcfg.default_values[i] = (uint8_t)!!values[i];
+ }
+
+ line = gpiod_line_bulk_get_line(bulk, 0);
+ fd = line_get_fd(line);
+
+ rv = ioctl(fd, GPIOHANDLE_SET_CONFIG_IOCTL, &hcfg);
+ if (rv < 0)
+ return -1;
+
+ gpiod_line_bulk_foreach_line_off(bulk, line, i) {
+ line->req_flags = flags;
+ if (direction == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
+ line->output_value = hcfg.default_values[i];
+ rv = gpiod_line_update(line);
+ if (rv < 0)
+ return rv;
+ }
+ return 0;
+}
+
+int gpiod_line_set_flags(struct gpiod_line *line, int flags)
+{
+ struct gpiod_line_bulk bulk;
+
+ gpiod_line_bulk_init(&bulk);
+ gpiod_line_bulk_add(&bulk, line);
+
+ return gpiod_line_set_flags_bulk(&bulk, flags);
+}
+
+int gpiod_line_set_flags_bulk(struct gpiod_line_bulk *bulk, int flags)
+{
+ struct gpiod_line *line;
+ int values[GPIOD_LINE_BULK_MAX_LINES];
+ unsigned int i;
+ int direction;
+
+ line = gpiod_line_bulk_get_line(bulk, 0);
+ if (line->direction == GPIOD_LINE_DIRECTION_OUTPUT) {
+ gpiod_line_bulk_foreach_line_off(bulk, line, i) {
+ values[i] = line->output_value;
+ }
+ direction = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT;
+ } else {
+ direction = GPIOD_LINE_REQUEST_DIRECTION_INPUT;
+ }
+
+ return gpiod_line_set_config_bulk(bulk, direction,
+ flags, values);
+}
+
+int gpiod_line_set_direction_input(struct gpiod_line *line)
+{
+ return gpiod_line_set_config(line, GPIOD_LINE_REQUEST_DIRECTION_INPUT,
+ line->req_flags, 0);
+}
+
+int gpiod_line_set_direction_input_bulk(struct gpiod_line_bulk *bulk)
+{
+ struct gpiod_line *line;
+
+ line = gpiod_line_bulk_get_line(bulk, 0);
+ return gpiod_line_set_config_bulk(bulk,
+ GPIOD_LINE_REQUEST_DIRECTION_INPUT,
+ line->req_flags, NULL);
+}
+
+int gpiod_line_set_direction_output(struct gpiod_line *line, int value)
+{
+ return gpiod_line_set_config(line, GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
+ line->req_flags, value);
+}
+
+int gpiod_line_set_direction_output_bulk(struct gpiod_line_bulk *bulk,
+ const int *values)
+{
+ struct gpiod_line *line;
+
+ line = gpiod_line_bulk_get_line(bulk, 0);
+ return gpiod_line_set_config_bulk(bulk,
+ GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
+ line->req_flags, values);
+}
+
int gpiod_line_event_wait(struct gpiod_line *line,
const struct timespec *timeout)
{
--
2.24.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [libgpiod][PATCH v3 07/14] core: add support for SET_CONFIG
2019-11-25 14:31 ` [libgpiod][PATCH v3 07/14] core: add support for SET_CONFIG Kent Gibson
@ 2019-11-28 10:29 ` Bartosz Golaszewski
0 siblings, 0 replies; 21+ messages in thread
From: Bartosz Golaszewski @ 2019-11-28 10:29 UTC (permalink / raw)
To: Kent Gibson; +Cc: linux-gpio
pon., 25 lis 2019 o 15:32 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> Extend the libgpiod API to support the setting line configuration using the
> GPIO GPIOHANDLE_SET_CONFIG_IOCTL uAPI ioctl.
>
> The core change is the addition of gpiod_line_set_config, which provides a
> low level wrapper around the ioctl.
>
> Additionally, higher level helper functions, gpiod_line_set_flags,
> gpiod_line_set_direction_input, and gpiod_line_set_direction_output provide
> slightly simplified APIs for common use cases.
>
> Bulk forms of all functions are also provided.
>
> Signed-off-by: Kent Gibson <warthog618@gmail.com>
> ---
> include/gpiod.h | 123 +++++++++++++++++++++++++++++++
> lib/core.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 307 insertions(+), 3 deletions(-)
>
> diff --git a/include/gpiod.h b/include/gpiod.h
> index 86c3ea9..185e2f4 100644
> --- a/include/gpiod.h
> +++ b/include/gpiod.h
> @@ -1246,6 +1246,15 @@ void gpiod_line_release_bulk(struct gpiod_line_bulk *bulk) GPIOD_API;
> */
> bool gpiod_line_is_requested(struct gpiod_line *line) GPIOD_API;
>
> +/**
> + * @brief Check if the calling user has ownership of this line for values,
> + * not events.
For consistency: please align this with the beginning of the
description above...
> + * @param line GPIO line object.
> + * @return True if given line was requested for reading/setting values,
> + * false otherwise.
> + */
> +bool gpiod_line_is_requested_values(struct gpiod_line *line) GPIOD_API;
... but also: why do we need to export this anyway?
> +
> /**
> * @brief Check if the calling user has neither requested ownership of this
> * line nor configured any event notifications.
> @@ -1296,6 +1305,7 @@ int gpiod_line_set_value(struct gpiod_line *line, int value) GPIOD_API;
> * @brief Set the values of a set of GPIO lines.
> * @param bulk Set of GPIO lines to reserve.
> * @param values An array holding line_bulk->num_lines new values for lines.
> + * A NULL pointer is interpreted as a logical low for all lines.
This looks like part of a different commit.
> * @return 0 is the operation succeeds. In case of an error this routine
> * returns -1 and sets the last error number.
> *
> @@ -1305,6 +1315,119 @@ int gpiod_line_set_value(struct gpiod_line *line, int value) GPIOD_API;
> int gpiod_line_set_value_bulk(struct gpiod_line_bulk *bulk,
> const int *values) GPIOD_API;
>
> +/**
> + * @}
> + *
> + * @defgroup __line_config__ Setting line configuration
> + * @{
> + */
> +
> +/**
> + * @brief Update the configuration of a single GPIO line.
> + * @param line GPIO line object.
> + * @param direction Updated direction which may be one of
> + * GPIOD_LINE_REQUEST_DIRECTION_AS_IS,
> + * GPIOD_LINE_REQUEST_DIRECTION_INPUT, or
> + * GPIOD_LINE_REQUEST_DIRECTION_OUTPUT.
> + * @param flags Replacement flags.
> + * @param value The new output value for the line when direction is
> + * GPIOD_LINE_REQUEST_DIRECTION_OUTPUT.
> + * @return 0 is the operation succeeds. In case of an error this routine
> + * returns -1 and sets the last error number.
> + */
> +int gpiod_line_set_config(struct gpiod_line *line, int direction,
> + int flags, int value) GPIOD_API;
> +
> +/**
> + * @brief Update the configuration of a set of GPIO lines.
> + * @param bulk Set of GPIO lines.
> + * @param direction Updated direction which may be one of
> + * GPIOD_LINE_REQUEST_DIRECTION_AS_IS,
> + * GPIOD_LINE_REQUEST_DIRECTION_INPUT, or
> + * GPIOD_LINE_REQUEST_DIRECTION_OUTPUT.
> + * @param flags Replacement flags.
> + * @param values An array holding line_bulk->num_lines new logical values
> + * for lines when direction is
> + * GPIOD_LINE_REQUEST_DIRECTION_OUTPUT.
> + * A NULL pointer is interpreted as a logical low for all lines.
> + * @return 0 is the operation succeeds. In case of an error this routine
> + * returns -1 and sets the last error number.
> + *
> + * If the lines were not previously requested together, the behavior is
> + * undefined.
> + */
> +int gpiod_line_set_config_bulk(struct gpiod_line_bulk *bulk,
> + int direction, int flags,
> + const int *values) GPIOD_API;
> +
> +
> +/**
> + * @brief Update the configuration flags of a single GPIO line.
> + * @param line GPIO line object.
> + * @param flags Replacement flags.
> + * @return 0 is the operation succeeds. In case of an error this routine
> + * returns -1 and sets the last error number.
> + */
> +int gpiod_line_set_flags(struct gpiod_line *line, int flags) GPIOD_API;
> +
> +/**
> + * @brief Update the configuration flags of a set of GPIO lines.
> + * @param bulk Set of GPIO lines.
> + * @param flags Replacement flags.
> + * @return 0 is the operation succeeds. In case of an error this routine
> + * returns -1 and sets the last error number.
> + *
> + * If the lines were not previously requested together, the behavior is
> + * undefined.
> + */
> +int gpiod_line_set_flags_bulk(struct gpiod_line_bulk *bulk,
> + int flags) GPIOD_API;
> +
> +/**
> + * @brief Set the direction of a single GPIO line to input.
> + * @param line GPIO line object.
> + * @return 0 is the operation succeeds. In case of an error this routine
> + * returns -1 and sets the last error number.
> + */
> +int gpiod_line_set_direction_input(struct gpiod_line *line) GPIOD_API;
> +
> +/**
> + * @brief Set the direction of a set of GPIO lines to input.
> + * @param bulk Set of GPIO lines.
> + * @return 0 is the operation succeeds. In case of an error this routine
> + * returns -1 and sets the last error number.
> + *
> + * If the lines were not previously requested together, the behavior is
> + * undefined.
> + */
> +int gpiod_line_set_direction_input_bulk(struct gpiod_line_bulk *bulk
> + ) GPIOD_API;
> +
> +/**
> + * @brief Set the direction of a single GPIO line to output.
> + * @param line GPIO line object.
> + * @param value The logical value output on the line.
> + * @return 0 is the operation succeeds. In case of an error this routine
> + * returns -1 and sets the last error number.
> + */
> +int gpiod_line_set_direction_output(struct gpiod_line *line,
> + int value) GPIOD_API;
> +
> +/**
> + * @brief Set the direction of a set of GPIO lines to output.
> + * @param bulk Set of GPIO lines.
> + * @param values An array holding line_bulk->num_lines new logical values
> + * for lines. A NULL pointer is interpreted as a logical low
> + * for all lines.
> + * @return 0 is the operation succeeds. In case of an error this routine
> + * returns -1 and sets the last error number.
> + *
> + * If the lines were not previously requested together, the behavior is
> + * undefined.
> + */
> +int gpiod_line_set_direction_output_bulk(struct gpiod_line_bulk *bulk,
> + const int *values) GPIOD_API;
> +
> /**
> * @}
> *
> diff --git a/lib/core.c b/lib/core.c
> index 0465de9..71bb4fb 100644
> --- a/lib/core.c
> +++ b/lib/core.c
> @@ -34,10 +34,26 @@ struct line_fd_handle {
>
> struct gpiod_line {
> unsigned int offset;
> +
> + /* The GPIOD_LINE_DIRECTION */
> int direction;
> +
> + /* The GPIOD_LINE_ACTIVE_STATE */
> int active_state;
> +
> + /* The logical value last written to the line. */
> + int output_value;
> +
> + /* The GPIOLINE_FLAGs returned by GPIO_GET_LINEINFO_IOCTL */
> __u32 info_flags;
>
> + /* The GPIOD_LINE_REQUEST_FLAGs provided to request the line. */
> + __u32 req_flags;
> +
> + /*
> + * Indicator of LINE_FREE, LINE_REQUESTED_VALUES or
> + * LINE_REQUESTED_EVENTS
> + */
> int state;
Please include the mention on documenting this in the commit message.
Otherwise it looks like it should be part of a different commit.
>
> struct gpiod_chip *chip;
> @@ -445,6 +461,20 @@ static bool line_bulk_all_requested(struct gpiod_line_bulk *bulk)
> return true;
> }
>
> +static bool line_bulk_all_requested_values(struct gpiod_line_bulk *bulk)
> +{
> + struct gpiod_line *line, **lineptr;
> +
> + gpiod_line_bulk_foreach_line(bulk, line, lineptr) {
> + if (!gpiod_line_is_requested_values(line)) {
> + errno = EPERM;
> + return false;
> + }
> + }
> +
> + return true;
> +}
> +
> static bool line_bulk_all_free(struct gpiod_line_bulk *bulk)
> {
> struct gpiod_line *line, **lineptr;
> @@ -459,6 +489,27 @@ static bool line_bulk_all_free(struct gpiod_line_bulk *bulk)
> return true;
> }
>
> +static bool line_request_direction_is_valid(int direction)
> +{
> + if ((direction == GPIOD_LINE_REQUEST_DIRECTION_AS_IS) ||
> + (direction == GPIOD_LINE_REQUEST_DIRECTION_INPUT) ||
> + (direction == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT))
> + return true;
> +
> + errno = EINVAL;
> + return false;
> +}
Same here: please be a bit more elaborate in the commit message. Say
something like: "while at it: restructure the code by doing this and
that".
> +
> +static __u32 line_request_direction_to_gpio_handleflag(int direction)
> +{
> + if (direction == GPIOD_LINE_REQUEST_DIRECTION_INPUT)
> + return GPIOHANDLE_REQUEST_INPUT;
> + if (direction == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
> + return GPIOHANDLE_REQUEST_OUTPUT;
> +
> + return 0;
> +}
> +
> static __u32 line_request_flag_to_gpio_handleflag(int flags)
> {
> int hflags = 0;
> @@ -483,7 +534,7 @@ static int line_request_values(struct gpiod_line_bulk *bulk,
> const struct gpiod_line_request_config *config,
> const int *default_vals)
> {
> - struct gpiod_line *line, **lineptr;
> + struct gpiod_line *line;
> struct line_fd_handle *line_fd;
> struct gpiohandle_request req;
> unsigned int i;
> @@ -512,7 +563,6 @@ static int line_request_values(struct gpiod_line_bulk *bulk,
> else if (config->request_type == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
> req.flags |= GPIOHANDLE_REQUEST_OUTPUT;
>
> -
Fixing stray newlines etc should be in separate commits too IMO but
let's let is slip here, this is already a big patch anyway.
> gpiod_line_bulk_foreach_line_off(bulk, line, i) {
> req.lineoffsets[i] = gpiod_line_offset(line);
> if (config->request_type ==
> @@ -536,8 +586,12 @@ static int line_request_values(struct gpiod_line_bulk *bulk,
> if (!line_fd)
> return -1;
>
> - gpiod_line_bulk_foreach_line(bulk, line, lineptr) {
> + gpiod_line_bulk_foreach_line_off(bulk, line, i) {
> line->state = LINE_REQUESTED_VALUES;
> + line->req_flags = config->flags;
> + if (config->request_type ==
> + GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
Add another tab here because otherwise there's no indentation
difference between this line and the line below.
> + line->output_value = req.default_values[i];
> line_set_fd(line, line_fd);
>
> rv = gpiod_line_update(line);
> @@ -583,6 +637,7 @@ static int line_request_event_single(struct gpiod_line *line,
> return -1;
>
> line->state = LINE_REQUESTED_EVENTS;
> + line->req_flags = config->flags;
> line_set_fd(line, line_fd);
>
> rv = gpiod_line_update(line);
> @@ -686,6 +741,11 @@ bool gpiod_line_is_requested(struct gpiod_line *line)
> line->state == LINE_REQUESTED_EVENTS);
> }
>
> +bool gpiod_line_is_requested_values(struct gpiod_line *line)
> +{
> + return (line->state == LINE_REQUESTED_VALUES);
> +}
> +
> bool gpiod_line_is_free(struct gpiod_line *line)
> {
> return line->state == LINE_FREE;
> @@ -766,9 +826,130 @@ int gpiod_line_set_value_bulk(struct gpiod_line_bulk *bulk, const int *values)
> if (rv < 0)
> return -1;
>
> + gpiod_line_bulk_foreach_line_off(bulk, line, i)
> + line->output_value = data.values[i];
> +
> return 0;
> }
>
> +int gpiod_line_set_config(struct gpiod_line *line, int direction,
> + int flags, int value)
> +{
> + struct gpiod_line_bulk bulk;
> +
> + gpiod_line_bulk_init(&bulk);
> + gpiod_line_bulk_add(&bulk, line);
> +
> + return gpiod_line_set_config_bulk(&bulk, direction, flags, &value);
> +}
> +
> +int gpiod_line_set_config_bulk(struct gpiod_line_bulk *bulk,
> + int direction, int flags,
> + const int *values)
> +{
> + struct gpiohandle_config hcfg;
> + struct gpiod_line *line;
> + unsigned int i;
> + int rv, fd;
> +
> + if (!line_bulk_same_chip(bulk) ||
> + !line_bulk_all_requested_values(bulk))
> + return -1;
> +
> + if (!line_request_direction_is_valid(direction))
> + return -1;
> +
> + memset(&hcfg, 0, sizeof(hcfg));
> +
> + hcfg.flags = line_request_flag_to_gpio_handleflag(flags);
> + hcfg.flags |= line_request_direction_to_gpio_handleflag(direction);
> + if (direction == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT && values) {
> + for (i = 0; i < gpiod_line_bulk_num_lines(bulk); i++)
> + hcfg.default_values[i] = (uint8_t)!!values[i];
> + }
> +
> + line = gpiod_line_bulk_get_line(bulk, 0);
> + fd = line_get_fd(line);
> +
> + rv = ioctl(fd, GPIOHANDLE_SET_CONFIG_IOCTL, &hcfg);
> + if (rv < 0)
> + return -1;
> +
> + gpiod_line_bulk_foreach_line_off(bulk, line, i) {
> + line->req_flags = flags;
> + if (direction == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
> + line->output_value = hcfg.default_values[i];
Please add a newline here.
> + rv = gpiod_line_update(line);
> + if (rv < 0)
> + return rv;
> + }
> + return 0;
> +}
> +
> +int gpiod_line_set_flags(struct gpiod_line *line, int flags)
> +{
> + struct gpiod_line_bulk bulk;
> +
> + gpiod_line_bulk_init(&bulk);
> + gpiod_line_bulk_add(&bulk, line);
> +
> + return gpiod_line_set_flags_bulk(&bulk, flags);
> +}
> +
> +int gpiod_line_set_flags_bulk(struct gpiod_line_bulk *bulk, int flags)
> +{
> + struct gpiod_line *line;
> + int values[GPIOD_LINE_BULK_MAX_LINES];
> + unsigned int i;
> + int direction;
> +
> + line = gpiod_line_bulk_get_line(bulk, 0);
> + if (line->direction == GPIOD_LINE_DIRECTION_OUTPUT) {
> + gpiod_line_bulk_foreach_line_off(bulk, line, i) {
> + values[i] = line->output_value;
> + }
No need for brackets here.
> + direction = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT;
> + } else {
> + direction = GPIOD_LINE_REQUEST_DIRECTION_INPUT;
> + }
> +
> + return gpiod_line_set_config_bulk(bulk, direction,
> + flags, values);
> +}
> +
> +int gpiod_line_set_direction_input(struct gpiod_line *line)
> +{
> + return gpiod_line_set_config(line, GPIOD_LINE_REQUEST_DIRECTION_INPUT,
> + line->req_flags, 0);
> +}
> +
> +int gpiod_line_set_direction_input_bulk(struct gpiod_line_bulk *bulk)
> +{
> + struct gpiod_line *line;
> +
> + line = gpiod_line_bulk_get_line(bulk, 0);
> + return gpiod_line_set_config_bulk(bulk,
> + GPIOD_LINE_REQUEST_DIRECTION_INPUT,
> + line->req_flags, NULL);
> +}
> +
> +int gpiod_line_set_direction_output(struct gpiod_line *line, int value)
> +{
> + return gpiod_line_set_config(line, GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
> + line->req_flags, value);
> +}
> +
> +int gpiod_line_set_direction_output_bulk(struct gpiod_line_bulk *bulk,
> + const int *values)
> +{
> + struct gpiod_line *line;
> +
> + line = gpiod_line_bulk_get_line(bulk, 0);
> + return gpiod_line_set_config_bulk(bulk,
> + GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
> + line->req_flags, values);
> +}
> +
> int gpiod_line_event_wait(struct gpiod_line *line,
> const struct timespec *timeout)
> {
> --
> 2.24.0
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [libgpiod][PATCH v3 08/14] tests: add tests for SET_CONFIG
2019-11-25 14:31 [libgpiod][PATCH v3 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
` (6 preceding siblings ...)
2019-11-25 14:31 ` [libgpiod][PATCH v3 07/14] core: add support for SET_CONFIG Kent Gibson
@ 2019-11-25 14:31 ` Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 09/14] bindings: cxx: add support " Kent Gibson
` (5 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Kent Gibson @ 2019-11-25 14:31 UTC (permalink / raw)
To: linux-gpio, bgolaszewski; +Cc: Kent Gibson
Extend test coverage over the SET_CONFIG functions.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
tests/tests-line.c | 370 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 369 insertions(+), 1 deletion(-)
diff --git a/tests/tests-line.c b/tests/tests-line.c
index 4bf7c02..97b7df9 100644
--- a/tests/tests-line.c
+++ b/tests/tests-line.c
@@ -265,6 +265,7 @@ GPIOD_TEST_CASE(set_value, 0, { 8 })
ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 0);
g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
ret = gpiod_line_set_value(line, 1);
g_assert_cmpint(ret, ==, 0);
@@ -327,6 +328,351 @@ GPIOD_TEST_CASE(set_value_bulk, 0, { 8 })
g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
}
+GPIOD_TEST_CASE(set_config_bulk_null_values, 0, { 8 })
+{
+ g_autoptr(gpiod_chip_struct) chip = NULL;
+ struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER;
+ struct gpiod_line *line0, *line1, *line2;
+ gint ret;
+
+ chip = gpiod_chip_open(gpiod_test_chip_path(0));
+ g_assert_nonnull(chip);
+ gpiod_test_return_if_failed();
+
+ line0 = gpiod_chip_get_line(chip, 0);
+ line1 = gpiod_chip_get_line(chip, 1);
+ line2 = gpiod_chip_get_line(chip, 2);
+
+ g_assert_nonnull(line0);
+ g_assert_nonnull(line1);
+ g_assert_nonnull(line2);
+ gpiod_test_return_if_failed();
+
+ gpiod_line_bulk_add(&bulk, line0);
+ gpiod_line_bulk_add(&bulk, line1);
+ gpiod_line_bulk_add(&bulk, line2);
+
+ ret = gpiod_line_request_bulk_output(&bulk, GPIOD_TEST_CONSUMER, 0);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_active_state(line0), ==,
+ GPIOD_LINE_ACTIVE_STATE_HIGH);
+ g_assert_cmpint(gpiod_line_active_state(line1), ==,
+ GPIOD_LINE_ACTIVE_STATE_HIGH);
+ g_assert_cmpint(gpiod_line_active_state(line2), ==,
+ GPIOD_LINE_ACTIVE_STATE_HIGH);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+ ret = gpiod_line_set_config_bulk(&bulk,
+ GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
+ GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW, NULL);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_active_state(line0), ==,
+ GPIOD_LINE_ACTIVE_STATE_LOW);
+ g_assert_cmpint(gpiod_line_active_state(line1), ==,
+ GPIOD_LINE_ACTIVE_STATE_LOW);
+ g_assert_cmpint(gpiod_line_active_state(line2), ==,
+ GPIOD_LINE_ACTIVE_STATE_LOW);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 1);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 1);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+ ret = gpiod_line_set_config_bulk(&bulk,
+ GPIOD_LINE_REQUEST_DIRECTION_OUTPUT, 0, NULL);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_active_state(line0), ==,
+ GPIOD_LINE_ACTIVE_STATE_HIGH);
+ g_assert_cmpint(gpiod_line_active_state(line1), ==,
+ GPIOD_LINE_ACTIVE_STATE_HIGH);
+ g_assert_cmpint(gpiod_line_active_state(line2), ==,
+ GPIOD_LINE_ACTIVE_STATE_HIGH);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+}
+
+GPIOD_TEST_CASE(set_flags_active_state, 0, { 8 })
+{
+ g_autoptr(gpiod_chip_struct) chip = NULL;
+ struct gpiod_line *line;
+ gint ret;
+
+ chip = gpiod_chip_open(gpiod_test_chip_path(0));
+ g_assert_nonnull(chip);
+ gpiod_test_return_if_failed();
+
+ line = gpiod_chip_get_line(chip, 2);
+ g_assert_nonnull(line);
+ gpiod_test_return_if_failed();
+
+ ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 1);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_active_state(line), ==,
+ GPIOD_LINE_ACTIVE_STATE_HIGH);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+ ret = gpiod_line_set_flags(line, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_active_state(line), ==,
+ GPIOD_LINE_ACTIVE_STATE_LOW);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+ ret = gpiod_line_set_flags(line, 0);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_active_state(line), ==,
+ GPIOD_LINE_ACTIVE_STATE_HIGH);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+}
+
+GPIOD_TEST_CASE(set_flags_bias, 0, { 8 })
+{
+ g_autoptr(gpiod_chip_struct) chip = NULL;
+ struct gpiod_line *line;
+ gint ret;
+
+ chip = gpiod_chip_open(gpiod_test_chip_path(0));
+ g_assert_nonnull(chip);
+ gpiod_test_return_if_failed();
+
+ line = gpiod_chip_get_line(chip, 2);
+ g_assert_nonnull(line);
+ gpiod_test_return_if_failed();
+
+ ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
+
+ ret = gpiod_line_set_flags(line,
+ GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_DISABLE);
+
+ ret = gpiod_line_set_flags(line,
+ GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_UP);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+ ret = gpiod_line_set_flags(line,
+ GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_DOWN);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+}
+
+GPIOD_TEST_CASE(set_flags_drive, 0, { 8 })
+{
+ g_autoptr(gpiod_chip_struct) chip = NULL;
+ struct gpiod_line *line;
+ gint ret;
+
+ chip = gpiod_chip_open(gpiod_test_chip_path(0));
+ g_assert_nonnull(chip);
+ gpiod_test_return_if_failed();
+
+ line = gpiod_chip_get_line(chip, 2);
+ g_assert_nonnull(line);
+ gpiod_test_return_if_failed();
+
+ ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 0);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_is_open_drain(line), ==, false);
+ g_assert_cmpint(gpiod_line_is_open_source(line), ==, false);
+
+ ret = gpiod_line_set_flags(line,
+ GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_is_open_drain(line), ==, true);
+ g_assert_cmpint(gpiod_line_is_open_source(line), ==, false);
+
+ ret = gpiod_line_set_flags(line,
+ GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_is_open_drain(line), ==, false);
+ g_assert_cmpint(gpiod_line_is_open_source(line), ==, true);
+}
+
+GPIOD_TEST_CASE(set_direction, 0, { 8 })
+{
+ g_autoptr(gpiod_chip_struct) chip = NULL;
+ struct gpiod_line *line;
+ gint ret;
+
+ chip = gpiod_chip_open(gpiod_test_chip_path(0));
+ g_assert_nonnull(chip);
+ gpiod_test_return_if_failed();
+
+ line = gpiod_chip_get_line(chip, 2);
+ g_assert_nonnull(line);
+ gpiod_test_return_if_failed();
+
+ ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 0);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_direction(line), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+ ret = gpiod_line_set_direction_input(line);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_direction(line), ==,
+ GPIOD_LINE_DIRECTION_INPUT);
+
+ ret = gpiod_line_set_direction_output(line, 1);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_direction(line), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+}
+
+GPIOD_TEST_CASE(set_direction_bulk, 0, { 8 })
+{
+ g_autoptr(gpiod_chip_struct) chip = NULL;
+ struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER;
+ struct gpiod_line *line0, *line1, *line2;
+ int values[3];
+ gint ret;
+
+ chip = gpiod_chip_open(gpiod_test_chip_path(0));
+ g_assert_nonnull(chip);
+ gpiod_test_return_if_failed();
+
+ line0 = gpiod_chip_get_line(chip, 0);
+ line1 = gpiod_chip_get_line(chip, 1);
+ line2 = gpiod_chip_get_line(chip, 2);
+
+ g_assert_nonnull(line0);
+ g_assert_nonnull(line1);
+ g_assert_nonnull(line2);
+ gpiod_test_return_if_failed();
+
+ gpiod_line_bulk_add(&bulk, line0);
+ gpiod_line_bulk_add(&bulk, line1);
+ gpiod_line_bulk_add(&bulk, line2);
+
+ values[0] = 0;
+ values[1] = 1;
+ values[2] = 2;
+
+ ret = gpiod_line_request_bulk_output(&bulk,
+ GPIOD_TEST_CONSUMER, values);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_direction(line0), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_line_direction(line1), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_line_direction(line2), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 1);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+ ret = gpiod_line_set_direction_input_bulk(&bulk);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_direction(line0), ==,
+ GPIOD_LINE_DIRECTION_INPUT);
+ g_assert_cmpint(gpiod_line_direction(line1), ==,
+ GPIOD_LINE_DIRECTION_INPUT);
+ g_assert_cmpint(gpiod_line_direction(line2), ==,
+ GPIOD_LINE_DIRECTION_INPUT);
+
+ values[0] = 2;
+ values[1] = 1;
+ values[2] = 0;
+
+ ret = gpiod_line_set_direction_output_bulk(&bulk, values);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_direction(line0), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_line_direction(line1), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_line_direction(line2), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 1);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 1);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+ ret = gpiod_line_set_direction_output_bulk(&bulk, NULL);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_line_direction(line0), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_line_direction(line1), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_line_direction(line2), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+}
+
+GPIOD_TEST_CASE(output_value_caching, 0, { 8 })
+{
+ g_autoptr(gpiod_chip_struct) chip = NULL;
+ struct gpiod_line *line;
+ struct gpiod_line_bulk bulk;
+ gint ret;
+
+ chip = gpiod_chip_open(gpiod_test_chip_path(0));
+ g_assert_nonnull(chip);
+ gpiod_test_return_if_failed();
+
+ line = gpiod_chip_get_line(chip, 2);
+ g_assert_nonnull(line);
+ gpiod_test_return_if_failed();
+
+ /* check cached by request... */
+ ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 1);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+ /* ...by checking cached value applied by set_flags */
+ ret = gpiod_line_set_flags(line, 0);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+ /* check cached by set_value */
+ ret = gpiod_line_set_value(line, 0);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+ ret = gpiod_line_set_flags(line, 0);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+ ret = gpiod_line_set_value(line, 1);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+ ret = gpiod_line_set_flags(line, 0);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+ /* check cached by set_config */
+ ret = gpiod_line_set_config(line, GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
+ 0, 0);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+ ret = gpiod_line_set_flags(line, 0);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+ /* check cached by set_value_bulk default */
+ ret = gpiod_line_set_value(line, 1);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+ gpiod_line_bulk_init(&bulk);
+ gpiod_line_bulk_add(&bulk, line);
+ ret = gpiod_line_set_value_bulk(&bulk, NULL);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+ ret = gpiod_line_set_flags(line, 0);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+}
+
GPIOD_TEST_CASE(get_value_different_chips, 0, { 8, 8 })
{
g_autoptr(gpiod_chip_struct) chipA = NULL;
@@ -441,10 +787,11 @@ GPIOD_TEST_CASE(direction, 0, { 8 })
g_assert_nonnull(line);
gpiod_test_return_if_failed();
- ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 0);
+ ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 1);
g_assert_cmpint(ret, ==, 0);
g_assert_cmpint(gpiod_line_direction(line), ==,
GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 5), ==, 1);
gpiod_line_release(line);
@@ -482,6 +829,27 @@ GPIOD_TEST_CASE(active_state, 0, { 8 })
g_assert_cmpint(gpiod_line_direction(line), ==,
GPIOD_LINE_DIRECTION_INPUT);
+
+ gpiod_line_release(line);
+
+ ret = gpiod_line_request_output_flags(line, GPIOD_TEST_CONSUMER,
+ GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW, 0);
+ g_assert_cmpint(ret, ==, 0);
+
+ g_assert_cmpint(gpiod_line_direction(line), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 5), ==, 1);
+
+ gpiod_line_release(line);
+
+ ret = gpiod_line_request_output_flags(line,
+ GPIOD_TEST_CONSUMER, 0, 0);
+ g_assert_cmpint(ret, ==, 0);
+
+ g_assert_cmpint(gpiod_line_direction(line), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_test_chip_get_value(0, 5), ==, 0);
+
}
GPIOD_TEST_CASE(misc_flags, 0, { 8 })
--
2.24.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [libgpiod][PATCH v3 09/14] bindings: cxx: add support for SET_CONFIG
2019-11-25 14:31 [libgpiod][PATCH v3 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
` (7 preceding siblings ...)
2019-11-25 14:31 ` [libgpiod][PATCH v3 08/14] tests: add tests " Kent Gibson
@ 2019-11-25 14:31 ` Kent Gibson
2019-11-28 10:29 ` Bartosz Golaszewski
2019-11-25 14:31 ` [libgpiod][PATCH v3 10/14] bindings: cxx: tests: add tests for SET_CONFIG methods Kent Gibson
` (4 subsequent siblings)
13 siblings, 1 reply; 21+ messages in thread
From: Kent Gibson @ 2019-11-25 14:31 UTC (permalink / raw)
To: linux-gpio, bgolaszewski; +Cc: Kent Gibson
Add methods to support setting line configuration.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
bindings/cxx/gpiod.hpp | 55 +++++++++++++++++++++++++
bindings/cxx/line.cpp | 37 +++++++++++++++++
bindings/cxx/line_bulk.cpp | 83 ++++++++++++++++++++++++++++++++++++++
3 files changed, 175 insertions(+)
diff --git a/bindings/cxx/gpiod.hpp b/bindings/cxx/gpiod.hpp
index 2b1a6ab..dcae431 100644
--- a/bindings/cxx/gpiod.hpp
+++ b/bindings/cxx/gpiod.hpp
@@ -381,6 +381,32 @@ public:
*/
GPIOD_API void set_value(int val) const;
+ /**
+ * @brief Set configuration of this line.
+ * @param direction New direction.
+ * @param flags Replacement flags.
+ * @param value New value (0 or 1) - only matters for OUTPUT direction.
+ */
+ GPIOD_API void set_config(int direction, ::std::bitset<32> flags,
+ int value = 0) const;
+
+ /**
+ * @brief Set configuration flags of this line.
+ * @param flags Replacement flags.
+ */
+ GPIOD_API void set_flags(::std::bitset<32> flags) const;
+
+ /**
+ * @brief Change the direction this line to input.
+ */
+ GPIOD_API void set_direction_input() const;
+
+ /**
+ * @brief Change the direction this lines to output.
+ * @param value New value (0 or 1).
+ */
+ GPIOD_API void set_direction_output(int value = 0) const;
+
/**
* @brief Wait for an event on this line.
* @param timeout Time to wait before returning if no event occurred.
@@ -648,6 +674,35 @@ public:
*/
GPIOD_API void set_values(const ::std::vector<int>& values) const;
+ /**
+ * @brief Set configuration of all lines held by this object.
+ * @param direction New direction.
+ * @param flags Replacement flags.
+ * @param values Vector of values to set. Must be the same size as the
+ * number of lines held by this line_bulk.
+ * Only relevant for output direction requests.
+ */
+ GPIOD_API void set_config(int direction, ::std::bitset<32> flags,
+ const ::std::vector<int> values = std::vector<int>()) const;
+
+ /**
+ * @brief Set configuration flags of all lines held by this object.
+ * @param flags Replacement flags.
+ */
+ GPIOD_API void set_flags(::std::bitset<32> flags) const;
+
+ /**
+ * @brief Change the direction all lines held by this object to input.
+ */
+ GPIOD_API void set_direction_input() const;
+
+ /**
+ * @brief Change the direction all lines held by this object to output.
+ * @param values Vector of values to set. Must be the same size as the
+ * number of lines held by this line_bulk.
+ */
+ GPIOD_API void set_direction_output(const ::std::vector<int>& values) const;
+
/**
* @brief Poll the set of lines for line events.
* @param timeout Number of nanoseconds to wait before returning an
diff --git a/bindings/cxx/line.cpp b/bindings/cxx/line.cpp
index dd6bb6a..a688b5d 100644
--- a/bindings/cxx/line.cpp
+++ b/bindings/cxx/line.cpp
@@ -158,6 +158,43 @@ void line::set_value(int val) const
bulk.set_values({ val });
}
+void line::set_config(int direction, ::std::bitset<32> flags,
+ int value) const
+{
+ this->throw_if_null();
+
+ line_bulk bulk({ *this });
+
+ bulk.set_config(direction, flags, { value });
+}
+
+void line::set_flags(::std::bitset<32> flags) const
+{
+ this->throw_if_null();
+
+ line_bulk bulk({ *this });
+
+ bulk.set_flags(flags);
+}
+
+void line::set_direction_input() const
+{
+ this->throw_if_null();
+
+ line_bulk bulk({ *this });
+
+ bulk.set_direction_input();
+}
+
+void line::set_direction_output(int value) const
+{
+ this->throw_if_null();
+
+ line_bulk bulk({ *this });
+
+ bulk.set_direction_output({ value });
+}
+
bool line::event_wait(const ::std::chrono::nanoseconds& timeout) const
{
this->throw_if_null();
diff --git a/bindings/cxx/line_bulk.cpp b/bindings/cxx/line_bulk.cpp
index 5f1cac4..b8f5eb7 100644
--- a/bindings/cxx/line_bulk.cpp
+++ b/bindings/cxx/line_bulk.cpp
@@ -176,6 +176,89 @@ void line_bulk::set_values(const ::std::vector<int>& values) const
"error setting GPIO line values");
}
+void line_bulk::set_config(int direction, ::std::bitset<32> flags,
+ const ::std::vector<int> values) const
+{
+ this->throw_if_empty();
+
+ if (!values.empty() && this->_m_bulk.size() != values.size())
+ throw ::std::invalid_argument("the number of default values must correspond with the number of lines");
+
+ ::gpiod_line_bulk bulk;
+ int rv, gflags;
+
+ gflags = 0;
+
+ for (auto& it: reqflag_mapping) {
+ if ((it.first & flags).to_ulong())
+ gflags |= it.second;
+ }
+
+ this->to_line_bulk(::std::addressof(bulk));
+
+ rv = ::gpiod_line_set_config_bulk(::std::addressof(bulk), direction,
+ gflags, values.data());
+ if (rv)
+ throw ::std::system_error(errno, ::std::system_category(),
+ "error setting GPIO line config");
+}
+
+void line_bulk::set_flags(::std::bitset<32> flags) const
+{
+ this->throw_if_empty();
+
+ ::gpiod_line_bulk bulk;
+ int rv, gflags;
+
+ this->to_line_bulk(::std::addressof(bulk));
+
+ gflags = 0;
+
+ for (auto& it: reqflag_mapping) {
+ if ((it.first & flags).to_ulong())
+ gflags |= it.second;
+ }
+
+ rv = ::gpiod_line_set_flags_bulk(::std::addressof(bulk), gflags);
+ if (rv)
+ throw ::std::system_error(errno, ::std::system_category(),
+ "error setting GPIO line flags");
+}
+
+void line_bulk::set_direction_input() const
+{
+ this->throw_if_empty();
+
+ ::gpiod_line_bulk bulk;
+ int rv;
+
+ this->to_line_bulk(::std::addressof(bulk));
+
+ rv = ::gpiod_line_set_direction_input_bulk(::std::addressof(bulk));
+ if (rv)
+ throw ::std::system_error(errno, ::std::system_category(),
+ "error setting GPIO line direction to input");
+}
+
+void line_bulk::set_direction_output(const ::std::vector<int>& values) const
+{
+ this->throw_if_empty();
+
+ if (values.size() != this->_m_bulk.size())
+ throw ::std::invalid_argument("the size of values array must correspond with the number of lines");
+
+ ::gpiod_line_bulk bulk;
+ int rv;
+
+ this->to_line_bulk(::std::addressof(bulk));
+
+ rv = ::gpiod_line_set_direction_output_bulk(::std::addressof(bulk),
+ values.data());
+ if (rv)
+ throw ::std::system_error(errno, ::std::system_category(),
+ "error setting GPIO line direction to output");
+}
+
line_bulk line_bulk::event_wait(const ::std::chrono::nanoseconds& timeout) const
{
this->throw_if_empty();
--
2.24.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [libgpiod][PATCH v3 09/14] bindings: cxx: add support for SET_CONFIG
2019-11-25 14:31 ` [libgpiod][PATCH v3 09/14] bindings: cxx: add support " Kent Gibson
@ 2019-11-28 10:29 ` Bartosz Golaszewski
0 siblings, 0 replies; 21+ messages in thread
From: Bartosz Golaszewski @ 2019-11-28 10:29 UTC (permalink / raw)
To: Kent Gibson; +Cc: linux-gpio
pon., 25 lis 2019 o 15:33 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> Add methods to support setting line configuration.
>
> Signed-off-by: Kent Gibson <warthog618@gmail.com>
> ---
> bindings/cxx/gpiod.hpp | 55 +++++++++++++++++++++++++
> bindings/cxx/line.cpp | 37 +++++++++++++++++
> bindings/cxx/line_bulk.cpp | 83 ++++++++++++++++++++++++++++++++++++++
> 3 files changed, 175 insertions(+)
>
> diff --git a/bindings/cxx/gpiod.hpp b/bindings/cxx/gpiod.hpp
> index 2b1a6ab..dcae431 100644
> --- a/bindings/cxx/gpiod.hpp
> +++ b/bindings/cxx/gpiod.hpp
> @@ -381,6 +381,32 @@ public:
> */
> GPIOD_API void set_value(int val) const;
>
> + /**
> + * @brief Set configuration of this line.
> + * @param direction New direction.
> + * @param flags Replacement flags.
> + * @param value New value (0 or 1) - only matters for OUTPUT direction.
> + */
> + GPIOD_API void set_config(int direction, ::std::bitset<32> flags,
> + int value = 0) const;
Please align this with the opening bracket. Same elsewhere.
> +
> + /**
> + * @brief Set configuration flags of this line.
> + * @param flags Replacement flags.
> + */
> + GPIOD_API void set_flags(::std::bitset<32> flags) const;
> +
> + /**
> + * @brief Change the direction this line to input.
> + */
> + GPIOD_API void set_direction_input() const;
> +
> + /**
> + * @brief Change the direction this lines to output.
> + * @param value New value (0 or 1).
> + */
> + GPIOD_API void set_direction_output(int value = 0) const;
> +
> /**
> * @brief Wait for an event on this line.
> * @param timeout Time to wait before returning if no event occurred.
> @@ -648,6 +674,35 @@ public:
> */
> GPIOD_API void set_values(const ::std::vector<int>& values) const;
>
> + /**
> + * @brief Set configuration of all lines held by this object.
> + * @param direction New direction.
> + * @param flags Replacement flags.
> + * @param values Vector of values to set. Must be the same size as the
> + * number of lines held by this line_bulk.
> + * Only relevant for output direction requests.
> + */
> + GPIOD_API void set_config(int direction, ::std::bitset<32> flags,
> + const ::std::vector<int> values = std::vector<int>()) const;
> +
> + /**
> + * @brief Set configuration flags of all lines held by this object.
> + * @param flags Replacement flags.
> + */
> + GPIOD_API void set_flags(::std::bitset<32> flags) const;
> +
> + /**
> + * @brief Change the direction all lines held by this object to input.
> + */
> + GPIOD_API void set_direction_input() const;
> +
> + /**
> + * @brief Change the direction all lines held by this object to output.
> + * @param values Vector of values to set. Must be the same size as the
> + * number of lines held by this line_bulk.
> + */
> + GPIOD_API void set_direction_output(const ::std::vector<int>& values) const;
> +
> /**
> * @brief Poll the set of lines for line events.
> * @param timeout Number of nanoseconds to wait before returning an
> diff --git a/bindings/cxx/line.cpp b/bindings/cxx/line.cpp
> index dd6bb6a..a688b5d 100644
> --- a/bindings/cxx/line.cpp
> +++ b/bindings/cxx/line.cpp
> @@ -158,6 +158,43 @@ void line::set_value(int val) const
> bulk.set_values({ val });
> }
>
> +void line::set_config(int direction, ::std::bitset<32> flags,
> + int value) const
> +{
> + this->throw_if_null();
> +
> + line_bulk bulk({ *this });
> +
> + bulk.set_config(direction, flags, { value });
> +}
> +
> +void line::set_flags(::std::bitset<32> flags) const
> +{
> + this->throw_if_null();
> +
> + line_bulk bulk({ *this });
> +
> + bulk.set_flags(flags);
> +}
> +
> +void line::set_direction_input() const
> +{
> + this->throw_if_null();
> +
> + line_bulk bulk({ *this });
> +
> + bulk.set_direction_input();
> +}
> +
> +void line::set_direction_output(int value) const
> +{
> + this->throw_if_null();
> +
> + line_bulk bulk({ *this });
> +
> + bulk.set_direction_output({ value });
> +}
> +
> bool line::event_wait(const ::std::chrono::nanoseconds& timeout) const
> {
> this->throw_if_null();
> diff --git a/bindings/cxx/line_bulk.cpp b/bindings/cxx/line_bulk.cpp
> index 5f1cac4..b8f5eb7 100644
> --- a/bindings/cxx/line_bulk.cpp
> +++ b/bindings/cxx/line_bulk.cpp
> @@ -176,6 +176,89 @@ void line_bulk::set_values(const ::std::vector<int>& values) const
> "error setting GPIO line values");
> }
>
> +void line_bulk::set_config(int direction, ::std::bitset<32> flags,
> + const ::std::vector<int> values) const
> +{
> + this->throw_if_empty();
> +
> + if (!values.empty() && this->_m_bulk.size() != values.size())
> + throw ::std::invalid_argument("the number of default values must correspond with the number of lines");
> +
> + ::gpiod_line_bulk bulk;
> + int rv, gflags;
> +
> + gflags = 0;
> +
> + for (auto& it: reqflag_mapping) {
> + if ((it.first & flags).to_ulong())
> + gflags |= it.second;
> + }
> +
> + this->to_line_bulk(::std::addressof(bulk));
> +
> + rv = ::gpiod_line_set_config_bulk(::std::addressof(bulk), direction,
> + gflags, values.data());
> + if (rv)
> + throw ::std::system_error(errno, ::std::system_category(),
> + "error setting GPIO line config");
> +}
> +
> +void line_bulk::set_flags(::std::bitset<32> flags) const
> +{
> + this->throw_if_empty();
> +
> + ::gpiod_line_bulk bulk;
> + int rv, gflags;
> +
> + this->to_line_bulk(::std::addressof(bulk));
> +
> + gflags = 0;
> +
> + for (auto& it: reqflag_mapping) {
> + if ((it.first & flags).to_ulong())
> + gflags |= it.second;
> + }
> +
> + rv = ::gpiod_line_set_flags_bulk(::std::addressof(bulk), gflags);
> + if (rv)
> + throw ::std::system_error(errno, ::std::system_category(),
> + "error setting GPIO line flags");
> +}
> +
> +void line_bulk::set_direction_input() const
> +{
> + this->throw_if_empty();
> +
> + ::gpiod_line_bulk bulk;
> + int rv;
> +
> + this->to_line_bulk(::std::addressof(bulk));
> +
> + rv = ::gpiod_line_set_direction_input_bulk(::std::addressof(bulk));
> + if (rv)
> + throw ::std::system_error(errno, ::std::system_category(),
> + "error setting GPIO line direction to input");
> +}
> +
> +void line_bulk::set_direction_output(const ::std::vector<int>& values) const
> +{
> + this->throw_if_empty();
> +
> + if (values.size() != this->_m_bulk.size())
> + throw ::std::invalid_argument("the size of values array must correspond with the number of lines");
> +
> + ::gpiod_line_bulk bulk;
> + int rv;
> +
> + this->to_line_bulk(::std::addressof(bulk));
> +
> + rv = ::gpiod_line_set_direction_output_bulk(::std::addressof(bulk),
> + values.data());
> + if (rv)
> + throw ::std::system_error(errno, ::std::system_category(),
> + "error setting GPIO line direction to output");
> +}
> +
> line_bulk line_bulk::event_wait(const ::std::chrono::nanoseconds& timeout) const
> {
> this->throw_if_empty();
> --
> 2.24.0
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [libgpiod][PATCH v3 10/14] bindings: cxx: tests: add tests for SET_CONFIG methods
2019-11-25 14:31 [libgpiod][PATCH v3 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
` (8 preceding siblings ...)
2019-11-25 14:31 ` [libgpiod][PATCH v3 09/14] bindings: cxx: add support " Kent Gibson
@ 2019-11-25 14:31 ` Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 11/14] bindings: python: add support for SET_CONFIG Kent Gibson
` (3 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Kent Gibson @ 2019-11-25 14:31 UTC (permalink / raw)
To: linux-gpio, bgolaszewski; +Cc: Kent Gibson
Extend test coverage over set_config, set_flags, set_direction_input, and
set_direction_output methods.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
bindings/cxx/tests/tests-line.cpp | 128 ++++++++++++++++++++++++++++++
1 file changed, 128 insertions(+)
diff --git a/bindings/cxx/tests/tests-line.cpp b/bindings/cxx/tests/tests-line.cpp
index 9a0b488..5353093 100644
--- a/bindings/cxx/tests/tests-line.cpp
+++ b/bindings/cxx/tests/tests-line.cpp
@@ -324,6 +324,134 @@ TEST_CASE("Line values can be set and read", "[line]")
}
}
+TEST_CASE("Line can be reconfigured", "[line]")
+{
+ mockup::probe_guard mockup_chips({ 8 });
+ ::gpiod::chip chip(mockup::instance().chip_name(0));
+ ::gpiod::line_request config;
+
+ config.consumer = consumer.c_str();
+
+ SECTION("set config (single line, active-state)")
+ {
+ auto line = chip.get_line(3);
+ config.request_type = ::gpiod::line_request::DIRECTION_INPUT;
+ config.flags = 0;
+ line.request(config);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_INPUT);
+ REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
+
+ line.set_config(::gpiod::line_request::DIRECTION_OUTPUT,
+ ::gpiod::line_request::FLAG_ACTIVE_LOW,1);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_LOW);
+ REQUIRE(mockup::instance().chip_get_value(0, 3) == 0);
+ line.set_value(0);
+ REQUIRE(mockup::instance().chip_get_value(0, 3) == 1);
+
+ line.set_config(::gpiod::line_request::DIRECTION_OUTPUT, 0);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
+ REQUIRE(mockup::instance().chip_get_value(0, 3) == 0);
+ line.set_value(1);
+ REQUIRE(mockup::instance().chip_get_value(0, 3) == 1);
+ }
+
+ SECTION("set flags (single line, active-state)")
+ {
+ auto line = chip.get_line(3);
+ config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+ config.flags = 0;
+ line.request(config,1);
+ REQUIRE(mockup::instance().chip_get_value(0, 3) == 1);
+
+ line.set_flags(::gpiod::line_request::FLAG_ACTIVE_LOW);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_LOW);
+ REQUIRE(mockup::instance().chip_get_value(0, 3) == 0);
+
+ line.set_flags(0);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
+ REQUIRE(mockup::instance().chip_get_value(0, 3) == 1);
+ }
+
+ SECTION("set flags (single line, drive)")
+ {
+ auto line = chip.get_line(3);
+ config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+ config.flags = 0;
+ line.request(config);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE_FALSE(line.is_open_drain());
+ REQUIRE_FALSE(line.is_open_source());
+
+ line.set_flags(::gpiod::line_request::FLAG_OPEN_DRAIN);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE(line.is_open_drain());
+ REQUIRE_FALSE(line.is_open_source());
+
+ line.set_flags(::gpiod::line_request::FLAG_OPEN_SOURCE);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE_FALSE(line.is_open_drain());
+ REQUIRE(line.is_open_source());
+
+ line.set_flags(0);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE_FALSE(line.is_open_drain());
+ REQUIRE_FALSE(line.is_open_source());
+ }
+
+ SECTION("set flags (single line, bias)")
+ {
+ auto line = chip.get_line(3);
+ config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+ config.flags = 0;
+ line.request(config);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE_FALSE(line.is_open_drain());
+ REQUIRE_FALSE(line.is_open_source());
+
+ line.set_flags(::gpiod::line_request::FLAG_OPEN_DRAIN);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE(line.is_open_drain());
+ REQUIRE_FALSE(line.is_open_source());
+
+ line.set_flags(::gpiod::line_request::FLAG_OPEN_SOURCE);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE_FALSE(line.is_open_drain());
+ REQUIRE(line.is_open_source());
+
+ line.set_flags(0);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE_FALSE(line.is_open_drain());
+ REQUIRE_FALSE(line.is_open_source());
+ }
+
+ SECTION("set direction input (single line)")
+ {
+ auto line = chip.get_line(3);
+ config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+ config.flags = 0;
+ line.request(config);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ line.set_direction_input();
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_INPUT);
+ }
+
+ SECTION("set direction output (single line)")
+ {
+ auto line = chip.get_line(3);
+ config.request_type = ::gpiod::line_request::DIRECTION_INPUT;
+ config.flags = 0;
+ line.request(config);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_INPUT);
+ line.set_direction_output(1);
+ REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+ REQUIRE(mockup::instance().chip_get_value(0, 3) == 1);
+ }
+}
+
TEST_CASE("Exported line can be released", "[line]")
{
mockup::probe_guard mockup_chips({ 8 });
--
2.24.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [libgpiod][PATCH v3 11/14] bindings: python: add support for SET_CONFIG
2019-11-25 14:31 [libgpiod][PATCH v3 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
` (9 preceding siblings ...)
2019-11-25 14:31 ` [libgpiod][PATCH v3 10/14] bindings: cxx: tests: add tests for SET_CONFIG methods Kent Gibson
@ 2019-11-25 14:31 ` Kent Gibson
2019-11-28 10:29 ` Bartosz Golaszewski
2019-11-25 14:31 ` [libgpiod][PATCH v3 12/14] bindings: python: tests: add tests for SET_CONFIG methods Kent Gibson
` (2 subsequent siblings)
13 siblings, 1 reply; 21+ messages in thread
From: Kent Gibson @ 2019-11-25 14:31 UTC (permalink / raw)
To: linux-gpio, bgolaszewski; +Cc: Kent Gibson
Add methods to support setting line configuration.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
bindings/python/gpiodmodule.c | 381 +++++++++++++++++++++++++++++++++-
1 file changed, 379 insertions(+), 2 deletions(-)
diff --git a/bindings/python/gpiodmodule.c b/bindings/python/gpiodmodule.c
index 4723771..4f5e117 100644
--- a/bindings/python/gpiodmodule.c
+++ b/bindings/python/gpiodmodule.c
@@ -585,14 +585,149 @@ static PyObject *gpiod_Line_set_value(gpiod_LineObject *self, PyObject *args)
if (!bulk_obj)
return NULL;
- vals = Py_BuildValue("((O))", val);
+ vals = Py_BuildValue("(O)", val);
if (!vals) {
Py_DECREF(bulk_obj);
return NULL;
}
ret = PyObject_CallMethod((PyObject *)bulk_obj,
- "set_values", "O", vals);
+ "set_values", "(O)", vals);
+ Py_DECREF(bulk_obj);
+ Py_DECREF(vals);
+
+ return ret;
+}
+
+PyDoc_STRVAR(gpiod_Line_set_config_doc,
+"set_config(direction,flags,value) -> None\n"
+"\n"
+"Set the configuration of this GPIO line.\n"
+"\n"
+" direction\n"
+" New direction (integer)\n"
+" flags\n"
+" New flags (integer)\n"
+" value\n"
+" New value (integer)");
+
+static PyObject *gpiod_Line_set_config(gpiod_LineObject *self, PyObject *args)
+{
+ gpiod_LineBulkObject *bulk_obj;
+ PyObject *dirn, *flags, *val, *vals, *ret;
+ int rv;
+
+ val = NULL;
+ rv = PyArg_ParseTuple(args, "OO|O", &dirn, &flags, &val);
+ if (!rv)
+ return NULL;
+
+ bulk_obj = gpiod_LineToLineBulk(self);
+ if (!bulk_obj)
+ return NULL;
+
+ if (val) {
+ vals = Py_BuildValue("(O)", val);
+ if (!vals) {
+ Py_DECREF(bulk_obj);
+ return NULL;
+ }
+ ret = PyObject_CallMethod((PyObject *)bulk_obj,
+ "set_config", "OO(O)", dirn, flags, vals);
+ Py_DECREF(vals);
+ } else
+ ret = PyObject_CallMethod((PyObject *)bulk_obj,
+ "set_config", "OO", dirn, flags);
+
+ Py_DECREF(bulk_obj);
+
+ return ret;
+}
+
+PyDoc_STRVAR(gpiod_Line_set_flags_doc,
+"set_flags(flags) -> None\n"
+"\n"
+"Set the flags of this GPIO line.\n"
+"\n"
+" flags\n"
+" New flags (integer)");
+
+static PyObject *gpiod_Line_set_flags(gpiod_LineObject *self, PyObject *args)
+{
+ gpiod_LineBulkObject *bulk_obj;
+ PyObject *ret;
+
+ bulk_obj = gpiod_LineToLineBulk(self);
+ if (!bulk_obj)
+ return NULL;
+
+ ret = PyObject_CallMethod((PyObject *)bulk_obj,
+ "set_flags", "O", args);
+ Py_DECREF(bulk_obj);
+
+ return ret;
+}
+
+PyDoc_STRVAR(gpiod_Line_set_direction_input_doc,
+"set_direction_input() -> None\n"
+"\n"
+"Set the direction of this GPIO line to input.\n");
+
+static PyObject *gpiod_Line_set_direction_input(gpiod_LineObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ gpiod_LineBulkObject *bulk_obj;
+ PyObject *ret;
+
+ bulk_obj = gpiod_LineToLineBulk(self);
+ if (!bulk_obj)
+ return NULL;
+
+ ret = PyObject_CallMethod((PyObject *)bulk_obj,
+ "set_direction_input", "");
+ Py_DECREF(bulk_obj);
+
+ return ret;
+}
+
+PyDoc_STRVAR(gpiod_Line_set_direction_output_doc,
+"set_direction_output(value) -> None\n"
+"\n"
+"Set the direction of this GPIO line to output.\n"
+"\n"
+" value\n"
+" New value (integer)");
+
+static PyObject *gpiod_Line_set_direction_output(gpiod_LineObject *self,
+ PyObject *args)
+{
+ gpiod_LineBulkObject *bulk_obj;
+ PyObject *val, *vals, *ret;
+ int rv;
+ const char *fmt;
+
+ val = NULL;
+ rv = PyArg_ParseTuple(args, "|O", &val);
+ if (!rv)
+ return NULL;
+
+ if (val) {
+ fmt = "(O)";
+ vals = Py_BuildValue(fmt, val);
+ } else {
+ vals = Py_BuildValue("()");
+ fmt = "O"; /* pass empty args to bulk */
+ }
+ if (!vals)
+ return NULL;
+
+ bulk_obj = gpiod_LineToLineBulk(self);
+ if (!bulk_obj)
+ return NULL;
+
+ ret = PyObject_CallMethod((PyObject *)bulk_obj,
+ "set_direction_output", fmt, vals);
+
Py_DECREF(bulk_obj);
Py_DECREF(vals);
@@ -838,6 +973,30 @@ static PyMethodDef gpiod_Line_methods[] = {
.ml_flags = METH_VARARGS,
.ml_doc = gpiod_Line_set_value_doc,
},
+ {
+ .ml_name = "set_config",
+ .ml_meth = (PyCFunction)gpiod_Line_set_config,
+ .ml_flags = METH_VARARGS,
+ .ml_doc = gpiod_Line_set_config_doc,
+ },
+ {
+ .ml_name = "set_flags",
+ .ml_meth = (PyCFunction)gpiod_Line_set_flags,
+ .ml_flags = METH_VARARGS,
+ .ml_doc = gpiod_Line_set_flags_doc,
+ },
+ {
+ .ml_name = "set_direction_input",
+ .ml_meth = (PyCFunction)gpiod_Line_set_direction_input,
+ .ml_flags = METH_NOARGS,
+ .ml_doc = gpiod_Line_set_direction_input_doc,
+ },
+ {
+ .ml_name = "set_direction_output",
+ .ml_meth = (PyCFunction)gpiod_Line_set_direction_output,
+ .ml_flags = METH_VARARGS,
+ .ml_doc = gpiod_Line_set_direction_output_doc,
+ },
{
.ml_name = "release",
.ml_meth = (PyCFunction)gpiod_Line_release,
@@ -1283,6 +1442,200 @@ static PyObject *gpiod_LineBulk_set_values(gpiod_LineBulkObject *self,
Py_RETURN_NONE;
}
+static int convert_values(PyObject *src, int *dst, Py_ssize_t n)
+{
+ int val;
+ Py_ssize_t num_vals, i;
+ PyObject *iter, *next;
+
+ num_vals = PyObject_Size(src);
+ if (num_vals != n) {
+ PyErr_SetString(PyExc_TypeError,
+ "Number of values must correspond to the number of lines");
+ return -1;
+ }
+ iter = PyObject_GetIter(src);
+ if (!iter)
+ return -1;
+ for (i = 0;; i++) {
+ next = PyIter_Next(iter);
+ if (!next) {
+ Py_DECREF(iter);
+ break;
+ }
+ val = PyLong_AsLong(next);
+ Py_DECREF(next);
+ if (PyErr_Occurred()) {
+ Py_DECREF(iter);
+ return -1;
+ }
+ dst[i] = (int)val;
+ }
+ return 0;
+}
+
+PyDoc_STRVAR(gpiod_LineBulk_set_config_doc,
+"set_config(direction,flags,values) -> None\n"
+"\n"
+"Set the configuration of all the lines held by this LineBulk object.\n"
+"\n"
+" direction\n"
+" New direction (integer)\n"
+" flags\n"
+" New flags (integer)\n"
+" values\n"
+" List of values (integers) to set when direction is output.\n"
+"\n"
+"The number of values in the list passed as argument must be the same as\n"
+"the number of lines held by this gpiod.LineBulk object. The index of each\n"
+"value corresponds to the index of each line in the object.\n");
+
+static PyObject *gpiod_LineBulk_set_config(gpiod_LineBulkObject *self,
+ PyObject *args)
+{
+ int rv, vals[GPIOD_LINE_BULK_MAX_LINES];
+ PyObject *val_list;
+ struct gpiod_line_bulk bulk;
+ const int *valp;
+ int dirn, flags;
+
+ if (gpiod_LineBulkOwnerIsClosed(self))
+ return NULL;
+
+ gpiod_LineBulkObjToCLineBulk(self, &bulk);
+
+ val_list = NULL;
+ rv = PyArg_ParseTuple(args, "ii|(O)", &dirn, &flags, &val_list);
+ if (!rv)
+ return NULL;
+
+ if (val_list == NULL)
+ valp = NULL;
+ else {
+ memset(vals, 0, sizeof(vals));
+ rv = convert_values(val_list, vals, self->num_lines);
+ if (rv)
+ return NULL;
+ valp = vals;
+ }
+
+ Py_BEGIN_ALLOW_THREADS;
+ rv = gpiod_line_set_config_bulk(&bulk, dirn, flags, valp);
+ Py_END_ALLOW_THREADS;
+ if (rv)
+ return PyErr_SetFromErrno(PyExc_OSError);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(gpiod_LineBulk_set_flags_doc,
+"set_flags(flags) -> None\n"
+"\n"
+"Set the flags of all the lines held by this LineBulk object.\n"
+"\n"
+" flags\n"
+" New flags (integer)");
+
+static PyObject *gpiod_LineBulk_set_flags(gpiod_LineBulkObject *self,
+ PyObject *args)
+{
+ int rv;
+ struct gpiod_line_bulk bulk;
+ int flags;
+
+ if (gpiod_LineBulkOwnerIsClosed(self))
+ return NULL;
+
+ gpiod_LineBulkObjToCLineBulk(self, &bulk);
+
+ rv = PyArg_ParseTuple(args, "i", &flags);
+ if (!rv)
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS;
+ rv = gpiod_line_set_flags_bulk(&bulk, flags);
+ Py_END_ALLOW_THREADS;
+ if (rv)
+ return PyErr_SetFromErrno(PyExc_OSError);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(gpiod_LineBulk_set_direction_input_doc,
+"set_direction_input() -> None\n"
+"\n"
+"Set the direction of all the lines held by this LineBulk object to input.\n");
+
+static PyObject *gpiod_LineBulk_set_direction_input(gpiod_LineBulkObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct gpiod_line_bulk bulk;
+ int rv;
+
+ if (gpiod_LineBulkOwnerIsClosed(self))
+ return NULL;
+
+ gpiod_LineBulkObjToCLineBulk(self, &bulk);
+
+ Py_BEGIN_ALLOW_THREADS;
+ rv = gpiod_line_set_direction_input_bulk(&bulk);
+ Py_END_ALLOW_THREADS;
+ if (rv)
+ return PyErr_SetFromErrno(PyExc_OSError);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(gpiod_LineBulk_set_direction_output_doc,
+"set_direction_output(value) -> None\n"
+"\n"
+"Set the direction of all the lines held by this LineBulk object to output.\n"
+"\n"
+" values\n"
+" List of values (integers) to set when direction is output.\n"
+"\n"
+"The number of values in the list passed as argument must be the same as\n"
+"the number of lines held by this gpiod.LineBulk object. The index of each\n"
+"value corresponds to the index of each line in the object.\n");
+
+static PyObject *gpiod_LineBulk_set_direction_output(
+ gpiod_LineBulkObject *self,
+ PyObject *args)
+{
+ int rv, vals[GPIOD_LINE_BULK_MAX_LINES];
+ PyObject *val_list;
+ struct gpiod_line_bulk bulk;
+ const int *valp;
+
+ if (gpiod_LineBulkOwnerIsClosed(self))
+ return NULL;
+
+ gpiod_LineBulkObjToCLineBulk(self, &bulk);
+
+ val_list = NULL;
+ rv = PyArg_ParseTuple(args, "|O", &val_list);
+ if (!rv)
+ return NULL;
+
+ if (val_list == NULL)
+ valp = NULL;
+ else {
+ memset(vals, 0, sizeof(vals));
+ rv = convert_values(val_list, vals, self->num_lines);
+ if (rv)
+ return NULL;
+ valp = vals;
+ }
+
+ Py_BEGIN_ALLOW_THREADS;
+ rv = gpiod_line_set_direction_output_bulk(&bulk, valp);
+ Py_END_ALLOW_THREADS;
+ if (rv)
+ return PyErr_SetFromErrno(PyExc_OSError);
+
+ Py_RETURN_NONE;
+}
+
PyDoc_STRVAR(gpiod_LineBulk_release_doc,
"release() -> None\n"
"\n"
@@ -1431,6 +1784,30 @@ static PyMethodDef gpiod_LineBulk_methods[] = {
.ml_doc = gpiod_LineBulk_set_values_doc,
.ml_flags = METH_VARARGS,
},
+ {
+ .ml_name = "set_config",
+ .ml_meth = (PyCFunction)gpiod_LineBulk_set_config,
+ .ml_flags = METH_VARARGS,
+ .ml_doc = gpiod_LineBulk_set_config_doc,
+ },
+ {
+ .ml_name = "set_flags",
+ .ml_meth = (PyCFunction)gpiod_LineBulk_set_flags,
+ .ml_flags = METH_VARARGS,
+ .ml_doc = gpiod_LineBulk_set_flags_doc,
+ },
+ {
+ .ml_name = "set_direction_input",
+ .ml_meth = (PyCFunction)gpiod_LineBulk_set_direction_input,
+ .ml_flags = METH_NOARGS,
+ .ml_doc = gpiod_LineBulk_set_direction_input_doc,
+ },
+ {
+ .ml_name = "set_direction_output",
+ .ml_meth = (PyCFunction)gpiod_LineBulk_set_direction_output,
+ .ml_flags = METH_VARARGS,
+ .ml_doc = gpiod_LineBulk_set_direction_output_doc,
+ },
{
.ml_name = "release",
.ml_meth = (PyCFunction)gpiod_LineBulk_release,
--
2.24.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [libgpiod][PATCH v3 11/14] bindings: python: add support for SET_CONFIG
2019-11-25 14:31 ` [libgpiod][PATCH v3 11/14] bindings: python: add support for SET_CONFIG Kent Gibson
@ 2019-11-28 10:29 ` Bartosz Golaszewski
0 siblings, 0 replies; 21+ messages in thread
From: Bartosz Golaszewski @ 2019-11-28 10:29 UTC (permalink / raw)
To: Kent Gibson; +Cc: linux-gpio
pon., 25 lis 2019 o 15:33 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> Add methods to support setting line configuration.
>
> Signed-off-by: Kent Gibson <warthog618@gmail.com>
> ---
> bindings/python/gpiodmodule.c | 381 +++++++++++++++++++++++++++++++++-
> 1 file changed, 379 insertions(+), 2 deletions(-)
>
> diff --git a/bindings/python/gpiodmodule.c b/bindings/python/gpiodmodule.c
> index 4723771..4f5e117 100644
> --- a/bindings/python/gpiodmodule.c
> +++ b/bindings/python/gpiodmodule.c
> @@ -585,14 +585,149 @@ static PyObject *gpiod_Line_set_value(gpiod_LineObject *self, PyObject *args)
> if (!bulk_obj)
> return NULL;
>
> - vals = Py_BuildValue("((O))", val);
> + vals = Py_BuildValue("(O)", val);
Please don't try to sneak in changes like this. If you think this
should be changed, make it a separate commit with proper explanation.
I vaguely remember using this because previously I didn't use
PyObject_CallMethod() but called the set_values() function directly
and it was easier to package it right away. Anyway - is it broken? Do
we gain something from changing it? If so, let's have a separate patch
for this.
> if (!vals) {
> Py_DECREF(bulk_obj);
> return NULL;
> }
>
> ret = PyObject_CallMethod((PyObject *)bulk_obj,
> - "set_values", "O", vals);
> + "set_values", "(O)", vals);
> + Py_DECREF(bulk_obj);
> + Py_DECREF(vals);
> +
> + return ret;
> +}
> +
> +PyDoc_STRVAR(gpiod_Line_set_config_doc,
> +"set_config(direction,flags,value) -> None\n"
> +"\n"
> +"Set the configuration of this GPIO line.\n"
> +"\n"
> +" direction\n"
> +" New direction (integer)\n"
> +" flags\n"
> +" New flags (integer)\n"
> +" value\n"
> +" New value (integer)");
> +
> +static PyObject *gpiod_Line_set_config(gpiod_LineObject *self, PyObject *args)
> +{
> + gpiod_LineBulkObject *bulk_obj;
> + PyObject *dirn, *flags, *val, *vals, *ret;
> + int rv;
> +
> + val = NULL;
> + rv = PyArg_ParseTuple(args, "OO|O", &dirn, &flags, &val);
> + if (!rv)
> + return NULL;
> +
> + bulk_obj = gpiod_LineToLineBulk(self);
> + if (!bulk_obj)
> + return NULL;
> +
> + if (val) {
> + vals = Py_BuildValue("(O)", val);
> + if (!vals) {
> + Py_DECREF(bulk_obj);
> + return NULL;
> + }
> + ret = PyObject_CallMethod((PyObject *)bulk_obj,
> + "set_config", "OO(O)", dirn, flags, vals);
> + Py_DECREF(vals);
> + } else
> + ret = PyObject_CallMethod((PyObject *)bulk_obj,
> + "set_config", "OO", dirn, flags);
Please use brackets here even if it's a single line after you used it
in the first branch. Same elsewhere if needed.
> +
> + Py_DECREF(bulk_obj);
> +
> + return ret;
> +}
> +
> +PyDoc_STRVAR(gpiod_Line_set_flags_doc,
> +"set_flags(flags) -> None\n"
> +"\n"
> +"Set the flags of this GPIO line.\n"
> +"\n"
> +" flags\n"
> +" New flags (integer)");
> +
> +static PyObject *gpiod_Line_set_flags(gpiod_LineObject *self, PyObject *args)
> +{
> + gpiod_LineBulkObject *bulk_obj;
> + PyObject *ret;
> +
> + bulk_obj = gpiod_LineToLineBulk(self);
> + if (!bulk_obj)
> + return NULL;
> +
> + ret = PyObject_CallMethod((PyObject *)bulk_obj,
> + "set_flags", "O", args);
> + Py_DECREF(bulk_obj);
> +
> + return ret;
> +}
> +
> +PyDoc_STRVAR(gpiod_Line_set_direction_input_doc,
> +"set_direction_input() -> None\n"
> +"\n"
> +"Set the direction of this GPIO line to input.\n");
> +
> +static PyObject *gpiod_Line_set_direction_input(gpiod_LineObject *self,
> + PyObject *Py_UNUSED(ignored))
> +{
> + gpiod_LineBulkObject *bulk_obj;
> + PyObject *ret;
> +
> + bulk_obj = gpiod_LineToLineBulk(self);
> + if (!bulk_obj)
> + return NULL;
> +
> + ret = PyObject_CallMethod((PyObject *)bulk_obj,
> + "set_direction_input", "");
> + Py_DECREF(bulk_obj);
> +
> + return ret;
> +}
> +
> +PyDoc_STRVAR(gpiod_Line_set_direction_output_doc,
> +"set_direction_output(value) -> None\n"
> +"\n"
> +"Set the direction of this GPIO line to output.\n"
> +"\n"
> +" value\n"
> +" New value (integer)");
> +
> +static PyObject *gpiod_Line_set_direction_output(gpiod_LineObject *self,
> + PyObject *args)
> +{
> + gpiod_LineBulkObject *bulk_obj;
> + PyObject *val, *vals, *ret;
> + int rv;
> + const char *fmt;
> +
> + val = NULL;
> + rv = PyArg_ParseTuple(args, "|O", &val);
> + if (!rv)
> + return NULL;
> +
> + if (val) {
> + fmt = "(O)";
> + vals = Py_BuildValue(fmt, val);
> + } else {
> + vals = Py_BuildValue("()");
> + fmt = "O"; /* pass empty args to bulk */
> + }
> + if (!vals)
> + return NULL;
> +
> + bulk_obj = gpiod_LineToLineBulk(self);
> + if (!bulk_obj)
> + return NULL;
> +
> + ret = PyObject_CallMethod((PyObject *)bulk_obj,
> + "set_direction_output", fmt, vals);
> +
> Py_DECREF(bulk_obj);
> Py_DECREF(vals);
>
> @@ -838,6 +973,30 @@ static PyMethodDef gpiod_Line_methods[] = {
> .ml_flags = METH_VARARGS,
> .ml_doc = gpiod_Line_set_value_doc,
> },
> + {
> + .ml_name = "set_config",
> + .ml_meth = (PyCFunction)gpiod_Line_set_config,
> + .ml_flags = METH_VARARGS,
> + .ml_doc = gpiod_Line_set_config_doc,
> + },
> + {
> + .ml_name = "set_flags",
> + .ml_meth = (PyCFunction)gpiod_Line_set_flags,
> + .ml_flags = METH_VARARGS,
> + .ml_doc = gpiod_Line_set_flags_doc,
> + },
> + {
> + .ml_name = "set_direction_input",
> + .ml_meth = (PyCFunction)gpiod_Line_set_direction_input,
> + .ml_flags = METH_NOARGS,
> + .ml_doc = gpiod_Line_set_direction_input_doc,
> + },
> + {
> + .ml_name = "set_direction_output",
> + .ml_meth = (PyCFunction)gpiod_Line_set_direction_output,
> + .ml_flags = METH_VARARGS,
> + .ml_doc = gpiod_Line_set_direction_output_doc,
> + },
> {
> .ml_name = "release",
> .ml_meth = (PyCFunction)gpiod_Line_release,
> @@ -1283,6 +1442,200 @@ static PyObject *gpiod_LineBulk_set_values(gpiod_LineBulkObject *self,
> Py_RETURN_NONE;
> }
>
> +static int convert_values(PyObject *src, int *dst, Py_ssize_t n)
Coding convention and readability: this module is a bit different as I
tried to stay consistent with Python C code when naming symbols.
Please use the common 'gpiod_' prefix even for non-exported functions
and maybe name this routine something else as "convert_values" doesn't
really indicate concrete functionality. I'm still not sure what it
does.
> +{
> + int val;
> + Py_ssize_t num_vals, i;
> + PyObject *iter, *next;
> +
> + num_vals = PyObject_Size(src);
> + if (num_vals != n) {
> + PyErr_SetString(PyExc_TypeError,
> + "Number of values must correspond to the number of lines");
> + return -1;
> + }
> + iter = PyObject_GetIter(src);
> + if (!iter)
> + return -1;
> + for (i = 0;; i++) {
> + next = PyIter_Next(iter);
> + if (!next) {
> + Py_DECREF(iter);
> + break;
> + }
> + val = PyLong_AsLong(next);
> + Py_DECREF(next);
> + if (PyErr_Occurred()) {
> + Py_DECREF(iter);
> + return -1;
> + }
> + dst[i] = (int)val;
> + }
> + return 0;
> +}
> +
> +PyDoc_STRVAR(gpiod_LineBulk_set_config_doc,
> +"set_config(direction,flags,values) -> None\n"
> +"\n"
> +"Set the configuration of all the lines held by this LineBulk object.\n"
> +"\n"
> +" direction\n"
> +" New direction (integer)\n"
> +" flags\n"
> +" New flags (integer)\n"
> +" values\n"
> +" List of values (integers) to set when direction is output.\n"
> +"\n"
> +"The number of values in the list passed as argument must be the same as\n"
> +"the number of lines held by this gpiod.LineBulk object. The index of each\n"
> +"value corresponds to the index of each line in the object.\n");
> +
> +static PyObject *gpiod_LineBulk_set_config(gpiod_LineBulkObject *self,
> + PyObject *args)
> +{
> + int rv, vals[GPIOD_LINE_BULK_MAX_LINES];
> + PyObject *val_list;
> + struct gpiod_line_bulk bulk;
> + const int *valp;
> + int dirn, flags;
> +
> + if (gpiod_LineBulkOwnerIsClosed(self))
> + return NULL;
> +
> + gpiod_LineBulkObjToCLineBulk(self, &bulk);
> +
> + val_list = NULL;
> + rv = PyArg_ParseTuple(args, "ii|(O)", &dirn, &flags, &val_list);
> + if (!rv)
> + return NULL;
> +
> + if (val_list == NULL)
> + valp = NULL;
> + else {
> + memset(vals, 0, sizeof(vals));
> + rv = convert_values(val_list, vals, self->num_lines);
> + if (rv)
> + return NULL;
> + valp = vals;
> + }
> +
> + Py_BEGIN_ALLOW_THREADS;
> + rv = gpiod_line_set_config_bulk(&bulk, dirn, flags, valp);
> + Py_END_ALLOW_THREADS;
> + if (rv)
> + return PyErr_SetFromErrno(PyExc_OSError);
> +
> + Py_RETURN_NONE;
> +}
> +
> +PyDoc_STRVAR(gpiod_LineBulk_set_flags_doc,
> +"set_flags(flags) -> None\n"
> +"\n"
> +"Set the flags of all the lines held by this LineBulk object.\n"
> +"\n"
> +" flags\n"
> +" New flags (integer)");
> +
> +static PyObject *gpiod_LineBulk_set_flags(gpiod_LineBulkObject *self,
> + PyObject *args)
> +{
> + int rv;
> + struct gpiod_line_bulk bulk;
> + int flags;
> +
> + if (gpiod_LineBulkOwnerIsClosed(self))
> + return NULL;
> +
> + gpiod_LineBulkObjToCLineBulk(self, &bulk);
> +
> + rv = PyArg_ParseTuple(args, "i", &flags);
> + if (!rv)
> + return NULL;
> +
> + Py_BEGIN_ALLOW_THREADS;
> + rv = gpiod_line_set_flags_bulk(&bulk, flags);
> + Py_END_ALLOW_THREADS;
> + if (rv)
> + return PyErr_SetFromErrno(PyExc_OSError);
> +
> + Py_RETURN_NONE;
> +}
> +
> +PyDoc_STRVAR(gpiod_LineBulk_set_direction_input_doc,
> +"set_direction_input() -> None\n"
> +"\n"
> +"Set the direction of all the lines held by this LineBulk object to input.\n");
> +
> +static PyObject *gpiod_LineBulk_set_direction_input(gpiod_LineBulkObject *self,
> + PyObject *Py_UNUSED(ignored))
> +{
> + struct gpiod_line_bulk bulk;
> + int rv;
> +
> + if (gpiod_LineBulkOwnerIsClosed(self))
> + return NULL;
> +
> + gpiod_LineBulkObjToCLineBulk(self, &bulk);
> +
> + Py_BEGIN_ALLOW_THREADS;
> + rv = gpiod_line_set_direction_input_bulk(&bulk);
> + Py_END_ALLOW_THREADS;
> + if (rv)
> + return PyErr_SetFromErrno(PyExc_OSError);
> +
> + Py_RETURN_NONE;
> +}
> +
> +PyDoc_STRVAR(gpiod_LineBulk_set_direction_output_doc,
> +"set_direction_output(value) -> None\n"
> +"\n"
> +"Set the direction of all the lines held by this LineBulk object to output.\n"
> +"\n"
> +" values\n"
> +" List of values (integers) to set when direction is output.\n"
> +"\n"
> +"The number of values in the list passed as argument must be the same as\n"
> +"the number of lines held by this gpiod.LineBulk object. The index of each\n"
> +"value corresponds to the index of each line in the object.\n");
> +
> +static PyObject *gpiod_LineBulk_set_direction_output(
> + gpiod_LineBulkObject *self,
> + PyObject *args)
> +{
> + int rv, vals[GPIOD_LINE_BULK_MAX_LINES];
> + PyObject *val_list;
> + struct gpiod_line_bulk bulk;
> + const int *valp;
> +
> + if (gpiod_LineBulkOwnerIsClosed(self))
> + return NULL;
> +
> + gpiod_LineBulkObjToCLineBulk(self, &bulk);
> +
> + val_list = NULL;
> + rv = PyArg_ParseTuple(args, "|O", &val_list);
> + if (!rv)
> + return NULL;
> +
> + if (val_list == NULL)
> + valp = NULL;
> + else {
> + memset(vals, 0, sizeof(vals));
> + rv = convert_values(val_list, vals, self->num_lines);
> + if (rv)
> + return NULL;
> + valp = vals;
> + }
> +
> + Py_BEGIN_ALLOW_THREADS;
> + rv = gpiod_line_set_direction_output_bulk(&bulk, valp);
> + Py_END_ALLOW_THREADS;
> + if (rv)
> + return PyErr_SetFromErrno(PyExc_OSError);
> +
> + Py_RETURN_NONE;
> +}
> +
> PyDoc_STRVAR(gpiod_LineBulk_release_doc,
> "release() -> None\n"
> "\n"
> @@ -1431,6 +1784,30 @@ static PyMethodDef gpiod_LineBulk_methods[] = {
> .ml_doc = gpiod_LineBulk_set_values_doc,
> .ml_flags = METH_VARARGS,
> },
> + {
> + .ml_name = "set_config",
> + .ml_meth = (PyCFunction)gpiod_LineBulk_set_config,
> + .ml_flags = METH_VARARGS,
> + .ml_doc = gpiod_LineBulk_set_config_doc,
> + },
> + {
> + .ml_name = "set_flags",
> + .ml_meth = (PyCFunction)gpiod_LineBulk_set_flags,
> + .ml_flags = METH_VARARGS,
> + .ml_doc = gpiod_LineBulk_set_flags_doc,
> + },
> + {
> + .ml_name = "set_direction_input",
> + .ml_meth = (PyCFunction)gpiod_LineBulk_set_direction_input,
> + .ml_flags = METH_NOARGS,
> + .ml_doc = gpiod_LineBulk_set_direction_input_doc,
> + },
> + {
> + .ml_name = "set_direction_output",
> + .ml_meth = (PyCFunction)gpiod_LineBulk_set_direction_output,
> + .ml_flags = METH_VARARGS,
> + .ml_doc = gpiod_LineBulk_set_direction_output_doc,
> + },
> {
> .ml_name = "release",
> .ml_meth = (PyCFunction)gpiod_LineBulk_release,
> --
> 2.24.0
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [libgpiod][PATCH v3 12/14] bindings: python: tests: add tests for SET_CONFIG methods
2019-11-25 14:31 [libgpiod][PATCH v3 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
` (10 preceding siblings ...)
2019-11-25 14:31 ` [libgpiod][PATCH v3 11/14] bindings: python: add support for SET_CONFIG Kent Gibson
@ 2019-11-25 14:31 ` Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 13/14] tools: add support for bias flags Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 14/14] tools: add tests for bias and drive flags Kent Gibson
13 siblings, 0 replies; 21+ messages in thread
From: Kent Gibson @ 2019-11-25 14:31 UTC (permalink / raw)
To: linux-gpio, bgolaszewski; +Cc: Kent Gibson
Extend test coverage over set_config, set_flags, set_direction_input, and
set_direction_output methods.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
bindings/python/tests/gpiod_py_test.py | 163 +++++++++++++++++++++++++
1 file changed, 163 insertions(+)
diff --git a/bindings/python/tests/gpiod_py_test.py b/bindings/python/tests/gpiod_py_test.py
index 9330b43..704d916 100755
--- a/bindings/python/tests/gpiod_py_test.py
+++ b/bindings/python/tests/gpiod_py_test.py
@@ -493,6 +493,169 @@ class LineValues(MockupTestCase):
line.set_value(0)
self.assertEqual(mockup.chip_get_value(0, 3), 1)
+class LineConfig(MockupTestCase):
+
+ chip_sizes = ( 8, )
+
+ def test_set_config_direction(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_IN)
+ self.assertEqual(line.direction(), gpiod.Line.DIRECTION_INPUT)
+ line.set_config(gpiod.LINE_REQ_DIR_IN, 0, 0)
+ self.assertEqual(line.direction(), gpiod.Line.DIRECTION_INPUT)
+ line.set_config(gpiod.LINE_REQ_DIR_OUT,0,0)
+ self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+
+ def test_set_config_flags(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT)
+ line.set_config(gpiod.LINE_REQ_DIR_OUT,
+ gpiod.LINE_REQ_FLAG_ACTIVE_LOW, 0)
+ self.assertEqual(mockup.chip_get_value(0, 3), 1)
+ line.set_config(gpiod.LINE_REQ_DIR_OUT, 0, 0)
+ self.assertEqual(mockup.chip_get_value(0, 3), 0)
+
+ def test_set_config_output_value(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_IN)
+ line.set_config(gpiod.LINE_REQ_DIR_OUT,0,1)
+ self.assertEqual(mockup.chip_get_value(0, 3), 1)
+ line.set_config(gpiod.LINE_REQ_DIR_OUT,0,0)
+ self.assertEqual(mockup.chip_get_value(0, 3), 0)
+
+ def test_set_config_output_no_value(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT,
+ default_val=1)
+ self.assertEqual(mockup.chip_get_value(0, 3), 1)
+ line.set_config(gpiod.LINE_REQ_DIR_OUT,0)
+ self.assertEqual(mockup.chip_get_value(0, 3), 0)
+
+ def test_set_config_bulk_output_no_values(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ lines = chip.get_lines(( 0, 3, 4, 6 ))
+ lines.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT,
+ default_vals=(1,1,1,1))
+ self.assertEqual(mockup.chip_get_value(0, 0), 1)
+ self.assertEqual(mockup.chip_get_value(0, 3), 1)
+ self.assertEqual(mockup.chip_get_value(0, 4), 1)
+ self.assertEqual(mockup.chip_get_value(0, 6), 1)
+ lines.set_config(gpiod.LINE_REQ_DIR_OUT,0)
+ self.assertEqual(mockup.chip_get_value(0, 0), 0)
+ self.assertEqual(mockup.chip_get_value(0, 3), 0)
+ self.assertEqual(mockup.chip_get_value(0, 4), 0)
+ self.assertEqual(mockup.chip_get_value(0, 6), 0)
+
+class LineFlags(MockupTestCase):
+
+ chip_sizes = ( 8, )
+
+ def test_set_flags(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT,
+ default_val=1)
+ self.assertEqual(mockup.chip_get_value(0, 3), 1)
+ line.set_flags(gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
+ self.assertEqual(mockup.chip_get_value(0, 3), 0)
+ line.set_flags(0)
+ self.assertEqual(mockup.chip_get_value(0, 3), 1)
+
+ def test_set_flags_bulk(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ lines = chip.get_lines(( 0, 3, 4, 6 ))
+ lines.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT,
+ default_vals=(1,1,1,1))
+ self.assertEqual(mockup.chip_get_value(0, 0), 1)
+ self.assertEqual(mockup.chip_get_value(0, 3), 1)
+ self.assertEqual(mockup.chip_get_value(0, 4), 1)
+ self.assertEqual(mockup.chip_get_value(0, 6), 1)
+ lines.set_flags(gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
+ self.assertEqual(mockup.chip_get_value(0, 0), 0)
+ self.assertEqual(mockup.chip_get_value(0, 3), 0)
+ self.assertEqual(mockup.chip_get_value(0, 4), 0)
+ self.assertEqual(mockup.chip_get_value(0, 6), 0)
+ lines.set_flags(0)
+ self.assertEqual(mockup.chip_get_value(0, 0), 1)
+ self.assertEqual(mockup.chip_get_value(0, 3), 1)
+ self.assertEqual(mockup.chip_get_value(0, 4), 1)
+ self.assertEqual(mockup.chip_get_value(0, 6), 1)
+
+class LineDirection(MockupTestCase):
+
+ chip_sizes = ( 8, )
+
+ def test_set_direction(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT)
+ self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+ line.set_direction_input()
+ self.assertEqual(line.direction(), gpiod.Line.DIRECTION_INPUT)
+ line.set_direction_output(0)
+ self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(mockup.chip_get_value(0, 3), 0)
+ line.set_direction_output(1)
+ self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(mockup.chip_get_value(0, 3), 1)
+ line.set_direction_output()
+ self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(mockup.chip_get_value(0, 3), 0)
+
+ def test_set_direction_bulk(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ lines = chip.get_lines(( 0, 3, 4, 6 ))
+ lines.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT)
+ self.assertEqual(lines.to_list()[0].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(lines.to_list()[1].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(lines.to_list()[2].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(lines.to_list()[3].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ lines.set_direction_input()
+ self.assertEqual(lines.to_list()[0].direction(), gpiod.Line.DIRECTION_INPUT)
+ self.assertEqual(lines.to_list()[1].direction(), gpiod.Line.DIRECTION_INPUT)
+ self.assertEqual(lines.to_list()[2].direction(), gpiod.Line.DIRECTION_INPUT)
+ self.assertEqual(lines.to_list()[3].direction(), gpiod.Line.DIRECTION_INPUT)
+ lines.set_direction_output((0,0,1,0))
+ self.assertEqual(lines.to_list()[0].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(lines.to_list()[1].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(lines.to_list()[2].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(lines.to_list()[3].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(mockup.chip_get_value(0, 0), 0)
+ self.assertEqual(mockup.chip_get_value(0, 3), 0)
+ self.assertEqual(mockup.chip_get_value(0, 4), 1)
+ self.assertEqual(mockup.chip_get_value(0, 6), 0)
+ lines.set_direction_output((1,1,1,0))
+ self.assertEqual(lines.to_list()[0].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(lines.to_list()[1].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(lines.to_list()[2].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(lines.to_list()[3].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(mockup.chip_get_value(0, 0), 1)
+ self.assertEqual(mockup.chip_get_value(0, 3), 1)
+ self.assertEqual(mockup.chip_get_value(0, 4), 1)
+ self.assertEqual(mockup.chip_get_value(0, 6), 0)
+ lines.set_direction_output()
+ self.assertEqual(lines.to_list()[0].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(lines.to_list()[1].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(lines.to_list()[2].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(lines.to_list()[3].direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(mockup.chip_get_value(0, 0), 0)
+ self.assertEqual(mockup.chip_get_value(0, 3), 0)
+ self.assertEqual(mockup.chip_get_value(0, 4), 0)
+ self.assertEqual(mockup.chip_get_value(0, 6), 0)
+
class LineRequestBehavior(MockupTestCase):
chip_sizes = ( 8, )
--
2.24.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [libgpiod][PATCH v3 13/14] tools: add support for bias flags
2019-11-25 14:31 [libgpiod][PATCH v3 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
` (11 preceding siblings ...)
2019-11-25 14:31 ` [libgpiod][PATCH v3 12/14] bindings: python: tests: add tests for SET_CONFIG methods Kent Gibson
@ 2019-11-25 14:31 ` Kent Gibson
2019-11-28 10:29 ` Bartosz Golaszewski
2019-11-25 14:31 ` [libgpiod][PATCH v3 14/14] tools: add tests for bias and drive flags Kent Gibson
13 siblings, 1 reply; 21+ messages in thread
From: Kent Gibson @ 2019-11-25 14:31 UTC (permalink / raw)
To: linux-gpio, bgolaszewski; +Cc: Kent Gibson
Add support for bias flags to applicable tools - gpioget, gpioset, and
gpiomon.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
tools/gpioget.c | 32 +++++++++++++++++++++++++----
tools/gpiomon.c | 36 +++++++++++++++++++++++++++------
tools/gpioset.c | 54 ++++++++++++++++++++++++++++++++++++++++++++-----
3 files changed, 107 insertions(+), 15 deletions(-)
diff --git a/tools/gpioget.c b/tools/gpioget.c
index 196ebeb..17614cb 100644
--- a/tools/gpioget.c
+++ b/tools/gpioget.c
@@ -17,10 +17,11 @@ static const struct option longopts[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ "active-low", no_argument, NULL, 'l' },
+ { "bias", required_argument, NULL, 'B' },
{ GETOPT_NULL_LONGOPT },
};
-static const char *const shortopts = "+hvl";
+static const char *const shortopts = "+hvlB:";
static void print_help(void)
{
@@ -32,6 +33,25 @@ static void print_help(void)
printf(" -h, --help:\t\tdisplay this message and exit\n");
printf(" -v, --version:\tdisplay the version and exit\n");
printf(" -l, --active-low:\tset the line active state to low\n");
+ printf(" -B, --bias=[as-is|disable|pull-down|pull-up] (defaults to 'as-is'):\n");
+ printf(" set the line bias\n");
+ printf("\n");
+ printf("Biases:\n");
+ printf(" as-is:\tleave bias unchanged\n");
+ printf(" disable:\tdisable bias\n");
+ printf(" pull-up:\tenable pull-up\n");
+ printf(" pull-down:\tenable pull-down\n");
+}
+
+static int bias_flags(const char *option)
+{
+ if (strcmp(option, "pull-down") == 0)
+ return GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN;
+ if (strcmp(option, "pull-up") == 0)
+ return GPIOD_CTXLESS_FLAG_BIAS_PULL_UP;
+ if (strcmp(option, "disable") == 0)
+ return GPIOD_CTXLESS_FLAG_BIAS_DISABLE;
+ return 0;
}
int main(int argc, char **argv)
@@ -39,6 +59,7 @@ int main(int argc, char **argv)
unsigned int *offsets, i, num_lines;
int *values, optc, opti, rv;
bool active_low = false;
+ int flags = 0;
char *device, *end;
for (;;) {
@@ -56,6 +77,9 @@ int main(int argc, char **argv)
case 'l':
active_low = true;
break;
+ case 'B':
+ flags = bias_flags(optarg);
+ break;
case '?':
die("try %s --help", get_progname());
default:
@@ -86,9 +110,9 @@ int main(int argc, char **argv)
die("invalid GPIO offset: %s", argv[i + 1]);
}
- rv = gpiod_ctxless_get_value_multiple(device, offsets, values,
- num_lines, active_low,
- "gpioget");
+ rv = gpiod_ctxless_get_value_multiple_ext(device, offsets, values,
+ num_lines, active_low,
+ "gpioget", flags);
if (rv < 0)
die_perror("error reading GPIO values");
diff --git a/tools/gpiomon.c b/tools/gpiomon.c
index 9a1843b..687212d 100644
--- a/tools/gpiomon.c
+++ b/tools/gpiomon.c
@@ -22,6 +22,7 @@ static const struct option longopts[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ "active-low", no_argument, NULL, 'l' },
+ { "bias", required_argument, NULL, 'B' },
{ "num-events", required_argument, NULL, 'n' },
{ "silent", no_argument, NULL, 's' },
{ "rising-edge", no_argument, NULL, 'r' },
@@ -31,7 +32,7 @@ static const struct option longopts[] = {
{ GETOPT_NULL_LONGOPT },
};
-static const char *const shortopts = "+hvln:srfbF:";
+static const char *const shortopts = "+hvlB:n:srfbF:";
static void print_help(void)
{
@@ -43,6 +44,8 @@ static void print_help(void)
printf(" -h, --help:\t\tdisplay this message and exit\n");
printf(" -v, --version:\tdisplay the version and exit\n");
printf(" -l, --active-low:\tset the line active state to low\n");
+ printf(" -B, --bias=[as-is|disable|pull-down|pull-up] (defaults to 'as-is'):\n");
+ printf(" set the line bias\n");
printf(" -n, --num-events=NUM:\texit after processing NUM events\n");
printf(" -s, --silent:\t\tdon't print event info\n");
printf(" -r, --rising-edge:\tonly process rising edge events\n");
@@ -50,6 +53,12 @@ static void print_help(void)
printf(" -b, --line-buffered:\tset standard output as line buffered\n");
printf(" -F, --format=FMT\tspecify custom output format\n");
printf("\n");
+ printf("Biases:\n");
+ printf(" as-is:\tleave bias unchanged\n");
+ printf(" disable:\tdisable bias\n");
+ printf(" pull-up:\tenable pull-up\n");
+ printf(" pull-down:\tenable pull-down\n");
+ printf("\n");
printf("Format specifiers:\n");
printf(" %%o: GPIO line offset\n");
printf(" %%e: event type (0 - falling edge, 1 rising edge)\n");
@@ -240,10 +249,22 @@ static int make_signalfd(void)
return sigfd;
}
+static int bias_flags(const char *option)
+{
+ if (strcmp(option, "pull-down") == 0)
+ return GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN;
+ if (strcmp(option, "pull-up") == 0)
+ return GPIOD_CTXLESS_FLAG_BIAS_PULL_UP;
+ if (strcmp(option, "disable") == 0)
+ return GPIOD_CTXLESS_FLAG_BIAS_DISABLE;
+ return 0;
+}
+
int main(int argc, char **argv)
{
unsigned int offsets[GPIOD_LINE_BULK_MAX_LINES], num_lines = 0, offset;
bool active_low = false, watch_rising = false, watch_falling = false;
+ int flags = 0;
struct timespec timeout = { 10, 0 };
int optc, opti, rv, i, event_type;
struct mon_ctx ctx;
@@ -266,6 +287,9 @@ int main(int argc, char **argv)
case 'l':
active_low = true;
break;
+ case 'B':
+ flags = bias_flags(optarg);
+ break;
case 'n':
ctx.events_wanted = strtoul(optarg, &end, 10);
if (*end != '\0')
@@ -320,11 +344,11 @@ int main(int argc, char **argv)
ctx.sigfd = make_signalfd();
- rv = gpiod_ctxless_event_monitor_multiple(argv[0], event_type,
- offsets, num_lines,
- active_low, "gpiomon",
- &timeout, poll_callback,
- event_callback, &ctx);
+ rv = gpiod_ctxless_event_monitor_multiple_ext(
+ argv[0], event_type, offsets,
+ num_lines, active_low, "gpiomon",
+ &timeout, poll_callback,
+ event_callback, &ctx, flags);
if (rv)
die_perror("error waiting for events");
diff --git a/tools/gpioset.c b/tools/gpioset.c
index d9977a7..b91baea 100644
--- a/tools/gpioset.c
+++ b/tools/gpioset.c
@@ -23,6 +23,8 @@ static const struct option longopts[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ "active-low", no_argument, NULL, 'l' },
+ { "bias", required_argument, NULL, 'B' },
+ { "drive", required_argument, NULL, 'D' },
{ "mode", required_argument, NULL, 'm' },
{ "sec", required_argument, NULL, 's' },
{ "usec", required_argument, NULL, 'u' },
@@ -30,7 +32,7 @@ static const struct option longopts[] = {
{ GETOPT_NULL_LONGOPT },
};
-static const char *const shortopts = "+hvlm:s:u:b";
+static const char *const shortopts = "+hvlB:D:m:s:u:b";
static void print_help(void)
{
@@ -42,12 +44,27 @@ static void print_help(void)
printf(" -h, --help:\t\tdisplay this message and exit\n");
printf(" -v, --version:\tdisplay the version and exit\n");
printf(" -l, --active-low:\tset the line active state to low\n");
+ printf(" -B, --bias=[as-is|disable|pull-down|pull-up] (defaults to 'as-is'):\n");
+ printf(" set the line bias\n");
+ printf(" -D, --drive=[push-pull|open-drain|open-source] (defaults to 'push-pull'):\n");
+ printf(" set the line drive mode\n");
printf(" -m, --mode=[exit|wait|time|signal] (defaults to 'exit'):\n");
printf(" tell the program what to do after setting values\n");
printf(" -s, --sec=SEC:\tspecify the number of seconds to wait (only valid for --mode=time)\n");
printf(" -u, --usec=USEC:\tspecify the number of microseconds to wait (only valid for --mode=time)\n");
printf(" -b, --background:\tafter setting values: detach from the controlling terminal\n");
printf("\n");
+ printf("Biases:\n");
+ printf(" as-is:\tleave bias unchanged\n");
+ printf(" disable:\tdisable bias\n");
+ printf(" pull-up:\tenable pull-up\n");
+ printf(" pull-down:\tenable pull-down\n");
+ printf("\n");
+ printf("Drives:\n");
+ printf(" push-pull:\tdrive the line both high and low\n");
+ printf(" open-drain:\tdrive the line low or go high impedance\n");
+ printf(" open-source:\tdrive the line high or go high impedance\n");
+ printf("\n");
printf("Modes:\n");
printf(" exit:\t\tset values and exit immediately\n");
printf(" wait:\t\tset values and wait for user to press ENTER\n");
@@ -178,11 +195,31 @@ static const struct mode_mapping *parse_mode(const char *mode)
return NULL;
}
+static int bias_flags(const char *option)
+{
+ if (strcmp(option, "pull-down") == 0)
+ return GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN;
+ if (strcmp(option, "pull-up") == 0)
+ return GPIOD_CTXLESS_FLAG_BIAS_PULL_UP;
+ if (strcmp(option, "disable") == 0)
+ return GPIOD_CTXLESS_FLAG_BIAS_DISABLE;
+ return 0;
+}
+
+static int drive_flags(const char *option)
+{
+ if (strcmp(option, "open-drain") == 0)
+ return GPIOD_CTXLESS_FLAG_OPEN_DRAIN;
+ if (strcmp(option, "open-source") == 0)
+ return GPIOD_CTXLESS_FLAG_OPEN_SOURCE;
+ return 0;
+}
+
int main(int argc, char **argv)
{
const struct mode_mapping *mode = &modes[MODE_EXIT];
unsigned int *offsets, num_lines, i;
- int *values, rv, optc, opti;
+ int *values, rv, optc, opti, flags = 0;
struct callback_data cbdata;
bool active_low = false;
char *device, *end;
@@ -204,6 +241,12 @@ int main(int argc, char **argv)
case 'l':
active_low = true;
break;
+ case 'B':
+ flags |= bias_flags(optarg);
+ break;
+ case 'D':
+ flags |= drive_flags(optarg);
+ break;
case 'm':
mode = parse_mode(optarg);
if (!mode)
@@ -268,9 +311,10 @@ int main(int argc, char **argv)
die("invalid offset: %s", argv[i + 1]);
}
- rv = gpiod_ctxless_set_value_multiple(device, offsets, values,
- num_lines, active_low, "gpioset",
- mode->callback, &cbdata);
+ rv = gpiod_ctxless_set_value_multiple_ext(
+ device, offsets, values,
+ num_lines, active_low, "gpioset",
+ mode->callback, &cbdata, flags);
if (rv < 0)
die_perror("error setting the GPIO line values");
--
2.24.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [libgpiod][PATCH v3 13/14] tools: add support for bias flags
2019-11-25 14:31 ` [libgpiod][PATCH v3 13/14] tools: add support for bias flags Kent Gibson
@ 2019-11-28 10:29 ` Bartosz Golaszewski
0 siblings, 0 replies; 21+ messages in thread
From: Bartosz Golaszewski @ 2019-11-28 10:29 UTC (permalink / raw)
To: Kent Gibson; +Cc: linux-gpio
pon., 25 lis 2019 o 15:33 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> Add support for bias flags to applicable tools - gpioget, gpioset, and
> gpiomon.
>
> Signed-off-by: Kent Gibson <warthog618@gmail.com>
> ---
> tools/gpioget.c | 32 +++++++++++++++++++++++++----
> tools/gpiomon.c | 36 +++++++++++++++++++++++++++------
> tools/gpioset.c | 54 ++++++++++++++++++++++++++++++++++++++++++++-----
> 3 files changed, 107 insertions(+), 15 deletions(-)
>
> diff --git a/tools/gpioget.c b/tools/gpioget.c
> index 196ebeb..17614cb 100644
> --- a/tools/gpioget.c
> +++ b/tools/gpioget.c
> @@ -17,10 +17,11 @@ static const struct option longopts[] = {
> { "help", no_argument, NULL, 'h' },
> { "version", no_argument, NULL, 'v' },
> { "active-low", no_argument, NULL, 'l' },
> + { "bias", required_argument, NULL, 'B' },
> { GETOPT_NULL_LONGOPT },
> };
>
> -static const char *const shortopts = "+hvl";
> +static const char *const shortopts = "+hvlB:";
>
> static void print_help(void)
> {
> @@ -32,6 +33,25 @@ static void print_help(void)
> printf(" -h, --help:\t\tdisplay this message and exit\n");
> printf(" -v, --version:\tdisplay the version and exit\n");
> printf(" -l, --active-low:\tset the line active state to low\n");
> + printf(" -B, --bias=[as-is|disable|pull-down|pull-up] (defaults to 'as-is'):\n");
> + printf(" set the line bias\n");
> + printf("\n");
> + printf("Biases:\n");
> + printf(" as-is:\tleave bias unchanged\n");
> + printf(" disable:\tdisable bias\n");
> + printf(" pull-up:\tenable pull-up\n");
> + printf(" pull-down:\tenable pull-down\n");
> +}
> +
> +static int bias_flags(const char *option)
> +{
> + if (strcmp(option, "pull-down") == 0)
> + return GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN;
> + if (strcmp(option, "pull-up") == 0)
> + return GPIOD_CTXLESS_FLAG_BIAS_PULL_UP;
> + if (strcmp(option, "disable") == 0)
> + return GPIOD_CTXLESS_FLAG_BIAS_DISABLE;
> + return 0;
> }
>
> int main(int argc, char **argv)
> @@ -39,6 +59,7 @@ int main(int argc, char **argv)
> unsigned int *offsets, i, num_lines;
> int *values, optc, opti, rv;
> bool active_low = false;
> + int flags = 0;
> char *device, *end;
>
> for (;;) {
> @@ -56,6 +77,9 @@ int main(int argc, char **argv)
> case 'l':
> active_low = true;
> break;
> + case 'B':
> + flags = bias_flags(optarg);
> + break;
> case '?':
> die("try %s --help", get_progname());
> default:
> @@ -86,9 +110,9 @@ int main(int argc, char **argv)
> die("invalid GPIO offset: %s", argv[i + 1]);
> }
>
> - rv = gpiod_ctxless_get_value_multiple(device, offsets, values,
> - num_lines, active_low,
> - "gpioget");
> + rv = gpiod_ctxless_get_value_multiple_ext(device, offsets, values,
> + num_lines, active_low,
> + "gpioget", flags);
> if (rv < 0)
> die_perror("error reading GPIO values");
>
> diff --git a/tools/gpiomon.c b/tools/gpiomon.c
> index 9a1843b..687212d 100644
> --- a/tools/gpiomon.c
> +++ b/tools/gpiomon.c
> @@ -22,6 +22,7 @@ static const struct option longopts[] = {
> { "help", no_argument, NULL, 'h' },
> { "version", no_argument, NULL, 'v' },
> { "active-low", no_argument, NULL, 'l' },
> + { "bias", required_argument, NULL, 'B' },
> { "num-events", required_argument, NULL, 'n' },
> { "silent", no_argument, NULL, 's' },
> { "rising-edge", no_argument, NULL, 'r' },
> @@ -31,7 +32,7 @@ static const struct option longopts[] = {
> { GETOPT_NULL_LONGOPT },
> };
>
> -static const char *const shortopts = "+hvln:srfbF:";
> +static const char *const shortopts = "+hvlB:n:srfbF:";
>
> static void print_help(void)
> {
> @@ -43,6 +44,8 @@ static void print_help(void)
> printf(" -h, --help:\t\tdisplay this message and exit\n");
> printf(" -v, --version:\tdisplay the version and exit\n");
> printf(" -l, --active-low:\tset the line active state to low\n");
> + printf(" -B, --bias=[as-is|disable|pull-down|pull-up] (defaults to 'as-is'):\n");
> + printf(" set the line bias\n");
> printf(" -n, --num-events=NUM:\texit after processing NUM events\n");
> printf(" -s, --silent:\t\tdon't print event info\n");
> printf(" -r, --rising-edge:\tonly process rising edge events\n");
> @@ -50,6 +53,12 @@ static void print_help(void)
> printf(" -b, --line-buffered:\tset standard output as line buffered\n");
> printf(" -F, --format=FMT\tspecify custom output format\n");
> printf("\n");
> + printf("Biases:\n");
> + printf(" as-is:\tleave bias unchanged\n");
> + printf(" disable:\tdisable bias\n");
> + printf(" pull-up:\tenable pull-up\n");
> + printf(" pull-down:\tenable pull-down\n");
> + printf("\n");
> printf("Format specifiers:\n");
> printf(" %%o: GPIO line offset\n");
> printf(" %%e: event type (0 - falling edge, 1 rising edge)\n");
> @@ -240,10 +249,22 @@ static int make_signalfd(void)
> return sigfd;
> }
>
> +static int bias_flags(const char *option)
> +{
> + if (strcmp(option, "pull-down") == 0)
> + return GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN;
> + if (strcmp(option, "pull-up") == 0)
> + return GPIOD_CTXLESS_FLAG_BIAS_PULL_UP;
> + if (strcmp(option, "disable") == 0)
> + return GPIOD_CTXLESS_FLAG_BIAS_DISABLE;
> + return 0;
Does it mean that any other string would be interpreted as 'as-is'?
I'd prefer it to bail out on invalid value.
> +}
> +
> int main(int argc, char **argv)
> {
> unsigned int offsets[GPIOD_LINE_BULK_MAX_LINES], num_lines = 0, offset;
> bool active_low = false, watch_rising = false, watch_falling = false;
> + int flags = 0;
> struct timespec timeout = { 10, 0 };
> int optc, opti, rv, i, event_type;
> struct mon_ctx ctx;
> @@ -266,6 +287,9 @@ int main(int argc, char **argv)
> case 'l':
> active_low = true;
> break;
> + case 'B':
> + flags = bias_flags(optarg);
> + break;
> case 'n':
> ctx.events_wanted = strtoul(optarg, &end, 10);
> if (*end != '\0')
> @@ -320,11 +344,11 @@ int main(int argc, char **argv)
>
> ctx.sigfd = make_signalfd();
>
> - rv = gpiod_ctxless_event_monitor_multiple(argv[0], event_type,
> - offsets, num_lines,
> - active_low, "gpiomon",
> - &timeout, poll_callback,
> - event_callback, &ctx);
> + rv = gpiod_ctxless_event_monitor_multiple_ext(
> + argv[0], event_type, offsets,
> + num_lines, active_low, "gpiomon",
> + &timeout, poll_callback,
> + event_callback, &ctx, flags);
> if (rv)
> die_perror("error waiting for events");
>
> diff --git a/tools/gpioset.c b/tools/gpioset.c
> index d9977a7..b91baea 100644
> --- a/tools/gpioset.c
> +++ b/tools/gpioset.c
> @@ -23,6 +23,8 @@ static const struct option longopts[] = {
> { "help", no_argument, NULL, 'h' },
> { "version", no_argument, NULL, 'v' },
> { "active-low", no_argument, NULL, 'l' },
> + { "bias", required_argument, NULL, 'B' },
> + { "drive", required_argument, NULL, 'D' },
> { "mode", required_argument, NULL, 'm' },
> { "sec", required_argument, NULL, 's' },
> { "usec", required_argument, NULL, 'u' },
> @@ -30,7 +32,7 @@ static const struct option longopts[] = {
> { GETOPT_NULL_LONGOPT },
> };
>
> -static const char *const shortopts = "+hvlm:s:u:b";
> +static const char *const shortopts = "+hvlB:D:m:s:u:b";
>
> static void print_help(void)
> {
> @@ -42,12 +44,27 @@ static void print_help(void)
> printf(" -h, --help:\t\tdisplay this message and exit\n");
> printf(" -v, --version:\tdisplay the version and exit\n");
> printf(" -l, --active-low:\tset the line active state to low\n");
> + printf(" -B, --bias=[as-is|disable|pull-down|pull-up] (defaults to 'as-is'):\n");
> + printf(" set the line bias\n");
> + printf(" -D, --drive=[push-pull|open-drain|open-source] (defaults to 'push-pull'):\n");
> + printf(" set the line drive mode\n");
> printf(" -m, --mode=[exit|wait|time|signal] (defaults to 'exit'):\n");
> printf(" tell the program what to do after setting values\n");
> printf(" -s, --sec=SEC:\tspecify the number of seconds to wait (only valid for --mode=time)\n");
> printf(" -u, --usec=USEC:\tspecify the number of microseconds to wait (only valid for --mode=time)\n");
> printf(" -b, --background:\tafter setting values: detach from the controlling terminal\n");
> printf("\n");
> + printf("Biases:\n");
> + printf(" as-is:\tleave bias unchanged\n");
> + printf(" disable:\tdisable bias\n");
> + printf(" pull-up:\tenable pull-up\n");
> + printf(" pull-down:\tenable pull-down\n");
> + printf("\n");
> + printf("Drives:\n");
> + printf(" push-pull:\tdrive the line both high and low\n");
> + printf(" open-drain:\tdrive the line low or go high impedance\n");
> + printf(" open-source:\tdrive the line high or go high impedance\n");
> + printf("\n");
> printf("Modes:\n");
> printf(" exit:\t\tset values and exit immediately\n");
> printf(" wait:\t\tset values and wait for user to press ENTER\n");
> @@ -178,11 +195,31 @@ static const struct mode_mapping *parse_mode(const char *mode)
> return NULL;
> }
>
> +static int bias_flags(const char *option)
> +{
> + if (strcmp(option, "pull-down") == 0)
> + return GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN;
> + if (strcmp(option, "pull-up") == 0)
> + return GPIOD_CTXLESS_FLAG_BIAS_PULL_UP;
> + if (strcmp(option, "disable") == 0)
> + return GPIOD_CTXLESS_FLAG_BIAS_DISABLE;
> + return 0;
> +}
> +
> +static int drive_flags(const char *option)
> +{
> + if (strcmp(option, "open-drain") == 0)
> + return GPIOD_CTXLESS_FLAG_OPEN_DRAIN;
> + if (strcmp(option, "open-source") == 0)
> + return GPIOD_CTXLESS_FLAG_OPEN_SOURCE;
> + return 0;
Thanks for doing this, but please put it into a separate commit that
adds support for drive flags.
> +}
> +
> int main(int argc, char **argv)
> {
> const struct mode_mapping *mode = &modes[MODE_EXIT];
> unsigned int *offsets, num_lines, i;
> - int *values, rv, optc, opti;
> + int *values, rv, optc, opti, flags = 0;
> struct callback_data cbdata;
> bool active_low = false;
> char *device, *end;
> @@ -204,6 +241,12 @@ int main(int argc, char **argv)
> case 'l':
> active_low = true;
> break;
> + case 'B':
> + flags |= bias_flags(optarg);
> + break;
> + case 'D':
> + flags |= drive_flags(optarg);
> + break;
> case 'm':
> mode = parse_mode(optarg);
> if (!mode)
> @@ -268,9 +311,10 @@ int main(int argc, char **argv)
> die("invalid offset: %s", argv[i + 1]);
> }
>
> - rv = gpiod_ctxless_set_value_multiple(device, offsets, values,
> - num_lines, active_low, "gpioset",
> - mode->callback, &cbdata);
> + rv = gpiod_ctxless_set_value_multiple_ext(
> + device, offsets, values,
> + num_lines, active_low, "gpioset",
> + mode->callback, &cbdata, flags);
> if (rv < 0)
> die_perror("error setting the GPIO line values");
>
> --
> 2.24.0
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [libgpiod][PATCH v3 14/14] tools: add tests for bias and drive flags
2019-11-25 14:31 [libgpiod][PATCH v3 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
` (12 preceding siblings ...)
2019-11-25 14:31 ` [libgpiod][PATCH v3 13/14] tools: add support for bias flags Kent Gibson
@ 2019-11-25 14:31 ` Kent Gibson
13 siblings, 0 replies; 21+ messages in thread
From: Kent Gibson @ 2019-11-25 14:31 UTC (permalink / raw)
To: linux-gpio, bgolaszewski; +Cc: Kent Gibson
Add tests for bias flags to applicable tools - gpioget, gpioset, and
gpiomon, as well as drive flags for gpioset.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
tools/gpio-tools-test.bats | 139 +++++++++++++++++++++++++++++++++++++
1 file changed, 139 insertions(+)
diff --git a/tools/gpio-tools-test.bats b/tools/gpio-tools-test.bats
index aff54f7..8bced02 100755
--- a/tools/gpio-tools-test.bats
+++ b/tools/gpio-tools-test.bats
@@ -312,6 +312,34 @@ teardown() {
test "$output" = "1 1 0 0 1 0 1 0"
}
+@test "gpioget: read all lines (pull-up)" {
+ gpio_mockup_probe 8 8 8
+
+ gpio_mockup_set_pull 1 2 1
+ gpio_mockup_set_pull 1 3 1
+ gpio_mockup_set_pull 1 5 1
+ gpio_mockup_set_pull 1 7 1
+
+ run_tool gpioget --bias=pull-up "$(gpio_mockup_chip_name 1)" 0 1 2 3 4 5 6 7
+
+ test "$status" -eq "0"
+ test "$output" = "1 1 1 1 1 1 1 1"
+}
+
+@test "gpioget: read all lines (pull-down)" {
+ gpio_mockup_probe 8 8 8
+
+ gpio_mockup_set_pull 1 2 1
+ gpio_mockup_set_pull 1 3 1
+ gpio_mockup_set_pull 1 5 1
+ gpio_mockup_set_pull 1 7 1
+
+ run_tool gpioget --bias=pull-down "$(gpio_mockup_chip_name 1)" 0 1 2 3 4 5 6 7
+
+ test "$status" -eq "0"
+ test "$output" = "0 0 0 0 0 0 0 0"
+}
+
@test "gpioget: read some lines" {
gpio_mockup_probe 8 8 8
@@ -405,6 +433,79 @@ teardown() {
test "$status" -eq "0"
}
+@test "gpioset: set lines and wait for SIGTERM (push-pull)" {
+ gpio_mockup_probe 8 8 8
+
+ coproc_run_tool gpioset --drive=push-pull --mode=signal "$(gpio_mockup_chip_name 2)" \
+ 0=0 1=0 2=1 3=1 4=1 5=1 6=0 7=1
+
+ gpio_mockup_check_value 2 0 0
+ gpio_mockup_check_value 2 1 0
+ gpio_mockup_check_value 2 2 1
+ gpio_mockup_check_value 2 3 1
+ gpio_mockup_check_value 2 4 1
+ gpio_mockup_check_value 2 5 1
+ gpio_mockup_check_value 2 6 0
+ gpio_mockup_check_value 2 7 1
+
+ coproc_tool_kill
+ coproc_tool_wait
+
+ test "$status" -eq "0"
+}
+
+@test "gpioset: set lines and wait for SIGTERM (open-drain)" {
+ gpio_mockup_probe 8 8 8
+
+ gpio_mockup_set_pull 2 2 1
+ gpio_mockup_set_pull 2 3 1
+ gpio_mockup_set_pull 2 5 1
+ gpio_mockup_set_pull 2 7 1
+
+ coproc_run_tool gpioset --drive=open-drain --mode=signal "$(gpio_mockup_chip_name 2)" \
+ 0=0 1=0 2=1 3=1 4=1 5=1 6=0 7=1
+
+ gpio_mockup_check_value 2 0 0
+ gpio_mockup_check_value 2 1 0
+ gpio_mockup_check_value 2 2 1
+ gpio_mockup_check_value 2 3 1
+ gpio_mockup_check_value 2 4 0
+ gpio_mockup_check_value 2 5 1
+ gpio_mockup_check_value 2 6 0
+ gpio_mockup_check_value 2 7 1
+
+ coproc_tool_kill
+ coproc_tool_wait
+
+ test "$status" -eq "0"
+}
+
+@test "gpioset: set lines and wait for SIGTERM (open-source)" {
+ gpio_mockup_probe 8 8 8
+
+ gpio_mockup_set_pull 2 2 1
+ gpio_mockup_set_pull 2 3 1
+ gpio_mockup_set_pull 2 5 1
+ gpio_mockup_set_pull 2 7 1
+
+ coproc_run_tool gpioset --drive=open-source --mode=signal "$(gpio_mockup_chip_name 2)" \
+ 0=0 1=0 2=1 3=0 4=1 5=1 6=0 7=1
+
+ gpio_mockup_check_value 2 0 0
+ gpio_mockup_check_value 2 1 0
+ gpio_mockup_check_value 2 2 1
+ gpio_mockup_check_value 2 3 1
+ gpio_mockup_check_value 2 4 1
+ gpio_mockup_check_value 2 5 1
+ gpio_mockup_check_value 2 6 0
+ gpio_mockup_check_value 2 7 1
+
+ coproc_tool_kill
+ coproc_tool_wait
+
+ test "$status" -eq "0"
+}
+
@test "gpioset: set some lines and wait for ENTER" {
gpio_mockup_probe 8 8 8
@@ -576,6 +677,44 @@ teardown() {
"event:\\s+FALLING\\s+EDGE\\s+offset:\\s+4\\s+timestamp:\\s+\[[0-9]+\.[0-9]+\]"
}
+@test "gpiomon: single falling edge event (pull-up)" {
+ gpio_mockup_probe 8 8
+
+ gpio_mockup_set_pull 1 4 0
+
+ coproc_run_tool gpiomon --bias=pull-up "$(gpio_mockup_chip_name 1)" 4
+
+ gpio_mockup_set_pull 1 4 0
+ sleep 0.2
+
+ coproc_tool_kill
+ coproc_tool_wait
+
+ test "$status" -eq "0"
+ output_regex_match \
+"event:\\s+FALLING\\s+EDGE\\s+offset:\\s+4\\s+timestamp:\\s+\[[0-9]+\.[0-9]+\]"
+
+}
+
+@test "gpiomon: single rising edge event (pull-down)" {
+ gpio_mockup_probe 8 8
+
+ gpio_mockup_set_pull 1 4 1
+
+ coproc_run_tool gpiomon --bias=pull-down "$(gpio_mockup_chip_name 1)" 4
+
+ gpio_mockup_set_pull 1 4 1
+ sleep 0.2
+
+ coproc_tool_kill
+ coproc_tool_wait
+
+ test "$status" -eq "0"
+ output_regex_match \
+"event:\\s+RISING\\s+EDGE\\s+offset:\\s+4\\s+timestamp:\\s+\[[0-9]+\.[0-9]+\]"
+
+}
+
@test "gpiomon: single rising edge event (active-low)" {
gpio_mockup_probe 8 8
--
2.24.0
^ permalink raw reply related [flat|nested] 21+ messages in thread