Skip to main content
RKTK API Docs RKTK Home Repo

rktk_drivers_common/
encoder.rs

1//! Encoder driver implementations.
2
3use embassy_futures::select::{Either, select, select_slice};
4use embassy_time::Timer;
5use embedded_hal::digital::InputPin;
6use embedded_hal_async::digital::Wait;
7use rktk::drivers::interface::encoder::{EncoderDirection, EncoderDriver};
8
9/// General encoder driver that can be used with any digital input pin.
10pub struct GeneralEncoder<PIN: Wait + InputPin, const ENCODER_COUNT: usize> {
11    encoders: [(PIN, PIN); ENCODER_COUNT],
12}
13
14impl<PIN: Wait + InputPin, const ENCODER_COUNT: usize> GeneralEncoder<PIN, ENCODER_COUNT> {
15    pub fn new(encoders: [(PIN, PIN); ENCODER_COUNT]) -> Self {
16        Self { encoders }
17    }
18}
19
20impl<PIN: Wait + InputPin, const ENCODER_COUNT: usize> EncoderDriver
21    for GeneralEncoder<PIN, ENCODER_COUNT>
22{
23    async fn read_wait(&mut self) -> (u8, EncoderDirection) {
24        let encoders = self.encoders.each_mut();
25
26        let mut i = 0;
27        let futures = encoders.map(|pins| {
28            let id = i;
29            i += 1;
30            async move {
31                let a = &mut pins.0;
32                let b = &mut pins.1;
33                let dir = match select(a.wait_for_any_edge(), b.wait_for_any_edge()).await {
34                    Either::First(_) => {
35                        Timer::after_ticks(100).await;
36                        if a.is_high().unwrap() ^ b.is_high().unwrap() {
37                            EncoderDirection::Clockwise
38                        } else {
39                            EncoderDirection::CounterClockwise
40                        }
41                    }
42                    Either::Second(_) => {
43                        Timer::after_ticks(100).await;
44                        if a.is_high().unwrap() ^ b.is_high().unwrap() {
45                            EncoderDirection::CounterClockwise
46                        } else {
47                            EncoderDirection::Clockwise
48                        }
49                    }
50                };
51                (id as u8, dir)
52            }
53        });
54
55        select_slice(core::pin::pin!(futures)).await.0
56    }
57}