Skip to content

Commit 6203207

Browse files
committed
Implement Wait for CdevPin.
1 parent f7b1505 commit 6203207

File tree

3 files changed

+157
-11
lines changed

3 files changed

+157
-11
lines changed

Cargo.toml

+7-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ edition = "2018"
1515
[features]
1616
gpio_sysfs = ["sysfs_gpio"]
1717
gpio_cdev = ["gpio-cdev"]
18-
async-tokio = ["gpio-cdev/async-tokio", "dep:embedded-hal-async", "tokio/time"]
18+
async-tokio = ["gpio-cdev/async-tokio", "dep:embedded-hal-async", "tokio/time", "tokio/rt", "gpiocdev/async_tokio"]
1919
i2c = ["i2cdev"]
2020
spi = ["spidev"]
2121

@@ -26,6 +26,7 @@ embedded-hal = "1"
2626
embedded-hal-nb = "1"
2727
embedded-hal-async = { version = "1", optional = true }
2828
gpio-cdev = { version = "0.6.0", optional = true }
29+
gpiocdev = { version = "0.6.0" }
2930
sysfs_gpio = { version = "0.6.1", optional = true }
3031
i2cdev = { version = "0.6.0", optional = true }
3132
nb = "1"
@@ -36,8 +37,13 @@ tokio = { version = "1", default-features = false, optional = true }
3637

3738
[dev-dependencies]
3839
openpty = "0.2.0"
40+
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
3941

4042
[dependencies.cast]
4143
# we don't need the `Error` implementation
4244
default-features = false
4345
version = "0.3"
46+
47+
[[example]]
48+
name = "gpio-wait"
49+
required-features = ["async-tokio"]

examples/gpio-wait.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use std::error::Error;
2+
use std::time::Duration;
3+
4+
use embedded_hal::digital::{InputPin, OutputPin, PinState};
5+
use embedded_hal_async::digital::Wait;
6+
use gpio_cdev::{Chip, LineRequestFlags};
7+
use linux_embedded_hal::CdevPin;
8+
use tokio::time::{sleep, timeout};
9+
10+
// This example assumes that input/output pins are shorted.
11+
const INPUT_LINE: u32 = 4;
12+
const OUTPUT_LINE: u32 = 17;
13+
14+
#[tokio::main]
15+
async fn main() -> Result<(), Box<dyn Error>> {
16+
let mut chip = Chip::new("/dev/gpiochip0")?;
17+
let input = chip.get_line(INPUT_LINE)?;
18+
let output = chip.get_line(OUTPUT_LINE)?;
19+
20+
let mut input_pin =
21+
CdevPin::new(input.request(LineRequestFlags::INPUT, 0, "")?)?.into_input_pin()?;
22+
let mut output_pin = CdevPin::new(output.request(LineRequestFlags::OUTPUT, 0, "")?)?
23+
.into_output_pin(PinState::Low)?;
24+
25+
timeout(Duration::from_secs(10), async move {
26+
let set_output = tokio::spawn(async move {
27+
sleep(Duration::from_secs(5)).await;
28+
println!("Setting output high.");
29+
output_pin.set_high()
30+
});
31+
32+
println!("Waiting for input to go high.");
33+
34+
input_pin.wait_for_high().await?;
35+
36+
assert!(input_pin.is_high()?);
37+
println!("Input is now high.");
38+
39+
set_output.await??;
40+
41+
Ok::<_, Box<dyn Error>>(())
42+
})
43+
.await??;
44+
45+
Ok(())
46+
}

src/cdev_pin.rs

+104-10
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,75 @@
44
55
use std::fmt;
66

7+
use embedded_hal::digital::InputPin;
8+
#[cfg(feature = "async-tokio")]
9+
use gpiocdev::{line::EdgeDetection, request::Request, tokio::AsyncRequest};
10+
711
/// Newtype around [`gpio_cdev::LineHandle`] that implements the `embedded-hal` traits
812
///
913
/// [`gpio_cdev::LineHandle`]: https://docs.rs/gpio-cdev/0.5.0/gpio_cdev/struct.LineHandle.html
10-
pub struct CdevPin(pub gpio_cdev::LineHandle, gpio_cdev::LineInfo);
14+
#[derive(Debug)]
15+
pub struct CdevPin(pub Option<gpio_cdev::LineHandle>, gpio_cdev::LineInfo);
16+
17+
#[cfg(feature = "async-tokio")]
18+
#[derive(Debug)]
19+
struct CdevPinEdgeWaiter<'a> {
20+
pin: &'a mut CdevPin,
21+
edge: EdgeDetection,
22+
}
23+
24+
#[cfg(feature = "async-tokio")]
25+
impl<'a> CdevPinEdgeWaiter<'a> {
26+
pub fn new(pin: &'a mut CdevPin, edge: EdgeDetection) -> Result<Self, gpiocdev::Error> {
27+
Ok(Self { pin, edge })
28+
}
29+
30+
pub async fn wait(self) -> Result<(), gpiocdev::Error> {
31+
let line_handle = self.pin.0.take().unwrap();
32+
let line_info = &self.pin.1;
33+
34+
let line = line_handle.line().clone();
35+
let flags = line_handle.flags();
36+
let chip = line.chip().path().to_owned();
37+
let offset = line.offset();
38+
let consumer = line_info.consumer().unwrap_or("").to_owned();
39+
let edge = self.edge;
40+
41+
// Close line handle.
42+
drop(line_handle);
43+
44+
let req = Request::builder()
45+
.on_chip(chip)
46+
.with_line(offset)
47+
.as_is()
48+
.with_consumer(consumer.clone())
49+
.with_edge_detection(edge)
50+
.request()?;
51+
52+
let req = AsyncRequest::new(req);
53+
let event = req.read_edge_event().await;
54+
drop(req);
55+
56+
// Recreate line handle.
57+
self.pin.0 = Some(line.request(flags, 0, &consumer).unwrap());
58+
59+
event?;
60+
61+
Ok(())
62+
}
63+
}
1164

