Created
February 2, 2019 21:38
-
-
Save ilya-epifanov/1e335b133943ab40c34fc1a15db59d02 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![no_std] | |
use core::default::Default; | |
use num::Bounded; | |
use num::CheckedSub; | |
use num::Signed; | |
use num::Unsigned; | |
use num::traits::WrappingAdd; | |
use num::traits::WrappingSub; | |
use num::traits::AsPrimitive; | |
use num::Num; | |
pub struct RotaryEncoder<Pos, Tick, Delta> where | |
Pos: Num + WrappingAdd + WrappingSub + Bounded + Copy + PartialOrd + AsPrimitive<Delta> + Default, | |
Tick: Unsigned + Bounded + Copy + PartialOrd + CheckedSub + Default, | |
Delta: Signed + Copy + AsPrimitive<Pos>, | |
{ | |
last_active: Tick, | |
last_effective_raw_position: Pos, | |
last_real_raw_position: Pos, | |
reset_timeout: Tick, | |
div: Delta, | |
} | |
impl<Pos, Tick, Delta> RotaryEncoder<Pos, Tick, Delta> where | |
Pos: Num + WrappingAdd + WrappingSub + Bounded + Copy + PartialOrd + AsPrimitive<Delta> + Default, | |
Tick: Unsigned + Bounded + Copy + PartialOrd + CheckedSub + Default, | |
Delta: Signed + Copy + AsPrimitive<Pos>, | |
{ | |
pub fn new(div: Delta, reset_timeout: Tick) -> Self { | |
RotaryEncoder { | |
div, | |
last_active: Default::default(), | |
last_effective_raw_position: Default::default(), | |
last_real_raw_position: Default::default(), | |
reset_timeout, | |
} | |
} | |
pub fn get_delta(&mut self, raw_position: Pos, ts: Tick) -> Delta where | |
{ | |
if (self.last_active + self.reset_timeout).checked_sub(&ts) == None { | |
self.last_effective_raw_position = self.last_real_raw_position; | |
} | |
let delta: Delta = raw_position.wrapping_sub(&self.last_effective_raw_position).as_(); | |
let divisions = delta / self.div; | |
let remainder = delta % self.div; | |
self.last_effective_raw_position = self.last_effective_raw_position.wrapping_add(&(delta - remainder).as_()); | |
if self.last_real_raw_position != raw_position { | |
self.last_active = ts; | |
self.last_real_raw_position = raw_position; | |
} | |
divisions | |
} | |
} | |
#[cfg(test)] | |
mod tests { | |
use self::super::*; | |
#[test] | |
fn zero() { | |
let mut enc = RotaryEncoder::new(1i8, 10u32); | |
assert_eq!(enc.get_delta(0, 1), 0); | |
} | |
#[test] | |
fn increment() { | |
let mut enc = RotaryEncoder::new(1i8, 10u32); | |
assert_eq!(enc.get_delta(1, 1), 1); | |
} | |
#[test] | |
fn decrement() { | |
let mut enc = RotaryEncoder::new(1i8, 10u32); | |
assert_eq!(enc.get_delta(-1, 1), -1); | |
} | |
#[test] | |
fn rollover_up() { | |
let mut enc = RotaryEncoder::new(1i8, 10u32); | |
assert_eq!(enc.get_delta(127, 1), 127); | |
assert_eq!(enc.get_delta(-128, 1), 1); | |
} | |
#[test] | |
fn rollover_down() { | |
let mut enc = RotaryEncoder::new(1i8, 10u32); | |
assert_eq!(enc.get_delta(-128, 1), -128); | |
assert_eq!(enc.get_delta(127, 1), -1); | |
} | |
#[test] | |
fn all_the_way_up() { | |
let mut enc = RotaryEncoder::new(1i8, 10u32); | |
for p in 1..512 { | |
assert_eq!(enc.get_delta((p % 256) as i8, 1), 1); | |
} | |
} | |
#[test] | |
fn all_the_way_down() { | |
let mut enc = RotaryEncoder::new(1i8, 10u32); | |
for p in -1..-512 { | |
assert_eq!(enc.get_delta((p % 256) as i8, 1), 1); | |
} | |
} | |
#[test] | |
fn increment_4divs() { | |
let mut enc = RotaryEncoder::new(4i8, 10u32); | |
assert_eq!(enc.get_delta(1, 1), 0); | |
assert_eq!(enc.get_delta(2, 1), 0); | |
assert_eq!(enc.get_delta(3, 1), 0); | |
assert_eq!(enc.get_delta(4, 1), 1); | |
} | |
#[test] | |
fn decrement_4divs() { | |
let mut enc = RotaryEncoder::new(4i8, 10u32); | |
assert_eq!(enc.get_delta(-1, 1), 0); | |
assert_eq!(enc.get_delta(-2, 1), 0); | |
assert_eq!(enc.get_delta(-3, 1), 0); | |
assert_eq!(enc.get_delta(-4, 1), -1); | |
} | |
#[test] | |
fn rollover_up_4divs() { | |
let mut enc = RotaryEncoder::new(4i8, 10u32); | |
assert_eq!(enc.get_delta(124, 1), 31); | |
assert_eq!(enc.get_delta(127, 1), 0); | |
assert_eq!(enc.get_delta(-128, 1), 1); | |
assert_eq!(enc.get_delta(-127, 1), 0); | |
assert_eq!(enc.get_delta(-126, 1), 0); | |
assert_eq!(enc.get_delta(-125, 1), 0); | |
assert_eq!(enc.get_delta(-124, 1), 1); | |
} | |
#[test] | |
fn rollover_down_4divs() { | |
let mut enc = RotaryEncoder::new(4i8, 10u32); | |
assert_eq!(enc.get_delta(-128, 1), -32); | |
assert_eq!(enc.get_delta(127, 1), 0); | |
assert_eq!(enc.get_delta(126, 1), 0); | |
assert_eq!(enc.get_delta(125, 1), 0); | |
assert_eq!(enc.get_delta(124, 1), -1); | |
} | |
#[test] | |
fn all_the_way_up_4divs() { | |
let mut enc = RotaryEncoder::new(4i8, 10u32); | |
for p in 1..512 { | |
assert_eq!(enc.get_delta((p % 256) as i8, 1), if p % 4 == 0 { 1 } else { 0 }); | |
} | |
} | |
#[test] | |
fn all_the_way_down_4divs() { | |
let mut enc = RotaryEncoder::new(4i8, 10u32); | |
for p in -1..-512 { | |
assert_eq!(enc.get_delta((p % 256) as i8, 1), if p % 4 == 0 { -1 } else { 0 }); | |
} | |
} | |
#[test] | |
fn zero_unsigned() { | |
let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(1i8, 10u32); | |
assert_eq!(enc.get_delta(0, 1), 0); | |
} | |
#[test] | |
fn increment_unsigned() { | |
let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(1i8, 10u32); | |
assert_eq!(enc.get_delta(1, 1), 1); | |
} | |
#[test] | |
fn decrement_unsigned() { | |
let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(1i8, 10u32); | |
assert_eq!(enc.get_delta(255, 1), -1); | |
} | |
#[test] | |
fn rollover_up_unsigned() { | |
let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(1i8, 10u32); | |
assert_eq!(enc.get_delta(127, 1), 127); | |
assert_eq!(enc.get_delta(128, 1), 1); | |
assert_eq!(enc.get_delta(255, 1), 127); | |
assert_eq!(enc.get_delta(0, 1), 1); | |
} | |
#[test] | |
fn rollover_down_unsigned() { | |
let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(1i8, 10u32); | |
assert_eq!(enc.get_delta(255, 1), -1); | |
} | |
#[test] | |
fn all_the_way_up_unsigned() { | |
let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(1i8, 10u32); | |
for p in 1..512 { | |
assert_eq!(enc.get_delta((p % 256) as u8, 1), 1); | |
} | |
} | |
#[test] | |
fn all_the_way_down_unsigned() { | |
let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(1i8, 10u32); | |
for p in -1..-512 { | |
assert_eq!(enc.get_delta((p % 256) as u8, 1), 1); | |
} | |
} | |
#[test] | |
fn increment_4divs_unsigned() { | |
let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(4i8, 10u32); | |
assert_eq!(enc.get_delta(1, 1), 0); | |
assert_eq!(enc.get_delta(2, 1), 0); | |
assert_eq!(enc.get_delta(3, 1), 0); | |
assert_eq!(enc.get_delta(4, 1), 1); | |
} | |
#[test] | |
fn decrement_4divs_unsigned() { | |
let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(4i8, 10u32); | |
assert_eq!(enc.get_delta(255, 1), 0); | |
assert_eq!(enc.get_delta(254, 1), 0); | |
assert_eq!(enc.get_delta(253, 1), 0); | |
assert_eq!(enc.get_delta(252, 1), -1); | |
} | |
#[test] | |
fn rollover_up_4divs_unsigned() { | |
let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(4i8, 10u32); | |
assert_eq!(enc.get_delta(127, 1), 31); | |
assert_eq!(enc.get_delta(128, 1), 1); | |
assert_eq!(enc.get_delta(252, 1), 31); | |
assert_eq!(enc.get_delta(253, 1), 0); | |
assert_eq!(enc.get_delta(254, 1), 0); | |
assert_eq!(enc.get_delta(255, 1), 0); | |
assert_eq!(enc.get_delta(0, 1), 1); | |
assert_eq!(enc.get_delta(1, 1), 0); | |
assert_eq!(enc.get_delta(2, 1), 0); | |
assert_eq!(enc.get_delta(3, 1), 0); | |
assert_eq!(enc.get_delta(4, 1), 1); | |
} | |
#[test] | |
fn rollover_down_4divs_unsigned() { | |
let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(4i8, 10u32); | |
assert_eq!(enc.get_delta(255, 1), 0); | |
assert_eq!(enc.get_delta(254, 1), 0); | |
assert_eq!(enc.get_delta(253, 1), 0); | |
assert_eq!(enc.get_delta(252, 1), -1); | |
} | |
#[test] | |
fn all_the_way_up_4divs_unsigned() { | |
let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(4i8, 10u32); | |
for p in 1..512 { | |
assert_eq!(enc.get_delta((p % 256) as u8, 1), if p % 4 == 0 { 1 } else { 0 }); | |
} | |
} | |
#[test] | |
fn all_the_way_down_4divs_unsigned() { | |
let mut enc: RotaryEncoder<u8, _, _> = RotaryEncoder::new(4i8, 10u32); | |
for p in -1..-512 { | |
assert_eq!(enc.get_delta((p % 256) as u8, 1), if p % 4 == 0 { -1 } else { 0 }); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment