Skip to contentSkip to conversation

libgpiod: Add Rust bindings

PATCH In review Viresh Kumar 4 participants 16 messages Nov 18, 2022 – Nov 22, 2022 GPIO

lore
Share & tools
lore
#0 lore raw

v10 cover libgpiod: Add Rust bindings

Hello,

Here is another version of the rust bindings, based of the master branch.

Pushed here:

https://github.com/vireshk/libgpiod v10

V9->V10:
- Removed auto-built bindings.rs files.
- Updated license and copyright information for all files.
- Renamed gpiosim crate as gpiosim-sys.
- Cargo specific .gitnore changes moved to bindings/rust/.gitignore.
- Fixed few SAFETY comments.
- Added Reviewed-by tag from Kent. Since the changes were all minor, I haven't dropped them.

V8->V9:
- Merged the last patch (supporting Events) with the other patches.
- Events implementation is simplified and made efficient. nth() is also implemented for the iterator.
- Unnecessary comment removed from Cargo.toml files.
- Updated categories in libgpiod's Cargo.toml.
- Updated gpio_events example to show cloned events live past another read_edge_events().
- Implement AsRawFd for Chip.
- Other minor changes.

V7->V8:
- Several updates to cargo.toml files, like license, version, etc.
- Removed Sync support for chip and gpiosim.
- Implemented, in a separate patch, iterator support for Events.
- Fixed missing SAFETY comments.
- Fixed build for 32 bit systems.
- Use errno::Errno.
- Removed Clone derive for many structures, that store raw pointers.
- line setting helpers return the object back, so another helper can be called directly on them. Also made all helpers public and used the same in tests and example for single configurations.
- Enums for gpiosim constants.
- New examples to demonstrate parallelism and event handling.
- Separated out HTE tests and marked as #[ignore] now.
- Updated commit subjects.
- Other minor changes.

V6->V7:
- Don't let buffer read new events if the earlier events are still referenced.
- BufferIntenal is gone now, to make the above work.
- Update example and tests too for the same.

V5->V6:
- Updates according to the new line-settings interface.
- New file, line_settings.rs.
- Renamed 'enum Setting' as 'SettingVal' to avoid conflicting names, as we also have 'struct Settings' now.
- Support for HTE clock type.
- Implement 'Eq' for public structure/enums (reported by build).
- Remove 'SettingKindMap' and 'SettingMap' as they aren't required anymore.
- Updated tests based on new interface.

V4->V5:
- Arrange as workspace with crates for libgpiod-sys, libgpiod, gpiosim.
- Use static libgpiod and libgpiosim libraries instead of rebuilding again.
- Arrange in modules instead of flattened approach.
- New enums like Setting and SettingKind and new types based on them SettingMap and SettingKindMap.
- New property independent helpers for line_config, like set_prop_default().
- Improved tests/examples, new example for gpiowatch.
- Add pre-built bindings for gpiosim too.
- Many other changes.

V3->V4:
- Rebased on top of new changes, and made changes accordingly.
- Added rust integration tests with gpiosim.
- Found a kernel bug with tests, sent a patch for that to LKML.

V2->V3:
- Remove naming redundancy, users just need to do this now
use libgpiod:{Chip, Direction, LineConfig} now (Bartosz);
- Fix lifetime issues between event-buffer and edge-event modules, the event buffer is released after the last edge-event reference is dropped (Bartosz).
- Allow edge-event to be copied, and freed later (Bartosz).
- Add two separate rust crates, sys and wrapper (Gerard).
- Null-terminate the strings passed to libgpiod (Wedson).
- Drop unnecessary checks to validate string returned from chip:name/label/path.
- Fix SAFETY comments (Wedson).
- Drop unnecessary clone() instances (Bartosz).