1265
impl CdevPin {
1366
/// See [`gpio_cdev::Line::request`][0] for details.
1467
///
1568
/// [0]: https://docs.rs/gpio-cdev/0.5.0/gpio_cdev/struct.Line.html#method.request
1669
pub fn new(handle: gpio_cdev::LineHandle) -> Result<Self, gpio_cdev::errors::Error> {
1770
let info = handle.line().info()?;
18-
Ok(CdevPin(handle, info))
71+
Ok(CdevPin(Some(handle), info))
72+
}
73+
74+
fn line_handle(&self) -> &gpio_cdev::LineHandle {
75+
self.0.as_ref().unwrap()
1976
}
2077

2178
fn get_input_flags(&self) -> gpio_cdev::LineRequestFlags {
@@ -43,7 +100,7 @@ impl CdevPin {
43100
if self.1.direction() == gpio_cdev::LineDirection::In {
44101
return Ok(self);
45102
}
46-
let line = self.0.line().clone();
103+
let line = self.line_handle().line().clone();
47104
let input_flags = self.get_input_flags();
48105
let consumer = self.1.consumer().unwrap_or("").to_owned();
49106

@@ -62,7 +119,7 @@ impl CdevPin {
62119
return Ok(self);
63120
}
64121

65-
let line = self.0.line().clone();
122+
let line = self.line_handle().line().clone();
66123
let output_flags = self.get_output_flags();
67124
let consumer = self.1.consumer().unwrap_or("").to_owned();
68125

@@ -138,7 +195,7 @@ impl embedded_hal::digital::ErrorType for CdevPin {
138195

139196
impl embedded_hal::digital::OutputPin for CdevPin {
140197
fn set_low(&mut self) -> Result<(), Self::Error> {
141-
self.0
198+
self.line_handle()
142199
.set_value(state_to_value(
143200
embedded_hal::digital::PinState::Low,
144201
self.1.is_active_low(),
@@ -147,7 +204,7 @@ impl embedded_hal::digital::OutputPin for CdevPin {
147204
}
148205

149206
fn set_high(&mut self) -> Result<(), Self::Error> {
150-
self.0
207+
self.line_handle()
151208
.set_value(state_to_value(
152209
embedded_hal::digital::PinState::High,
153210
self.1.is_active_low(),
@@ -156,9 +213,9 @@ impl embedded_hal::digital::OutputPin for CdevPin {
156213
}
157214
}
158215

159-
impl embedded_hal::digital::InputPin for CdevPin {
216+
impl InputPin for CdevPin {
160217
fn is_high(&mut self) -> Result<bool, Self::Error> {
161-
self.0
218+
self.line_handle()
162219
.get_value()
163220
.map(|val| {
164221
val == state_to_value(
@@ -178,12 +235,49 @@ impl core::ops::Deref for CdevPin {
178235
type Target = gpio_cdev::LineHandle;
179236

180237
fn deref(&self) -> &Self::Target {
181-
&self.0
238+
self.line_handle()
182239
}
183240
}
184241

185242
impl core::ops::DerefMut for CdevPin {
186243
fn deref_mut(&mut self) -> &mut Self::Target {
187-
&mut self.0
244+
self.0.as_mut().unwrap()
245+
}
246+
}
247+
248+
#[cfg(feature = "async-tokio")]
249+
impl embedded_hal_async::digital::Wait for CdevPin {
250+
async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
251+
if self.is_high()? {
252+
return Ok(());
253+
}
254+
255+
self.wait_for_rising_edge().await
256+
}
257+
258+
async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
259+
if self.is_low()? {
260+
return Ok(());
261+
}
262+
263+
self.wait_for_falling_edge().await
264+
}
265+
266+
async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
267+
let waiter = CdevPinEdgeWaiter::new(self, EdgeDetection::RisingEdge).unwrap();
268+
waiter.wait().await.unwrap();
269+
Ok(())
270+
}
271+
272+
async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
273+
let waiter = CdevPinEdgeWaiter::new(self, EdgeDetection::FallingEdge).unwrap();
274+
waiter.wait().await.unwrap();
275+
Ok(())
276+
}
277+
278+
async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
279+
let waiter = CdevPinEdgeWaiter::new(self, EdgeDetection::BothEdges).unwrap();
280+
waiter.wait().await.unwrap();
281+
Ok(())
188282
}
189283
}

0 commit comments

Comments
 (0)