stepper/stepper/set_direction.rs
1use core::task::Poll;
2
3use embedded_hal::digital::blocking::OutputPin;
4use embedded_hal::digital::ErrorType;
5use fugit::TimerDurationU32 as TimerDuration;
6use fugit_timer::Timer as TimerTrait;
7
8use crate::{traits::SetDirection, Direction};
9
10use super::SignalError;
11
12/// The "future" returned by [`Stepper::set_direction`]
13///
14/// Please note that this type provides a custom API and does not implement
15/// [`core::future::Future`]. This might change, when using futures for embedded
16/// development becomes more practical.
17///
18/// [`Stepper::set_direction`]: crate::Stepper::set_direction
19#[must_use]
20pub struct SetDirectionFuture<Driver, Timer, const TIMER_HZ: u32> {
21 direction: Direction,
22 driver: Driver,
23 timer: Timer,
24 state: State,
25}
26
27impl<Driver, Timer, const TIMER_HZ: u32>
28 SetDirectionFuture<Driver, Timer, TIMER_HZ>
29where
30 Driver: SetDirection,
31 Timer: TimerTrait<TIMER_HZ>,
32{
33 /// Create new instance of `SetDirectionFuture`
34 ///
35 /// This constructor is public to provide maximum flexibility for
36 /// non-standard use cases. Most users can ignore this and just use
37 /// [`Stepper::set_direction`] instead.
38 ///
39 /// [`Stepper::set_direction`]: crate::Stepper::set_direction
40 pub fn new(direction: Direction, driver: Driver, timer: Timer) -> Self {
41 Self {
42 direction,
43 driver,
44 timer,
45 state: State::Initial,
46 }
47 }
48
49 /// Poll the future
50 ///
51 /// The future must be polled for the operation to make progress. The
52 /// operation won't start, until this method has been called once. Returns
53 /// [`Poll::Pending`], if the operation is not finished yet, or
54 /// [`Poll::Ready`], once it is.
55 ///
56 /// If this method returns [`Poll::Pending`], the user can opt to keep
57 /// calling it at a high frequency (see [`Self::wait`]) until the operation
58 /// completes, or set up an interrupt that fires once the timer finishes
59 /// counting down, and call this method again once it does.
60 pub fn poll(
61 &mut self,
62 ) -> Poll<
63 Result<
64 (),
65 SignalError<
66 Driver::Error,
67 <Driver::Dir as ErrorType>::Error,
68 Timer::Error,
69 >,
70 >,
71 > {
72 match self.state {
73 State::Initial => {
74 match self.direction {
75 Direction::Forward => self
76 .driver
77 .dir()
78 .map_err(|err| SignalError::PinUnavailable(err))?
79 .set_high()
80 .map_err(|err| SignalError::Pin(err))?,
81 Direction::Backward => self
82 .driver
83 .dir()
84 .map_err(|err| SignalError::PinUnavailable(err))?
85 .set_low()
86 .map_err(|err| SignalError::Pin(err))?,
87 }
88
89 let ticks: TimerDuration<TIMER_HZ> =
90 Driver::SETUP_TIME.convert();
91 self.timer
92 .start(ticks)
93 .map_err(|err| SignalError::Timer(err))?;
94
95 self.state = State::DirectionSet;
96 Poll::Pending
97 }
98 State::DirectionSet => match self.timer.wait() {
99 Ok(()) => {
100 self.state = State::Finished;
101 Poll::Ready(Ok(()))
102 }
103 Err(nb::Error::Other(err)) => {
104 self.state = State::Finished;
105 Poll::Ready(Err(SignalError::Timer(err)))
106 }
107 Err(nb::Error::WouldBlock) => Poll::Pending,
108 },
109 State::Finished => Poll::Ready(Ok(())),
110 }
111 }
112
113 /// Wait until the operation completes
114 ///
115 /// This method will call [`Self::poll`] in a busy loop until the operation
116 /// has finished.
117 pub fn wait(
118 &mut self,
119 ) -> Result<
120 (),
121 SignalError<
122 Driver::Error,
123 <Driver::Dir as ErrorType>::Error,
124 Timer::Error,
125 >,
126 > {
127 loop {
128 if let Poll::Ready(result) = self.poll() {
129 return result;
130 }
131 }
132 }
133
134 /// Drop the future and release the resources that were moved into it
135 pub fn release(self) -> (Driver, Timer) {
136 (self.driver, self.timer)
137 }
138}
139
140enum State {
141 Initial,
142 DirectionSet,
143 Finished,
144}