rotary_encoder_embedded/
lib.rs

1//! # rotary-encoder
2//! A rotary encoder library built for embedded applications
3
4#![deny(missing_docs)]
5#![deny(warnings)]
6#![cfg_attr(not(test), no_std)]
7
8use embedded_hal::digital::InputPin;
9
10/// Angular velocity api
11pub mod angular_velocity;
12/// Quadrature table encoder - suitable for intentless encoders
13pub mod quadrature;
14/// Standard encoder - suitable for indented encoders
15pub mod standard;
16
17/// Direction of Rotary Encoder rotation
18#[derive(Clone, Copy, Debug, Eq, PartialEq)]
19pub enum Direction {
20    /// No Direction is specified,
21    None,
22    /// Clockwise direction
23    Clockwise,
24    /// Anti-clockwise direction
25    Anticlockwise,
26}
27
28/// Rotary Encoder
29pub struct RotaryEncoder<MODE, DT, CLK> {
30    mode: MODE,
31    pin_dt: DT,
32    pin_clk: CLK,
33}
34
35/// Common
36impl<MODE, DT, CLK> RotaryEncoder<MODE, DT, CLK>
37where
38    DT: InputPin,
39    CLK: InputPin,
40{
41    /// Borrow a mutable reference to the underlying InputPins. This is useful for clearing hardware interrupts.
42    pub fn pins_mut(&mut self) -> (&mut DT, &mut CLK) {
43        (&mut self.pin_dt, &mut self.pin_clk)
44    }
45
46    /// Release the underying resources such as the InputPins back to the initiator
47    pub fn release(self) -> (DT, CLK) {
48        (self.pin_dt, self.pin_clk)
49    }
50
51    /// Borrow the underlying mode
52    pub fn mode(&mut self) -> &mut MODE {
53        &mut self.mode
54    }
55}
56
57/// InitializeMode
58/// This is the plain `RotaryEncoder` with no business logic attached. In order to use the `RotaryEncoder` it must be initialized to a valid `Mode`
59pub struct InitalizeMode;
60
61impl<DT, CLK> RotaryEncoder<InitalizeMode, DT, CLK>
62where
63    DT: InputPin,
64    CLK: InputPin,
65{
66    /// Initiates a new `RotaryEncoder` in `InitalizeMode`, taking two InputPins [`InputPin`](https://docs.rs/embedded-hal/0.2.3/embedded_hal/digital/v2/trait.InputPin.html).
67    pub fn new(pin_dt: DT, pin_clk: CLK) -> Self {
68        RotaryEncoder {
69            pin_dt,
70            pin_clk,
71            mode: InitalizeMode {},
72        }
73    }
74}
75
76#[cfg(test)]
77mod test {
78    use crate::{
79        angular_velocity::AngularVelocityMode, quadrature::QuadratureTableMode,
80        standard::StandardMode, Direction, RotaryEncoder,
81    };
82    use embedded_hal_mock::eh1::digital::{Mock, State, Transaction};
83
84    #[test]
85    fn standard_mode() {
86        let expectations = [Transaction::get(State::High)];
87
88        let dt = Mock::new(&expectations);
89        let clk = Mock::new(&expectations);
90
91        // Standard mode can be used with embedded-hal pins
92        let mut encoder = RotaryEncoder::new(dt, clk).into_standard_mode();
93        let _dir = encoder.update();
94
95        // Or it can be used directly, bypassing the pins
96        let mut raw_encoder = StandardMode::new();
97        let _dir = raw_encoder.update(true, false);
98
99        let (mut dt, mut clk) = encoder.release();
100        dt.done();
101        clk.done();
102    }
103
104    #[test]
105    fn quadrature_table_mode() {
106        let expectations = [Transaction::get(State::High)];
107
108        let dt = Mock::new(&expectations);
109        let clk = Mock::new(&expectations);
110
111        // Standard mode can be used with embedded-hal pins
112        let mut encoder = RotaryEncoder::new(dt, clk).into_quadrature_table_mode(1);
113        let _dir = encoder.update();
114
115        // Or it can be used directly, bypassing the pins
116        let mut raw_encoder = QuadratureTableMode::new(1);
117        let _dir = raw_encoder.update(true, false);
118
119        let (mut dt, mut clk) = encoder.release();
120        dt.done();
121        clk.done();
122    }
123
124    #[test]
125    fn angular_velocity_mode() {
126        let expectations = [Transaction::get(State::High)];
127
128        let dt = Mock::new(&expectations);
129        let clk = Mock::new(&expectations);
130
131        // Angular velocity mode can be used with embedded-hal pins
132        let mut encoder = RotaryEncoder::new(dt, clk).into_angular_velocity_mode();
133        let dir = encoder.update(2);
134        assert_eq!(dir, Direction::None);
135
136        // Or it can be used directly, bypassing the pins
137        let mut raw_encoder = AngularVelocityMode::new();
138        let _dir = raw_encoder.update(false, false, 100);
139        assert_eq!(dir, Direction::None);
140
141        let (mut dt, mut clk) = encoder.release();
142        dt.done();
143        clk.done();
144    }
145}