V1->V2:
- Added examples (I tested everything except gpiomon.rs, didn't have right hardware/mock device to test).
- Build rust bindings as part of Make, update documentation.

Thanks.

--
Viresh

Viresh Kumar (6):
bindings: rust: Add libgpiod-sys rust crate
bindings: rust: Add libgpiod crate
bindings: rust: Add gpiosim-sys crate
bindings: rust: Add examples to libgpiod crate
bindings: rust: Add tests for libgpiod crate
bindings: rust: Integrate building of bindings with make

 README                                        |   8 +-
 TODO                                          |   8 -
 bindings/Makefile.am                          |   6 +
 bindings/rust/.gitignore                      |   4 +
 bindings/rust/Cargo.toml                      |  11 +
 bindings/rust/Makefile.am                     |  19 +
 bindings/rust/gpiosim-sys/Cargo.toml          |  23 +
 bindings/rust/gpiosim-sys/README.md           |  14 +
 bindings/rust/gpiosim-sys/build.rs            |  43 ++
 bindings/rust/gpiosim-sys/src/lib.rs          |  74 +++
 bindings/rust/gpiosim-sys/src/sim.rs          | 330 ++++++++++++
 bindings/rust/libgpiod-sys/Cargo.toml         |  21 +
 bindings/rust/libgpiod-sys/README.md          |  14 +
 bindings/rust/libgpiod-sys/build.rs           |  41 ++
 bindings/rust/libgpiod-sys/src/lib.rs         |  11 +
 bindings/rust/libgpiod/Cargo.toml             |  25 +
 .../rust/libgpiod/examples/gpio_events.rs     |  88 +++
 .../examples/gpio_threaded_info_events.rs     | 132 +++++
 bindings/rust/libgpiod/examples/gpiodetect.rs |  30 ++
 bindings/rust/libgpiod/examples/gpiofind.rs   |  36 ++
 bindings/rust/libgpiod/examples/gpioget.rs    |  45 ++
 bindings/rust/libgpiod/examples/gpioinfo.rs   |  97 ++++
 bindings/rust/libgpiod/examples/gpiomon.rs    |  74 +++
 bindings/rust/libgpiod/examples/gpioset.rs    |  63 +++
 bindings/rust/libgpiod/examples/gpiowatch.rs  |  53 ++
 bindings/rust/libgpiod/src/chip.rs            | 309 +++++++++++
 bindings/rust/libgpiod/src/edge_event.rs      |  92 ++++
 bindings/rust/libgpiod/src/event_buffer.rs    | 168 ++++++
 bindings/rust/libgpiod/src/info_event.rs      |  68 +++
 bindings/rust/libgpiod/src/lib.rs             | 478 ++++++++++++++++
 bindings/rust/libgpiod/src/line_config.rs     | 134 +++++
 bindings/rust/libgpiod/src/line_info.rs       | 161 ++++++
 bindings/rust/libgpiod/src/line_request.rs    | 226 ++++++++
 bindings/rust/libgpiod/src/line_settings.rs   | 296 ++++++++++
 bindings/rust/libgpiod/src/request_config.rs  |  94 ++++
 bindings/rust/libgpiod/tests/chip.rs          |  97 ++++
 bindings/rust/libgpiod/tests/common/config.rs | 142 +++++
 bindings/rust/libgpiod/tests/common/mod.rs    |   9 +
 bindings/rust/libgpiod/tests/edge_event.rs    | 297 ++++++++++
 bindings/rust/libgpiod/tests/info_event.rs    | 166 ++++++
 bindings/rust/libgpiod/tests/line_config.rs   |  95 ++++
 bindings/rust/libgpiod/tests/line_info.rs     | 275 ++++++++++
 bindings/rust/libgpiod/tests/line_request.rs  | 509 ++++++++++++++++++
 bindings/rust/libgpiod/tests/line_settings.rs | 203 +++++++
 .../rust/libgpiod/tests/request_config.rs     |  38 ++
 configure.ac                                  |  16 +
 46 files changed, 5132 insertions(+), 11 deletions(-)
 create mode 100644 bindings/rust/.gitignore
 create mode 100644 bindings/rust/Cargo.toml
 create mode 100644 bindings/rust/Makefile.am
 create mode 100644 bindings/rust/gpiosim-sys/Cargo.toml
 create mode 100644 bindings/rust/gpiosim-sys/README.md
 create mode 100644 bindings/rust/gpiosim-sys/build.rs
 create mode 100644 bindings/rust/gpiosim-sys/src/lib.rs
 create mode 100644 bindings/rust/gpiosim-sys/src/sim.rs
 create mode 100644 bindings/rust/libgpiod-sys/Cargo.toml
 create mode 100644 bindings/rust/libgpiod-sys/README.md
 create mode 100644 bindings/rust/libgpiod-sys/build.rs
 create mode 100644 bindings/rust/libgpiod-sys/src/lib.rs
 create mode 100644 bindings/rust/libgpiod/Cargo.toml
 create mode 100644 bindings/rust/libgpiod/examples/gpio_events.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpio_threaded_info_events.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpiodetect.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpiofind.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpioget.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpioinfo.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpiomon.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpioset.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpiowatch.rs
 create mode 100644 bindings/rust/libgpiod/src/chip.rs
 create mode 100644 bindings/rust/libgpiod/src/edge_event.rs
 create mode 100644 bindings/rust/libgpiod/src/event_buffer.rs
 create mode 100644 bindings/rust/libgpiod/src/info_event.rs
 create mode 100644 bindings/rust/libgpiod/src/lib.rs
 create mode 100644 bindings/rust/libgpiod/src/line_config.rs
 create mode 100644 bindings/rust/libgpiod/src/line_info.rs
 create mode 100644 bindings/rust/libgpiod/src/line_request.rs
 create mode 100644 bindings/rust/libgpiod/src/line_settings.rs
 create mode 100644 bindings/rust/libgpiod/src/request_config.rs
 create mode 100644 bindings/rust/libgpiod/tests/chip.rs
 create mode 100644 bindings/rust/libgpiod/tests/common/config.rs
 create mode 100644 bindings/rust/libgpiod/tests/common/mod.rs
 create mode 100644 bindings/rust/libgpiod/tests/edge_event.rs
 create mode 100644 bindings/rust/libgpiod/tests/info_event.rs
 create mode 100644 bindings/rust/libgpiod/tests/line_config.rs
 create mode 100644 bindings/rust/libgpiod/tests/line_info.rs
 create mode 100644 bindings/rust/libgpiod/tests/line_request.rs
 create mode 100644 bindings/rust/libgpiod/tests/line_settings.rs
 create mode 100644 bindings/rust/libgpiod/tests/request_config.rs
Signature · 1 line
2.31.1.272.g89b43f80a514
#1 lore raw

PATCH v10 1/6 bindings: rust: Add libgpiod-sys rust crate

This adds libgpiod-sys rust crate, which provides FFI (foreign function interface) bindings for libgpiod APIs.

---
 bindings/rust/.gitignore              |  4 +++
 bindings/rust/Cargo.toml              |  9 ++++++
 bindings/rust/libgpiod-sys/Cargo.toml | 21 ++++++++++++++
 bindings/rust/libgpiod-sys/README.md  | 14 +++++++++
 bindings/rust/libgpiod-sys/build.rs   | 41 +++++++++++++++++++++++++++
 bindings/rust/libgpiod-sys/src/lib.rs | 11 +++++++
 6 files changed, 100 insertions(+)
 create mode 100644 bindings/rust/.gitignore
 create mode 100644 bindings/rust/Cargo.toml
 create mode 100644 bindings/rust/libgpiod-sys/Cargo.toml
 create mode 100644 bindings/rust/libgpiod-sys/README.md
 create mode 100644 bindings/rust/libgpiod-sys/build.rs
 create mode 100644 bindings/rust/libgpiod-sys/src/lib.rs
bindings/rust/.gitignore new file +4 -0
new file mode 100644
index 000000000000..95054d9da312
@@ -0,0 +1,4 @@
+# Added by cargo
+
+target
+Cargo.lock
bindings/rust/Cargo.toml new file +9 -0
new file mode 100644
index 000000000000..e3e253a4cf5e
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2022 Linaro Ltd.
+# SPDX-FileCopyrightTest: 2022 Viresh Kumar <[email protected]>
+
+[workspace]
+
+members = [
+    "libgpiod-sys"
+]
bindings/rust/libgpiod-sys/Cargo.toml new file +21 -0
new file mode 100644
index 000000000000..479184da3f7b
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2022 Linaro Ltd.
+# SPDX-FileCopyrightTest: 2022 Viresh Kumar <[email protected]>
+
+[package]
+name = "libgpiod-sys"
+version = "0.1.0"
+authors = ["Viresh Kumar <[email protected]>"]
+description = "libgpiod public header bindings"
+repository = "https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git"
+categories = ["external-ffi-bindings", "os::linux-apis"]
+rust-version = "1.56"
+keywords = ["libgpiod", "gpio"]
+license = "Apache-2.0 OR BSD-3-Clause"
+edition = "2021"
+
+[dependencies]
+
+[build-dependencies]
+bindgen = "0.59.1"
+cc = "1.0.46"
bindings/rust/libgpiod-sys/README.md new file +14 -0
new file mode 100644
index 000000000000..7e6e643ab2ab
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2022 Linaro Ltd.
+# SPDX-FileCopyrightTest: 2022 Viresh Kumar <[email protected]>
+
+# Generated libgpiod-sys Rust FFI bindings
+Automatically generated Rust FFI bindings via
+	[bindgen](https://github.com/rust-lang/rust-bindgen).
+
+## License
+
+This project is licensed under either of
+
+- [Apache License](http://www.apache.org/licenses/LICENSE-2.0), Version 2.0
+- [BSD-3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
bindings/rust/libgpiod-sys/build.rs new file +41 -0

41 lines not on this page · raw message

bindings/rust/libgpiod-sys/src/lib.rs new file +11 -0
new file mode 100644
index 000000000000..68526910c8ee
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
+// SPDX-FileCopyrightText: 2022 Linaro Ltd.
+// SPDX-FileCopyrightTest: 2022 Viresh Kumar <[email protected]>
+
+#[allow(non_camel_case_types, non_upper_case_globals)]
+#[cfg_attr(test, allow(deref_nullptr, non_snake_case))]
+
+mod bindings_raw {
+    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+}
+pub use bindings_raw::*;
Signature · 1 line
2.31.1.272.g89b43f80a514
#2 lore raw

PATCH v10 2/6 bindings: rust: Add libgpiod crate

In reply to Viresh Kumar

Add rust wrapper crate, around the libpiod-sys crate added earlier, to provide a convenient interface for the users.

---
 bindings/rust/Cargo.toml                     |   1 +
 bindings/rust/libgpiod/Cargo.toml            |  22 +
 bindings/rust/libgpiod/src/chip.rs           | 309 ++++++++++++
 bindings/rust/libgpiod/src/edge_event.rs     |  92 ++++
 bindings/rust/libgpiod/src/event_buffer.rs   | 168 +++++++
 bindings/rust/libgpiod/src/info_event.rs     |  68 +++
 bindings/rust/libgpiod/src/lib.rs            | 478 +++++++++++++++++++
 bindings/rust/libgpiod/src/line_config.rs    | 134 ++++++
 bindings/rust/libgpiod/src/line_info.rs      | 161 +++++++
 bindings/rust/libgpiod/src/line_request.rs   | 226 +++++++++
 bindings/rust/libgpiod/src/line_settings.rs  | 296 ++++++++++++
 bindings/rust/libgpiod/src/request_config.rs |  94 ++++
 12 files changed, 2049 insertions(+)
 create mode 100644 bindings/rust/libgpiod/Cargo.toml
 create mode 100644 bindings/rust/libgpiod/src/chip.rs
 create mode 100644 bindings/rust/libgpiod/src/edge_event.rs
 create mode 100644 bindings/rust/libgpiod/src/event_buffer.rs
 create mode 100644 bindings/rust/libgpiod/src/info_event.rs
 create mode 100644 bindings/rust/libgpiod/src/lib.rs
 create mode 100644 bindings/rust/libgpiod/src/line_config.rs
 create mode 100644 bindings/rust/libgpiod/src/line_info.rs
 create mode 100644 bindings/rust/libgpiod/src/line_request.rs
 create mode 100644 bindings/rust/libgpiod/src/line_settings.rs
 create mode 100644 bindings/rust/libgpiod/src/request_config.rs
bindings/rust/Cargo.toml +1 -0
index e3e253a4cf5e..f4051387d581 100644
@@ -5,5 +5,6 @@
 [workspace]
 
 members = [
+    "libgpiod",
     "libgpiod-sys"
 ]
bindings/rust/libgpiod/Cargo.toml new file +22 -0
new file mode 100644
index 000000000000..a38df1c0b10d
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2022 Linaro Ltd.
+# SPDX-FileCopyrightTest: 2022 Viresh Kumar <[email protected]>
+
+[package]
+name = "libgpiod"
+version = "0.1.0"
+authors = ["Viresh Kumar <[email protected]>"]
+description = "libgpiod wrappers"
+repository = "https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git"
+categories = ["api-bindings", "hardware-support", "embedded", "os::linux-apis"]
+rust-version = "1.56"
+keywords = ["libgpiod", "gpio"]
+license = "Apache-2.0 OR BSD-3-Clause"
+edition = "2021"
+
+[dependencies]
+errno = "0.2.8"
+intmap = "2.0.0"
+libc = "0.2.39"
+libgpiod-sys = { path = "../libgpiod-sys" }
+thiserror = "1.0"
bindings/rust/libgpiod/src/chip.rs new file +309 -0

309 lines not on this page · raw message

bindings/rust/libgpiod/src/edge_event.rs new file +92 -0

92 lines not on this page · raw message

bindings/rust/libgpiod/src/event_buffer.rs new file +168 -0

168 lines not on this page · raw message

bindings/rust/libgpiod/src/info_event.rs new file +68 -0

68 lines not on this page · raw message

bindings/rust/libgpiod/src/lib.rs new file +478 -0

478 lines not on this page · raw message

bindings/rust/libgpiod/src/line_config.rs new file +134 -0

134 lines not on this page · raw message

bindings/rust/libgpiod/src/line_info.rs new file +161 -0

161 lines not on this page · raw message

bindings/rust/libgpiod/src/line_request.rs new file +226 -0

226 lines not on this page · raw message

bindings/rust/libgpiod/src/line_settings.rs new file +296 -0

296 lines not on this page · raw message

bindings/rust/libgpiod/src/request_config.rs new file +94 -0

94 lines not on this page · raw message

Signature · 1 line
2.31.1.272.g89b43f80a514
#3 lore raw

Re: [libgpiod][PATCH V10 2/6] bindings: rust: Add libgpiod crate

Quoted 5 lines
bindings/rust/libgpiod/src/lib.rs new file +5 -0
+/// Get the API version of the libgpiod library as a human-readable string.
+pub fn libgpiod_version() -> Result<&'static str> {
+    // SAFETY: The string returned by libgpiod is guaranteed to live forever.
+    let version = unsafe { gpiod::gpiod_version_string() };
+

bindings/rust/libgpiod/src/lib.rs line 474

Quoted 10 lines
bindings/rust/libgpiod/src/lib.rs new file +10 -0
+    if version.is_null() {
+        return Err(Error::NullString("GPIO library version"));
+    }
+
+    // SAFETY: The string is guaranteed to be valid here by the C API.
+    unsafe { CStr::from_ptr(version) }
+        .to_str()
+        .map_err(Error::StringNotUtf8)
+}
+

This is not a blocker, I will apply this series to master later and we can add modifications on top of that, but I am now questioning the need for this function here and also the value of __version__ in Python bindings.

Previously the python bindings were built with autotools as part of the whole library. In v2 python now has a proper setup.py script and I intend to publish the bindings on pypi. It can now be built separately from the rest of the libgpiod code as long as the system satisfies the dependency for libgpiod. Example: I will split the yocto recipe for libgpiod into one for the core lib + tools + C++ bindings and another for python that will go to meta-python. The latter will depend on the libgpiod package but will be built in a separate sysroot.

In that case keeping the libgpiod API version as the Python's package __version__ (which made sense before when that code was closely integrated with libgpiod core) is no longer necessary. I'm thinking about setting __version__ to v2.0.0 (because we already had python bindings with v1.x.y versioning out there) but decoupling it from libgpiod's API version.

In your rust code all the crates already have their own versions that don't follow libgpiod's API's version. I think we should drop this function. What do you think?

Also: is there a standardized way for crates to inspect their version? As in: println!(crate.version()) or something?

Bart

#4 lore raw

Re: [libgpiod][PATCH V10 2/6] bindings: rust: Add libgpiod crate

Quoted 21 lines · Bartosz Golaszewski

This is not a blocker, I will apply this series to master later and we can add modifications on top of that, but I am now questioning the need for this function here and also the value of __version__ in Python bindings.

Previously the python bindings were built with autotools as part of the whole library. In v2 python now has a proper setup.py script and I intend to publish the bindings on pypi. It can now be built separately from the rest of the libgpiod code as long as the system satisfies the dependency for libgpiod. Example: I will split the yocto recipe for libgpiod into one for the core lib + tools + C++ bindings and another for python that will go to meta-python. The latter will depend on the libgpiod package but will be built in a separate sysroot.

In that case keeping the libgpiod API version as the Python's package __version__ (which made sense before when that code was closely integrated with libgpiod core) is no longer necessary. I'm thinking about setting __version__ to v2.0.0 (because we already had python bindings with v1.x.y versioning out there) but decoupling it from libgpiod's API version.

Quoted 3 lines

In your rust code all the crates already have their own versions that don't follow libgpiod's API's version. I think we should drop this function. What do you think?

whatever you and Kent decide is fine with me :)

Quoted 2 lines

Also: is there a standardized way for crates to inspect their version? As in: println!(crate.version()) or something?

I think that would be "version!()" [1].

Signature · 3 lines
viresh

[1] https://crates.io/crates/version
#5 lore raw

Re: [libgpiod][PATCH V10 2/6] bindings: rust: Add libgpiod crate

Quoted 22 lines · Viresh Kumar
Quoted 21 lines · Bartosz Golaszewski

This is not a blocker, I will apply this series to master later and we can add modifications on top of that, but I am now questioning the need for this function here and also the value of __version__ in Python bindings.

Previously the python bindings were built with autotools as part of the whole library. In v2 python now has a proper setup.py script and I intend to publish the bindings on pypi. It can now be built separately from the rest of the libgpiod code as long as the system satisfies the dependency for libgpiod. Example: I will split the yocto recipe for libgpiod into one for the core lib + tools + C++ bindings and another for python that will go to meta-python. The latter will depend on the libgpiod package but will be built in a separate sysroot.

In that case keeping the libgpiod API version as the Python's package __version__ (which made sense before when that code was closely integrated with libgpiod core) is no longer necessary. I'm thinking about setting __version__ to v2.0.0 (because we already had python bindings with v1.x.y versioning out there) but decoupling it from libgpiod's API version.

Quoted 6 lines
Quoted 3 lines

In your rust code all the crates already have their own versions that don't follow libgpiod's API's version. I think we should drop this function. What do you think?

whatever you and Kent decide is fine with me :)

As previously mentioned, it makes sense to me for there to be functions that return both the binding version and the libgpiod version you are running against. Separately, as the two are distinct.

So keeping the wrapper around the libgpiod version method for the latter, and another function that returns the CARGO_PKG_VERSION for the binding crate.

Then, if the user is interested, they can report them in their help, version, log, startup banner or whatever works for them.

Quoted 5 lines
Quoted 2 lines

Also: is there a standardized way for crates to inspect their version? As in: println!(crate.version()) or something?

I think that would be "version!()" [1].

Which is a library that reads the envvars set by Cargo at compile time, so you could also just

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

and provide a function that returns that.

Cheers,
Kent.

#6 lore raw

Re: [libgpiod][PATCH V10 2/6] bindings: rust: Add libgpiod crate

Quoted 6 lines · Kent Gibson

Which is a library that reads the envvars set by Cargo at compile time, so you could also just

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

and provide a function that returns that.

Right, this is what we are doing currently:

/// Get the API version of the libgpiod crate as a human-readable string.

pub fn crate_version() -> &'static str {
    env!("CARGO_PKG_VERSION")
}
Signature · 1 line
viresh
#7 lore raw

