Skip to content

Instantly share code, notes, and snippets.

@ilya-epifanov
Created February 2, 2019 21:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ilya-epifanov/1e335b133943ab40c34fc1a15db59d02 to your computer and use it in GitHub Desktop.
Save ilya-epifanov/1e335b133943ab40c34fc1a15db59d02 to your computer and use it in GitHub Desktop.
#![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