treewide: continue beating libgpiod v2 into shape for an upcoming release
Subsystems (2)
v2 cover treewide: continue beating libgpiod v2 into shape for an upcoming release
From: Bartosz Golaszewski <[email protected]>
This series contains an assortment of smaller and bigger changes. Some are just simple updates to docs, some fix bugs and we have two more changes to the API: unifying the get_offsets functions for line config and line request as well as providing an interface for setting multiple output values at once in line_config before requesting lines.
Rust bindings have also been updated slightly so Viresh please make sure to take a look and review.
I really hope this is the last set of bigger changes and that I'll be able to tag an RC and release v2 in the next couple of weeks.
v1 -> v2:
- apply non-controversial patches and drop them from the series
- fix README as per Andy's suggestions
- extend the test cases for gpiod_line_config/request_get_offsets()
- improve rust code for getting line settings from line config
- improve the documentation for gpiod_line_config_set_output_values()
- extend the python support for setting global output values by allowing to pass mappings from line names/offsets to line values
Bartosz Golaszewski (8):
README: update for libgpiod v2
treewide: unify gpiod_line_config/request_get_offsets() functions
core: provide gpiod_line_config_set_output_values()
gpioset: use gpiod_line_config_set_output_values()
bindings: cxx: add line_config.set_output_values()
bindings: python: add the output_values argument to
Chip.request_lines()
bindings: rust: make mutators return &mut self
bindings: rust: provide line_config.set_output_values()
README | 33 ++-- bindings/cxx/gpiodcxx/line-config.hpp | 7 + bindings/cxx/internal.hpp | 1 + bindings/cxx/line-config.cpp | 33 ++-- bindings/cxx/line-request.cpp | 6 +- bindings/cxx/line-settings.cpp | 5 + bindings/cxx/tests/tests-line-config.cpp | 51 +++++++ bindings/python/gpiod/chip.py | 30 ++++ bindings/python/gpiod/ext/line-config.c | 64 ++++++++ bindings/python/gpiod/ext/request.c | 8 +- bindings/python/tests/tests_line_request.py | 55 +++++++ .../rust/libgpiod/examples/gpio_events.rs | 2 +- .../examples/gpio_threaded_info_events.rs | 6 +- bindings/rust/libgpiod/examples/gpioget.rs | 4 +- bindings/rust/libgpiod/examples/gpiomon.rs | 2 +- bindings/rust/libgpiod/examples/gpioset.rs | 4 +- bindings/rust/libgpiod/src/lib.rs | 1 + bindings/rust/libgpiod/src/line_config.rs | 84 +++++----- bindings/rust/libgpiod/src/line_request.rs | 24 +-- bindings/rust/libgpiod/src/request_config.rs | 8 +- bindings/rust/libgpiod/tests/common/config.rs | 8 +- bindings/rust/libgpiod/tests/info_event.rs | 6 +- bindings/rust/libgpiod/tests/line_config.rs | 76 ++++++++-- bindings/rust/libgpiod/tests/line_request.rs | 73 ++++----- .../rust/libgpiod/tests/request_config.rs | 2 +- configure.ac | 1 + include/gpiod.h | 87 ++++++++--- lib/line-config.c | 97 +++++++++--- lib/line-request.c | 23 ++- tests/gpiod-test-helpers.h | 10 ++ tests/tests-line-config.c | 143 +++++++++++++++--- tests/tests-line-request.c | 49 +++++- tools/gpioset.c | 21 +-- 33 files changed, 777 insertions(+), 247 deletions(-)
Signature · 1 line
2.37.2
PATCH v2 1/8 README: update for libgpiod v2
From: Bartosz Golaszewski <[email protected]>
Certain parts of the README file still refer to concepts removed from libgpiod v2. Update whatever needs updating.
--- README | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-)
README +17 -16
@@ -1,5 +1,5 @@ # SPDX-License-Identifier: CC-BY-SA-4.0 -# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <[email protected]> +# SPDX-FileCopyrightText: 2017-2023 Bartosz Golaszewski <[email protected]> libgpiod ========
@@ -30,14 +30,10 @@ allow an easy conversion of user scripts to using the character device. BUILDING -------- -This is a pretty standard autotools project. It does not depend on any -libraries other than the standard C library with GNU extensions. +This is a pretty standard autotools project. The core C library does not have +any external dependencies other than the standard C library with GNU extensions. -The autoconf version needed to compile the project is 2.61. - -Recent kernel headers are also required for the GPIO user API definitions. For -the exact version of kernel headers required, please refer to the configure.ac -contents. +The command-line tools optionally depend on libedit for the interactive feature. To build the project (including command-line utilities) run:
@@ -51,6 +47,8 @@ arguments to it. If building from release tarballs, the configure script is already provided and there's no need to invoke autogen.sh. +For all configure features, see: ./configure --help. + TOOLS -----
@@ -231,10 +229,10 @@ interface. The minimum kernel version required to run the tests can be checked in the tests/gpiod-test.c source file (it's subject to change if new features are -added to the kernel). The tests work together with the gpio-mockup kernel -module which must be enabled. NOTE: the module must not be built-in. A helper -library - libgpiomockup - is included to enable straightforward interaction -with the module. +added to the kernel). The tests work together with the gpio-sim kernel module +which must either be built-in or available for loading using kmod. A helper +library - libgpiosim - is included to enable straightforward interaction with +the module. To build the testing executable add the '--enable-tests' option when running the configure script. If enabled, the tests will be installed next to
@@ -251,12 +249,13 @@ The gpio-tools programs can be tested separately using the gpio-tools-test.bats script. It requires bats[1] to run and assumes that the tested executables are in the same directory as the script. -Both C++ and Python bindings also include their own test-suites. Both reuse the -libgpiomockup library to avoid code duplication when interacting with -gpio-mockup. +C++, Rust and Python bindings also include their own test-suites. All three +reuse the libgpiosim library to avoid code duplication when interacting with +gpio-sim. Python test-suite uses the standard unittest package. C++ tests use an external -testing framework - Catch2 - which must be installed in the system. +testing framework - Catch2 - which must be installed in the system. Rust +bindings use the standard tests module layout and the #[test] attribute. DOCUMENTATION -------------
@@ -268,6 +267,8 @@ doxygen markup blocks. Doxygen documentation can be generated by executing Python bindings contain help strings that can be accessed with the help builtin. +Rust bindings use rustdoc. + Man pages for command-line programs are generated automatically if gpio-tools were selected and help2man is available in the system.
Signature · 1 line
2.37.2
PATCH v2 2/8 treewide: unify gpiod_line_config/request_get_offsets() functions
In reply to Bartosz GolaszewskiFrom: Bartosz Golaszewski <[email protected]>
We have two functions in the C API that allow users to retrieve a list of offsets from objects: gpiod_line_request_get_offsets() and gpiod_line_config_get_offsets(). Even though they serve pretty much the same purpose, they have different signatures and one of them also requires the user to free the memory allocated within the libgpiod library with a non-libgpiod free() function.
Unify them: make them take the array in which to store offsets and the size of this array. Make them return the number of offsets actually stored in the array and make them impossible to fail. Change their names to be more descriptive and in the case of line_config: add a new function that allows users to get the number of configured offsets.
Update the entire tree to use the new interfaces.
For rust bindings: also unify the line config interface to return a map of line settings like C++ bindings do instead of having a function to get settings by offset. A map returned from a single call is easier to iterate over with a for loop than using an integer and calling the previous line_settings() method.
--- bindings/cxx/line-config.cpp | 18 ++--- bindings/cxx/line-request.cpp | 6 +- bindings/python/gpiod/ext/request.c | 8 +-- bindings/rust/libgpiod/src/line_config.rs | 72 ++++++++----------- bindings/rust/libgpiod/src/line_request.rs | 8 ++- bindings/rust/libgpiod/tests/line_config.rs | 24 ++----- configure.ac | 1 + include/gpiod.h | 62 +++++++++++------ lib/line-config.c | 39 +++++------ lib/line-request.c | 23 ++++--- tests/tests-line-config.c | 76 +++++++++++++++------ tests/tests-line-request.c | 49 +++++++++++-- 12 files changed, 227 insertions(+), 159 deletions(-)
bindings/cxx/line-config.cpp +7 -11
@@ -102,31 +102,27 @@ GPIOD_CXX_API line_config& line_config::add_line_settings(const line::offsets& o GPIOD_CXX_API ::std::map<line::offset, line_settings> line_config::get_line_settings() const { + ::std::size_t num_offsets = ::gpiod_line_config_get_num_configured_offsets( + this->_m_priv->config.get()); ::std::map<line::offset, line_settings> settings_map; - ::std::size_t num_offsets; - unsigned int *offsets_ptr; - int ret; - - ret = ::gpiod_line_config_get_offsets(this->_m_priv->config.get(), - &num_offsets, &offsets_ptr); - if (ret) - throw_from_errno("unable to retrieve line offsets"); + ::std::vector<unsigned int> offsets(num_offsets); if (num_offsets == 0) return settings_map; - ::std::unique_ptr<unsigned int, malloc_deleter> offsets(offsets_ptr); + ::gpiod_line_config_get_configured_offsets(this->_m_priv->config.get(), + offsets.data(), num_offsets); for (size_t i = 0; i < num_offsets; i++) { line_settings settings; settings._m_priv->settings.reset(::gpiod_line_config_get_line_settings( this->_m_priv->config.get(), - offsets.get()[i])); + offsets[i])); if (!settings._m_priv->settings) throw_from_errno("unable to retrieve line settings"); - settings_map[offsets.get()[i]] = ::std::move(settings); + settings_map[offsets[i]] = ::std::move(settings); } return settings_map;
bindings/cxx/line-request.cpp +3 -3
@@ -18,7 +18,7 @@ void line_request::impl::throw_if_released() const void line_request::impl::set_request_ptr(line_request_ptr& ptr) { this->request = ::std::move(ptr); - this->offset_buf.resize(::gpiod_line_request_get_num_lines(this->request.get())); + this->offset_buf.resize(::gpiod_line_request_get_num_requested_lines(this->request.get())); } void line_request::impl::fill_offset_buf(const line::offsets& offsets)
@@ -67,7 +67,7 @@ GPIOD_CXX_API ::std::size_t line_request::num_lines() const { this->_m_priv->throw_if_released(); - return ::gpiod_line_request_get_num_lines(this->_m_priv->request.get()); + return ::gpiod_line_request_get_num_requested_lines(this->_m_priv->request.get()); } GPIOD_CXX_API line::offsets line_request::offsets() const
@@ -78,7 +78,7 @@ GPIOD_CXX_API line::offsets line_request::offsets() const ::std::vector<unsigned int> buf(num_lines); line::offsets offsets(num_lines); - ::gpiod_line_request_get_offsets(this->_m_priv->request.get(), buf.data()); + ::gpiod_line_request_get_requested_offsets(this->_m_priv->request.get(), buf.data(), buf.size()); for (unsigned int i = 0; i < num_lines; i++) offsets[i] = buf[i];
bindings/python/gpiod/ext/request.c +4 -4
@@ -41,7 +41,7 @@ static PyObject * request_num_lines(request_object *self, void *Py_UNUSED(ignored)) {return PyLong_FromUnsignedLong ( -gpiod_line_request_get_num_lines (self->request)); +gpiod_line_request_get_num_requested_lines (self->request)); }static PyObject *request_offsets (request_object *self,void *Py_UNUSED (ignored ))
@@ -51,13 +51,13 @@ static PyObject *request_offsets(request_object *self, void *Py_UNUSED(ignored))size_t num_lines, i;int ret; - num_lines =gpiod_line_request_get_num_lines (self->request); + num_lines =gpiod_line_request_get_num_requested_lines (self->request); offsets =PyMem_Calloc (num_lines,sizeof (unsigned int ));if (!offsets)return PyErr_NoMemory (); -gpiod_line_request_get_offsets (self->request, offsets); +gpiod_line_request_get_requested_offsets (self->request, offsets, num_lines); lines =PyList_New (num_lines);if (!lines) {
@@ -365,7 +365,7 @@ PyObject *Py_gpiod_MakeRequestObject(struct gpiod_line_request *request,unsigned int *offsets;size_t num_lines; - num_lines =gpiod_line_request_get_num_lines (request); + num_lines =gpiod_line_request_get_num_requested_lines (request); req_obj =PyObject_New (request_object, &request_type);if (!req_obj)
bindings/rust/libgpiod/src/line_config.rs +27 -45
86 lines not on this page · raw message
bindings/rust/libgpiod/src/line_request.rs +6 -2
@@ -28,7 +28,7 @@ impl Request {/// Get the number of lines in the request. pub fn num_lines (&self) ->usize {// SAFETY: `gpiod_line_request` is guaranteed to be valid here. -unsafe { gpiod::gpiod_line_request_get_num_lines (self.request)as usize } +unsafe { gpiod::gpiod_line_request_get_num_requested_lines (self.request)as usize } }/// Get the offsets of lines in the request.
@@ -36,7 +36,11 @@ impl Request {let mut offsets =vec! [0 ; self.num_lines ()as usize ];// SAFETY: `gpiod_line_request` is guaranteed to be valid here. -unsafe { gpiod::gpiod_line_request_get_offsets (self.request, offsets.as_mut_ptr ()) }; +let num_offsets =unsafe { gpiod::gpiod_line_request_get_requested_offsets ( + self.request, + offsets.as_mut_ptr (), + self.num_lines ()as u64 ) }; + offsets.shrink_to (num_offsetsas usize ); offsets }
bindings/rust/libgpiod/tests/line_config.rs +4 -20
@@ -37,8 +37,10 @@ mod line_config { lconfig.add_line_settings (&[0 ,1 ,2 ], lsettings1).unwrap (); lconfig.add_line_settings (&[4 ,5 ], lsettings2).unwrap (); +let settings_map = lconfig.line_settings ().unwrap (); +// Retrieve settings -let lsettings = lconfig.line_settings (1 ).unwrap (); +let lsettings = settings_map.get (&1 ).unwrap ();assert_eq! ( lsettings.prop (SettingKind ::Direction ).unwrap (),SettingVal ::Direction (Direction ::Input )
@@ -56,7 +58,7 @@ mod line_config {SettingVal ::Drive (Drive ::PushPull ) ); -let lsettings = lconfig.line_settings (5 ).unwrap (); +let lsettings = settings_map.get (&5 ).unwrap ();assert_eq! ( lsettings.prop (SettingKind ::Direction ).unwrap (),SettingVal ::Direction (Direction ::Output )
@@ -74,22 +76,4 @@ mod line_config {SettingVal ::OutputValue (Value ::Active ) ); } - -#[test] -fn offsets () { -let mut lsettings1 = line::Settings ::new ().unwrap (); - lsettings1.set_direction (Direction ::Input ).unwrap (); - -let mut lsettings2 = line::Settings ::new ().unwrap (); - lsettings2.set_event_clock (EventClock ::Realtime ).unwrap (); - -// Add settings for multiple lines -let lconfig = line::Config ::new ().unwrap (); - lconfig.add_line_settings (&[0 ,1 ,2 ], lsettings1).unwrap (); - lconfig.add_line_settings (&[4 ,5 ], lsettings2).unwrap (); - -// Verify offsets -let offsets = lconfig.offsets ().unwrap (); -assert_eq! (offsets, [0 ,1 ,2 ,4 ,5 ]); - } }
configure.ac +1 -0
@@ -88,6 +88,7 @@ AC_CHECK_HEADERS([dirent.h], [], [HEADER_NOT_FOUND_LIB([dirent.h])]) AC_CHECK_HEADERS([poll.h], [], [HEADER_NOT_FOUND_LIB([poll.h])]) AC_CHECK_HEADERS([sys/sysmacros.h], [], [HEADER_NOT_FOUND_LIB([sys/sysmacros.h])]) AC_CHECK_HEADERS([sys/ioctl.h], [], [HEADER_NOT_FOUND_LIB([sys/ioctl.h])]) +AC_CHECK_HEADERS([sys/param.h], [], [HEADER_NOT_FOUND_LIB([sys/param.h])]) AC_CHECK_HEADERS([sys/stat.h], [], [HEADER_NOT_FOUND_LIB([sys/stat.h])]) AC_CHECK_HEADERS([sys/types.h], [], [HEADER_NOT_FOUND_LIB([sys/types.h])]) AC_CHECK_HEADERS([linux/const.h], [], [HEADER_NOT_FOUND_LIB([linux/const.h])])
include/gpiod.h +40 -22
97 lines not on this page · raw message
lib/line-config.c +18 -21
@@ -6,6 +6,7 @@#include <gpiod.h> #include <stdlib.h> #include <string.h> +#include <sys/param.h> #include "internal.h"
@@ -152,36 +153,32 @@ gpiod_line_config_get_line_settings(struct gpiod_line_config *config,return NULL ; } -GPIOD_API int gpiod_line_config_get_offsets(struct gpiod_line_config *config, -size_t *num_offsets, -unsigned int **offsets) +GPIOD_API size_t +gpiod_line_config_get_num_configured_offsets (struct gpiod_line_config *config) { -unsigned int *offs; -size_t i; -assert (config); -if (!num_offsets || !offsets) { - errno =EINVAL ; -return -1 ; - } +return config->num_configs; +} - *num_offsets = config->num_configs; - *offsets =NULL ; +GPIOD_API size_t +gpiod_line_config_get_configured_offsets (struct gpiod_line_config *config, +unsigned int *offsets, +size_t max_offsets) +{ +size_t num_offsets, i; -if (!config->num_configs) -return 0 ; +assert (config); - offs =calloc (config->num_configs,sizeof (unsigned int )); -if (!offs) -return -1 ; +if (!offsets || !max_offsets || !config->num_configs) +return 0 ; -for (i =0 ; i < config->num_configs; i++) - offs[i] = config->line_configs[i].offset; + num_offsets =MIN (config->num_configs, max_offsets); - *offsets = offs; +for (i =0 ; i < num_offsets; i++) + offsets[i] = config->line_configs[i].offset; -return 0 ; +return num_offsets; } static void set_offsets(struct gpiod_line_config *config,
lib/line-request.c +15 -8
@@ -7,6 +7,7 @@#include <stdlib.h> #include <string.h> #include <sys/ioctl.h> +#include <sys/param.h> #include <unistd.h> #include "internal.h"
@@ -45,24 +46,30 @@ GPIOD_API void gpiod_line_request_release(struct gpiod_line_request *request) } GPIOD_API size_t -gpiod_line_request_get_num_lines (struct gpiod_line_request *request) +gpiod_line_request_get_num_requested_lines (struct gpiod_line_request *request) {assert (request);return request->num_lines; } -GPIOD_API void -gpiod_line_request_get_offsets (struct gpiod_line_request *request, -unsigned int *offsets) +GPIOD_API size_t +gpiod_line_request_get_requested_offsets (struct gpiod_line_request *request, +unsigned int *offsets, +size_t max_offsets) { +size_t num_offsets; +assert (request); -if (!offsets) -return ; +if (!offsets || !max_offsets) +return 0 ; + + num_offsets =MIN (request->num_lines, max_offsets); + +memcpy (offsets, request->offsets,sizeof (*offsets) * num_offsets); -memcpy (offsets, request->offsets, -sizeof (*offsets) * request->num_lines); +return num_offsets; } GPIOD_API enum gpiod_line_value
tests/tests-line-config.c +57 -19
106 lines not on this page · raw message
tests/tests-line-request.c +45 -4
66 lines not on this page · raw message
Signature · 1 line
2.37.2
PATCH v2 3/8 core: provide gpiod_line_config_set_output_values()
In reply to Bartosz GolaszewskiFrom: Bartosz Golaszewski <[email protected]>
Currently if user wants to use the same settings for a set of requested lines with the exception of the output value - they need to go through hoops by updating the line settings object and adding it one by one to the line config. Provide a helper function that allows to set a global list of output values that override the settings. For details on the
interface: see documentation in this commit.
--- include/gpiod.h | 25 ++++++++++++++ lib/line-config.c | 60 +++++++++++++++++++++++++++++++--- tests/gpiod-test-helpers.h | 10 ++++++ tests/tests-line-config.c | 67 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 4 deletions(-)
include/gpiod.h +25 -0
@@ -785,6 +785,31 @@ struct gpiod_line_settings * gpiod_line_config_get_line_settings(struct gpiod_line_config *config, unsigned int offset); +/** +* @brief Set output values for a number of lines. +* @param config Line config object. +* @param values Buffer containing the output values. +* @param num_values Number of values in the buffer. +* @return 0 on success, -1 on error. +* +* This is a helper that allows users to set multiple (potentially different) +* output values at once while using the same line settings object. Instead of +* modifying the output value in the settings object and calling +* ::gpiod_line_config_add_line_settings multiple times, we can specify the +* settings, add them for a set of offsets and then call this function to +* set the output values. +* +* Values set by this function override whatever values were specified in the +* regular line settings. +* +* Each value must be associated with the line identified by the corresponding +* entry in the offset array filled by +* ::gpiod_line_request_get_requested_offsets. +*/ +int gpiod_line_config_set_output_values (struct gpiod_line_config *config, +const enum gpiod_line_value *values, +size_t num_values); +/** * @brief Get the number of configured line offsets. * @param config Line config object.
lib/line-config.c +56 -4
99 lines not on this page · raw message
tests/gpiod-test-helpers.h +10 -0
@@ -136,6 +136,16 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_edge_event_buffer, _settings; \ }) +#define gpiod_test_line_config_set_output_values_or_fail (_line_cfg, _values, \ + _num_values) \ + do { \ + gint _ret = gpiod_line_config_set_output_values(_line_cfg, \ + _values, \ + _num_values); \ + g_assert_cmpint(_ret, ==, 0); \ + gpiod_test_return_if_failed(); \ + } while (0) +#define gpiod_test_create_request_config_or_fail () \ ({ \ struct gpiod_request_config *_config = \
tests/tests-line-config.c +67 -0
70 lines not on this page · raw message
Signature · 1 line
2.37.2
PATCH v2 4/8 gpioset: use gpiod_line_config_set_output_values()
In reply to Bartosz GolaszewskiFrom: Bartosz Golaszewski <[email protected]>
Use the new line config function to shrink the gpioset code and drop one for loop.
--- tools/gpioset.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-)
tools/gpioset.c +11 -10
@@ -870,9 +870,9 @@ int main(int argc, char **argv)struct gpiod_line_config *line_cfg;struct line_resolver *resolver;enum gpiod_line_value *values; -int i, j, num_lines, ret;struct gpiod_chip *chip;unsigned int *offsets; +int i, num_lines, ret;struct config cfg;char **lines;
@@ -933,15 +933,16 @@ int main(int argc, char **argv) values);gpiod_line_config_reset (line_cfg); -for (j =0 ; j < num_lines; j++) { -gpiod_line_settings_set_output_value (settings, - values[j]); - - ret =gpiod_line_config_add_line_settings ( - line_cfg, &offsets[j],1 , settings); -if (ret) -die_perror ("unable to add line settings" ); - } + + ret =gpiod_line_config_add_line_settings (line_cfg, offsets, + num_lines, settings); +if (ret) +die_perror ("unable to add line settings" ); + + ret =gpiod_line_config_set_output_values (line_cfg, + values, num_lines); +if (ret) +die_perror ("unable to set output values" ); chip =gpiod_chip_open (resolver->chips[i].path);if (!chip)
Signature · 1 line
2.37.2
PATCH v2 5/8 bindings: cxx: add line_config.set_output_values()
In reply to Bartosz GolaszewskiFrom: Bartosz Golaszewski <[email protected]>
Extend line_config to expose a new method - set_output_values() - which wraps the new C function for setting multiple output values at once.
--- bindings/cxx/gpiodcxx/line-config.hpp | 7 ++++ bindings/cxx/internal.hpp | 1 + bindings/cxx/line-config.cpp | 15 +++++++ bindings/cxx/line-settings.cpp | 5 +++ bindings/cxx/tests/tests-line-config.cpp | 51 ++++++++++++++++++++++++ 5 files changed, 79 insertions(+)
bindings/cxx/gpiodcxx/line-config.hpp +7 -0
@@ -76,6 +76,13 @@ public: */ line_config& add_line_settings(const line::offsets& offsets, const line_settings& settings); + /** + * @brief Set output values for a number of lines. + * @param values Buffer containing the output values. + * @return Reference to self. + */ + line_config& set_output_values(const line::values& values); + /** * @brief Get a mapping of offsets to line settings stored by this * object.
bindings/cxx/internal.hpp +1 -0
@@ -31,6 +31,7 @@ map_enum_c_to_cxx(c_enum_type value, const ::std::map<c_enum_type, cxx_enum_type } void throw_from_errno(const ::std::string& what); +::gpiod_line_value map_output_value(line::value value); template<class T, void F(T*)> struct deleter {
bindings/cxx/line-config.cpp +15 -0
@@ -100,6 +100,21 @@ GPIOD_CXX_API line_config& line_config::add_line_settings(const line::offsets& o return *this; } +GPIOD_CXX_API line_config& line_config::set_output_values(const line::values& values) +{ + ::std::vector<::gpiod_line_value> mapped_values(values.size()); + + for (unsigned int i = 0; i < values.size(); i++) + mapped_values[i] = map_output_value(values[i]); + + auto ret = ::gpiod_line_config_set_output_values(this->_m_priv->config.get(), + mapped_values.data(), mapped_values.size()); + if (ret) + throw_from_errno("unable to set output values"); + + return *this; +} + GPIOD_CXX_API ::std::map<line::offset, line_settings> line_config::get_line_settings() const { ::std::size_t num_offsets = ::gpiod_line_config_get_num_configured_offsets(
bindings/cxx/line-settings.cpp +5 -0
@@ -139,6 +139,11 @@ cxx_enum_type get_mapped_value(::gpiod_line_settings* settings, } /* namespace */ +::gpiod_line_value map_output_value(line::value value) +{ + return do_map_value(value, value_mapping); +} + line_settings::impl::impl() : settings(make_line_settings()) {
bindings/cxx/tests/tests-line-config.cpp +51 -0
69 lines not on this page · raw message
Signature · 1 line
2.37.2
PATCH v2 6/8 bindings: python: add the output_values argument to Chip.request_lines()
In reply to Bartosz GolaszewskiFrom: Bartosz Golaszewski <[email protected]>
Add a new optional argument to Chip.request_lines() called output_values. It accepts a dictionary of mappings between line names or offsets to the output values the requested lines should be set to at request-time.
--- bindings/python/gpiod/chip.py | 30 ++++++++++ bindings/python/gpiod/ext/line-config.c | 64 +++++++++++++++++++++ bindings/python/tests/tests_line_request.py | 55 ++++++++++++++++++ 3 files changed, 149 insertions(+)
bindings/python/gpiod/chip.py +30 -0
@@ -6,10 +6,12 @@ from .chip_info import ChipInfo from .exception import ChipClosedError from .info_event import InfoEvent from .internal import poll_fd +from .line import Value from .line_info import LineInfo from .line_settings import LineSettings, _line_settings_to_ext from .line_request import LineRequest from collections import Counter +from collections.abc import Iterable from datetime import timedelta from errno import ENOENT from select import select
@@ -221,6 +223,7 @@ class Chip: config: dict[tuple[Union[int, str]], Optional[LineSettings]], consumer: Optional[str] = None, event_buffer_size: Optional[int] = None, + output_values: Optional[dict[tuple[Union[int, str]], Value]] = None, ) -> LineRequest: """ Request a set of lines for exclusive usage.
@@ -234,6 +237,10 @@ class Chip: Consumer string to use for this request. event_buffer_size: Size of the kernel edge event buffer to configure for this request. + output_values: + Dictionary mapping offsets or names to line.Value. This can be used + to set the desired output values globally while reusing LineSettings + for more lines. Returns: New LineRequest object.
@@ -260,10 +267,20 @@ class Chip: ) ) + # If we have global output values - map line names to offsets + if output_values: + mapped_output_values = { + self.line_offset_from_id(line): value + for line, value in output_values.items() + } + else: + mapped_output_values = None + for lines, settings in config.items(): offsets = list() name_map = dict() offset_map = dict() + global_output_values = list() if isinstance(lines, int) or isinstance(lines, str): lines = (lines,)
@@ -271,6 +288,16 @@ class Chip: for line in lines: offset = self.line_offset_from_id(line) offsets.append(offset) + + # If there's a global output value for this offset, store it in the + # list for later. + if mapped_output_values: + global_output_values.append( + mapped_output_values[offset] + if offset in mapped_output_values + else Value.INACTIVE + ) + if isinstance(line, str): name_map[line] = offset offset_map[offset] = line
@@ -279,6 +306,9 @@ class Chip: offsets, _line_settings_to_ext(settings or LineSettings()) ) + if len(global_output_values): + line_cfg.set_output_values(global_output_values) + req_internal = self._chip.request_lines(line_cfg, consumer, event_buffer_size) request = LineRequest(req_internal)
bindings/python/gpiod/ext/line-config.c +64 -0
76 lines not on this page · raw message
bindings/python/tests/tests_line_request.py +55 -0
61 lines not on this page · raw message
Signature · 1 line
2.37.2
PATCH v2 7/8 bindings: rust: make mutators return &mut self
In reply to Bartosz GolaszewskiFrom: Bartosz Golaszewski <[email protected]>
In C++ bindings we can chain the mutators as they all return a reference to the object they modify. It's a common practice to allow that in Rust too so make all mutators that don't already do it return a mutable reference to self.
It's also logically incorrect to make mutators borrow an immutable reference to self. Even if that builds - as we're fiddling with C pointers - it could change in the future. It's fine for getters but setters should all use mutable references.
--- .../rust/libgpiod/examples/gpio_events.rs | 2 +- .../examples/gpio_threaded_info_events.rs | 6 +- bindings/rust/libgpiod/examples/gpioget.rs | 4 +- bindings/rust/libgpiod/examples/gpiomon.rs | 2 +- bindings/rust/libgpiod/examples/gpioset.rs | 4 +- bindings/rust/libgpiod/src/line_config.rs | 4 +- bindings/rust/libgpiod/src/line_request.rs | 16 ++-- bindings/rust/libgpiod/src/request_config.rs | 8 +- bindings/rust/libgpiod/tests/common/config.rs | 8 +- bindings/rust/libgpiod/tests/info_event.rs | 6 +- bindings/rust/libgpiod/tests/line_config.rs | 2 +- bindings/rust/libgpiod/tests/line_request.rs | 73 ++++++++----------- .../rust/libgpiod/tests/request_config.rs | 2 +- 13 files changed, 65 insertions(+), 72 deletions(-)
bindings/rust/libgpiod/examples/gpio_events.rs +1 -1
@@ -25,7 +25,7 @@ fn main() -> Result<()> { }let mut lsettings = line::Settings ::new ()?; -let lconfig = line::Config ::new ()?; +let mut lconfig = line::Config ::new ()?;let mut offsets =Vec ::<Offset >::new ();for argin &args[2 ..] {
bindings/rust/libgpiod/examples/gpio_threaded_info_events.rs +3 -3
@@ -32,12 +32,12 @@ fn request_reconfigure_line( rx: Receiver<()>, ) { thread::spawn (move || { -let lconfig = line::Config ::new ().unwrap (); +let mut lconfig = line::Config ::new ().unwrap ();let lsettings = line::Settings ::new ().unwrap (); lconfig.add_line_settings (&[offset], lsettings).unwrap ();let rconfig = request::Config ::new ().unwrap (); -let request = chip +let mut request = chip .lock () .unwrap () .request_lines (Some (&rconfig), &lconfig)
@@ -49,7 +49,7 @@ fn request_reconfigure_line(// Wait for parent to signal rx.recv ().expect ("Could not receive from channel" ); -let lconfig = line::Config ::new ().unwrap (); +let mut lconfig = line::Config ::new ().unwrap ();let mut lsettings = line::Settings ::new ().unwrap (); lsettings.set_direction (Direction ::Output ).unwrap (); lconfig.add_line_settings (&[offset], lsettings).unwrap ();
bindings/rust/libgpiod/examples/gpioget.rs +2 -2
@@ -20,7 +20,7 @@ fn main() -> Result<()> { }let mut lsettings = line::Settings ::new ()?; -let lconfig = line::Config ::new ()?; +let mut lconfig = line::Config ::new ()?;let mut offsets =Vec ::<Offset >::new ();for argin &args[2 ..] {
@@ -34,7 +34,7 @@ fn main() -> Result<()> {let path =format! ("/dev/gpiochip{}" , args[1 ]);let chip =Chip ::open (&path)?; -let rconfig = request::Config ::new ()?; +let mut rconfig = request::Config ::new ()?; rconfig.set_consumer (&args[0 ])?;let request = chip.request_lines (Some (&rconfig), &lconfig)?;
bindings/rust/libgpiod/examples/gpiomon.rs +1 -1
@@ -24,7 +24,7 @@ fn main() -> Result<()> { }let mut lsettings = line::Settings ::new ()?; -let lconfig = line::Config ::new ()?; +let mut lconfig = line::Config ::new ()?;let mut offsets =Vec ::<Offset >::new ();for argin &args[2 ..] {
bindings/rust/libgpiod/examples/gpioset.rs +2 -2
@@ -24,7 +24,7 @@ fn main() -> Result<()> {return Err (Error ::InvalidArguments ); } -let lconfig = line::Config ::new ()?; +let mut lconfig = line::Config ::new ()?;for argin &args[2 ..] {let pair:Vec <&str > = arg.split ('=' ).collect ();
@@ -51,7 +51,7 @@ fn main() -> Result<()> {let path =format! ("/dev/gpiochip{}" , args[1 ]);let chip =Chip ::open (&path)?; -let rconfig = request::Config ::new ()?; +let mut rconfig = request::Config ::new ()?; rconfig.set_consumer (&args[0 ])?; chip.request_lines (Some (&rconfig), &lconfig)?;
bindings/rust/libgpiod/src/line_config.rs +2 -2
@@ -56,7 +56,7 @@ impl Config { }/// Add line settings for a set of offsets. -pub fn add_line_settings (&self, offsets: &[Offset ], settings:Settings ) ->Result <()> { +pub fn add_line_settings (&mut self, offsets: &[Offset ], settings:Settings ) ->Result <&mut Self > {// SAFETY: `gpiod_line_config` is guaranteed to be valid here. let ret =unsafe { gpiod::gpiod_line_config_add_line_settings(
@@ -73,7 +73,7 @@ impl Config { errno::errno(), )) }else { -Ok (()) +Ok (self) } }
bindings/rust/libgpiod/src/line_request.rs +8 -8
@@ -95,7 +95,7 @@ impl Request { }/// Set the value of a single line associated with the request. -pub fn set_value (&self, offset:Offset , value:Value ) ->Result <()> { +pub fn set_value (&mut self, offset:Offset , value:Value ) ->Result <&mut Self > {// SAFETY: `gpiod_line_request` is guaranteed to be valid here. let ret =unsafe { gpiod::gpiod_line_request_set_value (self.request, offset, value.value ()) };
@@ -106,12 +106,12 @@ impl Request { errno::errno(), )) }else { -Ok (()) +Ok (self) } }/// Set values of a subset of lines associated with the request. -pub fn set_values_subset (&self, map:ValueMap ) ->Result <()> { +pub fn set_values_subset (&mut self, map:ValueMap ) ->Result <&mut Self > {let mut offsets =Vec ::new ();let mut values =Vec ::new ();
@@ -136,12 +136,12 @@ impl Request { errno::errno(), )) }else { -Ok (()) +Ok (self) } }/// Set values of all lines associated with the request. -pub fn set_values (&self, values: &[Value ]) ->Result <()> { +pub fn set_values (&mut self, values: &[Value ]) ->Result <&mut Self > {if values.len () != self.num_lines ()as usize {return Err (Error ::InvalidArguments ); }
@@ -161,12 +161,12 @@ impl Request { errno::errno(), )) }else { -Ok (()) +Ok (self) } }/// Update the configuration of lines associated with the line request. -pub fn reconfigure_lines (&self, lconfig: &line::Config ) ->Result <()> { +pub fn reconfigure_lines (&mut self, lconfig: &line::Config ) ->Result <&mut Self > {// SAFETY: `gpiod_line_request` is guaranteed to be valid here. let ret =unsafe { gpiod::gpiod_line_request_reconfigure_lines (self.request, lconfig.config) };
@@ -177,7 +177,7 @@ impl Request { errno::errno(), )) }else { -Ok (()) +Ok (self) } }
bindings/rust/libgpiod/src/request_config.rs +5 -3
@@ -40,7 +40,7 @@ impl Config {/// /// If the consumer string is too long, it will be truncated to the max /// accepted length. -pub fn set_consumer (&self, consumer: &str ) ->Result <()> { +pub fn set_consumer (&mut self, consumer: &str ) ->Result <&mut Self > {let consumer =CString ::new (consumer).map_err (|_|Error ::InvalidString )?;// SAFETY: `gpiod_request_config` is guaranteed to be valid here.
@@ -51,7 +51,7 @@ impl Config { ) } -Ok (()) +Ok (self) }/// Get the consumer name configured in the request config.
@@ -73,9 +73,11 @@ impl Config { }/// Set the size of the kernel event buffer for the request. -pub fn set_event_buffer_size (&self, size:usize ) { +pub fn set_event_buffer_size (&mut self, size:usize ) -> &mut Self {// SAFETY: `gpiod_request_config` is guaranteed to be valid here. unsafe { gpiod::gpiod_request_config_set_event_buffer_size (self.config, sizeas c_ulong ) } + + self }/// Get the edge event buffer size setting for the request config.
bindings/rust/libgpiod/tests/common/config.rs +4 -4
@@ -43,7 +43,7 @@ impl TestConfig { } } -pub (crate )fn rconfig_set_consumer (&self, consumer: &str ) { +pub (crate )fn rconfig_set_consumer (&mut self, consumer: &str ) { self.rconfig.set_consumer (consumer).unwrap (); }
@@ -100,7 +100,7 @@ impl TestConfig {pub (crate )fn lconfig_add_settings (&mut self, offsets: &[Offset ]) { self.lconfig .add_line_settings (offsets, self.lsettings.take ().unwrap ()) - .unwrap () + .unwrap (); }pub (crate )fn request_lines (&mut self) ->Result <()> {
@@ -128,8 +128,8 @@ impl TestConfig { self.lsettings.as_mut ().unwrap () } -pub (crate )fn request (&self) -> &request::Request { - self.request.as_ref ().unwrap () +pub (crate )fn request (&mut self) -> &mut request::Request { + self.request.as_mut ().unwrap () } }
bindings/rust/libgpiod/tests/info_event.rs +3 -3
@@ -24,12 +24,12 @@ mod info_event {fn request_reconfigure_line (chip:Arc <Mutex <Chip >>, tx:Sender <()>, rx:Receiver <()>) { thread::spawn (move || { -let lconfig1 = line::Config ::new ().unwrap (); +let mut lconfig1 = line::Config ::new ().unwrap ();let lsettings = line::Settings ::new ().unwrap (); lconfig1.add_line_settings (&[7 ], lsettings).unwrap ();let rconfig = request::Config ::new ().unwrap (); -let request = chip +let mut request = chip .lock () .unwrap () .request_lines (Some (&rconfig), &lconfig1)
@@ -41,7 +41,7 @@ mod info_event {// Wait for parent to signal rx.recv ().expect ("Could not receive from channel" ); -let lconfig2 = line::Config ::new ().unwrap (); +let mut lconfig2 = line::Config ::new ().unwrap ();let mut lsettings = line::Settings ::new ().unwrap (); lsettings.set_direction (Direction ::Output ).unwrap (); lconfig2.add_line_settings (&[7 ], lsettings).unwrap ();
bindings/rust/libgpiod/tests/line_config.rs +1 -1
@@ -33,7 +33,7 @@ mod line_config { .unwrap();// Add settings for multiple lines -let lconfig = line::Config ::new ().unwrap (); +let mut lconfig = line::Config ::new ().unwrap (); lconfig.add_line_settings (&[0 ,1 ,2 ], lsettings1).unwrap (); lconfig.add_line_settings (&[4 ,5 ], lsettings2).unwrap ();
bindings/rust/libgpiod/tests/line_request.rs +32 -41
240 lines not on this page · raw message
bindings/rust/libgpiod/tests/request_config.rs +1 -1
@@ -27,7 +27,7 @@ mod request_config {#[test] fn initialized () {const CONSUMER : &str ="foobar" ; -let rconfig = request::Config ::new ().unwrap (); +let mut rconfig = request::Config ::new ().unwrap (); rconfig.set_consumer (CONSUMER ).unwrap (); rconfig.set_event_buffer_size (64 );
Signature · 1 line
2.37.2
Re: [libgpiod][PATCH v2 7/8] bindings: rust: make mutators return &mut self
Quoted 13 lines · Bartosz Golaszewski
From: Bartosz Golaszewski <[email protected]>
In C++ bindings we can chain the mutators as they all return a reference to the object they modify. It's a common practice to allow that in Rust too so make all mutators that don't already do it return a mutable reference to self.
It's also logically incorrect to make mutators borrow an immutable reference to self. Even if that builds - as we're fiddling with C pointers - it could change in the future. It's fine for getters but setters should all use mutable references.
Signed-off-by Bartosz Golaszewski <[email protected]>
Quoted 15 lines
--- .../rust/libgpiod/examples/gpio_events.rs | 2 +- .../examples/gpio_threaded_info_events.rs | 6 +- bindings/rust/libgpiod/examples/gpioget.rs | 4 +- bindings/rust/libgpiod/examples/gpiomon.rs | 2 +- bindings/rust/libgpiod/examples/gpioset.rs | 4 +- bindings/rust/libgpiod/src/line_config.rs | 4 +- bindings/rust/libgpiod/src/line_request.rs | 16 ++-- bindings/rust/libgpiod/src/request_config.rs | 8 +- bindings/rust/libgpiod/tests/common/config.rs | 8 +- bindings/rust/libgpiod/tests/info_event.rs | 6 +- bindings/rust/libgpiod/tests/line_config.rs | 2 +- bindings/rust/libgpiod/tests/line_request.rs | 73 ++++++++----------- .../rust/libgpiod/tests/request_config.rs | 2 +- 13 files changed, 65 insertions(+), 72 deletions(-)
Signature · 1 line
viresh
PATCH v2 8/8 bindings: rust: provide line_config.set_output_values()
In reply to Bartosz GolaszewskiFrom: Bartosz Golaszewski <[email protected]>
Add a new function to line config allowing to set a list of output values for requested lines. This works very similarily to the C++ version of the new C interface.
--- bindings/rust/libgpiod/src/lib.rs | 1 + bindings/rust/libgpiod/src/line_config.rs | 24 +++++++- bindings/rust/libgpiod/tests/line_config.rs | 62 +++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-)
bindings/rust/libgpiod/src/lib.rs +1 -0
@@ -71,6 +71,7 @@ pub enum OperationType { InfoEventGetLineInfo, LineConfigNew, LineConfigAddSettings, + LineConfigSetOutputValues, LineConfigGetOffsets, LineConfigGetSettings, LineRequestReconfigLines,
bindings/rust/libgpiod/src/line_config.rs +23 -1
@@ -7,7 +7,7 @@ use std::collections::HashMap;use super ::{ gpiod, - line::{Offset ,Settings }, + line::{Offset ,Settings ,Value },Error ,OperationType ,Result , };
@@ -77,6 +77,28 @@ impl Config { } } +/// Set output values for a number of lines. +pub fn set_output_values (&mut self, values: &[Value ]) ->Result <&mut Self > { +let mut mapped_values =Vec ::new (); +for valuein values { + mapped_values.push (value.value ()); + } + +let ret =unsafe { + gpiod::gpiod_line_config_set_output_values (self.config, mapped_values.as_ptr (), + values.len ()as u64 ) + }; + +if ret == -1 { +Err (Error ::OperationFailed ( +OperationType ::LineConfigSetOutputValues , + errno::errno (), + )) + }else { +Ok (self) + } + } +/// Get a mapping of offsets to line settings stored by this object. pub fn line_settings (&self) ->Result <HashMap <Offset ,Settings >> {let mut map:HashMap <Offset ,Settings > =HashMap ::new ();
bindings/rust/libgpiod/tests/line_config.rs +62 -0
75 lines not on this page · raw message
Signature · 1 line
2.37.2
Re: [libgpiod][PATCH v2 8/8] bindings: rust: provide line_config.set_output_values()
Quoted 6 lines · Bartosz Golaszewski
From: Bartosz Golaszewski <[email protected]>
Add a new function to line config allowing to set a list of output values for requested lines. This works very similarily to the C++ version of the new C interface.
Quoted 6 lines
Signed-off-by Bartosz Golaszewski <[email protected]>--- bindings/rust/libgpiod/src/lib.rs | 1 + bindings/rust/libgpiod/src/line_config.rs | 24 +++++++- bindings/rust/libgpiod/tests/line_config.rs | 62 +++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-)
Signature · 1 line
viresh