1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(test), no_std)]
3#![warn(missing_docs)]
4
5#[rustfmt::skip]
10const STATE_MAP: [[i8; 4]; 4] = [
11 [0, -1, 1, 0],
12 [1, 0, 0, -1],
13 [-1, 0, 0, 1],
14 [0, 1, -1, 0]
15];
16
17#[derive(Debug, Default)]
19pub struct RotaryEncoder {
20 inputstate: u8,
22
23 initial_inputstate: Option<u8>,
25
26 raw_value: i32,
28
29 value: i32,
31
32 tick: Option<u64>,
34}
35
36impl RotaryEncoder {
37 pub fn new() -> Self {
39 Self::default()
40 }
41
42 pub fn update<T: Into<bool>>(
47 &mut self,
48 input_a: T,
49 input_b: T,
50 tick: Option<u64>,
51 pulse_divider: i32,
52 ) -> Option<RotaryEncoderEvent> {
53 let inputstate = ((input_a.into() as u8) << 1) | (input_b.into() as u8);
54
55 if inputstate == self.inputstate {
56 return None;
58 }
59
60 if self.initial_inputstate.is_none() {
61 self.initial_inputstate = Some(inputstate);
64 }
65
66 let state_value = STATE_MAP[self.inputstate as usize][inputstate as usize];
67 self.inputstate = inputstate;
68
69 if state_value == 0 {
70 return None;
72 }
73
74 self.raw_value += state_value as i32;
75
76 if self.raw_value % pulse_divider != 0 {
77 return None;
79 }
80
81 let value = self.raw_value / pulse_divider;
82
83 if pulse_divider > 1 {
84 let aligned_raw_value =
86 ((self.raw_value + (pulse_divider - 1)) / pulse_divider) * pulse_divider;
87 if self.raw_value != aligned_raw_value {
88 self.raw_value = aligned_raw_value;
89 self.value = self.raw_value / pulse_divider;
90 }
91 self.inputstate = self.initial_inputstate.unwrap_or_default();
92 }
93
94 let timedelta = if let Some(timestamp) = tick {
95 Some(timestamp - self.tick.unwrap_or_default())
96 } else {
97 None
98 };
99
100 let event = Some(RotaryEncoderEvent {
101 value,
102 direction: if state_value > 0 {
103 Direction::Clockwise
104 } else {
105 Direction::CounterClockwise
106 },
107 timedelta,
108 });
109
110 self.value = value;
111 self.tick = tick;
112
113 event
114 }
115
116 pub fn reset(&mut self) {
118 *self = Self::default();
119 }
120
121 pub fn value(&self) -> i32 {
123 self.value
124 }
125
126 pub fn set_value(&mut self, value: i32) {
128 self.value = value;
129 }
130}
131
132#[derive(Copy, Clone, Debug, PartialEq, Eq)]
134pub struct RotaryEncoderEvent {
135 value: i32,
137
138 direction: Direction,
140
141 timedelta: Option<u64>,
143}
144
145impl RotaryEncoderEvent {
146 pub fn value(&self) -> i32 {
148 self.value
149 }
150
151 pub fn direction(&self) -> Direction {
153 self.direction
154 }
155
156 pub fn step(&self) -> i32 {
158 match self.direction {
159 Direction::Clockwise => 1,
160 Direction::CounterClockwise => -1,
161 }
162 }
163
164 pub fn timedelta(&self) -> Option<u64> {
166 self.timedelta
167 }
168
169 pub fn velocity(&self, update_freq: i32) -> Option<i32> {
173 if let Some(timedelta) = self.timedelta {
174 if timedelta > 0 {
175 Some((update_freq as u64 / timedelta) as i32)
176 } else {
177 Some(0)
178 }
179 } else {
180 None
181 }
182 }
183}
184
185#[derive(Copy, Clone, Debug, PartialEq, Eq)]
187pub enum Direction {
188 Clockwise,
190
191 CounterClockwise,
193}
194
195#[cfg(test)]
196mod tests;