diff mbox series

[V4,5/8] libgpiod: Add rust examples

Message ID acd12e70cfb30f04761f3c2efc868ec138c90c63.1657279685.git.viresh.kumar@linaro.org
State New
Headers show
Series libgpiod: Add Rust bindings | expand

Commit Message

Viresh Kumar July 8, 2022, 11:34 a.m. UTC
Add examples for the usage of the rust bindings, quite similar to the
ones in cxx bindings.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 bindings/rust/examples/gpiodetect.rs | 37 ++++++++++++
 bindings/rust/examples/gpiofind.rs   | 42 +++++++++++++
 bindings/rust/examples/gpioget.rs    | 42 +++++++++++++
 bindings/rust/examples/gpioinfo.rs   | 89 ++++++++++++++++++++++++++++
 bindings/rust/examples/gpiomon.rs    | 68 +++++++++++++++++++++
 bindings/rust/examples/gpioset.rs    | 52 ++++++++++++++++
 6 files changed, 330 insertions(+)
 create mode 100644 bindings/rust/examples/gpiodetect.rs
 create mode 100644 bindings/rust/examples/gpiofind.rs
 create mode 100644 bindings/rust/examples/gpioget.rs
 create mode 100644 bindings/rust/examples/gpioinfo.rs
 create mode 100644 bindings/rust/examples/gpiomon.rs
 create mode 100644 bindings/rust/examples/gpioset.rs

Comments

