Add support for bias flags and SET_CONFIG
Subsystems (2)
v4 cover Add support for bias flags and SET_CONFIG
Changes v3 -> v4:
- tests require kernel v5.5.0
- use std::map for bias mappings in cxx bindings
- drop gpiod_line_is_requested_values
- various formatting and coding style fixes
- relocate common tool code into tools-common
- tools bail on bad command line parameters
- add drive option to gpioset in a separate patch
- split out documentation update for gpiod_line_set_value_bulk
- split out change to vals variable in gpiod_Line_set_value
This patch series adds support for changes to the GPIO uAPI that are on track to be included in the v5.5 kernel. There are two components to the uAPI changes - the addition of bias flags and a new SET_CONFIG ioctl. This series adds support to the libgpiod API, and to both C++ and Python bindings, for both of those components.
The libgpiod tools are also updated, where appropriate, to support the bias flags.
The series is based on the current libgpiod master:
master@00418df tests: fix a typo in comment
Kent Gibson (20):
core: add support for bias flags
tests: add tests for bias flags
bindings: cxx: add support for bias flags
bindings: cxx: tests: add tests for bias flags
bindings: python: add support for bias flags
bindings: python: tests: add tests for bias flags
core: add support for SET_CONFIG
tests: add tests for SET_CONFIG
bindings: cxx: add support for SET_CONFIG
bindings: cxx: tests: add tests for SET_CONFIG methods
bindings: python: move tuple to int array conversion into helper
function
bindings: python: add support for SET_CONFIG
bindings: python: tests: add tests for SET_CONFIG methods
tools: add support for bias flags
tools: add tests for bias flags
tools: gpioset: add support for drive flags
tools: add tests for drive flags
core: document gpiod_line_set_value_bulk NULL values behaviour
bindings: cxx: fix indentation of wrapped field descriptions
bindings: python: make vals in gpiod_Line_set_value consistent with
other functions
bindings/cxx/gpiod.hpp | 85 ++++- bindings/cxx/line.cpp | 56 +++ bindings/cxx/line_bulk.cpp | 89 +++++ bindings/cxx/tests/gpiod-cxx-test.cpp | 2 +- bindings/cxx/tests/tests-line.cpp | 215 +++++++++++ bindings/python/gpiodmodule.c | 485 +++++++++++++++++++++++-- bindings/python/tests/gpiod_py_test.py | 256 ++++++++++++- include/gpiod.h | 297 +++++++++++++++ lib/core.c | 214 ++++++++++- lib/ctxless.c | 114 +++++- tests/gpiod-test.c | 4 +- tests/tests-ctxless.c | 64 +++- tests/tests-event.c | 120 ++++++ tests/tests-line.c | 468 +++++++++++++++++++++++- tools/gpio-tools-test | 2 +- tools/gpio-tools-test.bats | 175 +++++++++ tools/gpioget.c | 17 +- tools/gpiomon.c | 21 +- tools/gpioset.c | 41 ++- tools/tools-common.c | 22 ++ tools/tools-common.h | 2 + 21 files changed, 2679 insertions(+), 70 deletions(-)
Signature · 1 line
2.24.0
PATCH v4 1/20 core: add support for bias flags
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 <[email protected]>.
--- include/gpiod.h | 183 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/core.c | 32 ++++++--- lib/ctxless.c | 114 +++++++++++++++++++++++++++--- 3 files changed, 311 insertions(+), 18 deletions(-)
include/gpiod.h +183 -0
@@ -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 */ };/**
lib/core.c +23 -9
@@ -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; }
lib/ctxless.c +105 -9
182 lines not on this page · raw message
Signature · 1 line
2.24.0
PATCH v4 2/20 tests: add tests for bias flags
In reply to Kent GibsonExtend 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.
--- tests/gpiod-test.c | 4 +- tests/tests-ctxless.c | 64 +++++++++++++++++++++- tests/tests-event.c | 120 ++++++++++++++++++++++++++++++++++++++++++ tests/tests-line.c | 98 ++++++++++++++++++++++++++++++++++ 4 files changed, 282 insertions(+), 4 deletions(-)
tests/gpiod-test.c +2 -2
@@ -16,8 +16,8 @@#include "gpiod-test.h" #define MIN_KERNEL_MAJOR 5 -#define MIN_KERNEL_MINOR 2 -#define MIN_KERNEL_RELEASE 11 +#define MIN_KERNEL_MINOR 5 +#define MIN_KERNEL_RELEASE 0#define MIN_KERNEL_VERSION KERNEL_VERSION(MIN_KERNEL_MAJOR, \ MIN_KERNEL_MINOR, \ MIN_KERNEL_RELEASE)
tests/tests-ctxless.c +62 -2
86 lines not on this page · raw message
tests/tests-event.c +120 -0
126 lines not on this page · raw message
tests/tests-line.c +98 -0
138 lines not on this page · raw message
Signature · 1 line
2.24.0
PATCH v4 3/20 bindings: cxx: add support for bias flags
In reply to Kent GibsonAdd support for bias flags in line requests and returning the line bias setting via a bias accessor.
Based on initial work by Drew Fustini <[email protected]>.
--- bindings/cxx/gpiod.hpp | 26 ++++++++++++++++++++++++++ bindings/cxx/line.cpp | 19 +++++++++++++++++++ bindings/cxx/line_bulk.cpp | 6 ++++++ 3 files changed, 51 insertions(+)
bindings/cxx/gpiod.hpp +26 -0
@@ -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);
bindings/cxx/line.cpp +19 -0
@@ -6,10 +6,22 @@ */ #include <gpiod.hpp> +#include <map> #include <system_error> namespace gpiod { +namespace { + +const ::std::map<int, int> bias_mapping = { + { GPIOD_LINE_BIAS_PULL_UP, line::BIAS_PULL_UP, }, + { GPIOD_LINE_BIAS_PULL_DOWN, line::BIAS_PULL_DOWN, }, + { GPIOD_LINE_BIAS_DISABLE, line::BIAS_DISABLE, }, + { GPIOD_LINE_BIAS_AS_IS, line::BIAS_AS_IS, }, +}; + +} /* namespace */ + line::line(void) : _m_line(nullptr), _m_chip()
@@ -67,6 +79,13 @@ 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(); + + return bias_mapping.at(::gpiod_line_bias(this->_m_line)); +} + bool line::is_used(void) const { this->throw_if_null();
bindings/cxx/line_bulk.cpp +6 -0
@@ -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 */
Signature · 1 line
2.24.0
PATCH v4 4/20 bindings: cxx: tests: add tests for bias flags
In reply to Kent GibsonExtend test coverage over the bias flags in requests and the bias setting returned by line.bias().
--- bindings/cxx/tests/gpiod-cxx-test.cpp | 2 +- bindings/cxx/tests/tests-line.cpp | 87 +++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-)
bindings/cxx/tests/gpiod-cxx-test.cpp +1 -1
@@ -54,6 +54,6 @@ public: kernel_checker& operator=(kernel_checker&& other) = delete; }; -kernel_checker require_kernel(5, 2, 11); +kernel_checker require_kernel(5, 5, 0); } /* namespace */
bindings/cxx/tests/tests-line.cpp +87 -0
105 lines not on this page · raw message
Signature · 1 line
2.24.0
PATCH v4 5/20 bindings: python: add support for bias flags
In reply to Kent GibsonAdd support for bias flags in line requests and returning the line bias setting via a bias accessor.
Based on initial work by Drew Fustini <[email protected]>.
--- bindings/python/gpiodmodule.c | 82 +++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+)
bindings/python/gpiodmodule.c +82 -0
@@ -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, + }, { } };
Signature · 1 line
2.24.0
PATCH v4 6/20 bindings: python: tests: add tests for bias flags
In reply to Kent GibsonExtend test coverage to cover the bias flags in requests and the bias setting returned by line.bias().
--- bindings/python/tests/gpiod_py_test.py | 93 +++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-)
bindings/python/tests/gpiod_py_test.py +92 -1
@@ -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:
@@ -659,6 +750,6 @@ class EventFileDescriptor(MockupTestCase): # if __name__ == '__main__': - check_kernel(5, 2, 11) + check_kernel(5, 5, 0) mockup = gpiomockup.Mockup() unittest.main()
Signature · 1 line
2.24.0
PATCH v4 7/20 core: add support for SET_CONFIG
In reply to Kent GibsonExtend 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.
Documented the fields of gpiod_line to better identify the purpose of each where the field name alone is not sufficiently clear, and to indicate which flags are applicable to each field.
Implementation includes a few helper functions that serve to keep the code tidier and are consistent with similar helper functions already present.
--- include/gpiod.h | 113 ++++++++++++++++++++++++++++++ lib/core.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 293 insertions(+), 2 deletions(-)
include/gpiod.h +113 -0
@@ -1305,6 +1305,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; +/** * @} *
lib/core.c +180 -2
232 lines not on this page · raw message
Signature · 1 line
2.24.0
PATCH v4 8/20 tests: add tests for SET_CONFIG
In reply to Kent GibsonExtend test coverage over the SET_CONFIG functions.
--- tests/tests-line.c | 370 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 369 insertions(+), 1 deletion(-)
tests/tests-line.c +369 -1
@@ -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 })
Signature · 1 line
2.24.0
PATCH v4 9/20 bindings: cxx: add support for SET_CONFIG
In reply to Kent GibsonAdd methods to support setting line configuration.
--- bindings/cxx/gpiod.hpp | 55 +++++++++++++++++++++++++ bindings/cxx/line.cpp | 37 +++++++++++++++++ bindings/cxx/line_bulk.cpp | 83 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+)
bindings/cxx/gpiod.hpp +55 -0
@@ -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
bindings/cxx/line.cpp +37 -0
@@ -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();
bindings/cxx/line_bulk.cpp +83 -0
89 lines not on this page · raw message
Signature · 1 line
2.24.0
PATCH v4 10/20 bindings: cxx: tests: add tests for SET_CONFIG methods
In reply to Kent GibsonExtend test coverage over set_config, set_flags, set_direction_input, and set_direction_output methods.
--- bindings/cxx/tests/tests-line.cpp | 128 ++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+)
bindings/cxx/tests/tests-line.cpp +128 -0
@@ -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 });
Signature · 1 line
2.24.0
PATCH v4 11/20 bindings: python: move tuple to int array conversion into helper function
In reply to Kent GibsonRestructured gpiod_LineBulk_set_values to move the conversion of values from Python tuple to int array into a helper function as it is useful for similar functions.
--- bindings/python/gpiodmodule.c | 65 +++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 29 deletions(-)
bindings/python/gpiodmodule.c +36 -29
@@ -1216,6 +1216,38 @@ static PyObject *gpiod_LineBulk_get_values(gpiod_LineBulkObject *self,return val_list; } +static int gpiod_TupleToIntArray (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_values_doc,"set_values(values) -> None\n" "\n"
@@ -1231,10 +1263,9 @@ PyDoc_STRVAR(gpiod_LineBulk_set_values_doc,static PyObject *gpiod_LineBulk_set_values (gpiod_LineBulkObject *self,PyObject *args) { -int rv, vals[GPIOD_LINE_BULK_MAX_LINES ], val; -PyObject *val_list, *iter, *next; +int rv, vals[GPIOD_LINE_BULK_MAX_LINES ]; +PyObject *val_list;struct gpiod_line_bulk bulk; -Py_ssize_t num_vals, i;if (gpiod_LineBulkOwnerIsClosed (self))return NULL ;
@@ -1246,34 +1277,10 @@ static PyObject *gpiod_LineBulk_set_values(gpiod_LineBulkObject *self,if (!rv)return NULL ; - num_vals =PyObject_Size (val_list); -if (self->num_lines != num_vals) { -PyErr_SetString (PyExc_TypeError, -"Number of values must correspond to the number of lines" ); -return NULL ; - } - - iter =PyObject_GetIter (val_list); -if (!iter) + rv =gpiod_TupleToIntArray (val_list, vals, self->num_lines); +if (rv)return NULL ; -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 NULL ; - } - - vals[i] = (int )val; - } - Py_BEGIN_ALLOW_THREADS; rv =gpiod_line_set_value_bulk (&bulk, vals); Py_END_ALLOW_THREADS;
Signature · 1 line
2.24.0
PATCH v4 12/20 bindings: python: add support for SET_CONFIG
In reply to Kent GibsonAdd methods to support setting line configuration.
--- bindings/python/gpiodmodule.c | 346 ++++++++++++++++++++++++++++++++++ 1 file changed, 346 insertions(+)
bindings/python/gpiodmodule.c +346 -0
@@ -599,6 +599,142 @@ static PyObject *gpiod_Line_set_value(gpiod_LineObject *self, PyObject *args)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); + +return ret; +} +PyDoc_STRVAR (gpiod_Line_release_doc,"release() -> None\n" "\n"
@@ -838,6 +974,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,
@@ -1290,6 +1450,168 @@ static PyObject *gpiod_LineBulk_set_values(gpiod_LineBulkObject *self, Py_RETURN_NONE; } +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 =gpiod_TupleToIntArray (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 =gpiod_TupleToIntArray (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"
@@ -1438,6 +1760,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,
Signature · 1 line
2.24.0
PATCH v4 13/20 bindings: python: tests: add tests for SET_CONFIG methods
In reply to Kent GibsonExtend test coverage over set_config, set_flags, set_direction_input, and set_direction_output methods.
--- bindings/python/tests/gpiod_py_test.py | 163 +++++++++++++++++++++++++ 1 file changed, 163 insertions(+)
bindings/python/tests/gpiod_py_test.py +163 -0
@@ -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, )
Signature · 1 line
2.24.0
PATCH v4 14/20 tools: add support for bias flags
In reply to Kent GibsonAdd support for bias flags to applicable tools - gpioget, gpioset, and gpiomon.
--- tools/gpioget.c | 17 +++++++++++++---- tools/gpiomon.c | 21 +++++++++++++++------ tools/gpioset.c | 19 ++++++++++++++----- tools/tools-common.c | 22 ++++++++++++++++++++++ tools/tools-common.h | 2 ++ 5 files changed, 66 insertions(+), 15 deletions(-)
tools/gpioget.c +13 -4
@@ -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,10 @@ 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" ); +print_bias_help (); }int main (int argc,char **argv)
@@ -39,6 +44,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 +62,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 +95,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" );
tools/gpiomon.c +15 -6
@@ -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,8 @@ 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" ); +print_bias_help (); +printf ("\n" );printf ("Format specifiers:\n" );printf (" %%o: GPIO line offset\n" );printf (" %%e: event type (0 - falling edge, 1 rising edge)\n" );
@@ -244,6 +249,7 @@ 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 +272,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 +329,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" );
tools/gpioset.c +14 -5
@@ -23,6 +23,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' }, { "mode", required_argument, NULL, 'm' }, { "sec", required_argument, NULL, 's' }, { "usec", required_argument, NULL, 'u' },
@@ -30,7 +31,7 @@ static const struct option longopts[] = { { GETOPT_NULL_LONGOPT }, }; -static const char *const shortopts ="+hvlm:s:u:b" ; +static const char *const shortopts ="+hvlB:m:s:u:b" ;static void print_help (void ) {
@@ -42,12 +43,16 @@ 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 (" -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" ); +print_bias_help (); +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" );
@@ -182,7 +187,7 @@ 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 +209,9 @@ int main(int argc, char **argv)case 'l' : active_low = true;break ; +case 'B' : + flags |=bias_flags (optarg); +break ;case 'm' : mode =parse_mode (optarg);if (!mode)
@@ -268,9 +276,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" );
tools/tools-common.c +22 -0
@@ -57,3 +57,25 @@ void print_version(void)printf ("This is free software: you are free to change and redistribute it.\n" );printf ("There is NO WARRANTY, to the extent permitted by law.\n" ); } + +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 ; +if (strcmp (option,"as-is" ) !=0 ) +die ("invalid bias: %s" , option); +return 0 ; +} + +void print_bias_help (void ) +{ +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" ); +}
tools/tools-common.h +2 -0
@@ -25,5 +25,7 @@ const char *get_progname(void); void die(const char *fmt, ...) NORETURN PRINTF(1, 2); void die_perror(const char *fmt, ...) NORETURN PRINTF(1, 2);void print_version (void ); +int bias_flags (const char *option); +void print_bias_help (void );#endif /* __GPIOD_TOOLS_COMMON_H__ */
Signature · 1 line
2.24.0
PATCH v4 15/20 tools: add tests for bias flags
In reply to Kent GibsonAdd tests for bias flags to applicable tools - gpioget, gpioset, and gpiomon.
--- tools/gpio-tools-test | 2 +- tools/gpio-tools-test.bats | 93 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-)
tools/gpio-tools-test +1 -1
@@ -7,7 +7,7 @@ # Copyright (C) 2019 Bartosz Golaszewski <[email protected]> # -MIN_KERNEL_VERSION="5.2.7" +MIN_KERNEL_VERSION="5.5.0" BATS_SCRIPT="gpio-tools-test.bats" SOURCE_DIR="$(dirname ${BASH_SOURCE[0]})"
tools/gpio-tools-test.bats +93 -0
123 lines not on this page · raw message
Signature · 1 line
2.24.0
PATCH v4 16/20 tools: gpioset: add support for drive flags
In reply to Kent GibsonAdd support for drive flags to gpioset so that line drive flags (open-drain,open-source) can be set from the command line.
--- tools/gpioset.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-)
tools/gpioset.c +23 -1
@@ -24,6 +24,7 @@ static const struct option longopts[] = { { "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' },
@@ -31,7 +32,7 @@ static const struct option longopts[] = { { GETOPT_NULL_LONGOPT }, }; -static const char *const shortopts ="+hvlB:m:s:u:b" ; +static const char *const shortopts ="+hvlB:D:m:s:u:b" ;static void print_help (void ) {
@@ -45,6 +46,8 @@ static void print_help(void)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" );
@@ -53,6 +56,11 @@ static void print_help(void)printf ("\n" );print_bias_help ();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" );
@@ -183,6 +191,17 @@ static const struct mode_mapping *parse_mode(const char *mode)return NULL ; } +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 ; +if (strcmp (option,"push-pull" ) !=0 ) +die ("invalid drive: %s" , option); +return 0 ; +} +int main (int argc,char **argv) {const struct mode_mapping *mode = &modes[MODE_EXIT ];
@@ -212,6 +231,9 @@ int main(int argc, char **argv)case 'B' : flags |=bias_flags (optarg);break ; +case 'D' : + flags |=drive_flags (optarg); +break ;case 'm' : mode =parse_mode (optarg);if (!mode)
Signature · 1 line
2.24.0
PATCH v4 17/20 tools: add tests for drive flags
In reply to Kent GibsonAdd tests for drive flags in gpioset.
--- tools/gpio-tools-test.bats | 82 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+)
tools/gpio-tools-test.bats +82 -0
@@ -442,6 +442,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
@@ -567,6 +640,15 @@ teardown() { output_regex_match ".*invalid bias.*" } +@test "gpioset: invalid drive" { + gpio_mockup_probe 8 8 8 + + run_tool gpioset --drive=bad "$(gpio_mockup_chip_name 1)" 0=1 1=1 + + test "$status" -eq "1" + output_regex_match ".*invalid drive.*" +} + @test "gpioset: daemonize in invalid mode" { gpio_mockup_probe 8 8 8
Signature · 1 line
2.24.0
PATCH v4 18/20 core: document gpiod_line_set_value_bulk NULL values behaviour
In reply to Kent GibsonThe handling of NULL values by gpiod_line_set_value_bulk has been changed to interpret NULL as low values for all lines. This patch updates the documentation of the function to describe that.
--- include/gpiod.h | 1 + 1 file changed, 1 insertion(+)
include/gpiod.h +1 -0
@@ -1296,6 +1296,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. *
Signature · 1 line
2.24.0
PATCH v4 19/20 bindings: cxx: fix indentation of wrapped field descriptions
In reply to Kent GibsonMinor formatting fix to make long text descriptions of params wrap under the text, not under the param name.
--- bindings/cxx/gpiod.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
bindings/cxx/gpiod.hpp +2 -2
@@ -670,7 +670,7 @@ public: /** * @brief Set values of all lines held by this object. * @param values Vector of values to set. Must be the same size as the - * number of lines held by this line_bulk. + * number of lines held by this line_bulk. */ GPIOD_API void set_values(const ::std::vector<int>& values) const;
@@ -706,7 +706,7 @@ public: /** * @brief Poll the set of lines for line events. * @param timeout Number of nanoseconds to wait before returning an - * empty line_bulk. + * empty line_bulk. * @return Returns a line_bulk object containing lines on which events * occurred. */
Signature · 1 line
2.24.0
PATCH v4 20/20 bindings: python: make vals in gpiod_Line_set_value consistent with other functions
In reply to Kent GibsonChange the vals in gpiod_Line_set_value from a tuple of tuples to just a tuple. This brings it into line with other vals in the module such as gpiod_Line_set_config and gpiod_Line_set_direction_output.
The previous usage made the vals equivalent to an args (a tuple of arguments equivalent to argc,argv in C), as per gpiod_Line_set_flags.
Renaming vals to args in gpiod_Line_set_value was not an option as there is already an args parameter.
--- bindings/python/gpiodmodule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
bindings/python/gpiodmodule.c +2 -2
@@ -585,14 +585,14 @@ 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);
Signature · 1 line
2.24.0
niedz., 1 gru 2019 o 04:24 Kent Gibson <[email protected]> napisał(a):
Quoted 71 lines
Changes v3 -> v4:
- tests require kernel v5.5.0
- usestd::mapfor bias mappings in cxx bindings
- dropgpiod_line_is_requested_values
- various formatting and coding style fixes
- relocate common tool code into tools-common
- tools bail on bad command line parameters
- add drive option to gpioset in a separate patch
- split out documentation update forgpiod_line_set_value_bulk
- split out change to vals variable ingpiod_Line_set_valueThis patch series adds support for changes to the GPIO uAPI that are on track to be included in the v5.5 kernel. There are two components to the uAPI changes - the addition of bias flags and a new
SET_CONFIGioctl. This series adds support to the libgpiod API, and to both C++ and Python bindings, for both of those components.The libgpiod tools are also updated, where appropriate, to support the bias flags.
The series is based on the current libgpiod master:
master@00418df tests: fix a typo in commentKent Gibson (20):
core: add support for bias flags
tests: add tests for bias flags
bindings: cxx: add support for bias flags
bindings: cxx: tests: add tests for bias flags
bindings: python: add support for bias flags
bindings: python: tests: add tests for bias flags
core: add support forSET_CONFIG
tests: add tests forSET_CONFIG
bindings: cxx: add support forSET_CONFIG
bindings: cxx: tests: add tests forSET_CONFIGmethods
bindings: python: move tuple to int array conversion into helper
function
bindings: python: add support forSET_CONFIG
bindings: python: tests: add tests forSET_CONFIGmethods
tools: add support for bias flags
tools: add tests for bias flags
tools: gpioset: add support for drive flags
tools: add tests for drive flags
core: documentgpiod_line_set_value_bulkNULL values behaviour
bindings: cxx: fix indentation of wrapped field descriptions
bindings: python: make vals ingpiod_Line_set_valueconsistent with
other functionsbindings/cxx/gpiod.hpp | 85 ++++- bindings/cxx/line.cpp | 56 +++ bindings/cxx/line_bulk.cpp | 89 +++++ bindings/cxx/tests/gpiod-cxx-test.cpp | 2 +- bindings/cxx/tests/tests-line.cpp | 215 +++++++++++ bindings/python/gpiodmodule.c | 485 +++++++++++++++++++++++-- bindings/python/tests/gpiod_py_test.py | 256 ++++++++++++- include/gpiod.h | 297 +++++++++++++++ lib/core.c | 214 ++++++++++- lib/ctxless.c | 114 +++++- tests/gpiod-test.c | 4 +- tests/tests-ctxless.c | 64 +++- tests/tests-event.c | 120 ++++++ tests/tests-line.c | 468 +++++++++++++++++++++++- tools/gpio-tools-test | 2 +- tools/gpio-tools-test.bats | 175 +++++++++ tools/gpioget.c | 17 +- tools/gpiomon.c | 21 +- tools/gpioset.c | 41 ++- tools/tools-common.c | 22 ++ tools/tools-common.h | 2 + 21 files changed, 2679 insertions(+), 70 deletions(-)
Quoted 3 lines
--
2.24.0
I applied the entire series with some very minor tweaks to coding style and commit messages. Great work! Let's fix any leftover bugs (if any) during this linux release cycle and release libgpiod v1.5 together with linux v5.5.
Best regards,
Bartosz Golaszewski