Re: [libgpiod][PATCH V10 2/6] bindings: rust: Add libgpiod crate

Quoted 6 lines · Viresh Kumar
Quoted 5 lines · Kent Gibson

Which is a library that reads the envvars set by Cargo at compile time, so you could also just

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

Quoted 9 lines
Quoted 1 line

and provide a function that returns that.

Right, this is what we are doing currently:

/// Get the API version of the libgpiod crate as a human-readable string.

pub fn crate_version() -> &'static str {
    env!("CARGO_PKG_VERSION")
}

Which is already the standard way, so not sure how the discussion took the path it did, but anyway...

It is safe to assume the libgpiod-sys version is tied to the libgpiod crate version?

Cheers,
Kent.

#8 lore raw

Re: [libgpiod][PATCH V10 2/6] bindings: rust: Add libgpiod crate

Quoted 2 lines · Kent Gibson

It is safe to assume the libgpiod-sys version is tied to the libgpiod crate version?

I think so.

Signature · 1 line
viresh
#9 lore raw

PATCH v10 3/6 bindings: rust: Add gpiosim-sys crate

In reply to Viresh Kumar

This adds gpiosim-sys rust crate, which provides helpers to emulate GPIO chips.

---
 bindings/rust/Cargo.toml             |   1 +
 bindings/rust/gpiosim-sys/Cargo.toml |  23 ++
 bindings/rust/gpiosim-sys/README.md  |  14 ++
 bindings/rust/gpiosim-sys/build.rs   |  43 ++++
 bindings/rust/gpiosim-sys/src/lib.rs |  74 ++++++
 bindings/rust/gpiosim-sys/src/sim.rs | 330 +++++++++++++++++++++++++++
 6 files changed, 485 insertions(+)
 create mode 100644 bindings/rust/gpiosim-sys/Cargo.toml
 create mode 100644 bindings/rust/gpiosim-sys/README.md
 create mode 100644 bindings/rust/gpiosim-sys/build.rs
 create mode 100644 bindings/rust/gpiosim-sys/src/lib.rs
 create mode 100644 bindings/rust/gpiosim-sys/src/sim.rs
