Skip to content

Commit e11348e

Browse files
Add WaitForEdgeForever and WaitForStateForever transactions (#125)
These return a Pending future to the callee.
1 parent fb83b9e commit e11348e

File tree

2 files changed

+139
-27
lines changed

2 files changed

+139
-27
lines changed

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ eh0 = ["dep:eh0", "dep:nb"]
2424
eh1 = ["dep:eh1", "dep:embedded-hal-nb"]
2525

2626
embedded-time = ["dep:embedded-time", "dep:void"]
27-
embedded-hal-async = ["dep:embedded-hal-async"]
27+
embedded-hal-async = ["dep:embedded-hal-async","dep:futures"]
2828

2929
default = ["eh1", "embedded-time"]
3030

@@ -33,12 +33,13 @@ eh0 = { package = "embedded-hal", version = "0.2.7", features = ["unproven"], op
3333
eh1 = { package = "embedded-hal", version = "1.0", optional = true }
3434
embedded-hal-nb = { version = "1.0", optional = true }
3535
embedded-hal-async = { version = "1.0", optional = true }
36+
futures = { version = "0.3.31", default-features = false, optional = true }
3637
embedded-time = { version = "0.12", optional = true }
3738
nb = { version = "1.1", optional = true }
3839
void = { version = "^1.0", optional = true }
3940

4041
[dev-dependencies]
41-
tokio = { version = "1.21.1", features = ["rt", "macros"] }
42+
tokio = { version = "1.21.1", features = ["rt", "macros", "time"] }
4243

4344
[package.metadata.docs.rs]
4445
all-features = true

src/eh1/digital.rs

Lines changed: 136 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,28 @@ impl Transaction {
120120
Transaction::new(TransactionKind::WaitForState(state))
121121
}
122122

123+
/// Create a new wait_for_state transaction,
124+
/// which returns a forever-Pending future when called.
125+
/// This simulates waiting on a pin that never changes.
126+
#[cfg(feature = "embedded-hal-async")]
127+
pub fn wait_for_state_forever(state: State) -> Transaction {
128+
Transaction::new(TransactionKind::WaitForStateForever(state))
129+
}
130+
123131
/// Crate a new wait_for_edge transaction
124132
#[cfg(feature = "embedded-hal-async")]
125133
pub fn wait_for_edge(edge: Edge) -> Transaction {
126134
Transaction::new(TransactionKind::WaitForEdge(edge))
127135
}
128136

137+
/// Crate a new wait_for_edge transaction,
138+
/// which returns a forever-Pending future when called.
139+
/// This simulates waiting on a pin that never changes.
140+
#[cfg(feature = "embedded-hal-async")]
141+
pub fn wait_for_edge_forever(edge: Edge) -> Transaction {
142+
Transaction::new(TransactionKind::WaitForEdgeForever(edge))
143+
}
144+
129145
/// Add an error return to a transaction
130146
///
131147
/// This is used to mock failure behaviours.
@@ -157,9 +173,15 @@ pub enum TransactionKind {
157173
/// Wait for the given pin state
158174
#[cfg(feature = "embedded-hal-async")]
159175
WaitForState(State),
176+
/// Wait for the given pin state, returning Pending to simulate a never-changing pin
177+
#[cfg(feature = "embedded-hal-async")]
178+
WaitForStateForever(State),
160179
/// Wait for the given pin edge
161180
#[cfg(feature = "embedded-hal-async")]
162181
WaitForEdge(Edge),
182+
/// Wait for the given pin edge, returning Pending to simulate a never-changing pin
183+
#[cfg(feature = "embedded-hal-async")]
184+
WaitForEdgeForever(Edge),
163185
}
164186

165187
impl TransactionKind {
@@ -309,6 +331,9 @@ impl StatefulOutputPin for Mock {
309331
}
310332
}
311333

334+
#[cfg(feature = "embedded-hal-async")]
335+
use futures::future::pending;
336+
312337
#[cfg(feature = "embedded-hal-async")]
313338
impl embedded_hal_async::digital::Wait for Mock {
314339
/// Wait for the pin to go high
@@ -320,14 +345,18 @@ impl embedded_hal_async::digital::Wait for Mock {
320345
.expect("no expectation for pin::wait_for_high call");
321346

322347
assert!(
323-
matches!(kind, TransactionKind::WaitForState(State::High)),
348+
matches!(
349+
kind,
350+
TransactionKind::WaitForState(State::High)
351+
| TransactionKind::WaitForStateForever(State::High)
352+
),
324353
"got call to wait_for_high"
325354
);
326355

327-
if let Some(e) = err {
328-
Err(e)
329-
} else {
330-
Ok(())
356+
match (kind, err) {
357+
(_, Some(e)) => Err(e),
358+
(TransactionKind::WaitForState(State::High), _) => Ok(()),
359+
_ => pending().await,
331360
}
332361
}
333362

@@ -339,14 +368,18 @@ impl embedded_hal_async::digital::Wait for Mock {
339368
s.next().expect("no expectation for pin::wait_for_low call");
340369

341370
assert!(
342-
matches!(kind, TransactionKind::WaitForState(State::Low)),
371+
matches!(
372+
kind,
373+
TransactionKind::WaitForState(State::Low)
374+
| TransactionKind::WaitForStateForever(State::Low)
375+
),
343376
"got call to wait_for_low"
344377
);
345378

346-
if let Some(e) = err {
347-
Err(e)
348-
} else {
349-
Ok(())
379+
match (kind, err) {
380+
(_, Some(e)) => Err(e),
381+
(TransactionKind::WaitForState(State::Low), _) => Ok(()),
382+
_ => pending().await,
350383
}
351384
}
352385

@@ -359,14 +392,18 @@ impl embedded_hal_async::digital::Wait for Mock {
359392
.expect("no expectation for pin::wait_for_rising_edge call");
360393

361394
assert!(
362-
matches!(kind, TransactionKind::WaitForEdge(Edge::Rising)),
395+
matches!(
396+
kind,
397+
TransactionKind::WaitForEdge(Edge::Rising)
398+
| TransactionKind::WaitForEdgeForever(Edge::Rising)
399+
),
363400
"got call to wait_for_rising_edge"
364401
);
365402

366-
if let Some(e) = err {
367-
Err(e)
368-
} else {
369-
Ok(())
403+
match (kind, err) {
404+
(_, Some(e)) => Err(e),
405+
(TransactionKind::WaitForEdge(Edge::Rising), _) => Ok(()),
406+
_ => pending().await,
370407
}
371408
}
372409

@@ -379,14 +416,18 @@ impl embedded_hal_async::digital::Wait for Mock {
379416
.expect("no expectation for pin::wait_for_falling_edge call");
380417

381418
assert!(
382-
matches!(kind, TransactionKind::WaitForEdge(Edge::Falling)),
419+
matches!(
420+
kind,
421+
TransactionKind::WaitForEdge(Edge::Falling)
422+
| TransactionKind::WaitForEdgeForever(Edge::Falling)
423+
),
383424
"got call to wait_for_falling_edge"
384425
);
385426

386-
if let Some(e) = err {
387-
Err(e)
388-
} else {
389-
Ok(())
427+
match (kind, err) {
428+
(_, Some(e)) => Err(e),
429+
(TransactionKind::WaitForEdge(Edge::Falling), _) => Ok(()),
430+
_ => pending().await,
390431
}
391432
}
392433

@@ -399,24 +440,32 @@ impl embedded_hal_async::digital::Wait for Mock {
399440
.expect("no expectation for pin::wait_for_any_edge call");
400441

401442
assert!(
402-
matches!(kind, TransactionKind::WaitForEdge(Edge::Any)),
443+
matches!(
444+
kind,
445+
TransactionKind::WaitForEdge(Edge::Any)
446+
| TransactionKind::WaitForEdgeForever(Edge::Any)
447+
),
403448
"got call to wait_for_any_edge"
404449
);
405450

406-
if let Some(e) = err {
407-
Err(e)
408-
} else {
409-
Ok(())
451+
match (kind, err) {
452+
(_, Some(e)) => Err(e),
453+
(TransactionKind::WaitForEdge(Edge::Any), _) => Ok(()),
454+
_ => pending().await,
410455
}
411456
}
412457
}
413458

414459
#[cfg(test)]
415460
mod test {
416461
use std::io::ErrorKind;
462+
#[cfg(feature = "embedded-hal-async")]
463+
use std::time::Duration;
417464

418465
use eh1 as embedded_hal;
419466
use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin};
467+
#[cfg(feature = "embedded-hal-async")]
468+
use tokio::time::timeout;
420469

421470
use super::{
422471
super::error::MockError,
@@ -528,6 +577,35 @@ mod test {
528577
pin.done();
529578
}
530579

580+
#[tokio::test]
581+
#[cfg(feature = "embedded-hal-async")]
582+
async fn test_can_wait_for_state_forever() {
583+
use embedded_hal_async::digital::Wait;
584+
585+
let expectations = [
586+
Transaction::new(TransactionKind::WaitForStateForever(State::High)),
587+
Transaction::new(TransactionKind::WaitForStateForever(State::Low)),
588+
Transaction::new(TransactionKind::WaitForStateForever(State::High))
589+
.with_error(MockError::Io(ErrorKind::NotConnected)),
590+
];
591+
let mut pin = Mock::new(&expectations);
592+
593+
// we should not return Ok while asking to wait forever!
594+
timeout(Duration::from_millis(10), pin.wait_for_high())
595+
.await
596+
.expect_err("expected wait_for_high timeout");
597+
timeout(Duration::from_millis(10), pin.wait_for_low())
598+
.await
599+
.expect_err("expected wait_for_low timeout");
600+
601+
// errors are still returned, since maybe awaiting on the pin failed for some reason
602+
pin.wait_for_high()
603+
.await
604+
.expect_err("expected error return");
605+
606+
pin.done();
607+
}
608+
531609
#[tokio::test]
532610
#[cfg(feature = "embedded-hal-async")]
533611
async fn test_can_wait_for_edge() {
@@ -553,6 +631,39 @@ mod test {
553631
pin.done();
554632
}
555633

634+
#[tokio::test]
635+
#[cfg(feature = "embedded-hal-async")]
636+
async fn test_can_wait_for_edge_forever() {
637+
use embedded_hal_async::digital::Wait;
638+
639+
let expectations = [
640+
Transaction::new(TransactionKind::WaitForEdgeForever(Edge::Rising)),
641+
Transaction::new(TransactionKind::WaitForEdgeForever(Edge::Falling)),
642+
Transaction::new(TransactionKind::WaitForEdgeForever(Edge::Any)),
643+
Transaction::new(TransactionKind::WaitForEdgeForever(Edge::Rising))
644+
.with_error(MockError::Io(ErrorKind::NotConnected)),
645+
];
646+
let mut pin = Mock::new(&expectations);
647+
648+
// we should not return Ok while asking to wait forever!
649+
timeout(Duration::from_millis(10), pin.wait_for_rising_edge())
650+
.await
651+
.expect_err("expected wait_for_rising_edge timeout");
652+
timeout(Duration::from_millis(10), pin.wait_for_falling_edge())
653+
.await
654+
.expect_err("expected wait_for_falling_edge timeout");
655+
timeout(Duration::from_millis(10), pin.wait_for_any_edge())
656+
.await
657+
.expect_err("expected wait_for_any_edge timeout");
658+
659+
// errors are still returned, since maybe awaiting on the pin failed for some reason
660+
pin.wait_for_rising_edge()
661+
.await
662+
.expect_err("expected error return");
663+
664+
pin.done();
665+
}
666+
556667
#[tokio::test]
557668
#[should_panic(expected = "got call to wait_for_rising_edge")]
558669
#[cfg(feature = "embedded-hal-async")]

0 commit comments

Comments
 (0)