embedded_controls/
encoder.rs

1use crate::{Control, DebouncedInput, DebouncedInputConfig, DebouncedInputEvent};
2
3use core::ops::AddAssign;
4use num_integer::Integer;
5use num_traits::{One, Signed, Zero};
6use switch_hal::InputSwitch;
7
8/// Represents a config for [`Encoder`](crate::Encoder).
9pub trait EncoderConfig: DebouncedInputConfig {
10    /// The type of counts counter.
11    type Counts: AddAssign + Integer + Signed + Copy;
12
13    /// The number of counts to register one turn of the encoder.
14    const COUNTS_DIV: Self::Counts;
15}
16
17/// Concrete implementation of encoder.
18///
19/// # Type Params
20/// `SwitchA` - [`InputSwitch`](switch_hal::InputSwitch) that provides input A channel.
21///
22/// `SwitchB` - [`InputSwitch`](switch_hal::InputSwitch) that provides input B channel.
23///
24/// `Config` - [`EncoderConfig`](crate::EncoderConfig) that provides configs for encoder.
25///
26/// # Example
27/// ```ignore
28/// encoder_config!(
29///     SomeEncoderConfig,
30///     debounce_timer: MyElapsedTimer = MyElapsedTimer::new(2.millis()),
31///     counts_div: i8 = 4
32/// );
33///
34/// type MyEncoder<SwitchA, SwitchB> = Encoder<SwitchA, SwitchB, SomeEncoderConfig>;
35///
36/// let mut encoder = MyEncoder::new(
37///     pin_a.into_active_low_switch(),
38///     pin_b.into_active_low_switch(),
39/// );
40///
41/// loop {
42///     match encoder.update().unwrap() {
43///         EncoderEvent::NoTurn => do_something_when_no_turn(),
44///         EncoderEvent::ClockwiseTurn => do_something_upon_clockwise_turn(),
45///         EncoderEvent::CounterClockwiseTurn => do_something_upon_counter_clockwise_turn(),
46///     }
47/// }
48/// ```
49pub struct Encoder<SwitchA: InputSwitch, SwitchB: InputSwitch, Config: EncoderConfig> {
50    debounced_input_a: DebouncedInput<SwitchA, Config>,
51    debounced_input_b: DebouncedInput<SwitchB, Config>,
52    counts: Config::Counts,
53}
54
55/// The event result of update [`Encoder`](crate::Encoder).
56#[derive(Debug, Clone, Copy, PartialEq)]
57pub enum EncoderEvent {
58    /// Encoder doesn't rotate.
59    NoTurn,
60    /// Encoder rotates clockwise.
61    ClockwiseTurn,
62    /// Encoder rotates counter clockwise.
63    CounterClockwiseTurn,
64}
65
66impl<SwitchA: InputSwitch, SwitchB: InputSwitch, Config: EncoderConfig>
67    Encoder<SwitchA, SwitchB, Config>
68{
69    /// Creates a new [`Encoder<SwitchA, SwitchB, Config>`] from concretes `SwitchA`, `SwitchB`.
70    pub fn new(input_switch_a: SwitchA, input_switch_b: SwitchB) -> Self {
71        Encoder {
72            debounced_input_a: DebouncedInput::new(input_switch_a),
73            debounced_input_b: DebouncedInput::new(input_switch_b),
74            counts: Zero::zero(),
75        }
76    }
77
78    /// Consumses `self` and release `(SwitchA, SwitchB)`.
79    pub fn release_input_switches(self) -> (SwitchA, SwitchB) {
80        (
81            self.debounced_input_a.release_input_switch(),
82            self.debounced_input_b.release_input_switch(),
83        )
84    }
85}
86
87impl<SwitchA: InputSwitch, SwitchB: InputSwitch, Config: EncoderConfig> Control
88    for Encoder<SwitchA, SwitchB, Config>
89where
90    <DebouncedInput<SwitchA, Config> as Control>::Error:
91        From<<DebouncedInput<SwitchB, Config> as Control>::Error>,
92{
93    type Event = EncoderEvent;
94    type Error = <DebouncedInput<SwitchA, Config> as Control>::Error;
95
96    fn update(&mut self) -> Result<Self::Event, Self::Error> {
97        let a_event = self.debounced_input_a.update()?;
98        let b_event = self.debounced_input_b.update()?;
99
100        fn check_event<Counts: Signed>(
101            event: DebouncedInputEvent,
102            antogonist_state: bool,
103            direct: Counts,
104        ) -> Counts {
105            match event {
106                DebouncedInputEvent::Rise if antogonist_state => -direct,
107                DebouncedInputEvent::Rise => direct,
108                DebouncedInputEvent::Fall if antogonist_state => direct,
109                DebouncedInputEvent::Fall => -direct,
110                _ => Zero::zero(),
111            }
112        }
113
114        let direct = One::one();
115
116        self.counts += check_event(a_event, self.debounced_input_b.is_high(), direct);
117        self.counts += check_event(b_event, self.debounced_input_a.is_high(), -direct);
118
119        let result_event = if !self.counts.is_zero() && (self.counts % Config::COUNTS_DIV).is_zero()
120        {
121            let counts = self.counts;
122            self.counts = Zero::zero();
123
124            match counts.is_positive() {
125                true => EncoderEvent::ClockwiseTurn,
126                false => EncoderEvent::CounterClockwiseTurn,
127            }
128        } else {
129            EncoderEvent::NoTurn
130        };
131
132        Ok(result_event)
133    }
134}