Kent Gibson July 27, 2022, 2:58 a.m. UTC | #1
On Fri, Jul 08, 2022 at 05:04:58PM +0530, Viresh Kumar wrote:
> Add examples for the usage of the rust bindings, quite similar to the
> ones in cxx bindings.
> 
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
> ---
>  bindings/rust/examples/gpiodetect.rs | 37 ++++++++++++
>  bindings/rust/examples/gpiofind.rs   | 42 +++++++++++++
>  bindings/rust/examples/gpioget.rs    | 42 +++++++++++++
>  bindings/rust/examples/gpioinfo.rs   | 89 ++++++++++++++++++++++++++++
>  bindings/rust/examples/gpiomon.rs    | 68 +++++++++++++++++++++
>  bindings/rust/examples/gpioset.rs    | 52 ++++++++++++++++
>  6 files changed, 330 insertions(+)
>  create mode 100644 bindings/rust/examples/gpiodetect.rs
>  create mode 100644 bindings/rust/examples/gpiofind.rs
>  create mode 100644 bindings/rust/examples/gpioget.rs
>  create mode 100644 bindings/rust/examples/gpioinfo.rs
>  create mode 100644 bindings/rust/examples/gpiomon.rs
>  create mode 100644 bindings/rust/examples/gpioset.rs
> 
> diff --git a/bindings/rust/examples/gpiodetect.rs b/bindings/rust/examples/gpiodetect.rs
> new file mode 100644
> index 000000000000..82307e4eecea
> --- /dev/null
> +++ b/bindings/rust/examples/gpiodetect.rs
> @@ -0,0 +1,37 @@
> +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
> +//
> +// Copyright 2022 Linaro Ltd. All Rights Reserved.
> +//     Viresh Kumar <viresh.kumar@linaro.org>
> +//
> +// Simplified Rust implementation of gpiodetect tool.
> +
> +use std::env;
> +use std::fs;
> +use std::path::Path;
> +
> +use libgpiod::{gpiod_is_gpiochip_device, Chip};
> +
> +fn main() {
> +    let args: Vec<String> = env::args().collect();
> +    if args.len() > 1 {
> +        println!("Usage: {}", args[0]);
> +        return;
> +    }
> +
> +    for entry in fs::read_dir(Path::new("/dev")).unwrap() {

use .flatten() to have the iterator unwrap the entry so it is actually
an entry, not a Result.

> +        let pathbuf = entry.unwrap().path();
> +        let path = pathbuf.to_str().unwrap();
> +

is_gpiochip_device() and Chip::open() (and ChipInternal) should accept
anything that can be converted into a &Path, e.g. a PathBuf, so the path
variable becomes redundant.

e.g. 
    pub(crate) fn open<P: AsRef<std::path::Path>>(path: &P) -> Result<Self> {
        // Null-terminate the string
        let path = path.as_ref().to_string_lossy() + "\0";
        ...

and then example code becomes:

    for entry in fs::read_dir(Path::new("/dev")).unwrap().flatten() {
        let path = entry.path();

        if gpiod_is_gpiochip_device(&path) {
            let chip = Chip::open(&path).unwrap();
            ...

(renaming pathbuf to path)

Similarly other examples.

> +        if gpiod_is_gpiochip_device(path) {
> +            let chip = Chip::open(path).unwrap();
> +            let ngpio = chip.get_num_lines();
> +

Why does ngpio get a variable, unlike name and label?

> +            println!(
> +                "{} [{}] ({})",
> +                chip.get_name().unwrap(),
> +                chip.get_label().unwrap(),
> +                ngpio
> +            );
> +        }
> +    }
> +}

Avoid using unwrap().  Have main return a Result and use ?.
Not so important here, but below for helper functions returning
Results allows the caller to determine how to handle the error.
And it reads better.

> diff --git a/bindings/rust/examples/gpiofind.rs b/bindings/rust/examples/gpiofind.rs
> new file mode 100644
> index 000000000000..bbbd7a87ece8
> --- /dev/null
> +++ b/bindings/rust/examples/gpiofind.rs
> @@ -0,0 +1,42 @@
> +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
> +//
> +// Copyright 2022 Linaro Ltd. All Rights Reserved.
> +//     Viresh Kumar <viresh.kumar@linaro.org>
> +//
> +// Simplified Rust implementation of gpiofind tool.
> +
> +use std::env;
> +use std::fs;
> +use std::path::Path;
> +
> +use libgpiod::{gpiod_is_gpiochip_device, Chip};
> +
> +fn main() {
> +    let args: Vec<String> = env::args().collect();
> +    if args.len() != 2 {
> +        println!("Usage: {} <line-name>", args[0]);
> +        return;
> +    }
> +
> +    for entry in fs::read_dir(Path::new("/dev")).unwrap() {
> +        let pathbuf = entry.unwrap().path();
> +        let path = pathbuf.to_str().unwrap();
> +
> +        if gpiod_is_gpiochip_device(path) {

Perhaps have the bindings provide an iterator that returns the paths of
available gpiochips?

> +            let chip = Chip::open(path).unwrap();
> +
> +            let offset = chip.find_line(&args[1]);
> +            if offset.is_ok() {
> +                println!(
> +                    "Line {} found: Chip: {}, offset: {}",
> +                    args[1],
> +                    chip.get_name().unwrap(),
> +                    offset.unwrap()
> +                );
> +                return;
> +            }
> +        }
> +    }
> +
> +    println!("Failed to find line: {}", args[1]);
> +}
> diff --git a/bindings/rust/examples/gpioget.rs b/bindings/rust/examples/gpioget.rs
> new file mode 100644
> index 000000000000..c3bc35fcfdb6
> --- /dev/null
> +++ b/bindings/rust/examples/gpioget.rs
> @@ -0,0 +1,42 @@
> +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
> +//
> +// Copyright 2022 Linaro Ltd. All Rights Reserved.
> +//     Viresh Kumar <viresh.kumar@linaro.org>
> +//
> +// Simplified Rust implementation of gpioget tool.
> +
> +use std::env;
> +
> +use libgpiod::{Chip, Direction, LineConfig, RequestConfig};
> +
> +fn main() {
> +    let args: Vec<String> = env::args().collect();
> +    if args.len() < 3 {
> +        println!("Usage: {} <chip> <line_offset0> ...", args[0]);
> +        return;
> +    }
> +
> +    let mut config = LineConfig::new().unwrap();
> +    let mut offsets = Vec::<u32>::new();
> +
> +    for arg in &args[2..] {
> +        let offset = arg.parse::<u32>().unwrap();
> +
> +        offsets.push(offset);
> +        config.set_direction_override(Direction::Input, offset);
> +    }
> +
> +    let path = format!("/dev/gpiochip{}", args[1]);
> +    let chip = Chip::open(&path).unwrap();
> +
> +    let rconfig = RequestConfig::new().unwrap();
> +    rconfig.set_consumer(&args[0]);
> +    rconfig.set_offsets(&offsets);
> +
> +    let request = chip.request_lines(&rconfig, &config).unwrap();
> +
> +    let mut values: Vec<i32> = vec![0; offsets.len()];
> +    request.get_values(&mut values).unwrap();
> +
> +    println!("{:?}", values);
> +}
> diff --git a/bindings/rust/examples/gpioinfo.rs b/bindings/rust/examples/gpioinfo.rs
> new file mode 100644
> index 000000000000..bd30d9096ce8
> --- /dev/null
> +++ b/bindings/rust/examples/gpioinfo.rs
> @@ -0,0 +1,89 @@
> +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
> +//
> +// Copyright 2022 Linaro Ltd. All Rights Reserved.
> +//     Viresh Kumar <viresh.kumar@linaro.org>
> +//
> +// Simplified Rust implementation of gpioinfo tool.
> +
> +use std::env;
> +use std::fs;
> +use std::path::Path;
> +
> +use libgpiod::{gpiod_is_gpiochip_device, Chip, Direction};
> +
> +fn line_info(chip: &Chip, offset: u32) {
> +    let info = chip.line_info(offset).unwrap();
> +    let off = info.get_offset();
> +
> +    let name = match info.get_name() {
> +        Ok(name) => name,
> +        _ => "unused",
> +    };
> +
> +    let consumer = match info.get_consumer() {
> +        Ok(name) => name,
> +        _ => "unnamed",
> +    };
> +
> +    let low = if info.is_active_low() {
> +        "active-low"
> +    } else {
> +        "active-high"
> +    };
> +
> +    let dir = match info.get_direction().unwrap() {
> +        Direction::AsIs => "None",
> +        Direction::Input => "Input",
> +        Direction::Output => "Output",
> +    };
> +
> +    println!(
> +        "\tline {:>3}\
> +              \t{:>10}\
> +              \t{:>10}\
> +              \t{:>6}\
> +              \t{:>14}",
> +        off, name, consumer, dir, low
> +    );
> +}
> +
> +fn chip_info(path: &str) {
> +    if gpiod_is_gpiochip_device(path) {
> +        let chip = Chip::open(path).unwrap();
> +        let ngpio = chip.get_num_lines();
> +
> +        println!("GPIO Chip name: {}", chip.get_name().unwrap());
> +        println!("\tlabel: {}", chip.get_label().unwrap());
> +        println!("\tpath: {}", chip.get_path().unwrap());
> +        println!("\tngpio: {}\n", ngpio);
> +
> +        println!("\tLine information:");
> +
> +        for offset in 0..ngpio {
> +            line_info(&chip, offset);
> +        }
> +        println!("\n");
> +    }
> +}
> +
> +fn main() {
> +    let args: Vec<String> = env::args().collect();
> +    if args.len() > 2 {
> +        println!("Usage: {}", args[0]);
> +        return;
> +    }
> +
> +    if args.len() == 1 {
> +        for entry in fs::read_dir(Path::new("/dev")).unwrap() {
> +            let pathbuf = entry.unwrap().path();
> +            let path = pathbuf.to_str().unwrap();
> +
> +            chip_info(path);
> +        }
> +    } else {
> +        let index = args[1].parse::<u32>().unwrap();
> +        let path = format!("/dev/gpiochip{}", index);
> +
> +        chip_info(&path);
> +    }
> +}
> diff --git a/bindings/rust/examples/gpiomon.rs b/bindings/rust/examples/gpiomon.rs
> new file mode 100644
> index 000000000000..872907b386f3
> --- /dev/null
> +++ b/bindings/rust/examples/gpiomon.rs
> @@ -0,0 +1,68 @@
> +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
> +//
> +// Copyright 2022 Linaro Ltd. All Rights Reserved.
> +//     Viresh Kumar <viresh.kumar@linaro.org>
> +//
> +// Simplified Rust implementation of the gpiomon tool.
> +
> +use std::env;
> +use std::time::Duration;
> +
> +use libgpiod::{Chip, Edge, EdgeEventBuffer, Error, LineConfig, LineEdgeEvent, RequestConfig};
> +
> +fn usage(name: &str) {
> +    println!("Usage: {} <chip> <offset0> ...", name);
> +}
> +
> +fn main() {
> +    let args: Vec<String> = env::args().collect();
> +    if args.len() < 3 {
> +        usage(&args[0]);
> +        return;
> +    }
> +
> +    let mut config = LineConfig::new().unwrap();
> +    let mut offsets = Vec::<u32>::new();
> +
> +    for arg in &args[2..] {
> +        let offset = arg.parse::<u32>().unwrap();
> +
> +        offsets.push(offset);
> +    }
> +
> +    config.set_edge_detection_default(Edge::Both);
> +
> +    let path = format!("/dev/gpiochip{}", args[1]);
> +    let chip = Chip::open(&path).unwrap();
> +
> +    let rconfig = RequestConfig::new().unwrap();
> +    rconfig.set_offsets(&offsets);
> +
> +    let buffer = EdgeEventBuffer::new(1).unwrap();
> +    let request = chip.request_lines(&rconfig, &config).unwrap();
> +
> +    loop {
> +        match request.wait_edge_event(Duration::new(1, 0)) {
> +            Err(Error::OperationTimedOut) => continue,

timeout/continue required as you can't (currently) block indefinitely?

> +            Err(x) => {
> +                println!("{:?}", x);
> +                return;
> +            }
> +            Ok(()) => (),
> +        }
> +
> +        let count = request.read_edge_event(&buffer, 1).unwrap();
> +        if count == 1 {
> +            let event = buffer.get_event(0).unwrap();
> +            println!(
> +                "line: {} type: {}, time: {:?}",
> +                event.get_line_offset(),
> +                match event.get_event_type().unwrap() {
> +                    LineEdgeEvent::Rising => "Rising",
> +                    LineEdgeEvent::Falling => "Falling",
> +                },
> +                event.get_timestamp()
> +            );
> +        }
> +    }
> +}
> diff --git a/bindings/rust/examples/gpioset.rs b/bindings/rust/examples/gpioset.rs
> new file mode 100644
> index 000000000000..ef70e8edbaae
> --- /dev/null
> +++ b/bindings/rust/examples/gpioset.rs
> @@ -0,0 +1,52 @@
> +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
> +//
> +// Copyright 2022 Linaro Ltd. All Rights Reserved.
> +//     Viresh Kumar <viresh.kumar@linaro.org>
> +//
> +// Simplified Rust implementation of the gpioset tool.
> +
> +use std::env;
> +
> +use libgpiod::{Chip, Direction, LineConfig, RequestConfig};
> +
> +fn usage(name: &str) {
> +    println!("Usage: {} <chip> <line_offset0>=<value0> ...", name);
> +}
> +
> +fn main() {
> +    let args: Vec<String> = env::args().collect();
> +    if args.len() < 3 {
> +        usage(&args[0]);
> +        return;
> +    }
> +
> +    let mut config = LineConfig::new().unwrap();
> +    let mut offsets = Vec::<u32>::new();
> +    let mut values = Vec::<i32>::new();
> +
> +    for arg in &args[2..] {
> +        let pair: Vec<&str> = arg.split('=').collect();
> +        if pair.len() != 2 {
> +            usage(&args[0]);
> +            return;
> +        }
> +
> +        let offset = pair[0].parse::<u32>().unwrap();
> +        let value = pair[1].parse::<u32>().unwrap();
> +
> +        offsets.push(offset);
> +        values.push(value as i32);
> +    }
> +
> +    config.set_direction_default(Direction::Output);
> +    config.set_output_values(&offsets, &values).unwrap();
> +
> +    let path = format!("/dev/gpiochip{}", args[1]);
> +    let chip = Chip::open(&path).unwrap();
> +
> +    let rconfig = RequestConfig::new().unwrap();
> +    rconfig.set_consumer(&args[0]);
> +    rconfig.set_offsets(&offsets);
> +
> +    chip.request_lines(&rconfig, &config).unwrap();

Wait rather than exiting immediately?

> +}
> -- 
> 2.31.1.272.g89b43f80a514
> 

And, as mentioned elsewhere, add a gpiowatch example.

Cheers,
Kent.
Viresh Kumar July 27, 2022, 9:23 a.m. UTC | #2
On 27-07-22, 10:58, Kent Gibson wrote:
> On Fri, Jul 08, 2022 at 05:04:58PM +0530, Viresh Kumar wrote:
> > diff --git a/bindings/rust/examples/gpioset.rs b/bindings/rust/examples/gpioset.rs
> > +    let rconfig = RequestConfig::new().unwrap();
> > +    rconfig.set_consumer(&args[0]);
> > +    rconfig.set_offsets(&offsets);
> > +
> > +    chip.request_lines(&rconfig, &config).unwrap();
> 
> Wait rather than exiting immediately?

Wait for what exactly ?

> And, as mentioned elsewhere, add a gpiowatch example.

Will do, sure. Any existing example of the same will help though.
Kent Gibson July 27, 2022, 9:59 a.m. UTC | #3
On Wed, Jul 27, 2022 at 02:53:19PM +0530, Viresh Kumar wrote:
> On 27-07-22, 10:58, Kent Gibson wrote:
> > On Fri, Jul 08, 2022 at 05:04:58PM +0530, Viresh Kumar wrote:
> > > diff --git a/bindings/rust/examples/gpioset.rs b/bindings/rust/examples/gpioset.rs
> > > +    let rconfig = RequestConfig::new().unwrap();
> > > +    rconfig.set_consumer(&args[0]);
> > > +    rconfig.set_offsets(&offsets);
> > > +
> > > +    chip.request_lines(&rconfig, &config).unwrap();
> > 
> > Wait rather than exiting immediately?
> 
> Wait for what exactly ?
> 

For long enough for the user to check that the line is set, as there is
the possibility that when the line is released it will be set back to
its default value and you will get users reporting that your set
doesn't work ;-).

So wait for a keypress?

> > And, as mentioned elsewhere, add a gpiowatch example.
> 
> Will do, sure. Any existing example of the same will help though.
> 

There is an example in my proposed tool changes for v2[1].
It is very similar to gpiomon, just on the chip and with line info
instead of edge events.

Though that example is more complicated than you need as it supports
named lines and operating over multiple chips.
Hopefully you can see past that.
The basic operation is watch the line, then wait for the chip fd to be
readable and read the info changed event from it.

You would only unwatch if you no longer had an interest in the line,
which I expect will be the case in the D-BUS daemon that Bart has
suggested.

Cheers,
Kent.

[1]https://lore.kernel.org/linux-gpio/20220708120626.89844-5-warthog618@gmail.com/
Viresh Kumar July 27, 2022, 10:06 a.m. UTC | #4
On 27-07-22, 17:59, Kent Gibson wrote:
> For long enough for the user to check that the line is set, as there is
> the possibility that when the line is released it will be set back to
> its default value and you will get users reporting that your set
> doesn't work ;-).
> 
> So wait for a keypress?

I thought we wanted to avoid human-intervention to the tests :)

Can't we just read the values of the lines again here somehow and match ? I
don't expect/want the user to do this for running the test. Not to mention, the
user may eventually be a bot running the tests for each commit added to the
tree.
Kent Gibson July 27, 2022, 10:32 a.m. UTC | #5
On Wed, Jul 27, 2022 at 03:36:33PM +0530, Viresh Kumar wrote:
> On 27-07-22, 17:59, Kent Gibson wrote:
> > For long enough for the user to check that the line is set, as there is
> > the possibility that when the line is released it will be set back to
> > its default value and you will get users reporting that your set
> > doesn't work ;-).
> > 
> > So wait for a keypress?
> 
> I thought we wanted to avoid human-intervention to the tests :)
> 

This is for an example gpioset, right?
You have tests for your examples?

And even then you could either inject a keypress or just kill the
process. (e.g. the tests for the proposed tool changes do that)

Cheers,
Kent.

> Can't we just read the values of the lines again here somehow and match ? I
> don't expect/want the user to do this for running the test. Not to mention, the
> user may eventually be a bot running the tests for each commit added to the
> tree.
>
Viresh Kumar July 27, 2022, 10:33 a.m. UTC | #6
On 27-07-22, 18:32, Kent Gibson wrote:
> This is for an example gpioset, right?

Damn, got confused :(
diff mbox series

Patch

diff --git a/bindings/rust/examples/gpiodetect.rs b/bindings/rust/examples/gpiodetect.rs
new file mode 100644
index 000000000000..82307e4eecea
--- /dev/null
+++ b/bindings/rust/examples/gpiodetect.rs
@@ -0,0 +1,37 @@ 
+// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
+//
+// Copyright 2022 Linaro Ltd. All Rights Reserved.
+//     Viresh Kumar <viresh.kumar@linaro.org>
+//
+// Simplified Rust implementation of gpiodetect tool.
+
+use std::env;
+use std::fs;
+use std::path::Path;
+
+use libgpiod::{gpiod_is_gpiochip_device, Chip};
+
+fn main() {
+    let args: Vec<String> = env::args().collect();
+    if args.len() > 1 {
+        println!("Usage: {}", args[0]);
+        return;
+    }
+
+    for entry in fs::read_dir(Path::new("/dev")).unwrap() {
+        let pathbuf = entry.unwrap().path();
+        let path = pathbuf.to_str().unwrap();
+
+        if gpiod_is_gpiochip_device(path) {
+            let chip = Chip::open(path).unwrap();
+            let ngpio = chip.get_num_lines();
+
+            println!(
+                "{} [{}] ({})",
+                chip.get_name().unwrap(),
+                chip.get_label().unwrap(),
+                ngpio
+            );
+        }
+    }
+}
diff --git a/bindings/rust/examples/gpiofind.rs b/bindings/rust/examples/gpiofind.rs
new file mode 100644
index 000000000000..bbbd7a87ece8
--- /dev/null
+++ b/bindings/rust/examples/gpiofind.rs
@@ -0,0 +1,42 @@ 
+// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
+//
+// Copyright 2022 Linaro Ltd. All Rights Reserved.
+//     Viresh Kumar <viresh.kumar@linaro.org>
+//
+// Simplified Rust implementation of gpiofind tool.
+
+use std::env;
+use std::fs;
+use std::path::Path;
+
+use libgpiod::{gpiod_is_gpiochip_device, Chip};
+
+fn main() {
+    let args: Vec<String> = env::args().collect();
+    if args.len() != 2 {
+        println!("Usage: {} <line-name>", args[0]);
+        return;
+    }
+
+    for entry in fs::read_dir(Path::new("/dev")).unwrap() {
+        let pathbuf = entry.unwrap().path();
+        let path = pathbuf.to_str().unwrap();
+
+        if gpiod_is_gpiochip_device(path) {
+            let chip = Chip::open(path).unwrap();
+
+            let offset = chip.find_line(&args[1]);
+            if offset.is_ok() {
+                println!(
+                    "Line {} found: Chip: {}, offset: {}",
+                    args[1],
+                    chip.get_name().unwrap(),
+                    offset.unwrap()
+                );
+                return;
+            }
+        }
+    }
+
+    println!("Failed to find line: {}", args[1]);
+}
diff --git a/bindings/rust/examples/gpioget.rs b/bindings/rust/examples/gpioget.rs
new file mode 100644
index 000000000000..c3bc35fcfdb6
--- /dev/null
+++ b/bindings/rust/examples/gpioget.rs
@@ -0,0 +1,42 @@ 
+// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
+//
+// Copyright 2022 Linaro Ltd. All Rights Reserved.
+//     Viresh Kumar <viresh.kumar@linaro.org>
+//
+// Simplified Rust implementation of gpioget tool.
+
+use std::env;
+
+use libgpiod::{Chip, Direction, LineConfig, RequestConfig};
+
+fn main() {
+    let args: Vec<String> = env::args().collect();
+    if args.len() < 3 {
+        println!("Usage: {} <chip> <line_offset0> ...", args[0]);
+        return;
+    }
+
+    let mut config = LineConfig::new().unwrap();
+    let mut offsets = Vec::<u32>::new();
+
+    for arg in &args[2..] {
+        let offset = arg.parse::<u32>().unwrap();
+
+        offsets.push(offset);
+        config.set_direction_override(Direction::Input, offset);
+    }
+
+    let path = format!("/dev/gpiochip{}", args[1]);
+    let chip = Chip::open(&path).unwrap();
+
+    let rconfig = RequestConfig::new().unwrap();
+    rconfig.set_consumer(&args[0]);
+    rconfig.set_offsets(&offsets);
+
+    let request = chip.request_lines(&rconfig, &config).unwrap();
+
+    let mut values: Vec<i32> = vec![0; offsets.len()];
+    request.get_values(&mut values).unwrap();
+
+    println!("{:?}", values);
+}
diff --git a/bindings/rust/examples/gpioinfo.rs b/bindings/rust/examples/gpioinfo.rs
new file mode 100644
index 000000000000..bd30d9096ce8
--- /dev/null
+++ b/bindings/rust/examples/gpioinfo.rs
@@ -0,0 +1,89 @@ 
+// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
+//
+// Copyright 2022 Linaro Ltd. All Rights Reserved.
+//     Viresh Kumar <viresh.kumar@linaro.org>
+//
+// Simplified Rust implementation of gpioinfo tool.
+
+use std::env;
+use std::fs;
+use std::path::Path;
+
+use libgpiod::{gpiod_is_gpiochip_device, Chip, Direction};
+
+fn line_info(chip: &Chip, offset: u32) {
+    let info = chip.line_info(offset).unwrap();
+    let off = info.get_offset();
+
+    let name = match info.get_name() {
+        Ok(name) => name,
+        _ => "unused",
+    };
+
+    let consumer = match info.get_consumer() {
+        Ok(name) => name,
+        _ => "unnamed",
+    };
+
+    let low = if info.is_active_low() {
+        "active-low"
+    } else {
+        "active-high"
+    };
+
+    let dir = match info.get_direction().unwrap() {
+        Direction::AsIs => "None",
+        Direction::Input => "Input",
+        Direction::Output => "Output",
+    };
+
+    println!(
+        "\tline {:>3}\
+              \t{:>10}\
+              \t{:>10}\
+              \t{:>6}\
+              \t{:>14}",
+        off, name, consumer, dir, low
+    );
+}
+
+fn chip_info(path: &str) {
+    if gpiod_is_gpiochip_device(path) {
+        let chip = Chip::open(path).unwrap();
+        let ngpio = chip.get_num_lines();
+
+        println!("GPIO Chip name: {}", chip.get_name().unwrap());
+        println!("\tlabel: {}", chip.get_label().unwrap());
+        println!("\tpath: {}", chip.get_path().unwrap());
+        println!("\tngpio: {}\n", ngpio);
+
+        println!("\tLine information:");
+
+        for offset in 0..ngpio {
+            line_info(&chip, offset);
+        }
+        println!("\n");
+    }
+}
+
+fn main() {
+    let args: Vec<String> = env::args().collect();
+    if args.len() > 2 {
+        println!("Usage: {}", args[0]);
+        return;
+    }
+
+    if args.len() == 1 {
+        for entry in fs::read_dir(Path::new("/dev")).unwrap() {
+            let pathbuf = entry.unwrap().path();
+            let path = pathbuf.to_str().unwrap();
+
+            chip_info(path);
+        }
+    } else {
+        let index = args[1].parse::<u32>().unwrap();
+        let path = format!("/dev/gpiochip{}", index);
+
+        chip_info(&path);
+    }
+}
diff --git a/bindings/rust/examples/gpiomon.rs b/bindings/rust/examples/gpiomon.rs
new file mode 100644
index 000000000000..872907b386f3
--- /dev/null
+++ b/bindings/rust/examples/gpiomon.rs
@@ -0,0 +1,68 @@ 
+// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
+//
+// Copyright 2022 Linaro Ltd. All Rights Reserved.
+//     Viresh Kumar <viresh.kumar@linaro.org>
+//
+// Simplified Rust implementation of the gpiomon tool.
+
+use std::env;
+use std::time::Duration;
+
+use libgpiod::{Chip, Edge, EdgeEventBuffer, Error, LineConfig, LineEdgeEvent, RequestConfig};
+
+fn usage(name: &str) {
+    println!("Usage: {} <chip> <offset0> ...", name);
+}
+
+fn main() {
+    let args: Vec<String> = env::args().collect();
+    if args.len() < 3 {
+        usage(&args[0]);
+        return;
+    }
+
+    let mut config = LineConfig::new().unwrap();
+    let mut offsets = Vec::<u32>::new();
+
+    for arg in &args[2..] {
+        let offset = arg.parse::<u32>().unwrap();
+
+        offsets.push(offset);
+    }
+
+    config.set_edge_detection_default(Edge::Both);
+
+    let path = format!("/dev/gpiochip{}", args[1]);
+    let chip = Chip::open(&path).unwrap();
+
+    let rconfig = RequestConfig::new().unwrap();
+    rconfig.set_offsets(&offsets);
+
+    let buffer = EdgeEventBuffer::new(1).unwrap();
+    let request = chip.request_lines(&rconfig, &config).unwrap();
+
+    loop {
+        match request.wait_edge_event(Duration::new(1, 0)) {
+            Err(Error::OperationTimedOut) => continue,
+            Err(x) => {
+                println!("{:?}", x);
+                return;
+            }
+            Ok(()) => (),
+        }
+
+        let count = request.read_edge_event(&buffer, 1).unwrap();
+        if count == 1 {
+            let event = buffer.get_event(0).unwrap();
+            println!(
+                "line: {} type: {}, time: {:?}",
+                event.get_line_offset(),
+                match event.get_event_type().unwrap() {
+                    LineEdgeEvent::Rising => "Rising",
+                    LineEdgeEvent::Falling => "Falling",
+                },
+                event.get_timestamp()
+            );
+        }
+    }
+}
diff --git a/bindings/rust/examples/gpioset.rs b/bindings/rust/examples/gpioset.rs
new file mode 100644
index 000000000000..ef70e8edbaae
--- /dev/null
+++ b/bindings/rust/examples/gpioset.rs
@@ -0,0 +1,52 @@ 
+// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
+//
+// Copyright 2022 Linaro Ltd. All Rights Reserved.
+//     Viresh Kumar <viresh.kumar@linaro.org>
+//
+// Simplified Rust implementation of the gpioset tool.
+
+use std::env;
+
+use libgpiod::{Chip, Direction, LineConfig, RequestConfig};
+
+fn usage(name: &str) {
+    println!("Usage: {} <chip> <line_offset0>=<value0> ...", name);
+}
+
+fn main() {
+    let args: Vec<String> = env::args().collect();
+    if args.len() < 3 {
+        usage(&args[0]);
+        return;
+    }
+
+    let mut config = LineConfig::new().unwrap();
+    let mut offsets = Vec::<u32>::new();
+    let mut values = Vec::<i32>::new();
+
+    for arg in &args[2..] {
+        let pair: Vec<&str> = arg.split('=').collect();
+        if pair.len() != 2 {
+            usage(&args[0]);
+            return;
+        }
+
+        let offset = pair[0].parse::<u32>().unwrap();
+        let value = pair[1].parse::<u32>().unwrap();
+
+        offsets.push(offset);
+        values.push(value as i32);
+    }
+
+    config.set_direction_default(Direction::Output);
+    config.set_output_values(&offsets, &values).unwrap();
+
+    let path = format!("/dev/gpiochip{}", args[1]);
+    let chip = Chip::open(&path).unwrap();
+
+    let rconfig = RequestConfig::new().unwrap();
+    rconfig.set_consumer(&args[0]);
+    rconfig.set_offsets(&offsets);
+
+    chip.request_lines(&rconfig, &config).unwrap();
+}