1use core::marker::PhantomData;
4
5use num_traits::{One, SaturatingAdd, WrappingNeg, Zero};
6use quadrature_decoder::{Change, FullStep, IndexedIncrementalDecoder, StepMode};
7
8#[allow(unused_imports)]
9use crate::{
10 mode::{Async, Blocking, Movement, OperationMode, PollMode},
11 traits::*,
12 Error, InputPinError, Linear, Rotary,
13};
14
15pub type IndexedRotaryEncoder<Clk, Dt, Steps = FullStep, T = i32, PM = Blocking> =
17 IndexedIncrementalEncoder<Rotary, Clk, Dt, Steps, T, PM>;
18pub type IndexedLinearEncoder<Clk, Dt, Steps = FullStep, T = i32, PM = Blocking> =
20 IndexedIncrementalEncoder<Linear, Clk, Dt, Steps, T, PM>;
21
22#[derive(Debug)]
24pub struct IndexedIncrementalEncoder<Mode, Clk, Dt, Idx, Steps = FullStep, T = i32, PM = Blocking> {
25 decoder: IndexedIncrementalDecoder<Steps, T>,
26 pin_clk: Clk,
27 pin_dt: Dt,
28 pin_idx: Idx,
29 pin_clk_state: bool,
30 pin_dt_state: bool,
31 pin_idx_state: bool,
32 is_reversed: bool,
33 _mode: PhantomData<Mode>,
34 _poll_mode: PhantomData<PM>,
35}
36
37impl<Mode, Clk, Dt, Idx, Steps, T, PM> IndexedIncrementalEncoder<Mode, Clk, Dt, Idx, Steps, T, PM>
38where
39 Mode: OperationMode,
40 Clk: InputPin,
41 Dt: InputPin,
42 Idx: InputPin,
43 Steps: StepMode,
44 T: Zero,
45 PM: PollMode,
46{
47 pub fn new(mut pin_clk: Clk, mut pin_dt: Dt, mut pin_idx: Idx) -> Self
49 where
50 IndexedIncrementalDecoder<Steps, T>: Default,
51 {
52 let pin_clk_state = pin_clk.is_high().unwrap_or(false);
53 let pin_dt_state = pin_dt.is_high().unwrap_or(false);
54 let pin_idx_state = pin_idx.is_high().unwrap_or(false);
55
56 Self {
57 decoder: Default::default(),
58 pin_clk,
59 pin_dt,
60 pin_idx,
61 pin_clk_state,
62 pin_dt_state,
63 pin_idx_state,
64 is_reversed: false,
65 _mode: PhantomData,
66 _poll_mode: PhantomData,
67 }
68 }
69}
70
71impl<Mode, Clk, Dt, Idx, Steps, T, PM> IndexedIncrementalEncoder<Mode, Clk, Dt, Idx, Steps, T, PM>
72where
73 Mode: OperationMode,
74 Clk: InputPin,
75 Dt: InputPin,
76 Idx: InputPin,
77 Steps: StepMode,
78 T: Copy + Zero + One + SaturatingAdd + WrappingNeg + From<i8>,
79 PM: PollMode,
80{
81 pub fn reversed(mut self) -> Self {
83 self.is_reversed = true;
84 self
85 }
86
87 pub fn is_reversed(&self) -> bool {
89 self.is_reversed
90 }
91
92 pub fn pins_mut(&mut self) -> (&mut Clk, &mut Dt) {
94 (&mut self.pin_clk, &mut self.pin_dt)
95 }
96
97 pub fn release(self) -> (Clk, Dt) {
99 (self.pin_clk, self.pin_dt)
100 }
101
102 fn update(&mut self) -> Result<Option<Mode::Movement>, Error> {
105 let change: Option<Change> = self
106 .decoder
107 .update(self.pin_clk_state, self.pin_dt_state, self.pin_idx_state)
108 .map_err(Error::Quadrature)?;
109 let movement: Option<Mode::Movement> = change.map(From::from);
110
111 Ok(movement.map(|movement| {
112 if self.is_reversed() {
113 movement.flipped()
114 } else {
115 movement
116 }
117 }))
118 }
119
120 pub fn reset(&mut self) {
122 self.decoder.reset();
123 }
124
125 pub fn position(&self) -> T {
127 match self.is_reversed {
128 true => self.decoder.counter().wrapping_neg(),
129 false => self.decoder.counter(),
130 }
131 }
132
133 pub fn set_position(&mut self, position: T) {
135 match self.is_reversed {
136 true => self.decoder.set_counter(position.wrapping_neg()),
137 false => self.decoder.set_counter(position),
138 }
139 }
140}
141
142impl<Mode, Clk, Dt, Idx, Steps, T> IndexedIncrementalEncoder<Mode, Clk, Dt, Idx, Steps, T, Blocking>
143where
144 Mode: OperationMode,
145 Clk: InputPin,
146 Dt: InputPin,
147 Idx: InputPin,
148 Steps: StepMode,
149 T: Copy + Zero + One + SaturatingAdd + WrappingNeg + From<i8>,
150{
151 pub fn poll(&mut self) -> Result<Option<Mode::Movement>, Error> {
160 self.pin_clk_state = self
161 .pin_clk
162 .is_high()
163 .map_err(|_| Error::InputPin(InputPinError::PinClk))?;
164 self.pin_dt_state = self
165 .pin_dt
166 .is_high()
167 .map_err(|_| Error::InputPin(InputPinError::PinDt))?;
168 self.pin_idx_state = self
169 .pin_idx
170 .is_high()
171 .map_err(|_| Error::InputPin(InputPinError::PinIdx))?;
172 self.update()
173 }
174}
175
176#[cfg(feature = "async")]
178impl<Mode, Clk, Dt, Idx, Steps, T> IndexedIncrementalEncoder<Mode, Clk, Dt, Idx, Steps, T, Blocking>
179where
180 Mode: OperationMode,
181 Clk: InputPin + Wait,
182 Dt: InputPin + Wait,
183 Idx: InputPin + Wait,
184 Steps: StepMode,
185 T: Copy + Zero + One + SaturatingAdd + WrappingNeg + From<i8>,
186{
187 pub fn into_async(self) -> IndexedIncrementalEncoder<Mode, Clk, Dt, Idx, Steps, T, Async>
189 where
190 IndexedIncrementalDecoder<Steps, T>: Default,
191 {
192 IndexedIncrementalEncoder::<Mode, Clk, Dt, Idx, Steps, T, Async> {
193 decoder: self.decoder,
194 pin_clk: self.pin_clk,
195 pin_dt: self.pin_dt,
196 pin_idx: self.pin_idx,
197 pin_clk_state: self.pin_clk_state,
198 pin_dt_state: self.pin_dt_state,
199 pin_idx_state: self.pin_idx_state,
200 is_reversed: self.is_reversed,
201 _mode: PhantomData,
202 _poll_mode: PhantomData,
203 }
204 }
205}
206
207#[cfg(feature = "async")]
208impl<Mode, Clk, Dt, Idx, Steps, T> IndexedIncrementalEncoder<Mode, Clk, Dt, Idx, Steps, T, Async>
209where
210 Mode: OperationMode,
211 Clk: InputPin + Wait,
212 Dt: InputPin + Wait,
213 Idx: InputPin + Wait,
214 Steps: StepMode,
215 T: Copy + Zero + One + SaturatingAdd + WrappingNeg + From<i8>,
216{
217 pub async fn poll(&mut self) -> Result<Option<Mode::Movement>, Error> {
228 let clk_fut = match self.pin_clk_state {
229 true => self.pin_clk.wait_for_low().left_future(),
230 false => self.pin_clk.wait_for_high().right_future(),
231 };
232
233 let dt_fut = match self.pin_dt_state {
234 true => self.pin_dt.wait_for_low().left_future(),
235 false => self.pin_dt.wait_for_high().right_future(),
236 };
237
238 let idx_fut = match self.pin_idx_state {
239 true => self.pin_idx.wait_for_low().left_future(),
240 false => self.pin_idx.wait_for_high().right_future(),
241 };
242
243 match select3(clk_fut, dt_fut, idx_fut).await {
247 Either3::First(_) => {
248 self.pin_clk_state = !self.pin_clk_state;
249 }
250 Either3::Second(_) => {
251 self.pin_dt_state = !self.pin_dt_state;
252 }
253 Either3::Third(_) => {
254 self.pin_idx_state = !self.pin_idx_state;
255 }
256 };
257
258 self.update()
259 }
260
261 pub fn into_blocking(self) -> IndexedIncrementalEncoder<Mode, Clk, Dt, Idx, Steps, T, Blocking>
263 where
264 IndexedIncrementalDecoder<Steps, T>: Default,
265 {
266 IndexedIncrementalEncoder::<Mode, Clk, Dt, Idx, Steps, T, Blocking> {
267 decoder: self.decoder,
268 pin_clk: self.pin_clk,
269 pin_dt: self.pin_dt,
270 pin_idx: self.pin_idx,
271 pin_clk_state: self.pin_clk_state,
272 pin_dt_state: self.pin_dt_state,
273 pin_idx_state: self.pin_idx_state,
274 is_reversed: self.is_reversed,
275 _mode: PhantomData,
276 _poll_mode: PhantomData,
277 }
278 }
279}