new file mode 100644
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
+//
+// Copyright 2022 Linaro Ltd. All Rights Reserved.
+// Viresh Kumar <viresh.kumar@linaro.org>
+//
+// 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 count = request.read_edge_events(&mut buffer)?;
+ if count == 1 {
+ let event = buffer.event(0)?;
+ let cloned_event = request::Event::event_clone(&event)?;
+
+ // This is required before reading events again into the buffer.
+ drop(event);
+
+ let count = request.read_edge_events(&mut buffer)?;
+ if count == 1 {
+ let event = buffer.event(0)?;
+ println!(
+ "line: {} type: {:?}, time: {:?}",
+ cloned_event.line_offset(),
+ cloned_event.event_type(),
+ cloned_event.timestamp()
+ );
+ println!(
+ "line: {} type: {:?}, time: {:?}",
+ event.line_offset(),
+ event.event_type(),
+ event.timestamp()
+ );
+ }
+ }
+ }
+}
new file mode 100644
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
+//
+// Copyright 2022 Linaro Ltd. All Rights Reserved.
+// Viresh Kumar <viresh.kumar@linaro.org>
+//
+// Simplified Rust implementation to show handling of info events, that are
+// generated from another thread.
+
+use std::{
+ env,
+ sync::{
+ mpsc::{self, Receiver, Sender},
+ Arc, Mutex,
+ },
+ thread,
+ time::Duration,
+};
+
+use libgpiod::{
+ chip::Chip,
+ line::{self, Direction, InfoChangeKind, Offset},
+ request, Error, Result,
+};
+
+fn usage(name: &str) {
+ println!("Usage: {} <chip> <offset>", name);
+}
+
+fn request_reconfigure_line(
+ chip: Arc<Mutex<Chip>>,
+ offset: Offset,
+ tx: Sender<()>,
+ rx: Receiver<()>,
+) {
+ thread::spawn(move || {
+ let 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
+ .lock()
+ .unwrap()
+ .request_lines(&rconfig, &lconfig)
+ .unwrap();
+
+ // Signal the parent to continue
+ tx.send(()).expect("Could not send signal on channel");
+
+ // Wait for parent to signal
+ rx.recv().expect("Could not receive from channel");
+
+ let 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();
+
+ request.reconfigure_lines(&lconfig).unwrap();
+
+ // Signal the parent to continue
+ tx.send(()).expect("Could not send signal on channel");
+
+ // Wait for parent to signal
+ rx.recv().expect("Could not receive from channel");
+ });
+}
+
+fn main() -> Result<()> {
+ let args: Vec<String> = env::args().collect();
+ if args.len() != 3 {
+ usage(&args[0]);
+ return Err(Error::InvalidArguments);
+ }
+
+ let path = format!("/dev/gpiochip{}", args[1]);
+ let offset = args[2]
+ .parse::<Offset>()
+ .map_err(|_| Error::InvalidArguments)?;
+
+ let chip = Arc::new(Mutex::new(Chip::open(&path)?));
+ chip.lock().unwrap().watch_line_info(offset)?;
+
+ // Thread synchronizing mechanism
+ let (tx_main, rx_thread) = mpsc::channel();
+ let (tx_thread, rx_main) = mpsc::channel();
+
+ // Generate events
+ request_reconfigure_line(chip.clone(), offset, tx_thread, rx_thread);
+
+ // Wait for thread to signal
+ rx_main.recv().expect("Could not receive from channel");
+
+ // Line requested event
+ assert!(chip
+ .lock()
+ .unwrap()
+ .wait_info_event(Some(Duration::from_secs(1)))?);
+ let event = chip.lock().unwrap().read_info_event()?;
+ assert_eq!(event.event_type()?, InfoChangeKind::LineRequested);
+
+ // Signal the thread to continue
+ tx_main.send(()).expect("Could not send signal on channel");
+
+ // Wait for thread to signal
+ rx_main.recv().expect("Could not receive from channel");
+
+ // Line changed event
+ assert!(chip
+ .lock()
+ .unwrap()
+ .wait_info_event(Some(Duration::from_millis(10)))?);
+ let event = chip.lock().unwrap().read_info_event()?;
+ assert_eq!(event.event_type()?, InfoChangeKind::LineConfigChanged);
+
+ // Signal the thread to continue
+ tx_main.send(()).expect("Could not send signal on channel");
+
+ // Line released event
+ assert!(chip
+ .lock()
+ .unwrap()
+ .wait_info_event(Some(Duration::from_millis(10)))?);
+ let event = chip.lock().unwrap().read_info_event()?;
+ assert_eq!(event.event_type().unwrap(), InfoChangeKind::LineReleased);
+
+ // No events available
+ assert!(!chip
+ .lock()
+ .unwrap()
+ .wait_info_event(Some(Duration::from_millis(100)))?);
+
+ Ok(())
+}
new file mode 100644
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: Apache-2.0 OR 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::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(())
+}
new file mode 100644
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: Apache-2.0 OR 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::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(())
+}
new file mode 100644
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: Apache-2.0 OR 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::Chip,
+ line::{self, Direction, Offset},
+ request, Error, Result,
+};
+
+fn main() -> Result<()> {
+ let args: Vec<String> = env::args().collect();
+ if args.len() < 3 {
+ println!("Usage: {} <chip> <line_offset0> ...", 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_direction(Direction::Input)?;
+ lconfig.add_line_settings(&offsets, lsettings)?;
+
+ let path = format!("/dev/gpiochip{}", args[1]);
+ let chip = Chip::open(&path)?;
+
+ let rconfig = request::Config::new()?;
+ rconfig.set_consumer(&args[0])?;
+
+ let request = chip.request_lines(&rconfig, &lconfig)?;
+ let map = request.values()?;
+
+ println!("{:?}", map);
+ Ok(())
+}
new file mode 100644
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: Apache-2.0 OR 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::path::Path;
+
+use libgpiod::{
+ chip::Chip,
+ line::{Direction, Offset},
+ Error, Result,
+};
+
+fn line_info(chip: &Chip, offset: Offset) -> Result<()> {
+ let info = chip.line_info(offset)?;
+ let off = info.offset();
+
+ let name = match info.name() {
+ Ok(name) => name,
+ _ => "unused",
+ };
+
+ let consumer = match info.consumer() {
+ Ok(name) => name,
+ _ => "unnamed",
+ };
+
+ let low = if info.is_active_low() {
+ "active-low"
+ } else {
+ "active-high"
+ };
+
+ let dir = match info.direction()? {
+ 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
+ );
+
+ Ok(())
+}
+
+fn chip_info(chip: &Chip) -> Result<()> {
+ let info = chip.info()?;
+ let ngpio = info.num_lines();
+
+ println!("GPIO Chip name: {}", info.name()?);
+ println!("\tlabel: {}", info.label()?);
+ println!("\tpath: {}", chip.path()?);
+ println!("\tngpio: {}\n", ngpio);
+
+ println!("\tLine information:");
+
+ for offset in 0..ngpio {
+ line_info(chip, offset as Offset)?;
+ }
+ println!("\n");
+
+ Ok(())
+}
+
+fn main() -> Result<()> {
+ let args: Vec<String> = env::args().collect();
+ if args.len() > 2 {
+ println!("Usage: {}", args[0]);
+ return Err(Error::InvalidArguments);
+ }
+
+ if args.len() == 1 {
+ for chip in libgpiod::gpiochip_devices(&Path::new("/dev"))? {
+ chip_info(&chip)?;
+ }
+ } else {
+ let index = args[1]
+ .parse::<u32>()
+ .map_err(|_| Error::InvalidArguments)?;
+ let path = format!("/dev/gpiochip{}", index);
+ if libgpiod::is_gpiochip_device(&path) {
+ let chip = Chip::open(&path)?;
+
+ chip_info(&chip)?;
+ }
+ }
+
+ Ok(())
+}
new file mode 100644
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: Apache-2.0 OR 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 libgpiod::{
+ chip::Chip,
+ line::{self, Edge, EdgeKind, 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 count = request.read_edge_events(&mut buffer)?;
+ if count == 1 {
+ let event = buffer.event(0)?;
+ println!(
+ "line: {} type: {}, time: {:?}",
+ event.line_offset(),
+ match event.event_type()? {
+ EdgeKind::Rising => "Rising",
+ EdgeKind::Falling => "Falling",
+ },
+ event.timestamp()
+ );
+ }
+ }
+}
new file mode 100644
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: Apache-2.0 OR 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 std::io::{stdin, Read};
+
+use libgpiod::{
+ chip::Chip,
+ line::{self, Direction, Offset, SettingVal, Value},
+ request, Error, Result,
+};
+
+fn usage(name: &str) {
+ println!("Usage: {} <chip> <line_offset0>=<value0> ...", name);
+}
+
+fn main() -> Result<()> {
+ let args: Vec<String> = env::args().collect();
+ if args.len() < 3 {
+ usage(&args[0]);
+ return Err(Error::InvalidArguments);
+ }
+
+ let lconfig = line::Config::new()?;
+
+ for arg in &args[2..] {
+ let pair: Vec<&str> = arg.split('=').collect();
+ if pair.len() != 2 {
+ usage(&args[0]);
+ return Err(Error::InvalidArguments);
+ }
+
+ let offset = pair[0]
+ .parse::<Offset>()
+ .map_err(|_| Error::InvalidArguments)?;
+ let value = pair[1]
+ .parse::<i32>()
+ .map_err(|_| Error::InvalidArguments)?;
+
+ let mut lsettings = line::Settings::new()?;
+ lsettings.set_prop(&[
+ SettingVal::Direction(Direction::Output),
+ SettingVal::OutputValue(Value::new(value)?),
+ ])?;
+ lconfig.add_line_settings(&[offset], lsettings)?;
+ }
+
+ let path = format!("/dev/gpiochip{}", args[1]);
+ let chip = Chip::open(&path)?;
+
+ let rconfig = request::Config::new()?;
+ rconfig.set_consumer(&args[0])?;
+
+ chip.request_lines(&rconfig, &lconfig)?;
+
+ // Wait for keypress, let user verify line status.
+ stdin().read_exact(&mut [0u8]).unwrap();
+
+ Ok(())
+}
new file mode 100644
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
+//
+// Copyright 2022 Linaro Ltd. All Rights Reserved.
+// Viresh Kumar <viresh.kumar@linaro.org>
+//
+// Simplified Rust implementation of the gpiowatch tool.
+
+use std::env;
+
+use libgpiod::{chip::Chip, line::Offset, Error, Result};
+
+fn usage(name: &str) {
+ println!("Usage: {} <chip> <offset0> ...", name);
+}
+
+fn main() -> Result<()> {
+ let args: Vec<String> = env::args().collect();
+ if args.len() < 2 {
+ usage(&args[0]);
+ return Err(Error::InvalidArguments);
+ }
+
+ let path = format!("/dev/gpiochip{}", args[1]);
+ let offset = args[2]
+ .parse::<Offset>()
+ .map_err(|_| Error::InvalidArguments)?;
+
+ let chip = Chip::open(&path)?;
+ let _info = chip.watch_line_info(offset)?;
+
+ match chip.wait_info_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 event = chip.read_info_event()?;
+ println!(
+ "line: {} type: {:?}, time: {:?}",
+ offset,
+ event.event_type()?,
+ event.timestamp()
+ );
+
+ chip.unwatch(offset);
+ Ok(())
+}
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> --- .../rust/libgpiod/examples/gpio_events.rs | 88 ++++++++++++ .../examples/gpio_threaded_info_events.rs | 133 ++++++++++++++++++ bindings/rust/libgpiod/examples/gpiodetect.rs | 31 ++++ bindings/rust/libgpiod/examples/gpiofind.rs | 37 +++++ bindings/rust/libgpiod/examples/gpioget.rs | 46 ++++++ bindings/rust/libgpiod/examples/gpioinfo.rs | 98 +++++++++++++ bindings/rust/libgpiod/examples/gpiomon.rs | 75 ++++++++++ bindings/rust/libgpiod/examples/gpioset.rs | 64 +++++++++ bindings/rust/libgpiod/examples/gpiowatch.rs | 54 +++++++ 9 files changed, 626 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