1#![no_std]
42
43use core::default::Default;
44
45use num_traits::Num;
46use num_traits::WrappingAdd;
47use num_traits::WrappingSub;
48use num_traits::Bounded;
49use num_traits::AsPrimitive;
50use num_traits::CheckedSub;
51use num_traits::Unsigned;
52use num_traits::Signed;
53
54pub struct RotaryEncoder<Pos, Tick, Delta> where
55 Pos: Num + WrappingAdd + WrappingSub + Bounded + Copy + PartialOrd + AsPrimitive<Delta> + Default,
56 Tick: Unsigned + Bounded + Copy + PartialOrd + CheckedSub + Default,
57 Delta: Signed + Copy + AsPrimitive<Pos>,
58{
59 last_active: Tick,
60 last_effective_raw_position: Pos,
61 last_real_raw_position: Pos,
62 reset_timeout: Tick,
63 div: Delta,
64}
65
66impl<Pos, Tick, Delta> RotaryEncoder<Pos, Tick, Delta> where
67 Pos: Num + WrappingAdd + WrappingSub + Bounded + Copy + PartialOrd + AsPrimitive<Delta> + Default,
68 Tick: Unsigned + Bounded + Copy + PartialOrd + CheckedSub + Default,
69 Delta: Signed + Copy + AsPrimitive<Pos>,
70{
71 pub fn new(div: Delta, reset_timeout: Tick) -> Self {
72 RotaryEncoder {
73 div,
74 last_active: Default::default(),
75 last_effective_raw_position: Default::default(),
76 last_real_raw_position: Default::default(),
77 reset_timeout,
78 }
79 }
80
81 pub fn get_delta(&mut self, raw_position: Pos, ts: Tick) -> Delta where
82 {
83 if (self.last_active + self.reset_timeout).checked_sub(&ts) == None {
84 self.last_effective_raw_position = self.last_real_raw_position;
85 }
86
87 let delta: Delta = raw_position.wrapping_sub(&self.last_effective_raw_position).as_();
88
89 let divisions = delta / self.div;
90 let remainder = delta % self.div;
91
92 self.last_effective_raw_position = self.last_effective_raw_position.wrapping_add(&(delta - remainder).as_());
93 if self.last_real_raw_position != raw_position {
94 self.last_active = ts;
95 self.last_real_raw_position = raw_position;
96 }
97 divisions
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use self::super::*;
104
105 #[test]
106 fn zero() {
107 let mut enc = RotaryEncoder::new(1i8, 10u32);
108 assert_eq!(enc.get_delta(0, 1), 0);
109 }
110
111 #[test]
112 fn increment() {
113 let mut enc = RotaryEncoder::new(1i8, 10u32);
114 assert_eq!(enc.get_delta(1, 1), 1);
115 }
116
117 #[test]
118 fn decrement() {
119 let mut enc = RotaryEncoder::new(1i8, 10u32);
120 assert_eq!(enc.get_delta(-1, 1), -1);
121 }
122
123 #[test]
124 fn rollover_up() {
125 let mut enc = RotaryEncoder::new(1i8, 10u32);
126
127 assert_eq!(enc.get_delta(127, 1), 127);
128 assert_eq!(enc.get_delta(-128, 1), 1);
129 }
130
131 #[test]
132 fn rollover_down() {
133 let mut enc = RotaryEncoder::new(1i8, 10u32);
134
135 assert_eq!(enc.get_delta(-128, 1), -128);
136 assert_eq!(enc.get_delta(127, 1), -1);
137 }
138
139 #[test]
140 fn all_the_way_up() {
141 let mut enc = RotaryEncoder::new(1i8, 10u32);
142
143 for p in 1..512 {
144 assert_eq!(enc.get_delta((p % 256) as i8, 1), 1);
145 }
146 }
147
148 #[test]
149 fn all_the_way_down() {
150 let mut enc = RotaryEncoder::new(1i8, 10u32);
151
152 for p in -1..-512 {
153 assert_eq!(enc.get_delta((p % 256) as i8, 1), 1);
154 }
155 }
156
157 #[test]
158 fn increment_4divs() {
159 let mut enc = RotaryEncoder::new(4i8, 10u32);
160
161 assert_eq!(enc.get_delta(1, 1), 0);
162 assert_eq!(enc.get_delta(2, 1), 0);
163 assert_eq!(enc.get_delta(3, 1), 0);
164 assert_eq!(enc.get_delta(4, 1), 1);
165 }
166
167 #[test]
168 fn decrement_4divs() {
169 let mut enc = RotaryEncoder::new(4i8, 10u32);
170 assert_eq!(enc.get_delta(-1, 1), 0);
171 assert_eq!(enc.get_delta(-2, 1), 0);
172 assert_eq!(enc.get_delta(-3, 1), 0);
173 assert_eq!(enc.get_delta(-4, 1), -1);
174 }
175
176 #[test]
177 fn rollover_up_4divs() {
178 let mut enc = RotaryEncoder::new(4i8, 10u32);
179
180 assert_eq!(enc.get_delta(124, 1), 31);
181 assert_eq!(enc.get_delta(127, 1), 0);
182 assert_eq!(enc.get_delta(-128, 1), 1);
183 assert_eq!(enc.get_delta(-127, 1), 0);
184 assert_eq!(enc.get_delta(-126, 1), 0);
185 assert_eq!(enc.get_delta(-125, 1), 0);
186 assert_eq!(enc.get_delta(-124, 1), 1);
187 }
188
189 #[test]
190 fn rollover_down_4divs() {
191 let mut enc = RotaryEncoder::new(4i8, 10u32);
192
193 assert_eq!(enc.get_delta(-128, 1), -32);
194 assert_eq!(enc.get_delta(127, 1), 0);
195 assert_eq!(enc.get_delta(126, 1), 0);
196 assert_eq!(enc.get_delta(125, 1), 0);
197 assert_eq!(enc.get_delta(124, 1), -1);
198 }
199
200 #[test]
201 fn all_the_way_up_4divs() {
202 let mut enc = RotaryEncoder::new(4i8, 10u32);
203
204 for p in 1..512 {
205 assert_eq!(enc.get_delta((p % 256) as i8, 1), if p % 4 == 0 { 1 } else { 0 });
206 }
207 }
208
209 #[test]
210 fn all_the_way_down_4divs() {
211 let mut enc = RotaryEncoder::new(4i8, 10u32);
212
213 for p in -1..-512 {
214 assert_eq!(enc.get_delta((p % 256) as i8, 1), if p % 4 == 0 { -1 } else { 0 });
215 }
216 }
217
218 #[test]
219 fn zero_unsigned() {
220 let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(1i8, 10u32);
221 assert_eq!(enc.get_delta(0, 1), 0);
222 }
223
224 #[test]
225 fn increment_unsigned() {
226 let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(1i8, 10u32);
227 assert_eq!(enc.get_delta(1, 1), 1);
228 }
229
230 #[test]
231 fn decrement_unsigned() {
232 let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(1i8, 10u32);
233 assert_eq!(enc.get_delta(255, 1), -1);
234 }
235
236 #[test]
237 fn rollover_up_unsigned() {
238 let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(1i8, 10u32);
239
240 assert_eq!(enc.get_delta(127, 1), 127);
241 assert_eq!(enc.get_delta(128, 1), 1);
242 assert_eq!(enc.get_delta(255, 1), 127);
243 assert_eq!(enc.get_delta(0, 1), 1);
244 }
245
246 #[test]
247 fn rollover_down_unsigned() {
248 let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(1i8, 10u32);
249
250 assert_eq!(enc.get_delta(255, 1), -1);
251 }
252
253 #[test]
254 fn all_the_way_up_unsigned() {
255 let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(1i8, 10u32);
256
257 for p in 1..512 {
258 assert_eq!(enc.get_delta((p % 256) as u8, 1), 1);
259 }
260 }
261
262 #[test]
263 fn all_the_way_down_unsigned() {
264 let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(1i8, 10u32);
265
266 for p in -1..-512 {
267 assert_eq!(enc.get_delta((p % 256) as u8, 1), 1);
268 }
269 }
270
271 #[test]
272 fn increment_4divs_unsigned() {
273 let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(4i8, 10u32);
274
275 assert_eq!(enc.get_delta(1, 1), 0);
276 assert_eq!(enc.get_delta(2, 1), 0);
277 assert_eq!(enc.get_delta(3, 1), 0);
278 assert_eq!(enc.get_delta(4, 1), 1);
279 }
280
281 #[test]
282 fn decrement_4divs_unsigned() {
283 let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(4i8, 10u32);
284 assert_eq!(enc.get_delta(255, 1), 0);
285 assert_eq!(enc.get_delta(254, 1), 0);
286 assert_eq!(enc.get_delta(253, 1), 0);
287 assert_eq!(enc.get_delta(252, 1), -1);
288 }
289
290 #[test]
291 fn rollover_up_4divs_unsigned() {
292 let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(4i8, 10u32);
293
294 assert_eq!(enc.get_delta(127, 1), 31);
295 assert_eq!(enc.get_delta(128, 1), 1);
296 assert_eq!(enc.get_delta(252, 1), 31);
297 assert_eq!(enc.get_delta(253, 1), 0);
298 assert_eq!(enc.get_delta(254, 1), 0);
299 assert_eq!(enc.get_delta(255, 1), 0);
300 assert_eq!(enc.get_delta(0, 1), 1);
301 assert_eq!(enc.get_delta(1, 1), 0);
302 assert_eq!(enc.get_delta(2, 1), 0);
303 assert_eq!(enc.get_delta(3, 1), 0);
304 assert_eq!(enc.get_delta(4, 1), 1);
305 }
306
307 #[test]
308 fn rollover_down_4divs_unsigned() {
309 let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(4i8, 10u32);
310
311 assert_eq!(enc.get_delta(255, 1), 0);
312 assert_eq!(enc.get_delta(254, 1), 0);
313 assert_eq!(enc.get_delta(253, 1), 0);
314 assert_eq!(enc.get_delta(252, 1), -1);
315 }
316
317 #[test]
318 fn all_the_way_up_4divs_unsigned() {
319 let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(4i8, 10u32);
320
321 for p in 1..512 {
322 assert_eq!(enc.get_delta((p % 256) as u8, 1), if p % 4 == 0 { 1 } else { 0 });
323 }
324 }
325
326 #[test]
327 fn all_the_way_down_4divs_unsigned() {
328 let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(4i8, 10u32);
329
330 for p in -1..-512 {
331 assert_eq!(enc.get_delta((p % 256) as u8, 1), if p % 4 == 0 { -1 } else { 0 });
332 }
333 }
334}