bindings/rust/Cargo.toml +1 -0
index f4051387d581..b4a28fd7129c 100644
@@ -5,6 +5,7 @@
 [workspace]
 
 members = [
+    "gpiosim-sys",
     "libgpiod",
     "libgpiod-sys"
 ]
bindings/rust/gpiosim-sys/Cargo.toml new file +23 -0
new file mode 100644
index 000000000000..c3571d2cf48e
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2022 Linaro Ltd.
+# SPDX-FileCopyrightTest: 2022 Viresh Kumar <[email protected]>
+
+[package]
+name = "gpiosim-sys"
+version = "0.1.0"
+authors = ["Viresh Kumar <[email protected]>"]
+description = "gpiosim header bindings"
+repository = "https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git"
+categories = ["external-ffi-bindings", "os::linux-apis"]
+rust-version = "1.56"
+keywords = ["libgpiod", "gpio", "gpiosim"]
+license = "Apache-2.0 OR BSD-3-Clause"
+edition = "2021"
+
+[dependencies]
+errno = "0.2.8"
+libgpiod = { path = "../libgpiod" }
+
+[build-dependencies]
+bindgen = "0.59.1"
+cc = "1.0.46"
bindings/rust/gpiosim-sys/README.md new file +14 -0
new file mode 100644
index 000000000000..686d522bf174
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2022 Linaro Ltd.
+# SPDX-FileCopyrightTest: 2022 Viresh Kumar <[email protected]>
+
+# Generated gpiosim Rust FFI bindings
+Automatically generated Rust FFI bindings via
+	[bindgen](https://github.com/rust-lang/rust-bindgen).
+
+## License
+
+This project is licensed under either of
+
+- [Apache License](http://www.apache.org/licenses/LICENSE-2.0), Version 2.0
+- [BSD-3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
bindings/rust/gpiosim-sys/build.rs new file +43 -0

43 lines not on this page · raw message

bindings/rust/gpiosim-sys/src/lib.rs new file +74 -0

74 lines not on this page · raw message

bindings/rust/gpiosim-sys/src/sim.rs new file +330 -0

330 lines not on this page · raw message

Signature · 1 line
2.31.1.272.g89b43f80a514
#10 lore raw

PATCH v10 4/6 bindings: rust: Add examples to libgpiod crate

In reply to Viresh Kumar

Add examples for the usage of the rust bindings, quite similar to the ones in cxx bindings.

---
 .../rust/libgpiod/examples/gpio_events.rs     |  88 ++++++++++++
 .../examples/gpio_threaded_info_events.rs     | 132 ++++++++++++++++++
 bindings/rust/libgpiod/examples/gpiodetect.rs |  30 ++++
 bindings/rust/libgpiod/examples/gpiofind.rs   |  36 +++++
 bindings/rust/libgpiod/examples/gpioget.rs    |  45 ++++++
 bindings/rust/libgpiod/examples/gpioinfo.rs   |  97 +++++++++++++
 bindings/rust/libgpiod/examples/gpiomon.rs    |  74 ++++++++++
 bindings/rust/libgpiod/examples/gpioset.rs    |  63 +++++++++
 bindings/rust/libgpiod/examples/gpiowatch.rs  |  53 +++++++
 9 files changed, 618 insertions(+)
 create mode 100644 bindings/rust/libgpiod/examples/gpio_events.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpio_threaded_info_events.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpiodetect.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpiofind.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpioget.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpioinfo.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpiomon.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpioset.rs
 create mode 100644 bindings/rust/libgpiod/examples/gpiowatch.rs
bindings/rust/libgpiod/examples/gpio_events.rs new file +88 -0
new file mode 100644
index 000000000000..981005043d55
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
+// SPDX-FileCopyrightText: 2022 Linaro Ltd.
+// SPDX-FileCopyrightTest: 2022 Viresh Kumar <[email protected]>
+//
+// Simplified Rust implementation to show handling of events, when the buffer
+// is read into multiple times. Based on gpiomon example.
+
+use std::env;
+
+use libgpiod::{
+    chip::Chip,
+    line::{self, Edge, Offset},
+    request, Error, Result,
+};
+
+fn usage(name: &str) {
+    println!("Usage: {} <chip> <offset0> ...", name);
+}
+
+fn main() -> Result<()> {
+    let args: Vec<String> = env::args().collect();
+    if args.len() < 3 {
+        usage(&args[0]);
+        return Err(Error::InvalidArguments);
+    }
+
+    let mut lsettings = line::Settings::new()?;
+    let lconfig = line::Config::new()?;
+    let mut offsets = Vec::<Offset>::new();
+
+    for arg in &args[2..] {
+        let offset = arg.parse::<Offset>().map_err(|_| Error::InvalidArguments)?;
+        offsets.push(offset);
+    }
+
+    lsettings.set_edge_detection(Some(Edge::Both))?;
+    lconfig.add_line_settings(&offsets, lsettings)?;
+
+    let path = format!("/dev/gpiochip{}", args[1]);
+    let chip = Chip::open(&path)?;
+
+    let rconfig = request::Config::new()?;
+
+    let mut buffer = request::Buffer::new(1)?;
+    let request = chip.request_lines(&rconfig, &lconfig)?;
+
+    loop {
+        match request.wait_edge_event(None) {
+            Err(x) => {
+                println!("{:?}", x);
+                return Err(Error::InvalidArguments);
+            }
+
+            Ok(false) => {
+                // This shouldn't happen as the call is blocking.
+                panic!();
+            }
+            Ok(true) => (),
+        }
+
+        let mut events = request.read_edge_events(&mut buffer)?;
+
+        // This can't be used across the next read_edge_events().
+        let event = events.next().unwrap()?;
+
+        // This will out live `event` and the next read_edge_events().
+        let cloned_event = request::Event::event_clone(event)?;
+
+        let events = request.read_edge_events(&mut buffer)?;
+        for event in events {
+            let event = event?;
+            println!(
+                "line: {} type: {:?}, time: {:?}",
+                event.line_offset(),
+                event.event_type(),
+                event.timestamp()
+            );
+        }
+
+        // `cloned_event` is still available to be used.
+        println!(
+            "line: {} type: {:?}, time: {:?}",
+            cloned_event.line_offset(),
+            cloned_event.event_type(),
+            cloned_event.timestamp()
+        );
+    }
+}
bindings/rust/libgpiod/examples/gpio_threaded_info_events.rs new file +132 -0

132 lines not on this page · raw message

bindings/rust/libgpiod/examples/gpiodetect.rs new file +30 -0
new file mode 100644
index 000000000000..96581bc604c6
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
+// SPDX-FileCopyrightText: 2022 Linaro Ltd.
+// SPDX-FileCopyrightTest: 2022 Viresh Kumar <[email protected]>
+//
+// Simplified Rust implementation of gpiodetect tool.
+
+use std::env;
+use std::path::Path;
+
+use libgpiod::{self, Error, Result};
+
+fn main() -> Result<()> {
+    let args: Vec<String> = env::args().collect();
+    if args.len() > 1 {
+        println!("Usage: {}", args[0]);
+        return Err(Error::InvalidArguments);
+    }
+
+    for chip in libgpiod::gpiochip_devices(&Path::new("/dev"))? {
+        let info = chip.info()?;
+        println!(
+            "{} [{}] ({})",
+            info.name()?,
+            info.label()?,
+            info.num_lines(),
+        );
+    }
+
+    Ok(())
+}
bindings/rust/libgpiod/examples/gpiofind.rs new file +36 -0
new file mode 100644
index 000000000000..99fba30c1a3c
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
+// SPDX-FileCopyrightText: 2022 Linaro Ltd.
+// SPDX-FileCopyrightTest: 2022 Viresh Kumar <[email protected]>
+//
+// Simplified Rust implementation of gpiofind tool.
+
+use std::env;
+use std::path::Path;
+
+use libgpiod::{self, Error, Result};
+
+fn main() -> Result<()> {
+    let args: Vec<String> = env::args().collect();
+    if args.len() != 2 {
+        println!("Usage: {} <line-name>", args[0]);
+        return Err(Error::InvalidArguments);
+    }
+
+    for chip in libgpiod::gpiochip_devices(&Path::new("/dev"))? {
+        let offset = chip.line_offset_from_name(&args[1]);
+        let info = chip.info()?;
+
+        if offset.is_ok() {
+            println!(
+                "Line {} found: Chip: {}, offset: {}",
+                args[1],
+                info.name()?,
+                offset?
+            );
+            return Ok(());
+        }
+    }
+
+    println!("Failed to find line: {}", args[1]);
+    Ok(())
+}
bindings/rust/libgpiod/examples/gpioget.rs new file +45 -0

45 lines not on this page · raw message

bindings/rust/libgpiod/examples/gpioinfo.rs new file +97 -0

97 lines not on this page · raw message

bindings/rust/libgpiod/examples/gpiomon.rs new file +74 -0

74 lines not on this page · raw message

bindings/rust/libgpiod/examples/gpioset.rs new file +63 -0

63 lines not on this page · raw message

bindings/rust/libgpiod/examples/gpiowatch.rs new file +53 -0

53 lines not on this page · raw message

Signature · 1 line
2.31.1.272.g89b43f80a514
#11 lore raw

PATCH v10 5/6 bindings: rust: Add tests for libgpiod crate

In reply to Viresh Kumar

Add tests for the rust bindings, quite similar to the ones in cxx bindings.

---
 bindings/rust/libgpiod/Cargo.toml             |   3 +
 bindings/rust/libgpiod/tests/chip.rs          |  97 ++++
 bindings/rust/libgpiod/tests/common/config.rs | 142 +++++
 bindings/rust/libgpiod/tests/common/mod.rs    |   9 +
 bindings/rust/libgpiod/tests/edge_event.rs    | 297 ++++++++++
 bindings/rust/libgpiod/tests/info_event.rs    | 166 ++++++
 bindings/rust/libgpiod/tests/line_config.rs   |  95 ++++
 bindings/rust/libgpiod/tests/line_info.rs     | 275 ++++++++++
 bindings/rust/libgpiod/tests/line_request.rs  | 509 ++++++++++++++++++
 bindings/rust/libgpiod/tests/line_settings.rs | 203 +++++++
 .../rust/libgpiod/tests/request_config.rs     |  38 ++
 11 files changed, 1834 insertions(+)
 create mode 100644 bindings/rust/libgpiod/tests/chip.rs
 create mode 100644 bindings/rust/libgpiod/tests/common/config.rs
 create mode 100644 bindings/rust/libgpiod/tests/common/mod.rs
 create mode 100644 bindings/rust/libgpiod/tests/edge_event.rs
 create mode 100644 bindings/rust/libgpiod/tests/info_event.rs
 create mode 100644 bindings/rust/libgpiod/tests/line_config.rs
 create mode 100644 bindings/rust/libgpiod/tests/line_info.rs
 create mode 100644 bindings/rust/libgpiod/tests/line_request.rs
 create mode 100644 bindings/rust/libgpiod/tests/line_settings.rs
 create mode 100644 bindings/rust/libgpiod/tests/request_config.rs
bindings/rust/libgpiod/Cargo.toml +3 -0
index a38df1c0b10d..655e7a2ce107 100644
@@ -20,3 +20,6 @@ intmap = "2.0.0"
 libc = "0.2.39"
 libgpiod-sys = { path = "../libgpiod-sys" }
 thiserror = "1.0"
+
+[dev-dependencies]
+gpiosim-sys = { path = "../gpiosim-sys" }
bindings/rust/libgpiod/tests/chip.rs new file +97 -0

97 lines not on this page · raw message

bindings/rust/libgpiod/tests/common/config.rs new file +142 -0

142 lines not on this page · raw message

bindings/rust/libgpiod/tests/common/mod.rs new file +9 -0
new file mode 100644
index 000000000000..5f725c61f905
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
+// SPDX-FileCopyrightText: 2022 Linaro Ltd.
+// SPDX-FileCopyrightTest: 2022 Viresh Kumar <[email protected]>
+
+#[allow(dead_code)]
+mod config;
+
+#[allow(unused_imports)]
+pub(crate) use config::*;
bindings/rust/libgpiod/tests/edge_event.rs new file +297 -0

297 lines not on this page · raw message

bindings/rust/libgpiod/tests/info_event.rs new file +166 -0

166 lines not on this page · raw message

bindings/rust/libgpiod/tests/line_config.rs new file +95 -0

95 lines not on this page · raw message

bindings/rust/libgpiod/tests/line_info.rs new file +275 -0

275 lines not on this page · raw message

bindings/rust/libgpiod/tests/line_request.rs new file +509 -0

509 lines not on this page · raw message

bindings/rust/libgpiod/tests/line_settings.rs new file +203 -0

203 lines not on this page · raw message

bindings/rust/libgpiod/tests/request_config.rs new file +38 -0
new file mode 100644
index 000000000000..8c676384b7c3
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
+// SPDX-FileCopyrightText: 2022 Linaro Ltd.
+// SPDX-FileCopyrightTest: 2022 Viresh Kumar <[email protected]>
+
+mod common;
+
+mod request_config {
+    use libgpiod::{request, Error as ChipError, OperationType};
+
+    mod verify {
+        use super::*;
+
+        #[test]
+        fn default() {
+            let rconfig = request::Config::new().unwrap();
+
+            assert_eq!(rconfig.event_buffer_size(), 0);
+            assert_eq!(
+                rconfig.consumer().unwrap_err(),
+                ChipError::OperationFailed(
+                    OperationType::RequestConfigGetConsumer,
+                    errno::Errno(0),
+                )
+            );
+        }
+
+        #[test]
+        fn initialized() {
+            const CONSUMER: &str = "foobar";
+            let rconfig = request::Config::new().unwrap();
+            rconfig.set_consumer(CONSUMER).unwrap();
+            rconfig.set_event_buffer_size(64);
+
+            assert_eq!(rconfig.event_buffer_size(), 64);
+            assert_eq!(rconfig.consumer().unwrap(), CONSUMER);
+        }
+    }
+}
Signature · 1 line
2.31.1.272.g89b43f80a514
#12 lore raw

PATCH v10 6/6 bindings: rust: Integrate building of bindings with make

In reply to Viresh Kumar

Lets make build rust bindings as well.

---
 README                    |  8 +++++---
 TODO                      |  8 --------
 bindings/Makefile.am      |  6 ++++++
 bindings/rust/Makefile.am | 19 +++++++++++++++++++
 configure.ac              | 16 ++++++++++++++++
 5 files changed, 46 insertions(+), 11 deletions(-)
 create mode 100644 bindings/rust/Makefile.am
README +5 -3
index 814a0f161fd2..68b5d69f9b66 100644
@@ -119,9 +119,9 @@ TOOLS
 BINDINGS
 --------
 
-High-level, object-oriented bindings for C++ and python3 are provided. They
-can be enabled by passing --enable-bindings-cxx and --enable-bindings-python
-arguments respectively to configure.
+High-level, object-oriented bindings for C++, python3 and Rust are provided.
+They can be enabled by passing --enable-bindings-cxx, --enable-bindings-python
+and --enable-bindings-rust arguments respectively to configure.
 
 C++ bindings require C++11 support and autoconf-archive collection if building
 from git.
@@ -132,6 +132,8 @@ the PYTHON_CPPFLAGS and PYTHON_LIBS variables in order to point the build
 system to the correct locations. During native builds, the configure script
 can auto-detect the location of the development files.
 
+Rust bindings require cargo support.
+
 TESTING
 -------
 
TODO +0 -8
index 8bb4d8f3ad56..cf4fd7b4a962 100644
@@ -28,14 +28,6 @@ and is partially functional.
 
 ----------
 
-* implement rust bindings
-
-With Rust gaining popularity as a low-level system's language and the
-possibility of it making its way into the linux kernel, it's probably time to
-provide Rust bindings to libgpiod as part of the project.
-
-----------
-
 * implement a simple daemon for controlling GPIOs in C together with a client
   program
 
bindings/Makefile.am +6 -0
index 8f8c762f254f..004ae23dbc58 100644
@@ -14,3 +14,9 @@ if WITH_BINDINGS_PYTHON
 SUBDIRS += python
 
 endif
+
+if WITH_BINDINGS_RUST
+
+SUBDIRS += rust
+
+endif
bindings/rust/Makefile.am new file +19 -0
new file mode 100644
index 000000000000..a0d0772b01cb
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2022 Linaro Ltd.
+# SPDX-FileCopyrightTest: 2022 Viresh Kumar <[email protected]>
+
+command = cargo build --release --lib
+
+if WITH_TESTS
+command += --tests
+endif
+
+if WITH_EXAMPLES
+command += --examples
+endif
+
+all:
+	$(command)
+
+clean:
+	cargo clean
configure.ac +16 -0
index 048b2ac7af8f..4a2cdb68b8b0 100644
@@ -212,6 +212,21 @@ then
 		[AC_SUBST(PYTHON_LIBS, [`$PYTHON-config --libs`])])
 fi
 
+AC_ARG_ENABLE([bindings-rust],
+	[AS_HELP_STRING([--enable-bindings-rust],[enable rust bindings [default=no]])],
+	[if test "x$enableval" = xyes; then with_bindings_rust=true; fi],
+	[with_bindings_rust=false])
+AM_CONDITIONAL([WITH_BINDINGS_RUST], [test "x$with_bindings_rust" = xtrue])
+
+if test "x$with_bindings_rust" = xtrue
+then
+	AC_CHECK_PROG([has_cargo], [cargo], [true], [false])
+	if test "x$has_cargo" = xfalse
+	then
+		AC_MSG_ERROR([cargo not found - needed for rust bindings])
+	fi
+fi
+
 AC_CHECK_PROG([has_doxygen], [doxygen], [true], [false])
 AM_CONDITIONAL([HAS_DOXYGEN], [test "x$has_doxygen" = xtrue])
 if test "x$has_doxygen" = xfalse
@@ -249,6 +264,7 @@ AC_CONFIG_FILES([Makefile
 		 bindings/python/examples/Makefile
 		 bindings/python/tests/Makefile
 		 bindings/python/tests/gpiosim/Makefile
+		 bindings/rust/Makefile
 		 man/Makefile])
 
 AC_OUTPUT
Signature · 1 line
2.31.1.272.g89b43f80a514
#14 lore raw
Quoted 11 lines · Linus Walleij
Quoted 1 line · Viresh Kumar

Here is another version of the rust bindings, based of the master branch.

This stuff is great for the GPIO and Rust communities. Also, looks finished. Here is a cheerful:

Yours,
Linus Walleij

Agreed. Series applied. Great work and thank you Viresh for the perseverance!

Bart

#15 lore raw
Quoted 4 lines · Bartosz Golaszewski
Quoted 3 lines · Linus Walleij

This stuff is great for the GPIO and Rust communities. Also, looks finished. Here is a cheerful:

Thanks Linus.

Quoted 1 line

Agreed. Series applied. Great work and thank you Viresh for the perseverance!

Thanks Bartosz.

Just for fun, I went back to see when I started doing this work. I shared my work with everyone for the first time on 31 Aug 2021. Almost 15 months :)

A special thanks to Miguel and Kent, who were very kind to allocate time to provide reviews for this work.

Signature · 1 line
viresh