Skip to contentSkip to conversation

treewide: continue beating libgpiod v2 into shape for an upcoming release

PATCH In review Bartosz Golaszewski 2 participants 11 messages Jan 20, 2023 – Jan 25, 2023

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

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
#1 lore raw

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
index d51d701..b71739e 100644
@@ -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
#2 lore raw

PATCH v2 2/8 treewide: unify gpiod_line_config/request_get_offsets() functions

In reply to Bartosz Golaszewski

From: 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
index f7f1bfa..3ec99f0 100644
@@ -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
index b52ceaf..b0723c3 100644
@@ -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
index d3e1448..a32ff8f 100644
@@ -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
index d9e041c..7915924 100644
@@ -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_offsets as usize);
         offsets
     }
 
bindings/rust/libgpiod/tests/line_config.rs +4 -20
index bebf106..95f2178 100644
@@ -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
index 4a91723..c5fb7c7 100644
@@ -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
index bc10059..877e7ef 100644
@@ -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
index c9ad337..e536355 100644
@@ -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
#3 lore raw

PATCH v2 3/8 core: provide gpiod_line_config_set_output_values()

In reply to Bartosz Golaszewski

From: 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
index fea2076..a895dae 100644
@@ -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
index fb3fd7d..760949e 100644
@@ -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
#4 lore raw

PATCH v2 4/8 gpioset: use gpiod_line_config_set_output_values()

In reply to Bartosz Golaszewski

From: 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
index a871a16..1429d65 100644
@@ -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
#5 lore raw

PATCH v2 5/8 bindings: cxx: add line_config.set_output_values()

In reply to Bartosz Golaszewski

From: 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
index a917913..b76fdff 100644
@@ -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
index 6aceac1..8322e12 100644
@@ -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
index 3ec99f0..233ba33 100644
@@ -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
index 32f21a3..2159062 100644
@@ -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
#6 lore raw

PATCH v2 6/8 bindings: python: add the output_values argument to Chip.request_lines()

In reply to Bartosz Golaszewski

From: 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
index ad2eddd..97ff340 100644
@@ -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
#7 lore raw

PATCH v2 7/8 bindings: rust: make mutators return &mut self

In reply to 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.

---
 .../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
index cbdf1b5..b26c60b 100644
@@ -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 arg in &args[2..] {
bindings/rust/libgpiod/examples/gpio_threaded_info_events.rs +3 -3
index 367b2f6..620f4ec 100644
@@ -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
index 74baf30..a71612b 100644
@@ -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 arg in &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
index a09ddfc..8f2a71a 100644
@@ -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 arg in &args[2..] {
bindings/rust/libgpiod/examples/gpioset.rs +2 -2
index 6247996..4b43010 100644
@@ -24,7 +24,7 @@ fn main() -> Result<()> {
         return Err(Error::InvalidArguments);
     }
 
-    let lconfig = line::Config::new()?;
+    let mut lconfig = line::Config::new()?;
 
     for arg in &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
index 42dad9f..3f42dad 100644
@@ -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
index 7915924..ff701fb 100644
@@ -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
index 9d38548..939838c 100644
@@ -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, size as c_ulong) }
+
+        self
     }
 
     /// Get the edge event buffer size setting for the request config.
bindings/rust/libgpiod/tests/common/config.rs +4 -4
index b838b66..36ccc94 100644
@@ -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
index 6bf7a0f..f06dd2d 100644
@@ -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
index 95f2178..92a7af3 100644
@@ -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
index 8c67638..d78c4bd 100644
@@ -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
Acked-by on v2 7/8
#8 lore raw

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.

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
#9 lore raw

PATCH v2 8/8 bindings: rust: provide line_config.set_output_values()

In reply to 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.

---
 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
index a5d018c..f268ceb 100644
@@ -71,6 +71,7 @@ pub enum OperationType {
     InfoEventGetLineInfo,
     LineConfigNew,
     LineConfigAddSettings,
+    LineConfigSetOutputValues,
     LineConfigGetOffsets,
     LineConfigGetSettings,
     LineRequestReconfigLines,
bindings/rust/libgpiod/src/line_config.rs +23 -1
index 3f42dad..32f057f 100644
@@ -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 value in 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
Acked-by on v2 8/8
#10 lore raw

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
---
 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